예제 #1
0
 /// <summary>
 /// Controls the addition of several variables to the especified patches
 /// </summary>
 /// <param name="PatchesToAdd">The list of patches to which the stuff will be added</param>
 /// <param name="StuffToAdd">The values of the variables to add (supplied as deltas)</param>
 private void AddStuffToPatches(List <int> PatchesToAdd, AddSoilCNPatchwithFOMType StuffToAdd)
 {
     for (int i = PatchesToAdd.Count - 1; i >= 0; i--)
     {
         patches[PatchesToAdd[i]].Add(StuffToAdd);
     }
 }
예제 #2
0
        /// <summary>
        /// Controls the addition of several variables to the especified patches
        /// </summary>
        /// <param name="PatchesToAdd">The list of patches to which the stuff will be added</param>
        /// <param name="StuffToAdd">The values of the variables to add (supplied as deltas)</param>
        private void AddStuffToPatches(List <int> PatchesToAdd, AddSoilCNPatchwithFOMType StuffToAdd)
        {
            // Relevant data passed from OnAddSoilCNPatch event - these are all considered deltas:
            //.Sender: the name of the module that sent this values
            //.Urea: amount of urea to add per layer (kgN/ha)
            //.NH4: amount of ammonium to add per layer (kgN/ha)
            //.NO3: amount of nitrate to add per layer (kgN/ha)
            //.FOM: fresh organic matter to add, per fom pool
            //   .type: type of the given pool being altered (not used here yet)
            //   .Pool[]: info about FOM pools being added
            //      .C: amount of carbon in given pool to add per layer (kgC/ha)
            //      .N: amount of nitrogen in given pool to add per layer (kgN/ha)

            senderModule = StuffToAdd.Sender.ToLower();

            for (int i = PatchesToAdd.Count - 1; i >= 0; i--)
            {
                if ((StuffToAdd.Urea != null) && Math.Abs(SumDoubleArray(StuffToAdd.Urea)) > epsilon)
                {
                    Patch[PatchesToAdd[i]].dlt_urea = StuffToAdd.Urea;
                }
                if ((StuffToAdd.NH4 != null) && Math.Abs(SumDoubleArray(StuffToAdd.NH4)) > epsilon)
                {
                    Patch[PatchesToAdd[i]].dlt_nh4 = StuffToAdd.NH4;
                }
                if ((StuffToAdd.NO3 != null) && Math.Abs(SumDoubleArray(StuffToAdd.NO3)) > epsilon)
                {
                    Patch[PatchesToAdd[i]].dlt_no3 = StuffToAdd.NO3;
                }
                if ((StuffToAdd.FOM != null) && (StuffToAdd.FOM.Pool != null))
                {
                    bool       SomethingAdded = false;
                    double[][] CValues        = new double[3][];
                    double[][] NValues        = new double[3][];
                    for (int pool = 0; pool < StuffToAdd.FOM.Pool.Length; pool++)
                    {
                        if ((StuffToAdd.FOM.Pool[pool].C != null) && Math.Abs(SumDoubleArray(StuffToAdd.FOM.Pool[pool].C)) > epsilon)
                        {
                            CValues[pool]  = StuffToAdd.FOM.Pool[pool].C;
                            SomethingAdded = true;
                        }
                        if ((StuffToAdd.FOM.Pool[pool].N != null) && Math.Abs(SumDoubleArray(StuffToAdd.FOM.Pool[pool].N)) > epsilon)
                        {
                            NValues[pool]  = StuffToAdd.FOM.Pool[pool].N;
                            SomethingAdded = true;
                        }
                    }
                    if (SomethingAdded)
                    {
                        Patch[PatchesToAdd[i]].dlt_fom_c = CValues;
                        Patch[PatchesToAdd[i]].dlt_fom_n = NValues;
                    }
                }
            }
        }
예제 #3
0
        /// <summary>
        /// Add a solutes and FOM.
        /// </summary>
        /// <param name="StuffToAdd">The instance desribing what to add.</param>
        public void Add(AddSoilCNPatchwithFOMType StuffToAdd)
        {
            if ((StuffToAdd.Urea != null) && MathUtilities.IsGreaterThan(Math.Abs(StuffToAdd.Urea.Sum()), 0))
            {
                GetSoluteObject("Urea").AddKgHaDelta(SoluteSetterType.Other, StuffToAdd.Urea);
            }
            if ((StuffToAdd.NH4 != null) && MathUtilities.IsGreaterThan(Math.Abs(StuffToAdd.NH4.Sum()), 0))
            {
                GetSoluteObject("NH4").AddKgHaDelta(SoluteSetterType.Other, StuffToAdd.NH4);
            }
            if ((StuffToAdd.NO3 != null) && MathUtilities.IsGreaterThan(Math.Abs(StuffToAdd.NO3.Sum()), 0))
            {
                GetSoluteObject("NO3").AddKgHaDelta(SoluteSetterType.Other, StuffToAdd.NO3);
            }

            if ((StuffToAdd.FOM != null) && (StuffToAdd.FOM.Pool != null))
            {
                if (StuffToAdd.FOM.Pool.Length != 3)
                {
                    throw new Exception("Expected 3 pools of FOM to be added in PatchManager");
                }
                if (StuffToAdd.FOM.Pool[0].C.Length != lignin.C.Length ||
                    StuffToAdd.FOM.Pool[0].N.Length != lignin.N.Length ||
                    StuffToAdd.FOM.Pool[1].C.Length != cellulose.C.Length ||
                    StuffToAdd.FOM.Pool[1].N.Length != cellulose.N.Length ||
                    StuffToAdd.FOM.Pool[2].C.Length != carbohydrate.C.Length ||
                    StuffToAdd.FOM.Pool[2].N.Length != carbohydrate.N.Length)
                {
                    throw new Exception("Mismatched number of layers of FOM being added in PatchManager");
                }

                for (int i = 0; i < lignin.C.Length; i++)
                {
                    lignin.C[i]       += StuffToAdd.FOM.Pool[0].C[i] * RelativeArea;
                    lignin.N[i]       += StuffToAdd.FOM.Pool[0].N[i] * RelativeArea;
                    cellulose.C[i]    += StuffToAdd.FOM.Pool[1].C[i] * RelativeArea;
                    cellulose.N[i]    += StuffToAdd.FOM.Pool[1].N[i] * RelativeArea;
                    carbohydrate.C[i] += StuffToAdd.FOM.Pool[2].C[i] * RelativeArea;
                    carbohydrate.N[i] += StuffToAdd.FOM.Pool[2].N[i] * RelativeArea;
                }
            }
        }
예제 #4
0
        /// <summary>
        /// Handles the addition of new CNPatches
        /// </summary>
        /// <param name="PatchtoAdd">Patch data</param>
        private void AddNewCNPatch(AddSoilCNPatchwithFOMType PatchtoAdd)
        {
            // Data passed from OnAddSoilCNPatch event:
            //.Sender: the name of the module that raised this event
            //.SuppressMessages: flags wheter massages are suppressed or not (default is not)
            //.DepositionType: the type of deposition:
            //  - ToAllPaddock: No patch is created, add stuff as given to all patches. It is the default;
            //  - ToSpecificPatch: No patch is created, add stuff to given patches;
            //      (recipient patch is given using its index or name; if not supplied, defaults to homogeneous)
            //  - ToNewPatch: create new patch based on an existing patch, add stuff to created patch;
            //      - recipient or base patch is given using index or name; if not supplied, new patch will be based on the base/Patch[0];
            //      - patches are only created if area is larger than a minimum (minPatchArea);
            //      - new areas are proportional to existing patches;
            //  - NewOverlappingPatches: create new patch(es), these overlap with all existing patches, add stuff to created patches;
            //      (new patches are created only if their area is larger than a minimum (minPatchArea))
            //.AffectedPatches_id (AffectedPatchesByIndex): the index of the existing patches affected by new patch
            //.AffectedPatches_nm (AffectedPatchesByName): the name of the existing patches affected by new patch
            //.AreaNewPatch: the relative area (fraction) of new patches (0-1)
            //.PatchName: the name(s) of the patch(es) being created
            //.Water: amount of water to add per layer (mm), not handled here
            //.Urea: amount of urea to add per layer (kgN/ha)
            //.NH4: amount of ammonium to add per layer (kgN/ha)
            //.NO3: amount of nitrate to add per layer (kgN/ha)
            //.POX: amount of POx to add per layer (kgP/ha), not handled here
            //.SO4: amount of SO4 to add per layer (kgS/ha), not handled here
            //.AshAlk: ash amount to add per layer (mol/ha), not handled here
            //.FOM: fresh organic matter to add, per fom pool
            //   .name: name of given pool being altered
            //   .type: type of the given pool being altered (not used here)
            //   .Pool[]: info about FOM pools being added
            //      .type: type of the given pool being altered (not used here)
            //      .type: type of the given pool being altered (not used here)
            //      .C: amount of carbon in given pool to add per layer (kgC/ha)
            //      .N: amount of nitrogen in given pool to add per layer (kgN/ha)
            //      .P: amount of phosphorus (kgC/ha), not handled here
            //      .S: amount of sulphur (kgC/ha), not handled here
            //      .AshAlk: amount of alkaline ash (kg/ha), not handled here


            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.ToLower() == "ToNewPatch".ToLower())
            {
                // check which patches are affected
                idPatchesAffected = CheckPatchIDs(PatchtoAdd.AffectedPatches_id, PatchtoAdd.AffectedPatches_nm);
                for (int i = 0; i < idPatchesAffected.Count; i++)
                {
                    AreaAffected += Patch[idPatchesAffected[i]].RelativeArea;
                }
            }
            else if (PatchtoAdd.DepositionType.ToLower() == "NewOverlappingPatches".ToLower())
            {
                // all patches are affected
                idPatchesAffected = new List <int>();
                for (int k = 0; k < Patch.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 = Patch[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
                        mySummary.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 = Patch.Count - 1;
                        Patch[k].RelativeArea = NewPatch_NewArea;
                        if (PatchtoAdd.AreaNewPatch > 0)
                        {
                            // a name was supplied
                            Patch[k].PatchName = PatchtoAdd.PatchName + "_" + i.ToString();
                        }
                        else
                        {
                            // use default naming
                            Patch[k].PatchName = "patch" + k.ToString();
                        }
                        Patch[k].CreationDate = Clock.Today;
                        idPatchesJustAdded.Add(k);
                    }
                    else
                    {
                        // create new patch by spliting an existing one
                        ClonePatch(idPatchesAffected[i]);
                        Patch[idPatchesAffected[i]].RelativeArea = OldPatch_NewArea;
                        int k = Patch.Count - 1;
                        Patch[k].RelativeArea = NewPatch_NewArea;
                        if (PatchtoAdd.PatchName.Length > 0)
                        {
                            // a name was supplied
                            Patch[k].PatchName = PatchtoAdd.PatchName + "_" + i.ToString();
                        }
                        else
                        {
                            // use default naming
                            Patch[k].PatchName = "patch" + k.ToString();
                        }
                        Patch[k].CreationDate = Clock.Today;
                        idPatchesJustAdded.Add(k);
                        if (PatchtoAdd.SuppressMessages.ToLower() != "yes")
                        {
                            mySummary.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);
            }
        }
예제 #5
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);
            }
        }
예제 #6
0
        /// <summary>
        /// Add a new patch.
        /// </summary>
        /// <param name="patch">Details of the patch to add.</param>
        public void Add(AddSoilCNPatchType patch)
        {
            AddSoilCNPatchwithFOMType PatchtoAdd = new AddSoilCNPatchwithFOMType();

            PatchtoAdd.Sender             = patch.Sender;
            PatchtoAdd.SuppressMessages   = patch.SuppressMessages;
            PatchtoAdd.DepositionType     = patch.DepositionType;
            PatchtoAdd.AreaNewPatch       = patch.AreaFraction;
            PatchtoAdd.AffectedPatches_id = patch.AffectedPatches_id;
            PatchtoAdd.AffectedPatches_nm = patch.AffectedPatches_nm;
            PatchtoAdd.Urea = patch.Urea;
            PatchtoAdd.NH4  = patch.NH4;
            PatchtoAdd.NO3  = patch.NO3;

            bool isDataOK = true;

            if (PatchtoAdd.DepositionType == DepositionTypeEnum.ToNewPatch)
            {
                if (PatchtoAdd.AffectedPatches_id.Length == 0 && PatchtoAdd.AffectedPatches_nm.Length == 0)
                {
                    summary.WriteMessage(this, " Command to add patch did not supply a valid patch to be used as base for the new one. Command will be ignored.");
                    isDataOK = false;
                }
                else if (PatchtoAdd.AreaNewPatch <= 0.0)
                {
                    summary.WriteMessage(this, " Command to add patch did not supply a valid area fraction for the new patch. Command will be ignored.");
                    isDataOK = false;
                }
            }
            else if (PatchtoAdd.DepositionType == DepositionTypeEnum.ToSpecificPatch)
            {
                if (PatchtoAdd.AffectedPatches_id.Length == 0 && PatchtoAdd.AffectedPatches_nm.Length == 0)
                {
                    summary.WriteMessage(this, " Command to add patch did not supply a valid patch to be used as base for the new one. Command will be ignored.");
                    isDataOK = false;
                }
            }
            else if (PatchtoAdd.DepositionType == DepositionTypeEnum.NewOverlappingPatches)
            {
                if (PatchtoAdd.AreaNewPatch <= 0.0)
                {
                    summary.WriteMessage(this, " Command to add patch did not supply a valid area fraction for the new patch. Command will be ignored.");
                    isDataOK = false;
                }
            }
            else if (PatchtoAdd.DepositionType == DepositionTypeEnum.ToAllPaddock)
            {
                // assume stuff is added homogeneously and with no patch creation, thus no factors are actually required
            }
            else
            {
                summary.WriteMessage(this, " Command to add patch did not supply a valid DepositionType. Command will be ignored.");
                isDataOK = false;
            }

            if (isDataOK)
            {
                List <int> PatchesToAddStuff;

                if ((PatchtoAdd.DepositionType == DepositionTypeEnum.ToNewPatch) ||
                    (PatchtoAdd.DepositionType == DepositionTypeEnum.NewOverlappingPatches))
                { // New patch(es) will be added
                    AddNewCNPatch(PatchtoAdd);
                }
                else if (PatchtoAdd.DepositionType == DepositionTypeEnum.ToSpecificPatch)
                {  // add stuff to selected patches, no new patch will be created
                    // 1. get the list of patch id's to which stuff will be added
                    PatchesToAddStuff = CheckPatchIDs(PatchtoAdd.AffectedPatches_id, PatchtoAdd.AffectedPatches_nm);
                    // 2. add the stuff to patches listed
                    AddStuffToPatches(PatchesToAddStuff, PatchtoAdd);
                }
                else
                {  // add stuff to all existing patches, no new patch will be created
                   // 1. create the list of patches receiving stuff (all)
                    PatchesToAddStuff = new List <int>();
                    for (int k = 0; k < patches.Count; k++)
                    {
                        PatchesToAddStuff.Add(k);
                    }
                    // 2. add the stuff to patches listed
                    AddStuffToPatches(PatchesToAddStuff, PatchtoAdd);
                }
            }
        }