cropphenology.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588
  1. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2. /// \file cropphenology.cpp
  3. /// \brief Crop phenology including phu calculations
  4. /// \author Mats Lindeskog
  5. /// $Date: $
  6. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  7. #include "config.h"
  8. #include "landcover.h"
  9. #include "cropphenology.h"
  10. const double MAXHUTEMP = 30; // Degree limit for heat unit summation
  11. /// Calculation of down-scaling of lai during crop senescence
  12. /** Follows Bondeau et al. 2007.
  13. */
  14. double senescence_curve(Pft& pft, double fphu) {
  15. if (pft.shapesenescencenorm)
  16. return pow(1-fphu,2) / pow(1 - pft.fphusen, 2) * (1 - pft.flaimaxharvest) + pft.flaimaxharvest;
  17. else
  18. return pow(1 - fphu, 0.5) / pow(1 - pft.fphusen, 0.5) * (1 - pft.flaimaxharvest) + pft.flaimaxharvest;
  19. }
  20. /// Initiation of potential heat unit calculation
  21. /** Calculates pvd (required vernalising days), tb (base temperature)
  22. * and phu (potential heat units) based on Bondeau et al. 2007.
  23. * Dynamic phu calculation based on Lindeskog et al. 2013.
  24. * Called on sowing date.
  25. */
  26. void phu_init(cropphen_struct& ppftcrop, Gridcellpft& gridcellpft, Patch& patch) {
  27. Pft& pft = gridcellpft.pft;
  28. const Climate& climate = patch.get_climate();
  29. double phu_last_year = ppftcrop.phu;
  30. ppftcrop.husum = 0.0;
  31. ppftcrop.vrf = 1.0;
  32. ppftcrop.vdsum = 0;
  33. ppftcrop.prf = 1.0;
  34. ppftcrop.pvd = pft.pvd; // default; kept for TrMi, TePu, TeSb, TrMa, TeSo, TrPe
  35. ppftcrop.phu = pft.phu;
  36. ppftcrop.tb = pft.tb;
  37. ppftcrop.vdsum_alloc=0.0;
  38. ppftcrop.vd=0.0;
  39. ppftcrop.dev_stage=0.0;
  40. // Calculation of phu and pvd according to Bondeau et al. 2007
  41. if (pft.ifsdautumn) { // TeWW,TeRa
  42. // maximum pvd allowed
  43. const int max_pvd = 60;
  44. if (gridcellpft.wintertype) { // Autumn sowing
  45. // if neither spring or winter conditions for the past 20 years
  46. if ((gridcellpft.first_autumndate20 == climate.testday_temp || gridcellpft.first_autumndate20 == climate.coldestday)
  47. && gridcellpft.first_autumndate % date.year_length() == gridcellpft.first_autumndate20
  48. && (gridcellpft.last_springdate20 == climate.testday_temp || gridcellpft.last_springdate20 == climate.coldestday)
  49. && gridcellpft.last_springdate == gridcellpft.last_springdate20) {
  50. ppftcrop.pvd = pft.pvd;
  51. ppftcrop.phu = pft.phu;
  52. }
  53. // not all past 20 years without vernendoccurred: too cold
  54. else if (!(gridcellpft.last_verndate20 == gridcellpft.last_springdate20 + def_verndate_ndays_after_last_springdate
  55. && gridcellpft.last_verndate == gridcellpft.last_verndate20)) {
  56. // pvd (required vernalising days): undocumented equations from Bondeau's code
  57. // vernalization (below 12 degrees) is supposed to occur directly at sowing (trg=tempautumn) for TeWW, for TeRa a 20-day lag (tempautumn=17)
  58. // first_autumndate20 occurred before last_verndate20
  59. if ((ppftcrop.sdate < 180 || gridcellpft.last_verndate20 >= 180) && climate.lat >= 0.0 || climate.lat < 0.0) {
  60. ppftcrop.pvd = (int)max(0, min(max_pvd, gridcellpft.last_verndate20 - ppftcrop.sdate - pft.vern_lag));
  61. }
  62. // first_autumndate20 occurred after last_verndate20
  63. else {
  64. ppftcrop.pvd = (int)max(0, min(max_pvd, gridcellpft.last_verndate20 + date.year_length() - ppftcrop.sdate - pft.vern_lag));
  65. }
  66. // phu (potential heat units): quadratic calculation according to sowing month; see Fig.2 in Bondeau et al.2007
  67. const double k1 = -0.1081;
  68. const double k2 = 3.1633;
  69. if (ppftcrop.sdate < 184 + climate.adjustlat) {
  70. ppftcrop.phu = max(pft.phu_min, k1 * pow((double)(ppftcrop.sdate - climate.adjustlat),2) + k2 * ((double)(ppftcrop.sdate - climate.adjustlat)) + pft.phu_max);
  71. }
  72. else {
  73. ppftcrop.phu = max(pft.phu_min, k1 * pow((double)ppftcrop.sdate - date.year_length(),2) + k2 * ((double)ppftcrop.sdate - 365) + pft.phu_max);
  74. ppftcrop.phu *= pft.phu_red_spring_sow; // undocumented reduction in spring variants from Bondeau's code
  75. }
  76. }
  77. }
  78. else { // spring sowing
  79. // default pvd of spring varieties when vernalisation has not occurred during the past 20 years
  80. const int pvd_def_spring = 30;
  81. // phu of spring varieties when vernalisation has occurred during the past 20 years
  82. const double phu_spring_ifvern = 1300.0;
  83. // phu of spring varieties when vernalisation has not occurred during the past 20 years
  84. const double phu_spring_ifnvern = 1500.0;
  85. // If last_verndate has occurred during the past 20 years (or too warm):
  86. if (!(gridcellpft.last_verndate20 == ppftcrop.sdate + def_verndate_ndays_after_last_springdate
  87. && gridcellpft.last_verndate == gridcellpft.last_verndate20)) {
  88. ppftcrop.pvd = (int)min(max_pvd, gridcellpft.last_verndate20 - ppftcrop.sdate);
  89. ppftcrop.phu = phu_spring_ifvern;
  90. }
  91. // If no last_verndate occurred during the past 20 year (too cold):
  92. else {
  93. ppftcrop.pvd = pvd_def_spring;
  94. ppftcrop.phu = phu_spring_ifnvern;
  95. }
  96. }
  97. }
  98. else {
  99. // phu: Linear calculation according to sowing month; see Fig.2 in Bondeau et al.2007
  100. if (pft.phu_calc_lin) {
  101. ppftcrop.phu = min(pft.phu_max, max(pft.phu_min, -(pft.phu_max - pft.phu_min) / pft.ndays_ramp_phu * (double)(ppftcrop.sdate - climate.adjustlat) + pft.phu_interc));
  102. }
  103. }
  104. // Calculation of potential heat units according to local climate.
  105. if (ifcalcdynamic_phu) {
  106. const double min_phu = 900.0; // minimum allowed phu based on phu range in the literature
  107. const int min_phu_sample_period = 20; // minimum no. of years of the phu sample period
  108. // add last year's husum_max to running 10-year mean
  109. if (ppftcrop.husum_max) {
  110. ppftcrop.nyears_hu_sample++;
  111. int years = min(ppftcrop.nyears_hu_sample, 10);
  112. ppftcrop.husum_max_10 = (ppftcrop.husum_max_10 * (years - 1) + ppftcrop.husum_max) / years;
  113. }
  114. ppftcrop.husum_max = 0.0;
  115. ppftcrop.phu_old = ppftcrop.phu; // phu_old for printout
  116. // set phu according to running mean
  117. if (ppftcrop.nyears_hu_sample)
  118. ppftcrop.phu = max(min_phu, 0.9 * ppftcrop.husum_max_10);
  119. // ... unless past specified time period
  120. if (ifdyn_phu_limit && patch.stand.get_gridcell().getsimulationyear(date.year) >= patch.stand.first_year + min_phu_sample_period && patch.stand.get_gridcell().getsimulationyear(date.year) >= nyear_spinup + nyear_dyn_phu)
  121. ppftcrop.phu = phu_last_year;
  122. }
  123. }
  124. /// Calculation of harvest index
  125. /** Based on fphu. Restricted by water stress.
  126. * SWAT equations are from Neitsch et al. 2002.
  127. */
  128. void harvest_index(Patch& patch, Pft& pft) {
  129. double wdf, fwdf, hi_save;
  130. Patchpft& patchpft = patch.pft[pft.id];
  131. cropphen_struct& ppftcrop = *(patchpft.get_cropphen());
  132. ppftcrop.hi = pft.hiopt * 100 * ppftcrop.fphu / (100 * ppftcrop.fphu + exp(11.1 - 10.0 * ppftcrop.fphu)); // SWAT 5:2.4.1
  133. ppftcrop.fhi_phen = ppftcrop.hi / pft.hiopt;
  134. // Correction of HI according to water stress:
  135. ppftcrop.demandsum_crop += patch.wdemand;
  136. if (patchpft.wsupply > patch.wdemand)
  137. ppftcrop.supplysum_crop += patch.wdemand;
  138. else
  139. ppftcrop.supplysum_crop += patchpft.wsupply;
  140. if (ppftcrop.demandsum_crop > 0.0)
  141. wdf = 100.0 * ppftcrop.supplysum_crop / ppftcrop.demandsum_crop; // SWAT 5:3.3.2 : aetsum/petsum
  142. else
  143. wdf = 100.0;
  144. fwdf = wdf / (wdf + exp(6.13 - 0.0883 * wdf)); // (SWAT 5:3.3.1)
  145. hi_save = ppftcrop.hi;
  146. ppftcrop.hi = ppftcrop.fhi_phen * ((pft.hiopt - pft.himin) * fwdf + pft.himin);
  147. if (ppftcrop.hi > 0.0 && hi_save)
  148. ppftcrop.fhi_water = ppftcrop.hi / hi_save;
  149. ppftcrop.fhi = ppftcrop.fhi_phen * ppftcrop.fhi_water;
  150. }
  151. /// Calculation of accumulated of heat units
  152. /** Accumulation of heat units during sampling period used for calculation of
  153. * dynamic phu if ifcalcdynamic_phu = true. SWAT equation is from Neitsch et al. 2002
  154. */
  155. void heat_units(Patch& patch, Pft& pft) {
  156. Patchpft& patchpft = patch.pft[pft.id];
  157. cropphen_struct& ppftcrop = *(patchpft.get_cropphen());
  158. const Climate& climate = patch.get_climate();
  159. // calculation av fphu:
  160. double hu = max(0.0, min(climate.temp, MAXHUTEMP) - ppftcrop.tb);
  161. // account for vernalization if needs for vernalization not yet satisfied //trg=tb for crops other than TeWW and TeRa and don't enter here
  162. if (climate.temp < pft.trg && ppftcrop.vdsum < ppftcrop.pvd) { //trg=12 for TeWW & TeRa
  163. ppftcrop.vdsum++;
  164. ppftcrop.vrf = min(1.0, (double)ppftcrop.vdsum / (double)ppftcrop.pvd);
  165. // vernalisation reduction factor has no effect once temp>trg even if needs are not satisfied
  166. // no effect as well if temp>trg at the beginning of the growing season...
  167. hu *= ppftcrop.vrf;
  168. }
  169. // account for response to photoperiod
  170. ppftcrop.prf = (1 - pft.psens) * min(1.0, max(0.0, (climate.daylength_save[date.day] - pft.pb) / (pft.ps - pft.pb))) + pft.psens;
  171. hu *= ppftcrop.prf;
  172. if (date.day == ppftcrop.sdate) {
  173. ppftcrop.husum = 0.0;
  174. }
  175. // Accumulate heat units during growing period
  176. if (ppftcrop.growingseason) {
  177. // daily effective temperature sum (degree-days)
  178. ppftcrop.husum += hu;
  179. // phenological scale (fraction of growing season)
  180. ppftcrop.fphu = min(1.0, ppftcrop.husum / ppftcrop.phu); // SWAT 5:2.1.11
  181. }
  182. // Sample heat units for dynamic phu calculation
  183. if (ifcalcdynamic_phu) {
  184. if (date.day == ppftcrop.sdate) {
  185. ppftcrop.hu_samplingperiod = true;
  186. ppftcrop.hu_samplingdays = 0;
  187. ppftcrop.husum_sampled = 0;
  188. }
  189. if (ppftcrop.hu_samplingperiod) {
  190. ppftcrop.husum_sampled += hu;
  191. ppftcrop.hu_samplingdays++;
  192. if (date.day == ppftcrop.hucountend) {
  193. ppftcrop.husum_sampled -= hu; // Don't count the hu's on last day
  194. ppftcrop.husum_max = ppftcrop.husum_sampled;
  195. ppftcrop.hu_samplingperiod = false;
  196. }
  197. }
  198. }
  199. }
  200. /// Temperature factor used in development stage calculation
  201. inline double temperature_factor(double temp, double min, double opt, double max) {
  202. if (temp <= min || temp >= max) {
  203. return 0;
  204. }
  205. double _opt = opt - min;
  206. double alpha = log(2.) / log((max - min) / _opt);
  207. return (2 * pow(temp - min, alpha) * pow(_opt, alpha) - pow(temp - min, 2*alpha))/
  208. pow(_opt, 2*alpha);
  209. }
  210. /// Calculation of development stage
  211. /** Accumulation of development during sampling period, based on Wang & Engel 1998.
  212. */
  213. void development_stage(Patch& patch, Pft& pft) {
  214. Patchpft& patchpft = patch.pft[pft.id];
  215. cropphen_struct& ppftcrop = *(patchpft.get_cropphen());
  216. const Climate& climate = patch.get_climate();
  217. // account for vernalization if needs for vernalization not yet satisfied //trg=tb for crops other than TeWW and TeRa and don't enter here
  218. if (ppftcrop.vdsum_alloc < 1 && climate.temp > pft.T_vn_min && climate.temp < pft.T_vn_max) {
  219. ppftcrop.vd += temperature_factor(climate.temp, pft.T_vn_min, pft.T_vn_opt, pft.T_vn_max);
  220. double vd5 = pow(ppftcrop.vd, 5.);
  221. ppftcrop.vdsum_alloc = min(1.0, vd5 / (pow(22.5, 5.0) + vd5));
  222. }
  223. double daylength = max(0.0, climate.daylength_save[date.day] - pft.photo[0]);
  224. double e = exp(-pft.photo[1] * daylength);
  225. double fP = min(1.0, pft.photo[2] > 0 ? e : 1.0 - e);
  226. double T_min = pft.T_veg_min;
  227. double T_opt = pft.T_veg_opt;
  228. double T_max = pft.T_veg_max;
  229. if (ppftcrop.dev_stage >= 1) {
  230. T_min = pft.T_rep_min;
  231. T_opt = pft.T_rep_opt;
  232. T_max = pft.T_rep_max;
  233. }
  234. double fT = min(1.0, temperature_factor(climate.temp, T_min, T_opt, T_max));
  235. double dev_rate = 0.0;
  236. if (ppftcrop.dev_stage < 1.0)
  237. dev_rate = pft.dev_rate_veg * ppftcrop.vdsum_alloc * fP * fT;
  238. else
  239. dev_rate = pft.dev_rate_rep * fT;
  240. ppftcrop.dev_stage = min(2.0, ppftcrop.dev_stage + dev_rate);
  241. }
  242. /// Handles heat unit and harvest index calculation and identifies harvest, senescence and intercrop events.
  243. /** Accumulation of heat units during sampling period used for calculation of dynamic phu if DYNAMIC_PHU defined.
  244. * Sets patchpft.cropphen variables growingseason, hdate, intercropseason and senescence
  245. */
  246. void crop_phenology(Patch& patch) {
  247. patch.pft.firstobj();
  248. while (patch.pft.isobj) {
  249. Patchpft& patchpft = patch.pft.getobj();
  250. Pft& pft=patchpft.pft;
  251. Standpft& standpft = patch.stand.pft[pft.id];
  252. Gridcell& gridcell = patch.stand.get_gridcell();
  253. Climate& climate = gridcell.climate;
  254. Gridcellpft& gridcellpft = gridcell.pft[pft.id];
  255. if (patch.stand.pft[pft.id].active) {
  256. if (pft.phenology == CROPGREEN) {
  257. cropphen_struct& ppftcrop = *(patchpft.get_cropphen());
  258. ppftcrop.growingseason_ystd = ppftcrop.growingseason;
  259. // resets on first day of the year:
  260. if (date.day == 0) {
  261. ppftcrop.fphu_harv = -1.0;
  262. ppftcrop.fhi_harv = -1.0;
  263. ppftcrop.sdate_harv = -1;
  264. ppftcrop.nsow = 0;
  265. ppftcrop.sendate = -1;
  266. ppftcrop.nharv = 0;
  267. ppftcrop.sownlastyear=false;
  268. for(int i=0;i<2;i++) {
  269. ppftcrop.sdate_harvest[i] = -1;
  270. ppftcrop.hdate_harvest[i] = -1;
  271. ppftcrop.sdate_thisyear[i] = -1;
  272. }
  273. }
  274. // initiations on sowing day:
  275. if (date.day == ppftcrop.sdate) {
  276. ppftcrop.fphu = 0.0;
  277. ppftcrop.fhi = 0.0;
  278. ppftcrop.fhi_phen = 0.0;
  279. ppftcrop.fhi_water = 1.0;
  280. ppftcrop.hdate = -1;
  281. ppftcrop.bicdate = -1;
  282. ppftcrop.growingseason = true;
  283. ppftcrop.growingdays = 0;
  284. ppftcrop.nsow++;
  285. if (ppftcrop.nsow == 1)
  286. ppftcrop.sdate_thisyear[0] = ppftcrop.sdate;
  287. else if (ppftcrop.nsow == 2)
  288. ppftcrop.sdate_thisyear[1] = ppftcrop.sdate;
  289. // calculate pvd, phu & tb
  290. phu_init(ppftcrop, gridcellpft, patch);
  291. }
  292. // Calculation of accumulated heat units and harvest index from sowing to maturity
  293. if (ppftcrop.growingseason) {
  294. ppftcrop.senescence_ystd = ppftcrop.senescence;
  295. ppftcrop.intercropseason = false;
  296. ppftcrop.growingdays++;
  297. // check if harvest is prescribed
  298. bool force_harvest = date.day == standpft.hdate_force;
  299. // before maturity is reached
  300. bool pre_maturity = ifnlim ? ppftcrop.dev_stage < 2.0 : ppftcrop.husum < ppftcrop.phu;
  301. if (pre_maturity && dayinperiod(date.day, ppftcrop.sdate, stepfromdate(ppftcrop.hlimitdate, -1)) && !force_harvest) {
  302. // count accumulated heat units after sowing date
  303. heat_units(patch, pft);
  304. if (ifnlim)
  305. development_stage(patch, pft);
  306. // test for senescence
  307. if (ppftcrop.fphu >= pft.fphusen) {
  308. if (ppftcrop.senescence_ystd == false)
  309. ppftcrop.sendate = date.day;
  310. ppftcrop.senescence = true;
  311. }
  312. // calculated harvest index
  313. harvest_index(patch, pft);
  314. }
  315. else { // harvest
  316. // save today as harvest day
  317. ppftcrop.hdate = date.day;
  318. ppftcrop.growingseason = false;
  319. ppftcrop.intercropseason = false;
  320. ppftcrop.senescence = false;
  321. ppftcrop.fertilised[0] = false;
  322. ppftcrop.fertilised[1] = false;
  323. ppftcrop.fertilised[2] = false;
  324. // set start of intercrop grass growth
  325. ppftcrop.bicdate = stepfromdate(ppftcrop.hdate, 15);
  326. // count number of harvest events this year
  327. ppftcrop.nharv++;
  328. // Save phenological values and dates at harvest:
  329. ppftcrop.fphu_harv = ppftcrop.fphu;
  330. ppftcrop.fhi_harv = ppftcrop.fhi;
  331. ppftcrop.sdate_harv = ppftcrop.sdate;
  332. ppftcrop.lgp = ppftcrop.growingdays;
  333. // allowing saving at two harvests per year
  334. if (ppftcrop.nharv == 1) {
  335. ppftcrop.sdate_harvest[0] = ppftcrop.sdate;
  336. ppftcrop.hdate_harvest[0] = date.day;
  337. if (ppftcrop.sdate > date.day)
  338. ppftcrop.sownlastyear = true;
  339. }
  340. else if (ppftcrop.nharv == 2) {
  341. ppftcrop.sdate_harvest[1] = ppftcrop.sdate;
  342. ppftcrop.hdate_harvest[1] = date.day;
  343. }
  344. ppftcrop.demandsum_crop = 0.0;
  345. ppftcrop.supplysum_crop = 0.0;
  346. ppftcrop.sdate = -1;
  347. ppftcrop.eicdate = -1;
  348. } //end harvest
  349. } //from sowing has taken place until harvest day
  350. // continue sampling heat units from hdate until last sampling date
  351. if (ifcalcdynamic_phu && ppftcrop.growingseason == false && ppftcrop.hu_samplingperiod) {
  352. heat_units(patch, pft);
  353. }
  354. if (patch.stand.pftid == pft.id && stlist[patch.stand.stid].intercrop == NATURALGRASS) {
  355. if (!ppftcrop.intercropseason && date.day == ppftcrop.bicdate) {
  356. ppftcrop.intercropseason = true;
  357. }
  358. if (date.day == ppftcrop.eicdate) {
  359. ppftcrop.intercropseason = false;
  360. }
  361. }
  362. }
  363. else if (pft.phenology == ANY) { // crop grasses using standard guess phenology calculation
  364. if (patch.stand.pftid != pft.id) {
  365. cropphen_struct& ppftcrop = *(patchpft.get_cropphen());
  366. if (date.day == 0) {
  367. ppftcrop.nharv = 0;
  368. }
  369. if (date.day == patch.pft[patch.stand.pftid].cropphen->bicdate) {
  370. ppftcrop.growingseason = true;
  371. ppftcrop.growingdays = 0;
  372. }
  373. else if (date.day == patch.pft[patch.stand.pftid].cropphen->eicdate) {
  374. ppftcrop.growingseason = false;
  375. ppftcrop.lgp = ppftcrop.growingdays;
  376. }
  377. if (ppftcrop.growingseason == true) {
  378. ppftcrop.growingdays++;
  379. }
  380. }
  381. }
  382. }
  383. patch.pft.nextobj();
  384. }
  385. }
  386. /// Updates crop phen from yesterday's lai_daily
  387. /** True crops derive phen from yesterday's fpc_daily, assuming only one crop individual.
  388. * Intercrop grass and pasture grass grown in crop stands use gdd5 and is treated
  389. * similar to pasture grass.
  390. */
  391. void leaf_phenology_crop(Pft& pft, Patch& patch) {
  392. Gridcell& gridcell = patch.stand.get_gridcell();
  393. Climate& climate = gridcell.climate;
  394. Patchpft& patchpft = patch.pft[pft.id];
  395. cropphen_struct& ppftcrop = *(patchpft.get_cropphen());
  396. if (pft.phenology == CROPGREEN) {
  397. if (ppftcrop.growingseason) {
  398. Vegetation& vegetation = patch.vegetation;
  399. vegetation.firstobj();
  400. while (vegetation.isobj) {
  401. Individual& indiv = vegetation.getobj();
  402. if (indiv.pft.id == pft.id) {
  403. patchpft.phen = indiv.fpc ? indiv.fpc_daily / indiv.fpc : 0;
  404. }
  405. vegetation.nextobj();
  406. }
  407. }
  408. else if (date.day == ppftcrop.hdate) {
  409. patchpft.phen = 0.0;
  410. }
  411. }
  412. else if (pft.phenology == ANY) { // crop grasses using standard guess phenology calculation
  413. if (patch.stand.pftid == pft.id // pasture grass in crop stand
  414. || patch.stand.hasgrassintercrop && (patch.pft[patch.stand.pftid].cropphen->intercropseason // intercrop grass
  415. || date.day == patch.pft[patch.stand.pftid].cropphen->eicdate)) { // intercrop grass
  416. if (patch.stand.pftid != pft.id) {
  417. if (date.day == patch.pft[patch.stand.pftid].cropphen->bicdate) {
  418. patch.stand.gdd0_intercrop = climate.gdd5;
  419. }
  420. if (date.day == patch.pft[patch.stand.pftid].cropphen->eicdate) {
  421. patch.stand.gdd0_intercrop = 0.0;
  422. patchpft.phen = 0.0;
  423. }
  424. }
  425. // reset stand.gdd0_intercrop same day as gdd5
  426. if (climate.lat >= 0.0 && date.day == COLDEST_DAY_NHEMISPHERE
  427. || climate.lat < 0.0 && date.day == COLDEST_DAY_SHEMISPHERE
  428. || climate.gdd5 == 0.0) {
  429. patch.stand.gdd0_intercrop = 0.0;
  430. }
  431. if (ppftcrop.growingseason) { // includes bicdate, not eicdate
  432. if (patch.stand.pftid == pft.id || gridcell.pft[patch.stand.pftid].sowing_restriction) { // Normal grass growth: gives identical result to natural stands.
  433. patchpft.phen = min(1.0, climate.gdd5 / pft.phengdd5ramp);
  434. }
  435. else if (patch.stand.gdd0_intercrop > 0.0) {
  436. patchpft.phen = min(1.0, (climate.gdd5 - patch.stand.gdd0_intercrop) / (pft.phengdd5ramp * 0.9)); // intercrop grass
  437. }
  438. else {
  439. patchpft.phen = min(1.0, (climate.gdd5 - patch.stand.gdd0_intercrop) / pft.phengdd5ramp); // intercrop grass
  440. }
  441. if (patchpft.phen < 0.0) {
  442. patchpft.phen = 0.0;
  443. }
  444. // raingreen phenology
  445. if (patchpft.wscal < pft.wscal_min) {
  446. patchpft.phen = 0.0;
  447. patch.stand.gdd0_intercrop = climate.gdd5;
  448. }
  449. }
  450. }
  451. }
  452. }
  453. //////////////////////////////////////////////////////////////////////////////////////////
  454. // REFERENCES
  455. //
  456. // Bondeau A, Smith PC, Zaehle S, Schaphoff S, Lucht W, Cramer W, Gerten D, Lotze-Campen H,
  457. // Müller C, Reichstein M & Smith B 2007. Modelling the role of agriculture for the
  458. // 20th century global terrestrial carbon balance. Global Change Biology, 13:679-706.
  459. // Lindeskog M, Arneth A, Bondeau A, Waha K, Seaquist J, Olin S, & Smith B 2013.
  460. // Implications of accounting for land use in simulations of ecosystem carbon cycling
  461. // in Africa. Earth Syst Dynam 4:385-407.
  462. // Neitsch SL, Arnold JG, Kiniry JR et al.2002 Soil and Water Assessment Tool, Theorethical
  463. // Documentation + User's Manual. USDA_ARS-SR Grassland, Soil and Water Research Laboratory.
  464. // Agricultural Reasearch Service, Temple,Tx, US.
  465. // Wang, E. and Engel, T. 1998 Simulation of phenological development
  466. // of wheat crops, Agr. Syst., 58, 1-24