예제 #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));
                }
            }
        }
예제 #2
0
        private void OnWFAnimalBuy(object sender, EventArgs e)
        {
            RuminantHerd ruminantHerd = Resources.RuminantHerd();

            Finance     Accounts    = Resources.FinanceResource() as Finance;
            FinanceType bankAccount = Accounts.GetFirst() as FinanceType;

            var newRequests = ruminantHerd.PurchaseIndividuals.Where(a => a.BreedParams.Breed == BreedName).ToList();

            foreach (var newgroup in newRequests.GroupBy(a => a.SaleFlag))
            {
                double fundsAvailable = 100000000;
                if (bankAccount != null)
                {
                    fundsAvailable = bankAccount.FundsAvailable;
                }
                double cost = 0;
                foreach (var newind in newgroup)
                {
                    double value = 0;
                    if (newgroup.Key == Common.HerdChangeReason.SirePurchase)
                    {
                        value = BreedingSirePrice;
                    }
                    else
                    {
                        RuminantValue getvalue = PriceList.Where(a => a.Age < newind.Age).OrderBy(a => a.Age).LastOrDefault();
                        value = getvalue.PurchaseValue * ((getvalue.Style == Common.PricingStyleType.perKg) ? newind.Weight : 1.0);
                    }
                    if (cost + value <= fundsAvailable)
                    {
                        ruminantHerd.AddRuminant(newind);
                        cost += value;
                    }
                    else
                    {
                        break;
                    }
                }
                if (bankAccount != null)
                {
                    bankAccount.Remove(cost, this.Name, newgroup.Key.ToString());
                }
            }
        }
예제 #3
0
        private void BuyWithTrucking()
        {
            // This activity will purchase animals based on available funds.
            RuminantHerd ruminantHerd = Resources.RuminantHerd();

            int    trucks         = 0;
            int    head           = 0;
            double aESum          = 0;
            double fundsAvailable = 0;

            if (bankAccount != null)
            {
                fundsAvailable = bankAccount.FundsAvailable;
            }
            double cost          = 0;
            double shortfall     = 0;
            bool   fundsexceeded = false;

            // get current untrucked list of animal purchases
            List <Ruminant> herd = ruminantHerd.PurchaseIndividuals.Where(a => a.BreedParams.Breed == this.PredictedHerdBreed).OrderByDescending(a => a.Weight).ToList();

            if (herd.Count() == 0)
            {
                return;
            }

            // if purchase herd > min loads before allowing trucking
            if (herd.Select(a => a.Weight / 450.0).Sum() / trucking.Number450kgPerTruck >= trucking.MinimumTrucksBeforeSelling)
            {
                // while truck to fill
                while (herd.Select(a => a.Weight / 450.0).Sum() / trucking.Number450kgPerTruck > trucking.MinimumLoadBeforeSelling)
                {
                    bool nonloaded = true;
                    trucks++;
                    double load450kgs = 0;
                    // while truck below carrying capacity load individuals
                    foreach (var ind in herd)
                    {
                        if (load450kgs + (ind.Weight / 450.0) <= trucking.Number450kgPerTruck)
                        {
                            nonloaded = false;
                            head++;
                            aESum      += ind.AdultEquivalent;
                            load450kgs += ind.Weight / 450.0;

                            if (bankAccount != null)  // perform with purchasing
                            {
                                double value = 0;
                                if (ind.SaleFlag == HerdChangeReason.SirePurchase)
                                {
                                    value = ind.BreedParams.ValueofIndividual(ind, PurchaseOrSalePricingStyleType.Purchase, RuminantFilterParameters.BreedingSire, "true");
                                }
                                else
                                {
                                    value = ind.BreedParams.ValueofIndividual(ind, PurchaseOrSalePricingStyleType.Purchase);
                                }
                                if (cost + value <= fundsAvailable && fundsexceeded == false)
                                {
                                    ind.ID = ruminantHerd.NextUniqueID;
                                    ruminantHerd.AddRuminant(ind, this);
                                    ruminantHerd.PurchaseIndividuals.Remove(ind);
                                    cost += value;
                                }
                                else
                                {
                                    fundsexceeded = true;
                                    shortfall    += value;
                                }
                            }
                            else // no financial transactions
                            {
                                ind.ID = ruminantHerd.NextUniqueID;
                                ruminantHerd.AddRuminant(ind, this);
                                ruminantHerd.PurchaseIndividuals.Remove(ind);
                            }
                        }
                    }
                    if (nonloaded)
                    {
                        Summary.WriteWarning(this, String.Format("There was a problem loading the purchase truck as purchase individuals did not meet the loading criteria for breed [r={0}]", this.PredictedHerdBreed));
                        break;
                    }
                    if (shortfall > 0)
                    {
                        break;
                    }

                    herd = ruminantHerd.PurchaseIndividuals.Where(a => a.BreedParams.Breed == this.PredictedHerdBreed).OrderByDescending(a => a.Weight).ToList();
                }

                // create trucking emissions
                if (trucking != null && trucks > 0)
                {
                    trucking.ReportEmissions(trucks, false);
                    SetStatusSuccess();
                }

                if (bankAccount != null && (trucks > 0 || trucking == null))
                {
                    ResourceRequest purchaseRequest = new ResourceRequest
                    {
                        ActivityModel      = this,
                        Required           = cost,
                        AllowTransmutation = false,
                        Reason             = this.PredictedHerdName + " purchases"
                    };
                    bankAccount.Remove(purchaseRequest);

                    // report any financial shortfall in purchases
                    if (shortfall > 0)
                    {
                        purchaseRequest.Available        = bankAccount.Amount;
                        purchaseRequest.Required         = cost + shortfall;
                        purchaseRequest.Provided         = cost;
                        purchaseRequest.ResourceType     = typeof(Finance);
                        purchaseRequest.ResourceTypeName = BankAccountName;
                        ResourceRequestEventArgs rre = new ResourceRequestEventArgs()
                        {
                            Request = purchaseRequest
                        };
                        OnShortfallOccurred(rre);
                    }

                    ResourceRequest expenseRequest = new ResourceRequest
                    {
                        Available          = bankAccount.Amount,
                        ActivityModel      = this,
                        AllowTransmutation = false
                    };

                    // calculate transport costs
                    if (trucking != null)
                    {
                        expenseRequest.Required = trucks * trucking.DistanceToMarket * trucking.CostPerKmTrucking;
                        expenseRequest.Reason   = "Transport purchases";
                        bankAccount.Remove(expenseRequest);

                        if (expenseRequest.Required > expenseRequest.Available)
                        {
                            expenseRequest.Available        = bankAccount.Amount;
                            expenseRequest.ResourceType     = typeof(Finance);
                            expenseRequest.ResourceTypeName = BankAccountName;
                            ResourceRequestEventArgs rre = new ResourceRequestEventArgs()
                            {
                                Request = expenseRequest
                            };
                            OnShortfallOccurred(rre);
                        }
                    }
                }
            }
        }
예제 #4
0
        private void BuyWithoutTrucking()
        {
            // This activity will purchase animals based on available funds.
            RuminantHerd ruminantHerd = Resources.RuminantHerd();

            // get current untrucked list of animal purchases
            List <Ruminant> herd = ruminantHerd.PurchaseIndividuals.Where(a => a.BreedParams.Breed == this.PredictedHerdBreed).ToList();

            if (herd.Count() > 0)
            {
                SetStatusSuccess();
            }

            double fundsAvailable = 0;

            if (bankAccount != null)
            {
                fundsAvailable = bankAccount.FundsAvailable;
            }
            double cost          = 0;
            double shortfall     = 0;
            bool   fundsexceeded = false;

            foreach (var newind in herd)
            {
                if (bankAccount != null)  // perform with purchasing
                {
                    double value = 0;
                    if (newind.SaleFlag == HerdChangeReason.SirePurchase)
                    {
                        value = newind.BreedParams.ValueofIndividual(newind, PurchaseOrSalePricingStyleType.Purchase, RuminantFilterParameters.BreedingSire, "true");
                    }
                    else
                    {
                        value = newind.BreedParams.ValueofIndividual(newind, PurchaseOrSalePricingStyleType.Purchase);
                    }
                    if (cost + value <= fundsAvailable && fundsexceeded == false)
                    {
                        ruminantHerd.PurchaseIndividuals.Remove(newind);
                        newind.ID = ruminantHerd.NextUniqueID;
                        ruminantHerd.AddRuminant(newind, this);
                        cost += value;
                    }
                    else
                    {
                        fundsexceeded = true;
                        shortfall    += value;
                    }
                }
                else // no financial transactions
                {
                    ruminantHerd.PurchaseIndividuals.Remove(newind);
                    newind.ID = ruminantHerd.NextUniqueID;
                    ruminantHerd.AddRuminant(newind, this);
                }
            }

            if (bankAccount != null)
            {
                ResourceRequest purchaseRequest = new ResourceRequest
                {
                    ActivityModel      = this,
                    Required           = cost,
                    AllowTransmutation = false,
                    Reason             = this.PredictedHerdName + " purchases"
                };
                bankAccount.Remove(purchaseRequest);

                // report any financial shortfall in purchases
                if (shortfall > 0)
                {
                    purchaseRequest.Available        = bankAccount.Amount;
                    purchaseRequest.Required         = cost + shortfall;
                    purchaseRequest.Provided         = cost;
                    purchaseRequest.ResourceType     = typeof(Finance);
                    purchaseRequest.ResourceTypeName = BankAccountName;
                    ResourceRequestEventArgs rre = new ResourceRequestEventArgs()
                    {
                        Request = purchaseRequest
                    };
                    OnShortfallOccurred(rre);
                }
            }
        }
        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));
                }
            }
        }
예제 #6
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())
            {
            }
        }