private void OnCLEMInitialiseActivity(object sender, EventArgs e)
        {
            // activity is performed in CLEMDoCutAndCarry not CLEMGetResources
            this.AllocationStyle = ResourceAllocationStyle.Manual;

            // get pasture
            pasture = Resources.FindResourceType <GrazeFoodStore, GrazeFoodStoreType>(this, PaddockName, OnMissingResourceActionTypes.ReportErrorAndStop, OnMissingResourceActionTypes.ReportErrorAndStop);

            // get food store
            foodstore = Resources.FindResourceType <AnimalFoodStore, AnimalFoodStoreType>(this, AnimalFoodStoreName, OnMissingResourceActionTypes.ReportErrorAndStop, OnMissingResourceActionTypes.ReportErrorAndStop);

            // locate a cut and carry limiter associarted with this event.
            limiter = LocateCutAndCarryLimiter(this);

            switch (CutStyle)
            {
            case RuminantFeedActivityTypes.ProportionOfPotentialIntake:
            case RuminantFeedActivityTypes.ProportionOfRemainingIntakeRequired:
            case RuminantFeedActivityTypes.ProportionOfWeight:
            case RuminantFeedActivityTypes.SpecifiedDailyAmountPerIndividual:
                InitialiseHerd(true, true);
                break;

            default:
                break;
            }
        }
Esempio n. 2
0
        private void OnCLEMAnimalStock(object sender, EventArgs e)
        {
            // this event happens after management has marked individuals for purchase or sale.
            if (Clock.Today.Month == AssessmentMonth)
            {
                this.Status = ActivityStatus.NotNeeded;
                // calculate dry season pasture available for each managed paddock holding stock not flagged for sale
                RuminantHerd ruminantHerd = Resources.RuminantHerd();
                foreach (var paddockGroup in ruminantHerd.Herd.Where(a => a.Location != "").GroupBy(a => a.Location))
                {
                    // multiple breeds are currently not supported as we need to work out what to do with diferent AEs
                    if (paddockGroup.GroupBy(a => a.Breed).Count() > 1)
                    {
                        throw new ApsimXException(this, "Dry season destocking paddocks with multiple breeds is currently not supported\nActivity:" + this.Name + ", Paddock: " + paddockGroup.Key);
                    }

                    // total adult equivalents not marked for sale of all breeds on pasture for utilisation
                    double totalAE = paddockGroup.Where(a => a.SaleFlag == HerdChangeReason.None).Sum(a => a.AdultEquivalent);

                    double shortfallAE = 0;
                    // Determine total feed requirements for dry season for all ruminants on the pasture
                    // We assume that all ruminant have the BaseAnimalEquivalent to the specified herd
                    shortfallAE = 0;
                    GrazeFoodStoreType pasture        = Resources.GetResourceItem(this, typeof(GrazeFoodStore), paddockGroup.Key, OnMissingResourceActionTypes.ReportErrorAndStop, OnMissingResourceActionTypes.ReportErrorAndStop) as GrazeFoodStoreType;
                    double             pastureBiomass = pasture.Amount;

                    // Adjust fodder balance for detachment rate (6%/month)
                    double feedRequiredAE = paddockGroup.FirstOrDefault().BreedParams.BaseAnimalEquivalent * 0.02 * 30.4; //  2% of AE animal per day
                    for (int i = 0; i < this.DrySeasonLength; i++)
                    {
                        pastureBiomass *= (1.0 - pasture.DetachRate);
                        pastureBiomass -= feedRequiredAE * totalAE;
                    }

                    // Shortfall in Fodder in kg per hectare
                    // pasture at end of period in kg/ha
                    double pastureShortFallKgHa = pastureBiomass / pasture.Manager.Area;
                    // shortfall from low limit
                    pastureShortFallKgHa = Math.Max(0, FeedLowLimit - pastureShortFallKgHa);
                    // Shortfall in Fodder in kg for paddock
                    double pastureShortFallKg = pastureShortFallKgHa * pasture.Manager.Area;

                    if (pastureShortFallKg == 0)
                    {
                        return;
                    }

                    // number of AE to sell to balance shortfall_kg
                    shortfallAE = pastureShortFallKg / feedRequiredAE;

                    // get prediction
                    HandleDestocking(shortfallAE, paddockGroup.Key);
                }
            }
            else
            {
                this.Status = ActivityStatus.Ignored;
            }
        }
Esempio n. 3
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));
                }
            }
        }
Esempio n. 4
0
        private void OnCLEMInitialiseActivity(object sender, EventArgs e)
        {
            // get pasture
            pasture = Resources.FindResourceType <GrazeFoodStore, GrazeFoodStoreType>(this, PaddockName, OnMissingResourceActionTypes.ReportErrorAndStop, OnMissingResourceActionTypes.ReportErrorAndStop);

            if (MethaneStoreName is null || MethaneStoreName == "Use store named Methane if present")
            {
                methaneStore = Resources.FindResourceType <GreenhouseGases, GreenhouseGasesType>(this, "Methane", OnMissingResourceActionTypes.Ignore, OnMissingResourceActionTypes.Ignore);
            }
        private double HandleRestocking(double animalEquivalentsToBuy, string paddockName, Ruminant exampleRuminant)
        {
            if (animalEquivalentsToBuy <= 0)
            {
                return(0);
            }

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

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

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

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

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

                        Resources.RuminantHerd().PurchaseIndividuals.Add(newIndividual);
                        double indAE = newIndividual.AdultEquivalent;
                        animalEquivalentsToBuy -= indAE;
                        sumAE += indAE;
                    }
                }
                return(Math.Max(0, animalEquivalentsToBuy));
            }
            return(animalEquivalentsToBuy);
        }
        private void OnCLEMInitialiseActivity(object sender, EventArgs e)
        {
            ForecastSequence = new Dictionary <DateTime, double>();
            // load ENSO file into memory

            Simulation simulation = Apsim.Parent(this, typeof(Simulation)) as Simulation;

            if (simulation != null)
            {
                fullFilename = PathUtilities.GetAbsolutePath(this.MonthlySIOFile, simulation.FileName);
            }
            else
            {
                fullFilename = this.MonthlySIOFile;
            }

            //check file exists
            if (!File.Exists(fullFilename))
            {
                Summary.WriteWarning(this, String.Format("@error:Could not find ENSO SIO datafile [x={0}[ for [a={1}]", MonthlySIOFile, this.Name));
            }

            // load data
            using (StreamReader ensoStream = new StreamReader(MonthlySIOFile))
            {
                string line = "";
                while ((line = ensoStream.ReadLine()) != null)
                {
                    if (!line.StartsWith("Year"))
                    {
                        string[] items = line.Split(' ');
                        for (int i = 1; i < items.Count(); i++)
                        {
                            ForecastSequence.Add(
                                new DateTime(Convert.ToInt16(items[0]), Convert.ToInt16(i, CultureInfo.InvariantCulture), 1),
                                Convert.ToDouble(items[i], CultureInfo.InvariantCulture)
                                );
                        }
                    }
                }
            }

            // check GrazeFoodStoreExists
            if (GrazeFoodStoreName == null)
            {
                GrazeFoodStoreName = "";
            }

            if (GrazeFoodStoreName != "")
            {
                foodStore = Resources.GetResourceItem(this, typeof(GrazeFoodStore), GrazeFoodStoreName, OnMissingResourceActionTypes.Ignore, OnMissingResourceActionTypes.ReportErrorAndStop) as GrazeFoodStoreType;
            }
        }
        private void OnCLEMAnimalStock(object sender, EventArgs e)
        {
            // this event happens after management has marked individuals for purchase or sale.
            if (Clock.Today.Month == AssessmentMonth)
            {
                // Get ENSO forcase for current time
                ENSOState forecastEnsoState = GetENSOMeasure();

                // calculate dry season pasture available for each managed paddock holding stock
                RuminantHerd ruminantHerd = Resources.RuminantHerd();
                foreach (var newgroup in ruminantHerd.Herd.Where(a => a.Location != "").GroupBy(a => a.Location))
                {
                    // total adult equivalents of all breeds on pasture for utilisation
                    double totalAE = newgroup.Sum(a => a.AdultEquivalent);
                    // determine AE marked for sale and purchase of managed herd
                    double markedForSaleAE = newgroup.Where(a => a.ReadyForSale && a.HerdName == HerdName).Sum(a => a.AdultEquivalent);
                    double purchaseAE      = ruminantHerd.PurchaseIndividuals.Where(a => a.Location == newgroup.Key && a.HerdName == HerdName).Sum(a => a.AdultEquivalent);

                    double herdChange = 1.0;
                    switch (forecastEnsoState)
                    {
                    case ENSOState.Neutral:
                        break;

                    case ENSOState.ElNino:
                        GrazeFoodStoreType pasture = Resources.GetResourceItem(this, typeof(GrazeFoodStoreType), newgroup.Key, OnMissingResourceActionTypes.Ignore, OnMissingResourceActionTypes.Ignore) as GrazeFoodStoreType;
                        double             kgha    = pasture.TonnesPerHectare * 1000;
                        //NOTE: ensure calculation method in relationship is fixed values
                        herdChange = this.PastureToStockingChangeElNino.SolveY(kgha);
                        break;

                    case ENSOState.LaNina:
                        pasture    = Resources.GetResourceItem(this, typeof(GrazeFoodStoreType), newgroup.Key, OnMissingResourceActionTypes.Ignore, OnMissingResourceActionTypes.Ignore) as GrazeFoodStoreType;
                        kgha       = pasture.TonnesPerHectare * 1000;
                        herdChange = this.PastureToStockingChangeLaNina.SolveY(kgha);
                        break;

                    default:
                        break;
                    }
                    if (herdChange > 1.0)
                    {
                        double toBuyAE = Math.Max(0, (totalAE * herdChange) - purchaseAE);
                        HandleRestocking(toBuyAE, newgroup.Key, newgroup.FirstOrDefault());
                    }
                    else if (herdChange < 1.0)
                    {
                        double toSellAE = Math.Max(0, (totalAE * (1 - herdChange)) - markedForSaleAE);
                        HandleDestocking(toSellAE, newgroup.Key);
                    }
                }
            }
        }
Esempio n. 8
0
        private void OnCLEMInitialiseResource(object sender, EventArgs e)
        {
            if (Area == 0 & AreaRequested > 0)
            {
                ResourceRequestList = new List <ResourceRequest>();
                ResourceRequestList.Add(new ResourceRequest()
                {
                    AllowTransmutation = false,
                    Required           = AreaRequested,
                    ResourceType       = typeof(Land),
                    ResourceTypeName   = LandTypeNameToUse,
                    ActivityModel      = this,
                    Reason             = "Assign",
                    FilterDetails      = null
                }
                                        );
            }
            // if we get here we assume some land has been supplied
            if (ResourceRequestList != null || ResourceRequestList.Count() > 0)
            {
                gotLandRequested = TakeResources(ResourceRequestList, false);
            }

            //Now the Land has been allocated we have an Area
            if (gotLandRequested)
            {
                //get the units of area for this run from the Land resource parent.
                unitsOfArea2Ha = Resources.Land().UnitsOfAreaToHaConversion;

                // locate Pasture Type resource
                LinkedNativeFoodType = Resources.GetResourceItem(this, typeof(GrazeFoodStore), FeedTypeName, OnMissingResourceActionTypes.ReportErrorAndStop, OnMissingResourceActionTypes.ReportErrorAndStop) as GrazeFoodStoreType;

                //Assign the area actually got after taking it. It might be less than AreaRequested (if partial)
                Area = ResourceRequestList.FirstOrDefault().Provided;

                LinkedNativeFoodType.Area = Area;

                soilIndex = ((LandType)ResourceRequestList.FirstOrDefault().Resource).SoilType;

                LinkedNativeFoodType.CurrentEcologicalIndicators.LandConditionIndex = LandConditionIndex.StartingValue;
                LinkedNativeFoodType.CurrentEcologicalIndicators.GrassBasalArea     = GrassBasalArea.StartingValue;
                LinkedNativeFoodType.CurrentEcologicalIndicators.StockingRate       = StartingStockingRate;
                StockingRateSummed = StartingStockingRate;

                //Now we have a stocking rate and we have starting values for Land Condition and Grass Basal Area
                //get the starting pasture data list from GRASP
                GetPastureDataList_TodayToNextEcolCalculation();

                SetupStartingPasturePools(StartingAmount);
            }
        }
        private void OnCLEMAnimalStock(object sender, EventArgs e)
        {
            // this event happens after management has marked individuals for purchase or sale.
            if (Clock.Today.Month == AssessmentMonth)
            {
                // calculate dry season pasture available for each managed paddock holding stock not flagged for sale
                RuminantHerd ruminantHerd = Resources.RuminantHerd();
                foreach (var paddockGroup in ruminantHerd.Herd.Where(a => a.Location != "" & a.SaleFlag == HerdChangeReason.None).GroupBy(a => a.Location))
                {
                    // total adult equivalents of all breeds on pasture for utilisation
                    double AETotal = paddockGroup.Sum(a => a.AdultEquivalent);
                    // determine AE marked for sale and purchase of managed herd
                    double AEmarkedForSale = paddockGroup.Where(a => a.ReadyForSale & a.HerdName == HerdName).Sum(a => a.AdultEquivalent);
                    double AEPurchase      = ruminantHerd.PurchaseIndividuals.Where(a => a.Location == paddockGroup.Key & a.HerdName == HerdName).Sum(a => a.AdultEquivalent);

                    double ShortfallAE = 0;
                    // Determine total feed requirements for dry season for all ruminants on the pasture
                    // We assume that all ruminant have the BaseAnimalEquivalent to the specified herd
                    ShortfallAE = 0;
                    GrazeFoodStoreType pasture        = Resources.GetResourceItem(this, typeof(GrazeFoodStoreType), paddockGroup.Key, OnMissingResourceActionTypes.ReportErrorAndStop, OnMissingResourceActionTypes.ReportErrorAndStop) as GrazeFoodStoreType;
                    double             pastureBiomass = pasture.Amount;

                    // Adjust fodder balance for detachment rate (6%/month)
                    double feedRequiredAE = paddockGroup.FirstOrDefault().BreedParams.BaseAnimalEquivalent * 0.02 * 30.4; //  2% of AE animal per day
                    for (int i = 0; i < this.DrySeasonLength; i++)
                    {
                        pastureBiomass *= (1.0 - pasture.DetachRate);
                        pastureBiomass -= feedRequiredAE * AETotal;
                    }

                    // Shortfall in Fodder in kg per hectare
                    double pastureShortFallKgHa = pastureBiomass / pasture.Area;
                    pastureShortFallKgHa = Math.Max(0, pastureShortFallKgHa - FeedLowLimit);
                    // Shortfalll in Fodder in kg for paddock
                    double pastureShortFallKg = pastureShortFallKgHa * pasture.Area;

                    if (pastureShortFallKg == 0)
                    {
                        return;
                    }

                    // number of AE to sell to balance shortfall_kg
                    ShortfallAE = pastureShortFallKg / feedRequiredAE;

                    // get prediction
                    HandleDestocking(ShortfallAE, paddockGroup.Key);
                }
            }
        }
Esempio n. 10
0
        private void OnCLEMInitialiseActivity(object sender, EventArgs e)
        {
            this.InitialiseHerd(false, true);
            breedParams = Resources.GetResourceItem(this, typeof(RuminantHerd), this.PredictedHerdBreed, OnMissingResourceActionTypes.ReportErrorAndStop, OnMissingResourceActionTypes.ReportErrorAndStop) as RuminantType;

            // check GrazeFoodStoreExists
            if (GrazeFoodStoreName == null)
            {
                GrazeFoodStoreName = "";
            }
            if (GrazeFoodStoreName != "")
            {
                foodStore = Resources.GetResourceItem(this, typeof(GrazeFoodStore), GrazeFoodStoreName, OnMissingResourceActionTypes.ReportErrorAndStop, OnMissingResourceActionTypes.ReportErrorAndStop) as GrazeFoodStoreType;
            }
        }
        private void OnCLEMInitialiseActivity(object sender, EventArgs e)
        {
            // This method will only fire if the user has added this activity to the UI
            // Otherwise all details will be provided from GrazeAll code [CLEMInitialiseActivity]

            GrazeFoodStoreModel = Resources.FindResourceType <GrazeFoodStore, GrazeFoodStoreType>(this, GrazeFoodStoreTypeName, OnMissingResourceActionTypes.ReportErrorAndStop, OnMissingResourceActionTypes.ReportErrorAndStop);

            //Create list of children by breed
            foreach (RuminantType herdType in Resources.FindResourceGroup <RuminantHerd>().FindAllChildren <RuminantType>())
            {
                RuminantActivityGrazePastureHerd ragpb = new RuminantActivityGrazePastureHerd
                {
                    GrazeFoodStoreModel = GrazeFoodStoreModel,
                    RuminantTypeModel   = herdType,
                    Parent = this,
                    Clock  = this.Clock,
                    Name   = "Graze_" + (GrazeFoodStoreModel as Model).Name + "_" + herdType.Name
                };

                ragpb.SetLinkedModels(Resources);

                if (ragpb.Clock == null)
                {
                    ragpb.Clock = this.Clock;
                }

                ragpb.InitialiseHerd(true, true);

                if (ActivityList == null)
                {
                    ActivityList = new List <CLEMActivityBase>();
                }

                ActivityList.Add(ragpb);
                ragpb.ResourceShortfallOccurred += Paddock_ResourceShortfallOccurred;
                ragpb.ActivityPerformed         += BubbleHerd_ActivityPerformed;
            }
        }
Esempio n. 12
0
        private void OnCLEMInitialiseActivity(object sender, EventArgs e)
        {
            this.InitialiseHerd(false, false);

            // get herd to add to
            herdToUse = Resources.FindResourceType <RuminantHerd, RuminantType>(this, this.PredictedHerdName, OnMissingResourceActionTypes.ReportErrorAndStop, OnMissingResourceActionTypes.ReportErrorAndStop);

            if (!herdToUse.PricingAvailable())
            {
                Summary.WriteMessage(this, "No pricing is supplied for herd [" + PredictedHerdName + "] and so no pricing will be included with [" + this.Name + "]", MessageType.Warning);
            }

            // check GrazeFoodStoreExists
            grazeStore = "";
            if (GrazeFoodStoreName != null && !GrazeFoodStoreName.StartsWith("Not specified"))
            {
                grazeStore = GrazeFoodStoreName.Split('.').Last();
            }

            // check for managed paddocks and warn if animals placed in yards.
            if (grazeStore == "")
            {
                var ah = this.FindInScope <ActivitiesHolder>();
                if (ah.FindAllDescendants <PastureActivityManage>().Count() != 0)
                {
                    Summary.WriteMessage(this, String.Format("Trade 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 moved and will require feeding while in yards.\r\nSolution: Set the [GrazeFoodStore to place purchase in] located in the properties [General].[PastureDetails]", this.Name), MessageType.Warning);
                }
            }

            numberToStock = this.FindAllChildren <Relationship>().FirstOrDefault() as Relationship;
            if (numberToStock != null)
            {
                if (grazeStore != "")
                {
                    foodStore = Resources.FindResourceType <GrazeFoodStore, GrazeFoodStoreType>(this, GrazeFoodStoreName, OnMissingResourceActionTypes.ReportErrorAndStop, OnMissingResourceActionTypes.ReportErrorAndStop);
                }
            }
        }
Esempio n. 13
0
        private void OnCLEMAnimalStock(object sender, EventArgs e)
        {
            // this event happens after management has marked individuals for purchase or sale.
            if (Clock.Today.Month == AssessmentMonth)
            {
                // Get ENSO forcase for current time
                ENSOState ForecastEnsoState = GetENSOMeasure();

                // calculate dry season pasture available for each managed paddock holding stock
                RuminantHerd ruminantHerd = Resources.RuminantHerd();
                foreach (var newgroup in ruminantHerd.Herd.Where(a => a.Location != "").GroupBy(a => a.Location))
                {
                    // total adult equivalents of all breeds on pasture for utilisation
                    double AETotal = newgroup.Sum(a => a.AdultEquivalent);
                    // determine AE marked for sale and purchase of managed herd
                    double AEmarkedForSale = newgroup.Where(a => a.ReadyForSale & a.HerdName == HerdName).Sum(a => a.AdultEquivalent);
                    double AEPurchase      = ruminantHerd.PurchaseIndividuals.Where(a => a.Location == newgroup.Key & a.HerdName == HerdName).Sum(a => a.AdultEquivalent);

                    double herdChange = 1.0;
                    switch (ForecastEnsoState)
                    {
                    case ENSOState.Neutral:
                        break;

                    case ENSOState.ElNino:
                        GrazeFoodStoreType pasture = Resources.GetResourceItem(this, typeof(GrazeFoodStoreType), newgroup.Key, OnMissingResourceActionTypes.Ignore, OnMissingResourceActionTypes.Ignore) as GrazeFoodStoreType;
                        double             kgha    = pasture.TonnesPerHectare * 1000;
                        herdChange = this.PastureToStockingChangeElNino.SolveY(kgha, false);
                        break;

                    case ENSOState.LaNina:
                        pasture    = Resources.GetResourceItem(this, typeof(GrazeFoodStoreType), newgroup.Key, OnMissingResourceActionTypes.Ignore, OnMissingResourceActionTypes.Ignore) as GrazeFoodStoreType;
                        kgha       = pasture.TonnesPerHectare * 1000;
                        herdChange = this.PastureToStockingChangeLaNina.SolveY(kgha, false);
                        break;

                    default:
                        break;
                    }
                    if (herdChange > 1.0)
                    {
                        double AEtoBuy = Math.Max(0, (AETotal * herdChange) - AEPurchase);
                        HandleRestocking(AEtoBuy, newgroup.Key, newgroup.FirstOrDefault());
                    }
                    else if (herdChange < 1.0)
                    {
                        double AEtoSell = Math.Max(0, (AETotal * (1 - herdChange)) - AEmarkedForSale);
                        HandleDestocking(AEtoSell, newgroup.Key);
                    }

                    //switch (ForecastEnsoState)
                    //{
                    //    case ENSOState.Neutral:
                    //        break;
                    //    case ENSOState.LaNina:
                    //        double AEtoBuy = 0;
                    //        GrazeFoodStoreType pasture = Resources.GetResourceItem(typeof(GrazeFoodStoreType), newgroup.Key, out available) as GrazeFoodStoreType;
                    //        double kgha = pasture.TonnesPerHectare * 1000;
                    //        if (kgha > 3000)
                    //        {
                    //            AEtoBuy = AETotal * 0.2; //Buy 20% of Total Animal Equivalents
                    //        }
                    //        else if (kgha < 1000)
                    //        {
                    //            AEtoBuy = 0; //Don't buy any nore
                    //        }
                    //        else
                    //        {
                    //            AEtoBuy = AETotal * 0.1; //Buy 10 % of Total Animal Equivalents
                    //        }
                    //        // adjust for the AE already marked for purchase if any
                    //        AEtoBuy = Math.Max(0, AEtoBuy - AEPurchase);
                    //        HandleRestocking(AEtoBuy, newgroup.Key, newgroup.FirstOrDefault());
                    //        break;
                    //    case ENSOState.ElNino:
                    //        pasture = Resources.GetResourceItem(typeof(GrazeFoodStoreType), newgroup.Key, out available) as GrazeFoodStoreType;
                    //        kgha = pasture.TonnesPerHectare * 1000;
                    //        if (kgha > 3000)
                    //        {
                    //            ShortfallAE = AETotal * 0.1; //Sell 10% of Total Animal Equivalents
                    //        }
                    //        else if (kgha < 1000)
                    //        {
                    //            ShortfallAE = AETotal * 0.3; //Sell 30% of Total Animal Equivalents
                    //        }
                    //        else
                    //        {
                    //            ShortfallAE = AETotal * 0.2; //Sell 20 % of Total Animal Equivalents
                    //        }
                    //        // Adjust for AE already flagged for sale if any
                    //        ShortfallAE = Math.Max(0, ShortfallAE - AEmarkedForSale);
                    //        HandleDestocking(ShortfallAE, newgroup.Key);
                    //        break;
                    //    default:
                    //        break;
                    //}
                }
            }
        }
        private void OnCLEMAnimalStock(object sender, EventArgs e)
        {
            AeToDestock = 0;
            AeDestocked = 0;
            // this event happens after management has marked individuals for purchase or sale.
            if (clock.Today.Month == (int)AssessmentMonth)
            {
                this.Status = ActivityStatus.NotNeeded;
                // calculate dry season pasture available for each managed paddock holding stock not flagged for sale

                foreach (var paddockGroup in HerdResource.Herd.Where(a => (a.Location ?? "") != "").GroupBy(a => a.Location))
                {
                    // multiple breeds are currently not supported as we need to work out what to do with diferent AEs
                    if (paddockGroup.GroupBy(a => a.Breed).Count() > 1)
                    {
                        throw new ApsimXException(this, "Seasonal destocking paddocks containing multiple breeds is currently not supported\r\nActivity:" + this.Name + ", Paddock: " + paddockGroup.Key);
                    }

                    // total adult equivalents not marked for sale of all breeds on pasture for utilisation
                    double totalAE = paddockGroup.Where(a => a.SaleFlag == HerdChangeReason.None).Sum(a => a.AdultEquivalent);

                    double shortfallAE = 0;
                    // Determine total feed requirements for dry season for all ruminants on the pasture
                    // We assume that all ruminant have the BaseAnimalEquivalent to the specified herd

                    GrazeFoodStoreType pasture        = Resources.FindResourceType <GrazeFoodStore, GrazeFoodStoreType>(this, paddockGroup.Key, OnMissingResourceActionTypes.ReportErrorAndStop, OnMissingResourceActionTypes.ReportErrorAndStop);
                    double             pastureBiomass = pasture.Amount;

                    // Adjust fodder balance for detachment rate (6%/month in NABSA, user defined in CLEM, 3%)
                    // AL found the best estimate for AAsh Barkly example was 2/3 difference between detachment and carryover detachment rate with average 12month pool ranging from 10 to 96% and average 46% of total pasture.
                    double detachrate = pasture.DetachRate + ((pasture.CarryoverDetachRate - pasture.DetachRate) * 0.66);
                    // Assume a consumption rate of 2% of body weight.
                    double feedRequiredAE = paddockGroup.FirstOrDefault().BreedParams.BaseAnimalEquivalent * 0.02 * 30.4; //  2% of AE animal per day
                    for (int i = 0; i <= this.DrySeasonLength; i++)
                    {
                        // only include detachemnt if current biomass is positive, not already overeaten
                        if (pastureBiomass > 0)
                        {
                            pastureBiomass *= (1.0 - detachrate);
                        }

                        if (i > 0) // not in current month as already consumed by this time.
                        {
                            pastureBiomass -= (feedRequiredAE * totalAE);
                        }
                    }

                    // Shortfall in Fodder in kg per hectare
                    // pasture at end of period in kg/ha
                    double pastureShortFallKgHa = pastureBiomass / pasture.Manager.Area;
                    PasturePredicted = pastureShortFallKgHa;
                    // shortfall from low limit
                    pastureShortFallKgHa = Math.Max(0, FeedLowLimit - pastureShortFallKgHa);
                    // Shortfall in Fodder in kg for paddock
                    double pastureShortFallKg = pastureShortFallKgHa * pasture.Manager.Area;

                    if (pastureShortFallKg == 0)
                    {
                        return;
                    }

                    // number of AE to sell to balance shortfall_kg over entire season
                    shortfallAE = pastureShortFallKg / (feedRequiredAE * this.DrySeasonLength);
                    AeToDestock = shortfallAE;

                    // get prediction
                    HandleDestocking(shortfallAE, paddockGroup.Key);

                    // fire event to allow reporting of findings
                    OnReportStatus(new EventArgs());
                }
            }
            else
            {
                this.Status = ActivityStatus.Ignored;
            }
        }
        private void OnCLEMAnimalStock(object sender, EventArgs e)
        {
            AeToDestock = 0;
            AeDestocked = 0;
            AeToRestock = 0;
            AeRestocked = 0;

            // this event happens after management has marked individuals for purchase or sale.
            if (this.TimingOK)
            {
                // Get ENSO forcase for current time
                ENSOState forecastEnsoState = GetENSOMeasure();

                this.Status = ActivityStatus.NotNeeded;

                // calculate dry season pasture available for each managed paddock holding stock
                RuminantHerd ruminantHerd = Resources.RuminantHerd();
                foreach (var newgroup in ruminantHerd.Herd.Where(a => a.Location != "").GroupBy(a => a.Location))
                {
                    double aELocationNeeded = 0;

                    // total adult equivalents of all breeds on pasture for utilisation
                    double totalAE = newgroup.Sum(a => a.AdultEquivalent);
                    // determine AE marked for sale and purchase of managed herd
                    double markedForSaleAE = newgroup.Where(a => a.ReadyForSale).Sum(a => a.AdultEquivalent);
                    double purchaseAE      = ruminantHerd.PurchaseIndividuals.Where(a => a.Location == newgroup.Key).Sum(a => a.AdultEquivalent);

                    double herdChange        = 1.0;
                    bool   relationshipFound = false;
                    switch (forecastEnsoState)
                    {
                    case ENSOState.Neutral:
                        break;

                    case ENSOState.ElNino:
                        if (!(pastureToStockingChangeElNino is null))
                        {
                            GrazeFoodStoreType pasture = Resources.GetResourceItem(this, typeof(GrazeFoodStoreType), newgroup.Key, OnMissingResourceActionTypes.Ignore, OnMissingResourceActionTypes.Ignore) as GrazeFoodStoreType;
                            double             kgha    = pasture.TonnesPerHectare * 1000;
                            herdChange        = pastureToStockingChangeElNino.SolveY(kgha);
                            relationshipFound = true;
                        }
                        break;

                    case ENSOState.LaNina:
                        if (!(pastureToStockingChangeLaNina is null))
                        {
                            GrazeFoodStoreType pasture = Resources.GetResourceItem(this, typeof(GrazeFoodStoreType), newgroup.Key, OnMissingResourceActionTypes.Ignore, OnMissingResourceActionTypes.Ignore) as GrazeFoodStoreType;
                            double             kgha    = pasture.TonnesPerHectare * 1000;
                            herdChange        = pastureToStockingChangeLaNina.SolveY(kgha);
                            relationshipFound = true;
                        }
                        break;

                    default:
                        break;
                    }
                    if (!relationshipFound)
                    {
                        string warn = $"No pasture biomass to herd change proportion [Relationship] provided for {((forecastEnsoState== ENSOState.ElNino)? "El Niño":"La Niña")} phase in [a={this.Name}]\r\nNo stock management will be performed in this phase.";
                        this.Status = ActivityStatus.Warning;
                        if (!Warnings.Exists(warn))
                        {
                            Summary.WriteWarning(this, warn);
                            Warnings.Add(warn);
                        }
                    }

                    if (herdChange > 1.0)
                    {
                        aELocationNeeded = Math.Max(0, (totalAE * herdChange) - purchaseAE);
                        AeToRestock     += aELocationNeeded;
                        double notHandled = HandleRestocking(aELocationNeeded, newgroup.Key, newgroup.FirstOrDefault());
                        AeRestocked += (aELocationNeeded - notHandled);
                    }
                    else if (herdChange < 1.0)
                    {
                        aELocationNeeded = Math.Max(0, (totalAE * (1 - herdChange)) - markedForSaleAE);
                        AeToDestock     += aELocationNeeded;
                        double notHandled = HandleDestocking(AeToDestock, newgroup.Key);
                        AeDestocked += (aELocationNeeded - notHandled);
                    }
                }

                if (this.Status != ActivityStatus.Warning & AeToDestock + AeToRestock > 0)
                {
                    if (Math.Max(0, AeToRestock - AeRestocked) + Math.Max(0, AeToDestock - AeDestocked) == 0)
                    {
                        this.Status = ActivityStatus.Success;
                    }
                    else
                    {
                        this.Status = ActivityStatus.Partial;
                    }
                }
            }
        }
Esempio n. 16
0
        private void OnCommencing(object sender, EventArgs e)
        {
            dataToWriteToDb = null;
            // sanitise the variable names and remove duplicates
            IModel        zone          = Apsim.Parent(this, typeof(Zone));
            List <string> variableNames = new List <string>();

            if (VariableNames != null)
            {
                for (int i = 0; i < this.VariableNames.Length; i++)
                {
                    // each variable name is now a GrazeFoodStoreType
                    bool isDuplicate = StringUtilities.IndexOfCaseInsensitive(variableNames, this.VariableNames[i].Trim()) != -1;
                    if (!isDuplicate && this.VariableNames[i] != string.Empty)
                    {
                        if (this.VariableNames[i].StartsWith("["))
                        {
                            variableNames.Add(this.VariableNames[i]);
                        }
                        else
                        {
                            string[] splitName = this.VariableNames[i].Split('.');
                            if (splitName.Count() == 2)
                            {
                                // get specified grazeFoodStoreType
                                grazeStore = Resources.GetResourceItem(this, typeof(GrazeFoodStore), splitName[0], OnMissingResourceActionTypes.Ignore, OnMissingResourceActionTypes.ReportErrorAndStop) as GrazeFoodStoreType;

                                // make each pool entry
                                for (int j = 0; j <= 12; j++)
                                {
                                    variableNames.Add(splitName[0] + "-" + j.ToString() + "-" + splitName[1]);
                                }
                                if (splitName[1] == "Amount")
                                {
                                    // add amounts
                                    variableNames.Add("[Resources].GrazeFoodStore." + splitName[0] + ".Amount as Total amount");
                                    variableNames.Add("[Resources].GrazeFoodStore." + splitName[0] + ".KilogramsPerHa as Total kgPerHa");
                                }
                            }
                            else
                            {
                                throw new ApsimXException(this, "Invalid report property. Expecting full property link or GrazeFoodStoreTypeName.Property");
                            }
                        }
                    }
                }
                // check if clock.today was included.
                if (!variableNames.Contains("[Clock].Today"))
                {
                    variableNames.Insert(0, "[Clock].Today");
                }
            }
            // Tidy up variable/event names.
            VariableNames = variableNames.ToArray();
            VariableNames = TidyUpVariableNames();
            EventNames    = TidyUpEventNames();
            this.FindVariableMembers();

            // Subscribe to events.
            if (EventNames == null || EventNames.Count() == 0)
            {
                events.Subscribe("[Clock].CLEMHerdSummary", DoOutputEvent);
            }
            else
            {
                foreach (string eventName in EventNames)
                {
                    if (eventName != string.Empty)
                    {
                        events.Subscribe(eventName.Trim(), DoOutputEvent);
                    }
                }
            }
        }
        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));
                }
            }
        }