guess.cpp 85 KB

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