/// <summary> /// Size structures for iValue number of plants /// </summary> /// <param name="iValue"></param> protected override void setNoPlants(int iValue) { base.setNoPlants(iValue); Array.Resize(ref FParams, iValue); ExtMath.ResizeArray(FWaterSupply, iValue, GrazType.MaxSoilLayers); }
/// <summary> /// Size structures for iValue number of plants /// </summary> /// <param name="iValue"></param> protected virtual void setNoPlants(int iValue) { FNoPlants = iValue; Array.Resize(ref FPlantInfo, FNoPlants); ExtMath.ResizeArray(FWaterUptake, FNoPlants, GrazType.MaxSoilLayers); ExtMath.ResizeArray(FSoilFract, FNoPlants, GrazType.MaxSoilLayers); }
public static void ParseUpdate(BitStream stream, StringTable table, ushort entries) { Debug.Assert(stream.Cursor == 0); IList <StringTableEntry> history = new List <StringTableEntry>(); byte entryBits = (byte)ExtMath.Log2(table.MaxEntries); int lastEntry = -1; for (int i = 0; i < entries; i++) { // Did we read the entry from the BitStream or just assume it was lastEntry + 1? //bool readEntry = false; int entryIndex = lastEntry + 1; if (!stream.ReadBool()) { entryIndex = (int)stream.ReadUInt(entryBits); //readEntry = true; } lastEntry = entryIndex; if (entryIndex < 0 || entryIndex > table.MaxEntries) { throw new FormatException("Server sent bogus string index for stringtable"); } string value = null; if (stream.ReadBool()) { bool substringcheck = stream.ReadBool(); if (substringcheck) { int index = (int)stream.ReadUInt(5); int bytesToCopy = (int)stream.ReadUInt(SUBSTRING_BITS); string restOfString = stream.ReadCString(); var testLength = history[index].Value?.Length; value = history[index].Value?.Substring(0, bytesToCopy) + restOfString; } else { value = stream.ReadCString(); } } BitStream userData = null; if (stream.ReadBool()) { if (table.UserDataSize.HasValue) { userData = stream.Subsection(stream.Cursor, stream.Cursor + table.UserDataSizeBits.Value); stream.Seek(table.UserDataSizeBits.Value, System.IO.SeekOrigin.Current); } else { ulong nBytes = stream.ReadUInt(MAX_USERDATA_BITS); userData = stream.Subsection(stream.Cursor, stream.Cursor + (nBytes * 8)); stream.Seek(nBytes * 8, System.IO.SeekOrigin.Current); } } StringTableEntry existingEntry = table.Entries.SingleOrDefault(s => s.ID == entryIndex); if (existingEntry != null) { existingEntry.UserData = userData; if (value != null && value != existingEntry.Value) { //throw new FormatException("Corrupted demo?"); existingEntry.Value = value; } else { value = existingEntry.Value; } existingEntry.Value = value; } else { //Debug.Assert(entryIndex == table.Entries.Count); if (value == null) { Debug.Assert(true); } //Debug.Assert(value != null); //if (value == null) // value = string.Empty; StringTableEntry newEntry = new StringTableEntry(table); newEntry.ID = (ushort)entryIndex; newEntry.UserData = userData; newEntry.Value = value; table.Add(newEntry); existingEntry = newEntry; } if (history.Count > 31) { history.RemoveAt(0); } history.Add(existingEntry); } Debug.Assert((stream.Length - stream.Cursor) < 8); }
/// <summary> /// - /// </summary> /// <param name="Ldx">-</param> /// <param name="fTheta">-</param> /// <param name="fPotentialET">-</param> public void computeWaterSupply(int Ldx, double fTheta, double fPotentialET) { //const double BOUND_APPROACH = 0.95; double Psi_s; Boolean bWetEnough; double[,] Alpha; double[] Beta; double[] Deltas; int iLayerPlants; int[] iPlantMap = new int[99]; double N; double d2PiOnRhoG; double dK_Psi_Soil; double dK_Surface; double[] SurfacePsi = new double[99]; double[] dPrev_Psi = new double[99]; double dMaxError; //double dPrev_Error; double[] Qr = new double[99]; double[] dQr_dPsi = new double[99]; double[] Qs = new double[99]; double[] dExtractRadius = new double[99]; int iIterations; double dQ2Radius; double dLnTerm; Boolean bDone; double[] dDeltaScale = new double[99]; //Boolean bFirstTime; Boolean bRadiusOK; int Idx, Kdx, Ndx; Psi_s = Psi(fTheta, Ldx); // Water potential in this soil layer // units of kPa, negative iLayerPlants = 0; for (Idx = 0; Idx <= FNoPlants - 1; Idx++) { if (fPotentialET > 0.0) { bWetEnough = (Psi_s > FPlantInfo[Idx].UptakeK[3] / fPotentialET); } else { bWetEnough = true; } if (bWetEnough && (FPlantInfo[Idx].RootLengthD[Ldx] > 0.0)) { iPlantMap[iLayerPlants] = Idx; iLayerPlants++; } } if (iLayerPlants > 0) // Only run the water uptake model if { // uptake will be non-negative N = FCond_N[Ldx]; d2PiOnRhoG = (2.0 * Math.PI) / (GRAVITY * DENSITY); dK_Psi_Soil = Conductivity(Psi_s, Ldx) * Psi_s; for (Kdx = 0; Kdx <= iLayerPlants - 1; Kdx++) { Idx = iPlantMap[Kdx]; FParams[Kdx].Q_max = FPlantInfo[Idx].UptakeK[0] // Convert max. uptake/root area to max. * 2.0 * Math.PI * FPlantInfo[Idx].RootRadius[Ldx]; // uptake/root length FParams[Kdx].Psi_max = FPlantInfo[Idx].UptakeK[1]; FParams[Kdx].Curvature = FPlantInfo[Idx].UptakeK[2]; FParams[Kdx].Psi_zero = FPlantInfo[Idx].UptakeK[3] / Math.Max(fPotentialET, 0.00001); FParams[Kdx].PiRLD = Math.PI * FPlantInfo[Idx].RootLengthD[Ldx]; FParams[Kdx].RootRadius = FPlantInfo[Idx].RootRadius[Ldx]; } Alpha = new double[iLayerPlants, iLayerPlants]; Beta = new double[iLayerPlants]; Deltas = new double[iLayerPlants]; iIterations = 0; for (Kdx = 0; Kdx <= iLayerPlants - 1; Kdx++) // Initial guesses for SurfacePsi { SurfacePsi[Kdx] = Psi_s; } // Multi-dimensional Newton-Raphson do // procedure, with modifications { dQ2Radius = 0.0; // Use Q2Radius to compute the current for (Kdx = 0; Kdx <= iLayerPlants - 1; Kdx++) // r(s) values { ComputeQr(Kdx, SurfacePsi[Kdx], ref Qr[Kdx], ref dQr_dPsi[Kdx]); dQ2Radius = dQ2Radius + FParams[Kdx].PiRLD * Math.Pow(Qr[Kdx], 2); } dQ2Radius = Math.Sqrt(dQ2Radius); for (Kdx = 0; Kdx <= iLayerPlants - 1; Kdx++) // We need all the r(s) values before { if (Qr[Kdx] > 0.0) // computing any element of Alpha { dExtractRadius[Kdx] = Qr[Kdx] / dQ2Radius; } else { dExtractRadius[Kdx] = FParams[Kdx].RootRadius; } } for (Kdx = 0; Kdx <= iLayerPlants - 1; Kdx++) { dK_Surface = Conductivity(SurfacePsi[Kdx], Ldx); dLnTerm = Math.Log(dExtractRadius[Kdx] / FParams[Kdx].RootRadius); Qs[Kdx] = d2PiOnRhoG / (N - 1.0) * (dK_Surface * SurfacePsi[Kdx] - dK_Psi_Soil) / dLnTerm; for (Ndx = 0; Ndx <= iLayerPlants - 1; Ndx++) { Alpha[Kdx, Ndx] = FParams[Kdx].PiRLD * dExtractRadius[Kdx] * dExtractRadius[Ndx] * dQr_dPsi[Ndx]; if (Kdx == Ndx) { Alpha[Kdx, Ndx] = Alpha[Kdx, Ndx] - d2PiOnRhoG * dK_Surface - (dLnTerm + 1.0) * dQr_dPsi[Kdx]; } } Beta[Kdx] = (Qr[Kdx] - Qs[Kdx]) * dLnTerm; } dMaxError = 0.0; for (Kdx = 0; Kdx <= iLayerPlants - 1; Kdx++) { dMaxError = Math.Max(dMaxError, Math.Abs(Qr[Kdx] - Qs[Kdx]) / FParams[Kdx].Q_max); } bDone = (dMaxError <= 1.0E-6); if (!bDone) { for (Kdx = 0; Kdx <= iLayerPlants - 1; Kdx++) { dPrev_Psi[Kdx] = SurfacePsi[Kdx]; } ExtMath.SolveLinear(Alpha, ref Deltas, Beta); // Here is the Newton-Raphson step that // computes the deltas for (Kdx = 0; Kdx <= iLayerPlants - 1; Kdx++) { dDeltaScale[Kdx] = 1.0; // Enforce approach from above, i.e. } do // keep the SurfacePsi values between { for (Kdx = 0; Kdx <= iLayerPlants - 1; Kdx++) // Psi_s and the solution { SurfacePsi[Kdx] = dPrev_Psi[Kdx] + dDeltaScale[Kdx] * Deltas[Kdx]; } dQ2Radius = 0.0; for (Kdx = 0; Kdx <= iLayerPlants - 1; Kdx++) { ComputeQr(Kdx, SurfacePsi[Kdx], ref Qr[Kdx], ref dQr_dPsi[Kdx]); dQ2Radius = dQ2Radius + FParams[Kdx].PiRLD * Math.Pow(Qr[Kdx], 2); } dQ2Radius = Math.Sqrt(dQ2Radius); bRadiusOK = true; for (Kdx = 0; Kdx <= iLayerPlants - 1; Kdx++) { if (dQ2Radius > 0.0) { dExtractRadius[Kdx] = Qr[Kdx] / dQ2Radius; } else { dExtractRadius[Kdx] = 0.0; } if (dExtractRadius[Kdx] < FParams[Kdx].RootRadius) { bRadiusOK = false; dDeltaScale[Kdx] = 0.5 * dDeltaScale[Kdx]; } else { dK_Surface = Conductivity(SurfacePsi[Kdx], Ldx); dLnTerm = Math.Log(dExtractRadius[Kdx] / FParams[Kdx].RootRadius); Qs[Kdx] = d2PiOnRhoG / (N - 1.0) * (dK_Surface * SurfacePsi[Kdx] - dK_Psi_Soil) / dLnTerm; if ((Qr[Kdx] - Qs[Kdx]) / FParams[Kdx].Q_max < -1.0E-6) { bRadiusOK = false; dDeltaScale[Kdx] = 0.5 * dDeltaScale[Kdx]; } } if (dDeltaScale[Kdx] < 1.0E-8) { throw new Exception("Numerical failure in water uptake model"); } } }while (!bRadiusOK); } //_ if not bDone iIterations++; if (iIterations > 10000) { throw new Exception("Numerical failure in water uptake model"); } }while (!bDone); //commented code removed for (Kdx = 0; Kdx <= iLayerPlants - 1; Kdx++) // Compute the final water supply rate { // from this layer for each species Idx = iPlantMap[Kdx]; FWaterSupply[Idx, Ldx] = Qr[Kdx] * FPlantInfo[Idx].RootLengthD[Ldx] * FLayerDepth_M[Ldx]; FSoilFract[Idx, Ldx] = Math.PI * FPlantInfo[Idx].RootLengthD[Ldx] * Math.Pow(dExtractRadius[Kdx], 2); } } //_ if iLayerPlants > 0 }