private void BuyWithoutTrucking() { // This activity will purchase animals based on available funds. // get current untrucked list of animal purchases List <Ruminant> herd = HerdResource.PurchaseIndividuals.Where(a => a.BreedParams.Breed == this.PredictedHerdBreed).ToList(); if (herd.Count > 0) { if (this.Status != ActivityStatus.Warning) { this.Status = ActivityStatus.Success; } } else { return; } List <Ruminant> boughtIndividuals = new List <Ruminant>(); double fundsAvailable = 0; if (bankAccount != null) { fundsAvailable = bankAccount.FundsAvailable; } double cost = 0; double shortfall = 0; bool fundsexceeded = false; foreach (var newind in herd) { if (bankAccount != null) // perform with purchasing { double value = 0; AnimalPriceGroup pricing = null; if (newind.SaleFlag == HerdChangeReason.SirePurchase) { pricing = newind.BreedParams.ValueofIndividual(newind, PurchaseOrSalePricingStyleType.Purchase, "Male.IsSire", "true"); } else { pricing = newind.BreedParams.ValueofIndividual(newind, PurchaseOrSalePricingStyleType.Purchase); } if (pricing != null) { value = pricing.CalculateValue(newind); } if (cost + value <= fundsAvailable && fundsexceeded == false) { boughtIndividuals.Add(newind); HerdResource.PurchaseIndividuals.Remove(newind); newind.ID = HerdResource.NextUniqueID; HerdResource.AddRuminant(newind, this); cost += value; } else { fundsexceeded = true; shortfall += value; } } else // no financial transactions { boughtIndividuals.Add(newind); HerdResource.PurchaseIndividuals.Remove(newind); newind.ID = HerdResource.NextUniqueID; HerdResource.AddRuminant(newind, this); } } if (bankAccount != null) { ResourceRequest purchaseRequest = new ResourceRequest { ActivityModel = this, Required = cost, AllowTransmutation = false, Category = TransactionCategory, RelatesToResource = this.PredictedHerdName }; //bankAccount.Add(saleValue, this, this.PredictedHerdName, TransactionCategory); var groupedIndividuals = HerdResource.SummarizeIndividualsByGroups(boughtIndividuals, PurchaseOrSalePricingStyleType.Purchase); foreach (var item in groupedIndividuals) { foreach (var item2 in item.RuminantTypeGroup) { purchaseRequest.Required = item2.TotalPrice ?? 0; purchaseRequest.Category = $"{TransactionCategory}.{item2.GroupName}"; bankAccount.Remove(purchaseRequest); // bankAccount.Add(item2.TotalPrice, this, item.RuminantTypeName, $"{TransactionCategory}.{item2.GroupName}"); } } // report any financial shortfall in purchases if (shortfall > 0) { purchaseRequest.Available = bankAccount.Amount; purchaseRequest.Required = cost + shortfall; purchaseRequest.Provided = cost; purchaseRequest.ResourceType = typeof(Finance); purchaseRequest.ResourceTypeName = BankAccountName; ResourceRequestEventArgs rre = new ResourceRequestEventArgs() { Request = purchaseRequest }; OnShortfallOccurred(rre); } } }
private void BuyWithTrucking() { // This activity will purchase animals based on available funds. int trucks = 0; int head = 0; double aESum = 0; double fundsAvailable = 0; if (bankAccount != null) { fundsAvailable = bankAccount.FundsAvailable; } double cost = 0; double shortfall = 0; bool fundsexceeded = false; // get current untrucked list of animal purchases List <Ruminant> herd = HerdResource.PurchaseIndividuals.Where(a => a.BreedParams.Breed == this.PredictedHerdBreed).OrderByDescending(a => a.Weight).ToList(); if (herd.Count == 0) { return; } List <Ruminant> boughtIndividuals = new List <Ruminant>(); // if purchase herd > min loads before allowing trucking if (herd.Select(a => a.Weight / 450.0).Sum() / trucking.Number450kgPerTruck >= trucking.MinimumTrucksBeforeBuying) { // while truck to fill while (herd.Select(a => a.Weight / 450.0).Sum() / trucking.Number450kgPerTruck > trucking.MinimumLoadBeforeBuying) { 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; if (bankAccount != null) // perform with purchasing { double value = 0; AnimalPriceGroup pricing = null; if (ind.SaleFlag == HerdChangeReason.SirePurchase) { pricing = ind.BreedParams.ValueofIndividual(ind, PurchaseOrSalePricingStyleType.Purchase, "IsSire", "true"); } else { pricing = ind.BreedParams.ValueofIndividual(ind, PurchaseOrSalePricingStyleType.Purchase); } if (pricing != null) { value = pricing.CalculateValue(ind); } if (cost + value <= fundsAvailable && fundsexceeded == false) { ind.ID = HerdResource.NextUniqueID; boughtIndividuals.Add(ind); HerdResource.AddRuminant(ind, this); HerdResource.PurchaseIndividuals.Remove(ind); cost += value; } else { fundsexceeded = true; shortfall += value; } } else // no financial transactions { ind.ID = HerdResource.NextUniqueID; boughtIndividuals.Add(ind); HerdResource.AddRuminant(ind, this); HerdResource.PurchaseIndividuals.Remove(ind); } } } if (nonloaded) { Summary.WriteWarning(this, String.Format("There was a problem loading the purchase truck as purchase individuals did not meet the loading criteria for breed [r={0}]", this.PredictedHerdBreed)); break; } if (shortfall > 0) { break; } herd = HerdResource.PurchaseIndividuals.Where(a => a.BreedParams.Breed == this.PredictedHerdBreed).OrderByDescending(a => a.Weight).ToList(); } if (Status != ActivityStatus.Warning) { if (HerdResource.PurchaseIndividuals.Where(a => a.BreedParams.Breed == this.PredictedHerdBreed).Any() == false) { SetStatusSuccess(); } else { Status = ActivityStatus.Partial; } } // create trucking emissions if (trucking != null && trucks > 0) { trucking.ReportEmissions(trucks, false); } if (bankAccount != null && (trucks > 0 || trucking == null)) { ResourceRequest purchaseRequest = new ResourceRequest { ActivityModel = this, Required = cost, AllowTransmutation = false, Category = TransactionCategory, RelatesToResource = this.PredictedHerdName }; var groupedIndividuals = HerdResource.SummarizeIndividualsByGroups(boughtIndividuals, PurchaseOrSalePricingStyleType.Purchase); foreach (var item in groupedIndividuals) { foreach (var item2 in item.RuminantTypeGroup) { purchaseRequest.Required = item2.TotalPrice ?? 0; purchaseRequest.Category = $"{TransactionCategory}.{item2.GroupName}"; bankAccount.Remove(purchaseRequest); } } // report any financial shortfall in purchases if (shortfall > 0) { purchaseRequest.Available = bankAccount.Amount; purchaseRequest.Required = cost + shortfall; purchaseRequest.Provided = cost; purchaseRequest.ResourceType = typeof(Finance); purchaseRequest.ResourceTypeName = BankAccountName; ResourceRequestEventArgs rre = new ResourceRequestEventArgs() { Request = purchaseRequest }; OnShortfallOccurred(rre); } ResourceRequest expenseRequest = new ResourceRequest { Available = bankAccount.Amount, ActivityModel = this, AllowTransmutation = false }; // calculate transport costs if (trucking != null) { expenseRequest.Required = trucks * trucking.DistanceToMarket * trucking.CostPerKmTrucking; expenseRequest.Category = trucking.TransactionCategory; bankAccount.Remove(expenseRequest); if (expenseRequest.Required > expenseRequest.Available) { expenseRequest.Available = bankAccount.Amount; expenseRequest.ResourceType = typeof(Finance); expenseRequest.ResourceTypeName = BankAccountName; ResourceRequestEventArgs rre = new ResourceRequestEventArgs() { Request = expenseRequest }; OnShortfallOccurred(rre); } } } } else { this.Status = ActivityStatus.Warning; } }
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(); }