Example #1
0
        private void OnCLEMInitialiseActivity(object sender, EventArgs e)
        {
            this.InitialiseHerd(false, true);
            breedParams = Resources.GetResourceItem(this, typeof(RuminantHerd), this.PredictedHerdName, OnMissingResourceActionTypes.ReportErrorAndStop, OnMissingResourceActionTypes.ReportErrorAndStop) as RuminantType;

            // max sires
            if (MaximumSiresKept < 1 & MaximumSiresKept > 0)
            {
                SiresKept = Convert.ToInt32(Math.Ceiling(MaximumBreedersKept * MaximumSiresKept), CultureInfo.InvariantCulture);
            }
            else
            {
                SiresKept = Convert.ToInt32(Math.Truncate(MaximumSiresKept), CultureInfo.InvariantCulture);
            }

            if (FillBreedingMalesAtStartup)
            {
                RuminantHerd herd = Resources.RuminantHerd();
                if (herd != null)
                {
                    // get number in herd
                    int numberPresent = this.CurrentHerd(false).Where(a => a.Gender == Sex.Male).Cast <RuminantMale>().Where(a => a.BreedingSire).Count();
                    // fill to number needed
                    for (int i = numberPresent; i < SiresKept; i++)
                    {
                        RuminantMale newbull = new RuminantMale(48, Sex.Male, 450, breedParams)
                        {
                            Breed          = this.PredictedHerdBreed,
                            HerdName       = this.PredictedHerdName,
                            BreedingSire   = true,
                            ID             = herd.NextUniqueID,
                            PreviousWeight = 450,
                            SaleFlag       = HerdChangeReason.InitialHerd
                        };
                        herd.AddRuminant(newbull, this);
                    }
                }
            }

            // check GrazeFoodStoreExists
            grazeStore = "";
            if (GrazeFoodStoreName != null && !GrazeFoodStoreName.StartsWith("Not specified"))
            {
                grazeStore = GrazeFoodStoreName.Split('.').Last();
                foodStore  = Resources.GetResourceItem(this, GrazeFoodStoreName, OnMissingResourceActionTypes.ReportErrorAndStop, OnMissingResourceActionTypes.ReportErrorAndStop) as GrazeFoodStoreType;
            }

            // check for managed paddocks and warn if animals placed in yards.
            if (grazeStore == "")
            {
                var ah = Apsim.Find(this, typeof(ActivitiesHolder));
                if (Apsim.ChildrenRecursively(ah, typeof(PastureActivityManage)).Count() != 0)
                {
                    Summary.WriteWarning(this, String.Format("Animals purchased by [a={0}] are currently placed in [Not specified - general yards] while a managed pasture is available. These animals will not graze until mustered and will require feeding while in yards.\nSolution: Set the [GrazeFoodStore to place purchase in] located in the properties [General].[PastureDetails]", this.Name));
                }
            }
        }
Example #2
0
        private void OnCLEMAnimalManage(object sender, EventArgs e)
        {
            //List<Ruminant> localHerd = this.CurrentHerd();
            RuminantHerd ruminantHerd = Resources.RuminantHerd();

            // clear store of individuals to try and purchase
            //            ruminantHerd.PurchaseIndividuals.Clear();

            // remove only the individuals that are affected by this activity.
            ruminantHerd.PurchaseIndividuals.RemoveAll(a => a.Breed == this.PredictedHerdBreed);

            List <Ruminant> herd = this.CurrentHerd(true);

            //            List<Ruminant> herd = ruminantHerd.Herd.Where(a => a.HerdName == HerdName).ToList();

            // can sell off males any month as per NABSA
            // if we don't need this monthly, then it goes into next if statement with herd declaration
            // NABSA MALES - weaners, 1-2, 2-3 and 3-4 yo, we check for any male weaned and not a breeding sire.
            // check for sell age/weight of young males
            // if SellYoungFemalesLikeMales then all apply to both sexes else only males.
            if (this.TimingOK || ContinuousMaleSales)
            {
                foreach (var ind in herd.Where(a => a.Weaned & (SellFemalesLikeMales ? true : (a.Gender == Sex.Male)) & (a.Age >= MaleSellingAge || a.Weight >= MaleSellingWeight)))
                {
                    bool sell = true;
                    if (ind.GetType() == typeof(RuminantMale))
                    {
                        // don't sell breeding sires.
                        sell = !((ind as RuminantMale).BreedingSire);
                    }
                    if (sell)
                    {
                        ind.SaleFlag = HerdChangeReason.AgeWeightSale;
                    }
                }
            }

            // if management month
            if (this.TimingOK)
            {
                bool sufficientFood = true;
                if (foodStore != null)
                {
                    sufficientFood = (foodStore.TonnesPerHectare * 1000) > MinimumPastureBeforeRestock;
                }

                // check for maximum age (females and males have different cutoffs)
                foreach (var ind in herd.Where(a => a.Age >= ((a.Gender == Sex.Female) ? MaximumBreederAge : MaximumBullAge)))
                {
                    ind.SaleFlag = HerdChangeReason.MaxAgeSale;
                }

                // MALES
                // check for breeder bulls after sale of old individuals and buy/sell
                int numberMaleSiresInHerd = herd.Where(a => a.Gender == Sex.Male & a.SaleFlag == HerdChangeReason.None).Cast <RuminantMale>().Where(a => a.BreedingSire).Count();

                // Number of females
                int numberFemaleBreedingInHerd = herd.Where(a => a.Gender == Sex.Female & a.Age >= a.BreedParams.MinimumAge1stMating & a.SaleFlag == HerdChangeReason.None).Count();
                int numberFemaleTotalInHerd    = herd.Where(a => a.Gender == Sex.Female & a.SaleFlag == HerdChangeReason.None).Count();
                int numberFemaleOldInHerd      = herd.Where(a => a.Gender == Sex.Female & MaximumBreederAge - a.Age <= 12 & a.SaleFlag == HerdChangeReason.None).Count();

                if (numberMaleSiresInHerd > MaximumSiresKept)
                {
                    // sell bulls
                    // What rule? oldest first as they may be lost soonest
                    int numberToRemove = MaximumSiresKept - numberMaleSiresInHerd;
                    foreach (var male in herd.Where(a => a.Gender == Sex.Male).Cast <RuminantMale>().Where(a => a.BreedingSire).OrderByDescending(a => a.Age).Take(numberToRemove))
                    {
                        male.SaleFlag = HerdChangeReason.ExcessBullSale;
                        numberToRemove--;
                        if (numberToRemove == 0)
                        {
                            break;
                        }
                    }
                }
                else if (numberMaleSiresInHerd < MaximumSiresKept)
                {
                    if ((foodStore == null) || (sufficientFood))
                    {
                        if (AllowSireReplacement)
                        {
                            // remove young bulls from sale herd to replace breed bulls (not those sold because too old)
                            foreach (RuminantMale male in herd.Where(a => a.Gender == Sex.Male & a.SaleFlag == HerdChangeReason.AgeWeightSale).OrderByDescending(a => a.Weight))
                            {
                                male.SaleFlag     = HerdChangeReason.None;
                                male.BreedingSire = true;
                                numberMaleSiresInHerd++;
                                if (numberMaleSiresInHerd >= MaximumSiresKept)
                                {
                                    break;
                                }
                            }
                            // if still insufficent, look into current herd for replacement
                            // remaining males assumed to be too small, so await next time-step
                        }

                        // if still insufficient buy bulls.
                        if (numberMaleSiresInHerd < MaximumSiresKept && (MaximumSiresPerPurchase > 0))
                        {
                            // limit by breeders as proportion of max breeders so we don't spend alot on sires when building the herd and females more valuable
                            double propOfBreeders = (double)numberFemaleBreedingInHerd / (double)MaximumBreedersKept;

                            int sires       = Convert.ToInt32(Math.Ceiling(Math.Ceiling(MaximumSiresKept * propOfBreeders)));
                            int numberToBuy = Math.Min(MaximumSiresPerPurchase, Math.Max(0, sires - numberMaleSiresInHerd));

                            for (int i = 0; i < numberToBuy; i++)
                            {
                                RuminantMale newbull = new RuminantMale
                                {
                                    Location     = GrazeFoodStoreName,
                                    Age          = 48,
                                    Breed        = this.PredictedHerdBreed,// breedParams.Breed;
                                    HerdName     = this.PredictedHerdName,
                                    BreedingSire = true,
                                    BreedParams  = breedParams,
                                    Gender       = Sex.Male,
                                    ID           = 0, // ruminantHerd.NextUniqueID;
                                    Weight       = 450,
                                    HighWeight   = 450,
                                    SaleFlag     = HerdChangeReason.SirePurchase
                                };

                                // add to purchase request list and await purchase in Buy/Sell
                                ruminantHerd.PurchaseIndividuals.Add(newbull);
                            }
                        }
                    }
                }

                // FEMALES
                // Breeding herd traded as heifers only
                int excessHeifers = 0;

                // check for maximum number of breeders remaining after sale and buy/sell
                if (numberFemaleBreedingInHerd > MaximumBreedersKept)
                {
                    // herd mortality of 5% plus those that will be culled in next 12 months
                    excessHeifers = Convert.ToInt32((numberFemaleTotalInHerd - numberFemaleOldInHerd) * 0.05) + numberFemaleOldInHerd;
                    // shortfall + (number of young - replacement heifers)
                    excessHeifers = (numberFemaleTotalInHerd - MaximumBreedersKept) + ((numberFemaleTotalInHerd - numberFemaleBreedingInHerd) - excessHeifers);
                }
                else
                {
                    // shortfall between actual and desired numbers
                    excessHeifers = MaximumBreedersKept - numberFemaleBreedingInHerd;
                    // add future cull for age + 5%
                    excessHeifers += Convert.ToInt32((numberFemaleTotalInHerd - numberFemaleOldInHerd) * 0.05) + numberFemaleOldInHerd;
                    excessHeifers  = (numberFemaleTotalInHerd - numberFemaleBreedingInHerd) - excessHeifers;
                }

                // surplus heifers to sell
                if (excessHeifers > 0)
                {
                    foreach (var female in herd.Where(a => a.Gender == Sex.Female & a.Age < a.BreedParams.MinimumAge1stMating & a.Weaned).OrderByDescending(a => a.Age).Take(excessHeifers))
                    {
                        // tag fo sale.
                        female.SaleFlag = HerdChangeReason.ExcessHeiferSale;
                        excessHeifers--;
                        if (excessHeifers == 0)
                        {
                            break;
                        }
                    }
                }
                else if (excessHeifers < 0)
                {
                    excessHeifers *= -1;
                    if ((foodStore == null) || (sufficientFood))
                    {
                        // remove young females from sale herd to replace breeders (not those sold because too old)
                        foreach (RuminantFemale female in herd.Where(a => a.Gender == Sex.Female & a.SaleFlag == HerdChangeReason.AgeWeightSale).OrderByDescending(a => a.Age))
                        {
                            female.SaleFlag = HerdChangeReason.None;
                            excessHeifers--;
                            if (excessHeifers == 0)
                            {
                                break;
                            }
                        }

                        // if still insufficient buy heifers.
                        if (excessHeifers > 0 & (MaximumBreedersPerPurchase > 0))
                        {
                            int    ageOfHeifer    = 12;
                            double weightOfHeifer = 260;

                            // buy 5% more to account for deaths before these individuals grow to breeding age
                            int numberToBuy = Math.Min(MaximumBreedersPerPurchase, Math.Max(0, Convert.ToInt32(excessHeifers * 1.05)));

                            for (int i = 0; i < numberToBuy; i++)
                            {
                                RuminantFemale newheifer = new RuminantFemale
                                {
                                    Location    = GrazeFoodStoreName,
                                    Age         = ageOfHeifer,
                                    Breed       = this.PredictedHerdBreed,
                                    HerdName    = this.PredictedHerdName,
                                    BreedParams = breedParams,
                                    Gender      = Sex.Female,
                                    ID          = 0,
                                    Weight      = weightOfHeifer,
                                    HighWeight  = weightOfHeifer,
                                    SaleFlag    = HerdChangeReason.HeiferPurchase
                                };

                                // add to purchase request list and await purchase in Buy/Sell
                                ruminantHerd.PurchaseIndividuals.Add(newheifer);
                            }
                        }
                    }
                }

                // report that this activity was performed as it does not use base GetResourcesRequired
                //this.TriggerOnActivityPerformed();

                // Breeders themselves don't get sold. Trading is with Heifers
                // Breeders can be sold in seasonal and ENSO destocking.
                // sell breeders
                // What rule? oldest first as they may be lost soonest
                // should keep pregnant females... and young...
                // this will currently remove pregnant females and females with suckling calf

                //            int numberToRemove = Convert.ToInt32((numberFemaleInHerd-MaximumBreedersKept));
                //    foreach (var female in herd.Where(a => a.Gender == Sex.Female & a.Age >= a.BreedParams.MinimumAge1stMating).OrderByDescending(a => a.Age).Take(numberToRemove))
                //    {
                //        female.SaleFlag = HerdChangeReason.ExcessBreederSale;
                //                    numberToRemove--;
                //                    if (numberToRemove == 0) break;
                //                }
                //            }
                //else
                //{
                //}
            }
        }
        private void OnCLEMAnimalManage(object sender, EventArgs e)
        {
            // purchase details only on timer
            if (TimingOK)
            {
                // remove any old potential sales from list as these will be updated here
                Resources.RuminantHerd().PurchaseIndividuals.RemoveAll(a => a.Breed == this.PredictedHerdBreed & a.SaleFlag == HerdChangeReason.TradePurchase);

                foreach (RuminantTypeCohort purchasetype in this.Children.Where(a => a.GetType() == typeof(RuminantTypeCohort)).Cast <RuminantTypeCohort>())
                {
                    for (int i = 0; i < purchasetype.Number; i++)
                    {
                        object ruminantBase = null;
                        if (purchasetype.Gender == Sex.Male)
                        {
                            ruminantBase = new RuminantMale();
                        }
                        else
                        {
                            ruminantBase = new RuminantFemale();
                        }

                        Ruminant ruminant = ruminantBase as Ruminant;
                        ruminant.ID          = 0;
                        ruminant.BreedParams = herdToUse;
                        ruminant.Breed       = this.PredictedHerdBreed;
                        ruminant.HerdName    = this.PredictedHerdName;
                        ruminant.Gender      = purchasetype.Gender;
                        ruminant.Age         = purchasetype.Age;
                        ruminant.PurchaseAge = purchasetype.Age;
                        ruminant.SaleFlag    = HerdChangeReason.TradePurchase;
                        ruminant.Location    = "";

                        double u1            = ZoneCLEM.RandomGenerator.NextDouble();
                        double u2            = ZoneCLEM.RandomGenerator.NextDouble();
                        double randStdNormal = Math.Sqrt(-2.0 * Math.Log(u1)) *
                                               Math.Sin(2.0 * Math.PI * u2);
                        ruminant.Weight         = purchasetype.Weight + purchasetype.WeightSD * randStdNormal;
                        ruminant.PreviousWeight = ruminant.Weight;

                        switch (purchasetype.Gender)
                        {
                        case Sex.Male:
                            RuminantMale ruminantMale = ruminantBase as RuminantMale;
                            ruminantMale.BreedingSire = false;
                            break;

                        case Sex.Female:
                            RuminantFemale ruminantFemale = ruminantBase as RuminantFemale;
                            ruminantFemale.DryBreeder         = true;
                            ruminantFemale.WeightAtConception = ruminant.Weight;
                            ruminantFemale.NumberOfBirths     = 0;
                            break;

                        default:
                            break;
                        }

                        Resources.RuminantHerd().PurchaseIndividuals.Add(ruminantBase as Ruminant);
                    }
                }
                //this.TriggerOnActivityPerformed();
            }
            // sale details any timestep when conditions are met.
            foreach (Ruminant ind in this.CurrentHerd(true))
            {
                if (ind.Age - ind.PurchaseAge >= MinMonthsKept & ind.Weight >= TradeWeight)
                {
                    ind.SaleFlag = HerdChangeReason.TradeSale;
                }
            }
        }
        private void OnCLEMAnimalManage(object sender, EventArgs e)
        {
            // purchase details only on timer
            if (TimingOK)
            {
                this.Status = ActivityStatus.NotNeeded;
                // remove any old potential sales from list as these will be updated here
                Resources.RuminantHerd().PurchaseIndividuals.RemoveAll(a => a.Breed == this.PredictedHerdBreed && a.SaleFlag == HerdChangeReason.TradePurchase);

                foreach (RuminantTypeCohort purchasetype in this.Children.Where(a => a.GetType() == typeof(RuminantTypeCohort)).Cast <RuminantTypeCohort>())
                {
                    double number = purchasetype.Number;
                    if (numberToStock != null && foodStore != null)
                    {
                        //NOTE: ensure calculation method in relationship is fixed values
                        number = Convert.ToInt32(numberToStock.SolveY(foodStore.TonnesPerHectare), CultureInfo.InvariantCulture);
                    }

                    for (int i = 0; i < number; i++)
                    {
                        object ruminantBase = null;

                        double u1            = RandomNumberGenerator.Generator.NextDouble();
                        double u2            = RandomNumberGenerator.Generator.NextDouble();
                        double randStdNormal = Math.Sqrt(-2.0 * Math.Log(u1)) *
                                               Math.Sin(2.0 * Math.PI * u2);
                        double weight = purchasetype.Weight + purchasetype.WeightSD * randStdNormal;

                        if (purchasetype.Gender == Sex.Male)
                        {
                            ruminantBase = new RuminantMale(purchasetype.Age, purchasetype.Gender, weight, herdToUse);
                        }
                        else
                        {
                            ruminantBase = new RuminantFemale(purchasetype.Age, purchasetype.Gender, weight, herdToUse);
                        }

                        Ruminant ruminant = ruminantBase as Ruminant;
                        ruminant.ID             = 0;
                        ruminant.Breed          = this.PredictedHerdBreed;
                        ruminant.HerdName       = this.PredictedHerdName;
                        ruminant.PurchaseAge    = purchasetype.Age;
                        ruminant.SaleFlag       = HerdChangeReason.TradePurchase;
                        ruminant.Location       = grazeStore;
                        ruminant.PreviousWeight = ruminant.Weight;

                        switch (purchasetype.Gender)
                        {
                        case Sex.Male:
                            RuminantMale ruminantMale = ruminantBase as RuminantMale;
                            ruminantMale.BreedingSire = false;
                            break;

                        case Sex.Female:
                            RuminantFemale ruminantFemale = ruminantBase as RuminantFemale;
                            ruminantFemale.DryBreeder         = true;
                            ruminantFemale.WeightAtConception = ruminant.Weight;
                            ruminantFemale.NumberOfBirths     = 0;
                            break;

                        default:
                            break;
                        }

                        Resources.RuminantHerd().PurchaseIndividuals.Add(ruminantBase as Ruminant);
                        this.Status = ActivityStatus.Success;
                    }
                }
            }
            // sale details any timestep when conditions are met.
            foreach (Ruminant ind in this.CurrentHerd(true))
            {
                if (ind.Age - ind.PurchaseAge >= MinMonthsKept)
                {
                    ind.SaleFlag = HerdChangeReason.TradeSale;
                    this.Status  = ActivityStatus.Success;
                }
                if (TradeWeight > 0 && ind.Weight >= TradeWeight)
                {
                    ind.SaleFlag = HerdChangeReason.TradeSale;
                    this.Status  = ActivityStatus.Success;
                }
            }
        }
Example #5
0
        private void OnCLEMAnimalManage(object sender, EventArgs e)
        {
            RuminantHerd ruminantHerd = Resources.RuminantHerd();

            // remove only the individuals that are affected by this activity.
            // these are old purchases that were not made. This list will be regenerated in this method.
            ruminantHerd.PurchaseIndividuals.RemoveAll(a => a.Breed == this.PredictedHerdBreed);

            List <Ruminant> herd = this.CurrentHerd(true);

            // can sell off males any month as per NABSA
            // if we don't need this monthly, then it goes into next if statement with herd declaration
            // NABSA MALES - weaners, 1-2, 2-3 and 3-4 yo, we check for any male weaned and not a breeding sire.
            // check for sell age/weight of young males
            // if SellYoungFemalesLikeMales then all apply to both sexes else only males.
            // SellFemalesLikeMales will grow out excess heifers until age/weight rather than sell immediately.
            if (this.TimingOK || ContinuousMaleSales)
            {
                foreach (var ind in herd.Where(a => a.Weaned && (SellFemalesLikeMales ? true : (a.Gender == Sex.Male)) && (a.Age >= MaleSellingAge || a.Weight >= MaleSellingWeight)))
                {
                    bool sell = true;
                    if (ind.GetType() == typeof(RuminantMale))
                    {
                        // don't sell breeding sires.
                        sell = !((ind as RuminantMale).BreedingSire);
                    }
                    else
                    {
                        // only sell females that were marked as excess
                        sell = ind.Tags.Contains("GrowHeifer");
                    }

                    if (sell)
                    {
                        ind.SaleFlag = HerdChangeReason.AgeWeightSale;
                    }
                }
            }

            // if management month
            if (this.TimingOK)
            {
                // ensure pasture limits are ok before purchases
                bool sufficientFood = true;
                if (foodStore != null)
                {
                    sufficientFood = (foodStore.TonnesPerHectare * 1000) >= MinimumPastureBeforeRestock;
                }

                // check for maximum age (females and males have different cutoffs)
                foreach (var ind in herd.Where(a => a.Age >= ((a.Gender == Sex.Female) ? MaximumBreederAge : MaximumBullAge)))
                {
                    ind.SaleFlag = HerdChangeReason.MaxAgeSale;

                    // ensure females are not pregnant and add warning if pregnant old females found.
                    if (ind.Gender == Sex.Female && (ind as RuminantFemale).IsPregnant)
                    {
                        string warning = "Some females sold at maximum age in [a=" + this.Name + "] were pregnant.\nConsider changing the MaximumBreederAge in [a=RuminantActivityManage] or ensure [r=RuminantType.MaxAgeMating] is less than or equal to the MaximumBreederAge to avoid selling pregnant individuals.";
                        if (!Warnings.Exists(warning))
                        {
                            Warnings.Add(warning);
                            Summary.WriteWarning(this, warning);
                        }
                    }
                }

                // MALES
                // check for breeder bulls after sale of old individuals and buy/sell
                int numberMaleSiresInHerd = herd.Where(a => a.Gender == Sex.Male && a.SaleFlag == HerdChangeReason.None).Cast <RuminantMale>().Where(a => a.BreedingSire).Count();

                // Number of females
                int numberFemaleBreedingInHerd = herd.Where(a => a.Gender == Sex.Female && a.Age >= a.BreedParams.MinimumAge1stMating && a.SaleFlag == HerdChangeReason.None).Count();
                int numberFemaleTotalInHerd    = herd.Where(a => a.Gender == Sex.Female && a.SaleFlag == HerdChangeReason.None).Count();

                // these are females that will exceed max age and be sold in next 12 months
                int numberFemaleOldInHerd = herd.Where(a => a.Gender == Sex.Female && (a.Age + 12 >= MaximumBreederAge) && a.SaleFlag == HerdChangeReason.None).Count();

                // defined heifers here as weaned and will be a breeder in the next year
                int numberFemaleHeifersInHerd = herd.Where(a => a.Gender == Sex.Female && a.Weaned && ((a.Age - a.BreedParams.MinimumAge1stMating < 0) && (a.Age - a.BreedParams.MinimumAge1stMating > -12)) && a.SaleFlag == HerdChangeReason.None).Count();

                if (numberMaleSiresInHerd > SiresKept)
                {
                    // sell bulls
                    // What rule? oldest first as they may be lost soonest?
                    int numberToRemove = numberMaleSiresInHerd - SiresKept;
                    if (numberToRemove > 0)
                    {
                        foreach (var male in herd.Where(a => a.Gender == Sex.Male).Cast <RuminantMale>().Where(a => a.BreedingSire).OrderByDescending(a => a.Age).Take(numberToRemove))
                        {
                            male.SaleFlag = HerdChangeReason.ExcessBullSale;
                            numberToRemove--;
                            if (numberToRemove == 0)
                            {
                                break;
                            }
                        }
                    }
                }
                else if (numberMaleSiresInHerd < SiresKept)
                {
                    if ((foodStore == null) || (sufficientFood))
                    {
                        if (AllowSireReplacement)
                        {
                            // remove young bulls from sale herd to replace breed bulls (not those sold because too old)
                            foreach (RuminantMale male in herd.Where(a => a.Gender == Sex.Male && a.SaleFlag == HerdChangeReason.AgeWeightSale).OrderByDescending(a => a.Weight))
                            {
                                male.SaleFlag     = HerdChangeReason.None;
                                male.BreedingSire = true;
                                numberMaleSiresInHerd++;
                                if (numberMaleSiresInHerd >= SiresKept)
                                {
                                    break;
                                }
                            }
                            // if still insufficent, look into current herd for replacement
                            // remaining males assumed to be too small, so await next time-step
                        }

                        // if still insufficient buy bulls.
                        if (numberMaleSiresInHerd < SiresKept && (MaximumSiresPerPurchase > 0))
                        {
                            // limit by breeders as proportion of max breeders so we don't spend alot on sires when building the herd and females more valuable
                            double propOfBreeders = (double)numberFemaleBreedingInHerd / (double)MaximumBreedersKept;
                            propOfBreeders = 1;

                            int sires       = Convert.ToInt32(Math.Ceiling(Math.Ceiling(SiresKept * propOfBreeders)));
                            int numberToBuy = Math.Min(MaximumSiresPerPurchase, Math.Max(0, sires - numberMaleSiresInHerd));

                            for (int i = 0; i < numberToBuy; i++)
                            {
                                if (i < MaximumSiresPerPurchase)
                                {
                                    RuminantMale newbull = new RuminantMale(48, Sex.Male, 450, breedParams)
                                    {
                                        Location       = grazeStore,
                                        Breed          = this.PredictedHerdBreed,
                                        HerdName       = this.PredictedHerdName,
                                        BreedingSire   = true,
                                        Gender         = Sex.Male,
                                        ID             = 0, // Next unique ide will be assigned when added
                                        PreviousWeight = 450,
                                        SaleFlag       = HerdChangeReason.SirePurchase
                                    };

                                    // add to purchase request list and await purchase in Buy/Sell
                                    ruminantHerd.PurchaseIndividuals.Add(newbull);
                                }
                            }
                        }
                    }
                }

                // FEMALES
                // Breeding herd sold as heifers only, purchased as breeders (>= minAge1stMating)
                int excessBreeders = 0;

                // get the mortality rate for the herd if available or assume zero
                double mortalityRate = breedParams.MortalityBase;

                // shortfall between actual and desired numbers of breeders (-ve for shortfall)
                excessBreeders = numberFemaleBreedingInHerd - MaximumBreedersKept;
                // IAT-NABSA removes adjusts to account for the old animals that will be sold in the next year
                // This is not required in CLEM as they have been sold in this method, and it wont be until this method is called again that the next lot are sold.
                // Like IAT-NABSA we will account for mortality losses in the next year in our breeder purchases
                // Account for whole individuals only.
                int numberDyingInNextYear = Convert.ToInt32(Math.Floor(numberFemaleBreedingInHerd * mortalityRate), CultureInfo.InvariantCulture);
                // adjust for future mortality
                excessBreeders -= numberDyingInNextYear;

                // account for heifers already in the herd
                // These are the next cohort that will become breeders in the next 12 months (before this method is called again)
                excessBreeders += numberFemaleHeifersInHerd;

                if (excessBreeders > 0) // surplus heifers to sell
                {
                    foreach (var female in herd.Where(a => a.Gender == Sex.Female && (a as RuminantFemale).IsHeifer).Take(excessBreeders))
                    {
                        // if sell like males tag for grow out otherwise mark for sale
                        if (SellFemalesLikeMales)
                        {
                            if (!female.Tags.Contains("GrowHeifer"))
                            {
                                female.Tags.Add("GrowHeifer");
                            }
                        }
                        else
                        {
                            // tag for sale.
                            female.SaleFlag = HerdChangeReason.ExcessHeiferSale;
                        }
                        excessBreeders--;
                        if (excessBreeders == 0)
                        {
                            break;
                        }
                    }
                }
                else if (excessBreeders < 0) // shortfall heifers to buy
                {
                    double minBreedAge = breedParams.MinimumAge1stMating;
                    excessBreeders *= -1;
                    if ((foodStore == null) || (sufficientFood))
                    {
                        // remove grow out heifers from grow out herd to replace breeders
                        if (SellFemalesLikeMales)
                        {
                            foreach (Ruminant female in herd.Where(a => a.Tags.Contains("GrowHeifer")).OrderByDescending(a => a.Age))
                            {
                                female.Tags.Remove("GrowHeifer");
                                excessBreeders--;
                                if (excessBreeders == 0)
                                {
                                    break;
                                }
                            }
                        }

                        // remove young females from sale herd to replace breeders (not those sold because too old)
                        foreach (RuminantFemale female in herd.Where(a => a.Gender == Sex.Female && (a.SaleFlag == HerdChangeReason.AgeWeightSale || a.SaleFlag == HerdChangeReason.ExcessHeiferSale)).OrderByDescending(a => a.Age))
                        {
                            female.SaleFlag = HerdChangeReason.None;
                            excessBreeders--;
                            if (excessBreeders == 0)
                            {
                                break;
                            }
                        }

                        // if still insufficient buy breeders.
                        if (excessBreeders > 0 && (MaximumProportionBreedersPerPurchase > 0))
                        {
                            int ageOfBreeder = 0;

                            // IAT-NABSA had buy mortality base% more to account for deaths before these individuals grow to breeding age
                            // These individuals are already of breeding age so we will ignore this in CLEM
                            // minimum of (max kept x prop in single purchase) and (the number needed + annual mortality)
                            int numberToBuy             = Math.Min(excessBreeders, Convert.ToInt32(Math.Ceiling(MaximumProportionBreedersPerPurchase * MaximumBreedersKept), CultureInfo.InvariantCulture));
                            int numberPerPurchaseCohort = Convert.ToInt32(Math.Ceiling(numberToBuy / Convert.ToDouble(NumberOfBreederPurchaseAgeClasses, CultureInfo.InvariantCulture)), CultureInfo.InvariantCulture);

                            int numberBought = 0;
                            while (numberBought < numberToBuy)
                            {
                                int breederClass = Convert.ToInt32(numberBought / numberPerPurchaseCohort, CultureInfo.InvariantCulture);
                                ageOfBreeder = Convert.ToInt32(minBreedAge + (breederClass * 12), CultureInfo.InvariantCulture);

                                RuminantFemale newBreeder = new RuminantFemale(ageOfBreeder, Sex.Female, 0, breedParams)
                                {
                                    Location    = grazeStore,
                                    Breed       = this.PredictedHerdBreed,
                                    HerdName    = this.PredictedHerdName,
                                    BreedParams = breedParams,
                                    Gender      = Sex.Female,
                                    ID          = 0,
                                    SaleFlag    = HerdChangeReason.BreederPurchase
                                };
                                // weight will be set to normalised weight as it was assigned 0 at initialisation
                                newBreeder.PreviousWeight = newBreeder.Weight;

                                // this individual must be weaned to be permitted to start breeding.
                                newBreeder.Wean(false, "Initial");
                                // add to purchase request list and await purchase in Buy/Sell
                                ruminantHerd.PurchaseIndividuals.Add(newBreeder);
                                numberBought++;
                            }
                        }
                    }
                }
                // Breeders themselves don't get sold. Trading is with Heifers
                // Breeders can be sold in seasonal and ENSO destocking.
                // sell breeders
                // What rule? oldest first as they may be lost soonest
                // should keep pregnant females... and young...
                // this will currently remove pregnant females and females with suckling calf
            }
        }
        private void OnCLEMAnimalBreeding(object sender, EventArgs e)
        {
//            RuminantHerd ruminantHerd = Resources.RuminantHerd();
            List <Ruminant> herd = CurrentHerd(true); //ruminantHerd.Herd.Where(a => a.BreedParams.Name == HerdName).ToList();

            // get list of all individuals of breeding age and condition
            // grouped by location
            var breeders = from ind in herd
                           where
                           (ind.Gender == Sex.Male & ind.Age >= ind.BreedParams.MinimumAge1stMating) ||
                           (ind.Gender == Sex.Female &
                            ind.Age >= ind.BreedParams.MinimumAge1stMating &
                            ind.Weight >= (ind.BreedParams.MinimumSize1stMating * ind.StandardReferenceWeight)
                           )
                           group ind by ind.Location into grp
                           select grp;


            // calculate labour and finance limitations if needed when doing AI
            int breedersCount  = breeders.Count();
            int numberPossible = breedersCount;
            int numberServiced = 1;

            if (UseAI & TimingOK)
            {
                // attempt to get required resources
                List <ResourceRequest> resourcesneeded = GetResourcesNeededForActivityLocal();
                bool tookRequestedResources            = TakeResources(resourcesneeded, true);
                // get all shortfalls
                if (tookRequestedResources & (ResourceRequestList != null))
                {
                    //TODO: fix this to account for perHead payments and labour and not fixed expenses
                    double amountCashNeeded     = resourcesneeded.Where(a => a.ResourceType == typeof(Finance)).Sum(a => a.Required);
                    double amountCashProvided   = resourcesneeded.Where(a => a.ResourceType == typeof(Finance)).Sum(a => a.Provided);
                    double amountLabourNeeded   = resourcesneeded.Where(a => a.ResourceType == typeof(Labour)).Sum(a => a.Required);
                    double amountLabourProvided = resourcesneeded.Where(a => a.ResourceType == typeof(Labour)).Sum(a => a.Provided);
                    double cashlimit            = 1;
                    if (amountCashNeeded > 0)
                    {
                        if (amountCashProvided == 0)
                        {
                            cashlimit = 0;
                        }
                        else
                        {
                            cashlimit = amountCashNeeded / amountCashProvided;
                        }
                    }
                    double labourlimit = 1;
                    if (amountLabourNeeded > 0)
                    {
                        if (amountLabourProvided == 0)
                        {
                            labourlimit = 0;
                        }
                        else
                        {
                            labourlimit = amountLabourNeeded / amountLabourProvided;
                        }
                    }
                    double limiter = Math.Min(cashlimit, labourlimit);
                    numberPossible = Convert.ToInt32(limiter * breedersCount);

                    // TODO: determine if fixed payments were not possible
                    // TODO: determine limits by insufficient labour or cash for per head payments
                }
                // report that this activity was performed as it does not use base GetResourcesRequired
                this.TriggerOnActivityPerformed();
            }

            if (!UseAI)
            {
                // report that this activity was performed as it does not use base GetResourcesRequired
                this.TriggerOnActivityPerformed();
            }

            // for each location where parts of this herd are located
            foreach (var location in breeders)
            {
                // determine all foetus and newborn mortality.
                foreach (RuminantFemale female in location.Where(a => a.Gender == Sex.Female).Cast <RuminantFemale>().ToList())
                {
                    if (female.IsPregnant)
                    {
                        // calculate foetus and newborn mortality
                        // total mortality / (gestation months + 1) to get monthly mortality
                        // done here before births to account for post birth motality as well..
                        double rnd = ZoneCLEM.RandomGenerator.NextDouble();
                        if (rnd < (female.BreedParams.PrenatalMortality / (female.BreedParams.GestationLength + 1)))
                        {
                            female.OneOffspringDies();
                        }
                    }
                }

                // check for births of all pregnant females.
                foreach (RuminantFemale female in location.Where(a => a.Gender == Sex.Female).Cast <RuminantFemale>().ToList())
                {
                    if (female.BirthDue)
                    {
                        female.WeightLossDueToCalf = 0;
                        int numberOfNewborn = (female.CarryingTwins) ? 2 : 1;
                        for (int i = 0; i < numberOfNewborn; i++)
                        {
                            // Foetal mortality is now performed each timestep at base of this method
                            object newCalf = null;
                            bool   isMale  = (ZoneCLEM.RandomGenerator.NextDouble() > 0.5);
                            if (isMale)
                            {
                                newCalf = new RuminantMale();
                            }
                            else
                            {
                                newCalf = new RuminantFemale();
                            }
                            Ruminant newCalfRuminant = newCalf as Ruminant;
                            newCalfRuminant.Age         = 0;
                            newCalfRuminant.HerdName    = female.HerdName;
                            newCalfRuminant.BreedParams = female.BreedParams;
                            newCalfRuminant.Breed       = female.BreedParams.Breed;
                            newCalfRuminant.Gender      = (isMale) ? Sex.Male : Sex.Female;
                            newCalfRuminant.ID          = Resources.RuminantHerd().NextUniqueID;
                            newCalfRuminant.Location    = female.Location;
                            newCalfRuminant.Mother      = female;
                            newCalfRuminant.Number      = 1;
                            newCalfRuminant.SetUnweaned();
                            // calf weight from  Freer
                            newCalfRuminant.Weight     = female.BreedParams.SRWBirth * female.StandardReferenceWeight * (1 - 0.33 * (1 - female.Weight / female.StandardReferenceWeight));
                            newCalfRuminant.HighWeight = newCalfRuminant.Weight;
                            newCalfRuminant.SaleFlag   = HerdChangeReason.Born;
                            Resources.RuminantHerd().AddRuminant(newCalfRuminant);

                            // add to sucklings
                            female.SucklingOffspring.Add(newCalfRuminant);
                            // remove calf weight from female
                            female.WeightLossDueToCalf += newCalfRuminant.Weight;
                        }
                        female.UpdateBirthDetails();
                    }
                }
                // uncontrolled conception
                if (!UseAI)
                {
                    // check if males and females of breeding condition are together
                    if (location.GroupBy(a => a.Gender).Count() == 2)
                    {
                        // servicing rate
                        int    maleCount       = location.Where(a => a.Gender == Sex.Male).Count();
                        int    femaleCount     = location.Where(a => a.Gender == Sex.Female).Count();
                        double matingsPossible = maleCount * location.FirstOrDefault().BreedParams.MaximumMaleMatingsPerDay * 30;
                        double maleLimiter     = Math.Min(1.0, matingsPossible / femaleCount);

                        foreach (RuminantFemale female in location.Where(a => a.Gender == Sex.Female).Cast <RuminantFemale>().ToList())
                        {
                            if (!female.IsPregnant && !female.IsLactating && (female.Age - female.AgeAtLastBirth) * 30.4 >= female.BreedParams.MinimumDaysBirthToConception)
                            {
                                // calculate conception
                                double conceptionRate = ConceptionRate(female) * maleLimiter;
                                conceptionRate = Math.Min(conceptionRate, MaximumConceptionRateUncontrolled);
                                if (ZoneCLEM.RandomGenerator.NextDouble() <= conceptionRate)
                                {
                                    female.UpdateConceptionDetails(ZoneCLEM.RandomGenerator.NextDouble() < female.BreedParams.TwinRate, conceptionRate);
                                }
                            }
                        }
                    }
                }
                // controlled conception
                else
                {
                    if (this.TimingOK)
                    {
                        foreach (RuminantFemale female in location.Where(a => a.Gender == Sex.Female).Cast <RuminantFemale>().ToList())
                        {
                            if (!female.IsPregnant && !female.IsLactating && (female.Age - female.AgeAtLastBirth) * 30.4 >= female.BreedParams.MinimumDaysBirthToConception)
                            {
                                // calculate conception
                                double conceptionRate = ConceptionRate(female);
                                if (numberServiced <= numberPossible) // labour/finance limited number
                                {
                                    if (ZoneCLEM.RandomGenerator.NextDouble() <= conceptionRate)
                                    {
                                        female.UpdateConceptionDetails(ZoneCLEM.RandomGenerator.NextDouble() < female.BreedParams.TwinRate, conceptionRate);
                                    }
                                    numberServiced++;
                                }
                            }
                        }
                    }
                }
            }
        }
        private void OnCLEMAnimalBreeding(object sender, EventArgs e)
        {
            this.Status     = ActivityStatus.NotNeeded;
            NumberConceived = 0;

            // get list of all pregnant females
            List <RuminantFemale> pregnantherd = CurrentHerd(true).Where(a => a.Gender == Sex.Female).Cast <RuminantFemale>().Where(a => a.IsPregnant).ToList();

            // determine all fetus and newborn mortality of all pregnant females.
            foreach (RuminantFemale female in pregnantherd)
            {
                // calculate fetus and newborn mortality
                // total mortality / (gestation months + 1) to get monthly mortality
                // done here before births to account for post birth motality as well..
                // IsPregnant status does not change until births occur in next section so will include mortality in month of birth
                // needs to be calculated for each offspring carried.
                for (int i = 0; i < female.CarryingCount; i++)
                {
                    if (RandomNumberGenerator.Generator.NextDouble() < (female.BreedParams.PrenatalMortality / (female.BreedParams.GestationLength + 1)))
                    {
                        female.OneOffspringDies();
                        if (female.NumberOfOffspring == 0)
                        {
                            // report conception status changed when last multiple birth dies.
                            female.BreedParams.OnConceptionStatusChanged(new Reporting.ConceptionStatusChangedEventArgs(Reporting.ConceptionStatus.Failed, female, Clock.Today));
                        }
                    }
                }

                if (female.BirthDue)
                {
                    int numberOfNewborn = female.CarryingCount;
                    for (int i = 0; i < numberOfNewborn; i++)
                    {
                        object newCalf = null;
                        bool   isMale  = (RandomNumberGenerator.Generator.NextDouble() <= female.BreedParams.ProportionOffspringMale);
                        double weight  = female.BreedParams.SRWBirth * female.StandardReferenceWeight * (1 - 0.33 * (1 - female.Weight / female.StandardReferenceWeight));
                        if (isMale)
                        {
                            newCalf = new RuminantMale(0, Sex.Male, weight, female.BreedParams);
                        }
                        else
                        {
                            newCalf = new RuminantFemale(0, Sex.Female, weight, female.BreedParams);
                        }
                        Ruminant newCalfRuminant = newCalf as Ruminant;
                        newCalfRuminant.HerdName = female.HerdName;
                        newCalfRuminant.Breed    = female.BreedParams.Breed;
                        newCalfRuminant.ID       = Resources.RuminantHerd().NextUniqueID;
                        newCalfRuminant.Location = female.Location;
                        newCalfRuminant.Mother   = female;
                        newCalfRuminant.Number   = 1;
                        newCalfRuminant.SetUnweaned();
                        // calf weight from  Freer
                        newCalfRuminant.PreviousWeight = newCalfRuminant.Weight;
                        newCalfRuminant.SaleFlag       = HerdChangeReason.Born;

                        // add attributes inherited from mother
                        foreach (var attribute in female.Attributes)
                        {
                            newCalfRuminant.AddAttribute(attribute.Key, attribute.Value.GetInheritedAttribute() as ICLEMAttribute);
                        }

                        Resources.RuminantHerd().AddRuminant(newCalfRuminant, this);

                        // add to sucklings
                        female.SucklingOffspringList.Add(newCalfRuminant);
                        // this now reports for each individual born not a birth event as individual wean events are reported
                        female.BreedParams.OnConceptionStatusChanged(new Reporting.ConceptionStatusChangedEventArgs(Reporting.ConceptionStatus.Birth, female, Clock.Today));
                    }
                    female.UpdateBirthDetails();
                    this.Status = ActivityStatus.Success;
                }
            }

            // Perform breeding
            IEnumerable <Ruminant> herd = null;

            if (useControlledMating && controlledMating.TimingOK)
            {
                // determined by controlled mating and subsequent timer (e.g. smart milking)
                herd = controlledMating.BreedersToMate();
                this.TriggerOnActivityPerformed();
            }
            else if (!useControlledMating && TimingOK)
            {
                // whole herd for activity
                herd = CurrentHerd(true);
                // report that this activity was performed as it does not use base GetResourcesRequired
                this.TriggerOnActivityPerformed();
            }

            if (herd != null && herd.Count() > 0)
            {
                // group by location
                var breeders = from ind in herd
                               where ind.IsAbleToBreed
                               group ind by ind.Location into grp
                               select grp;

                int             breedersCount  = breeders.Count();
                int             numberPossible = breedersCount;
                int             numberServiced = 1;
                List <Ruminant> maleBreeders   = new List <Ruminant>();

                // for each location where parts of this herd are located
                foreach (var location in breeders)
                {
                    numberPossible = -1;
                    if (useControlledMating)
                    {
                        numberPossible = Convert.ToInt32(location.Where(a => a.Gender == Sex.Female).Count(), CultureInfo.InvariantCulture);
                    }
                    else
                    {
                        numberPossible = 0;
                        // uncontrolled conception
                        if (location.GroupBy(a => a.Gender).Count() == 2)
                        {
                            int maleCount = location.Where(a => a.Gender == Sex.Male).Count();
                            // get a list of males to provide attributes when incontrolled mating.
                            if (maleCount > 0 && location.FirstOrDefault().BreedParams.IncludedAttributeInheritanceWhenMating)
                            {
                                maleBreeders = location.Where(a => a.Gender == Sex.Male).ToList();
                            }
                            int femaleCount = location.Where(a => a.Gender == Sex.Female).Count();
                            numberPossible = Convert.ToInt32(Math.Ceiling(maleCount * location.FirstOrDefault().BreedParams.MaximumMaleMatingsPerDay * 30), CultureInfo.InvariantCulture);
                        }
                    }

                    numberServiced = 1;
                    foreach (RuminantFemale female in location.Where(a => a.Gender == Sex.Female).Cast <RuminantFemale>().Where(a => !a.IsPregnant & a.Age <= a.BreedParams.MaximumAgeMating).ToList())
                    {
                        Reporting.ConceptionStatus status = Reporting.ConceptionStatus.NotMated;
                        if (numberServiced <= numberPossible)
                        {
                            // calculate conception
                            double conceptionRate = ConceptionRate(female, out status);
                            if (conceptionRate > 0)
                            {
                                if (RandomNumberGenerator.Generator.NextDouble() <= conceptionRate)
                                {
                                    female.UpdateConceptionDetails(female.CalulateNumberOfOffspringThisPregnancy(), conceptionRate, 0);

                                    // if mandatory attributes are present in the herd, save male value with female details.
                                    if (female.BreedParams.IncludedAttributeInheritanceWhenMating)
                                    {
                                        if (useControlledMating)
                                        {
                                            // save all male attributes
                                            AddMalesAttributeDetails(female, controlledMating.SireAttributes);
                                        }
                                        else
                                        {
                                            // randomly select male
                                            AddMalesAttributeDetails(female, maleBreeders[RandomNumberGenerator.Generator.Next(0, maleBreeders.Count() - 1)]);
                                        }
                                    }
                                    status = Reporting.ConceptionStatus.Conceived;
                                    NumberConceived++;
                                }
                            }
                            numberServiced++;
                            this.Status = ActivityStatus.Success;
                        }

                        // report change in breeding status
                        // do not report for -1 (controlled mating outside timing)
                        if (numberPossible >= 0 && status != Reporting.ConceptionStatus.NotAvailable)
                        {
                            female.BreedParams.OnConceptionStatusChanged(new Reporting.ConceptionStatusChangedEventArgs(status, female, Clock.Today));
                        }
                    }

                    // report a natural mating locations for transparency via a message
                    if (numberServiced > 0 & !useControlledMating)
                    {
                        string warning = "Natural (uncontrolled) mating ocurred in [r=" + location.Key + "]";
                        if (!Warnings.Exists(warning))
                        {
                            Warnings.Add(warning);
                            Summary.WriteMessage(this, warning);
                        }
                    }
                }
            }
        }
Example #8
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);
                    }
                }
            }
        }
        private void OnCLEMInitialiseActivity(object sender, EventArgs e)
        {
            // create local version of max breeders so we can modify without affecting user set value
            maxBreeders = Math.Max(this.MaximumBreedersKept, this.MinimumBreedersKept);

            this.InitialiseHerd(false, true);
            breedParams = Resources.GetResourceItem(this, typeof(RuminantHerd), this.PredictedHerdName, OnMissingResourceActionTypes.ReportErrorAndStop, OnMissingResourceActionTypes.ReportErrorAndStop) as RuminantType;

            decimal breederHerdSize = 0;

            if (AdjustBreedingFemalesAtStartup)
            {
                RuminantHerd    herd    = Resources.RuminantHerd();
                List <Ruminant> rumHerd = this.CurrentHerd(false);
                if (rumHerd != null && rumHerd.Count() > 0)
                {
                    int                    numberAdded = 0;
                    RuminantType           breedParams = rumHerd.FirstOrDefault().BreedParams;
                    RuminantInitialCohorts cohorts     = Apsim.Children(rumHerd.FirstOrDefault().BreedParams, typeof(RuminantInitialCohorts)).FirstOrDefault() as RuminantInitialCohorts;

                    if (cohorts != null)
                    {
                        List <RuminantTypeCohort> cohortList = Apsim.Children(cohorts, typeof(RuminantTypeCohort)).Cast <RuminantTypeCohort>().Where(a => a.Gender == Sex.Female && (a.Age >= breedParams.MinimumAge1stMating & a.Age <= this.MaximumBreederAge)).ToList();
                        int initialBreeders = Convert.ToInt32(cohortList.Sum(a => a.Number));
                        if (initialBreeders < this.MinimumBreedersKept)
                        {
                            double scaleFactor = this.MinimumBreedersKept / Convert.ToDouble(initialBreeders);
                            // add new individuals
                            foreach (var item in cohortList)
                            {
                                int numberToAdd = Convert.ToInt32(Math.Round(item.Number * scaleFactor) - item.Number);
                                foreach (var newind in item.CreateIndividuals(numberToAdd))
                                {
                                    newind.SaleFlag = HerdChangeReason.FillInitialHerd;
                                    herd.AddRuminant(newind, this);
                                    numberAdded++;
                                }
                            }
                            if (numberAdded == 0)
                            {
                                throw new ApsimXException(this, $"Unable to scale breeding female population up to the maximum breeders kept at startup\nNo cohorts representing breeders were found in the initial herd structure [r=InitialCohorts] for [r={breedParams.Name}]\nAdd at least one initial cohort that meets the breeder criteria of age at first mating and max age kept");
                            }
                            breederHerdSize = initialBreeders + numberAdded;
                        }
                        else if (initialBreeders > maxBreeders)
                        {
                            int reduceBy = Math.Max(0, initialBreeders - maxBreeders);
                            // reduce initial herd size
                            // randomly select the individuals to remove form the breeder herd
                            List <Ruminant> breeders = rumHerd.Where(a => a.Gender == Sex.Female && a.Age > breedParams.MinimumAge1stMating && a.Age < this.MaximumBreederAge).OrderBy(x => Guid.NewGuid()).Take(reduceBy).ToList();
                            foreach (var item in breeders)
                            {
                                item.SaleFlag = HerdChangeReason.ReduceInitialHerd;
                                herd.RemoveRuminant(item, this);
                                reduceBy--;
                            }

                            if (reduceBy > 0)
                            {
                                // add warning
                                string warn = $"Unable to reduce breeders at the start of the simulation to number required [{maxBreeders}] using [a={this.Name}]";
                                if (!Warnings.Exists(warn))
                                {
                                    Summary.WriteWarning(this, warn);
                                    Warnings.Add(warn);
                                }
                            }
                            breederHerdSize = maxBreeders;
                        }
                    }
                    else
                    {
                        throw new ApsimXException(this, $"Unable to adjust breeding female population to the maximum breeders kept at startup\nNo initial herd structure [r=InitialCohorts] has been provided in [r={breedParams.Name}]");
                    }
                }
            }

            // max sires
            if (MaximumSiresKept < 1 & MaximumSiresKept > 0)
            {
                SiresKept = Convert.ToInt32(Math.Ceiling(maxBreeders * breederHerdSize), CultureInfo.InvariantCulture);
            }
            else
            {
                SiresKept = Convert.ToInt32(Math.Truncate(MaximumSiresKept), CultureInfo.InvariantCulture);
            }

            if (AdjustBreedingMalesAtStartup)
            {
                RuminantHerd herd = Resources.RuminantHerd();
                if (herd != null)
                {
                    // get number in herd
                    List <Ruminant> rumHerd       = this.CurrentHerd(false);
                    int             numberPresent = rumHerd.Where(a => a.Gender == Sex.Male).Cast <RuminantMale>().Where(a => a.BreedingSire).Count();
                    if (numberPresent < SiresKept)
                    {
                        // fill to number needed
                        for (int i = numberPresent; i < SiresKept; i++)
                        {
                            RuminantMale newSire = new RuminantMale(SireAgeAtPurchase, Sex.Male, 0, breedParams)
                            {
                                Breed        = this.PredictedHerdBreed,
                                HerdName     = this.PredictedHerdName,
                                BreedingSire = true,
                                ID           = herd.NextUniqueID,
                                SaleFlag     = HerdChangeReason.FillInitialHerd
                            };
                            herd.AddRuminant(newSire, this);
                        }
                    }
                    else if (numberPresent > SiresKept)
                    {
                        // reduce initial herd.
                        int reduceBy = Math.Max(0, numberPresent - SiresKept);
                        // reduce initial sire herd size
                        // randomly select the individuals to remove form the breeder herd
                        List <RuminantMale> sires = rumHerd.Where(a => a.Gender == Sex.Male).Cast <RuminantMale>().Where(a => a.BreedingSire).OrderBy(x => Guid.NewGuid()).Take(reduceBy).ToList();
                        foreach (var item in sires)
                        {
                            item.SaleFlag = HerdChangeReason.ReduceInitialHerd;
                            herd.RemoveRuminant(item, this);
                            reduceBy--;
                        }

                        if (reduceBy > 0)
                        {
                            // add warning
                            string warn = $"Unable to reduce breeding sires at the start of the simulation to number required [{SiresKept}] using [a={this.Name}]";
                            if (!Warnings.Exists(warn))
                            {
                                Summary.WriteWarning(this, warn);
                                Warnings.Add(warn);
                            }
                        }
                    }
                }
            }

            // check GrazeFoodStoreExists for breeders
            grazeStoreBreeders = "";
            if (GrazeFoodStoreNameBreeders != null && !GrazeFoodStoreNameBreeders.StartsWith("Not specified"))
            {
                grazeStoreBreeders = GrazeFoodStoreNameBreeders.Split('.').Last();
                foodStoreBreeders  = Resources.GetResourceItem(this, GrazeFoodStoreNameBreeders, OnMissingResourceActionTypes.ReportErrorAndStop, OnMissingResourceActionTypes.ReportErrorAndStop) as GrazeFoodStoreType;
            }

            // check for managed paddocks and warn if breeders placed in yards.
            if (grazeStoreBreeders == "" && this.MaximumProportionBreedersPerPurchase > 0)
            {
                var ah = Apsim.Find(this, typeof(ActivitiesHolder));
                if (Apsim.ChildrenRecursively(ah, typeof(PastureActivityManage)).Count() != 0)
                {
                    Summary.WriteWarning(this, String.Format("Breeders purchased by [a={0}] are currently placed in [Not specified - general yards] while a managed pasture is available. These animals will not graze until mustered and will require feeding while in yards.\nSolution: Set the [GrazeFoodStore to place purchase in] located in the properties [General].[PastureDetails]", this.Name));
                }
            }

            // check GrazeFoodStoreExists for sires
            grazeStoreSires = "";
            if (GrazeFoodStoreNameSires != null && !GrazeFoodStoreNameSires.StartsWith("Not specified"))
            {
                grazeStoreSires = GrazeFoodStoreNameSires.Split('.').Last();
                foodStoreSires  = Resources.GetResourceItem(this, GrazeFoodStoreNameSires, OnMissingResourceActionTypes.ReportErrorAndStop, OnMissingResourceActionTypes.ReportErrorAndStop) as GrazeFoodStoreType;
            }

            // check for managed paddocks and warn if sires placed in yards.
            if (grazeStoreBreeders == "" && this.SiresKept > 0)
            {
                var ah = Apsim.Find(this, typeof(ActivitiesHolder));
                if (Apsim.ChildrenRecursively(ah, typeof(PastureActivityManage)).Count() != 0)
                {
                    Summary.WriteWarning(this, String.Format("Sires purchased by [a={0}] are currently placed in [Not specified - general yards] while a managed pasture is available. These animals will not graze until mustered and will require feeding while in yards.\nSolution: Set the [GrazeFoodStore to place purchase in] located in the properties [General].[PastureDetails]", this.Name));
                }
            }
        }
        private void OnWFAnimalManage(object sender, EventArgs e)
        {
            RuminantHerd    ruminantHerd = Resources.RuminantHerd();
            List <Ruminant> herd         = ruminantHerd.Herd.Where(a => a.HerdName == HerdName).ToList();

            RuminantType breedParams;

            // get breedParams when no herd remaining
            if (herd.Count() == 0)
            {
                bool resourceAvailable = false;
                breedParams = Resources.GetResourceItem("Ruminants", HerdName, out resourceAvailable) as RuminantType;
            }
            else
            {
                breedParams = herd.FirstOrDefault().BreedParams;
            }

            // can sell off males any month as per NABSA
            // if we don't need this monthly, then it goes into next if statement with herd declaration
            // NABSA MALES - weaners, 1-2, 2-3 and 3-4 yo, we check for any male weaned and not a breeding sire.
            // check for sell age/weight of young males
            // if SellYoungFemalesLikeMales then all apply to both sexes else only males.
            foreach (var ind in herd.Where(a => a.Weaned & (SellFemalesLikeMales ? true : (a.Gender == Sex.Male)) & (a.Age >= SellingAge ^ a.Weight >= SellingWeight)))
            {
                bool sell = true;
                if (ind.GetType() == typeof(RuminantMale))
                {
                    // don't sell breeding sires.
                    sell = !((ind as RuminantMale).BreedingSire);
                }
                if (sell)
                {
                    ind.SaleFlag = Common.HerdChangeReason.AgeWeightSale;
                }
            }

            // if management month
            if (Clock.Today.Month == ManagementMonth ^ MonthlyManagement)
            {
                // Perform weaning
                foreach (var ind in herd.Where(a => a.Weaned == false))
                {
                    if (ind.Age >= WeaningAge ^ ind.Weight >= WeaningWeight)
                    {
                        ind.Wean();
                    }
                }

                // check for maximum age (females and males have different cutoffs)
                foreach (var ind in herd.Where(a => a.Age >= ((a.Gender == Sex.Female) ? MaximumBreederAge : MaximumBullAge)))
                {
                    ind.SaleFlag = Common.HerdChangeReason.MaxAgeSale;
                }

                // MALES
                // check for breeder bulls after sale of old individuals and buy/sell
                int numberinherd = herd.Where(a => a.Gender == Sex.Male & a.SaleFlag == Common.HerdChangeReason.None).Cast <RuminantMale>().Where(a => a.BreedingSire).Count();

                if (numberinherd > MaximumSiresKept)
                {
                    // sell bulls
                    // What rule? oldest first as they may be lost soonest
                    int numberToRemove = MaximumSiresKept - numberinherd;
                    foreach (var male in herd.Where(a => a.Gender == Sex.Male).Cast <RuminantMale>().Where(a => a.BreedingSire).OrderByDescending(a => a.Age).Take(numberToRemove))
                    {
                        male.SaleFlag = Common.HerdChangeReason.ExcessBullSale;
                    }
                }
                else if (numberinherd < MaximumSiresKept)
                {
                    // remove young bulls from sale herd to replace breed bulls (not those sold because too old)
                    foreach (RuminantMale male in herd.Where(a => a.Gender == Sex.Male & a.SaleFlag == Common.HerdChangeReason.AgeWeightSale).OrderByDescending(a => a.Weight))
                    {
                        male.SaleFlag     = Common.HerdChangeReason.None;
                        male.BreedingSire = true;
                        numberinherd++;
                        if (numberinherd >= MaximumSiresKept)
                        {
                            break;
                        }
                    }

                    // if still insufficient buy bulls.
                    if (numberinherd < MaximumSiresKept)
                    {
                        int numberToBuy = Convert.ToInt32((MaximumSiresKept - numberinherd) * 0.05);

                        for (int i = 0; i < numberToBuy; i++)
                        {
                            RuminantMale newbull = new RuminantMale();
                            newbull.Age          = 48;
                            newbull.HerdName     = HerdName;
                            newbull.BreedingSire = true;
                            newbull.BreedParams  = breedParams;
                            newbull.Gender       = Sex.Male;
                            newbull.ID           = ruminantHerd.NextUniqueID;
                            newbull.Weight       = 450;
                            newbull.HighWeight   = newbull.Weight;
                            newbull.SaleFlag     = Common.HerdChangeReason.SirePurchase;

                            // add to purchase request list and await purchase in Buy/ Sell
                            ruminantHerd.PurchaseIndividuals.Add(newbull);
                        }
                    }
                }

                // FEMALES
                // check for maximum number of breeders remaining after sale and buy/sell
                numberinherd = herd.Where(a => a.Gender == Sex.Female & a.Age >= a.BreedParams.MinimumAge1stMating & a.SaleFlag == Common.HerdChangeReason.None).Count();

                if (numberinherd > MaximumBreedersKept)
                {
                    // sell breeders
                    // What rule? oldest first as they may be lost soonest
                    // should keep pregnant females... and young...
                    // this will currently remove pregnant females and females with suckling calf
                    int numberToRemove = MaximumBreedersKept - numberinherd;
                    foreach (var female in herd.Where(a => a.Gender == Sex.Female & a.Age >= a.BreedParams.MinimumAge1stMating).OrderByDescending(a => a.Age).Take(numberToRemove))
                    {
                        female.SaleFlag = Common.HerdChangeReason.ExcessBreederSale;
                    }
                }
                else
                {
                    // remove young females from sale herd to replace breeders (not those sold because too old)
                    foreach (RuminantFemale female in herd.Where(a => a.Gender == Sex.Female & a.SaleFlag == Common.HerdChangeReason.AgeWeightSale).OrderByDescending(a => a.Weight))
                    {
                        female.SaleFlag = Common.HerdChangeReason.None;
                        numberinherd++;
                        if (numberinherd >= MaximumBreedersKept)
                        {
                            break;
                        }
                    }

                    // if still insufficient buy breeders.
                    if (numberinherd < MaximumBreedersKept)
                    {
                        int    ageOfHeifer    = 12;
                        double weightOfHeifer = 260;

                        int numberToBuy = Convert.ToInt32((MaximumBreedersKept - numberinherd) * 0.05);

                        for (int i = 0; i < numberToBuy; i++)
                        {
                            RuminantFemale newheifer = new RuminantFemale();
                            newheifer.Age         = ageOfHeifer;
                            newheifer.HerdName    = HerdName;
                            newheifer.BreedParams = breedParams;
                            newheifer.Gender      = Sex.Female;
                            newheifer.ID          = ruminantHerd.NextUniqueID;
                            newheifer.Weight      = weightOfHeifer;
                            newheifer.HighWeight  = newheifer.Weight;
                            newheifer.SaleFlag    = Common.HerdChangeReason.HeiferPurchase;

                            // add to purchase request list and await purchase in Buy/ Sell
                            ruminantHerd.PurchaseIndividuals.Add(newheifer);
                        }
                    }
                }
            }
        }
Example #11
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())
            {
            }
        }