/////////////////////////////////////////////////////////////////////////////////////// /// \file guess.h /// \brief Framework header file, LPJ-GUESS Combined Modular Framework /// /// This header file contains: /// (1) definitions of all main classes used by the framework and modules. Modules may /// require classes to contain certain member variables and functions (see module /// source files for details). /// (2) other type, constant and function definitions to be accessible throughout the /// model code. /// (3) a forward declaration of the framework function if this is not the main /// function. /// /// \author Ben Smith /// $Date: 2020-06-23 10:44:28 +0200 (mar, 23 jun 2020) $ /// /////////////////////////////////////////////////////////////////////////////////////// #ifndef LPJ_GUESS_GUESS_H #define LPJ_GUESS_GUESS_H #define CRESCENDO_FACE #undef CRESCENDO_FACE /////////////////////////////////////////////////////////////////////////////////////// // #INCLUDES FOR LIBRARY HEADER FILES // C/C++ libraries required for member functions of classes defined in this file. // These libraries will also be available globally (so omit these #includes from source // files). In addition to various standard C/C++ runtime libraries, the framework // requires the following libraries (individual modules may use additional libraries) // // GUTIL // Includes class xtring, providing functionality for pointer-free dynamic handling // of character strings; wherever possible in LPJ-GUESS, strings are represented as // objects of type xtring rather than simple arrays of type char. GUTIL also provides // templates for dynamic collection classes (list arrays of various types), argument // processing for printf-style functions, timing functions and other utilities. #include #include #include #include #include "gutil.h" #include #include #include "shell.h" #include "guessmath.h" #include "archive.h" #include "parameters.h" #include "guesscontainer.h" #include "lamarquendep.h" /////////////////////////////////////////////////////////////////////////////////////// // GLOBAL ENUMERATED TYPE DEFINITIONS /// Life form class for PFTs (trees, grasses) typedef enum {NOLIFEFORM, TREE, GRASS} lifeformtype; /// Phenology class for PFTs typedef enum {NOPHENOLOGY, EVERGREEN, RAINGREEN, SUMMERGREEN, CROPGREEN, ANY} phenologytype; /// Biochemical pathway for photosynthesis (C3 or C4) typedef enum {NOPATHWAY, C3, C4} pathwaytype; /// Leaf physiognomy types for PFTs typedef enum {NOLEAFTYPE, NEEDLELEAF, BROADLEAF} leafphysiognomytype; /// Units for insolation driving data /** Insolation can be expressed as: * * - Percentage sunshine * - Net instantaneous downward shortwave radiation flux (W/m2) * - Total (i.e. with no correction for surface albedo) instantaneous downward * shortwave radiation flux (W/m2) * * Radiation flux can be interpreted as W/m2 during daylight hours, or averaged * over the whole time step which it represents (24 hours in daily mode). For * this reason there are two enumerators for these insolation types (e.g. SWRAD * and SWRAD_TS). */ typedef enum { /// No insolation type chosen NOINSOL, /// Percentage sunshine SUNSHINE, /// Net shortwave radiation flux during daylight hours (W/m2) NETSWRAD, /// Total shortwave radiation flux during daylight hours (W/m2) SWRAD, /// Net shortwave radiation flux during whole time step (W/m2) NETSWRAD_TS, /// Total shortwave radiation flux during whole time step (W/m2) SWRAD_TS } insoltype; /// CENTURY pool names, NSOMPOOL number of SOM pools typedef enum {SURFSTRUCT, SOILSTRUCT, SOILMICRO, SURFHUMUS, SURFMICRO, SURFMETA, SURFFWD, SURFCWD, SOILMETA, SLOWSOM, PASSIVESOM, LEACHED, NSOMPOOL} pooltype; /// Irrigation type for PFTs typedef enum {RAINFED, IRRIGATED} hydrologytype; /// Intercrop type for PFTs typedef enum {NOINTERCROP, NATURALGRASS} intercroptype; /// Seasonality type of gridcell /** 0:SEASONALITY_NO No seasonality * 1:SEASONALITY_PREC Precipitation seasonality only * 2:SEASONALITY_PRECTEMP Both temperature and precipitation seasonality, but "weak" temperature seasonality (coldest month > 10degC) * 3:SEASONALITY_TEMP Temperature seasonality only * 4:SEASONALITY_TEMPPREC Both temperature and precipitation seasonality, but temperature most important (coldest month < 10degC) * 5:SEASONALITY_TEMPWARM Temperature seasonality, always above 10 degrees (currently not used) */ typedef enum {SEASONALITY_NO, SEASONALITY_PREC, SEASONALITY_PRECTEMP, SEASONALITY_TEMP, SEASONALITY_TEMPPREC} seasonality_type; /// Precipitation seasonality type of gridcell /** 0:DRY (minprec_pet20<=0.5 && maxprec_pet20<=0.5) * 1:DRY_INTERMEDIATE (minprec_pet20<=0.5 && maxprec_pet20>0.5 && maxprec_pet20<=1.0) * 2:DRY_WET (minprec_pet20<=0.5 && maxprec_pet20>1.0) * 3:INTERMEDIATE (minprec_pet20>0.5 && minprec_pet20<=1.0 && maxprec_pet20>0.5 && maxprec_pet20<=1.0) * 4:INTERMEDIATE_WET (minprec_pet20>0.5 && minprec_pet20<=1.0 && maxprec_pet20>1.0) * 5:WET (minprec_pet20>1.0 && maxprec_pet20>1.0) */ typedef enum {DRY, DRY_INTERMEDIATE, DRY_WET, INTERMEDIATE, INTERMEDIATE_WET, WET} prec_seasonality_type; /// Temperature seasonality type of gridcell /** 0:COLD (mtemp_max20<=10) * 1:COLD_WARM (mtemp_min20<=10 && mtemp_max20>10 && mtemp_max20<=30) * 2:COLD_HOT (mtemp_min20<=10 && mtemp_max20>30) * 3:WARM (mtemp_min20>10 && mtemp_max20<=30) * 4:WARM_HOT (mtemp_min20>10 && mtemp_max20>30) * 5:HOT (mtemp_min20>30) */ typedef enum {COLD, COLD_WARM, COLD_HOT, WARM, WARM_HOT, HOT} temp_seasonality_type; /////////////////////////////////////////////////////////////////////////////////////// // GLOBAL CONSTANTS /// number of soil layers modelled const int NSOILLAYER = 2; /// bvoc: number of monoterpene species used const int NMTCOMPOUNDS = NMTCOMPOUNDTYPES; // SOIL DEPTH VALUES /// soil upper layer depth (mm) const double SOILDEPTH_UPPER = 500.0; /// soil lower layer depth (mm) const double SOILDEPTH_LOWER = 1000.0; /// Year at which to calculate equilibrium soil carbon const int SOLVESOM_END=400; /// Year at which to begin documenting means for calculation of equilibrium soil carbon const int SOLVESOM_BEGIN = 350; /// Number of years to average growth efficiency over in function mortality const int NYEARGREFF = 5; /// Coldest day in N hemisphere (January 15) /** Used to decide when to start counting GDD's and leaf-on days * for summergreen phenology. */ const int COLDEST_DAY_NHEMISPHERE = 14; /// Coldest day in S hemisphere (July 15) /** Used to decide when to start counting GDD's and leaf-on days * for summergreen phenology. */ const int COLDEST_DAY_SHEMISPHERE = 195; /// Warmest day in N hemisphere (same as COLDEST_DAY_SHEMISPHERE) const int WARMEST_DAY_NHEMISPHERE = COLDEST_DAY_SHEMISPHERE; /// Warmest day in S hemisphere (same as COLDEST_DAY_NHEMISPHERE) const int WARMEST_DAY_SHEMISPHERE = COLDEST_DAY_NHEMISPHERE; /// number of years to average aaet over in function soilnadd const int NYEARAAET = 5; /// Priestley-Taylor coefficient (conversion factor from equilibrium evapotranspiration to PET) const double PRIESTLEY_TAYLOR = 1.32; // Solving Century SOM pools /// fraction of nyear_spinup minus freenyears at which to begin documenting for calculation of Century equilibrium const double SOLVESOMCENT_SPINBEGIN = 0.1; /// fraction of nyear_spinup minus freenyears at which to end documentation and start calculation of Century equilibrium const double SOLVESOMCENT_SPINEND = 0.3; /// Kelvin to deg c conversion const double K2degC = 273.15; /// Maximum number of crop rotation items const int NROTATIONPERIODS_MAX = 3; /// Conversion factor for CO2 from ppmv to mole fraction const double CO2_CONV = 1.0e-6; /// Initial carbon allocated to crop organs at sowing, kg m-2 const double CMASS_SEED = 0.01; /// Precision in land cover fraction input const double INPUT_PRECISION = 1.0e-14; const double INPUT_ERROR = 0.5e-6; const double INPUT_RESOLUTION = INPUT_PRECISION - INPUT_PRECISION * INPUT_ERROR; /////////////////////////////////////////////////////////////////////////////////////// // FORWARD DECLARATIONS OF CLASSES DEFINED IN THIS FILE // Forward declarations of classes used as types (e.g. for reference variables in some // classes) before they are actually defined class Date; class Stand; class Patch; class Vegetation; class Individual; class Gridcell; class Patchpft; /////////////////////////////////////////////////////////////////////////////////////// // GLOBAL VARIABLES WITH EXTERNAL LINKAGE // These variables are defined in the framework source code file, and are accessible // throughout the code /// Object describing timing stage of simulation extern Date date; /// Number of possible PFTs extern int npft; /// Number of stand types in stlist extern int nst; /// Number of stand types per land cover extern int nst_lc[NLANDCOVERTYPES]; /// Number of management types in stlist extern int nmt; /// General purpose object for handling simulation timing. /** In general, frameworks should use a single Date object for all simulation * timing. * * Member variables of the class (see below) provide various kinds of calender * and timing information, assuming init has been called to initialise the * object, and next() has been called at the end of each simulation day. */ class Date { // MEMBER VARIABLES public: /// Maximum number of days in an LPJ-GUESS simulation year /** The standard version doesn't yet support leap years. */ static const int MAX_YEAR_LENGTH = 366; // ecev3 /// number of days in each month (0=January - 11=December) int ndaymonth[12]; /// julian day of year (0-364; 0=Jan 1) int day; /// day of current month (0=first day) int dayofmonth; /// month number (0=January - 11=December) int month; /// year since start of simulation (0=first simulation year) int year; /// number of subdaily periods in a day (to be set in IO module) int subdaily; /// julian day for middle day of each month int middaymonth[12]; /// true if last year of simulation, false otherwise bool islastyear; /// true if last month of year, false otherwise bool islastmonth; /// true if last day of month, false otherwise bool islastday; /// true if middle day of month, false otherwise bool ismidday; /// The calendar year corresponding to simulation year 0 int first_calendar_year; /// ecev3 int hour, minute, second; private: int nyear; // MEMBER FUNCTIONS public: /// Constructor function called automatically when Date object is created /** Do not call explicitly. Initialises some member variables. */ Date() { const int data[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; int month; int dayct = 0; for (month=0; month<12; month++) { ndaymonth[month] = data[month]; middaymonth[month] = dayct + data[month] / 2; dayct += data[month]; } subdaily = 1; first_calendar_year = 0; } /// Initialises date to day 0 of year 0 and sets intended number of simulation years /** Intended number of simulation years is only used to set islastyear flag, * actual simulation may be longer or shorter. * * \param nyearsim Intended number of simulation years */ void init(int nyearsim) { nyear = nyearsim; day = month=year = dayofmonth = 0; islastmonth = islastday = ismidday = false; if (nyear == 1) islastyear = true; else islastyear = false; hour=minute=second=0; // ecev3 } Date(int y,int m,int d,int h,int n,int s) { // Constructor with initialisation to given date and time init(1); set(y,m,d,h,n,s); } // ecev3 void set(int y,int m,int d,int h,int n,int s) { int i; if (y != year || m != month || d != dayofmonth) { //timestep = 0; } year = y; // ecev3 - leap year? if (is_leap(year)) ndaymonth[1] = 29; else ndaymonth[1] = 28; month = m; dayofmonth = d; day = d; hour = h; minute = n; second = s; for (i = 0; i < m; i++) { day += ndaymonth[i]; } if (dayofmonth == ndaymonth[m] - 1) islastday = true; else islastday = false; if (m == 11) islastmonth = true; else islastmonth = false; if (y == nyear - 1) islastyear = true; else islastyear = false; if (dayofmonth == ndaymonth[m] / 2) ismidday = true; else ismidday = false; } /// Call at end of every simulation day to update member variables. void next() { if (islastday) { if (islastmonth) { dayofmonth = 0; day = 0; month = 0; year++; if (year == nyear - 1) islastyear = true; islastmonth = false; } else { day++; dayofmonth = 0; month++; if (month == 11) islastmonth = true; } islastday = false; } else { day++; dayofmonth++; if (dayofmonth == ndaymonth[month] / 2) ismidday = true; else { ismidday = false; if (dayofmonth == ndaymonth[month] - 1) islastday = true; } } } // \returns index (0-11) of previous month (11 if currently month 0). int prevmonth() { if (month > 0) return month - 1; return 11; } /// \returns index of next month (0 if currently month 11) int nextmonth() { if (month < 11) return month+1; return 0; } /// Check if the year is leap /** \param year Calendar year * The algorith is as follows: only year that are divisible by 4 could * potentially be leap (e.g., 1904), however, not if they're divisible by * 100 (e.g., 1900 is not leap), unless they're divisible by 400 (e.g., 2000 * is still leap). */ static bool is_leap(int year);// { // return (!(year % 4) && (year % 100 | !(year % 400))); //} /// Whether the current mode is diurnal bool diurnal() const { return subdaily > 1; } /// Sets calendar year for simulation year 0 /** Astronomical year numbering is used, so year 1 BC is represented by 0, * 2 BC = -1 etc. See ISO 8601. */ void set_first_calendar_year(int calendar_year) { first_calendar_year = calendar_year; } /// Returns the calendar year corresponding to the current simulation year /** Astronomical year numbering is used, so year 1 BC is represented by 0, * 2 BC = -1 etc. See ISO 8601. */ int get_calendar_year() const { return year + first_calendar_year; } /// \returns the number of days in the current simulation year /** For this function to work properly in simulations with varying number * of days per year, the set_first_calendar_year must have been called first. * * Currently there is no support for leap years, so this function * always returns 365. */ int year_length() const { if (is_leap(year)) // ecev3 - added leap year check return 366; else return 365; } /// Step n days from a date. /** Current implementation does not consider leap days, and the same * apply for the current use of the function through-out the model. */ static int stepfromdate(int day, int step) { if(day < 0) // a negative value should not be a valid day return -1; else if(day + step > 0) return (day + step) % MAX_YEAR_LENGTH; else if(day + step < 0) return day + step + MAX_YEAR_LENGTH; else return 0; } /// \returns the number of days in a month in the current simulation year /** This function returns the number of days in a month */ int month_length(int mth) { if (is_leap(year) && mth == 1) // ecev3 - leap year and February return 29; else return ndaymonth[mth]; } }; /// Object describing sub-daily periods class Day { public: /// Whether sub-daily period first/last within day (both true in daily mode) bool isstart, isend; /// Ordinal number of the sub-daily period [0, date.subdaily) int period; /// Constructs beginning of the day period (the only one in daily mode) Day() { isstart = true; isend = !date.diurnal(); period = 0; } /// Advances to the next sub-daily period void next() { period++; isstart = false; isend = period == date.subdaily - 1; } }; /// Object updating gridcell mass balance; currently used in framework() class MassBalance : public Serializable { int start_year; double ccont; double ccont_zero; double ccont_zero_scaled; double cflux; double cflux_zero; double ncont; double ncont_zero; double ncont_zero_scaled; double nflux; double nflux_zero; public: MassBalance() { start_year = nyear_spinup; ccont = 0.0; ccont_zero = 0.0; ccont_zero_scaled = 0.0; cflux = 0.0; cflux_zero = 0.0; ncont = 0.0; ncont_zero = 0.0; ncont_zero_scaled = 0.0; nflux = 0.0; nflux_zero = 0.0; } MassBalance(int start_yearX) { start_year = start_yearX; ccont = 0.0; ccont_zero = 0.0; ccont_zero_scaled = 0.0; cflux = 0.0; cflux_zero = 0.0; ncont = 0.0; ncont_zero = 0.0; ncont_zero_scaled = 0.0; nflux = 0.0; nflux_zero = 0.0; } void init(Gridcell& gridcell); void check(Gridcell& gridcell); // indiv and patch-level functions are for use with true crop stands only void init_indiv(Individual& indiv); bool check_indiv(Individual& indiv, bool check_harvest = false); bool check_indiv_C(Individual& indiv, bool check_harvest = false); bool check_indiv_N(Individual& indiv, bool check_harvest = false); void init_patch(Patch& patch); bool check_patch(Patch& patch, bool check_harvest = false); bool check_patch_C(Patch& patch, bool check_harvest = false); bool check_patch_N(Patch& patch, bool check_harvest = false); void check_year(Gridcell& gridcell); void check_period(Gridcell& gridcell); void serialize(ArchiveStream& arch); }; /// Struct containing wood harvest information struct Wood_harvest_struct { double prim_frac; double prim_vol; double sec_mature_frac; double sec_mature_vol; double sec_young_frac; double sec_young_vol; void zero() { prim_frac = 0.0; prim_vol = 0.0; sec_mature_frac = 0.0; sec_mature_vol = 0.0; sec_young_frac = 0.0; sec_young_vol = 0.0; } }; /// This struct contains the result of a photosynthesis calculation. /** \see photosynthesis */ struct PhotosynthesisResult {// : public Serializable { /// Constructs an empty result PhotosynthesisResult() { clear(); } /// Clears all members /** This is returned by the photosynthesis function when no photosynthesis * takes place. */ void clear() { agd_g = 0; adtmm = 0; rd_g = 0; vm = 0; je = 0; nactive_opt = 0.0; vmaxnlim = 1.0; } /// RuBisCO capacity (gC/m2/day) double vm; /// gross daily photosynthesis (gC/m2/day) double agd_g; /// leaf-level net daytime photosynthesis /** expressed in CO2 diffusion units (mm/m2/day) */ double adtmm; /// leaf respiration (gC/m2/day) double rd_g; /// PAR-limited photosynthesis rate (gC/m2/h) double je; /// optimal leaf nitrogen associated with photosynthesis (kgN/m2) double nactive_opt; /// nitrogen limitation on vm double vmaxnlim; /// net C-assimilation (gross photosynthesis minus leaf respiration) (kgC/m2/day) double net_assimilation() const { return (agd_g - rd_g) * 1e-3; } //void serialize(ArchiveStream& arch); }; /// The Climate for a grid cell /** Stores all static and variable data relating to climate parameters, as well as * latitude, atmospheric CO2 concentration and daylength for a grid cell. Includes * a reference to the parent Gridcell object (defined below). Initialised by a * call to initdrivers. */ class Climate : public Serializable { // MEMBER VARIABLES public: /// reference to parent Gridcell object Gridcell& gridcell; /// mean air temperature today (deg C) double temp; /// total daily net downward shortwave solar radiation today (J/m2/day) double rad; /// total daily photosynthetically-active radiation today (J/m2/day) double par; /// precipitation today (mm) double prec; /// day length today (h) double daylength; /// atmospheric ambient CO2 concentration today (ppmv) double co2; /// monthly atmospheric ambient CO2 concentration (ppmv) double mco2[12]; /// latitude (degrees; +=north, -=south) double lat; /// Insolation today, see also instype double insol; /// Type of insolation /** This decides how to interpret the variable insol, * see also documentation for the insoltype enum. */ insoltype instype; /// net LW today. Used to calculate eet double netlw; /// equilibrium evapotranspiration today (mm/day) double eet; /// mean temperature for the last 31 days (deg C) double mtemp; /// mean of lowest mean monthly temperature for the last 20 years (deg C) double mtemp_min20; /// mean of highest mean monthly temperature for the last 20 years (deg C) double mtemp_max20; /// highest mean monthly temperature for the last 12 months (deg C) double mtemp_max; /// accumulated growing degree day sum on 5 degree base /** reset when temperatures fall below 5 deg C */ double gdd5; /// total gdd5 (accumulated) for this year (reset 1 January) double agdd5; /// total gdd5 for this year for each of the last five simulation years Historic agdd5_5; /// number of days with temperatures <5 deg C /** reset when temperatures fall below 5 deg C; * maximum value is number of days in the year */ int chilldays; /// true if chill day count may be reset by temperature fall below 5 deg C bool ifsensechill; /** Respiration response to today's air temperature incorporating damping of Q10 * due to temperature acclimation (Lloyd & Taylor 1994) */ double gtemp; /// daily temperatures for the last 31 days (deg C) Historic dtemp_31; /// daily precipitation for the last 31 days (deg C) Historic dprec_31; /// daily eet for the last 31 days (deg C) Historic deet_31; /// minimum monthly temperatures for the last 20 years (deg C) double mtemp_min_20[20]; /// maximum monthly temperatures for the last 20 years (deg C) double mtemp_max_20[20]; /// minimum monthly temperature for the last 12 months (deg C) double mtemp_min; /// mean of monthly temperatures for the last 12 months (deg C) double atemp_mean; /// annual nitrogen deposition (kgN/m2/year) double andep; /// daily nitrogen deposition (kgN/m2) double dndep; // ecev3 - needed if we're forcing with IFS soil properties: double ifssoiltemp; double ifsw_surf; double ifsw_deep; // Saved parameters used by function daylengthinsoleet double sinelat; double cosinelat; double qo[Date::MAX_YEAR_LENGTH]; double u[Date::MAX_YEAR_LENGTH]; double v[Date::MAX_YEAR_LENGTH]; double hh[Date::MAX_YEAR_LENGTH]; double sinehh[Date::MAX_YEAR_LENGTH]; double daylength_save[Date::MAX_YEAR_LENGTH]; /// indicates whether saved values exist for this day bool doneday[Date::MAX_YEAR_LENGTH]; /// diurnal temperature range, used in daily/monthly BVOC (deg C) double dtr; // containers for sub-daily values of temperature, short-wave downward // radiation, par, rad and gtemp (equivalent to temp, insol, par, rad and gtemp) // NB: units of these variable are the same as their daily counterparts, // i.e. representing daily averages (e.g. pars [J/m2/day]) /// Sub-daily temperature (deg C) (\see temp) std::vector temps; /// Sub-daily insolation (\see insol) std::vector insols; /// Sub-daily PAR (\see par) std::vector pars; /// Sub-daily net downward shortwave solar radiation (\see rad) std::vector rads; /// Sub-daily respiration response (\see gtemp) std::vector gtemps; /// Variables used for crop sowing date or seasonality calculation /// daily precipitations for the last 10 days (mm) double dprec_10[10]; /// daily 10 day-sums of precipitations for today and yesterday (mm) double sprec_2[2]; /// max temperature during the last test period double maxtemp; /// summer day when we test last year's crossing of sowing temperature limits; NH:June 30(day 180), SH:Dec.31(day 364), set in getgridcell() int testday_temp; /// last day of dry month when we test last year's crossing of sowing precipitation limits; NH:Dec.31(day 364), SH:June 30(day 180), set in getgridcell() int testday_prec; /// date used for sowing if no frost or spring occured during the year between the testmonths; NH:14, SH:195, set in getgridcell() int coldestday; /// used to adapt equations to hemisphere, set in getgridcell() int adjustlat; /// accumulated monthly pet values for this year double mpet_year[12]; /// past 20 years monthly temperature values double mtemp_20[20][12]; /// past 20 years monthly precipitation values double mprec_20[20][12]; /// past 20 years monthly PET values double mpet_20[20][12]; /// past 20 years monthly precipitation to PET ratios double mprec_pet_20[20][12]; /// past 20 years minimum of monthly precipitation to PET ratios double mprec_petmin_20[20]; /// past 20 years maximum of monthly precipitation to PET ratios double mprec_petmax_20[20]; /// 20-year running average monthly temperature values double mtemp20[12]; /// 20-year running average monthly precipitation values double mprec20[12]; /// 20-year running average monthly PET values double mpet20[12]; /// 20-year running average monthly precipitation to PET ratios double mprec_pet20[12]; /// 20-year running average of minimum monthly precipitation to PET ratios double mprec_petmin20; /// 20-year running average of maximum monthly precipitation to PET ratios double mprec_petmax20; Historic hmtemp_20[12]; Historic hmprec_20[12]; Historic hmeet_20[12]; /// seasonality type (SEASONALITY_NO, SEASONALITY_PREC, SEASONALITY_PRECTEMP, SEASONALITY_TEMP, SEASONALITY_TEMPPREC) seasonality_type seasonality; seasonality_type seasonality_lastyear; /// precipitation seasonality type (DRY, DRY_INTERMEDIATE, DRY_WET, INTERMEDIATE, INTERMEDIATE_WET, WET) /** based on the extremes of the 20-year monthly means */ prec_seasonality_type prec_seasonality; prec_seasonality_type prec_seasonality_lastyear; /// precipitation range (DRY, DRY_INTERMEDIATE, DRY_WET, INTERMEDIATE, INTERMEDIATE_WET, WET) /** based on the average of the 20-year monthly extremes */ prec_seasonality_type prec_range; prec_seasonality_type prec_range_lastyear; /// temperature seasonality (COLD, COLD_WARM, COLD_HOT, WARM, WARM_HOT, HOT) temp_seasonality_type temp_seasonality; temp_seasonality_type temp_seasonality_lastyear; /// whether several months with precipitation maxima exists (remains to be implemented) bool biseasonal; /// variation coefficient of 20-year mean monthly temperatures double var_prec; /// variation coefficient of 20-year mean monthly precipitation to PET ratios double var_temp; /// annual precipitation sum double aprec; /// CRESCENDO physical variables output /// Near Surface Air Temperature [K] double mtemp_K[12]; /// Precipitation [kg m-2 s-1] double mprec[12]; /// Daily precipitation [kg m-2 s-1] double dprec[366]; /// Surface Downwelling Shortwave Radiation [W m-2] double mrsds[12]; #ifdef CRESCENDO_FACE /// Daily CO2 (mean ppm) double co2_daily[366]; /// Daily PAR (mol day-1) double par_daily[366]; /// Daily Air Temperature (mean oC) double at_daily[366]; /// Daily N deposition (gN m-2 day-1) double ndep_daily[366]; #endif public: /// constructor function: initialises gridcell member Climate(Gridcell& gc):gridcell(gc) { for(int m=0;m<12;m++) { mtemp20[m] = 0.0; mprec20[m] = 0.0; mpet20[m] = 0.0; mpet_year[m] = 0.0; mprec_pet20[m] = 0.0; for(int y=0;y<20;y++) { mtemp_20[y][m] = 0.0; mprec_20[y][m] = 0.0; mpet_20[y][m] = 0.0; mprec_pet_20[y][m] = 0.0; } } for(int y=0;y<20;y++) { mprec_petmin_20[y] = 0.0; mprec_petmax_20[y] = 0.0; } mprec_petmin20=0.0; mprec_petmax20=0.0; seasonality=SEASONALITY_NO; seasonality_lastyear=SEASONALITY_NO; prec_seasonality=DRY; prec_seasonality_lastyear=DRY; prec_range=DRY; prec_range_lastyear=DRY; temp_seasonality=COLD; temp_seasonality_lastyear=COLD; biseasonal=false; eet=0.0; }; /// Initialises certain member variables /** Should be called before Climate object is applied to a new grid cell */ void initdrivers(double latitude) { std::fill_n(mtemp_min_20, 20, 0.0); std::fill_n(mtemp_max_20, 20, 0.0); mtemp_min20 = 0.0; mtemp_max20 = 0.0; mtemp = 0.0; maxtemp = 0.0; gdd5 = 0.0; chilldays = 0; ifsensechill = true; atemp_mean = 0.0; lat = latitude; std::fill_n(doneday, Date::MAX_YEAR_LENGTH, false); sinelat = sin(lat * DEGTORAD); cosinelat = cos(lat * DEGTORAD); // Set crop-specific members if (latitude >= 0) { testday_temp = 180; //June 30(day 180) testday_prec = 364; //Dec.31(day 364) coldestday = COLDEST_DAY_NHEMISPHERE; adjustlat = 0; } else { testday_temp = 364; //Dec.31(day 364) testday_prec = 180; //June 30(day 180) coldestday = COLDEST_DAY_SHEMISPHERE; adjustlat = 181; } // ecev3 - needed if we're forcing with IFS soil properties: ifssoiltemp = 0.0; ifsw_surf = 0.0; ifsw_deep = 0.0; } /// ecev3 - transfer today's drivers from IFS to Climate void setdrivers(double ifstemp, double ifsprec, double ifsrad, double ifslw, double tm5co2, double ifstemp_soil, double ifssoilw_surf, double ifssoilw_deep, double dailyndep, double dailynfert); void serialize(ArchiveStream& arch); }; /// Stores accumulated monthly and annual fluxes. /** This class handles the storage and accounting of fluxes for a single patch. * Different fluxes can be stored in different ways, depending on what kind of * flux it is and what kind of output we want. The details of whether fluxes * are stored per PFT or just as a patch total, or per day, month or only a * yearly sum, is hidden from the 'scientific' code, which merely reports the * fluxes generated. */ class Fluxes : public Serializable { public: /// Daily fluxes stored as totals for the whole patch enum DailyPerPatchFluxType { /// Carbon flux to atmosphere from soil respiration (kgC/m2) SOILC, /// Carbon flux to atmosphere from burnt vegetation and litter (kgC/m2) FIREC, /// Flux from atmosphere to vegetation associated with sowing (kgC/m2) SEEDC, /// Flux to atmosphere from consumed harvested products (kgC/m2) HARVESTC, /// Number of types, must be last NDAILYPERPATCHFLUXTYPES }; /// Fluxes stored as totals for the whole patch enum PerPatchFluxType { /// Carbon flux to atmosphere from burnt vegetation (kgC/m2) FIREVEGC, /// Carbon flux to atmosphere from burnt litter (kgC/m2) FIRELITTERC, /// Carbon flux to atmosphere from litter respiration (kgC/m2) LITTERC, /// Flux from atmosphere to vegetation associated with establishment (kgC/m2) ESTC, /// Flux to atmosphere from consumed grazing harvested products (kgC/m2) HARVGRAZC, /// Flux to slow product pool from grazing (kgC/m2) HARVGRAZSLOWC, /// Flux to atmosphere from consumed cropping harvested products (kgC/m2) HARVCROPC, /// Flux to litter from harvested crops (kgC/m2) HARVCROPRESC, /// Flux to slow product pool from harvested crop (kgC/m2) HARVCROPSLOWC, /// Reproduction costs REPRC, /// Carbon leached LEACHC, /// Total Carbon Flux from Vegetation to Litter VEGLITTERC, /// Total Carbon Flux from Litter to Soil LITTERSOILC, /// Total Carbon Flux from excess and debt to atmosphere DEBEXCC, /// Total Carbon Flux from natural sources to atmosphere (flux seen by TM5) CO2NAT, /// Total Carbon Flux from anthropogenic sources to atmosphere (flux seen by TM5) CO2ANTT, /// Nitrogen flux from atmosphere to vegetation associated with sowing (kgC/m2) SEEDN, /// NH3 flux to atmosphere from fire NH3_FIRE, /// NOx flux to atmosphere from fire NOx_FIRE, /// N2O flux to atmosphere from fire N2O_FIRE, /// N2 flux to atmosphere from fire N2_FIRE, /// N flux from soil N_SOIL, /// N deposition NDEP, /// Biological N fixation NFIX, /// N fertilisation NFERT, /// Plant N Uptake NUP, /// Net N mineralisation NMIN, /// N leached LEACHN, /// Total nitrogen Flux from vegetation to litter VEGLITTERN, /// Total nitrogen Flux from litter to soil LITTERSOILN, /// Nitrogen flux to atmosphere from consumed harvested products (kgN/m2) HARVESTN, /// Autotrophic respiration from leaf (kgC/m2) RALEAF, /// Autotrophic respiration from stem (kgC/m2) RASTEM, /// Autotrophic respiration from roots (kgC/m2) RAROOT, /// Autotrophic respiration from growth (kgC/m2) RAGROWTH, /// Gross primary production for grass (kgC/m2) GPPGRASS, /// Gross primary production for tree (kgC/m2) GPPTREE, /// Autotrophic respiration from grass (kgC/m2) RAGRASS, /// Autotrophic respiration from tree (kgC/m2) RATREE, /// Number of types, must be last NPERPATCHFLUXTYPES }; /// Fluxes stored per pft enum PerPFTFluxType { /// NPP (kgC/m2) NPP, /// GPP (kgC/m2) GPP, /// Autotrophic respiration (kgC/m2) RA, /// Isoprene (mgC/m2) ISO, /// Monoterpene (mgC/m2) MT1, // MT_APIN, MT_LIMO, MT_TRIC MT2, // MT_BPIN, MT_MYRC, MT_SABI, MT_CAMP, MT_TBOC, MT_OTHR /// Number of types, must be last NPERPFTFLUXTYPES }; #ifdef CRESCENDO_FACE /// Daily FACE fluxes stored as totals for the whole patch enum DailyPerPatchFACEFluxType { /// Reproduction costs DREPRC, /// Flux from atmosphere to vegetation associated with establishment (kgC/m2) DESTC, /// Autotrophic respiration from leaf (kgC/m2) DRALEAF, /// Autotrophic respiration from stem (kgC/m2) DRASTEM, /// Autotrophic respiration from roots (kgC/m2) DRAROOT, /// Autotrophic respiration from growth (kgC/m2) DRAGROWTH, /// Plant leaf N growth DNGL, /// Plant sapwood N growth DNGW, /// Plant root N growth DNGR, /// Leaf nitrogen Flux from vegetation to litter DLEAFLITN, /// Wood nitrogen Flux from vegetation to litter DWOODLITN, /// Root nitrogen Flux from vegetation to litter DROOTLITN, /// Biological N fixation DNFIX, /// Plant N Uptake DNUP, /// Gross N mineralisation DGNMIN, /// Net N mineralisation DNMIN, /// N leached DLEACHN, /// N flux from soil DN_SOIL, /// Leaf Carbon Flux from Vegetation to Litter DLEAFLITC, /// Wood Carbon Flux from Vegetation to Litter DWOODLITC, /// Root Carbon Flux from Vegetation to Litter DROOTLITC, /// Number of types, must be last NDAILYPERPATCHFACEFLUXTYPE }; #endif // emission ratios from fire (NH3, NOx, N2O, N2) Delmas et al. 1995 // values in .cpp file static const double NH3_FIRERATIO; static const double NOx_FIRERATIO; static const double N2O_FIRERATIO; static const double N2_FIRERATIO; /// Reference to patch to which this Fluxes object belongs Patch& patch; // MEMBER FUNCTIONS public: /// constructor: initialises members Fluxes(Patch& p); /// Sets all fluxes to zero (call at the beginning of each year) void reset(); void serialize(ArchiveStream& arch); /// Report flux for a certain flux type void report_flux(PerPFTFluxType flux_type, int pft_id, double value); /// Report flux for a certain flux type void report_flux(PerPatchFluxType flux_type, double value); /// Report flux for a certain flux type void report_flux(DailyPerPatchFluxType flux_type, double value); /// \returns flux for a given month and flux type (for all PFTs) double get_monthly_flux(PerPFTFluxType flux_type, int month) const; /// \returns flux for a given month and flux type double get_monthly_flux(PerPatchFluxType flux_type, int month) const; /// \returns flux for a given month and flux type double get_monthly_flux(DailyPerPatchFluxType flux_type, int month) const; /// \returns annual flux for a given PFT and flux type double get_annual_flux(PerPFTFluxType flux_type, int pft_id) const; /// \returns annual flux for a given flux type (for all PFTs) double get_annual_flux(PerPFTFluxType flux_type) const; /// \returns annual flux for a given flux type double get_annual_flux(PerPatchFluxType flux_type) const; /// \returns annual flux for a given flux type double get_annual_flux(DailyPerPatchFluxType flux_type) const; // ecev3 /// \returns flux for a given day and flux type (for all PFTs) double get_daily_flux(PerPFTFluxType flux_type, int day) const; /// \returns flux for a given day and flux type double get_daily_flux(DailyPerPatchFluxType flux_type, int day) const; #ifdef CRESCENDO_FACE /// Report flux for a certain flux type void report_flux(DailyPerPatchFACEFluxType flux_type, double value); /// \returns flux for a given day and flux type double get_daily_flux(DailyPerPatchFACEFluxType flux_type, int day) const; #endif private: /// Stores one flux value per PFT and flux type std::vector > annual_fluxes_per_pft; /// Stores one flux value per month and flux type /** For the fluxes only stored as totals for the whole patch */ float monthly_fluxes_patch[12][NPERPATCHFLUXTYPES]; /// Stores one flux value per month and flux type /** For the fluxes stored per pft for annual values */ float monthly_fluxes_pft[12][NPERPFTFLUXTYPES]; // ecev3 also in LPJ-GUESS trunk but 365 instead of 366 /// Stores one flux value per day for GPP and NPP only /** For the fluxes stored per pft for annual values */ float daily_fluxes_pft[366][NPERPFTFLUXTYPES]; // ecev3 /// Stores one flux value per day /** For the fluxes only stored as totals for the whole patch */ float daily_fluxes_patch[366][NDAILYPERPATCHFLUXTYPES]; #ifdef CRESCENDO_FACE /// Stores one flux value per day /** For the fluxes only stored as totals for the whole patch */ float daily_fluxes_patch_FACE[366][NDAILYPERPATCHFACEFLUXTYPE]; #endif }; /// Storage class of crop management information for one rotation period for a stand type, read from the instruction file. class ManagementType { public: /// id code (should be zero based and sequential, 0...nst-1) int id; /// name of management type xtring name; /// type of planting system ("", "MONOCULTURE", "SELECTION", etc.) xtring planting_system; /// type of harvest system ("", "CLEARCUT", "CONTINUOUS") xtring harvest_system; /// name of crop pft xtring pftname; /// identifier of pft selection xtring selection; /// Rotation period in years double nyears; /// hydrology (RAINFED,IRRIGATED) hydrologytype hydrology; /// irrigation efficiency // double firr; /// forced sowing date, unless sdate_force read from file int sdate; /// forced harvest date, unless hdate_force read from file int hdate; /// Harvested forest area fraction, unless woodharv_frac read from file double woodharv_frac; /// Wood harvest volume, unless woodharv_volume read from file double woodharv_vol; /// Nitrogen fertilisation amount, unless Nfert_read read from file double nfert; /// Whether grass is grown in fallow bool fallow; /// Double cropping of one crop (e.g. rice) bool multicrop; ManagementType() { planting_system = ""; harvest_system = ""; pftname = ""; selection = ""; nyears = 1.0; hydrology = RAINFED; // firr = 0.0; sdate = -1; hdate = -1; nfert = -1.0; woodharv_frac = -1.0; woodharv_vol = -1.0; fallow = false; multicrop = false; } // Copy constructor ManagementType(const ManagementType& from) { name = from.name; pftname = from.pftname; hydrology = from.hydrology; sdate = from.sdate; hdate = from.hdate; nfert = from.nfert; fallow = from.fallow; } bool is_managed() { // Add new management parameters here if(pftname != "" || planting_system != "" || selection != ""|| harvest_system != "" || hydrology == IRRIGATED || fallow || nfert > -1.0) return true; else return false; } /// Returns true if pft is in pftselection. int pftinselection(const char* name) { bool found = false; char *p = NULL, string_copy[200] = {0}; strcpy(string_copy, selection); p = strtok(string_copy, "\t\n "); if(p) { if(!strcmp(name, p)) { found = true; } } do { p = strtok(NULL, "\t\n "); if(p) { if(!strcmp(name, p)) { found = true; } } } while(p && !found); return found; } }; /// A list of management types /** Functionality for building, maintaining, referencing and destroying a list array of * management types objects. * * Functionality is inherited from the ListArray_id template type in the GUTIL * Library. Sequential management type objects can be referenced as array elements by id: * * ManagementTypelist mtlist; * ... * for (i=0; i { public: int getmtid(xtring mtname) { int id = -1; for(unsigned int i=0; i< this->nobj; i++) { ManagementType& mt = (*this)[i]; if(mt.name == mtname) { id = mt.id; break; } } return id; } }; /// The one and only linked list of ManagementType objects extern ManagementTypelist mtlist; /// Storage class of crop rotation information for a stand type, read from the instruction file. struct CropRotation { /// Number of crops in rotation int ncrops; /// First rotation year int firstrotyear; CropRotation() { ncrops = 0; firstrotyear = 0; } }; /// Stand type class for storing both static parameters, read from the instruction file, /* and dynamic variables, updated in landcover_change() * Active stand types are stored in the stlist analogous to the pftlist. */ class StandType { public: /// id code (should be zero based and sequential, 0...nst-1) int id; /// name of stand type xtring name; /// specifies type of landcover /** \see landcovertype */ landcovertype landcover; // specifies type of landcover (0 = URBAN, 1 = CROP, 2 = PASTURE, 3 = FOREST, 4 = NATURAL, 5 = PEATLAND) /// Rotation information, read from the instruction file CropRotation rotation; /// Management struct (static) ManagementType management; /// Management types in a rotation cycle xtring mtnames[NROTATIONPERIODS_MAX]; /// First management year: sets time when common features for managed stands begin, e.g. relaxed establishment rules and absence of disturbance before harvest begins /** \this currently only applies for stands with wood havest */ int firstmanageyear; /// intercrop (NOINTERCROP,NATURALGRASS) intercroptype intercrop; /// whether natural pft:s are allowed to grow in stand type xtring naturalveg; // "", "GRASSONLY", "ALL" // whether only pft:s defined in management are allowed (plus intercrop or naturalveg/grass) bool restrictpfts; /// whether planted pft:s or all active pft:s are allowed to established after planting in a forest stand ("", "RESTRICTED", "ALL") xtring reestab; StandType() { intercrop = NOINTERCROP; naturalveg = ""; restrictpfts = false; reestab = "ALL"; firstmanageyear = 100000; } ManagementType& get_management(int rot = 0) { if(rotation.ncrops > 1) { return mtlist[mtlist.getmtid(mtnames[rot])]; } else { return management; } } /// Returns position of management in rotation list if present. Returns -1 if not. int mtinrotation(xtring name) { int mtno = -1; for(int i=0; i { }; /// The one and only linked list of StandType objects extern StandTypelist stlist; /// Holds static functional parameters for a plant functional type (PFT). /** There should be one Pft object for each potentially occurring PFT. The same Pft object * may be referenced (via the pft member of the Individual object; see below) by different * average individuals. Member functions are included for initialising SLA given leaf * longevity, and for initialising sapling/regen characteristics (required for * population mode). */ class Pft { // MEMBER VARIABLES public: /// id code (should be zero based and sequential, 0...npft-1) int id; /// name of PFT xtring name; /// life form (tree or grass) lifeformtype lifeform; /// leaf phenology (raingreen, summergreen, evergreen, rain+summergreen, cropgreen) phenologytype phenology; /// leaf physiognomy (needleleaf, broadleaf) leafphysiognomytype leafphysiognomy; /// growing degree sum on 5 degree base required for full leaf cover double phengdd5ramp; /// water stress threshold for leaf abscission (range 0-1; raingreen PFTs) double wscal_min; /// biochemical pathway for photosynthesis (C3 or C4) pathwaytype pathway; /// approximate low temperature limit for photosynthesis (deg C) double pstemp_min; /// approximate lower range of temperature optimum for photosynthesis (deg C) double pstemp_low; /// approximate upper range of temperature optimum for photosynthesis (deg C) double pstemp_high; /// maximum temperature limit for photosynthesis (deg C) double pstemp_max; /// non-water-stressed ratio of intercellular to ambient CO2 partial pressure double lambda_max; /// vegetation root profile /** array containing fraction of roots in each soil layer, [0=upper layer] */ double rootdist[NSOILLAYER]; /// canopy conductance component not associated with photosynthesis (mm/s) double gmin; /// maximum evapotranspiration rate (mm/day) double emax; /// maintenance respiration coefficient (0-1) double respcoeff; /// minimum leaf C:N mass ratio allowed when nitrogen demand is determined double cton_leaf_min; /// maximum leaf C:N mass ratio allowed when nitrogen demand is determined double cton_leaf_max; /// average leaf C:N mass ratio (between min and max) double cton_leaf_avr; /// average fine root C:N mass ratio (connected cton_leaf_avr) double cton_root_avr; /// maximum fine root C:N mass ratio (used when mass is negligible) double cton_root_max; /// average sapwood C:N mass ratio (connected cton_leaf_avr) double cton_sap_avr; /// maximum sapwood C:N mass ratio (used when mass is negligible) double cton_sap_max; /// reference fine root C:N mass ratio double cton_root; /// reference sapwood C:N mass ratio double cton_sap; /// Maximum nitrogen (NH4+ and NO3- seperatly) uptake per fine root [kgN kgC-1 day-1] double nuptoroot; /// coefficient to compensate for vertical distribution of fine root on nitrogen uptake double nupscoeff; /// fraction of sapwood (root for herbaceous pfts) that can be used as a nitrogen longterm storage scalar double fnstorage; /// Michaelis-Menten kinetic parameters /** Half saturation concentration for N uptake [kgN l-1] (Rothstein 2000) */ double km_volume; /// fraction of NPP allocated to reproduction double reprfrac; /// annual leaf turnover as a proportion of leaf C biomass double turnover_leaf; /// annual fine root turnover as a proportion of fine root C biomass double turnover_root; /// annual sapwood turnover as a proportion of sapwood C biomass double turnover_sap; /// sapwood and heartwood density (kgC/m3) double wooddens; /// maximum tree crown area (m2) double crownarea_max; /// constant in allometry equations double k_allom1; /// constant in allometry equations double k_allom2; /// constant in allometry equations double k_allom3; /// constant in allometry equations double k_rp; /// tree leaf to sapwood area ratio double k_latosa; /// specific leaf area (m2/kgC) double sla; /// leaf longevity (years) double leaflong; /// leaf to root mass ratio under non-water-stressed conditions double ltor_max; /// litter moisture flammability threshold (fraction of AWC) double litterme; /// fire resistance (0-1) double fireresist; /// minimum forest-floor PAR level for growth (grasses) or establishment (trees) /** J/m2/day, individual and cohort modes */ double parff_min; /** parameter capturing non-linearity in recruitment rate relative to * understorey growing conditions for trees (Fulton 1991) (individual and * cohort modes) */ double alphar; /// maximum sapling establishment rate (saplings/m2/year) (individual and cohort modes) double est_max; /** constant used in calculation of sapling establishment rate when spatial * mass effect enabled (individual and cohort modes) */ double kest_repr; /// constant affecting amount of background establishment /** \see ifbgestab */ double kest_bg; /** constant used in calculation of sapling establishment rate when spatial * mass effect disabled (individual and cohort modes) */ double kest_pres; /// expected longevity under non-stressed conditions (individual and cohort modes) double longevity; /// threshold growth efficiency for imposition of growth suppression mortality /** kgC/m2 leaf/year, individual and cohort modes */ double greff_min; // Bioclimatic limits (all temperatures deg C) /// minimum 20-year coldest month mean temperature for survival double tcmin_surv; /// maximum 20-year coldest month mean temperature for establishment double tcmax_est; /// minimum degree day sum on 5 deg C base for establishment double gdd5min_est; /// minimum 20-year coldest month mean temperature for establishment double tcmin_est; /// minimum warmest month mean temperature for establishment double twmin_est; /// continentality parameter for boreal summergreen trees double twminusc; /// constant in equation for budburst chilling time requirement (Sykes et al 1996) double k_chilla; /// coefficient in equation for budburst chilling time requirement double k_chillb; /// exponent in equation for budburst chilling time requirement double k_chillk; /// array containing values for GDD0(c) given c=number of chill days /** Sykes et al 1996, Eqn 1 * gdd0 has one element for each possible value for number of chill days */ double gdd0[Date::MAX_YEAR_LENGTH + 1]; /// interception coefficient (unitless) double intc; /// the amount of N that is applied (kg N m-2) double N_appfert; /// 0 - 1 how much of the fertiliser is applied the first date, default 1. double fertrate[2]; /// dates relative to sowing date int fertdates[2]; double fert_stages[2]; bool fertilised[2]; double T_vn_min; double T_vn_opt; double T_vn_max; double T_veg_min; double T_veg_opt; double T_veg_max; double T_rep_min; double T_rep_opt; double T_rep_max; double photo[3]; double dev_rate_veg; double dev_rate_rep; double a1, b1, c1, d1, a2, b2, c2, d2, a3, b3, c3, d3; double cton_stem_avr; double cton_stem_max; /// Drought tolerance level (0 = very -> 1 = not at all) (unitless) /** Used to implement drought-limited establishment */ double drought_tolerance; // bvoc /// aerodynamic conductance (m s-1) double ga; /// isoprene emission capacity (ug C g-1 h-1) double eps_iso; /// whether (1) or not (1) isoprene emissions show a seasonality bool seas_iso; /// monoterpene emission capacity (ug C g-1 h-1) per monoterpene species double eps_mon[NMTCOMPOUNDS]; /// fraction of monoterpene production that goes into storage pool (-) per monoterpene species double storfrac_mon[NMTCOMPOUNDS]; /// Sapling/regeneration characteristics (used only in population mode) /** For trees, on sapling individual basis (kgC); for grasses, on stand area basis, * kgC/m2 */ struct { /// leaf C biomass double cmass_leaf; /// fine root C biomass double cmass_root; /// sapwood C biomass double cmass_sap; /// heartwood C biomass double cmass_heart; } regen; /// specifies type of landcover pft is allowed to grow in (0 = URBAN, 1 = CROP, 2 = PASTURE, 3 = FOREST, 4 = NATURAL, 5 = PEATLAND) landcovertype landcover; /// pft selection xtring selection; /// fraction of residue outtake at harvest double res_outtake; /// harvest efficiency double harv_eff; /// harvest efficiency of intercrop grass double harv_eff_ic; /// fraction of harvested products that goes into patchpft.harvested_products_slow double harvest_slow_frac; /// yearly turnover fraction of patchpft.harvested_products_slow (goes to gridcell.acflux_harvest_slow) double turnover_harv_prod; /// whether pft may grow as cover crop bool isintercropgrass; /// whether autumn temperature dependent sowing date is calculated bool ifsdautumn; /// upper temperature limit for autumn sowing double tempautumn; /// lower temperature limit for spring sowing double tempspring; /// default length of growing period int lgp_def; /// upper minimum temperature limit for crop sowing double maxtemp_sowing; /// default sowing date in the northern hemisphere (julian day) int sdatenh; /// default sowing date in the southern hemisphere int sdatesh; /// whether sowing date adjusting equation is used bool sd_adjust; /// parameter 1 in sowing date adjusting equation double sd_adjust_par1; /// parameter 2 in sowing date adjusting equation double sd_adjust_par2; /// parameter 3 in sowing date adjusting equation double sd_adjust_par3; /// latest date for harvesting in the northern hemisphere int hlimitdatenh; /// latest date for harvesting in the southern hemisphere int hlimitdatesh; /// default base temperature (°C) for heat unit (hu) calculation double tb; /// temperature under which vernalisation is possible (°C) double trg; /// default number of vernalising days required int pvd; /// sensitivity to the photoperiod effect [0-1] double psens; /// basal photoperiod (h) (pb { public: int getpftid(xtring pftname) { int id = -1; for(unsigned int i=0; i< this->nobj; i++) { Pft& pft = (*this)[i]; if(pft.name == pftname) { id = pft.id; break; } } return id; } }; /// The one and only linked list of Pft objects extern Pftlist pftlist; /// Container for crop-specific data at the individual level struct cropindiv_struct : public Serializable { //Plant carbon biomass variables are all on patch area basis (kgC/m2) /// year's harvestable organ C biomass (= ycmass_plant) double cmass_ho; /// above-ground pool C biomass (when calculating daily cmass_leaf from lai_crop) (= ycmass_agpool) double cmass_agpool; double cmass_stem; /// year's maximum value of leaf C biomass double cmass_leaf_max; /// grs_cmass_leaf value saved at day before senescence (for LAI-calculation in allometry) double cmass_leaf_sen; /// today's increase of whole plant C biomass double dcmass_plant; /// today's increase of leaf C biomass double dcmass_leaf; /// today's increase of root C biomass double dcmass_root; /// today's increase of harvestable organ C biomass double dcmass_ho; /// today's increase of above-ground pool C biomass double dcmass_agpool; double dcmass_stem; /// today's increase of leaf N biomass double dnmass_leaf; /// today's increase of root N biomass double dnmass_root; /// today's increase of harvestable organ N biomass double dnmass_ho; /// today's increase of above-ground pool N biomass double dnmass_agpool; ///CARBON /// daily updated whole plant C biomass, reset at harvest day double grs_cmass_plant; /// daily updated leaf C biomass, reset at harvest day double grs_cmass_leaf; /// daily updated root C biomass, reset at harvest day double grs_cmass_root; /// daily updated harvestable organ C biomass, reset at harvest day double grs_cmass_ho; /// daily updated above-ground pool C biomass, reset at harvest day double grs_cmass_agpool; /// daily updated dead leaf C biomass, reset at harvest day double grs_cmass_dead_leaf; /// daily updated stem pool C biomass, reset at harvest day double grs_cmass_stem; /// carbon content of harvestable organs saved on first day of land use change year double grs_cmass_leaf_luc; /// carbon content of harvestable organs saved on first day of land use change year double grs_cmass_root_luc; /// carbon content of harvestable organs saved on first day of land use change year double grs_cmass_ho_luc; /// carbon content of above-ground pool saved on first day of land use change year double grs_cmass_agpool_luc; /// carbon content of dead leaves saved on first day of land use change year double grs_cmass_dead_leaf_luc; /// carbon content of stem saved on first day of land use change year double grs_cmass_stem_luc; /// daily updated whole plant C biomass, reset at day 0 double ycmass_plant; /// daily updated leaf C biomass, reset at day 0 double ycmass_leaf; /// daily updated root C biomass, reset at day 0 double ycmass_root; /// daily updated harvestable organ C biomass, reset at day 0 double ycmass_ho; /// daily updated above-ground pool C biomass, reset at day 0 double ycmass_agpool; /// daily updated dead leaf C biomass, reset at day 0 double ycmass_dead_leaf; /// daily updated stem C biomass, reset at day 0 double ycmass_stem; /// year's whole plant C biomass at time of harvest (cumulative if several harvest events) double harv_cmass_plant; /// year's leaf C biomass at time of harvest (cumulative if several harvest events) double harv_cmass_leaf; /// year's root C biomass at time of harvest (cumulative if several harvest events) double harv_cmass_root; /// year's harvestable organ C biomass at time of harvest (cumulative if several harvest events) double harv_cmass_ho; /// year's above-ground pool C biomass at time of harvest (cumulative if several harvest events) double harv_cmass_agpool; /// year's stem C biomass at time of harvest (cumulative if several harvest events) double harv_cmass_stem; ///NITROGEN /// nitrogen content of harvestable organs double nmass_ho; /// nitrogen content of above-ground pool double nmass_agpool; /// nitrogen content of dead leaves double nmass_dead_leaf; /// nitrogen content of harvestable organs saved on first day of land use change year double nmass_ho_luc; /// nitrogen content of above-ground pool saved on first day of land use change year double nmass_agpool_luc; /// nitrogen content of dead leaves saved on first day of land use change year double nmass_dead_leaf_luc; /// daily updated leaf N biomass, reset at day 0 double ynmass_leaf; /// daily updated root N biomass, reset at day 0 double ynmass_root; /// daily updated harvestable organ N biomass, reset at day 0 double ynmass_ho; /// daily updated above-ground pool N biomass, reset at day 0 double ynmass_agpool; /// daily updated dead leaf N biomass, reset at day 0 double ynmass_dead_leaf; /// year's leaf N biomass at time of harvest (cumulative if several harvest events) double harv_nmass_leaf; /// year's root N biomass at time of harvest (cumulative if several harvest events) double harv_nmass_root; /// year's harvestable organ N biomass at time of harvest (cumulative if several harvest events) double harv_nmass_ho; /// year's above-ground pool N biomass at time of harvest (cumulative if several harvest events) double harv_nmass_agpool; /// dry weight crop yield harvested this year (cumulative if several harvest events), based on harv_cmass_xx double harv_yield; /// harvestable organ C biomass at the last two harvest events this year double cmass_ho_harvest[2]; /// harvestable organ N biomass at the last two harvest events this year double nmass_ho_harvest[2]; /// dry weight crop yield at the last two harvest events this year double yield_harvest[2]; /// dry weight crop yield grown this year (cumulative if several harvest events), based on ycmass_xx double yield; /// whether this pft is the main crop in the stand (pft.id==stand.pftid) bool isprimarycrop; /// whether this pft is allowed to compete with the main crop during the same growing period (for future use) bool isprimarycovegetation; /// whether this pft is grown during a second growing period, different from the primary (main) crop (for future use) // bool issecondarycrop; /// set to true if pft.isintercropgrass is true and the stand's main crop pft.intercrop is "naturalgrass" bool isintercropgrass; cropindiv_struct() { cmass_ho=0.0; cmass_agpool=0.0; cmass_stem = 0.0; cmass_leaf_max=0.0; cmass_leaf_sen=0.0; yield=0.0; yield_harvest[0]=0.0; yield_harvest[1]=0.0; dcmass_leaf=0.0; dcmass_root=0.0; dcmass_plant=0.0; dcmass_ho=0.0; dcmass_agpool=0.0; grs_cmass_leaf=0.0; grs_cmass_root=0.0; grs_cmass_plant=0.0; grs_cmass_ho=0.0; grs_cmass_agpool=0.0; grs_cmass_stem = 0.0; grs_cmass_dead_leaf = 0.0; grs_cmass_leaf_luc=0.0; grs_cmass_root_luc=0.0; grs_cmass_ho_luc=0.0; grs_cmass_agpool_luc=0.0; grs_cmass_dead_leaf_luc = 0.0; grs_cmass_stem_luc = 0.0; nmass_ho=0.0; nmass_agpool=0.0; nmass_dead_leaf = 0.0; ycmass_leaf=0.0; ycmass_root=0.0; ycmass_plant=0.0; ycmass_ho=0.0; ycmass_agpool=0.0; ycmass_stem = 0.0; ycmass_dead_leaf = 0.0; harv_cmass_leaf=0.0; harv_cmass_root=0.0; harv_cmass_root=0.0; harv_cmass_ho=0.0; harv_yield=0.0; harv_cmass_agpool=0.0; harv_cmass_stem = 0.0; cmass_ho_harvest[0]=0.0; cmass_ho_harvest[1]=0.0; //Nitrogen dnmass_leaf=0.0; dnmass_root=0.0; dnmass_ho=0.0; dnmass_agpool=0.0; ynmass_leaf=0.0; ynmass_root=0.0; ynmass_ho=0.0; ynmass_agpool=0.0; ynmass_dead_leaf = 0.0; harv_nmass_leaf=0.0; harv_nmass_root=0.0; harv_nmass_root=0.0; harv_nmass_ho=0.0; harv_nmass_agpool=0.0; nmass_dead_leaf_luc = 0.0; nmass_ho_harvest[0]=0.0; nmass_ho_harvest[1]=0.0; // ecev3 nmass_ho_luc=0.0; nmass_agpool_luc = 0.0; isprimarycrop=false; isprimarycovegetation=false; // issecondarycrop=false; isintercropgrass=false; } void serialize(ArchiveStream& arch); }; /// A vegetation individual. /** In population mode this is the average individual of a PFT population; * in cohort mode: the average individual of a cohort; * in individual mode: an individual plant. Each grass PFT is represented as a single * individual in all modes. Individual objects are collected within list arrays of * class Vegetation (defined below), of which there is one for each patch, and include * a reference to their 'parent' Vegetation object. Use the createobj member function * of class Vegetation to add new individuals. */ class Individual : public Serializable { public: /// reference to Pft object containing static parameters for this individual Pft& pft; /// reference to Vegetation object to which this Individual belongs Vegetation& vegetation; /// id code (0-based, sequential) int id; /// leaf C biomass on modelled area basis (kgC/m2) double cmass_leaf; /// fine root C biomass on modelled area basis (kgC/m2) double cmass_root; /// sapwood C biomass on modelled area basis (kgC/m2) double cmass_sap; /// heartwood C biomass on modelled area basis (kgC/m2) double cmass_heart; /// C "debt" (retrospective storage) (kgC/m2) double cmass_debt; /// Total C mass at land use change (kgC/m2) double cmass_tot_luc; /// leaf C mass after tunrnover double cmass_leaf_post_turnover; /// root C mass after turnover double cmass_root_post_turnover; /// Latest tunover day for this individual int last_turnover_day; /// leaf N biomass on modelled area basis (kgN/m2) double nmass_leaf; /// root N biomass on modelled area basis (kgN/m2) double nmass_root; /// sap N biomass on modelled area basis (kgN/m2) double nmass_sap; /// heart N biomass on modelled area basis (kgN/m2) double nmass_heart; /// leaf N biomass on modelled area basis saved on first day of land use change year double nmass_leaf_luc; /// root N biomass on modelled area basis on first day of land use change year double nmass_root_luc; /// sap N biomass on modelled area basis on first day of land use change year double nmass_sap_luc; /// heart N biomass on modelled area basis on first day of land use change year double nmass_heart_luc; /// total N biomass on modelled area basis on first day of land use change year double nmass_tot_luc; /// foliar projective cover (FPC) under full leaf cover as fraction of modelled area double fpc; /// foliar projective cover (FPC) this day as fraction of modelled area double fpc_daily; /// monthly average daily foliar projective cover (FPC) as fraction of modelled area double mfpc[12]; /// fraction of PAR absorbed by foliage over projective area today, taking account of leaf phenological state double fpar; /// monthly average fraction of PAR absorbed by foliage over projective area, taking account of leaf phenological state double mfpar[12]; /// average density of individuals over patch (indiv/m2) double densindiv; /// vegetation phenological state (fraction of potential leaf cover) double phen; /// annual sum of daily fractional leaf cover /** Equivalent number of days with full leaf cover * (population mode only; reset on expected coldest day of year) */ double aphen; /// annual number of days with full leaf cover) (raingreen PFTs only; reset on 1 January) int aphen_raingreen; /// Photosynthesis values for this individual under non-water-stress conditions PhotosynthesisResult photosynthesis; /// sub-daily version of the above variable (NB: daily units) std::vector phots; /// accumulated NPP over modelled area (kgC/m2/year); /** annual NPP following call to growth module on last day of simulation year */ double anpp; /// actual evapotranspiration over projected area (mm/day) double aet; /// annual actual evapotranspiration over projected area (mm/year) double aaet; /// leaf to root mass ratio double ltor; /// plant height (m) double height; /// plant crown area (m2) double crownarea; /// increment in fpc since last simulation year double deltafpc; /// bole height, i.e. height above ground of bottom of crown cylinder (m) /** (individual and cohort modes only) */ double boleht; /// patch-level lai for this individual or cohort (function fpar) double lai; /// patch-level lai for cohort in current vertical layer (function fpar) double lai_layer; /// individual leaf area index (individual and cohort modes only) double lai_indiv; /// patch-level individual leaf area index (individual and cohort modes only) double lai_daily; /// daily individual leaf area index (individual and cohort modes only) double lai_indiv_daily; /// growth efficiency (NPP/leaf area) for each of the last five simulation years (kgC/m2/yr) Historic greff_5; /// increment of wood C for each of the last five simulation years (kgC/m2/yr) Historic cmass_wood_inc_5; /// individual/cohort age (years) double age; /// monthly LAI (including phenology component) double mlai[12]; /// monthly maximum LAI (including phenology component) double mlai_max[12]; /// FPAR assuming full leaf cover for all vegetation double fpar_leafon; /// LAI for current layer in canopy (cohort/individual mode; see function fpar) double lai_leafon_layer; /// non-water-stressed canopy conductance on FPC basis (mm/s) double gpterm; /// sub-daily version of the above variable (mm/s) std::vector gpterms; /// interception associated with this individual today (patch basis) double intercep; /// accumulated mean fraction of potential leaf cover double phen_mean; /// whether individual subject to water stress bool wstress; /// leaf nitrogen that is photosyntetic active double nactive; /// Nitrogen extinction scalar /** Scalar to account for leaf nitrogen not following the optimal light * extinction, but is shallower. */ double nextin; /// long-term storage of labile nitrogen double nstore_longterm; /// storage of labile nitrogen double nstore_labile; /// long-term storage of labile nitrogen saved on first day of land use change year double nstore_longterm_luc; /// storage of labile nitrogen saved on first day of land use change year double nstore_labile_luc; /// daily total nitrogen demand double ndemand; /// fraction of individual nitrogen demand available for uptake double fnuptake; /// annual nitrogen uptake double anuptake; /// maximum size of nitrogen storage double max_n_storage; /// scales annual npp to maximum nitrogen storage double scale_n_storage; /// annual nitrogen limitation on vmax double avmaxnlim; /// annual optimal leaf C:N ratio double cton_leaf_aopt; /// annual average leaf C:N ratio double cton_leaf_aavr; /// plant mobile nitrogen status double cton_status; /// total carbon in compartments before growth double cmass_veg; /// total nitrogen in compartments before growth double nmass_veg; /// whether individual subject to nitrogen stress bool nstress; /// daily leaf nitrogen demand calculated from Vmax (kgN/m2) double leafndemand; /// daily root nitrogen demand based on leafndemand double rootndemand; /// daily sap wood nitrogen demand based on leafndemand double sapndemand; /// daily labile nitrogen demand based on npp double storendemand; /// daily harvestable organ nitrogen demand double hondemand; /// leaf fraction of total nitrogen demand double leaffndemand; /// root fraction of total nitrogen demand double rootfndemand; /// sap fraction of total nitrogen demand double sapfndemand; /// store fraction of total nitrogen demand double storefndemand; /// daily leaf nitrogen demand over possible uptake (storage demand) double leafndemand_store; /// daily root nitrogen demand over possible uptake (storage demand) double rootndemand_store; /// The daily C lossed from leaves due to senescense, only crops. double daily_cmass_leafloss; /// The daily N lossed from leaves due to senescense, only crops. double daily_nmass_leafloss; /// The daily C lossed from roots due to senescense, only crops. double daily_cmass_rootloss; /// The daily N lossed from roots due to senescense, only crops. double daily_nmass_rootloss; /// Number of days with non-negligible phenology this month int nday_leafon; // Whether this individual is truly alive. /** Set to false for first year after the Individual object is created, then true. */ bool alive; /// NPP this day double dnpp; // bvoc /// isoprene production (mg C m-2 d-1) double iso; /// monoterpene production (mg C m-2 d-1) per monoteprene species double mon[NMTCOMPOUNDS]; /// monoterpene storage pool (mg C m-2) per monoterpene species double monstor[NMTCOMPOUNDS]; /// isoprene seasonality factor (-) double fvocseas; // Lambda output /// monthly lambda (Ci/Ca) double mlambda_gpp[12]; /// monthly gpp double mgpp[12]; /// Pointer to struct with crop-specific data cropindiv_struct *cropindiv; // MEMBER FUNCTIONS public: // Constructor function for objects of class Individual // Initialisation of certain member variables Individual(int i,Pft& p,Vegetation& v); ~Individual(); /// Access functions for cropindiv: cropindiv_struct* get_cropindiv() const; cropindiv_struct* set_cropindiv(); void serialize(ArchiveStream& arch); /// Report a flux associated with this Individual /** Fluxes from 'new' Individuals (alive == false) will not be reported */ void report_flux(Fluxes::PerPFTFluxType flux_type, double value); /// Report a flux associated with this Individual /** Fluxes from 'new' Individuals (alive == false) will not be reported */ void report_flux(Fluxes::PerPatchFluxType flux_type, double value); /// Report a flux associated with this Individual /** Fluxes from 'new' Individuals (alive == false) will not be reported */ void report_flux(Fluxes::DailyPerPatchFluxType flux_type, double value); #ifdef CRESCENDO_FACE /// Report a flux associated with this Individual /** Fluxes from 'new' Individuals (alive == false) will not be reported */ void report_flux(Fluxes::DailyPerPatchFACEFluxType flux_type, double value); #endif /// Whether an individual is either a true crop or a cover crop grass inline bool istruecrop_or_intercropgrass() const { return (pft.landcover==CROPLAND && (pft.phenology==CROPGREEN || cropindiv->isintercropgrass)); } /// Whether harvest and turnover is done on actual C and N on harvest or turnover day, which can occur any day of the year. bool has_daily_turnover() const; /// Whether resetting of grs_cmass and turnover (if has_daily_turnover() returns true) of continuous grass is to be done this day. /** This should occur at the very end of the growing period */ bool is_turnover_day() const; /// Reduce current biomass due to mortality and/or fire /** The removed biomass is put into litter pools and/or goes to fire fluxes. * * \param mortality fraction of Individual's biomass killed due to * mortality (including fire) * \param mortality_fire fraction of Individual's biomass killed due to * fire only */ void reduce_biomass(double mortality, double mortality_fire); /// Total storage of nitrogen double nstore() const { return nstore_longterm + nstore_labile; } /// Total carbon wood biomass double cmass_wood() const { return cmass_sap + cmass_heart - cmass_debt; } /// Total nitrogen wood biomass double nmass_wood() const { return nmass_sap + nmass_heart; } /// Total carbon biomass double ccont(double scale_indiv = 1.0, bool luc = false) const; /// Total nitrogen biomass double ncont(double scale_indiv = 1.0, bool luc = false) const; /// Leaf carbon biomass double cleafcont(double scale_indiv = 1.0, bool luc = false) const; /// Leaf nitrogen biomass double nleafcont(double scale_indiv = 1.0, bool luc = false) const; /// Root carbon biomass double crootcont(double scale_indiv = 1.0, bool luc = false) const; /// Root nitrogen biomass double nrootcont(double scale_indiv = 1.0, bool luc = false) const; /// Whether grass growth is uninterrupted by crop growth. bool continous_grass() const; /// Checks whether any grs_cmass is negative, in which case it is zeroed and fluxes are corrected (only cropland). double check_C_mass(); /// Checks whether any nmass is negative, in which case it is zeroed and fluxes are corrected (only cropland). double check_N_mass(); /// Save cmass-values on first day of the year of land cover change in expanding stands void save_cmass_luc(); /// Save nmass-values on first day of the year of land cover change in expanding stands void save_nmass_luc(); /// Current leaf C:N ratio /** * \param use_phen Set to false if indiv.phen shouldn't be considered * when calculating C:N ratio */ double cton_leaf(bool use_phen = true) const; /// Current fine root C:N ratio /** * \param use_phen Set to false if indiv.phen shouldn't be considered * when calculating C:N ratio */ double cton_root(bool use_phen = true) const; /// Current sap C:N ratio double cton_sap() const; /// Gets the individual's Patchpft Patchpft& patchpft() const; /// Transfers the individual's biomass (C and N) to litter and harvest pools/fluxes /** * \param harvest Set to true if some of the biomass should be harvested, * harvest will be done according to the PFT's harvest efficiency * and residue outtake. */ void kill(bool harvest = false); /// Annual mean wscal - water stress parameter (0-1 range; 1 = minimum stress) /** Value only valid at end of year, after call to canopy_exchange(). * * Currently, all Individuals belonging to a Patchpft share the same water stress. */ double wscal_mean() const; /// Gets the individual's daily cmass_leaf value double cmass_leaf_today() const; /// Gets the individual's daily cmass_root value double cmass_root_today() const; /// Gets the individual's daily LAI value (patch-level) /** Based on total leaf area for whatever the individual represents * (individual, cohort, population), over the whole patch. */ double lai_today() const; /// Gets the individual's daily LAI value (individual-level) /** Based on the leaf area for the average individual and * the average individual's crown area. */ double lai_indiv_today() const; /// Gets the Nitrogen limited LAI, Eq. 8 Olin 2015 double lai_nitrogen_today() const; /// Gets the individual's daily fpc value double fpc_today() const; /// Gets the growingseason status for crop individual. Non-crop individuals always return true. bool growingseason() const; /// The N demand of the storage, only used for PNV. double ndemand_storage(double cton_leaf_opt); }; /// The vegetation in a patch - a list of individuals /** Functionality for building, maintaining, referencing and destroying a list array of * Individual objects. A single Vegetation object is defined for each patch. A * reference to the parent Patch object (defined below) is included as a member * variable. * * Functionality is inherited from the ListArray_idin1 template type in the GUTIL * Library. Sequential Individual objects can be referenced as array elements by id, * or by iteration through the linked list: * * Vegetation vegetation * ... * vegetation.firstobj(); * while (vegetation.isobj) { * Individual& thisindiv=vegetation.getobj(); * // query or modify object thisindiv here * vegetation.nextobj(); * } */ class Vegetation : public ListArray_idin2, public Serializable { public: // MEMBER VARIABLES /// reference to parent Patch object Patch& patch; // MEMBER FUNCTIONS /// constructor (initialises member variable patch) Vegetation(Patch& p):patch(p) {}; void serialize(ArchiveStream& arch); }; /// Soiltype stores static parameters for soils and the snow pack. /** One Soiltype object is defined for each Gridcell. State variables for soils * are held by objects of class Soil, of which there is one for each patch * (see below). */ class Soiltype { // MEMBER VARIABLES public: /// available water holding capacity as fraction of soil volume double awc_frac; /// available water holding capacity of soil layers [0=upper layer] (mm) double awc[NSOILLAYER]; /// coefficient in percolation calculation (K in Eqn 31, Haxeltine & Prentice 1996) double perc_base; /// exponent in percolation calculation (=4 in Eqn 31, Haxeltine & Prentice 1996) double perc_exp; /// thermal diffusivity at 0% WHC (mm2/s) double thermdiff_0; /// thermal diffusivity at 15% WHC (mm2/s) double thermdiff_15; /// thermal diffusivity at 100% WHC (mm2/s) double thermdiff_100; /// wilting point of soil layers [0=upper layer] (mm) Cosby et al 1984 double wp[NSOILLAYER]; /// saturation point. Cosby et al 1984 double wsats[NSOILLAYER]; /// year at which to calculate equilibrium soil carbon int solvesom_end; /// year at which to begin documenting means for calculation of equilibrium soil carbon int solvesom_begin; /// water holding capacity plus wilting point for whole soil volume double wtot; // For CENTURY ... /// fraction of soil that is sand double sand_frac; /// fraction of soil that is clay double clay_frac; /// fraction of soil that is silt double silt_frac; // ecev3 // New volumetric soil moisture parameters from H-TESSEL/IFS - see Balsamo et al. // Units: m3 m-3 double wilt_point; // Wilting point double field_cap; // Field capacity double whcap; // Water holding capacity (field_cap - wilt_point) // MEMBER FUNCTIONS public: /// Constructor: initialises certain member variables Soiltype() { solvesom_end = SOLVESOM_END; solvesom_begin = SOLVESOM_BEGIN; } /// Override the default SOM years with 70-80% of the spin-up period length void updateSolveSOMvalues(const int& nyrspinup) { solvesom_end = static_cast(0.8 * nyrspinup); solvesom_begin = static_cast(0.7 * nyrspinup); } }; /// CENTURY SOIL POOL class Sompool : public Serializable { public: /// Constructor Sompool() { // Initialise pool cmass = 0.0; nmass = 0.0; ligcfrac = 0.0; delta_cmass = 0.0; delta_nmass = 0.0; fracremain = 0.0; litterme = 0.0; fireresist = 0.0; ntoc = 0.0; // ecev3 cdec = 0.0; // ecev3 ndec = 0.0; // ecev3 // ecev3 - extra initialisation ntoc = 0.0; cdec = 0.0; ndec = 0.0; for (int m = 0; m < 12; m++) { mfracremain_mean[m] = 0.0; } } /// C mass in pool kgC/m2 double cmass; /// Nitrogen mass in pool kgN/m2 double nmass; /// (potential) decrease in C following decomposition today (kgC/m2) double cdec; /// (potential) decrease in nitrogen following decomposition today (kgN/m2) double ndec; /// daily change in carbon and nitrogen double delta_cmass,delta_nmass; /// lignin fractions double ligcfrac; /// fraction of pool remaining after decomposition double fracremain; /// nitrogen to carbon ratio double ntoc; // Fire /// soil litter moisture flammability threshold (fraction of AWC) double litterme; /// soil litter fire resistance (0-1) double fireresist; // Fast SOM spinup variables /// monthly mean fraction of carbon pool remaining after decomposition double mfracremain_mean[12]; void serialize(ArchiveStream& arch); }; /// This struct contains litter for solving Century SOM pools. /** \see equilsom() */ struct LitterSolveSOM {// : public Serializable { /// Constructs an empty result LitterSolveSOM() { clear(); } /// Clears all members void clear() { for (int p = 0; p < NSOMPOOL; p++) { clitter[p] = 0.0; nlitter[p] = 0.0; } } /// Add litter void add_litter(double cvalue, double nvalue, int pool) { clitter[pool] += cvalue; nlitter[pool] += nvalue; } double get_clitter(int pool) { return clitter[pool]; } double get_nlitter(int pool) { return nlitter[pool]; } //void serialize(ArchiveStream& arch); private: /// Carbon litter double clitter[NSOMPOOL]; /// Nitrogen litter double nlitter[NSOMPOOL]; }; /// Soil stores state variables for soils and the snow pack. /** Initialised by a call to initdrivers. One Soil object is defined for each patch. * A reference to the parent Patch object (defined below) is included as a member * variable. Soil static parameters are stored as objects of class Soiltype, of which * there is one for each grid cell. A reference to the Soiltype object holding the * static parameters for this soil is included as a member variable. */ class Soil : public Serializable { // MEMBER VARIABLES public: /// reference to parent Patch object Patch& patch; /// reference to Soiltype object holding static parameters for this soil Soiltype& soiltype; /// water content of soil layers [0=upper layer] as fraction of available water holding capacity; double wcont[NSOILLAYER]; /// DLE - the average wcont over the growing season, for each soil layer double awcont[NSOILLAYER]; /// water content of sublayer of upper soil layer for which evaporation from the bare soil surface is possible /** fraction of available water holding capacity */ double wcont_evap; /// daily water content in upper soil layer for each day of year double dwcontupper[Date::MAX_YEAR_LENGTH]; /// mean water content in upper soil layer for last month /** (valid only on last day of month following call to daily_accounting_patch) */ double mwcontupper; /// stored snow as average over modelled area (mm rainfall equivalents) double snowpack; /// total runoff today (mm/day) double runoff; /// soil temperature today at 0.25 m depth (deg C) double temp; /// daily temperatures for the last month (deg C) /** (valid only on last day of month following call to daily_accounting_patch) */ double dtemp[31]; /// mean soil temperature for the last month (deg C) /** (valid only on last day of month following call to daily_accounting_patch) */ double mtemp; /// mean top soil temperature for every month (deg K) double mtemp_K[12]; /// Carbon transfer between litter and soil (kg C m-2) double litter2soilc; /// Nitrogen transfer between litter and soil (kg N m-2) double litter2soiln; /** respiration response to today's soil temperature at 0.25 m depth * incorporating damping of Q10 due to temperature acclimation (Lloyd & Taylor 1994) */ double gtemp; /// soil organic matter (SOM) pool with c. 1000 yr turnover (kgC/m2) double cpool_slow; /// soil organic matter (SOM) pool with c. 33 yr turnover (kgC/m2) double cpool_fast; // Running sums (converted to long term means) maintained by SOM dynamics module /// mean annual litter decomposition (kgC/m2/yr) double decomp_litter_mean; /// mean value of decay constant for fast SOM fraction double k_soilfast_mean; /// mean value of decay constant for slow SOM fraction double k_soilslow_mean; // Parameters used by function soiltemp and updated monthly double alag, exp_alag; /// water content of soil layers [0=upper layer] as fraction of available water holding capacity double mwcont[12][NSOILLAYER]; /// daily water content in lower soil layer for each day of year double dwcontlower[Date::MAX_YEAR_LENGTH]; double dwcontlower_today; // ecev3 use a daily value to minimize memory issues /// mean water content in lower soil layer for last month /** (valid only on last day of month following call to daily_accounting_patch) */ // double mwcontlower; // ecev3 - no longer needed /// rainfall and snowmelt today (mm) double rain_melt; /// upper limit for percolation (mm) double max_rain_melt; /// whether to percolate today bool percolate; /// CRESCENDO /// Monthly averaged depth of snow layer (m rainfall equivalents) double msnd[12]; // Snow density (kg m-3), value from Ling and Zhang, 2006 double snowdens; /// C4MIP / CRESCENDO double mcLitter[12]; double mcLitterCwd[12]; double mcLitterSurf[12]; double mcLitterSubSurf[12]; double mcLitterAbove[12]; double mcLitterBelow[12]; double mcSoil[12]; double mcMedium[12]; double mcSlow[12]; double mnLitter[12]; double mnLitterCwd[12]; double mnLitterSurf[12]; double mnLitterSubSurf[12]; double mnSoil[12]; double mnMineralNH4[12]; double mnMineralNO3[12]; double dtsl[366][NSOILLAYER]; double dmrsol[366][NSOILLAYER]; #ifdef CRESCENDO_FACE // CRESCENDO FACE only variables // daily carbon Fine Litter above [kg C m-2] double dcflita[366]; // daily nitrogen litter aboveground [kg N m-2] double dnlit[366]; // daily carbon Fine Litter below [kg C m-2] double dcflitb[366]; // daily nitrogen litter belowground [kg N m-2] double dnrlit[366]; // daily carbon Coarse Litter [kg C m-2] double dcclitb[366]; // daily nitrogen dead wood [kg N m-2] double dndw[366]; // daily carbon Soil [kg C m-2] double dcsoil[366]; // daily nitrogen soil total [kg N m-2] double dnsoil[366]; // daily mineral soil nitrogen [kg N m-2] double dnmineral[366]; #endif ////////////////////////////////////////////////////////////////////////////////// // CENTURY SOM pools and other variables Sompool sompool[NSOMPOOL]; /// daily percolation (mm) double dperc; /// fraction of decayed organic nitrogen leached each day; double orgleachfrac; /// soil mineral nitrogen pool (kgN/m2) double nmass_avail; /// soil nitrogen input (kgN/m2) double ninput; /// annual sum of nitrogen mineralisation double anmin; /// annual sum of nitrogen immobilisation double animmob; /// annual leaching from available nitrogen pool double aminleach; /// annual leaching of organics nitrogen from the active nitrogen pool double aorgNleach; /// total annual nitrogen fixation double anfix; /// calculated annual mean nitrogen fixation double anfix_calc; /// annual leaching of organics carbon from the active carbon pool double aorgCleach; // Variables for fast spinup of SOM pools /// monthly fraction of available mineral nitrogen taken up double fnuptake_mean[12]; /// monthly fraction of organic carbon/nitrogen leached double morgleach_mean[12]; /// monthly fraction of available mineral nitrogen leached double mminleach_mean[12]; /// annual nitrogen fixation double anfix_mean; // Solving Century SOM pools /// years at which to begin documenting for calculation of Century equilibrium int solvesomcent_beginyr; /// years at which to end documentation and start calculation of Century equilibrium int solvesomcent_endyr; /// Cumulative litter pools for one year. LitterSolveSOM litterSolveSOM; std::vector solvesom; /// stored nitrogen deposition in snowpack double snowpack_nmass; // MEMBER FUNCTIONS public: /// constructor (initialises member variable patch) Soil(Patch& p,Soiltype& s):patch(p),soiltype(s) { initdrivers(); } void initdrivers() { // Initialises certain member variables alag = 0.0; exp_alag = 1.0; cpool_slow = 0.0; cpool_fast = 0.0; decomp_litter_mean = 0.0; k_soilfast_mean = 0.0; k_soilslow_mean = 0.0; wcont[0] = 0.0; wcont[1] = 0.0; wcont_evap = 0.0; snowpack = 0.0; orgleachfrac = 0.0; snowdens = 362.0; mwcontupper = 0.0; //mwcontlower = 0.0; for (int mth=0; mth<12; mth++) { mwcont[mth][0] = 0.0; mwcont[mth][1] = 0.0; fnuptake_mean[mth] = 0.0; morgleach_mean[mth] = 0.0; mminleach_mean[mth] = 0.0; msnd[mth] = 0.0; mcLitter[mth] = 0.0; mcLitterCwd[mth] = 0.0; mcLitterSurf[mth] = 0.0; mcLitterSubSurf[mth] = 0.0; mcSoil[mth] = 0.0; mcMedium[mth] = 0.0; mcSlow[mth] = 0.0; mnLitter[mth] = 0.0; mnLitterCwd[mth] = 0.0; mnLitterSurf[mth] = 0.0; mnLitterSubSurf[mth] = 0.0; mnSoil[mth] = 0.0; mnMineralNH4[mth] = 0.0; mnMineralNO3[mth] = 0.0; } std::fill_n(dwcontupper, Date::MAX_YEAR_LENGTH, 0.0); // std::fill_n(dwcontlower, Date::MAX_YEAR_LENGTH, 0.0); // ecev3 dwcontlower_today = 0.0; ///////////////////////////////////////////////////// // Initialise CENTURY pools // Set initial CENTURY pool N:C ratios // Parton et al 1993, Fig 4 sompool[SOILMICRO].ntoc = 1.0 / 15.0; sompool[SURFHUMUS].ntoc = 1.0 / 15.0; sompool[SLOWSOM].ntoc = 1.0 / 20.0; sompool[SURFMICRO].ntoc = 1.0 / 20.0; // passive has a fixed value sompool[PASSIVESOM].ntoc = 1.0 / 9.0; nmass_avail = 0.0; ninput = 0.0; anmin = 0.0; animmob = 0.0; aminleach = 0.0; aorgNleach = 0.0; aorgCleach = 0.0; anfix = 0.0; anfix_calc = 0.0; anfix_mean = 0.0; snowpack_nmass = 0.0; dperc = 0.0; solvesomcent_beginyr = (int)(SOLVESOMCENT_SPINBEGIN * (nyear_spinup - freenyears) + freenyears); solvesomcent_endyr = (int)(SOLVESOMCENT_SPINEND * (nyear_spinup - freenyears) + freenyears); } void serialize(ArchiveStream& arch); }; /// Container for crop-specific data at patchpft level struct cropphen_struct : public Serializable { /// latest sowing date int sdate; /// sowing date of growing period ending in latest harvest this year int sdate_harv; /// sowing dates of growing periods ending in the two latest harvests this year int sdate_harvest[2]; /// sowing dates of growing periods starting this year int sdate_thisyear[2]; /// number of sowings this year int nsow; /// latest harvest date int hdate; /// two latest harvest dates this year int hdate_harvest[2]; /// last date for harvest int hlimitdate; /// last day of heat unit sampling period, set in Crop_sowing_date_new() int hucountend; /// number of harvests this year int nharv; /// whether sdate_harvest[0] happened last year bool sownlastyear; /// latest senescence start date this year int sendate; /// latest beginning of intercropseason (2 weeks after the harvest date) int bicdate; /// latest end of intercropseason (2 weeks before the sowing date) int eicdate; /// number of growing days this growing period int growingdays; /// number of growing days this year (used for wscal_mean calculation) int growingdays_y; /// length of growingseason ending in last harvest int lgp; /// base temp for heat unit calculation (°C) double tb; /// number of vernalising days required int pvd; /// number of accumulated vernalizing days int vdsum; /// heat unit reduction factor due to vernalization [0-1] double vrf; /// heat unit reduction factor due to photoperiodism [0-1] double prf; /// potential heat units required for crop maturity (°Cd) double phu; /// potential heat units that would have been used without dynamic phu calculation double phu_old; /// heat unit sum aquired during last growing period (°Cd) double husum; /// heat unit sum aquired durin sampling period, starting with sdate double husum_sampled; /// this year's heat unit sum aquired from sdate to hucountend double husum_max; /// running mean of recent past's husum_max double husum_max_10; /// number of heat units sampling years int nyears_hu_sample; /// fraction of growing season [0-1] (husum/phu) double fphu; /// fraction of growing season at latest harvest double fphu_harv; /// whether in period of heat unit sampling bool hu_samplingperiod; /// number of heat unit sampling days int hu_samplingdays; /// harvest index today [0-1, >1 if below-ground ho], harvestable organ/above-ground C for above-ground harvestable organs, dependent on fphu, reduced by water stress double hi; /// fraction of harvest index today double fhi; /// phenology (fphu) contribution of fraction of harvest index today double fhi_phen; //Phenology (fPHU) compoment of fhi /// water stress contribution of fraction of harvest index today double fhi_water; /// fraction of harvest index at latest harvest double fhi_harv; /// sum of crop patch demand (patch.wdemand) during crop growing period, reset on harvest day double demandsum_crop; /// sum of crop supply (patchpft.wsupply) during crop growing period, reset on harvest day double supplysum_crop; /// whether inside crop/intercrop grass growing period bool growingseason; /// whether yesterday was inside crop/intercrop grass growing period bool growingseason_ystd; /// whether inside crop senescence bool senescence; /// whether yesterday was inside crop senescence bool senescence_ystd; /// whether inside intercrop crass growing period (main crop pft variable) bool intercropseason; double vdsum_alloc; double vd; /// The fraction of the daily assimilates allocated to roots. double f_alloc_root; /// The fraction of the daily assimilates allocated to leaves. double f_alloc_leaf; /// The fraction of the daily assimilates allocated to harvestable organs, seeds. double f_alloc_horg; /// The fraction of the daily assimilates allocated to stem. double f_alloc_stem; /// Development stage from Wang & Engel 1998 double dev_stage; // A variable holding the memory of whether this field was fertilised or not. bool fertilised[3]; cropphen_struct() { sdate=-1; sdate_harv=-1; nsow=0; sownlastyear=false; sendate=-1; hdate=-1; hlimitdate=-1; hucountend=-1; nharv=0; tb=0.0; pvd=0; vdsum=0; vrf=1.0; phu=0.0; phu_old=0.0; husum_max=0.0; husum_sampled=0.0; husum_max_10=0.0; nyears_hu_sample = 0; prf=1.0; husum=0.0; fphu=0.0; fphu_harv=0.0; hu_samplingdays=0; hu_samplingperiod=false; hi=0.0; fhi=0.0; fhi_phen=0.0; fhi_water=1.0; fhi_harv=0.0; demandsum_crop=0.0; supplysum_crop=0.0; growingseason=false; //Initialized to true for normal grass growth (CC3G & CC4G) in establishment growingseason_ystd=false; senescence=false; senescence_ystd=false; intercropseason=false; bicdate=-1; eicdate=-1; growingdays=0; growingdays_y=0; lgp=0; for(int j=0;j<2;j++) { sdate_harvest[j]=-1; hdate_harvest[j]=-1; sdate_thisyear[j]=-1; } vdsum_alloc=0.0; vd = 0.0; f_alloc_root=0.0; f_alloc_leaf=0.0; f_alloc_horg=0.0; f_alloc_stem=0.0; dev_stage = 0.0; fertilised[0] = false; fertilised[1] = false; fertilised[2] = false; } void serialize(ArchiveStream& arch); }; /// State variables common to all individuals of a particular PFT in a particular patch /** Used in individual and cohort modes only. */ class Patchpft : public Serializable { // MEMBER VARIABLES: public: /// id code (equal to value of member variable id in corresponding Pft object) int id; /// reference to corresponding Pft object in PFT list Pft& pft; /// potential annual net assimilation (leaf-level net photosynthesis) at forest floor (kgC/m2/year) double anetps_ff; /// water stress parameter (0-1 range; 1=minimum stress) double wscal; /// running sum (converted to annual mean) for wscal double wscal_mean; /// potential annual net assimilation at forest floor averaged over establishment interval (kgC/m2/year) double anetps_ff_est; /// first-year value of anetps_ff_est double anetps_ff_est_initial; /// annual mean wscal averaged over establishment interval double wscal_mean_est; /// vegetation phenological state (fraction of potential leaf cover), updated daily double phen; /// annual sum of daily fractional leaf cover /** equivalent number of days with full leaf cover * (reset on expected coldest day of year) */ double aphen; /// whether PFT can establish in this patch under current conditions bool establish; /// running total for number of saplings of this PFT to establish (cohort mode) double nsapling; /// leaf-derived litter for PFT on modelled area basis (kgC/m2) double litter_leaf; /// fine root-derived litter for PFT on modelled area basis (kgC/m2) double litter_root; /// remaining sapwood-derived litter for PFT on modelled area basis (kgC/m2) double litter_sap; /// year's sapwood-derived litter for PFT on modelled area basis (kgC/m2) double litter_sap_year; /// remaining heartwood-derived litter for PFT on modelled area basis (kgC/m2) double litter_heart; /// year's heartwood-derived litter for PFT on modelled area basis (kgC/m2) double litter_heart_year; /// litter derived from allocation to reproduction for PFT on modelled area basis (kgC/m2) double litter_repr; /// leaf-derived nitrogen litter for PFT on modelled area basis (kgN/m2) double nmass_litter_leaf; /// root-derived nitrogen litter for PFT on modelled area basis (kgN/m2) double nmass_litter_root; /// remaining sapwood-derived nitrogen litter for PFT on modelled area basis (kgN/m2) double nmass_litter_sap; /// year's sapwood-derived nitrogen litter for PFT on modelled area basis (kgN/m2) double nmass_litter_sap_year; /// remaining heartwood-derived nitrogen litter for PFT on modelled area basis (kgN/m2) double nmass_litter_heart; /// year's heartwood-derived nitrogen litter for PFT on modelled area basis (kgN/m2) double nmass_litter_heart_year; /// non-FPC-weighted canopy conductance value for PFT under water-stress conditions (mm/s) double gcbase; /// daily value of the above variable (mm/s) double gcbase_day; /// evapotranspirational "supply" function for this PFT today (mm/day) double wsupply; double wsupply_leafon; /// fractional uptake of water from each soil layer today double fwuptake[NSOILLAYER]; /// whether water-stress conditions for this PFT bool wstress; /// daily version of the above variable bool wstress_day; /// carbon depository for long-lived products like wood double harvested_products_slow; /// nitrogen depository for long-lived products like wood double harvested_products_slow_nmass; /// first and last day of crop sowing window, calculated in crop_sowing_patch() or Crop_sowing_date_new() int swindow[2]; /// daily value of water deficit, calculated in irrigated_water_uptake() double water_deficit_d; /// yearly sum of water deficit double water_deficit_y; /// Struct for crop-specific variables cropphen_struct *cropphen; // MEMBER FUNCTIONS: /// Constructor: initialises id, pft and data members Patchpft(int i,Pft& p):id(i),pft(p) { litter_leaf = 0.0; litter_root = 0.0; litter_sap = 0.0; litter_sap_year = 0.0; litter_heart = 0.0; litter_heart_year = 0.0; litter_repr = 0.0; nmass_litter_leaf = 0.0; nmass_litter_root = 0.0; nmass_litter_sap = 0.0; nmass_litter_sap_year = 0.0; nmass_litter_heart = 0.0; nmass_litter_heart_year = 0.0; wscal = 1.0; wscal_mean = 1.0; anetps_ff = 0.0; aphen = 0.0; phen = 0.0; wsupply = 0.0; wsupply_leafon = 0.0; anetps_ff_est = 0.0; anetps_ff_est_initial = 0.0; wscal_mean_est = 0.0; nsapling = 0; for(int i=0;i pft; /// vegetation for this patch Vegetation vegetation; /// soil for this patch Soil soil; /// fluxes for this patch Fluxes fluxes; /// FPAR at top of grass canopy today double fpar_grass; /// FPAR at soil surface today double fpar_ff; /// mean growing season PAR at top of grass canopy (J/m2/day) double par_grass_mean; /// number of days in growing season, estimated from mean vegetation leaf-on fraction /** \see function fpar in canopy exchange module */ int nday_growingseason; /// total patch FPC double fpc_total; /// whether patch was disturbed last year bool disturbed; /// patch age (years since last disturbance) int age; /// probability of fire this year double fireprob; /// whether management has started on this patch bool managed; /// cutting intensity (initial percent of trees cut, further selection at individual level has to be done in a separate function) double man_strength; bool managed_this_year; bool plant_this_year; /// DLE - the number of days over which wcont is averaged for this patch /** i.e. those days for which daily temp > 5.0 degC */ int growingseasondays; // Variables used by new hydrology (Dieter Gerten 2002-07) /// interception by vegetation today on patch basis (mm) double intercep; /// annual sum of AET (mm/year) double aaet; /// annual sum of AET (mm/year) for each of the last five simulation years Historic aaet_5; /// annual sum of soil evaporation (mm/year) double aevap; /// annual sum of interception (mm/year) double aintercep; /// annual sum of runoff (mm/year) double asurfrunoff; /// annual sum of runoff (mm/year) double adrainrunoff; /// annual sum of runoff (mm/year) double abaserunoff; /// annual sum of runoff (mm/year) double arunoff; /// annual sum of potential evapotranspiration (mm/year) double apet; /// equilibrium evapotranspiration today, deducting interception (mm) double eet_net_veg; /// transpirative demand for patch, patch vegetative area basis (mm/day) double wdemand; /// daily average of the above variable (mm/day) double wdemand_day; /// transpirative demand for patch assuming full leaf cover today /** mm/day, patch vegetative area basis */ double wdemand_leafon; /// rescaling factor to account for spatial overlap between individuals/cohorts populations double fpc_rescale; /// monthly AET (mm/month) double maet[12]; /// monthly soil evaporation (mm/month) double mevap[12]; /// monthly interception (mm/month) double mintercep[12]; /// monthly runoff (mm/month) double mrunoff[12]; /// monthly surface runoff (mm/month) double mrunoff_surf[12]; /// monthly PET (mm/month) double mpet[12]; /// daily nitrogen demand double ndemand; /// annual nitrogen fertilization (kgN/m2/year) double anfert; /// daily nitrogen fertilization (kgN/m2/day) double dnfert; /// daily value of irrigation water (mm), set in irrigation(), derived from water_deficit_d double irrigation_d; /// monthly sum of irrigation water (mm) double irrigation_m[12]; /// yearly sum of irrigation water (mm) double irrigation_y; /// whether litter is to be sent to the soil today bool is_litter_day; /// number of harvests and/or cover-crop killing or turnover events int nharv; /// whether today is a harvest day and/or cover-crop killing or turnover day bool isharvestday; // C4MIP / CRESCENDO /// monthly vegetation carbon (kg C m-2) double mcVeg[12]; /// monthly vegetation nitrogen (kg N m-2) double mnVeg[12]; /// monthly leaf carbon (kg C m-2) double mcLeaf[12]; /// monthly leaf nitrogen (kg N m-2) double mnLeaf[12]; /// monthly root carbon (kg C m-2) double mcRoot[12]; /// monthly root nitrogen (kg N m-2) double mnRoot[12]; /// monthly stem carbon (kg C m-2) double mcStem[12]; /// monthly stem nitrogen (kg N m-2) double mnStem[12]; /// monthly other plant parts carbon (kg C m-2) double mcOther[12]; /// monthly other plant parts carbon (Phen) (kg C m-2) double mcOtherPhen[12]; /// monthly other plant parts nitrogen (kg N m-2) double mnOther[12]; /// monthly product carbon (kg C m-2) double mcProduct[12]; /// monthly product nitrogen (kg N m-2) double mnProduct[12]; /// monthly total land carbon (kg C m-2) double mcLand[12]; /// monthly total land nitrogen (kg N m-2) double mnLand[12]; /// daily total LAI (m2 m-2) double dlai[366]; /// daily PET (mm day-1) double dpet[366]; /// daily AET (mm day-1) double daet[366]; /// daily soil evaporation (mm day-1) double devap[366]; /// daily interception by vegetation (mm day-1) double dintercep[366]; /// daily runoff (mm day-1) double dmrro[366]; /// LUMIP deforest_glob: Whether for this patch a deforestation is active bool deforest_active; #ifdef CRESCENDO_FACE /// CRESCENDO FACE only variables /// daily runoff (mm day-1) double drunoff[366]; /// daily drainage (mm day-1) double ddrain[366]; /// daily leaf carbon (kg C m-2) double dcLeaf[366]; /// daily leaf nitrogen (kg N m-2) double dnLeaf[366]; /// daily root carbon (kg C m-2) double dcRoot[366]; /// daily root nitrogen (kg N m-2) double dnRoot[366]; /// daily stem carbon (kg C m-2) double dcStem[366]; /// daily stem nitrogen (kg N m-2) double dnStem[366]; /// daily other plant parts carbon (kg C m-2) double dcOther[366]; /// daily other plant parts nitrogen (kg N m-2) double dnOther[366]; /// Leaf carbon growth (kg C m-2) double gl; /// Wood carbon growth double gw; /// Root carbon growth double gr; #endif // MEMBER FUNCTIONS /// Constructor: initialises various members and builds list array of Patchpft objects. Patch(int i,Stand& s,Soiltype& st); void serialize(ArchiveStream& arch); /// Returns the Climate for this Patch /** This function returns a const reference to prevent code which operates * on a patch basis to modify the climate and thereby affect other * patches/stands. */ const Climate& get_climate() const; /// Returns whether we should model fire in this patch bool has_fires() const; /// Returns whether we should model disturbances in this patch bool has_disturbances() const; /// Total patch carbon biomass and litter double ccont(double scale_indiv = 1.0, bool luc = false); /// Total patch nitrogen biomass and litter double ncont(double scale_indiv = 1.0, bool luc = false); /// Total patch carbon fluxes so far this year double cflux(); /// Total patch nitrogen fluxes so far this year double nflux(); /// Get 5-year mean of wood C mass increase (periodic annual increment) double get_cmass_wood_inc_5() { double cmass_wood_inc_5_mean = 0.0; for (unsigned int i=0; i 10) { if(indiv.cmass_wood_inc_5.size()) cmass_wood_inc_5_mean += indiv.cmass_wood_inc_5.mean(); } } return cmass_wood_inc_5_mean; } /// Get cmass_wood of all individuals in patch double cmass_wood() { double cmass_wood = 0.0; for (unsigned int i=0; i, public Serializable { public: // MEMBER VARIABLES /// list array [0...npft-1] of Standpft (initialised in constructor) ListArray_idin1 pft; /// A number identifying this Stand within the grid cell int id; /// stand type id int stid; /// pft id of main crop, updated during rotation int pftid; /// current crop rotation item int current_rot; /// number of days passed in current rotation item int ndays_inrotation; /// Returns true if stand is in fallow (with cover crop grass) bool infallow; /// Returns true if crop rotation item is to be updated today bool isrotationday; /// Returns true if current crop management hydrology == irrigated, updated during rotation bool isirrigated; /// Returns true if the stand's main crop pft intercrop==naturalgrass and a pft with isintercrop==true is in the pftlist. bool hasgrassintercrop; /// gdd5-value at first intercrop grass growth double gdd0_intercrop; /// old fraction of this stand relative to the gridcell before update double frac_old; /// used during land cover change involving several calls to reveiving_stand_change() /** Set to frac_old in reduce_stands(), then modified in donor_stand_change() and receiving_stand_change(). */ double frac_temp; /// fraction unavailable for transfer to other stand types double protected_frac; /// net stand fraction change double frac_change; /// gross fraction increase double gross_frac_increase; /// gross fraction decrease double gross_frac_decrease; /// fraction that has been cloned from another stand double cloned_fraction; /// Returns true if this stand is cloned from another stand bool cloned; /// pointer to array of fractions transferred from this stand to other stand types double *transfer_area_st; /// land cover origin of this stand landcovertype origin; /// used for output from separate stands double anpp; /// used for output from separate stands double cmass; /// Seed for generating random numbers within this Stand /** The reason why Stand has its own seed, rather than using for instance * a single global seed is to make it easier to compare results when using * different land cover types. * * Randomness not associated with a specific stand, but rather a whole * grid cell should instead use the seed in the Gridcell class. * * \see randfrac() */ long seed; /// type of landcover /** \see landcovertype * initialised in constructor */ landcovertype landcover; /// The year when this stand was created. /** Will typically be year zero unless running with dynamic * land cover. * * Needed to set patchpft.anetps_ff_est_initial */ int first_year; // The year this stand was cloned from another stand int clone_year; /// scaling factor for stands that have grown in area this year (old fraction/new fraction) double scale_LC_change; // ecev3 - NEW MEMBER VARIABLES /// Integer type identifying the IFS high vegetation type (0-20). 0 for low vegetation //int typehigh; /// Fraction of the gridcell covered by the dominant vegetation type //double frachigh; /// grass LAI on stand basis //float laiphen_grass[366]; /// total LAI on stand basis //float laiphen_total[366]; /// total daily natural cflux on stand basis (kg C m-2) float dcfluxnat_today; /// total daily anthropogenic cflux on stand basis (kg C m-2) float dcfluxant_today; /// total daily NPP on stand basis (kg C m-2) float dnpp_today; /// Sum of natural fluxes. Updated on Dec 31 double previousyearsCfluxNat; // was previousyearsCflux /// Sum of anthropogenic fluxes. Updated on Dec 31 float previousyearsCfluxAnt; // was previousyearsCfireflux, now a float since it took the place of dnpp_today /// Total land C pool on 1st of Jan double cLand; /// Total land C flux during the year double cFlux; // MEMBER FUNCTIONS /// Constructs a Stand /** \param i The id for the stand within the grid cell * \param gc The parent grid cell * \param st The soil type to be used within this Stand * \param landcover The type of landcover to use for this stand */ Stand(int i, Gridcell* gc, Soiltype& st, landcovertype landcover, int no_patch = 0); ~Stand(); /// Gives the fraction of this Stand relative to the whole grid cell double get_gridcell_fraction() const; /// Gives the fraction of this Stand relative to its land cover type; NB: unsafe to use within landcover_dynamics() ! double get_landcover_fraction() const; /// Set the fraction of this Stand relative to the gridcell void set_gridcell_fraction(double fraction); /// Returns the number of patches in this Stand unsigned int npatch() const { return nobj; } /// Returns true if stand is true crop stand, as opposed to pasture grass grown on cropland or other land cover inline bool is_true_crop_stand() { return landcover==CROPLAND && pft[pftid].pft.phenology==CROPGREEN; // OK also for fallow (pftid always cropgreen) } /// Moves crop rotation forward void rotate(); /// Returns area transferred to other land cover during land cover change double transfer_area_lc(landcovertype to); /// Initiates new stand land cover settings void init_stand_lu(StandType& st, double fraction); /// Total stand carbon biomass and litter double ccont(double scale_indiv = 1.0); /// Total stand nitrogen biomass and litter double ncont(double scale_indiv = 1.0); /// Total stand carbon fluxes so far this year double cflux(); /// Total stand nitrogen fluxes so far this year double nflux(); /// Creates a duplicate stand with a new landcovertype /** The new stand is added to this stand's gridcell. * * \returns reference to the new stand */ Stand& clone(StandType& st, double fraction); void serialize(ArchiveStream& arch); /// Returns the Climate for this Stand /** This function returns a const reference to prevent code which operates * on a stand basis to modify the climate and thereby affect other * stands. */ const Climate& get_climate() const; /// Returns the Gridcell containing this Stand Gridcell& get_gridcell() const; private: /// Pointer to parent object, could be a null pointer /** Prefer to access the gridcell through get_gridcell(), even internally * within the Stand class. */ Gridcell* gridcell; /// Soil type to be used in this Stand Soiltype& soiltype; /// Fraction of this stand relative to the gridcell /** used by crop stands; initialized in constructor to 1, * set in landcover_init() */ double frac; }; /// State variables common to all individuals of a particular PFT in a GRIDCELL. class Gridcellpft : public Serializable { public: // MEMBER VARIABLES /// A number identifying this object within its list array int id; /// A reference to the Pft object for this Gridcellpft Pft& pft; /// annual degree day sum above threshold damaging temperature /** used in calculation of heat stess mortality; Sitch et al 2000, Eqn 55 */ double addtw; /// Michaelis-Menten kinetic parameters /** Half saturation concentration for N uptake (Rothstein 2000, Macduff 2002) */ double Km; ///Crop-specific variables: /// whether the daily temperature has fallen below the autumn temperature limit (tempautumn) this year bool autumnoccurred; /// whether the daily temperature has risen above the spring temperature limit (tempspring) this year bool springoccurred; /// whether the daily temperature has fallen below the vernalization limit (trg) this year bool vernstartoccurred; /// whether the daily temperature rises over the vernalization limit (trg) this year bool vernendoccurred; /// first day when temperature fell below the autumn temperature limit (tempautumn) this year int first_autumndate; /// 20-year mean int first_autumndate20; /// memory of the last 20 years' values int first_autumndate_20[20]; /// last day when temperature rose above the spring temperature limit (tempspring) this year int last_springdate; /// 20-year mean int last_springdate20; /// memory of the last 20 years' values int last_springdate_20[20]; /// last day when temperature has fallen below the vernilisation temperature limit (trg) this year (if vernstartoccurred==true) int last_verndate; /// 20-year mean int last_verndate20; /// memory of the last 20 years' values int last_verndate_20[20]; /// default sowing date (pft.sdatenh/sdatesh) int sdate_default; /// calculated sowing date from temperature limits int sdatecalc_temp; /// calculated sowing date from precipitation limits int sdatecalc_prec; /// sowing date from input file int sdate_force; /// harvest date from input file int hdate_force; /// N fertilization from input file double Nfert_read; /// default harvest date (pft.hlimitdatenh/hlimitdatesh) int hlimitdate_default; /// whether autumn sowing is either calculated or prescribed bool wintertype; /// first and last day of crop sowing window, calculated in calc_sowing_windows() int swindow[2]; /// first and last day of crop sowing window for irrigated crops, calculated in calc_sowing_windows() int swindow_irr[2]; /// temperature limits precludes crop sowing bool sowing_restriction; // MEMBER FUNCTIONS /// Constructs a Gridcellpft object /** \param i The id for this object * \param p A reference to the Pft for this Gridcellpft */ Gridcellpft(int i,Pft& p):id(i),pft(p) { addtw = 0.0; Km = 0.0; autumnoccurred=false; springoccurred=false; vernstartoccurred=false; vernendoccurred=false; first_autumndate=-1; first_autumndate20=-1; last_springdate=-1; last_springdate20=-1; last_verndate=-1; last_verndate20=-1; for (int year=0;year<20;year++) { first_autumndate_20[year]=-1; last_springdate_20[year]=-1; last_verndate_20[year]=-1; } sdate_default=-1; sdate_force=-1; hdate_force=-1; Nfert_read=-1; sdatecalc_temp=-1; sdatecalc_prec=-1; hlimitdate_default=-1; wintertype=false; swindow[0]=-1; swindow[1]=-1; sowing_restriction = false; } void serialize(ArchiveStream& arch); }; /// State variables common to all individuals of a particular STANDTYPE in a GRIDCELL. class Gridcellst : public Serializable { public: // MEMBER VARIABLES /// A number identifying this object within its list array int id; /// A reference to the StandType object for this Gridcellst StandType& st; /// fraction of this stand type relative to the gridcell double frac; /// old fraction of this stand type relative to the gridcell before update double frac_old; /// original input value of old fraction of this stand type before rescaling double frac_old_orig; /// fraction unavailable for transfer to other stand types double protected_frac; /// net fraction change double frac_change; /// gross fraction increase double gross_frac_increase; /// gross fraction decrease double gross_frac_decrease; // current number of stands of this stand type int nstands; /// Nitrogen fertilisation amount double nfert; /// Harvested forest area fraction double woodharv_frac; /// Wood harvest volume double woodharv_vol; // MEMBER FUNCTIONS /// Constructs a Gridcellst object /** \param i The id for this object * \param s A reference to the StandType for this Gridcellst */ Gridcellst(int i,StandType& s):id(i),st(s) { frac = 1.0; frac_old = 0.0; frac_old_orig = 0.0; protected_frac = 0.0; frac_change = 0.0; gross_frac_increase = 0.0; gross_frac_decrease = 0.0; nstands = 0; nfert = -1.0; woodharv_frac = -1.0; woodharv_vol = -1.0; } void serialize(ArchiveStream& arch); }; struct forest_lc_frac_transfer { double primary[NLANDCOVERTYPES][NLANDCOVERTYPES]; double secondary_young[NLANDCOVERTYPES][NLANDCOVERTYPES]; forest_lc_frac_transfer() { for(int i=0;i, public Serializable { public: // MEMBER VARIABLES /// climate, insolation and CO2 for this grid cell Climate climate; /// soil static parameters for this grid cell Soiltype soiltype; /// landcover fractions and landcover-specific variables Landcover landcover; /// Total gridcell C mass on first day of each month including accumulated NPP [kg C m-2] double mcLand1[12]; /// Total gridcell C mass on Jan 1 including yearly fluxes happening on Dec 31 previous year [kg C m-2] double cLand; /// Total gridcell C flux (including organic C leaching) over current year but with previous years Dec 31 yearly fluxes [kg C m-2] double cFlux; /// Previous years Dec 31 yearly natural fluxes [kg C m-2] double previousyearsCfluxNat; // was previousyearsCflux /// Previous years Dec 31 yearly anthropogenic fluxes [kg C m-2] double previousyearsCfluxAnt; // was previousyearsCfireflux // ecev3 - For coupling to IFS - MUST be serialized!!!! int id; int ifs_index; int IFStypehigh; // 0 to 20 double IFSfrachigh; // 0 to 1 int IFStypelow; // 0 to 20 double IFSfraclow; // 0 to 1. Note: IFSfrachigh + IFSfraclow <= 1 bool transferhightolow; int simulationyear; // 0 to nyear_spinup during spinup, then date.year bool isspinup; int ndep_lon_index, ndep_lat_index; // For CMIP6 N dep data int ndep_index; // For conservatively remapped CMIP6 N dep data double mdrynhx[12], mwetnhx[12], mdrynoy[12], mwetnoy[12], mndrydep[12], mnwetdep[12]; // ecev3 - the following do not need to be serialized double laiphen_high_today; // updated daily double laiphen_low_today; // updated daily double landcover_fpc[NLANDCOVERTYPES]; // updated on Dec 31 double landcover_lai[NLANDCOVERTYPES]; // updated on Dec 31 double naturaltreeFPC; // (0-1) - NATURAL stand, calculated on Dec 31 double naturalgrassFPC; // (0-1) - NATURAL stand, calculated on Dec 31 int fixedLUafter; // Year from which on Land Use is frozen // ecev3 - inputs from IFS to be output for checking double ifs_co2[366]; double ifs_par[366]; double ifs_lw[366]; double ifs_precip[366]; double ifs_temp2m[366]; double ifs_tempsoil[366]; double ifs_soilw_surf[366]; double ifs_soilw_deep[366]; /// average gridcell soil column wcont for this year for each of the last five simulation years Historic awcont_5; Date date; // allow each gridcell to keep track of its own date /// Nitrogen deposition forcing for current gridcell Lamarque::NDepData ndepts; /// list array [0...npft-1] of Gridcellpft (initialised in constructor) ListArray_idin1 pft; /// list array [0...nst-1] of Gridcellst (initialised in constructor) ListArray_idin1 st; /// object for keeping track of carbon and nitrogen balance MassBalance balance; /// Seed for generating random numbers within this Gridcell /** The reason why Gridcell has its own seed, rather than using for instance * a single global seed is to make it easier to compare results when for * instance changing the order in which the simulation proceeds. It also * gets serialized together with the rest of the Gridcell state to make it * possible to get exactly identical results after a restart. * * \see randfrac() */ long seed; // MEMBER FUNCTIONS /// Constructs a Gridcell object Gridcell(); /// Longitude for this grid cell double get_lon() const; /// Latitude for this grid cell double get_lat() const; /// Set longitude and latitude for this grid cell void set_coordinates(double longitude, double latitude); /// Get nitrogen deposition data for this point bool getndep(const char* ndepfile, double rcp); /// Get historical CMIP6 nitrogen deposition data for this point bool getndepCMIP6(const char* ndepfile, int fixedNDepafter); /// Get simulation year int getsimulationyear(int year); void serialize(ArchiveStream& arch); /// Creates a new Stand in this grid cell Stand& create_stand(landcovertype lc, int no_patch = 0); /// Creates new stand and initiates land cover settings when run_landcover==true Stand& create_stand_lu(StandType& st, double fraction, int no_patch = 0); /// Total gridcell carbon biomass and litter double ccont(); /// Total gridcell nitrogen biomass and litter double ncont(); /// Total gridcell carbon fluxes so far this year double cflux(); /// Total gridcell nitrogen fluxes so far this year double nflux(); /// Deletes the stand which the iterator is pointing at /** Returns an iterator pointing to the object following the erased object. */ iterator delete_stand(iterator itr); /// Returns number of stands unsigned int nbr_stands() const; // ecev3 - set first year void set_first_year(int fy); private: /// Longitude for this grid cell double lon; /// Latitude for this grid cell double lat; }; #endif // LPJ_GUESS_GUESS_H /////////////////////////////////////////////////////////////////////////////////////// // REFERENCES // // LPJF refers to the original FORTRAN implementation of LPJ as described by Sitch // et al 2000 // Delmas, R., Lacaux, J.P., Menaut, J.C., Abbadie, L., Le Roux, X., Helaa, G., Lobert, J., 1995. // Nitrogen compound emission from biomass burning in tropical African Savanna FOS/DECAFE 1991 // experiment. Journal of Atmospheric Chemistry 22, 175-193. // Cosby, B. J., Hornberger, C. M., Clapp, R. B., & Ginn, T. R. 1984 A statistical // exploration of the relationships of soil moisture characteristic to the // physical properties of soil. // Water Resources Research, 20: 682-690. // Franzlubbers, AJ & Stuedemann, JA 2009 Soil-profile organic carbon and total // nitrogen during 12 years of pasture management in the Southern Piedmont USA. // Agriculture Ecosystems & Environment, 129, 28-36. // Friend, A. D., Stevens, A. K., Knox, R. G. & Cannell, M. G. R. 1997. A // process-based, terrestrial biosphere model of ecosystem dynamics // (Hybrid v3.0). Ecological Modelling, 95, 249-287. // Fulton, MR 1991 Adult recruitment rate as a function of juvenile growth in size- // structured plant populations. Oikos 61: 102-105. // Haxeltine A & Prentice IC 1996 BIOME3: an equilibrium terrestrial biosphere // model based on ecophysiological constraints, resource availability, and // competition among plant functional types. Global Biogeochemical Cycles 10: // 693-709 // Lloyd, J & Taylor JA 1994 On the temperature dependence of soil respiration // Functional Ecology 8: 315-323 // Macduff, JH, Humphreys, MO & Thomas, H 2002. Effects of a stay-green mutation on // plant nitrogen relations in Lolium perenne during N starvation and after // defoliation. Annals of Botany, 89, 11-21. // Monsi M & Saeki T 1953 Ueber den Lichtfaktor in den Pflanzengesellschaften und // seine Bedeutung fuer die Stoffproduktion. Japanese Journal of Botany 14: 22-52 // Olin S., G. Schurgers, M. Lindeskog, D. Wårlind, B. Smith, P. Bodin, J. // Holmér, and A. Arneth. 2015 Biogeosciences Discuss., 12, 1047-1111. The // impact of atmospheric CO2 and N management on yields and tissue C:N in // the main wheat regions of Western Europe // Parton, W. J., Hanson, P. J., Swanston, C., Torn, M., Trumbore, S. E., Riley, W. // & Kelly, R. 2010. ForCent model development and testing using the Enriched // Background Isotope Study experiment. Journal of Geophysical // Research-Biogeosciences, 115. // Prentice, IC, Sykes, MT & Cramer W 1993 A simulation model for the transient // effects of climate change on forest landscapes. Ecological Modelling 65: 51-70. // Reich, PB, Walters MB & Ellsworth DS 1992 Leaf Life-Span in Relation to Leaf, // Plant, and Stand Characteristics among Diverse Ecosystems. // Ecological Monographs 62: 365-392. // Sitch, S, Prentice IC, Smith, B & Other LPJ Consortium Members (2000) LPJ - a // coupled model of vegetation dynamics and the terrestrial carbon cycle. In: // Sitch, S. The Role of Vegetation Dynamics in the Control of Atmospheric CO2 // Content, PhD Thesis, Lund University, Lund, Sweden. // Sykes, MT, Prentice IC & Cramer W 1996 A bioclimatic model for the potential // distributions of north European tree species under present and future climates. // Journal of Biogeography 23: 209-233. // Wang, E, Engel, T, 1998 Simulation of phenological development of wheat crops // Agricultural Systems 58:1-24 // White, M A, Thornton, P E, Running, S. & Nemani, R 2000 Parameterization and // Sensitivity Analysis of the BIOME-BGC Terrestrial Ecosystem Model: Net Primary // Production Controls. Earth Interactions, 4, 1-55.