Skip to content

Commit

Permalink
Merge commit '21ee3f51b0f4862ee440102e5f21e04cd1b6fa25'
Browse files Browse the repository at this point in the history
  • Loading branch information
ftomei committed Feb 13, 2025
2 parents 6f04f1f + 21ee3f5 commit 646500b
Show file tree
Hide file tree
Showing 5 changed files with 331 additions and 53 deletions.
246 changes: 209 additions & 37 deletions agrolib/hydrall/hydrall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,30 +17,30 @@
Crit3DHydrallMaps::Crit3DHydrallMaps()
{
mapLAI = new gis::Crit3DRasterGrid;
aboveGroundBiomassMap = new gis::Crit3DRasterGrid;
standBiomassMap = new gis::Crit3DRasterGrid;
rootBiomassMap = new gis::Crit3DRasterGrid;
mapLast30DaysTavg = new gis::Crit3DRasterGrid;
}

void Crit3DHydrallMaps::initialize(const gis::Crit3DRasterGrid& DEM)
{
mapLAI->initializeGrid(DEM);
aboveGroundBiomassMap->initializeGrid(DEM);
standBiomassMap->initializeGrid(DEM);
rootBiomassMap->initializeGrid(DEM);
mapLast30DaysTavg->initializeGrid(DEM);
}

Crit3DHydrallMaps::~Crit3DHydrallMaps()
{
mapLAI->clear();
aboveGroundBiomassMap->clear();
standBiomassMap->clear();
rootBiomassMap->clear();
mapLast30DaysTavg->clear();
}

bool Crit3D_Hydrall::computeHydrallPoint(Crit3DDate myDate, double myTemperature, double myElevation, int secondPerStep, double &AGBiomass, double &rootBiomass)
{
getCO2(myDate, myTemperature, myElevation);
//getCO2(myDate, myTemperature, myElevation);


// da qui in poi bisogna fare un ciclo su tutte le righe e le colonne
Expand Down Expand Up @@ -97,9 +97,65 @@ double Crit3D_Hydrall::photosynthesisAndTranspiration()
{
TweatherDerivedVariable weatherDerivedVariable;

Crit3D_Hydrall::radiationAbsorption();
Crit3D_Hydrall::aerodynamicalCoupling();
Crit3D_Hydrall::upscale();

Crit3D_Hydrall::carbonWaterFluxesProfile();
Crit3D_Hydrall::cumulatedResults();

return 0;
}

double Crit3D_Hydrall::photosynthesisAndTranspirationUnderstorey()
{
const double rootEfficiencyInWaterExtraction = 1.25e-3; //[kgH2O kgDM-1 s-1]
const double understoreyLightUtilization = 1.77e-9; //[kgC J-1]
double cumulatedUnderstoreyTranspirationRate = 0;
double waterUseEfficiency; //[molC molH2O-1]

if (understorey.absorbedPAR > EPSILON)
{
waterUseEfficiency = environmentalVariable.CO2 * 0.1875 / weatherVariable.vaporPressureDeficit;

double lightLimitedUnderstoreyAssimilation; //[molC m-2 s-1]
double waterLimitedUnderstoreyAssimilation; //[molC m-2 s-1]

lightLimitedUnderstoreyAssimilation = understoreyLightUtilization * understorey.absorbedPAR / MC; //convert units from kgC m-2 s-1 into molC m-2 s-1

for (int i = 0; i < soil.layersNr; i++)
{
understoreyTranspirationRate[i] = rootEfficiencyInWaterExtraction * understoreyBiomass.fineRoot * soil.stressCoefficient[i];
cumulatedUnderstoreyTranspirationRate += understoreyTranspirationRate[i];
}

cumulatedUnderstoreyTranspirationRate /= MH2O; //convert units from kgH2O m-2 s-1 into molH2O m-2 s-1
waterLimitedUnderstoreyAssimilation = cumulatedUnderstoreyTranspirationRate * waterUseEfficiency;

if (lightLimitedUnderstoreyAssimilation > waterLimitedUnderstoreyAssimilation)
{
understoreyAssimilationRate = waterLimitedUnderstoreyAssimilation;
}
else
{
understoreyAssimilationRate = lightLimitedUnderstoreyAssimilation;
double lightWaterRatio = lightLimitedUnderstoreyAssimilation/waterLimitedUnderstoreyAssimilation;
for (int j = 0; j < soil.layersNr; j++)
{
understoreyTranspirationRate[j] *= lightWaterRatio;
}
}
}
else
{
for (int i = 0; i < understoreyTranspirationRate.size(); i++)
understoreyTranspirationRate[i] = 0;
understoreyAssimilationRate = 0;
}
return 0;
}


void Crit3D_Hydrall::initialize()
{
plant.myChlorophyllContent = NODATA;
Expand Down Expand Up @@ -156,7 +212,7 @@ void Crit3D_Hydrall::setPlantVariables(double chlorophyllContent)
plant.myChlorophyllContent = chlorophyllContent;
}

void Crit3D_Hydrall::radiationAbsorption(double mySunElevation)
void Crit3D_Hydrall::radiationAbsorption()
{
// taken from Hydrall Model, Magnani UNIBO

Expand Down Expand Up @@ -190,6 +246,7 @@ void Crit3D_Hydrall::radiationAbsorption(double mySunElevation)
//Leaf area index of sunlit (1) and shaded (2) big-leaf
sunlit.leafAreaIndex = UPSCALINGFUNC(directLightExtinctionCoefficient.global,leafAreaIndex);
shaded.leafAreaIndex = leafAreaIndex - sunlit.leafAreaIndex ;
understorey.leafAreaIndex = 0.2;
//Extinction coefficients for direct and diffuse PAR and NIR radiation, scattering leaves
//Based on approximation by Goudriaan 1977 (in Goudriaan & van Laar 1994)
double exponent= -pow(10,0.28 + 0.63*log10(plant.myChlorophyllContent*0.85/1000));
Expand Down Expand Up @@ -241,6 +298,11 @@ void Crit3D_Hydrall::radiationAbsorption(double mySunElevation)
// Isothermal net radiation for sunlit (1) and shaded (2) big-leaf
sunlit.isothermalNetRadiation= sunlit.absorbedPAR + sunlitAbsorbedNIR + sunlitAbsorbedLW ;
shaded.isothermalNetRadiation = shaded.absorbedPAR + shadedAbsorbedNIR + shadedAbsorbedLW ;

//TODO: cover
double cover = 1;
understorey.absorbedPAR = (directIncomingPAR + diffuseIncomingPAR - sunlit.absorbedPAR - shaded.absorbedPAR) * cover + (directIncomingPAR + diffuseIncomingPAR) * (1 - cover);
understorey.absorbedPAR *= (1-std::exp(-0.8*understorey.leafAreaIndex));
}
else
{
Expand All @@ -252,6 +314,9 @@ void Crit3D_Hydrall::radiationAbsorption(double mySunElevation)
sunlitAbsorbedLW = 0.0 ;
sunlit.isothermalNetRadiation = 0.0 ;

understorey.absorbedPAR = 0.0;
understorey.leafAreaIndex = 0.0;

shaded.leafAreaIndex = leafAreaIndex;
shaded.absorbedPAR = 0.0 ;
shadedAbsorbedNIR = 0.0 ;
Expand Down Expand Up @@ -429,20 +494,6 @@ void Crit3D_Hydrall::upscale()
// taken from Hydrall Model, Magnani UNIBO
static double BETA = 0.5 ;

//CONSTANTS (only used here)
const double CRD = 18.7; /*!< scaling factor in RD0 response to temperature (-) */
const double HARD = 46.39; /*!< activation energy of RD0 (kJ mol-1) */
const double CKC = 38.05; /*!< scaling factor in KCT0 response to temperature (-) */
const double CKO = 20.30; /*!< scaling factor in KOT0 response to temperature (-) */
const double HAKO = 36.38; /*!< activation energy of KOT0 (kJ mol-1) */
const double HAGSTAR = 37.83; /*!< activation energy of Gamma_star (kJ mol-1) */
const double HAKC = 79.43; /*!< activation energy of KCT0 (kJ mol-1) */
const double CGSTAR = 19.02; /*!< scaling factor in Gamma_star response to temperature (-) */
const double HAJM = 43.9; /*!< activation energy of JMOP (kJ mol-1 e-) */
const double HDEACTIVATION = 200; /*!< deactivation energy from Kattge & Knorr 2007 (kJ mol-1) */
const double HAVCM = 65.33; /*!< activation energy of VCMOP (kJ mol-1) */


double dum[10],darkRespirationT0;
double optimalCarboxylationRate,optimalElectronTransportRate ;
double leafConvexityFactor ;
Expand All @@ -454,7 +505,7 @@ void Crit3D_Hydrall::upscale()



// optimalCarboxylationRate = (nitrogen.interceptLeaf + nitrogen.slopeLeaf * nitrogen.leafNitrogen/specificLeafArea*1000)*1e-6; // carboxylation rate based on nitrogen leaf
// optimalCarboxylationRate = (nitrogenContent.interceptLeaf + nitrogenContent.slopeLeaf * nitrogenContent.leafNitrogen/specificLeafArea*1000)*1e-6; // carboxylation rate based on nitrogen leaf
optimalCarboxylationRate = maxCarboxRate * 1.0e-6; // [mol m-2 s-1] from Greer et al. 2011
darkRespirationT0 = 0.0089 * optimalCarboxylationRate ;
// Adjust unit dark respiration rate for temperature (mol m-2 s-1)
Expand Down Expand Up @@ -538,22 +589,24 @@ double Crit3D_Hydrall::acclimationFunction(double Ha , double Hd, double leafTem
}


/*void Crit3D_Hydrall::carbonWaterFluxesProfile()
void Crit3D_Hydrall::carbonWaterFluxesProfile()
{
// taken from Hydrall Model, Magnani UNIBO
double assimilationInstant = 0 ;
treeAssimilationRate = 0 ;

treeTranspirationRate.resize(soil.layersNr);

double totalStomatalConductance = 0 ;
for (int i=0; i < modelCase->soilLayersNr; i++)
for (int i=0; i < soil.layersNr; i++)
{
transpirationInstantLayer[i] = 0 ;
treeTranspirationRate[i] = 0 ;

if(sunlit.leafAreaIndex > 0)
{
Crit3D_Hydrall::photosynthesisKernel(modelCase->cultivar, sunlit.compensationPoint, sunlit.minimalStomatalConductance,
Crit3D_Hydrall::photosynthesisKernel(sunlit.compensationPoint, sunlit.aerodynamicConductanceCO2Exchange, sunlit.aerodynamicConductanceHeatExchange, sunlit.minimalStomatalConductance,
sunlit.maximalElectronTrasportRate, sunlit.carbonMichaelisMentenConstant,
sunlit.oxygenMichaelisMentenConstant,sunlit.darkRespiration,
alphaLeuning * stressCoefficientProfile[i], sunlit.maximalCarboxylationRate,
sunlit.oxygenMichaelisMentenConstant,sunlit.darkRespiration, sunlit.isothermalNetRadiation,
parameterWangLeuning.alpha * soil.stressCoefficient[i], sunlit.maximalCarboxylationRate,
&(sunlit.assimilation), &(sunlit.stomatalConductance),
&(sunlit.transpiration));
}
Expand All @@ -564,21 +617,21 @@ double Crit3D_Hydrall::acclimationFunction(double Ha , double Hd, double leafTem
sunlit.transpiration = 0.0;
}

assimilationInstant += sunlit.assimilation * modelCase->rootDensity[i] ;
transpirationInstantLayer[i] += sunlit.transpiration * modelCase->rootDensity[i] ;
totalStomatalConductance += sunlit.stomatalConductance * modelCase->rootDensity[i] ;
treeAssimilationRate += sunlit.assimilation * soil.rootDensity[i] ;
treeTranspirationRate[i] += sunlit.transpiration * soil.rootDensity[i] ;

// shaded big leaf
Crit3D_Hydrall::photosynthesisKernel(modelCase->cultivar, shaded.compensationPoint, shaded.minimalStomatalConductance,
Crit3D_Hydrall::photosynthesisKernel(shaded.compensationPoint, shaded.aerodynamicConductanceCO2Exchange,shaded.aerodynamicConductanceHeatExchange, shaded.minimalStomatalConductance,
shaded.maximalElectronTrasportRate, shaded.carbonMichaelisMentenConstant,
shaded.oxygenMichaelisMentenConstant,shaded.darkRespiration,
alphaLeuning * stressCoefficientProfile[i], shaded.maximalCarboxylationRate,
shaded.oxygenMichaelisMentenConstant,shaded.darkRespiration, shaded.isothermalNetRadiation,
parameterWangLeuning.alpha * soil.stressCoefficient[i], shaded.maximalCarboxylationRate,
&(shaded.assimilation), &(shaded.stomatalConductance),
&(shaded.transpiration));
assimilationInstant += shaded.assimilation * modelCase->rootDensity[i] ; //canopy gross assimilation (mol m-2 s-1)
transpirationInstantLayer[i] += shaded.transpiration * modelCase->rootDensity[i] ; //canopy transpiration (mol m-2 s-1)
totalStomatalConductance += shaded.stomatalConductance * modelCase->rootDensity[i] ; //canopy conductance to CO2 (mol m-2 s-1)
treeAssimilationRate += shaded.assimilation * soil.rootDensity[i] ; //canopy gross assimilation (mol m-2 s-1)
treeTranspirationRate[i] += shaded.transpiration * soil.rootDensity[i] ; //canopy transpiration (mol m-2 s-1)

}
}*/
}


void Crit3D_Hydrall::photosynthesisKernel(double COMP,double GAC,double GHR,double GSCD,double J,double KC,double KO
Expand Down Expand Up @@ -639,3 +692,122 @@ void Crit3D_Hydrall::photosynthesisKernel(double COMP,double GAC,double GHR,doub
*TR = (*GSC / 0.64) * VPDS/weatherVariable.atmosphericPressure ; //Transpiration rate (mol m-2 s-1). Ratio of diffusivities from Wang & Leuning 1998
*TR = MAXVALUE(1.0E-8,*TR) ;
}


void Crit3D_Hydrall::cumulatedResults()
{
// taken from Hydrall Model, Magnani UNIBO
// Cumulate hourly values of gas exchange
deltaTime.absorbedPAR = simulationStepInSeconds*(sunlit.absorbedPAR+shaded.absorbedPAR); //absorbed PAR (mol m-2 yr-1)
deltaTime.grossAssimilation = simulationStepInSeconds * treeAssimilationRate ; // canopy gross assimilation (mol m-2)
deltaTime.respiration = simulationStepInSeconds * Crit3D_Hydrall::plantRespiration() ;
deltaTime.netAssimilation = deltaTime.grossAssimilation- deltaTime.respiration ;
deltaTime.netAssimilation = deltaTime.netAssimilation*12/1000.0/CARBONFACTOR ;

//statePlant.stateGrowth.cumulatedBiomass += deltaTime.netAssimilation ; TODO stand biomass

deltaTime.transpiration = 0.;

for (int i=0; i < soil.layersNr; i++)
{
treeTranspirationRate[i] = simulationStepInSeconds * MH2O * treeTranspirationRate[i]; // [mm]
deltaTime.transpiration += treeTranspirationRate[i];
}


}


double Crit3D_Hydrall::plantRespiration()
{
// taken from Hydrall Model, Magnani UNIBO
double leafRespiration,rootRespiration,sapwoodRespiration,shootRespiration ;
double totalRespiration;
nitrogenContent.leaf = 0.02; //[kg kgDM-1] //0.02 * 10^3 [g kgDM-1]
nitrogenContent.root = 0.0078; //[kg kgDM-1]
nitrogenContent.stem = 0.0021; //[kg kgDM-1]

// Compute hourly stand respiration at 10 oC (mol m-2 h-1)
leafRespiration = 0.0106/2.0 * (treeBiomass.leaf * nitrogenContent.leaf/0.014) / 3600 ; //TODO: CHECK se veramente erano output orari da trasformare in respirazione al secondo
sapwoodRespiration = 0.0106/2.0 * (treeBiomass.sapwood * nitrogenContent.stem/0.014) / 3600 ;
rootRespiration = 0.0106/2.0 * (treeBiomass.fineRoot * nitrogenContent.root/0.014) / 3600 ;

// Adjust for temperature effects
//leafRespiration *= MAXVALUE(0,MINVALUE(1,Vine3D_Grapevine::temperatureMoistureFunction(myInstantTemp + ZEROCELSIUS))) ;
//sapwoodRespiration *= MAXVALUE(0,MINVALUE(1,Vine3D_Grapevine::temperatureMoistureFunction(myInstantTemp + ZEROCELSIUS))) ;
//shootRespiration *= MAXVALUE(0,MINVALUE(1,Vine3D_Grapevine::temperatureMoistureFunction(myInstantTemp + ZEROCELSIUS))) ;
soil.temperature = Crit3D_Hydrall::soilTemperatureModel();
rootRespiration *= MAXVALUE(0,MINVALUE(1,Crit3D_Hydrall::temperatureMoistureFunction(soil.temperature + ZEROCELSIUS))) ;
// hourly canopy respiration (sapwood+fine roots)
totalRespiration =(leafRespiration + sapwoodRespiration + rootRespiration);
// per second respiration
totalRespiration /= double(HOUR_SECONDS);

//TODO understorey respiration

return totalRespiration;
}

double Crit3D_Hydrall::soilTemperatureModel()
{
// taken from Hydrall Model, Magnani UNIBO
double temp;
temp = 0.8 * weatherVariable.last30DaysTAvg + 0.2 * weatherVariable.myInstantTemp;
return temp;
}

double Crit3D_Hydrall::temperatureMoistureFunction(double temperature)
{
double temperatureMoistureFactor;
// TODO
/*// taken from Hydrall Model, Magnani UNIBO
int MODEL;
double temperatureMoistureFactor,correctionSoilMoisture; //K_VW
//K_VW= 1.5;
temperatureMoistureFactor = 1. ;
MODEL = 2;
//T = climate.instantT;
//1. AP_H model
if (MODEL == 1) {
if(psiSoilAverage >= psiFieldCapacityAverage)
{
correctionSoilMoisture = 1.0; //effects of soil water potential
}
else if (psiSoilAverage <= wiltingPoint)
{
correctionSoilMoisture = 0.0;
}
else
{
correctionSoilMoisture = log(wiltingPoint/psiSoilAverage) / log(wiltingPoint/psiFieldCapacityAverage);
}
temperatureMoistureFactor = pow(2.0,((temperature - parameterWangLeuningFix.optimalTemperatureForPhotosynthesis)/10.0)); // temperature dependence of respiration, based on Q10 approach
temperatureMoistureFactor *= correctionSoilMoisture;
}
// 2. AP_LT model
else if (MODEL == 2){
//effects of soil water potential
if (psiSoilAverage >= psiFieldCapacityAverage)
{
correctionSoilMoisture = 1.0;
}
else if (psiSoilAverage <= wiltingPoint)
{
correctionSoilMoisture = 0.0;
}
else
{
correctionSoilMoisture = log(wiltingPoint/psiSoilAverage) / log(wiltingPoint/psiFieldCapacityAverage);
}
temperatureMoistureFactor= exp(308.56 * (1.0/(parameterWangLeuningFix.optimalTemperatureForPhotosynthesis + 46.02) - 1.0/(temperature+46.02))); //temperature dependence of respiration, based on Lloyd & Taylor (1994)
temperatureMoistureFactor *= correctionSoilMoisture;
}*/
return temperatureMoistureFactor;
}

bool Crit3D_Hydrall::growthStand()
{

return true;
}
Loading

0 comments on commit 646500b

Please sign in to comment.