private void OnCLEMInitialiseActivity(object sender, EventArgs e) { // activity is performed in CLEMDoCutAndCarry not CLEMGetResources this.AllocationStyle = ResourceAllocationStyle.Manual; // get pasture pasture = Resources.FindResourceType <GrazeFoodStore, GrazeFoodStoreType>(this, PaddockName, OnMissingResourceActionTypes.ReportErrorAndStop, OnMissingResourceActionTypes.ReportErrorAndStop); // get food store foodstore = Resources.FindResourceType <AnimalFoodStore, AnimalFoodStoreType>(this, AnimalFoodStoreName, OnMissingResourceActionTypes.ReportErrorAndStop, OnMissingResourceActionTypes.ReportErrorAndStop); // locate a cut and carry limiter associarted with this event. limiter = LocateCutAndCarryLimiter(this); switch (CutStyle) { case RuminantFeedActivityTypes.ProportionOfPotentialIntake: case RuminantFeedActivityTypes.ProportionOfRemainingIntakeRequired: case RuminantFeedActivityTypes.ProportionOfWeight: case RuminantFeedActivityTypes.SpecifiedDailyAmountPerIndividual: InitialiseHerd(true, true); break; default: break; } }
private void OnCLEMAnimalStock(object sender, EventArgs e) { // this event happens after management has marked individuals for purchase or sale. if (Clock.Today.Month == AssessmentMonth) { this.Status = ActivityStatus.NotNeeded; // calculate dry season pasture available for each managed paddock holding stock not flagged for sale RuminantHerd ruminantHerd = Resources.RuminantHerd(); foreach (var paddockGroup in ruminantHerd.Herd.Where(a => a.Location != "").GroupBy(a => a.Location)) { // multiple breeds are currently not supported as we need to work out what to do with diferent AEs if (paddockGroup.GroupBy(a => a.Breed).Count() > 1) { throw new ApsimXException(this, "Dry season destocking paddocks with multiple breeds is currently not supported\nActivity:" + this.Name + ", Paddock: " + paddockGroup.Key); } // total adult equivalents not marked for sale of all breeds on pasture for utilisation double totalAE = paddockGroup.Where(a => a.SaleFlag == HerdChangeReason.None).Sum(a => a.AdultEquivalent); double shortfallAE = 0; // Determine total feed requirements for dry season for all ruminants on the pasture // We assume that all ruminant have the BaseAnimalEquivalent to the specified herd shortfallAE = 0; GrazeFoodStoreType pasture = Resources.GetResourceItem(this, typeof(GrazeFoodStore), paddockGroup.Key, OnMissingResourceActionTypes.ReportErrorAndStop, OnMissingResourceActionTypes.ReportErrorAndStop) as GrazeFoodStoreType; double pastureBiomass = pasture.Amount; // Adjust fodder balance for detachment rate (6%/month) double feedRequiredAE = paddockGroup.FirstOrDefault().BreedParams.BaseAnimalEquivalent * 0.02 * 30.4; // 2% of AE animal per day for (int i = 0; i < this.DrySeasonLength; i++) { pastureBiomass *= (1.0 - pasture.DetachRate); pastureBiomass -= feedRequiredAE * totalAE; } // Shortfall in Fodder in kg per hectare // pasture at end of period in kg/ha double pastureShortFallKgHa = pastureBiomass / pasture.Manager.Area; // shortfall from low limit pastureShortFallKgHa = Math.Max(0, FeedLowLimit - pastureShortFallKgHa); // Shortfall in Fodder in kg for paddock double pastureShortFallKg = pastureShortFallKgHa * pasture.Manager.Area; if (pastureShortFallKg == 0) { return; } // number of AE to sell to balance shortfall_kg shortfallAE = pastureShortFallKg / feedRequiredAE; // get prediction HandleDestocking(shortfallAE, paddockGroup.Key); } } else { this.Status = ActivityStatus.Ignored; } }
private void OnCLEMInitialiseActivity(object sender, EventArgs e) { this.InitialiseHerd(false, true); breedParams = Resources.GetResourceItem(this, typeof(RuminantHerd), this.PredictedHerdName, OnMissingResourceActionTypes.ReportErrorAndStop, OnMissingResourceActionTypes.ReportErrorAndStop) as RuminantType; // max sires if (MaximumSiresKept < 1 & MaximumSiresKept > 0) { SiresKept = Convert.ToInt32(Math.Ceiling(MaximumBreedersKept * MaximumSiresKept), CultureInfo.InvariantCulture); } else { SiresKept = Convert.ToInt32(Math.Truncate(MaximumSiresKept), CultureInfo.InvariantCulture); } if (FillBreedingMalesAtStartup) { RuminantHerd herd = Resources.RuminantHerd(); if (herd != null) { // get number in herd int numberPresent = this.CurrentHerd(false).Where(a => a.Gender == Sex.Male).Cast <RuminantMale>().Where(a => a.BreedingSire).Count(); // fill to number needed for (int i = numberPresent; i < SiresKept; i++) { RuminantMale newbull = new RuminantMale(48, Sex.Male, 450, breedParams) { Breed = this.PredictedHerdBreed, HerdName = this.PredictedHerdName, BreedingSire = true, ID = herd.NextUniqueID, PreviousWeight = 450, SaleFlag = HerdChangeReason.InitialHerd }; herd.AddRuminant(newbull, this); } } } // check GrazeFoodStoreExists grazeStore = ""; if (GrazeFoodStoreName != null && !GrazeFoodStoreName.StartsWith("Not specified")) { grazeStore = GrazeFoodStoreName.Split('.').Last(); foodStore = Resources.GetResourceItem(this, GrazeFoodStoreName, OnMissingResourceActionTypes.ReportErrorAndStop, OnMissingResourceActionTypes.ReportErrorAndStop) as GrazeFoodStoreType; } // check for managed paddocks and warn if animals placed in yards. if (grazeStore == "") { var ah = Apsim.Find(this, typeof(ActivitiesHolder)); if (Apsim.ChildrenRecursively(ah, typeof(PastureActivityManage)).Count() != 0) { Summary.WriteWarning(this, String.Format("Animals purchased by [a={0}] are currently placed in [Not specified - general yards] while a managed pasture is available. These animals will not graze until mustered and will require feeding while in yards.\nSolution: Set the [GrazeFoodStore to place purchase in] located in the properties [General].[PastureDetails]", this.Name)); } } }
private void OnCLEMInitialiseActivity(object sender, EventArgs e) { // get pasture pasture = Resources.FindResourceType <GrazeFoodStore, GrazeFoodStoreType>(this, PaddockName, OnMissingResourceActionTypes.ReportErrorAndStop, OnMissingResourceActionTypes.ReportErrorAndStop); if (MethaneStoreName is null || MethaneStoreName == "Use store named Methane if present") { methaneStore = Resources.FindResourceType <GreenhouseGases, GreenhouseGasesType>(this, "Methane", OnMissingResourceActionTypes.Ignore, OnMissingResourceActionTypes.Ignore); }
private double HandleRestocking(double animalEquivalentsToBuy, string paddockName, Ruminant exampleRuminant) { if (animalEquivalentsToBuy <= 0) { return(0); } GrazeFoodStoreType foodStore = Resources.GetResourceItem(this, typeof(GrazeFoodStore), paddockName, OnMissingResourceActionTypes.Ignore, OnMissingResourceActionTypes.ReportErrorAndStop) as GrazeFoodStoreType; // ensure min pasture for restocking if ((foodStore == null) || ((foodStore.TonnesPerHectare * 1000) > MinimumFeedBeforeRestock)) { var specifyComponents = FindAllChildren <SpecifyRuminant>(); if (specifyComponents.Count() == 0) { string warn = $"No [f=SpecifyRuminant]s were provided in [a={this.Name}]\r\nNo restocking will be performed."; this.Status = ActivityStatus.Warning; if (!Warnings.Exists(warn)) { Summary.WriteWarning(this, warn); Warnings.Add(warn); } } // buy animals specified in restock ruminant groups foreach (SpecifyRuminant item in specifyComponents) { double sumAE = 0; double limitAE = animalEquivalentsToBuy * item.Proportion; while (sumAE < limitAE && animalEquivalentsToBuy > 0) { Ruminant newIndividual = item.Details.CreateIndividuals(1, null).FirstOrDefault(); newIndividual.Location = paddockName; newIndividual.BreedParams = item.BreedParams; newIndividual.HerdName = item.BreedParams.Name; newIndividual.PurchaseAge = newIndividual.Age; newIndividual.SaleFlag = HerdChangeReason.RestockPurchase; if (newIndividual.Weight == 0) { throw new ApsimXException(this, $"Specified individual added during restock cannot have no weight in [{this.Name}]"); } Resources.RuminantHerd().PurchaseIndividuals.Add(newIndividual); double indAE = newIndividual.AdultEquivalent; animalEquivalentsToBuy -= indAE; sumAE += indAE; } } return(Math.Max(0, animalEquivalentsToBuy)); } return(animalEquivalentsToBuy); }
private void OnCLEMInitialiseActivity(object sender, EventArgs e) { ForecastSequence = new Dictionary <DateTime, double>(); // load ENSO file into memory Simulation simulation = Apsim.Parent(this, typeof(Simulation)) as Simulation; if (simulation != null) { fullFilename = PathUtilities.GetAbsolutePath(this.MonthlySIOFile, simulation.FileName); } else { fullFilename = this.MonthlySIOFile; } //check file exists if (!File.Exists(fullFilename)) { Summary.WriteWarning(this, String.Format("@error:Could not find ENSO SIO datafile [x={0}[ for [a={1}]", MonthlySIOFile, this.Name)); } // load data using (StreamReader ensoStream = new StreamReader(MonthlySIOFile)) { string line = ""; while ((line = ensoStream.ReadLine()) != null) { if (!line.StartsWith("Year")) { string[] items = line.Split(' '); for (int i = 1; i < items.Count(); i++) { ForecastSequence.Add( new DateTime(Convert.ToInt16(items[0]), Convert.ToInt16(i, CultureInfo.InvariantCulture), 1), Convert.ToDouble(items[i], CultureInfo.InvariantCulture) ); } } } } // check GrazeFoodStoreExists if (GrazeFoodStoreName == null) { GrazeFoodStoreName = ""; } if (GrazeFoodStoreName != "") { foodStore = Resources.GetResourceItem(this, typeof(GrazeFoodStore), GrazeFoodStoreName, OnMissingResourceActionTypes.Ignore, OnMissingResourceActionTypes.ReportErrorAndStop) as GrazeFoodStoreType; } }
private void OnCLEMAnimalStock(object sender, EventArgs e) { // this event happens after management has marked individuals for purchase or sale. if (Clock.Today.Month == AssessmentMonth) { // Get ENSO forcase for current time ENSOState forecastEnsoState = GetENSOMeasure(); // calculate dry season pasture available for each managed paddock holding stock RuminantHerd ruminantHerd = Resources.RuminantHerd(); foreach (var newgroup in ruminantHerd.Herd.Where(a => a.Location != "").GroupBy(a => a.Location)) { // total adult equivalents of all breeds on pasture for utilisation double totalAE = newgroup.Sum(a => a.AdultEquivalent); // determine AE marked for sale and purchase of managed herd double markedForSaleAE = newgroup.Where(a => a.ReadyForSale && a.HerdName == HerdName).Sum(a => a.AdultEquivalent); double purchaseAE = ruminantHerd.PurchaseIndividuals.Where(a => a.Location == newgroup.Key && a.HerdName == HerdName).Sum(a => a.AdultEquivalent); double herdChange = 1.0; switch (forecastEnsoState) { case ENSOState.Neutral: break; case ENSOState.ElNino: GrazeFoodStoreType pasture = Resources.GetResourceItem(this, typeof(GrazeFoodStoreType), newgroup.Key, OnMissingResourceActionTypes.Ignore, OnMissingResourceActionTypes.Ignore) as GrazeFoodStoreType; double kgha = pasture.TonnesPerHectare * 1000; //NOTE: ensure calculation method in relationship is fixed values herdChange = this.PastureToStockingChangeElNino.SolveY(kgha); break; case ENSOState.LaNina: pasture = Resources.GetResourceItem(this, typeof(GrazeFoodStoreType), newgroup.Key, OnMissingResourceActionTypes.Ignore, OnMissingResourceActionTypes.Ignore) as GrazeFoodStoreType; kgha = pasture.TonnesPerHectare * 1000; herdChange = this.PastureToStockingChangeLaNina.SolveY(kgha); break; default: break; } if (herdChange > 1.0) { double toBuyAE = Math.Max(0, (totalAE * herdChange) - purchaseAE); HandleRestocking(toBuyAE, newgroup.Key, newgroup.FirstOrDefault()); } else if (herdChange < 1.0) { double toSellAE = Math.Max(0, (totalAE * (1 - herdChange)) - markedForSaleAE); HandleDestocking(toSellAE, newgroup.Key); } } } }
private void OnCLEMInitialiseResource(object sender, EventArgs e) { if (Area == 0 & AreaRequested > 0) { ResourceRequestList = new List <ResourceRequest>(); ResourceRequestList.Add(new ResourceRequest() { AllowTransmutation = false, Required = AreaRequested, ResourceType = typeof(Land), ResourceTypeName = LandTypeNameToUse, ActivityModel = this, Reason = "Assign", FilterDetails = null } ); } // if we get here we assume some land has been supplied if (ResourceRequestList != null || ResourceRequestList.Count() > 0) { gotLandRequested = TakeResources(ResourceRequestList, false); } //Now the Land has been allocated we have an Area if (gotLandRequested) { //get the units of area for this run from the Land resource parent. unitsOfArea2Ha = Resources.Land().UnitsOfAreaToHaConversion; // locate Pasture Type resource LinkedNativeFoodType = Resources.GetResourceItem(this, typeof(GrazeFoodStore), FeedTypeName, OnMissingResourceActionTypes.ReportErrorAndStop, OnMissingResourceActionTypes.ReportErrorAndStop) as GrazeFoodStoreType; //Assign the area actually got after taking it. It might be less than AreaRequested (if partial) Area = ResourceRequestList.FirstOrDefault().Provided; LinkedNativeFoodType.Area = Area; soilIndex = ((LandType)ResourceRequestList.FirstOrDefault().Resource).SoilType; LinkedNativeFoodType.CurrentEcologicalIndicators.LandConditionIndex = LandConditionIndex.StartingValue; LinkedNativeFoodType.CurrentEcologicalIndicators.GrassBasalArea = GrassBasalArea.StartingValue; LinkedNativeFoodType.CurrentEcologicalIndicators.StockingRate = StartingStockingRate; StockingRateSummed = StartingStockingRate; //Now we have a stocking rate and we have starting values for Land Condition and Grass Basal Area //get the starting pasture data list from GRASP GetPastureDataList_TodayToNextEcolCalculation(); SetupStartingPasturePools(StartingAmount); } }
private void OnCLEMAnimalStock(object sender, EventArgs e) { // this event happens after management has marked individuals for purchase or sale. if (Clock.Today.Month == AssessmentMonth) { // calculate dry season pasture available for each managed paddock holding stock not flagged for sale RuminantHerd ruminantHerd = Resources.RuminantHerd(); foreach (var paddockGroup in ruminantHerd.Herd.Where(a => a.Location != "" & a.SaleFlag == HerdChangeReason.None).GroupBy(a => a.Location)) { // total adult equivalents of all breeds on pasture for utilisation double AETotal = paddockGroup.Sum(a => a.AdultEquivalent); // determine AE marked for sale and purchase of managed herd double AEmarkedForSale = paddockGroup.Where(a => a.ReadyForSale & a.HerdName == HerdName).Sum(a => a.AdultEquivalent); double AEPurchase = ruminantHerd.PurchaseIndividuals.Where(a => a.Location == paddockGroup.Key & a.HerdName == HerdName).Sum(a => a.AdultEquivalent); double ShortfallAE = 0; // Determine total feed requirements for dry season for all ruminants on the pasture // We assume that all ruminant have the BaseAnimalEquivalent to the specified herd ShortfallAE = 0; GrazeFoodStoreType pasture = Resources.GetResourceItem(this, typeof(GrazeFoodStoreType), paddockGroup.Key, OnMissingResourceActionTypes.ReportErrorAndStop, OnMissingResourceActionTypes.ReportErrorAndStop) as GrazeFoodStoreType; double pastureBiomass = pasture.Amount; // Adjust fodder balance for detachment rate (6%/month) double feedRequiredAE = paddockGroup.FirstOrDefault().BreedParams.BaseAnimalEquivalent * 0.02 * 30.4; // 2% of AE animal per day for (int i = 0; i < this.DrySeasonLength; i++) { pastureBiomass *= (1.0 - pasture.DetachRate); pastureBiomass -= feedRequiredAE * AETotal; } // Shortfall in Fodder in kg per hectare double pastureShortFallKgHa = pastureBiomass / pasture.Area; pastureShortFallKgHa = Math.Max(0, pastureShortFallKgHa - FeedLowLimit); // Shortfalll in Fodder in kg for paddock double pastureShortFallKg = pastureShortFallKgHa * pasture.Area; if (pastureShortFallKg == 0) { return; } // number of AE to sell to balance shortfall_kg ShortfallAE = pastureShortFallKg / feedRequiredAE; // get prediction HandleDestocking(ShortfallAE, paddockGroup.Key); } } }
private void OnCLEMInitialiseActivity(object sender, EventArgs e) { this.InitialiseHerd(false, true); breedParams = Resources.GetResourceItem(this, typeof(RuminantHerd), this.PredictedHerdBreed, OnMissingResourceActionTypes.ReportErrorAndStop, OnMissingResourceActionTypes.ReportErrorAndStop) as RuminantType; // check GrazeFoodStoreExists if (GrazeFoodStoreName == null) { GrazeFoodStoreName = ""; } if (GrazeFoodStoreName != "") { foodStore = Resources.GetResourceItem(this, typeof(GrazeFoodStore), GrazeFoodStoreName, OnMissingResourceActionTypes.ReportErrorAndStop, OnMissingResourceActionTypes.ReportErrorAndStop) as GrazeFoodStoreType; } }
private void OnCLEMInitialiseActivity(object sender, EventArgs e) { // This method will only fire if the user has added this activity to the UI // Otherwise all details will be provided from GrazeAll code [CLEMInitialiseActivity] GrazeFoodStoreModel = Resources.FindResourceType <GrazeFoodStore, GrazeFoodStoreType>(this, GrazeFoodStoreTypeName, OnMissingResourceActionTypes.ReportErrorAndStop, OnMissingResourceActionTypes.ReportErrorAndStop); //Create list of children by breed foreach (RuminantType herdType in Resources.FindResourceGroup <RuminantHerd>().FindAllChildren <RuminantType>()) { RuminantActivityGrazePastureHerd ragpb = new RuminantActivityGrazePastureHerd { GrazeFoodStoreModel = GrazeFoodStoreModel, RuminantTypeModel = herdType, Parent = this, Clock = this.Clock, Name = "Graze_" + (GrazeFoodStoreModel as Model).Name + "_" + herdType.Name }; ragpb.SetLinkedModels(Resources); if (ragpb.Clock == null) { ragpb.Clock = this.Clock; } ragpb.InitialiseHerd(true, true); if (ActivityList == null) { ActivityList = new List <CLEMActivityBase>(); } ActivityList.Add(ragpb); ragpb.ResourceShortfallOccurred += Paddock_ResourceShortfallOccurred; ragpb.ActivityPerformed += BubbleHerd_ActivityPerformed; } }
private void OnCLEMInitialiseActivity(object sender, EventArgs e) { this.InitialiseHerd(false, false); // get herd to add to herdToUse = Resources.FindResourceType <RuminantHerd, RuminantType>(this, this.PredictedHerdName, OnMissingResourceActionTypes.ReportErrorAndStop, OnMissingResourceActionTypes.ReportErrorAndStop); if (!herdToUse.PricingAvailable()) { Summary.WriteMessage(this, "No pricing is supplied for herd [" + PredictedHerdName + "] and so no pricing will be included with [" + this.Name + "]", MessageType.Warning); } // check GrazeFoodStoreExists grazeStore = ""; if (GrazeFoodStoreName != null && !GrazeFoodStoreName.StartsWith("Not specified")) { grazeStore = GrazeFoodStoreName.Split('.').Last(); } // check for managed paddocks and warn if animals placed in yards. if (grazeStore == "") { var ah = this.FindInScope <ActivitiesHolder>(); if (ah.FindAllDescendants <PastureActivityManage>().Count() != 0) { Summary.WriteMessage(this, String.Format("Trade animals purchased by [a={0}] are currently placed in [Not specified - general yards] while a managed pasture is available. These animals will not graze until moved and will require feeding while in yards.\r\nSolution: Set the [GrazeFoodStore to place purchase in] located in the properties [General].[PastureDetails]", this.Name), MessageType.Warning); } } numberToStock = this.FindAllChildren <Relationship>().FirstOrDefault() as Relationship; if (numberToStock != null) { if (grazeStore != "") { foodStore = Resources.FindResourceType <GrazeFoodStore, GrazeFoodStoreType>(this, GrazeFoodStoreName, OnMissingResourceActionTypes.ReportErrorAndStop, OnMissingResourceActionTypes.ReportErrorAndStop); } } }
private void OnCLEMAnimalStock(object sender, EventArgs e) { // this event happens after management has marked individuals for purchase or sale. if (Clock.Today.Month == AssessmentMonth) { // Get ENSO forcase for current time ENSOState ForecastEnsoState = GetENSOMeasure(); // calculate dry season pasture available for each managed paddock holding stock RuminantHerd ruminantHerd = Resources.RuminantHerd(); foreach (var newgroup in ruminantHerd.Herd.Where(a => a.Location != "").GroupBy(a => a.Location)) { // total adult equivalents of all breeds on pasture for utilisation double AETotal = newgroup.Sum(a => a.AdultEquivalent); // determine AE marked for sale and purchase of managed herd double AEmarkedForSale = newgroup.Where(a => a.ReadyForSale & a.HerdName == HerdName).Sum(a => a.AdultEquivalent); double AEPurchase = ruminantHerd.PurchaseIndividuals.Where(a => a.Location == newgroup.Key & a.HerdName == HerdName).Sum(a => a.AdultEquivalent); double herdChange = 1.0; switch (ForecastEnsoState) { case ENSOState.Neutral: break; case ENSOState.ElNino: GrazeFoodStoreType pasture = Resources.GetResourceItem(this, typeof(GrazeFoodStoreType), newgroup.Key, OnMissingResourceActionTypes.Ignore, OnMissingResourceActionTypes.Ignore) as GrazeFoodStoreType; double kgha = pasture.TonnesPerHectare * 1000; herdChange = this.PastureToStockingChangeElNino.SolveY(kgha, false); break; case ENSOState.LaNina: pasture = Resources.GetResourceItem(this, typeof(GrazeFoodStoreType), newgroup.Key, OnMissingResourceActionTypes.Ignore, OnMissingResourceActionTypes.Ignore) as GrazeFoodStoreType; kgha = pasture.TonnesPerHectare * 1000; herdChange = this.PastureToStockingChangeLaNina.SolveY(kgha, false); break; default: break; } if (herdChange > 1.0) { double AEtoBuy = Math.Max(0, (AETotal * herdChange) - AEPurchase); HandleRestocking(AEtoBuy, newgroup.Key, newgroup.FirstOrDefault()); } else if (herdChange < 1.0) { double AEtoSell = Math.Max(0, (AETotal * (1 - herdChange)) - AEmarkedForSale); HandleDestocking(AEtoSell, newgroup.Key); } //switch (ForecastEnsoState) //{ // case ENSOState.Neutral: // break; // case ENSOState.LaNina: // double AEtoBuy = 0; // GrazeFoodStoreType pasture = Resources.GetResourceItem(typeof(GrazeFoodStoreType), newgroup.Key, out available) as GrazeFoodStoreType; // double kgha = pasture.TonnesPerHectare * 1000; // if (kgha > 3000) // { // AEtoBuy = AETotal * 0.2; //Buy 20% of Total Animal Equivalents // } // else if (kgha < 1000) // { // AEtoBuy = 0; //Don't buy any nore // } // else // { // AEtoBuy = AETotal * 0.1; //Buy 10 % of Total Animal Equivalents // } // // adjust for the AE already marked for purchase if any // AEtoBuy = Math.Max(0, AEtoBuy - AEPurchase); // HandleRestocking(AEtoBuy, newgroup.Key, newgroup.FirstOrDefault()); // break; // case ENSOState.ElNino: // pasture = Resources.GetResourceItem(typeof(GrazeFoodStoreType), newgroup.Key, out available) as GrazeFoodStoreType; // kgha = pasture.TonnesPerHectare * 1000; // if (kgha > 3000) // { // ShortfallAE = AETotal * 0.1; //Sell 10% of Total Animal Equivalents // } // else if (kgha < 1000) // { // ShortfallAE = AETotal * 0.3; //Sell 30% of Total Animal Equivalents // } // else // { // ShortfallAE = AETotal * 0.2; //Sell 20 % of Total Animal Equivalents // } // // Adjust for AE already flagged for sale if any // ShortfallAE = Math.Max(0, ShortfallAE - AEmarkedForSale); // HandleDestocking(ShortfallAE, newgroup.Key); // break; // default: // break; //} } } }
private void OnCLEMAnimalStock(object sender, EventArgs e) { AeToDestock = 0; AeDestocked = 0; // this event happens after management has marked individuals for purchase or sale. if (clock.Today.Month == (int)AssessmentMonth) { this.Status = ActivityStatus.NotNeeded; // calculate dry season pasture available for each managed paddock holding stock not flagged for sale foreach (var paddockGroup in HerdResource.Herd.Where(a => (a.Location ?? "") != "").GroupBy(a => a.Location)) { // multiple breeds are currently not supported as we need to work out what to do with diferent AEs if (paddockGroup.GroupBy(a => a.Breed).Count() > 1) { throw new ApsimXException(this, "Seasonal destocking paddocks containing multiple breeds is currently not supported\r\nActivity:" + this.Name + ", Paddock: " + paddockGroup.Key); } // total adult equivalents not marked for sale of all breeds on pasture for utilisation double totalAE = paddockGroup.Where(a => a.SaleFlag == HerdChangeReason.None).Sum(a => a.AdultEquivalent); double shortfallAE = 0; // Determine total feed requirements for dry season for all ruminants on the pasture // We assume that all ruminant have the BaseAnimalEquivalent to the specified herd GrazeFoodStoreType pasture = Resources.FindResourceType <GrazeFoodStore, GrazeFoodStoreType>(this, paddockGroup.Key, OnMissingResourceActionTypes.ReportErrorAndStop, OnMissingResourceActionTypes.ReportErrorAndStop); double pastureBiomass = pasture.Amount; // Adjust fodder balance for detachment rate (6%/month in NABSA, user defined in CLEM, 3%) // AL found the best estimate for AAsh Barkly example was 2/3 difference between detachment and carryover detachment rate with average 12month pool ranging from 10 to 96% and average 46% of total pasture. double detachrate = pasture.DetachRate + ((pasture.CarryoverDetachRate - pasture.DetachRate) * 0.66); // Assume a consumption rate of 2% of body weight. double feedRequiredAE = paddockGroup.FirstOrDefault().BreedParams.BaseAnimalEquivalent * 0.02 * 30.4; // 2% of AE animal per day for (int i = 0; i <= this.DrySeasonLength; i++) { // only include detachemnt if current biomass is positive, not already overeaten if (pastureBiomass > 0) { pastureBiomass *= (1.0 - detachrate); } if (i > 0) // not in current month as already consumed by this time. { pastureBiomass -= (feedRequiredAE * totalAE); } } // Shortfall in Fodder in kg per hectare // pasture at end of period in kg/ha double pastureShortFallKgHa = pastureBiomass / pasture.Manager.Area; PasturePredicted = pastureShortFallKgHa; // shortfall from low limit pastureShortFallKgHa = Math.Max(0, FeedLowLimit - pastureShortFallKgHa); // Shortfall in Fodder in kg for paddock double pastureShortFallKg = pastureShortFallKgHa * pasture.Manager.Area; if (pastureShortFallKg == 0) { return; } // number of AE to sell to balance shortfall_kg over entire season shortfallAE = pastureShortFallKg / (feedRequiredAE * this.DrySeasonLength); AeToDestock = shortfallAE; // get prediction HandleDestocking(shortfallAE, paddockGroup.Key); // fire event to allow reporting of findings OnReportStatus(new EventArgs()); } } else { this.Status = ActivityStatus.Ignored; } }
private void OnCLEMAnimalStock(object sender, EventArgs e) { AeToDestock = 0; AeDestocked = 0; AeToRestock = 0; AeRestocked = 0; // this event happens after management has marked individuals for purchase or sale. if (this.TimingOK) { // Get ENSO forcase for current time ENSOState forecastEnsoState = GetENSOMeasure(); this.Status = ActivityStatus.NotNeeded; // calculate dry season pasture available for each managed paddock holding stock RuminantHerd ruminantHerd = Resources.RuminantHerd(); foreach (var newgroup in ruminantHerd.Herd.Where(a => a.Location != "").GroupBy(a => a.Location)) { double aELocationNeeded = 0; // total adult equivalents of all breeds on pasture for utilisation double totalAE = newgroup.Sum(a => a.AdultEquivalent); // determine AE marked for sale and purchase of managed herd double markedForSaleAE = newgroup.Where(a => a.ReadyForSale).Sum(a => a.AdultEquivalent); double purchaseAE = ruminantHerd.PurchaseIndividuals.Where(a => a.Location == newgroup.Key).Sum(a => a.AdultEquivalent); double herdChange = 1.0; bool relationshipFound = false; switch (forecastEnsoState) { case ENSOState.Neutral: break; case ENSOState.ElNino: if (!(pastureToStockingChangeElNino is null)) { GrazeFoodStoreType pasture = Resources.GetResourceItem(this, typeof(GrazeFoodStoreType), newgroup.Key, OnMissingResourceActionTypes.Ignore, OnMissingResourceActionTypes.Ignore) as GrazeFoodStoreType; double kgha = pasture.TonnesPerHectare * 1000; herdChange = pastureToStockingChangeElNino.SolveY(kgha); relationshipFound = true; } break; case ENSOState.LaNina: if (!(pastureToStockingChangeLaNina is null)) { GrazeFoodStoreType pasture = Resources.GetResourceItem(this, typeof(GrazeFoodStoreType), newgroup.Key, OnMissingResourceActionTypes.Ignore, OnMissingResourceActionTypes.Ignore) as GrazeFoodStoreType; double kgha = pasture.TonnesPerHectare * 1000; herdChange = pastureToStockingChangeLaNina.SolveY(kgha); relationshipFound = true; } break; default: break; } if (!relationshipFound) { string warn = $"No pasture biomass to herd change proportion [Relationship] provided for {((forecastEnsoState== ENSOState.ElNino)? "El Niño":"La Niña")} phase in [a={this.Name}]\r\nNo stock management will be performed in this phase."; this.Status = ActivityStatus.Warning; if (!Warnings.Exists(warn)) { Summary.WriteWarning(this, warn); Warnings.Add(warn); } } if (herdChange > 1.0) { aELocationNeeded = Math.Max(0, (totalAE * herdChange) - purchaseAE); AeToRestock += aELocationNeeded; double notHandled = HandleRestocking(aELocationNeeded, newgroup.Key, newgroup.FirstOrDefault()); AeRestocked += (aELocationNeeded - notHandled); } else if (herdChange < 1.0) { aELocationNeeded = Math.Max(0, (totalAE * (1 - herdChange)) - markedForSaleAE); AeToDestock += aELocationNeeded; double notHandled = HandleDestocking(AeToDestock, newgroup.Key); AeDestocked += (aELocationNeeded - notHandled); } } if (this.Status != ActivityStatus.Warning & AeToDestock + AeToRestock > 0) { if (Math.Max(0, AeToRestock - AeRestocked) + Math.Max(0, AeToDestock - AeDestocked) == 0) { this.Status = ActivityStatus.Success; } else { this.Status = ActivityStatus.Partial; } } } }
private void OnCommencing(object sender, EventArgs e) { dataToWriteToDb = null; // sanitise the variable names and remove duplicates IModel zone = Apsim.Parent(this, typeof(Zone)); List <string> variableNames = new List <string>(); if (VariableNames != null) { for (int i = 0; i < this.VariableNames.Length; i++) { // each variable name is now a GrazeFoodStoreType bool isDuplicate = StringUtilities.IndexOfCaseInsensitive(variableNames, this.VariableNames[i].Trim()) != -1; if (!isDuplicate && this.VariableNames[i] != string.Empty) { if (this.VariableNames[i].StartsWith("[")) { variableNames.Add(this.VariableNames[i]); } else { string[] splitName = this.VariableNames[i].Split('.'); if (splitName.Count() == 2) { // get specified grazeFoodStoreType grazeStore = Resources.GetResourceItem(this, typeof(GrazeFoodStore), splitName[0], OnMissingResourceActionTypes.Ignore, OnMissingResourceActionTypes.ReportErrorAndStop) as GrazeFoodStoreType; // make each pool entry for (int j = 0; j <= 12; j++) { variableNames.Add(splitName[0] + "-" + j.ToString() + "-" + splitName[1]); } if (splitName[1] == "Amount") { // add amounts variableNames.Add("[Resources].GrazeFoodStore." + splitName[0] + ".Amount as Total amount"); variableNames.Add("[Resources].GrazeFoodStore." + splitName[0] + ".KilogramsPerHa as Total kgPerHa"); } } else { throw new ApsimXException(this, "Invalid report property. Expecting full property link or GrazeFoodStoreTypeName.Property"); } } } } // check if clock.today was included. if (!variableNames.Contains("[Clock].Today")) { variableNames.Insert(0, "[Clock].Today"); } } // Tidy up variable/event names. VariableNames = variableNames.ToArray(); VariableNames = TidyUpVariableNames(); EventNames = TidyUpEventNames(); this.FindVariableMembers(); // Subscribe to events. if (EventNames == null || EventNames.Count() == 0) { events.Subscribe("[Clock].CLEMHerdSummary", DoOutputEvent); } else { foreach (string eventName in EventNames) { if (eventName != string.Empty) { events.Subscribe(eventName.Trim(), DoOutputEvent); } } } }
private void OnCLEMInitialiseActivity(object sender, EventArgs e) { // create local version of max breeders so we can modify without affecting user set value maxBreeders = Math.Max(this.MaximumBreedersKept, this.MinimumBreedersKept); this.InitialiseHerd(false, true); breedParams = Resources.GetResourceItem(this, typeof(RuminantHerd), this.PredictedHerdName, OnMissingResourceActionTypes.ReportErrorAndStop, OnMissingResourceActionTypes.ReportErrorAndStop) as RuminantType; decimal breederHerdSize = 0; if (AdjustBreedingFemalesAtStartup) { RuminantHerd herd = Resources.RuminantHerd(); List <Ruminant> rumHerd = this.CurrentHerd(false); if (rumHerd != null && rumHerd.Count() > 0) { int numberAdded = 0; RuminantType breedParams = rumHerd.FirstOrDefault().BreedParams; RuminantInitialCohorts cohorts = Apsim.Children(rumHerd.FirstOrDefault().BreedParams, typeof(RuminantInitialCohorts)).FirstOrDefault() as RuminantInitialCohorts; if (cohorts != null) { List <RuminantTypeCohort> cohortList = Apsim.Children(cohorts, typeof(RuminantTypeCohort)).Cast <RuminantTypeCohort>().Where(a => a.Gender == Sex.Female && (a.Age >= breedParams.MinimumAge1stMating & a.Age <= this.MaximumBreederAge)).ToList(); int initialBreeders = Convert.ToInt32(cohortList.Sum(a => a.Number)); if (initialBreeders < this.MinimumBreedersKept) { double scaleFactor = this.MinimumBreedersKept / Convert.ToDouble(initialBreeders); // add new individuals foreach (var item in cohortList) { int numberToAdd = Convert.ToInt32(Math.Round(item.Number * scaleFactor) - item.Number); foreach (var newind in item.CreateIndividuals(numberToAdd)) { newind.SaleFlag = HerdChangeReason.FillInitialHerd; herd.AddRuminant(newind, this); numberAdded++; } } if (numberAdded == 0) { throw new ApsimXException(this, $"Unable to scale breeding female population up to the maximum breeders kept at startup\nNo cohorts representing breeders were found in the initial herd structure [r=InitialCohorts] for [r={breedParams.Name}]\nAdd at least one initial cohort that meets the breeder criteria of age at first mating and max age kept"); } breederHerdSize = initialBreeders + numberAdded; } else if (initialBreeders > maxBreeders) { int reduceBy = Math.Max(0, initialBreeders - maxBreeders); // reduce initial herd size // randomly select the individuals to remove form the breeder herd List <Ruminant> breeders = rumHerd.Where(a => a.Gender == Sex.Female && a.Age > breedParams.MinimumAge1stMating && a.Age < this.MaximumBreederAge).OrderBy(x => Guid.NewGuid()).Take(reduceBy).ToList(); foreach (var item in breeders) { item.SaleFlag = HerdChangeReason.ReduceInitialHerd; herd.RemoveRuminant(item, this); reduceBy--; } if (reduceBy > 0) { // add warning string warn = $"Unable to reduce breeders at the start of the simulation to number required [{maxBreeders}] using [a={this.Name}]"; if (!Warnings.Exists(warn)) { Summary.WriteWarning(this, warn); Warnings.Add(warn); } } breederHerdSize = maxBreeders; } } else { throw new ApsimXException(this, $"Unable to adjust breeding female population to the maximum breeders kept at startup\nNo initial herd structure [r=InitialCohorts] has been provided in [r={breedParams.Name}]"); } } } // max sires if (MaximumSiresKept < 1 & MaximumSiresKept > 0) { SiresKept = Convert.ToInt32(Math.Ceiling(maxBreeders * breederHerdSize), CultureInfo.InvariantCulture); } else { SiresKept = Convert.ToInt32(Math.Truncate(MaximumSiresKept), CultureInfo.InvariantCulture); } if (AdjustBreedingMalesAtStartup) { RuminantHerd herd = Resources.RuminantHerd(); if (herd != null) { // get number in herd List <Ruminant> rumHerd = this.CurrentHerd(false); int numberPresent = rumHerd.Where(a => a.Gender == Sex.Male).Cast <RuminantMale>().Where(a => a.BreedingSire).Count(); if (numberPresent < SiresKept) { // fill to number needed for (int i = numberPresent; i < SiresKept; i++) { RuminantMale newSire = new RuminantMale(SireAgeAtPurchase, Sex.Male, 0, breedParams) { Breed = this.PredictedHerdBreed, HerdName = this.PredictedHerdName, BreedingSire = true, ID = herd.NextUniqueID, SaleFlag = HerdChangeReason.FillInitialHerd }; herd.AddRuminant(newSire, this); } } else if (numberPresent > SiresKept) { // reduce initial herd. int reduceBy = Math.Max(0, numberPresent - SiresKept); // reduce initial sire herd size // randomly select the individuals to remove form the breeder herd List <RuminantMale> sires = rumHerd.Where(a => a.Gender == Sex.Male).Cast <RuminantMale>().Where(a => a.BreedingSire).OrderBy(x => Guid.NewGuid()).Take(reduceBy).ToList(); foreach (var item in sires) { item.SaleFlag = HerdChangeReason.ReduceInitialHerd; herd.RemoveRuminant(item, this); reduceBy--; } if (reduceBy > 0) { // add warning string warn = $"Unable to reduce breeding sires at the start of the simulation to number required [{SiresKept}] using [a={this.Name}]"; if (!Warnings.Exists(warn)) { Summary.WriteWarning(this, warn); Warnings.Add(warn); } } } } } // check GrazeFoodStoreExists for breeders grazeStoreBreeders = ""; if (GrazeFoodStoreNameBreeders != null && !GrazeFoodStoreNameBreeders.StartsWith("Not specified")) { grazeStoreBreeders = GrazeFoodStoreNameBreeders.Split('.').Last(); foodStoreBreeders = Resources.GetResourceItem(this, GrazeFoodStoreNameBreeders, OnMissingResourceActionTypes.ReportErrorAndStop, OnMissingResourceActionTypes.ReportErrorAndStop) as GrazeFoodStoreType; } // check for managed paddocks and warn if breeders placed in yards. if (grazeStoreBreeders == "" && this.MaximumProportionBreedersPerPurchase > 0) { var ah = Apsim.Find(this, typeof(ActivitiesHolder)); if (Apsim.ChildrenRecursively(ah, typeof(PastureActivityManage)).Count() != 0) { Summary.WriteWarning(this, String.Format("Breeders purchased by [a={0}] are currently placed in [Not specified - general yards] while a managed pasture is available. These animals will not graze until mustered and will require feeding while in yards.\nSolution: Set the [GrazeFoodStore to place purchase in] located in the properties [General].[PastureDetails]", this.Name)); } } // check GrazeFoodStoreExists for sires grazeStoreSires = ""; if (GrazeFoodStoreNameSires != null && !GrazeFoodStoreNameSires.StartsWith("Not specified")) { grazeStoreSires = GrazeFoodStoreNameSires.Split('.').Last(); foodStoreSires = Resources.GetResourceItem(this, GrazeFoodStoreNameSires, OnMissingResourceActionTypes.ReportErrorAndStop, OnMissingResourceActionTypes.ReportErrorAndStop) as GrazeFoodStoreType; } // check for managed paddocks and warn if sires placed in yards. if (grazeStoreBreeders == "" && this.SiresKept > 0) { var ah = Apsim.Find(this, typeof(ActivitiesHolder)); if (Apsim.ChildrenRecursively(ah, typeof(PastureActivityManage)).Count() != 0) { Summary.WriteWarning(this, String.Format("Sires purchased by [a={0}] are currently placed in [Not specified - general yards] while a managed pasture is available. These animals will not graze until mustered and will require feeding while in yards.\nSolution: Set the [GrazeFoodStore to place purchase in] located in the properties [General].[PastureDetails]", this.Name)); } } }