soilwater.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  1. ///////////////////////////////////////////////////////////////////////////////////////
  2. /// \file soilwater.cpp
  3. /// \brief Soil hydrology and snow
  4. ///
  5. /// Version including evaporation from soil surface, based on work by Dieter Gerten,
  6. /// Sibyll Schaphoff and Wolfgang Lucht, Potsdam
  7. ///
  8. /// Includes baseflow runoff
  9. ///
  10. /// \author Ben Smith
  11. /// $Date: 2013-06-28 13:13:33 +0200 (Fri, 28 Jun 2013) $
  12. ///
  13. ///////////////////////////////////////////////////////////////////////////////////////
  14. // WHAT SHOULD THIS FILE CONTAIN?
  15. // Module source code files should contain, in this order:
  16. // (1) a "#include" directive naming the framework header file. The framework header
  17. // file should define all classes used as arguments to functions in the present
  18. // module. It may also include declarations of global functions, constants and
  19. // types, accessible throughout the model code;
  20. // (2) other #includes, including header files for other modules accessed by the
  21. // present one;
  22. // (3) type definitions, constants and file scope global variables for use within
  23. // the present module only;
  24. // (4) declarations of functions defined in this file, if needed;
  25. // (5) definitions of all functions. Functions that are to be accessible to other
  26. // modules or to the calling framework should be declared in the module header
  27. // file.
  28. //
  29. // PORTING MODULES BETWEEN FRAMEWORKS:
  30. // Modules should be structured so as to be fully portable between models (frameworks).
  31. // When porting between frameworks, the only change required should normally be in the
  32. // "#include" directive referring to the framework header file.
  33. #include "config.h"
  34. #include "soilwater.h"
  35. void snow(double prec, double temp, double& snowpack, double& rain_melt) {
  36. // Daily calculation of snowfall and rainfall from precipitation and snow melt from
  37. // snow pack; update of snow pack with new snow and snow melt and snow melt
  38. // INPUT PARAMETERS
  39. // prec = precipitation today (mm)
  40. // temp = air temperature today (deg C)
  41. // INPUT AND OUTPUT PARAMETER
  42. // snowpack = stored snow (rainfall mm equivalents)
  43. // OUTPUT PARAMETERS
  44. // rain_melt = rainfall and snow melt today (mm)
  45. const double TSNOW = 0.0;
  46. // maximum temperature for precipitation as snow (deg C)
  47. // previously 2 deg C; new value suggested by Dieter Gerten 2002-12
  48. const double SNOWPACK_MAX = 10000.0;
  49. // maximum size of snowpack (mm) (S. Sitch, pers. comm. 2001-11-28)
  50. double melt;
  51. if (temp < TSNOW) { // snowing today
  52. melt = -min(prec, SNOWPACK_MAX-snowpack);
  53. } else { // raining today
  54. // New snow melt formulation
  55. // Dieter Gerten 021121
  56. // Ref: Choudhury et al 1998
  57. melt = min((1.5+0.007*prec)*(temp-TSNOW), snowpack);
  58. }
  59. snowpack -= melt;
  60. rain_melt = prec + melt;
  61. }
  62. /// SNOW_NINPUT
  63. /** Nitrogen deposition and fertilization on a snowpack stays in snowpack
  64. * until it starts melting. If no snowpack daily nitrogen deposition and
  65. * fertilization goes to the soil available mineral nitrogen pool.
  66. */
  67. void snow_ninput(double prec, double snowpack_after, double rain_melt,
  68. double dndep, double dnfert, double& snowpack_nmass, double& ninput) {
  69. // calculates this day melt and original snowpack size
  70. double melt = max(0.0, rain_melt - prec);
  71. double snowpack = melt + snowpack_after;
  72. // snow exist
  73. if (!negligible(snowpack) && !negligible(snowpack_nmass)) {
  74. // if some snow is melted, fraction of nitrogen in snowpack
  75. // will go to soil available nitrogen pool
  76. if (melt > 0.0) {
  77. double frac_melt = melt / snowpack;
  78. double melt_nmass = frac_melt * snowpack_nmass;
  79. ninput = melt_nmass + dndep + dnfert;
  80. snowpack_nmass -= melt_nmass;
  81. }
  82. // if no snow is melted, then add daily nitrogen deposition
  83. // and fertilization to snowpack nitrogen pool
  84. else {
  85. snowpack_nmass += (dndep + dnfert);
  86. ninput = 0.0;
  87. }
  88. }
  89. else {
  90. ninput = dndep + dnfert;
  91. }
  92. }
  93. void hydrology_lpjf(Patch& patch, Climate& climate, double rain_melt, double perc_base,
  94. double perc_exp, double awc[NSOILLAYER], double fevap, double snowpack,
  95. bool percolate, double max_rain_melt, double awcont[NSOILLAYER],
  96. double wcont[NSOILLAYER], double& wcont_evap, double& runoff, double& dperc) {
  97. // Daily update of water content for each soil layer given snow melt, rainfall,
  98. // evapotranspiration from vegetation (AET) and percolation between layers;
  99. // calculation of runoff
  100. // INPUT PARAMETERS
  101. // rain_melt = inward water flux to soil today (rain + snowmelt) (mm)
  102. // perc_base = coefficient in percolation calculation (K in Eqn 31, Haxeltine
  103. // & Prentice 1996)
  104. // perc_exp = exponent in percolation calculation (=4 in Eqn 31, Haxeltine &
  105. // Prentice 1996)
  106. // awc = array containing available water holding capacity of soil
  107. // layers (mm rainfall) [0=upper layer]
  108. // fevap = fraction of modelled area (grid cell or patch) subject to
  109. // evaporation from soil surface
  110. // snowpack = depth of snow (mm)
  111. // INPUT AND OUTPUT PARAMETERS
  112. // wcont = array containing water content of soil layers [0=upper layer] as
  113. // fraction of available water holding capacity (AWC)
  114. // wcont_evap = water content of evaporation sublayer at top of upper soil layer
  115. // as fraction of available water holding capacity (AWC)
  116. // awcont = wcont averaged over the growing season - guess2008
  117. // dperc = daily percolation beyond system (mm)
  118. // OUTPUT PARAMETER
  119. // runoff = total daily runoff from all soil layers (mm/day)
  120. const double SOILDEPTH_EVAP = 200.0;
  121. // depth of sublayer at top of upper soil layer, from which evaporation is
  122. // possible (NB: must not exceed value of global constant SOILDEPTH_UPPER)
  123. const double BASEFLOW_FRAC = 0.5;
  124. // Fraction of standard percolation amount from lower soil layer that is
  125. // diverted to baseflow runoff
  126. const double K_DEPTH = 0.4;
  127. const double K_AET = 0.52;
  128. // Fraction of total (vegetation) AET from upper soil layer that is derived
  129. // from the top K_DEPTH (fraction) of the upper soil layer
  130. // (parameters for calculating K_AET_DEPTH below)
  131. const double K_AET_DEPTH = (SOILDEPTH_UPPER / SOILDEPTH_EVAP - 1.0) *
  132. (K_AET / K_DEPTH - 1.0) / (1.0 / K_DEPTH - 1.0) + 1.0;
  133. // Weighting coefficient for AET flux from evaporation layer, assuming active
  134. // root density decreases with soil depth
  135. // Equates to 1.3 given SOILDEPTH_EVAP=200 mm, SOILDEPTH_UPPER=500 mm,
  136. // K_DEPTH=0.4, K_AET=0.52
  137. int s;
  138. // Reset annuals
  139. if (date.day == 0) {
  140. patch.aevap = 0.0;
  141. patch.asurfrunoff = 0.0;
  142. patch.adrainrunoff = 0.0;
  143. patch.abaserunoff = 0.0;
  144. patch.arunoff = 0.0;
  145. for (int d = 0; d < date.year_length(); d++) {
  146. patch.daet[d] = 0.0;
  147. patch.devap[d] = 0.0;
  148. patch.dmrro[d] = 0.0;
  149. #ifdef CRESCENDO_FACE
  150. patch.drunoff[d] = 0.0;
  151. patch.ddrain[d] = 0.0;
  152. #endif
  153. }
  154. }
  155. // Reset monthlys
  156. if (date.dayofmonth == 0) {
  157. patch.mevap[date.month] = 0.0;
  158. patch.mrunoff[date.month] = 0.0;
  159. patch.mrunoff_surf[date.month] = 0.0;
  160. }
  161. double aet; // AET for a particular layer and individual (mm)
  162. double aet_layer[NSOILLAYER]; // total AET for each soil layer (mm)
  163. double perc_frac;
  164. for (s=0; s<NSOILLAYER; s++) {
  165. aet_layer[s] = 0.0;
  166. }
  167. double aet_total = 0.0;
  168. // Sum AET for across all vegetation individuals
  169. Vegetation& vegetation=patch.vegetation;
  170. vegetation.firstobj();
  171. while (vegetation.isobj) {
  172. Individual& indiv = vegetation.getobj();
  173. for (s=0; s<NSOILLAYER; s++) {
  174. aet = !negligible(indiv.aet) ? patch.pft[indiv.pft.id].fwuptake[s] * indiv.aet : 0.0;
  175. aet_layer[s] += aet;
  176. aet_total += aet;
  177. }
  178. vegetation.nextobj();
  179. }
  180. // Evaporation from soil surface
  181. // guess2008 - changed to wcont_evap**2, as in LPJ-mL
  182. // - see Bondeau et al. (2007), Rost et al. (2008)
  183. // Added the snowdepth restriction too.
  184. double evap = 0.0;
  185. if (snowpack < 10.0) { // evap only if snow depth < 10mm
  186. evap = climate.eet * PRIESTLEY_TAYLOR * wcont_evap * wcont_evap * fevap;
  187. }
  188. // Implement in- and outgoing fluxes to upper soil layer
  189. // BLARP: water content can become negative, though apparently only very slightly
  190. // - quick fix implemented here, should be done better later
  191. wcont[0] += (rain_melt - aet_layer[0] - evap) / awc[0];
  192. if (wcont[0] != 0.0 && wcont[0] < 0.0001) { // guess2008 - bugfix
  193. wcont[0] = 0.0;
  194. }
  195. // Surface runoff
  196. double runoff_surf = 0.0;
  197. if (wcont[0] > 1.0) {
  198. runoff_surf = (wcont[0]-1.0) * awc[0];
  199. wcont[0] = 1.0;
  200. }
  201. // Update water content in evaporation layer for tomorrow
  202. wcont_evap += (rain_melt-aet_layer[0]*SOILDEPTH_EVAP*K_AET_DEPTH/SOILDEPTH_UPPER-evap)
  203. /awc[0];
  204. if (wcont_evap < 0) {
  205. wcont_evap = 0;
  206. }
  207. if (wcont_evap > wcont[0]) {
  208. wcont_evap = wcont[0];
  209. }
  210. // Percolation from evaporation layer
  211. double perc = 0.0;
  212. if (percolate) {
  213. perc = min(SOILDEPTH_EVAP/SOILDEPTH_UPPER*perc_base*pow(wcont_evap,perc_exp),
  214. max_rain_melt);
  215. }
  216. wcont_evap -= perc/awc[0];
  217. // Percolation and fluxes to and from lower soil layer(s)
  218. // Transfer percolation between soil layers
  219. // Excess water transferred to runoff
  220. // Eqns 26, 27, 31, Haxeltine & Prentice 1996
  221. double runoff_drain = 0.0;
  222. for (s=1; s<NSOILLAYER; s++) {
  223. // Percolation
  224. // Allow only on days with rain or snowmelt (Dieter Gerten, 021216)
  225. if (percolate) {
  226. perc = min(perc_base*pow(wcont[s-1],perc_exp), max_rain_melt);
  227. } else {
  228. perc=0.0;
  229. }
  230. perc_frac = min(perc/awc[s-1], wcont[s-1]);
  231. wcont[s-1] -= perc_frac;
  232. wcont[s] += perc_frac * awc[s-1] / awc[s];
  233. if (wcont[s] > 1.0) {
  234. runoff_drain += (wcont[s]-1.0)*awc[s];
  235. wcont[s] = 1.0;
  236. }
  237. // Deduct AET from this soil layer
  238. // BLARP! Quick fix here to prevent negative soil water
  239. wcont[s] -= aet_layer[s] / awc[s];
  240. if (wcont[s] < 0.0) {
  241. wcont[s] = 0.0;
  242. }
  243. }
  244. // Baseflow runoff (Dieter Gerten 021216) (rain or snowmelt days only)
  245. double runoff_baseflow = 0.0;
  246. if (percolate) {
  247. double perc_baseflow = BASEFLOW_FRAC*perc_base*pow(!negligible(wcont[NSOILLAYER - 1]) ? wcont[NSOILLAYER - 1] : 0.0, perc_exp);
  248. // guess2008 - Added "&& rain_melt >= runoff_surf" to guarantee nonnegative baseflow.
  249. if (perc_baseflow > rain_melt - runoff_surf && rain_melt >= runoff_surf) {
  250. perc_baseflow = rain_melt - runoff_surf;
  251. }
  252. // Deduct from water content of bottom soil layer
  253. perc_frac = min(perc_baseflow/awc[NSOILLAYER-1], wcont[NSOILLAYER-1]);
  254. wcont[NSOILLAYER-1] -= perc_frac;
  255. runoff_baseflow = perc_frac * awc[NSOILLAYER-1];
  256. }
  257. // save percolation from system (needed in leaching())
  258. dperc = runoff_baseflow + runoff_drain;
  259. runoff = runoff_surf + runoff_drain + runoff_baseflow;
  260. patch.asurfrunoff += runoff_surf;
  261. patch.adrainrunoff += runoff_drain;
  262. patch.abaserunoff += runoff_baseflow;
  263. patch.arunoff += runoff;
  264. patch.aaet += aet_total;
  265. patch.aevap += evap;
  266. patch.maet[date.month] += aet_total;
  267. patch.mevap[date.month] += evap;
  268. patch.mrunoff[date.month] += runoff;
  269. patch.mrunoff_surf[date.month] += runoff_surf;
  270. patch.daet[date.day] += aet_total;
  271. patch.devap[date.day] += evap;
  272. patch.dmrro[date.day] += runoff;
  273. #ifdef CRESCENDO_FACE
  274. patch.drunoff[date.day] += runoff_surf;
  275. patch.ddrain[date.day] += runoff_drain + runoff_baseflow;
  276. #endif
  277. // guess2008 - DLE - update awcont
  278. // Original algorithm by Thomas Hickler
  279. for (s=0; s<NSOILLAYER; s++) {
  280. // Reset the awcont array on the first day of every year
  281. if (date.day == 0) {
  282. awcont[s] = 0.0;
  283. if (s == 0) {
  284. patch.growingseasondays = 0;
  285. }
  286. }
  287. // If it's warm enough for growth, update awcont with this day's wcont
  288. if (climate.temp > 5.0) {
  289. awcont[s] += wcont[s];
  290. if (s==0) {
  291. patch.growingseasondays++;
  292. }
  293. }
  294. // Do the averaging on the last day of every year
  295. if (date.islastday && date.islastmonth) {
  296. awcont[s] /= (double)patch.growingseasondays;
  297. }
  298. // In case it's never warm enough:
  299. if (patch.growingseasondays < 1) {
  300. awcont[s] = 1.0;
  301. }
  302. }
  303. }
  304. /// Derive and re-distribute available rain-melt for today
  305. /** Function to be called after interception and before canopy_exchange
  306. * Calculate snowmelt
  307. * If there's any rain-melt available, refill top layer, leaving any excessive
  308. * rainmelt to be re-distributed later in hydrology_lpjf
  309. */
  310. void initial_infiltration(Patch& patch, Climate& climate) {
  311. Soil& soil = patch.soil;
  312. snow(climate.prec - patch.intercep, climate.temp, soil.snowpack, soil.rain_melt);
  313. snow_ninput(climate.prec - patch.intercep, soil.snowpack, soil.rain_melt, climate.dndep, patch.dnfert, soil.snowpack_nmass, soil.ninput);
  314. soil.percolate = soil.rain_melt >= 0.1;
  315. soil.max_rain_melt = soil.rain_melt;
  316. patch.fluxes.report_flux(Fluxes::NDEP, climate.dndep);
  317. if (soil.percolate) {
  318. soil.wcont[0] += soil.rain_melt / soil.soiltype.awc[0];
  319. if (soil.wcont[0] > 1) {
  320. soil.rain_melt = (soil.wcont[0] - 1) * soil.soiltype.awc[0];
  321. soil.wcont[0] = 1;
  322. } else {
  323. soil.rain_melt = 0;
  324. }
  325. soil.wcont_evap = soil.wcont[0];
  326. }
  327. }
  328. /// Calculate required irrigation according to water deficiency.
  329. /** Function to be called after canopy_exchange and before soilwater.
  330. */
  331. void irrigation(Patch& patch) {
  332. Soil& soil = patch.soil;
  333. patch.irrigation_d = 0.0;
  334. if (date.day == 0) {
  335. for (int m = 0; m < 12; m++) {
  336. patch.irrigation_m[m] = 0.0;
  337. }
  338. patch.irrigation_y = 0.0;
  339. }
  340. if (!patch.stand.isirrigated) {
  341. return;
  342. }
  343. for (int i = 0; i < npft; i++) {
  344. Patchpft& ppft = patch.pft[i];
  345. if (patch.stand.pft[i].irrigated && ppft.growingseason()) {
  346. if (ppft.water_deficit_d < 0.0) {
  347. fail("irrigation: Negative water deficit for PFT %s!\n", (char*)ppft.pft.name);
  348. }
  349. patch.irrigation_d += ppft.water_deficit_d;
  350. }
  351. }
  352. patch.irrigation_m[date.month] += patch.irrigation_d;
  353. patch.irrigation_y += patch.irrigation_d;
  354. soil.rain_melt += patch.irrigation_d;
  355. soil.max_rain_melt += patch.irrigation_d;
  356. }
  357. ///////////////////////////////////////////////////////////////////////////////////////
  358. // SOIL WATER
  359. // Call this function each simulation day for each modelled area or patch, following
  360. // calculation of vegetation production and evapotranspiration and before soil organic
  361. // matter and litter dynamics
  362. void soilwater(Patch& patch, Climate& climate) {
  363. // DESCRIPTION
  364. // Performs daily accounting of soil water
  365. // Sum vegetation phenology-weighted FPC
  366. // Fraction of grid cell subject to evaporation from soil surface is
  367. // complement of summed vegetation projective cover (FPC)
  368. double fpc_phen_total = 0.0; // phenology-weighted FPC sum for patch
  369. Vegetation& vegetation = patch.vegetation;
  370. vegetation.firstobj();
  371. while (vegetation.isobj) {
  372. Individual& indiv = vegetation.getobj();
  373. fpc_phen_total += indiv.fpc_today();
  374. vegetation.nextobj();
  375. }
  376. Soil& soil = patch.soil;
  377. hydrology_lpjf(patch, climate, soil.rain_melt, soil.soiltype.perc_base,
  378. soil.soiltype.perc_exp, soil.soiltype.awc, max(1.0-fpc_phen_total,0.0),
  379. soil.snowpack, soil.percolate, soil.max_rain_melt, soil.awcont, soil.wcont,
  380. soil.wcont_evap, soil.runoff, soil.dperc);
  381. }
  382. ///////////////////////////////////////////////////////////////////////////////////////
  383. // REFERENCES
  384. //
  385. // Haxeltine A & Prentice IC 1996 BIOME3: an equilibrium terrestrial biosphere
  386. // model based on ecophysiological constraints, resource availability, and
  387. // competition among plant functional types. Global Biogeochemical Cycles 10:
  388. // 693-709
  389. // Bondeau, A., Smith, P.C., Zaehle, S., Schaphoff, S., Lucht, W., Cramer, W.,
  390. // Gerten, D., Lotze-Campen, H., Müller, C., Reichstein, M. and Smith, B. (2007),
  391. // Modelling the role of agriculture for the 20th century global terrestrial carbon balance.
  392. // Global Change Biology, 13: 679-706. doi: 10.1111/j.1365-2486.2006.01305.x
  393. // Rost, S., D. Gerten, A. Bondeau, W. Luncht, J. Rohwer, and S. Schaphoff (2008),
  394. // Agricultural green and blue water consumption and its influence on the global
  395. // water system, Water Resour. Res., 44, W09405, doi:10.1029/2007WR006331