guess.cpp 84 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274
  1. ///////////////////////////////////////////////////////////////////////////////////////
  2. /// \file guess.cpp
  3. /// \brief LPJ-GUESS Combined Modular Framework
  4. ///
  5. /// \author Ben Smith
  6. /// $Date: 2014-05-13 14:55:59 +0200 (Tue, 13 May 2014) $
  7. ///
  8. ///////////////////////////////////////////////////////////////////////////////////////
  9. #include <sstream>
  10. #include "config.h"
  11. #include "guess.h"
  12. #include <netcdf.h>
  13. ///////////////////////////////////////////////////////////////////////////////////////
  14. // GLOBAL VARIABLES WITH EXTERNAL LINKAGE
  15. // These variables are declared in the framework header file, and defined here.
  16. // They are accessible throughout the model code.
  17. Date date; // object describing timing stage of simulation
  18. int npft; // number of possible PFTs
  19. int nst; // number of possible stand types
  20. int nst_lc[NLANDCOVERTYPES]; // number of possible stand types in each land cover type
  21. int nmt; // number of possible management types
  22. ManagementTypelist mtlist;
  23. StandTypelist stlist;
  24. Pftlist pftlist;
  25. // emission ratios from fire (NH3, NOx, N2O, N2) Delmas et al. 1995
  26. const double Fluxes::NH3_FIRERATIO = 0.005;
  27. const double Fluxes::NOx_FIRERATIO = 0.237;
  28. const double Fluxes::N2O_FIRERATIO = 0.036;
  29. const double Fluxes::N2_FIRERATIO = 0.722;
  30. // IFS related experiment settings for CMIPx
  31. // Year of
  32. ////////////////////////////////////////////////////////////////////////////////
  33. // Implementation of PhotosynthesisResult member functions
  34. ////////////////////////////////////////////////////////////////////////////////
  35. /*void PhotosynthesisResult::serialize(ArchiveStream& arch) {
  36. arch & agd_g
  37. & adtmm
  38. & rd_g
  39. & vm
  40. & je
  41. & nactive_opt
  42. & vmaxnlim;
  43. }*/
  44. ////////////////////////////////////////////////////////////////////////////////
  45. // Implementation of Climate member functions
  46. ////////////////////////////////////////////////////////////////////////////////
  47. // ecev3
  48. void Climate::setdrivers(double ifstemp, double ifsprec, double ifsrad, double ifslw, double tm5co2, double ifstemp_soil, double ifssoilw_surf, double ifssoilw_deep, double dailyndep, double dailynfert) {
  49. temp=ifstemp;
  50. prec=ifsprec;
  51. insol=ifsrad;
  52. netlw = ifslw;
  53. co2=tm5co2;
  54. dndep=dailyndep;
  55. //dnfert=dailynfert;
  56. // needed if we're forcing with IFS soil properties:
  57. ifssoiltemp=ifstemp_soil; // degC
  58. ifsw_surf=ifssoilw_surf;
  59. ifsw_deep=ifssoilw_deep;
  60. gridcell.ifs_co2[date.day] = tm5co2;
  61. gridcell.ifs_par[date.day] = ifsrad;
  62. gridcell.ifs_lw[date.day] = ifslw;
  63. gridcell.ifs_precip[date.day] = ifsprec;
  64. gridcell.ifs_temp2m[date.day] = ifstemp;
  65. gridcell.ifs_tempsoil[date.day] = ifstemp_soil;
  66. gridcell.ifs_soilw_surf[date.day] = ifssoilw_surf;
  67. gridcell.ifs_soilw_deep[date.day] = ifssoilw_deep;
  68. // ecev3 - bugfix - set DTR to 0 in the BVOC calculation.
  69. // Will be updated in CRESCENDO
  70. dtr = 0.0;
  71. }
  72. void Climate::serialize(ArchiveStream& arch) {
  73. arch & temp
  74. & rad
  75. & par
  76. & prec
  77. & daylength
  78. & co2
  79. & lat
  80. & insol
  81. & instype
  82. & eet
  83. & mtemp
  84. & mtemp_min20
  85. & mtemp_max20
  86. & mtemp_max
  87. & gdd5
  88. & agdd5
  89. & agdd5_5
  90. & chilldays
  91. & ifsensechill
  92. & gtemp
  93. & dtemp_31
  94. & dprec_31
  95. & deet_31
  96. & mtemp_min_20
  97. & mtemp_max_20
  98. & mtemp_min
  99. & atemp_mean
  100. & mtemp_K
  101. & sinelat
  102. & cosinelat
  103. & qo & u & v & hh & sinehh
  104. & daylength_save
  105. & doneday
  106. & andep
  107. & dndep
  108. & dprec_10
  109. & sprec_2
  110. & maxtemp
  111. & mtemp_20
  112. & mprec_20
  113. & mpet_20
  114. & mprec_pet_20
  115. & mprec_petmin_20
  116. & mprec_petmax_20
  117. & mtemp20
  118. & mprec20
  119. & mpet20
  120. & mprec_pet20
  121. & mprec_petmin20
  122. & mprec_petmax20
  123. & hmtemp_20
  124. & hmprec_20
  125. & hmeet_20
  126. & seasonality
  127. & seasonality_lastyear
  128. & prec_seasonality
  129. & prec_seasonality_lastyear
  130. & prec_range
  131. & prec_range_lastyear
  132. & temp_seasonality
  133. & temp_seasonality_lastyear
  134. & var_prec
  135. & var_temp
  136. & aprec
  137. & ifssoiltemp // ecev3
  138. & ifsw_surf // ecev3
  139. & ifsw_deep; // ecev3
  140. }
  141. ////////////////////////////////////////////////////////////////////////////////
  142. // Implementation of Fluxes member functions
  143. ////////////////////////////////////////////////////////////////////////////////
  144. Fluxes::Fluxes(Patch& p)
  145. : patch(p),
  146. annual_fluxes_per_pft(npft, std::vector<float>(NPERPFTFLUXTYPES)) {
  147. reset();
  148. }
  149. void Fluxes::reset() {
  150. for (size_t i = 0; i < annual_fluxes_per_pft.size(); ++i) {
  151. std::fill_n(annual_fluxes_per_pft[i].begin(), int(NPERPFTFLUXTYPES), 0);
  152. }
  153. for (int m = 0; m < 12; ++m) {
  154. std::fill_n(monthly_fluxes_pft[m], int(NPERPFTFLUXTYPES), 0);
  155. std::fill_n(monthly_fluxes_patch[m], int(NPERPATCHFLUXTYPES), 0);
  156. }
  157. // ecev3 - sync-r4610 - can be 366
  158. for (int d = 0; d < date.year_length(); ++d) {
  159. std::fill_n(daily_fluxes_pft[d], int(NPERPFTFLUXTYPES), 0);
  160. std::fill_n(daily_fluxes_patch[d], int(NDAILYPERPATCHFLUXTYPES), 0);
  161. #ifdef CRESCENDO_FACE
  162. std::fill_n(daily_fluxes_patch_FACE[d], int(NDAILYPERPATCHFACEFLUXTYPE), 0);
  163. #endif
  164. }
  165. }
  166. void Fluxes::serialize(ArchiveStream& arch) {
  167. arch & annual_fluxes_per_pft
  168. /*
  169. & monthly_fluxes_patch
  170. & monthly_fluxes_pft
  171. & daily_fluxes_pft
  172. & daily_fluxes_patch
  173. */
  174. ;
  175. }
  176. void Fluxes::report_flux(PerPFTFluxType flux_type, int pft_id, double value) {
  177. annual_fluxes_per_pft[pft_id][flux_type] += (float)value;
  178. monthly_fluxes_pft[date.month][flux_type] += (float)value;
  179. daily_fluxes_pft[date.day][flux_type] += (float)value;
  180. }
  181. void Fluxes::report_flux(PerPatchFluxType flux_type, double value) {
  182. monthly_fluxes_patch[date.month][flux_type] += (float)value;
  183. }
  184. void Fluxes::report_flux(DailyPerPatchFluxType flux_type, double value) {
  185. daily_fluxes_patch[date.day][flux_type] += (float)value;
  186. }
  187. #ifdef CRESCENDO_FACE
  188. void Fluxes::report_flux(DailyPerPatchFACEFluxType flux_type, double value) {
  189. daily_fluxes_patch_FACE[date.day][flux_type] += (float)value;
  190. }
  191. #endif
  192. double Fluxes::get_monthly_flux(PerPFTFluxType flux_type, int month) const {
  193. return (double)monthly_fluxes_pft[month][flux_type];
  194. }
  195. double Fluxes::get_monthly_flux(PerPatchFluxType flux_type, int month) const {
  196. return (double)monthly_fluxes_patch[month][flux_type];
  197. }
  198. double Fluxes::get_monthly_flux(DailyPerPatchFluxType flux_type, int month) const {
  199. double sum = 0.0;
  200. int day = 0;
  201. for (int m = 0; m < month; m++) {
  202. day += date.month_length(m);
  203. }
  204. for (int d = 0; d < date.month_length(month); d++) {
  205. sum += (double)daily_fluxes_patch[day][flux_type];
  206. day++;
  207. }
  208. return sum;
  209. }
  210. // ecev3
  211. double Fluxes::get_daily_flux(PerPFTFluxType flux_type, int day) const {
  212. return (double)daily_fluxes_pft[day][flux_type];
  213. }
  214. // ecev3
  215. double Fluxes::get_daily_flux(DailyPerPatchFluxType flux_type, int day) const {
  216. return (double)daily_fluxes_patch[day][flux_type];
  217. }
  218. #ifdef CRESCENDO_FACE
  219. // ecev3
  220. double Fluxes::get_daily_flux(DailyPerPatchFACEFluxType flux_type, int day) const {
  221. return (double)daily_fluxes_patch_FACE[day][flux_type];
  222. }
  223. #endif
  224. double Fluxes::get_annual_flux(PerPFTFluxType flux_type, int pft_id) const {
  225. return (double)annual_fluxes_per_pft[pft_id][flux_type];
  226. }
  227. double Fluxes::get_annual_flux(PerPFTFluxType flux_type) const {
  228. double sum = 0;
  229. for (size_t i = 0; i < annual_fluxes_per_pft.size(); ++i) {
  230. sum += (double)annual_fluxes_per_pft[i][flux_type];
  231. }
  232. /*
  233. // ecev3 - for debugging. sum and testsum should be identical
  234. double testsum=0.0;
  235. if (sum != 0.0) {
  236. for (int day = 0; day < 366; ++day) {
  237. testsum += daily_fluxes_pft[day][flux_type];
  238. }
  239. }
  240. */
  241. return sum;
  242. }
  243. double Fluxes::get_annual_flux(PerPatchFluxType flux_type) const {
  244. double sum = 0;
  245. for (int m = 0; m < 12; ++m) {
  246. sum += (double)monthly_fluxes_patch[m][flux_type];
  247. }
  248. // ecev3 - for debugging. sum and testsum should be identical
  249. /*
  250. double testsum=0.0;
  251. if (sum != 0.0) {
  252. for (int day = 0; day < 366; ++day) {
  253. testsum += daily_fluxes_patch[day][flux_type];
  254. }
  255. }
  256. */
  257. return sum;
  258. }
  259. double Fluxes::get_annual_flux(DailyPerPatchFluxType flux_type) const {
  260. double sum = 0;
  261. for (int d = 0; d < date.year_length(); d++) {
  262. sum += (double)daily_fluxes_patch[d][flux_type];
  263. }
  264. return sum;
  265. }
  266. ////////////////////////////////////////////////////////////////////////////////
  267. // Implementation of Vegetation member functions
  268. ////////////////////////////////////////////////////////////////////////////////
  269. void Vegetation::serialize(ArchiveStream& arch) {
  270. if (arch.save()) {
  271. arch & nobj;
  272. for (unsigned int i = 0; i < nobj; i++) {
  273. Individual& indiv = (*this)[i];
  274. arch & indiv.pft.id
  275. & indiv;
  276. }
  277. }
  278. else {
  279. killall();
  280. unsigned int number_of_individuals;
  281. arch & number_of_individuals;
  282. for (unsigned int i = 0; i < number_of_individuals; i++) {
  283. int pft_id;
  284. arch & pft_id;
  285. Individual& indiv = createobj(pftlist[pft_id], *this);
  286. arch & indiv;
  287. }
  288. }
  289. }
  290. ////////////////////////////////////////////////////////////////////////////////
  291. // Implementation of LitterSolveSOM member functions
  292. ////////////////////////////////////////////////////////////////////////////////
  293. /*void LitterSolveSOM::serialize(ArchiveStream& arch) {
  294. arch & clitter
  295. & nlitter;
  296. }*/
  297. ////////////////////////////////////////////////////////////////////////////////
  298. // Implementation of Soil member functions
  299. ////////////////////////////////////////////////////////////////////////////////
  300. void Soil::serialize(ArchiveStream& arch) {
  301. arch & wcont
  302. //& awcont
  303. & wcont_evap
  304. //& dwcontupper
  305. //& mwcontupper
  306. & snowpack
  307. //& runoff
  308. //& temp
  309. //& dtemp
  310. //& mtemp
  311. //& mtemp_K
  312. & litter2soilc
  313. & litter2soiln
  314. //& gtemp
  315. & cpool_slow
  316. & cpool_fast
  317. & decomp_litter_mean
  318. & k_soilfast_mean
  319. & k_soilslow_mean
  320. & alag
  321. & exp_alag
  322. //& mwcont
  323. //& dwcontlower
  324. //& mwcontlower
  325. //& rain_melt
  326. //& max_rain_melt
  327. //& percolate
  328. ;
  329. for (int i = 0; i<NSOMPOOL; i++) {
  330. arch & sompool[i];
  331. }
  332. arch & dperc
  333. & orgleachfrac
  334. & nmass_avail
  335. & ninput
  336. //& anmin
  337. //& animmob
  338. //& aminleach
  339. //& aorgNleach
  340. //& aorgCleach
  341. //& anfix
  342. & anfix_calc
  343. //& anfix_mean
  344. & snowpack_nmass
  345. & solvesomcent_beginyr
  346. & solvesomcent_endyr
  347. //& solvesom
  348. & fnuptake_mean
  349. & morgleach_mean
  350. & mminleach_mean
  351. & msnd
  352. //& mcLitter
  353. //& mcLitterCwd
  354. //& mcLitterSurf
  355. //& mcLitterSubSurf
  356. //& mcSoil
  357. //& mnLitter
  358. //& mnLitterCwd
  359. //& mnLitterSurf
  360. //& mnLitterSubSurf
  361. //& mnSoil
  362. //& mnMineralNH4
  363. //& mnMineralNO3
  364. ;
  365. }
  366. ////////////////////////////////////////////////////////////////////////////////
  367. // Implementation of cropphen_struct member functions
  368. ////////////////////////////////////////////////////////////////////////////////
  369. void cropphen_struct::serialize(ArchiveStream& arch) {
  370. arch & sdate
  371. & sdate_harv
  372. & sdate_harvest
  373. & hdate
  374. & hlimitdate
  375. & hucountend
  376. & sendate
  377. & bicdate
  378. & eicdate
  379. & growingdays
  380. & growingdays_y
  381. & lgp
  382. & tb
  383. & pvd
  384. & vdsum
  385. & vrf
  386. & prf
  387. & phu
  388. & phu_old
  389. & husum
  390. & husum_max
  391. & husum_sampled
  392. & husum_max_10
  393. & nyears_hu_sample
  394. & hu_samplingperiod
  395. & hu_samplingdays
  396. & fphu
  397. & fphu_harv
  398. & hi
  399. & fhi_harv
  400. & demandsum_crop
  401. & supplysum_crop
  402. & growingseason
  403. & growingseason_ystd
  404. & senescence
  405. & senescence_ystd
  406. & intercropseason
  407. & fertilised
  408. & vdsum_alloc
  409. & vd
  410. & dev_stage;
  411. }
  412. ////////////////////////////////////////////////////////////////////////////////
  413. // Implementation of Patchpft member functions
  414. ////////////////////////////////////////////////////////////////////////////////
  415. void Patchpft::serialize(ArchiveStream& arch) {
  416. arch & anetps_ff
  417. & wscal
  418. & wscal_mean
  419. & anetps_ff_est
  420. & anetps_ff_est_initial
  421. & wscal_mean_est
  422. & phen
  423. & aphen
  424. & establish
  425. & nsapling
  426. & litter_leaf
  427. & litter_root
  428. & litter_sap
  429. & litter_heart
  430. & litter_repr
  431. & gcbase
  432. & gcbase_day
  433. & wsupply
  434. & wsupply_leafon
  435. & fwuptake
  436. & wstress
  437. & wstress_day
  438. & harvested_products_slow
  439. & nmass_litter_leaf
  440. & nmass_litter_root
  441. & nmass_litter_sap
  442. & nmass_litter_heart
  443. & harvested_products_slow_nmass
  444. & swindow
  445. & water_deficit_y;
  446. if (pft.landcover==CROPLAND)
  447. arch & *cropphen;
  448. }
  449. cropphen_struct* Patchpft::get_cropphen() {
  450. if (pft.landcover != CROPLAND) {
  451. fail("Only crop individuals have cropindiv struct. Re-write code !\n");
  452. }
  453. return cropphen;
  454. }
  455. cropphen_struct* Patchpft::set_cropphen() {
  456. if (pft.landcover != CROPLAND) {
  457. fail("Only crop individuals have cropindiv struct. Re-write code !\n");
  458. }
  459. return cropphen;
  460. }
  461. /// Gets the growingseason status for crop patch pft. Non-crop patch pft:s always return true.
  462. bool Patchpft::growingseason() const {
  463. if(cropphen)
  464. return cropphen->growingseason;
  465. else
  466. return true;
  467. }
  468. ////////////////////////////////////////////////////////////////////////////////
  469. // Implementation of Patch member functions
  470. ////////////////////////////////////////////////////////////////////////////////
  471. Patch::Patch(int i,Stand& s,Soiltype& st):
  472. id(i),stand(s),vegetation(*this),soil(*this,st),fluxes(*this) {
  473. for (unsigned int p = 0; p < pftlist.nobj; p++) {
  474. pft.createobj(pftlist[p]);
  475. }
  476. age = 0;
  477. disturbed = false;
  478. managed = false;
  479. man_strength = 0.0;
  480. managed_this_year = false;
  481. plant_this_year = false;
  482. wdemand = 0.0;
  483. wdemand_leafon = 0.0;
  484. growingseasondays = 0;
  485. fireprob = 0.0;
  486. ndemand = 0.0;
  487. dnfert = 0.0;
  488. anfert = 0.0;
  489. nharv = 0;
  490. for (int i = 0; i < NYEARAAET; i++)
  491. aaet_5.add(0.0);
  492. deforest_active=false;
  493. }
  494. void Patch::serialize(ArchiveStream& arch) {
  495. if (arch.save()) {
  496. for (unsigned int i = 0; i < pft.nobj; i++) {
  497. arch & pft[i];
  498. }
  499. }
  500. else {
  501. pft.killall();
  502. for (unsigned int i = 0; i < pftlist.nobj; i++) {
  503. pft.createobj(pftlist[i]);
  504. arch & pft[i];
  505. }
  506. }
  507. arch & vegetation
  508. & soil
  509. & fluxes
  510. //& fpar_grass
  511. //& fpar_ff
  512. //& par_grass_mean
  513. //& nday_growingseason
  514. //& fpc_total
  515. & disturbed
  516. & managed
  517. & age
  518. //& fireprob
  519. //& growingseasondays
  520. //& intercep
  521. //& aaet
  522. & aaet_5
  523. //& aevap
  524. //& aintercep
  525. //& arunoff
  526. //& apet
  527. //& eet_net_veg
  528. & wdemand
  529. //& wdemand_day
  530. //& wdemand_leafon
  531. //& fpc_rescale
  532. //& maet
  533. //& mevap
  534. //& mintercep
  535. //& mrunoff
  536. //& mrunoff_surf
  537. //& mpet
  538. //& ndemand
  539. //& irrigation_d
  540. //& irrigation_y
  541. //& mcVeg
  542. //& mnVeg
  543. //& mcLeaf
  544. //& mnLeaf
  545. //& mcRoot
  546. //& mnRoot
  547. //& mcStem
  548. //& mnStem
  549. //& mcOther
  550. //& mnOther
  551. //& mcProduct
  552. //& mnProduct
  553. //& mcLand
  554. //& mnLand
  555. & deforest_active;
  556. }
  557. const Climate& Patch::get_climate() const {
  558. // All patches within a stand share the same climate
  559. return stand.get_climate();
  560. }
  561. bool Patch::has_fires() const {
  562. return iffire
  563. && stand.landcover != CROPLAND
  564. && stand.landcover != URBAN // ecev3
  565. && stand.landcover != PEATLAND // ecev3
  566. && !managed
  567. && (stand.landcover != PASTURE || disturb_pasture);
  568. }
  569. bool Patch::has_disturbances() const {
  570. return ifdisturb && stand.landcover != CROPLAND && !managed &&
  571. (stand.landcover != PASTURE || disturb_pasture);
  572. }
  573. /// C content of patch
  574. /**
  575. * INPUT PARAMETERS
  576. *
  577. * \param scale_indiv scaling factor for living C
  578. * \param luc down-scales living C (used in C balance tests)
  579. */
  580. double Patch::ccont(double scale_indiv, bool luc) {
  581. double ccont = 0.0;
  582. ccont += soil.cpool_fast;
  583. ccont += soil.cpool_slow;
  584. for (int i=0; i<NSOMPOOL-1; i++) {
  585. ccont += soil.sompool[i].cmass;
  586. }
  587. for (int i=0; i<npft; i++) {
  588. Patchpft& ppft = pft[i];
  589. ccont += ppft.litter_leaf;
  590. ccont += ppft.litter_root;
  591. ccont += ppft.litter_sap;
  592. ccont += ppft.litter_heart;
  593. ccont += ppft.litter_repr;
  594. ccont += ppft.harvested_products_slow;
  595. }
  596. for (unsigned int i=0; i<vegetation.nobj; i++) {
  597. Individual& indiv = vegetation[i];
  598. ccont += indiv.ccont(scale_indiv, luc);
  599. }
  600. return ccont;
  601. }
  602. /// N content of patch
  603. /**
  604. * INPUT PARAMETERS
  605. *
  606. * \param scale_indiv scaling factor for living N
  607. * \param luc down-scales living N (used in N balance tests)
  608. */
  609. double Patch::ncont(double scale_indiv, bool luc) {
  610. double ncont = 0.0;
  611. ncont += soil.nmass_avail;
  612. ncont += soil.snowpack_nmass;
  613. for (int i=0; i<NSOMPOOL-1; i++)
  614. ncont += soil.sompool[i].nmass;
  615. for (int i=0; i<npft; i++) {
  616. Patchpft& ppft = pft[i];
  617. ncont += ppft.nmass_litter_leaf;
  618. ncont += ppft.nmass_litter_root;
  619. ncont += ppft.nmass_litter_sap;
  620. ncont += ppft.nmass_litter_heart;
  621. ncont += ppft.harvested_products_slow_nmass;
  622. }
  623. for (unsigned int i=0; i<vegetation.nobj; i++) {
  624. Individual& indiv = vegetation[i];
  625. ncont += indiv.ncont(scale_indiv, luc);
  626. }
  627. return ncont;
  628. }
  629. /// C flux of patch
  630. double Patch::cflux() {
  631. double cflux = 0.0;
  632. cflux += soil.aorgCleach;
  633. cflux += -fluxes.get_annual_flux(Fluxes::NPP);
  634. cflux += fluxes.get_annual_flux(Fluxes::REPRC);
  635. cflux += fluxes.get_annual_flux(Fluxes::SOILC);
  636. cflux += fluxes.get_annual_flux(Fluxes::FIREC);
  637. cflux += fluxes.get_annual_flux(Fluxes::ESTC);
  638. cflux += fluxes.get_annual_flux(Fluxes::SEEDC);
  639. cflux += fluxes.get_annual_flux(Fluxes::HARVESTC);
  640. return cflux;
  641. }
  642. /// N flux of patch
  643. double Patch::nflux() {
  644. double nflux = 0.0;
  645. nflux += -stand.get_climate().andep;
  646. nflux += -anfert;
  647. nflux += -soil.anfix;
  648. nflux += soil.aminleach;
  649. nflux += soil.aorgNleach;
  650. nflux += fluxes.get_annual_flux(Fluxes::HARVESTN);
  651. nflux += fluxes.get_annual_flux(Fluxes::SEEDN);
  652. nflux += fluxes.get_annual_flux(Fluxes::NH3_FIRE);
  653. nflux += fluxes.get_annual_flux(Fluxes::NOx_FIRE);
  654. nflux += fluxes.get_annual_flux(Fluxes::N2O_FIRE);
  655. nflux += fluxes.get_annual_flux(Fluxes::N2_FIRE);
  656. nflux += fluxes.get_annual_flux(Fluxes::N_SOIL);
  657. return nflux;
  658. }
  659. ////////////////////////////////////////////////////////////////////////////////
  660. // Implementation of Standpft member functions
  661. ////////////////////////////////////////////////////////////////////////////////
  662. void Standpft::serialize(ArchiveStream& arch) {
  663. arch & cmass_repr
  664. & anetps_ff_max
  665. & fpc_total
  666. & active
  667. & plant
  668. & reestab
  669. & irrigated;
  670. }
  671. ////////////////////////////////////////////////////////////////////////////////
  672. // Implementation of Stand member functions
  673. ////////////////////////////////////////////////////////////////////////////////
  674. Stand::Stand(int i, Gridcell* gc, Soiltype& st, landcovertype landcoverX, int npatch)
  675. : id(i),
  676. gridcell(gc),
  677. soiltype(st),
  678. landcover(landcoverX),
  679. origin(landcoverX),
  680. frac(1.0),
  681. //typehigh(0), // ecev3
  682. //frachigh(0.0), // ecev3
  683. previousyearsCflux(0.0), // ecev3
  684. previousyearsCfireflux(0.0) { // ecev3
  685. // Constructor: initialises reference member of climate and
  686. // builds list array of Standpft objects
  687. if (landcover >= NLANDCOVERTYPES) {
  688. fail("Unrecognized landcover type %i of NLANDCOVERTYPES=%i \n",landcover,NLANDCOVERTYPES);
  689. }
  690. for (unsigned int p=0;p<pftlist.nobj;p++) {
  691. pft.createobj(pftlist[p]);
  692. }
  693. unsigned int num_patches = 1;
  694. if (landcover == FOREST || landcover == NATURAL || (disturb_pasture && landcover == PASTURE)) {
  695. // stands with stochastic events
  696. if (npatch > 0) {
  697. num_patches = npatch; // use patch number provided by calling funciton
  698. }
  699. else {
  700. num_patches = ::npatch; // use the global variable npatch
  701. }
  702. }
  703. for (unsigned int p=0;p<num_patches;p++) {
  704. createobj(*this, soiltype);
  705. }
  706. first_year = date.year;
  707. clone_year = -1;
  708. transfer_area_st = new double[nst];
  709. for(int i=0;i<nst;i++)
  710. transfer_area_st[i] = 0.0;
  711. seed = 12345678;
  712. stid = 0;
  713. pftid = -1;
  714. current_rot = 0;
  715. ndays_inrotation = 0;
  716. infallow = false;
  717. isrotationday = false;
  718. isirrigated = false;
  719. hasgrassintercrop = false;
  720. gdd0_intercrop = 0.0;
  721. frac = 1.0;
  722. frac_old = 0.0;
  723. frac_temp = 0.0;
  724. protected_frac = 0.0;
  725. frac_change = 0.0;
  726. gross_frac_increase = 0.0;
  727. gross_frac_decrease = 0.0;
  728. cloned_fraction = 0.0;
  729. cloned = false;
  730. anpp = 0.0;
  731. cmass = 0.0;
  732. scale_LC_change = 1.0;
  733. // ecev3 - initialise
  734. dcflux_today = 0.0;
  735. dnpp_today = 0.0;
  736. previousyearsCflux = 0.0;
  737. previousyearsCfireflux = 0.0;
  738. /*
  739. for (int dd=0; dd<366; dd++) {
  740. //laiphen_grass[dd]=0.0;
  741. //laiphen_total[dd]=0.0;
  742. dcflux[dd]=0.0;
  743. }
  744. */
  745. }
  746. Stand::~Stand() {
  747. if (transfer_area_st) {
  748. delete[] transfer_area_st;
  749. }
  750. }
  751. double Stand::get_gridcell_fraction() const {
  752. return frac;
  753. }
  754. /// Initiation of stand variables when run_landcover==true
  755. /**
  756. * Rules for which PFT:s are allowed to establish are set in the instruction file by the parameters landcover
  757. * (allows all active PFT:s with the same landcovertype), naturalveg (allows none, natural grass or all natural pft:s)
  758. * and intercrop ("naturalgrass" allows dedicated covercrop grass pft:s).
  759. * If restrictpfts is true, further restriction of pft:s are specified in the management settings.
  760. * Rules for reestablishment (after sowing or planting) are set by the parameter reestab, "none", "restricted" - only planted pft:s
  761. */
  762. void Stand::init_stand_lu(StandType& st, double fraction) {
  763. landcovertype lc = st.landcover;
  764. landcover = lc;
  765. stid = st.id;
  766. set_gridcell_fraction(fraction);
  767. frac_old = 0.0;
  768. frac_change = fraction;
  769. gross_frac_increase = fraction;
  770. bool naturalveg = st.naturalveg == "ALL";
  771. bool naturalgrass = st.naturalveg == "ALL" || st.naturalveg == "GRASSONLY";
  772. pftlist.firstobj();
  773. while (pftlist.isobj) {
  774. Pft& pftx = pftlist.getobj();
  775. if(!st.restrictpfts && pftx.landcover == lc
  776. || !st.restrictpfts && naturalveg && pftx.landcover == NATURAL // Allow all natural pft:s to grow in e.g. forests
  777. || naturalgrass && pftx.landcover == NATURAL && pftx.lifeform == GRASS // Allow natural grass pft:s to grow in e.g. forests
  778. || pftx.landcover == lc && lc == FOREST && pftx.lifeform == GRASS) { // Always allow forest grass pft:s to grow in forests
  779. pft[pftx.id].active = true;
  780. pft[pftx.id].reestab = true;
  781. // If restrictpfts = false, plant all tree pft:s after clearcut
  782. if(pftx.lifeform == TREE)
  783. pft[pftx.id].plant = true;
  784. }
  785. else {
  786. pft[pftx.id].active = false;
  787. }
  788. pftlist.nextobj();
  789. }
  790. if(date.get_calendar_year() >= st.firstmanageyear) {
  791. for(unsigned int i=0;i<npatch();i++)
  792. (*this)[i].managed = true;
  793. }
  794. ManagementType& mt0 = st.get_management(0);
  795. pftid = pftlist.getpftid(mt0.pftname); // First main crop, will change during crop rotation
  796. current_rot = 0;
  797. if (mt0.hydrology == IRRIGATED) {
  798. isirrigated = true; // First main crop, may change during crop rotation
  799. if (pftid >= 0)
  800. pft[pftid].irrigated = true;
  801. }
  802. if (st.intercrop==NATURALGRASS && ifintercropgrass) {
  803. hasgrassintercrop = true;
  804. for (unsigned int i=0; i<pftlist.nobj; i++) {
  805. if (pftlist[i].isintercropgrass)
  806. pft[pftlist[i].id].active = true;
  807. }
  808. }
  809. if(pftid > -1) {
  810. if (!readNfert)
  811. gridcell->pft[pftid].Nfert_read = mt0.nfert;
  812. if (!readsowingdates)
  813. pft[pftid].sdate_force = mt0.sdate;
  814. if (!readharvestdates)
  815. pft[pftid].hdate_force = mt0.hdate;
  816. }
  817. if(!readNfert_st)
  818. gridcell->st[st.id].nfert = mt0.nfert;
  819. if(!st.restrictpfts)
  820. return;
  821. // Set standpft- and patchpft-variables for active crops
  822. for (int rot=0; rot<st.rotation.ncrops; rot++) {
  823. ManagementType& mt = st.get_management(rot);
  824. if(mt.planting_system == "MONOCULTURE") {
  825. int id = pftlist.getpftid(mt.pftname);
  826. if (id >=0) {
  827. if(lc == CROPLAND) {
  828. pft[id].active = true;
  829. if (rot == 0) {
  830. // Set crop cycle dates to default values only for first crop in a rotation.
  831. for (unsigned int p = 0; p < nobj; p++) {
  832. Gridcellpft& gcpft = get_gridcell().pft[id];
  833. Patchpft& ppft = (*this)[p].pft[id];
  834. ppft.set_cropphen()->sdate = gcpft.sdate_default;
  835. ppft.set_cropphen()->hlimitdate = gcpft.hlimitdate_default;
  836. if (pftlist[id].phenology == ANY)
  837. ppft.set_cropphen()->growingseason = true;
  838. else if (pftlist[id].phenology == CROPGREEN) {
  839. ppft.set_cropphen()->eicdate = Date::stepfromdate(ppft.get_cropphen()->sdate, -15);
  840. }
  841. }
  842. }
  843. }
  844. else if(rot == 0) {
  845. // Only first tree rotation implemented; pft[id].active etc. has to be set anew in stand.crop_rotation()
  846. pft[id].active = true;
  847. pft[id].plant = true;
  848. if(st.reestab == "RESTRICTED") {
  849. pft[id].reestab = true;
  850. }
  851. else if(st.reestab == "ALL") {
  852. pftlist.firstobj();
  853. while (pftlist.isobj) {
  854. Pft& pftx = pftlist.getobj();
  855. // Options here are only relevant when planted trees (FOREST) and regenerated growth (FOREST and/or NATURAL) needs to be distinguished in the output
  856. // 1. reestablishment by both forest and natural pfts
  857. // if(pftx.landcover == lc || st.naturalveg == "ALL" && pftx.landcover == NATURAL) {
  858. // 2. reestablishment by natural pfts (when active) and planted forest pfts
  859. // if(pftx.landcover == lc && (st.naturalveg != "ALL" || pft[pftx.id].plant) || st.naturalveg == "ALL" && pftx.landcover == NATURAL) {
  860. // 3. reestablishment only by natural pfts (when active)
  861. if(pftx.landcover == lc && st.naturalveg != "ALL" || st.naturalveg == "ALL" && pftx.landcover == NATURAL) {
  862. pft[pftx.id].active = true;
  863. pft[pftx.id].reestab = true;
  864. }
  865. pftlist.nextobj();
  866. }
  867. }
  868. }
  869. }
  870. else if(!mt.fallow) {
  871. dprintf("Warning: stand type %d pft %s not in pftlist !\n", stid, (char*)mt.pftname);;
  872. break;
  873. }
  874. }
  875. else if(mt.planting_system == "SELECTION") {
  876. if(mt.selection != "") {
  877. pftlist.firstobj();
  878. while (pftlist.isobj) {
  879. Pft& pftx = pftlist.getobj();
  880. if(mt.pftinselection((const char*)pftx.name)) {
  881. pft[pftx.id].active = true;
  882. pft[pftx.id].reestab = true;
  883. if(pftx.lifeform == TREE)
  884. pft[pftx.id].plant = true;
  885. }
  886. else if(pftx.lifeform == TREE) { // Whether grass is allowed is specified in the generic code above
  887. pft[pftx.id].active = false;
  888. }
  889. pftlist.nextobj();
  890. }
  891. }
  892. else {
  893. dprintf("Warning: stand type %d planting selection not defined !\n", stid);;
  894. break;
  895. }
  896. }
  897. else if(mt.planting_system != "") {
  898. // planting systems (pft selections) defined here
  899. }
  900. }
  901. }
  902. void Stand::rotate() {
  903. if (pftid >= 0 && stid >= 0) {
  904. ndays_inrotation = 0;
  905. int pftid_old = pftid;
  906. current_rot = (current_rot + 1) % stlist[stid].rotation.ncrops;
  907. ManagementType& mt = stlist[stid].get_management(current_rot);
  908. pftid = pftlist.getpftid(mt.pftname);
  909. // If fallow, use old pftid !
  910. if(mt.fallow)
  911. pftid = pftid_old;
  912. Standpft& standpft = pft[pftid];
  913. if (mt.hydrology == IRRIGATED) {
  914. isirrigated = true;
  915. standpft.irrigated = true;
  916. }
  917. else {
  918. isirrigated = false;
  919. standpft.irrigated = false;
  920. }
  921. if (!readNfert)
  922. gridcell->pft[pftid].Nfert_read = mt.nfert;
  923. if (!readsowingdates)
  924. standpft.sdate_force = mt.sdate;
  925. if (!readharvestdates)
  926. standpft.hdate_force = mt.hdate;
  927. if(!readNfert_st)
  928. gridcell->st[stid].nfert = mt.nfert;
  929. }
  930. }
  931. double Stand::transfer_area_lc(landcovertype to) {
  932. double area = 0.0;
  933. if (transfer_area_st) {
  934. for (int j=0; j<nst; j++) {
  935. if (stlist[j].landcover == to)
  936. area += transfer_area_st[j];
  937. }
  938. }
  939. return area;
  940. }
  941. double Stand::ccont(double scale_indiv) {
  942. double ccont = 0.0;
  943. for (unsigned int p = 0; p < nobj; p++)
  944. ccont += (*this)[p].ccont(scale_indiv) / nobj;
  945. return ccont;
  946. }
  947. double Stand::ncont(double scale_indiv) {
  948. double ncont = 0.0;
  949. for (unsigned int p = 0; p < nobj; p++)
  950. ncont += (*this)[p].ncont(scale_indiv) / nobj;
  951. return ncont;
  952. }
  953. double Stand::cflux() {
  954. double cflux = 0.0;
  955. for (unsigned int p = 0; p < nobj; p++)
  956. cflux += (*this)[p].cflux() / nobj;
  957. return cflux;
  958. }
  959. double Stand::nflux() {
  960. double nflux = 0.0;
  961. for (unsigned int p = 0; p < nobj; p++)
  962. nflux += (*this)[p].nflux() / nobj;
  963. return nflux;
  964. }
  965. Stand& Stand::clone(StandType& st, double fraction) {
  966. // Serialize this stand to an in-memory stream
  967. std::stringstream ss;
  968. ArchiveOutStream aos(ss);
  969. serialize(aos);
  970. // Create a new stand in the gridcell...
  971. // NB: the patch number is always that of the old stand, even if the new stand is a pasture or crop stand
  972. Stand& new_stand = gridcell->create_stand(st.landcover, nobj);
  973. int new_seed = new_stand.seed;
  974. // ...and deserialize to that stand
  975. ArchiveInStream ais(ss);
  976. new_stand.serialize(ais);
  977. new_stand.clone_year = date.year;
  978. // new_stand.seed = new_seed; // ?
  979. // Set land use settings for new stand
  980. new_stand.init_stand_lu(st, fraction);
  981. for (unsigned int p = 0; p < nobj; p++) {
  982. // new_stand[p].age = 0; // probably not what we want
  983. new_stand[p].managed = false; // or use value of mother stand ?
  984. }
  985. return new_stand;
  986. }
  987. double Stand::get_landcover_fraction() const {
  988. if (get_gridcell().landcover.frac[landcover])
  989. return frac / get_gridcell().landcover.frac[landcover];
  990. else
  991. return 0.0;
  992. }
  993. void Stand::set_gridcell_fraction(double fraction) {
  994. frac = fraction;
  995. }
  996. void Stand::serialize(ArchiveStream& arch) {
  997. if (arch.save()) {
  998. for (unsigned int i = 0; i < pft.nobj; i++) {
  999. arch & pft[i];
  1000. }
  1001. arch & nobj;
  1002. for (unsigned int k = 0; k < nobj; k++) {
  1003. arch & (*this)[k];
  1004. }
  1005. }
  1006. else {
  1007. pft.killall();
  1008. for (unsigned int i = 0; i < pftlist.nobj; i++) {
  1009. Standpft& standpft = pft.createobj(pftlist[i]);
  1010. arch & standpft;
  1011. }
  1012. killall();
  1013. unsigned int npatch;
  1014. arch & npatch;
  1015. for (unsigned int k = 0; k < npatch; k++) {
  1016. Patch& patch = createobj(*this, soiltype);
  1017. arch & patch;
  1018. }
  1019. }
  1020. arch & first_year
  1021. & clone_year
  1022. & frac
  1023. & stid
  1024. & pftid
  1025. & current_rot
  1026. & ndays_inrotation
  1027. & infallow
  1028. & isirrigated
  1029. & hasgrassintercrop
  1030. & gdd0_intercrop
  1031. & cloned
  1032. & origin
  1033. & landcover
  1034. & seed
  1035. // ecev3 - serialize these new member variables
  1036. //& typehigh
  1037. //& frachigh
  1038. //& laiphen_grass
  1039. //& laiphen_total
  1040. & dcflux_today
  1041. & dnpp_today
  1042. & previousyearsCflux;
  1043. & previousyearsCfireflux; // NEEDS TO BE ADDED
  1044. }
  1045. const Climate& Stand::get_climate() const {
  1046. // In this implementation all stands within a grid cell
  1047. // share the same climate. Note that this might not be
  1048. // true in all versions of LPJ-GUESS, some may have
  1049. // different climate per landcover type for instance.
  1050. return get_gridcell().climate;
  1051. }
  1052. Gridcell& Stand::get_gridcell() const {
  1053. assert(gridcell);
  1054. return *gridcell;
  1055. }
  1056. ////////////////////////////////////////////////////////////////////////////////
  1057. // Implementation of cropindiv_struct member functions
  1058. ////////////////////////////////////////////////////////////////////////////////
  1059. void cropindiv_struct::serialize(ArchiveStream& arch) {
  1060. arch & grs_cmass_plant
  1061. & grs_cmass_leaf
  1062. & grs_cmass_root
  1063. & grs_cmass_ho
  1064. & grs_cmass_agpool
  1065. & grs_cmass_dead_leaf
  1066. & grs_cmass_stem
  1067. & cmass_leaf_sen
  1068. & nmass_ho
  1069. & nmass_agpool
  1070. & nmass_dead_leaf
  1071. & isintercropgrass;
  1072. }
  1073. ////////////////////////////////////////////////////////////////////////////////
  1074. // Implementation of Individual member functions
  1075. ////////////////////////////////////////////////////////////////////////////////
  1076. Individual::Individual(int i,Pft& p,Vegetation& v):pft(p),vegetation(v),id(i) {
  1077. anpp = 0.0;
  1078. fpc = 0.0;
  1079. fpc_daily = 0.0;
  1080. densindiv = 0.0;
  1081. cmass_leaf = 0.0;
  1082. cmass_root = 0.0;
  1083. cmass_sap = 0.0;
  1084. cmass_heart = 0.0;
  1085. cmass_debt = 0.0;
  1086. cmass_leaf_post_turnover = 0.0;
  1087. cmass_root_post_turnover = 0.0;
  1088. cmass_tot_luc = 0.0;
  1089. phen = 0.0;
  1090. aphen = 0.0;
  1091. deltafpc = 0.0;
  1092. nmass_leaf = 0.0;
  1093. nmass_root = 0.0;
  1094. nmass_sap = 0.0;
  1095. nmass_heart = 0.0;
  1096. cton_leaf_aopt = 0.0;
  1097. cton_leaf_aavr = 0.0;
  1098. cton_status = 0.0;
  1099. cmass_veg = 0.0;
  1100. nmass_veg = 0.0;
  1101. nmass_tot_luc = 0.0;
  1102. nactive = 0.0;
  1103. nextin = 1.0;
  1104. nstore_longterm = 0.0;
  1105. nstore_labile = 0.0;
  1106. ndemand = 0.0;
  1107. fnuptake = 1.0;
  1108. anuptake = 0.0;
  1109. max_n_storage = 0.0;
  1110. scale_n_storage = 0.0;
  1111. leafndemand = 0.0;
  1112. rootndemand = 0.0;
  1113. sapndemand = 0.0;
  1114. storendemand = 0.0;
  1115. leaffndemand = 0.0;
  1116. rootfndemand = 0.0;
  1117. sapfndemand = 0.0;
  1118. storefndemand = 0.0;
  1119. leafndemand_store = 0.0;
  1120. rootndemand_store = 0.0;
  1121. nstress = false;
  1122. // additional initialisation
  1123. age = 0.0;
  1124. fpar = 0.0;
  1125. aphen_raingreen = 0;
  1126. intercep = 0.0;
  1127. phen_mean = 0.0;
  1128. wstress = false;
  1129. lai = 0.0;
  1130. lai_layer = 0.0;
  1131. lai_indiv = 0.0;
  1132. lai_daily = 0.0;
  1133. lai_indiv_daily = 0.0;
  1134. alive = false;
  1135. int m;
  1136. for (m=0; m<12; m++) {
  1137. mlai[m] = 0.0;
  1138. mlai_max[m] = 0.0;
  1139. mfpc[m] = 0.0;
  1140. mfpar[m] = 0.0;
  1141. mlambda_gpp[m] = 0.0;
  1142. mgpp[m] = 0.0;
  1143. }
  1144. // bvoc
  1145. iso = 0.;
  1146. fvocseas = 1.;
  1147. for (int im=0; im<NMTCOMPOUNDS; im++){
  1148. mon[im] = 0.;
  1149. monstor[im] = 0.;
  1150. }
  1151. dnpp = 0.0;
  1152. cropindiv = NULL;
  1153. last_turnover_day = -1;
  1154. Stand& stand = vegetation.patch.stand;
  1155. if (pft.landcover==CROPLAND) {
  1156. cropindiv=new cropindiv_struct;
  1157. if (stand.pftid == pft.id) {
  1158. cropindiv->isprimarycrop = true;
  1159. }
  1160. else if (stand.hasgrassintercrop && pft.isintercropgrass) { // grass cover crop growth
  1161. cropindiv->isintercropgrass = true;
  1162. }
  1163. }
  1164. // dprintf("Year %d: Individual in stand %d created:id=%d, pft=%s\n", ::date.year-nyear_spinup+1901,vegetation.patch.stand.id,id,(char*)pft.name);
  1165. }
  1166. void Individual::serialize(ArchiveStream& arch) {
  1167. arch & cmass_leaf
  1168. & cmass_root
  1169. & cmass_sap
  1170. & cmass_heart
  1171. & cmass_debt
  1172. & cmass_leaf_post_turnover
  1173. & cmass_root_post_turnover
  1174. & last_turnover_day
  1175. & fpc
  1176. & fpc_daily
  1177. & fpar
  1178. & densindiv
  1179. & phen
  1180. //& aphen
  1181. //& aphen_raingreen
  1182. //& anpp
  1183. & aet
  1184. //& aaet
  1185. //& ltor
  1186. & height
  1187. & crownarea
  1188. //& deltafpc
  1189. & boleht
  1190. & lai
  1191. & lai_layer
  1192. & lai_indiv
  1193. & lai_daily
  1194. & lai_indiv_daily
  1195. & greff_5
  1196. & age
  1197. //& mlai
  1198. //& mfpc
  1199. //& fpar_leafon
  1200. //& lai_leafon_layer
  1201. //& intercep
  1202. //& phen_mean
  1203. //& wstress
  1204. & alive
  1205. //& iso
  1206. //& mon
  1207. & monstor
  1208. & fvocseas
  1209. & nmass_leaf
  1210. & nmass_root
  1211. & nmass_sap
  1212. & nmass_heart
  1213. //& nactive
  1214. //& nextin
  1215. & nstore_longterm
  1216. & nstore_labile
  1217. //& ndemand
  1218. //& fnuptake
  1219. //& anuptake
  1220. & max_n_storage
  1221. & scale_n_storage
  1222. //& avmaxnlim
  1223. //& cton_leaf_aopt
  1224. //& cton_leaf_aavr
  1225. //& cton_status
  1226. //& cmass_veg // - should be a function returning this value instead of having a variable saving it...
  1227. //& nmass_veg // - should be a function returning this value instead of having a variable saving it...
  1228. //& photosynthesis
  1229. //& nstress
  1230. //& leafndemand
  1231. //& rootndemand
  1232. //& sapndemand
  1233. //& storendemand
  1234. //& leaffndemand
  1235. //& rootfndemand
  1236. //& sapfndemand
  1237. //& storefndemand
  1238. //& leafndemand_store
  1239. //& rootndemand_store
  1240. //& nday_leafon
  1241. ;
  1242. if (pft.landcover==CROPLAND)
  1243. arch & *cropindiv;
  1244. }
  1245. Individual::~Individual() {
  1246. if (cropindiv)
  1247. delete cropindiv;
  1248. }
  1249. /// Access functions for cropindiv
  1250. cropindiv_struct* Individual::get_cropindiv() const {
  1251. if (pft.landcover != CROPLAND) {
  1252. fail("Only crop individuals have cropindiv struct. Re-write code !\n");
  1253. }
  1254. return cropindiv;
  1255. }
  1256. cropindiv_struct* Individual::set_cropindiv() {
  1257. if (pft.landcover != CROPLAND) {
  1258. fail("Only crop individuals have cropindiv struct. Re-write code !\n");
  1259. }
  1260. return cropindiv;
  1261. }
  1262. void Individual::report_flux(Fluxes::PerPFTFluxType flux_type, double value) {
  1263. if (alive || istruecrop_or_intercropgrass()) {
  1264. vegetation.patch.fluxes.report_flux(flux_type, pft.id, value);
  1265. }
  1266. }
  1267. void Individual::report_flux(Fluxes::PerPatchFluxType flux_type, double value) {
  1268. if (alive || istruecrop_or_intercropgrass()) {
  1269. vegetation.patch.fluxes.report_flux(flux_type, value);
  1270. }
  1271. }
  1272. void Individual::report_flux(Fluxes::DailyPerPatchFluxType flux_type, double value) {
  1273. if (alive || istruecrop_or_intercropgrass()) {
  1274. vegetation.patch.fluxes.report_flux(flux_type, value);
  1275. }
  1276. }
  1277. #ifdef CRESCENDO_FACE
  1278. void Individual::report_flux(Fluxes::DailyPerPatchFACEFluxType flux_type, double value) {
  1279. if (alive || istruecrop_or_intercropgrass()) {
  1280. vegetation.patch.fluxes.report_flux(flux_type, value);
  1281. }
  1282. }
  1283. #endif
  1284. /// Help function for reduce_biomass(), partitions nstore into leafs and roots
  1285. /**
  1286. * As leaf and roots can have a very low N concentration after growth and allocation,
  1287. * N in nstore() is split between them to saticfy relationship between their average C:N ratios
  1288. */
  1289. void nstore_adjust(double& cmass_leaf,double& cmass_root, double& nmass_leaf, double& nmass_root,
  1290. double nstore, double cton_leaf, double cton_root) {
  1291. // (1) cmass_leaf / ((nmass_leaf + leaf_ndemand) * cton_leaf) = cmass_root / ((nmass_root + root_ndemand) * cton_root)
  1292. // (2) leaf_ndemand + root_ndemand = nstore
  1293. // (1) + (2) leaf_ndemand = (cmass_leaf * ratio (nmass_root + nstore) - cmass_root * nmass_leaf) / (cmass_root + cmass_leaf * ratio)
  1294. //
  1295. // where ratio = cton_root / cton_leaf
  1296. double ratio = cton_root / cton_leaf;
  1297. double leaf_ndemand = 0.0;
  1298. double root_ndemand = 0.0;
  1299. if (!negligible((cmass_root + cmass_leaf * ratio))) {
  1300. leaf_ndemand = (cmass_leaf * ratio * (nmass_root + nstore) - cmass_root * nmass_leaf) / (cmass_root + cmass_leaf * ratio);
  1301. root_ndemand = nstore - leaf_ndemand;
  1302. }
  1303. nmass_leaf += leaf_ndemand;
  1304. nmass_root += root_ndemand;
  1305. }
  1306. void Individual::reduce_biomass(double mortality, double mortality_fire) {
  1307. // This function needs to be modified if a new lifeform is added,
  1308. // specifically to deal with nstore().
  1309. assert(pft.lifeform == TREE || pft.lifeform == GRASS);
  1310. if (!negligible(mortality)) {
  1311. const double mortality_non_fire = mortality - mortality_fire;
  1312. // Transfer killed biomass to litter
  1313. // (above-ground biomass killed by fire enters atmosphere, not litter)
  1314. Patchpft& ppft = patchpft();
  1315. double cmass_leaf_litter = mortality * cmass_leaf;
  1316. double cmass_root_litter = mortality * cmass_root;
  1317. if (pft.landcover==CROPLAND) {
  1318. if (pft.aboveground_ho)
  1319. cmass_leaf_litter += mortality * cropindiv->cmass_ho;
  1320. else
  1321. cmass_root_litter += mortality * cropindiv->cmass_ho;
  1322. cmass_leaf_litter += mortality * cropindiv->cmass_agpool;
  1323. }
  1324. ppft.litter_leaf += cmass_leaf_litter * mortality_non_fire / mortality;
  1325. ppft.litter_root += cmass_root_litter;
  1326. if (cmass_debt <= cmass_heart + cmass_sap) {
  1327. if (cmass_debt <= cmass_heart) {
  1328. ppft.litter_sap += mortality_non_fire * cmass_sap;
  1329. ppft.litter_heart += mortality_non_fire * (cmass_heart - cmass_debt);
  1330. }
  1331. else {
  1332. ppft.litter_sap += mortality_non_fire * (cmass_sap + cmass_heart - cmass_debt);
  1333. }
  1334. }
  1335. else {
  1336. double debt_excess = mortality_non_fire * (cmass_debt - (cmass_sap + cmass_heart));
  1337. report_flux(Fluxes::NPP, debt_excess);
  1338. report_flux(Fluxes::RA, -debt_excess);
  1339. }
  1340. double nmass_leaf_litter = mortality * nmass_leaf;
  1341. double nmass_root_litter = mortality * nmass_root;
  1342. if (pft.landcover==CROPLAND) {
  1343. if (pft.aboveground_ho)
  1344. nmass_leaf_litter += mortality * cropindiv->nmass_ho;
  1345. else
  1346. nmass_root_litter += mortality * cropindiv->nmass_ho;
  1347. nmass_leaf_litter += mortality * cropindiv->nmass_agpool;
  1348. }
  1349. // stored N is partioned out to leaf and root biomass as new tissue after growth might have extremely low
  1350. // N content (to get closer to relationship between compartment averages (cton_leaf, cton_root, cton_sap))
  1351. nstore_adjust(cmass_leaf_litter, cmass_root_litter, nmass_leaf_litter, nmass_root_litter,
  1352. mortality * nstore(), pft.cton_leaf_avr,pft.cton_root_avr);
  1353. ppft.nmass_litter_leaf += nmass_leaf_litter * mortality_non_fire / mortality;
  1354. ppft.nmass_litter_root += nmass_root_litter;
  1355. ppft.nmass_litter_sap += mortality_non_fire * nmass_sap;
  1356. ppft.nmass_litter_heart += mortality_non_fire * nmass_heart;
  1357. // Flux to atmosphere from burnt above-ground biomass
  1358. double cflux_fire = mortality_fire * (cmass_leaf_litter / mortality + cmass_wood());
  1359. double nflux_fire = mortality_fire * (nmass_leaf_litter / mortality + nmass_wood());
  1360. report_flux(Fluxes::FIREC, cflux_fire);
  1361. report_flux(Fluxes::FIREVEGC, cflux_fire);
  1362. report_flux(Fluxes::NH3_FIRE, Fluxes::NH3_FIRERATIO * nflux_fire);
  1363. report_flux(Fluxes::NOx_FIRE, Fluxes::NOx_FIRERATIO * nflux_fire);
  1364. report_flux(Fluxes::N2O_FIRE, Fluxes::N2O_FIRERATIO * nflux_fire);
  1365. report_flux(Fluxes::N2_FIRE, Fluxes::N2_FIRERATIO * nflux_fire);
  1366. // Reduce this Individual's biomass values
  1367. const double remaining = 1.0 - mortality;
  1368. if (pft.lifeform != GRASS) {
  1369. densindiv *= remaining;
  1370. }
  1371. cmass_leaf *= remaining;
  1372. cmass_root *= remaining;
  1373. cmass_sap *= remaining;
  1374. cmass_heart *= remaining;
  1375. cmass_debt *= remaining;
  1376. if (pft.landcover==CROPLAND) {
  1377. cropindiv->cmass_ho *= remaining;
  1378. cropindiv->cmass_agpool *= remaining;
  1379. }
  1380. nmass_leaf *= remaining;
  1381. nmass_root *= remaining;
  1382. nmass_sap *= remaining;
  1383. nmass_heart *= remaining;
  1384. nstore_longterm *= remaining;
  1385. nstore_labile *= remaining;
  1386. if (pft.landcover==CROPLAND) {
  1387. cropindiv->nmass_ho *= remaining;
  1388. cropindiv->nmass_agpool *= remaining;
  1389. }
  1390. }
  1391. }
  1392. double Individual::cton_leaf(bool use_phen /* = true*/) const {
  1393. Stand& stand = vegetation.patch.stand;
  1394. if (stand.is_true_crop_stand() && !negligible(cmass_leaf_today()) && !negligible(nmass_leaf)) {
  1395. return cmass_leaf_today() / nmass_leaf;
  1396. }
  1397. else if (!stand.is_true_crop_stand() && !negligible(cmass_leaf) && !negligible(nmass_leaf)) {
  1398. if (use_phen) {
  1399. if (!negligible(phen)) {
  1400. return cmass_leaf_today() / nmass_leaf;
  1401. }
  1402. else {
  1403. return pft.cton_leaf_avr;
  1404. }
  1405. }
  1406. else {
  1407. return cmass_leaf / nmass_leaf;
  1408. }
  1409. }
  1410. else {
  1411. return pft.cton_leaf_max;
  1412. }
  1413. }
  1414. double Individual::cton_root(bool use_phen /* = true*/) const {
  1415. if (!negligible(cmass_root) && !negligible(nmass_root)) {
  1416. if (use_phen) {
  1417. if (!negligible(cmass_root_today())) {
  1418. return cmass_root_today() / nmass_root;
  1419. }
  1420. else {
  1421. return pft.cton_root_avr;
  1422. }
  1423. }
  1424. else {
  1425. return cmass_root / nmass_root;
  1426. }
  1427. }
  1428. else {
  1429. return pft.cton_root_max;
  1430. }
  1431. }
  1432. double Individual::cton_sap() const {
  1433. if (pft.lifeform == TREE) {
  1434. if (!negligible(cmass_sap) && !negligible(nmass_sap))
  1435. return cmass_sap / nmass_sap;
  1436. else
  1437. return pft.cton_sap_max;
  1438. }
  1439. else {
  1440. return 1.0;
  1441. }
  1442. }
  1443. /// C content of individual
  1444. /**
  1445. * INPUT PARAMETERS
  1446. *
  1447. * \param scale_indiv scaling factor for living C
  1448. * \param luc down-scales living C (used in C balance tests)
  1449. */
  1450. double Individual::ccont(double scale_indiv, bool luc) const {
  1451. double ccont = 0.0;
  1452. if (alive || istruecrop_or_intercropgrass()) {
  1453. if (has_daily_turnover()) { // Not taking into account future daily wood allocation/turnover
  1454. if (cropindiv) {
  1455. if (luc) {
  1456. ccont += cropindiv->grs_cmass_leaf - cropindiv->grs_cmass_leaf_luc * (1.0 - scale_indiv);
  1457. ccont += cropindiv->grs_cmass_root - cropindiv->grs_cmass_root_luc * (1.0 - scale_indiv);
  1458. }
  1459. else {
  1460. ccont += cropindiv->grs_cmass_leaf * scale_indiv;
  1461. ccont += cropindiv->grs_cmass_root * scale_indiv;
  1462. }
  1463. if (pft.phenology == CROPGREEN) {
  1464. if (luc) {
  1465. ccont += cropindiv->grs_cmass_ho - cropindiv->grs_cmass_ho_luc * (1.0 - scale_indiv);
  1466. ccont += cropindiv->grs_cmass_agpool - cropindiv->grs_cmass_agpool_luc * (1.0 - scale_indiv);
  1467. ccont += cropindiv->grs_cmass_dead_leaf - cropindiv->grs_cmass_dead_leaf_luc * (1.0 - scale_indiv);
  1468. ccont += cropindiv->grs_cmass_stem - cropindiv->grs_cmass_stem_luc * (1.0 - scale_indiv);
  1469. }
  1470. else {
  1471. ccont += cropindiv->grs_cmass_ho * scale_indiv;
  1472. ccont += cropindiv->grs_cmass_agpool * scale_indiv;
  1473. ccont += cropindiv->grs_cmass_dead_leaf * scale_indiv;
  1474. ccont += cropindiv->grs_cmass_stem * scale_indiv;
  1475. }
  1476. }
  1477. }
  1478. }
  1479. else {
  1480. ccont = cmass_leaf + cmass_root + cmass_sap + cmass_heart - cmass_debt;
  1481. if (pft.landcover == CROPLAND) {
  1482. ccont += cropindiv->cmass_ho + cropindiv->cmass_agpool;
  1483. // Yearly allocation not defined for crops with nlim
  1484. }
  1485. ccont *= scale_indiv;
  1486. }
  1487. }
  1488. return ccont;
  1489. }
  1490. /// N content of individual
  1491. /**
  1492. * INPUT PARAMETERS
  1493. *
  1494. * \param scale_indiv scaling factor for living N
  1495. * \param luc down-scales living N (used in C balance tests)
  1496. */
  1497. double Individual::ncont(double scale_indiv, bool luc) const {
  1498. double ncont = 0.0;
  1499. if (luc) {
  1500. ncont += nmass_leaf - nmass_leaf_luc * (1.0 - scale_indiv);
  1501. ncont += nmass_root - nmass_root_luc * (1.0 - scale_indiv);
  1502. ncont += nmass_sap - nmass_sap_luc * (1.0 - scale_indiv);
  1503. ncont += nmass_heart - nmass_heart_luc * (1.0 - scale_indiv);
  1504. ncont += nstore_longterm - nstore_longterm_luc * (1.0 - scale_indiv);
  1505. ncont += nstore_labile - nstore_labile_luc * (1.0 - scale_indiv);
  1506. }
  1507. else {
  1508. ncont += nmass_leaf * scale_indiv;
  1509. ncont += nmass_root * scale_indiv;
  1510. ncont += nmass_sap * scale_indiv;
  1511. ncont += nmass_heart * scale_indiv;
  1512. ncont += nstore_longterm * scale_indiv;
  1513. ncont += nstore_labile * scale_indiv;
  1514. }
  1515. if (pft.landcover == CROPLAND) {
  1516. if (luc) {
  1517. ncont += cropindiv->nmass_ho - cropindiv->nmass_ho_luc * (1.0 - scale_indiv);
  1518. ncont += cropindiv->nmass_agpool - cropindiv->nmass_agpool_luc * (1.0 - scale_indiv);
  1519. ncont += cropindiv->nmass_dead_leaf - cropindiv->nmass_dead_leaf_luc * (1.0 - scale_indiv);
  1520. }
  1521. else {
  1522. ncont += cropindiv->nmass_ho * scale_indiv;
  1523. ncont += cropindiv->nmass_agpool * scale_indiv;
  1524. ncont += cropindiv->nmass_dead_leaf * scale_indiv;
  1525. }
  1526. }
  1527. return ncont;
  1528. }
  1529. /// Leaf C content of individual
  1530. /**
  1531. * INPUT PARAMETERS
  1532. *
  1533. * \param scale_indiv scaling factor for living C
  1534. * \param luc down-scales living C (used in C balance tests)
  1535. */
  1536. double Individual::cleafcont(double scale_indiv, bool luc) const {
  1537. double cleafcont = 0.0;
  1538. if (alive || istruecrop_or_intercropgrass()) {
  1539. if (has_daily_turnover()) { // Not taking into account future daily wood allocation/turnover
  1540. if (cropindiv) {
  1541. if (luc) {
  1542. cleafcont += cropindiv->grs_cmass_leaf - cropindiv->grs_cmass_leaf_luc * (1.0 - scale_indiv);
  1543. }
  1544. else {
  1545. cleafcont += cropindiv->grs_cmass_leaf * scale_indiv;
  1546. }
  1547. }
  1548. if (pft.phenology == CROPGREEN) {
  1549. if (luc) {
  1550. cleafcont += cropindiv->grs_cmass_dead_leaf - cropindiv->grs_cmass_dead_leaf_luc * (1.0 - scale_indiv);
  1551. }
  1552. else {
  1553. cleafcont += cropindiv->grs_cmass_dead_leaf * scale_indiv;
  1554. }
  1555. }
  1556. }
  1557. else {
  1558. cleafcont = cmass_leaf * scale_indiv;
  1559. }
  1560. }
  1561. return cleafcont;
  1562. }
  1563. ///Leaf N content of individual
  1564. /**
  1565. * INPUT PARAMETERS
  1566. *
  1567. * \param scale_indiv scaling factor for living N
  1568. * \param luc down-scales living N (used in C balance tests)
  1569. */
  1570. double Individual::nleafcont(double scale_indiv, bool luc) const {
  1571. double nleafcont = 0.0;
  1572. if (luc)
  1573. nleafcont += nmass_leaf - nmass_leaf_luc * (1.0 - scale_indiv);
  1574. else
  1575. nleafcont += nmass_leaf * scale_indiv;
  1576. if (pft.landcover == CROPLAND) {
  1577. if (luc) {
  1578. nleafcont += cropindiv->nmass_dead_leaf - cropindiv->nmass_dead_leaf_luc * (1.0 - scale_indiv);
  1579. }
  1580. else {
  1581. nleafcont += cropindiv->nmass_dead_leaf * scale_indiv;
  1582. }
  1583. }
  1584. return nleafcont;
  1585. }
  1586. /// Root C content of individual
  1587. /**
  1588. * INPUT PARAMETERS
  1589. *
  1590. * \param scale_indiv scaling factor for living C
  1591. * \param luc down-scales living C (used in C balance tests)
  1592. */
  1593. double Individual::crootcont(double scale_indiv, bool luc) const {
  1594. double crootcont = 0.0;
  1595. if (alive || istruecrop_or_intercropgrass()) {
  1596. if (has_daily_turnover()) { // Not taking into account future daily wood allocation/turnover
  1597. if (cropindiv) {
  1598. if (luc) {
  1599. crootcont += cropindiv->grs_cmass_root - cropindiv->grs_cmass_root_luc * (1.0 - scale_indiv);
  1600. }
  1601. else {
  1602. crootcont += cropindiv->grs_cmass_root * scale_indiv;
  1603. }
  1604. }
  1605. }
  1606. else {
  1607. crootcont = cmass_root * scale_indiv;
  1608. }
  1609. }
  1610. return crootcont;
  1611. }
  1612. /// Root N content of individual
  1613. /**
  1614. * INPUT PARAMETERS
  1615. *
  1616. * \param scale_indiv scaling factor for living N
  1617. * \param luc down-scales living N (used in C balance tests)
  1618. */
  1619. double Individual::nrootcont(double scale_indiv, bool luc) const {
  1620. double nrootcont = 0.0;
  1621. if (luc) {
  1622. nrootcont += nmass_root - nmass_root_luc * (1.0 - scale_indiv);
  1623. }
  1624. else {
  1625. nrootcont += nmass_root * scale_indiv;
  1626. }
  1627. if (pft.lifeform != TREE) {
  1628. if (luc) {
  1629. nrootcont += nstore_longterm - nstore_longterm_luc * (1.0 - scale_indiv);
  1630. nrootcont += nstore_labile - nstore_labile_luc * (1.0 - scale_indiv);
  1631. }
  1632. else {
  1633. nrootcont += nstore_longterm * scale_indiv;
  1634. nrootcont += nstore_labile * scale_indiv;
  1635. }
  1636. }
  1637. return nrootcont;
  1638. }
  1639. /// Whether grass growth is uninterrupted by crop growth.
  1640. bool Individual::continous_grass() const {
  1641. if (pft.landcover != CROPLAND) {
  1642. return false;
  1643. }
  1644. Stand& stand = vegetation.patch.stand;
  1645. StandType& st = stlist[stand.stid];
  1646. bool sowing_restriction = true;
  1647. for (int i=0; i<st.rotation.ncrops; i++) {
  1648. int pftid = pftlist.getpftid(st.get_management(i).pftname);
  1649. if (pftid > -1 && !stand.get_gridcell().pft[pftid].sowing_restriction) {
  1650. sowing_restriction = false;
  1651. }
  1652. }
  1653. return cropindiv->isintercropgrass && sowing_restriction;
  1654. }
  1655. double Individual::ndemand_storage(double cton_leaf_opt) {
  1656. if (vegetation.patch.stand.is_true_crop_stand() && ifnlim) // only CROPGREEN, only ifnlim ?
  1657. // analogous with root demand
  1658. storendemand = max(0.0, cropindiv->grs_cmass_stem / (cton_leaf_opt * pft.cton_stem_avr / pft.cton_leaf_avr) - cropindiv->nmass_agpool);
  1659. else
  1660. storendemand = max(0.0, min(anpp * scale_n_storage / cton_leaf(), max_n_storage) - nstore());
  1661. return storendemand;
  1662. }
  1663. /// Checks C mass and zeroes any negative value, balancing by adding to npp and reducing respiration
  1664. double Individual::check_C_mass() {
  1665. if (pft.landcover != CROPLAND)
  1666. return 0;
  1667. double negative_cmass = 0.0;
  1668. if (cropindiv->grs_cmass_leaf < 0.0) {
  1669. negative_cmass -= cropindiv->grs_cmass_leaf;
  1670. cropindiv->ycmass_leaf -= cropindiv->grs_cmass_leaf;
  1671. cropindiv->grs_cmass_plant -= cropindiv->grs_cmass_leaf;
  1672. cropindiv->grs_cmass_leaf = 0.0;
  1673. }
  1674. if (cropindiv->grs_cmass_root < 0.0) {
  1675. negative_cmass -= cropindiv->grs_cmass_root;
  1676. cropindiv->ycmass_root -= cropindiv->grs_cmass_root;
  1677. cropindiv->grs_cmass_plant -= cropindiv->grs_cmass_root;
  1678. cropindiv->grs_cmass_root = 0.0;
  1679. }
  1680. if (cropindiv->grs_cmass_ho < 0.0) {
  1681. negative_cmass -= cropindiv->grs_cmass_ho;
  1682. cropindiv->ycmass_ho -= cropindiv->grs_cmass_ho;
  1683. cropindiv->grs_cmass_plant -= cropindiv->grs_cmass_ho;
  1684. cropindiv->grs_cmass_ho = 0.0;
  1685. }
  1686. if (cropindiv->grs_cmass_agpool < 0.0) {
  1687. negative_cmass -= cropindiv->grs_cmass_agpool;
  1688. cropindiv->ycmass_agpool -= cropindiv->grs_cmass_agpool;
  1689. cropindiv->grs_cmass_plant -= cropindiv->grs_cmass_agpool;
  1690. cropindiv->grs_cmass_agpool = 0.0;
  1691. }
  1692. if (cropindiv->grs_cmass_dead_leaf < 0.0) {
  1693. negative_cmass -= cropindiv->grs_cmass_dead_leaf;
  1694. cropindiv->ycmass_dead_leaf -= cropindiv->grs_cmass_dead_leaf;
  1695. cropindiv->grs_cmass_plant -= cropindiv->grs_cmass_dead_leaf;
  1696. cropindiv->grs_cmass_dead_leaf = 0.0;
  1697. }
  1698. if (cropindiv->grs_cmass_stem < 0.0) {
  1699. negative_cmass -= cropindiv->grs_cmass_stem;
  1700. cropindiv->ycmass_stem -= cropindiv->grs_cmass_stem;
  1701. cropindiv->grs_cmass_plant -= cropindiv->grs_cmass_stem;
  1702. cropindiv->grs_cmass_stem = 0.0;
  1703. }
  1704. if (largerthanzero(negative_cmass, -14)) {
  1705. anpp += negative_cmass;
  1706. report_flux(Fluxes::NPP, negative_cmass);
  1707. report_flux(Fluxes::RA, -negative_cmass);
  1708. }
  1709. return negative_cmass;
  1710. }
  1711. /// Checks N mass and zeroes any negative value, balancing by reducing N mass of other organs and (if needed) reducing anflux_landuse_change
  1712. double Individual::check_N_mass() {
  1713. // ecev3 - added URBAN and PEATLAND to avoid minor, but exceedlingly rare bugs in coupled runs
  1714. if (pft.landcover != CROPLAND && pft.landcover != PASTURE && pft.landcover != URBAN && pft.landcover != PEATLAND)
  1715. return 0;
  1716. double negative_nmass = 0.0;
  1717. if (nmass_leaf < 0.0) {
  1718. negative_nmass -= nmass_leaf;
  1719. if (cropindiv)
  1720. cropindiv->ynmass_leaf -= nmass_leaf;
  1721. nmass_leaf = 0.0;
  1722. }
  1723. if (nmass_root < 0.0) {
  1724. negative_nmass -= nmass_root;
  1725. if (cropindiv)
  1726. cropindiv->ynmass_root -= nmass_root;
  1727. nmass_root = 0.0;
  1728. }
  1729. if (cropindiv) {
  1730. if (cropindiv->nmass_ho < 0.0) {
  1731. negative_nmass -= cropindiv->nmass_ho;
  1732. cropindiv->ynmass_ho -= cropindiv->nmass_ho;
  1733. cropindiv->nmass_ho = 0.0;
  1734. }
  1735. if (cropindiv->nmass_agpool < 0.0) {
  1736. negative_nmass -= cropindiv->nmass_agpool;
  1737. cropindiv->ynmass_agpool -= cropindiv->nmass_agpool;
  1738. cropindiv->nmass_agpool = 0.0;
  1739. }
  1740. if (cropindiv->nmass_dead_leaf < 0.0) {
  1741. negative_nmass -= cropindiv->nmass_dead_leaf;
  1742. cropindiv->ynmass_dead_leaf -= cropindiv->nmass_dead_leaf;
  1743. cropindiv->nmass_dead_leaf = 0.0;
  1744. }
  1745. }
  1746. if (nstore_labile < 0.0) {
  1747. negative_nmass -= nstore_labile;
  1748. nstore_labile = 0.0;
  1749. }
  1750. if (nstore_longterm < 0.0) {
  1751. negative_nmass -= nstore_longterm;
  1752. nstore_longterm = 0.0;
  1753. }
  1754. if (largerthanzero(negative_nmass, -14)) {
  1755. double pos_nmass = ncont();
  1756. if (pos_nmass > negative_nmass) {
  1757. nmass_leaf -= negative_nmass * nmass_leaf / pos_nmass;
  1758. nmass_root -= negative_nmass * nmass_root / pos_nmass;
  1759. if (cropindiv) {
  1760. cropindiv->nmass_ho -= negative_nmass * cropindiv->nmass_ho / pos_nmass;
  1761. cropindiv->nmass_agpool -= negative_nmass * cropindiv->nmass_agpool / pos_nmass;
  1762. cropindiv->nmass_dead_leaf -= negative_nmass * cropindiv->nmass_dead_leaf / pos_nmass;
  1763. }
  1764. }
  1765. else {
  1766. vegetation.patch.stand.get_gridcell().landcover.anflux_landuse_change -= (negative_nmass - pos_nmass) * vegetation.patch.stand.get_gridcell_fraction();
  1767. nmass_leaf = 0.0;
  1768. nmass_leaf = 0.0;
  1769. if (cropindiv) {
  1770. cropindiv->nmass_ho = 0.0;
  1771. cropindiv->nmass_agpool = 0.0;
  1772. cropindiv->nmass_dead_leaf = 0.0;
  1773. }
  1774. }
  1775. }
  1776. return negative_nmass;
  1777. }
  1778. /// Whether resetting of grs_cmass and turnover (if has_daily_turnover() returns true) of continuous grass is to be done this day.
  1779. bool Individual::is_turnover_day() const {
  1780. if (patchpft().cropphen && patchpft().cropphen->growingseason) {
  1781. const Climate& climate = vegetation.patch.get_climate();
  1782. return date.day == climate.testday_prec;
  1783. }
  1784. else {
  1785. return false;
  1786. }
  1787. }
  1788. Patchpft& Individual::patchpft() const {
  1789. return vegetation.patch.pft[pft.id];
  1790. }
  1791. /// Save cmass-values on first day of the year of land cover change in expanding stands
  1792. void Individual::save_cmass_luc() {
  1793. cmass_tot_luc = 0.0;
  1794. if (cropindiv) {
  1795. cropindiv->grs_cmass_leaf_luc = cropindiv->grs_cmass_leaf;
  1796. cropindiv->grs_cmass_root_luc = cropindiv->grs_cmass_root;
  1797. cropindiv->grs_cmass_ho_luc = cropindiv->grs_cmass_ho;
  1798. cropindiv->grs_cmass_agpool_luc = cropindiv->grs_cmass_agpool;
  1799. cropindiv->grs_cmass_dead_leaf_luc = cropindiv->grs_cmass_dead_leaf;
  1800. cropindiv->grs_cmass_stem_luc = cropindiv->grs_cmass_stem;
  1801. }
  1802. cmass_tot_luc = ccont();
  1803. }
  1804. /// Save nmass-values on first day of the year of land cover change in expanding stands
  1805. void Individual::save_nmass_luc() {
  1806. nmass_leaf_luc = nmass_leaf;
  1807. nmass_root_luc = nmass_root;
  1808. nmass_sap_luc = nmass_sap;
  1809. nmass_heart_luc = nmass_heart;
  1810. nstore_longterm_luc = nstore_longterm;
  1811. nstore_labile_luc = nstore_labile;
  1812. if (cropindiv) {
  1813. cropindiv->nmass_ho_luc = cropindiv->nmass_ho;
  1814. cropindiv->nmass_agpool_luc = cropindiv->nmass_agpool;
  1815. cropindiv->nmass_dead_leaf_luc = cropindiv->nmass_dead_leaf;
  1816. }
  1817. nmass_tot_luc = ncont();
  1818. }
  1819. /// Gets the individual's daily cmass_leaf value
  1820. double Individual::cmass_leaf_today() const {
  1821. if (istruecrop_or_intercropgrass())
  1822. return patchpft().cropphen->growingseason ? cropindiv->grs_cmass_leaf : 0;
  1823. else
  1824. return cmass_leaf * phen;
  1825. }
  1826. /// Gets the individual's daily cmass_root value
  1827. double Individual::cmass_root_today() const {
  1828. if (istruecrop_or_intercropgrass())
  1829. return patchpft().cropphen->growingseason ? cropindiv->grs_cmass_root : 0;
  1830. else
  1831. return cmass_root * phen;
  1832. }
  1833. /// Gets the individual's daily fpc value
  1834. double Individual::fpc_today() const {
  1835. if (pft.phenology == CROPGREEN)
  1836. return patchpft().cropphen->growingseason ? fpc_daily : 0;
  1837. else
  1838. return fpc * phen;
  1839. }
  1840. /// Gets the individual's daily lai value
  1841. double Individual::lai_today() const {
  1842. if (pft.phenology == CROPGREEN)
  1843. return patchpft().cropphen->growingseason ? lai_daily : 0;
  1844. else
  1845. return lai * phen;
  1846. }
  1847. /// Gets the individual's daily lai_indiv value
  1848. double Individual::lai_indiv_today() const {
  1849. if (pft.phenology == CROPGREEN)
  1850. return patchpft().cropphen->growingseason ? lai_indiv_daily : 0;
  1851. else
  1852. return lai_indiv * phen;
  1853. }
  1854. /// Gets the Nitrigen limited LAI
  1855. double Individual::lai_nitrogen_today() const{
  1856. if (pft.phenology==CROPGREEN) {
  1857. double Ln = 0.0;
  1858. if (patchpft().cropphen->growingseason && cmass_leaf_today() > 0.0) {
  1859. const double k = 0.5;
  1860. const double ktn = 0.52*k + 0.01; // Yin et al 2003
  1861. double nb = 1/(pft.cton_leaf_max*pft.sla);
  1862. Ln = (1/ktn) * log(1+ktn*nmass_leaf/nb);
  1863. }
  1864. return Ln;
  1865. }
  1866. else {
  1867. return 1.0;
  1868. }
  1869. }
  1870. /// Gets the growingseason status for crop individual. Non-crop individuals always return true.
  1871. bool Individual::growingseason() const {
  1872. return patchpft().cropphen ? patchpft().cropphen->growingseason : true;
  1873. }
  1874. /// Whether harvest and turnover is done on actual C and N on harvest or turnover day, which can occur any day of the year.
  1875. bool Individual::has_daily_turnover() const {
  1876. return istruecrop_or_intercropgrass();
  1877. }
  1878. /// Help function for kill(), partitions wood biomass into litter and harvest
  1879. /**
  1880. * Wood biomass (either C or N) is partitioned into litter pools and
  1881. * harvest, according to PFT specific harvest fractions.
  1882. *
  1883. * Biomass is sent in as sap and heart, any debt should already have been
  1884. * subtracted from these before calling this function.
  1885. *
  1886. * \param mass_sap Sapwood
  1887. * \param mass_heart Heartwood
  1888. * \param harv_eff Harvest efficiency (fraction of biomass harvested)
  1889. * \param harvest_slow_frac Fraction of harvested products that goes into slow depository
  1890. * \param res_outtake Fraction of residue outtake at harvest
  1891. * \param litter_sap Biomass going to sapwood litter pool
  1892. * \param litter_heart Biomass going to heartwood litter pool
  1893. * \param fast_harvest Biomass going to harvest flux
  1894. * \param slow_harvest Biomass going to slow depository
  1895. */
  1896. void partition_wood_biomass(double mass_sap, double mass_heart,
  1897. double harv_eff, double harvest_slow_frac, double res_outtake,
  1898. double& litter_sap, double& litter_heart,
  1899. double& fast_harvest, double& slow_harvest) {
  1900. double sap_left = mass_sap;
  1901. double heart_left = mass_heart;
  1902. // Remove harvest
  1903. double total_wood_harvest = harv_eff * (sap_left + heart_left);
  1904. sap_left *= 1 - harv_eff;
  1905. heart_left *= 1 - harv_eff;
  1906. // Partition wood harvest into slow and fast
  1907. slow_harvest = total_wood_harvest * harvest_slow_frac;
  1908. fast_harvest = total_wood_harvest * (1 - harvest_slow_frac);
  1909. // Remove residue outtake
  1910. fast_harvest += res_outtake * (sap_left + heart_left);
  1911. sap_left *= 1 - res_outtake;
  1912. heart_left *= 1 - res_outtake;
  1913. // The rest goes to litter
  1914. litter_sap = sap_left;
  1915. litter_heart = heart_left;
  1916. }
  1917. void Individual::kill(bool harvest /* = false */) {
  1918. Patchpft& ppft = patchpft();
  1919. double charvest_flux = 0.0;
  1920. double charvested_products_slow = 0.0;
  1921. double nharvest_flux = 0.0;
  1922. double nharvested_products_slow = 0.0;
  1923. double harv_eff = 0.0;
  1924. double harvest_slow_frac = 0.0;
  1925. double res_outtake = 0.0;
  1926. // The function always deals with harvest, but the harvest
  1927. // fractions are zero when there is no harvest.
  1928. if (harvest) {
  1929. harv_eff = pft.harv_eff;
  1930. if (ifslowharvestpool) {
  1931. harvest_slow_frac = pft.harvest_slow_frac;
  1932. }
  1933. res_outtake = pft.res_outtake;
  1934. }
  1935. // C doesn't return to litter/harvest if the Individual isn't alive
  1936. if (alive || istruecrop_or_intercropgrass()) {
  1937. // For leaf and root, catches small, negative values too
  1938. // Leaf: remove residue outtake and send the rest to litter
  1939. if (has_daily_turnover() && cropindiv) {
  1940. if (pft.lifeform == GRASS && pft.phenology != CROPGREEN) {
  1941. charvest_flux += cropindiv->grs_cmass_leaf * harv_eff;
  1942. cropindiv->grs_cmass_leaf *= (1 - harv_eff);
  1943. }
  1944. ppft.litter_leaf += cropindiv->grs_cmass_leaf * (1 - res_outtake);
  1945. charvest_flux += cropindiv->grs_cmass_leaf * res_outtake;
  1946. }
  1947. else {
  1948. if (pft.lifeform == GRASS && pft.phenology != CROPGREEN) {
  1949. charvest_flux += cmass_leaf * harv_eff;
  1950. cmass_leaf *= (1 - harv_eff);
  1951. }
  1952. ppft.litter_leaf += cmass_leaf * (1 - res_outtake);
  1953. charvest_flux += cmass_leaf * res_outtake;
  1954. }
  1955. // Root: all goes to litter
  1956. if (has_daily_turnover() && cropindiv)
  1957. ppft.litter_root += cropindiv->grs_cmass_root;
  1958. else
  1959. ppft.litter_root += cmass_root;
  1960. if (pft.landcover == CROPLAND) {
  1961. if (has_daily_turnover()) {
  1962. charvest_flux += cropindiv->grs_cmass_ho * harv_eff;
  1963. cropindiv->grs_cmass_ho *= (1 - harv_eff);
  1964. if (pft.aboveground_ho) {
  1965. ppft.litter_leaf+=cropindiv->grs_cmass_ho * (1 - res_outtake);
  1966. charvest_flux += cropindiv->grs_cmass_ho * res_outtake;
  1967. }
  1968. else {
  1969. ppft.litter_root+=cropindiv->grs_cmass_ho;
  1970. }
  1971. ppft.litter_leaf+=cropindiv->grs_cmass_agpool * (1 - res_outtake);
  1972. charvest_flux += cropindiv->grs_cmass_agpool * res_outtake;
  1973. ppft.litter_leaf+=cropindiv->grs_cmass_dead_leaf * (1 - res_outtake);
  1974. charvest_flux += cropindiv->grs_cmass_dead_leaf * res_outtake;
  1975. ppft.litter_leaf+=cropindiv->grs_cmass_stem * (1 - res_outtake);
  1976. charvest_flux += cropindiv->grs_cmass_stem * res_outtake;
  1977. }
  1978. else {
  1979. charvest_flux += cropindiv->cmass_ho * harv_eff;
  1980. cropindiv->cmass_ho *= (1 - harv_eff);
  1981. if (pft.aboveground_ho) {
  1982. ppft.litter_leaf+=cropindiv->cmass_ho * (1 - res_outtake);
  1983. charvest_flux += cropindiv->cmass_ho * res_outtake;
  1984. }
  1985. else {
  1986. ppft.litter_root+=cropindiv->cmass_ho;
  1987. }
  1988. ppft.litter_leaf+=cropindiv->cmass_agpool * (1 - res_outtake);
  1989. charvest_flux += cropindiv->cmass_agpool * res_outtake;
  1990. }
  1991. }
  1992. // Deal with the wood biomass and carbon debt for trees
  1993. if (pft.lifeform == TREE) {
  1994. // debt smaller than existing wood biomass
  1995. if (cmass_debt <= cmass_sap + cmass_heart) {
  1996. // before partitioning the biomass into litter and harvest,
  1997. // first get rid of the debt so we're left with only
  1998. // sap and heart
  1999. double to_partition_sap = 0.0;
  2000. double to_partition_heart = 0.0;
  2001. if (cmass_heart >= cmass_debt) {
  2002. to_partition_sap = cmass_sap;
  2003. to_partition_heart = cmass_heart - cmass_debt;
  2004. }
  2005. else {
  2006. to_partition_sap = cmass_sap + cmass_heart - cmass_debt;
  2007. }
  2008. double clitter_sap, clitter_heart, cwood_harvest;
  2009. partition_wood_biomass(to_partition_sap, to_partition_heart,
  2010. harv_eff, harvest_slow_frac, res_outtake,
  2011. clitter_sap, clitter_heart,
  2012. cwood_harvest, charvested_products_slow);
  2013. ppft.litter_sap += clitter_sap;
  2014. ppft.litter_heart += clitter_heart;
  2015. charvest_flux += cwood_harvest;
  2016. }
  2017. // debt larger than existing wood biomass
  2018. else {
  2019. double debt_excess = cmass_debt - (cmass_sap + cmass_heart);
  2020. report_flux(Fluxes::NPP, debt_excess);
  2021. report_flux(Fluxes::RA, -debt_excess);
  2022. }
  2023. }
  2024. }
  2025. // Nitrogen always return to soil litter
  2026. if (pft.lifeform == TREE) {
  2027. double nlitter_sap, nlitter_heart, nwood_harvest;
  2028. // Transfer nitrogen storage to sapwood nitrogen litter/harvest
  2029. partition_wood_biomass(nmass_sap + nstore(), nmass_heart,
  2030. harv_eff, harvest_slow_frac, res_outtake,
  2031. nlitter_sap, nlitter_heart,
  2032. nwood_harvest, nharvested_products_slow);
  2033. ppft.nmass_litter_sap += nlitter_sap;
  2034. ppft.nmass_litter_heart += nlitter_heart;
  2035. nharvest_flux += nwood_harvest;
  2036. }
  2037. else {
  2038. // Transfer nitrogen storage to root nitrogen litter
  2039. ppft.nmass_litter_root += nstore();
  2040. }
  2041. // Leaf: remove residue outtake and send the rest to litter
  2042. ppft.nmass_litter_leaf += nmass_leaf * (1 - res_outtake);
  2043. nharvest_flux += nmass_leaf * res_outtake;
  2044. // Root: all goes to litter
  2045. ppft.nmass_litter_root += nmass_root;
  2046. if (pft.landcover == CROPLAND) {
  2047. if (pft.aboveground_ho) {
  2048. ppft.nmass_litter_leaf+=cropindiv->nmass_ho * (1 - res_outtake);
  2049. nharvest_flux += cropindiv->nmass_ho * res_outtake;
  2050. }
  2051. else
  2052. ppft.litter_root+=cropindiv->nmass_ho;
  2053. ppft.nmass_litter_leaf+=cropindiv->nmass_agpool * (1 - res_outtake);
  2054. nharvest_flux += cropindiv->nmass_agpool * res_outtake;
  2055. ppft.nmass_litter_leaf += cropindiv->nmass_dead_leaf * (1 - res_outtake);
  2056. nharvest_flux += cropindiv->nmass_dead_leaf * res_outtake;
  2057. }
  2058. // Report harvest fluxes
  2059. report_flux(Fluxes::HARVESTC, charvest_flux);
  2060. report_flux(Fluxes::HARVESTN, nharvest_flux);
  2061. // Add to biomass depositories for long-lived products
  2062. ppft.harvested_products_slow += charvested_products_slow;
  2063. ppft.harvested_products_slow_nmass += nharvested_products_slow;
  2064. }
  2065. double Individual::wscal_mean() const {
  2066. return patchpft().wscal_mean;
  2067. }
  2068. ////////////////////////////////////////////////////////////////////////////////
  2069. // Implementation of Gridcellpft member functions
  2070. ////////////////////////////////////////////////////////////////////////////////
  2071. void Gridcellpft::serialize(ArchiveStream& arch) {
  2072. arch & addtw
  2073. & Km
  2074. & autumnoccurred
  2075. & springoccurred
  2076. & vernstartoccurred
  2077. & vernendoccurred
  2078. & first_autumndate
  2079. & first_autumndate20
  2080. & first_autumndate_20
  2081. & last_springdate
  2082. & last_springdate20
  2083. & last_springdate_20
  2084. & last_verndate
  2085. & last_verndate20
  2086. & last_verndate_20
  2087. & sdate_default
  2088. & sdatecalc_temp
  2089. & sdatecalc_prec
  2090. & sdate_force
  2091. & hdate_force
  2092. & Nfert_read
  2093. & hlimitdate_default
  2094. & wintertype
  2095. & swindow
  2096. & swindow_irr
  2097. & sowing_restriction;
  2098. }
  2099. ////////////////////////////////////////////////////////////////////////////////
  2100. // Implementation of Gridcellst member functions
  2101. ////////////////////////////////////////////////////////////////////////////////
  2102. void Gridcellst::serialize(ArchiveStream& arch) {
  2103. arch & frac
  2104. & frac_old_orig
  2105. & nstands
  2106. & nfert;
  2107. }
  2108. ////////////////////////////////////////////////////////////////////////////////
  2109. // Implementation of Landcover member functions
  2110. ////////////////////////////////////////////////////////////////////////////////
  2111. Landcover::Landcover() {
  2112. updated = false;
  2113. // ecev3 - no need to serialize these
  2114. dcflux_harvest_slow = 0.0;
  2115. dcflux_landuse_change = 0.0;
  2116. acflux_harvest_slow = 0.0;
  2117. acflux_landuse_change = 0.0;
  2118. anflux_harvest_slow = 0.0;
  2119. anflux_landuse_change = 0.0;
  2120. for (int i=0; i<NLANDCOVERTYPES; i++) {
  2121. frac[i] = 0.0;
  2122. frac_old[i] = 0.0;
  2123. frac_change[i] = 0.0;
  2124. acflux_harvest_slow_lc[i] = 0.0;
  2125. acflux_landuse_change_lc[i] = 0.0;
  2126. anflux_harvest_slow_lc[i] = 0.0;
  2127. anflux_landuse_change_lc[i] = 0.0;
  2128. for(int j=0;j<NLANDCOVERTYPES;j++) {
  2129. frac_transfer[i][j] = 0.0;
  2130. }
  2131. expand_to_new_stand[i] = (i == NATURAL || i == FOREST);
  2132. pool_to_all_landcovers[i] = false; // from a donor landcover; alt.c
  2133. pool_from_all_landcovers[i] = false; // to a receptor landcover; alt.a
  2134. }
  2135. }
  2136. void Landcover::serialize(ArchiveStream& arch) {
  2137. arch & frac;
  2138. }
  2139. ////////////////////////////////////////////////////////////////////////////////
  2140. // Implementation of Gridcell member functions
  2141. ////////////////////////////////////////////////////////////////////////////////
  2142. Gridcell::Gridcell():climate(*this) {
  2143. for (unsigned int p=0; p<pftlist.nobj; p++) {
  2144. pft.createobj(pftlist[p]);
  2145. }
  2146. for (unsigned int s=0; s<stlist.nobj; s++) {
  2147. st.createobj(stlist[s]);
  2148. }
  2149. if (!run_landcover) {
  2150. create_stand(NATURAL);
  2151. landcover.frac[NATURAL] = 1.0;
  2152. }
  2153. seed = 12345678;
  2154. // ecev3
  2155. IFStypehigh = 0; // 0 to 20
  2156. IFSfrachigh = 0.0; // 0 to 1
  2157. IFStypelow = 0; // 0 to 20
  2158. IFSfraclow = 0.0; // 0 to 1
  2159. simulationyear = 0;
  2160. isspinup = false;
  2161. ndep_lon_index = -999; // for CMIP6 N dep. data
  2162. ndep_lat_index = -999; // for CMIP6 N dep. data
  2163. // ecev3
  2164. laiphen_high_today = 0.0;
  2165. laiphen_low_today = 0.0;
  2166. for(int ii=0;ii<NLANDCOVERTYPES;ii++) {
  2167. landcover_fpc[ii]=0.0;
  2168. landcover_lai[ii]=0.0;
  2169. }
  2170. naturaltreeFPC = 0.0;
  2171. naturalgrassFPC = 0.0;
  2172. transferhightolow = false;
  2173. // Year from which on Land Use is frozen
  2174. fixedLUafter = -1; // -1 means unfrozen, dynamic LU.
  2175. }
  2176. double Gridcell::get_lon() const {
  2177. return lon;
  2178. }
  2179. double Gridcell::get_lat() const {
  2180. return lat;
  2181. }
  2182. void Gridcell::set_coordinates(double longitude, double latitude) {
  2183. lon = longitude;
  2184. lat = latitude;
  2185. }
  2186. Stand& Gridcell::create_stand_lu(StandType& st, double fraction, int no_patch) {
  2187. Stand& stand = create_stand(st.landcover, no_patch);
  2188. stand.init_stand_lu(st, fraction);
  2189. return stand;
  2190. }
  2191. double Gridcell::ccont() {
  2192. double ccont = 0.0;
  2193. for (unsigned int s = 0; s < nbr_stands(); s++) {
  2194. Stand& stand = (*this)[s];
  2195. ccont += stand.ccont() * stand.get_gridcell_fraction();
  2196. }
  2197. return ccont;
  2198. }
  2199. double Gridcell::ncont() {
  2200. double ncont = 0.0;
  2201. for (unsigned int s = 0; s < nbr_stands(); s++) {
  2202. Stand& stand = (*this)[s];
  2203. ncont += stand.ncont() * stand.get_gridcell_fraction();
  2204. }
  2205. return ncont;
  2206. }
  2207. double Gridcell::cflux() {
  2208. double cflux = 0.0;
  2209. for (unsigned int s = 0; s < nbr_stands(); s++) {
  2210. Stand& stand = (*this)[s];
  2211. cflux += stand.cflux() * stand.get_gridcell_fraction();
  2212. }
  2213. cflux += landcover.acflux_landuse_change;
  2214. cflux += landcover.acflux_harvest_slow;
  2215. return cflux;
  2216. }
  2217. // ecev3
  2218. void Gridcell::set_first_year(int fy) {
  2219. for (unsigned int s = 0; s < nbr_stands(); s++) {
  2220. Stand& stand = (*this)[s];
  2221. stand.first_year=fy;
  2222. }
  2223. }
  2224. double Gridcell::nflux() {
  2225. double nflux = 0.0;
  2226. for (unsigned int s = 0; s < nbr_stands(); s++) {
  2227. Stand& stand = (*this)[s];
  2228. nflux += stand.nflux() * stand.get_gridcell_fraction();
  2229. }
  2230. nflux += landcover.anflux_landuse_change;
  2231. nflux += landcover.anflux_harvest_slow;
  2232. return nflux;
  2233. }
  2234. /// ecev3 - Get nitrogen deposition data for this gridcell
  2235. /**
  2236. * Determine N deposition forcing for this cell. We use the nearest 0.5 degree cell in the
  2237. * Lamarque dataset. Calls
  2238. *
  2239. *
  2240. * \param ndepfile .bin file containing the N dep. data. Read from guess.ins
  2241. * \param rcp Set in guess.ins, with (integer) values 0 to 4, where
  2242. * 0 - historical only
  2243. * 1 - rcp3PD
  2244. * 2 - rcp45
  2245. * 3 - rcp60
  2246. * 4 - rcp85
  2247. */
  2248. bool Gridcell::getndep(const char* ndepfile, double rcp) {
  2249. Lamarque::timeseriestype timeseries;
  2250. switch (int(rcp)) {
  2251. case 0:
  2252. timeseries = Lamarque::HISTORIC;
  2253. break;
  2254. case 1:
  2255. timeseries = Lamarque::RCP26;
  2256. break;
  2257. case 2:
  2258. timeseries = Lamarque::RCP45;
  2259. break;
  2260. case 3:
  2261. timeseries = Lamarque::RCP60;
  2262. break;
  2263. case 4:
  2264. timeseries = Lamarque::RCP85;
  2265. break;
  2266. default:
  2267. // shouldn't happen
  2268. fail("Unexpected timeseriestype/RCP in guess.ins!");
  2269. }
  2270. // Call the EC-Earth version of getndep to determine the NEAREST N dep data
  2271. bool ndepOK = ndepts.getndep_nearest(ndepfile, lon, lat, timeseries);
  2272. return ndepOK;
  2273. }
  2274. bool getmonthlyNdepforcingConserve(const char* varname, int year, double data[12], int ndepindex) {
  2275. // 1st (".nc") or 2nd order remapping file?
  2276. const char* filenametail = "2.nc";
  2277. xtring ndep_cmip6_dir = param["ndep_cmip6_dir"].str;
  2278. const char* filevar = varname;
  2279. if (!strcmp(varname, "drynhx"))
  2280. filevar = "drynhx";
  2281. if (!strcmp(varname, "drynoy"))
  2282. filevar = "drynoy";
  2283. if (!strcmp(varname, "wetnhx"))
  2284. filevar = "wetnhx";
  2285. if (!strcmp(varname, "wetnoy"))
  2286. filevar = "wetnoy";
  2287. // First create NC file name for this data
  2288. std::string full_path((char*)ndep_cmip6_dir);
  2289. // AMIP
  2290. full_path += filevar;
  2291. full_path += filenametail;
  2292. // Open NC file
  2293. int status, ncid;
  2294. status = nc_open(full_path.c_str(), NC_NOWRITE, &ncid);
  2295. if (status != NC_NOERR)
  2296. return false;
  2297. // Get the ID for varname
  2298. int var_id;
  2299. status = nc_inq_varid(ncid, varname, &var_id);
  2300. if (status != NC_NOERR)
  2301. return false;
  2302. // Read data
  2303. for (int mm = 0; mm < 12; mm++) {
  2304. size_t index[] = { year * 12 + mm, ndepindex };
  2305. double val;
  2306. status = nc_get_var1_double(ncid, var_id, index, &val);
  2307. // < 0?
  2308. val = max(val, 0.0);
  2309. if (status != NC_NOERR)
  2310. return false;
  2311. data[mm] = val * 86400.0; // convert from kg N m-2 s-1 to kg N m-2 day-1
  2312. }
  2313. nc_close(ncid);
  2314. return true;
  2315. } // getmonthlyNdepforcingConserve
  2316. /// ecev3 - Get simulation year
  2317. /**
  2318. * Return simulation year depending on simulation setups
  2319. */
  2320. int Gridcell::getsimulationyear(int year) {
  2321. if (ECEARTH && !ECEARTHWITHCRUNCEP) // ecev3
  2322. return simulationyear;
  2323. else
  2324. return year;
  2325. }
  2326. /// ecev3 - Get nitrogen deposition data for this gridcell
  2327. /**
  2328. * Determine N deposition forcing for this cell and year.
  2329. *
  2330. * \param ndepfile netcdf file containing the N dep. data. Read from guess.ins
  2331. */
  2332. bool Gridcell::getndepCMIP6(const char* ndepfile, int fixedNDepafter) {
  2333. // N deposition data year
  2334. int ndep_year = max(0, date.get_calendar_year() - CMIP6STARTYEAR);
  2335. // if DECK experiments are ON set Ndep to 1850
  2336. if (fixedNDepafter >= 0 && date.get_calendar_year() >= fixedNDepafter) {
  2337. ndep_year = max(0, fixedNDepafter - CMIP6STARTYEAR);
  2338. dprintf("N-Dep set fix to year %i \n", ndep_year + CMIP6STARTYEAR);
  2339. }
  2340. else {
  2341. dprintf("N-Dep set to calendar year %i \n", date.get_calendar_year());
  2342. }
  2343. // Monthly dry NH4 deposition (kg m-2 s-1)
  2344. const char* vartoread = "drynhx";
  2345. bool dataOK = getmonthlyNdepforcingConserve(vartoread, ndep_year, mdrynhx, ndep_index);
  2346. if (!dataOK) {
  2347. dprintf("Error reading dry NHx deposition data before LPJ-GUESS spinup. Quitting... \n");
  2348. return false;
  2349. }
  2350. // Monthly wet NH4 deposition (kg m-2 s-1)
  2351. vartoread = "wetnhx";
  2352. dataOK = getmonthlyNdepforcingConserve(vartoread, ndep_year, mwetnhx, ndep_index);
  2353. if (!dataOK) {
  2354. dprintf("Error reading wet NHx deposition data before LPJ-GUESS spinup. Quitting... \n");
  2355. return false;
  2356. }
  2357. // Monthly dry NO3 deposition (kg m-2 s-1)
  2358. vartoread = "drynoy";
  2359. dataOK = getmonthlyNdepforcingConserve(vartoread, ndep_year, mdrynoy, ndep_index);
  2360. if (!dataOK) {
  2361. dprintf("Error reading dry NOy deposition data before LPJ-GUESS spinup. Quitting... \n");
  2362. return false;
  2363. }
  2364. // Monthly wet NO3 deposition (kg m-2 s-1)
  2365. vartoread = "wetnoy";
  2366. dataOK = getmonthlyNdepforcingConserve(vartoread, ndep_year, mwetnoy, ndep_index);
  2367. if (!dataOK) {
  2368. dprintf("Error reading wet NOy deposition data before LPJ-GUESS spinup. Quitting... \n");
  2369. return false;
  2370. }
  2371. // Add up dry and wet deposition
  2372. for (int m = 0; m < 12; m++) {
  2373. mndrydep[m] = mdrynhx[m] + mdrynoy[m];
  2374. mnwetdep[m] = mwetnhx[m] + mwetnoy[m];
  2375. }
  2376. return dataOK;
  2377. }
  2378. void Gridcell::serialize(ArchiveStream& arch) {
  2379. arch & climate
  2380. & landcover
  2381. & seed
  2382. & balance
  2383. & id // ecev3
  2384. & ifs_index // ecev3
  2385. & ndep_index // ecev3
  2386. // & mdrynhx // ecev3
  2387. // & mwetnhx // ecev3
  2388. // & mdrynoy // ecev3
  2389. // & mwetnoy // ecev3
  2390. & mndrydep // ecev3
  2391. & mnwetdep // ecev3
  2392. & IFStypehigh // ecev3
  2393. & IFSfrachigh // ecev3
  2394. & IFStypelow // ecev3
  2395. & IFSfraclow // ecev3
  2396. & naturaltreeFPC // ecev3
  2397. & naturalgrassFPC // ecev3
  2398. & transferhightolow // ecev3
  2399. & simulationyear // ecev3
  2400. & ndep_lon_index // ecev3
  2401. & ndep_lat_index // ecev3
  2402. & fixedLUafter // ecev3
  2403. & awcont_5; // ecev3
  2404. if (arch.save()) {
  2405. for (unsigned int i = 0; i < pft.nobj; i++) {
  2406. arch & pft[i];
  2407. }
  2408. for (unsigned int i = 0; i < st.nobj; i++) {
  2409. arch & st[i];
  2410. }
  2411. unsigned int nstands = nbr_stands();
  2412. arch & nstands;
  2413. for (unsigned int s = 0; s < nstands; s++) {
  2414. arch & (*this)[s].landcover
  2415. & (*this)[s];
  2416. }
  2417. }
  2418. else {
  2419. pft.killall();
  2420. for (unsigned int i = 0; i < pftlist.nobj; i++) {
  2421. pft.createobj(pftlist[i]);
  2422. arch & pft[i];
  2423. }
  2424. st.killall();
  2425. for (unsigned int i = 0; i < stlist.nobj; i++) {
  2426. st.createobj(stlist[i]);
  2427. arch & st[i];
  2428. }
  2429. clear();
  2430. unsigned int number_of_stands;
  2431. arch & number_of_stands;
  2432. for (unsigned int s = 0; s < number_of_stands; s++) {
  2433. landcovertype landcover;
  2434. arch & landcover;
  2435. create_stand(landcover);
  2436. arch & (*this)[s];
  2437. }
  2438. }
  2439. }
  2440. Stand& Gridcell::create_stand(landcovertype landcover, int no_patch) {
  2441. Stand* stand = new Stand(get_next_id(), this, soiltype, landcover, no_patch);
  2442. push_back(stand);
  2443. return *stand;
  2444. }
  2445. Gridcell::iterator Gridcell::delete_stand(iterator itr) {
  2446. return erase(itr);
  2447. }
  2448. unsigned int Gridcell::nbr_stands() const {
  2449. return (int) size();
  2450. }
  2451. void Sompool::serialize(ArchiveStream& arch) {
  2452. arch & cmass
  2453. & nmass
  2454. //& cdec
  2455. //& ndec
  2456. //& delta_cmass
  2457. //& delta_nmass
  2458. & ligcfrac
  2459. //& fracremain
  2460. & ntoc
  2461. & litterme
  2462. & fireresist
  2463. & mfracremain_mean;
  2464. }
  2465. ////////////////////////////////////////////////////////////////////////////////
  2466. // Implementation of MassBalance member functions
  2467. ////////////////////////////////////////////////////////////////////////////////
  2468. void MassBalance::serialize(ArchiveStream& arch) {
  2469. arch & start_year
  2470. & ccont_zero
  2471. & ccont_zero_scaled
  2472. & cflux_zero
  2473. & ncont_zero
  2474. & ncont_zero_scaled
  2475. & nflux_zero
  2476. & ccont
  2477. & ncont
  2478. & cflux
  2479. & nflux;
  2480. }
  2481. /// Should be used together with check_indiv()
  2482. void MassBalance::init_indiv(Individual& indiv) {
  2483. Patch& patch = indiv.vegetation.patch;
  2484. Stand& stand = patch.stand;
  2485. if (!stand.is_true_crop_stand())
  2486. return;
  2487. Gridcell& gridcell = stand.get_gridcell();
  2488. double scale = 1.0;
  2489. if (patch.stand.get_gridcell().landcover.updated && (patch.nharv == 0 || date.day == 0))
  2490. scale = stand.scale_LC_change;
  2491. ccont_zero = indiv.ccont();
  2492. ccont_zero_scaled = indiv.ccont(scale, true);
  2493. // Add soil C
  2494. ccont_zero += patch.ccont(0.0);
  2495. ccont_zero_scaled += patch.ccont(0.0);
  2496. cflux_zero = patch.cflux();
  2497. ncont_zero = indiv.ncont();
  2498. ncont_zero_scaled = indiv.ncont(scale, true);
  2499. // Add soil N
  2500. ncont_zero += patch.ncont(0.0);
  2501. ncont_zero_scaled += patch.ncont(0.0);
  2502. nflux_zero = patch.nflux();
  2503. }
  2504. bool MassBalance::check_indiv_C(Individual& indiv, bool check_harvest) {
  2505. bool balance = true;
  2506. Patch& patch = indiv.vegetation.patch;
  2507. Stand& stand = patch.stand;
  2508. if(!stand.is_true_crop_stand())
  2509. return balance;
  2510. Gridcell& gridcell = stand.get_gridcell();
  2511. double ccont = indiv.ccont();
  2512. ccont += patch.ccont(0.0);
  2513. double cflux = patch.cflux();
  2514. if(check_harvest && patch.isharvestday)
  2515. ccont_zero = ccont_zero_scaled;
  2516. if (gridcell.getsimulationyear(date.year) >= nyear_spinup && !negligible(ccont - ccont_zero + cflux - cflux_zero, -10)) {
  2517. dprintf("\nStand %d Patch %d Indiv %d C balance year %d day %d: %.10f\n", patch.stand.id, patch.id, indiv.id, date.year, date.day, ccont - ccont_zero + cflux - cflux_zero);
  2518. dprintf("C pool change: %.10f\n", ccont - ccont_zero);
  2519. dprintf("C flux: %.10f\n\n", cflux - cflux_zero);
  2520. balance = false;
  2521. }
  2522. return balance;
  2523. }
  2524. bool MassBalance::check_indiv_N(Individual& indiv, bool check_harvest) {
  2525. bool balance = true;
  2526. Patch& patch = indiv.vegetation.patch;
  2527. Stand& stand = patch.stand;
  2528. if (!stand.is_true_crop_stand())
  2529. return balance;
  2530. Gridcell& gridcell = stand.get_gridcell();
  2531. double ncont = indiv.ncont();
  2532. ncont += patch.ncont(0.0);
  2533. double nflux = patch.nflux();
  2534. if (check_harvest && patch.isharvestday)
  2535. ncont_zero = ncont_zero_scaled;
  2536. if (gridcell.getsimulationyear(date.year) >= nyear_spinup && !negligible(ncont - ncont_zero + nflux - nflux_zero, -14)) {
  2537. dprintf("\nStand %d Patch %d Indiv %d N balance year %d day %d: %.10f\n", patch.stand.id, patch.id, indiv.id, date.year, date.day, ncont - ncont_zero + nflux - nflux_zero);
  2538. dprintf("N pool change: %.14f\n", ncont - ncont_zero);
  2539. dprintf("N flux: %.14f\n\n", nflux - nflux_zero);
  2540. balance = false;
  2541. }
  2542. return balance;
  2543. }
  2544. /// Should be preceded by init_indiv()
  2545. /** check_harvest must be true if growth_daily() is tested
  2546. * canopy_exchange() and growth_daily() and functions in between cannot be tested separately
  2547. */
  2548. bool MassBalance::check_indiv(Individual& indiv, bool check_harvest) {
  2549. return check_indiv_C(indiv, check_harvest) && check_indiv_N(indiv, check_harvest);
  2550. }
  2551. /// Should be used together with check_patch() e.g. in framework()
  2552. void MassBalance::init_patch(Patch& patch) {
  2553. Stand& stand = patch.stand;
  2554. if (!stand.is_true_crop_stand())
  2555. return;
  2556. Gridcell& gridcell = stand.get_gridcell();
  2557. double scale = 1.0;
  2558. if (patch.stand.get_gridcell().landcover.updated && (patch.nharv == 0 || date.day == 0))
  2559. scale = stand.scale_LC_change;
  2560. ccont_zero = patch.ccont();
  2561. ccont_zero_scaled = patch.ccont(scale, true);
  2562. cflux_zero = patch.cflux();
  2563. if (stand.get_gridcell_fraction())
  2564. cflux_zero += gridcell.landcover.acflux_harvest_slow / stand.get_gridcell_fraction();
  2565. ncont_zero = patch.ncont();
  2566. ncont_zero_scaled = patch.ncont(scale, true);
  2567. nflux_zero = patch.nflux();
  2568. if (stand.get_gridcell_fraction())
  2569. nflux_zero += gridcell.landcover.anflux_harvest_slow / stand.get_gridcell_fraction();
  2570. }
  2571. bool MassBalance::check_patch_C(Patch& patch, bool check_harvest) {
  2572. bool balance = true;
  2573. Stand& stand = patch.stand;
  2574. if (!stand.is_true_crop_stand())
  2575. return balance;
  2576. Gridcell& gridcell = stand.get_gridcell();
  2577. double ccont = patch.ccont();
  2578. double cflux = patch.cflux();
  2579. if (stand.get_gridcell_fraction())
  2580. cflux += gridcell.landcover.acflux_harvest_slow / stand.get_gridcell_fraction();
  2581. if (check_harvest && patch.isharvestday)
  2582. ccont_zero = ccont_zero_scaled;
  2583. if (gridcell.getsimulationyear(date.year) >= nyear_spinup && !negligible(ccont - ccont_zero + cflux - cflux_zero, -10)) {
  2584. dprintf("\nStand %d Patch %d C balance year %d day %d: %.10f\n", patch.stand.id, patch.id, date.year, date.day, ccont - ccont_zero + cflux - cflux_zero);
  2585. dprintf("C pool change: %.10f\n", ccont - ccont_zero);
  2586. dprintf("C flux: %.10f\n\n", cflux - cflux_zero);
  2587. balance = false;
  2588. }
  2589. return balance;
  2590. }
  2591. bool MassBalance::check_patch_N(Patch& patch, bool check_harvest) {
  2592. bool balance = true;
  2593. Stand& stand = patch.stand;
  2594. if (!stand.is_true_crop_stand())
  2595. return balance;
  2596. Gridcell& gridcell = stand.get_gridcell();
  2597. double ncont = patch.ncont();
  2598. double nflux = patch.nflux();
  2599. if (stand.get_gridcell_fraction())
  2600. nflux += gridcell.landcover.anflux_harvest_slow / stand.get_gridcell_fraction();
  2601. if (check_harvest && patch.isharvestday)
  2602. ncont_zero = ncont_zero_scaled;
  2603. if (gridcell.getsimulationyear(date.year) >= nyear_spinup && date.year >= nyear_spinup && !negligible(ncont - ncont_zero + nflux - nflux_zero, -14)) {
  2604. dprintf("\nStand %d Patch %d N balance year %d day %d: %.14f\n", patch.stand.id, patch.id, date.year, date.day, ncont - ncont_zero + nflux - nflux_zero);
  2605. dprintf("N pool change: %.14f\n", ncont - ncont_zero);
  2606. dprintf("N flux: %.14f\n\n", nflux - nflux_zero);
  2607. balance = false;
  2608. }
  2609. return balance;
  2610. }
  2611. /// Should be preceded by init_patch() e.g. i framework()
  2612. /** check_harvest must be true if growth_daily() is tested
  2613. * canopy_exchange() and growth_daily() and functions in between cannot be tested separately
  2614. * (init_patch() must be before canopy_exchange() and check_patch() after growth_daily()
  2615. */
  2616. bool MassBalance::check_patch(Patch& patch, bool check_harvest) {
  2617. return check_patch_C(patch, check_harvest) && check_patch_N(patch, check_harvest);
  2618. }
  2619. void MassBalance::check_year(Gridcell& gridcell) {
  2620. if (gridcell.getsimulationyear(date.year) < start_year) {
  2621. return;
  2622. }
  2623. double ccont_year = gridcell.ccont();
  2624. double cflux_year = gridcell.cflux();
  2625. double ncont_year = gridcell.ncont();
  2626. double nflux_year = gridcell.nflux();
  2627. if (gridcell.getsimulationyear(date.year) == start_year) {
  2628. ccont_zero = ccont_year;
  2629. ncont_zero = ncont_year;
  2630. }
  2631. else {
  2632. cflux += cflux_year;
  2633. nflux += nflux_year;
  2634. // C balance check:
  2635. if (!negligible(ccont_year - ccont + cflux_year, -9)) {
  2636. dprintf("\n(%.2f, %.2f): C balance year %d: %.10f\n", gridcell.get_lon(), gridcell.get_lat(), date.year, ccont_year - ccont + cflux_year);
  2637. dprintf("C pool change: %.5f\n", ccont_year - ccont);
  2638. dprintf("C flux: %.5f\n", cflux_year);
  2639. }
  2640. // Cropland without N-limitation is not balanced in N, fertilisation gives poorer N-balance
  2641. // For natural vegetation or unfertilised N-limited cropland, the check can be much stricter
  2642. // N balance check:
  2643. if (!negligible(ncont_year - ncont + nflux_year, -9)) {
  2644. dprintf("\n(%.2f, %.2f): N balance year %d: %.9f\n", gridcell.get_lon(), gridcell.get_lat(), date.year, ncont_year - ncont + nflux_year);
  2645. dprintf("N pool change: %.9f\n", ncont_year - ncont);
  2646. dprintf("N flux: %.9f\n", nflux_year);
  2647. }
  2648. }
  2649. ccont = ccont_year;
  2650. ncont = ncont_year;
  2651. }
  2652. void MassBalance::check_period(Gridcell& gridcell) {
  2653. // C balance check:
  2654. if (!negligible(ccont - ccont_zero + cflux, -9)) {
  2655. dprintf("\nWARNING: (%.2f, %.2f): Period C balance: %.10f\n", gridcell.get_lon(), gridcell.get_lat(), ccont - ccont_zero + cflux);
  2656. dprintf("C pool change: %.10f\n", ccont - ccont_zero);
  2657. dprintf("C fluxes: %.10f\n", cflux);
  2658. }
  2659. // Cropland without N-limitation is not balanced in N, fertilisation gives poorer N-balance
  2660. // For natural vegetation or unfertilised N-limited cropland, the check can be much stricter
  2661. // N balance check:
  2662. if (!negligible(ncont - ncont_zero + nflux, -9)) {
  2663. dprintf("\nWARNING: (%.2f, %.2f): Period N balance: %.10f\n", gridcell.get_lon(), gridcell.get_lat(), ncont - ncont_zero + nflux);
  2664. dprintf("N pool change: %.10f\n", ncont - ncont_zero);
  2665. dprintf("N fluxes: %.10f\n", nflux);
  2666. }
  2667. }
  2668. void MassBalance::init(Gridcell& gridcell) {
  2669. // start_year = date.year;
  2670. ccont_zero = gridcell.ccont();
  2671. cflux_zero = gridcell.cflux();
  2672. }
  2673. void MassBalance::check(Gridcell& gridcell) {
  2674. double ccont = gridcell.ccont();
  2675. double cflux = gridcell.cflux();
  2676. if (!negligible(ccont - ccont_zero + cflux, -5)) {
  2677. dprintf("\n(%.2f, %.2f): C balance year %d: %.5f\n", gridcell.get_lon(), gridcell.get_lat(), date.year, ccont - ccont_zero + cflux);
  2678. dprintf("C pool change: %.5f\n", ccont - ccont_zero);
  2679. dprintf("C flux: %.5f\n\n", cflux);
  2680. }
  2681. }
  2682. bool Date::is_leap(int year) {
  2683. if (ECEARTH) {
  2684. if (!ECEARTHWITHCRUNCEP) {
  2685. return (!(year % 4) && (year % 100 | !(year % 400)));
  2686. }
  2687. else {
  2688. int yr = date.year - nyear_spinup + 1901; // should be FIRSTHISTYEAR==1901 for CRUNCEP
  2689. return (!(yr % 4) && (yr % 100 | !(yr % 400)));
  2690. }
  2691. }
  2692. }
  2693. ///////////////////////////////////////////////////////////////////////////////////////
  2694. // REFERENCES
  2695. //
  2696. // LPJF refers to the original FORTRAN implementation of LPJ as described by Sitch
  2697. // et al 2000
  2698. // Delmas, R., Lacaux, J.P., Menaut, J.C., Abbadie, L., Le Roux, X., Helaa, G., Lobert, J., 1995.
  2699. // Nitrogen compound emission from biomass burning in tropical African Savanna FOS/DECAFE 1991
  2700. // experiment. Journal of Atmospheric Chemistry 22, 175-193.