Пример #1
0
 /// <summary>
 /// Method to set defaults from
 /// </summary>
 public void SetDefaults()
 {
     //Iterate through properties
     foreach (var property in GetType().GetProperties())
     {
         //Iterate through attributes of this property
         foreach (Attribute attr in property.GetCustomAttributes(true))
         {
             //does this property have [DefaultValueAttribute]?
             if (attr is System.ComponentModel.DefaultValueAttribute)
             {
                 //So lets try to load default value to the property
                 System.ComponentModel.DefaultValueAttribute dv = (System.ComponentModel.DefaultValueAttribute)attr;
                 try
                 {
                     object result = property.GetValue(this, null);
                     if (result is null)
                     {
                         //Is it an array?
                         if (property.PropertyType.IsArray)
                         {
                             property.SetValue(this, dv.Value, null);
                         }
                         else
                         {
                             //Use set value for.. not arrays
                             property.SetValue(this, dv.Value, null);
                         }
                     }
                 }
                 catch (Exception ex)
                 {
                     Summary.WriteWarning(this, ex.Message);
                     //eat it... Or maybe Debug.Writeline(ex);
                 }
             }
         }
     }
 }
Пример #2
0
        private void OnSimulationCommencing(object sender, EventArgs e)
        {
            // check payment interval > 0
            if (PaymentInterval <= 0)
            {
                Summary.WriteWarning(this, String.Format("Overhead payment interval must be greater than 1 ({0})", this.Name));
                throw new Exception(String.Format("Invalid payment interval supplied for overhead {0}", this.Name));
            }

            if (MonthDue >= Clock.StartDate.Month)
            {
                NextDueDate = new DateTime(Clock.StartDate.Year, MonthDue, Clock.StartDate.Day);
            }
            else
            {
                NextDueDate = new DateTime(Clock.StartDate.Year, MonthDue, Clock.StartDate.Day);
                while (Clock.StartDate > NextDueDate)
                {
                    NextDueDate = NextDueDate.AddMonths(PaymentInterval);
                }
            }
        }
Пример #3
0
        /// <summary>Removes plant material simulating a graze event.</summary>
        /// <param name="type">The type of amount being defined (SetResidueAmount or SetRemoveAmount)</param>
        /// <param name="amount">The DM amount (g/m2)</param>
        /// <param name="summary">Optional summary object.</param>
        public void RemoveBiomass(string type, double amount, ISummary summary = null)
        {
            double harvestableWt = Material.Sum(m => m.Consumable.Wt);

            if (!MathUtilities.FloatsAreEqual(harvestableWt, 0.0))
            {
                // Get the amount required to remove
                double amountRequired;
                if (type.ToLower() == "setresidueamount")
                {
                    // Remove all DM above given residual amount
                    amountRequired = Math.Max(0.0, harvestableWt - amount);
                }
                else if (type.ToLower() == "setremoveamount")
                {
                    // Remove a given amount
                    amountRequired = Math.Max(0.0, amount);
                }
                else
                {
                    throw new Exception("Type of amount to remove on graze not recognized (use \'SetResidueAmount\' or \'SetRemoveAmount\'");
                }

                // Get the actual amount to remove
                double amountToRemove = Math.Max(0.0, Math.Min(amountRequired, harvestableWt));

                // Do the actual removal
                if (!MathUtilities.FloatsAreEqual(amountToRemove, 0, 0.0001))
                {
                    RemoveBiomass(amountToRemove);
                }
            }
            else
            {
                summary.WriteWarning(forageModel as IModel, "Could not graze due to lack of DM available");
            }
        }
Пример #4
0
        /// <summary>
        /// Create the individual ruminant animals using the Cohort parameterisations.
        /// </summary>
        /// <returns></returns>
        public List <Ruminant> CreateIndividuals()
        {
            List <Ruminant> Individuals = new List <Ruminant>();

            RuminantType parent = this.Parent.Parent as RuminantType;

            // get Ruminant Herd resource for unique ids
            RuminantHerd ruminantHerd = Resources.RuminantHerd();

            if (Number > 0)
            {
                for (int i = 1; i <= Number; i++)
                {
                    object ruminantBase = null;
                    if (this.Gender == Sex.Male)
                    {
                        ruminantBase = new RuminantMale();
                    }
                    else
                    {
                        ruminantBase = new RuminantFemale();
                    }

                    Ruminant ruminant = ruminantBase as Ruminant;

                    ruminant.ID          = ruminantHerd.NextUniqueID;
                    ruminant.BreedParams = parent;
                    ruminant.Breed       = parent.Breed;
                    ruminant.HerdName    = parent.Name;
                    ruminant.Gender      = Gender;
                    ruminant.Age         = Age;
                    ruminant.SaleFlag    = HerdChangeReason.None;
                    if (Suckling)
                    {
                        ruminant.SetUnweaned();
                    }
                    if (Sire)
                    {
                        if (this.Gender == Sex.Male)
                        {
                            RuminantMale ruminantMale = ruminantBase as RuminantMale;
                            ruminantMale.BreedingSire = true;
                        }
                        else
                        {
                            Summary.WriteWarning(this, "Breeding sire switch is not valid for individual females");
                        }
                    }

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

                    if (this.Gender == Sex.Female)
                    {
                        RuminantFemale ruminantFemale = ruminantBase as RuminantFemale;
                        ruminantFemale.DryBreeder         = true;
                        ruminantFemale.WeightAtConception = ruminant.Weight;
                        ruminantFemale.NumberOfBirths     = 0;
                    }

                    Individuals.Add(ruminantBase as Ruminant);
                }
            }

            return(Individuals);
        }
Пример #5
0
        /// <summary>Checks for soil for errors.</summary>
        private void CheckForErrors()
        {
            const double specific_bd = 2.65;

            double min_sw = 0.0;

            for (int i = 0; i < properties.Water.Thickness.Length; i++)
            {
                double max_sw = 1.0 - MathUtilities.Divide(properties.Water.BD[i], specific_bd, 0.0); // ie. Total Porosity

                if (MathUtilities.IsLessThan(properties.Water.AirDry[i], min_sw))
                {
                    summary.WriteWarning(this, String.Format("({0} {1:G}) {2} {3} {4} {5} {6:G})",
                                                             " Air dry lower limit of ",
                                                             properties.Water.AirDry[i],
                                                             " in layer ",
                                                             i,
                                                             "\n",
                                                             "         is below acceptable value of ",
                                                             min_sw));
                }

                if (MathUtilities.IsLessThan(properties.Water.LL15[i], properties.Water.AirDry[i]))
                {
                    summary.WriteWarning(this, String.Format("({0} {1:G}) {2} {3} {4} {5} {6:G})",
                                                             " 15 bar lower limit of ",
                                                             properties.Water.LL15[i],
                                                             " in layer ",
                                                             i,
                                                             "\n",
                                                             "         is below air dry value of ",
                                                             properties.Water.AirDry[i]));
                }

                if (MathUtilities.IsLessThanOrEqual(properties.Water.DUL[i], properties.Water.LL15[i]))
                {
                    summary.WriteWarning(this, String.Format("({0} {1:G}) {2} {3} {4} {5} {6:G})",
                                                             " drained upper limit of ",
                                                             properties.Water.DUL[i],
                                                             " in layer ",
                                                             i,
                                                             "\n",
                                                             "         is at or below lower limit of ",
                                                             properties.Water.LL15[i]));
                }

                if (MathUtilities.IsLessThanOrEqual(properties.Water.SAT[i], properties.Water.DUL[i]))
                {
                    summary.WriteWarning(this, String.Format("({0} {1:G}) {2} {3} {4} {5} {6:G})",
                                                             " saturation of ",
                                                             properties.Water.SAT[i],
                                                             " in layer ",
                                                             i,
                                                             "\n",
                                                             "         is at or below drained upper limit of ",
                                                             properties.Water.DUL[i]));
                }

                if (MathUtilities.IsGreaterThan(properties.Water.SAT[i], max_sw))
                {
                    summary.WriteWarning(this, String.Format("({0} {1:G}) {2} {3} {4} {5} {6:G} {7} {8} {9:G} {10} {11} {12:G})",
                                                             " saturation of ",
                                                             properties.Water.SAT[i],
                                                             " in layer ",
                                                             i,
                                                             "\n",
                                                             "         is above acceptable value of ",
                                                             max_sw,
                                                             "\n",
                                                             "You must adjust bulk density (bd) to below ",
                                                             (1.0 - properties.Water.SAT[i]) * specific_bd,
                                                             "\n",
                                                             "OR saturation (sat) to below ",
                                                             max_sw));
                }

                if (MathUtilities.IsGreaterThan(Water[i], properties.Water.SAT[i]))
                {
                    summary.WriteWarning(this, String.Format("({0} {1:G}) {2} {3} {4} {5} {6:G}",
                                                             " soil water of ",
                                                             Water[i],
                                                             " in layer ",
                                                             i,
                                                             "\n",
                                                             "         is above saturation of ",
                                                             properties.Water.SAT[i]));
                }

                if (MathUtilities.IsLessThan(Water[i], properties.Water.AirDry[i]))
                {
                    summary.WriteWarning(this, String.Format("({0} {1:G}) {2} {3} {4} {5} {6:G}",
                                                             " soil water of ",
                                                             Water[i],
                                                             " in layer ",
                                                             i,
                                                             "\n",
                                                             "         is below air-dry value of ",
                                                             properties.Water.AirDry[i]));
                }
            }
        }
Пример #6
0
        /// <summary>Partitions the dm.</summary>
        /// <param name="Organs">The organs.</param>
        /// <exception cref="System.Exception">Unknown Partition Rule  + PartitionRules[i]</exception>
        internal void PartitionDM(List <Organ1> Organs)
        {
            // Get all DM supply terms.
            DMSupply = 0;
            foreach (Organ1 Organ in Organs)
            {
                DMSupply += Organ.DMSupply;
            }

            // Tell each organ to do it's DM Demand
            foreach (Organ1 Organ in Organs)
            {
                Organ.DoDMDemand(DMSupply);
            }

            foreach (Organ1 Organ in Organs)
            {
                Organ.Growth.Clear();
            }

            double dm_remaining     = DMSupply;
            double dlt_dm_green_tot = 0.0;

            for (int i = 0; i != PartitionOrgans.Length; i++)
            {
                Organ1 Organ = FindOrgan(PartitionOrgans[i], Organs);

                if (PartitionRules[i] == "magic")
                {
                    Organ.GiveDmGreen(RatioRootShoot.Value * DMSupply);
                }
                else if (PartitionRules[i] == "seasonal")                  // (PFR)
                {
                    double uptake = RatioRootPlant * dm_remaining;
                    Organ.GiveDmGreen(uptake);                               // (PFR)
                    dm_remaining     = dm_remaining - uptake;                // Here total RUE is used so remaining discounts root uptake(PFR)
                    dlt_dm_green_tot = dlt_dm_green_tot + uptake;
                }

                else
                {
                    double uptake;
                    if (PartitionRules[i] == "demand")
                    {
                        uptake = Math.Min(Organ.DMGreenDemand, dm_remaining);
                    }
                    else if (PartitionRules[i] == "frac")
                    {
                        uptake = Math.Min(FracDMRemainingInPart(Organ.Name) * dm_remaining, Organ.DMGreenDemand);
                    }
                    else if (PartitionRules[i] == "remainder")
                    {
                        uptake = dm_remaining;
                    }
                    else
                    {
                        throw new Exception("Unknown Partition Rule " + PartitionRules[i]);
                    }

                    Organ.GiveDmGreen(uptake);
                    dm_remaining     = dm_remaining - uptake;
                    dlt_dm_green_tot = dlt_dm_green_tot + uptake;
                }
            }


            if (!MathUtilities.FloatsAreEqual(dlt_dm_green_tot, DMSupply, 1.0E-4f))
            {
                string msg = "dlt_dm_green_tot mass balance is off: "
                             + dlt_dm_green_tot.ToString("f6")
                             + " vs "
                             + DMSupply.ToString("f6");
                Summary.WriteWarning(this, msg);
            }

            Util.Debug("Arbitrator.DMSupply=%f", DMSupply);
            Util.Debug("Arbitrator.dlt_dm_green_tot=%f", dlt_dm_green_tot);
        }
Пример #7
0
        /// <summary>
        /// Internal method to iterate through all children in CLEM and report any parameter setting errors
        /// </summary>
        /// <param name="model"></param>
        /// <param name="modelPath">Pass blank string. Used for tracking model path</param>
        /// <returns>Boolean indicating whether validation was successful</returns>
        private bool Validate(IModel model, string modelPath)
        {
            string starter = "[";

            if (typeof(IResourceType).IsAssignableFrom(model.GetType()))
            {
                starter = "[r=";
            }
            if (model.GetType() == typeof(ResourcesHolder))
            {
                starter = "[r=";
            }
            if (model.GetType().IsSubclassOf(typeof(ResourceBaseWithTransactions)))
            {
                starter = "[r=";
            }
            if (model.GetType() == typeof(ActivitiesHolder))
            {
                starter = "[a=";
            }
            if (model.GetType().IsSubclassOf(typeof(CLEMActivityBase)))
            {
                starter = "[a=";
            }
            if (model.GetType().Name.Contains("Group"))
            {
                starter = "[f=";
            }
            if (model.GetType().Name.Contains("Timer"))
            {
                starter = "[f=";
            }
            if (model.GetType().Name.Contains("Filter"))
            {
                starter = "[f=";
            }

            modelPath += starter + model.Name + "]";
            modelPath  = modelPath.Replace("][", "]&shy;[");
            bool valid             = true;
            var  validationContext = new ValidationContext(model, null, null);
            var  validationResults = new List <ValidationResult>();

            Validator.TryValidateObject(model, validationContext, validationResults, true);
            if (model.Name.EndsWith(" "))
            {
                validationResults.Add(new ValidationResult("Component name cannot end with a space character", new string[] { "Name" }));
            }

            if (validationResults.Count > 0)
            {
                valid = false;
                // report all errors
                foreach (var validateError in validationResults)
                {
                    // get description
                    string text     = "";
                    var    property = model.GetType().GetProperty(validateError.MemberNames.FirstOrDefault());
                    if (property != null)
                    {
                        text = "";
                        if (property.GetCustomAttributes(typeof(DescriptionAttribute), true).Count() > 0)
                        {
                            var attribute   = property.GetCustomAttributes(typeof(DescriptionAttribute), true)[0];
                            var description = (DescriptionAttribute)attribute;
                            text = description.ToString();
                        }
                    }
                    string error = String.Format("@validation:Invalid parameter value in " + modelPath + "" + Environment.NewLine + "PARAMETER: " + validateError.MemberNames.FirstOrDefault());
                    if (text != "")
                    {
                        error += String.Format(Environment.NewLine + "DESCRIPTION: " + text);
                    }
                    error += String.Format(Environment.NewLine + "PROBLEM: " + validateError.ErrorMessage + Environment.NewLine);
                    Summary.WriteWarning(this, error);
                }
            }
            foreach (var child in model.Children)
            {
                bool result = Validate(child, modelPath);
                if (valid && !result)
                {
                    valid = false;
                }
            }
            return(valid);
        }
Пример #8
0
 /// <summary>
 /// Issues the warning.
 /// </summary>
 /// <param name="warningText">The warning text.</param>
 public void IssueWarning(string warningText)
 {
     Summary.WriteWarning(thismodel, warningText);
 }
Пример #9
0
        /// <summary>Removes a given amount of biomass (and N) from the plant.</summary>
        /// <param name="amountToRemove">The amount of biomass to remove (g/m2).</param>
        /// <param name="PreferenceForGreenOverDead">Relative preference for live over dead material during graze (>0.0).</param>
        /// <param name="PreferenceForLeafOverStems">Relative preference for leaf over stem-stolon material during graze (>0.0).</param>
        /// <param name="summary">Optional summary object.</param>
        public DigestibleBiomass RemoveBiomass(double amountToRemove,
                                               double PreferenceForGreenOverDead = 1.0,
                                               double PreferenceForLeafOverStems = 1.0,
                                               ISummary summary = null)
        {
            if (!MathUtilities.FloatsAreEqual(amountToRemove, 0.0))
            {
                var allMaterial = Material.ToList();

                // get existing DM and N amounts
                double harvestableWt     = allMaterial.Sum(m => m.Consumable.Wt);
                double preRemovalDMShoot = harvestableWt;
                double preRemovalNShoot  = allMaterial.Sum(m => m.Consumable.N);

                // Compute the fraction of each tissue to be removed
                var fracRemoving = new List <FractionDigestibleBiomass>();
                if (MathUtilities.FloatsAreEqual(amountToRemove - harvestableWt, 0.0))
                {
                    // All existing DM is removed
                    amountToRemove = harvestableWt;
                    foreach (var material in allMaterial)
                    {
                        double frac = MathUtilities.Divide(material.Consumable.Wt, harvestableWt, 0.0);
                        fracRemoving.Add(new FractionDigestibleBiomass(material, frac));
                    }
                }
                else
                {
                    // Initialise the fractions to be removed (these will be normalised later)
                    foreach (var material in allMaterial)
                    {
                        double frac;
                        if (material.IsLive)
                        {
                            if (material.Name == "Leaf")
                            {
                                frac = material.Consumable.Wt * PreferenceForGreenOverDead * PreferenceForLeafOverStems;
                            }
                            else
                            {
                                frac = material.Consumable.Wt * PreferenceForGreenOverDead;
                            }
                        }
                        else
                        {
                            if (material.Name == "Leaf")
                            {
                                frac = material.Consumable.Wt * PreferenceForLeafOverStems;
                            }
                            else
                            {
                                frac = material.Consumable.Wt;
                            }
                        }
                        fracRemoving.Add(new FractionDigestibleBiomass(material, frac));
                    }

                    // Normalise the fractions of each tissue to be removed, they should add to one
                    double totalFrac = fracRemoving.Sum(m => m.Fraction);
                    foreach (var f in fracRemoving)
                    {
                        double fracRemovable = f.Material.Consumable.Wt / amountToRemove;
                        f.Fraction = Math.Min(fracRemovable, f.Fraction / totalFrac);
                    }

                    // Iterate until sum of fractions to remove is equal to one
                    //  The initial normalised fractions are based on preference and existing DM. Because the value of fracRemoving is limited
                    //   to fracRemovable, the sum of fracRemoving may not be equal to one, as it should be. We need to iterate adjusting the
                    //   values of fracRemoving until we get a sum close enough to one. The previous values are used as weighting factors for
                    //   computing new ones at each iteration.
                    int count = 1;
                    totalFrac = totalFrac = fracRemoving.Sum(m => m.Fraction);
                    while (!MathUtilities.FloatsAreEqual(1.0 - totalFrac, 0.0))
                    {
                        count += 1;
                        foreach (var f in fracRemoving)
                        {
                            double fracRemovable = f.Material.Consumable.Wt / amountToRemove;
                            f.Fraction = Math.Min(fracRemovable, f.Fraction / totalFrac);
                        }
                        totalFrac = totalFrac = fracRemoving.Sum(m => m.Fraction);
                        if (count > 1000)
                        {
                            summary?.WriteWarning(forageModel as IModel, "SimpleGrazing could not remove or graze all the DM required for " + forageModel.Name);
                            break;
                        }
                    }
                }

                // Get digestibility of DM being harvested (do this before updating pools)
                double defoliatedDigestibility = fracRemoving.Sum(m => m.Material.Digestibility * m.Fraction);

                // Iterate through all live material, find the associated dead material and then
                // tell the forage model to remove it.
                var liveMaterial = fracRemoving.Where(f => f.Material.IsLive).ToList();
                foreach (var live in liveMaterial)
                {
                    var dead = fracRemoving.Find(frac => frac.Material.Name == live.Material.Name &&
                                                 !frac.Material.IsLive);
                    if (dead == null)
                    {
                        throw new Exception("Cannot find associated dead material while removing biomass in SimpleGrazing");
                    }

                    RemoveBiomass(live.Material.Name, new OrganBiomassRemovalType()
                    {
                        FractionLiveToRemove = Math.Max(0.0, MathUtilities.Divide(amountToRemove * live.Fraction, live.Material.Total.Wt, 0.0)),
                        FractionDeadToRemove = Math.Max(0.0, MathUtilities.Divide(amountToRemove * dead.Fraction, dead.Material.Total.Wt, 0.0))
                    });
                }

                if (liveMaterial.Count == 0)
                {
                    var deadMaterial = fracRemoving.Where(f => !f.Material.IsLive).ToList();
                    foreach (var dead in deadMaterial)
                    {
                        // This can happen for surface organic matter which only has dead material.
                        RemoveBiomass(dead.Material.Name, new OrganBiomassRemovalType()
                        {
                            FractionLiveToRemove = 0,
                            FractionDeadToRemove = Math.Max(0.0, MathUtilities.Divide(amountToRemove * dead.Fraction, dead.Material.Consumable.Wt, 0.0))
                        });
                    }
                }

                // Set outputs and check balance
                var defoliatedDM = preRemovalDMShoot - Material.Sum(m => m.Consumable.Wt);
                var defoliatedN  = preRemovalNShoot - Material.Sum(m => m.Consumable.N);
                if (!MathUtilities.FloatsAreEqual(defoliatedDM, amountToRemove))
                {
                    throw new Exception("Removal of DM resulted in loss of mass balance");
                }
                else
                {
                    summary?.WriteMessage(forageModel as IModel, "Biomass removed from " + forageModel.Name + " by grazing: " + (defoliatedDM * 10).ToString("#0.0") + "kg/ha");
                }

                return(new DigestibleBiomass(new DamageableBiomass(Name, new Biomass()
                {
                    StructuralWt = defoliatedDM,
                    StructuralN = defoliatedN,
                }, isLive: true), defoliatedDigestibility));
            }
            return(null);
        }
Пример #10
0
        /// <summary>
        /// Try to take the Resources based on Resource Request List provided.
        /// Returns true if it was able to take the resources it needed.
        /// Returns false if it was unable to take the resources it needed.
        /// </summary>
        /// <param name="ResourceRequestList"></param>
        /// <param name="TriggerActivityPerformed"></param>
        public bool TakeResources(List <ResourceRequest> ResourceRequestList, bool TriggerActivityPerformed)
        {
            bool resourceAvailable = false;

            // no resources required or this is an Activity folder.
            if ((ResourceRequestList == null) || (ResourceRequestList.Count() == 0))
            {
                return(false);
            }

            Guid uniqueRequestID = Guid.NewGuid();

            // check resource amounts available
            foreach (ResourceRequest request in ResourceRequestList)
            {
                request.ActivityID = uniqueRequestID;
                request.Available  = 0;
                // get resource
                if (request.Resource == null)
                {
                    //If it hasn't been assigned try and find it now.
                    request.Resource = Resources.GetResourceItem(request, OnMissingResourceActionTypes.Ignore, OnMissingResourceActionTypes.Ignore) as IResourceType;
                }
                if (request.Resource != null)
                {
                    // get amount available
                    request.Available = Math.Min(request.Resource.Amount, request.Required);
                }
                else
                {
                    if (!resourceAvailable)
                    {
                        // if resource does not exist in simulation assume unlimited resource available
                        // otherwise 0 will be assigned to available when no resouces match request
                        request.Available = request.Required;
                    }
                }
            }

            // are all resources available
            List <ResourceRequest> shortfallRequests = ResourceRequestList.Where(a => a.Required > a.Available).ToList();
            int countShortfallRequests = shortfallRequests.Count();

            if (countShortfallRequests > 0)
            {
                // check what transmutations can occur
                Resources.TransmutateShortfall(shortfallRequests, true);
            }

            // check if need to do transmutations
            int  countTransmutationsSuccessful = shortfallRequests.Where(a => a.TransmutationPossible == true & a.AllowTransmutation).Count();
            bool allTransmutationsSuccessful   = (shortfallRequests.Where(a => a.TransmutationPossible == false & a.AllowTransmutation).Count() == 0);

            // OR at least one transmutation successful and PerformWithPartialResources
            if (((countShortfallRequests > 0) & (countShortfallRequests == countTransmutationsSuccessful)) || (countTransmutationsSuccessful > 0 & OnPartialResourcesAvailableAction == OnPartialResourcesAvailableActionTypes.UseResourcesAvailable))
            {
                // do transmutations.
                Resources.TransmutateShortfall(shortfallRequests, false);

                // recheck resource amounts now that resources have been topped up
                foreach (ResourceRequest request in ResourceRequestList)
                {
                    // get resource
                    request.Available = 0;
                    if (request.Resource != null)
                    {
                        // get amount available
                        request.Available = Math.Min(request.Resource.Amount, request.Required);
                    }
                }
            }

            // report any resource defecits here
            foreach (var item in ResourceRequestList.Where(a => a.Required > a.Available))
            {
                ResourceRequestEventArgs rrEventArgs = new ResourceRequestEventArgs()
                {
                    Request = item
                };
                OnShortfallOccurred(rrEventArgs);
                Status = ActivityStatus.Partial;
            }

            // remove activity resources
            // check if deficit and performWithPartial
            if ((ResourceRequestList.Where(a => a.Required > a.Available).Count() == 0) || OnPartialResourcesAvailableAction != OnPartialResourcesAvailableActionTypes.SkipActivity)
            {
                if (OnPartialResourcesAvailableAction == OnPartialResourcesAvailableActionTypes.ReportErrorAndStop)
                {
                    string resourcelist = "";
                    foreach (var item in ResourceRequestList.Where(a => a.Required > a.Available))
                    {
                        Summary.WriteWarning(this, String.Format("Insufficient ({0}) resource of type ({1}) for activity ({2})", item.ResourceType, item.ResourceTypeName, this.Name));
                        resourcelist += ((resourcelist.Length > 0)?",":"") + item.ResourceType.Name;
                    }
                    if (resourcelist.Length > 0)
                    {
                        Summary.WriteWarning(this, String.Format("Ensure resources are available or change OnPartialResourcesAvailableAction setting for activity ({0}) to handle previous error", this.Name));
                        Status = ActivityStatus.Critical;
                        throw new Exception(String.Format("Insufficient resources ({0}) for activity ({1}) (see Summary for details)", resourcelist, this.Name));
                    }
                }

                foreach (ResourceRequest request in ResourceRequestList)
                {
                    // get resource
                    request.Provided = 0;
                    if (request.Resource != null)
                    {
                        // remove resource
                        request.Resource.Remove(request);
                    }
                }
                //return true; //could take all the resources it needed or is able to do with partial amounts
            }
            else
            {
                Status = ActivityStatus.Ignored;
                //return false;  //could not take all the resources it needed.
            }

            return(Status != ActivityStatus.Ignored);
        }
Пример #11
0
        private void OnStartOfSimulation(object sender, EventArgs e)
        {
            // This needs to happen after all herd creation has been performed
            // Therefore we use StartOfSimulation event

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

            // get list of females of breeding age and condition
            List <RuminantFemale> breedFemales = herd.Where(a => a.Gender == Sex.Female & a.Age >= a.BreedParams.MinimumAge1stMating + 12 & a.Weight >= (a.BreedParams.MinimumSize1stMating * a.StandardReferenceWeight) & a.Weight >= (a.BreedParams.CriticalCowWeight * a.StandardReferenceWeight)).OrderByDescending(a => a.Age).ToList().Cast <RuminantFemale>().ToList();

            // get list of all sucking individuals
            List <Ruminant> sucklingList = herd.Where(a => a.Weaned == false).ToList();

            if (breedFemales.Count() == 0)
            {
                if (sucklingList.Count > 0)
                {
                    Summary.WriteWarning(this, String.Format("No breeding females to assign sucklings for herd ({0})", HerdName));
                }
                return;
            }

            // gestation interval at smallest size generalised curve
            double minAnimalWeight = breedFemales[0].StandardReferenceWeight - ((1 - breedFemales[0].BreedParams.SRWBirth) * breedFemales[0].StandardReferenceWeight) * Math.Exp(-(breedFemales[0].BreedParams.AgeGrowthRateCoefficient * (breedFemales[0].BreedParams.MinimumAge1stMating * 30.4)) / (Math.Pow(breedFemales[0].StandardReferenceWeight, breedFemales[0].BreedParams.SRWGrowthScalar)));
            double IPIminsize      = Math.Pow(breedFemales[0].BreedParams.InterParturitionIntervalIntercept * (minAnimalWeight / breedFemales[0].StandardReferenceWeight), breedFemales[0].BreedParams.InterParturitionIntervalCoefficient) * 30.64;

            // restrict minimum period between births
            IPIminsize = Math.Max(IPIminsize, breedFemales[0].BreedParams.GestationLength + 61);

            // assign calves to cows
            foreach (var suckling in sucklingList)
            {
                if (breedFemales.Count > 0)
                {
                    breedFemales[0].DryBreeder = false;

                    //Initialise female milk production in at birth so ready for sucklings to consume
                    double milkTime       = 15;               // equivalent to mid month production
                    double milkProduction = breedFemales[0].BreedParams.MilkPeakYield * breedFemales[0].Weight / breedFemales[0].NormalisedAnimalWeight * (Math.Pow(((milkTime + breedFemales[0].BreedParams.MilkOffsetDay) / breedFemales[0].BreedParams.MilkPeakDay), breedFemales[0].BreedParams.MilkCurveSuckling)) * Math.Exp(breedFemales[0].BreedParams.MilkCurveSuckling * (1 - (milkTime + breedFemales[0].BreedParams.MilkOffsetDay) / breedFemales[0].BreedParams.MilkPeakDay));
                    breedFemales[0].MilkProduction = Math.Max(milkProduction, 0.0);
                    breedFemales[0].MilkAmount     = milkProduction * 30.4;

                    // generalised curve
                    double IPIcurrent = Math.Pow(breedFemales[0].BreedParams.InterParturitionIntervalIntercept * (breedFemales[0].Weight / breedFemales[0].StandardReferenceWeight), breedFemales[0].BreedParams.InterParturitionIntervalCoefficient) * 30.64;
                    // restrict minimum period between births
                    IPIcurrent = Math.Max(IPIcurrent, breedFemales[0].BreedParams.GestationLength + 61);

                    breedFemales[0].NumberOfBirths = Convert.ToInt32((breedFemales[0].Age - suckling.Age - breedFemales[0].BreedParams.GestationLength - breedFemales[0].BreedParams.MinimumAge1stMating) / ((IPIcurrent + IPIminsize) / 2));

                    //breedFemales[0].Parity = breedFemales[0].Age - suckling.Age - 9;
                    // I removed the -9 as this would make it conception month not birth month
                    breedFemales[0].AgeAtLastBirth      = breedFemales[0].Age - suckling.Age;
                    breedFemales[0].AgeAtLastConception = breedFemales[0].AgeAtLastBirth - breedFemales[0].BreedParams.GestationLength;

                    // suckling mother set
                    suckling.Mother = breedFemales[0];

                    // check if a twin and if so apply next individual to same mother.
                    // otherwise remove this mother from the list
                    if (randomGenerator.RandNo >= breedFemales[0].BreedParams.TwinRate)
                    {
                        breedFemales.RemoveAt(0);
                    }
                }
                else
                {
                    Summary.WriteWarning(this, String.Format("Insufficient breeding females to assign sucklings for herd ({0})", HerdName));
                    return;
                }
            }

            // assing values for the remaining females who haven't just bred.
            foreach (var female in breedFemales)
            {
                female.DryBreeder = true;
                // generalised curve
                double IPIcurrent = Math.Pow(breedFemales[0].BreedParams.InterParturitionIntervalIntercept * (breedFemales[0].Weight / breedFemales[0].StandardReferenceWeight), breedFemales[0].BreedParams.InterParturitionIntervalCoefficient) * 30.64;
                // restrict minimum period between births
                IPIcurrent = Math.Max(IPIcurrent, breedFemales[0].BreedParams.GestationLength + 61);
                breedFemales[0].NumberOfBirths = Convert.ToInt32((breedFemales[0].Age - breedFemales[0].BreedParams.MinimumAge1stMating) / ((IPIcurrent + IPIminsize) / 2)) - 1;
                female.AgeAtLastBirth          = breedFemales[0].Age - 12;
            }
        }
Пример #12
0
        private void OnWFFeedAllocation(object sender, EventArgs e)
        {
            // if no requests end
            if (requests.Count() == 0)
            {
                return;
            }

            // month needed for montly pasture limits.
            int month = Clock.Today.Month;

            // get list of unique priorities provided in requests
            List <int> priorityList = requests.OrderBy(b => b.FeedActivity.FeedPriority).Select(a => a.FeedActivity.FeedPriority).Distinct().ToList();

            foreach (int priority in priorityList)
            {
                // group by feed types requested with each priority
                var feedGrouping = requests.Where(a => a.FeedActivity.FeedPriority == priority).GroupBy(a => a.FeedActivity.FeedType);
                foreach (var feedTypeGroup in feedGrouping)
                {
                    IFeedType feedType = feedTypeGroup.Key as IFeedType;

                    // determine the total requested for each feedtype
                    double amountRequested = feedTypeGroup.Sum(a => Math.Min(a.Amount, (a.Requestor.PotentialIntake - a.Requestor.Intake) * 30.4) * a.Requestor.Number);

                    // if something requested and something available
                    if (amountRequested > 0 & feedType.Amount > 0)
                    {
                        // determine if shortfall
                        double deficit = Math.Min(1.0, feedType.Amount / amountRequested);
                        if (deficit < 1.0)
                        {
                            // TODO: work out what do do.
                            // Buy fodder
                            // Use common land
                            // use Animal Food Stores.
                        }
                        // prepare to take available from resource store
                        amountRequested *= deficit;

                        // group requests by ruminant breed to allow calculations of limits
                        var breedGrouping = feedTypeGroup.GroupBy(a => a.Requestor.BreedParams.Name);
                        foreach (var breedGroup in breedGrouping)
                        {
                            // If feeding on pasture calculate limits based on proportion green
                            // This needs to be done for pasture/breed combinations each month
                            // So cannot be done for Ruminants or Pasture seperately at start of month
                            if (feedType.GetType().Name == "PastureType")
                            {
                                GrazeFoodStoreType pasture = feedType as GrazeFoodStoreType;

                                double total = 0;
                                foreach (var pool in pasture.Pools)
                                {
                                    pool.Limit = 1.0;
                                    total     += pool.Amount;
                                }

                                // if Jan-March then user first three months otherwise use 2
                                int greenage = 2;
                                if (month <= 3)
                                {
                                    greenage = 3;
                                }

                                double green      = pasture.Pools.Where(a => (a.Age <= greenage)).Sum(b => b.Amount);
                                double propgreen  = green / total;
                                double greenlimit = breedGroup.FirstOrDefault().Requestor.BreedParams.GreenDietMax *(1 - Math.Exp(-breedGroup.FirstOrDefault().Requestor.BreedParams.GreenDietCoefficient *((propgreen * 100.0) - breedGroup.FirstOrDefault().Requestor.BreedParams.GreenDietZero)));
                                greenlimit = Math.Max(0.0, greenlimit);
                                if (propgreen > 90)
                                {
                                    greenlimit = 100;
                                }

                                foreach (var pool in pasture.Pools.Where(a => a.Age <= greenage))
                                {
                                    pool.Limit = greenlimit / 100.0;
                                }
                            }

                            // update Ruminants Intake, ProteinConcentration and DietDryMatterDigestibility
                            foreach (var request in feedTypeGroup)
                            {
                                switch (request.FeedActivity.FeedType.GetType().Name)
                                {
                                case "GrazeFoodStoreType":
                                    // take from pools as specified for the individual
                                    GrazeFoodStoreType pasture        = request.FeedActivity.FeedType as GrazeFoodStoreType;
                                    double             amountRequired = (request.Requestor.PotentialIntake - request.Requestor.Intake) * 30.4;

                                    int  index = 0;
                                    bool secondTakeFromPools = request.Requestor.BreedParams.StrictFeedingLimits;
                                    while (amountRequired > 0)
                                    {
                                        // limiter obtained from filter group or unlimited if second take of pools
                                        double limiter = 1.0;
                                        if (!secondTakeFromPools)
                                        {
                                            limiter = pasture.Pools[index].Limit;
                                        }

                                        double amountToRemove = Math.Min(pasture.Pools[index].Amount, amountRequired * limiter);
                                        amountRequired -= amountToRemove;

                                        request.Amount = amountToRemove;
                                        pasture.Pools[index].Remove(request);

                                        index++;
                                        if (index >= pasture.Pools.Count)
                                        {
                                            // if we've already given second chance to get food so finish without full satisfying individual
                                            // or strict feeding limits are enforced
                                            if (secondTakeFromPools)
                                            {
                                                break;
                                            }
                                            // if not strict limits allow a second request for food from previously limited pools.
                                            secondTakeFromPools = true;
                                            index = 0;
                                        }
                                    }
                                    break;

                                case "AnimalFoodStoreType":
                                    // take directly from store if available
                                    request.Amount *= deficit;
                                    feedTypeGroup.FirstOrDefault().FeedActivity.FeedType.Remove(request);
                                    break;

                                default:
                                    string error = String.Format("Unrecognised feed type {0} in {1} of name {2}", request.GetType().ToString(), this.GetType().ToString(), this.Name);
                                    Summary.WriteWarning(this, error);
                                    throw new Exception("Unrecognised Feedtype found in feed request");
                                }
                            }
                        }
                    }
                }
            }
        }
Пример #13
0
        private void OnCLEMInitialiseResource(object sender, EventArgs e)
        {
            id   = 1;
            Herd = new List <Ruminant>();
            PurchaseIndividuals   = new List <Ruminant>();
            LastIndividualChanged = new Ruminant();

            // for each Ruminant type
            foreach (RuminantType rType in Apsim.Children(this, typeof(RuminantType)))
            {
                foreach (RuminantInitialCohorts ruminantCohorts in Apsim.Children(rType, typeof(RuminantInitialCohorts)))
                {
                    foreach (var ind in ruminantCohorts.CreateIndividuals())
                    {
                        ind.SaleFlag = HerdChangeReason.InitialHerd;
                        AddRuminant(ind);
                    }
                }
            }

            // Assign mothers to suckling calves
            foreach (string HerdName in Herd.Select(a => a.HerdName).Distinct())
            {
                List <Ruminant> herd = Herd.Where(a => a.HerdName == HerdName).ToList();

                // get list of females of breeding age and condition
                List <RuminantFemale> breedFemales = herd.Where(a => a.Gender == Sex.Female & a.Age >= a.BreedParams.MinimumAge1stMating + a.BreedParams.GestationLength & a.Weight >= (a.BreedParams.MinimumSize1stMating * a.StandardReferenceWeight) & a.Weight >= (a.BreedParams.CriticalCowWeight * a.StandardReferenceWeight)).OrderByDescending(a => a.Age).ToList().Cast <RuminantFemale>().ToList();

                // get list of all sucking individuals
                List <Ruminant> sucklingList = herd.Where(a => a.Weaned == false).ToList();

                if (breedFemales.Count() == 0)
                {
                    if (sucklingList.Count > 0)
                    {
                        Summary.WriteWarning(this, String.Format("Insufficient breeding females to assign ({0}) sucklings for herd ({1})", sucklingList.Count, HerdName));
                    }
                }
                else
                {
                    // gestation interval at smallest size generalised curve
                    double minAnimalWeight = breedFemales[0].StandardReferenceWeight - ((1 - breedFemales[0].BreedParams.SRWBirth) * breedFemales[0].StandardReferenceWeight) * Math.Exp(-(breedFemales[0].BreedParams.AgeGrowthRateCoefficient * (breedFemales[0].BreedParams.MinimumAge1stMating * 30.4)) / (Math.Pow(breedFemales[0].StandardReferenceWeight, breedFemales[0].BreedParams.SRWGrowthScalar)));
                    double IPIminsize      = Math.Pow(breedFemales[0].BreedParams.InterParturitionIntervalIntercept * (minAnimalWeight / breedFemales[0].StandardReferenceWeight), breedFemales[0].BreedParams.InterParturitionIntervalCoefficient) * 30.64;
                    // restrict minimum period between births
                    IPIminsize = Math.Max(IPIminsize, breedFemales[0].BreedParams.GestationLength + 61);

                    // assign calves to cows
                    int sucklingCount = 0;
                    foreach (var suckling in sucklingList)
                    {
                        sucklingCount++;
                        if (breedFemales.Count > 0)
                        {
                            breedFemales[0].DryBreeder = false;

                            //Initialise female milk production in at birth so ready for sucklings to consume
                            double milkTime = 15; // equivalent to mid month production

                            // need to calculate normalised animal weight here for milk production
                            breedFemales[0].NormalisedAnimalWeight = breedFemales[0].StandardReferenceWeight - ((1 - breedFemales[0].BreedParams.SRWBirth) * breedFemales[0].StandardReferenceWeight) * Math.Exp(-(breedFemales[0].BreedParams.AgeGrowthRateCoefficient * (breedFemales[0].Age * 30.4)) / (Math.Pow(breedFemales[0].StandardReferenceWeight, breedFemales[0].BreedParams.SRWGrowthScalar)));
                            double milkProduction = breedFemales[0].BreedParams.MilkPeakYield * breedFemales[0].Weight / breedFemales[0].NormalisedAnimalWeight * (Math.Pow(((milkTime + breedFemales[0].BreedParams.MilkOffsetDay) / breedFemales[0].BreedParams.MilkPeakDay), breedFemales[0].BreedParams.MilkCurveSuckling)) * Math.Exp(breedFemales[0].BreedParams.MilkCurveSuckling * (1 - (milkTime + breedFemales[0].BreedParams.MilkOffsetDay) / breedFemales[0].BreedParams.MilkPeakDay));
                            breedFemales[0].MilkProduction = Math.Max(milkProduction, 0.0);
                            breedFemales[0].MilkAmount     = milkProduction * 30.4;

                            // generalised curve
                            double IPIcurrent = Math.Pow(breedFemales[0].BreedParams.InterParturitionIntervalIntercept * (breedFemales[0].Weight / breedFemales[0].StandardReferenceWeight), breedFemales[0].BreedParams.InterParturitionIntervalCoefficient) * 30.64;
                            // restrict minimum period between births
                            IPIcurrent = Math.Max(IPIcurrent, breedFemales[0].BreedParams.GestationLength + 61);

                            breedFemales[0].NumberOfBirths = Convert.ToInt32((breedFemales[0].Age - suckling.Age - breedFemales[0].BreedParams.GestationLength - breedFemales[0].BreedParams.MinimumAge1stMating) / ((IPIcurrent + IPIminsize) / 2));

                            //breedFemales[0].Parity = breedFemales[0].Age - suckling.Age - 9;
                            // I removed the -9 as this would make it conception month not birth month
                            breedFemales[0].AgeAtLastBirth      = breedFemales[0].Age - suckling.Age;
                            breedFemales[0].AgeAtLastConception = breedFemales[0].AgeAtLastBirth - breedFemales[0].BreedParams.GestationLength;
                            breedFemales[0].SuccessfulPregnancy = true;

                            // suckling mother set
                            suckling.Mother = breedFemales[0];
                            // add suckling to suckling offspring of mother.
                            suckling.Mother.SucklingOffspring.Add(suckling);

                            // check if a twin and if so apply next individual to same mother.
                            // otherwise remove this mother from the list
                            if (ZoneCLEM.RandomGenerator.NextDouble() >= breedFemales[0].BreedParams.TwinRate)
                            {
                                breedFemales.RemoveAt(0);
                            }
                        }
                        else
                        {
                            Summary.WriteWarning(this, String.Format("Insufficient breeding females to assign ({0}) sucklings for herd ({1})", sucklingList.Count - sucklingCount, HerdName));
                        }
                    }

                    // assigning values for the remaining females who haven't just bred.
                    foreach (var female in breedFemales)
                    {
                        female.DryBreeder = true;
                        // generalised curve
                        double IPIcurrent = Math.Pow(breedFemales[0].BreedParams.InterParturitionIntervalIntercept * (breedFemales[0].Weight / breedFemales[0].StandardReferenceWeight), breedFemales[0].BreedParams.InterParturitionIntervalCoefficient) * 30.64;
                        // restrict minimum period between births
                        IPIcurrent = Math.Max(IPIcurrent, breedFemales[0].BreedParams.GestationLength + 61);
                        breedFemales[0].NumberOfBirths = Convert.ToInt32((breedFemales[0].Age - breedFemales[0].BreedParams.MinimumAge1stMating) / ((IPIcurrent + IPIminsize) / 2)) - 1;
                        female.AgeAtLastBirth          = breedFemales[0].Age - 12;
                    }
                }
            }

            //List<IModel> childNodes = Apsim.Children(this, typeof(IModel));

            //foreach (IModel childModel in childNodes)
            //{
            //    //cast the generic IModel to a specfic model.
            //    RuminantType ruminantType = childModel as RuminantType;
            //    foreach (var ind in ruminantType.CreateIndividuals())
            //    {
            //        ind.SaleFlag = HerdChangeReason.InitialHerd;
            //        AddRuminant(ind);
            //    }
            //}
        }
Пример #14
0
        private void OnCommencing(object sender, EventArgs e)
        {
            int lossModifier = 1;

            if (ReportLossesAsNegative)
            {
                lossModifier = -1;
            }

            // check if running from a CLEM.Market
            bool market = (FindAncestor <Zone>().GetType() == typeof(Market));

            dataToWriteToDb = null;
            // sanitise the variable names and remove duplicates
            List <string> variableNames = new List <string>
            {
                "[Clock].Today as Date"
            };

            if (VariableNames != null && VariableNames.Count() > 0)
            {
                if (VariableNames.Count() > 1)
                {
                    Summary.WriteWarning(this, String.Format("Multiple resource groups not permitted in ReportResourceLedger [{0}]\r\nAdditional entries have been ignored", this.Name));
                }

                for (int i = 0; i < 1; i++)
                {
                    // each variable name is now a ResourceGroup
                    bool isDuplicate = StringUtilities.IndexOfCaseInsensitive(variableNames, this.VariableNames[i].Trim()) != -1;
                    if (!isDuplicate && this.VariableNames[i] != string.Empty)
                    {
                        // check it is a ResourceGroup
                        CLEMModel model = Resources.GetResourceGroupByName(this.VariableNames[i]) as CLEMModel;
                        if (model == null)
                        {
                            Summary.WriteWarning(this, String.Format("Invalid resource group [{0}] in ReportResourceBalances [{1}]\r\nEntry has been ignored", this.VariableNames[i], this.Name));
                        }
                        else
                        {
                            bool pricingIncluded = false;
                            if (model.GetType() == typeof(RuminantHerd))
                            {
                                pricingIncluded = model.FindAllDescendants <AnimalPricing>().Where(a => a.Enabled).Count() > 0;

                                variableNames.Add("[Resources]." + this.VariableNames[i] + ".LastTransaction.ExtraInformation.ID as uID");
                                variableNames.Add("[Resources]." + this.VariableNames[i] + ".LastTransaction.ExtraInformation.Breed as Breed");
                                variableNames.Add("[Resources]." + this.VariableNames[i] + ".LastTransaction.ExtraInformation.Gender as Sex");
                                variableNames.Add("[Resources]." + this.VariableNames[i] + ".LastTransaction.ExtraInformation.Age as Age");
                                variableNames.Add("[Resources]." + this.VariableNames[i] + ".LastTransaction.ExtraInformation.Weight as Weight");
                                variableNames.Add("[Resources]." + this.VariableNames[i] + ".LastTransaction.ExtraInformation.AdultEquivalent as AE");
                                variableNames.Add("[Resources]." + this.VariableNames[i] + ".LastTransaction.ExtraInformation.SaleFlag as Category");
                                variableNames.Add("[Resources]." + this.VariableNames[i] + ".LastTransaction.ExtraInformation.HerdName as RelatesTo");
                                variableNames.Add("[Resources]." + this.VariableNames[i] + ".LastTransaction.ExtraInformation.PopulationChangeDirection as Change");

                                // ToDo: add pricing for ruminants including buy and sell pricing
                                // Needs update in CLEMResourceTypeBase and link between ResourcePricing and AnimalPricing.
                            }
                            else
                            {
                                pricingIncluded = model.FindAllDescendants <ResourcePricing>().Where(a => a.Enabled).Count() > 0;

                                if (ReportStyle == ReportTransactionStyle.GainAndLossColumns)
                                {
                                    variableNames.Add("[Resources]." + this.VariableNames[i] + ".LastTransaction.Gain as Gain");
                                    variableNames.Add("[Resources]." + this.VariableNames[i] + $".LastTransaction.Loss * {lossModifier} as Loss");
                                }
                                else
                                {
                                    variableNames.Add("[Resources]." + this.VariableNames[i] + ".LastTransaction.TransactionType as Type");
                                    variableNames.Add("[Resources]." + this.VariableNames[i] + $".LastTransaction.AmountModifiedForLoss({ReportLossesAsNegative}) as Amount");
                                }

                                // get all converters for this type of resource
                                if (IncludeConversions)
                                {
                                    var converterList = model.FindAllDescendants <ResourceUnitsConverter>().Select(a => a.Name).Distinct();
                                    if (converterList != null)
                                    {
                                        foreach (var item in converterList)
                                        {
                                            if (ReportStyle == ReportTransactionStyle.GainAndLossColumns)
                                            {
                                                variableNames.Add("[Resources]." + this.VariableNames[i] + ".LastTransaction.ConvertTo(" + item + $",\"gain\",{ReportLossesAsNegative}) as " + item + "_Gain");
                                                variableNames.Add("[Resources]." + this.VariableNames[i] + ".LastTransaction.ConvertTo(" + item + $",\"loss\",{ReportLossesAsNegative}) as " + item + "_Loss");
                                            }
                                            else
                                            {
                                                variableNames.Add("[Resources]." + this.VariableNames[i] + ".LastTransaction.ConvertTo(" + item + $"\", {ReportLossesAsNegative}) as " + item + "_Amount");
                                            }
                                        }
                                    }
                                }

                                // add pricing
                                if (IncludePrice && pricingIncluded)
                                {
                                    if (ReportStyle == ReportTransactionStyle.GainAndLossColumns)
                                    {
                                        variableNames.Add("[Resources]." + this.VariableNames[i] + $".LastTransaction.ConvertTo(\"$gain\",\"gain\", {ReportLossesAsNegative}) as Price_Gain");
                                        variableNames.Add("[Resources]." + this.VariableNames[i] + $".LastTransaction.ConvertTo(\"$loss\",\"loss\", {ReportLossesAsNegative}) as Price_Loss");
                                    }
                                    else
                                    {
                                        variableNames.Add("[Resources]." + this.VariableNames[i] + $".LastTransaction.ConvertTo(\"$gain\", {ReportLossesAsNegative}) as Price_Amount");
                                    }
                                }

                                variableNames.Add("[Resources]." + this.VariableNames[i] + ".LastTransaction.ResourceType.Name as Resource");
                                // if this is a multi CLEM model simulation then add a new column with the parent Zone name
                                if (FindAncestor <Simulation>().FindChild <Market>() != null)
                                {
                                    variableNames.Add("[Resources]." + this.VariableNames[i] + ".LastTransaction.Activity.CLEMParentName as Source");
                                }
                                variableNames.Add("[Resources]." + this.VariableNames[i] + ".LastTransaction.Activity.Name as Activity");
                                variableNames.Add("[Resources]." + this.VariableNames[i] + ".LastTransaction.RelatesToResource as RelatesTo");
                                variableNames.Add("[Resources]." + this.VariableNames[i] + ".LastTransaction.Category as Category");
                            }
                        }
                    }
                }
                events.Subscribe("[Resources]." + this.VariableNames[0] + ".TransactionOccurred", DoOutputEvent);
            }
            // Tidy up variable/event names.
            base.VariableNames = variableNames.ToArray();
            VariableNames      = variableNames.ToArray();
            base.VariableNames = TidyUpVariableNames();
            VariableNames      = base.VariableNames;
            base.EventNames    = TidyUpEventNames();
            EventNames         = base.EventNames;
            this.FindVariableMembers();
        }
Пример #15
0
        private void OnCommencing(object sender, EventArgs e)
        {
            int lossModifier = 1;

            if (ReportLossesAsNegative)
            {
                lossModifier = -1;
            }

            // check if running from a CLEM.Market
            bool market = (FindAncestor <Zone>().GetType() == typeof(Market));

            List <string> variableNames = new List <string>
            {
                "[Clock].Today as Date"
            };
            List <string> eventNames = new List <string>();

            if (ResourceGroupsToReport != null && ResourceGroupsToReport.Trim() != "")
            {
                // check it is a ResourceGroup
                CLEMModel model = resources.FindResource <ResourceBaseWithTransactions>(ResourceGroupsToReport);
                if (model == null)
                {
                    summary.WriteWarning(this, String.Format("Invalid resource group [{0}] in ReportResourceBalances [{1}]\r\nEntry has been ignored", this.ResourceGroupsToReport, this.Name));
                }
                else
                {
                    bool pricingIncluded = false;
                    if (model.GetType() == typeof(RuminantHerd))
                    {
                        pricingIncluded = model.FindAllDescendants <AnimalPricing>().Where(a => a.Enabled).Count() > 0;

                        variableNames.Add("[Resources]." + this.ResourceGroupsToReport + ".LastIndividualChanged.ID as uID");
                        variableNames.Add("[Resources]." + this.ResourceGroupsToReport + ".LastIndividualChanged.Breed as Breed");
                        variableNames.Add("[Resources]." + this.ResourceGroupsToReport + ".LastIndividualChanged.Sex as Sex");
                        variableNames.Add("[Resources]." + this.ResourceGroupsToReport + ".LastIndividualChanged.Age as Age");
                        variableNames.Add("[Resources]." + this.ResourceGroupsToReport + ".LastIndividualChanged.Weight as Weight");
                        variableNames.Add("[Resources]." + this.ResourceGroupsToReport + ".LastIndividualChanged.AdultEquivalent as AE");
                        variableNames.Add("[Resources]." + this.ResourceGroupsToReport + ".LastIndividualChanged.SaleFlag as Category");
                        variableNames.Add("[Resources]." + this.ResourceGroupsToReport + ".LastIndividualChanged.Class as Class");
                        variableNames.Add("[Resources]." + this.ResourceGroupsToReport + ".LastIndividualChanged.HerdName as RelatesTo");
                        variableNames.Add("[Resources]." + this.ResourceGroupsToReport + ".LastIndividualChanged.PopulationChangeDirection as Change");

                        // ToDo: add pricing for ruminants including buy and sell pricing
                        // Needs update in CLEMResourceTypeBase and link between ResourcePricing and AnimalPricing.
                    }
                    else
                    {
                        pricingIncluded = model.FindAllDescendants <ResourcePricing>().Where(a => a.Enabled).Count() > 0;

                        if (ReportStyle == ReportTransactionStyle.GainAndLossColumns)
                        {
                            variableNames.Add("[Resources]." + this.ResourceGroupsToReport + ".LastTransaction.Gain as Gain");
                            variableNames.Add("[Resources]." + this.ResourceGroupsToReport + $".LastTransaction.Loss * {lossModifier} as Loss");
                        }
                        else
                        {
                            variableNames.Add("[Resources]." + this.ResourceGroupsToReport + ".LastTransaction.TransactionType as Type");
                            variableNames.Add("[Resources]." + this.ResourceGroupsToReport + $".LastTransaction.AmountModifiedForLoss({ReportLossesAsNegative}) as Amount");
                        }

                        // get all converters for this type of resource
                        if (IncludeConversions)
                        {
                            var converterList = model.FindAllDescendants <ResourceUnitsConverter>().Select(a => a.Name).Distinct();
                            if (converterList != null)
                            {
                                foreach (var item in converterList)
                                {
                                    if (ReportStyle == ReportTransactionStyle.GainAndLossColumns)
                                    {
                                        variableNames.Add("[Resources]." + this.ResourceGroupsToReport + ".LastTransaction.ConvertTo(" + item + $",\"gain\",{ReportLossesAsNegative}) as " + item + "_Gain");
                                        variableNames.Add("[Resources]." + this.ResourceGroupsToReport + ".LastTransaction.ConvertTo(" + item + $",\"loss\",{ReportLossesAsNegative}) as " + item + "_Loss");
                                    }
                                    else
                                    {
                                        variableNames.Add("[Resources]." + this.ResourceGroupsToReport + ".LastTransaction.ConvertTo(" + item + $"\", {ReportLossesAsNegative}) as " + item + "_Amount");
                                    }
                                }
                            }
                        }

                        // add pricing
                        if (IncludePrice && pricingIncluded)
                        {
                            if (ReportStyle == ReportTransactionStyle.GainAndLossColumns)
                            {
                                variableNames.Add("[Resources]." + this.ResourceGroupsToReport + $".LastTransaction.ConvertTo(\"$gain\",\"gain\", {ReportLossesAsNegative}) as Price_Gain");
                                variableNames.Add("[Resources]." + this.ResourceGroupsToReport + $".LastTransaction.ConvertTo(\"$loss\",\"loss\", {ReportLossesAsNegative}) as Price_Loss");
                            }
                            else
                            {
                                variableNames.Add("[Resources]." + this.ResourceGroupsToReport + $".LastTransaction.ConvertTo(\"$gain\", {ReportLossesAsNegative}) as Price_Amount");
                            }
                        }

                        variableNames.Add("[Resources]." + this.ResourceGroupsToReport + ".LastTransaction.ResourceType.Name as Resource");
                        // if this is a multi CLEM model simulation then add a new column with the parent Zone name
                        if (FindAncestor <Simulation>().FindChild <Market>() != null)
                        {
                            variableNames.Add("[Resources]." + this.ResourceGroupsToReport + ".LastTransaction.Activity.CLEMParentName as Source");
                        }
                        variableNames.Add("[Resources]." + this.ResourceGroupsToReport + ".LastTransaction.Activity.Name as Activity");
                        variableNames.Add("[Resources]." + this.ResourceGroupsToReport + ".LastTransaction.RelatesToResource as RelatesTo");
                        variableNames.Add("[Resources]." + this.ResourceGroupsToReport + ".LastTransaction.Category as Category");
                    }
                }
                eventNames.Add("[Resources]." + this.ResourceGroupsToReport + ".TransactionOccurred");
            }

            VariableNames = variableNames.ToArray();
            EventNames    = eventNames.ToArray();
            SubscribeToEvents();
        }
Пример #16
0
        private void OnWFAnimalSell(object sender, EventArgs e)
        {
            RuminantHerd ruminantHerd = Resources.RuminantHerd();

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

            int    trucks     = 0;
            double saleValue  = 0;
            double saleWeight = 0;
            int    head       = 0;

            // get current untrucked list of animals flagged for sale
            List <Ruminant> herd = ruminantHerd.Herd.Where(a => a.SaleFlag != Common.HerdChangeReason.None & a.Breed == BreedName).OrderByDescending(a => a.Weight).ToList();

            // if sale herd > min loads before allowing sale
            if (herd.Select(a => a.Weight / 450.0).Sum() / Number450kgPerTruck >= MinimumTrucksBeforeSelling)
            {
                // while truck to fill
                while (herd.Select(a => a.Weight / 450.0).Sum() / Number450kgPerTruck > MinimumLoadBeforeSelling)
                {
                    bool nonloaded = true;
                    trucks++;
                    double load450kgs = 0;
                    // while truck below carrying capacity load individuals
                    foreach (var ind in herd)
                    {
                        if (load450kgs + (ind.Weight / 450.0) <= Number450kgPerTruck)
                        {
                            nonloaded = false;
                            head++;
                            load450kgs += ind.Weight / 450.0;
                            RuminantValue getvalue = PriceList.Where(a => a.Age < ind.Age).OrderBy(a => a.Age).LastOrDefault();
                            saleValue  += getvalue.SellValue * ((getvalue.Style == Common.PricingStyleType.perKg) ? ind.Weight : 1.0);
                            saleWeight += ind.Weight;
                            ruminantHerd.RemoveRuminant(ind);
                        }
                    }
                    if (nonloaded)
                    {
                        Summary.WriteWarning(this, String.Format("There was a problem loading the sale truck as sale individuals did not meet the loading criteria for breed {0}", BreedName));
                        break;
                    }
                    herd = ruminantHerd.Herd.Where(a => a.SaleFlag != Common.HerdChangeReason.None & a.Breed == BreedName).OrderByDescending(a => a.Weight).ToList();
                }

                if (trucks > 0 & bankAccount != null)
                {
                    // calculate transport costs
                    double transportCost = trucks * DistanceToMarket * CostPerKmTrucking;
                    bankAccount.Remove(transportCost, this.Name, "Transport");
                    // calculate MLA fees
                    double mlaCost = head * MLAFees;
                    bankAccount.Remove(mlaCost, this.Name, "R&DFee");
                    // calculate yard fees
                    double yardCost = head * YardFees;
                    bankAccount.Remove(yardCost, this.Name, "YardCosts");
                    // calculate commission
                    double commissionCost = saleValue * SalesCommission;
                    bankAccount.Remove(commissionCost, this.Name, "SalesCommission");

                    // add and remove from bank
                    bankAccount.Add(saleValue, this.Name, "Sales");
                }
            }
        }
Пример #17
0
        /// <summary>This is only called from a Plant1 process method - not used in Plant2.</summary>
        /// <returns></returns>
        internal bool PlantDeath()
        {
            das++;
            if (Phenology.InPhase("sowing"))
            {
                dlt_plants_failure_germ = CropFailureGermination();
            }

            else
            {
                dlt_plants_failure_germ = 0.0;
            }

            if (Phenology.InPhase("germination"))
            {
                dlt_plants_failure_emergence = CropFailureEmergence();
            }
            else
            {
                dlt_plants_failure_emergence = 0.0;
            }

            dlt_plants_death_seedling = 0.0;
            if (Phenology.OnDayOf("emergence"))
            {
                dlt_plants_death_seedling = DeathSeedling();
            }

            /*XXXX this needs to be coupled with dlt_leaf_area_sen, c_sen_start_stage  FIXME*/
            if (!Phenology.InPhase("SowingToGermination") && !Phenology.InPhase("GerminationToEmergence"))
            {
                dlt_plants_failure_leaf_sen = CropFailureLeafSen();
            }
            else
            {
                dlt_plants_failure_leaf_sen = 0.0;
            }

            if (CropFailureStressPeriod.Value() == 1)
            {
                dlt_plants_failure_phen_delay = CropFailurePhenDelay();
            }
            else
            {
                dlt_plants_failure_phen_delay = 0.0;
            }

            if (CropFailureStressPeriod.Value() == 1)
            {
                dlt_plants_death_drought = DeathDrought();
            }
            else
            {
                dlt_plants_death_drought = 0.0;
            }

            DeathActual();
            Util.Debug("Population.dlt_plants=%f", dlt_plants);
            if (MathUtilities.FloatsAreEqual(dlt_plants + Density, 0.0))
            {
                //!!!!! fix problem with deltas in update when change from alive to dead ?zero deltas

                double biomass = 0;
                foreach (Organ1 Organ in Plant.Tops)
                {
                    biomass += (Organ.Live.Wt + Organ.Dead.Wt) * Conversions.gm2kg / Conversions.sm2ha;
                }

                // report
                string msg = "Plant death. standing above-ground dm = " + biomass.ToString("f2") + " (kg/ha)";
                Summary.WriteWarning(this, msg);
                return(true);
                // XX Needs to signal a need to call zero_variables here...
                // Present method is to rely on calling zero_xx at tomorrow's prepare() event.. :(
            }
            return(false);
        }
Пример #18
0
        /// <summary>
        /// Retrieve a ResourceType from a ResourceGroup based on a request item including filter and sort options
        /// </summary>
        /// <param name="Request">A resource request item</param>
        /// <param name="MissingResourceAction">Action to take if requested resource group not found</param>
        /// <param name="MissingResourceTypeAction">Action to take if requested resource type not found</param>
        /// <returns>A reference to the item of type Model</returns>
        public Model GetResourceItem(ResourceRequest Request, OnMissingResourceActionTypes MissingResourceAction, OnMissingResourceActionTypes MissingResourceTypeAction)
        {
            if (Request.FilterDetails != null)
            {
                if (Request.ResourceType == null)
                {
                    string errorMsg = String.Format("Resource type must be supplied in resource request from {0}", Request.ActivityModel.Name);
                    Summary.WriteWarning(Request.ActivityModel, String.Format("Resource type must be supplied in resource request from {0}", Request.ActivityModel.Name));
                    throw new Exception(errorMsg);
                }

                IModel resourceGroup = this.GetByType(Request.ResourceType);
                if (resourceGroup == null)
                {
                    string errorMsg = String.Format("Unable to locate resources of type ({0}) for ({1})", Request.ResourceType, Request.ActivityModel.Name);
                    switch (MissingResourceAction)
                    {
                    case OnMissingResourceActionTypes.ReportErrorAndStop:
                        throw new Exception(errorMsg);

                    case OnMissingResourceActionTypes.ReportWarning:
                        Summary.WriteWarning(Request.ActivityModel, errorMsg);
                        break;

                    default:
                        break;
                    }
                    return(null);
                }

                // get list of children matching the conditions in filter
                // and return the lowest item that has enough time available
                object resourceGroupObject = resourceGroup as object;
                switch (resourceGroupObject.GetType().ToString())
                {
                case "Models.CLEM.Resources.Labour":
                    // get matching labour types
                    // use activity uid to ensure unique for this request
                    List <LabourType> items = (resourceGroup as Labour).Items;
                    items = items.Filter(Request.FilterDetails.FirstOrDefault() as Model);
                    items = items.Where(a => a.LastActivityRequestID != Request.ActivityID).ToList();
                    if (items.Where(a => a.Amount >= Request.Required).Count() > 0)
                    {
                        // get labour least available but with the amount needed
                        return(items.Where(a => a.Amount >= Request.Required).OrderByDescending(a => a.Amount).FirstOrDefault());
                    }
                    else
                    {
                        // get labour with most available but with less than the amount needed
                        return(items.OrderByDescending(a => a.Amount).FirstOrDefault());
                    }

                default:
                    string errorMsg = "Resource cannot be filtered. Filtering not implemented for " + resourceGroupObject.GetType().ToString() + " from activity (" + Request.ActivityModel.Name + ")";
                    Summary.WriteWarning(Request.ActivityModel, errorMsg);
                    throw new Exception(errorMsg);
                }
            }
            else
            {
                return(GetResourceItem(Request.ActivityModel, Request.ResourceType, Request.ResourceTypeName, MissingResourceAction, MissingResourceTypeAction));
            }
        }
Пример #19
0
        private void OnCommencing(object sender, EventArgs e)
        {
            dataToWriteToDb = null;
            // sanitise the variable names and remove duplicates
            List <string> variableNames = new List <string>
            {
                "[Clock].Today"
            };

            if (VariableNames != null && VariableNames.Count() > 0)
            {
                if (VariableNames.Count() > 1)
                {
                    Summary.WriteWarning(this, String.Format("Multiple resource groups not permitted in ReportResourceLedger [{0}]\nAdditional entries have been ignored", this.Name));
                }

                for (int i = 0; i < 1; i++)
                {
                    // each variable name is now a ResourceGroup
                    bool isDuplicate = StringUtilities.IndexOfCaseInsensitive(variableNames, this.VariableNames[i].Trim()) != -1;
                    if (!isDuplicate && this.VariableNames[i] != string.Empty)
                    {
                        // check it is a ResourceGroup
                        CLEMModel model = Resources.GetResourceGroupByName(this.VariableNames[i]) as CLEMModel;
                        if (model == null)
                        {
                            Summary.WriteWarning(this, String.Format("Invalid resource group [{0}] in ReportResourceBalances [{1}]\nEntry has been ignored", this.VariableNames[i], this.Name));
                        }
                        else
                        {
                            bool pricingIncluded = false;
                            if (model.GetType() == typeof(RuminantHerd))
                            {
                                pricingIncluded = Apsim.ChildrenRecursively(model, typeof(AnimalPricing)).Count() > 0;

                                variableNames.Add("[Resources]." + this.VariableNames[i] + ".LastTransaction.ExtraInformation.ID as uID");
                                variableNames.Add("[Resources]." + this.VariableNames[i] + ".LastTransaction.ExtraInformation.Breed as Breed");
                                variableNames.Add("[Resources]." + this.VariableNames[i] + ".LastTransaction.ExtraInformation.HerdName as Herd");
                                variableNames.Add("[Resources]." + this.VariableNames[i] + ".LastTransaction.ExtraInformation.GenderAsString as Sex");
                                variableNames.Add("[Resources]." + this.VariableNames[i] + ".LastTransaction.ExtraInformation.Age as Age");
                                variableNames.Add("[Resources]." + this.VariableNames[i] + ".LastTransaction.ExtraInformation.Weight as Weight");
                                variableNames.Add("[Resources]." + this.VariableNames[i] + ".LastTransaction.ExtraInformation.SaleFlagAsString as Reason");
                                variableNames.Add("[Resources]." + this.VariableNames[i] + ".LastTransaction.ExtraInformation.PopulationChangeDirection as Change");

                                // ToDo: add pricing for ruminants including buy and sell pricing
                                // Needs update in CLEMResourceTypeBase and link between ResourcePricing and AnimalPricing.
                            }
                            else
                            {
                                pricingIncluded = Apsim.ChildrenRecursively(model, typeof(ResourcePricing)).Count() > 0;

                                variableNames.Add("[Resources]." + this.VariableNames[i] + ".LastTransaction.Gain as Gain");
                                variableNames.Add("[Resources]." + this.VariableNames[i] + ".LastTransaction.Loss * -1.0 as Loss");
                                // get all converters for this type of resource
                                var converterList = Apsim.ChildrenRecursively(model, typeof(ResourceUnitsConverter)).Select(a => a.Name).Distinct();
                                if (converterList != null)
                                {
                                    foreach (var item in converterList)
                                    {
                                        variableNames.Add("[Resources]." + this.VariableNames[i] + ".LastTransaction.ConvertTo(" + item + ",\"gain\") as " + item + "_Gain");
                                        variableNames.Add("[Resources]." + this.VariableNames[i] + ".LastTransaction.ConvertTo(" + item + ",\"loss\") as " + item + "_Loss");
                                    }
                                }

                                // add pricing
                                if (pricingIncluded)
                                {
                                    variableNames.Add("[Resources]." + this.VariableNames[i] + ".LastTransaction.ConvertTo(\"$\",\"gain\") as Price_Gain");
                                    variableNames.Add("[Resources]." + this.VariableNames[i] + ".LastTransaction.ConvertTo(\"$\",\"loss\") as Price_Loss");
                                }

                                variableNames.Add("[Resources]." + this.VariableNames[i] + ".LastTransaction.ResourceType.Name as Resource");
                                variableNames.Add("[Resources]." + this.VariableNames[i] + ".LastTransaction.Activity.Name as Activity");
                                variableNames.Add("[Resources]." + this.VariableNames[i] + ".LastTransaction.Reason as Reason");
                            }
                        }
                    }
                }
                events.Subscribe("[Resources]." + this.VariableNames[0] + ".TransactionOccurred", DoOutputEvent);
            }
            // Tidy up variable/event names.
            VariableNames = variableNames.ToArray();
            VariableNames = TidyUpVariableNames();
            EventNames    = TidyUpEventNames();
            this.FindVariableMembers();
        }
Пример #20
0
        /// <summary>
        /// Handles the addition of new CNPatches
        /// </summary>
        /// <param name="PatchtoAdd">Patch data</param>
        private void AddNewCNPatch(AddSoilCNPatchwithFOMType PatchtoAdd)
        {
            List <int> idPatchesJustAdded = new List <int>(); // list of IDs of patches created (exclude patches that would be too small)
            List <int> idPatchesToDelete  = new List <int>(); //list of IDs of existing patches that became too small and need to be deleted
            List <int> idPatchesAffected;                     //list of IDs of patches affected by new addition

            // 1. get the list of id's of patches which are affected by this addition, and the area affected
            double AreaAffected = 0;

            if (PatchtoAdd.DepositionType == DepositionTypeEnum.ToNewPatch)
            {
                // check which patches are affected
                idPatchesAffected = CheckPatchIDs(PatchtoAdd.AffectedPatches_id, PatchtoAdd.AffectedPatches_nm);
                for (int i = 0; i < idPatchesAffected.Count; i++)
                {
                    AreaAffected += patches[idPatchesAffected[i]].RelativeArea;
                }
            }
            else if (PatchtoAdd.DepositionType == DepositionTypeEnum.NewOverlappingPatches)
            {
                // all patches are affected
                idPatchesAffected = new List <int>();
                for (int k = 0; k < patches.Count; k++)
                {
                    idPatchesAffected.Add(k);
                }
                AreaAffected = 1.0;
            }
            else
            {
                idPatchesAffected = new List <int>();
            }

            // check that total area of affected patches is larger than new patch area
            if (AreaAffected - PatchtoAdd.AreaNewPatch < -minimumPatchArea)
            {
                throw new Exception(" AddSoilCNPatch - area of selected patches (" + AreaAffected.ToString("#0.00#")
                                    + ") is smaller than area of new patch(" + PatchtoAdd.AreaNewPatch.ToString("#0.00#") +
                                    "). Command cannot be executed");
            }
            else
            {
                // check the area for each patch
                for (int i = 0; i < idPatchesAffected.Count; i++)
                {
                    double OldPatch_OldArea = patches[idPatchesAffected[i]].RelativeArea;
                    double NewPatch_NewArea = PatchtoAdd.AreaNewPatch * (OldPatch_OldArea / AreaAffected);
                    double OldPatch_NewArea = OldPatch_OldArea - NewPatch_NewArea;
                    if (NewPatch_NewArea < minimumPatchArea)
                    {
                        // area of patch to create is too small, patch will not be created
                        throw new Exception("   attempt to create a new patch with area too small or negative ("
                                            + NewPatch_NewArea.ToString("#0.00#") +
                                            "). The patch will not be created. Command cannot be executed");
                    }
                    else if (OldPatch_NewArea < -minimumPatchArea)
                    {
                        // area of patch to create is too big, patch will not be created
                        throw new Exception("   attempt to create a new patch with area greater than the existing patch area ("
                                            + NewPatch_NewArea.ToString("#0.00#") +
                                            "). The patch will not be created. Command cannot be executed");
                    }
                    else if (OldPatch_NewArea < minimumPatchArea)
                    {
                        // remaining area is too small or negative, patch will be created but old one will be deleted
                        summary.WriteWarning(this, " attempt to set the area of existing patch(" + idPatchesAffected[i].ToString()
                                             + ") to a value too small or negative (" + OldPatch_NewArea.ToString("#0.00#")
                                             + "). The patch will be eliminated.");

                        // mark old patch for deletion
                        idPatchesToDelete.Add(idPatchesAffected[i]);

                        // create new patch based on old one - the original one will be deleted later
                        ClonePatch(idPatchesAffected[i]);
                        int k = patches.Count - 1;
                        patches[k].RelativeArea = NewPatch_NewArea;
                        if (PatchtoAdd.AreaNewPatch > 0)
                        {
                            // a name was supplied
                            patches[k].Name = PatchtoAdd.PatchName + "_" + i.ToString();
                        }
                        else
                        {
                            // use default naming
                            patches[k].Name = "patch" + k.ToString();
                        }
                        patches[k].CreationDate = clock.Today;
                        idPatchesJustAdded.Add(k);
                    }
                    else
                    {
                        // create new patch by spliting an existing one
                        ClonePatch(idPatchesAffected[i]);
                        patches[idPatchesAffected[i]].RelativeArea = OldPatch_NewArea;
                        int k = patches.Count - 1;
                        patches[k].RelativeArea = NewPatch_NewArea;
                        if (PatchtoAdd.PatchName.Length > 0)
                        {
                            // a name was supplied
                            patches[k].Name = PatchtoAdd.PatchName + "_" + i.ToString();
                        }
                        else
                        {
                            // use default naming
                            patches[k].Name = "patch" + k.ToString();
                        }
                        patches[k].CreationDate = clock.Today;
                        idPatchesJustAdded.Add(k);
                        if (!PatchtoAdd.SuppressMessages)
                        {
                            summary.WriteMessage(this, "create new patch, with area = " + NewPatch_NewArea.ToString("#0.00#") +
                                                 ", based on existing patch(" + idPatchesAffected[i].ToString() +
                                                 ") - Old area = " + OldPatch_OldArea.ToString("#0.00#") +
                                                 ", new area = " + OldPatch_NewArea.ToString("#0.00#"));
                        }
                    }
                }
            }

            // add the stuff to patches just created
            AddStuffToPatches(idPatchesJustAdded, PatchtoAdd);

            // delete the patches in excess
            if (idPatchesToDelete.Count > 0)
            {
                DeletePatches(idPatchesToDelete);
            }
        }