Example #1
0
        /// <summary>
        /// calculate how the dlt's (C and N) are partitioned amongst patches
        /// </summary>
        /// <param name="callingModelType">Type of calling model.</param>
        /// <param name="incomingDelta">The dlt to be partioned amongst patches</param>
        /// <param name="soluteName">The solute or pool that is changing</param>
        /// <param name="partitionApproach">The type of partition to be used</param>
        /// <returns>The values of dlt partitioned for each existing patch</returns>
        private double[][] PartitionDelta(double[] incomingDelta, string soluteName, SoluteSetterType callingModelType, PartitionApproachEnum partitionApproach)
        {
            int numberLayers = incomingDelta.Length;

            // 1. initialise the result array
            double[][] Result = new double[patches.Count][];
            for (int k = 0; k < patches.Count; k++)
            {
                Result[k] = new double[numberLayers];
            }

            try
            {
                // 1.5 If the calling model is a plant and the solute is NO3 or NH4 then use the 'PlantAvailable' solutes instead.
                if (callingModelType == SoluteSetterType.Plant && (soluteName == "NO3" || soluteName == "NH4"))
                {
                    soluteName = "PlantAvailable" + soluteName;
                }

                // 2- gather how much solute is already in the soil
                double[][] existingSoluteAmount = new double[patches.Count][];
                for (int k = 0; k < patches.Count; k++)
                {
                    existingSoluteAmount[k] = patches[k].GetSoluteKgHa(soluteName);
                }

                // 3- calculate partition weighting factors, done for each layer based on existing solute amount
                double[] partitionWeight;
                double[] thisLayerPatchSolute;
                double   thisLayersTotalSolute;
                for (int layer = 0; layer < numberLayers; layer++)
                {
                    if (Math.Abs(incomingDelta[layer]) > epsilon)
                    {
                        // 3.1- zero and initialise the variables
                        partitionWeight      = new double[patches.Count];
                        thisLayerPatchSolute = new double[patches.Count];

                        // 3.2- get the solute amounts for each patch in this layer
                        if (partitionApproach == PartitionApproachEnum.BasedOnLayerConcentration ||
                            (partitionApproach == PartitionApproachEnum.BasedOnConcentrationAndDelta && incomingDelta[layer] < epsilon))
                        {
                            for (int k = 0; k < patches.Count; k++)
                            {
                                thisLayerPatchSolute[k] = existingSoluteAmount[k][layer] * patches[k].RelativeArea;
                            }
                        }
                        else if (partitionApproach == PartitionApproachEnum.BasedOnSoilConcentration ||
                                 (partitionApproach == PartitionApproachEnum.BasedOnConcentrationAndDelta && incomingDelta[layer] >= epsilon))
                        {
                            for (int k = 0; k < patches.Count; k++)
                            {
                                double layerUsed = 0.0;
                                for (int z = layer; z >= 0; z--)        // goes backwards till soil surface (but may stop before that)
                                {
                                    thisLayerPatchSolute[k] += existingSoluteAmount[k][z];
                                    layerUsed += soilPhysical.Thickness[z];
                                    if ((LayerForNPartition > epsilon) && (layerUsed >= LayerForNPartition))
                                    {
                                        // stop if thickness reaches a defined value
                                        z = -1;
                                    }
                                }
                                thisLayerPatchSolute[k] *= patches[k].RelativeArea;
                            }
                        }

                        // 3.3- get the total solute amount for this layer
                        thisLayersTotalSolute = MathUtilities.Sum(thisLayerPatchSolute);

                        // 3.4- Check whether the existing solute is greater than the incoming delta
                        if (MathUtilities.IsLessThan(thisLayersTotalSolute + incomingDelta[layer], 0))
                        {
                            throw new Exception($"Attempt to change {soluteName}[{layer + 1}] to a negative value");
                        }

                        // 3.5- Compute the partition weights for each patch
                        for (int k = 0; k < patches.Count; k++)
                        {
                            partitionWeight[k] = 0.0;
                            if (thisLayersTotalSolute >= epsilon)
                            {
                                partitionWeight[k] = MathUtilities.Divide(thisLayerPatchSolute[k], thisLayersTotalSolute, 0.0);
                            }
                        }

                        // 4- Compute the partitioned values for each patch
                        for (int k = 0; k < patches.Count; k++)
                        {
                            Result[k][layer] = (incomingDelta[layer] * partitionWeight[k]) / patches[k].RelativeArea;
                        }
                    }
                    else
                    {
                        // there is no incoming solute for this layer
                        for (int k = 0; k < patches.Count; k++)
                        {
                            Result[k][layer] = 0.0;
                        }
                    }
                }
            }
            catch (Exception e)
            {
                throw new Exception($"Problems with partitioning {soluteName} - {e}");
            }

            return(Result);
        }
        /// <summary>
        /// calculate how the dlt's (C and N) are partitioned amongst patches
        /// </summary>
        /// <param name="incomingDelta">The dlt to be partioned amongst patches</param>
        /// <param name="SoluteName">The solute or pool that is changing</param>
        /// <param name="PartitionType">The type of partition to be used</param>
        /// <returns>The values of dlt partitioned for each existing patch</returns>
        private double[][] partitionDelta(double[] incomingDelta, string SoluteName, PartitionApproachEnum PartitionType)
        {
            int nPatches = Patch.Count;

            // 1. initialise the result array
            double[][] Result = new double[nPatches][];
            for (int k = 0; k < nPatches; k++)
            {
                Result[k] = new double[nLayers];
            }

            try
            {
                if (senderModule.Equals("Plant", StringComparison.InvariantCultureIgnoreCase))
                {
                    for (int k = 0; k < nPatches; k++)
                    {
                        Patch[k].CalcTotalMineralNInRootZone();
                    }
                }

                // 2- gather how much solute is already in the soil
                double[][] existingSoluteAmount = new double[nPatches][];
                for (int k = 0; k < nPatches; k++)
                {
                    switch (SoluteName.ToUpper())
                    {
                    case "UREA":
                        existingSoluteAmount[k] = Patch[k].urea;
                        break;

                    case "NH4":
                        if (senderModule.Equals("Plant", StringComparison.InvariantCultureIgnoreCase))
                        {
                            existingSoluteAmount[k] = Patch[k].nh4AvailableToPlants;
                        }
                        else
                        {
                            existingSoluteAmount[k] = Patch[k].nh4;
                        }
                        break;

                    case "NO3":
                        if (senderModule.Equals("Plant", StringComparison.InvariantCultureIgnoreCase))
                        {
                            existingSoluteAmount[k] = Patch[k].no3AvailableToPlants;
                        }
                        else
                        {
                            existingSoluteAmount[k] = Patch[k].no3;
                        }
                        break;

                    default:
                        throw new Exception(" The solute " + SoluteName
                                            + " is not recognised by SoilNitrogen -  solute partition");
                    }
                }

                // 3- calculate partition weighting factors, done for each layer based on existing solute amount
                double[] partitionWeight;
                double[] thisLayerPatchSolute;
                double   thisLayersTotalSolute;
                for (int layer = 0; layer < (nLayers); layer++)
                {
                    if (Math.Abs(incomingDelta[layer]) > epsilon)
                    {
                        // 3.1- zero and initialise the variables
                        partitionWeight      = new double[nPatches];
                        thisLayerPatchSolute = new double[nPatches];

                        // 3.2- get the solute amounts for each patch in this layer
                        if ((PartitionType == PartitionApproachEnum.BasedOnLayerConcentration) ||
                            (PartitionType == PartitionApproachEnum.BasedOnConcentrationAndDelta && incomingDelta[layer] < epsilon))
                        {
                            for (int k = 0; k < nPatches; k++)
                            {
                                thisLayerPatchSolute[k] = existingSoluteAmount[k][layer] * Patch[k].RelativeArea;
                            }
                        }
                        else if ((PartitionType == PartitionApproachEnum.BasedOnSoilConcentration) ||
                                 (PartitionType == PartitionApproachEnum.BasedOnConcentrationAndDelta && incomingDelta[layer] >= epsilon))
                        {
                            for (int k = 0; k < nPatches; k++)
                            {
                                double layerUsed = 0.0;
                                for (int z = layer; z >= 0; z--)        // goes backwards till soil surface (but may stop before that)
                                {
                                    thisLayerPatchSolute[k] += existingSoluteAmount[k][z];
                                    layerUsed += dlayer[z];
                                    if ((LayerForNPartition > epsilon) && (layerUsed >= LayerForNPartition))
                                    {
                                        // stop if thickness reaches a defined value
                                        z = -1;
                                    }
                                }
                                thisLayerPatchSolute[k] *= Patch[k].RelativeArea;
                            }
                        }

                        // 3.3- get the total solute amount for this layer
                        thisLayersTotalSolute = SumDoubleArray(thisLayerPatchSolute);

                        // 3.4- Check whether the existing solute is greater than the incoming delta
                        if (MathUtilities.IsLessThan(thisLayersTotalSolute + incomingDelta[layer], 0))
                        {
                            string myMessage = "attempt to change " + SoluteName + "[" + (layer + 1) +
                                               "] to a negative value";
                            throw new Exception(myMessage);
                        }

                        // 3.5- Compute the partition weights for each patch
                        for (int k = 0; k < nPatches; k++)
                        {
                            partitionWeight[k] = 0.0;
                            if (thisLayersTotalSolute >= epsilon)
                            {
                                partitionWeight[k] = MathUtilities.Divide(thisLayerPatchSolute[k], thisLayersTotalSolute, 0.0);
                            }
                        }

                        // 4- Compute the partitioned values for each patch
                        for (int k = 0; k < nPatches; k++)
                        {
                            Result[k][layer] = (incomingDelta[layer] * partitionWeight[k]) / Patch[k].RelativeArea;
                        }
                    }
                    else
                    { // there is no incoming solute for this layer
                        for (int k = 0; k < nPatches; k++)
                        {
                            Result[k][layer] = 0.0;
                        }
                    }
                }
            }
            catch (Exception e)
            {
                throw new Exception(" problems with partitioning " + SoluteName + " - " + e.ToString());
            }

            return(Result);
        }