/// <summary> /// Calculate conception rate for a female /// </summary> /// <param name="female">Female to calculate conception rate for</param> /// <param name="status">Returns conception status</param> /// <returns></returns> private double ConceptionRate(RuminantFemale female, out Reporting.ConceptionStatus status) { bool isConceptionReady = false; status = Reporting.ConceptionStatus.NotAvailable; if (!female.IsPregnant) { status = Reporting.ConceptionStatus.NotReady; if (female.Age >= female.BreedParams.MinimumAge1stMating && female.NumberOfBirths == 0) { isConceptionReady = true; } else { // add one to age to ensure that conception is due this timestep if ((female.Age + 1 - female.AgeAtLastBirth) * 30.4 > female.BreedParams.MinimumDaysBirthToConception) { // only based upon period since birth isConceptionReady = true; // DEVELOPMENT NOTE: // The following IPI calculation and check present in NABSA has been removed for testing // It is assumed that the individual based model with weight influences will handle the old IPI calculation // These parameters can now be removed form the RuminantType list //double currentIPI = female.BreedParams.InterParturitionIntervalIntercept * Math.Pow(female.ProportionOfNormalisedWeight, female.BreedParams.InterParturitionIntervalCoefficient) * 30.4; //double ageNextConception = female.AgeAtLastConception + (currentIPI / 30.4); //isConceptionReady = (female.Age+1 >= ageNextConception); } } } // if first mating and of age or sufficient time since last birth if (isConceptionReady) { status = Reporting.ConceptionStatus.Unsuccessful; // Get conception rate from conception model associated with the Ruminant Type parameters if (female.BreedParams.ConceptionModel == null) { throw new ApsimXException(this, String.Format("No conception details were found for [r={0}]\r\nPlease add a conception component below the [r=RuminantType]", female.BreedParams.Name)); } return(female.BreedParams.ConceptionModel.ConceptionRate(female)); } return(0); }
private void OnCLEMInitialiseActivity(object sender, EventArgs e) { this.AllocationStyle = ResourceAllocationStyle.Manual; controlledMating = this.FindAllChildren <RuminantActivityControlledMating>().FirstOrDefault(); // Assignment of mothers was moved to RuminantHerd resource to ensure this is done even if no breeding activity is included this.InitialiseHerd(false, true); // report what is happening with timing when uncontrolled mating if (!useControlledMating & this.TimingExists) { Summary.WriteMessage(this, $"Uncontrolled/natural breeding should occur every month. The timer associated with [a={this.Name}] may restrict uncontrolled mating regardless of whether males and females of breeding condition are located together.\r\nYou can also seperate genders by moving to different paddocks to manage the timing of natural mating or add a [a=RuminantActivityControlledMating] component to define controlled mating", MessageType.Warning); } // set up pre start conception status of breeders IEnumerable <Ruminant> herd = CurrentHerd(true); // report previous pregnancies as conceptions foreach (RuminantFemale female in herd.OfType <RuminantFemale>().Where(a => a.IsPregnant)) { // report conception status changed from those assigned suckling at startup female.BreedParams.OnConceptionStatusChanged(new Reporting.ConceptionStatusChangedEventArgs(Reporting.ConceptionStatus.Conceived, female, clock.Today)); } // work out pregnancy status of initial herd if (InferStartupPregnancy) { // only initialise if herd present if (herd.Any()) { // go back (gestation - 1) months // this won't include those individuals due to give birth on day 1. int monthsAgoStart = 0 - (Convert.ToInt32(Math.Truncate(herd.FirstOrDefault().BreedParams.GestationLength), CultureInfo.InvariantCulture) - 1); int monthsAgoStop = -1; for (int i = monthsAgoStart; i <= monthsAgoStop; i++) { DateTime previousDate = clock.Today.AddMonths(i); DateTime conceiveDate = clock.Today.AddMonths(i); conceiveDate = new DateTime(conceiveDate.Year, conceiveDate.Month, DateTime.DaysInMonth(conceiveDate.Year, conceiveDate.Month)); // get list of all individuals of breeding age and condition // grouped by location var breeders = from ind in herd where (ind.Sex == Sex.Male && ind.Age + i >= ind.BreedParams.MinimumAge1stMating) || (ind.Sex == Sex.Female && ind.Age + i >= ind.BreedParams.MinimumAge1stMating && !(ind as RuminantFemale).IsPregnant ) group ind by ind.Location into grp select grp; // must be breeders to bother checking any further // must be either uncontrolled mating or the timing of controlled mating if (breeders.Count() > 0 & (!useControlledMating || this.TimingCheck(previousDate))) { int numberPossible = 0; int numberServiced = 1; double limiter = 1; List <Ruminant> maleBreeders = new List <Ruminant>(); // for each location where parts of this herd are located foreach (var location in breeders) { // uncontrolled conception if (!useControlledMating) { // check if males and females of breeding condition are together if (location.GroupBy(a => a.Sex).Count() == 2) { // servicing rate int maleCount = location.Where(a => a.Sex == 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.Sex == Sex.Male).ToList(); } int femaleCount = location.OfType <RuminantFemale>().Count(); double matingsPossible = maleCount * location.FirstOrDefault().BreedParams.MaximumMaleMatingsPerDay * 30; double maleLimiter = Math.Min(1, matingsPossible / femaleCount); // only get non-pregnant females of breeding age at the time before the simulation included var availableBreeders = location.OfType <RuminantFemale>().Where(b => !b.IsPregnant && b.Age + i >= b.BreedParams.MinimumAge1stMating); // only get selection of these of breeders available to spread conceptions // only 15% of breeding herd of age can conceive in any month or male limited proportion whichever is smaller int count = Convert.ToInt32(Math.Ceiling(availableBreeders.Count() * Math.Min(0.15, maleLimiter)), CultureInfo.InvariantCulture); availableBreeders = availableBreeders.OrderBy(x => RandomNumberGenerator.Generator.NextDouble()).Take(count); foreach (RuminantFemale female in availableBreeders) { // calculate conception Reporting.ConceptionStatus status = Reporting.ConceptionStatus.NotMated; double conceptionRate = ConceptionRate(female, out status); if (RandomNumberGenerator.Generator.NextDouble() <= conceptionRate) { female.UpdateConceptionDetails(female.CalulateNumberOfOffspringThisPregnancy(), conceptionRate, i); female.LastMatingStyle = MatingStyle.PreSimulation; // if mandatory attributes are present in the herd, save male value with female details. if (female.BreedParams.IncludedAttributeInheritanceWhenMating) { // randomly select male as father AddMalesAttributeDetails(female, maleBreeders[RandomNumberGenerator.Generator.Next(0, maleBreeders.Count() - 1)]); } // report conception status changed female.BreedParams.OnConceptionStatusChanged(new Reporting.ConceptionStatusChangedEventArgs(Reporting.ConceptionStatus.Conceived, female, conceiveDate)); // check for perenatal mortality for (int j = i; j < monthsAgoStop; j++) { DateTime lossDate = clock.Today.AddMonths(i); lossDate = new DateTime(lossDate.Year, lossDate.Month, DateTime.DaysInMonth(lossDate.Year, lossDate.Month)); for (int k = 0; k < 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, lossDate)); } } } } } } } } // controlled conception else { numberPossible = Convert.ToInt32(limiter * location.OfType <RuminantFemale>().Count(), CultureInfo.InvariantCulture); foreach (RuminantFemale female in location.OfType <RuminantFemale>()) { if (!female.IsPregnant && (female.Age - female.AgeAtLastBirth) * 30.4 >= female.BreedParams.MinimumDaysBirthToConception) { // calculate conception Reporting.ConceptionStatus status = Reporting.ConceptionStatus.NotMated; double conceptionRate = ConceptionRate(female, out status); if (numberServiced <= numberPossible) // labour/finance limited number { if (RandomNumberGenerator.Generator.NextDouble() <= conceptionRate) { female.UpdateConceptionDetails(female.CalulateNumberOfOffspringThisPregnancy(), conceptionRate, i); female.LastMatingStyle = MatingStyle.Controlled; // if mandatory attributes are present in the herd, save male value with female details. if (female.BreedParams.IncludedAttributeInheritanceWhenMating) { // save all male attributes AddMalesAttributeDetails(female, controlledMating.SireAttributes); } // report conception status changed female.BreedParams.OnConceptionStatusChanged(new Reporting.ConceptionStatusChangedEventArgs(Reporting.ConceptionStatus.Conceived, female, conceiveDate)); // check for perenatal mortality for (int j = i; j < monthsAgoStop; j++) { DateTime lossDate = clock.Today.AddMonths(i); lossDate = new DateTime(lossDate.Year, lossDate.Month, DateTime.DaysInMonth(lossDate.Year, lossDate.Month)); for (int k = 0; k < female.CarryingCount; k++) { 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, lossDate)); } } } } } 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).OfType <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++) { var rnd = RandomNumberGenerator.Generator.NextDouble(); if (rnd < (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++) { bool isMale = RandomNumberGenerator.Generator.NextDouble() <= female.BreedParams.ProportionOffspringMale; Sex sex = isMale ? Sex.Male : Sex.Female; double weight = female.BreedParams.SRWBirth * female.StandardReferenceWeight * (1 - 0.33 * (1 - female.Weight / female.StandardReferenceWeight)); Ruminant newSucklingRuminant = Ruminant.Create(sex, female.BreedParams, 0, weight); newSucklingRuminant.HerdName = female.HerdName; newSucklingRuminant.Breed = female.BreedParams.Breed; newSucklingRuminant.ID = HerdResource.NextUniqueID; newSucklingRuminant.Location = female.Location; newSucklingRuminant.Mother = female; newSucklingRuminant.Number = 1; newSucklingRuminant.SetUnweaned(); // suckling/calf weight from Freer newSucklingRuminant.PreviousWeight = newSucklingRuminant.Weight; newSucklingRuminant.SaleFlag = HerdChangeReason.Born; // add attributes inherited from mother foreach (var attribute in female.Attributes.Items) { if (attribute.Value != null) { newSucklingRuminant.Attributes.Add(attribute.Key, attribute.Value.GetInheritedAttribute() as IIndividualAttribute); } } HerdResource.AddRuminant(newSucklingRuminant, this); // add to sucklings female.SucklingOffspringList.Add(newSucklingRuminant); // 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(); } else if (!useControlledMating && TimingOK) { // whole herd for activity including males herd = CurrentHerd(true); } if (herd != null && herd.Any()) { // group by location var breeders = from ind in herd where ind.IsAbleToBreed group ind by ind.Location into grp select grp; // identify not ready for reporting and tracking var notReadyBreeders = herd.Where(a => a.Sex == Sex.Female).Cast <RuminantFemale>().Where(a => a.IsBreeder && !a.IsAbleToBreed && !a.IsPregnant); foreach (RuminantFemale female in notReadyBreeders) { female.BreedParams.OnConceptionStatusChanged(new Reporting.ConceptionStatusChangedEventArgs(Reporting.ConceptionStatus.NotReady, female, clock.Today)); } int numberPossible = breeders.Sum(a => a.Count()); 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.OfType <RuminantFemale>().Count(), CultureInfo.InvariantCulture); } else { numberPossible = 0; // uncontrolled conception if (location.GroupBy(a => a.Sex).Count() == 2) { int maleCount = location.OfType <RuminantMale>().Count(); // get a list of males to provide attributes when incontrolled mating. if (maleCount > 0 && location.FirstOrDefault().BreedParams.IncludedAttributeInheritanceWhenMating) { maleBreeders = location.Where(a => a.Sex == Sex.Male).ToList(); } int femaleCount = location.Where(a => a.Sex == Sex.Female).Count(); numberPossible = Convert.ToInt32(Math.Ceiling(maleCount * location.FirstOrDefault().BreedParams.MaximumMaleMatingsPerDay * 30), CultureInfo.InvariantCulture); } } numberServiced = 0; lastJoinIndex = -1; int cnt = 0; // shuffle the not pregnant females when obtained to avoid any inherant order by creation of individuals affecting which individuals are available first var notPregnantFemales = location.OfType <RuminantFemale>().Where(a => !a.IsPregnant).OrderBy(a => RandomNumberGenerator.Generator.Next()).ToList(); int totalToBreed = notPregnantFemales.Count; while (cnt < totalToBreed) { RuminantFemale female = notPregnantFemales.ElementAt(cnt); Reporting.ConceptionStatus status = Reporting.ConceptionStatus.NotMated; if (numberServiced < numberPossible) { // calculate conception double conceptionRate = ConceptionRate(female, out status); // if mandatory attributes are present in the herd, save male value with female details. // update male for both successful and failed matings (next if statement if (female.BreedParams.IncludedAttributeInheritanceWhenMating) { object male = null; if (useControlledMating) { bool newJoining = needsNewJoiningMale(controlledMating.JoiningsPerMale, numberServiced); // save all male attributes AddMalesAttributeDetails(female, controlledMating.SireAttributes, newJoining); } else { male = maleBreeders[RandomNumberGenerator.Generator.Next(0, maleBreeders.Count() - 1)]; female.LastMatingStyle = ((male as RuminantMale).IsWildBreeder ? MatingStyle.WildBreeder : MatingStyle.Natural); // randomly select male AddMalesAttributeDetails(female, male as Ruminant); } } if (conceptionRate > 0) { if (RandomNumberGenerator.Generator.NextDouble() <= conceptionRate) { female.UpdateConceptionDetails(female.CalulateNumberOfOffspringThisPregnancy(), conceptionRate, 0); if (useControlledMating) { female.LastMatingStyle = MatingStyle.Controlled; } status = Reporting.ConceptionStatus.Conceived; NumberConceived++; } else { status = Reporting.ConceptionStatus.Unsuccessful; } } 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)); } cnt++; } // report a natural mating locations for transparency via a message if (numberServiced > 0 & !useControlledMating) { string warning = $"Natural (uncontrolled) mating ocurred in [r={(location.Key ?? "Not specified - general yards")}]"; Warnings.CheckAndWrite(warning, Summary, this, MessageType.Information); } } } // report that this activity was performed as it does not use base GetResourcesRequired this.TriggerOnActivityPerformed(); }
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 OnCLEMInitialiseActivity(object sender, EventArgs e) { this.AllocationStyle = ResourceAllocationStyle.Manual; // Assignment of mothers was moved to RuminantHerd resource to ensure this is done even if no breeding activity is included this.InitialiseHerd(false, true); // get labour specifications labour = this.FindAllChildren <LabourRequirement>().Cast <LabourRequirement>().ToList(); // this.Children.Where(a => a.GetType() == typeof(LabourFilterGroupSpecified)).Cast<LabourFilterGroupSpecified>().ToList(); if (labour.Count() == 0) { labour = new List <LabourRequirement>(); } // check that timer exists for AI if (UseAI) { if (!this.TimingExists) { Summary.WriteWarning(this, String.Format("Breeding with Artificial Insemination (AI) requires a Timer otherwise breeding will be undertaken every time step in activity [a={0}]", this.Name)); } } else { if (this.TimingExists) { Summary.WriteWarning(this, String.Format("Uncontrolled/natural breeding will occur every month and the timer associated with [a={0}] will be ignored.", this.Name)); } } // work out pregnancy status of initial herd if (InferStartupPregnancy) { // set up pre start conception status of breeders List <Ruminant> herd = CurrentHerd(true); int aDay = Clock.Today.Year; // go back (gestation - 1) months // this won't include those individuals due to give birth on day 1. int monthsAgoStart = 0 - (Convert.ToInt32(Math.Truncate(herd.FirstOrDefault().BreedParams.GestationLength), CultureInfo.InvariantCulture) - 1); int monthsAgoStop = -1; for (int i = monthsAgoStart; i <= monthsAgoStop; i++) { DateTime previousDate = Clock.Today.AddMonths(i); // 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 + i >= ind.BreedParams.MinimumAge1stMating) || (ind.Gender == Sex.Female && ind.Age + i >= ind.BreedParams.MinimumAge1stMating && !(ind as RuminantFemale).IsPregnant ) group ind by ind.Location into grp select grp; int breedersCount = breeders.Count(); // must be breeders to bother checking any further // must be either uncontrolled mating or the timing of controlled mating if (breedersCount > 0 & (!UseAI || this.TimingCheck(previousDate))) { int numberPossible = breedersCount; int numberServiced = 1; double limiter = 1; // for each location where parts of this herd are located foreach (var location in breeders) { // 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, matingsPossible / femaleCount); // only get non-pregnant females of breeding age at the time before the simulation included var availableBreeders = location.Where(b => b.Gender == Sex.Female && b.Age + i >= b.BreedParams.MinimumAge1stMating) .Cast <RuminantFemale>().Where(a => !a.IsPregnant).ToList(); // only get selection of these of breeders available to spread conceptions // only 15% of breeding herd of age can conceive in any month or male limited proportion whichever is smaller int count = Convert.ToInt32(Math.Ceiling(availableBreeders.Count() * Math.Min(0.15, maleLimiter))); availableBreeders = availableBreeders.OrderBy(x => RandomNumberGenerator.Generator.NextDouble()).Take(count).ToList(); foreach (RuminantFemale female in availableBreeders) { // calculate conception Reporting.ConceptionStatus status = Reporting.ConceptionStatus.NotMated; double conceptionRate = ConceptionRate(female, out status); if (RandomNumberGenerator.Generator.NextDouble() <= conceptionRate) { female.UpdateConceptionDetails(female.CalulateNumberOfOffspringThisPregnancy(), conceptionRate, i); // report conception status changed female.BreedParams.OnConceptionStatusChanged(new Reporting.ConceptionStatusChangedEventArgs(Reporting.ConceptionStatus.Conceived, female, Clock.Today)); // check for perenatal mortality for (int j = i; j < monthsAgoStop; j++) { for (int k = 0; k < 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)); } } } } } } } } // controlled conception else { numberPossible = Convert.ToInt32(limiter * location.Where(a => a.Gender == Sex.Female).Count(), CultureInfo.InvariantCulture); foreach (RuminantFemale female in location.Where(a => a.Gender == Sex.Female).Cast <RuminantFemale>().ToList()) { if (!female.IsPregnant && (female.Age - female.AgeAtLastBirth) * 30.4 >= female.BreedParams.MinimumDaysBirthToConception) { // calculate conception Reporting.ConceptionStatus status = Reporting.ConceptionStatus.NotMated; double conceptionRate = ConceptionRate(female, out status); if (numberServiced <= numberPossible) // labour/finance limited number { if (RandomNumberGenerator.Generator.NextDouble() <= conceptionRate) { female.UpdateConceptionDetails(female.CalulateNumberOfOffspringThisPregnancy(), conceptionRate, i); // report conception status changed female.BreedParams.OnConceptionStatusChanged(new Reporting.ConceptionStatusChangedEventArgs(Reporting.ConceptionStatus.Conceived, female, Clock.Today)); // check for perenatal mortality for (int j = i; j < monthsAgoStop; j++) { for (int k = 0; k < female.CarryingCount; k++) { 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)); } } } } } numberServiced++; } } } } } } } } }
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) { // Assignment of mothers was moved to RuminantHerd resource to ensure this is done even if no breeding activity is included this.InitialiseHerd(false, true); // get labour specifications labour = Apsim.Children(this, typeof(LabourRequirement)).Cast <LabourRequirement>().ToList(); // this.Children.Where(a => a.GetType() == typeof(LabourFilterGroupSpecified)).Cast<LabourFilterGroupSpecified>().ToList(); if (labour.Count() == 0) { labour = new List <LabourRequirement>(); } // check that timer exists for AI if (UseAI) { if (!this.TimingExists) { Summary.WriteWarning(this, String.Format("Breeding with Artificial Insemination (AI) requires a Timer otherwise breeding will be undertaken every time step in activity [a={0}]", this.Name)); } } // work out pregnancy status of initial herd if (InferStartupPregnancy) { // set up pre start conception status of breeders List <Ruminant> herd = CurrentHerd(true); int aDay = Clock.Today.Year; // go back (gestation - 1) months // this won't include those individuals due to give birth on day 1. int monthsAgoStart = Clock.Today.Month - (Convert.ToInt32(Math.Truncate(herd.FirstOrDefault().BreedParams.GestationLength), CultureInfo.InvariantCulture) - 1); int monthsAgoStop = -1; for (int i = monthsAgoStart; i <= monthsAgoStop; i++) { DateTime previousDate = Clock.Today.AddMonths(i); // 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 + i >= ind.BreedParams.MinimumAge1stMating) || (ind.Gender == Sex.Female && ind.Age + i >= ind.BreedParams.MinimumAge1stMating //&& // ind.Weight >= (ind.BreedParams.MinimumSize1stMating * ind.StandardReferenceWeight) ) group ind by ind.Location into grp select grp; int breedersCount = breeders.Count(); int numberPossible = breedersCount; int numberServiced = 1; double limiter = 1; // for each location where parts of this herd are located foreach (var location in breeders) { // 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.Age - female.AgeAtLastBirth) * 30.4 >= female.BreedParams.MinimumDaysBirthToConception) { // calculate conception Reporting.ConceptionStatus status = Reporting.ConceptionStatus.NotMated; double conceptionRate = ConceptionRate(female, out status) * maleLimiter; if (ZoneCLEM.RandomGenerator.NextDouble() <= conceptionRate) { female.UpdateConceptionDetails(female.CalulateNumberOfOffspringThisPregnancy(), conceptionRate, i); // report conception status changed female.BreedParams.OnConceptionStatusChanged(new Reporting.ConceptionStatusChangedEventArgs(Reporting.ConceptionStatus.Conceived, female, Clock.Today)); } } } } } // controlled conception else { if (this.TimingCheck(previousDate)) { numberPossible = Convert.ToInt32(limiter * location.Where(a => a.Gender == Sex.Female).Count(), CultureInfo.InvariantCulture); foreach (RuminantFemale female in location.Where(a => a.Gender == Sex.Female).Cast <RuminantFemale>().ToList()) { if (!female.IsPregnant && (female.Age - female.AgeAtLastBirth) * 30.4 >= female.BreedParams.MinimumDaysBirthToConception) { // calculate conception Reporting.ConceptionStatus status = Reporting.ConceptionStatus.NotMated; double conceptionRate = ConceptionRate(female, out status); if (numberServiced <= numberPossible) // labour/finance limited number { if (ZoneCLEM.RandomGenerator.NextDouble() <= conceptionRate) { female.UpdateConceptionDetails(female.CalulateNumberOfOffspringThisPregnancy(), conceptionRate, i); // report conception status changed female.BreedParams.OnConceptionStatusChanged(new Reporting.ConceptionStatusChangedEventArgs(Reporting.ConceptionStatus.Conceived, female, Clock.Today)); } numberServiced++; } } } } } } } } }