/// <summary> /// Set paddock inits for the surfaceOM component. Including stubble masses. /// </summary> /// <param name="apsimCompNode">SurfaceOM component in the paddock</param> /// <param name="paddock"></param> private void setSurfaceOMPaddockInits(XmlNode apsimCompNode, FarmPaddockType paddock) { // Stubble. //* this needs to be implemented with "wheat canola barley ... array of values // * - read in the values in each field and find the specified stubble type, set it, store it back // * string stubbleType = paddock.StubbleType; if (stubbleType == null || stubbleType == "None") throw new Exception("No stubble type specified"); FarmSoilType farmSoil = paddock.SoilType; OrgMatter stubble = new OrgMatter(); XmlNode valueNode = apsimCompNode.SelectSingleNode("initdata/type"); if (valueNode != null) { strToArray(ref stubble.types, valueNode.InnerText.ToLower()); XmlNode nameNode = apsimCompNode.SelectSingleNode("initdata/name"); strToArray(ref stubble.names, nameNode.InnerText.ToLower()); XmlNode massNode = apsimCompNode.SelectSingleNode("initdata/mass"); strToArray(ref stubble.masses, massNode.InnerText.ToLower()); XmlNode cnrNode = apsimCompNode.SelectSingleNode("initdata/cnr"); strToArray(ref stubble.cnrs, cnrNode.InnerText.ToLower()); XmlNode sfNode = apsimCompNode.SelectSingleNode("initdata/standing_fraction"); strToArray(ref stubble.stand_fract, sfNode.InnerText.ToLower()); // check that all the residue types are listed that are in the crop rotation for (int crop = 0; crop < farmSoil.CropRotationList.Count; crop++) { string cropName = farmSoil.CropRotationList[crop].Name.ToLower(); if (CropPhases.IsValidCropName(cropName) && (stubble.types.IndexOf(cropName) < 0)) { //re-add the stubble with the correct values stubble.names.Add(cropName); stubble.types.Add(cropName); stubble.masses.Add("0.0"); stubble.cnrs.Add("60.0"); // ? stubble.stand_fract.Add("0.0"); } } int idx = stubble.types.IndexOf(paddock.StubbleType); // if the stubble type exists in the list already if (idx >= 0) { stubble.Remove(idx); } //remove all mass amounts for (int i = 0; i < stubble.masses.Count; i++) stubble.masses[i] = "0.0"; //re-add the stubble with the correct values stubble.names.Add(paddock.StubbleType); stubble.types.Add(paddock.StubbleType); stubble.masses.Add(paddock.StubbleMass.ToString()); stubble.cnrs.Add(YieldProphetUtility.GetStubbleCNRatio(paddock.StubbleType).ToString()); stubble.stand_fract.Add("0.0"); valueNode.InnerText = APSIM.Shared.Utilities.StringUtilities.BuildString(stubble.types.ToArray(), " "); nameNode.InnerText = APSIM.Shared.Utilities.StringUtilities.BuildString(stubble.names.ToArray(), " "); massNode.InnerText = APSIM.Shared.Utilities.StringUtilities.BuildString(stubble.masses.ToArray(), " "); cnrNode.InnerText = APSIM.Shared.Utilities.StringUtilities.BuildString(stubble.cnrs.ToArray(), " "); sfNode.InnerText = APSIM.Shared.Utilities.StringUtilities.BuildString(stubble.stand_fract.ToArray(), " "); } }
/// <summary> /// Configure the pasture components in the paddock. Set the rooting depths. /// </summary> /// <param name="defaultPaddock"></param> /// <param name="depth">The cumulative soil depth</param> /// <param name="paddocknode">The padddock to set</param> private void SetPastureComponents(FarmPaddockType defaultPaddock, double depth, XmlNode paddocknode, FarmSoilType soilArea) { XmlNodeList pastureNodes = paddocknode.SelectNodes("component[attribute::class=\"Pasture\"]"); foreach (XmlNode pastureNode in pastureNodes) { // get the current rooting depth from the pasture component in the simulation string sDepth = GetValue(pastureNode, "max_rtdep"); double maxRtDep = (sDepth.Length > 0) ? Convert.ToDouble(sDepth) : 0; string simCompName = XmlUtilities.NameAttr(pastureNode); // find one that matches in the cropping rotation list and see if it specifies a new depth CropSpec pastureCrop = soilArea.CropRotationList.Find(c => c.Name.Equals(simCompName, StringComparison.InvariantCultureIgnoreCase)); if (pastureCrop.MaxRootDepth > 0) { maxRtDep = pastureCrop.MaxRootDepth; SetValue(pastureNode, "max_rtdep", Math.Min(maxRtDep, depth * 0.95)); // allow up to 95% of soil depth } else { if (maxRtDep > (depth * 0.95)) // this won't need setting if it is less than the limit SetValue(pastureNode, "max_rtdep", Math.Min(maxRtDep, depth * 0.95)); // allow up to 95% of soil depth } } }
/// <summary> /// Set the soilwat, soiln, surfaceom components /// </summary> /// <param name="defaultPaddock"></param> /// <param name="soilConfig"></param> /// <param name="paddocknode"></param> private void SetSoilComponents(FarmPaddockType defaultPaddock, Soil soilConfig, XmlNode paddocknode) { XmlNode apsimCompNode; XmlNode translatorNode; //set soilwat apsimCompNode = paddocknode.SelectSingleNode("system/component[@class=\"SoilWat\"]"); initSoilWat(apsimCompNode, soilConfig); if (apsimCompNode != null) { translatorNode = apsimCompNode.ParentNode; initSoilWat_Trans(translatorNode, soilConfig, defaultPaddock.SoilType); } //set soiln apsimCompNode = paddocknode.SelectSingleNode("system/component[@class=\"SoilN\"]"); initSoilN(apsimCompNode, soilConfig, defaultPaddock); if (apsimCompNode != null) { translatorNode = apsimCompNode.ParentNode; initSoilN_Trans(translatorNode, soilConfig); } //set surfaceOM apsimCompNode = paddocknode.SelectSingleNode("system/component[@class=\"SurfaceOM\"]"); initSOM(apsimCompNode, soilConfig); if (apsimCompNode != null) { translatorNode = apsimCompNode.ParentNode; initSOM_Trans(translatorNode, soilConfig, defaultPaddock.SoilType); //if there is a paddock with init residue data and new crops in the rotation then set here setSurfaceOMPaddockInits(apsimCompNode, defaultPaddock); } }
/// <summary> /// Initialise a soiln component /// </summary> /// <param name="compNode"></param> /// <param name="aSoil"></param> private void initSoilN(XmlNode compNode, Soil aSoil, FarmPaddockType paddock) { XmlNode anode; anode = compNode.SelectSingleNode("initdata"); XmlNode comment = simulationXMLNode.OwnerDocument.CreateComment(aSoil.Name); anode.AppendChild(comment); anode = compNode.SelectSingleNode("initdata/soiltype"); anode.InnerText = aSoil.SoilType; anode = compNode.SelectSingleNode("initdata/root_cn"); anode.InnerText = asApsimStr(aSoil.SoilOrganicMatter.RootCN); anode = compNode.SelectSingleNode("initdata/root_wt"); anode.InnerText = asApsimStr(aSoil.SoilOrganicMatter.RootWt); anode = compNode.SelectSingleNode("initdata/soil_cn"); anode.InnerText = asApsimStr(aSoil.SoilOrganicMatter.SoilCN); anode = compNode.SelectSingleNode("initdata/enr_a_coeff"); anode.InnerText = asApsimStr(aSoil.SoilOrganicMatter.EnrACoeff); anode = compNode.SelectSingleNode("initdata/enr_b_coeff"); anode.InnerText = asApsimStr(aSoil.SoilOrganicMatter.EnrBCoeff); anode = compNode.SelectSingleNode("initdata/profile_reduction"); anode.InnerText = "off"; anode = compNode.SelectSingleNode("initdata/oc"); anode.InnerText = arrayAsStr(aSoil.SoilOrganicMatter.OC); anode = compNode.SelectSingleNode("initdata/ph"); anode.InnerText = arrayAsStr(aSoil.Analysis.PH); anode = compNode.SelectSingleNode("initdata/fbiom"); anode.InnerText = arrayAsStr(aSoil.SoilOrganicMatter.FBiom); anode = compNode.SelectSingleNode("initdata/finert"); anode.InnerText = arrayAsStr(aSoil.SoilOrganicMatter.FInert); // set all the initial nitrogen values for this soiln double[] NH4Array = new double[aSoil.SoilWater.Thickness.Length]; double[] NO3Array = new double[aSoil.SoilWater.Thickness.Length]; for (int i = 0; i < NH4Array.Length; i++) { NH4Array[i] = 0.0; NO3Array[i] = 0.0; } if (paddock.Sample != null) { // be cautious and allow incomplete sample array sizes int i = 0; while ((i < paddock.Sample.NH4.Length) && (i < aSoil.SoilWater.Thickness.Length)) { NH4Array[i] = paddock.Sample.NH4[i]; i++; } i = 0; while ((i < paddock.Sample.NO3.Length) && (i < aSoil.SoilWater.Thickness.Length)) { NO3Array[i] = paddock.Sample.NO3[i]; i++; } } // these values are now set from the paddock soil Sample object anode = compNode.SelectSingleNode("initdata/no3ppm"); anode.InnerText = arrayAsStr(NO3Array, "f3"); anode = compNode.SelectSingleNode("initdata/nh4ppm"); anode.InnerText = arrayAsStr(NH4Array, "f3"); }