private void OnWFAnimalDeath(object sender, EventArgs e) { // remove individuals that died // currently performed in the month after weight has been adjusted // and before breeding, trading, culling etc (See Clock event order) // Calculated by // critical weight & // juvenile (unweaned) death based on mothers weight & // adult weight adjusted base mortality. RuminantHerd ruminantHerd = Resources.RuminantHerd(); List <Ruminant> herd = ruminantHerd.Herd; // weight based mortality List <Ruminant> died = herd.Where(a => a.Weight < (a.HighWeight * (1.0 - a.BreedParams.ProportionOfMaxWeightToSurvive))).ToList(); // set died flag died.Select(a => { a.SaleFlag = Common.HerdChangeReason.Died; return(a); }).ToList(); ruminantHerd.RemoveRuminant(died); // base mortality adjusted for condition foreach (var ind in ruminantHerd.Herd) { double mortalityRate = 0; if (!ind.Weaned) { mortalityRate = 0; if ((ind.Mother == null) || (ind.Mother.Weight < ind.BreedParams.CriticalCowWeight * ind.StandardReferenceWeight)) { // if no mohter assigned or mother's weight is < CriticalCowWeight * SFR mortalityRate = ind.BreedParams.JuvenileMortalityMaximum; } else { // if mother's weight >= criticalCowWeight * SFR mortalityRate = Math.Exp(-Math.Pow(ind.BreedParams.JuvenileMortalityCoefficient * (ind.Mother.Weight / ind.Mother.NormalisedAnimalWeight), ind.BreedParams.JuvenileMortalityExponent)); } mortalityRate = mortalityRate + ind.BreedParams.MortalityBase; mortalityRate = Math.Max(mortalityRate, ind.BreedParams.JuvenileMortalityMaximum); } else { mortalityRate = 1 - (1 - ind.BreedParams.MortalityBase) * (1 - Math.Exp(Math.Pow(-(ind.BreedParams.MortalityCoefficient * (ind.Weight / ind.NormalisedAnimalWeight - ind.BreedParams.MortalityIntercept)), ind.BreedParams.MortalityExponent))); } if (WholeFarm.RandomGenerator.NextDouble() <= mortalityRate) { ind.Died = true; } } died = herd.Where(a => a.Died).ToList(); died.Select(a => { a.SaleFlag = Common.HerdChangeReason.Died; return(a); }).ToList(); ruminantHerd.RemoveRuminant(died); }
private void OnCLEMAnimalDeath(object sender, EventArgs e) { // remove individuals that died // currently performed in the month after weight has been adjusted // and before breeding, trading, culling etc (See Clock event order) // Calculated by // critical weight && // juvenile (unweaned) death based on mothers weight && // adult weight adjusted base mortality. RuminantHerd ruminantHerd = Resources.RuminantHerd(); List <Ruminant> herd = ruminantHerd.Herd; // weight based mortality List <Ruminant> died = herd.Where(a => a.Weight < (a.HighWeight * a.BreedParams.ProportionOfMaxWeightToSurvive)).ToList(); // set died flag died.Select(a => { a.SaleFlag = HerdChangeReason.DiedUnderweight; return(a); }).ToList(); ruminantHerd.RemoveRuminant(died, this); // base mortality adjusted for condition foreach (var ind in ruminantHerd.Herd) { double mortalityRate = 0; if (!ind.Weaned) { mortalityRate = 0; if ((ind.Mother == null) || (ind.Mother.Weight < ind.BreedParams.CriticalCowWeight * ind.StandardReferenceWeight)) { // if no mother assigned or mother's weight is < CriticalCowWeight * SFR mortalityRate = ind.BreedParams.JuvenileMortalityMaximum; } else { // if mother's weight >= criticalCowWeight * SFR mortalityRate = Math.Exp(-Math.Pow(ind.BreedParams.JuvenileMortalityCoefficient * (ind.Mother.Weight / ind.Mother.NormalisedAnimalWeight), ind.BreedParams.JuvenileMortalityExponent)); } mortalityRate += ind.BreedParams.MortalityBase; mortalityRate = Math.Min(mortalityRate, ind.BreedParams.JuvenileMortalityMaximum); } else { mortalityRate = 1 - (1 - ind.BreedParams.MortalityBase) * (1 - Math.Exp(Math.Pow(-(ind.BreedParams.MortalityCoefficient * (ind.Weight / ind.NormalisedAnimalWeight - ind.BreedParams.MortalityIntercept)), ind.BreedParams.MortalityExponent))); } // convert mortality from annual (calculated) to monthly (applied). if (ZoneCLEM.RandomGenerator.NextDouble() <= (mortalityRate / 12)) { ind.Died = true; } } died = herd.Where(a => a.Died).ToList(); died.Select(a => { a.SaleFlag = HerdChangeReason.DiedMortality; return(a); }).ToList(); // TODO: separate foster from real mother for genetics // check for death of mother with sucklings and try foster sucklings List <RuminantFemale> mothersWithCalf = died.Where(a => a.Gender == Sex.Female).Cast <RuminantFemale>().Where(a => a.SucklingOffspringList.Count() > 0).ToList(); List <RuminantFemale> wetMothersAvailable = died.Where(a => a.Gender == Sex.Female).Cast <RuminantFemale>().Where(a => a.IsLactating & a.SucklingOffspringList.Count() == 0).OrderBy(a => a.DaysLactating).ToList(); int wetMothersAssigned = 0; if (wetMothersAvailable.Count() > 0) { if (mothersWithCalf.Count() > 0) { foreach (var deadMother in mothersWithCalf) { foreach (var calf in deadMother.SucklingOffspringList) { if (wetMothersAssigned < wetMothersAvailable.Count()) { calf.Mother = wetMothersAvailable[wetMothersAssigned]; wetMothersAssigned++; } else { break; } } } } } ruminantHerd.RemoveRuminant(died, this); }
private void OnCLEMAnimalSell(object sender, EventArgs e) { RuminantHerd ruminantHerd = Resources.RuminantHerd(); int trucks = 0; double saleValue = 0; double saleWeight = 0; int head = 0; double aESum = 0; // get current untrucked list of animals flagged for sale List <Ruminant> herd = this.CurrentHerd(false).Where(a => a.SaleFlag != HerdChangeReason.None).OrderByDescending(a => a.Weight).ToList(); if (trucking == null) { // no trucking just sell head = herd.Count(); if (herd.Count() > 0) { SetStatusSuccess(); } foreach (var ind in herd) { aESum += ind.AdultEquivalent; saleValue += ind.BreedParams.ValueofIndividual(ind, PurchaseOrSalePricingStyleType.Sale); saleWeight += ind.Weight; ruminantHerd.RemoveRuminant(ind, this); } } else { // if sale herd > min loads before allowing sale if (herd.Select(a => a.Weight / 450.0).Sum() / trucking.Number450kgPerTruck >= trucking.MinimumTrucksBeforeSelling) { // while truck to fill while (herd.Select(a => a.Weight / 450.0).Sum() / trucking.Number450kgPerTruck > trucking.MinimumLoadBeforeSelling) { bool nonloaded = true; trucks++; double load450kgs = 0; // while truck below carrying capacity load individuals foreach (var ind in herd) { if (load450kgs + (ind.Weight / 450.0) <= trucking.Number450kgPerTruck) { nonloaded = false; head++; aESum += ind.AdultEquivalent; load450kgs += ind.Weight / 450.0; saleValue += ind.BreedParams.ValueofIndividual(ind, PurchaseOrSalePricingStyleType.Sale); saleWeight += ind.Weight; ruminantHerd.RemoveRuminant(ind, this); //TODO: work out what to do with suckling calves still with mothers if mother sold. } } if (nonloaded) { Summary.WriteWarning(this, String.Format("There was a problem loading the sale truck as sale individuals did not meet the loading criteria for breed [r={0}]", this.PredictedHerdBreed)); break; } herd = this.CurrentHerd(false).Where(a => a.SaleFlag != HerdChangeReason.None).OrderByDescending(a => a.Weight).ToList(); } // create trucking emissions if (trucks > 0) { SetStatusSuccess(); } trucking.ReportEmissions(trucks, true); } } if (bankAccount != null && head > 0) //(trucks > 0 || trucking == null) { ResourceRequest expenseRequest = new ResourceRequest { ActivityModel = this, AllowTransmutation = false }; // calculate transport costs if (trucking != null) { expenseRequest.Required = trucks * trucking.DistanceToMarket * trucking.CostPerKmTrucking; expenseRequest.Reason = "Transport sales"; bankAccount.Remove(expenseRequest); } foreach (RuminantActivityFee item in Apsim.Children(this, typeof(RuminantActivityFee))) { switch (item.PaymentStyle) { case AnimalPaymentStyleType.Fixed: expenseRequest.Required = item.Amount; break; case AnimalPaymentStyleType.perHead: expenseRequest.Required = head * item.Amount; break; case AnimalPaymentStyleType.perAE: expenseRequest.Required = aESum * item.Amount; break; case AnimalPaymentStyleType.ProportionOfTotalSales: expenseRequest.Required = saleValue * item.Amount; break; default: throw new Exception(String.Format("PaymentStyle ({0}) is not supported for ({1}) in ({2})", item.PaymentStyle, item.Name, this.Name)); } expenseRequest.Reason = item.Name; // uses bank account specified in the RuminantActivityFee item.BankAccount.Remove(expenseRequest); } // add and remove from bank if (saleValue > 0) { bankAccount.Add(saleValue, this, this.PredictedHerdName + " sales"); } } }
private void OnWFAnimalSell(object sender, EventArgs e) { RuminantHerd ruminantHerd = Resources.RuminantHerd(); Finance Accounts = Resources.FinanceResource() as Finance; FinanceType bankAccount = Accounts.GetFirst() as FinanceType; int trucks = 0; double saleValue = 0; double saleWeight = 0; int head = 0; // get current untrucked list of animals flagged for sale List <Ruminant> herd = ruminantHerd.Herd.Where(a => a.SaleFlag != Common.HerdChangeReason.None & a.Breed == BreedName).OrderByDescending(a => a.Weight).ToList(); // if sale herd > min loads before allowing sale if (herd.Select(a => a.Weight / 450.0).Sum() / Number450kgPerTruck >= MinimumTrucksBeforeSelling) { // while truck to fill while (herd.Select(a => a.Weight / 450.0).Sum() / Number450kgPerTruck > MinimumLoadBeforeSelling) { bool nonloaded = true; trucks++; double load450kgs = 0; // while truck below carrying capacity load individuals foreach (var ind in herd) { if (load450kgs + (ind.Weight / 450.0) <= Number450kgPerTruck) { nonloaded = false; head++; load450kgs += ind.Weight / 450.0; RuminantValue getvalue = PriceList.Where(a => a.Age < ind.Age).OrderBy(a => a.Age).LastOrDefault(); saleValue += getvalue.SellValue * ((getvalue.Style == Common.PricingStyleType.perKg) ? ind.Weight : 1.0); saleWeight += ind.Weight; ruminantHerd.RemoveRuminant(ind); } } if (nonloaded) { Summary.WriteWarning(this, String.Format("There was a problem loading the sale truck as sale individuals did not meet the loading criteria for breed {0}", BreedName)); break; } herd = ruminantHerd.Herd.Where(a => a.SaleFlag != Common.HerdChangeReason.None & a.Breed == BreedName).OrderByDescending(a => a.Weight).ToList(); } if (trucks > 0 & bankAccount != null) { // calculate transport costs double transportCost = trucks * DistanceToMarket * CostPerKmTrucking; bankAccount.Remove(transportCost, this.Name, "Transport"); // calculate MLA fees double mlaCost = head * MLAFees; bankAccount.Remove(mlaCost, this.Name, "R&DFee"); // calculate yard fees double yardCost = head * YardFees; bankAccount.Remove(yardCost, this.Name, "YardCosts"); // calculate commission double commissionCost = saleValue * SalesCommission; bankAccount.Remove(commissionCost, this.Name, "SalesCommission"); // add and remove from bank bankAccount.Add(saleValue, this.Name, "Sales"); } } }
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)); } } }