private void HandleRestocking(double aEtoBuy, string paddockName, Ruminant exampleRuminant)
        {
            if (aEtoBuy <= 0)
            {
                return;
            }

            // we won't remove individuals from the sale pool as we can't assume we can keep them in the herd
            // as management has already decided they need to be sold.

            // buy steers to fatten up and take advantage of the good season growth.

            // ensure min pasture for restocking
            if ((foodStore == null) || ((foodStore.TonnesPerHectare * 1000) > MinimumFeedBeforeRestock))
            {
                double weight      = exampleRuminant.StandardReferenceWeight - ((1 - exampleRuminant.BreedParams.SRWBirth) * exampleRuminant.StandardReferenceWeight) * Math.Exp(-(exampleRuminant.BreedParams.AgeGrowthRateCoefficient * (exampleRuminant.Age * 30.4)) / (Math.Pow(exampleRuminant.StandardReferenceWeight, exampleRuminant.BreedParams.SRWGrowthScalar)));
                double numberToBuy = aEtoBuy * Math.Pow(weight, 0.75) / Math.Pow(exampleRuminant.BreedParams.BaseAnimalEquivalent, 0.75); // convert to AE

                for (int i = 0; i < Convert.ToInt32(numberToBuy, CultureInfo.InvariantCulture); i++)
                {
                    Resources.RuminantHerd().PurchaseIndividuals.Add(new RuminantMale(192, Sex.Male, weight, exampleRuminant.BreedParams)
                    {
                        // Age = 192, or 16 months
                        HerdName     = exampleRuminant.HerdName,
                        Number       = 1,
                        SaleFlag     = HerdChangeReason.RestockPurchase,
                        Breed        = exampleRuminant.Breed,
                        BreedingSire = false,
                        Draught      = false,
                        Location     = paddockName,
                    }
                                                                     );
                }
            }
        }
 /// <summary>
 /// A method to add the male attributes to the female attribute store at mating
 /// </summary>
 /// <param name="female">The female breeder successfully mated</param>
 /// <param name="male">The mated male</param>
 private void AddMalesAttributeDetails(RuminantFemale female, Ruminant male)
 {
     if (male != null)
     {
         foreach (var attribute in female.Attributes)
         {
             var maleAttribute = male.GetAttributeValue(attribute.Key);
             if (maleAttribute != null)
             {
                 if (attribute.Value.InheritanceStyle != maleAttribute.InheritanceStyle)
                 {
                     throw new ApsimXException(this, $"The inheritance style for attribute [{attribute.Key}] differs between the breeder and breeding male from the herd in [a={this.Name}]");
                 }
                 attribute.Value.storedMateValue = maleAttribute.storedValue;
             }
             else
             {
                 attribute.Value.storedMateValue = null;
                 if (female.BreedParams.IsMandatoryAttribute(attribute.Key))
                 {
                     throw new ApsimXException(this, $"The attributes provided with the breeding male from the herd does not include the madatory attribute [{attribute.Key}] in [a={this.Name}]");
                 }
             }
         }
     }
 }
        private double HandleRestocking(double animalEquivalentsToBuy, string paddockName, Ruminant exampleRuminant)
        {
            if (animalEquivalentsToBuy <= 0)
            {
                return(0);
            }

            GrazeFoodStoreType foodStore = Resources.GetResourceItem(this, typeof(GrazeFoodStore), paddockName, OnMissingResourceActionTypes.Ignore, OnMissingResourceActionTypes.ReportErrorAndStop) as GrazeFoodStoreType;

            // ensure min pasture for restocking
            if ((foodStore == null) || ((foodStore.TonnesPerHectare * 1000) > MinimumFeedBeforeRestock))
            {
                var specifyComponents = FindAllChildren <SpecifyRuminant>();
                if (specifyComponents.Count() == 0)
                {
                    string warn = $"No [f=SpecifyRuminant]s were provided in [a={this.Name}]\r\nNo restocking will be performed.";
                    this.Status = ActivityStatus.Warning;
                    if (!Warnings.Exists(warn))
                    {
                        Summary.WriteWarning(this, warn);
                        Warnings.Add(warn);
                    }
                }

                // buy animals specified in restock ruminant groups
                foreach (SpecifyRuminant item in specifyComponents)
                {
                    double sumAE   = 0;
                    double limitAE = animalEquivalentsToBuy * item.Proportion;

                    while (sumAE < limitAE && animalEquivalentsToBuy > 0)
                    {
                        Ruminant newIndividual = item.Details.CreateIndividuals(1, null).FirstOrDefault();
                        newIndividual.Location    = paddockName;
                        newIndividual.BreedParams = item.BreedParams;
                        newIndividual.HerdName    = item.BreedParams.Name;
                        newIndividual.PurchaseAge = newIndividual.Age;
                        newIndividual.SaleFlag    = HerdChangeReason.RestockPurchase;

                        if (newIndividual.Weight == 0)
                        {
                            throw new ApsimXException(this, $"Specified individual added during restock cannot have no weight in [{this.Name}]");
                        }

                        Resources.RuminantHerd().PurchaseIndividuals.Add(newIndividual);
                        double indAE = newIndividual.AdultEquivalent;
                        animalEquivalentsToBuy -= indAE;
                        sumAE += indAE;
                    }
                }
                return(Math.Max(0, animalEquivalentsToBuy));
            }
            return(animalEquivalentsToBuy);
        }
Example #4
0
        /// <summary>
        /// A method to add the male attributes to the female attribute store at mating
        /// </summary>
        /// <param name="female">The female breeder successfully mated</param>
        /// <param name="male">The mated male</param>
        private void AddMalesAttributeDetails(RuminantFemale female, Ruminant male)
        {
            if (male is null)
            {
                return;
            }

            foreach (var attribute in female.Attributes.Items)
            {
                var maleAttribute = male.Attributes.GetValue(attribute.Key);
                SetFemaleMateAttributes(female, attribute, maleAttribute);
            }
        }
        private void CalculatePotentialIntake(Ruminant ind)
        {
            // calculate daily potential intake for the selected individual/cohort
            double standardReferenceWeight = ind.StandardReferenceWeight;

            // now calculated in Ruminant
            // ind.NormalisedAnimalWeight = standardReferenceWeight - ((1 - ind.BreedParams.SRWBirth) * standardReferenceWeight) * Math.Exp(-(ind.BreedParams.AgeGrowthRateCoefficient * (ind.Age * 30.4)) / (Math.Pow(standardReferenceWeight, ind.BreedParams.SRWGrowthScalar)));
            double liveWeightForIntake = ind.NormalisedAnimalWeight;

            // now performed at allocation of weight in Ruminant
            if (ind.HighWeight < ind.NormalisedAnimalWeight)
            {
                liveWeightForIntake = ind.HighWeight;
            }

            // Calculate potential intake based on current weight compared to SRW and previous highest weight
            double potentialIntake = 0;

            ind.MilkIntakePotential = 0;

            // calculate milk intake shortfall for sucklings
            if (!ind.Weaned)
            {
                // potential milk intake/animal/day
                ind.MilkIntakePotential = ind.BreedParams.MilkIntakeIntercept + ind.BreedParams.MilkIntakeCoefficient * ind.Weight;

                // get estimated milk available
                // this will be updated to the corrected milk available in the calculate energy section.
                ind.MilkIntake = Math.Min(ind.MilkIntakePotential, ind.MothersMilkProductionAvailable);

                // if milk supply low, calf will subsitute forage up to a specified % of bodyweight (R_C60)
                if (ind.MilkIntake < ind.Weight * ind.BreedParams.MilkLWTFodderSubstitutionProportion)
                {
                    potentialIntake = Math.Max(0.0, ind.Weight * ind.BreedParams.MaxJuvenileIntake - ind.MilkIntake * ind.BreedParams.ProportionalDiscountDueToMilk);
                }
            }
            else
            {
                if (ind.Weaner)
                {
                    // Reference: SCA Metabolic LWTs
                    // restored in v112 of NABSA for weaner animals
                    potentialIntake = ind.BreedParams.IntakeCoefficient * standardReferenceWeight * (Math.Pow(liveWeightForIntake, 0.75) / Math.Pow(standardReferenceWeight, 0.75)) * (ind.BreedParams.IntakeIntercept - (Math.Pow(liveWeightForIntake, 0.75) / Math.Pow(standardReferenceWeight, 0.75)));
                    // older individual check. previous method before adding calulation for weaners after discussions with Cam McD
                    //double prevint = ind.BreedParams.IntakeCoefficient * liveWeightForIntake * (ind.BreedParams.IntakeIntercept - liveWeightForIntake / standardReferenceWeight);
                }
                else // 12month+ individuals
                {
                    // Reference: SCA based actual LWTs
                    potentialIntake = ind.BreedParams.IntakeCoefficient * liveWeightForIntake * (ind.BreedParams.IntakeIntercept - liveWeightForIntake / standardReferenceWeight);
                }

                if (ind.Gender == Sex.Female)
                {
                    RuminantFemale femaleind = ind as RuminantFemale;
                    // Increase potential intake for lactating breeder
                    if (femaleind.IsLactating)
                    {
                        // move to half way through timestep
                        double dayOfLactation = femaleind.DaysLactating;
                        // Reference: Intake multiplier for lactating cow (M.Freer)
                        // double intakeMilkMultiplier = 1 + 0.57 * Math.Pow((dayOfLactation / 81.0), 0.7) * Math.Exp(0.7 * (1 - (dayOfLactation / 81.0)));
                        double intakeMilkMultiplier = 1 + ind.BreedParams.LactatingPotentialModifierConstantA * Math.Pow((dayOfLactation / ind.BreedParams.LactatingPotentialModifierConstantB), ind.BreedParams.LactatingPotentialModifierConstantC) * Math.Exp(ind.BreedParams.LactatingPotentialModifierConstantC * (1 - (dayOfLactation / ind.BreedParams.LactatingPotentialModifierConstantB))) * (1 - 0.5 + 0.5 * (ind.Weight / ind.NormalisedAnimalWeight));

                        // To make this flexible for sheep and goats, added three new Ruminant Coeffs
                        // Feeding standard values for Beef, Dairy suck, Dairy non-suck and sheep are:
                        // For 0.57 (A) use .42, .58, .85 and .69; for 0.7 (B) use 1.7, 0.7, 0.7 and 1.4, for 81 (C) use 62, 81, 81, 28
                        // added LactatingPotentialModifierConstantA, LactatingPotentialModifierConstantB and LactatingPotentialModifierConstantC
                        // replaces (A), (B) and (C)
                        potentialIntake *= intakeMilkMultiplier;

                        // calculate estimated milk production for time step here
                        // assuming average feed quality if no previous diet values
                        // This need to happen before suckling potential intake can be determined.
                        CalculateMilkProduction(femaleind);
                        femaleind.MilkProducedThisTimeStep = femaleind.MilkProduction * 30.4;
                    }
                    else
                    {
                        femaleind.MilkProduction = 0;
                    }
                }

                //TODO: option to restrict potential further due to stress (e.g. heat, cold, rain)
            }
            // get monthly intake
            potentialIntake    *= 30.4;
            ind.PotentialIntake = potentialIntake;
        }
        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;
                }
            }
        }
Example #7
0
        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
                HerdResource.PurchaseIndividuals.RemoveAll(a => a.Breed == this.PredictedHerdBreed && a.SaleFlag == HerdChangeReason.TradePurchase);

                foreach (SpecifyRuminant purchaseSpecific in this.FindAllChildren <SpecifyRuminant>())
                {
                    RuminantTypeCohort purchasetype = purchaseSpecific.FindChild <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);
                    }

                    number *= purchaseSpecific.Proportion;

                    for (int i = 0; i < Math.Ceiling(number); i++)
                    {
                        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;

                        var ruminant = Ruminant.Create(purchasetype.Sex, herdToUse, purchasetype.Age, weight);

                        ruminant.ID             = 0;
                        ruminant.Breed          = purchaseSpecific.BreedParams.Name;
                        ruminant.HerdName       = purchaseSpecific.BreedParams.Breed;
                        ruminant.PurchaseAge    = purchasetype.Age;
                        ruminant.SaleFlag       = HerdChangeReason.TradePurchase;
                        ruminant.Location       = grazeStore;
                        ruminant.PreviousWeight = ruminant.Weight;

                        if (ruminant is RuminantFemale female)
                        {
                            female.WeightAtConception = ruminant.Weight;
                            female.NumberOfBirths     = 0;
                        }

                        HerdResource.PurchaseIndividuals.Add(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)
        {
            // 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;
                }
            }
        }
        /// <summary>
        /// Function to calculate energy from intake and subsequent growth
        /// </summary>
        /// <param name="ind">Ruminant individual class</param>
        /// <param name="methaneProduced">Sets output variable to value of methane produced</param>
        /// <returns></returns>
        private void CalculateEnergy(Ruminant ind, out double methaneProduced)
        {
            double intakeDaily          = ind.Intake / 30.4;
            double potentialIntakeDaily = ind.PotentialIntake / 30.4;

            // Sme 1 for females and castrates
            // TODO: castrates not implemented
            double Sme = 1;

            // Sme 1.15 for all males.
            if (ind.Gender == Sex.Male)
            {
                Sme = 1.15;
            }

            double energyDiet = EnergyGross * ind.DietDryMatterDigestibility / 100.0;
            // Reference: Nutrient Requirements of domesticated ruminants (p7)
            double energyMetabolic          = energyDiet * 0.81;
            double energyMetablicFromIntake = energyMetabolic * intakeDaily;

            double km = ind.BreedParams.EMaintCoefficient * energyMetabolic / EnergyGross + ind.BreedParams.EMaintIntercept;
            // Reference: SCA p.49
            double kg = ind.BreedParams.EGrowthCoefficient * energyMetabolic / EnergyGross + ind.BreedParams.EGrowthIntercept;

            double energyPredictedBodyMassChange = 0;
            double energyMaintenance             = 0;

            if (!ind.Weaned)
            {
                // calculate engergy and growth from milk intake

                // old code
                // dum = potential milk intake daily
                // dumshort = potential intake. check that it isnt monthly

                // Below now uses actual intake received rather than assume all potential intake is eaten
                double kml = 1;
                double kgl = 1;
                if ((ind.Intake + ind.MilkIntake) > 0)
                {
                    // average energy efficiency for maintenance
                    kml = ((ind.MilkIntake * 0.7) + (intakeDaily * km)) / (ind.MilkIntake + intakeDaily);
                    // average energy efficiency for growth
                    kgl = ((ind.MilkIntake * 0.7) + (intakeDaily * kg)) / (ind.MilkIntake + intakeDaily);
                }
                double energyMilkConsumed = ind.MilkIntake * 3.2;
                // limit calf intake of milk per day
                energyMilkConsumed = Math.Min(ind.BreedParams.MilkIntakeMaximum * 3.2, energyMilkConsumed);

                energyMaintenance = (ind.BreedParams.EMaintCoefficient * Math.Pow(ind.Weight, 0.75) / kml) * Math.Exp(-ind.BreedParams.EMaintExponent * ind.AgeZeroCorrected);
                ind.EnergyBalance = energyMilkConsumed - energyMaintenance + energyMetablicFromIntake;

                double feedingValue = 0;
                if (ind.EnergyBalance > 0)
                {
                    feedingValue = 2 * 0.7 * ind.EnergyBalance / (kgl * energyMaintenance) - 1;
                }
                else
                {
                    //(from Hirata model)
                    feedingValue = 2 * ind.EnergyBalance / (0.85 * energyMaintenance) - 1;
                }
                double energyEmptyBodyGain = ind.BreedParams.GrowthEnergyIntercept1 + feedingValue + (ind.BreedParams.GrowthEnergyIntercept2 - feedingValue) / (1 + Math.Exp(-6 * (ind.Weight / ind.NormalisedAnimalWeight - 0.4)));

                energyPredictedBodyMassChange = ind.BreedParams.GrowthEfficiency * 0.7 * ind.EnergyBalance / energyEmptyBodyGain;
            }
            else
            {
                double energyMilk   = 0;
                double energyFoetus = 0;

                if (ind.Gender == Sex.Female)
                {
                    RuminantFemale femaleind = ind as RuminantFemale;

                    // calculate energy for lactation
                    if (femaleind.IsLactating)
                    {
                        // Reference: SCA p.
                        double kl       = ind.BreedParams.ELactationCoefficient * energyMetabolic / EnergyGross + ind.BreedParams.ELactationIntercept;
                        double milkTime = Math.Max(0.0, (ind.Age - femaleind.AgeAtLastBirth + 1) * 30.4);
                        if (milkTime <= ind.BreedParams.MilkingDays)
                        {
                            double milkCurve = 0;
                            if (femaleind.DryBreeder)                             // no suckling calf
                            {
                                milkCurve = ind.BreedParams.MilkCurveNonSuckling;
                            }
                            else                             // suckling calf
                            {
                                milkCurve = ind.BreedParams.MilkCurveSuckling;
                            }
                            //TODO: check this equation that I redefined it correctly.
                            double milkProduction = ind.BreedParams.MilkPeakYield * ind.Weight / ind.NormalisedAnimalWeight * (Math.Pow(((milkTime + ind.BreedParams.MilkOffsetDay) / ind.BreedParams.MilkPeakDay), milkCurve)) * Math.Exp(milkCurve * (1 - (milkTime + ind.BreedParams.MilkOffsetDay) / ind.BreedParams.MilkPeakDay));
                            milkProduction = Math.Max(milkProduction, 0.0);
                            // Reference: Potential milk prodn, 3.2 MJ/kg milk - Jouven et al 2008
                            energyMilk = milkProduction * 3.2 / kl;
                            if (ind.EnergyBalance < (-0.5936 / 0.322 * energyMilk))
                            {
                                ind.EnergyBalance = (-0.5936 / 0.322 * energyMilk);
                            }
                            milkProduction = Math.Max(0.0, milkProduction * (0.5936 + 0.322 * ind.EnergyBalance / energyMilk));
                            // Reference: Adjusted milk prodn, 3.2 MJ/kg milk - Jouven et al 2008
                            energyMilk = milkProduction * 3.2 / kl;
                        }
                    }

                    // Determine energy required for foetal development
                    if (femaleind.IsPregnant)
                    {
                        double standardReferenceWeight = ind.StandardReferenceWeight;
                        // Potential birth weight
                        // Reference: Freer
                        double potentialBirthWeight = ind.BreedParams.SRWBirth * standardReferenceWeight * (1 - 0.33 * (1 - ind.Weight / standardReferenceWeight));
                        double foetusAge            = (femaleind.Age - femaleind.AgeAtLastConception + 1) * 30.4;
                        //TODO: Check foetus gage correct
                        energyFoetus = potentialBirthWeight * 349.16 * 0.000058 * Math.Exp(345.67 - 0.000058 * foetusAge - 349.16 * Math.Exp(-0.000058 * foetusAge)) / 0.13;
                    }
                }

                //TODO: add draft energy requirement

                // set maintenance age to maximum of 6 years
                double maintenanceAge = Math.Min(ind.Age * 30.4, 2190);

                // Reference: SCA p.24
                // Regference p19 (1.20). Does not include MEgraze or Ecold, also skips M,
                // 0.000082 is -0.03 Age in Years/365 for days
                energyMaintenance = ind.BreedParams.Kme * Sme * (0.26 * Math.Pow(ind.Weight, 0.75) / km) * Math.Exp(-0.000082 * maintenanceAge) + (0.09 * energyMetablicFromIntake);
                ind.EnergyBalance = energyMetablicFromIntake - energyMaintenance - energyMilk - energyFoetus;                 // milk will be zero for non lactating individuals.

                // Reference: Feeding_value = Ajustment for rate of loss or gain (SCA p.43, ? different from Hirata model)
                double feedingValue = 0;
                if (ind.EnergyBalance > 0)
                {
                    feedingValue = 2 * ((kg * ind.EnergyBalance) / (km * energyMaintenance) - 1);
                }
                else
                {
                    feedingValue = 2 * (ind.EnergyBalance / (0.8 * energyMaintenance) - 1);                      //(from Hirata model)
                }
                double weightToReferenceRatio = Math.Min(1.0, ind.Weight / ind.StandardReferenceWeight);

                // Reference:  MJ of Energy required per kg Empty body gain (SCA p.43)
                double energyEmptyBodyGain = ind.BreedParams.GrowthEnergyIntercept1 + feedingValue + (ind.BreedParams.GrowthEnergyIntercept1 - feedingValue) / (1 + Math.Exp(-6 * (weightToReferenceRatio - 0.4)));
                // Determine Empty body change from Eebg and Ebal, and increase by 9% for LW change
                energyPredictedBodyMassChange = 0;
                if (ind.EnergyBalance > 0)
                {
                    energyPredictedBodyMassChange = ind.BreedParams.GrowthEfficiency * kg * ind.EnergyBalance / energyEmptyBodyGain;
                }
                else
                {
                    // Reference: from Hirata model
                    energyPredictedBodyMassChange = ind.BreedParams.GrowthEfficiency * km * ind.EnergyBalance / (0.8 * energyEmptyBodyGain);
                }
            }
            energyPredictedBodyMassChange *= 30.4;              // Convert to monthly

            ind.PreviousWeight = ind.Weight;
            ind.Weight        += energyPredictedBodyMassChange;
            ind.Weight         = Math.Max(0.0, ind.Weight);
            ind.Weight         = Math.Min(ind.Weight, ind.StandardReferenceWeight * ind.BreedParams.MaximumSizeOfIndividual);

            // Function to calculate approximate methane produced by animal, based on feed intake
            // Function based on Freer spreadsheet
            methaneProduced  = 0.02 * intakeDaily * ((13 + 7.52 * energyMetabolic) + energyMetablicFromIntake / energyMaintenance * (23.7 - 3.36 * energyMetabolic)); // MJ per day
            methaneProduced /= 55.28 * 1000;                                                                                                                          // grams per day
        }
        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);
                        }
                    }
                }
            }
        }
Example #12
0
        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);
                    }
                }
            }
        }
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="status">Change status</param>
        /// <param name="female">Individual being reported</param>
        /// <param name="dateTime">Current clock</param>
        /// <param name="offspring">The offspring related to</param>
        public ConceptionStatusChangedEventArgs(ConceptionStatus status, RuminantFemale female, DateTime dateTime, Ruminant offspring = null)
        {
            Status = status;
            Female = female;

            // Calculate conception date
            switch (Status)
            {
            case ConceptionStatus.Conceived:
            case ConceptionStatus.Failed:
            case ConceptionStatus.Birth:
                ConceptionDate = dateTime.AddMonths(-1 * Convert.ToInt32(female.Age - female.AgeAtLastConception, CultureInfo.InvariantCulture));
                ConceptionDate = new DateTime(ConceptionDate.Year, ConceptionDate.Month, DateTime.DaysInMonth(ConceptionDate.Year, ConceptionDate.Month));
                break;

            case ConceptionStatus.Weaned:
                if (offspring is null)
                {
                    throw new ArgumentException("Code logice error: An offspring must be supplied in ConceptionStatusChangedEventArgs when status is Weaned");
                }
                ConceptionDate = dateTime.AddMonths(-1 * Convert.ToInt32(offspring.Age + female.BreedParams.GestationLength, CultureInfo.InvariantCulture));
                ConceptionDate = new DateTime(ConceptionDate.Year, ConceptionDate.Month, DateTime.DaysInMonth(ConceptionDate.Year, ConceptionDate.Month));
                break;

            case ConceptionStatus.Unsuccessful:
            case ConceptionStatus.NotMated:
            case ConceptionStatus.NotReady:
                ConceptionDate = dateTime;
                break;

            default:
                break;
            }
        }
        private void CalculatePotentialIntake(Ruminant ind)
        {
            // calculate daily potential intake for the selected individual/cohort
            double standardReferenceWeight = ind.StandardReferenceWeight;

            ind.NormalisedAnimalWeight = standardReferenceWeight - ((1 - ind.BreedParams.SRWBirth) * standardReferenceWeight) * Math.Exp(-(ind.BreedParams.AgeGrowthRateCoefficient * (ind.Age * 30.4)) / (Math.Pow(standardReferenceWeight, ind.BreedParams.SRWGrowthScalar)));
            double liveWeightForIntake = ind.NormalisedAnimalWeight;

            ind.HighWeight = Math.Max(ind.HighWeight, ind.Weight);
            if (ind.HighWeight < ind.NormalisedAnimalWeight)
            {
                liveWeightForIntake = ind.HighWeight;
            }

            // Calculate potential intake based on current weight compared to SRW and previous highest weight
            double potentialIntake = 0;

            // calculate milk intake shortfall for sucklings
            if (!ind.Weaned)
            {
                // potential milk intake/animal/day
                double potentialMilkIntake = ind.BreedParams.MilkIntakeIntercept + ind.BreedParams.IntakeCoefficient * ind.Weight;

                // get mother
                ind.MilkIntake = Math.Min(potentialMilkIntake, ind.MothersMilkAvailable);

                // if milk supply low, calf will subsitute forage up to a specified % of bodyweight (R_C60)
                if (ind.MilkIntake < ind.Weight * ind.BreedParams.MilkLWTFodderSubstitutionProportion)
                {
                    potentialIntake = Math.Max(0.0, ind.Weight * ind.BreedParams.MaxJuvenileIntake - ind.MilkIntake * ind.BreedParams.ProportionalDiscountDueToMilk);
                }

                // This has been removed and replaced with prop of LWT based on milk supply.
                // Reference: SCA Metabolic LWTs
                //potentialIntake = ind.BreedParams.IntakeCoefficient * standardReferenceWeight * (Math.Pow(liveWeightForIntake, 0.75) / Math.Pow(standardReferenceWeight, 0.75)) * (ind.BreedParams.IntakeIntercept - (Math.Pow(liveWeightForIntake, 0.75) / Math.Pow(standardReferenceWeight, 0.75)));
            }
            else
            {
                // Reference: SCA based actual LWTs
                potentialIntake = ind.BreedParams.IntakeCoefficient * liveWeightForIntake * (ind.BreedParams.IntakeIntercept - liveWeightForIntake / standardReferenceWeight);

                if (ind.Gender == Sex.Female)
                {
                    RuminantFemale femaleind = ind as RuminantFemale;

                    // Increase potential intake for lactating breeder
                    if (femaleind.IsLactating)
                    {
                        double dayOfLactation = Math.Max((ind.Age - femaleind.AgeAtLastBirth) * 30.4, 0);
                        if (dayOfLactation > ind.BreedParams.MilkingDays)
                        {
                            // Reference: Intake multiplier for lactating cow (M.Freer)
                            // TODO: Need to look at equation to fix Math.Pow() ^ issue
                            //					double intakeMilkMultiplier = 1 + 0.57 * Math.Pow((dayOfLactation / 81.0), 0.7) * Math.Exp(0.7 * (1 - (dayOfLactation / 81.0)));
                            double intakeMilkMultiplier = 1 + ind.BreedParams.LactatingPotentialModifierConstantA * Math.Pow((dayOfLactation / ind.BreedParams.LactatingPotentialModifierConstantB), ind.BreedParams.LactatingPotentialModifierConstantC) * Math.Exp(ind.BreedParams.LactatingPotentialModifierConstantC * (1 - (dayOfLactation / ind.BreedParams.LactatingPotentialModifierConstantB)));
                            // To make this flexible for sheep and goats, added three new Ruminant Coeffs
                            // Feeding standard values for Beef, Dairy suck, Dairy non-suck and sheep are:
                            // For 0.57 (A) use .42, .58, .85 and .69; for 0.7 (B) use 1.7, 0.7, 0.7 and 1.4, for 81 (C) use 62, 81, 81, 28
                            // added LactatingPotentialModifierConstantA, LactatingPotentialModifierConstantB and LactatingPotentialModifierConstantC
                            potentialIntake *= intakeMilkMultiplier;
                        }
                    }
                }
                //TODO: option to restrict potential further due to stress (e.g. heat, cold, rain)

                // get monthly intake
                potentialIntake *= 30.4;
            }
            ind.PotentialIntake = potentialIntake;
        }
Example #15
0
        /// <summary>
        /// Function to calculate energy from intake and subsequent growth
        /// </summary>
        /// <param name="ind">Ruminant individual class</param>
        /// <param name="methaneProduced">Sets output variable to value of methane produced</param>
        /// <returns></returns>
        private void CalculateEnergy(Ruminant ind, out double methaneProduced)
        {
            double intakeDaily = ind.MetabilicIntake / 30.4;

            // Sme 1 for females and castrates
            // TODO: castrates not implemented
            double sme = 1;

            // Sme 1.15 for all males.
            if (ind.Gender == Sex.Male)
            {
                sme = 1.15;
            }

            double energyDiet = EnergyGross * ind.DietDryMatterDigestibility / 100.0;
            // Reference: Nutrient Requirements of domesticated ruminants (p7)
            double energyMetabolic          = energyDiet * 0.81;
            double energyMetablicFromIntake = energyMetabolic * intakeDaily;

            double km = ind.BreedParams.EMaintEfficiencyCoefficient * energyMetabolic / EnergyGross + ind.BreedParams.EMaintEfficiencyIntercept;
            // Reference: SCA p.49
            double kg = ind.BreedParams.EGrowthEfficiencyCoefficient * energyMetabolic / EnergyGross + ind.BreedParams.EGrowthEfficiencyIntercept;
            double energyPredictedBodyMassChange;
            double energyMaintenance;

            if (!ind.Weaned)
            {
                // calculate engergy and growth from milk intake

                // recalculate milk intake based on mothers updated milk production for the time step
                double potentialMilkIntake = ind.BreedParams.MilkIntakeIntercept + ind.BreedParams.MilkIntakeCoefficient * ind.Weight;
                ind.MilkIntake = Math.Min(potentialMilkIntake, ind.MothersMilkProductionAvailable);
                if (ind.Mother != null)
                {
                    ind.Mother.TakeMilk(ind.MilkIntake * 30.4, MilkUseReason.Suckling);
                }

                // Below now uses actual intake received rather than assume all potential intake is eaten
                double kml = 1;
                double kgl = 1;
                if ((ind.MetabilicIntake + ind.MilkIntake) > 0)
                {
                    // average energy efficiency for maintenance
                    kml = ((ind.MilkIntake * 0.7) + (intakeDaily * km)) / (ind.MilkIntake + intakeDaily);
                    // average energy efficiency for growth
                    kgl = ((ind.MilkIntake * 0.7) + (intakeDaily * kg)) / (ind.MilkIntake + intakeDaily);
                }
                double energyMilkConsumed = ind.MilkIntake * 3.2;
                // limit calf intake of milk per day
                energyMilkConsumed = Math.Min(ind.BreedParams.MilkIntakeMaximum * 3.2, energyMilkConsumed);

                energyMaintenance = (ind.BreedParams.EMaintCoefficient * Math.Pow(ind.Weight, 0.75) / kml) * Math.Exp(-ind.BreedParams.EMaintExponent * ind.AgeZeroCorrected);
                ind.EnergyBalance = energyMilkConsumed - energyMaintenance + energyMetablicFromIntake;
                double feedingValue;
                if (ind.EnergyBalance > 0)
                {
                    feedingValue = 2 * 0.7 * ind.EnergyBalance / (kgl * energyMaintenance) - 1;
                }
                else
                {
                    //(from Hirata model)
                    feedingValue = 2 * ind.EnergyBalance / (0.85 * energyMaintenance) - 1;
                }
                double energyEmptyBodyGain = ind.BreedParams.GrowthEnergyIntercept1 + feedingValue + (ind.BreedParams.GrowthEnergyIntercept2 - feedingValue) / (1 + Math.Exp(-6 * (ind.Weight / ind.NormalisedAnimalWeight - 0.4)));

                energyPredictedBodyMassChange = ind.BreedParams.GrowthEfficiency * 0.7 * ind.EnergyBalance / energyEmptyBodyGain;
            }
            else
            {
                double energyMilk   = 0;
                double energyFoetus = 0;

                if (ind.Gender == Sex.Female)
                {
                    RuminantFemale femaleind = ind as RuminantFemale;

                    // calculate energy for lactation
                    if (femaleind.IsLactating)
                    {
                        // recalculate milk production based on DMD of food provided
                        energyMilk = CalculateMilkProduction(femaleind);
                    }
                    else
                    {
                        femaleind.MilkProductionPotential = 0;
                    }

                    // Determine energy required for foetal development
                    if (femaleind.IsPregnant)
                    {
                        double standardReferenceWeight = ind.StandardReferenceWeight;
                        // Potential birth weight
                        // Reference: Freer
                        double potentialBirthWeight = ind.BreedParams.SRWBirth * standardReferenceWeight * (1 - 0.33 * (1 - ind.Weight / standardReferenceWeight));
                        double foetusAge            = (femaleind.Age - femaleind.AgeAtLastConception) * 30.4;
                        //TODO: Check foetus gage correct
                        energyFoetus = potentialBirthWeight * 349.16 * 0.000058 * Math.Exp(345.67 - 0.000058 * foetusAge - 349.16 * Math.Exp(-0.000058 * foetusAge)) / 0.13;
                    }
                }

                //TODO: add draft individual energy requirement

                // set maintenance age to maximum of 6 years (2190 days). Now uses EnergeyMaintenanceMaximumAge
                double maintenanceAge = Math.Min(ind.Age * 30.4, ind.BreedParams.EnergyMaintenanceMaximumAge * 365);

                // Reference: SCA p.24
                // Reference p19 (1.20). Does not include MEgraze or Ecold, also skips M,
                // 0.000082 is -0.03 Age in Years/365 for days
                energyMaintenance = ind.BreedParams.Kme * sme * (ind.BreedParams.EMaintCoefficient * Math.Pow(ind.Weight, 0.75) / km) * Math.Exp(-ind.BreedParams.EMaintExponent * maintenanceAge) + (ind.BreedParams.EMaintIntercept * energyMetablicFromIntake);
                ind.EnergyBalance = energyMetablicFromIntake - energyMaintenance - energyMilk - energyFoetus; // milk will be zero for non lactating individuals.
                double feedingValue;

                // Reference: Feeding_value = Ajustment for rate of loss or gain (SCA p.43, ? different from Hirata model)
                if (ind.EnergyBalance > 0)
                {
                    feedingValue = 2 * ((kg * ind.EnergyBalance) / (km * energyMaintenance) - 1);
                }
                else
                {
                    feedingValue = 2 * (ind.EnergyBalance / (0.8 * energyMaintenance) - 1);  //(from Hirata model)
                }
                double weightToReferenceRatio = Math.Min(1.0, ind.Weight / ind.StandardReferenceWeight);

                // Reference:  MJ of Energy required per kg Empty body gain (SCA p.43)
                double energyEmptyBodyGain = ind.BreedParams.GrowthEnergyIntercept1 + feedingValue + (ind.BreedParams.GrowthEnergyIntercept1 - feedingValue) / (1 + Math.Exp(-6 * (weightToReferenceRatio - 0.4)));
                // Determine Empty body change from Eebg and Ebal, and increase by 9% for LW change
                if (ind.EnergyBalance > 0)
                {
                    energyPredictedBodyMassChange = ind.BreedParams.GrowthEfficiency * kg * ind.EnergyBalance / energyEmptyBodyGain;
                }
                else
                {
                    // Reference: from Hirata model
                    energyPredictedBodyMassChange = ind.BreedParams.GrowthEfficiency * km * ind.EnergyBalance / (0.8 * energyEmptyBodyGain);
                }
            }
            energyPredictedBodyMassChange *= 30.4;  // Convert to monthly

            ind.PreviousWeight = ind.Weight;
            if (ind.Gender == Sex.Female && (ind as RuminantFemale).BirthDue)
            {
                ind.Weight -= (ind as RuminantFemale).WeightLossDueToCalf;
            }
            ind.Weight += energyPredictedBodyMassChange;
            ind.Weight  = Math.Max(0.0, ind.Weight);
            ind.Weight  = Math.Min(ind.Weight, ind.StandardReferenceWeight * ind.BreedParams.MaximumSizeOfIndividual);

            // Function to calculate approximate methane produced by animal, based on feed intake
            // Function based on Freer spreadsheet
            // methane is  0.02 * intakeDaily * ((13 + 7.52 * energyMetabolic) + energyMetablicFromIntake / energyMaintenance * (23.7 - 3.36 * energyMetabolic)); // MJ per day
            // methane is methaneProduced / 55.28 * 1000; // grams per day

            // Charmely et al 2016 can be substituted by intercept = 0 and coefficient = 20.7
            methaneProduced = ind.BreedParams.MethaneProductionCoefficient * intakeDaily;
        }
Example #16
0
        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();
        }
Example #17
0
        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())
            {
            }
        }