private void OnCLEMAnimalManage(object sender, EventArgs e)
        {
            // if management month
            if (this.TimingOK)
            {
                double          labourlimit = this.LabourLimitProportion;
                int             weanedCount = 0;
                ResourceRequest labour      = ResourceRequestList.Where(a => a.ResourceType == typeof(LabourType)).FirstOrDefault <ResourceRequest>();
                // Perform weaning
                int count = this.CurrentHerd(true).Where(a => a.Weaned == false).Count();
                foreach (var ind in this.CurrentHerd(true).Where(a => a.Weaned == false))
                {
                    if (ind.Age >= WeaningAge || ind.Weight >= WeaningWeight)
                    {
                        string reason = (ind.Age >= WeaningAge)? "Age" : "Weight";
                        ind.Wean(true, reason);
                        ind.Location = grazeStore;
                        weanedCount++;
                        Status = ActivityStatus.Success;
                    }

                    // stop if labour limited individuals reached and LabourShortfallAffectsActivity
                    if (weanedCount > Convert.ToInt32(count * labourlimit))
                    {
                        break;
                    }
                }
            }
        }
        private void OnCLEMCollectManure(object sender, EventArgs e)
        {
            Status = ActivityStatus.Critical;
            // is manure in resources
            if (manureStore != null)
            {
                if (this.TimingOK)
                {
                    List <ResourceRequest> resourcesneeded = GetResourcesNeededForActivityLocal();
                    bool tookRequestedResources            = TakeResources(resourcesneeded, true);
                    // get all shortfalls
                    double labourNeeded = 0;
                    double labourLimit  = 1;
                    if (tookRequestedResources & (ResourceRequestList != null))
                    {
                        labourNeeded = ResourceRequestList.Where(a => a.ResourceType == typeof(Labour)).Sum(a => a.Required);
                        double labourProvided = ResourceRequestList.Where(a => a.ResourceType == typeof(Labour)).Sum(a => a.Provided);
                        labourLimit = labourProvided / labourNeeded;
                    }

                    if (labourLimit == 1 || this.OnPartialResourcesAvailableAction == OnPartialResourcesAvailableActionTypes.UseResourcesAvailable)
                    {
                        foreach (ManureStoreUncollected msu in manureStore.UncollectedStores)
                        {
                            manureStore.Collect(msu.Name, labourLimit, this.Name);
                            SetStatusSuccess();
                        }
                    }
                }
            }
        }
Beispiel #3
0
        /// <summary>
        /// The method allows the activity to adjust resources requested based on shortfalls (e.g. labour) before they are taken from the pools
        /// </summary>
        public override void AdjustResourcesNeededForActivity()
        {
            // adjust amount needed by labour shortfall.
            double labprop = this.LabourLimitProportion;

            // get additional reduction based on labour cost shortfall as cost has already been accounted for
            double priceprop = 1;

            if (labprop < 1)
            {
                if (unitsCanAfford < units)
                {
                    priceprop = unitsCanAfford / units;
                }
                if (labprop < priceprop)
                {
                    unitsCanAfford = units * labprop;
                    if (price.UseWholePackets)
                    {
                        unitsCanAfford = Math.Truncate(unitsCanAfford);
                    }
                }
            }

            if (unitsCanAfford > 0 & (resourceToBuy as CLEMResourceTypeBase).MarketStoreExists)
            {
                // find resource entry in market if present and reduce
                ResourceRequest rr = ResourceRequestList.Where(a => a.Resource == (resourceToBuy as CLEMResourceTypeBase).EquivalentMarketStore).FirstOrDefault();
                if (rr.Required != unitsCanAfford * price.PacketSize * this.FarmMultiplier)
                {
                    rr.Required = unitsCanAfford * price.PacketSize * this.FarmMultiplier;
                }
            }
            return;
        }
Beispiel #4
0
        /// <summary>
        /// Method to provide the proportional limit based on specified resource type
        /// A proportion less than 1 will only be returned if LabourShortfallAffectsActivity is true in the LabourRequirement
        /// </summary>
        /// <returns></returns>
        public double LimitProportion(Type resourceType)
        {
            double proportion = 1.0;

            if (ResourceRequestList == null)
            {
                return(proportion);
            }

            double totalNeeded = ResourceRequestList.Where(a => a.ResourceType == resourceType).Sum(a => a.Required);

            foreach (ResourceRequest item in ResourceRequestList.Where(a => a.ResourceType == resourceType).ToList())
            {
                if (resourceType == typeof(LabourType))
                {
                    if (item.FilterDetails != null && ((item.FilterDetails.First() as LabourFilterGroup).Parent as LabourRequirement).LabourShortfallAffectsActivity)
                    {
                        proportion *= item.Provided / item.Required;
                    }
                }
                else // all other types
                {
                    proportion *= item.Provided / item.Required;
                }
            }
            return(proportion);
        }
Beispiel #5
0
        private void OnCLEMAnimalMilking(object sender, EventArgs e)
        {
            if (this.TimingOK & this.Status != ActivityStatus.Ignored)
            {
                if (ProportionToRemove > 0)
                {
                    // get labour shortfall
                    double labourLimiter = 1.0;
                    if (this.Status == ActivityStatus.Partial & this.OnPartialResourcesAvailableAction == OnPartialResourcesAvailableActionTypes.UseResourcesAvailable)
                    {
                        double labourLimit    = 1;
                        double labourNeeded   = ResourceRequestList.Where(a => a.ResourceType == typeof(Labour)).Sum(a => a.Required);
                        double labourProvided = ResourceRequestList.Where(a => a.ResourceType == typeof(Labour)).Sum(a => a.Provided);
                        if (labourNeeded > 0)
                        {
                            labourLimit = labourProvided / labourNeeded;
                        }
                    }

                    // get dry breeders
                    RuminantHerd          ruminantHerd = Resources.RuminantHerd();
                    List <RuminantFemale> herd         = this.CurrentHerd(true).Where(a => a.Gender == Sex.Female).Cast <RuminantFemale>().ToList();

                    // get dry breeders from females
                    foreach (RuminantFemale female in herd.Where(a => a.Age - a.AgeAtLastBirth >= MonthsSinceBirth & a.PreviousConceptionRate >= MinimumConceptionBeforeSell & a.AgeAtLastBirth > 0))
                    {
                        if (ZoneCLEM.RandomGenerator.NextDouble() <= ProportionToRemove * labourLimiter)
                        {
                            // flag female ready to transport.
                            female.SaleFlag = HerdChangeReason.DryBreederSale;
                        }
                    }
                }
            }
        }
Beispiel #6
0
        /// <inheritdoc/>
        public override void DoActivity()
        {
            if (PaymentCalculationStyle == PayHiredLabourCalculationStyle.ByAvailableLabour)
            {
                Status = ActivityStatus.Warning;

                // get amount of finance needed and provided
                double financeRequired = 0;
                double financeProvided = 0;
                foreach (ResourceRequest item in ResourceRequestList.Where(a => a.ResourceType == typeof(Finance)))
                {
                    financeRequired += item.Required;
                    financeProvided += item.Provided;
                    Status           = ActivityStatus.NotNeeded;
                }

                if (financeRequired > 0)
                {
                    Status = ActivityStatus.Success;
                }

                // reduce limiters based on financial shortfall
                if (financeProvided < financeRequired)
                {
                    if (this.OnPartialResourcesAvailableAction == OnPartialResourcesAvailableActionTypes.UseResourcesAvailable)
                    {
                        Status = ActivityStatus.Partial;
                        int    currentmonth = clock.Today.Month;
                        double currentCost  = 0;

                        // step through all hired labour in order and set limiter where needed
                        foreach (LabourType item in labour.Items.Where(a => a.Hired))
                        {
                            // get days needed
                            double daysNeeded = item.LabourAvailability.GetAvailability(currentmonth - 1);
                            // calculate rate and amount needed
                            double rate = item.PayRate();

                            double cost = daysNeeded * rate;

                            if (currentCost == financeProvided)
                            {
                                item.AvailabilityLimiter = 0;
                                cost = 0;
                            }
                            else if (currentCost + cost > financeProvided)
                            {
                                //  reduce limit
                                double excess = currentCost + cost - financeProvided;
                                item.AvailabilityLimiter = (cost - excess) / cost;
                                cost = financeProvided - currentCost;
                            }
                            currentCost += cost;
                        }
                    }
                }
            }
            return;
        }
Beispiel #7
0
        /// <summary>
        /// Method used to perform activity if it can occur as soon as resources are available.
        /// </summary>
        public override void DoActivity()
        {
            List <LabourType> group = Resources.Labour().Items.Where(a => a.Hired != true).ToList();

            if (group != null && group.Count > 0)
            {
                // calculate feed limit
                double feedLimit = 0.0;

                ResourceRequest feedRequest = ResourceRequestList.Where(a => a.ResourceType == typeof(HumanFoodStore)).FirstOrDefault();
                if (feedRequest != null)
                {
                    feedLimit = Math.Min(1.0, feedRequest.Provided / feedRequest.Required);
                }

                if (feedRequest == null || (feedRequest.Required == 0 | feedRequest.Available == 0))
                {
                    Status = ActivityStatus.NotNeeded;
                    return;
                }

                foreach (Model child in Apsim.Children(this, typeof(LabourFeedGroup)))
                {
                    double value = (child as LabourFeedGroup).Value;

                    foreach (LabourType ind in Resources.Labour().Items.Filter(child))
                    {
                        switch (FeedStyle)
                        {
                        case LabourFeedActivityTypes.SpecifiedDailyAmountPerIndividual:
                            feedRequest.Provided  = Math.Min(value * 30.4, FeedType.MaximumDailyIntakePerAE * ind.AdultEquivalent * 30.4);
                            feedRequest.Provided *= feedLimit;
                            ind.AddIntake(feedRequest);
                            break;

                        case LabourFeedActivityTypes.SpecifiedDailyAmountPerAE:
                            feedRequest.Provided  = Math.Min(value, FeedType.MaximumDailyIntakePerAE) * ind.AdultEquivalent * 30.4;
                            feedRequest.Provided *= feedLimit;
                            ind.AddIntake(feedRequest);
                            break;

                        default:
                            throw new Exception(String.Format("FeedStyle {0} is not supported in {1}", FeedStyle, this.Name));
                        }
                    }
                }
                SetStatusSuccess();
            }
        }
        /// <summary>
        /// Method used to perform activity if it can occur as soon as resources are available.
        /// </summary>
        public override void DoActivity()
        {
            if (this.TimingOK)
            {
                // reduce if labour limiting
                double labourlimit = 1;
                if (ResourceRequestList != null && ResourceRequestList.Where(a => a.ResourceType == typeof(Labour)).Count() > 0)
                {
                    double amountLabourNeeded   = ResourceRequestList.Where(a => a.ResourceType == typeof(Labour)).Sum(a => a.Required);
                    double amountLabourProvided = ResourceRequestList.Where(a => a.ResourceType == typeof(Labour)).Sum(a => a.Provided);
                    if (amountLabourNeeded > 0)
                    {
                        if (amountLabourProvided == 0)
                        {
                            labourlimit = 0;
                        }
                        else
                        {
                            labourlimit = amountLabourNeeded / amountLabourProvided;
                        }
                    }
                }
                double units = 0;
                if (labourlimit == 1 || this.OnPartialResourcesAvailableAction == OnPartialResourcesAvailableActionTypes.UseResourcesAvailable)
                {
                    units = UnitsAvailableForSale * labourlimit;
                    if (SellWholeUnitsOnly)
                    {
                        units = Math.Truncate(units);
                    }
                }

                if (units > 0)
                {
                    // remove resource
                    ResourceRequest purchaseRequest = new ResourceRequest();
                    purchaseRequest.ActivityModel      = this;
                    purchaseRequest.Required           = units * UnitSize;
                    purchaseRequest.AllowTransmutation = false;
                    purchaseRequest.Reason             = "Sales";
                    resourceToSell.Remove(purchaseRequest);

                    // transfer money earned
                    bankAccount.Add(units * UnitPrice, this.Name, "Sales");
                    SetStatusSuccess();
                }
            }
        }
Beispiel #9
0
        /// <inheritdoc/>
        public override void DoActivity()
        {
            // processed resource should already be taken
            Status = ActivityStatus.NotNeeded;
            // add created resources
            ResourceRequest rr = ResourceRequestList.Where(a => (a.Resource != null && a.Resource.GetType() == resourceTypeProcessModel.GetType())).FirstOrDefault();

            if (rr != null)
            {
                resourceTypeCreatedModel.Add(rr.Provided * ConversionRate, this, (resourceTypeCreatedModel as CLEMModel).NameWithParent, "Created");
                if (rr.Provided > 0)
                {
                    Status = ActivityStatus.Success;
                }
            }
        }
Beispiel #10
0
        private void OnCLEMAnimalManage(object sender, EventArgs e)
        {
            // Weaning is performed in the Management event to ensure weaned individuals are treated as unweaned for their intake calculations
            // and the mother is considered lactating for lactation energy demands otherwise IsLactating stops as soon as ind.wean() is performed.

            // if wean month
            if (this.TimingOK)
            {
                double          labourlimit = this.LabourLimitProportion;
                int             weanedCount = 0;
                ResourceRequest labour      = ResourceRequestList.Where(a => a.ResourceType == typeof(LabourType)).FirstOrDefault <ResourceRequest>();
                // Perform weaning
                int count = this.CurrentHerd(false).Where(a => a.Weaned == false).Count();
                foreach (var ind in this.CurrentHerd(false).Where(a => a.Weaned == false))
                {
                    if (ind.Age >= WeaningAge || ind.Weight >= WeaningWeight)
                    {
                        string reason = (ind.Age >= WeaningAge)? "Age" : "Weight";
                        ind.Wean(true, reason);
                        ind.Location = grazeStore;
                        weanedCount++;
                        if (ind.Mother != null)
                        {
                            // report conception status changed when offspring weaned.
                            ind.Mother.BreedParams.OnConceptionStatusChanged(new Reporting.ConceptionStatusChangedEventArgs(Reporting.ConceptionStatus.Weaned, ind.Mother, Clock.Today));
                        }
                    }

                    // stop if labour limited individuals reached and LabourShortfallAffectsActivity
                    if (weanedCount > Convert.ToInt32(count * labourlimit, CultureInfo.InvariantCulture))
                    {
                        this.Status = ActivityStatus.Partial;
                        break;
                    }
                }

                if (weanedCount > 0)
                {
                    SetStatusSuccess();
                }
                else
                {
                    this.Status = ActivityStatus.NotNeeded;
                }
            }
        }
Beispiel #11
0
        /// <inheritdoc/>
        public override void DoActivity()
        {
            // add all provided requests to the individuals intake pools.

            List <LabourType> group = people?.Items.Where(a => IncludeHiredLabour | a.Hired != true).ToList();

            Status = ActivityStatus.NotNeeded;
            if (group != null && group.Count > 0)
            {
                var requests = ResourceRequestList.Where(a => a.ResourceType == typeof(HumanFoodStore));
                if (requests.Any())
                {
                    double aE = group.Sum(a => a.TotalAdultEquivalents);
                    foreach (ResourceRequest request in requests.Where(a => a.Provided > 0))
                    {
                        // add to individual intake
                        foreach (LabourType labour in group)
                        {
                            double amount = request.Provided * (labour.TotalAdultEquivalents / aE);
                            labour.AddIntake(new LabourDietComponent()
                            {
                                AmountConsumed = amount,
                                FoodStore      = request.Resource as HumanFoodStoreType
                            });
                            labour.FeedToTargetIntake += amount;
                        }
                    }
                }
                if (this.FindAllChildren <LabourActivityFeedTarget>().Where(a => !a.TargetAchieved).Any())
                {
                    this.Status = ActivityStatus.Partial;
                }
                else
                {
                    this.Status = ActivityStatus.Success;
                }
            }
            // finished eating, so this household is now free to sell the resources
            // assumes all households above in the tree supply this level.
            // if sibling above relies on food from this household it own't work
            // selling is perfomed in the next method called in this same event
        }
Beispiel #12
0
        /// <summary>
        /// Method used to perform activity if it can occur as soon as resources are available.
        /// </summary>
        public override void DoActivity()
        {
            Status = ActivityStatus.NotNeeded;
            // take local equivalent of market from resource

            double provided = 0;

            if ((resourceToBuy as CLEMResourceTypeBase).MarketStoreExists)
            {
                // find resource entry in market if present and reduce
                ResourceRequest rr = ResourceRequestList.Where(a => a.Resource == (resourceToBuy as CLEMResourceTypeBase).EquivalentMarketStore).FirstOrDefault();
                provided = rr.Provided / this.FarmMultiplier;
            }
            else
            {
                provided = unitsCanAfford * price.PacketSize;
            }

            if (provided > 0)
            {
                resourceToBuy.Add(provided, this, "", "Purchase");
                Status = ActivityStatus.Success;
            }

            // make financial transactions
            if (bankAccount != null)
            {
                ResourceRequest payment = new ResourceRequest()
                {
                    AllowTransmutation          = false,
                    MarketTransactionMultiplier = this.FarmMultiplier,
                    Required          = provided / price.PacketSize * price.PricePerPacket,
                    ResourceType      = typeof(Finance),
                    ResourceTypeName  = bankAccount.Name,
                    Category          = "Purchase",
                    RelatesToResource = (resourceToBuy as CLEMModel).NameWithParent,
                    ActivityModel     = this
                };
                bankAccount.Remove(payment);
            }
        }
Beispiel #13
0
        /// <inheritdoc/>
        public override void AdjustResourcesNeededForActivity()
        {
            // get labour shortfall
            double labprop = this.LimitProportion(typeof(LabourType));
            // get finance shortfall
            double finprop = this.LimitProportion(typeof(FinanceType));

            // reduce amount used
            double limit = Math.Min(labprop, finprop);

            if (limit < 1)
            {
                // find process resource entry in resource list
                ResourceRequest rr = ResourceRequestList.Where(a => a.ResourceType == resourceTypeProcessModel.GetType()).FirstOrDefault();
                if (rr != null)
                {
                    // reduce amount required
                    rr.Required *= limit;
                }
            }
        }
Beispiel #14
0
        /// <summary>
        /// Method used to perform activity if it can occur as soon as resources are available.
        /// </summary>
        public override void DoActivity()
        {
            // add all provided requests to the individuals intake pools.

            List <LabourType> group = Resources.Labour().Items.Where(a => IncludeHiredLabour | a.Hired != true).ToList();
            double            aE    = group.Sum(a => a.AdultEquivalent);

            Status = ActivityStatus.NotNeeded;
            if (group != null && group.Count > 0)
            {
                var requests = ResourceRequestList.Where(a => a.ResourceType == typeof(HumanFoodStore));
                if (requests.Count() > 0)
                {
                    foreach (ResourceRequest request in requests)
                    {
                        if (request.Provided > 0)
                        {
                            // add to individual intake
                            foreach (LabourType labour in group)
                            {
                                labour.AddIntake(new LabourDietComponent()
                                {
                                    AmountConsumed = request.Provided * (labour.AdultEquivalent / aE),
                                    FoodStore      = request.Resource as HumanFoodStoreType
                                });
                            }
                        }
                    }
                }
                List <LabourActivityFeedTarget> labourActivityFeedTargets = this.FindAllChildren <LabourActivityFeedTarget>().Cast <LabourActivityFeedTarget>().ToList();
                if (labourActivityFeedTargets.Where(a => !a.TargetMet).Count() > 0)
                {
                    this.Status = ActivityStatus.Partial;
                }
                else
                {
                    this.Status = ActivityStatus.Success;
                }
            }
        }
Beispiel #15
0
        private void OnCLEMMilking(object sender, EventArgs e)
        {
            // take all milk
            List <RuminantFemale> herd = this.CurrentHerd(true).Where(a => a.Gender == Sex.Female).Cast <RuminantFemale>().Where(a => a.IsLactating == true & a.SucklingOffspring.Count() == 0).ToList();
            double milkTotal           = herd.Sum(a => a.MilkAmount);

            if (milkTotal > 0)
            {
                // set these females to state milking perfomred so they switch to the non-suckling milk production curves.
                herd.Select(a => a.MilkingPerformed == true);

                // only provide what labour would allow
                // calculate labour limit
                double labourLimit    = 1;
                double labourNeeded   = ResourceRequestList.Where(a => a.ResourceType == typeof(Labour)).Sum(a => a.Required);
                double labourProvided = ResourceRequestList.Where(a => a.ResourceType == typeof(Labour)).Sum(a => a.Provided);
                if (labourNeeded > 0)
                {
                    labourLimit = labourProvided / labourNeeded;
                }

                milkStore.Add(milkTotal * labourLimit, this.Name, this.PredictedHerdName);
            }
        }
        /// <summary>
        /// The method allows the activity to adjust resources requested based on shortfalls (e.g. labour) before they are taken from the pools
        /// </summary>
        public override void AdjustResourcesNeededForActivity()
        {
            // labour limiter
            var labourRequests = ResourceRequestList.Where(a => a.ResourceType == typeof(Labour)).ToList();

            if (labourRequests.Count > 0)
            {
                double required = labourRequests.Sum(a => a.Required);
                double provided = labourRequests.Sum(a => a.Provided);
                double limiter  = Math.Min(1.0, provided / required);

                // TODO add ability to turn off labour influence
                if (limiter < 1)
                {
                    // find pasture and reduce required based on labour limit.
                    ResourceRequest pastureRequest = ResourceRequestList.Where(a => a.ResourceType == typeof(GrazeFoodStoreType)).FirstOrDefault();
                    if (pastureRequest != null)
                    {
                        AmountHarvested        *= limiter;
                        pastureRequest.Required = AmountHarvested;
                    }
                }
            }
        }
Beispiel #17
0
        /// <summary>
        /// Method used to perform activity if it can occur as soon as resources are available.
        /// </summary>
        public override void PerformActivity()
        {
            RuminantHerd    ruminantHerd = Resources.RuminantHerd();
            List <Ruminant> herd         = ruminantHerd.Herd;

            if (herd != null && herd.Count > 0)
            {
                // calculate labour limit
                double labourLimit = 1.0;
                if (LabourShortfallLimitsFeeding)
                {
                    ResourceRequest labourRequest = ResourceRequestList.Where(a => a.ResourceName == "Labour").FirstOrDefault();
                    if (labourRequest != null)
                    {
                        labourLimit = Math.Min(1.0, labourRequest.Required / labourRequest.Provided);
                    }
                }

                // calculate feed limit
                double          feedLimit   = 0.0;
                ResourceRequest feedRequest = ResourceRequestList.Where(a => a.ResourceName == "AnimalFoodStore").FirstOrDefault();
                if (feedRequest != null)
                {
                    feedLimit = Math.Min(1.0, feedRequest.Required / feedRequest.Provided);
                }

                // feed animals
                int month = Clock.Today.Month - 1;

                // get list from filters
                foreach (RuminantFilterGroup child in this.Children.Where(a => a.GetType() == typeof(RuminantFilterGroup)))
                {
                    foreach (Ruminant ind in herd.Filter(child as RuminantFilterGroup))
                    {
                        double feedRequired = 0;
                        switch (FeedStyle)
                        {
                        case RuminantFeedActivityTypes.SpecifiedDailyAmount:
                            feedRequired += (child as RuminantFilterGroup).MonthlyValues[month] * 30.4;                                     // * ind.Number;
                            ind.Intake   += feedRequired * feedLimit * labourLimit;
                            break;

                        case RuminantFeedActivityTypes.ProportionOfWeight:
                            feedRequired += (child as RuminantFilterGroup).MonthlyValues[month] * ind.Weight * 30.4;                                     // * ind.Number;
                            ind.Intake   += feedRequired * feedLimit * labourLimit;
                            break;

                        case RuminantFeedActivityTypes.ProportionOfPotentialIntake:
                            feedRequired += (child as RuminantFilterGroup).MonthlyValues[month] * ind.PotentialIntake;                                     // * ind.Number;
                            ind.Intake   += feedRequired * feedLimit * labourLimit;
                            break;

                        case RuminantFeedActivityTypes.ProportionOfRemainingIntakeRequired:
                            feedRequired += (child as RuminantFilterGroup).MonthlyValues[month] * (ind.PotentialIntake - ind.Intake);                                      // * ind.Number;
                            ind.Intake   += feedRequired * feedLimit * labourLimit;
                            break;

                        default:
                            break;
                        }
                    }
                }
            }
        }
Beispiel #18
0
        /// <inheritdoc/>
        public override void DoActivity()
        {
            IEnumerable <LabourType> group = labour?.Items.Where(a => a.Hired != true);

            if (group != null && group.Any())
            {
                // calculate feed limit
                double feedLimit = 0.0;

                ResourceRequest feedRequest = ResourceRequestList.Where(a => a.ResourceType == typeof(HumanFoodStore)).FirstOrDefault();
                if (feedRequest != null)
                {
                    feedLimit = Math.Min(1.0, feedRequest.Provided / feedRequest.Required);
                }

                if (feedRequest == null || (feedRequest.Required == 0 | feedRequest.Available == 0))
                {
                    Status = ActivityStatus.NotNeeded;
                    return;
                }

                foreach (LabourFeedGroup child in this.FindAllChildren <LabourFeedGroup>())
                {
                    double value = child.Value;

                    foreach (LabourType ind in child.Filter(labour?.Items))
                    {
                        switch (FeedStyle)
                        {
                        case LabourFeedActivityTypes.SpecifiedDailyAmountPerIndividual:
                            feedRequest.Provided  = value * 30.4;
                            feedRequest.Provided *= feedLimit;
                            feedRequest.Provided *= (feedRequest.Resource as HumanFoodStoreType).EdibleProportion;
                            ind.AddIntake(new LabourDietComponent()
                            {
                                AmountConsumed = feedRequest.Provided,
                                FoodStore      = feedRequest.Resource as HumanFoodStoreType
                            }
                                          );
                            break;

                        case LabourFeedActivityTypes.SpecifiedDailyAmountPerAE:
                            feedRequest.Provided  = value * ind.AdultEquivalent * 30.4;
                            feedRequest.Provided *= feedLimit;
                            feedRequest.Provided *= (feedRequest.Resource as HumanFoodStoreType).EdibleProportion;
                            ind.AddIntake(new LabourDietComponent()
                            {
                                AmountConsumed = feedRequest.Provided,
                                FoodStore      = feedRequest.Resource as HumanFoodStoreType
                            }
                                          );
                            break;

                        default:
                            throw new Exception(String.Format("FeedStyle {0} is not supported in {1}", FeedStyle, this.Name));
                        }
                    }
                }
                SetStatusSuccess();
            }
        }
Beispiel #19
0
        /// <summary>
        /// Method used to perform activity if it can occur as soon as resources are available.
        /// </summary>
        public override void DoActivity()
        {
            List <Ruminant> herd = CurrentHerd(false);

            if (herd != null && herd.Count > 0)
            {
                // calculate feed limit
                double feedLimit            = 0.0;
                double wastage              = 1.0 - this.ProportionTramplingWastage;
                double dailyAmountShortfall = 1.0;

                ResourceRequest    feedRequest = ResourceRequestList.Where(a => a.ResourceType == typeof(AnimalFoodStore)).FirstOrDefault();
                FoodResourcePacket details     = new FoodResourcePacket();
                if (feedRequest != null)
                {
                    details   = feedRequest.AdditionalDetails as FoodResourcePacket;
                    feedLimit = Math.Min(1.0, feedRequest.Provided / feedRequest.Required);
                }

                // feed animals
                int month = Clock.Today.Month - 1;

                if (feedRequest == null || (feedRequest.Required == 0 | feedRequest.Available == 0))
                {
                    Status = ActivityStatus.NotNeeded;
                    return;
                }

                // if feed style is fixed daily amount compare amount received against herd requirement.
                // this produces a reduction from potential intake for each individual.
                if (FeedStyle == RuminantFeedActivityTypes.SpecifiedDailyAmount)
                {
                    double herdRequirement = 0;
                    foreach (Model child in this.Children.Where(a => a.GetType().ToString().Contains("RuminantFeedGroup")))
                    {
                        herdRequirement += herd.Filter(child).Sum(a => a.PotentialIntake - a.Intake);
                    }
                    dailyAmountShortfall = Math.Min(1.0, (feedRequest.Provided * wastage) / herdRequirement);
                }

                // get list from filters
                foreach (Model child in this.Children.Where(a => a.GetType().ToString().Contains("RuminantFeedGroup")))
                {
                    double value = 0;
                    if (child is RuminantFeedGroup)
                    {
                        value = (child as RuminantFeedGroup).Value;
                    }
                    else
                    {
                        value = (child as RuminantFeedGroupMonthly).MonthlyValues[month];
                    }

                    foreach (Ruminant ind in herd.Filter(child))
                    {
                        switch (FeedStyle)
                        {
                        case RuminantFeedActivityTypes.SpecifiedDailyAmount:
                            details.Amount  = (ind.PotentialIntake - ind.Intake);
                            details.Amount *= dailyAmountShortfall;
                            ind.AddIntake(details);
                            break;

                        case RuminantFeedActivityTypes.SpecifiedDailyAmountPerIndividual:
                            details.Amount  = value * 30.4;    // * ind.Number;
                            details.Amount *= feedLimit * wastage;
                            ind.AddIntake(details);
                            break;

                        case RuminantFeedActivityTypes.ProportionOfWeight:
                            details.Amount  = value * ind.Weight * 30.4;    // * ind.Number;
                            details.Amount *= feedLimit * wastage;
                            ind.AddIntake(details);
                            break;

                        case RuminantFeedActivityTypes.ProportionOfPotentialIntake:
                            details.Amount  = value * ind.PotentialIntake;    // * ind.Number;
                            details.Amount *= feedLimit * wastage;
                            ind.AddIntake(details);
                            break;

                        case RuminantFeedActivityTypes.ProportionOfRemainingIntakeRequired:
                            details.Amount  = value * (ind.PotentialIntake - ind.Intake);    // * ind.Number;
                            details.Amount *= feedLimit * wastage;
                            ind.AddIntake(details);
                            break;

                        default:
                            throw new Exception("Feed style used [" + FeedStyle + "] not implemented in [" + this.Name + "]");
                        }
                    }
                }
                SetStatusSuccess();
            }
        }
Beispiel #20
0
        /// <summary>
        /// Method used to perform activity if it can occur as soon as resources are available.
        /// </summary>
        public override void DoActivity()
        {
            List <Ruminant> herd = CurrentHerd(false);

            if (herd != null && herd.Count > 0)
            {
                // calculate labour limit
                double labourLimit    = 1;
                double labourNeeded   = ResourceRequestList.Where(a => a.ResourceType == typeof(Labour)).Sum(a => a.Required);
                double labourProvided = ResourceRequestList.Where(a => a.ResourceType == typeof(Labour)).Sum(a => a.Provided);
                if (labourNeeded > 0)
                {
                    labourLimit = labourProvided / labourNeeded;
                }

                // calculate feed limit
                double feedLimit = 0.0;
                double wastage   = 1.0 - this.ProportionTramplingWastage;

                ResourceRequest    feedRequest = ResourceRequestList.Where(a => a.ResourceType == typeof(AnimalFoodStore)).FirstOrDefault();
                FoodResourcePacket details     = new FoodResourcePacket();
                if (feedRequest != null)
                {
                    details   = feedRequest.AdditionalDetails as FoodResourcePacket;
                    feedLimit = Math.Min(1.0, feedRequest.Provided / feedRequest.Required);
                }

                // feed animals
                int month = Clock.Today.Month - 1;
                SetStatusSuccess();

                // get list from filters
                foreach (RuminantFeedGroup child in Apsim.Children(this, typeof(RuminantFeedGroup)))
                {
                    foreach (Ruminant ind in herd.Filter(child as RuminantFeedGroup))
                    {
                        switch (FeedStyle)
                        {
                        case RuminantFeedActivityTypes.SpecifiedDailyAmount:
                            details.Amount  = (child as RuminantFeedGroup).MonthlyValues[month] * 30.4;
                            details.Amount *= feedLimit * labourLimit * wastage;
                            ind.AddIntake(details);
                            break;

                        case RuminantFeedActivityTypes.ProportionOfWeight:
                            details.Amount  = (child as RuminantFeedGroup).MonthlyValues[month] * ind.Weight * 30.4;    // * ind.Number;
                            details.Amount *= feedLimit * labourLimit * wastage;
                            ind.AddIntake(details);
                            break;

                        case RuminantFeedActivityTypes.ProportionOfPotentialIntake:
                            details.Amount  = (child as RuminantFeedGroup).MonthlyValues[month] * ind.PotentialIntake;    // * ind.Number;
                            details.Amount *= feedLimit * labourLimit * wastage;
                            ind.AddIntake(details);
                            break;

                        case RuminantFeedActivityTypes.ProportionOfRemainingIntakeRequired:
                            details.Amount  = (child as RuminantFeedGroup).MonthlyValues[month] * (ind.PotentialIntake - ind.Intake);    // * ind.Number;
                            details.Amount *= feedLimit * labourLimit * wastage;
                            ind.AddIntake(details);
                            break;

                        default:
                            break;
                        }
                    }
                }
            }
        }
Beispiel #21
0
        /// <inheritdoc/>
        public override void DoActivity()
        {
            IEnumerable <Ruminant> herd = CurrentHerd(false);

            if (herd != null && herd.Any())
            {
                double feedLimit = 0.0;

                ResourceRequest    feedRequest = ResourceRequestList.Where(a => a.ResourceType == typeof(AnimalFoodStore)).LastOrDefault();
                FoodResourcePacket details     = new FoodResourcePacket();
                if (feedRequest != null)
                {
                    details   = feedRequest.AdditionalDetails as FoodResourcePacket;
                    feedLimit = Math.Min(1.0, feedRequest.Provided / feedRequest.Required);
                }

                // feed animals
                if (feedRequest == null | (feedRequest?.Required == 0 | feedRequest?.Available == 0) | APSIM.Shared.Utilities.MathUtilities.FloatsAreEqual(feedLimit, 0.0))
                {
                    Status = ActivityStatus.NotNeeded;
                    return;
                }

                // get list from filters
                foreach (var child in Children.OfType <FilterGroup <Ruminant> >())
                {
                    double value = 0;
                    if (child is RuminantFeedGroup rfg)
                    {
                        value = rfg.Value;
                    }
                    else if (child is RuminantFeedGroupMonthly rfgm)
                    {
                        value = rfgm.MonthlyValues[clock.Today.Month - 1];
                    }
                    else
                    {
                        continue;
                    }

                    foreach (Ruminant ind in child.Filter(herd))
                    {
                        switch (FeedStyle)
                        {
                        case RuminantFeedActivityTypes.SpecifiedDailyAmount:
                        case RuminantFeedActivityTypes.ProportionOfFeedAvailable:
                            details.Amount  = ((ind.PotentialIntake * (usingPotentialIntakeMultiplier ? ind.BreedParams.OverfeedPotentialIntakeModifier : 1)) - ind.Intake);
                            details.Amount *= feedLimit;
                            break;

                        case RuminantFeedActivityTypes.SpecifiedDailyAmountPerIndividual:
                            details.Amount  = value * 30.4;
                            details.Amount *= feedLimit;
                            break;

                        case RuminantFeedActivityTypes.ProportionOfWeight:
                            details.Amount  = value * ind.Weight * 30.4;
                            details.Amount *= feedLimit;
                            break;

                        case RuminantFeedActivityTypes.ProportionOfPotentialIntake:
                            details.Amount  = value * ind.PotentialIntake;
                            details.Amount *= feedLimit;
                            break;

                        case RuminantFeedActivityTypes.ProportionOfRemainingIntakeRequired:
                            details.Amount  = value * (ind.PotentialIntake - ind.Intake);
                            details.Amount *= feedLimit;
                            break;

                        default:
                            throw new Exception($"FeedStyle [{FeedStyle}] is not supported in [a={Name}]");
                        }
                        // check amount meets intake limits
                        if (usingPotentialIntakeMultiplier)
                        {
                            if (details.Amount > (ind.PotentialIntake + (Math.Max(0, ind.BreedParams.OverfeedPotentialIntakeModifier - 1) * overfeedProportion * ind.PotentialIntake)) - ind.Intake)
                            {
                                details.Amount = (ind.PotentialIntake + (Math.Max(0, ind.BreedParams.OverfeedPotentialIntakeModifier - 1) * overfeedProportion * ind.PotentialIntake)) - ind.Intake;
                            }
                        }

                        ind.AddIntake(details);
                    }
                }
                SetStatusSuccess();
            }
            else
            {
                Status = ActivityStatus.NotNeeded;
            }
        }
        /// <summary>
        /// Method to determine resources required for this activity in the current month
        /// </summary>
        /// <returns>List of required resource requests</returns>
        public override List <ResourceRequest> GetResourcesNeededForActivity()
        {
            if (people is null | food is null)
            {
                return(null);
            }

            List <LabourType> peopleList = people.Items.Where(a => IncludeHiredLabour || a.Hired == true).ToList();

            peopleList.Select(a => a.FeedToTargetIntake == 0);

            List <ResourceRequest> requests = new List <ResourceRequest>();

            // determine AEs to be fed
            double aE = peopleList.Sum(a => a.AdultEquivalent);

            // determine feed limits (max kg per AE per day * AEs * days)
            double intakeLimit = DailyIntakeLimit * aE * 30.4;

            // remove previous consumption
            intakeLimit -= this.DailyIntakeOtherSources * aE * 30.4;
            intakeLimit -= peopleList.Sum(a => a.GetAmountConsumed());

            List <LabourActivityFeedTarget> labourActivityFeedTargets = this.FindAllChildren <LabourActivityFeedTarget>().Cast <LabourActivityFeedTarget>().ToList();
            int feedTargetIndex = 0;

            // determine targets
            foreach (LabourActivityFeedTarget target in labourActivityFeedTargets)
            {
                // calculate target
                target.Target = target.TargetValue * aE * 30.4;

                // set initial level based on off store inputs
                target.CurrentAchieved = target.OtherSourcesValue * aE * 30.4;

                // calculate current level from previous intake this month (LabourActivityFeed)
                target.CurrentAchieved += people.GetDietaryValue(target.Metric, IncludeHiredLabour, true) * aE * 30.4;
            }

            // order food to achieve best returns for first criteria conversion factor decreasing
            List <HumanFoodStoreType> foodStoreTypes = food.FindAllChildren <HumanFoodStoreType>().Cast <HumanFoodStoreType>().OrderBy(a => a.ConversionFactor(labourActivityFeedTargets[feedTargetIndex].Metric)).ToList();

            // check availability to take food based on order in simulation tree
            while (foodStoreTypes.Count() > 0 & intakeLimit > 0)
            {
                // get next food store type
                HumanFoodStoreType foodtype = foodStoreTypes[0];

                // get amount people can still eat based on limits and previous consumption
                double amountNeededRaw = 0;
                foreach (LabourType labourType in peopleList)
                {
                    double indLimit         = (labourType.AdultEquivalent * DailyIntakeLimit * 30.4);
                    double alreadyEatenThis = labourType.GetAmountConsumed(foodtype.Name);
                    double alreadyEaten     = labourType.GetAmountConsumed() + labourType.FeedToTargetIntake;
                    double canStillEat      = Math.Max(0, indLimit - alreadyEaten);

                    double amountOfThisFood = canStillEat;
                    amountNeededRaw += amountOfThisFood / foodtype.EdibleProportion;
                }

                // update targets based on amount available (will update excess if transmutated later)
                double amountNeededEdible = Math.Min(amountNeededRaw, foodtype.Amount) * foodtype.EdibleProportion;
                foreach (LabourActivityFeedTarget target in labourActivityFeedTargets)
                {
                    target.CurrentAchieved += amountNeededEdible * foodtype.ConversionFactor(target.Metric);
                }

                if (amountNeededRaw > 0)
                {
                    // create request
                    requests.Add(new ResourceRequest()
                    {
                        AllowTransmutation = false,
                        Required           = amountNeededRaw,
                        Available          = foodtype.Amount,
                        ResourceType       = typeof(HumanFoodStore),
                        ResourceTypeName   = foodtype.Name,
                        ActivityModel      = this,
                        Category           = "Consumption"
                    }
                                 );
                }

                foodStoreTypes.RemoveAt(0);

                // check if target has been met (allows slight overrun)
                if (labourActivityFeedTargets[feedTargetIndex].CurrentAchieved >= labourActivityFeedTargets[feedTargetIndex].Target)
                {
                    feedTargetIndex++;
                    if (feedTargetIndex > labourActivityFeedTargets.Count())
                    {
                        // all feed targets have been met. Preserve remaining food for next time.
                        //TODO: eat food that will go off if not eaten and still below limits.
                        break;
                    }
                    // reorder remaining food types to next feed target if available
                    foodStoreTypes = foodStoreTypes.OrderBy(a => a.ConversionFactor(labourActivityFeedTargets[feedTargetIndex].Metric)).ToList();
                }
            }

            // We have now been through all food types or all targets have been achieved.
            // Any unused food will not be consumed even if it is about to spoil.
            // The food requests ready to send contain excesses that may need to be purchased but haven't been accounted for towards targets yet

            // Next we go through and check all requests that exceed available to see if we can and there is need to buy resources.
            foreach (ResourceRequest request in ResourceRequestList.Where(a => a.Required > a.Available))
            {
                // all targets have not been met
                if (feedTargetIndex <= labourActivityFeedTargets.Count())
                {
                    // allow if transmutation possible
                    if ((request.Resource as HumanFoodStoreType).TransmutationDefined)
                    {
                        // allow if still below threshold
                        if (labourActivityFeedTargets[feedTargetIndex].CurrentAchieved < labourActivityFeedTargets[feedTargetIndex].Target)
                        {
                            HumanFoodStoreType foodStore = request.Resource as HumanFoodStoreType;

                            // if this food type provides towards the target
                            if (foodStore.ConversionFactor(labourActivityFeedTargets[feedTargetIndex].Metric) > 0)
                            {
                                // work out what the extra is worth
                                double excess = request.Required - request.Available;
                                // get target needed
                                double remainingToTarget = labourActivityFeedTargets[feedTargetIndex].Target - labourActivityFeedTargets[feedTargetIndex].CurrentAchieved;
                                double excessConverted   = excess * foodStore.EdibleProportion * foodStore.ConversionFactor(labourActivityFeedTargets[feedTargetIndex].Metric);

                                // reduce if less than needed
                                double prop      = Math.Max(excessConverted / remainingToTarget, 1.0);
                                double newExcess = excess * prop;
                                request.Required           = request.Available + newExcess;
                                request.AllowTransmutation = true;

                                // update targets based on new amount eaten
                                foreach (LabourActivityFeedTarget target in labourActivityFeedTargets)
                                {
                                    target.CurrentAchieved += newExcess * foodStore.EdibleProportion * foodStore.ConversionFactor(target.Metric);
                                }

                                // move to next target if achieved.
                                if (labourActivityFeedTargets[feedTargetIndex].CurrentAchieved >= labourActivityFeedTargets[feedTargetIndex].Target)
                                {
                                    feedTargetIndex++;
                                }
                            }
                        }
                    }
                }
                // transmutation not allowed so only get what was available.
                if (request.AllowTransmutation == false)
                {
                    request.Required = request.Available;
                }
            }
            return(requests);
        }
Beispiel #23
0
        private void OnCLEMAnimalManage(object sender, EventArgs e)
        {
            // Weaning is performed in the Management event to ensure weaned individuals are treated as unweaned for their intake calculations
            // and the mother is considered lactating for lactation energy demands otherwise IsLactating stops as soon as ind.wean() is performed.

            // if wean month
            if (this.TimingOK)
            {
                double          labourlimit = this.LabourLimitProportion;
                int             weanedCount = 0;
                ResourceRequest labour      = ResourceRequestList.Where(a => a.ResourceType == typeof(LabourType)).FirstOrDefault <ResourceRequest>();
                // Perform weaning
                int count = 0;
                foreach (RuminantGroup item in filterGroups)
                {
                    count += this.GetIndividuals <Ruminant>(GetRuminantHerdSelectionStyle.NotMarkedForSale, null, false).Where(a => a.Weaned == false).Count();
                }

                foreach (RuminantGroup item in filterGroups)
                {
                    foreach (Ruminant ind in item.Filter(this.GetIndividuals <Ruminant>(GetRuminantHerdSelectionStyle.NotMarkedForSale, null, false).Where(a => a.Weaned == false)).ToList())
                    {
                        bool   readyToWean = false;
                        string reason      = "";
                        switch (Style)
                        {
                        case WeaningStyle.AgeOrWeight:
                            readyToWean = (ind.Age >= WeaningAge || ind.Weight >= WeaningWeight);
                            reason      = (ind.Age >= WeaningAge) ? ((ind.Weight >= WeaningWeight) ? "AgeAndWeight": "Age") : "Weight";
                            break;

                        case WeaningStyle.AgeOnly:
                            readyToWean = (ind.Age >= WeaningAge);
                            reason      = "Age";
                            break;

                        case WeaningStyle.WeightOnly:
                            readyToWean = (ind.Weight >= WeaningWeight);
                            reason      = "Weight";
                            break;
                        }

                        if (readyToWean)
                        {
                            this.Status = ActivityStatus.Success;
                            ind.Wean(true, reason);
                            ind.Location = grazeStore;
                            weanedCount++;

                            // report wean. If mother has died create temp female with the mother's ID for reporting only
                            ind.BreedParams.OnConceptionStatusChanged(new Reporting.ConceptionStatusChangedEventArgs(Reporting.ConceptionStatus.Weaned, ind.Mother ?? new RuminantFemale(ind.BreedParams, -1, 999)
                            {
                                ID = ind.MotherID
                            }, clock.Today, ind));
                        }

                        // stop if labour limited individuals reached and LabourShortfallAffectsActivity
                        if (weanedCount > Convert.ToInt32(count * labourlimit, CultureInfo.InvariantCulture))
                        {
                            this.Status = ActivityStatus.Partial;
                            break;
                        }
                    }
                }

                if (weanedCount > 0)
                {
                    SetStatusSuccess();
                }
                else
                {
                    this.Status = ActivityStatus.NotNeeded;
                }
            }
        }
        /// <summary>
        /// Method used to perform activity if it can occur as soon as resources are available.
        /// </summary>
        public override void DoActivity()
        {
            List <Ruminant> herd = CurrentHerd(false);

            if (herd != null && herd.Count > 0)
            {
                double feedLimit = 0.0;

                ResourceRequest    feedRequest = ResourceRequestList.Where(a => a.ResourceType == typeof(AnimalFoodStore)).LastOrDefault();
                FoodResourcePacket details     = new FoodResourcePacket();
                if (feedRequest != null)
                {
                    details   = feedRequest.AdditionalDetails as FoodResourcePacket;
                    feedLimit = Math.Min(1.0, feedRequest.Provided / feedRequest.Required);
                }

                // feed animals
                if (feedRequest == null || (feedRequest.Required == 0 | feedRequest.Available == 0))
                {
                    Status = ActivityStatus.NotNeeded;
                    return;
                }

                // get list from filters
                foreach (IFilterGroup child in Children.Where(a => a.GetType().ToString().Contains("RuminantFeedGroup")))
                {
                    double value = 0;
                    if (child is RuminantFeedGroup)
                    {
                        value = (child as RuminantFeedGroup).Value;
                    }
                    else
                    {
                        value = (child as RuminantFeedGroupMonthly).MonthlyValues[Clock.Today.Month - 1];
                    }

                    foreach (Ruminant ind in herd.FilterRuminants(child))
                    {
                        switch (FeedStyle)
                        {
                        case RuminantFeedActivityTypes.SpecifiedDailyAmount:
                        case RuminantFeedActivityTypes.ProportionOfFeedAvailable:
                            details.Amount  = ((ind.PotentialIntake * (usingPotentialintakeMultiplier ? ind.BreedParams.OverfeedPotentialIntakeModifier : 1)) - ind.Intake);
                            details.Amount *= feedLimit;
                            break;

                        case RuminantFeedActivityTypes.SpecifiedDailyAmountPerIndividual:
                            details.Amount  = value * 30.4;
                            details.Amount *= feedLimit;
                            break;

                        case RuminantFeedActivityTypes.ProportionOfWeight:
                            details.Amount  = value * ind.Weight * 30.4;
                            details.Amount *= feedLimit;
                            break;

                        case RuminantFeedActivityTypes.ProportionOfPotentialIntake:
                            details.Amount  = value * ind.PotentialIntake;
                            details.Amount *= feedLimit;
                            break;

                        case RuminantFeedActivityTypes.ProportionOfRemainingIntakeRequired:
                            details.Amount  = value * (ind.PotentialIntake - ind.Intake);
                            details.Amount *= feedLimit;
                            break;

                        default:
                            throw new Exception("Feed style used [" + FeedStyle + "] not implemented in [" + this.Name + "]");
                        }
                        // check amount meets intake limits
                        if (usingPotentialintakeMultiplier)
                        {
                            if (details.Amount > (ind.PotentialIntake + (Math.Max(0, ind.BreedParams.OverfeedPotentialIntakeModifier - 1) * overfeedProportion * ind.PotentialIntake)) - ind.Intake)
                            {
                                details.Amount = (ind.PotentialIntake + (Math.Max(0, ind.BreedParams.OverfeedPotentialIntakeModifier - 1) * overfeedProportion * ind.PotentialIntake)) - ind.Intake;
                            }
                        }
                        ind.AddIntake(details);
                    }
                }
                SetStatusSuccess();
            }
            else
            {
                Status = ActivityStatus.NotNeeded;
            }
        }
        /// <summary>
        /// The method allows the activity to adjust resources requested based on shortfalls (e.g. labour) before they are taken from the pools
        /// </summary>
        public override void AdjustResourcesNeededForActivity()
        {
            // labour shortfall if any
            double labourLimit = this.LabourLimitProportion;

            overfeedProportion = 0;

            // TODO: adjust if multiple animal food stores included in future.
            // FirstOrDefault() is still known to be food store request. After this call it will be last in list with wasted and excess at start of list
            ResourceRequest item = ResourceRequestList.Where(a => a.ResourceType == typeof(AnimalFoodStore)).FirstOrDefault();

            if (item != null)
            {
                //add limits to amout collected based on labour shortfall
                item.Required *= labourLimit;

                // account for any wastage
                // removed from food resource provided and then will be handled if required if less than provided in next section (DoActivity).
                if (ProportionTramplingWastage > 0)
                {
                    double wasted = Math.Min(item.Available, item.Required) * ProportionTramplingWastage;
                    if (wasted > 0)
                    {
                        ResourceRequest wastedRequest = new ResourceRequest()
                        {
                            AllowTransmutation = false,
                            Required           = wasted,
                            Available          = wasted,
                            ResourceType       = typeof(AnimalFoodStore),
                            ResourceTypeName   = item.ResourceTypeName,
                            ActivityModel      = this,
                            Category           = "Wastage",
                            RelatesToResource  = this.PredictedHerdName
                        };
                        ResourceRequestList.Insert(0, wastedRequest);
                        item.Required -= wasted;
                        // adjust the food known available for the actual feed
                        item.Available -= wasted;
                    }
                }

                // report any excess fed above feed needed to fill animals itake (including potential multiplier if required for overfeeding)
                double excess = 0;
                if (Math.Min(item.Available, item.Required) >= feedToOverSatisfy)
                {
                    excess = Math.Min(item.Available, item.Required) - feedToOverSatisfy;
                    if (feedToOverSatisfy > feedToSatisfy)
                    {
                        overfeedProportion = 1;
                    }
                }
                else if (feedToOverSatisfy > feedToSatisfy && Math.Min(item.Available, item.Required) > feedToSatisfy)
                {
                    overfeedProportion = (Math.Min(item.Available, item.Required) - feedToSatisfy) / (feedToOverSatisfy - feedToSatisfy);
                }
                if (excess > 0)
                {
                    ResourceRequest excessRequest = new ResourceRequest()
                    {
                        AllowTransmutation = false,
                        Required           = excess,
                        Available          = excess,
                        ResourceType       = typeof(AnimalFoodStore),
                        ResourceTypeName   = item.ResourceTypeName,
                        ActivityModel      = this,
                        Category           = "Overfed wastage",
                        RelatesToResource  = this.PredictedHerdName
                    };
                    ResourceRequestList.Insert(0, excessRequest);
                    item.Required  -= excess;
                    item.Available -= excess;
                }
            }
            return;
        }