framework.cpp 94 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099
  1. ///////////////////////////////////////////////////////////////////////////////////////
  2. /// \file framework.cpp
  3. /// \brief Implementation of the framework() function
  4. ///
  5. /// \author Ben Smith
  6. /// $Date: 2014-05-14 12:43:55 +0200 (Wed, 14 May 2014) $
  7. ///
  8. ///////////////////////////////////////////////////////////////////////////////////////
  9. #include "config.h"
  10. #include "framework.h"
  11. #include "commandlinearguments.h"
  12. #include "guessserializer.h"
  13. #include "parallel.h"
  14. #include "inputmodule.h"
  15. #include "driver.h"
  16. #include "canexch.h"
  17. #include "soilwater.h"
  18. #include "somdynam.h"
  19. #include "growth.h"
  20. #include "vegdynam.h"
  21. #include "landcover.h"
  22. #include "bvoc.h"
  23. #include "commonoutput.h"
  24. // ecev3 - not in trunk. Savestate functions copied from RCA branch
  25. #include "savestate.h"
  26. #include "eceframework.h"
  27. #include <string.h>
  28. #include <sstream>
  29. #include <netcdf.h>
  30. using namespace std;
  31. using namespace GuessParallel;
  32. #include <memory>
  33. // Declaration only. Definition below.
  34. //void updatehighcoverage(Stand& stand);
  35. //CLNvoid computeLAIforIFS(Gridcell& gridcell);
  36. void computeIFSVegetationCover(Gridcell& gridcell);
  37. void computeDailyLAIandFPCforIFS(Gridcell& gridcell);
  38. /// Prints the date and time together with the name of this simulation
  39. void print_logfile_heading() {
  40. xtring datetime;
  41. unixtime(datetime);
  42. xtring header = xtring("[LPJ-GUESS ") + datetime + "]\n\n";
  43. dprintf((char*)header);
  44. // Print the title of this run
  45. std::string dashed_line(50, '-');
  46. dprintf("\n\n%s\n%s\n%s\n",
  47. dashed_line.c_str(), (char*)title, dashed_line.c_str());
  48. }
  49. // ecev3
  50. void compute_gridcell_previous_cflux(Gridcell& gridcell) {
  51. // Compute previous years yearly C fluxes for gridcell
  52. // before stand fractions change due to landuse change
  53. if (date.day > 0)
  54. return;
  55. gridcell.previousyearsCfluxNat = 0.0;
  56. gridcell.previousyearsCfluxAnt = 0.0;
  57. Gridcell::iterator gc_itr = gridcell.begin();
  58. while (gc_itr != gridcell.end()) {
  59. // START OF LOOP THROUGH STANDS
  60. Stand& stand = *gc_itr;
  61. gridcell.previousyearsCfluxNat += stand.previousyearsCfluxNat * stand.get_gridcell_fraction();
  62. gridcell.previousyearsCfluxAnt += stand.previousyearsCfluxAnt * stand.get_gridcell_fraction();
  63. ++gc_itr;
  64. } // End of loop through stands
  65. gridcell.cLand = gridcell.ccont() + gridcell.previousyearsCfluxNat + gridcell.previousyearsCfluxAnt;
  66. gridcell.cFlux = 0.0;
  67. }
  68. // ecev3
  69. void compute_gridcell_cflux(Gridcell& gridcell) {
  70. // Compute daily fluxes released to the atmosphere where previous years
  71. // yearly fluxes (Dec 31 fluxes) and annual fluxes created on Jan 1
  72. // have been spread out over this year
  73. // Gridcell-level C flux from harvest and harvest decomposition associated with landcover change. Updated only on Jan 1
  74. if (date.day == 0) {
  75. gridcell.previousyearsCfluxAnt += gridcell.landcover.dcflux_landuse_change + gridcell.landcover.dcflux_harvest_slow;
  76. }
  77. Gridcell::iterator gc_itr = gridcell.begin();
  78. while (gc_itr != gridcell.end()) {
  79. // START OF LOOP THROUGH STANDS
  80. Stand& stand = *gc_itr;
  81. double npp = 0.0;
  82. double rh = 0.0;
  83. for (unsigned int p = 0; p < stand.npatch(); p++) {
  84. Patch& patch = stand[p];
  85. // Individual C fluxes. All kg C/m2
  86. npp += patch.fluxes.get_daily_flux(Fluxes::NPP, date.day);
  87. rh += patch.fluxes.get_daily_flux(Fluxes::SOILC, date.day);
  88. patch.fluxes.report_flux(Fluxes::CO2NAT, patch.fluxes.get_daily_flux(Fluxes::SOILC, date.day) -
  89. patch.fluxes.get_daily_flux(Fluxes::NPP, date.day) +
  90. gridcell.previousyearsCfluxNat / (double)date.year_length());
  91. patch.fluxes.report_flux(Fluxes::CO2ANTT, gridcell.previousyearsCfluxAnt / (double)date.year_length());
  92. }
  93. stand.dcfluxnat_today = (rh / (float)stand.npatch() + gridcell.previousyearsCfluxNat / (double)date.year_length());
  94. stand.dcfluxant_today = gridcell.previousyearsCfluxAnt / (double)date.year_length();
  95. stand.dnpp_today = -npp / (float)stand.npatch();
  96. gridcell.cFlux += ((rh - npp) / (float)stand.npatch() + (gridcell.previousyearsCfluxNat + gridcell.previousyearsCfluxAnt) / (double)date.year_length()) * stand.get_gridcell_fraction();
  97. // On Dec 31 we must update this stand's previousyearsCflux{Nat,Ant} values to be spread over next year
  98. if (date.islastday && date.islastmonth) {
  99. // Reset yearly fluxes
  100. stand.previousyearsCfluxNat = 0.0;
  101. stand.previousyearsCfluxAnt = 0.0;
  102. double estc, firec, reprc, seedc, harvestc, debexcc, orgcleach;
  103. for (unsigned int p = 0; p < stand.npatch(); p++) {
  104. Patch& patch = stand[p];
  105. // Individual C fluxes. All kg C m-2 and all updated on Dec 31
  106. reprc = patch.fluxes.get_annual_flux(Fluxes::REPRC);
  107. firec = patch.fluxes.get_annual_flux(Fluxes::FIREC);
  108. estc = patch.fluxes.get_annual_flux(Fluxes::ESTC);
  109. seedc = patch.fluxes.get_annual_flux(Fluxes::SEEDC);
  110. harvestc = patch.fluxes.get_annual_flux(Fluxes::HARVESTC);
  111. debexcc = patch.fluxes.get_annual_flux(Fluxes::DEBEXCC);
  112. orgcleach = patch.fluxes.get_annual_flux(Fluxes::LEACHC);
  113. stand.previousyearsCfluxNat += (estc + firec + reprc + orgcleach - debexcc) / (double)stand.npatch();
  114. stand.previousyearsCfluxAnt += (seedc + harvestc) / (double)stand.npatch();
  115. //gridcell.cFlux += patch.soil.aorgCleach / (double)stand.npatch() * stand.get_gridcell_fraction();
  116. //patch.fluxes.report_flux(Fluxes::CO2NAT, patch.soil.aorgCleach); // Add to get the same result as cFlux_yearly (gridcell.cFlux)
  117. }
  118. }
  119. ++gc_itr;
  120. } // End of loop through stands
  121. }
  122. // ecev3 NOTE:
  123. // We keep the trunk versions of simulate_day and framework. This makes it easier to svn MERGE.
  124. /// Simulate one day for a given Gridcell
  125. /**
  126. * The climate object in the gridcell needs to be set up with
  127. * the day's forcing data before calling this function.
  128. *
  129. * \param gridcell The gridcell to simulate
  130. * \param input_module Used to get land cover fractions
  131. */
  132. void simulate_day(Gridcell& gridcell, InputModule* input_module) { // ecev3 - TRUNK VERSION
  133. // Update daily climate drivers etc
  134. dailyaccounting_gridcell(gridcell, false); // ecev3 - added "false" to compile
  135. // Calculate daylength, insolation and potential evapotranspiration
  136. daylengthinsoleet(gridcell.climate);
  137. if (run_landcover) {
  138. if (run[CROPLAND]) {
  139. // Update crop sowing date calculation framework
  140. crop_sowing_gridcell(gridcell, false); // ecev3 - added false as firstsimulationday
  141. }
  142. if (date.day == 0) {
  143. // Update dynamic management options
  144. input_module->getmanagement(gridcell);
  145. // Dynamic landcover and crop fraction data during historical
  146. // period and create/kill stands.
  147. landcover_dynamics(gridcell, input_module);
  148. // Set forest management intensity for all stands this year
  149. cut_fractions(gridcell);
  150. }
  151. }
  152. Gridcell::iterator gc_itr = gridcell.begin();
  153. while (gc_itr != gridcell.end()) {
  154. // START OF LOOP THROUGH STANDS
  155. Stand& stand = *gc_itr;
  156. dailyaccounting_stand(stand);
  157. stand.firstobj();
  158. while (stand.isobj) {
  159. // START OF LOOP THROUGH PATCHES
  160. // Get reference to this patch
  161. Patch& patch = stand.getobj();
  162. // Update daily soil drivers including soil temperature
  163. dailyaccounting_patch(patch,false); // ecev3 - to get this to compile
  164. // Determine nitrogen fertilisation amount
  165. if(run_landcover)
  166. nfert(patch);
  167. if (stand.landcover == CROPLAND) {
  168. // Calculate crop sowing dates
  169. crop_sowing_patch(patch);
  170. // Crop phenology
  171. crop_phenology(patch);
  172. // necessary updates after changing growingperiod status
  173. update_patch_fpc(patch);
  174. }
  175. // Leaf phenology for PFTs and individuals
  176. leaf_phenology(patch, gridcell.climate);
  177. // Interception
  178. interception(patch, gridcell.climate);
  179. initial_infiltration(patch, gridcell.climate);
  180. // Photosynthesis, respiration, evapotranspiration
  181. canopy_exchange(patch, gridcell.climate);
  182. // Sum total required irrigation
  183. irrigation(patch);
  184. // Soil water accounting, snow pack accounting
  185. soilwater(patch, gridcell.climate);
  186. // Daily C allocation (cropland)
  187. growth_daily(patch);
  188. // Soil organic matter and litter dynamics
  189. som_dynamics(patch);
  190. if (date.islastday && date.islastmonth) {
  191. // LAST DAY OF YEAR
  192. // Tissue turnover, allocation to new biomass and reproduction,
  193. // updated allometry
  194. growth(stand, patch);
  195. }
  196. stand.nextobj();
  197. }// End of loop through patches
  198. // Update crop rotation status
  199. crop_rotation(stand);
  200. if (date.islastday && date.islastmonth) {
  201. // LAST DAY OF YEAR
  202. stand.firstobj();
  203. while (stand.isobj) {
  204. // For each patch ...
  205. Patch& patch = stand.getobj();
  206. // Establishment, mortality and disturbance by fire
  207. vegetation_dynamics(stand, patch);
  208. stand.nextobj();
  209. }
  210. }
  211. ++gc_itr;
  212. } // End of loop through stands
  213. }
  214. int framework(const CommandLineArguments& args) {
  215. // The 'mission control' of the model, responsible for maintaining the
  216. // primary model data structures and containing all explicit loops through
  217. // space (grid cells/stands) and time (days and years).
  218. using std::auto_ptr;
  219. const char* input_module_name = args.get_input_module();
  220. auto_ptr<InputModule> input_module(InputModuleRegistry::get_instance().create_input_module(input_module_name));
  221. GuessOutput::OutputModuleContainer output_modules;
  222. GuessOutput::OutputModuleRegistry::get_instance().create_all_modules(output_modules);
  223. // Read the instruction file to obtain PFT static parameters and
  224. // simulation settings
  225. read_instruction_file(args.get_instruction_file());
  226. print_logfile_heading();
  227. // Initialise input/output
  228. input_module->init();
  229. output_modules.init();
  230. // Nitrogen limitation
  231. if (ifnlim && !ifcentury) {
  232. fail("\n\nIf nitrogen limitation is switched on then century soil module also needs to be switched on!");
  233. }
  234. // bvoc
  235. if (ifbvoc) {
  236. initbvoc();
  237. }
  238. // Create objects for (de)serializing grid cells
  239. auto_ptr<GuessSerializer> serializer;
  240. auto_ptr<GuessDeserializer> deserializer;
  241. if (save_state) {
  242. serializer = auto_ptr<GuessSerializer>(new GuessSerializer(state_path, GuessParallel::get_rank_specific(localcomm), GuessParallel::get_num_processes()));
  243. }
  244. if (restart) {
  245. deserializer = auto_ptr<GuessDeserializer>(new GuessDeserializer(state_path));
  246. }
  247. while (true) {
  248. // START OF LOOP THROUGH GRID CELLS
  249. // Initialise global variable date
  250. // (argument nyear not used in this implementation)
  251. date.init(1);
  252. // Create and initialise a new Gridcell object for each locality
  253. Gridcell gridcell;
  254. // Call input module to obtain latitude and driver data for this grid cell.
  255. if (!input_module->getgridcell(gridcell)) {
  256. break;
  257. }
  258. // Initialise certain climate and soil drivers
  259. gridcell.climate.initdrivers(gridcell.get_lat());
  260. if (run_landcover && !restart) {
  261. // Read landcover and cft fraction data from
  262. // data files for the spinup period and create stands
  263. landcover_init(gridcell, input_module.get());
  264. }
  265. if (restart) {
  266. // Get the whole grid cell from file...
  267. deserializer->deserialize_gridcell(gridcell);
  268. // ...and jump to the restart year
  269. date.year = state_year;
  270. }
  271. // Call input/output to obtain climate, insolation and CO2 for this
  272. // day of the simulation. Function getclimate returns false if last year
  273. // has already been simulated for this grid cell
  274. while (input_module->getclimate(gridcell)) {
  275. // START OF LOOP THROUGH SIMULATION DAYS
  276. compute_gridcell_previous_cflux(gridcell);
  277. simulate_day(gridcell, input_module.get());
  278. // Compute daily fluxes released to the atmosphere where previous years
  279. // yearly fluxes (Dec 31 fluxes) and annual fluxes created on Jan 1
  280. // have been spread out over this year
  281. compute_gridcell_cflux(gridcell);
  282. output_modules.outdaily(gridcell);
  283. if (date.islastday && date.islastmonth) {
  284. // LAST DAY OF YEAR
  285. // Call output module to output results for end of year
  286. // or end of simulation for this grid cell
  287. output_modules.outannual(gridcell);
  288. gridcell.balance.check_year(gridcell);
  289. // Time to save state?
  290. if (date.year == state_year-1 && save_state) {
  291. serializer->serialize_gridcell(gridcell);
  292. }
  293. // Check whether to abort
  294. if (abort_request_received()) {
  295. return 99;
  296. }
  297. }
  298. // Advance timer to next simulation day
  299. date.next();
  300. // End of loop through simulation days
  301. } //while (getclimate())
  302. gridcell.balance.check_period(gridcell);
  303. } // End of loop through grid cells
  304. // END OF SIMULATION
  305. return 0;
  306. }
  307. ///////////////////////////////////////////////////////////////////////////////////////
  308. ///////////////////////////////////////////////////////////////////////////////////////
  309. // EC-Earth Coupling Code - THE GUESS WORLD
  310. ///////////////////////////////////////////////////////////////////////////////////////
  311. ///////////////////////////////////////////////////////////////////////////////////////
  312. // The one and only world (vector of gridcells, one forest and one vegetated open land stand
  313. // for each grid cell)
  314. typedef std::vector<Gridcell*> World;
  315. World world;
  316. // Initialisation flag (whether GUESS has been initialised yet true/false)
  317. bool ifinit=false;
  318. int inst=0;
  319. /// Number of years in the IFS output, spinup dataset
  320. const int NYEARIFS = 10;
  321. /// Number of years in the N deposition output, historical dataset (1850-01 - 2014-12)
  322. const int NYEARNDEP = 165;
  323. // ECE Parameters to be read from .ins file:
  324. /// atmospheric nitrogen deposition (kgN/yr/ha)
  325. double ndep;
  326. // Determine RCP from guess.ins
  327. double rcpforcing;
  328. // Use IFS/H-TESSEl soil temp & moisture (true) or not (false)
  329. //CLNbool ifssoilproperties;
  330. bool useifssoilmoist;
  331. bool useifssoiltemp;
  332. xtring statefile;
  333. // ecev3 - pointers
  334. using std::auto_ptr;
  335. // Objects for serializing and deserializing Gridcells
  336. static std::auto_ptr<GuessSerializer> serializer_ece;
  337. static std::auto_ptr<GuessDeserializer> deserializer_ece;
  338. // For output
  339. GuessOutput::OutputModuleContainer* output_modules_ece;
  340. // For input
  341. // Will give access to LULCC, crop types and management options for each cell.
  342. InputModule* input_module_ece;
  343. void initlog(int inst) {
  344. printf("Attempting to open log file for instance number %d\n",inst);
  345. const char* file_log_prefix = "guess";
  346. xtring filename;
  347. filename.printf("%s%d.log", file_log_prefix, inst);
  348. set_shell(new CommandLineShell((char*)filename));
  349. }
  350. // EC-Earth VERSION of simulate_day.
  351. /// Simulate one day for a given Gridcell
  352. /**
  353. * The climate object in the gridcell needs to be set up with
  354. * the day's forcing data before calling this function.
  355. *
  356. * \param gridcell The gridcell to simulate
  357. * \param prescribe_ifs_soilmoist New ecev3 option. Use IFS soil moisture if true,
  358. * but standard LPJ-GUESS parameterisations if false
  359. * \param prescribe_ifs_soiltemp New ecev3 option. Use IFS soil temperature if true,
  360. * but standard LPJ-GUESS parameterisations if false
  361. * \param firstsimulationday New ecev3 option sent to dailyaccounting_gridcell
  362. *
  363. * \param printoutput New ecev3 option. Update outputfiles if true. Set false at start of spinup
  364. *
  365. */
  366. void simulate_day_ece(Gridcell& gridcell, bool prescribe_ifs_soilmoist, bool prescribe_ifs_soiltemp,
  367. bool firstsimulationday, bool printoutput) {
  368. // Compute previous years yearly C fluxes for gridcell
  369. // before stand fractions change due to landuse change
  370. compute_gridcell_previous_cflux(gridcell);
  371. // Update daily climate drivers etc
  372. dailyaccounting_gridcell(gridcell, firstsimulationday);
  373. // Calculate daylength, insolation and potential evapotranspiration
  374. daylengthinsoleet(gridcell.climate);
  375. if (run_landcover) {
  376. if (run[CROPLAND]) {
  377. // Update crop sowing date calculation framework
  378. crop_sowing_gridcell(gridcell, firstsimulationday);
  379. }
  380. if (date.day == 0) {
  381. // Dynamic landcover and crop fraction data during historical
  382. // period and create/kill stands.
  383. landcover_dynamics(gridcell, input_module_ece);
  384. // Update dynamic management options
  385. input_module_ece->getmanagement(gridcell);
  386. }
  387. }
  388. Gridcell::iterator gc_itr = gridcell.begin();
  389. while (gc_itr != gridcell.end()) {
  390. // START OF LOOP THROUGH STANDS
  391. Stand& stand = *gc_itr;
  392. dailyaccounting_stand(stand);
  393. stand.firstobj();
  394. while (stand.isobj) {
  395. // START OF LOOP THROUGH PATCHES
  396. // Get reference to this patch
  397. Patch& patch = stand.getobj();
  398. // Update daily soil drivers including soil temperature
  399. dailyaccounting_patch(patch,prescribe_ifs_soiltemp); // ecev3 - override soil.temp?
  400. // Determine nitrogen fertilisation amount
  401. if (run_landcover)
  402. nfert(patch);
  403. if (stand.landcover == CROPLAND) {
  404. // Calculate crop sowing dates
  405. crop_sowing_patch(patch);
  406. // Crop phenology
  407. crop_phenology(patch);
  408. // necessary updates after changing growingperiod status
  409. update_patch_fpc(patch);
  410. }
  411. // Leaf phenology for PFTs and individuals
  412. leaf_phenology(patch, gridcell.climate);
  413. // Interception
  414. interception(patch, gridcell.climate);
  415. initial_infiltration(patch, gridcell.climate);
  416. // Photosynthesis, respiration, evapotranspiration
  417. canopy_exchange(patch, gridcell.climate);
  418. // Sum total required irrigation
  419. irrigation(patch);
  420. // Soil water accounting, snow pack accounting
  421. if (prescribe_ifs_soilmoist) {
  422. // Update wcont[0], wcont[0] and wcont_evap with IFS values
  423. patch.soil.wcont[0] = gridcell.climate.ifsw_surf;
  424. patch.soil.wcont[1] = gridcell.climate.ifsw_deep;
  425. patch.soil.wcont_evap = gridcell.climate.ifsw_surf;
  426. // MUST call soil water, otherwise aaet and dperc are not updated.
  427. // These are needed for N limitation etc.
  428. soilwater(patch, gridcell.climate);
  429. // Update daily soil water in both layers
  430. // Done in dailyaccounting_patch, but here we override with IFS values before
  431. // these values are used in the fire module.
  432. patch.soil.wcont[0] = gridcell.climate.ifsw_surf;
  433. patch.soil.wcont[1] = gridcell.climate.ifsw_deep;
  434. patch.soil.dwcontupper[date.day] = patch.soil.wcont[0];
  435. patch.soil.dwcontlower[date.day] = patch.soil.wcont[1];
  436. patch.soil.dwcontlower_today = patch.soil.wcont[1];
  437. }
  438. else {
  439. soilwater(patch, gridcell.climate);
  440. }
  441. // Daily C allocation (cropland)
  442. growth_daily(patch);
  443. // Soil organic matter and litter dynamics
  444. som_dynamics(patch);
  445. if (date.islastday && date.islastmonth) {
  446. // LAST DAY OF YEAR
  447. // Tissue turnover, allocation to new biomass and reproduction,
  448. // updated allometry
  449. growth(stand, patch);
  450. }
  451. stand.nextobj();
  452. } // End of loop through patches
  453. // Update crop rotation status
  454. crop_rotation(stand);
  455. if (date.islastday && date.islastmonth) {
  456. // LAST DAY OF YEAR
  457. stand.firstobj();
  458. while (stand.isobj) {
  459. // For each patch ...
  460. Patch& patch = stand.getobj();
  461. // Establishment, mortality and disturbance by fire
  462. vegetation_dynamics(stand, patch);
  463. stand.nextobj();
  464. }
  465. }
  466. // gridcell.nextobj();
  467. ++gc_itr;
  468. } // End of loop through stands
  469. // TODO check if outdaily should be after compute_gridcell_cflux() as in the standalone framework
  470. // Compute daily fluxes released to the atmosphere where previous years
  471. // yearly fluxes (Dec 31 fluxes) and annual fluxes created on Jan 1
  472. // have been spread out over this year
  473. compute_gridcell_cflux(gridcell);
  474. // ecev3 - not needed yet
  475. if (printoutput)
  476. (*output_modules_ece).outdaily(gridcell);
  477. if (date.islastday && date.islastmonth) {
  478. // LAST DAY OF YEAR
  479. // ecev3 - update the simulation year for this gridcell
  480. gridcell.simulationyear++;
  481. // Call output module to output results for end of year
  482. // or end of simulation for this grid cell
  483. if (printoutput) {
  484. (*output_modules_ece).outannual(gridcell);
  485. // ecev3 - compute vegetation type and cover fractions for this grid cell
  486. // outannual must be called first!
  487. computeIFSVegetationCover(gridcell);
  488. }
  489. // for debugging:
  490. // dprintf("Stands: %4d... \n", gridcell.nbr_stands());
  491. } // last day?
  492. }
  493. ///////////////////////////////////////////////////////////////////////////////////////
  494. // INITGUESS
  495. // Called at start of run to read settings from ins file
  496. // For now ins file name is prescribed in the function body
  497. void initguess(int myrank) {
  498. // Hard-wired ins file name
  499. xtring insfilename="guess.ins";
  500. // Get instance id
  501. inst = myrank;
  502. // Open log file
  503. initlog(inst);
  504. // Retrieve specified N value as read from ins file
  505. ndep=param["ndep"].num;
  506. // Determine RCP to follow
  507. rcpforcing=param["nrcp"].num;
  508. // Use IFS soil moisture and temp (1), or not (0)
  509. useifssoilmoist=true;
  510. if (param["useifssoilmoist"].num == 0.0)
  511. useifssoilmoist=false;
  512. useifssoiltemp=true;
  513. if (param["useifssoiltemp"].num == 0.0)
  514. useifssoiltemp=false;
  515. // State file params
  516. restart=true;
  517. if (param["restart"].num == 0.0)
  518. restart=false;
  519. state_path=param["state_path"].str;
  520. state_name=param["state_name"].str;
  521. // Nitrogen limitation
  522. if (ifnlim && !ifcentury) {
  523. fail("\n\nIf nitrogen limitation is switched on then century soil module also needs to be switched on!");
  524. }
  525. // ecev3 - CMIP6
  526. if (!printcmip6 && printcmip6daily) {
  527. fail("\n\nOnly print daily CMIP6 output when printcmip6 is true too!");
  528. }
  529. // ecev3 - CRESCENDO
  530. if (!printcrescendo && printcrescendodaily) {
  531. fail("\n\nOnly print daily CRESCENDO output when printcrescendo is true too!");
  532. }
  533. // ecev3 - CRESCENDO FACE
  534. bool printCRESCENDO_FACE = false;
  535. #ifdef CRESCENDO_FACE
  536. printCRESCENDO_FACE = true;
  537. #endif
  538. if (printcrescendofacedaily && !printCRESCENDO_FACE) {
  539. fail("\n\nOnly print daily CRESCENDO FACE output when CRESCENDO_FACE is defined!");
  540. }
  541. if (!printcrescendofacedaily && printCRESCENDO_FACE) {
  542. fail("\n\nOnly define CRESCENDO_FACE if daily CRESCENDO FACE outputs are to be printed!");
  543. }
  544. // bvoc
  545. if (ifbvoc) {
  546. initbvoc();
  547. }
  548. // Done it!
  549. ifinit=true;
  550. }
  551. // ecev3
  552. void swConvert(Soiltype& stype,double &sw_surf,double &sw_deep) {
  553. if (sw_surf < stype.wilt_point)
  554. sw_surf = 0.0;
  555. else if (sw_surf > stype.field_cap)
  556. sw_surf = 1.0;
  557. else
  558. sw_surf = (sw_surf - stype.wilt_point) / stype.whcap;
  559. if (sw_deep < stype.wilt_point)
  560. sw_deep = 0.0;
  561. else if (sw_deep > stype.field_cap)
  562. sw_deep = 1.0;
  563. else
  564. sw_deep = (sw_deep - stype.wilt_point) / stype.whcap;
  565. }
  566. // ecev3
  567. /*
  568. Called daily to update gridcell.laiphen_high_today and gridcell.laiphen_high_today
  569. computeIFSVegetationCover below updates these Gridcell values on Dec 31:
  570. gridcell.IFStypehigh
  571. gridcell.IFSfrachigh
  572. gridcell.IFStypelow
  573. gridcell.IFSfraclow
  574. gridcell.transferhightolow - use total LAI today if this is true
  575. These values are serialized, so they are available after a restart
  576. */
  577. void computeDailyLAIandFPCforIFS(Gridcell& gridcell) {
  578. const double MAX_DAILY_LAI = 10; // Max daily LAI - enforced at the end of this routine. Was 15.
  579. double ABSCUTOFF_FPC = 0.000; // Set to 0 to ensure we send nonzero values no matter how small. Was 0.005.
  580. double lai_tree_daily = 0.0;
  581. double lai_grass_daily = 0.0;
  582. double lai_crop_daily = 0.0;
  583. double lai_pasture_daily = 0.0;
  584. double lai_urban_daily = 0.0;
  585. double lai_peat_daily = 0.0;
  586. double fpc_tree_daily = 0.0;
  587. double fpc_grass_daily = 0.0;
  588. double fpc_crop_daily = 0.0;
  589. double fpc_pasture_daily = 0.0;
  590. double fpc_urban_daily = 0.0;
  591. double fpc_peat_daily = 0.0;
  592. // As updated in outannual
  593. double natural_frac = gridcell.landcover.frac[NATURAL];
  594. double cropland_frac = gridcell.landcover.frac[CROPLAND];
  595. double pasture_frac = gridcell.landcover.frac[PASTURE];
  596. double urban_frac = gridcell.landcover.frac[URBAN];
  597. double peatland_frac = gridcell.landcover.frac[PEATLAND];
  598. // Sum LAI and FPC across patches and PFTs
  599. Gridcell::iterator gc_itr = gridcell.begin();
  600. // Loop through Stands
  601. gc_itr = gridcell.begin();
  602. while (gc_itr != gridcell.end()) {
  603. Stand& stand = *gc_itr;
  604. stand.firstobj();
  605. double to_gridcell_average = stand.get_gridcell_fraction() / (double)stand.npatch();
  606. if (stand.landcover == NATURAL) { // Only look in NATURAL stands!
  607. // Loop through Patches for trees first
  608. while (stand.isobj) {
  609. Patch& patch = stand.getobj();
  610. // Loop through Individuals
  611. Vegetation& vegetation = patch.vegetation;
  612. // Tree and grass fpc for this patch
  613. double fpc_tree_patch = 0.0;
  614. double fpc_grass_patch = 0.0;
  615. vegetation.firstobj();
  616. while (vegetation.isobj) {
  617. Individual& indiv = vegetation.getobj();
  618. if (indiv.id != -1 && indiv.alive) {
  619. double current_fpc = indiv.crownarea * indiv.densindiv * (1.0 - lambertbeer(indiv.lai_indiv_today()));
  620. if (indiv.pft.lifeform == TREE) {
  621. lai_tree_daily += indiv.lai_today() * to_gridcell_average;
  622. fpc_tree_patch += current_fpc * to_gridcell_average;
  623. }
  624. else {
  625. lai_grass_daily += indiv.lai_today() * to_gridcell_average;
  626. fpc_grass_patch += current_fpc * to_gridcell_average;
  627. }
  628. } // alive && id != -1?
  629. vegetation.nextobj();
  630. } // while/vegetation loop for trees
  631. // Tree FPC shouldn't be larger than total patch area
  632. if (fpc_tree_patch > to_gridcell_average)
  633. fpc_tree_patch = to_gridcell_average;
  634. // Tree and grass FPC shouldn't be larger than total patch area (trees shade grass)
  635. if (fpc_tree_patch + fpc_grass_patch > to_gridcell_average)
  636. fpc_grass_patch = to_gridcell_average - fpc_tree_patch;
  637. fpc_tree_daily += fpc_tree_patch;
  638. fpc_grass_daily += fpc_grass_patch;
  639. stand.nextobj();
  640. } // patch loop
  641. }
  642. else if (stand.landcover == PASTURE || stand.landcover == URBAN || stand.landcover == PEATLAND) {
  643. // Look in pasture, peatland and urban stands for C3/C4
  644. // Loop through Patches
  645. while (stand.isobj) {
  646. Patch& patch = stand.getobj();
  647. // Loop through Individuals
  648. Vegetation& vegetation = patch.vegetation;
  649. vegetation.firstobj();
  650. while (vegetation.isobj) {
  651. Individual& indiv = vegetation.getobj();
  652. if (indiv.id != -1 && indiv.alive) {
  653. if (indiv.pft.lifeform == GRASS) {
  654. double current_fpc_daily = 1.0 - lambertbeer(indiv.lai_indiv_today());
  655. if (stand.landcover == PASTURE) {
  656. lai_pasture_daily += indiv.lai_today() * to_gridcell_average;
  657. fpc_pasture_daily += current_fpc_daily * to_gridcell_average;
  658. }
  659. else if (stand.landcover == URBAN) {
  660. lai_urban_daily += indiv.lai_today() * to_gridcell_average;
  661. fpc_urban_daily += current_fpc_daily * to_gridcell_average;
  662. }
  663. else {
  664. lai_peat_daily += indiv.lai_today() * to_gridcell_average;
  665. fpc_peat_daily += current_fpc_daily * to_gridcell_average;
  666. }
  667. } // GRASS?
  668. else {
  669. // Error!
  670. bool err = true;
  671. }
  672. } // alive && id != -1?
  673. vegetation.nextobj();
  674. } // while/vegetation loop
  675. stand.nextobj();
  676. } // patch loop
  677. }
  678. else if (stand.landcover == CROPLAND) {
  679. // Look in cropland to find irrigated and none irrigated / C3 or C4 crops
  680. // Loop through Patches
  681. while (stand.isobj) {
  682. Patch& patch = stand.getobj();
  683. // Loop through Individuals
  684. Vegetation& vegetation = patch.vegetation;
  685. vegetation.firstobj();
  686. while (vegetation.isobj) {
  687. Individual& indiv = vegetation.getobj();
  688. // Calculating real FCP as indiv.fpc for crops are always 1.0!
  689. double current_fpc_daily = 1.0 - lambertbeer(indiv.lai_indiv_today());
  690. lai_crop_daily += indiv.lai_today() * to_gridcell_average;
  691. fpc_crop_daily += current_fpc_daily * to_gridcell_average;
  692. vegetation.nextobj();
  693. } // while/vegetation loop
  694. stand.nextobj();
  695. } // patch loop
  696. }
  697. ++gc_itr;
  698. } // stand loop
  699. // Rescale if FPC > Land cover fraction
  700. // If Natural tree bigger than cover fracton -> tree cover all fraction, grass zero
  701. if (fpc_tree_daily > natural_frac) {
  702. fpc_tree_daily = natural_frac;
  703. fpc_grass_daily = 0.0;
  704. }
  705. double fpc_natural_daily = fpc_grass_daily + fpc_tree_daily;
  706. if (fpc_natural_daily > natural_frac) {
  707. fpc_grass_daily = natural_frac - fpc_tree_daily; // Trees covers low vegetation
  708. }
  709. // Pasture
  710. if (fpc_pasture_daily > pasture_frac) {
  711. fpc_pasture_daily = pasture_frac;
  712. }
  713. // Urban
  714. if (fpc_urban_daily > urban_frac) {
  715. fpc_urban_daily = urban_frac;
  716. }
  717. // Peatland
  718. if (fpc_peat_daily > peatland_frac) {
  719. fpc_peat_daily = peatland_frac;
  720. }
  721. // Cropland
  722. if (fpc_crop_daily > cropland_frac) {
  723. fpc_crop_daily = cropland_frac;
  724. }
  725. double fpc_grass_total_daily = fpc_grass_daily + fpc_crop_daily + fpc_pasture_daily + fpc_urban_daily + fpc_peat_daily;
  726. // Lower limit - Low
  727. if (fpc_grass_total_daily < ABSCUTOFF_FPC) {
  728. fpc_grass_total_daily = 0.0; // Impose lower limit of 0.5%, 0 otherwise
  729. }
  730. // Lower limit - High
  731. if (fpc_tree_daily < ABSCUTOFF_FPC) {
  732. fpc_tree_daily = 0.0; // Impose lower limit of 0.5%, 0 otherwise
  733. }
  734. // Catch small rounding errors
  735. double coversum = fpc_tree_daily + fpc_grass_total_daily;
  736. if (coversum > 1.0 && coversum <= 1.001) {
  737. fpc_tree_daily /= coversum;
  738. fpc_grass_total_daily /= coversum;
  739. coversum = 1.0;
  740. }
  741. // Sanity check!!!
  742. if (coversum > 1.001)
  743. fail("\nInvalid gridcell.IFSfrachigh (%f) and/or gridcell.IFSfraclow (%f) value (sum = %f) in computeDailyLAIandFPCforIFS!",
  744. fpc_tree_daily, fpc_grass_total_daily, fpc_tree_daily + fpc_grass_total_daily);
  745. // Determine FPC based LAI
  746. double lai_fpc_tree_daily = 0.0;
  747. if (fpc_tree_daily > 0.0) {
  748. lai_fpc_tree_daily = lai_tree_daily / fpc_tree_daily;
  749. }
  750. double lai_fpc_grass_daily = 0.0;
  751. if (fpc_grass_total_daily > 0.0) {
  752. lai_fpc_grass_daily = (lai_grass_daily + lai_crop_daily + lai_pasture_daily + lai_urban_daily + lai_peat_daily) / fpc_grass_total_daily;
  753. }
  754. // Sanity checks - limit LAI to sensible values
  755. if (lai_fpc_tree_daily >= MAX_DAILY_LAI)
  756. lai_fpc_tree_daily = MAX_DAILY_LAI;
  757. if (lai_fpc_grass_daily >= MAX_DAILY_LAI)
  758. lai_fpc_grass_daily = MAX_DAILY_LAI;
  759. gridcell.laiphen_high_today = lai_fpc_tree_daily;
  760. gridcell.laiphen_low_today = lai_fpc_grass_daily;
  761. gridcell.IFSfrachigh = fpc_tree_daily;
  762. gridcell.IFSfraclow = fpc_grass_total_daily;
  763. }
  764. // ecev3 - called on Dec 31
  765. void computeIFSVegetationCover(Gridcell& gridcell) {
  766. /*
  767. // LPJG vegetation mapped onto H-TESSEL vegetation types and fractions.
  768. // Types are one of (See IFS documentation, 36r1, Table 8.1):
  769. 0 No high vegetation
  770. 1 Crops, mixd farming
  771. 2 Short grass
  772. 3 Evergreen needleleaf trees
  773. 4 Deciduous needleleaf trees
  774. 5 Deciduous broadleaf trees
  775. 6 Evergreen broadleaf trees
  776. 7 Tall grass
  777. 8 Desert
  778. 9 Tundra
  779. 10 Irrigated crops
  780. 11 Semidesert
  781. 12 Ice caps and glaciers
  782. 13 Bogs and marshes
  783. 14 Inland water
  784. 15 Ocean
  785. 16 Evergreen shrubs
  786. 17 Deciduous shrubs
  787. 18 Mixed forest/woodland
  788. 19 Interrupted forest
  789. 20 Water and land mixtures
  790. */
  791. // -------------------------------------------------------------------------
  792. // 0. Initial constants and checks
  793. // -------------------------------------------------------------------------
  794. const double FORESTCUTOFF_FPC = 0.6; // FPC of 60%
  795. const double DNFORESTCUTOFF_FPC = 0.4; // FPC of 40%
  796. const double LOWTOHIGHCUTOFF_FPC = 0.05; // FPC of 5%
  797. const double DOMINANCE_FRACTION = 0.6; // 60% (IGBP)
  798. const double DOMINANCE_FRACTION_RAINGREEN = 0.3;// 30% (Otherwise raingreen dominance is not captured)
  799. const double TUNDRAGDD5LIMIT = 350.0; // degree day
  800. const double DESERTGDD5LIMIT = 1500.0; // degree day
  801. const double ABSCUTOFF_FPC = 0.000; // MIN FPC (as in IFS files now)
  802. // const double DESERTCUTOFF_FPC = 0.05; // FPC of 5%
  803. // const double SEMIDESERTCUTOFF_FPC = 0.4; // FPC of 40%
  804. const double DESERTCUTOFF_FPC_WCONT = 0.01; // FPC * AWCONT of 0.01
  805. const double SEMIDESERTCUTOFF_FPC_WCONT = 0.15; // FPC * AWCONT of 0.15
  806. const double MAX_DAILY_LAI = 10; // Max daily LAI - enforced at the end of this routine. Was 15.
  807. // Initialise these Gridcell values before updating them below
  808. gridcell.IFStypehigh = 0;
  809. double IFSfrachigh = 0.0;
  810. gridcell.IFStypelow = 0;
  811. double IFSfraclow = 0.0;
  812. gridcell.naturaltreeFPC = 0.0;
  813. gridcell.naturalgrassFPC = 0.0;
  814. // Whether we transfer possible tree characteristics from the NATURAL stand to the low veg information sent to IFS
  815. gridcell.transferhightolow = false;
  816. // Some quick checks
  817. if (gridcell.get_lat() < -65.0) {
  818. // Antarctica
  819. // gridcell.IFStypelow=12; // 12 Ice caps and glaciers
  820. return;
  821. }
  822. // As updated in outannual
  823. double natural_frac = gridcell.landcover.frac[NATURAL];
  824. double cropland_frac = gridcell.landcover.frac[CROPLAND];
  825. double pasture_frac = gridcell.landcover.frac[PASTURE];
  826. double urban_frac = gridcell.landcover.frac[URBAN];
  827. double peatland_frac = gridcell.landcover.frac[PEATLAND];
  828. // -------------------------------------------------------------------------
  829. // 1. Determine FPC for trees and grasses in Natural stands and real FPC for crops.
  830. // -------------------------------------------------------------------------
  831. double fpcEN = 0.0;
  832. double fpcDN = 0.0;
  833. double fpcDB = 0.0;
  834. double fpcRB = 0.0;
  835. double fpcEB = 0.0;
  836. double fpcgrass = 0.0;
  837. // To distinguish tall from short grass we need C3/C4 distinctions
  838. double fpcgrass_c3 = 0.0;
  839. double fpcgrass_c4 = 0.0;
  840. double fpcgrass_crop_c3 = 0.0;
  841. double fpcgrass_crop_c4 = 0.0;
  842. double fpcgrass_pasture_c3 = 0.0;
  843. double fpcgrass_pasture_c4 = 0.0;
  844. double fpcgrass_urban_c3 = 0.0;
  845. double fpcgrass_urban_c4 = 0.0;
  846. double fpcgrass_peatland_c3 = 0.0;
  847. double fpcgrass_peatland_c4 = 0.0;
  848. // To distinguish rainfed and irrigated crops
  849. double fpccrop_rain = 0.0;
  850. double fpccrop_irri = 0.0;
  851. double fpccrop = 0.0;
  852. Gridcell::iterator gc_itr = gridcell.begin();
  853. // Loop through Stands
  854. while (gc_itr != gridcell.end()) {
  855. Stand& stand = *gc_itr;
  856. stand.firstobj();
  857. double to_gridcell_average = stand.get_gridcell_fraction() / (double)stand.npatch();
  858. if (stand.landcover == NATURAL) { // Only look in NATURAL stands!
  859. // Loop through Patches
  860. while (stand.isobj) {
  861. Patch& patch = stand.getobj();
  862. // Loop through Individuals
  863. Vegetation& vegetation = patch.vegetation;
  864. vegetation.firstobj();
  865. while (vegetation.isobj) {
  866. Individual& indiv = vegetation.getobj();
  867. if (indiv.id != -1 && indiv.alive) {
  868. if (indiv.pft.lifeform == GRASS) {
  869. fpcgrass += indiv.fpc * to_gridcell_average;
  870. // C3 or C4?
  871. if (indiv.pft.pathway == C3) {
  872. fpcgrass_c3 += indiv.fpc * to_gridcell_average;
  873. }
  874. else {
  875. fpcgrass_c4 += indiv.fpc * to_gridcell_average;
  876. }
  877. }
  878. else if (indiv.pft.leafphysiognomy == NEEDLELEAF && indiv.pft.phenology == EVERGREEN) {
  879. fpcEN += indiv.fpc * to_gridcell_average;
  880. }
  881. else if (indiv.pft.leafphysiognomy == NEEDLELEAF && indiv.pft.phenology == SUMMERGREEN) {
  882. fpcDN += indiv.fpc * to_gridcell_average;
  883. }
  884. else if (indiv.pft.leafphysiognomy == BROADLEAF && indiv.pft.phenology == SUMMERGREEN) {
  885. fpcDB += indiv.fpc * to_gridcell_average;
  886. }
  887. else if (indiv.pft.leafphysiognomy == BROADLEAF && indiv.pft.phenology == EVERGREEN) {
  888. fpcEB += indiv.fpc * to_gridcell_average;
  889. }
  890. else if (indiv.pft.leafphysiognomy == BROADLEAF && indiv.pft.phenology == RAINGREEN) {
  891. fpcDB += indiv.fpc * to_gridcell_average;
  892. fpcRB += indiv.fpc * to_gridcell_average;
  893. }
  894. else {
  895. // Error!
  896. bool err = true;
  897. }
  898. } // alive && id != -1?
  899. vegetation.nextobj();
  900. } // while/vegetation loop
  901. stand.nextobj();
  902. } // patch loop
  903. }
  904. else if (stand.landcover == PASTURE || stand.landcover == URBAN || stand.landcover == PEATLAND) {
  905. // Look in pasture, peatland and urban stands for C3/C4
  906. // Loop through Patches
  907. while (stand.isobj) {
  908. Patch& patch = stand.getobj();
  909. // Loop through Individuals
  910. Vegetation& vegetation = patch.vegetation;
  911. vegetation.firstobj();
  912. while (vegetation.isobj) {
  913. Individual& indiv = vegetation.getobj();
  914. if (indiv.id != -1 && indiv.alive) {
  915. if (indiv.pft.lifeform == GRASS) {
  916. // C3 or C4?
  917. if (indiv.pft.pathway == C3) {
  918. // C3
  919. if (stand.landcover == PASTURE)
  920. fpcgrass_pasture_c3 += indiv.fpc * to_gridcell_average;
  921. else if (stand.landcover == URBAN)
  922. fpcgrass_urban_c3 += indiv.fpc * to_gridcell_average;
  923. else
  924. fpcgrass_peatland_c3 += indiv.fpc * to_gridcell_average;
  925. }
  926. else {
  927. // C4
  928. if (stand.landcover == PASTURE)
  929. fpcgrass_pasture_c4 += indiv.fpc * to_gridcell_average;
  930. else if (stand.landcover == URBAN)
  931. fpcgrass_urban_c4 += indiv.fpc * to_gridcell_average;
  932. else
  933. fpcgrass_peatland_c4 += indiv.fpc * to_gridcell_average;
  934. }
  935. } // GRASS?
  936. else {
  937. // Error!
  938. bool err = true;
  939. }
  940. } // alive && id != -1?
  941. vegetation.nextobj();
  942. } // while/vegetation loop
  943. stand.nextobj();
  944. } // patch loop
  945. }
  946. else if (stand.landcover == CROPLAND) {
  947. // Look in cropland to find irrigated and none irrigated / C3 or C4 crops
  948. // Loop through Patches
  949. while (stand.isobj) {
  950. Patch& patch = stand.getobj();
  951. // Loop through Individuals
  952. Vegetation& vegetation = patch.vegetation;
  953. vegetation.firstobj();
  954. while (vegetation.isobj) {
  955. Individual& indiv = vegetation.getobj();
  956. if (!indiv.pft.isintercropgrass) {
  957. // Calculating real FCP as indiv.fpc for crops are always 1.0!
  958. double indiv_fpc = 1.0 - lambertbeer(indiv.lai);
  959. if (patch.stand.isirrigated)
  960. fpccrop_irri += indiv_fpc * to_gridcell_average;
  961. else
  962. fpccrop_rain += indiv_fpc * to_gridcell_average;
  963. if (indiv.pft.pathway == C3)
  964. fpcgrass_crop_c3 += indiv_fpc * to_gridcell_average;
  965. else
  966. fpcgrass_crop_c4 += indiv_fpc * to_gridcell_average;
  967. fpccrop += indiv_fpc * to_gridcell_average;
  968. }
  969. vegetation.nextobj();
  970. } // while/vegetation loop
  971. stand.nextobj();
  972. } // patch loop
  973. }
  974. ++gc_itr;
  975. } // stand loop
  976. // Now determine the maximum type
  977. double fpcnatural = fpcEN + fpcDN + fpcDB + fpcEB + fpcgrass;
  978. double fpctree = fpcEN + fpcDN + fpcDB + fpcEB;
  979. double fpcpeatland = fpcgrass_peatland_c3 + fpcgrass_peatland_c4;
  980. double fpcpasture = fpcgrass_pasture_c3 + fpcgrass_pasture_c4;
  981. double fpcurban = fpcgrass_urban_c3 + fpcgrass_urban_c4;
  982. // Rescale if FPC > Land cover fraction
  983. // Natural
  984. if (fpcnatural > natural_frac) {
  985. fpcEN *= (natural_frac / fpcnatural);
  986. fpcDN *= (natural_frac / fpcnatural);
  987. fpcDB *= (natural_frac / fpcnatural);
  988. fpcRB *= (natural_frac / fpcnatural);
  989. fpcEB *= (natural_frac / fpcnatural);
  990. fpctree *= (natural_frac / fpcnatural);
  991. fpcgrass *= (natural_frac / fpcnatural);
  992. fpcgrass_c3 *= (natural_frac / fpcnatural);
  993. fpcgrass_c4 *= (natural_frac / fpcnatural);
  994. // Reset total to
  995. fpcnatural = natural_frac;
  996. }
  997. // Pasture
  998. if (fpcpasture > pasture_frac) {
  999. fpcgrass_pasture_c3 *= (pasture_frac / fpcpasture);
  1000. fpcgrass_pasture_c4 *= (pasture_frac / fpcpasture);
  1001. // Reset total to
  1002. fpcpasture = pasture_frac;
  1003. }
  1004. // Urban
  1005. if (fpcurban > urban_frac) {
  1006. fpcgrass_urban_c3 *= (urban_frac / fpcurban);
  1007. fpcgrass_urban_c4 *= (urban_frac / fpcurban);
  1008. // Reset total to
  1009. fpcurban = urban_frac;
  1010. }
  1011. // Peatland
  1012. if (fpcpeatland > peatland_frac) {
  1013. fpcgrass_peatland_c3 *= (peatland_frac / fpcpeatland);
  1014. fpcgrass_peatland_c4 *= (peatland_frac / fpcpeatland);
  1015. // Reset total to
  1016. fpcpeatland = peatland_frac;
  1017. }
  1018. // Cropland
  1019. if (fpccrop > cropland_frac) {
  1020. fpccrop_rain *= (cropland_frac / fpccrop);
  1021. fpccrop_irri *= (cropland_frac / fpccrop);
  1022. fpcgrass_crop_c3 *= (cropland_frac / fpccrop);
  1023. fpcgrass_crop_c4 *= (cropland_frac / fpccrop);
  1024. // Reset total to
  1025. fpccrop = cropland_frac;
  1026. }
  1027. // -------------------------------------------------------------------------
  1028. // 1. Lump together to totals
  1029. // -------------------------------------------------------------------------
  1030. // Note: we limit FPCs to be <= 1
  1031. double fpcgridcell = fpccrop + fpcpasture + fpcnatural + fpcurban + fpcpeatland;
  1032. // Gridcell C3/C4 grass distinctions - NATURAL, PASTURE, URBAN & PEATLAND - must be between 0 and 1
  1033. double fpcgrasses_c3 = fpcgrass_c3 + fpcgrass_crop_c3 + fpcgrass_pasture_c3 + fpcgrass_urban_c3 + fpcgrass_peatland_c3;
  1034. double fpcgrasses_c4 = fpcgrass_c4 + fpcgrass_crop_c4 + fpcgrass_pasture_c4 + fpcgrass_urban_c4 + fpcgrass_peatland_c4;
  1035. double fpcgrasses = fpcgrasses_c3 + fpcgrasses_c4;
  1036. // -------------------------------------------------------------------------
  1037. // 2. Forest types
  1038. // -------------------------------------------------------------------------
  1039. int typehigh;
  1040. // *** FOREST ***
  1041. // 4 Deciduous needleleaf trees
  1042. // 3 Evergreen needleleaf trees
  1043. // 5 Deciduous broadleaf trees
  1044. // 6 Evergreen broadleaf trees
  1045. // or
  1046. // 18 Mixed forest/woodland
  1047. if (fpcDN > DOMINANCE_FRACTION * fpctree)
  1048. typehigh = 4;
  1049. else if (fpcEN > DOMINANCE_FRACTION * fpctree)
  1050. typehigh = 3;
  1051. else if (fpcDB > DOMINANCE_FRACTION * fpctree || fpcRB > DOMINANCE_FRACTION_RAINGREEN * fpctree)
  1052. typehigh = 5;
  1053. else if (fpcEB > DOMINANCE_FRACTION * fpctree)
  1054. typehigh = 6;
  1055. else if (!negligible(fpctree))
  1056. typehigh = 18; // Mixed if no type exceeds 60% of the total
  1057. else
  1058. typehigh = 0;
  1059. gridcell.IFStypehigh = typehigh;
  1060. // -------------------------------------------------------------------------
  1061. // 3. Low types and fractions
  1062. // -------------------------------------------------------------------------
  1063. // Quick, initial check for desert and glacier-type conditions
  1064. if (negligible(fpcgrasses)) {
  1065. gridcell.IFStypelow = 0; // No Vegetation
  1066. }
  1067. // Peatland check - and this must depend on the hard-coded wetland fraction
  1068. else if (fpcpeatland > (fpcgrasses - fpcpeatland))
  1069. gridcell.IFStypelow = 13; // Bogs and marshes
  1070. else {
  1071. // Not Bogs and marshes ....
  1072. // Crops, mixed farming dominate
  1073. if (fpccrop > fpcgrass && fpccrop > fpcpasture) {
  1074. if (fpccrop_irri > fpccrop_rain)
  1075. gridcell.IFStypelow = 10; // Irrigated crops 10
  1076. else
  1077. gridcell.IFStypelow = 1; // Crops, mixed farming
  1078. }
  1079. else {
  1080. // Natural GRASSES (and maybe trees) dominate the low cover types
  1081. if (gridcell.climate.agdd5_5.mean() < TUNDRAGDD5LIMIT) {
  1082. gridcell.IFStypelow = 9; // Tundra (Hickler et al. 2006)
  1083. }
  1084. else {
  1085. if (fpcgrasses_c3 > fpcgrasses_c4)
  1086. gridcell.IFStypelow = 2; // Short grass 2
  1087. else
  1088. gridcell.IFStypelow = 7; // Tall grass 7
  1089. }
  1090. }
  1091. }
  1092. } // computeIFSVegetationCover
  1093. std::string lpjg_to_string(int d) {
  1094. std::ostringstream os;
  1095. os << d;
  1096. return os.str();
  1097. }
  1098. bool getdailyIFSforcing(const char* varname, const int& startyear, const int numyear, double data[NYEARIFS][366], int daysinyear, int ifsindex, bool depth) {
  1099. string filenametail = "_dayavg.nc";
  1100. // var39_1971_dayavg.nc
  1101. xtring ifs_spinup_dir=param["ifs_spinup_dir"].str;
  1102. int yrix = 0;
  1103. double yearavg = 0.0; // Test of annual averages
  1104. // New code for reading AMIP files
  1105. const char* filevar = varname;
  1106. if (startyear < 1900) {
  1107. // ECE v3.2 AMIP forcing only
  1108. if (!strcmp(varname,"var39"))
  1109. filevar = "var039";
  1110. if (!strcmp(varname, "var40"))
  1111. filevar = "var040";
  1112. if (!strcmp(varname, "var41"))
  1113. filevar = "var041";
  1114. if (!strcmp(varname, "var42"))
  1115. filevar = "var042";
  1116. }
  1117. // ecev3 - AMIP fix. No AMIP data before 1870, so use that data instead
  1118. int datastartyear = startyear;
  1119. if (startyear < 1870)
  1120. datastartyear = 1870;
  1121. for (int yr = datastartyear; yr < datastartyear+numyear; yr++) {
  1122. // First create NC file name for this year of data
  1123. string yearstr;
  1124. std::string full_path((char*)ifs_spinup_dir);
  1125. // AMIP
  1126. full_path += filevar + std::string("_") + lpjg_to_string(yr) + filenametail;
  1127. // Open NC file
  1128. int status, ncid;
  1129. status = nc_open(full_path.c_str(), NC_NOWRITE, &ncid);
  1130. if (status != NC_NOERR)
  1131. return false;
  1132. // Get the ID for varname
  1133. int var_id;
  1134. status = nc_inq_varid (ncid, varname, &var_id);
  1135. if (status != NC_NOERR)
  1136. return false;
  1137. // check for leap years
  1138. if (!(yr % 4) && (yr % 100 | !(yr % 400)))
  1139. daysinyear = 366;
  1140. else
  1141. daysinyear = 365;
  1142. // Read data
  1143. // double dataarray[365*88834];
  1144. //status = nc_get_var_double(ncid, var_id, dataarray);
  1145. for (int dd = 0; dd < daysinyear; dd++) {
  1146. size_t index[] = {(size_t)dd,0,(size_t)ifsindex-1}; // NB! because ifsindex has base 1
  1147. size_t depthindex[] = {(size_t)dd,0,0,(size_t)ifsindex-1}; // E.g. soil temp & moisture
  1148. double val;
  1149. if (!depth)
  1150. status = nc_get_var1_double(ncid, var_id, index, &val);
  1151. else
  1152. status = nc_get_var1_double(ncid, var_id, depthindex, &val);
  1153. if (status != NC_NOERR)
  1154. return false;
  1155. data[yrix][dd] = val;
  1156. yearavg+=data[yrix][dd];
  1157. }
  1158. nc_close(ncid);
  1159. // Get the data for variable longitude
  1160. //status = nc_get_var_double(ncid, lon_id, lon);
  1161. //if (status != NC_NOERR) handle_error(status);
  1162. // Read one year of data for this point (ifsindex)
  1163. yrix++;
  1164. }
  1165. yearavg/=(numyear*365);
  1166. return true;
  1167. } // getdailyIFSforcing
  1168. // Faster version of the above function.
  1169. // Read in the data for all NYEARIFS (10) years at once for this point.
  1170. // We created one file per variable as follows, for var143:
  1171. // cdo mergetime *var143* var143_1870-1879.nc
  1172. // ncpdq -a x,time,y var143_1870-1879.nc var143_1870-1879_fast.nc
  1173. bool getdailyIFSforcing_fast(const char* varname, const int& startyear, const int numyear, double data[NYEARIFS][366], int daysinyear, int ifsindex, bool depth) {
  1174. string filenametail = "_1870-1879_fast.nc";
  1175. xtring ifs_spinup_dir = param["ifs_spinup_dir"].str;
  1176. // New code for reading AMIP files
  1177. const char* filevar = varname;
  1178. if (startyear < 1900) {
  1179. // ECE v3.2 AMIP forcing only
  1180. if (!strcmp(varname, "var39"))
  1181. filevar = "var039";
  1182. if (!strcmp(varname, "var40"))
  1183. filevar = "var040";
  1184. if (!strcmp(varname, "var41"))
  1185. filevar = "var041";
  1186. if (!strcmp(varname, "var42"))
  1187. filevar = "var042";
  1188. }
  1189. // ecev3 - AMIP fix. No AMIP data before 1870, so use that data instead
  1190. int datastartyear = startyear;
  1191. if (startyear < 1870)
  1192. datastartyear = 1870;
  1193. // First create NC file name for this year of data
  1194. string yearstr;
  1195. std::string full_path((char*)ifs_spinup_dir);
  1196. // AMIP - merged and reordered
  1197. full_path += filevar + filenametail;
  1198. dprintf("full_path %s \n",full_path.c_str());
  1199. // Open NC file
  1200. int status, ncid;
  1201. status = nc_open(full_path.c_str(), NC_NOWRITE, &ncid);
  1202. if (status != NC_NOERR) {
  1203. fprintf(stderr, "Error opening %s: %s \n",full_path.c_str(),nc_strerror(status));
  1204. return false;
  1205. }
  1206. dprintf("file read \n");
  1207. // Get the ID for varname
  1208. int var_id;
  1209. status = nc_inq_varid(ncid, varname, &var_id);
  1210. if (status != NC_NOERR) {
  1211. fprintf(stderr, "Error inquiring var %s: %s \n",varname,nc_strerror(status));
  1212. return false;
  1213. }
  1214. // Read data
  1215. double data_arr[3652]; // 1870-79 daily data, incl. 2 leap years
  1216. size_t start[] = {(size_t)ifsindex - 1,0,0 }; // NB! because ifsindex has base 1
  1217. size_t start_depth[] = {(size_t)ifsindex - 1,0,0,0 }; // NB! because ifsindex has base 1
  1218. size_t count[] = {1,3652,1}; // NB! because ifsindex has base 1
  1219. size_t count_depth[] = {1,3652,1,1}; // NB! because ifsindex has base 1
  1220. if (!depth)
  1221. status = nc_get_vara_double(ncid, var_id, start, count, data_arr);
  1222. else
  1223. status = nc_get_vara_double(ncid, var_id, start_depth, count_depth, data_arr);
  1224. nc_close(ncid);
  1225. int yrix = 0;
  1226. int dayix = 0;
  1227. for (int yr = datastartyear; yr < datastartyear + NYEARIFS; yr++) {
  1228. // check for leap years
  1229. if (!(yr % 4) && (yr % 100 | !(yr % 400)))
  1230. daysinyear = 366;
  1231. else
  1232. daysinyear = 365;
  1233. for (int dd = 0; dd < daysinyear; dd++) {
  1234. data[yrix][dd] = data_arr[dayix];
  1235. dayix++;
  1236. }
  1237. yrix++;
  1238. }
  1239. return true;
  1240. } // getdailyIFSforcing_fast
  1241. // Read in ERA20C or GSWP3 data for NYEARIFS (10) years at once for this point.
  1242. // We created one file per variable as follows, for var143:
  1243. // cdo mergetime *var143* var143_1870-1879.nc
  1244. // ncpdq -a x,time,y var143_1901-1910.nc var143_1901-1910_fast.nc
  1245. bool getdailyERA20Cforcing_fast(const char* varname, const int& startyear, const int numyear, double data[NYEARIFS][366], int daysinyear, int ifsindex, bool depth) {
  1246. int datastartyear = datastartyear = startyear;
  1247. xtring filenametail;
  1248. filenametail.printf("_%4d-%4d_fast.nc", startyear, startyear+NYEARIFS-1);
  1249. xtring ifs_spinup_dir = param["ifs_spinup_dir"].str;
  1250. const char* filevar = varname;
  1251. // First create NC file name for this year of data
  1252. string yearstr;
  1253. xtring full_path = ifs_spinup_dir + filevar + filenametail;
  1254. //dprintf("Reading fast forcing file %s for era20c spinup \n", (const char*)full_path);
  1255. // Open NC file
  1256. int status, ncid;
  1257. status = nc_open((const char*)full_path, NC_NOWRITE, &ncid);
  1258. if (status != NC_NOERR)
  1259. return false;
  1260. // Get the ID for varname
  1261. int var_id;
  1262. status = nc_inq_varid(ncid, varname, &var_id);
  1263. if (status != NC_NOERR)
  1264. return false;
  1265. // Read data
  1266. double data_arr[3652]; // 1901-1910 daily data, incl. 2 leap years
  1267. size_t start[] = {(size_t)ifsindex - 1,0,0 }; // NB! because ifsindex has base 1
  1268. size_t start_depth[] = {(size_t)ifsindex - 1,0,0,0 }; // NB! because ifsindex has base 1
  1269. size_t count[] = { 1,3652,1 }; // NB! because ifsindex has base 1
  1270. size_t count_depth[] = { 1,3652,1,1 }; // NB! because ifsindex has base 1
  1271. if (!depth)
  1272. status = nc_get_vara_double(ncid, var_id, start, count, data_arr);
  1273. else
  1274. status = nc_get_vara_double(ncid, var_id, start_depth, count_depth, data_arr);
  1275. nc_close(ncid);
  1276. int yrix = 0;
  1277. int dayix = 0;
  1278. for (int yr = datastartyear; yr < datastartyear + NYEARIFS; yr++) {
  1279. // check for leap years
  1280. if (!(yr % 4) && (yr % 100 | !(yr % 400)))
  1281. daysinyear = 366;
  1282. else
  1283. daysinyear = 365;
  1284. for (int dd = 0; dd < daysinyear; dd++) {
  1285. data[yrix][dd] = data_arr[dayix];
  1286. dayix++;
  1287. }
  1288. yrix++;
  1289. }
  1290. return true;
  1291. } // getdailyERA20Cforcing_fast
  1292. // Used for nearest-neighbour N dep
  1293. void getndep_nearest_index(double lon, double lat, int ncid, int& lon_index, int& lat_index) {
  1294. // Search all coordinates in a square around (lon, lat), but first go down to
  1295. // multiple of 0.5 - ecev3 - add 0.25
  1296. double center_lon = floor(lon * 2) / 2 + 0.25;
  1297. double center_lat = floor(lat * 2) / 2 + 0.25;
  1298. int nrlat = 96;
  1299. int nrlon = 144;
  1300. // Get the ID for longitude
  1301. int status, lon_id;
  1302. status = nc_inq_varid(ncid, "lon", &lon_id);
  1303. if (status != NC_NOERR)
  1304. fail("Can't find N deposition longitude");
  1305. double val;
  1306. double diff = 360.0;
  1307. // Loop through latitudes to find the nearest
  1308. for (int lo = 0; lo < nrlon; lo++) {
  1309. size_t index[] = {(size_t)lo, 0, 1 };
  1310. status = nc_get_var1_double(ncid, lon_id, index, &val);
  1311. // same longitude scale
  1312. if (val >= 180.0)
  1313. val = val - 360.0;
  1314. // determine if this latitude is nearer
  1315. if (abs((val + 1.25) - center_lon) < diff) {
  1316. lon_index = lo;
  1317. diff = abs((val + 1.25) - center_lon);
  1318. }
  1319. }
  1320. // Get the ID for latitude
  1321. int lat_id;
  1322. status = nc_inq_varid(ncid, "lat", &lat_id);
  1323. if (status != NC_NOERR)
  1324. fail("Can't find N deposition latitude");
  1325. double val1, val1_c, val2;
  1326. diff = 180.0;
  1327. lat_index = -999;
  1328. // Loop through latitudes to find the nearest
  1329. size_t index[] = { 0, 0, 1 };
  1330. status = nc_get_var1_double(ncid, lat_id, index, &val1);
  1331. for (int la = 1; la < nrlat; la++) {
  1332. size_t index[] = {(size_t)la, 0, 1 };
  1333. status = nc_get_var1_double(ncid, lat_id, index, &val2);
  1334. // calculate center for previous latitude cell
  1335. val1_c = val1 - (val1 - val2) / 2.0;
  1336. // determine if the previous latitude is nearer
  1337. if (abs(val1_c - center_lat) < diff) {
  1338. lat_index = la - 1;
  1339. diff = abs(val1_c - center_lat);
  1340. }
  1341. val1 = val2;
  1342. // if the end if reached without updating the latitude index,
  1343. // then the last latitude cell is the correct one.
  1344. if (la == 95 && lat_index < 0)
  1345. lat_index = la;
  1346. }
  1347. }
  1348. // Used for nearest-neighbour N dep
  1349. bool getmonthlyNdepforcing(const char* varname, const int numyear, double data[NYEARNDEP][12], double lon, double lat, int& ndeplonindex, int& ndeplatindex) {
  1350. string filenametail = "_input4MIPs_surfaceFluxes_CMIP_NCAR-CCMI-1-0_gr_185001-201412.nc";
  1351. xtring ndep_cmip6_dir = param["ndep_cmip6_dir"].str;
  1352. const char* filevar = varname;
  1353. if (!strcmp(varname, "drynhx"))
  1354. filevar = "drynhx";
  1355. if (!strcmp(varname, "drynoy"))
  1356. filevar = "drynoy";
  1357. if (!strcmp(varname, "wetnhx"))
  1358. filevar = "wetnhx";
  1359. if (!strcmp(varname, "wetnoy"))
  1360. filevar = "wetnoy";
  1361. // First create NC file name for this data
  1362. std::string full_path((char*)ndep_cmip6_dir);
  1363. // AMIP
  1364. full_path += filevar + filenametail;
  1365. // Open NC file
  1366. int status, ncid;
  1367. status = nc_open(full_path.c_str(), NC_NOWRITE, &ncid);
  1368. if (status != NC_NOERR)
  1369. return false;
  1370. if (ndeplonindex < 0)
  1371. getndep_nearest_index(lon, lat, ncid, ndeplonindex, ndeplatindex);
  1372. // Get the ID for varname
  1373. int var_id;
  1374. status = nc_inq_varid(ncid, varname, &var_id);
  1375. if (status != NC_NOERR)
  1376. return false;
  1377. // Read data
  1378. for (int yy = 0; yy < numyear; yy++) {
  1379. for (int mm = 0; mm < 12; mm++) {
  1380. size_t index[] = { (size_t)yy*12+mm, (size_t)ndeplatindex - 1, (size_t)ndeplonindex - 1 }; // NB! because ndep index has base 1
  1381. double val;
  1382. status = nc_get_var1_double(ncid, var_id, index, &val);
  1383. if (status != NC_NOERR)
  1384. return false;
  1385. data[yy][mm] = val * 86400.0; // convert from kg N m-2 s-1 to kg N m-2 day-1
  1386. }
  1387. }
  1388. nc_close(ncid);
  1389. return true;
  1390. } // getmonthlyNdepforcing
  1391. bool getmonthlyNdepforcingConserve(const char* varname, const int numyear, double data[NYEARNDEP][12], int ndepindex) {
  1392. // 1st (".nc") or 2nd order remapping file?
  1393. string filenametail = "2.nc";
  1394. xtring ndep_cmip6_dir = param["ndep_cmip6_dir"].str;
  1395. const char* filevar = varname;
  1396. if (!strcmp(varname, "drynhx"))
  1397. filevar = "drynhx";
  1398. if (!strcmp(varname, "drynoy"))
  1399. filevar = "drynoy";
  1400. if (!strcmp(varname, "wetnhx"))
  1401. filevar = "wetnhx";
  1402. if (!strcmp(varname, "wetnoy"))
  1403. filevar = "wetnoy";
  1404. // First create NC file name for this data
  1405. std::string full_path((char*)ndep_cmip6_dir);
  1406. // AMIP
  1407. full_path += filevar + filenametail;
  1408. // Open NC file
  1409. int status, ncid;
  1410. status = nc_open(full_path.c_str(), NC_NOWRITE, &ncid);
  1411. if (status != NC_NOERR)
  1412. return false;
  1413. // Get the ID for varname
  1414. int var_id;
  1415. status = nc_inq_varid(ncid, varname, &var_id);
  1416. if (status != NC_NOERR)
  1417. return false;
  1418. // Read data
  1419. for (int yy = 0; yy < numyear; yy++) {
  1420. for (int mm = 0; mm < 12; mm++) {
  1421. size_t index[] = {(size_t)yy * 12 + mm, (size_t)ndepindex};
  1422. double val;
  1423. status = nc_get_var1_double(ncid, var_id, index, &val);
  1424. // < 0?
  1425. val = max(val, 0.0);
  1426. if (status != NC_NOERR)
  1427. return false;
  1428. data[yy][mm] = val * 86400.0; // convert from kg N m-2 s-1 to kg N m-2 day-1
  1429. }
  1430. }
  1431. nc_close(ncid);
  1432. return true;
  1433. } // getmonthlyNdepforcingConserve
  1434. /// Spinup LPJ-GUESS using IFS output data for EC-Earth restarts
  1435. /**
  1436. *
  1437. * \param gridcell The gridcell to simulate
  1438. * \param year The year to save the state for. e.g. 1850
  1439. * \param prescribe_ifs_soilmoist Use IFS soil moisture if true,
  1440. * but standard LPJ-GUESS parameterisations if false
  1441. * \param prescribe_ifs_soiltemp Use IFS soil temperature if true,
  1442. * but standard LPJ-GUESS parameterisations if false
  1443. */
  1444. bool IFSspinup(Gridcell& gridcell, int year, double co2spinup, bool prescribe_ifs_soilmoist,
  1445. bool prescribe_ifs_soiltemp) {
  1446. bool spinon=true;
  1447. // Read netcdf files with daily ECE output.
  1448. dprintf("Reading data before LPJ-GUESS IFS spinup \n");
  1449. int repetitions = (int) nyear_spinup / NYEARIFS;
  1450. int repix = 0;
  1451. int calyear = year;
  1452. int yrix = 0;
  1453. int spinupyear = 0;
  1454. // Keep a track of the simulation year for this cell.
  1455. gridcell.simulationyear = spinupyear;
  1456. // ecev3 - isspinup true will ensure fixed 1850 land use during spinup
  1457. gridcell.isspinup = true; // ONLY true during spinup!
  1458. // Arrays to be populated by data from IFS output
  1459. double ifstemp[NYEARIFS][366];
  1460. double ifsprecip[NYEARIFS][366];
  1461. double ifsprecipstrat[NYEARIFS][366];
  1462. double ifsprecipconv[NYEARIFS][366];
  1463. double ifsswradnet[NYEARIFS][366]; // net SW at the surface
  1464. double ifslwradnet[NYEARIFS][366]; // net LW at the surface
  1465. double ifstempsoil2[NYEARIFS][366];
  1466. double ifstempsoil3[NYEARIFS][366];
  1467. double ifssw1[NYEARIFS][366];
  1468. double ifssw2[NYEARIFS][366];
  1469. double ifssw3[NYEARIFS][366];
  1470. double ifssw4[NYEARIFS][366];
  1471. // Reset date
  1472. gridcell.date.set(year,0,0,0,0,0);
  1473. date = gridcell.date;
  1474. // Populate arrays one by one using gridcell.ifs_index for this gridcell
  1475. // T2M (K)
  1476. const char* vartoread = "var167";
  1477. bool dataOK = getdailyIFSforcing_fast(vartoread, year, NYEARIFS, ifstemp, gridcell.date.year_length(), gridcell.ifs_index, false);
  1478. if (!dataOK) {
  1479. dprintf("Error reading T2M data before LPJ-GUESS spinup. Quitting... \n");
  1480. return false;
  1481. }
  1482. // SURFACE SOLAR RAD - SW (W m-2 s - average of 4 6h periods)
  1483. vartoread = "var176";
  1484. dataOK = getdailyIFSforcing_fast(vartoread, year, NYEARIFS, ifsswradnet, gridcell.date.year_length(), gridcell.ifs_index, false);
  1485. if (!dataOK) {
  1486. dprintf("Error reading NETSW data before LPJ-GUESS spinup. Quitting... \n");
  1487. return false;
  1488. }
  1489. // SURFACE THERMAL RAD - LW (W m-2 s - average of 4 6h periods)
  1490. vartoread = "var177";
  1491. dataOK = getdailyIFSforcing_fast(vartoread, year, NYEARIFS, ifslwradnet, gridcell.date.year_length(), gridcell.ifs_index, false);
  1492. if (!dataOK) {
  1493. dprintf("Error reading NETLW data before LPJ-GUESS spinup. Quitting... \n");
  1494. return false;
  1495. }
  1496. // SOIL TEMP 2 (K)
  1497. vartoread = "var170";
  1498. dataOK = getdailyIFSforcing_fast(vartoread, year, NYEARIFS, ifstempsoil2, gridcell.date.year_length(), gridcell.ifs_index, true);
  1499. if (!dataOK) {
  1500. dprintf("Error reading SOIL TEMP 2 data before LPJ-GUESS spinup. Quitting... \n");
  1501. return false;
  1502. }
  1503. // SOIL TEMP 3 (K)
  1504. vartoread = "var183";
  1505. dataOK = getdailyIFSforcing_fast(vartoread, year, NYEARIFS, ifstempsoil3, gridcell.date.year_length(), gridcell.ifs_index, true);
  1506. if (!dataOK) {
  1507. dprintf("Error reading SOIL TEMP 3 data before LPJ-GUESS spinup. Quitting... \n");
  1508. return false;
  1509. }
  1510. // SOIL WATER 1 (m3 m-3)
  1511. vartoread = "var39";
  1512. dataOK = getdailyIFSforcing_fast(vartoread, year, NYEARIFS, ifssw1, gridcell.date.year_length(), gridcell.ifs_index, true);
  1513. if (!dataOK) {
  1514. dprintf("Error reading SOIL WATER 1 data before LPJ-GUESS spinup. Quitting... \n");
  1515. return false;
  1516. }
  1517. // SOIL WATER 2 (m3 m-3)
  1518. vartoread = "var40";
  1519. dataOK = getdailyIFSforcing_fast(vartoread, year, NYEARIFS, ifssw2, gridcell.date.year_length(), gridcell.ifs_index, true);
  1520. if (!dataOK) {
  1521. dprintf("Error reading SOIL WATER 2 data before LPJ-GUESS spinup. Quitting... \n");
  1522. return false;
  1523. }
  1524. // SOIL WATER 3 (m3 m-3)
  1525. vartoread = "var41";
  1526. dataOK = getdailyIFSforcing_fast(vartoread, year, NYEARIFS, ifssw3, gridcell.date.year_length(), gridcell.ifs_index, true);
  1527. if (!dataOK) {
  1528. dprintf("Error reading SOIL WATER 3 data before LPJ-GUESS spinup. Quitting... \n");
  1529. return false;
  1530. }
  1531. // SOIL WATER 4 (m3 m-3)
  1532. vartoread = "var42";
  1533. dataOK = getdailyIFSforcing_fast(vartoread, year, NYEARIFS, ifssw4, gridcell.date.year_length(), gridcell.ifs_index, true);
  1534. if (!dataOK) {
  1535. dprintf("Error reading SOIL WATER 4 data before LPJ-GUESS spinup. Quitting... \n");
  1536. return false;
  1537. }
  1538. // STRATIFORM PRECIP (m - average of 4 6h periods). NB! This includes both rain and snow
  1539. vartoread = "var142";
  1540. dataOK = getdailyIFSforcing_fast(vartoread, year, NYEARIFS, ifsprecipstrat, gridcell.date.year_length(), gridcell.ifs_index, false);
  1541. if (!dataOK) {
  1542. dprintf("Error reading STRATIFORM PRECIP data before LPJ-GUESS spinup. Quitting... \n");
  1543. return false;
  1544. }
  1545. // CONVECTIVE PRECIP (m - average of 4 6h periods) NB! This includes both rain and snow
  1546. vartoread = "var143";
  1547. dataOK = getdailyIFSforcing_fast(vartoread, year, NYEARIFS, ifsprecipconv, gridcell.date.year_length(), gridcell.ifs_index, false);
  1548. if (!dataOK) {
  1549. dprintf("Error reading CONVECTIVE PRECIP data before LPJ-GUESS spinup. Quitting... \n");
  1550. return false;
  1551. }
  1552. // CONVERSIONS and averages:
  1553. // **************************
  1554. float lpjgsw1[NYEARIFS][366];
  1555. float lpjgsw2[NYEARIFS][366];
  1556. // Precip: aggregation and conversion to mm/day (*4 for full day acc precip & * 1000 m to mm)
  1557. // SW: Conversion to W m-2. (* 4 as to get daily J m-2 (accumulated), / secs_in_day to get W m-2
  1558. double secs_in_day = 60.0 * 60.0 * 24.0;
  1559. // Annual averages - Forget about leap years
  1560. double t2mavg = 0.0;
  1561. double soiltavg = 0.0;
  1562. double precavg = 0.0;
  1563. double SWavg = 0.0;
  1564. double LWavg = 0.0;
  1565. double lpjg_wcont = 0.0;
  1566. int ndays = 0;
  1567. for (int yy = 0; yy < NYEARIFS; yy++) {
  1568. for (int dd = 0; dd < 366; dd++ ) {
  1569. // Precip:
  1570. ifsprecip[yy][dd] = (ifsprecipstrat[yy][dd] + ifsprecipconv[yy][dd]) * 4 * 1000; // ecev3 bugfix - removed snow
  1571. ifsprecip[yy][dd] = max(ifsprecip[yy][dd],0.0); // remove small -ve values
  1572. if (ifsprecip[yy][dd] < 0.000001) ifsprecip[yy][dd] = 0.0; // remove very small or negative precip amounts (< 0.000001 mm/day)
  1573. // SW:
  1574. ifsswradnet[yy][dd] *= 4.0 / secs_in_day;
  1575. if (ifsswradnet[yy][dd] < 0.000001) ifsswradnet[yy][dd] = 0.0; // remove very small or negative SSR amounts (< 0.000001 W m-2)
  1576. // LW:
  1577. ifslwradnet[yy][dd] *= 4.0 / secs_in_day; // can be positive or negative
  1578. // Soil water
  1579. ifs_to_lpjg_soilwater(ifssw1[yy][dd], ifssw2[yy][dd], ifssw3[yy][dd],
  1580. ifssw4[yy][dd], lpjgsw1[yy][dd], lpjgsw2[yy][dd]);
  1581. if (dd < 365) {
  1582. ndays++;
  1583. t2mavg += ifstemp[yy][dd];
  1584. SWavg += ifsswradnet[yy][dd];
  1585. LWavg += ifslwradnet[yy][dd];
  1586. precavg += ifsprecip[yy][dd];
  1587. soiltavg += ifstempsoil2[yy][dd];
  1588. lpjg_wcont += lpjgsw1[yy][dd];
  1589. }
  1590. }
  1591. }
  1592. t2mavg /= ndays;
  1593. precavg /= ndays;
  1594. SWavg /= ndays;
  1595. LWavg /= ndays;
  1596. soiltavg /= ndays;
  1597. lpjg_wcont /= ndays;
  1598. // Now loop through the X years until Y years of spinup have been performed
  1599. dprintf("Data loaded. Now performing LPJ-GUESS spinup \n");
  1600. dprintf("Spinup mean T2M, Prec, SW, LW, SoilT, SoilW for cell with lon=%f, lat=%f are: %f, %f, %f, %f, %f, %f \n", gridcell.get_lon(), gridcell.get_lat(),
  1601. t2mavg, precavg, SWavg, LWavg, soiltavg, lpjg_wcont);
  1602. // CO2 now passed into this routine
  1603. // double co2spinup = 284.725; // ppm - fixed for spinup period - preIndustrial, 1850
  1604. // double co2spinup = 353.855; // ppm - fixed for spinup period - modern, 1990
  1605. // double co2spinup = 324.985; // ppm - fixed for spinup period - modern, 1970
  1606. //////////////// ERROR fix N dep index, nearest cell
  1607. gridcell.ndep_lon_index = -999;
  1608. gridcell.ndep_lat_index = -999;
  1609. // Monthly dry NH4 deposition (kg m-2 s-1)
  1610. vartoread = "drynhx";
  1611. double drynhx_data[NYEARNDEP][12];
  1612. // dataOK = getmonthlyNdepforcing(vartoread, NYEARNDEP, drynhx_data, gridcell.get_lon(), gridcell.get_lat(), gridcell.ndep_lon_index, gridcell.ndep_lat_index);
  1613. dataOK = getmonthlyNdepforcingConserve(vartoread, NYEARNDEP, drynhx_data, gridcell.ndep_index);
  1614. if (!dataOK) {
  1615. dprintf("Error reading dry NHx deposition data before LPJ-GUESS spinup. Quitting... \n");
  1616. return false;
  1617. }
  1618. // Monthly wet NH4 deposition (kg m-2 s-1)
  1619. vartoread = "wetnhx";
  1620. double wetnhx_data[NYEARNDEP][12];
  1621. //dataOK = getmonthlyNdepforcing(vartoread, NYEARNDEP, wetnhx_data, gridcell.get_lon(), gridcell.get_lat(), gridcell.ndep_lon_index, gridcell.ndep_lat_index);
  1622. dataOK = getmonthlyNdepforcingConserve(vartoread, NYEARNDEP, wetnhx_data, gridcell.ndep_index);
  1623. if (!dataOK) {
  1624. dprintf("Error reading wet NHx deposition data before LPJ-GUESS spinup. Quitting... \n");
  1625. return false;
  1626. }
  1627. // Monthly dry NO3 deposition (kg m-2 s-1)
  1628. vartoread = "drynoy";
  1629. double drynoy_data[NYEARNDEP][12];
  1630. //dataOK = getmonthlyNdepforcing(vartoread, NYEARNDEP, drynoy_data, gridcell.get_lon(), gridcell.get_lat(), gridcell.ndep_lon_index, gridcell.ndep_lat_index);
  1631. dataOK = getmonthlyNdepforcingConserve(vartoread, NYEARNDEP, drynoy_data, gridcell.ndep_index);
  1632. if (!dataOK) {
  1633. dprintf("Error reading dry NOy deposition data before LPJ-GUESS spinup. Quitting... \n");
  1634. return false;
  1635. }
  1636. // Monthly wet NO3 deposition (kg m-2 s-1)
  1637. vartoread = "wetnoy";
  1638. double wetnoy_data[NYEARNDEP][12];
  1639. //dataOK = getmonthlyNdepforcing(vartoread, NYEARNDEP, wetnoy_data, gridcell.get_lon(), gridcell.get_lat(), gridcell.ndep_lon_index, gridcell.ndep_lat_index);
  1640. dataOK = getmonthlyNdepforcingConserve(vartoread, NYEARNDEP, wetnoy_data, gridcell.ndep_index);
  1641. if (!dataOK) {
  1642. dprintf("Error reading wet NOy deposition data before LPJ-GUESS spinup. Quitting... \n");
  1643. return false;
  1644. }
  1645. // Get monthly ndep values and convert to daily
  1646. double mndrydep[12];
  1647. double mnwetdep[12];
  1648. /// Daily N deposition for current year
  1649. double dndep[Date::MAX_YEAR_LENGTH];
  1650. bool veryfirstday = true; // needed to initialise below
  1651. bool printoutput = false; // Will be set to true for the final 50 years of the spinup simulation
  1652. bool printdlai = false; // print daily LAI on the last day of the spinup.
  1653. FILE *ofp; // Daily LAI
  1654. while (spinon) {
  1655. // START OF LOOP THROUGH SIMULATION DAYS
  1656. // First get the climate and soil drivers for this day of the simulation:
  1657. // temp, precip, netswrad, temp_soil,soilw_surf,soilw_deep
  1658. double temp = 0.0;
  1659. double precip = 0.0;
  1660. double netswrad = 0.0;
  1661. double netlwrad = 0.0;
  1662. double temp_soil = 0.0;
  1663. double temp_soil_2 = 0.0;
  1664. double temp_soil_3 = 0.0;
  1665. double soilw_surf = 0.0;
  1666. double soilw_deep = 0.0;
  1667. // T2M
  1668. temp = ifstemp[yrix][gridcell.date.day];
  1669. temp-=K2degC; // Convert to degC
  1670. // PRECIP, NET SW & LW
  1671. precip = ifsprecip[yrix][gridcell.date.day];
  1672. netswrad = ifsswradnet[yrix][gridcell.date.day];
  1673. netlwrad = ifslwradnet[yrix][gridcell.date.day];
  1674. if (veryfirstday) {
  1675. // ecev3 - Only need to populate the dndep array ONCE during the spinup
  1676. // When using .bin files:
  1677. // gridcell.ndepts.get_one_calendar_year(gridcell.date.year, mndrydep, mnwetdep);
  1678. // Use CMIP6 N dep historical data
  1679. for (int mm = 0; mm < 12; mm++) {
  1680. mndrydep[mm] = drynhx_data[0][mm] + drynoy_data[0][mm]; // values for year 1850 during spinup
  1681. mnwetdep[mm] = wetnhx_data[0][mm] + wetnoy_data[0][mm]; // values for year 1850 during spinup
  1682. }
  1683. // Distribute N deposition
  1684. distribute_ndep(mndrydep, mnwetdep, ifsprecip[yrix], gridcell.date.ndaymonth, dndep);
  1685. }
  1686. // SOIL TEMP
  1687. temp_soil_2 = ifstempsoil2[yrix][gridcell.date.day];
  1688. temp_soil_3 = ifstempsoil3[yrix][gridcell.date.day];
  1689. // Interpolate soil temp to 25cm
  1690. temp_soil = ifs_to_lpjg_soiltemp(temp_soil_2,temp_soil_3);
  1691. temp_soil-=K2degC; // Convert to degC
  1692. // SOIL WATER
  1693. soilw_surf = (double)lpjgsw1[yrix][gridcell.date.day];
  1694. soilw_deep = (double)lpjgsw2[yrix][gridcell.date.day];
  1695. // Convert from m3 m-3 to AWC [0-1] depending on soil type
  1696. swConvert(gridcell.soiltype,soilw_surf,soilw_deep);
  1697. // Daily N deposition (Read from file)
  1698. // double dndep = ndep / (365.0 * 10000.0); // units kgN/ha/year to kgN/m2/day
  1699. // double dndep_today = ndep / (365.0 * 10000.0); // units kgN/ha/year to kgN/m2/day
  1700. double dndep_today = dndep[gridcell.date.day]; // units: kgN/m2/day
  1701. double dnfert = 0.0;
  1702. // NB! ecev3 - Could call getgridcell here if LU cover changes during spinup...
  1703. // Transfer today's climate data to the Climate object in Gridcell.
  1704. gridcell.climate.setdrivers(temp, precip, netswrad, netlwrad, co2spinup, temp_soil, soilw_surf, soilw_deep, dndep_today, dnfert);
  1705. // Simulate vegetation today!
  1706. simulate_day_ece(gridcell, prescribe_ifs_soilmoist, prescribe_ifs_soiltemp,
  1707. veryfirstday, printoutput);
  1708. veryfirstday= false; // NB! gridcell.simulationyear is updated on Dec 31 in simulate_day_ece
  1709. // Daily LAI?
  1710. if (spinupyear == nyear_spinup - 1 && gridcell.date.day == 0) {
  1711. printdlai = true;
  1712. // Print out dLAI?
  1713. ofp = fopen("dailyLAIandFPC.txt", "a");
  1714. }
  1715. if (printdlai) {
  1716. // Now calculate the LAI for high and low fractions
  1717. computeDailyLAIandFPCforIFS(gridcell);
  1718. fprintf(ofp, "%8.6f\t %8.6f\t %d\t %d\t %8.5f\t %8.5f\t %8.5f\t %8.5f\n", gridcell.get_lon(), gridcell.get_lat(), date.get_calendar_year(), date.day + 1,
  1719. gridcell.laiphen_low_today, gridcell.laiphen_high_today, gridcell.IFSfraclow,gridcell.IFSfrachigh);
  1720. }
  1721. // Advance day and check for new years, number of repetitions etc.
  1722. int oldyear = gridcell.date.year;
  1723. // Next day of the simulation
  1724. gridcell.date.next();
  1725. date=gridcell.date;
  1726. int newyear = gridcell.date.year;
  1727. if (newyear != oldyear) {
  1728. // If Jan 1...
  1729. calyear++;
  1730. yrix++;
  1731. spinupyear++;
  1732. // if (spinupyear >= 0) // for testing & debugging
  1733. if (spinupyear >= nyear_spinup-5)
  1734. printoutput = true; // Only print output if we're in the final 10 years of the spinup
  1735. // test with:
  1736. // dprintf("Repetition %4d... \n", spinupyear);
  1737. // dprintf("Nr of stands %4d\n", gridcell.nbr_stands());
  1738. if (calyear == year + NYEARIFS) {
  1739. repix++; // One more repetition completed...
  1740. calyear = year; // so reset the clock
  1741. gridcell.date.set(year,0,0,0,0,0);
  1742. date=gridcell.date;
  1743. yrix=0; // Refer to correct array elements above
  1744. }
  1745. }
  1746. if (repix==repetitions) // End of spinup if we've run all repetitions
  1747. spinon=false;
  1748. }
  1749. // Close LAI file
  1750. if (printdlai) {
  1751. fclose(ofp);
  1752. }
  1753. dprintf("LPJ-GUESS IFS spinup complete\n");
  1754. gridcell.isspinup = false; // set to false
  1755. return true;
  1756. } // IFSspinup
  1757. /// Spinup LPJ-GUESS using ERA20C or GSWP3 output data for EC-Earth restarts
  1758. /**
  1759. *
  1760. * \param gridcell The gridcell to simulate
  1761. * \param year The year to save the state for. e.g. 1850
  1762. * \param prescribe_ifs_soilmoist Use IFS soil moisture if true,
  1763. * but standard LPJ-GUESS parameterisations if false
  1764. * \param prescribe_ifs_soiltemp Use IFS soil temperature if true,
  1765. * but standard LPJ-GUESS parameterisations if false
  1766. */
  1767. bool ERA20Cspinup(Gridcell& gridcell, int year, double co2spinup, bool prescribe_ifs_soilmoist,
  1768. bool prescribe_ifs_soiltemp) {
  1769. bool spinon = true;
  1770. // Read netcdf files with daily ECE output.
  1771. dprintf("Reading data before LPJ-GUESS ERA20C spinup \n");
  1772. int repetitions = (int)nyear_spinup / NYEARIFS;
  1773. int repix = 0;
  1774. int calyear = year;
  1775. int yrix = 0;
  1776. int spinupyear = 0;
  1777. // Keep a track of the simulation year for this cell.
  1778. gridcell.simulationyear = spinupyear;
  1779. // ecev3 - isspinup true will ensure fixed 1850 land use during spinup
  1780. gridcell.isspinup = true; // ONLY true during spinup!
  1781. // Arrays to be populated by data from IFS output
  1782. double ifstemp[NYEARIFS][366];
  1783. double ifsprecip[NYEARIFS][366];
  1784. double ifsswradnet[NYEARIFS][366]; // net SW at the surface
  1785. double ifslwradnet[NYEARIFS][366]; // net LW at the surface
  1786. double ifstempsoil2[NYEARIFS][366];
  1787. double ifstempsoil3[NYEARIFS][366];
  1788. double ifssw1[NYEARIFS][366];
  1789. double ifssw2[NYEARIFS][366];
  1790. double ifssw3[NYEARIFS][366];
  1791. double ifssw4[NYEARIFS][366];
  1792. // Reset date
  1793. gridcell.date.set(year, 0, 0, 0, 0, 0);
  1794. date = gridcell.date;
  1795. // Populate arrays one by one using gridcell.ifs_index for this gridcell
  1796. // T2M (K)
  1797. const char* vartoread = "var167";
  1798. bool dataOK = getdailyERA20Cforcing_fast(vartoread, year, NYEARIFS, ifstemp, gridcell.date.year_length(), gridcell.ifs_index, false);
  1799. if (!dataOK) {
  1800. dprintf("Error reading ERA20C T2M data before LPJ-GUESS spinup. Quitting... \n");
  1801. return false;
  1802. }
  1803. // SURFACE SOLAR RAD - SW (W m-2)
  1804. vartoread = "var176";
  1805. dataOK = getdailyERA20Cforcing_fast(vartoread, year, NYEARIFS, ifsswradnet, gridcell.date.year_length(), gridcell.ifs_index, false);
  1806. if (!dataOK) {
  1807. dprintf("Error reading ERA20C NETSW spinup data before LPJ-GUESS spinup. Quitting... \n");
  1808. return false;
  1809. }
  1810. // SURFACE THERMAL RAD - LW (W m-2)
  1811. vartoread = "var177";
  1812. dataOK = getdailyERA20Cforcing_fast(vartoread, year, NYEARIFS, ifslwradnet, gridcell.date.year_length(), gridcell.ifs_index, false);
  1813. if (!dataOK) {
  1814. dprintf("Error reading ERA20C NETLW data before LPJ-GUESS spinup. Quitting... \n");
  1815. return false;
  1816. }
  1817. // SOIL TEMP 2 (K)
  1818. vartoread = "var170";
  1819. dataOK = getdailyERA20Cforcing_fast(vartoread, year, NYEARIFS, ifstempsoil2, gridcell.date.year_length(), gridcell.ifs_index, true);
  1820. if (!dataOK) {
  1821. dprintf("Error reading ERA20C SOIL TEMP 2 data before LPJ-GUESS spinup. Quitting... \n");
  1822. return false;
  1823. }
  1824. // SOIL TEMP 3 (K)
  1825. vartoread = "var183";
  1826. dataOK = getdailyERA20Cforcing_fast(vartoread, year, NYEARIFS, ifstempsoil3, gridcell.date.year_length(), gridcell.ifs_index, true);
  1827. if (!dataOK) {
  1828. dprintf("Error reading ERA20C SOIL TEMP 3 data before LPJ-GUESS spinup. Quitting... \n");
  1829. return false;
  1830. }
  1831. // SOIL WATER 1 (m3 m-3)
  1832. vartoread = "var39";
  1833. dataOK = getdailyERA20Cforcing_fast(vartoread, year, NYEARIFS, ifssw1, gridcell.date.year_length(), gridcell.ifs_index, true);
  1834. if (!dataOK) {
  1835. dprintf("Error reading ERA20C SOIL WATER 1 data before LPJ-GUESS spinup. Quitting... \n");
  1836. return false;
  1837. }
  1838. // SOIL WATER 2 (m3 m-3)
  1839. vartoread = "var40";
  1840. dataOK = getdailyERA20Cforcing_fast(vartoread, year, NYEARIFS, ifssw2, gridcell.date.year_length(), gridcell.ifs_index, true);
  1841. if (!dataOK) {
  1842. dprintf("Error reading ERA20C SOIL WATER 2 data before LPJ-GUESS spinup. Quitting... \n");
  1843. return false;
  1844. }
  1845. // SOIL WATER 3 (m3 m-3)
  1846. vartoread = "var41";
  1847. dataOK = getdailyERA20Cforcing_fast(vartoread, year, NYEARIFS, ifssw3, gridcell.date.year_length(), gridcell.ifs_index, true);
  1848. if (!dataOK) {
  1849. dprintf("Error reading ERA20C SOIL WATER 3 data before LPJ-GUESS spinup. Quitting... \n");
  1850. return false;
  1851. }
  1852. // SOIL WATER 4 (m3 m-3)
  1853. vartoread = "var42";
  1854. dataOK = getdailyERA20Cforcing_fast(vartoread, year, NYEARIFS, ifssw4, gridcell.date.year_length(), gridcell.ifs_index, true);
  1855. if (!dataOK) {
  1856. dprintf("Error reading ERA20C SOIL WATER 4 data before LPJ-GUESS spinup. Quitting... \n");
  1857. return false;
  1858. }
  1859. // PRECIP (mm). NB! This includes both rain and snow
  1860. vartoread = "var228";
  1861. dataOK = getdailyERA20Cforcing_fast(vartoread, year, NYEARIFS, ifsprecip, gridcell.date.year_length(), gridcell.ifs_index, false);
  1862. if (!dataOK) {
  1863. dprintf("Error reading ERA20C PRECIP data before LPJ-GUESS spinup. Quitting... \n");
  1864. return false;
  1865. }
  1866. // CONVERSIONS and averages:
  1867. // **************************
  1868. float lpjgsw1[NYEARIFS][366];
  1869. float lpjgsw2[NYEARIFS][366];
  1870. // Precip: aggregation and conversion to mm/day (*4 for full day acc precip & * 1000 m to mm)
  1871. // SW: Conversion to W m-2. (* 4 as to get daily J m-2 (accumulated), / secs_in_day to get W m-2
  1872. double secs_in_day = 60.0 * 60.0 * 24.0;
  1873. // Annual averages - Forget about leap years
  1874. double t2mavg = 0.0;
  1875. double soiltavg = 0.0;
  1876. double precavg = 0.0;
  1877. double SWavg = 0.0;
  1878. double LWavg = 0.0;
  1879. double lpjg_wcont = 0.0;
  1880. int ndays = 0;
  1881. for (int yy = 0; yy < NYEARIFS; yy++) {
  1882. for (int dd = 0; dd < 366; dd++) {
  1883. // Precip:
  1884. ifsprecip[yy][dd] = max(ifsprecip[yy][dd], 0.0); // remove small -ve values
  1885. if (ifsprecip[yy][dd] < 0.000001) ifsprecip[yy][dd] = 0.0; // remove very small precip amounts (< 0.000001 mm/day)
  1886. // SW
  1887. if (ifsswradnet[yy][dd] < 0.000001) ifsswradnet[yy][dd] = 0.0; // remove very small or negative SSR amounts (< 0.000001 W m-2)
  1888. // Soil water
  1889. ifs_to_lpjg_soilwater(ifssw1[yy][dd], ifssw2[yy][dd], ifssw3[yy][dd], ifssw4[yy][dd], lpjgsw1[yy][dd], lpjgsw2[yy][dd]);
  1890. if (dd < 365) {
  1891. ndays++;
  1892. t2mavg += ifstemp[yy][dd];
  1893. SWavg += ifsswradnet[yy][dd];
  1894. LWavg += ifslwradnet[yy][dd];
  1895. precavg += ifsprecip[yy][dd];
  1896. soiltavg += ifstempsoil2[yy][dd];
  1897. lpjg_wcont += lpjgsw1[yy][dd];
  1898. }
  1899. }
  1900. }
  1901. t2mavg /= ndays;
  1902. precavg /= ndays;
  1903. SWavg /= ndays;
  1904. LWavg /= ndays;
  1905. soiltavg /= ndays;
  1906. lpjg_wcont /= ndays;
  1907. // Now loop through the X years until Y years of spinup have been performed
  1908. dprintf("Data loaded. Now performing LPJ-GUESS ERA20C spinup \n");
  1909. dprintf("Spinup mean T2M, Prec, SW, LW, SoilT, SoilW for cell with lon=%f, lat=%f are: %f, %f, %f, %f, %f, %f \n", gridcell.get_lon(), gridcell.get_lat(),
  1910. t2mavg, precavg, SWavg, LWavg, soiltavg, lpjg_wcont);
  1911. // CO2 now passed into this routine
  1912. // double co2spinup = 284.725; // ppm - fixed for spinup period - preIndustrial, 1850
  1913. // double co2spinup = 353.855; // ppm - fixed for spinup period - modern, 1990
  1914. // double co2spinup = 324.985; // ppm - fixed for spinup period - modern, 1970
  1915. //////////////// ERROR fix N dep index, nearest cell
  1916. gridcell.ndep_lon_index = -999;
  1917. gridcell.ndep_lat_index = -999;
  1918. // Monthly dry NH4 deposition (kg m-2 s-1)
  1919. vartoread = "drynhx";
  1920. double drynhx_data[NYEARNDEP][12];
  1921. dataOK = getmonthlyNdepforcingConserve(vartoread, NYEARNDEP, drynhx_data, gridcell.ndep_index);
  1922. if (!dataOK) {
  1923. dprintf("Error reading dry NHx deposition data before LPJ-GUESS spinup. Quitting... \n");
  1924. return false;
  1925. }
  1926. // Monthly wet NH4 deposition (kg m-2 s-1)
  1927. vartoread = "wetnhx";
  1928. double wetnhx_data[NYEARNDEP][12];
  1929. dataOK = getmonthlyNdepforcingConserve(vartoread, NYEARNDEP, wetnhx_data, gridcell.ndep_index);
  1930. if (!dataOK) {
  1931. dprintf("Error reading wet NHx deposition data before LPJ-GUESS spinup. Quitting... \n");
  1932. return false;
  1933. }
  1934. // Monthly dry NO3 deposition (kg m-2 s-1)
  1935. vartoread = "drynoy";
  1936. double drynoy_data[NYEARNDEP][12];
  1937. dataOK = getmonthlyNdepforcingConserve(vartoread, NYEARNDEP, drynoy_data, gridcell.ndep_index);
  1938. if (!dataOK) {
  1939. dprintf("Error reading dry NOy deposition data before LPJ-GUESS spinup. Quitting... \n");
  1940. return false;
  1941. }
  1942. // Monthly wet NO3 deposition (kg m-2 s-1)
  1943. vartoread = "wetnoy";
  1944. double wetnoy_data[NYEARNDEP][12];
  1945. dataOK = getmonthlyNdepforcingConserve(vartoread, NYEARNDEP, wetnoy_data, gridcell.ndep_index);
  1946. if (!dataOK) {
  1947. dprintf("Error reading wet NOy deposition data before LPJ-GUESS spinup. Quitting... \n");
  1948. return false;
  1949. }
  1950. // Get monthly ndep values and convert to daily
  1951. double mndrydep[12];
  1952. double mnwetdep[12];
  1953. /// Daily N deposition for current year
  1954. double dndep[Date::MAX_YEAR_LENGTH];
  1955. bool veryfirstday = true; // needed to initialise below
  1956. bool printoutput = false; // Will be set to true for the final 50 years of the spinup simulation
  1957. bool printdlai = false; // print daily LAI on the last day of the spinup.
  1958. FILE *ofp; // Daily LAI
  1959. while (spinon) {
  1960. // START OF LOOP THROUGH SIMULATION DAYS
  1961. // First get the climate and soil drivers for this day of the simulation:
  1962. // temp, precip, netswrad, temp_soil,soilw_surf,soilw_deep
  1963. double temp = 0.0;
  1964. double precip = 0.0;
  1965. double netswrad = 0.0;
  1966. double netlwrad = 0.0;
  1967. double temp_soil = 0.0;
  1968. double temp_soil_2 = 0.0;
  1969. double temp_soil_3 = 0.0;
  1970. double soilw_surf = 0.0;
  1971. double soilw_deep = 0.0;
  1972. // T2M
  1973. temp = ifstemp[yrix][gridcell.date.day];
  1974. temp -= K2degC; // Convert to degC
  1975. // PRECIP, NET SW & LW
  1976. precip = ifsprecip[yrix][gridcell.date.day];
  1977. precip = precip*1.e3*secs_in_day/1000; // Convert from kg m-2 s-1 to mm
  1978. netswrad = ifsswradnet[yrix][gridcell.date.day];
  1979. netlwrad = ifslwradnet[yrix][gridcell.date.day];
  1980. if (veryfirstday) {
  1981. // ecev3 - Only need to populate the dndep array ONCE during the spinup
  1982. // When using .bin files:
  1983. // gridcell.ndepts.get_one_calendar_year(gridcell.date.year, mndrydep, mnwetdep);
  1984. // Use CMIP6 N dep historical data
  1985. for (int mm = 0; mm < 12; mm++) {
  1986. mndrydep[mm] = drynhx_data[0][mm] + drynoy_data[0][mm]; // values for year 1850 during spinup
  1987. mnwetdep[mm] = wetnhx_data[0][mm] + wetnoy_data[0][mm]; // values for year 1850 during spinup
  1988. }
  1989. // Distribute N deposition
  1990. distribute_ndep(mndrydep, mnwetdep, ifsprecip[yrix], gridcell.date.ndaymonth, dndep);
  1991. }
  1992. // SOIL TEMP
  1993. temp_soil_2 = ifstempsoil2[yrix][gridcell.date.day];
  1994. temp_soil_3 = ifstempsoil3[yrix][gridcell.date.day];
  1995. // Interpolate soil temp to 25cm
  1996. temp_soil = ifs_to_lpjg_soiltemp(temp_soil_2, temp_soil_3);
  1997. temp_soil -= K2degC; // Convert to degC
  1998. // SOIL WATER
  1999. soilw_surf = (double)lpjgsw1[yrix][gridcell.date.day];
  2000. soilw_deep = (double)lpjgsw2[yrix][gridcell.date.day];
  2001. // Convert from m3 m-3 to AWC [0-1] depending on soil type
  2002. swConvert(gridcell.soiltype, soilw_surf, soilw_deep);
  2003. // Daily N deposition (Read from file)
  2004. // double dndep = ndep / (365.0 * 10000.0); // units kgN/ha/year to kgN/m2/day
  2005. // double dndep_today = ndep / (365.0 * 10000.0); // units kgN/ha/year to kgN/m2/day
  2006. double dndep_today = dndep[gridcell.date.day]; // units: kgN/m2/day
  2007. double dnfert = 0.0;
  2008. // NB! ecev3 - Could call getgridcell here if LU cover changes during spinup...
  2009. // Transfer today's climate data to the Climate object in Gridcell.
  2010. gridcell.climate.setdrivers(temp, precip, netswrad, netlwrad, co2spinup, temp_soil, soilw_surf, soilw_deep, dndep_today, dnfert);
  2011. // Simulate vegetation today!
  2012. simulate_day_ece(gridcell, prescribe_ifs_soilmoist, prescribe_ifs_soiltemp,
  2013. veryfirstday, printoutput);
  2014. veryfirstday = false; // NB! gridcell.simulationyear is updated on Dec 31 in simulate_day_ece
  2015. // Daily LAI?
  2016. if (spinupyear == nyear_spinup - 1 && gridcell.date.day == 0) {
  2017. printdlai = true;
  2018. // Print out dLAI?
  2019. ofp = fopen("dailyLAIandFPC.txt", "a");
  2020. }
  2021. if (printdlai) {
  2022. // Now calculate the LAI for high and low fractions
  2023. computeDailyLAIandFPCforIFS(gridcell);
  2024. fprintf(ofp, "%8.6f\t %8.6f\t %d\t %d\t %8.5f\t %8.5f\t %8.5f\t %8.5f\n", gridcell.get_lon(), gridcell.get_lat(), date.get_calendar_year(), date.day + 1,
  2025. gridcell.laiphen_low_today, gridcell.laiphen_high_today, gridcell.IFSfraclow, gridcell.IFSfrachigh);
  2026. }
  2027. // Advance day and check for new years, number of repetitions etc.
  2028. int oldyear = gridcell.date.year;
  2029. // Next day of the simulation
  2030. gridcell.date.next();
  2031. date = gridcell.date;
  2032. int newyear = gridcell.date.year;
  2033. if (newyear != oldyear) {
  2034. // If Jan 1...
  2035. calyear++;
  2036. yrix++;
  2037. spinupyear++;
  2038. // if (spinupyear >= 0) // for testing & debugging
  2039. if (spinupyear >= nyear_spinup - 5)
  2040. printoutput = true; // Only print output if we're in the final 10 years of the spinup
  2041. if (calyear == year + NYEARIFS) {
  2042. repix++; // One more repetition completed...
  2043. calyear = year; // so reset the clock
  2044. gridcell.date.set(year, 0, 0, 0, 0, 0);
  2045. date = gridcell.date;
  2046. yrix = 0; // Refer to correct array elements above
  2047. }
  2048. }
  2049. if (repix == repetitions) // End of spinup if we've run all repetitions
  2050. spinon = false;
  2051. }
  2052. // Close LAI file
  2053. if (printdlai) {
  2054. fclose(ofp);
  2055. }
  2056. dprintf("LPJ-GUESS ERA20C spinup complete\n");
  2057. gridcell.isspinup = false; // set to false
  2058. return true;
  2059. } // ERA20Cspinup
  2060. ///////////////////////////////////////////////////////////////////////////////////////
  2061. // GUESS_COUPLED
  2062. //
  2063. void guess_coupled(int& id,
  2064. int localrank,
  2065. int numlpjgprocesses,
  2066. int isfinal,
  2067. double lon,
  2068. double lat,
  2069. int ifs_soilcd,
  2070. int ifs_index,
  2071. int ndep_index,
  2072. int year,
  2073. int sim_year,
  2074. int month,
  2075. int monthday,
  2076. int hour,
  2077. double temp,
  2078. double precip,
  2079. double netswrad,
  2080. double netlwrad,
  2081. double co2std,
  2082. double temp_soil,
  2083. double soilw_surf,
  2084. double soilw_deep, // Arg18
  2085. double vegl,
  2086. int vegl_type,
  2087. float& cfluxnattoday,
  2088. float& cfluxanttoday,
  2089. float& npptoday,
  2090. float& laiphen_high,
  2091. float& laiphen_low,
  2092. float& ifsvegfrachigh,
  2093. int& ifsvegtypehigh,
  2094. float& ifsvegfraclow,
  2095. int& ifsvegtypelow,
  2096. bool islpjgspinup,
  2097. int fixedNDepafter,
  2098. int fixedLUafter)
  2099. {
  2100. // ARGUMENTS:
  2101. // id = id from Gridcell object, 0 if initialising
  2102. // is_final = 0: not the last timestep. 1: the final timestep - so save state!
  2103. // ifs_soilcd = soil code used in IFS (1-8)
  2104. // ifs_index = IFS index, i.e. cell 1 to 35718 (T159), or XXXXX (T255)
  2105. // tile = forest or open land
  2106. // year = calender! year (e.g. 1964)
  2107. // sim_year = simulation year (0 to ...)
  2108. // month = month (0-11)
  2109. // dayofmonth = what it says (0-30)
  2110. // hour = hour (0-23)
  2111. // temp = instantaneous temperature 2m above ground (deg C)
  2112. // precip = precip (total mm this time step)
  2113. // netswrad = net downward shortwave radiation (J/m2/s)
  2114. // netlwrad = net longwave radiation (J/m2/s)
  2115. // co2std = ambient CO2 concentration (ppmv)
  2116. // temp_soil = soil temperature (deg C)
  2117. // soilw_surf = m3 m-3 from IFS - will convert below to soil water content AWC (0-1) - surface layer 0-50 cm
  2118. // soilw_deep = m3 m-3 from IFS - will convert below to soil water content AWC (0-1) - deep layer 50-150 cm
  2119. // vegl = fraction of IFS gridcell covered by the low type
  2120. // vegl_type = IFS/H-TESSEL low vegetation type - needed to distinguish crops/agriculture, and tundra
  2121. // cfluxnattoday = natural c clux for the gridcell
  2122. // cfluxanttoday = anthropogenic c flux for the gridcell
  2123. // npptoday = npp for the gridcell
  2124. // laiphen_high = LAI from high vegetation today
  2125. // laiphen_low = LAI from low vegetation today
  2126. // ifsvegfrachigh = fraction of high vegetation in this cell
  2127. // updated after spinup and on Dec 31
  2128. // ifsvegtypehigh = Dominant IFS/H-TESSEL type of high vegetation in this cell
  2129. // Values allowed: 3 (EN), 4 (DN), 5 (DB), 6 (EB), 18 (Mixed forest), 19 (Interrupted forest)
  2130. // updated after spinup on Dec 31, for FOREST/HIGH stands only. 0 for GRASS/LOW stands
  2131. // ifsvegfraclow = fraction of low vegetation in this cell
  2132. // updated after spinup and on Dec 31
  2133. // ifsvegtypelow = Dominant IFS/H-TESSEL type of low vegetation in this cell
  2134. // Values allowed:
  2135. // updated after spinup on Dec 31
  2136. // islpjgspinup = Is this a spinup?
  2137. // fixedNDepafter = year at which N deposition is fixed. Needed for DECK runs. Value -1 if not needed
  2138. // fixedLUafter = year at which land use is fixed. Needed for DECK runs. Value -1 if not needed
  2139. bool initialising=false;
  2140. // Initialise variables to be returned to IFS
  2141. cfluxnattoday=0.0;
  2142. cfluxanttoday=0.0;
  2143. npptoday=0.0;
  2144. laiphen_high=0.0;
  2145. laiphen_low=0.0;
  2146. ifsvegfrachigh=0.0;
  2147. ifsvegtypehigh=0;
  2148. ifsvegfraclow=0.0;
  2149. ifsvegtypelow=0;
  2150. // Set to TRUE if we want debugguing print statements
  2151. bool LPJG_debug = false;
  2152. // Initialise GUESS if not yet done
  2153. if (!ifinit) {
  2154. // Input and output modules
  2155. const char* input_module_name = "ece"; // ecev3 - use new EC-Earth InputModule
  2156. InputModuleRegistry& theinstance = InputModuleRegistry::get_instance();
  2157. input_module_ece = theinstance.create_input_module(input_module_name);
  2158. output_modules_ece = new GuessOutput::OutputModuleContainer();
  2159. GuessOutput::OutputModuleRegistry::get_instance().create_all_modules(*output_modules_ece);
  2160. // Read the instruction file to obtain PFT static parameters and
  2161. // simulation settings
  2162. read_instruction_file("guess.ins");
  2163. print_logfile_heading();
  2164. // Initialise input/output - MUST be before the output module is initialized
  2165. input_module_ece->init();
  2166. // Initialise output
  2167. (*output_modules_ece).init();
  2168. // Initialise LPJ-GUESS
  2169. initguess(localrank);
  2170. // Create objects for (de)serializing grid cells
  2171. if (!islpjgspinup && restart==1) { // Do not restart from file if we're spinning up.
  2172. dprintf("LPJG: deserialization preparation for state path %s and name %s \n", (char*)state_path, (char*)state_name);
  2173. deserializer_ece.reset(create_deserializer(state_path, state_name, year));
  2174. }
  2175. }
  2176. if (LPJG_debug)
  2177. dprintf("LPJG DEBUG 1 - Date is YEAR: %04d, MONTH: %02d, DOY:%03d, HOUR:%02d\n",year,month+1,monthday+1,hour);
  2178. if (!id) {
  2179. // Create new Gridcell object and initialise
  2180. if (LPJG_debug) dprintf("LPJG DEBUG 2 - Date is YEAR: %04d, MONTH: %02d, DOY:%03d, HOUR:%02d\n",year,month+1,monthday+1,hour);
  2181. initialising=true;
  2182. world.push_back(new Gridcell());
  2183. Gridcell& gridcell = *world.back();
  2184. gridcell.id = world.size();
  2185. gridcell.date.init(1);
  2186. gridcell.ifs_index = ifs_index; // Record this gridcell's IFS index - used to get IFS spinup data
  2187. gridcell.ndep_index = ndep_index; // Record this gridcell's N deposition index - used to access N deposition data
  2188. date.init(1); // date.year needs to be zero when landcover_init/getlandcover is called
  2189. // Store id
  2190. id = gridcell.id;
  2191. // Tell framework the coordinates of this grid cell
  2192. gridcell.set_coordinates(lon, lat);
  2193. // The insolation data is sent in as net SW over the whole day, not just daylight hours
  2194. gridcell.climate.instype=NETSWRAD_TS;
  2195. // Tell framework the soil type of this grid cell
  2196. // Set soilcode to the value used by IFS.
  2197. ifssoilparameters(gridcell.soiltype,ifs_soilcd);
  2198. // Initialise dates AFTER call to landcover_init. This ensures that the stands are created.
  2199. // NB - ecev3 - this makes sure that stand.first_year is set in landcover_init!!!
  2200. date.set(year,month,monthday,hour,0,0);
  2201. gridcell.date = date;
  2202. gridcell.set_first_year(date.year); // Now initialise the first year. This ensures that anetps_ff_est_initial is initialised
  2203. // Initialise certain climate and soil drivers
  2204. gridcell.climate.initdrivers(gridcell.get_lat());
  2205. // RESTART from state file?
  2206. if (deserializer_ece.get() && !islpjgspinup) {
  2207. deserializer_ece->deserialize_gridcell(gridcell);
  2208. dprintf("LPJG: Loaded state from file\n");
  2209. if (calc_phen_after_restart) {
  2210. // Update phenology - not saved in earlier versions of the code
  2211. // Now it is saved, so there is no need for this code anymore, but it is kept to
  2212. // ensure for consistency with non-C4MIP CMIP6 runs. Set in guess.ins
  2213. for(unsigned int i = 0; i < gridcell.nbr_stands(); i++) {
  2214. // For each stand ...
  2215. Stand& stand = gridcell[i];
  2216. stand.firstobj();
  2217. while (stand.isobj) {
  2218. // For each patch ...
  2219. Patch& patch = stand.getobj();
  2220. leaf_phenology(patch,gridcell.climate);
  2221. stand.nextobj();
  2222. }
  2223. }
  2224. }
  2225. } else
  2226. dprintf("LPJG: Did not load state from file\n");
  2227. // ecev3 - set a year from which to freeze Land Use Change
  2228. // Moved here, after deserialization because fixedLUafter is serialized.
  2229. //TODO: remove from serialization
  2230. gridcell.fixedLUafter = fixedLUafter;
  2231. int thisyear = date.get_calendar_year();
  2232. if (gridcell.fixedLUafter >= 0 && thisyear >= gridcell.fixedLUafter) {
  2233. gross_land_transfer = 0;
  2234. if (date.day == 0)
  2235. dprintf("Setting gross_land_transfer = 0. fixedLUfter = %d, year = %d \n", gridcell.fixedLUafter, thisyear);
  2236. }
  2237. // Call input module to obtain updated LU driver data for this grid cell.
  2238. if (!input_module_ece->getgridcell(gridcell)) {
  2239. dprintf("LPJG: error in getgridcell !\n");
  2240. return;
  2241. }
  2242. if(run_landcover && islpjgspinup) {
  2243. // ecev3 - moved from above. We should call this when we're spinning up, and on Jan 1 each year
  2244. // Read static landcover and cft fraction data from ins-file and/or from data files for the spinup period and create stands
  2245. // make sure that landcover is initialized with isspinup = true
  2246. gridcell.isspinup = true;
  2247. landcover_init(gridcell, input_module_ece); // ecev3
  2248. }
  2249. // SPINUP?
  2250. if (islpjgspinup) {
  2251. // Always use IFS data to spinup
  2252. bool spinupOK = false;
  2253. if (!ERA20CSPINUP)
  2254. spinupOK = IFSspinup(gridcell, year, co2std, useifssoilmoist, useifssoiltemp);
  2255. else // ERA20C or GSWP3 forcing
  2256. spinupOK = ERA20Cspinup(gridcell, year, co2std, useifssoilmoist, useifssoiltemp);
  2257. if (!spinupOK) {
  2258. dprintf("Error in spinup \n\n\n");
  2259. fail();
  2260. }
  2261. // Save the state so we don't need a spinup next time
  2262. dprintf("Rank %i is saving state after spinup for cell with lon=%f, lat=%f\n", localrank, lon, lat);
  2263. if (!serializer_ece.get()) {
  2264. serializer_ece.reset(create_serializer(state_path, state_name,
  2265. year,
  2266. inst,
  2267. numlpjgprocesses));
  2268. }
  2269. serializer_ece->serialize_gridcell(gridcell);
  2270. // Save the state so we don't need a spinup next time
  2271. dprintf("Rank %i has saved the state after spinup for cell with lon=%f, lat=%f\n", localrank, lon, lat);
  2272. }
  2273. if (LPJG_debug) dprintf("LPJG DEBUG - initialisation OK \n\n\n");
  2274. // End of initialisation
  2275. }
  2276. // No need for return values when spinning up
  2277. if (islpjgspinup) {
  2278. cfluxnattoday=0.0;
  2279. cfluxanttoday=0.0;
  2280. npptoday=0.0;
  2281. laiphen_high=0.0;
  2282. laiphen_low=0.0;
  2283. ifsvegfrachigh=0.0;
  2284. ifsvegtypehigh=0;
  2285. ifsvegfraclow=0.0;
  2286. ifsvegtypelow=0;
  2287. world.clear(); // reduce memory usage during spinup
  2288. return;
  2289. }
  2290. // Retrieve gridcell object
  2291. Gridcell& gridcell = *world[id-1];
  2292. // Reset dates
  2293. date.set(year,month,monthday,hour,0,0);
  2294. gridcell.date = date;
  2295. // Convert from m3 m-3 to AWC [0-1] depending on soil type
  2296. swConvert(gridcell.soiltype,soilw_surf,soilw_deep);
  2297. /// Daily N deposition for current year
  2298. double dndep[Date::MAX_YEAR_LENGTH];
  2299. if (gridcell.date.day == 0) {
  2300. // Jan 1 only
  2301. // We use the following call to instead read conservatively-mapped N deposition data into
  2302. // gridcell.mndrydep[12] and gridcell.mnwetdep[12] in getndepCMIP6.
  2303. // Saves the data in gridcell.mndrydep[12] and gridcell.mnwetdep[12], so only need to call this once per year, per gridcell
  2304. bool Ndepdatafound = gridcell.getndepCMIP6(param["ndep_cmip6_dir"].str, fixedNDepafter);
  2305. if (!Ndepdatafound) {
  2306. dprintf("Rank %i could not read N deposition files for cell with lon=%f, lat=%f\n", localrank, lon, lat);
  2307. fail();
  2308. }
  2309. }
  2310. double drizzle[Date::MAX_YEAR_LENGTH];
  2311. for (int dd=0; dd<Date::MAX_YEAR_LENGTH; dd++) drizzle[dd]=1.0; // Assume 1 mm/day
  2312. // Distribute N deposition, assuming it rains a bit every day
  2313. distribute_ndep(gridcell.mndrydep, gridcell.mnwetdep, drizzle, date.ndaymonth, dndep);
  2314. double dndep_today = dndep[gridcell.date.day]; // NB! "day" is actually month day
  2315. double dnfert = 0.0;
  2316. // Call input module to obtain LU driver data for this grid cell.
  2317. if (gridcell.date.day == 0) {
  2318. if (!input_module_ece->getgridcell(gridcell)) {
  2319. dprintf("LPJG: error in getgridcell !\n");
  2320. return;
  2321. }
  2322. }
  2323. // Transfer today's climate data to the Climate object in Gridcell.
  2324. gridcell.climate.setdrivers(temp, precip, netswrad, netlwrad, co2std,temp_soil,soilw_surf,soilw_deep, dndep_today, dnfert);
  2325. // simulate vegetation today (and assume that Gridcell properties have already been initialised)
  2326. simulate_day_ece(gridcell, useifssoilmoist, useifssoiltemp, false, true);
  2327. // Don't update date. This is driven outside the call to guess_coupled and updated in Reset dates above
  2328. /*
  2329. gridcell.date.next();
  2330. date=gridcell.date;
  2331. */
  2332. // Calculate return values
  2333. // -------------
  2334. // 1. C FLUX TODAY
  2335. // NB! a positive C flux (cfluxtoday or npptoday) implies a net C RELEASE by this gridcell,
  2336. // and a negative value implies a net C UPTAKE
  2337. // Update C flux variable of interest
  2338. unsigned int nrst = gridcell.nbr_stands();
  2339. for(unsigned int i = 0; i < nrst; i++) {
  2340. // For each stand ...
  2341. cfluxnattoday += gridcell[i].dcfluxnat_today * gridcell[i].get_gridcell_fraction();
  2342. cfluxanttoday += gridcell[i].dcfluxant_today * gridcell[i].get_gridcell_fraction();
  2343. npptoday += gridcell[i].dnpp_today * gridcell[i].get_gridcell_fraction();
  2344. }
  2345. // 2. VEGETATION STATE
  2346. // Dominant vegetation type and cover fractions for this grid cell are updated on Dec 31
  2347. // each year, when computeIFSVegetationCover(gridcell) is called from simulate_day_ece() above,
  2348. // just after outannual
  2349. // Now calculate the LAI for high and low fractions
  2350. computeDailyLAIandFPCforIFS(gridcell);
  2351. // Send the vegetation state information back to IFS
  2352. // Values updated daily:
  2353. laiphen_high = gridcell.laiphen_high_today;
  2354. laiphen_low = gridcell.laiphen_low_today;
  2355. ifsvegfrachigh = gridcell.IFSfrachigh;
  2356. ifsvegfraclow = gridcell.IFSfraclow;
  2357. // Values updated on Dec 31:
  2358. ifsvegtypehigh = gridcell.IFStypehigh;
  2359. ifsvegtypelow = gridcell.IFStypelow;
  2360. /*
  2361. if (date.month==11 && date.dayofmonth==30)
  2362. dprintf("Year, number of stands: %04d, %04d\n", date.year, gridcell.nbr_stands());
  2363. */
  2364. // SAVESTATE???
  2365. // -------------
  2366. // Finally, we determine if the state file should be created
  2367. if (isfinal && !initialising) {
  2368. dprintf("Date info for isfinal is: %04d-%02d-%02d, %02d\n",date.year,date.month+1,date.dayofmonth+1);
  2369. // Serialize by increasing the year by 1, i.e. so we can restart on Jan 1 the following year
  2370. if (!serializer_ece.get()) {
  2371. serializer_ece.reset(create_serializer(state_path, state_name, year+1, inst, numlpjgprocesses));
  2372. }
  2373. serializer_ece->serialize_gridcell(gridcell);
  2374. } else {
  2375. // When it's no longer time to save state we'll get rid of the serializer
  2376. // object so that the files get flushed. The next time it's time to
  2377. // save state, we'll create a new serializer object with a new date.
  2378. serializer_ece.reset();
  2379. }
  2380. }
  2381. // cleans up after run has finished
  2382. void guess_coupled_finish()
  2383. {
  2384. delete output_modules_ece;
  2385. }