/*! * \brief adjust drainage according to changed root depth. * * \param lastConditions The last soil conditions. * \param tawRz The totally available water in root zone. * \param tawDz The totally available water in the zone under root up to 2m or maxDepth. * \param zr The rooting depth. * \param maxDepth The maximum depth of the soil profile. * * \return The fixed SoilConditions. */ internal static SoilConditions AdjustSoilConditionsZr(SoilConditions lastConditions, double tawRz, double tawDz, double zr, double maxDepth) { if (lastConditions.tawRz == null) { lastConditions.tawRz = tawRz; } if (lastConditions.tawDz == null) { lastConditions.tawDz = tawDz; } if (zr == lastConditions.zr) { return(lastConditions); } var drSum = lastConditions.drRz + lastConditions.drDz; //catch special case root zone from max to 0 if (lastConditions.zr == maxDepth && zr == 0) { lastConditions.drRz = 0; lastConditions.drDz = lastConditions.drRz; } //catch special case root zone from 0 to max else if (lastConditions.zr == 0 && zr == maxDepth) { lastConditions.drRz = lastConditions.drDz; lastConditions.drDz = 0; } //root zone shrinks -> add root drainage to deep zone else if (zr < lastConditions.zr) { var tawRzRatio = ((double)lastConditions.tawRz / lastConditions.zr) / (tawRz / zr); var zrFactor = zr / lastConditions.zr; lastConditions.drRz = lastConditions.drRz * zrFactor / tawRzRatio; lastConditions.drDz = drSum - lastConditions.drRz; } //root zone grows -> add deep drainage to root zone else { var tawDzRatio = ((double)lastConditions.tawDz / (maxDepth - lastConditions.zr)) / (tawDz / (maxDepth - zr)); var zrFactor = (maxDepth - zr) / (maxDepth - lastConditions.zr); lastConditions.drDz = lastConditions.drDz * zrFactor / tawDzRatio; lastConditions.drRz = drSum - lastConditions.drDz; } lastConditions.tawRz = tawRz; lastConditions.tawDz = tawDz; return(lastConditions); }
/*! * \brief Clone constructor. * * \param soilConditions The soil conditions to clone. */ public SoilConditions(SoilConditions soilConditions) { //use this for .net 4.0 //foreach (PropertyInfo pi in this.GetType().GetProperties()) //use this for .net 4.5 foreach (PropertyInfo pi in this.GetType().GetRuntimeProperties()) { if (soilConditions.GetType().GetRuntimeProperty(pi.Name) == null) { continue; } pi.SetValue(this, soilConditions.GetType().GetRuntimeProperty(pi.Name).GetValue(soilConditions, null), null); } }
/*! * \brief adjust soil conditions if drainage is exceeded and the water content is negative. * * \param lastConditions The last soil conditions. * \param tawRz The totally available water in root zone. * \param tawDz The totally available water in the zone under root up to 2m or maxDepth. * \param zrNew The new rooting depth. * \param maxDepth The maximum depth of the soil profile. * \param [in,out] e The actual evaporation, may be adjusted. * \param [in,out] t The actual transpiration, may be adjusted. * * \return The fixed SoilConditions. */ internal static SoilConditions AdjustSoilConditionsExceeded(SoilConditions lastConditions, double tawRz, double tawDz, double zrNew, double maxDepth, ref double e, ref double t) { if (zrNew != lastConditions.zr) { lastConditions = AdjustSoilConditionsZr(lastConditions, tawRz, tawDz, zrNew, maxDepth); } var balanceSum = e + t; //calculate soil water balance var dpRz = Math.Max(0, balanceSum - lastConditions.drRz); var drRz = lastConditions.drRz - balanceSum + dpRz; if (drRz < 0) { //negative drainage should not happen -> percolate excess water to deep zone dpRz -= drRz; drRz = 0; } else if (drRz > lastConditions.tawRz) { //drainage exceeds taw -> adjust this day values to stay beyond this limit var drRzExceeded = drRz - (double)lastConditions.tawRz; var eFactor = e / balanceSum; var etFactor = t / balanceSum; t = Math.Min(0, t - drRzExceeded * etFactor); e = Math.Min(0, e - drRzExceeded * eFactor); drRz = lastConditions.drRz - balanceSum - drRzExceeded + dpRz; } var dpDz = Math.Max(0, dpRz - lastConditions.drDz); var drDz = lastConditions.drDz - dpRz + dpDz; if (drDz < 0) { //negative drainage should not happen -> deep percolate excess water dpDz -= drDz; drDz = 0; } if (drDz > tawDz) { //drainage exceeds taw should not happen in deep zone -> write exceed value to result table drDz = tawDz; } return(lastConditions); }
/*! * \brief calculate evaporation. * * \param [in,out] lastConditions The last soil conditions. * \param plantSet Set the plant values. * \param climateSet Set the climate values. * \param irrigationType Type of the irrigation. * \param et0 The reference evapotranspiration. * \param eFactor The factor e is reduced by. May be used to consider mulching etc. * \param tew The totally evaporable water. * \param irrigationFw The fraction of wetted surface depending on irrigation type. * \param autoIrrigationFw The fraction of wetted surface depending on automatic irrigation type. * \param netIrrigation The netto irrigation. * \param autoNetIrrigation The automatic netto irrigation. * \param interception The interception. * \param interceptionIrr The interception of the irrigated water. * \param interceptionAutoIrr The interception of the automatic irrigated water. * \param [in,out] eResult The result of the calculation. * * \return true if it succeeds, false if it fails. */ public static bool ECalculation( ref SoilConditions lastConditions, PlantValues plantSet, ClimateValues climateSet, String irrigationType, double et0, double eFactor, double tew, double irrigationFw, double autoIrrigationFw, double netIrrigation, double autoNetIrrigation, double interception, double interceptionIrr, double interceptionAutoIrr, ref EvaporationResult eResult ) { if (eResult == null) { eResult = new EvaporationResult(); } var rewFactor = 2.2926; var kcMax = 1.2; var kcMin = 0.0; var kcb = 0.0; var fc = 0.0; if (!(plantSet.isFallow == true)) { kcb = (double)plantSet.Kcb; kcMax = 1.2 + (0.04 * ((double)climateSet.windspeed - 2) - 0.004 * ((double)climateSet.humidity - 45)) * Math.Pow(((double)plantSet.height / 3), 0.3); kcMax = Math.Max(kcMax, kcb + 0.05); kcMax = Math.Min(kcMax, 1.3); kcMax = Math.Max(kcMax, 1.05); kcMin = 0.175; fc = Math.Pow(Math.Max((kcb - kcMin), 0.01) / (kcMax - kcMin), 1 + 0.5 * (double)plantSet.height); fc = Math.Min(0.99, fc); } eResult.kcMin = kcMin; eResult.kcMax = kcMax; eResult.kcb = kcb; eResult.fc = fc; var few = Math.Min(1 - fc, Math.Min(irrigationFw, autoIrrigationFw)); if ((netIrrigation > 0 || autoNetIrrigation > 0) && (irrigationType == "drip")) { few = Math.Min(1 - fc, (1 - (2 / 3) * fc) * Math.Min(irrigationFw, autoIrrigationFw)); } eResult.few = few; eResult.tew = tew; var rew = tew / rewFactor; eResult.rew = rew; var kr = 1.0; if (lastConditions.de > rew) { kr = (tew - lastConditions.de) / (tew - rew); kr = Math.Max(0, kr); } if (rew == 0) { kr = 0; } eResult.kr = kr; var ke = Math.Min(kr * (kcMax - kcb), few * kcMax); eResult.ke = ke; var e = ke * et0; e = e * eFactor; eResult.e = e; var rpPrecipitation = climateSet.rpPrecipitation != null ? (double)climateSet.rpPrecipitation : (double)climateSet.precipitation; var netPrecititationTc = rpPrecipitation - interception + netIrrigation - interceptionIrr + autoNetIrrigation - interceptionAutoIrr; var dpe = netPrecititationTc - lastConditions.de; dpe = Math.Max(0, dpe); var de = lastConditions.de - netPrecititationTc + e / few + dpe; de = Math.Max(0, de); de = Math.Min(tew, de); lastConditions.de = de; lastConditions.dpe = dpe; eResult.de = de; eResult.dpe = dpe; return(true); }