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 OnCLEMAnimalManage(object sender, EventArgs e) { //List<Ruminant> localHerd = this.CurrentHerd(); RuminantHerd ruminantHerd = Resources.RuminantHerd(); // clear store of individuals to try and purchase // ruminantHerd.PurchaseIndividuals.Clear(); // remove only the individuals that are affected by this activity. ruminantHerd.PurchaseIndividuals.RemoveAll(a => a.Breed == this.PredictedHerdBreed); List <Ruminant> herd = this.CurrentHerd(true); // List<Ruminant> herd = ruminantHerd.Herd.Where(a => a.HerdName == HerdName).ToList(); // can sell off males any month as per NABSA // if we don't need this monthly, then it goes into next if statement with herd declaration // NABSA MALES - weaners, 1-2, 2-3 and 3-4 yo, we check for any male weaned and not a breeding sire. // check for sell age/weight of young males // if SellYoungFemalesLikeMales then all apply to both sexes else only males. if (this.TimingOK || ContinuousMaleSales) { foreach (var ind in herd.Where(a => a.Weaned & (SellFemalesLikeMales ? true : (a.Gender == Sex.Male)) & (a.Age >= MaleSellingAge || a.Weight >= MaleSellingWeight))) { bool sell = true; if (ind.GetType() == typeof(RuminantMale)) { // don't sell breeding sires. sell = !((ind as RuminantMale).BreedingSire); } if (sell) { ind.SaleFlag = HerdChangeReason.AgeWeightSale; } } } // if management month if (this.TimingOK) { bool sufficientFood = true; if (foodStore != null) { sufficientFood = (foodStore.TonnesPerHectare * 1000) > MinimumPastureBeforeRestock; } // check for maximum age (females and males have different cutoffs) foreach (var ind in herd.Where(a => a.Age >= ((a.Gender == Sex.Female) ? MaximumBreederAge : MaximumBullAge))) { ind.SaleFlag = HerdChangeReason.MaxAgeSale; } // MALES // check for breeder bulls after sale of old individuals and buy/sell int numberMaleSiresInHerd = herd.Where(a => a.Gender == Sex.Male & a.SaleFlag == HerdChangeReason.None).Cast <RuminantMale>().Where(a => a.BreedingSire).Count(); // Number of females int numberFemaleBreedingInHerd = herd.Where(a => a.Gender == Sex.Female & a.Age >= a.BreedParams.MinimumAge1stMating & a.SaleFlag == HerdChangeReason.None).Count(); int numberFemaleTotalInHerd = herd.Where(a => a.Gender == Sex.Female & a.SaleFlag == HerdChangeReason.None).Count(); int numberFemaleOldInHerd = herd.Where(a => a.Gender == Sex.Female & MaximumBreederAge - a.Age <= 12 & a.SaleFlag == HerdChangeReason.None).Count(); if (numberMaleSiresInHerd > MaximumSiresKept) { // sell bulls // What rule? oldest first as they may be lost soonest int numberToRemove = MaximumSiresKept - numberMaleSiresInHerd; foreach (var male in herd.Where(a => a.Gender == Sex.Male).Cast <RuminantMale>().Where(a => a.BreedingSire).OrderByDescending(a => a.Age).Take(numberToRemove)) { male.SaleFlag = HerdChangeReason.ExcessBullSale; numberToRemove--; if (numberToRemove == 0) { break; } } } else if (numberMaleSiresInHerd < MaximumSiresKept) { if ((foodStore == null) || (sufficientFood)) { if (AllowSireReplacement) { // remove young bulls from sale herd to replace breed bulls (not those sold because too old) foreach (RuminantMale male in herd.Where(a => a.Gender == Sex.Male & a.SaleFlag == HerdChangeReason.AgeWeightSale).OrderByDescending(a => a.Weight)) { male.SaleFlag = HerdChangeReason.None; male.BreedingSire = true; numberMaleSiresInHerd++; if (numberMaleSiresInHerd >= MaximumSiresKept) { break; } } // if still insufficent, look into current herd for replacement // remaining males assumed to be too small, so await next time-step } // if still insufficient buy bulls. if (numberMaleSiresInHerd < MaximumSiresKept && (MaximumSiresPerPurchase > 0)) { // limit by breeders as proportion of max breeders so we don't spend alot on sires when building the herd and females more valuable double propOfBreeders = (double)numberFemaleBreedingInHerd / (double)MaximumBreedersKept; int sires = Convert.ToInt32(Math.Ceiling(Math.Ceiling(MaximumSiresKept * propOfBreeders))); int numberToBuy = Math.Min(MaximumSiresPerPurchase, Math.Max(0, sires - numberMaleSiresInHerd)); for (int i = 0; i < numberToBuy; i++) { RuminantMale newbull = new RuminantMale { Location = GrazeFoodStoreName, Age = 48, Breed = this.PredictedHerdBreed,// breedParams.Breed; HerdName = this.PredictedHerdName, BreedingSire = true, BreedParams = breedParams, Gender = Sex.Male, ID = 0, // ruminantHerd.NextUniqueID; Weight = 450, HighWeight = 450, SaleFlag = HerdChangeReason.SirePurchase }; // add to purchase request list and await purchase in Buy/Sell ruminantHerd.PurchaseIndividuals.Add(newbull); } } } } // FEMALES // Breeding herd traded as heifers only int excessHeifers = 0; // check for maximum number of breeders remaining after sale and buy/sell if (numberFemaleBreedingInHerd > MaximumBreedersKept) { // herd mortality of 5% plus those that will be culled in next 12 months excessHeifers = Convert.ToInt32((numberFemaleTotalInHerd - numberFemaleOldInHerd) * 0.05) + numberFemaleOldInHerd; // shortfall + (number of young - replacement heifers) excessHeifers = (numberFemaleTotalInHerd - MaximumBreedersKept) + ((numberFemaleTotalInHerd - numberFemaleBreedingInHerd) - excessHeifers); } else { // shortfall between actual and desired numbers excessHeifers = MaximumBreedersKept - numberFemaleBreedingInHerd; // add future cull for age + 5% excessHeifers += Convert.ToInt32((numberFemaleTotalInHerd - numberFemaleOldInHerd) * 0.05) + numberFemaleOldInHerd; excessHeifers = (numberFemaleTotalInHerd - numberFemaleBreedingInHerd) - excessHeifers; } // surplus heifers to sell if (excessHeifers > 0) { foreach (var female in herd.Where(a => a.Gender == Sex.Female & a.Age < a.BreedParams.MinimumAge1stMating & a.Weaned).OrderByDescending(a => a.Age).Take(excessHeifers)) { // tag fo sale. female.SaleFlag = HerdChangeReason.ExcessHeiferSale; excessHeifers--; if (excessHeifers == 0) { break; } } } else if (excessHeifers < 0) { excessHeifers *= -1; if ((foodStore == null) || (sufficientFood)) { // remove young females from sale herd to replace breeders (not those sold because too old) foreach (RuminantFemale female in herd.Where(a => a.Gender == Sex.Female & a.SaleFlag == HerdChangeReason.AgeWeightSale).OrderByDescending(a => a.Age)) { female.SaleFlag = HerdChangeReason.None; excessHeifers--; if (excessHeifers == 0) { break; } } // if still insufficient buy heifers. if (excessHeifers > 0 & (MaximumBreedersPerPurchase > 0)) { int ageOfHeifer = 12; double weightOfHeifer = 260; // buy 5% more to account for deaths before these individuals grow to breeding age int numberToBuy = Math.Min(MaximumBreedersPerPurchase, Math.Max(0, Convert.ToInt32(excessHeifers * 1.05))); for (int i = 0; i < numberToBuy; i++) { RuminantFemale newheifer = new RuminantFemale { Location = GrazeFoodStoreName, Age = ageOfHeifer, Breed = this.PredictedHerdBreed, HerdName = this.PredictedHerdName, BreedParams = breedParams, Gender = Sex.Female, ID = 0, Weight = weightOfHeifer, HighWeight = weightOfHeifer, SaleFlag = HerdChangeReason.HeiferPurchase }; // add to purchase request list and await purchase in Buy/Sell ruminantHerd.PurchaseIndividuals.Add(newheifer); } } } } // report that this activity was performed as it does not use base GetResourcesRequired //this.TriggerOnActivityPerformed(); // Breeders themselves don't get sold. Trading is with Heifers // Breeders can be sold in seasonal and ENSO destocking. // sell breeders // What rule? oldest first as they may be lost soonest // should keep pregnant females... and young... // this will currently remove pregnant females and females with suckling calf // int numberToRemove = Convert.ToInt32((numberFemaleInHerd-MaximumBreedersKept)); // foreach (var female in herd.Where(a => a.Gender == Sex.Female & a.Age >= a.BreedParams.MinimumAge1stMating).OrderByDescending(a => a.Age).Take(numberToRemove)) // { // female.SaleFlag = HerdChangeReason.ExcessBreederSale; // numberToRemove--; // if (numberToRemove == 0) break; // } // } //else //{ //} } }
private void OnCLEMAnimalManage(object sender, EventArgs e) { // purchase details only on timer if (TimingOK) { // remove any old potential sales from list as these will be updated here Resources.RuminantHerd().PurchaseIndividuals.RemoveAll(a => a.Breed == this.PredictedHerdBreed & a.SaleFlag == HerdChangeReason.TradePurchase); foreach (RuminantTypeCohort purchasetype in this.Children.Where(a => a.GetType() == typeof(RuminantTypeCohort)).Cast <RuminantTypeCohort>()) { for (int i = 0; i < purchasetype.Number; i++) { object ruminantBase = null; if (purchasetype.Gender == Sex.Male) { ruminantBase = new RuminantMale(); } else { ruminantBase = new RuminantFemale(); } Ruminant ruminant = ruminantBase as Ruminant; ruminant.ID = 0; ruminant.BreedParams = herdToUse; ruminant.Breed = this.PredictedHerdBreed; ruminant.HerdName = this.PredictedHerdName; ruminant.Gender = purchasetype.Gender; ruminant.Age = purchasetype.Age; ruminant.PurchaseAge = purchasetype.Age; ruminant.SaleFlag = HerdChangeReason.TradePurchase; ruminant.Location = ""; double u1 = ZoneCLEM.RandomGenerator.NextDouble(); double u2 = ZoneCLEM.RandomGenerator.NextDouble(); double randStdNormal = Math.Sqrt(-2.0 * Math.Log(u1)) * Math.Sin(2.0 * Math.PI * u2); ruminant.Weight = purchasetype.Weight + purchasetype.WeightSD * randStdNormal; ruminant.PreviousWeight = ruminant.Weight; switch (purchasetype.Gender) { case Sex.Male: RuminantMale ruminantMale = ruminantBase as RuminantMale; ruminantMale.BreedingSire = false; break; case Sex.Female: RuminantFemale ruminantFemale = ruminantBase as RuminantFemale; ruminantFemale.DryBreeder = true; ruminantFemale.WeightAtConception = ruminant.Weight; ruminantFemale.NumberOfBirths = 0; break; default: break; } Resources.RuminantHerd().PurchaseIndividuals.Add(ruminantBase as Ruminant); } } //this.TriggerOnActivityPerformed(); } // sale details any timestep when conditions are met. foreach (Ruminant ind in this.CurrentHerd(true)) { if (ind.Age - ind.PurchaseAge >= MinMonthsKept & ind.Weight >= TradeWeight) { ind.SaleFlag = HerdChangeReason.TradeSale; } } }
private void OnCLEMAnimalManage(object sender, EventArgs e) { // purchase details only on timer if (TimingOK) { this.Status = ActivityStatus.NotNeeded; // remove any old potential sales from list as these will be updated here Resources.RuminantHerd().PurchaseIndividuals.RemoveAll(a => a.Breed == this.PredictedHerdBreed && a.SaleFlag == HerdChangeReason.TradePurchase); foreach (RuminantTypeCohort purchasetype in this.Children.Where(a => a.GetType() == typeof(RuminantTypeCohort)).Cast <RuminantTypeCohort>()) { double number = purchasetype.Number; if (numberToStock != null && foodStore != null) { //NOTE: ensure calculation method in relationship is fixed values number = Convert.ToInt32(numberToStock.SolveY(foodStore.TonnesPerHectare), CultureInfo.InvariantCulture); } for (int i = 0; i < number; i++) { object ruminantBase = null; double u1 = RandomNumberGenerator.Generator.NextDouble(); double u2 = RandomNumberGenerator.Generator.NextDouble(); double randStdNormal = Math.Sqrt(-2.0 * Math.Log(u1)) * Math.Sin(2.0 * Math.PI * u2); double weight = purchasetype.Weight + purchasetype.WeightSD * randStdNormal; if (purchasetype.Gender == Sex.Male) { ruminantBase = new RuminantMale(purchasetype.Age, purchasetype.Gender, weight, herdToUse); } else { ruminantBase = new RuminantFemale(purchasetype.Age, purchasetype.Gender, weight, herdToUse); } Ruminant ruminant = ruminantBase as Ruminant; ruminant.ID = 0; ruminant.Breed = this.PredictedHerdBreed; ruminant.HerdName = this.PredictedHerdName; ruminant.PurchaseAge = purchasetype.Age; ruminant.SaleFlag = HerdChangeReason.TradePurchase; ruminant.Location = grazeStore; ruminant.PreviousWeight = ruminant.Weight; switch (purchasetype.Gender) { case Sex.Male: RuminantMale ruminantMale = ruminantBase as RuminantMale; ruminantMale.BreedingSire = false; break; case Sex.Female: RuminantFemale ruminantFemale = ruminantBase as RuminantFemale; ruminantFemale.DryBreeder = true; ruminantFemale.WeightAtConception = ruminant.Weight; ruminantFemale.NumberOfBirths = 0; break; default: break; } Resources.RuminantHerd().PurchaseIndividuals.Add(ruminantBase as Ruminant); this.Status = ActivityStatus.Success; } } } // sale details any timestep when conditions are met. foreach (Ruminant ind in this.CurrentHerd(true)) { if (ind.Age - ind.PurchaseAge >= MinMonthsKept) { ind.SaleFlag = HerdChangeReason.TradeSale; this.Status = ActivityStatus.Success; } if (TradeWeight > 0 && ind.Weight >= TradeWeight) { ind.SaleFlag = HerdChangeReason.TradeSale; this.Status = ActivityStatus.Success; } } }
private void OnCLEMAnimalManage(object sender, EventArgs e) { RuminantHerd ruminantHerd = Resources.RuminantHerd(); // remove only the individuals that are affected by this activity. // these are old purchases that were not made. This list will be regenerated in this method. ruminantHerd.PurchaseIndividuals.RemoveAll(a => a.Breed == this.PredictedHerdBreed); List <Ruminant> herd = this.CurrentHerd(true); // can sell off males any month as per NABSA // if we don't need this monthly, then it goes into next if statement with herd declaration // NABSA MALES - weaners, 1-2, 2-3 and 3-4 yo, we check for any male weaned and not a breeding sire. // check for sell age/weight of young males // if SellYoungFemalesLikeMales then all apply to both sexes else only males. // SellFemalesLikeMales will grow out excess heifers until age/weight rather than sell immediately. if (this.TimingOK || ContinuousMaleSales) { foreach (var ind in herd.Where(a => a.Weaned && (SellFemalesLikeMales ? true : (a.Gender == Sex.Male)) && (a.Age >= MaleSellingAge || a.Weight >= MaleSellingWeight))) { bool sell = true; if (ind.GetType() == typeof(RuminantMale)) { // don't sell breeding sires. sell = !((ind as RuminantMale).BreedingSire); } else { // only sell females that were marked as excess sell = ind.Tags.Contains("GrowHeifer"); } if (sell) { ind.SaleFlag = HerdChangeReason.AgeWeightSale; } } } // if management month if (this.TimingOK) { // ensure pasture limits are ok before purchases bool sufficientFood = true; if (foodStore != null) { sufficientFood = (foodStore.TonnesPerHectare * 1000) >= MinimumPastureBeforeRestock; } // check for maximum age (females and males have different cutoffs) foreach (var ind in herd.Where(a => a.Age >= ((a.Gender == Sex.Female) ? MaximumBreederAge : MaximumBullAge))) { ind.SaleFlag = HerdChangeReason.MaxAgeSale; // ensure females are not pregnant and add warning if pregnant old females found. if (ind.Gender == Sex.Female && (ind as RuminantFemale).IsPregnant) { string warning = "Some females sold at maximum age in [a=" + this.Name + "] were pregnant.\nConsider changing the MaximumBreederAge in [a=RuminantActivityManage] or ensure [r=RuminantType.MaxAgeMating] is less than or equal to the MaximumBreederAge to avoid selling pregnant individuals."; if (!Warnings.Exists(warning)) { Warnings.Add(warning); Summary.WriteWarning(this, warning); } } } // MALES // check for breeder bulls after sale of old individuals and buy/sell int numberMaleSiresInHerd = herd.Where(a => a.Gender == Sex.Male && a.SaleFlag == HerdChangeReason.None).Cast <RuminantMale>().Where(a => a.BreedingSire).Count(); // Number of females int numberFemaleBreedingInHerd = herd.Where(a => a.Gender == Sex.Female && a.Age >= a.BreedParams.MinimumAge1stMating && a.SaleFlag == HerdChangeReason.None).Count(); int numberFemaleTotalInHerd = herd.Where(a => a.Gender == Sex.Female && a.SaleFlag == HerdChangeReason.None).Count(); // these are females that will exceed max age and be sold in next 12 months int numberFemaleOldInHerd = herd.Where(a => a.Gender == Sex.Female && (a.Age + 12 >= MaximumBreederAge) && a.SaleFlag == HerdChangeReason.None).Count(); // defined heifers here as weaned and will be a breeder in the next year int numberFemaleHeifersInHerd = herd.Where(a => a.Gender == Sex.Female && a.Weaned && ((a.Age - a.BreedParams.MinimumAge1stMating < 0) && (a.Age - a.BreedParams.MinimumAge1stMating > -12)) && a.SaleFlag == HerdChangeReason.None).Count(); if (numberMaleSiresInHerd > SiresKept) { // sell bulls // What rule? oldest first as they may be lost soonest? int numberToRemove = numberMaleSiresInHerd - SiresKept; if (numberToRemove > 0) { foreach (var male in herd.Where(a => a.Gender == Sex.Male).Cast <RuminantMale>().Where(a => a.BreedingSire).OrderByDescending(a => a.Age).Take(numberToRemove)) { male.SaleFlag = HerdChangeReason.ExcessBullSale; numberToRemove--; if (numberToRemove == 0) { break; } } } } else if (numberMaleSiresInHerd < SiresKept) { if ((foodStore == null) || (sufficientFood)) { if (AllowSireReplacement) { // remove young bulls from sale herd to replace breed bulls (not those sold because too old) foreach (RuminantMale male in herd.Where(a => a.Gender == Sex.Male && a.SaleFlag == HerdChangeReason.AgeWeightSale).OrderByDescending(a => a.Weight)) { male.SaleFlag = HerdChangeReason.None; male.BreedingSire = true; numberMaleSiresInHerd++; if (numberMaleSiresInHerd >= SiresKept) { break; } } // if still insufficent, look into current herd for replacement // remaining males assumed to be too small, so await next time-step } // if still insufficient buy bulls. if (numberMaleSiresInHerd < SiresKept && (MaximumSiresPerPurchase > 0)) { // limit by breeders as proportion of max breeders so we don't spend alot on sires when building the herd and females more valuable double propOfBreeders = (double)numberFemaleBreedingInHerd / (double)MaximumBreedersKept; propOfBreeders = 1; int sires = Convert.ToInt32(Math.Ceiling(Math.Ceiling(SiresKept * propOfBreeders))); int numberToBuy = Math.Min(MaximumSiresPerPurchase, Math.Max(0, sires - numberMaleSiresInHerd)); for (int i = 0; i < numberToBuy; i++) { if (i < MaximumSiresPerPurchase) { RuminantMale newbull = new RuminantMale(48, Sex.Male, 450, breedParams) { Location = grazeStore, Breed = this.PredictedHerdBreed, HerdName = this.PredictedHerdName, BreedingSire = true, Gender = Sex.Male, ID = 0, // Next unique ide will be assigned when added PreviousWeight = 450, SaleFlag = HerdChangeReason.SirePurchase }; // add to purchase request list and await purchase in Buy/Sell ruminantHerd.PurchaseIndividuals.Add(newbull); } } } } } // FEMALES // Breeding herd sold as heifers only, purchased as breeders (>= minAge1stMating) int excessBreeders = 0; // get the mortality rate for the herd if available or assume zero double mortalityRate = breedParams.MortalityBase; // shortfall between actual and desired numbers of breeders (-ve for shortfall) excessBreeders = numberFemaleBreedingInHerd - MaximumBreedersKept; // IAT-NABSA removes adjusts to account for the old animals that will be sold in the next year // This is not required in CLEM as they have been sold in this method, and it wont be until this method is called again that the next lot are sold. // Like IAT-NABSA we will account for mortality losses in the next year in our breeder purchases // Account for whole individuals only. int numberDyingInNextYear = Convert.ToInt32(Math.Floor(numberFemaleBreedingInHerd * mortalityRate), CultureInfo.InvariantCulture); // adjust for future mortality excessBreeders -= numberDyingInNextYear; // account for heifers already in the herd // These are the next cohort that will become breeders in the next 12 months (before this method is called again) excessBreeders += numberFemaleHeifersInHerd; if (excessBreeders > 0) // surplus heifers to sell { foreach (var female in herd.Where(a => a.Gender == Sex.Female && (a as RuminantFemale).IsHeifer).Take(excessBreeders)) { // if sell like males tag for grow out otherwise mark for sale if (SellFemalesLikeMales) { if (!female.Tags.Contains("GrowHeifer")) { female.Tags.Add("GrowHeifer"); } } else { // tag for sale. female.SaleFlag = HerdChangeReason.ExcessHeiferSale; } excessBreeders--; if (excessBreeders == 0) { break; } } } else if (excessBreeders < 0) // shortfall heifers to buy { double minBreedAge = breedParams.MinimumAge1stMating; excessBreeders *= -1; if ((foodStore == null) || (sufficientFood)) { // remove grow out heifers from grow out herd to replace breeders if (SellFemalesLikeMales) { foreach (Ruminant female in herd.Where(a => a.Tags.Contains("GrowHeifer")).OrderByDescending(a => a.Age)) { female.Tags.Remove("GrowHeifer"); excessBreeders--; if (excessBreeders == 0) { break; } } } // remove young females from sale herd to replace breeders (not those sold because too old) foreach (RuminantFemale female in herd.Where(a => a.Gender == Sex.Female && (a.SaleFlag == HerdChangeReason.AgeWeightSale || a.SaleFlag == HerdChangeReason.ExcessHeiferSale)).OrderByDescending(a => a.Age)) { female.SaleFlag = HerdChangeReason.None; excessBreeders--; if (excessBreeders == 0) { break; } } // if still insufficient buy breeders. if (excessBreeders > 0 && (MaximumProportionBreedersPerPurchase > 0)) { int ageOfBreeder = 0; // IAT-NABSA had buy mortality base% more to account for deaths before these individuals grow to breeding age // These individuals are already of breeding age so we will ignore this in CLEM // minimum of (max kept x prop in single purchase) and (the number needed + annual mortality) int numberToBuy = Math.Min(excessBreeders, Convert.ToInt32(Math.Ceiling(MaximumProportionBreedersPerPurchase * MaximumBreedersKept), CultureInfo.InvariantCulture)); int numberPerPurchaseCohort = Convert.ToInt32(Math.Ceiling(numberToBuy / Convert.ToDouble(NumberOfBreederPurchaseAgeClasses, CultureInfo.InvariantCulture)), CultureInfo.InvariantCulture); int numberBought = 0; while (numberBought < numberToBuy) { int breederClass = Convert.ToInt32(numberBought / numberPerPurchaseCohort, CultureInfo.InvariantCulture); ageOfBreeder = Convert.ToInt32(minBreedAge + (breederClass * 12), CultureInfo.InvariantCulture); RuminantFemale newBreeder = new RuminantFemale(ageOfBreeder, Sex.Female, 0, breedParams) { Location = grazeStore, Breed = this.PredictedHerdBreed, HerdName = this.PredictedHerdName, BreedParams = breedParams, Gender = Sex.Female, ID = 0, SaleFlag = HerdChangeReason.BreederPurchase }; // weight will be set to normalised weight as it was assigned 0 at initialisation newBreeder.PreviousWeight = newBreeder.Weight; // this individual must be weaned to be permitted to start breeding. newBreeder.Wean(false, "Initial"); // add to purchase request list and await purchase in Buy/Sell ruminantHerd.PurchaseIndividuals.Add(newBreeder); numberBought++; } } } } // Breeders themselves don't get sold. Trading is with Heifers // Breeders can be sold in seasonal and ENSO destocking. // sell breeders // What rule? oldest first as they may be lost soonest // should keep pregnant females... and young... // this will currently remove pregnant females and females with suckling calf } }
private void OnCLEMAnimalBreeding(object sender, EventArgs e) { // RuminantHerd ruminantHerd = Resources.RuminantHerd(); List <Ruminant> herd = CurrentHerd(true); //ruminantHerd.Herd.Where(a => a.BreedParams.Name == HerdName).ToList(); // get list of all individuals of breeding age and condition // grouped by location var breeders = from ind in herd where (ind.Gender == Sex.Male & ind.Age >= ind.BreedParams.MinimumAge1stMating) || (ind.Gender == Sex.Female & ind.Age >= ind.BreedParams.MinimumAge1stMating & ind.Weight >= (ind.BreedParams.MinimumSize1stMating * ind.StandardReferenceWeight) ) group ind by ind.Location into grp select grp; // calculate labour and finance limitations if needed when doing AI int breedersCount = breeders.Count(); int numberPossible = breedersCount; int numberServiced = 1; if (UseAI & TimingOK) { // attempt to get required resources List <ResourceRequest> resourcesneeded = GetResourcesNeededForActivityLocal(); bool tookRequestedResources = TakeResources(resourcesneeded, true); // get all shortfalls if (tookRequestedResources & (ResourceRequestList != null)) { //TODO: fix this to account for perHead payments and labour and not fixed expenses double amountCashNeeded = resourcesneeded.Where(a => a.ResourceType == typeof(Finance)).Sum(a => a.Required); double amountCashProvided = resourcesneeded.Where(a => a.ResourceType == typeof(Finance)).Sum(a => a.Provided); double amountLabourNeeded = resourcesneeded.Where(a => a.ResourceType == typeof(Labour)).Sum(a => a.Required); double amountLabourProvided = resourcesneeded.Where(a => a.ResourceType == typeof(Labour)).Sum(a => a.Provided); double cashlimit = 1; if (amountCashNeeded > 0) { if (amountCashProvided == 0) { cashlimit = 0; } else { cashlimit = amountCashNeeded / amountCashProvided; } } double labourlimit = 1; if (amountLabourNeeded > 0) { if (amountLabourProvided == 0) { labourlimit = 0; } else { labourlimit = amountLabourNeeded / amountLabourProvided; } } double limiter = Math.Min(cashlimit, labourlimit); numberPossible = Convert.ToInt32(limiter * breedersCount); // TODO: determine if fixed payments were not possible // TODO: determine limits by insufficient labour or cash for per head payments } // report that this activity was performed as it does not use base GetResourcesRequired this.TriggerOnActivityPerformed(); } if (!UseAI) { // report that this activity was performed as it does not use base GetResourcesRequired this.TriggerOnActivityPerformed(); } // for each location where parts of this herd are located foreach (var location in breeders) { // determine all foetus and newborn mortality. foreach (RuminantFemale female in location.Where(a => a.Gender == Sex.Female).Cast <RuminantFemale>().ToList()) { if (female.IsPregnant) { // calculate foetus and newborn mortality // total mortality / (gestation months + 1) to get monthly mortality // done here before births to account for post birth motality as well.. double rnd = ZoneCLEM.RandomGenerator.NextDouble(); if (rnd < (female.BreedParams.PrenatalMortality / (female.BreedParams.GestationLength + 1))) { female.OneOffspringDies(); } } } // check for births of all pregnant females. foreach (RuminantFemale female in location.Where(a => a.Gender == Sex.Female).Cast <RuminantFemale>().ToList()) { if (female.BirthDue) { female.WeightLossDueToCalf = 0; int numberOfNewborn = (female.CarryingTwins) ? 2 : 1; for (int i = 0; i < numberOfNewborn; i++) { // Foetal mortality is now performed each timestep at base of this method object newCalf = null; bool isMale = (ZoneCLEM.RandomGenerator.NextDouble() > 0.5); if (isMale) { newCalf = new RuminantMale(); } else { newCalf = new RuminantFemale(); } Ruminant newCalfRuminant = newCalf as Ruminant; newCalfRuminant.Age = 0; newCalfRuminant.HerdName = female.HerdName; newCalfRuminant.BreedParams = female.BreedParams; newCalfRuminant.Breed = female.BreedParams.Breed; newCalfRuminant.Gender = (isMale) ? Sex.Male : Sex.Female; newCalfRuminant.ID = Resources.RuminantHerd().NextUniqueID; newCalfRuminant.Location = female.Location; newCalfRuminant.Mother = female; newCalfRuminant.Number = 1; newCalfRuminant.SetUnweaned(); // calf weight from Freer newCalfRuminant.Weight = female.BreedParams.SRWBirth * female.StandardReferenceWeight * (1 - 0.33 * (1 - female.Weight / female.StandardReferenceWeight)); newCalfRuminant.HighWeight = newCalfRuminant.Weight; newCalfRuminant.SaleFlag = HerdChangeReason.Born; Resources.RuminantHerd().AddRuminant(newCalfRuminant); // add to sucklings female.SucklingOffspring.Add(newCalfRuminant); // remove calf weight from female female.WeightLossDueToCalf += newCalfRuminant.Weight; } female.UpdateBirthDetails(); } } // uncontrolled conception if (!UseAI) { // check if males and females of breeding condition are together if (location.GroupBy(a => a.Gender).Count() == 2) { // servicing rate int maleCount = location.Where(a => a.Gender == Sex.Male).Count(); int femaleCount = location.Where(a => a.Gender == Sex.Female).Count(); double matingsPossible = maleCount * location.FirstOrDefault().BreedParams.MaximumMaleMatingsPerDay * 30; double maleLimiter = Math.Min(1.0, matingsPossible / femaleCount); foreach (RuminantFemale female in location.Where(a => a.Gender == Sex.Female).Cast <RuminantFemale>().ToList()) { if (!female.IsPregnant && !female.IsLactating && (female.Age - female.AgeAtLastBirth) * 30.4 >= female.BreedParams.MinimumDaysBirthToConception) { // calculate conception double conceptionRate = ConceptionRate(female) * maleLimiter; conceptionRate = Math.Min(conceptionRate, MaximumConceptionRateUncontrolled); if (ZoneCLEM.RandomGenerator.NextDouble() <= conceptionRate) { female.UpdateConceptionDetails(ZoneCLEM.RandomGenerator.NextDouble() < female.BreedParams.TwinRate, conceptionRate); } } } } } // controlled conception else { if (this.TimingOK) { foreach (RuminantFemale female in location.Where(a => a.Gender == Sex.Female).Cast <RuminantFemale>().ToList()) { if (!female.IsPregnant && !female.IsLactating && (female.Age - female.AgeAtLastBirth) * 30.4 >= female.BreedParams.MinimumDaysBirthToConception) { // calculate conception double conceptionRate = ConceptionRate(female); if (numberServiced <= numberPossible) // labour/finance limited number { if (ZoneCLEM.RandomGenerator.NextDouble() <= conceptionRate) { female.UpdateConceptionDetails(ZoneCLEM.RandomGenerator.NextDouble() < female.BreedParams.TwinRate, conceptionRate); } numberServiced++; } } } } } } }
private void OnCLEMAnimalBreeding(object sender, EventArgs e) { this.Status = ActivityStatus.NotNeeded; NumberConceived = 0; // get list of all pregnant females List <RuminantFemale> pregnantherd = CurrentHerd(true).Where(a => a.Gender == Sex.Female).Cast <RuminantFemale>().Where(a => a.IsPregnant).ToList(); // determine all fetus and newborn mortality of all pregnant females. foreach (RuminantFemale female in pregnantherd) { // calculate fetus and newborn mortality // total mortality / (gestation months + 1) to get monthly mortality // done here before births to account for post birth motality as well.. // IsPregnant status does not change until births occur in next section so will include mortality in month of birth // needs to be calculated for each offspring carried. for (int i = 0; i < female.CarryingCount; i++) { if (RandomNumberGenerator.Generator.NextDouble() < (female.BreedParams.PrenatalMortality / (female.BreedParams.GestationLength + 1))) { female.OneOffspringDies(); if (female.NumberOfOffspring == 0) { // report conception status changed when last multiple birth dies. female.BreedParams.OnConceptionStatusChanged(new Reporting.ConceptionStatusChangedEventArgs(Reporting.ConceptionStatus.Failed, female, Clock.Today)); } } } if (female.BirthDue) { int numberOfNewborn = female.CarryingCount; for (int i = 0; i < numberOfNewborn; i++) { object newCalf = null; bool isMale = (RandomNumberGenerator.Generator.NextDouble() <= female.BreedParams.ProportionOffspringMale); double weight = female.BreedParams.SRWBirth * female.StandardReferenceWeight * (1 - 0.33 * (1 - female.Weight / female.StandardReferenceWeight)); if (isMale) { newCalf = new RuminantMale(0, Sex.Male, weight, female.BreedParams); } else { newCalf = new RuminantFemale(0, Sex.Female, weight, female.BreedParams); } Ruminant newCalfRuminant = newCalf as Ruminant; newCalfRuminant.HerdName = female.HerdName; newCalfRuminant.Breed = female.BreedParams.Breed; newCalfRuminant.ID = Resources.RuminantHerd().NextUniqueID; newCalfRuminant.Location = female.Location; newCalfRuminant.Mother = female; newCalfRuminant.Number = 1; newCalfRuminant.SetUnweaned(); // calf weight from Freer newCalfRuminant.PreviousWeight = newCalfRuminant.Weight; newCalfRuminant.SaleFlag = HerdChangeReason.Born; // add attributes inherited from mother foreach (var attribute in female.Attributes) { newCalfRuminant.AddAttribute(attribute.Key, attribute.Value.GetInheritedAttribute() as ICLEMAttribute); } Resources.RuminantHerd().AddRuminant(newCalfRuminant, this); // add to sucklings female.SucklingOffspringList.Add(newCalfRuminant); // this now reports for each individual born not a birth event as individual wean events are reported female.BreedParams.OnConceptionStatusChanged(new Reporting.ConceptionStatusChangedEventArgs(Reporting.ConceptionStatus.Birth, female, Clock.Today)); } female.UpdateBirthDetails(); this.Status = ActivityStatus.Success; } } // Perform breeding IEnumerable <Ruminant> herd = null; if (useControlledMating && controlledMating.TimingOK) { // determined by controlled mating and subsequent timer (e.g. smart milking) herd = controlledMating.BreedersToMate(); this.TriggerOnActivityPerformed(); } else if (!useControlledMating && TimingOK) { // whole herd for activity herd = CurrentHerd(true); // report that this activity was performed as it does not use base GetResourcesRequired this.TriggerOnActivityPerformed(); } if (herd != null && herd.Count() > 0) { // group by location var breeders = from ind in herd where ind.IsAbleToBreed group ind by ind.Location into grp select grp; int breedersCount = breeders.Count(); int numberPossible = breedersCount; int numberServiced = 1; List <Ruminant> maleBreeders = new List <Ruminant>(); // for each location where parts of this herd are located foreach (var location in breeders) { numberPossible = -1; if (useControlledMating) { numberPossible = Convert.ToInt32(location.Where(a => a.Gender == Sex.Female).Count(), CultureInfo.InvariantCulture); } else { numberPossible = 0; // uncontrolled conception if (location.GroupBy(a => a.Gender).Count() == 2) { int maleCount = location.Where(a => a.Gender == Sex.Male).Count(); // get a list of males to provide attributes when incontrolled mating. if (maleCount > 0 && location.FirstOrDefault().BreedParams.IncludedAttributeInheritanceWhenMating) { maleBreeders = location.Where(a => a.Gender == Sex.Male).ToList(); } int femaleCount = location.Where(a => a.Gender == Sex.Female).Count(); numberPossible = Convert.ToInt32(Math.Ceiling(maleCount * location.FirstOrDefault().BreedParams.MaximumMaleMatingsPerDay * 30), CultureInfo.InvariantCulture); } } numberServiced = 1; foreach (RuminantFemale female in location.Where(a => a.Gender == Sex.Female).Cast <RuminantFemale>().Where(a => !a.IsPregnant & a.Age <= a.BreedParams.MaximumAgeMating).ToList()) { Reporting.ConceptionStatus status = Reporting.ConceptionStatus.NotMated; if (numberServiced <= numberPossible) { // calculate conception double conceptionRate = ConceptionRate(female, out status); if (conceptionRate > 0) { if (RandomNumberGenerator.Generator.NextDouble() <= conceptionRate) { female.UpdateConceptionDetails(female.CalulateNumberOfOffspringThisPregnancy(), conceptionRate, 0); // if mandatory attributes are present in the herd, save male value with female details. if (female.BreedParams.IncludedAttributeInheritanceWhenMating) { if (useControlledMating) { // save all male attributes AddMalesAttributeDetails(female, controlledMating.SireAttributes); } else { // randomly select male AddMalesAttributeDetails(female, maleBreeders[RandomNumberGenerator.Generator.Next(0, maleBreeders.Count() - 1)]); } } status = Reporting.ConceptionStatus.Conceived; NumberConceived++; } } numberServiced++; this.Status = ActivityStatus.Success; } // report change in breeding status // do not report for -1 (controlled mating outside timing) if (numberPossible >= 0 && status != Reporting.ConceptionStatus.NotAvailable) { female.BreedParams.OnConceptionStatusChanged(new Reporting.ConceptionStatusChangedEventArgs(status, female, Clock.Today)); } } // report a natural mating locations for transparency via a message if (numberServiced > 0 & !useControlledMating) { string warning = "Natural (uncontrolled) mating ocurred in [r=" + location.Key + "]"; if (!Warnings.Exists(warning)) { Warnings.Add(warning); Summary.WriteMessage(this, warning); } } } } }
private void OnCLEMAnimalBreeding(object sender, EventArgs e) { List <Ruminant> herd = CurrentHerd(true); int aDay = Clock.Today.Year; // get list of all individuals of breeding age and condition // grouped by location var breeders = from ind in herd where ind.IsBreedingCondition group ind by ind.Location into grp select grp; // calculate labour and finance limitations if needed when doing AI int breedersCount = breeders.Count(); int numberPossible = breedersCount; int numberServiced = 1; double limiter = 1; if (UseAI && TimingOK) { // attempt to get required resources List <ResourceRequest> resourcesneeded = GetResourcesNeededForActivityLocal(); CheckResources(resourcesneeded, Guid.NewGuid()); bool tookRequestedResources = TakeResources(resourcesneeded, true); // get all shortfalls if (tookRequestedResources && (ResourceRequestList != null)) { //TODO: fix this to account for perHead payments and labour and not fixed expenses double amountCashNeeded = resourcesneeded.Where(a => a.ResourceType == typeof(Finance)).Sum(a => a.Required); double amountCashProvided = resourcesneeded.Where(a => a.ResourceType == typeof(Finance)).Sum(a => a.Provided); double amountLabourNeeded = resourcesneeded.Where(a => a.ResourceType == typeof(Labour)).Sum(a => a.Required); double amountLabourProvided = resourcesneeded.Where(a => a.ResourceType == typeof(Labour)).Sum(a => a.Provided); double cashlimit = 1; if (amountCashNeeded > 0) { cashlimit = amountCashProvided == 0 ? 0 : amountCashNeeded / amountCashProvided; } double labourlimit = 1; if (amountLabourNeeded > 0) { labourlimit = amountLabourProvided == 0 ? 0 : amountLabourNeeded / amountLabourProvided; } limiter = Math.Min(cashlimit, labourlimit); // TODO: determine if fixed payments were not possible // TODO: determine limits by insufficient labour or cash for per head payments } // report that this activity was performed as it does not use base GetResourcesRequired this.TriggerOnActivityPerformed(); } if (!UseAI) { // report that this activity was performed as it does not use base GetResourcesRequired this.TriggerOnActivityPerformed(); this.Status = ActivityStatus.NotNeeded; } // for each location where parts of this herd are located foreach (var location in breeders) { // determine all fetus and newborn mortality of all pregnant females. foreach (RuminantFemale female in location.Where(a => a.Gender == Sex.Female).Cast <RuminantFemale>().Where(a => a.IsPregnant).ToList()) { // calculate fetus and newborn mortality // total mortality / (gestation months + 1) to get monthly mortality // done here before births to account for post birth motality as well.. // IsPregnant status does not change until births occur in next section so will include mortality in month of birth // needs to be caclulated for each offspring carried. for (int i = 0; i < female.CarryingCount; i++) { if (RandomNumberGenerator.Generator.NextDouble() < (female.BreedParams.PrenatalMortality / (female.BreedParams.GestationLength + 1))) { female.OneOffspringDies(); if (female.NumberOfOffspring == 0) { // report conception status changed when last multiple birth dies. female.BreedParams.OnConceptionStatusChanged(new Reporting.ConceptionStatusChangedEventArgs(Reporting.ConceptionStatus.Failed, female, Clock.Today)); } } } } // check for births of all pregnant females. int month = Clock.Today.Month; foreach (RuminantFemale female in location.Where(a => a.Gender == Sex.Female).Cast <RuminantFemale>().ToList()) { if (female.BirthDue) { int numberOfNewborn = female.CarryingCount; for (int i = 0; i < numberOfNewborn; i++) { // Foetal mortality is now performed each timestep at base of this method object newCalf = null; bool isMale = (RandomNumberGenerator.Generator.NextDouble() <= female.BreedParams.ProportionOffspringMale); double weight = female.BreedParams.SRWBirth * female.StandardReferenceWeight * (1 - 0.33 * (1 - female.Weight / female.StandardReferenceWeight)); if (isMale) { newCalf = new RuminantMale(0, Sex.Male, weight, female.BreedParams); } else { newCalf = new RuminantFemale(0, Sex.Female, weight, female.BreedParams); } Ruminant newCalfRuminant = newCalf as Ruminant; newCalfRuminant.HerdName = female.HerdName; newCalfRuminant.Breed = female.BreedParams.Breed; newCalfRuminant.ID = Resources.RuminantHerd().NextUniqueID; newCalfRuminant.Location = female.Location; newCalfRuminant.Mother = female; newCalfRuminant.Number = 1; newCalfRuminant.SetUnweaned(); // calf weight from Freer newCalfRuminant.PreviousWeight = newCalfRuminant.Weight; newCalfRuminant.SaleFlag = HerdChangeReason.Born; Resources.RuminantHerd().AddRuminant(newCalfRuminant, this); // add to sucklings female.SucklingOffspringList.Add(newCalfRuminant); // this now reports for each individual born not a birth event as individual wean events are reported female.BreedParams.OnConceptionStatusChanged(new Reporting.ConceptionStatusChangedEventArgs(Reporting.ConceptionStatus.Birth, female, Clock.Today)); } female.UpdateBirthDetails(); this.Status = ActivityStatus.Success; } } numberPossible = -1; if (!UseAI) { numberPossible = 0; // uncontrolled conception if (location.GroupBy(a => a.Gender).Count() == 2) { int maleCount = location.Where(a => a.Gender == Sex.Male).Count(); int femaleCount = location.Where(a => a.Gender == Sex.Female).Count(); numberPossible = Convert.ToInt32(Math.Ceiling(maleCount * location.FirstOrDefault().BreedParams.MaximumMaleMatingsPerDay * 30), CultureInfo.InvariantCulture); } } else { // controlled mating (AI) if (this.TimingOK) { numberPossible = Convert.ToInt32(limiter * location.Where(a => a.Gender == Sex.Female).Count(), CultureInfo.InvariantCulture); } } numberServiced = 1; foreach (RuminantFemale female in location.Where(a => a.Gender == Sex.Female).Cast <RuminantFemale>().Where(a => !a.IsPregnant & a.Age <= a.BreedParams.MaximumAgeMating).ToList()) { Reporting.ConceptionStatus status = Reporting.ConceptionStatus.NotMated; if (numberServiced <= numberPossible) { // calculate conception double conceptionRate = ConceptionRate(female, out status); if (conceptionRate > 0) { if (RandomNumberGenerator.Generator.NextDouble() <= conceptionRate) { female.UpdateConceptionDetails(female.CalulateNumberOfOffspringThisPregnancy(), conceptionRate, 0); status = Reporting.ConceptionStatus.Conceived; } } numberServiced++; this.Status = ActivityStatus.Success; } // report change in breeding status // do not report for -1 (controlled mating outside timing) if (numberPossible >= 0 && status != Reporting.ConceptionStatus.NotAvailable) { female.BreedParams.OnConceptionStatusChanged(new Reporting.ConceptionStatusChangedEventArgs(status, female, Clock.Today)); } } // report a natural mating locations for transparency via a message if (this.Status == ActivityStatus.Success && !UseAI) { string warning = "Natural (uncontrolled) mating ocurred in [r=" + location.Key + "]"; if (!Warnings.Exists(warning)) { Warnings.Add(warning); Summary.WriteMessage(this, warning); } } } }
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)); } } }
private void OnWFAnimalManage(object sender, EventArgs e) { RuminantHerd ruminantHerd = Resources.RuminantHerd(); List <Ruminant> herd = ruminantHerd.Herd.Where(a => a.HerdName == HerdName).ToList(); RuminantType breedParams; // get breedParams when no herd remaining if (herd.Count() == 0) { bool resourceAvailable = false; breedParams = Resources.GetResourceItem("Ruminants", HerdName, out resourceAvailable) as RuminantType; } else { breedParams = herd.FirstOrDefault().BreedParams; } // can sell off males any month as per NABSA // if we don't need this monthly, then it goes into next if statement with herd declaration // NABSA MALES - weaners, 1-2, 2-3 and 3-4 yo, we check for any male weaned and not a breeding sire. // check for sell age/weight of young males // if SellYoungFemalesLikeMales then all apply to both sexes else only males. foreach (var ind in herd.Where(a => a.Weaned & (SellFemalesLikeMales ? true : (a.Gender == Sex.Male)) & (a.Age >= SellingAge ^ a.Weight >= SellingWeight))) { bool sell = true; if (ind.GetType() == typeof(RuminantMale)) { // don't sell breeding sires. sell = !((ind as RuminantMale).BreedingSire); } if (sell) { ind.SaleFlag = Common.HerdChangeReason.AgeWeightSale; } } // if management month if (Clock.Today.Month == ManagementMonth ^ MonthlyManagement) { // Perform weaning foreach (var ind in herd.Where(a => a.Weaned == false)) { if (ind.Age >= WeaningAge ^ ind.Weight >= WeaningWeight) { ind.Wean(); } } // check for maximum age (females and males have different cutoffs) foreach (var ind in herd.Where(a => a.Age >= ((a.Gender == Sex.Female) ? MaximumBreederAge : MaximumBullAge))) { ind.SaleFlag = Common.HerdChangeReason.MaxAgeSale; } // MALES // check for breeder bulls after sale of old individuals and buy/sell int numberinherd = herd.Where(a => a.Gender == Sex.Male & a.SaleFlag == Common.HerdChangeReason.None).Cast <RuminantMale>().Where(a => a.BreedingSire).Count(); if (numberinherd > MaximumSiresKept) { // sell bulls // What rule? oldest first as they may be lost soonest int numberToRemove = MaximumSiresKept - numberinherd; foreach (var male in herd.Where(a => a.Gender == Sex.Male).Cast <RuminantMale>().Where(a => a.BreedingSire).OrderByDescending(a => a.Age).Take(numberToRemove)) { male.SaleFlag = Common.HerdChangeReason.ExcessBullSale; } } else if (numberinherd < MaximumSiresKept) { // remove young bulls from sale herd to replace breed bulls (not those sold because too old) foreach (RuminantMale male in herd.Where(a => a.Gender == Sex.Male & a.SaleFlag == Common.HerdChangeReason.AgeWeightSale).OrderByDescending(a => a.Weight)) { male.SaleFlag = Common.HerdChangeReason.None; male.BreedingSire = true; numberinherd++; if (numberinherd >= MaximumSiresKept) { break; } } // if still insufficient buy bulls. if (numberinherd < MaximumSiresKept) { int numberToBuy = Convert.ToInt32((MaximumSiresKept - numberinherd) * 0.05); for (int i = 0; i < numberToBuy; i++) { RuminantMale newbull = new RuminantMale(); newbull.Age = 48; newbull.HerdName = HerdName; newbull.BreedingSire = true; newbull.BreedParams = breedParams; newbull.Gender = Sex.Male; newbull.ID = ruminantHerd.NextUniqueID; newbull.Weight = 450; newbull.HighWeight = newbull.Weight; newbull.SaleFlag = Common.HerdChangeReason.SirePurchase; // add to purchase request list and await purchase in Buy/ Sell ruminantHerd.PurchaseIndividuals.Add(newbull); } } } // FEMALES // check for maximum number of breeders remaining after sale and buy/sell numberinherd = herd.Where(a => a.Gender == Sex.Female & a.Age >= a.BreedParams.MinimumAge1stMating & a.SaleFlag == Common.HerdChangeReason.None).Count(); if (numberinherd > MaximumBreedersKept) { // sell breeders // What rule? oldest first as they may be lost soonest // should keep pregnant females... and young... // this will currently remove pregnant females and females with suckling calf int numberToRemove = MaximumBreedersKept - numberinherd; foreach (var female in herd.Where(a => a.Gender == Sex.Female & a.Age >= a.BreedParams.MinimumAge1stMating).OrderByDescending(a => a.Age).Take(numberToRemove)) { female.SaleFlag = Common.HerdChangeReason.ExcessBreederSale; } } else { // remove young females from sale herd to replace breeders (not those sold because too old) foreach (RuminantFemale female in herd.Where(a => a.Gender == Sex.Female & a.SaleFlag == Common.HerdChangeReason.AgeWeightSale).OrderByDescending(a => a.Weight)) { female.SaleFlag = Common.HerdChangeReason.None; numberinherd++; if (numberinherd >= MaximumBreedersKept) { break; } } // if still insufficient buy breeders. if (numberinherd < MaximumBreedersKept) { int ageOfHeifer = 12; double weightOfHeifer = 260; int numberToBuy = Convert.ToInt32((MaximumBreedersKept - numberinherd) * 0.05); for (int i = 0; i < numberToBuy; i++) { RuminantFemale newheifer = new RuminantFemale(); newheifer.Age = ageOfHeifer; newheifer.HerdName = HerdName; newheifer.BreedParams = breedParams; newheifer.Gender = Sex.Female; newheifer.ID = ruminantHerd.NextUniqueID; newheifer.Weight = weightOfHeifer; newheifer.HighWeight = newheifer.Weight; newheifer.SaleFlag = Common.HerdChangeReason.HeiferPurchase; // add to purchase request list and await purchase in Buy/ Sell ruminantHerd.PurchaseIndividuals.Add(newheifer); } } } } }
private void OnWFAnimalBreeding(object sender, EventArgs e) { RuminantHerd ruminantHerd = Resources.RuminantHerd(); List <Ruminant> herd = ruminantHerd.Herd.Where(a => a.BreedParams.Name == HerdName).ToList(); // get list of all individuals of breeding age and condition // grouped by location var breeders = from ind in herd where (ind.Gender == Sex.Male & ind.Age >= ind.BreedParams.MinimumAge1stMating) ^ (ind.Gender == Sex.Female & ind.Age >= ind.BreedParams.MinimumAge1stMating & ind.Weight >= (ind.BreedParams.MinimumSize1stMating * ind.StandardReferenceWeight) ) group ind by ind.Location into grp select grp; // for each location where parts of this herd are located foreach (var location in breeders) { // check for births of all pregnant females. foreach (RuminantFemale female in location.Where(a => a.Gender == Sex.Female).Cast <RuminantFemale>().ToList()) { if (female.BirthDue) { int numberOfNewborn = (female.CarryingTwins) ? 2 : 1; for (int i = 0; i < numberOfNewborn; i++) { // Determine if the offspring died during pregancy from conception to after birth // This is currently only performed at time of birth rather than monthly during pregnancy // and so does not reflect changes in female intake etc after dead of foetus. object newCalf = null; bool isMale = (WholeFarm.RandomGenerator.NextDouble() > 0.5); if (isMale) { newCalf = new RuminantMale(); } else { newCalf = new RuminantFemale(); } Ruminant newCalfRuminant = newCalf as Ruminant; newCalfRuminant.Age = 0; newCalfRuminant.HerdName = female.HerdName; newCalfRuminant.BreedParams = female.BreedParams; newCalfRuminant.Gender = (isMale) ? Sex.Male : Sex.Female; newCalfRuminant.ID = ruminantHerd.NextUniqueID; newCalfRuminant.Location = female.Location; newCalfRuminant.Mother = female; // newCalfRuminant.Number = 1; newCalfRuminant.SetUnweaned(); // calf weight from Freer newCalfRuminant.Weight = female.BreedParams.SRWBirth * female.StandardReferenceWeight * (1 - 0.33 * (1 - female.Weight / female.StandardReferenceWeight)); newCalfRuminant.HighWeight = newCalfRuminant.Weight; newCalfRuminant.SaleFlag = Common.HerdChangeReason.Born; ruminantHerd.AddRuminant(newCalfRuminant); // add to sucklings female.SucklingOffspring.Add(newCalfRuminant); } female.UpdateBirthDetails(); } } // uncontrolled conception if (ControlledMatings == null) { // check if males and females of breeding condition are together if (location.GroupBy(a => a.Gender).Count() == 2) { // servicing rate int maleCount = location.Where(a => a.Gender == Sex.Male).Count(); int femaleCount = location.Where(a => a.Gender == Sex.Female).Count(); double matingsPossible = maleCount * location.FirstOrDefault().BreedParams.MaximumMaleMatingsPerDay * 30; double maleLimiter = Math.Max(1.0, matingsPossible / femaleCount); foreach (RuminantFemale female in location.Where(a => a.Gender == Sex.Female).Cast <RuminantFemale>().ToList()) { //TODO: ensure enough time since last calf if (!female.IsPregnant & !female.IsLactating) { // calculate conception double conceptionRate = ConceptionRate(female) * maleLimiter; conceptionRate = Math.Min(conceptionRate, MaximumConceptionRateUncontrolled); if (WholeFarm.RandomGenerator.NextDouble() <= conceptionRate) { female.UpdateConceptionDetails(WholeFarm.RandomGenerator.NextDouble() > female.BreedParams.TwinRate, conceptionRate); } } } } } // controlled conception else if (ControlledMatings != null && ControlledMatings.IsDueDate()) { foreach (RuminantFemale female in location.Where(a => a.Gender == Sex.Female).Cast <RuminantFemale>().ToList()) { //TODO: ensure enough time since last calf if (!female.IsPregnant & !female.IsLactating) { // calculate conception double conceptionRate = ConceptionRate(female); if (WholeFarm.RandomGenerator.NextDouble() <= conceptionRate) { female.UpdateConceptionDetails(WholeFarm.RandomGenerator.NextDouble() > female.BreedParams.TwinRate, conceptionRate); } } } } // determine all foetus and newborn mortality. foreach (RuminantFemale female in location.Where(a => a.Gender == Sex.Female).Cast <RuminantFemale>().ToList()) { if (female.IsPregnant) { // calculate foetus and newborn mortality // total mortality / gestation months to get monthly mortality // TODO: check if need to be done before births to get last month mortality if (WholeFarm.RandomGenerator.NextDouble() > female.BreedParams.PrenatalMortality / female.BreedParams.GestationLength) { female.OneOffspringDies(); } } } } if (ControlledMatings != null && ControlledMatings.IsDueDate()) { } }