Professional Documents
Culture Documents
Weather.h
#pragma once
#ifndef _WEATHER_H_
#define _WEATHER_H_
struct TWeather
public:
TWeather()
PredawnLWP=-0.05;
int year;
int jday;
double CO2, airT, PFD, solRad, RH, wind, rain, dayLength, soilT,ET_supply,
LeafWP, PredawnLWP,
pcrs,pcrl,
float MaxRootDepth,ThetaAvail;
};
#endif
Weather .cpp
#include "stdafx.h"
#include "weather.h"
Timer.h
#ifndef __TIMER_H__
#define __TIMER_H__
#include "cpmdate.h"
class Timer
private:
CPMDate *date;
int day_of_year;
public:
CPMDate* get_date();
bool step();
~Timer();
Timer();
Timer(double ss);
int julday(const int mm, const int id, const int iyyy);
void caldat(const int julian, int &mm, int &id, int &iyyy);
};
#endif
Timer.cpp
#include "stdafx.h"
#include "timer.h"
#include <cmath>
#include <iostream>
Timer::Timer()
date=NULL;
day_of_year=julday(my,dy,yr)-julday(1,1,yr)+1;// day_number
hour = 0.0; // hr
step_size = ss; // hr
steps_per_day = 24.0/step_size;
}
Timer::~Timer()
Timer::Timer(double ss)
step_size = ss;
hour = 0.0;
steps_per_day = 24.0/step_size;
date=new CPMDate();
CPMDate* Timer::get_date()
return date;
bool Timer::step()
// hour = 0.0;
hour += step_size;
// cout << day_of_year << " " << hour << "\n";
hour = 0.0;
day_of_year += 1;
date->increment();
return true;
return false;
char* Timer::date_from_day_of_year(int d)
// return dt->get_date();
int Timer::julday(const int mm, const int id, const int iyyy)
int ja,jul,jy=iyyy,jm;
if (mm > 2) {
jm=mm+1;
} else {
--jy;
jm=mm+13;
jul = int(floor(365.25*jy)+floor(30.6001*jm)+id+1720995);
jul += 2-ja+int(0.25*ja);
return jul;
int ja,jalpha,jb,jc,jd,je;
julian=julian+2415019 ;
jalpha=int(((double)(julian-1867216)-0.25)/36524.25);
ja=julian+1+jalpha-int(0.25*jalpha);
ja=julian+36525*(1-julian/36525);
} else
ja=julian;
jb=ja+1524;
jc=int(6680.0+((double)(jb-2439870)-122.1)/365.25);
jd=int(365*jc+(0.25*jc));
je=int((jb-jd)/30.6001);
id=jb-jd-int(30.6001*je);
mm=je-1;
iyyy=jc-4715;
if (mm > 2) --iyyy;
ThermalTime.h
#pragma once
class CThermalTime
public:
CThermalTime(void);
virtual ~CThermalTime(void);
void set_temperatures(double Tb, double To, double Tm) {Tbase = Tb; Topt = To; Tmax = Tm;}
void add(double x);
private:
double Tcur;
double Tbase;
double Topt;
double Tmax;
double sum;
double dTmpr;
double timeStep;
double actualAge;
};
ThermalTime.cpp
#include "stdafx.h"
#include "thermaltime.h"
CThermalTime::CThermalTime(void)
Tcur = 25.0;
Tbase = 8.0;
Topt = 31.0;
Tmax = 43.3;
timeStep = 60.0;
Tcur = 0.0;
timeStep = step;
add(Tcur);
void CThermalTime::add(double x)
Tcur = x;
double dD = timeStep/MINUTESPERDAY;
dTmpr = 0.0;
else
dTmpr = (Tcur-Tbase);
sum += (dTmpr*dD);
actualAge += dD;
}
void CThermalTime::update(double Tmpr, double step)
timeStep = step;
add(Tmpr);
CThermalTime::~CThermalTime(void)
Stem.h
#pragma once
#ifndef _STEM_H_
#define _STEM_H_
#include "organ.h"
public:
CStem();
CStem(int);
~CStem();
private:
int rank;
double length;
double diameter;
};
#endif
Stem.cpp
#include "stdafx.h"
#include "stem.h"
CStem::CStem()
rank = n;
CStem::~CStem() {}
COrgan::set_temperature(dv->get_Tcur());
COrgan::update();
}
Stadfex.h
#include <iostream>
#include <cstring>
#ifdef _WIN32
#endif
#ifndef _WIN32
#endif
Stadfex.cpp
#include "stdafx.h"
Solar.h
#ifndef SOLAR_H
#define SOLAR_H
class solar
public:
solar();
protected:
private:
};
#pragma once
#define PI 3.1415
class CSolar
private:
int JDay;
// Environmental Components
// solar components
double NIRTotal,NIRDiffuse,NIRDirect,PARTotal,PARDiffuse,PARDirect;
double RowAzimuth;
void SetDayLength();
void SetSolarNoon();
double press();
double m() ;
void SetPotentialSolar();
void SetPotentialPAR();
void SetPotentialNIR();
void SetNIRTotal();
void SetNIRDirect();
void SetNIRDiffuse();
void SetPARTotal();
void SetPARDirect();
void SetPARDiffuse();
void SetFracPARDirect();
void SetFracNIRDirect();
void SetFracDiffuse();
void SetPARFraction();
public:
CSolar(void);
~CSolar(void);
void SetVal(int Day, double Time, double Lat, double Longi, double Alti, double SolRad0);
};
#endif // SOLAR_H
Solar.cpp
#include <cmath>
#include <algorithm>
#include "solar.h"
double CSolar::SDERP[9] = {
0.3964E-0,0.3631E1,0.3838E-1,0.7659E-1,0.0000E0,-0.2297E2,-0.3885E0,-0.1587E-0,-
0.1021E-1
};
CSolar::CSolar()
JDay = 0;
Time = 0;
Latitude = 0;
Longitude = 0;
tau = 0.75;
useTau = false;
PFD = -99;
PAR = -99;
SolarRadiation = -99;
PARFraction = 0.5;
useObs = false;
HalfDay= 6.0;
DayLength=12;
CSolar::~CSolar()
void CSolar::SetVal(int Day, double Time, double Lat, double Longi, double Alti, double SolRad0) //
Altitude available
JDay = Day;
this->Time = Time*24;
Latitude = DegToRad(Lat);
Longitude = Longi;
useTau = false;
useObs = true;
altitude = max(50.0,Alti);
SetDeclination();
SetDayLength();
SetSolarNoon();
SetSolarElevation();
SetAzimuth();
SetPotentialSolar();
SetPotentialPAR();
SetPotentialNIR();
SetPARFraction();
SolarRadiation=SolRad0;
PAR=SolarRadiation*PARFraction;
SetPARFraction(PAR/SolarRadiation);
SetPotentialNIR();
SetFracNIRDirect();
SetNIRDiffuse();
SetNIRTotal();
SetFracPARDirect();
SetPARTotal();
SetPARDirect();
SetPARDiffuse();
NIR=SolarRadiation*(1-PARFraction);
PFD=PAR*cPFD;
}
void CSolar::SetDeclination()
// From GLYCIM
double Ang1;
int i, n, j;
Declination = SDERP[0];
for (i=2;i<=5;i++)
n = i - 1;
j = i + 4;
Ang1 = n*0.01721*JDay;
Declination = DegToRad(Declination);
void CSolar::SetDayLength()
LatRad=Latitude;
D1 = sin(LatRad)*sin(Declination);
D2 = cos(LatRad)*cos(Declination);
D3 = D1 + D2;
hs = acos((-0.014544 - D1)/D2);
DayLength=hs*24/PI;
HalfDay=DayLength/2.0;
// 7.6394 = 180/3.1416/360*24*2
void CSolar::SetSolarNoon()
double divisor=15.0;
LC=fmod(Longitude,15);
LC=(LC*-1.0)*1/15;;
//
EqTime = (-104.7*sin(Epsil)+596.2*sin(2*Epsil)+4.3*sin(3*Epsil)
-12.7*sin(4*Epsil) - 429.3*cos(Epsil)-2.0*cos(2*Epsil)
SolarNoon=12.0 - LC - EqTime;
Sunrise=SolarNoon - HalfDay;
Sunset=SolarNoon + HalfDay;
void CSolar::SetSolarElevation()
// else
SinElevation= sin(Latitude)*sin(Declination)
+cos(Latitude)*cos(Declination)*cos(DegToRad(15*(Time-SolarNoon)));
Elevation=asin(SinElevation);
Elevation=max(FDIV_GUARD,Elevation);
if (fabs(CosTheta)<FDIV_GUARD)
{ CosTheta=0.0;}
CosElevation= sqrt(1-SinElevation*SinElevation);
void CSolar::SetAzimuth()
Azimuth=
-acos((SinElevation*sin(Latitude)-sin(Declination))/(cos(Latitude)*CosElevation));
{
Azimuth=
acos((SinElevation*sin(Latitude)-sin(Declination))/(cos(Latitude)*CosElevation));
else Azimuth=0;
double CSolar::press()
return 101.325*exp(-altitude/8200.0);
double CSolar::m()
return press()/(101.325*CosTheta);
void CSolar::SetPotentialSolar()
if (SinElevation>= 0.0)
PotentialSolarDirect = SolarConst*pow(tau,m())*SinElevation*(1+0.033*cos(2*PI*(JDay-
10)/365));
PotentialSolarDiffuse = 0.3*(1-
pow(tau,m()))*SolarConst*SinElevation*(1+0.033*cos(2*PI*(JDay-10)/365));
else
{
PotentialSolarDirect = 0.0;
PotentialSolarDiffuse = 0.0;
PotentialSolarTotal=PotentialSolarDiffuse + PotentialSolarDirect;
void CSolar::SetPotentialPAR()
PotentialPARDirect= 600.0*exp(-0.185*m())*CosTheta;
PotentialPARDiffuse= 0.4*(600.0-PotentialPARDirect)*CosTheta;
PotentialPARTotal=PotentialPARDirect+ PotentialPARDiffuse;
ratio2=A-FDIV_GUARD;
R1=A-min(A-FDIV_GUARD,ratio);
R2=R1/B;
R3=pow(R2,2.0/3.0);
FracPARDirect= max(0.0,(PotentialPARDirect/PotentialPARTotal)*(1-pow((A-min(A-
FDIV_GUARD,ratio))/B,(2.0/3.0))));
PARTotal= SolarRadiation*GetPARFraction();
PARDirect= PARTotal*FracPARDirect;
void CSolar::SetPARDiffuse()
PARDiffuse= PARTotal*GetFracPARDiffuse();
void CSolar::SetPotentialNIR()
{
double x, w;
x = 1/CosTheta;
w=-1.1950+0.4459*log10(x)-0.0345*log10(x)*log10(x);
w = 1320.0*pow(10.0,w);
PotentialNIRDirect= (720.0*exp(-0.06*m())-w)*CosTheta;
PotentialNIRDiffuse= 0.6*(720.0-PotentialNIRDirect-w)*CosTheta;
PotentialNIRTotal=PotentialNIRDirect+PotentialNIRDiffuse;
double ratio;
FracNIRDirect= max(0.0,(PotentialNIRDirect/PotentialNIRTotal)*(1-pow((C-min(C-
FDIV_GUARD,ratio))/D,2/3)));
NIRTotal= SolarRadiation*GetNIRFraction();
}
NIRDirect= NIRTotal*FracNIRDirect;
void CSolar::SetNIRDiffuse()
NIRDiffuse= NIRTotal*FracNIRDiffuse;
void CSolar::SetPARFraction()
double tmp;
tmp = PotentialPARTotal/(PotentialPARTotal+PotentialNIRTotal);
if (useTau)
else
tmp= 0.55;
else {
}
}
PARFraction=min(max(FDIV_GUARD, tmp),(1.0-FDIV_GUARD));
#include <cmath>
#include <algorithm>
#include "solar.h"
double CSolar::SDERP[9] = {
0.3964E-0,0.3631E1,0.3838E-1,0.7659E-1,0.0000E0,-0.2297E2,-0.3885E0,-0.1587E-0,-
0.1021E-1
};
CSolar::CSolar()
{
JDay = 0;
Time = 0;
Latitude = 0;
Longitude = 0;
tau = 0.75;
useTau = false;
PFD = -99;
PAR = -99;
SolarRadiation = -99;
PARFraction = 0.5;
useObs = false;
HalfDay= 6.0;
DayLength=12;
CSolar::~CSolar()
void CSolar::SetVal(int Day, double Time, double Lat, double Longi, double Alti, double SolRad0) //
Altitude available
JDay = Day;
this->Time = Time*24;
Latitude = DegToRad(Lat);
Longitude = Longi;
useTau = false;
useObs = true;
altitude = max(50.0,Alti);
SetDeclination();
SetDayLength();
SetSolarNoon();
SetSolarElevation();
SetAzimuth();
SetPotentialSolar();
SetPotentialPAR();
SetPotentialNIR();
SetPARFraction();
SolarRadiation=SolRad0;
PAR=SolarRadiation*PARFraction;
SetPARFraction(PAR/SolarRadiation);
SetPotentialNIR();
SetFracNIRDirect();
SetNIRDiffuse();
SetNIRTotal();
SetFracPARDirect();
SetPARTotal();
SetPARDirect();
SetPARDiffuse();
NIR=SolarRadiation*(1-PARFraction);
PFD=PAR*cPFD;
}
void CSolar::SetDeclination()
// From GLYCIM
double Ang1;
int i, n, j;
Declination = SDERP[0];
for (i=2;i<=5;i++)
n = i - 1;
j = i + 4;
Ang1 = n*0.01721*JDay;
Declination = DegToRad(Declination);
void CSolar::SetDayLength()
{
LatRad=Latitude;
D1 = sin(LatRad)*sin(Declination);
D2 = cos(LatRad)*cos(Declination);
D3 = D1 + D2;
hs = acos((-0.014544 - D1)/D2);
DayLength=hs*24/PI;
HalfDay=DayLength/2.0;
// 7.6394 = 180/3.1416/360*24*2
void CSolar::SetSolarNoon()
double divisor=15.0;
LC=fmod(Longitude,15);
LC=(LC*-1.0)*1/15;;
//
EqTime = (-104.7*sin(Epsil)+596.2*sin(2*Epsil)+4.3*sin(3*Epsil)
-12.7*sin(4*Epsil) - 429.3*cos(Epsil)-2.0*cos(2*Epsil)
+ 19.3*cos(3*Epsil))/3600; // Calculating Equation of Time Eq 11.4 in Campbell and
Norman (1998)
SolarNoon=12.0 - LC - EqTime;
Sunrise=SolarNoon - HalfDay;
Sunset=SolarNoon + HalfDay;
void CSolar::SetSolarElevation()
// else
SinElevation= sin(Latitude)*sin(Declination)
+cos(Latitude)*cos(Declination)*cos(DegToRad(15*(Time-SolarNoon)));
Elevation=asin(SinElevation);
Elevation=max(FDIV_GUARD,Elevation);
if (fabs(CosTheta)<FDIV_GUARD)
{ CosTheta=0.0;}
CosElevation= sqrt(1-SinElevation*SinElevation);
void CSolar::SetAzimuth()
{
Azimuth=
-acos((SinElevation*sin(Latitude)-sin(Declination))/(cos(Latitude)*CosElevation));
Azimuth=
acos((SinElevation*sin(Latitude)-sin(Declination))/(cos(Latitude)*CosElevation));
else Azimuth=0;
double CSolar::press()
return 101.325*exp(-altitude/8200.0);
double CSolar::m()
return press()/(101.325*CosTheta);
void CSolar::SetPotentialSolar()
if (SinElevation>= 0.0)
PotentialSolarDirect = SolarConst*pow(tau,m())*SinElevation*(1+0.033*cos(2*PI*(JDay-
10)/365));
PotentialSolarDiffuse = 0.3*(1-
pow(tau,m()))*SolarConst*SinElevation*(1+0.033*cos(2*PI*(JDay-10)/365));
else
PotentialSolarDirect = 0.0;
PotentialSolarDiffuse = 0.0;
PotentialSolarTotal=PotentialSolarDiffuse + PotentialSolarDirect;
void CSolar::SetPotentialPAR()
PotentialPARDirect= 600.0*exp(-0.185*m())*CosTheta;
PotentialPARDiffuse= 0.4*(600.0-PotentialPARDirect)*CosTheta;
PotentialPARTotal=PotentialPARDirect+ PotentialPARDiffuse;
ratio2=A-FDIV_GUARD;
R1=A-min(A-FDIV_GUARD,ratio);
R2=R1/B;
R3=pow(R2,2.0/3.0);
FracPARDirect= max(0.0,(PotentialPARDirect/PotentialPARTotal)*(1-pow((A-min(A-
FDIV_GUARD,ratio))/B,(2.0/3.0))));
PARTotal= SolarRadiation*GetPARFraction();
PARDirect= PARTotal*FracPARDirect;
void CSolar::SetPARDiffuse()
PARDiffuse= PARTotal*GetFracPARDiffuse();
}
void CSolar::SetPotentialNIR()
double x, w;
x = 1/CosTheta;
w=-1.1950+0.4459*log10(x)-0.0345*log10(x)*log10(x);
w = 1320.0*pow(10.0,w);
PotentialNIRDirect= (720.0*exp(-0.06*m())-w)*CosTheta;
PotentialNIRDiffuse= 0.6*(720.0-PotentialNIRDirect-w)*CosTheta;
PotentialNIRTotal=PotentialNIRDirect+PotentialNIRDiffuse;
double ratio;
FracNIRDirect= max(0.0,(PotentialNIRDirect/PotentialNIRTotal)*(1-pow((C-min(C-
FDIV_GUARD,ratio))/D,2/3)));
}
void CSolar::SetNIRTotal() // for measured
NIRTotal= SolarRadiation*GetNIRFraction();
NIRDirect= NIRTotal*FracNIRDirect;
void CSolar::SetNIRDiffuse()
NIRDiffuse= NIRTotal*FracNIRDiffuse;
Shealth.h
void CSolar::SetPARFraction()
double tmp;
tmp = PotentialPARTotal/(PotentialPARTotal+PotentialNIRTotal);
if (useTau)
else
else {
PARFraction=min(max(FDIV_GUARD, tmp),(1.0-FDIV_GUARD));
Root.h
#pragma once
#include "organ.h"
class CRoots :
public COrgan
public:
CRoots(void);
virtual ~CRoots(void);
bool Initialized;
};
Root.cpp
#include "stdafx.h"
#include "roots.h"
CRoots::CRoots(void)
Initialized=false;
CRoots::~CRoots(void)
Radstrans.h
#include "solar.h"
class CRadTrans
private:
CLeafAngle LeafAngle; // Solar elevation of a beam and cumulative LAI at the layer, diffused
fraction (fdf)
bool IsLeafAngleFactorUsed;
double Qsoil();
public:
~CRadTrans(void);
double Qsc();
double Qtot(double L); //total irradiance (dir + dif) at depth L, simple empirical approach
double Qsl();
double Qsh();
double Qdm() ;
double Qsoilm();
double GetZenith();
double Reflect();
double LAIsl();
double LAIsh();
};
Radtrans.cpp
#include "radtrans.h"
CRadTrans::CRadTrans()
LeafAngle = Spherical;
clump = 1.0;
CRadTrans::~CRadTrans()
IrradianceDirect = Irradiance.GetPFDDirect();
IrradianceDiffuse = Irradiance.GetPFDDiffuse();
// the transmittance values obtained from Day and Bailey (1999), chap 3, ecosystems of the world 20:
greenhouse ecosystem, page 76
LAI = SLAI;
Elev = Irradiance.GetSolarElevation();
LeafAngleFactor = LeafAngleFactorIn;
IsLeafAngleFactorUsed = true;
// GDiffuse = S;
}
double CRadTrans::GetZenith() // need to move this to CSolar
double zenith;
zenith=fabs(PI/2.0-Elev);
zenith=min(zenith,1.56);
return zenith;
double CRadTrans::Reflect()
return (1-sqrt(absorp))/(1+sqrt(absorp))*(2*GetKb()/(GetKb()+GetKd()));
double x, tmp;
tmp = 0.5;
switch (LeafAngle)
case Spherical:
tmp = 0.5/sin(Elev);
break;
case Horizontal:
tmp = 1/sin(Elev); //1
break;
case Vertical:
tmp = (2/cot(Elev))/PI;
break;
case Diaheliotropic:
tmp = 1; // 1/sin_elev;
break;
case Empirical:
tmp = 0.667;
break;
default:
tmp= 0.5/sin(Elev);
if (IsLeafAngleFactorUsed == true) {
x = LeafAngleFactor; }
else
switch (LeafAngle)
case Spherical:
x = 1; //
break;
case Horizontal:
x = 10; //1
break;
case Vertical:
x = 0;
break;
case Corn:
x = 1.37;
break;
default:
x =1;
tmp = sqrt(sqr(x)+sqr(tan(theta)))/(x+1.774*pow(x+1.182,-0.733));
KbVal=tmp*clump;
int i;
if (IsLeafAngleFactorUsed == true) {
x = LeafAngleFactor;}
else
{
switch (LeafAngle)
case Spherical:
x = 1; //
break;
case Horizontal:
x = 10; //1
break;
case Vertical:
x = 0;
break;
case Corn:
x = 1.37;
break;
default:
x = 1;
} //end else
FDiffuse = 0;
for (i = 0; i<3; i++) //diffused light ratio to ambient, itegrated over all incident angles from -90 to 90
tmp = sqrt(sqr(x)+sqr(tan(angle)))/(x+1.774*pow(x+1.182,-0.733));
K = 0.0;
}
else {K = -log(FDiffuse)/LA;}
KdVal=K*clump;
double CRadTrans::Irradiancetot() //total irradiance at the top of the canopy, passed over from either
observed PAR or TSolar or TIrradiance
double result;
result=Irradiancetot()*exp(-sqrt(absorp)*(GetKd()+GetKb())/2*L); //; //
return result;
return (IrradianceDirect*exp(-sqrt(absorp)*GetKb()*L));
return IrradianceDiffuse*exp(-sqrt(absorp)*GetKd()*L);
}
double CRadTrans::Qdm() // weighted average absorved diffuse flux over depth of L within canopy
accounting for exponential decay
if (LAI <= 0) {
return 0;}
else {
return IrradianceDiffuse*(1-exp(-sqrt(absorp)*GetKd()*LAI))/(sqrt(absorp)*GetKd()*LAI); //
Integral Qd / Integral L
double CRadTrans::Qb(double L) // unintercepted beam (direct beam) flux at depth of L within canopy
return IrradianceDirect*exp(-GetKb()*L);
{
return (Qdm() + Qsc() + Qsoilm()); // include soil reflection
double CRadTrans::Qsoilm() // weighted average of Soil reflectance over canopy accounting for
exponential decay
if (LAI <= 0) {
return 0;}
else {
return Qsoil()*rho_soil*(1-exp(-sqrt(absorp)*GetKd()*LAI))/(sqrt(absorp)*GetKd()*LAI); //
Integral Qd / Integral L
if (LAI == 0) {
return 0;}
else
// return (Qbt(LAI)-Qb(LAI));
double CRadTrans::Qsoil() // total PFD at the soil sufrace under the canopy
return Qtot(LAI);
double CRadTrans::LAIsl() // sunlit LAI assuming closed canopy; thus not accurate for row or isolated
canopy
return 0;}
else {
return (1-exp(-GetKb()*LAI))/GetKb();}
{
return LAI - LAIsl();
return 0;}
else {
return exp(-GetKb()*L);}
double CRadTrans::Fsh(double L)
return 1 - Fsl(L);
Plant.h
#pragma once
#ifndef _PLANT_H_
#define _PLANT_H_
#include "organ.h"
#include "nodalunit.h"
#include "development.h"
#include "Roots.h"
#include "ear.h"
#include "gas_exchange.h"
#include <iostream>
#include <string>
struct TStage
public:
double V, R;
};
class CPlant
public:
~CPlant();
CGasExchange * get_shaded() { return this->shaded; } //get access to the pointers that point to
the sunlit/shade leaves Yang 8/29/06
void setMass();
void set_CH2O();
void set_N(double x) {TotalNitrogen= x;} // Units are grams. Was scaled from mg in crop.cpp
double calcLeafArea();
double calcTotalLeafMass();
double calcActiveLeafMass();
double calcDroppedLeafMass();
double calcGreenLeafArea();
double calcActualGreenLeafArea();
double calcPotentialLeafArea();
void calcPerLeafRelativeAreaIncrease();
double calcSenescentLeafArea();
void grow();
private:
TInitInfo initInfo;
TGasExSpeciesParam gasExparam;
CGasExchange * shaded; //declare two pointers that point to a sunlit and a shaded leaf Yang
8/29/06
string note;
double C_avail; //Availabel carbon from long term reserved carbon pool YY
double C_pool_root; //storage for carbon allocated to roots but not used
double C_content;
double C_demand;
double C_supply;
double maintRespiration;
double sowingDay;
double age;
double CH2O; // carbohydrate, also dry matter, g
double N_pool; //SK 8/20/10: Short-term N pool for remobilization, this should come mostly
from senescing leaves and can be purged daily to active leaves, not implemented at the moment
double currentDroppedLfArea;
double previousDroppedlfArea;
double greenLeafArea,actualGreenLeafArea;
double senescentLeafArea;
double potentialLeafArea;
double PotentialLeafCarbonDemand; //Carbon demand for potential leaf growth without carbon
limitation YY
double VPD;
double conductance;
double temperature;
double shootPart_old; //g per plant carbohydrate partitioned to root in the previous time step
double rootPart_old;
double HourlyNitrogenSoilUptake;
double leaf_N; //total nitrogen in the leaves of a plant YY (grams N per plant)
double leaf_N_content; //leaf nitrogen content (per unit square meter) of a plant YY
sunlit_A_gross, shaded_A_gross,
sunlit_gs, shaded_gs;
double SunlitRatio; // daily ratio of sunlit leaf area to use for scaling leaf expansion due to
carbon stress
double C2_effect;
TStage stage;
};
#endif
Plant.cpp
//
#include "stdafx.h"
#include "plant.h"
//#include "gas_exchange.h"
#include "radtrans.h"
#include "timer.h"
#include <cmath>
#include <vector>
#include <iostream>
#include <sstream>
#include <iomanip>
#define PRIMORDIA 5
nodalUnit = NULL;
ear = NULL;
roots = NULL;
develop = NULL;
C_reserve = 0.0;
C_ReserveLeaf=0.0;
C_pool_root=0.0;
maintRespiration = 0.0;
C2_effect=1.0;
SunlitRatio=0.0;
shootPart = 0.60;
rootPart = 0.40;
earMass=droppedLeafmass=rootMass=0.0;
shootMass=seedMass*(1.0-rootPart);
rootMass=seedMass-shootMass;
leafMass = activeLeafMass=0.90*shootMass;
stemMass=0.10*shootMass;
leaf_N = 0;
leaf_NFraction = 0;
N_pool = 0.0;
CumulativeNitrogenDemand=0;
HourlyNitrogenDemand=0;
CumulativeNitrogenSoilUptake=0;
sunlit_A_net = shaded_A_net = 0;
sunlit_A_gross = shaded_A_gross = 0;
sunlit_gs=shaded_gs=0;
sowingDay = 1.0;
age = 0.0;
initInfo = info;
gasExparam = photoparam;
for (int i=1; i <= PRIMORDIA; i++) // leaf[0] is a coleoptile, should start at 1
nodalUnit[i].initialize(i, develop);
nodeNumber = i;
nodalUnit[0].initialize(0, develop);
finalNodeNumber = info.genericLeafNo;
VPD = 0;
conductance = 0;
emerge_gdd = 0;
SunlitRatio = 0.0;
CPlant::~CPlant()
int TotalGrowingLeaves = 0;
int TotalDroppedLeaves = 0;
int TotalMatureLeaves = 0;
double PlantNitrogenContent;
double percentN;
if (develop->Emerged())
{
calcRed_FRedRatio(weather);
develop->update(weather);
finalNodeNumber = develop->get_youngestLeaf();
//SK: get N fraction allocated to leaves, this code is just moved from the end of the procedure,
this may be taken out to become a separate fn
//Calculate faction of nitrogen in leaves (leaf NFraction) as a function of thermal time from
emergence
leaf_NFraction = 0.79688-0.00023747*thermal_time-
0.000000086145*thermal_time*thermal_time;
if (leaf_NFraction <=0)
PlantNitrogenContent=this->get_N();
percentN=this->get_N()/shootMass;
double Ratio=0;
if (NitrogenRatio>0)
Ratio= percentN/NitrogenRatio;
if (!develop->Germinated())
temperature = develop->get_Tcur();
return;
if (!this->get_roots()->GetInitialized())
this->get_roots()->SetInitialized();
this->get_roots()->import_CH2O(rootMass);
//rootMass=weather.TotalRootWeight;
temperature = develop->get_Tcur();
C_reserve = seedMass*C_content;
// C_pool +=
C_reserve*(1/20)*(1/24)*(initInfo.timeStep/60); // assume it takes 20 days to exhaust seed C reserve
C_pool = C_reserve;
if(!nodalUnit[i].isInitiated())
nodalUnit[i].initialize(i,develop);
nodeNumber = i;
else
nodalUnit[i].update(develop,weather.PredawnLWP);
if (nodalUnit[i].get_leaf()->isGrowing())
TotalGrowingLeaves++;
TotalDroppedLeaves++;
// calculate relative area increases for leaves now that they are updated
nodalUnit[0].get_leaf()->set_TotalGrowingLeaves(TotalGrowingLeaves);
nodalUnit[0].get_leaf()->set_TotalDroppedLeaves(TotalDroppedLeaves);
if(nodalUnit[1].get_leaf()->isInitiated() && !nodalUnit[1].get_leaf()->isAppeared())
calcMaintRespiration(weather);
C_allocation(weather);
setMass();
else if (nodalUnit[1].get_leaf()->isAppeared())
calcPerLeafRelativeAreaIncrease();
calcLeafArea();
if (develop->Emerged())
C_pool += c_pool2;
calcMaintRespiration(weather);
C_allocation(weather);
setMass();
return;
if(!nodalUnit[i].isInitiated())
nodalUnit[i].initialize(i,develop);
nodeNumber = i;
else
if (nodalUnit[i].get_leaf()->isGrowing())
TotalGrowingLeaves++;
if (nodalUnit[i].get_leaf()->isDropped())
TotalDroppedLeaves++;
}
if (nodalUnit[i].get_leaf()->isMature())
TotalMatureLeaves++;
//SK 8/22/10: Why is this infor being stored in node0? this is confusing because it is supposed to be the
coleoptile
nodalUnit[0].get_leaf()->set_TotalDroppedLeaves(TotalDroppedLeaves);
nodalUnit[0].get_leaf()->set_TotalMatureLeaves(TotalMatureLeaves);
develop->death.done = true;
develop->death.daytime = weather.daytime;
this->set_N(temp);
calcPotentialLeafArea();
calcGreenLeafArea();
calcActualGreenLeafArea();
calcLeafArea();
//defining leaf nitrogen content this way, we did not consider the difference in leaf
nitrogen content
// calcSenescentLeafArea();
//SK 8/22/10: N remobilization is implicitly done by adjusting greenleaf area after determining
senesced leaf area. Currently it is assumed that all N is moved from the senesced to the active
previousDroppedlfArea = droppedLfArea;
//when less than 5% of total leaf area is green, physiological maturity is reached. SK
//see http://www.agry.purdue.edu/ext/corn/news/timeless/TopLeafDeath.html
develop->maturity.done = true;
develop->maturity.daytime = weather.daytime;
develop->death.done = true;
develop->death.daytime = weather.daytime;
cout << "* Physiological maturity " << develop->get_GDDsum() << " T growth: "
<< develop->get_Tgrow()
calcGasExchange(weather, gasExparam);
calcMaintRespiration(weather);
C_allocation(weather);
{
C_reserve += __max(0, C_pool);
setMass();
void CPlant::setMass()
//TODO: allocate biomass into individual organs, currently it is allocated as a bulk to leaf, stem, and so
on
//so individual leaf doesn't have mass but the first or the last one has it all
double m = 0;
double CPlant::calcLeafArea()
double dL = 0.0;
dL = nodalUnit[i].get_leaf()->get_area();
area += dL ;
leafArea = area;
return area;
double CPlant::calcGreenLeafArea()
area += nodalUnit[i].get_leaf()->get_greenArea();
greenLeafArea = area;
return area;
double CPlant::calcActualGreenLeafArea()
area +=nodalUnit[i].get_leaf()->get_actualgreenArea();
actualGreenLeafArea=area;
return area;
double CPlant::calcSenescentLeafArea()
{
area += nodalUnit[i].get_leaf()->get_senescentArea();
senescentLeafArea = area;
return area;
double CPlant::calcPotentialLeafArea()
area += nodalUnit[i].get_leaf()->get_potentialArea();
potentialLeafArea = area;
return area;
double CPlant::calcPotentialLeafAreaIncrease()
areaIncrease +=nodalUnit[i].get_leaf()->get_potentialAreaIncrease();
potentialLeafAreaIncrease = areaIncrease;
return areaIncrease;
// calculate relative area increases for leaves now that they are updated
void CPlant::calcPerLeafRelativeAreaIncrease()
double PotentialLeafAreaIncrease=calcPotentialLeafAreaIncrease();
double RelativeLeafAreaIncrease=0;
if (PotentialLeafAreaIncrease>0)
RelativeLeafAreaIncrease=nodalUnit[i].get_leaf()-
>get_potentialAreaIncrease()/PotentialLeafAreaIncrease;
nodalUnit[i].get_leaf()-
>set_RelativeAreaIncrease(RelativeLeafAreaIncrease);
double CPlant::calcActiveLeafMass() //this is the total mass of active leaves that are not entirely dead
(e.g., dropped).
//It would be slightly greather than the green leaf mass because some senesced leaf area is included
until they are complely aged (dead), SK
if (!nodalUnit[i].get_leaf()->isDropped())
Mass +=nodalUnit[i].get_leaf()->get_mass();
activeLeafMass=Mass;
return Mass;
double CPlant::calcDroppedLeafMass() //It has been pointed that corn leaves don't really drop and is
still likely to be attached to the node.
// this is true so a better term would be "dead" leaves (entirely senesced) but I am fine with continuing
to use dropped leaf as long as we are clear about the meaning, SK
if (nodalUnit[i].get_leaf()->isDropped())
Mass+=nodalUnit[i].get_leaf()->get_mass();
droppedLeafmass=Mass;
return Mass;
double CPlant::calcTotalLeafMass()
Mass = nodalUnit[i].get_leaf()->get_mass();
Area = nodalUnit[i].get_leaf()->get_area();
TotalMass += Mass;
return TotalMass;
double CPlant::calcPotentialCarbondemand()
{ //this will only be used for total leaf area adjustment. If the individual leaf thing works
double SLA=200; //Just a mocking value for now. Need to find a more mechanistic way to
simulate change in SLA YY
// SK 8/20/10: changed it to 200 cm2/g based on data from Kim et al. (2007) EEB
return LeafMassDemand;
const double tau = 0.50; // atmospheric transmittance, to be implemented as a variable => done
const double LAF = 1.37; // leaf angle factor for corn leaves, Campbell and Norman (1998)
//Make leaf width a function of growing leaves as average width will increase as the plant grows
// add it as a
const double leafwidth = 5.0; //to be calculated when implemented for individal leaves
Timer timer;
double temp7;
temp7=sun->GetNIRTotal();
sunlit_PFD = light->Qsl();
shaded_PFD = light->Qsh();
sunlit_LAI = light->LAIsl();
shaded_LAI = light->LAIsh();
if (weather.jday == 37356 && weather.time * 24 >= 6) {
double temp10 = 1;
//Calculating transpiration and photosynthesis with stomatal controlled by leaf water potential
LeafWP Y
transpiration=0;
transpiration=transpiration/(initInfo.plantDensity)*3600.0*18.01;//plantsPerMeterSquare units
are grams per plant per hour ;
// Units of Transpiration from sunlit->ET are mol m-2 (leaf area) s-1
// Calculation of transpiration from ET involves the conversion to gr per plant per hour
this->VPD = sunlit->get_VPD();
photosynthesis_gross=photosynthesis_gross*CH2O_MW/1.0e6*(60.0*initInfo.timeStep)/initInfo.plantD
ensity; //grams carbo per plant per hour
photosynthesis_net=
photosynthesis_net*CH2O_MW/1.0e6*(60.0*initInfo.timeStep)/initInfo.plantDensity; //grams carbo
per plant per hour
this->conductance=(sunlit->get_StomatalConductance()*sunlit_LAI+shaded-
>get_StomatalConductance()*shaded_LAI)/LAI; //average stomatal conductance Yang
if (this->conductance<0)
conductance=0;
else
this->conductance =0;
sunlit_A_net = sunlit->get_ANet();
shaded_A_net = shaded->get_ANet();
sunlit_A_gross = sunlit->get_AGross();
shaded_A_gross = shaded->get_AGross();
sunlit_gs = sunlit->get_StomatalConductance();
shaded_gs = shaded->get_StomatalConductance();
delete sunlit;
delete shaded;
delete sun;
delete light;
double b2=0.185418876; // I'm using this because it can have broad optimal region unlike beta fn or
Arrhenius eqn
double b3=0.203535650;
//double leafPart = 0.0; made class variable for now to transfer, may have to do this for all
double g2=0.0;
if (w.airT<Td) g2=1-exp(-b3*(Td-w.airT));
double t1 = develop->get_progressToAnthesis();
double t2 = develop->get_phyllochronsFromTI();
if (C_pool > C_demand) //C_demand does not enter into equations until grain fill
C_pool -= C_supply; // C_Pool is what is left over from the carbon available for growth
else
if (C_reserve >0)
else
C_pool = 0;
C_reserve += C_pool; // send remaining C (not enough to meet the demand) in shorterm
pool to reserve
else
C_supply = maintRespiration;
C_pool -= __max(C_supply,0);
else
C_supply = maintRespiration;
C_reserve -= __max(C_supply,0);
C_reserve += C_pool; // send remaining C (not enough to meet the demand) in shorterm
pool to reserve
else
C_reserve += C_pool;
C_pool = 0.0;
// const double convFactor = 1/1.43; // equivalent Yg, Goudriaan and van Laar (1994)
double Yg = 0.750; // synthesis efficiency, ranges between 0.7 to 0.76 for corn, see Loomis and
Amthor (1999), Grant (1989), McCree (1988)
if (!develop->Germinated())
return;
else if (!develop->TasselInitiated())
if (w.pcrs>rootPart_old) // if in time step t-1, the value of pcrs is higher than that of pcrl
else
C_pool_root +=__max(0,rootPart_old-w.pcrs);
shootPart_real = shootPart;
rootPart_old = rootPart;
leafPart = shootPart_real*0.725;
sheathPart = shootPart_real*0.275;
stalkPart = 0.0;
reservePart = 0.0;
huskPart = 0.0;
cobPart = 0.0;
grainPart = 0.0;
else if (!develop->GrainFillBegan())
// rootPart=0.0;
if (w.pcrs>rootPart_old)
rootPart_real = rootPart+(w.pcrs-rootPart_old);
else
C_pool_root +=__max(0,rootPart_old-w.pcrs);
shootPart_real = shootPart;
rootPart_old = rootPart;
if (scale <=0.85)
stalkPart = shootPart_real*1.10*scale;
else
huskPart = shootPart_real*__max(exp(-7.75+6.60*scale),0);
else
cobPart = shootPart_real*exp(-8.4+7.0*scale);
else
cobPart = shootPart_real*0.625;
//give reserve part what is left over, right now it is too high
if (reservePart>0)
double sum=cobPart+huskPart+leafPart+stalkPart+sheathPart;
reservePart=__max(0,shootPart-sum);
// here only grain and root dry matter increases root should be zero but it is small now.
const int maxKernelNo = 800; // assumed maximum kerner number per ear
if (w.pcrs>rootPart_old)
else
C_pool_root +=__max(0,rootPart_old-w.pcrs);
shootPart_real = shootPart;
flag = 0;
rootPart_old = rootPart;
grainPart = shootPart_real*1.0;
else
{
double stemPart = sheathPart + stalkPart; //TODO: sheath and stalk haven't been separated in this
model
CLeaf* leaf;
// first find the number of growing leaves. This is saved as a variable in the [0] nodal unit
double LeafPartSum=leafPart;
double PCarboDemandPerLeaf;
leaf= nodalUnit[i].get_leaf();
double totLA;
{
if (!leaf->isDead())
totLA = calcPotentialLeafArea();
PCarboDemandPerLeaf=__max(0.0, leaf-
>get_potentialArea()/totLA*leafPart); //Adjusting C allocation based on leaf size if not aging.
leaf->import_CH2O(PCarboDemandPerLeaf);
LeafPartSum-=PCarboDemandPerLeaf;
else
leaf->import_CH2O(__min(LeafPartSum,
PCarboDemandPerLeaf));
LeafPartSum=0.0;
this->get_nodalUnit()->get_stem()->import_CH2O(stemPart);
// this->get_nodalUnit()->get_leaf()->import_CH2O(leafPart);
// before emergence root weight has been initialized. Just dump this carbon for now.
if (develop->Emerged()) this->get_roots()->import_CH2O(rootPart_real);
this->get_ear()->import_CH2O(earPart);
double partSum = stemPart + earPart + leafPart; // checking the balance if sums up to shootPart
// based on McCree's paradigm, See McCree(1988), Amthor (2000), Goudriaan and van Laar (1994)
// units very important here, be explicit whether dealing with gC, gCH2O, or gCO2
const double Q10 = 2.0; // typical Q10 value for respiration, Loomis and Amthor (1999) Crop Sci
39:1584-1596 - could try 1.8
double dt = initInfo.timeStep/(24*60);
// const double maintCoeff = 0.015; // gCH2O g-1DM day-1 at 20C for young plants, Goudriaan and
van Laar (1994) Wageningen textbook p 54, 60-61
//no maint cost for dead materials but needs to be more mechanistic, SK
//agefn=1.0;
// this function calculates an estimate of the Red to Far red light ratio from sunlit and shaded ET. This
// ration is used to estimate the effects of plant density on leaf expansion and LAI.
// A daily mean ratio is calculated. We use a 3 parameter sigmoid function to model the effect
double dt=initInfo.timeStep/(24.0*60);
double C2_effectTemp;
if (abs(weather.time)<0.0001)
//Zhu et al. Journal of Experimental Botany, Vol. 65, No. 2, pp. 641–653, 2014
C2_effectTemp=exp(-(SunlitRatio-Xo)/B);
C2_effect=__min(1.0,A/(1.0+C2_effectTemp));
develop->set_shadeEffect(C2_effect);
SunlitRatio=0.0;
else
{
SunlitRatio+=sunlit_LAI/(sunlit_LAI+shaded_LAI)*dt;
else SunlitRatio+=1.0*dt;
ostringstream oStr;
string s = "";
if (FLOAT_EQ(develop->germination.daytime,w.daytime)){s = "Germinated";}
if (FLOAT_EQ(develop->emergence.daytime,w.daytime)){s = "Emergence";}
if (s != "")
}
//note.swap(oStr.str());
note = oStr.str();
Organ.h
#pragma once
#ifndef _ORGAN_H_
#define _ORGAN_H_
#include "weather.h"
#include "thermaltime.h"
#include "initinfo.h"
#include "development.h"
struct TElement
double CHO;
double water;
double nitrogen;
};
class COrgan
public:
COrgan();
COrgan(const TInitInfo&);
virtual ~COrgan();
virtual void import_CH2O(double);// import CHO from the reserve, virtual common metabolic
reserve
// virtual double export_CHO(); //export CHO to the reserve, virtual common metabolic reserve
// from 2DSOIL
private:
COrgan(const COrgan&);
TInitInfo initInfo;
TElement * element;
CThermalTime * GDD;
double physAge; // physiological age accouting for temperature effect (in reference to
endGrowth and lifeSpan, days)
double growthDuration; // physiological days to reach the end of growth (both cell division and
expansion) at optimal temperature, days
};
#endif
Organ.cpp
#include "stdafx.h"
#include "organ.h"
COrgan::COrgan()
CH2O=N=0;
C_conc = 0.40;
temperature = 25;
growthDuration=10;
longevity=50;
GDD = NULL;
PotentialCarboIncrement = 0;
ActualCarboIncrement=0;
}
initInfo = info;
temperature=25.0;
CH2O=N=0;
C_conc = 0.40;
growthDuration=10;
longevity=50;
GDD = NULL;
COrgan::~COrgan()
void COrgan::initialize()
GDD->initialize(initInfo.timeStep);
void COrgan::update()
{
GDD->add(temperature);
age = GDD->get_actualAge();
physAge=GDD->get_sum();
CH2O += dCH2O;
N += dN;
void COrgan::respire()
Leaf.h
#pragma once
#ifndef _LEAF_H_
#define _LEAF_H_
#include "organ.h"
#include "weather.h"
#include "development.h"
public:
CLeaf(int rank, CDevelopment * dv); // take current leaf rank and total leaf number to calculate
potentialArea
~CLeaf();
double GTI(double);
private:
CLeaf(const CLeaf&);
int rank;
double FullyExpandedArea;
double RelativeAreaIncrease; //Area increase of this leaf relative to all other leaves. Used to
partition carbon
double area, unstressedArea; // actual leaf area and accumulated potential area
//SK 8/22/10: There appears to be no distinction between these two variables in the code.
double length;
double width;
double SLA;
double plastochrons, GDD2mature; // Fournier and Andrieu (1998), used for delay between
initiation and elongation
double phase1Delay, growthDuration, elongAge, elongRate, maxElongRate, seneAge, activeAge,
seneDuration;
double actualArea;
double actualLength,actualwidth; //actual length and width of leaf under both drought stress
and carbon limitation
bool first; //indicates if this is the first time we call the elongate method;
double N_content;
double N_effect;
/*
*/
};
#endif
Leaf.cpp
#include "stdafx.h"
#include "leaf.h"
#include "weather.h"
#include "initinfo.h"
#include <cmath>
#include <algorithm>
/* LWPeffect adjusts leaf growth for water stress. The functin is defined here. The parameter
psi_threshold_bars has two values, one for leaf growth
*/
rank = n;
SLA = 200.0; // temporary for now - it should vary by age. Value comes from some of Soo's work
PotentialAreaIncrease = 0;
RelativeAreaIncrease=0;
FullyExpandedArea=0;
TotalDroppedLeaves=0;
TotalMatureLeaves = 0;
actualLength=actualwidth=0;
ptnLength=ptnWidth = 0.0;
maxElongRate = 12.0; //max elongation rate (cm per day) at optipmal temperature (Topt: 31C
with Tbase = 9.8C using 0.564 cm/dd rate from Fournier 1998 paper above
activeAge = 0.0; // age during active phase after fully expansion before senescence
stayGreen = dv->get_stayGreen();
LM_min = dv->get_LM_min();
// T_peak is the optimal growth temperature at which the potential leaf size determined in
calc_mophology achieved. Similar concept to fig 3 of Fournier and Andreiu (1998)
CLeaf::~CLeaf() {}
// set potential leaf area of the current rank based on generic leaf no, see Fournier and Andrieu (1998),
Birch et al., (1998)
// Routine below to calculate potentialArea will repeat in CLeaf::update to get actual leaf area after the
inductive phase to any additional leaves developed before tassel initiation, SK 1-20-12
COrgan::initialize();
calc_dimensions(dv);
initiated = true;
// growing=true; // DT
first=true;
stayGreenDuration = stayGreen*growthDuration;
seneDuration = growthDuration;
#if _DEBUG
std::cout << " GDDay " << dv->get_GDDsum() << " leaf " << dv-
>get_LvsInitiated() << " " << rank << " totalLeaves " << dv->get_totalLeaves()
#endif
LA_max is a fn of leaf no (Birch et al, 1998 fig 4) with largest reported value
near 1000cm2.
Without lfno_effect, it can be set to 97cm for the largest leaf area to be at
750 cm2 with Nt ~= Ng (Lmax*Wmax*0.75)
If this routine runs before TI, totalLeaves = genericLeafNo, and needs to be run
with each update until TI and total leaves are finalized, SK
*/
double n_m, a, b;
int hrank=rank;
n_m = 5.93 + 0.33*totalLeaves; // the rank of the largest leaf. YY (need to adjust here for the
maximum leaf size as a function of plant pop -DT 8/12/2015)
a = -10.61 + 0.25*totalLeaves;
b = -5.99 + 0.27*totalLeaves;
hrank = rank - 1;
PotentialArea=lfno_effect*LA_max*exp(a*pow(hrank/n_m-1,2)+b*pow(hrank/n_m-
1,3)); //equa 6. Fournier and Andrieu(1998) multiplied by Birch et al. (1998) leaf no effect
}
void CLeaf::update(CDevelopment * dv, double PredawnLWP)
COrgan::set_temperature(dv->get_Tcur());
COrgan::update();
// calc_dimensions(dv);
expand(dv, PredawnLWP);
senescence(dv, PredawnLWP);
//leaf expansion rate based on a determinate sigmoid function by Yin et al. (2003)
double CriticalNitrogen;
CriticalNitrogen= __max(0.25,this->N_content);
double T = dv->get_Tcur();
//final leaf size is adjusted by growth temperature determining cell size during elongation
//final leaf
// See Kim et al. (2012) Agro J. for more information on how this relationship has been
derermined basned on multiple studies and is applicable across environments
appeared = true;
// elongAge indicates where it is now along the elongation stage or duration. duration is
determined by totallengh/maxElongRate which gives the shortest duration to reach full elongation in
the unit of days.
// The following equation is a beta function. The analogs are - growthDuration is T_Ceil,
growthDuration_half is optimum temp (T_OPT),
// elongage is temperature
pow(elongAge/growthDuration_half,growthDuration_half/(growthDuration-
growthDuration_half)))*dD);
//water_effect=1.0;
//N_effect=1.0;
//shade_effect = 1.0;
area += dA*__min(water_effect,N_effect)*shade_effect;
unstressedArea+=dA;
mature = true;
set_GDD2mature (get_physAge());
growing = false;
return;
}
double dD = dv->get_initInfo().timeStep/MINUTESPERDAY;
double T = (double)dv->get_Tcur();
// This assumes 0.25mg/m2 minimum N required, and below this the value is 0.0.
const double psi_threshold_bars = -4.0; //threshold predawn leaf water potential (in bars)
below which water stress triggers senescence, needs to be substantiated with lit or exp evidence, SK
// This is the water potential at which considerable reduction in leaf growth takes place in corn,
sunflower, and soybean in Boyear (1970)
//water_effect = 1;
//N_effect = 1;
// Assumes physiological time for senescence is the same as that for growth though this may be
adjusted by stayGreen trait
// a peaked fn like beta fn not used here because aging should accelerate with
increasing T not slowing down at very high T like growth,
// instead a q10 fn normalized to be 1 at T_opt is used, this means above T_opt aging
accelerates.
double scale = 1.0; // scale for reduction in leaf lifespan and aging rate
stayGreenDuration = stayGreen*growthDuration;
// changed this from 0.75 to 1.2 not sure if I will keep it.
activeAge += q10fn*dD;
scale = 0.5;
//One day of cumulative severe water stress (i.e., water_effect = 0.0 around -4MPa)
would result in a reduction of leaf lifespan in relation staygreeness and growthDuration, SK
//if scale is 1.0, one day of severe water stress shortens one day of stayGreenDuration
activeAge = stayGreenDuration;
aging = true;
seneAge += q10fn*dD;
scale = 0.5;
//if scale is 0.5, one day of severe water stress at predawn shortens one half day of agingDuration
seneDuration_half = seneDuration/2;
// double maxRate =
area*(2*seneDuration-seneDuration_half)/(seneDuration*(seneDuration-
seneDuration_half))*pow(seneDuration_half/seneDuration,seneDuration_half/(seneDuration-
seneDuration_half));
// double dA = nonstressAgingRate*dD;
// senescentArea += dA;
pow(seneAge/seneDuration, (seneDuration/(seneDuration-
seneDuration_half))));
dropped = true;
}
return;
//and rf_sensitivity are done with the data from Boyer (1970) and Tanguilig et al (1987) YY
//DT Oct 10, 2012 changed this so it was not as sensitive to stress near -0.5 lwp
//SK Sept 16, 2014 recalibrated/rescaled parameter estimates in Yang's paper. The scale of
Boyer data wasn't set correctly
//sensitivity = 1.92, LeafWPhalf = -1.86, the sensitivity parameter may be raised by 0.3 to 0.5 to
make it less sensitivy at high LWP, SK
double effect;
effect=__min(1.0, (1+exp(psi_f*s_f))/(1+exp(s_f*(psi_f-(predawn_psi_bars-psi_th)))));
return effect;
Intialize.h
#pragma once
#ifndef _INITINFO_H_
#define _INITINFO_H_
#ifndef FLOAT_EQ
#endif
struct TInitInfo
public:
TInitInfo()
char cultivar[255]="\0";
GDD_rating = 1331;
genericLeafNo=15;
sowingDay = 150;
year = 2004;
timeStep=5.0;
plantDensity = 8.0;
CO2 = 370.0;
Rmax_LIR=.0978;
Rmax_LTAR = 0.53;
DayLengthSensitive=true;
PhyllochronsToSilk=8;
PhyllochronsToTassel = 1;
stayGreen = 4.5;
LM_min = 125.0;
char description[255];
char cultivar[255];
int GDD_rating; // GDD or GTI rating of the cv, see Stewart 1999 for conversion between MRMR
and other ratings
int genericLeafNo; // leaf number at the end of juvenile phase independent of environmental
ques of leaf initiation
double plantDensity;
double CO2;
int year;
double timeStep;
double Rmax_LIR, Rmax_LTAR; // Maximum Leaf tip initiation and appearance rates
double PhyllochronsToSilk; //number of phyllochrons from tassel initiation for 75% silking.
double PhyllochronsToTassel; // number of phyllochrons past tassel initiation when tassels are
fully emerged. (not input yet)
//todo these above 2 variables are also in development - need to remove them from there.
//check units
};
#endif
Intialize.cpp
#include "stdafx.h"
#include "initinfo.h"
Development.h
#pragma once
#ifndef _DEVELOPMENT_H_
#define _DEVELOPMENT_H_
#include "weather.h"
#include "initinfo.h"
#include <iostream>
#include <string>
enum EPhase
};
struct TEvent
public:
double daytime;
bool done;
};
class CDevelopment
{
public:
CDevelopment(const TInitInfo&);
~CDevelopment();
double calcGDD(double);
int get_totalLeaves() {return (int) totLeafNo;} // removed +1 that was previously here to count
only those leaves fully initiated, SK 1-19-12
bool Dead() {return death.done;} // when all leaves are senescend and dead, the whole-plant is
pronounced dead. SK
TEvent germination;
TEvent emergence;
TEvent tasselInitiation;
TEvent tasselFull;
TEvent anthesis;
TEvent silking;
TEvent beginGrainFill;
TEvent maturity;
TEvent death;
private:
int GDD_rating;
double GDDsum; // cumulative GDD from sowing with Tbase= 8.0 and Topt = 34 as in CERES
double emerge_gdd; //thermal time need for a corn plant to emerge YY 4/2/09
double GTIsum; // cumulative GTI, Stewart et al (1998), equivalent to GDD of Tbase = 10 and
Topt 30
double T_base, T_opt, T_ceil, T_cur, T_avg, T_grow, T_grow_sum, T_ind, T_air; // T_grow: mean
temperature of the growing season from day 1 up to now, SK
double PhyllochronsToSilk; // number of phyllochrons past tassel initiation when silking takes
place
double PhyllochronsToTassel; // number of phyllochrons past tassel initiation when tassels are
fully emerged
double shadeEffect; //effect of shade with respect to R/FR, see JXB (2014) Zhu, 8-13-2015, SK
string note;
TInitInfo initInfo;
};
#endif
Development.cpp
#include "stdafx.h"
#include <cmath>
#include "development.h"
#include <iostream>
#include <string>
#include <algorithm>
//#using <mscorlib.dll>
{ // DT -8/16/2016 reorganized some of these variables to make the initialization more consistent.
// removed SetParms method since it duplicated a much of what is done in the constructor. I
moved
emerge_gdd = 0;
stayGreen = info.stayGreen;
LM_min = info.LM_min;
Rmax_LIR = info.Rmax_LIR;
Rmax_LTAR = info.Rmax_LTAR;
DayLengthSensitive = info.DayLengthSensitive;
PhyllochronsToSilk = info.PhyllochronsToSilk;
PhyllochronsToTassel = info.PhyllochronsToTassel;
GDD_rating = info.GDD_rating;
Rmax_Germination = Rmax_Emergence = 0;
initLeafNo = youngestLeaf = 5;
curLeafNo = 1;
LvsAtTI = 1;
LvsInitiated = initLeafNo;
LvsToInduce = 0.0;
inductionPeriod = 0.0;
inductions = 0;
shadeEffect = 1.0;
Rmax_Germination = 0.45*dt; // max rate of germination per day, assume it takes two day at 31
C, needs to be replaced
Rmax_Emergence = 0.2388*dt;
Rmax_LTAR = Rmax_LTAR*dt; // Kim et al. (2007); Kim and Reddy (2004), 0.581 from Yan and
Hunt (1999), equivalent phyllochron in CERES
Rmax_LIR = Rmax_LIR*dt; // best fit of K and W (1983), Kim and Reddy (2004) originally 0.978
(for colorado tried 0.558
T_base = 8.0;
T_opt = 32.1; // These Topt and Tceil values from Kim et al. (2007), also see Kim and Reddy
(2004), Yan and Hunt (1999), SK
T_ceil = 43.7;
P2 = 0.5;
initInfo = info;
CDevelopment::~CDevelopment(void)
T_air = wthr.airT;
if (!germination.done)
germination.done = true;
germination.daytime = wthr.daytime;
// initialize T_grow
T_grow = T_cur;
T_grow_sum = T_cur;
cout << "* Germinated: GDDsum " << GDDsum << " time step (min): " << dt*(24
* 60) << endl;
else // if (germination.done)
T_grow_sum += T_cur;
steps++;
emergence.done = true;
emergence.daytime = wthr.daytime;
cout << "* Emergence: GDDsum " << GDDsum << " Growing season T "
<< T_grow << endl;
// corn->LvsAppeared = 1.0;
//LvsAppeared = 2;
int iii = 1;
curLeafNo = (int)LvsInitiated;
// inductive phase begins after juvenile stage and ends with tassel
initiation
{
addLeafPhotoPeriod = 0.0;
if (DayLengthSensitive)
// Added back the temperature effect on leaf number and revised the
algorithm to accumulate addLeafNo to totLeafNo.
inductions++;
inductionPeriod += dt;
// totLeafNo = juvLeafNo + addedLvs/inductionPeriod; //get a
mean value over this period
// cout << "* Inductive phase: " << LvsInitiated << " " << totLeafNo << "
" << juvLeafNo << " " << addedLvs/inductionPeriod << endl;
curLeafNo = youngestLeaf;
tasselInitiation.done = true;
tasselInitiation.daytime = wthr.daytime;
LvsInitiated = youngestLeaf;
LvsAtTI = LvsAppeared;
cout << "* Tassel initiation: GDDsum " << GDDsum << " Growing
season T " << T_grow << endl;
else if (tasselInitiation.done)
LvsAppeared = LvsInitiated;
//DT Sep 21, 2016 added a variable to indicate tasseling is done at 1 phyllocrhon from
the last leaf appearing
if (!tasselFull.done)
tasselFull.done = true;
tasselFull.daytime = wthr.daytime;
cout << "* Tassel fully emerged: GDDsum " << GDDsum << " Growing
season T " << T_grow << endl;
{
silking.done = true;
silking.daytime = wthr.daytime;
cout << "* Silking: GDDsum " << GDDsum << " Growing season T " <<
T_grow << endl;
if (silking.done)
GDDgrain += calcGDD(T_cur)*dt;
//Todo: GTI was found more accurate for grain filling stage, See Thijs
phenolog paper (2014)
beginGrainFill.done = true;
beginGrainFill.daytime = wthr.daytime;
cout << "* Grain filling begins: GDDsum " << GDDsum << " Growing
season T " << T_grow << endl;
// if (!maturity.done)
dGDD = calcGDD(T_cur)*dt;
GDDsum += dGDD;
GTIsum += dGTI;
// maturity.done = true;
// maturity.daytime = wthr.daytime;
// cout << "* Matured: GDDsum " << GDDsum << " Growing season T " << T_grow
<< endl;
// }
return 0;
// beta function, See Yin et al. (1995), Ag For Meteorol., Yan and Hunt (1999) AnnBot, SK
double f, g, alpha;
}
double CDevelopment::calcGTI(double T_avg, bool Silked)
// double b1 = 0.0432;
double b1 = 0.011178;
//return b1*T_avg*T_avg*(1-0.6667*T_avg/T_opt);
//else
//and rf_sensitivity are done with the data from Boyer (1970) and Tanguilig et al (1987) YY
//DT Oct 10, 2012 changed this so it was not as sensitive to stress near -0.5 lwp
//SK Sept 16, 2014 recalibrated/rescaled parameter estimates in Yang's paper. The scale of
Boyer data wasn't set correctly
//sensitivity = 1.92, LeafWPhalf = -1.86, the sensitivity parameter may be raised by 0.3 to 0.5 to
make it less sensitivy at high LWP, SK
double effect;
return effect;
Crop.h
// The following ifdef block is the standard way of creating macros which make exporting
// from a DLL simpler. All files within this DLL are compiled with the PLANT_EXPORTS
// symbol defined on the command line. this symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see
// PLANT_API functions as being imported from a DLL, whereas this DLL sees symbols
// on how to do this
#ifdef _WIN32
#ifdef MYPLANT_EXPORTS
#else
#define PLANT_API __declspec(dllexport)
#endif
#else
#define PLANT_API
#endif
#include "initinfo.h"
double p_VMAX,
PopSlab,
MainStemLeafArea;
double netPhotosyn,respiration, GPhotosyn;
double NitrogenUptake=0; // nitrogen uptake value from 2dsoil accumulated between time
steps mg/plant
double NitrogenUptakeOld=0;
double U_N, U_M, U_P, U_D; //U_N maximum observed N uptake rate (g N m-2 ground d-1)
(Lindquist et al, 2007) YY
double d = 0.075; //d: shape coefficient in the logistic function to simulate cumulative N uptake
(Equation 9 in Lindquist et al. 2007)
double q_n = 0.032; //q_n the maximum ratio of daily N uptake to measured daily growth rate
(g N g-1) (Lindquist et al., 2007)
double N_min = 4.10; //maximum nitrogen concentration for C4 species: 4.1% (Lindquist et al.
2007)
double shoot_weightPerM2=0;
double CurrentNUptakeError=0;
double CumulativeNUptakeError=0;
NumGD = 3, NumPlD=100,
NumSurfDatD=3+NumGD+NumSD;
int compare(const void *arg1, const void *arg2); //Function for comparing two numbers in a
sort routine
#pragma pack(2)
struct ShootCommon{
double PCRL,PCRQ,PCRS,HourlyCarboUsed,ET_demand,LCAI,Cover,Convr;
float MaxRootDepth,Shade,Height,LAI,AWUPS,nitroDemand;
float xBStem,yBStem,SGT,PSIM,
LAREAT,PopRow,RowSp,RowAng,PopArea,CEC,
EORSCS,AWUPSS,SolRad,Total_Eor,
Total_Pcrs,SIncrSink,Psild,
TotalRootWeight, InitialRootCarbo,
ConstI[2],constK[2], Cmin0[2];
};
//Weather
struct WeathCommon{
int MSW1,MSW2,MSW3,MSW4,MSW5,MSW6,MSW7;
float CLDFAC,DEL[24],RINT[24],RNS,RNC,RAIN,IR;
float WIND,CO2,TDUSK,TDUSKY,CPREC[NumSD],TAIR[24],VPD[24],ROUGH,
RADINT[24],WATTSM[24],DIFINT[24],ROWINC[24];
float CLOUD, SHADOW[24],DIFWAT[24],DIRINT[24];
int NumF[40],NumFP;
float hFur[40],QF;
int IFUR;
RI,par[24],parint[24],daylng;
float AutoIrrigAmt;
int AutoIrrigateF;
};
//grid
struct GridCommon{
};
//nodal
struct NodeCommon{
int NumSol,NumG,ListN[NumNPD],ListNE[NumNPD],MatNumN[NumNPD];
Tmpr[NumNPD],Con[NumNPD],TcsXX[NumNPD],RO[NumNPD],
float ThAvail[NumNPD],ThFull[NMatD];
bool lOrt;
};
//elements
struct ElementCommon{
int MatNumE[NumElD];
gSink[NumGD][NumNPD],tSink[NumNPD],
RTWT[NumElD],RUTDEN[NumNPD];
};
//boundary
struct BoundaryCommon{
NDrain,NDR[NDrainD],NDNumDR[NDrainD],
KXB[NumBPD];
int CodeW[NumNPD],CodeS[NumNPD],CodeT[NumNPD],
CodeG[NumNPD],PCodeW[NumNPD];
VarBS[NumSD][NumBPD],
VarBT[4][NumBPD], VarBG[3][NumGD][NumBPD],EO,Tpot;
};
// Time
struct TimeCommon{
dMul1, dMul2,tTDB[4],Tfin,tAtm;
float Tinit;
int lInput,Iter;
double TimeStep;
};
//modules
struct ModuleCommon{
};
struct ErrorCommon{
int errPlant;
};
struct FileCommon{
double starter;
SoilFile[132],
ManagementFile[132], DripFile[132],
WaterFile[132], WaterBoundaryFile[132],
GraphicsFile[132], InitialsFile[132],VarietyFile[132],
NodeGraphics[132],ElemGraphics[132],NodeGeomFile[132],
GeometryFile[132], SurfaceGraphics[132],
FluxGraphics[132], MasssBalanceFile[132],MassBalanceFileOut[132],
};
#pragma pack()
#ifdef __cplusplus
extern "C" {
#endif
#ifdef _WIN32
#else
#endif
GridCommon *, NodeCommon *,
ElementCommon *,
BoundaryCommon *,
TimeCommon *,
ModuleCommon *,
FileCommon *);
#ifdef __cplusplus
#endif
Crop.cpp
#include "stdafx.h"
#include "crop.h"
#include "controller.h"
#include "time.h"
#include <cstdlib>
#include <cstdio>
#include <fstream>
#include <string>
#include <iomanip>
#include <cmath>
return 0;
};
#ifdef _WIN32
#else
void crop(struct
#endif
ShootCommon *SHOOTR,
WeathCommon *Weather,
GridCommon *grid_public,
NodeCommon *node_public,
ElementCommon *ele_public,
BoundaryCommon *bound_public,
TimeCommon *time_public,
ModuleCommon *module_public,
FileCommon *file_public
// I think pLeaf can be local since the leaf array holds the list
// and the pointers are not lost between invocations of the procedure
char* Buffer=(char*)calloc(256,sizeof(char));
static CController* pSC; //SK, declare as static to ensure only one copy is instantiated during
2DSOIL execution
// varFile contains variety information, GraphicFile holds output,LeafFile holds individual leaves
// Parse the file names from the FORTRAN strings passed from 2dsoil
//KY looks like GNU Fortran handle linebreak differently, making filename detection unusable
//KY this new macro based on std::string should work on both platforms with smaller code
SETSTR(GraphicFile, file_public->GraphicsFile);
SETSTR(LeafFile, file_public->LeafFileIn);
initInfo.plantDensity=SHOOTR->PopArea;
initInfo.latitude=Weather->LATUDE;
initInfo.longitude=Weather->Longitude;
initInfo.altitude=Weather->Altitude;
initInfo.year=time_public->Year;
initInfo.sowingDay=time_public->sowingDay;
initInfo.beginDay=time_public->beginDay;
initInfo.endDay=time_public->endDay;
initInfo.timeStep=time_public->TimeStep;
time_public->iTime=1;
SHOOTR->LCAI=0.0;
SHOOTR->LAREAT=0.0;
SHOOTR->Height=0.0;
SHOOTR->Convr=1.0; // was 0.1 or 0.38 should be 1.0 as dry matter is used in all cases
SHOOTR->LeafWP = -0.5;
SHOOTR->PCRS = 0.0;
SHOOTR->ET_demand = 0.0;
PopSlab=SHOOTR->PopRow/100.0*SHOOTR->EOMult;
SHOOTR->isEmerged=SHOOTR->isEmerged=0;
/*These two lines show the relationships among some of the space variables.
--PopSlab=SHOOTR->PopRow/100*SHOOTR->RowSp*SHOOTR->EOMult;
--PlantDensity=SHOOTR->PopRow*100.0/SHOOTR->RowSp;
*/
// A new plant model object is created and initialized (calls initialize function) here
// ***************************************************************************
// ***************************************************************************
SHOOTR->NDemandError=0;
SHOOTR->CumulativeNDemandError=0;
time_public->RunFlag=1;
module_public->NumMod=module_public->NumMod+1 ;
ModNum=module_public->NumMod;
time_public->tNext[ModNum-1]=pSC->getSowingDay();
} // end if
} //end initialization
// Note that SIncrSink has been multiplied by time step in the solute uptake routing
if(fabs(time_public->Time-time_public->tNext[ModNum-1])< fabs(0.001*time_public-
>Step))
//If the sowing date has come and there is not plant, let the program know so other
calculations are not done
module_public->NShoot=1;
//DT added soil temperature from around seed area (right now it is taken as
default - 20)
double Es;
// calculate error for demand and actual uptake, if negative, demand is greater
then uptake
CurrentNUptakeError=NitrogenUptake/PopSlab-pSC->getPlant()-
>get_CumulativeNitrogenDemand();
CumulativeNUptakeError+=CurrentNUptakeError;
TWeather wthr;
wthr.HourlyOutput= time_public->HourlyOutput;
wthr.DailyOutput=time_public->DailyOutput;
wthr.jday = Weather->JDAY;
wthr.time = time_public->Time-Weather->JDAY;
wthr.CO2 = Weather->CO2;
if (Weather->CO2<=0)
Es = (0.611*exp(17.502*wthr.airT/(240.97+wthr.airT))); // saturated
vapor pressure at airT
wthr.RH = (1-(Weather->VPD[time_public->iTime-1]/Es))*100.0; //
relative humidity in percent
wthr.rain = Weather->RINT[time_public->iTime-1];
wthr.dayLength = Weather->daylng;
wthr.pcrl=SHOOTR->PCRL/PopSlab/24.;
wthr.pcrq=SHOOTR->PCRQ/PopSlab/24.;
SHOOTR->HourlyCarboUsed=0.0;
wthr.TotalRootWeight=SHOOTR->TotalRootWeight/PopSlab;
wthr.MaxRootDepth=SHOOTR->MaxRootDepth;
wthr.ThetaAvail=node_public->ThetaAvail/PopSlab;
if (NitrogenUptake >0 )
if (SHOOTR->LAI==0)
wthr.ET_supply=0;
else
wthr.ET_supply = WaterUptake/(SHOOTR->EOMult*SHOOTR-
>PopRow)*100; //units area gr per plant per hour
ET_diff=wthr.ET_supply*24-SHOOTR->ET_demand;
int end=grid_public->NumNP;
double soilMP[400];
int count=0;
double LowerBoundary=5;
LowerBoundary=maxY-LowerBoundary;
// now find average temperature in layer between surface and lower boundary
{
if ( grid_public->y[i]>=LowerBoundary)
soilT=soilT+node_public->Tmpr[i];
soilMP[i] = node_public->hNew[i];
count++;
wthr.soilT=soilT/count;
if ( ier == 0 )
// Assumes that germination takes place about halfway through the sowing date
if (!pSC->getPlant()->get_develop()->Germinated())
{
cout << "Germinating:" <<wthr.jday <<endl;
// The remaining groups of code handle carbon and nitrogen exchange between 2dsoil and maizsim
if (!SHOOTR->isGerminated)
SHOOTR->isGerminated=1;
SHOOTR->InitialRootCarbo=pSC->getPlant()-
>get_rootMass()*PopSlab; // get initial root mass to distribute over initial nodes
if (pSC->getPlant()->get_develop()->Emerged())
if (!SHOOTR->isEmerged) SHOOTR->isEmerged=1;
// minimizes
complexity when p// since we have to add leftover carbo from pcrq to the shoot
{
SHOOTR->PCRL=(pSC->getPlant()->get_rootPart()
+pool)*24*PopSlab;
pSC->getPlant()->set_C_pool_root(0.0);
else
SHOOTR->PCRL=(pSC->getPlant()->get_rootPart())*24*PopSlab;
bool gf=pSC->getPlant()->get_develop()->GrainFillBegan();
SHOOTR->PCRQ=(pSC->getPlant()->get_rootPart()+ (pSC->getPlant()-
>get_shootPart()))*24*PopSlab;
if (gf)
SHOOTR->PCRQ=(pSC->getPlant()->get_rootPart())*24*PopSlab +
(0.75*pSC->getPlant()->get_shootPart())*24*PopSlab;
wthr.pcrl= SHOOTR->PCRL/PopSlab/24;
wthr.pcrq= SHOOTR->PCRQ/PopSlab/24;
SHOOTR->Shade=(float)SHOOTR->Cover*SHOOTR->RowSp*SHOOTR-
>EOMult;
SHOOTR->Height=min(SHOOTR->Shade,SHOOTR->RowSp);
SHOOTR->ET_demand = (pSC->getPlant()->get_ET()*24);//pass ET
demand from shoot to root. Yang
SHOOTR->LAI=(float)pSC->getPlant()->calcGreenLeafArea()*(float)pSC-
>getInitInfo().plantDensity/(100*100);
shoot_weightPerM2 = pSC->getPlant()->get_shootMass()*pSC-
>getInitInfo().plantDensity; //Calculate total shoot mass per meter aquared YY
if (shoot_weightPerM2<100)
else
pSC->getPlant()->set_NitrogenRatio(NitrogenRatio/10.0);
U_P = ((1.0-
N_shape)*N_min*10.0/100.0)*pow(shoot_weightPerM2,-N_shape)*massIncrease*24;
U_D = N_min*10/100*pow(shoot_weightPerM2,-N_shape)-pSC-
>getPlant()->get_N()*(pSC->getInitInfo().plantDensity/(100*100));
pSC->getPlant()->set_HourlyNitrogenSoilUptake(HourlyActualNFromSoil);
pSC->getPlant()->set_HourlyNitrogenDemand(HourlyNitrogenDemand);
// now do cumulative amounts
pSC->getPlant()-
>set_CumulativeNitrogenSoilUptake(NitrogenUptake/PopSlab);
double OldNDemand;
OldNDemand=SHOOTR->nitroDemand/PopSlab/1e6/24;
SHOOTR->nitroDemand =
(float)HourlyNitrogenDemand*(float)PopSlab*1e6*24; //Pass the nitrogen demand into 2dsoil YY
SHOOTR->NDemandError=(float)CurrentNUptakeError;
SHOOTR->CumulativeNDemandError=(float)CumulativeNUptakeError;
if (pSC->getPlant()->get_develop()->Dead())
time_public->RunFlag=0;
else
time_public->tNext[ModNum-1]=time_public->Time+Period;
WaterUptake=0;
//NitrogenUptake=0;
return;
Controll.h
//Class Controller
//
// Controller.h
//
#pragma once
#ifndef _CONTROLLER_H_
#define _CONTROLLER_H_
#include "timer.h"
#include "development.h"
#include "plant.h"
#include "weather.h"
#include "initinfo.h"
#include "gas_ex_species_param.h"
#ifndef FLOAT_EQ
#endif
class CController
private:
// cdt 12/06/2010 - I had to increase the size of these from 132 to 133. We couldn't use
// strcpy in vs 2008 so I changed to strcpy_s but apparently it requires enough space for the null
char DebugFile[133];
errorFlag;
TInitInfo initInfo;
CPlant* plant;
Timer* time;
TWeather* weather;
CDevelopment* develop;
InputDataFormat weatherFormat;
TGasExSpeciesParam GasExParam;
public:
~CController();
void addOutputMessage(char*);
void outputToCropFile();
void outputToLeafFile();
void outputToDebug();
double RootWeightFrom2DSOIL;
double ET_supply; //actual supply of water to plant mol m-2 (leaf) s-1
};
#endif
Control.cpp
#include "stdafx.h"
#include "controller.h"
#include "initinfo.h"
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <iomanip>
#include <cmath>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#ifndef FLOAT_EQ
#endif
//#using <mscorlib.dll>
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CController::CController(const char* filename, const char* outfile, const char* LFile, TInitInfo iniInfo)
time = NULL;
weather = NULL;
plant = NULL;
strcpy(varietyFile, filename);
strcpy(cropFile, outfile);
char *pch=(char*)calloc(133,sizeof(char));
char *next=(char*)calloc(133,sizeof(char));
char *ext=".dbg";
char* temp=(char*)calloc(133,sizeof(char));
// strcpy(temp, 133,cropFile);
temp=strcat(pch,ext);
strcpy(DebugFile,temp);
strcpy(LeafFile, LFile);
//DebugFile=outfile
//strcpy_s(DebugFile,"Debug.out");
initInfo = iniInfo;
iCur = 0;
weatherFormat = ICASA;
firstDayOfSim = 0;
lastDayOfSim = 365;
initialize();
errorFlag = 0;
CController::~CController()
if ( time != NULL )
delete time;
if ( weather != NULL )
delete [] weather ;
if ( plant != NULL )
delete plant;
// if ( output != NULL )
// delete output;
//**********************************************************************
void CController::initialize()
#ifndef _DEBUG_FILE
DebugOut
<<setw(9) <<"C2_effect"
<<setw(9) <<"sunlitRatio"
<<endl
DebugOut.close();
#endif
<< setiosflags(ios::fixed)
<< endl;
//This is the plant file for output (see function "output to crop file"
<< setiosflags(ios::fixed)
#ifndef _INTERFACE
#endif
<< endl;
try
if (!cfs)
cfs.getline(initInfo.description, sizeof(initInfo.description),'\n');
//Pull cultivar name from description
//cfs.getline(initInfo.cultivar, sizeof(initInfo.cultivar),'\n') ;
cfs.getline(Buffer, 256,'\n');
cfs.getline(Buffer, 256,'\n');
>>initInfo.stayGreen >>initInfo.LM_min
initInfo.GDD_rating = 1900;
int result=-1;
char strTest[255];
string strTest2;
do
cfs.getline(Buffer,256,'\n');
strcpy(strTest, Buffer); //Actually this is not needed, the assign statement will also take
char*
strTest2.assign(strTest); //I keep it to show another way of using char* and char. but,
buffer must be null terminated
result = strTest2.find(location);
// cfs.getline(strTest, strlen(strTest));
cfs.getline(Buffer, 256, '\n'); //get var names
GasExParam.EaVc >>
GasExParam.Eaj >>
GasExParam.Hj >>
GasExParam.Sj >>
GasExParam.Vpm25 >>
GasExParam.Vcm25 >>
GasExParam.Jm25 >>
GasExParam.Rd25 >>
GasExParam.Ear >>
GasExParam.g0 >>
GasExParam.g1 ;
cfs.getline(Buffer, 256, '\n'); // the '>>' operator does not read the carriage return after
all the data so we need to read once more
GasExParam.scatt >>
GasExParam.Kc25 >>
GasExParam.Ko25>>
GasExParam.Kp25 >>
GasExParam.gbs >>
GasExParam.gi >>
GasExParam.gamma1 ;
GasExParam.sf >>
GasExParam.phyf >>
GasExParam.stomaRatio >>
GasExParam.widthPara >>
GasExParam.LfWidth;
GasExParam.SC_param >>
GasExParam.BLC_param;
dConvert.caldat(initInfo.sowingDay,mm,dd,yy);
if (cfs.eof()) cfs.close();
cout << "Done reading variety file: " << varietyFile << endl <<endl;
<< setw(20) << "Description: " << initInfo.description << endl <<endl
<< setw(6) << "Generic Leaf Number: " << initInfo.genericLeafNo << endl
<< setw(6) << "Day Length Sensitive: " << initInfo.DayLengthSensitive << endl
<< setw(6) << "Stay Green Parameter: " <<initInfo.stayGreen << endl
<< setw(6) << "Maximum length of largest leaf: " << initInfo.LM_min <<endl
<< setw(6) << "Rmax Leaf initiation rate: " << initInfo.Rmax_LIR << " " << "Rmax
Leaf tip appearance rate: " << initInfo.Rmax_LTAR << endl
<< setw(6) << "Phyllochrons to Silk: " << initInfo.PhyllochronsToSilk << endl
<<endl
<< setw(6) << "Year: " << initInfo.year << endl
<< setw(6) << "Sowing day: " << mm << "/" <<dd <<"/" << yy << endl
<< setw(6) << "TimeStep (min): " << initInfo.timeStep << endl
<< setw(6) << "average [CO2]: " << initInfo.CO2 << endl << endl
exit(1);
firstDayOfSim = initInfo.beginDay;
lastDayOfSim = initInfo.endDay;
SowingDay =initInfo.sowingDay;
cropEmerged = false;
cropHarvested = false;
dConvert.caldat(firstDayOfSim,mm,dd,yy);
time = new Timer(dd, mm, yy,initInfo.timeStep/60.0); // Timer class gets stepsize in hours
plant = new CPlant(initInfo, GasExParam); //todo send gas exch params here?
}
void CController::readWeatherFrom2DSOIL(const TWeather & wthr)
weatherFormat = DDSOIL;
weather[iCur] = wthr;
ET_supply = wthr.ET_supply;
int CController::run(const TWeather & wthr) //todo pass gas exchange parameters here to plant
readWeatherFrom2DSOIL(wthr);
plant->update(weather[iCur]);
RootWeightFrom2DSOIL=wthr.TotalRootWeight;
MaxRootDepth= wthr.MaxRootDepth;
AvailableWater= wthr.ThetaAvail;
// plant->update(weather[iCur]);
// if ((weather[iCur].DailyOutput==1)&&(int(weather[iCur].time*24.0)==6))
// {
outputToCropFile();
// if (plant->get_develop()->Germinated())
outputToLeafFile();
#ifndef _DEBUG_FILE
if (plant->get_develop()->Germinated()) outputToDebug();
#endif
// }
// if (weather[iCur].HourlyOutput==1)
// {
// outputToCropFile();
// if (plant->get_develop()->Germinated())
// outputToLeafFile();
// }
iCur++;
time->step();
return 0;
void CController::outputToCropFile()
int mm,id,iyyy;
string DateForOutput;
if (!plant->get_develop()->Emerged())
av_gs=0;
if(vpd<0)
{
vpd=0;
#if 0
DateForOutput.Format("%.2d/%.2d/%4i",mm,id,iyyy);
#else
char DateForOutputBuff[16];
DateForOutput = DateForOutputBuff;
#endif
string s = "";
if (plant->get_develop()->Matured()) {s="Matured";}
else {s="none";}
// if (FLOAT_EQ(plant->get_develop()-
>emergence.daytime,weather[iCur].daytime)){s = "Emergence";}
//// if (FLOAT_EQ(plant->get_develop()-
>tasselInitiation.daytime,weather[iCur].daytime)){s = "Tassel Initiation";}
// if (FLOAT_EQ(plant->get_develop()->anthesis.daytime, weather[iCur].daytime))
{s = "Anthesis";}
// if (FLOAT_EQ(plant->get_develop()->silking.daytime, weather[iCur].daytime)){s
= "Silking";}
// if (FLOAT_EQ(plant->get_develop()->beginGrainFill.daytime,
weather[iCur].daytime)){s = "Begin grain filling";}
// if (FLOAT_EQ(plant->get_develop()->maturity.daytime,weather[iCur].daytime))
{s = "Begin grain filling";}
<< setiosflags(ios::fixed)
<< setw(8) << setprecision(4) << plant->get_Pn() << comma //g Carbo
per plant per hour
<< setw(8) << setprecision(4) << av_gs << comma //return average
stomatal conductance Yang 10/31/06
#ifndef _INTERFACE
#endif
<< endl;
ostr.close();
void CController::outputToLeafFile()
int mm,id,iyyy;
CNodalUnit* nU;
CDevelopment* myDevelop=plant->get_develop();
string DateForOutput;
time->caldat(weather[iCur].jday, mm, id,iyyy);
#if 0
DateForOutput.Format("%.2d/%.2d/%4i",mm,id,iyyy);
#else
char DateForOutputBuff[16];
DateForOutput = DateForOutputBuff;
#endif
<< setiosflags(ios::fixed);
// << scientific
<< fixed
<< endl;
ostr.close();
nU=NULL;
void CController::outputToDebug()
CNodalUnit* nU;
CDevelopment* myDevelop=plant->get_develop();
int mm,id,iyyy,i;
string DateForOutput;
#if 0
DateForOutput.Format("%.2d/%.2d/%4i",mm,id,iyyy);
#else
char DateForOutputBuff[16];
#endif
<< setiosflags(ios::fixed);
<< setw(8) << setprecision(2) << plant->get_Pn()*1000.0 //g Carbo per plant
per hour
<< endl;
myDevelop=NULL;
DebugOut.close();
}
Main.cpp
#include<iostream>
#include "Crop.h"
int main()
Crop obj1;
obj1.intialize();
obj1.calc();
return 0;