/// <summary> /// Returns soil Nitrogen uptake from each zone by the static tree model /// </summary> /// <param name="soilstate"></param> /// <returns></returns> public List <Soils.Arbitrator.ZoneWaterAndN> GetNitrogenUptakeEstimates(Soils.Arbitrator.SoilState soilstate) { Zone treeZone = ZoneList.FirstOrDefault() as Zone; List <ZoneWaterAndN> Uptakes = new List <ZoneWaterAndN>(); double PotNO3Supply = 0; // Total N supply (kg) double NDemandkg = GetNDemandToday() * 10 * treeZone.Area; foreach (ZoneWaterAndN Z in soilstate.Zones) { foreach (Zone ZI in ZoneList) { if (Z.Zone.Name == ZI.Name) { ZoneWaterAndN Uptake = new ZoneWaterAndN(ZI); //Find the soil for this zone Soils.Soil ThisSoil = null; Soils.IPhysical soilPhysical = null; foreach (Zone SearchZ in forestryZones) { if (SearchZ.Name == Z.Zone.Name) { ThisSoil = SearchZ.FindInScope <Soils.Soil>(); soilPhysical = ThisSoil.FindChild <Soils.IPhysical>(); break; } } double[] SW = Z.Water; Uptake.NO3N = new double[SW.Length]; Uptake.NH4N = new double[SW.Length]; Uptake.Water = new double[SW.Length]; double[] LL15mm = MathUtilities.Multiply(soilPhysical.LL15, soilPhysical.Thickness); double[] BD = soilPhysical.BD; double[] RLD = GetRLD(ZI); for (int i = 0; i <= SW.Length - 1; i++) { Uptake.NO3N[i] = PotentialNO3Uptake(soilPhysical.Thickness[i], Z.NO3N[i], Z.Water[i], RLD[i], RootRadius, BD[i], Kd); Uptake.NO3N[i] *= 10; // convert from g/m2 to kg/ha PotNO3Supply += Uptake.NO3N[i] * ZI.Area; } Uptakes.Add(Uptake); break; } } } // Now scale back uptakes if demand > supply double F = 0; // Uptake scaling factor if (PotNO3Supply > 0) { F = NDemandkg / PotNO3Supply; if (F > 1) { F = 1; } } else { F = 1; } NStress = Math.Min(1, Math.Max(0, PotNO3Supply / NDemandkg)); List <double> uptakeList = new List <double>(); foreach (ZoneWaterAndN Z in Uptakes) { Z.NO3N = MathUtilities.Multiply_Value(Z.NO3N, F); uptakeList.Add(Z.TotalNO3N); } NUptake = uptakeList.ToArray(); return(Uptakes); }
/// <summary> /// Returns soil water uptake from each zone by the static tree model /// </summary> /// <param name="soilstate"></param> /// <returns></returns> public List <Soils.Arbitrator.ZoneWaterAndN> GetWaterUptakeEstimates(Soils.Arbitrator.SoilState soilstate) { double Etz = treeZoneWater.Eo; //Eo of Tree Zone SWDemand = 0; foreach (Zone ZI in ZoneList) { SWDemand += Etz * (GetShade(ZI) / 100) * (ZI.Area * 10000); // 100 converts from %, 10000 converts from ha to m2 } IndividualTreeWaterDemand = SWDemand / NumberOfTrees; List <ZoneWaterAndN> Uptakes = new List <ZoneWaterAndN>(); double PotSWSupply = 0; // Total water supply (L) foreach (ZoneWaterAndN Z in soilstate.Zones) { foreach (Zone ZI in ZoneList) { if (Z.Zone.Name == ZI.Name) { ZoneWaterAndN Uptake = new ZoneWaterAndN(ZI); //Find the soil for this zone Soils.Soil ThisSoil = null; Soils.IPhysical soilPhysical = null; foreach (Zone SearchZ in forestryZones) { if (SearchZ.Name == Z.Zone.Name) { ThisSoil = SearchZ.FindInScope <Soils.Soil>(); soilPhysical = ThisSoil.FindChild <Soils.IPhysical>(); break; } } double[] SW = Z.Water; Uptake.NO3N = new double[SW.Length]; Uptake.NH4N = new double[SW.Length]; Uptake.Water = new double[SW.Length]; double[] LL15mm = MathUtilities.Multiply(soilPhysical.LL15, soilPhysical.Thickness); double[] RLD = GetRLD(ZI); for (int i = 0; i <= SW.Length - 1; i++) { Uptake.Water[i] = Math.Max(SW[i] - LL15mm[i], 0.0) * BaseKL * RLD[i]; PotSWSupply += Uptake.Water[i] * ZI.Area * 10000; } Uptakes.Add(Uptake); break; } } } // Now scale back uptakes if supply > demand double F = 0; // Uptake scaling factor if (PotSWSupply > 0) { F = SWDemand / PotSWSupply; if (F > 1) { F = 1; } } else { F = 1; } WaterStress = Math.Min(1, Math.Max(0, PotSWSupply / SWDemand)); List <double> uptakeList = new List <double>(); foreach (ZoneWaterAndN Z in Uptakes) { Z.Water = MathUtilities.Multiply_Value(Z.Water, F); uptakeList.Add(Z.TotalWater); } WaterUptake = uptakeList.ToArray(); return(Uptakes); }