driver.cpp 53 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489
  1. ///////////////////////////////////////////////////////////////////////////////////////
  2. /// \file driver.cpp
  3. /// \brief Environmental driver calculation/transformation
  4. ///
  5. /// \author Ben Smith
  6. /// $Date: 2014-05-14 12:43:55 +0200 (Wed, 14 May 2014) $
  7. ///
  8. ///////////////////////////////////////////////////////////////////////////////////////
  9. // WHAT SHOULD THIS FILE CONTAIN?
  10. // Module source code files should contain, in this order:
  11. // (1) a "#include" directive naming the framework header file. The framework header
  12. // file should define all classes used as arguments to functions in the present
  13. // module. It may also include declarations of global functions, constants and
  14. // types, accessible throughout the model code;
  15. // (2) other #includes, including header files for other modules accessed by the
  16. // present one;
  17. // (3) type definitions, constants and file scope global variables for use within
  18. // the present module only;
  19. // (4) declarations of functions defined in this file, if needed;
  20. // (5) definitions of all functions. Functions that are to be accessible to other
  21. // modules or to the calling framework should be declared in the module header
  22. // file.
  23. //
  24. // PORTING MODULES BETWEEN FRAMEWORKS:
  25. // Modules should be structured so as to be fully portable between models (frameworks).
  26. // When porting between frameworks, the only change required should normally be in the
  27. // "#include" directive referring to the framework header file.
  28. #include "config.h"
  29. #include "driver.h"
  30. /// Function for generating random numbers
  31. /** Returns a random floating-point number in the range 0-1.
  32. * Uses and updates the parameter 'seed' which may be initialised to any
  33. * positive integral value (the same initial value will result in the same sequence
  34. * of returned values on subsequent calls to randfrac every time the program is
  35. * run)
  36. */
  37. double randfrac(long& seed) {
  38. // Reference: Park & Miller 1988 CACM 31: 1192
  39. const long modulus = 2147483647;
  40. const double fmodulus = modulus;
  41. const long multiplier = 16807;
  42. const long q = 127773;
  43. const long r = 2836;
  44. seed = multiplier * (seed % q) - r * seed / q;
  45. if (!seed) seed++; // increment seed to 1 in unlikely event of 0 value
  46. else if (seed < 0) seed += modulus;
  47. return (double)seed / fmodulus;
  48. }
  49. ///////////////////////////////////////////////////////////////////////////////////////
  50. // SOILPARAMETERS
  51. // May be called from input/output module to initialise stand Soiltype objects when
  52. // soil data supplied as LPJ soil code rather than soil physical parameter values
  53. void soilparameters(Soiltype& soiltype, int soilcode) {
  54. // DESCRIPTION
  55. // Derivation of soil physical parameters given LPJ soil code
  56. // INPUT AND OUTPUT PARAMETER
  57. // soil = patch soil
  58. const double PERC_EXP = 2.0;
  59. // exponent in percolation equation [k2; LPJF]
  60. // (Eqn 31, Haxeltine & Prentice 1996)
  61. // Changed from 4 to 2 (Sitch, Thonicke, pers comm 26/11/01)
  62. double data[9][9] = {
  63. // 0 empirical parameter in percolation equation (k1) (mm/day)
  64. // 1 volumetric water holding capacity at field capacity minus vol water
  65. // holding capacity at wilting point (Hmax), as fraction of soil layer
  66. // depth
  67. // 2 thermal diffusivity (mm2/s) at wilting point (0% WHC)
  68. // 3 thermal diffusivity (mm2/s) at 15% WHC
  69. // 4 thermal diffusivity at field capacity (100% WHC)
  70. // Thermal diffusivities follow van Duin (1963),
  71. // Jury et al (1991), Fig 5.11.
  72. // 5 wilting point as fraction of depth (calculation method described in
  73. // Prentice et al 1992)
  74. // 6 saturation capacity following Cosby (1984)
  75. // 7 sand fraction
  76. // 8 clay fraction
  77. // 0 1 2 3 4 5 6 7 8 soilcode
  78. // ------------------------------------------------------------------
  79. { 5.0, 0.110, 0.2, 0.800, 0.4, 0.074, 0.395, 0.90, 0.05}, // 1 Coarse
  80. { 4.0, 0.150, 0.2, 0.650, 0.4, 0.184, 0.439, 0.35, 0.15}, // 2 Medium
  81. { 3.0, 0.120, 0.2, 0.500, 0.4, 0.274, 0.454, 0.30, 0.45}, // 3 Fine
  82. { 4.5, 0.130, 0.2, 0.725, 0.4, 0.129, 0.417, 0.60, 0.15}, // 4 Medium-coarse
  83. { 4.0, 0.115, 0.2, 0.650, 0.4, 0.174, 0.425, 0.60, 0.30}, // 5 Fine-coarse
  84. { 3.5, 0.135, 0.2, 0.575, 0.4, 0.229, 0.447, 0.20, 0.30}, // 6 Fine-medium
  85. { 4.0, 0.127, 0.2, 0.650, 0.4, 0.177, 0.430, 0.45, 0.25}, // 7 Fine-medium-coarse
  86. { 9.0, 0.300, 0.1, 0.100, 0.1, 0.200, 0.600, 0.28, 0.12}, // 8 Organic (values not know for wp), sand and clay are from Parton 2010
  87. { 0.2, 0.100, 0.2, 0.500, 0.4, 0.100, 0.250, 0.10, 0.80} // 9 Vertisols (values not know for wp)
  88. };
  89. if (soilcode<1 || soilcode>9)
  90. fail("soilparameters: invalid LPJ soil code (%d)",soilcode);
  91. if (textured_soil) {
  92. soiltype.sand_frac = data[soilcode-1][7];
  93. soiltype.clay_frac = data[soilcode-1][8];
  94. } else {
  95. // Using fixed values from Parton et al. (2010)
  96. soiltype.sand_frac = 0.28;
  97. soiltype.clay_frac = 0.12;
  98. }
  99. soiltype.silt_frac = 1 - soiltype.sand_frac - soiltype.clay_frac;
  100. soiltype.perc_base = data[soilcode-1][0];
  101. soiltype.perc_exp = PERC_EXP;
  102. soiltype.awc[0] = SOILDEPTH_UPPER * data[soilcode-1][1];
  103. soiltype.awc[1] = SOILDEPTH_LOWER * data[soilcode-1][1];
  104. soiltype.thermdiff_0 = data[soilcode-1][2];
  105. soiltype.thermdiff_15 = data[soilcode-1][3];
  106. soiltype.thermdiff_100 = data[soilcode-1][4];
  107. soiltype.wp[0] = SOILDEPTH_UPPER * data[soilcode-1][5];
  108. soiltype.wp[1] = SOILDEPTH_LOWER * data[soilcode-1][5];
  109. soiltype.wsats[0] = SOILDEPTH_UPPER * data[soilcode-1][6];
  110. soiltype.wsats[1] = SOILDEPTH_LOWER * data[soilcode-1][6];
  111. soiltype.wtot = (data[soilcode-1][1] + data[soilcode-1][5]) * (SOILDEPTH_UPPER + SOILDEPTH_LOWER);
  112. if (!ifcentury) {
  113. // override the default SOM years with 70-80% of the spin-up period
  114. soiltype.updateSolveSOMvalues(nyear_spinup);
  115. }
  116. }
  117. // Version for use in coupled EC-Earth runs.
  118. void ifssoilparameters(Soiltype& soiltype, int soilcode) {
  119. // DESCRIPTION
  120. // Derivation of soil physical parameters given H-TESSEL soil code
  121. // INPUT AND OUTPUT PARAMETER
  122. // soil = patch soil
  123. const double PERC_EXP = 2.0;
  124. // exponent in percolation equation [k2; LPJF]
  125. // (Eqn 31, Haxeltine & Prentice 1996)
  126. // Changed from 4 to 2 (Sitch, Thonicke, pers comm 26/11/01)
  127. // ecev3
  128. /*
  129. H-TESSEL has 7 soil types (standard LPJG has 9).
  130. Columns 1, 7 and 8 (base 0) calculated fron the van Genuchten equations, a la Balsamo et al.
  131. but with a PWP of -4.5 bar.
  132. Values in columns 1 (k1), and 2-4 were mapped from the standard LPJ-GUESS textures
  133. (see soilparameters) as follows:
  134. H-TESSEL Texture LPJ-GUESS Texture (Sitch et al. 2003 - Table 4)
  135. ---------------- -----------------------------------------------
  136. Coarse Coarse
  137. Medium Medium
  138. Medium Fine Fine-medium-coarse
  139. Fine Fine-medium
  140. Very fine Fine, nonvertisol
  141. Organic Organic
  142. Tropical Organic Organic
  143. */
  144. double data[7][12] = {
  145. // 0 empirical parameter in percolation equation (k1) (mm/day)
  146. // 1 volumetric water holding capacity at field capacity minus vol water
  147. // holding capacity at wilting point (Hmax), as fraction of soil layer
  148. // depth
  149. // 2 thermal diffusivity (mm2/s) at wilting point (0% WHC)
  150. // 3 thermal diffusivity (mm2/s) at 15% WHC
  151. // 4 thermal diffusivity at field capacity (100% WHC)
  152. // Thermal diffusivities follow van Duin (1963),
  153. // Jury et al (1991), Fig 5.11.
  154. // 5 wilting point as fraction of depth (calculation method described in
  155. // Prentice et al 1992)
  156. // 6 saturation capacity following Cosby (1984)
  157. // 7 sand fraction
  158. // 8 clay fraction
  159. // 9 volumetric water holding capacity at wilting point - Balsamo et al.
  160. // 10 volumetric water holding capacity at field capacity - Balsamo et al
  161. // 11 volumetric water holding capacity at saturation - Balsamo et al
  162. // 0 1 2 3 4 5 6 7 8 9 10 11 // H-TESSEL soilcode, type
  163. // ------------------------------------------------------------------------------------------
  164. { 5.0, 0.163, 0.2, 0.800, 0.4, 0.079, 0.242, 0.90, 0.05, 0.059, 0.244, 0.403}, // 1, Coarse
  165. { 4.0, 0.154, 0.2, 0.650, 0.4, 0.176, 0.346, 0.35, 0.15, 0.151, 0.347, 0.439}, // 2, Medium
  166. { 4.0, 0.205, 0.2, 0.500, 0.4, 0.177, 0.382, 0.45, 0.25, 0.133, 0.383, 0.430}, // 3, Medium Fine
  167. { 3.5, 0.134, 0.2, 0.725, 0.4, 0.314, 0.448, 0.20, 0.30, 0.279, 0.448, 0.520}, // 4, Fine
  168. { 3.0, 0.162, 0.2, 0.650, 0.4, 0.379, 0.541, 0.30, 0.45, 0.335, 0.541, 0.614}, // 5, Very fine
  169. { 9.0, 0.322, 0.1, 0.100, 0.1, 0.340, 0.662, 0.28, 0.12, 0.267, 0.663, 0.766}, // 6, Organic
  170. { 9.0, 0.322, 0.1, 0.100, 0.1, 0.340, 0.662, 0.28, 0.12, 0.267, 0.663, 0.766}, // 7, Tropical Organic
  171. };
  172. if (soilcode<1 || soilcode>7)
  173. fail("ifssoilparameters: invalid H-TESSEL soil code (%d)",soilcode);
  174. if (textured_soil) {
  175. soiltype.sand_frac = data[soilcode-1][7];
  176. soiltype.clay_frac = data[soilcode-1][8];
  177. } else {
  178. // Using fixed values from Parton et al. (2010)
  179. soiltype.sand_frac = 0.28;
  180. soiltype.clay_frac = 0.12;
  181. }
  182. soiltype.silt_frac = 1 - soiltype.sand_frac - soiltype.clay_frac;
  183. soiltype.perc_base = data[soilcode-1][0];
  184. soiltype.perc_exp = PERC_EXP;
  185. soiltype.awc[0] = SOILDEPTH_UPPER * (data[soilcode-1][10] - data[soilcode-1][9]);
  186. soiltype.awc[1] = SOILDEPTH_LOWER * (data[soilcode-1][10] - data[soilcode-1][9]);
  187. soiltype.thermdiff_0 = data[soilcode-1][2];
  188. soiltype.thermdiff_15 = data[soilcode-1][3];
  189. soiltype.thermdiff_100 = data[soilcode-1][4];
  190. soiltype.wp[0] = SOILDEPTH_UPPER * data[soilcode - 1][9];
  191. soiltype.wp[1] = SOILDEPTH_LOWER * data[soilcode - 1][9];
  192. soiltype.wsats[0] = SOILDEPTH_UPPER * data[soilcode - 1][10]; // should be 11, but to be consistent with former FC to SAT
  193. soiltype.wsats[1] = SOILDEPTH_LOWER * data[soilcode - 1][10]; // ratio IFS FC is used as SAT
  194. soiltype.wtot = data[soilcode-1][10] * (SOILDEPTH_UPPER + SOILDEPTH_LOWER);
  195. // ecev3
  196. soiltype.wilt_point = data[soilcode-1][9];
  197. soiltype.field_cap = data[soilcode-1][10];
  198. soiltype.whcap = soiltype.field_cap - soiltype.wilt_point;
  199. if (!ifcentury) {
  200. // override the default SOM years with 70-80% of the spin-up period
  201. soiltype.updateSolveSOMvalues(nyear_spinup);
  202. }
  203. }
  204. /// Climate interpolation from monthly means to quasi-daily values
  205. /** May be called from input/output module to generate daily climate values when
  206. * raw data are on monthly basis.
  207. *
  208. * \param mvals The monthly means
  209. * \param dvals The generated daily values
  210. */
  211. void interp_monthly_means(double mvals[12], double dvals[365]) {
  212. Date date; // Date object used for interpolation (local to this function)
  213. double nday, dayct;
  214. int thismonth, lastmonth;
  215. date.init(1);
  216. nday = (double)(date.middaymonth[0] - (date.middaymonth[11] - 365));
  217. thismonth = 0;
  218. lastmonth = 11;
  219. dayct = (double)(366 - date.middaymonth[11]);
  220. // Perform interpolation
  221. while (date.year == 0) {
  222. if (date.day == date.middaymonth[date.month]) {
  223. if (date.month == 11) // December
  224. nday = (double)(date.middaymonth[0] + 365 - date.middaymonth[11]);
  225. else
  226. nday = (double)(date.middaymonth[date.nextmonth()] -
  227. date.middaymonth[date.month]);
  228. thismonth = date.nextmonth();
  229. lastmonth = date.month;
  230. dayct = 0.0;
  231. }
  232. dvals[date.day] = (mvals[thismonth]-mvals[lastmonth]) / nday * dayct +
  233. mvals[lastmonth];
  234. date.next();
  235. dayct++;
  236. }
  237. }
  238. /// Climate interpolation from monthly totals to quasi-daily values
  239. /** May be called from input/output module to generate daily climate values when
  240. * raw data are on monthly basis.
  241. *
  242. * \param mvals The monthly totals
  243. * \param dvals The generated daily values
  244. */
  245. void interp_monthly_totals(double mvals[12], double dvals[365]) {
  246. // Local date object just used to get number of days for each month
  247. Date date;
  248. // Convert monthly totals to mean daily values
  249. double mvals_daily[12];
  250. for (int m=0; m<12; m++)
  251. mvals_daily[m] = mvals[m] / (double)date.ndaymonth[m];
  252. interp_monthly_means(mvals_daily, dvals);
  253. }
  254. /// Generates quasi-daily values for a single month, based on monthly means
  255. /**
  256. * The generated daily values will conserve the monthly mean.
  257. *
  258. * The daily values are generated by first choosing values for the beginning,
  259. * middle and end of the month, and interpolating linearly between them.
  260. * The end points will be chosen by taking the surrounding months into
  261. * account, and the mid point is then chosen so that we conserve the mean.
  262. *
  263. * Could be used for other interpolations than only monthly to daily,
  264. * but comments assume monthly to daily to avoid being too abstract.
  265. *
  266. * \param preceding_mean Mean value for preceding month
  267. * \param this_mean Mean value for the current month
  268. * \param succeeding_mean Mean value for the succeeding month
  269. * \param time_steps Number of days in the current month
  270. * \param result The generated daily values
  271. * (array expected to hold at least time_steps values)
  272. *
  273. */
  274. void interp_single_month(double preceding_mean,
  275. double this_mean,
  276. double succeeding_mean,
  277. int time_steps,
  278. double* result,
  279. double minimum = -std::numeric_limits<double>::max(),
  280. double maximum = std::numeric_limits<double>::max()) {
  281. // The values for the beginning and the end of the month are determined
  282. // from the average of the two adjacent monthly means
  283. const double first_value = mean(this_mean, preceding_mean);
  284. const double last_value = mean(this_mean, succeeding_mean);
  285. // The mid-point value is computed as offset from the mean, so that the
  286. // average deviation from the mean of first_value and last_value
  287. // is compensated for.
  288. // E.g., if the two values at beginning and end of the month are on average
  289. // 2 degrees cooler than the monthly mean, the mid-monthly value is
  290. // determined as monthly mean + 2 degrees, so that the monthly mean is
  291. // conserved.
  292. const double average_deviation =
  293. mean(first_value-this_mean, last_value-this_mean);
  294. const double middle_value = this_mean-average_deviation;
  295. const double half_time = time_steps/2.0;
  296. const double first_slope = (middle_value-first_value)/half_time;
  297. const double second_slope = (last_value-middle_value)/half_time;
  298. double sum = 0;
  299. int i = 0;
  300. // Interpolate the first half
  301. for (; i < time_steps/2; ++i) {
  302. double current_time = i+0.5; // middle of day i
  303. result[i] = first_value + first_slope*current_time;
  304. sum += result[i];
  305. }
  306. // Special case for dealing with the middle day if time_steps is odd
  307. if (time_steps%2 == 1) {
  308. // In this case we can't use the value corresponding to the middle
  309. // of the day. We'll simply skip it and calculate it based on
  310. // whatever the other days sum up to.
  311. ++i;
  312. }
  313. // Interpolate the other half
  314. for (; i < time_steps; ++i) {
  315. double current_time = i+0.5; // middle of day i
  316. result[i] = middle_value + second_slope*(current_time-half_time);
  317. sum += result[i];
  318. }
  319. if (time_steps%2 == 1) {
  320. // Go back and set the middle value to whatever is needed to
  321. // conserve the mean
  322. result[time_steps/2] = time_steps*this_mean-sum;
  323. }
  324. // Go through all values and make sure they're all above the minimum
  325. double added = 0;
  326. double sum_above = 0;
  327. for (int i = 0; i < time_steps; ++i) {
  328. if (result[i] < minimum) {
  329. added += minimum - result[i];
  330. result[i] = minimum;
  331. }
  332. else {
  333. sum_above += result[i] - minimum;
  334. }
  335. }
  336. double fraction_to_remove = sum_above > 0 ? added / sum_above : 0;
  337. for (int i = 0; i < time_steps; ++i) {
  338. if (result[i] > minimum) {
  339. result[i] -= fraction_to_remove * (result[i] - minimum);
  340. // Needed (only) due to limited precision in floating point arithmetic
  341. result[i] = max(result[i], minimum);
  342. }
  343. }
  344. // Go through all values and make sure they're all below the maximum
  345. double removed = 0;
  346. double sum_below = 0;
  347. for (int i = 0; i < time_steps; ++i) {
  348. if (result[i] > maximum) {
  349. removed += result[i] - maximum;
  350. result[i] = maximum;
  351. }
  352. else {
  353. sum_below += maximum - result[i];
  354. }
  355. }
  356. double fraction_to_add = sum_below > 0 ? removed / sum_below : 0;
  357. for (int i = 0; i < time_steps; ++i) {
  358. if (result[i] < maximum) {
  359. result[i] += fraction_to_add * (maximum - result[i]);
  360. // Needed (only) due to limited precision in floating point arithmetic
  361. result[i] = min(result[i], maximum);
  362. }
  363. }
  364. }
  365. /// Climate interpolation from monthly means to quasi-daily values
  366. /** May be called from input/output module to generate daily climate values when
  367. * raw data are on monthly basis.
  368. *
  369. * The generated daily values will have the same monthly means as the input.
  370. *
  371. * \param mvals The monthly means
  372. * \param dvals The generated daily values
  373. */
  374. void interp_monthly_means_conserve(const double* mvals, double* dvals,
  375. bool isleapyear, double minimum, double maximum) {
  376. Date date;
  377. int start_of_month = 0;
  378. if (isleapyear && ECEARTHWITHCRUNCEP) date.ndaymonth[1] = 29;
  379. for (int m = 0; m < 12; m++) {
  380. // Index of previous and next month, with wrap-around
  381. int next = (m+1)%12;
  382. int prev = (m+11)%12;
  383. // If a monthly mean value is outside of the allowed limits for daily
  384. // values (for instance negative radiation), we'll fail to make sure
  385. // the user knows the forcing data is broken.
  386. if (mvals[m] < minimum || mvals[m] > maximum) {
  387. fail("interp_monthly_means_conserve: Invalid monthly value given (%g), min = %g, max = %g",
  388. mvals[m], minimum, maximum);
  389. }
  390. interp_single_month(mvals[prev], mvals[m], mvals[next],
  391. date.ndaymonth[m], dvals+start_of_month,
  392. minimum, maximum);
  393. start_of_month += date.ndaymonth[m];
  394. }
  395. }
  396. /// Climate interpolation from monthly totals to quasi-daily values
  397. /** May be called from input/output module to generate daily climate values when
  398. * raw data are on monthly basis.
  399. *
  400. * The generated daily values will have the same monthly totals as the input.
  401. *
  402. * \param mvals The monthly totals
  403. * \param dvals The generated daily values
  404. */
  405. void interp_monthly_totals_conserve(const double* mvals, double* dvals,
  406. bool isleapyear, double minimum, double maximum) {
  407. // Local date object just used to get number of days for each month
  408. Date date;
  409. if (isleapyear && ECEARTHWITHCRUNCEP) date.ndaymonth[1] = 29;
  410. // Convert monthly totals to mean daily values
  411. double mvals_daily[12];
  412. for (int m=0; m<12; m++)
  413. mvals_daily[m] = mvals[m] / (double)date.ndaymonth[m];
  414. interp_monthly_means_conserve(mvals_daily, dvals, isleapyear, minimum, maximum);
  415. }
  416. /// Distributes a single month of N deposition values
  417. /** The dry component is simply spread out over all days, the
  418. * wet deposition is distributed over days with precipitation
  419. * (or evenly over all days if there is no precipitation).
  420. *
  421. * \see distribute_ndep
  422. *
  423. * \param ndry Dry N deposition (monthly mean of daily deposition)
  424. * \param nwet Wet N deposition (monthly mean of daily deposition)
  425. * \param time_steps Number of days in the month
  426. * \param dprec Array of precipitation values
  427. * \param dndep Output, total N deposition for each day
  428. */
  429. void distribute_ndep_single_month(double ndry,
  430. double nwet,
  431. int time_steps,
  432. const double* dprec,
  433. double* dndep) {
  434. // First count number of days with precipitation
  435. int raindays = 0;
  436. for (int i = 0; i < time_steps; i++) {
  437. if (!negligible(dprec[i])) {
  438. raindays++;
  439. }
  440. }
  441. // Distribute the values
  442. for (int i = 0; i < time_steps; i++) {
  443. // ndry is included in all days
  444. dndep[i] = ndry;
  445. if (raindays == 0) {
  446. dndep[i] += nwet;
  447. }
  448. else if (!negligible(dprec[i])) {
  449. dndep[i] += (nwet*time_steps)/raindays;
  450. }
  451. }
  452. }
  453. /// Distributes monthly mean N deposition values to daily values
  454. /** \see distribute_ndep_single_month for details about how the
  455. * distribution is done.
  456. *
  457. * \param mndry Monthly means of daily dry N deposition
  458. * \param mnwet Monthly means of daily wet N deposition
  459. * \param dprec Daily precipitation data
  460. * \param ndaymonth, number of days in months (imported to account for leap years)
  461. * \param dndep Output, total N deposition for each day
  462. */
  463. void distribute_ndep(const double* mndry, const double* mnwet,
  464. const double* dprec, int* ndaymonth, double* dndep) {
  465. int start_of_month = 0;
  466. for (int m = 0; m < 12; m++) {
  467. distribute_ndep_single_month(mndry[m], mnwet[m], ndaymonth[m],
  468. dprec+start_of_month, dndep+start_of_month);
  469. start_of_month += ndaymonth[m];
  470. }
  471. }
  472. /// Distribution of monthly precipitation totals to quasi-daily values
  473. /** \param mval_prec total rainfall (mm) for month
  474. * \param dval_prec actual rainfall (mm) for each day of year
  475. * \param mval_wet expected number of rain days for month
  476. * \param seed seed for generating random numbers (\see randfrac)
  477. * \param truncate if set to true the function will set small daily values
  478. * (< 0.1) to zero
  479. */
  480. void prdaily(double* mval_prec, double* dval_prec, double* mval_wet, long& seed, bool truncate /* = true */) {
  481. // Distribution of monthly precipitation totals to quasi-daily values
  482. // (From Dieter Gerten 021121)
  483. const double c1 = 1.0; // normalising coefficient for exponential distribution
  484. const double c2 = 1.2; // power for exponential distribution
  485. int m, d, dy, dyy, dy_hold;
  486. int daysum;
  487. double prob_rain; // daily probability of rain for this month
  488. double mprec; // average rainfall per rain day for this month
  489. double mprec_sum; // cumulative sum of rainfall for this month
  490. // (= mprecip in Dieter's code)
  491. double prob;
  492. dy = 0;
  493. daysum = 0;
  494. for (m=0; m<12; m++) {
  495. if (mval_prec[m] < 0.1) {
  496. // Special case if no rainfall expected for month
  497. for (d=0; d<date.ndaymonth[m]; d++) {
  498. dval_prec[dy] = 0.0;
  499. dy++;
  500. }
  501. }
  502. else {
  503. mprec_sum = 0.0;
  504. mval_wet[m] = max (mval_wet[m], 1.0);
  505. // force at least one rain day per month
  506. // rain on wet days (should be at least 0.1)
  507. mprec = max(mval_prec[m]/mval_wet[m], 0.1);
  508. mval_wet[m] = mval_prec[m] / mprec;
  509. prob_rain = mval_wet[m] / (double)date.ndaymonth[m];
  510. dy_hold = dy;
  511. while (negligible(mprec_sum)) {
  512. dy = dy_hold;
  513. for (d=0; d<date.ndaymonth[m]; d++) {
  514. // Transitional probabilities (Geng et al 1986)
  515. if (dy == 0) { // first day of year only
  516. prob = 0.75 * prob_rain;
  517. }
  518. else {
  519. if (dval_prec[dy-1] < 0.1)
  520. prob = 0.75 * prob_rain;
  521. else
  522. prob = 0.25 + (0.75 * prob_rain);
  523. }
  524. // Determine wet days randomly and use Krysanova/Cramer estimates of
  525. // parameter values (c1,c2) for an exponential distribution
  526. if (randfrac(seed)>prob)
  527. dval_prec[dy] = 0.0;
  528. else {
  529. double x=randfrac(seed);
  530. dval_prec[dy] = pow(-log(x), c2) * mprec * c1;
  531. if (dval_prec[dy] < 0.1) dval_prec[dy] = 0.0;
  532. }
  533. mprec_sum += dval_prec[dy];
  534. dy++;
  535. }
  536. // Normalise generated precipitation by prescribed monthly totals
  537. if (!negligible(mprec_sum)) {
  538. for (d=0; d<date.ndaymonth[m]; d++) {
  539. dyy = daysum + d;
  540. dval_prec[dyy] *= mval_prec[m] / mprec_sum;
  541. if (truncate && dval_prec[dyy] < 0.1) dval_prec[dyy] = 0.0;
  542. }
  543. }
  544. }
  545. }
  546. daysum += date.ndaymonth[m];
  547. }
  548. }
  549. ///////////////////////////////////////////////////////////////////////////////////////
  550. // SOIL TEMPERATURES
  551. // Call each simulation day following update of daily air temperature prior to canopy
  552. // exchange and SOM dynamics
  553. void soiltemp(const Climate& climate, Soil& soil) {
  554. // DESCRIPTION
  555. // Calculation of soil temperature at 0.25 m depth (middle of upper soil layer).
  556. // Soil temperatures are assumed to follow surface temperatures according to an
  557. // annual sinusoidal cycle with damped oscillation about a common mean, and a
  558. // temporal lag.
  559. // For a sinusoidal cycle, soil temperature at depth z and time t from beginning
  560. // of cycle given by (Carslaw & Jaeger 1959; Eqn 52; Jury et al 1991):
  561. //
  562. // (1) t(z,t) = t_av + a*exp(-z/d)*sin(omega*t - z/d)
  563. //
  564. // where
  565. // t_av = average (base) air/soil temperature
  566. // a = amplitude of air temp fluctuation
  567. // exp(-z/d) = fractional amplitude of temp fluctuation at soil depth z,
  568. // relative to surface temp fluctuation
  569. // z/d = oscillation lag in angular units at soil depth z
  570. // z = soil depth
  571. // d = sqrt(2*k/omega), damping depth
  572. // k = soil thermal diffusivity
  573. // omega = 2*PI/tau, angular frequency of oscillation (radians)
  574. // tau = oscillation period (365 days)
  575. //
  576. // Here we assume a sinusoidal cycle, but estimate soil temperatures based on
  577. // a lag (z/d, converted from angular units to days) relative to air temperature
  578. // and damping ( exp(-z/d) ) of soil temperature amplitude relative to air
  579. // temperature amplitude. A linear model for change in air temperature with time
  580. // during the last 31 days is used to estimate 'lagged' air temperature. Soil
  581. // temperature today is thus given by:
  582. //
  583. // (2) temp_soil = atemp_mean + exp( -alag ) * ( temp_lag - temp_mean )
  584. //
  585. // where
  586. // atemp_mean = mean of monthly mean temperatures for the last year (deg C)
  587. // alag = oscillation lag in angular units at depth 0.25 m
  588. // (corresponds to z/d in Eqn 1)
  589. // temp_lag = air temperature 'lag' days ago (estimated from linear model)
  590. // where 'lag' = 'alag' converted from angular units to days
  591. //
  592. // Soil thermal diffusivity (k) is sensitive to soil water content and is estimated
  593. // monthly based on mean daily soil water content for the past month, interpolating
  594. // between estimates for 0, 15% and 100% AWHC (Van Duin 1963; Jury et al 1991,
  595. // Fig 5.11).
  596. const double DIFFUS_CONV = 0.0864;
  597. // conversion factor for soil thermal diffusivity from mm2/s to m2/day
  598. const double HALF_OMEGA = 8.607E-3; // corresponds to omega/2 = pi/365 (Eqn 1)
  599. const double DEPTH = SOILDEPTH_UPPER * 0.0005;
  600. // soil depth at which to estimate temperature (m)
  601. const double LAG_CONV = 58.09;
  602. // conversion factor for oscillation lag from angular units to days (=365/(2*PI))
  603. double a, b; // regression parameters
  604. double k; // soil thermal diffusivity (m2/day)
  605. double temp_lag; // air temperature 'lag' days ago (see above; deg C)
  606. double day[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
  607. 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30};
  608. if ((date.year == 0 || date.year == soil.patch.stand.first_year) && date.month == 0 && !date.islastday) {
  609. // First month of simulation, use air temperature for soil temperature
  610. soil.temp = climate.temp;
  611. }
  612. else {
  613. if (date.islastday) {
  614. // Linearly interpolate soil thermal diffusivity given mean
  615. // soil water content
  616. if (soil.mwcontupper < 0.15)
  617. k = ((soil.soiltype.thermdiff_15 - soil.soiltype.thermdiff_0) / 0.15 *
  618. soil.mwcontupper + soil.soiltype.thermdiff_0) * DIFFUS_CONV;
  619. else
  620. k = ((soil.soiltype.thermdiff_100 - soil.soiltype.thermdiff_15) / 0.85 *
  621. (soil.mwcontupper - 0.15) + soil.soiltype.thermdiff_15) * DIFFUS_CONV;
  622. // Calculate parameters alag and exp(-alag) from Eqn 2
  623. soil.alag = DEPTH / sqrt(k / HALF_OMEGA); // from Eqn 1
  624. soil.exp_alag = exp(-soil.alag);
  625. }
  626. // Every day, calculate linear model for trend in daily air
  627. // temperatures for the last 31 days: temp_day = a + b * day
  628. double buffer[31];
  629. climate.dtemp_31.to_array(buffer);
  630. regress(day, buffer, 31, a, b);
  631. // Calculate soil temperature
  632. temp_lag = a + b * (30.0 - soil.alag * LAG_CONV);
  633. soil.temp = climate.atemp_mean + soil.exp_alag * (temp_lag - climate.atemp_mean);
  634. // Eqn 2
  635. }
  636. }
  637. /// Called each simulation day before any other driver or process functions
  638. void dailyaccounting_gridcell(Gridcell& gridcell, bool firstsimulationday) {
  639. // DESCRIPTION
  640. // Updates daily climate parameters including growing degree day sums and
  641. // exponential temperature response term (gtemp, see below). Maintains monthly
  642. // and longer term records of variation in climate variables. PFT-specific
  643. // degree-day sums in excess of damaging temperatures are also calculated here.
  644. const double W11DIV12 = 11.0 / 12.0;
  645. const double W1DIV12 = 1.0 / 12.0;
  646. int y, startyear;
  647. double hatom2 = 1.0 / 10000.0;
  648. // guess2008 - changed this from an int to a double
  649. double mtemp_last;
  650. // Reset each day
  651. gridcell.landcover.dcflux_landuse_change=0.0;
  652. gridcell.landcover.dcflux_harvest_slow=0.0;
  653. Climate& climate = gridcell.climate;
  654. // On first day of year ...
  655. if (date.day == 0) {
  656. if (ECEARTHWITHCRUNCEP) {
  657. if (date.is_leap(date.year))
  658. date.ndaymonth[1] = 29;
  659. else
  660. date.ndaymonth[1] = 28;
  661. }
  662. // ... reset annual GDD5 counter
  663. climate.agdd5 = 0.0;
  664. // reset annual nitrogen input variables
  665. climate.andep = 0.0;
  666. // reset gridcell-level harvest fluxes
  667. gridcell.landcover.harvest_product=0.0;
  668. gridcell.landcover.harvest_product_nmass=0.0;
  669. gridcell.landcover.acflux_harvest_wood_res=0.0;
  670. gridcell.landcover.acflux_landuse_change=0.0;
  671. gridcell.landcover.acflux_harvest_slow=0.0;
  672. gridcell.landcover.anflux_landuse_change=0.0;
  673. gridcell.landcover.anflux_harvest_slow=0.0;
  674. for(int i=0;i<NLANDCOVERTYPES;i++) {
  675. gridcell.landcover.harvest_product_lc[i]=0.0;
  676. gridcell.landcover.harvest_product_nmass_lc[i]=0.0;
  677. gridcell.landcover.acflux_harvest_wood_res_lc[i]=0.0;
  678. gridcell.landcover.acflux_landuse_change_lc[i]=0.0;
  679. gridcell.landcover.acflux_harvest_slow_lc[i]=0.0;
  680. gridcell.landcover.anflux_landuse_change_lc[i]=0.0;
  681. gridcell.landcover.anflux_harvest_slow_lc[i]=0.0;
  682. }
  683. gridcell.landcover.wood_harvest.zero();
  684. if (date.year == 0 || firstsimulationday) {
  685. // ecev3 - added firstsimulationday, otherwise we get crashes when spinning up or
  686. // when restarting the model
  687. // First day of simulation - initialise running annual mean temperature and daily temperatures for the last month
  688. for (unsigned int d = 0; d < climate.dtemp_31.CAPACITY; d++) {
  689. climate.dtemp_31.add(climate.temp);
  690. }
  691. climate.atemp_mean = climate.temp;
  692. // Initialise gridcellpfts Michaelis-Menten kinetic Km value
  693. pftlist.firstobj();
  694. while (pftlist.isobj) {
  695. gridcell.pft[pftlist.getobj().id].Km = pftlist.getobj().km_volume * gridcell.soiltype.wtot;
  696. pftlist.nextobj();
  697. }
  698. }
  699. // Reset fluxes for all patches
  700. // Belongs perhaps in dailyaccounting_patch, but needs to be done before
  701. // landcover_dynamics because harvest flux is generated there.
  702. // N-flux variables moved here for easier balance accounting
  703. Gridcell::iterator gc_itr = gridcell.begin();
  704. while (gc_itr != gridcell.end()) {
  705. Stand& stand = *gc_itr;
  706. stand.firstobj();
  707. while (stand.isobj) {
  708. Patch& patch = stand.getobj();
  709. patch.fluxes.reset();
  710. patch.soil.anfix = 0.0;
  711. patch.soil.aorgNleach = 0.0;
  712. patch.soil.aorgCleach = 0.0;
  713. patch.soil.aminleach = 0.0;
  714. patch.anfert = 0.0;
  715. patch.managed_this_year = false;
  716. patch.plant_this_year = false;
  717. stand.nextobj();
  718. }
  719. ++gc_itr;
  720. }
  721. }
  722. else if ( (climate.lat >= 0.0 && date.day == COLDEST_DAY_NHEMISPHERE) ||
  723. (climate.lat < 0.0 && date.day == COLDEST_DAY_SHEMISPHERE) ) {
  724. // In midwinter, reset GDD counter for summergreen phenology
  725. climate.gdd5 = 0.0;
  726. climate.ifsensechill = false;
  727. }
  728. else if ( (climate.lat >= 0.0 && date.day == WARMEST_DAY_NHEMISPHERE) ||
  729. (climate.lat < 0.0 && date.day == WARMEST_DAY_SHEMISPHERE) ) {
  730. climate.ifsensechill = true;
  731. }
  732. // Update GDD counters and chill day count
  733. climate.gdd5 += max(0.0, climate.temp - 5.0);
  734. climate.agdd5 += max(0.0, climate.temp - 5.0);
  735. if (climate.temp < 5.0 && climate.chilldays <= Date::MAX_YEAR_LENGTH)
  736. climate.chilldays++;
  737. // Calculate gtemp (daily/sub-daily depending on the mode)
  738. if (date.diurnal()) {
  739. climate.gtemps.assign(date.subdaily, 0);
  740. for (int i=0; i<date.subdaily; i++) {
  741. respiration_temperature_response(climate.temps[i], climate.gtemps[i]);
  742. }
  743. }
  744. else {
  745. respiration_temperature_response(climate.temp, climate.gtemp);
  746. }
  747. if (date.get_calendar_year() >= PLUSYEAR && PLUS200PPM)
  748. climate.co2 += 200.0; // CRESCENDO S3a experiment
  749. if (date.get_calendar_year() >= PLUSYEAR && PLUS50KGN)
  750. climate.dndep += 50.0 * hatom2 / date.year_length(); // CRESCENDO S3c experiment
  751. // Sum annual nitrogen addition to system
  752. climate.andep += climate.dndep;
  753. // Save yesterday's mean temperature for the last month
  754. mtemp_last = climate.mtemp;
  755. // Update daily temperatures, and mean overall temperature, for last 31 days
  756. climate.dtemp_31.add(climate.temp);
  757. climate.mtemp = climate.dtemp_31.mean();
  758. climate.dprec_31.add(climate.prec);
  759. climate.deet_31.add(climate.eet);
  760. // Reset GDD and chill day counter if mean monthly temperature falls below base
  761. // temperature
  762. if (mtemp_last >= 5.0 && climate.mtemp < 5.0 && climate.ifsensechill) {
  763. climate.gdd5 = 0.0;
  764. climate.chilldays = 0;
  765. }
  766. // First day of each month
  767. if (date.dayofmonth == 0) {
  768. gridcell.mcLand1[date.month] = gridcell.ccont();
  769. }
  770. // On last day of month ...
  771. if (date.islastday) {
  772. // Update mean temperature for the last 12 months
  773. // atemp_mean_new = atemp_mean_old * (11/12) + mtemp * (1/12)
  774. climate.atemp_mean = climate.atemp_mean * W11DIV12 + climate.mtemp * W1DIV12;
  775. // Record minimum and maximum monthly temperatures
  776. if (date.month == 0) {
  777. climate.mtemp_min = climate.mtemp;
  778. climate.mtemp_max = climate.mtemp;
  779. }
  780. else {
  781. if (climate.mtemp < climate.mtemp_min)
  782. climate.mtemp_min = climate.mtemp;
  783. if (climate.mtemp > climate.mtemp_max)
  784. climate.mtemp_max = climate.mtemp;
  785. }
  786. // On 31 December update records of minimum monthly temperatures for the last
  787. // 20 years and find mean of minimum monthly temperatures for the last 20 years
  788. if (date.islastmonth) {
  789. startyear = 20 - (int)min(19, gridcell.getsimulationyear(date.year));
  790. climate.mtemp_min20 = climate.mtemp_min;
  791. climate.mtemp_max20 = climate.mtemp_max;
  792. for (y=startyear; y<20; y++) {
  793. climate.mtemp_min_20[y-1] = climate.mtemp_min_20[y];
  794. climate.mtemp_min20 += climate.mtemp_min_20[y];
  795. climate.mtemp_max_20[y-1] = climate.mtemp_max_20[y];
  796. climate.mtemp_max20 += climate.mtemp_max_20[y];
  797. }
  798. climate.mtemp_min20 /= (double)(21 - startyear);
  799. climate.mtemp_max20 /= (double)(21 - startyear);
  800. climate.mtemp_min_20[19] = climate.mtemp_min;
  801. climate.mtemp_max_20[19] = climate.mtemp_max;
  802. climate.agdd5_5.add(climate.agdd5);
  803. double awcont = 0.0;
  804. Gridcell::iterator gc_itr = gridcell.begin();
  805. while (gc_itr != gridcell.end()) {
  806. Stand& stand = *gc_itr;
  807. double to_gridcell_average = stand.get_gridcell_fraction() / (double)stand.npatch();
  808. stand.firstobj();
  809. while (stand.isobj) {
  810. Patch& patch = stand.getobj();
  811. awcont += (patch.soil.awcont[0] * SOILDEPTH_UPPER + patch.soil.awcont[1] * SOILDEPTH_LOWER) / (SOILDEPTH_UPPER + SOILDEPTH_LOWER) * to_gridcell_average / date.year_length();
  812. stand.nextobj();
  813. }
  814. ++gc_itr;
  815. }
  816. gridcell.awcont_5.add(awcont);
  817. }
  818. climate.hmtemp_20[date.month].add(climate.dtemp_31.periodicmean(date.ndaymonth[date.month]));
  819. climate.hmprec_20[date.month].add(climate.dprec_31.periodicsum(date.ndaymonth[date.month]));
  820. climate.hmeet_20[date.month].add(climate.deet_31.periodicsum(date.ndaymonth[date.month]));
  821. }
  822. }
  823. void dailyaccounting_stand(Stand& stand) {
  824. }
  825. /// Manages C and N fluxes from slow harvest pools
  826. void dailyaccounting_patch_lc(Patch& patch) {
  827. if (date.day > 0 || !ifslowharvestpool) {
  828. return;
  829. }
  830. Landcover& lc = patch.stand.get_gridcell().landcover;
  831. double scale = patch.stand.get_gridcell_fraction() / (double)patch.stand.nobj;
  832. pftlist.firstobj();
  833. while(pftlist.isobj) { // NB. also inactive pft's
  834. Pft& pft = pftlist.getobj();
  835. Patchpft& ppft = patch.pft[pft.id];
  836. lc.dcflux_harvest_slow += ppft.harvested_products_slow * pft.turnover_harv_prod * scale; // ecev3 - reset to 0 each day
  837. lc.acflux_harvest_slow += ppft.harvested_products_slow * pft.turnover_harv_prod * scale;
  838. lc.acflux_harvest_slow_lc[patch.stand.landcover] += ppft.harvested_products_slow * pft.turnover_harv_prod * scale;
  839. ppft.harvested_products_slow = ppft.harvested_products_slow * (1 - pft.turnover_harv_prod);
  840. lc.anflux_harvest_slow += ppft.harvested_products_slow_nmass * pft.turnover_harv_prod * scale;
  841. lc.anflux_harvest_slow_lc[patch.stand.landcover] += ppft.harvested_products_slow_nmass * pft.turnover_harv_prod * scale;
  842. ppft.harvested_products_slow_nmass = ppft.harvested_products_slow_nmass * (1 - pft.turnover_harv_prod);
  843. pftlist.nextobj();
  844. }
  845. }
  846. void dailyaccounting_patch(Patch& patch, bool prescribe_ifs_soiltemp) {
  847. // DESCRIPTION
  848. // Updates daily soil parameters including exponential temperature response terms
  849. // (gtemp, see below). Maintains monthly and longer term records of variation in
  850. // soil variables. Initialises flux sums at start of simulation year.
  851. // INPUT AND OUTPUT PARAMETER
  852. // soil = patch soil
  853. Soil& soil = patch.soil;
  854. if (date.day == 0) {
  855. patch.aaet = 0.0;
  856. patch.aintercep = 0.0;
  857. patch.apet = 0.0;
  858. // Calculate total FPC
  859. patch.fpc_total = 0;
  860. Vegetation& vegetation = patch.vegetation;
  861. vegetation.firstobj();
  862. while (vegetation.isobj) {
  863. patch.fpc_total += vegetation.getobj().fpc; // indiv.fpc
  864. vegetation.getobj().cmass_veg = 0.0;
  865. vegetation.getobj().nmass_veg = 0.0;
  866. vegetation.nextobj();
  867. }
  868. // Calculate rescaling factor to account for overlap between populations/
  869. // cohorts/individuals (i.e. total FPC > 1)
  870. patch.fpc_rescale = 1.0 / max(patch.fpc_total, 1.0);
  871. for (int d = 0; d < 366; d++)
  872. patch.dpet[d] = 0.0;
  873. }
  874. if (date.dayofmonth == 0) {
  875. patch.maet[date.month] = 0.0;
  876. patch.mintercep[date.month] = 0.0;
  877. patch.mpet[date.month]=0.0;
  878. soil.mwcont[date.month][1] = 0.0; // ecev3
  879. }
  880. if(run_landcover)
  881. dailyaccounting_patch_lc(patch);
  882. // Store daily soil water in both layers
  883. soil.dwcontupper[date.day] = soil.wcont[0];
  884. soil.dwcontlower[date.day] = soil.wcont[1];
  885. // ecev3 - changes made for wcont lower as we removed dwcontlower[366] and replaced it with soil.dwcontlower_today
  886. // soil.dwcontlower[date.day] = soil.wcont[1]; // ecev3
  887. soil.dwcontlower_today = soil.wcont[1];
  888. // Update monthly average for wcont[1]
  889. soil.mwcont[date.month][1] += soil.dwcontlower_today / date.ndaymonth[date.month];
  890. // On last day of month, calculate mean content of upper soil layer
  891. if (date.islastday) {
  892. soil.mwcontupper = mean(soil.dwcontupper + date.day - date.ndaymonth[date.month] + 1,
  893. date.ndaymonth[date.month]);
  894. // guess2008 - record water in lower layer too, and then update mwcont
  895. //soil.mwcontlower = mean(soil.dwcontlower + date.day - date.ndaymonth[date.month] + 1,
  896. // date.ndaymonth[date.month]);
  897. soil.mwcont[date.month][0] = soil.mwcontupper;
  898. //soil.mwcont[date.month][1] = soil.mwcontlower;
  899. }
  900. // Calculate soil temperatures
  901. soiltemp(patch.get_climate(), soil);
  902. // ecev3 - override calculated soil temp before gtemp is calculated
  903. if (prescribe_ifs_soiltemp)
  904. soil.temp = patch.get_climate().ifssoiltemp;
  905. if (date.get_calendar_year() >= PLUSYEAR && PLUS5SOILT)
  906. soil.temp += 5.0; // CRESCENDO S3b experiment
  907. respiration_temperature_response(soil.temp, soil.gtemp);
  908. // On last day of month, calculate mean soil temperature for last month
  909. soil.dtemp[date.dayofmonth] = soil.temp;
  910. if (date.islastday)
  911. soil.mtemp = mean(soil.dtemp,date.ndaymonth[date.month]);
  912. Vegetation& vegetation = patch.vegetation;
  913. vegetation.firstobj();
  914. while (vegetation.isobj) {
  915. if (vegetation.getobj().ccont() > vegetation.getobj().cmass_veg) {
  916. vegetation.getobj().cmass_veg = vegetation.getobj().ccont();
  917. vegetation.getobj().nmass_veg = vegetation.getobj().ncont();
  918. }
  919. else if (vegetation.getobj().ncont() > vegetation.getobj().nmass_veg && !(vegetation.getobj().ccont() < vegetation.getobj().cmass_veg)) {
  920. vegetation.getobj().nmass_veg = vegetation.getobj().ncont();
  921. }
  922. vegetation.nextobj();
  923. }
  924. patch.is_litter_day = false;
  925. patch.isharvestday = false;
  926. }
  927. ///////////////////////////////////////////////////////////////////////////////////////
  928. // RESPIRATION TEMPERATURE RESPONSE
  929. // Called by dailyaccounting_patch and dailyaccounting_gridcell to calculate
  930. // response of respiration to temperature
  931. void respiration_temperature_response(double temp,double& gtemp) {
  932. // DESCRIPTION
  933. // Calculates g(T), response of respiration rate to temperature (T), based on
  934. // empirical relationship for temperature response of soil temperature across
  935. // ecosystems, incorporating damping of Q10 response due to temperature
  936. // acclimation (Eqn 11, Lloyd & Taylor 1994)
  937. //
  938. // r = r10 * g(t)
  939. // g(T) = EXP [308.56 * (1 / 56.02 - 1 / (T - 227.13))] (T in Kelvin)
  940. // INPUT PARAMETER
  941. // temp = air or soil temperature (deg C)
  942. // OUTPUT PARAMETER
  943. // gtemp = respiration temperature response
  944. if (temp >= -40.0) {
  945. gtemp = exp(308.56 * (1.0 / 56.02 - 1.0 / (temp + 46.02)));
  946. } else {
  947. gtemp = 0.0;
  948. }
  949. }
  950. ///////////////////////////////////////////////////////////////////////////////////////
  951. // DAYLENGTH, INSOLATION AND POTENTIAL EVAPOTRANSPIRATION
  952. // Called by framework each simulation day following update of daily air temperature
  953. // and before canopy exchange processes
  954. void daylengthinsoleet(Climate& climate) {
  955. // Calculation of daylength, insolation and equilibrium evapotranspiration
  956. // for each day, given mean daily temperature, insolation (as percentage
  957. // of full sunshine or mean daily instantaneous downward shortwave
  958. // radiation flux, W/m2), latitude and day of year
  959. // INPUT AND OUTPUT PARAMETER
  960. // climate = gridcell climate
  961. const double QOO = 1360.0;
  962. const double BETA = 0.17;
  963. const double A = 107.0;
  964. const double B = 0.2;
  965. const double C = 0.25;
  966. const double D = 0.5;
  967. const double K = 13750.98708;
  968. const double FRADPAR = 0.5;
  969. // fraction of net incident shortwave radiation that is photosynthetically
  970. // active (PAR)
  971. double w, hn;
  972. // CALCULATION OF NET DOWNWARD SHORT-WAVE RADIATION FLUX
  973. // Refs: Prentice et al 1993, Monteith & Unsworth 1990,
  974. // Henderson-Sellers & Robinson 1986
  975. // (1) rs = (c + d*ni) * (1 - beta) * Qo * cos Z * k
  976. // (Eqn 7, Prentice et al 1993)
  977. // (2) Qo = Qoo * ( 1 + 2*0.01675 * cos ( 2*pi*(i+0.5)/365) )
  978. // (Eqn 8, Prentice et al 1993; angle in radians)
  979. // (3) cos Z = sin(lat) * sin(delta) + cos(lat) * cos(delta) * cos h
  980. // (Eqn 9, Prentice et al 1993)
  981. // (4) delta = -23.4 * pi / 180 * cos ( 2*pi*(i+10.5)/365 )
  982. // (Eqn 10, Prentice et al 1993, angle in radians)
  983. // (5) h = 2 * pi * t / 24 = pi * t / 12
  984. // where rs = instantaneous net downward shortwave radiation
  985. // flux, including correction for terrestrial shortwave albedo
  986. // (W/m2 = J/m2/s)
  987. // c, d = empirical constants (c+d = clear sky
  988. // transmissivity)
  989. // ni = proportion of bright sunshine
  990. // beta = average 'global' value for shortwave albedo
  991. // (not associated with any particular vegetation)
  992. // i = julian day, (0-364, 0=1 Jan)
  993. // Qoo = solar constant, 1360 W/m2
  994. // Z = solar zenith angle (angular distance between the
  995. // sun's rays and the local vertical)
  996. // k = conversion factor from solar angular units to
  997. // seconds, 12 / pi * 3600
  998. // lat = latitude (+=N, -=S, in radians)
  999. // delta = solar declination (angle between the orbital
  1000. // plane and the Earth's equatorial plane) varying
  1001. // between +23.4 degrees in northern hemisphere
  1002. // midsummer and -23.4 degrees in N hemisphere
  1003. // midwinter
  1004. // h = hour angle, the fraction of 2*pi (radians) which
  1005. // the earth has turned since the local solar noon
  1006. // t = local time in hours from solar noon
  1007. // From (1) and (3), shortwave radiation flux at any hour during the
  1008. // day, any day of the year and any latitude given by
  1009. // (6) rs = (c + d*ni) * (1 - beta) * Qo * ( sin(lat) * sin(delta) +
  1010. // cos(lat) * cos(delta) * cos h ) * k
  1011. // Solar zenith angle equal to -pi/2 (radians) at sunrise and pi/2 at
  1012. // sunset. For Z=pi/2 or Z=-pi/2,
  1013. // (7) cos Z = 0
  1014. // From (3) and (7),
  1015. // (8) cos hh = - sin(lat) * sin(delta) / ( cos(lat) * cos(delta) )
  1016. // where hh = half-day length in angular units
  1017. // Define
  1018. // (9) u = sin(lat) * sin(delta)
  1019. // (10) v = cos(lat) * cos(delta)
  1020. // Thus
  1021. // (11) hh = acos (-u/v)
  1022. // To obtain the daily net downward short-wave radiation sum, integrate
  1023. // equation (6) from -hh to hh with respect to h,
  1024. // (12) rad = 2 * (c + d*ni) * (1 - beta) * Qo *
  1025. // ( u*hh + v*sin(hh) )
  1026. // Define
  1027. // (13) w = (c + d*ni) * (1 - beta) * Qo
  1028. // From (12) & (13), and converting from angular units to seconds
  1029. // (14) rad = 2 * w * ( u*hh + v*sin(hh) ) * k
  1030. if (!climate.doneday[date.day]) {
  1031. // Calculate values of saved parameters for this day
  1032. climate.qo[date.day] = QOO * (1.0 + 2.0 * 0.01675 *
  1033. cos(2.0 * PI * ((double)date.day + 0.5) / (double)date.year_length())); // Eqn 2
  1034. double delta = -23.4 * DEGTORAD * cos(2.0 * PI * ((double)date.day + 10.5) / (double)date.year_length());
  1035. // Eqn 4, solar declination angle (radians)
  1036. climate.u[date.day] = climate.sinelat * sin(delta); // Eqn 9
  1037. climate.v[date.day] = climate.cosinelat * cos(delta); // Eqn 10
  1038. if (climate.u[date.day] >= climate.v[date.day])
  1039. climate.hh[date.day] = PI; // polar day
  1040. else if (climate.u[date.day] <= -climate.v[date.day])
  1041. climate.hh[date.day] = 0.0; // polar night
  1042. else climate.hh[date.day] =
  1043. acos(-climate.u[date.day] / climate.v[date.day]); // Eqn 11
  1044. climate.sinehh[date.day] = sin(climate.hh[date.day]);
  1045. // Calculate daylength in hours from hh
  1046. climate.daylength_save[date.day] = 24.0 * climate.hh[date.day] / PI;
  1047. climate.doneday[date.day] = true;
  1048. }
  1049. climate.daylength = climate.daylength_save[date.day];
  1050. if (climate.instype == SUNSHINE) { // insolation is percentage sunshine
  1051. w = (C+D * climate.insol / 100.0) * (1.0 - BETA) * climate.qo[date.day]; // Eqn 13
  1052. climate.rad = 2.0 * w * (climate.u[date.day] * climate.hh[date.day] +
  1053. climate.v[date.day] * climate.sinehh[date.day]) * K; // Eqn 14
  1054. }
  1055. else { // insolation provided as instantaneous downward shortwave radiation flux
  1056. // deal with the fact that insolation can be radiation during
  1057. // daylight hours or during whole time step
  1058. double averaging_period = 24.0 * 3600.0;
  1059. if (climate.instype == NETSWRAD || climate.instype == SWRAD) {
  1060. // insolation is provided as radiation during daylight hours
  1061. averaging_period = climate.daylength_save[date.day] * 3600.0;
  1062. }
  1063. double net_coeff = 1;
  1064. if (climate.instype == SWRAD || climate.instype == SWRAD_TS) {
  1065. net_coeff = 1 - BETA; // albedo correction
  1066. }
  1067. climate.rad = climate.insol * net_coeff * averaging_period;
  1068. // If using diurnal data with SWRAD or SWRAD_TS insolation type move
  1069. // the following if-clause outside and below this if-else clause.
  1070. if (date.diurnal()) {
  1071. climate.pars.resize(date.subdaily);
  1072. climate.rads.resize(date.subdaily);
  1073. for (int i=0; i<date.subdaily; i++) {
  1074. climate.rads[i] = climate.insols[i] * net_coeff * averaging_period;
  1075. climate.pars[i] = climate.rads[i] * FRADPAR;
  1076. }
  1077. }
  1078. // special case for polar night
  1079. // if (climate.sinehh[date.day] < 0.001) { // polar night - ecev3 replaced below
  1080. if (climate.hh[date.day] < 0.001) {
  1081. w = 0;
  1082. }
  1083. else {
  1084. w = climate.rad/2.0/(climate.u[date.day]*climate.hh[date.day]
  1085. +climate.v[date.day]*climate.sinehh[date.day])/K; // from Eqn 14
  1086. }
  1087. }
  1088. // Calculate PAR from radiation (Eqn A1, Haxeltine & Prentice 1996)
  1089. climate.par = climate.rad * FRADPAR;
  1090. // CALCULATION OF DAILY EQUILIBRIUM EVAPOTRANSPIRATION
  1091. // (EET, or evaporative demand)
  1092. // Refs: Jarvis & McNaughton 1986, Prentice et al 1993
  1093. // (15) eet = ( s / (s + gamma) ) * rn / lambda
  1094. // (Eqn 5, Prentice et al 1993)
  1095. // (16) s = 2.503E+6 * exp ( 17.269 * temp / (237.3 + temp) ) /
  1096. // (237.3 + temp)**2
  1097. // (Eqn 6, Prentice et al 1993)
  1098. // (17) rn = rs - rl
  1099. // (18) rl = ( b + (1-b) * ni ) * ( a - temp )
  1100. // (Eqn 11, Prentice et al 1993)
  1101. // where eet = instantaneous evaporative demand (mm/s)
  1102. // gamma = psychrometer constant, c. 65 Pa/K
  1103. // lambda = latent heat of vapourisation of water,
  1104. // c. 2.5E+6 J/kg
  1105. // temp = temperature (deg C)
  1106. // rl = net upward longwave radiation flux
  1107. // ('terrestrial radiation') (W/m2)
  1108. // rn = net downward radiation flux (W/m2)
  1109. // a, b = empirical constants
  1110. // Note: gamma and lambda are weakly dependent on temperature. Simple
  1111. // linear functions are used to obtain approximate values for a
  1112. // given temperature
  1113. // From (13) & (18),
  1114. // (19) rl = ( b + (1-b) * ( w / Qo / (1 - beta) - c ) / d ) * ( a - temp )
  1115. // Define
  1116. // (20) uu = w * u - rl
  1117. // (21) vv = w * v
  1118. // Daily EET sum is instantaneous EET integrated over the period
  1119. // during which rn >= 0. Limits for the integration (half-period
  1120. // hn) are obtained by solving for
  1121. // (22) rn=0
  1122. // From (17) & (22),
  1123. // (23) rs - rl = 0
  1124. // From (6), (20), (21) and (23),
  1125. // (24) uu + vv * cos hn = 0
  1126. // From (24),
  1127. // (25) hn = acos ( -uu/vv )
  1128. // Integration of (15) w.r.t. h in the range -hn to hn leads to the
  1129. // following formula for total daily EET (mm)
  1130. // (26) eet_day = 2 * ( s / (s + gamma) / lambda ) *
  1131. // ( uu*hn + vv*sin(hn) ) * k
  1132. double rl = (B + (1.0 - B) * (w / climate.qo[date.day] / (1.0 - BETA) - C) / D) *
  1133. (A - climate.temp); // Eqn 19: instantaneous net upward longwave radiation flux (W/m2)
  1134. // Calculate gamma and lambda
  1135. double gamma = 65.05 + climate.temp * 0.064;
  1136. double lambda = 2.495e6 - climate.temp * 2380.;
  1137. double ct = 237.3 + climate.temp;
  1138. double s = 2.503e6 * exp(17.269 * climate.temp / ct) / ct / ct; // Eqn 16
  1139. // ecev3 - calculate EET using net SW and LW from IFS. Ignore rl above since it uses a global BETA parameter.
  1140. if (ECEARTH && !ECEARTHWITHCRUNCEP) {
  1141. // Use net surface radiation to compute eet, if positive
  1142. double net_surface_radiation = climate.insol + climate.netlw; // W m-2 - can be negative since netlw can be!!!
  1143. climate.eet = s / (s + gamma) / lambda * net_surface_radiation * 24.0 * 3600.0; // mm day-1
  1144. if (climate.eet < 0.0) // happens if net_surface_radiation < 0
  1145. climate.eet = 0.0; // No nightime condensation
  1146. }
  1147. else {
  1148. // eet from trunk
  1149. double uu = w * climate.u[date.day] - rl; // Eqn 20
  1150. double vv = w * climate.v[date.day]; // Eqn 21
  1151. // Calculate half-period with positive net radiation, hn
  1152. // In Eqn (25), hn defined for uu in range -vv to vv
  1153. // For uu >= vv, hn = pi (12 hours, i.e. polar day)
  1154. // For uu <= -vv, hn = 0 (i.e. polar night)
  1155. if (uu>=vv) hn = PI; // polar day
  1156. else if (uu<=-vv) hn = 0.0; // polar night
  1157. else hn=acos(-uu / vv); // Eqn 25
  1158. // Calculate total EET (equilibrium evapotranspiration) for this day, mm/day
  1159. climate.eet = 2.0 * (s / (s + gamma) / lambda) * (uu * hn + vv * sin(hn)) * K; // Eqn 26;
  1160. }
  1161. }
  1162. ///////////////////////////////////////////////////////////////////////////////////////
  1163. // REFERENCES
  1164. //
  1165. // LPJF refers to the original FORTRAN implementation of LPJ as described by Sitch
  1166. // et al 2000
  1167. // Balsamo G., P. Viterbo, A. Beljaars, BJJM. van den Hurk, A. Betts, K. Scipal.
  1168. // A revised hydrology for the ECMWF model: Verification from field site to terrestrial
  1169. // water storage and impact in the Integrated Forecast System. J. Hydrometeor., 1, 2009,
  1170. // 10, 623-643, doi 10.1175/2008JHM1068.1.
  1171. // Carslaw, HS & Jaeger JC 1959 Conduction of Heat in Solids, Oxford University
  1172. // Press, London
  1173. // Cosby, B. J., Hornberger, C. M., Clapp, R. B., & Ginn, T. R. 1984 A statistical exploration
  1174. // of the relationships of soil moisture characteristic to the physical properties of soil.
  1175. // Water Resources Research, 20: 682-690.
  1176. // Haxeltine A & Prentice IC 1996 BIOME3: an equilibrium terrestrial biosphere
  1177. // model based on ecophysiological constraints, resource availability, and
  1178. // competition among plant functional types. Global Biogeochemical Cycles 10:
  1179. // 693-709
  1180. // Henderson-Sellers, A & Robinson, PJ 1986 Contemporary Climatology. Longman,
  1181. // Essex.
  1182. // Jarvis, PG & McNaughton KG 1986 Stomatal control of transpiration: scaling up
  1183. // from leaf to region. Advances in Ecological Research 15: 1-49
  1184. // Jury WA, Gardner WR & Gardner WH 1991 Soil Physics 5th ed, John Wiley, NY
  1185. // Lloyd, J & Taylor JA 1994 On the temperature dependence of soil respiration
  1186. // Functional Ecology 8: 315-323
  1187. // Parton, W. J., Hanson, P. J., Swanston, C., Torn, M., Trumbore, S. E., Riley, W.
  1188. // & Kelly, R. 2010. ForCent model development and testing using the Enriched
  1189. // Background Isotope Study experiment. Journal of Geophysical
  1190. // Research-Biogeosciences, 115.
  1191. // Prentice, IC, Sykes, MT & Cramer W 1993 A simulation model for the transient
  1192. // effects of climate change on forest landscapes. Ecological Modelling 65:
  1193. // 51-70.
  1194. // Press, WH, Teukolsky, SA, Vetterling, WT & Flannery, BT. (1986) Numerical
  1195. // Recipes in FORTRAN, 2nd ed. Cambridge University Press, Cambridge
  1196. // Sitch, S, Prentice IC, Smith, B & Other LPJ Consortium Members (2000) LPJ - a
  1197. // coupled model of vegetation dynamics and the terrestrial carbon cycle. In:
  1198. // Sitch, S. The Role of Vegetation Dynamics in the Control of Atmospheric CO2
  1199. // Content, PhD Thesis, Lund University, Lund, Sweden.
  1200. // Monteith, JL & Unsworth, MH 1990 Principles of Environmental Physics, 2nd ed,
  1201. // Arnold, London
  1202. // van Duin, RHA 1963 The influence of soil management on the temperature
  1203. // wave near the surface. Tech Bull 29 Inst for Land and Water Management
  1204. // Research, Wageningen, Netherlands