private void OnPrune(PruneType Prune) { Summary.WriteMessage(this, "Pruning"); Live.Clear(); Dead.Clear(); }
/// <summary>Sow the crop with the specified parameters.</summary> /// <param name="cultivar">The cultivar.</param> /// <param name="population">The population.</param> /// <param name="depth">The depth.</param> /// <param name="rowSpacing">The row spacing.</param> /// <param name="maxCover">The maximum cover.</param> /// <param name="budNumber">The bud number.</param> public void Sow(string cultivar, double population, double depth, double rowSpacing, double maxCover = 1, double budNumber = 1) { SowingData = new SowPlant2Type(); SowingData.Plant = this; SowingData.Population = population; SowingData.Depth = depth; SowingData.Cultivar = cultivar; SowingData.MaxCover = maxCover; SowingData.BudNumber = budNumber; SowingData.RowSpacing = rowSpacing; this.Population = population; // Find cultivar and apply cultivar overrides. cultivarDefinition = PMF.Cultivar.Find(Cultivars, SowingData.Cultivar); cultivarDefinition.Apply(this); // Invoke an AboutToSow event. if (Sowing != null) { Sowing.Invoke(this, new EventArgs()); } // Invoke a sowing event. if (PlantSowing != null) { PlantSowing.Invoke(this, SowingData); } Summary.WriteMessage(this, string.Format("A crop of " + CropType + " (cultivar = " + cultivar + ") was sown today at a population of " + Population + " plants/m2 with " + budNumber + " buds per plant at a row spacing of " + rowSpacing + " and a depth of " + depth + " mm")); }
//MODEL #region Add Water to Pond private void AddWater(double Volume, WaterProperties addedProps) { //This logic is valid because people can not overfill their ponds in the real world //because the water comes from a river by opening up the gates and letting gravity fill the pond. //Therefore you can not overfill it because the water level just becomes equal to the river. //Not sure about filling due to pumping the water though. //If it overfills due to rain, then because saltwater is more dense than rain water //the rainwater just runs straight off without mixing with the pond water. //Therefore no solutes are lost due to this runoff. double maxPondVolume = SurfaceArea * MaxPondDepth; if (pondVolume + Volume > maxPondVolume) { Volume = maxPondVolume - pondVolume; Summary.WriteMessage(this, "You have overfilled the pond. Reduced the volume added to volume the pond could accept", MessageType.Warning); } AddWater_TempChange(Volume, addedProps.Temperature); AddWater_SalinityChange(Volume, addedProps.Salinity); AddWater_PHChange(Volume, addedProps.PH); AddWater_NChange(Volume, addedProps.N); AddWater_PChange(Volume, addedProps.P); AddWater_TSSChange(Volume, addedProps.TSS); //Add DOX pondVolume = pondVolume + Volume; }
private void OnStartOfSimulation(object sender, EventArgs e) { ChildStages = new List <LifeStage>(); foreach (LifeStage stage in Apsim.Children(this, typeof(LifeStage))) { stage.OwningCycle = this; ChildStages.Add(stage); } int i = 0; //create new cohorts from the InitialPopulation[] foreach (LifeStage stage in ChildStages) { if ((InitialPopulation != null) && (InitialPopulation.Length > i)) { Cohort newCohort = stage.NewCohort(); newCohort.Count = InitialPopulation[i]; mySummary.WriteMessage(this, "LifeStage " + stage.Name + " starting with " + newCohort.Count.ToString()); } else { mySummary.WriteWarning(this, "No initial population in " + stage.Name); } i++; } }
private void OnStartOfSimulation(object sender, EventArgs e) { // Check parameter values if ((zone.Slope < 0.0) || (zone.Slope > 90)) { throw new Exception("Slope angle is out of the expected range (0-90 deg)"); } if ((zone.AspectAngle < 0.0) || (zone.AspectAngle > 360)) { throw new Exception("Aspect angle is out of the expected range (0-360 deg)"); } if ((zone.Altitude < -100.0) || (SurroundsAlbedo > 5000)) { throw new Exception("Altitude value is out of bounds (0-1)"); } if ((SurroundsAlbedo < 0.0) || (SurroundsAlbedo > 1.0)) { throw new Exception("Albedo value is out of bounds (0-1)"); } if ((TurbidityCoefficient < 0.0) || (TurbidityCoefficient > 1.0)) { throw new Exception("Turbidity coefficient value is out of bounds (0-1)"); } // Convert and fix some parameters // zone.AspectAngle is degrees from north. This algorithm seems to work using aspect from south in radians. // Should really check this against original sources of the equations. Seems to make sense. aspectFromSouthInRadians = zone.AspectAngle + 180; if (aspectFromSouthInRadians > 360) { aspectFromSouthInRadians -= 360; } zone.Slope = Math.PI * zone.Slope / 180; aspectFromSouthInRadians = Math.PI * aspectFromSouthInRadians / 180; latitudeAngle = Math.PI * weather.Latitude / 180; // Get the local mean atmospheric pressure, similar to Allen et al (1998) double expPressure = standardGravitationalAcceleration * standardAtmosphericMolarMass / (universalGasConstant * standardTemperatureLapseRate); AtmosphericPressure = Math.Pow(1 - (standardTemperatureLapseRate * zone.Altitude / standardAtmosphericTemperature), expPressure); AtmosphericPressure *= standardAtmosphericPressure; // Get the slope factor for correcting reflected radiation, based on Allen et al. (2006) slopeFactor = 0.75 + (0.25 * Math.Cos(zone.Slope)) - (0.5 * zone.Slope / Math.PI); // Covert the user defined changes from percent into fraction dRain = Math.Max(-1.0, 0.01 * dRain); dWind = Math.Max(-1.0, 0.01 * dWind); dVapPressure = Math.Max(-1.0, 0.01 * dVapPressure); // NOTE: dVapPressure has a variable upper bound, it cannot be higher than the saturated VP // this upper limit will be assumed equal to 95% of saturation at daily Tmax summary.WriteMessage(this, " Weather variables will be adjusted for slope and aspect", MessageType.Diagnostic); summary.WriteMessage(this, " - Radiation and temperature adjusted based on the model described by Cichota (2015)", MessageType.Diagnostic); summary.WriteMessage(this, " - Rainfall, wind, and vapour pressure are simple relative changes - not explicitly linked to slope", MessageType.Diagnostic); summary.WriteMessage(this, " - The values of RH, if existent, will be adjusted whenever the temperature or vp change", MessageType.Diagnostic); }
/// <summary> /// Generate a weather file. /// </summary> /// <param name="cancelToken">Optional token which allows for cancellation of the child process.</param> public IWeather GenerateWeatherFile(CancellationToken cancelToken = default(CancellationToken)) { if (!Directory.Exists(bestiapopPath)) { Status = "Installing Bestiapop"; InstallBestiapop(bestiapopPath); } string output = OutputPath; if (string.IsNullOrEmpty(output)) { output = Path.Combine(Path.GetTempPath(), $"bestiapop-{Guid.NewGuid()}"); if (summary != null) { summary.WriteMessage(this, $"OutputPath was not specified. Files will be generated to temp directory: '{output}'"); } } if (!Directory.Exists(output)) { Directory.CreateDirectory(output); } string bestiapop = Path.Combine(bestiapopPath, "bestiapop", "bestiapop.py"); StringBuilder args = new StringBuilder($"{bestiapop} -a generate-climate-file -s silo -y {StartDate.Year}-{EndDate.Year} -lat {Latitude} -lon {Longitude} "); // todo: check that these are correct variables args.Append("-c \"daily_rain max_temp min_temp vp vp_deficit evap_pan radiation et_short_crop\" "); if (MultiProcess) { args.Append($"-m "); } args.Append($"-o {output}"); if (summary != null) { summary.WriteMessage(this, $"Running bestiapop with command: 'python {args}' from directory {output}"); } Status = "Running bestiapop"; try { string stdout = RunCommand("python", args.ToString(), output); summary.WriteMessage(this, $"Ran command 'python {args}' from directory '{output}'. Output from bestiapop:{Environment.NewLine}{stdout}"); } catch (Exception err) { throw new Exception("Encountered an error while running bestiapop", err); } Weather result = CreateWeatherComponent(Directory.GetFiles(output, "*.met").FirstOrDefault()); Status = null; return(result); }
/// <summary>Apply some irrigation.</summary> /// <param name="amount">The amount to apply (mm).</param> /// <param name="depth">The depth of application (mm).</param> /// <param name="duration">The duration of the irrigation event (minutes).</param> /// <param name="efficiency">The irrigation efficiency (mm/mm).</param> /// <param name="willRunoff">Whether irrigation can run off (<c>true</c>/<c>false</c>).</param> /// <param name="no3">Amount of NO3 in irrigation water</param> /// <param name="nh4">Amount of NH4 in irrigation water</param> public void Apply(double amount, double depth = 0.0, double duration = 1440.0, double efficiency = 1.0, bool willRunoff = false, double no3 = -1.0, double nh4 = -1.0) { if (Irrigated != null && amount > 0.0) { if (depth > soil.Thickness.Sum()) { throw new ApsimXException(this, "Check the depth for irrigation, it cannot be deeper than the soil depth"); } Depth = depth; if (duration > 1440.0) { throw new ApsimXException(this, "Check the duration for the irrigation, it must be less than 1440 minutes"); } Duration = duration; if (efficiency > 1.0) { throw new ApsimXException(this, "Check the value of irrigation efficiency, it must be between 0 and 1"); } Efficiency = efficiency; if (Depth > 0.0) { // Sub-surface irrigation: it cannot be intercepted nor run off directly willRunoff = false; } IrrigationApplied = amount; WillRunoff = willRunoff; // Prepare the irrigation data IrrigationApplicationType irrigData = new IrrigationApplicationType(); irrigData.Amount = IrrigationApplied; irrigData.Depth = Depth; irrigData.Duration = Duration; irrigData.WillRunoff = WillRunoff; if (no3 != -1) { irrigData.NO3 = no3; } if (nh4 != -1) { irrigData.NH4 = nh4; } // Raise event and write log Irrigated.Invoke(this, irrigData); summary.WriteMessage(this, string.Format("{0:F1} mm of water added via irrigation at depth {1} mm", IrrigationApplied, Depth)); } else { // write log of aborted event summary.WriteMessage(this, "Irrigation did not occur because the amount given was negative"); } }
/// <summary>Apply some irrigation.</summary> /// <param name="amount">The amount to apply (mm).</param> /// <param name="depth">The depth of application (mm).</param> /// <param name="duration">The duration of the irrigation event (minutes).</param> /// <param name="efficiency">The irrigation efficiency (mm/mm).</param> /// <param name="willRunoff">Whether irrigation can run off (<c>true</c>/<c>false</c>).</param> /// <param name="no3">Amount of NO3 in irrigation water</param> /// <param name="nh4">Amount of NH4 in irrigation water</param> /// <param name="doOutput">If true, output will be written to the summary.</param> public void Apply(double amount, double depth = 0.0, double duration = 1440.0, double efficiency = 1.0, bool willRunoff = false, double no3 = 0.0, double nh4 = 0.0, bool doOutput = true) { if (Irrigated != null && amount > 0.0) { if (depth > soilPhysical.Thickness.Sum()) { throw new ApsimXException(this, "Check the depth for irrigation, it cannot be deeper than the soil depth"); } Depth = depth; if (duration > 1440.0) { throw new ApsimXException(this, "Check the duration for the irrigation, it must be less than 1440 minutes"); } Duration = duration; if (efficiency > 1.0) { throw new ApsimXException(this, "Check the value of irrigation efficiency, it must be between 0 and 1"); } Efficiency = efficiency; // Sub-surface irrigation cannot run off if (Depth > 0.0) { willRunoff = false; } WillRunoff = willRunoff; // Prepare the irrigation data IrrigationApplicationType irrigData = new IrrigationApplicationType(); irrigData.Amount = amount * efficiency; irrigData.Depth = Depth; irrigData.Duration = Duration; irrigData.WillRunoff = WillRunoff; irrigData.NO3 = no3; irrigData.NH4 = nh4; // Raise event and write log Irrigated.Invoke(this, irrigData); if (doOutput) { summary.WriteMessage(this, string.Format("{0:F1} mm of water added via irrigation at depth {1} mm", irrigData.Amount, Depth), MessageType.Diagnostic); } IrrigationApplied += irrigData.Amount; } else if (doOutput && amount < 0) { summary.WriteMessage(this, "Irrigation did not occur because the amount given was negative", MessageType.Warning); } }
private void OnPhaseChanged(object sender, PhaseChangedType phaseChange) { if (sender == this && Phenology != null && Canopy != null && AboveGround != null) { string message = Phenology.CurrentPhase.Start + "\r\n"; if (Canopy != null) { message += " LAI = " + Canopy.LAI.ToString("f2") + " (m^2/m^2)" + "\r\n"; message += " Above Ground Biomass = " + AboveGround.Wt.ToString("f2") + " (g/m^2)" + "\r\n"; } Summary.WriteMessage(this, message); } }
private void OnPhaseChanged(PhaseChangedType PhaseChange) { if (Phenology != null && Leaf != null && AboveGround != null) { string message = Phenology.CurrentPhase.Start + "\r\n"; if (Leaf != null) { message += " LAI = " + Leaf.LAI.ToString("f2") + " (m^2/m^2)" + "\r\n"; message += " Above Ground Biomass = " + AboveGround.Wt.ToString("f2") + " (g/m^2)" + "\r\n"; } Summary.WriteMessage(this, message); } }
private void OnSimulationCommencing(object sender, EventArgs e) { if (Verbose) { summary.WriteMessage(this, "Initialising the Manager for grazing, urine return and reporting"); } if (GrazingRotationType == GrazingRotationTypeEnum.TargetMass || GrazingRotationType == GrazingRotationTypeEnum.TargetMassAndLength) { if (PreGrazeDMArray == null || PreGrazeDMArray.Length != 12) { throw new Exception("There must be 12 values input for the pre-grazing DM"); } if (PostGrazeDMArray == null || PostGrazeDMArray.Length != 12) { throw new Exception("There must be 12 values input for the post-grazing DM"); } } if (GrazingRotationType == GrazingRotationTypeEnum.TargetMassAndLength) { if (RotationLengthArray == null || RotationLengthArray.Length != 12) { throw new Exception("There must be 12 values input for rotation length"); } } if (FractionOfBiomassToDung.Length != 1 && FractionOfBiomassToDung.Length != 12) { throw new Exception("You must specify either a single value for 'proportion of biomass going to dung' or 12 monthly values."); } if (FractionOfBiomassToUrine.Length != 1 && FractionOfBiomassToUrine.Length != 12) { throw new Exception("You must specify either a single value for 'proportion of biomass going to urine' or 12 monthly values."); } if (Verbose) { summary.WriteMessage(this, "Finished initialising the Manager for grazing, urine return and reporting"); } if (NoGrazingStartString != null) { NoGrazingStart = DateUtilities.GetDate(NoGrazingStartString); } if (NoGrazingEndString != null) { NoGrazingEnd = DateUtilities.GetDate(NoGrazingEndString); } }
/// <summary> /// Execute harvest logic for reproductive organ /// </summary> public override void DoHarvest() { double YieldDW = (Live.Wt + Dead.Wt); Summary.WriteMessage(this, "Harvesting " + Name + " from " + Plant.Name); Summary.WriteMessage(this, " Yield DWt: " + YieldDW.ToString("f2") + " (g/m^2)"); Summary.WriteMessage(this, " Size: " + Size.ToString("f2") + " (g)"); Summary.WriteMessage(this, " Number: " + Number.ToString("f2") + " (/m^2)"); Live.Clear(); Dead.Clear(); Number = 0; _ReadyForHarvest = false; }
/// <summary>Perform grazing</summary> /// <param name="amountDMToRemove">The amount of biomas to remove (kg/ha).</param> public void Graze(double amountDMToRemove) { GrazingInterval = DaysSinceGraze; // i.e. yesterday's value DaysSinceGraze = 0; RemoveDMFromPlants(amountDMToRemove); AddUrineToSoil(); AddDungToSurface(); // Calculate post-grazed dry matter. PostGrazeDM = 0.0; foreach (var forage in allForages) { PostGrazeDM += forage.Material.Sum(m => m.Total.Wt); } // Calculate proportions of each species to the total biomass. for (int i = 0; i < allForages.Count; i++) { var proportionToTotalDM = MathUtilities.Divide(allForages[i].Material.Sum(m => m.Total.Wt), PostGrazeDM, 0); ProportionOfTotalDM[i] = proportionToTotalDM; } summary.WriteMessage(this, string.Format("Grazed {0:0.0} kgDM/ha, N content {1:0.0} kgN/ha, ME {2:0.0} MJME/ha", GrazedDM, GrazedN, GrazedME)); // Reduce plant population if necessary. if (FractionPopulationDecline > 0) { foreach (var forage in allForages) { if ((forage as IModel) is IHasPopulationReducer populationReducer) { populationReducer.ReducePopulation(populationReducer.Population * (1.0 - FractionPopulationDecline)); } else { throw new Exception($"Model {forage.Name} is unable to reduce its population due to grazing. Not implemented."); } } } // Convert PostGrazeDM to kg/ha PostGrazeDM *= 10; // Invoke grazed event. Grazed?.Invoke(this, new EventArgs()); }
/// <summary>Removes biomass from organs when harvest, graze or cut events are called.</summary> /// <param name="value">Biomass to remove</param> virtual public void DoRemoveBiomass(OrganBiomassRemovalType value) { double RemainFrac = 1 - (value.FractionToResidue + value.FractionRemoved); if (RemainFrac < 0) { throw new Exception("The sum of FractionToResidue and FractionRemoved sent with your " + "!!!!PLACE HOLDER FOR EVENT SENDER!!!!" + " is greater than 1. Had this execption not triggered you would be removing more biomass from " + Name + " than there is to remove"); } if (RemainFrac < 1) { double TotalFracRemoved = value.FractionRemoved + value.FractionToResidue; double PcToResidue = value.FractionToResidue / TotalFracRemoved * 100; double PcRemoved = value.FractionRemoved / TotalFracRemoved * 100; Summary.WriteMessage(this, "Removing " + TotalFracRemoved * 100 + "% of " + Name + " Biomass from " + Plant.Name + ". Of this " + PcRemoved + "% is removed from the system and " + PcToResidue + "% is returned to the surface organic matter"); SurfaceOrganicMatter.Add(Wt * 10 * value.FractionToResidue, N * 10 * value.FractionToResidue, 0, Plant.CropType, Name); if (Live.StructuralWt > 0) { Live.StructuralWt *= RemainFrac; } if (Live.NonStructuralWt > 0) { Live.NonStructuralWt *= RemainFrac; } if (Live.StructuralN > 0) { Live.StructuralN *= RemainFrac; } if (Live.NonStructuralN > 0) { Live.NonStructuralN *= RemainFrac; } } }
/// <summary> /// Check the sensibility of the zone. Write any warnings to the summary log. /// </summary> private void CheckSensibility() { if (FindInScope <MicroClimate>() == null) { summary.WriteMessage(this, "MicroClimate not found", MessageType.Warning); } }
private void OnPlantSowing(object sender, SowPlant2Type data) { if (DaysFromSowingToEndPhase > 0) { summary.WriteMessage(this, "FIXED number of days from sowing to " + Name + " = " + DaysFromSowingToEndPhase); } }
private void OnPlantSowing(object sender, SowPlant2Type data) { double SowDepth = 0; double accumDepth = 0; if (Plant != null) { SowDepth = Plant.SowingData.Depth; } if (Plant15 != null) { SowDepth = Plant15.SowingData.Depth; } bool layerfound = false; for (int layer = 0; layerfound; layer++) { accumDepth += Soil.Thickness[layer]; if (SowDepth <= accumDepth) { SowLayer = layer; layerfound = true; } } if (DaysFromSowingToEndPhase > 0) { summary.WriteMessage(this, "FIXED number of days from sowing to " + Name + " = " + DaysFromSowingToEndPhase); } }
/// <summary>Method to bring a new cohort of individuls to the specified LifeCyclePhase</summary> /// <param name="Immigrants"></param> public void Infest(Cohort Immigrants) { LifeCyclePhase InfestingPhase = Immigrants.BelongsToPhase; InfestingPhase.NewCohort(Immigrants.Population, Immigrants.ChronologicalAge, Immigrants.PhysiologicalAge); mySummary.WriteMessage(this, "An infestation of " + Immigrants.Population + " " + Apsim.FullPath(this) + " " + Immigrants.BelongsToPhase.Name + "'s occured today, just now :-)"); }
/// <summary>Apply fertiliser.</summary> /// <param name="Amount">The amount.</param> /// <param name="Type">The type.</param> /// <param name="Depth">The depth.</param> /// <exception cref="ApsimXException">Cannot find fertiliser type ' + Type + '</exception> public void Apply(double Amount, Types Type, double Depth = 0.0) { if (Amount > 0) { // find the layer that the fertilizer is to be added to. int layer = GetLayerDepth(Depth, Soil.Thickness); FertiliserType fertiliserType = Definitions.FirstOrDefault(f => f.Name == Type.ToString()); if (fertiliserType == null) { throw new ApsimXException(this, "Cannot find fertiliser type '" + Type + "'"); } if (fertiliserType.FractionNO3 != 0) { solutes.AddToLayer(layer, "NO3", SoluteManager.SoluteSetterType.Fertiliser, Amount * fertiliserType.FractionNO3); NitrogenApplied += Amount * fertiliserType.FractionNO3; } if (fertiliserType.FractionNH4 != 0) { solutes.AddToLayer(layer, "NH4", SoluteManager.SoluteSetterType.Fertiliser, Amount * fertiliserType.FractionNH4); NitrogenApplied += Amount * fertiliserType.FractionNH4; } if (fertiliserType.FractionUrea != 0) { solutes.AddToLayer(layer, "Urea", SoluteManager.SoluteSetterType.Fertiliser, Amount * fertiliserType.FractionUrea); NitrogenApplied += Amount * fertiliserType.FractionUrea; } Summary.WriteMessage(this, string.Format("{0} kg/ha of {1} added at depth {2} layer {3}", Amount, Type, Depth, layer + 1)); } }
/// <summary>Method to bring a new cohort of individuls to the specified LifeCyclePhase</summary> /// <param name="InfestationInfo"></param> public void Infest(SourceInfo InfestationInfo) { LifeCyclePhase InfestingPhase = FindChild <LifeCyclePhase>(InfestationInfo.LifeCyclePhase); InfestingPhase.NewCohort(InfestationInfo); mySummary.WriteMessage(this, "An infestation of " + InfestationInfo.Population + " " + FullPath + " " + InfestationInfo.LifeCyclePhase + "'s occured today, just now :-)"); }
/// <summary>Called to start the job.</summary> /// <param name="jobManager">The job manager running this job.</param> /// <param name="workerThread">The thread this job is running on.</param> public void Run(JobManager jobManager, BackgroundWorker workerThread) { try { StartRun(); DoRun(jobManager, workerThread); CleanupRun(); } catch (ApsimXException err) { ErrorMessage = "ERROR in file: " + FileName + "\r\n" + "Simulation name: " + Name + "\r\n" + err.ToString(); ISummary summary = Apsim.Find(this, typeof(Summary)) as ISummary; summary.WriteMessage(this, ErrorMessage); CleanupRun(); throw new Exception(ErrorMessage); } catch (Exception err) { ErrorMessage = "ERROR in file: " + FileName + "\r\n" + "Simulation name: " + Name + "\r\n" + err.ToString(); ISummary summary = Apsim.Find(this, typeof(Summary)) as ISummary; summary.WriteMessage(this, ErrorMessage); CleanupRun(); throw new Exception(ErrorMessage); } }
private void OnSimulationCommencing(object sender, EventArgs e) { ProportionOfTotalDM = new double[forages.Count]; if (Verbose) { summary.WriteMessage(this, "Initialising the Manager for grazing, urine return and reporting"); } if (GrazingRotationType == GrazingRotationTypeEnum.TargetMass) { if (PreGrazeDMArray == null || PreGrazeDMArray.Length != 12) { throw new Exception("There must be 12 values input for the pre-grazing DM"); } if (PostGrazeDMArray == null || PostGrazeDMArray.Length != 12) { throw new Exception("There must be 12 values input for the post-grazing DM"); } } else if (GrazingRotationType == GrazingRotationTypeEnum.Flexible) { if (string.IsNullOrEmpty(FlexibleExpressionForTimingOfGrazing)) { throw new Exception("You must specify an expression for timing of grazing."); } expressionFunction = new CSharpExpressionFunction(); expressionFunction.Parent = this; expressionFunction.Expression = "Convert.ToDouble(" + FlexibleExpressionForTimingOfGrazing + ")"; expressionFunction.CompileExpression(); } if (FractionOfBiomassToDung.Length != 1 && FractionOfBiomassToDung.Length != 12) { throw new Exception("You must specify either a single value for 'proportion of biomass going to dung' or 12 monthly values."); } if (FractionOfBiomassToUrine.Length != 1 && FractionOfBiomassToUrine.Length != 12) { throw new Exception("You must specify either a single value for 'proportion of biomass going to urine' or 12 monthly values."); } if (Verbose) { summary.WriteMessage(this, "Finished initialising the Manager for grazing, urine return and reporting"); } }
private void OnHarvesting(object sender, EventArgs e) { if (sender == Plant) { double YieldDW = (Live.Wt + Dead.Wt); Summary.WriteMessage(this, "Harvesting " + Name + " from " + Plant.Name); Summary.WriteMessage(this, " Yield DWt: " + YieldDW.ToString("f2") + " (g/m^2)"); Summary.WriteMessage(this, " Size: " + Size.ToString("f2") + " (g)"); Summary.WriteMessage(this, " Number: " + Number.ToString("f2") + " (/m^2)"); Live.Clear(); Dead.Clear(); Number = 0; _ReadyForHarvest = false; } }
/// <summary> /// Add new warning to the List if it hasn't been reported /// </summary> /// <param name="checkMessage">The warning message to check if it exists</param> /// <param name="summary">The summary model to write to</param> /// <param name="sender">The activity sending the warning</param> /// <param name="messageType">The type of message to write</param> /// <param name="fullMessage">A full message to report if check message does not exist, otherwise use check message</param> public void CheckAndWrite(string checkMessage, ISummary summary, IModel sender, MessageType messageType, string fullMessage = "") { if (!Exists(checkMessage) & summary != null) { summary.WriteMessage(sender, (fullMessage.Any())?fullMessage:checkMessage, messageType); Add(checkMessage); } }
private void OnPhaseChanged(object sender, PhaseChangedType phaseChange) { if (sender == this && Leaf != null && AboveGround != null) { string message = Phenology.CurrentPhase.Start + "\r\n"; if (Leaf != null) { message += " LAI = " + Leaf.LAI.ToString("f2") + " (m^2/m^2)" + "\r\n"; message += " Above Ground Biomass = " + AboveGround.Wt.ToString("f2") + " (g/m^2)" + "\r\n"; } summary.WriteMessage(this, message); if (Phenology.CurrentPhase.Start == "Flowering" && Flowering != null) { Flowering.Invoke(this, null); } } }
private void OnCutting(object sender, EventArgs e) { Summary.WriteMessage(this, "Cutting " + Name + " from " + Plant.Name); Live.Clear(); Dead.Clear(); Number = 0; _ReadyForHarvest = false; }
private void OnCutting(object sender, EventArgs e) { if (sender == Plant) { Summary.WriteMessage(this, "Cutting " + Name + " from " + Plant.Name); Live.Clear(); Dead.Clear(); } }
/// <summary>Incorporates the specified fraction.</summary> /// <param name="fraction">The fraction.</param> /// <param name="depth">The depth.</param> public void Incorporate(double fraction, double depth) { Incorp(fraction, depth); summary.WriteMessage(this, string.Format(@"Residue removed " + Environment.NewLine + "Fraction Incorporated = {0:0.0##}" + Environment.NewLine + "Incorporated Depth = {1:0.0##}", fraction, depth)); }
/// <summary> /// Accumulate rainfall for tillage cn reduction. /// The reduction in the runoff as a result of doing a tillage (tillage_cn_red) ceases after a set amount of rainfall (tillage_cn_rain). /// This function works out the accumulated rainfall since last tillage event, and turns off the reduction if it is over the amount of rain specified. /// </summary> private void ShouldIStopTillageCNReduction() { if (TillageCnCumWater > 0.0 && CumWaterSinceTillage > TillageCnCumWater) { // This tillage has lost all effect on cn. CN reduction // due to tillage is off until the next tillage operation. TillageCnCumWater = 0.0; TillageCnRed = 0.0; summary.WriteMessage(this, "Tillage CN reduction finished"); } }
/// <summary> /// Set amount of animal food available /// </summary> /// <param name="NewValue">New value to set food store to</param> public void Set(double NewValue) { if ((NewValue < 0) || (NewValue > this.LandArea)) { Summary.WriteMessage(this, "Tried to Set Available Land to Invalid New Amount." + Environment.NewLine + "New Value must be between 0 and the Land Area."); } else { this.areaAvailable = NewValue; } }