//--------------------------------------------------------------------------------------------------------- /// <summary> /// /// </summary> /// <param name="PM"></param> /// <param name="useAirTemp"></param> /// <param name="layer"></param> /// <param name="leafTemperature"></param> /// <param name="cm"></param> /// <param name="mode"></param> /// <param name="maxHourlyT"></param> /// <param name="Tfraction"></param> /// <returns></returns> public static bool CalcPhotosynthesis(this SunlitShadedCanopy s, PhotosynthesisModel PM, bool useAirTemp, int layer, double leafTemperature, double cm, double cc, double oc, TranspirationMode mode, double maxHourlyT, double Tfraction) { LeafCanopy canopy = PM.Canopy; s.LeafTemp__[layer] = leafTemperature; if (useAirTemp) { s.LeafTemp__[layer] = PM.EnvModel.GetTemp(PM.Time); } s.CalcConductanceResistance(PM, canopy); s.Cm__[layer] = cm; s.Cc[layer] = cc; s.Oc[layer] = oc; s.VcMaxT[layer] = TemperatureFunction.Val2(s.LeafTemp__[layer], s.VcMax25[layer], canopy.CPath.VcTEa); s.RdT[layer] = TemperatureFunction.Val2(s.LeafTemp__[layer], s.Rd25[layer], canopy.CPath.RdTEa); s.JMaxT[layer] = TemperatureFunction.Val(s.LeafTemp__[layer], s.JMax25[layer], canopy.CPath.JMaxC, canopy.CPath.JTMax, canopy.CPath.JTMin, canopy.CPath.JTOpt, canopy.CPath.JBeta); s.VpMaxT[layer] = TemperatureFunction.Val2(s.LeafTemp__[layer], s.VpMax25[layer], canopy.CPath.VpMaxTEa); s.GmT[layer] = TemperatureFunction.Val(s.LeafTemp__[layer], s.Gm25[layer], canopy.CPath.GmC, canopy.CPath.GmTMax, canopy.CPath.GmTMin, canopy.CPath.GmTOpt, canopy.CPath.GmBeta); s.Vpr[layer] = canopy.Vpr_l * s.LAIS[layer]; canopy.Ja = (1 - canopy.F) / 2; s.J[layer] = (canopy.Ja * s.AbsorbedIrradiance[layer] + s.JMaxT[layer] - Math.Pow(Math.Pow(canopy.Ja * s.AbsorbedIrradiance[layer] + s.JMaxT[layer], 2) - 4 * canopy.Theta * s.JMaxT[layer] * canopy.Ja * s.AbsorbedIrradiance[layer], 0.5)) / (2 * canopy.Theta); s.Kc[layer] = TemperatureFunction.Val2(s.LeafTemp__[layer], canopy.CPath.KcP25, canopy.CPath.KcTEa); s.Ko[layer] = TemperatureFunction.Val2(s.LeafTemp__[layer], canopy.CPath.KoP25, canopy.CPath.KoTEa); s.VcVo[layer] = TemperatureFunction.Val2(s.LeafTemp__[layer], canopy.CPath.VcMax_VoMaxP25, canopy.CPath.VcMax_VoMaxTEa); s.Oi[layer] = canopy.OxygenPartialPressure; s.Om[layer] = canopy.OxygenPartialPressure; s.ScO[layer] = s.Ko[layer] / s.Kc[layer] * s.VcVo[layer]; s.G_[layer] = 0.5 / s.ScO[layer]; canopy.Sco = s.ScO[layer]; s.K_[layer] = s.Kc[layer] * (1 + canopy.OxygenPartialPressure / s.Ko[layer]); s.Kp[layer] = TemperatureFunction.Val2(s.LeafTemp__[layer], canopy.CPath.KpP25, canopy.CPath.KpTEa); s.Gbs[layer] = canopy.Gbs_CO2 * s.LAIS[layer]; if (mode == TranspirationMode.unlimited) { s.Rm[layer] = s.RdT[layer] * 0.5; s.Gbs[layer] = canopy.Gbs_CO2 * s.LAIS[layer]; s.Ci[layer] = canopy.CPath.CiCaRatio * canopy.Ca; s.p = s.Ci[layer]; s.q = 1 / s.GmT[layer]; //Caculate A's if (s.type == SSType.Ac1) { s.A[layer] = CalcAc1(s, canopy, layer, TranspirationMode.unlimited); } else if (s.type == SSType.Ac2) { s.A[layer] = CalcAc2(s, canopy, layer, TranspirationMode.unlimited); } else if (s.type == SSType.Aj) { s.A[layer] = CalcAj(s, canopy, layer, TranspirationMode.unlimited); } s.DoWaterInteraction(PM, canopy, mode); } else if (mode == TranspirationMode.limited) { s.WaterUse[layer] = maxHourlyT * Tfraction; s.DoWaterInteraction(PM, canopy, mode); double Gt = 1 / (1 / s.GbCO2[layer] + 1 / s.GsCO2[layer]); s.p = canopy.Ca - s.WaterUseMolsSecond[layer] * canopy.Ca / (Gt + s.WaterUseMolsSecond[layer] / 2); s.q = 1 / (Gt + s.WaterUseMolsSecond[layer] / 2) + 1 / s.GmT[layer]; //Caculate A's if (s.type == SSType.Ac1) { s.A[layer] = CalcAc1(s, canopy, layer, TranspirationMode.limited); } else if (s.type == SSType.Ac2) { s.A[layer] = CalcAc2(s, canopy, layer, TranspirationMode.limited); } else if (s.type == SSType.Aj) { s.A[layer] = CalcAj(s, canopy, layer, TranspirationMode.limited); } s.Ci[layer] = ((Gt - s.WaterUseMolsSecond[0] / 2) * canopy.Ca - s.A[layer]) / (Gt + s.WaterUseMolsSecond[0] / 2); } s.Oc[layer] = canopy.Alpha * s.A[layer] / (canopy.Constant * s.Gbs[layer]) + s.Om[layer]; s.Cc[layer] = (s.Ci[layer] - s.A[layer] / s.GmT[layer]) + (((s.Ci[layer] - s.A[layer] / s.GmT[layer]) * s.x_4 + s.x_5) - s.x_6 * s.A[layer] - s.m - s.x_7) * s.x_8 / s.Gbs[layer]; s.Cm[layer] = s.Ci[layer] - s.A[layer] / s.GmT[layer]; s.LeafTemp[layer] = (s.LeafTemp[layer] + s.LeafTemp__[layer]) / 2; // Test if A is sensible if (double.IsNaN(s.A[layer]) || s.A[layer] <= 0.0) { return(true); } // Test if WaterUse is sensible else if (double.IsNaN(s.WaterUse[layer]) || s.WaterUse[layer] <= 0) { return(true); } // If both are sensible, return false (no errors fonud) else { return(false); } }
//--------------------------------------------------------------------------------------------------------- /// <summary> /// /// </summary> /// <param name="s"></param> /// <param name="PM"></param> /// <param name="useAirTemp"></param> /// <param name="layer"></param> /// <param name="leafTemperature"></param> /// <param name="mode"></param> /// <param name="maxHourlyT"></param> /// <param name="Tfraction"></param> /// <returns></returns> public static bool CalcPhotosynthesis(this SunlitShadedCanopy s, PhotosynthesisModel PM, bool useAirTemp, int layer, double leafTemperature, TranspirationMode mode, double maxHourlyT, double Tfraction) { double p, q; LeafCanopy canopy = PM.Canopy; s.Oi[layer] = canopy.OxygenPartialPressure; s.Om[layer] = canopy.OxygenPartialPressure; s.Oc[layer] = s.Oi[layer]; s.LeafTemp__[layer] = leafTemperature; if (useAirTemp) { s.LeafTemp__[layer] = PM.EnvModel.GetTemp(PM.Time); } s.CalcConductanceResistance(PM, canopy); s.VcMaxT[layer] = TemperatureFunction.Val2(s.LeafTemp__[layer], s.VcMax25[layer], canopy.CPath.VcTMin); s.RdT[layer] = TemperatureFunction.Val2(s.LeafTemp__[layer], s.Rd25[layer], canopy.CPath.RdTMin); s.JMaxT[layer] = TemperatureFunction.Val(s.LeafTemp__[layer], s.JMax25[layer], canopy.CPath.JMaxC, canopy.CPath.JTMax, canopy.CPath.JTMin, canopy.CPath.JTOpt, canopy.CPath.JBeta); canopy.Ja = (1 - canopy.F) / 2; s.J[layer] = (canopy.Ja * s.AbsorbedIrradiance[layer] + s.JMaxT[layer] - Math.Pow(Math.Pow(canopy.Ja * s.AbsorbedIrradiance[layer] + s.JMaxT[layer], 2) - 4 * canopy.Theta * s.JMaxT[layer] * canopy.Ja * s.AbsorbedIrradiance[layer], 0.5)) / (2 * canopy.Theta); s.Kc[layer] = TemperatureFunction.Val2(s.LeafTemp__[layer], canopy.CPath.KcP25, canopy.CPath.KcTMin); s.Ko[layer] = TemperatureFunction.Val2(s.LeafTemp__[layer], canopy.CPath.KoP25, canopy.CPath.KoTMin); s.VcVo[layer] = TemperatureFunction.Val2(s.LeafTemp__[layer], canopy.CPath.VcMax_VoMaxP25, canopy.CPath.VcMax_VoMaxTMin); s.ScO[layer] = s.Ko[layer] / s.Kc[layer] * s.VcVo[layer]; s.G_[layer] = 0.5 / s.ScO[layer]; s.r_[layer] = s.G_[layer] * s.Oc[layer]; canopy.Sco = s.ScO[layer]; s.gm_CO2T[layer] = s.LAIS[layer] * TemperatureFunction.Val(s.LeafTemp__[layer], canopy.Gm25[layer], canopy.CPath.GmC, canopy.CPath.GmTMax, canopy.CPath.GmTMin, canopy.CPath.GmTOpt, canopy.CPath.GmBeta); if (mode == TranspirationMode.unlimited) { s.Ci[layer] = canopy.CPath.CiCaRatio * canopy.Ca; p = s.Ci[layer]; q = 1 / s.gm_CO2T[layer]; //Caculate A's if (s.type == SSType.AC1) { s.A[layer] = CalcAc(s, canopy, layer, TranspirationMode.unlimited, p, q); } else if (s.type == SSType.AJ) { s.A[layer] = CalcAj(s, canopy, layer, TranspirationMode.unlimited, p, q); } if (s.A[layer] < 0 || double.IsNaN(s.A[layer])) { s.A[layer] = 0; } if (PM.conductanceModel == PhotosynthesisModel.ConductanceModel.DETAILED) { s.Ci[layer] = canopy.Ca - s.A[layer] / s.Gb_CO2[layer] - s.A[layer] / s.gs_CO2[layer]; } s.Cc[layer] = s.Ci[layer] - s.A[layer] / s.gm_CO2T[layer]; if (s.Cc[layer] < 0 || double.IsNaN(s.Cc[layer])) { s.Cc[layer] = 0; } s.CiCaRatio[layer] = s.Ci[layer] / canopy.Ca; s.DoWaterInteraction(PM, canopy, mode); } else if (mode == TranspirationMode.limited) { s.WaterUse[layer] = maxHourlyT * Tfraction; s.Elambda[layer] = s.WaterUse[layer] / (0.001 * 3600) * canopy.Lambda / 1000; s.DoWaterInteraction(PM, canopy, mode); s.gm_CO2T[layer] = s.LAIS[layer] * TemperatureFunction.Val(s.LeafTemp__[layer], canopy.Gm25[layer], canopy.CPath.GmC, canopy.CPath.GmTMax, canopy.CPath.GmTMin, canopy.CPath.GmTOpt, canopy.CPath.GmBeta); double Gt = 1 / (1 / s.GbCO2[layer] + 1 / s.GsCO2[layer]); p = canopy.Ca - s.WaterUseMolsSecond[layer] * canopy.Ca / (Gt + s.WaterUseMolsSecond[layer] / 2); q = 1 / (Gt + s.WaterUseMolsSecond[layer] / 2) + 1 / s.gm_CO2T[layer]; //Caculate A's if (s.type == SSType.AC1) { s.A[layer] = CalcAc(s, canopy, layer, TranspirationMode.limited, p, q); } else if (s.type == SSType.AJ) { s.A[layer] = CalcAj(s, canopy, layer, TranspirationMode.limited, p, q); } s.Cb[layer] = canopy.Ca - s.A[layer] / s.GbCO2[layer]; s.Ci[layer] = ((Gt - s.WaterUseMolsSecond[layer] / 2) * canopy.Ca - s.A[layer]) / (Gt + s.WaterUseMolsSecond[layer] / 2); } double airTemp = PM.EnvModel.GetTemp(PM.Time); if (useAirTemp) { s.LeafTemp[layer] = PM.EnvModel.GetTemp(PM.Time); } double diffTemp = s.LeafTemp__[layer] - s.LeafTemp[layer]; s.LeafTemp[layer] = (s.LeafTemp[layer] + s.LeafTemp__[layer]) / 2; if ((Math.Abs(diffTemp) > s.leafTempTolerance) || double.IsNaN(s.LeafTemp[layer])) { return(false); } return(true); }
//--------------------------------------------------------------------------------------------------------- /// <summary> /// /// </summary> /// <param name="PM"></param> /// <param name="useAirTemp"></param> /// <param name="layer"></param> /// <param name="leafTemperature"></param> /// <param name="cm"></param> /// <param name="mode"></param> /// <param name="maxHourlyT"></param> /// <param name="Tfraction"></param> /// <returns></returns> public static bool CalcPhotosynthesis(this SunlitShadedCanopy s, PhotosynthesisModel PM, bool useAirTemp, int layer, double leafTemperature, double cm, TranspirationMode mode, double maxHourlyT, double Tfraction) { double p, q; LeafCanopy canopy = PM.Canopy; //leafTemp[layer] = PM.envModel.getTemp(PM.time); s.LeafTemp__[layer] = leafTemperature; if (useAirTemp) { s.LeafTemp__[layer] = PM.EnvModel.GetTemp(PM.Time); } s.Cm__[layer] = cm; double vpd = PM.EnvModel.GetVPD(PM.Time); s.VcMaxT[layer] = TemperatureFunction.Val2(s.LeafTemp__[layer], s.VcMax25[layer], canopy.CPath.VcTMin); s.RdT[layer] = TemperatureFunction.Val2(s.LeafTemp__[layer], s.Rd25[layer], canopy.CPath.RdTMin); s.JMaxT[layer] = TemperatureFunction.Val(s.LeafTemp__[layer], s.JMax25[layer], canopy.CPath.JMaxC, canopy.CPath.JTMax, canopy.CPath.JTMin, canopy.CPath.JTOpt, canopy.CPath.JBeta); s.VpMaxT[layer] = TemperatureFunction.Val2(s.LeafTemp__[layer], s.VpMax25[layer], canopy.CPath.VpMaxTMin); s.Vpr[layer] = canopy.Vpr_l * s.LAIS[layer]; canopy.Ja = (1 - canopy.F) / 2; s.J[layer] = (canopy.Ja * s.AbsorbedIrradiance[layer] + s.JMaxT[layer] - Math.Pow(Math.Pow(canopy.Ja * s.AbsorbedIrradiance[layer] + s.JMaxT[layer], 2) - 4 * canopy.Theta * s.JMaxT[layer] * canopy.Ja * s.AbsorbedIrradiance[layer], 0.5)) / (2 * canopy.Theta); s.Kc[layer] = TemperatureFunction.Val2(s.LeafTemp__[layer], canopy.CPath.KcP25, canopy.CPath.KcTMin); s.Ko[layer] = TemperatureFunction.Val2(s.LeafTemp__[layer], canopy.CPath.KoP25, canopy.CPath.KoTMin); s.VcVo[layer] = TemperatureFunction.Val2(s.LeafTemp__[layer], canopy.CPath.VcMax_VoMaxP25, canopy.CPath.VcMax_VoMaxTMin); s.ScO[layer] = s.Ko[layer] / s.Kc[layer] * s.VcVo[layer]; s.G_[layer] = 0.5 / s.ScO[layer]; canopy.Sco = s.ScO[layer]; //For reporting ??? s.K_[layer] = s.Kc[layer] * (1 + canopy.OxygenPartialPressure / s.Ko[layer]); s.Kp[layer] = TemperatureFunction.Val2(s.LeafTemp__[layer], canopy.CPath.KpP25, canopy.CPath.KpTMin); s.Gbs[layer] = canopy.Gbs_CO2 * s.LAIS[layer]; s.Oi[layer] = canopy.OxygenPartialPressure; s.Om[layer] = canopy.OxygenPartialPressure; if (mode == TranspirationMode.unlimited) { s.VPD[layer] = PM.EnvModel.GetVPD(PM.Time); s.gm_CO2T[layer] = s.LAIS[layer] * TemperatureFunction.Val(s.LeafTemp__[layer], canopy.Gm25[layer], canopy.CPath.GmC, canopy.CPath.GmTMax, canopy.CPath.GmTMin, canopy.CPath.GmTOpt, canopy.CPath.GmBeta); s.Rm[layer] = s.RdT[layer] * 0.5; s.Gbs[layer] = canopy.Gbs_CO2 * s.LAIS[layer]; s.Ci[layer] = canopy.CPath.CiCaRatio * canopy.Ca; p = s.Ci[layer]; q = 1 / s.gm_CO2T[layer]; //Caculate A's if (s.type == SSType.AJ) { s.A[layer] = CalcAj(s, canopy, layer, TranspirationMode.unlimited, p, q); } else { s.A[layer] = CalcAc(s, canopy, layer, TranspirationMode.unlimited, p, q); } s.CalcConductanceResistance(PM, canopy); s.Cm[layer] = s.Ci[layer] - s.A[layer] / s.gm_CO2T[layer]; s.XX = s.Cm[layer] * s.X_4 + s.X_5; if (s.type == SSType.AC1 || s.type == SSType.AC2) { s.Vp[layer] = Math.Min(s.Cm[layer] * s.VpMaxT[layer] / (s.Cm[layer] + s.Kp[layer]), s.Vpr[layer]); } else if (s.type == SSType.AJ) { s.Vp[layer] = canopy.CPath.X * s.J[layer] / 2; } s.Oc[layer] = canopy.Alpha * s.A[layer] / (0.047 * s.Gbs[layer]) + s.Om[layer]; s.r_[layer] = s.G_[layer] * s.Oc[layer]; s.Cc[layer] = s.Cm[layer] + (s.XX - s.A[layer] - s.Rm[layer]) / s.Gbs[layer]; if (s.Cc[layer] < 0 || double.IsNaN(s.Cc[layer])) { s.Cc[layer] = 0; } s.F[layer] = s.Gbs[layer] * (s.Cc[layer] - s.Cm[layer]) / s.XX; s.DoWaterInteraction(PM, canopy, mode); } else if (mode == TranspirationMode.limited) { s.WaterUse[layer] = maxHourlyT * Tfraction; s.Elambda[layer] = s.WaterUse[layer] / (0.001 * 3600) * canopy.Lambda / 1000; double totalAbsorbed = s.AbsorbedIrradiancePAR[layer] + s.AbsorbedIrradianceNIR[layer]; s.Rn[layer] = totalAbsorbed - 2 * (canopy.Sigma * Math.Pow(273 + s.LeafTemp__[layer], 4) - canopy.Sigma * Math.Pow(273 + PM.EnvModel.GetTemp(PM.Time), 4)); s.CalcConductanceResistance(PM, canopy); s.DoWaterInteraction(PM, canopy, mode); s.gm_CO2T[layer] = s.LAIS[layer] * TemperatureFunction.Val(s.LeafTemp__[layer], canopy.Gm25[layer], canopy.CPath.GmC, canopy.CPath.GmTMax, canopy.CPath.GmTMin, canopy.CPath.GmTOpt, canopy.CPath.GmBeta); double Gt = 1 / (1 / s.GbCO2[layer] + 1 / s.GsCO2[layer]); p = canopy.Ca - s.WaterUseMolsSecond[layer] * canopy.Ca / (Gt + s.WaterUseMolsSecond[layer] / 2); q = 1 / (Gt + s.WaterUseMolsSecond[layer] / 2) + 1 / s.gm_CO2T[layer]; //Caculate A's if (s.type == SSType.AJ) { s.A[layer] = CalcAj(s, canopy, layer, TranspirationMode.limited, p, q); } else { s.A[layer] = CalcAc(s, canopy, layer, TranspirationMode.limited, p, q); } s.Cb[layer] = canopy.Ca - s.A[layer] / s.GbCO2[layer]; s.Ci[layer] = ((Gt - s.WaterUseMolsSecond[0] / 2) * canopy.Ca - s.A[layer]) / (Gt + s.WaterUseMolsSecond[0] / 2); s.Cm[layer] = s.Ci[layer] - s.A[layer] / s.gm_CO2T[layer]; s.XX = s.Cm[layer] * s.X_4 + s.X_5; s.Oc[layer] = canopy.Alpha * s.A[layer] / (0.047 * s.Gbs[layer]) + s.Om[layer]; s.r_[layer] = s.G_[layer] * s.Oc[layer]; s.Cc[layer] = s.Cm[layer] + (s.XX - s.A[layer] - s.Rm[layer]) / s.Gbs[layer]; if (s.Cc[layer] < 0 || double.IsNaN(s.Cc[layer])) { s.Cc[layer] = 0; } s.F[layer] = s.Gbs[layer] * (s.Cc[layer] - s.Cm[layer]) / s.XX; } double airTemp = PM.EnvModel.GetTemp(PM.Time); if (useAirTemp) { s.LeafTemp[layer] = PM.EnvModel.GetTemp(PM.Time); } double diffCm = (s.type == SSType.AC1 ? Math.Abs(s.Cm__[layer] - s.Cm[layer]) : 0); double diffTemp = s.LeafTemp__[layer] - s.LeafTemp[layer]; s.LeafTemp[layer] = (s.LeafTemp[layer] + s.LeafTemp__[layer]) / 2; s.Cm[layer] = (s.Cm[layer] + s.Cm__[layer]) / 2; if ((Math.Abs(diffCm) > s.CmTolerance) || (Math.Abs(diffTemp) > s.leafTempTolerance) || double.IsNaN(s.Cm[layer]) || double.IsNaN(s.LeafTemp[layer])) { return(false); } return(true); }