/// <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); } }
/// <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; } } } }
/// <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; } } }
/// <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); } }
/// <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); } }
/// <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); } } }