123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294 |
- ///////////////////////////////////////////////////////////////////////////////////////
- /// \file guess.cpp
- /// \brief LPJ-GUESS Combined Modular Framework
- ///
- /// \author Ben Smith
- /// $Date: 2014-05-13 14:55:59 +0200 (Tue, 13 May 2014) $
- ///
- ///////////////////////////////////////////////////////////////////////////////////////
- #include <sstream>
- #include "config.h"
- #include "guess.h"
- #include <netcdf.h>
- ///////////////////////////////////////////////////////////////////////////////////////
- // GLOBAL VARIABLES WITH EXTERNAL LINKAGE
- // These variables are declared in the framework header file, and defined here.
- // They are accessible throughout the model code.
- Date date; // object describing timing stage of simulation
- int npft; // number of possible PFTs
- int nst; // number of possible stand types
- int nst_lc[NLANDCOVERTYPES]; // number of possible stand types in each land cover type
- int nmt; // number of possible management types
- ManagementTypelist mtlist;
- StandTypelist stlist;
- Pftlist pftlist;
- // emission ratios from fire (NH3, NOx, N2O, N2) Delmas et al. 1995
- const double Fluxes::NH3_FIRERATIO = 0.005;
- const double Fluxes::NOx_FIRERATIO = 0.237;
- const double Fluxes::N2O_FIRERATIO = 0.036;
- const double Fluxes::N2_FIRERATIO = 0.722;
- // IFS related experiment settings for CMIPx
- // Year of
- ////////////////////////////////////////////////////////////////////////////////
- // Implementation of PhotosynthesisResult member functions
- ////////////////////////////////////////////////////////////////////////////////
- /*void PhotosynthesisResult::serialize(ArchiveStream& arch) {
- arch & agd_g
- & adtmm
- & rd_g
- & vm
- & je
- & nactive_opt
- & vmaxnlim;
- }*/
- ////////////////////////////////////////////////////////////////////////////////
- // Implementation of Climate member functions
- ////////////////////////////////////////////////////////////////////////////////
- // ecev3
- void Climate::setdrivers(double ifstemp, double ifsprec, double ifsrad, double ifslw, double tm5co2, double ifstemp_soil, double ifssoilw_surf, double ifssoilw_deep, double dailyndep, double dailynfert) {
- temp=ifstemp;
- prec=ifsprec;
- insol=ifsrad;
- netlw = ifslw;
- co2=tm5co2;
- dndep=dailyndep;
- //dnfert=dailynfert;
- // needed if we're forcing with IFS soil properties:
- ifssoiltemp=ifstemp_soil; // degC
- ifsw_surf=ifssoilw_surf;
- ifsw_deep=ifssoilw_deep;
-
- gridcell.ifs_co2[date.day] = tm5co2;
- gridcell.ifs_par[date.day] = ifsrad;
- gridcell.ifs_lw[date.day] = ifslw;
- gridcell.ifs_precip[date.day] = ifsprec;
- gridcell.ifs_temp2m[date.day] = ifstemp;
- gridcell.ifs_tempsoil[date.day] = ifstemp_soil;
- gridcell.ifs_soilw_surf[date.day] = ifssoilw_surf;
- gridcell.ifs_soilw_deep[date.day] = ifssoilw_deep;
- // ecev3 - bugfix - set DTR to 0 in the BVOC calculation.
- // Will be updated in CRESCENDO
- dtr = 0.0;
- if (date.day == 0) {
- for (int mth = 0; mth < 12; mth++) {
- gridcell.climate.mco2[mth] = 0.0;
- }
- }
- gridcell.climate.mco2[date.month] += tm5co2 / date.ndaymonth[date.month];
- }
- void Climate::serialize(ArchiveStream& arch) {
- arch & temp
- & rad
- & par
- & prec
- & daylength
- & co2
- & lat
- & insol
- & instype
- & eet
- & mtemp
- & mtemp_min20
- & mtemp_max20
- & mtemp_max
- & gdd5
- & agdd5
- & agdd5_5
- & chilldays
- & ifsensechill
- & gtemp
- & dtemp_31
- & dprec_31
- & deet_31
- & mtemp_min_20
- & mtemp_max_20
- & mtemp_min
- & atemp_mean
- & mtemp_K
- & sinelat
- & cosinelat
- & qo & u & v & hh & sinehh
- & daylength_save
- & doneday
- & andep
- & dndep
- & dprec_10
- & sprec_2
- & maxtemp
- & mtemp_20
- & mprec_20
- & mpet_20
- & mprec_pet_20
- & mprec_petmin_20
- & mprec_petmax_20
- & mtemp20
- & mprec20
- & mpet20
- & mprec_pet20
- & mprec_petmin20
- & mprec_petmax20
- & hmtemp_20
- & hmprec_20
- & hmeet_20
- & seasonality
- & seasonality_lastyear
- & prec_seasonality
- & prec_seasonality_lastyear
- & prec_range
- & prec_range_lastyear
- & temp_seasonality
- & temp_seasonality_lastyear
- & var_prec
- & var_temp
- & aprec
- & ifssoiltemp // ecev3
- & ifsw_surf // ecev3
- & ifsw_deep; // ecev3
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Implementation of Fluxes member functions
- ////////////////////////////////////////////////////////////////////////////////
- Fluxes::Fluxes(Patch& p)
- : patch(p),
- annual_fluxes_per_pft(npft, std::vector<float>(NPERPFTFLUXTYPES)) {
- reset();
- }
- void Fluxes::reset() {
- for (size_t i = 0; i < annual_fluxes_per_pft.size(); ++i) {
- std::fill_n(annual_fluxes_per_pft[i].begin(), int(NPERPFTFLUXTYPES), 0);
- }
- for (int m = 0; m < 12; ++m) {
- std::fill_n(monthly_fluxes_pft[m], int(NPERPFTFLUXTYPES), 0);
- std::fill_n(monthly_fluxes_patch[m], int(NPERPATCHFLUXTYPES), 0);
- }
- // ecev3 - sync-r4610 - can be 366
- for (int d = 0; d < date.year_length(); ++d) {
- std::fill_n(daily_fluxes_pft[d], int(NPERPFTFLUXTYPES), 0);
- std::fill_n(daily_fluxes_patch[d], int(NDAILYPERPATCHFLUXTYPES), 0);
- #ifdef CRESCENDO_FACE
- std::fill_n(daily_fluxes_patch_FACE[d], int(NDAILYPERPATCHFACEFLUXTYPE), 0);
- #endif
- }
- }
- void Fluxes::serialize(ArchiveStream& arch) {
- arch & annual_fluxes_per_pft
- /*
- & monthly_fluxes_patch
- & monthly_fluxes_pft
- & daily_fluxes_pft
- & daily_fluxes_patch
- */
- ;
- }
- void Fluxes::report_flux(PerPFTFluxType flux_type, int pft_id, double value) {
- annual_fluxes_per_pft[pft_id][flux_type] += (float)value;
- monthly_fluxes_pft[date.month][flux_type] += (float)value;
- daily_fluxes_pft[date.day][flux_type] += (float)value;
- }
- void Fluxes::report_flux(PerPatchFluxType flux_type, double value) {
- monthly_fluxes_patch[date.month][flux_type] += (float)value;
- }
- void Fluxes::report_flux(DailyPerPatchFluxType flux_type, double value) {
- daily_fluxes_patch[date.day][flux_type] += (float)value;
- }
- #ifdef CRESCENDO_FACE
- void Fluxes::report_flux(DailyPerPatchFACEFluxType flux_type, double value) {
- daily_fluxes_patch_FACE[date.day][flux_type] += (float)value;
- }
- #endif
- double Fluxes::get_monthly_flux(PerPFTFluxType flux_type, int month) const {
- return (double)monthly_fluxes_pft[month][flux_type];
- }
- double Fluxes::get_monthly_flux(PerPatchFluxType flux_type, int month) const {
- return (double)monthly_fluxes_patch[month][flux_type];
- }
- double Fluxes::get_monthly_flux(DailyPerPatchFluxType flux_type, int month) const {
- double sum = 0.0;
- int day = 0;
- for (int m = 0; m < month; m++) {
- day += date.month_length(m);
- }
- for (int d = 0; d < date.month_length(month); d++) {
- sum += (double)daily_fluxes_patch[day][flux_type];
- day++;
- }
- return sum;
- }
- // ecev3
- double Fluxes::get_daily_flux(PerPFTFluxType flux_type, int day) const {
- return (double)daily_fluxes_pft[day][flux_type];
- }
- // ecev3
- double Fluxes::get_daily_flux(DailyPerPatchFluxType flux_type, int day) const {
- return (double)daily_fluxes_patch[day][flux_type];
- }
- #ifdef CRESCENDO_FACE
- // ecev3
- double Fluxes::get_daily_flux(DailyPerPatchFACEFluxType flux_type, int day) const {
- return (double)daily_fluxes_patch_FACE[day][flux_type];
- }
- #endif
- double Fluxes::get_annual_flux(PerPFTFluxType flux_type, int pft_id) const {
- return (double)annual_fluxes_per_pft[pft_id][flux_type];
- }
- double Fluxes::get_annual_flux(PerPFTFluxType flux_type) const {
- double sum = 0;
- for (size_t i = 0; i < annual_fluxes_per_pft.size(); ++i) {
- sum += (double)annual_fluxes_per_pft[i][flux_type];
- }
- /*
- // ecev3 - for debugging. sum and testsum should be identical
- double testsum=0.0;
- if (sum != 0.0) {
- for (int day = 0; day < 366; ++day) {
- testsum += daily_fluxes_pft[day][flux_type];
- }
- }
- */
- return sum;
- }
- double Fluxes::get_annual_flux(PerPatchFluxType flux_type) const {
- double sum = 0;
- for (int m = 0; m < 12; ++m) {
- sum += (double)monthly_fluxes_patch[m][flux_type];
- }
- // ecev3 - for debugging. sum and testsum should be identical
- /*
- double testsum=0.0;
- if (sum != 0.0) {
- for (int day = 0; day < 366; ++day) {
- testsum += daily_fluxes_patch[day][flux_type];
- }
- }
- */
- return sum;
- }
- double Fluxes::get_annual_flux(DailyPerPatchFluxType flux_type) const {
- double sum = 0;
- for (int d = 0; d < date.year_length(); d++) {
- sum += (double)daily_fluxes_patch[d][flux_type];
- }
- return sum;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Implementation of Vegetation member functions
- ////////////////////////////////////////////////////////////////////////////////
- void Vegetation::serialize(ArchiveStream& arch) {
- if (arch.save()) {
- arch & nobj;
- for (unsigned int i = 0; i < nobj; i++) {
- Individual& indiv = (*this)[i];
- arch & indiv.pft.id
- & indiv;
- }
- }
- else {
- killall();
- unsigned int number_of_individuals;
- arch & number_of_individuals;
- for (unsigned int i = 0; i < number_of_individuals; i++) {
- int pft_id;
- arch & pft_id;
- Individual& indiv = createobj(pftlist[pft_id], *this);
- arch & indiv;
- }
- }
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Implementation of LitterSolveSOM member functions
- ////////////////////////////////////////////////////////////////////////////////
- /*void LitterSolveSOM::serialize(ArchiveStream& arch) {
- arch & clitter
- & nlitter;
- }*/
- ////////////////////////////////////////////////////////////////////////////////
- // Implementation of Soil member functions
- ////////////////////////////////////////////////////////////////////////////////
- void Soil::serialize(ArchiveStream& arch) {
- arch & wcont
- //& awcont
- & wcont_evap
- //& dwcontupper
- //& mwcontupper
- & snowpack
- //& runoff
- //& temp
- //& dtemp
- //& mtemp
- //& mtemp_K
- & litter2soilc
- & litter2soiln
- //& gtemp
- & cpool_slow
- & cpool_fast
- & decomp_litter_mean
- & k_soilfast_mean
- & k_soilslow_mean
- & alag
- & exp_alag
- //& mwcont
- //& dwcontlower
- //& mwcontlower
- //& rain_melt
- //& max_rain_melt
- //& percolate
- ;
- for (int i = 0; i<NSOMPOOL; i++) {
- arch & sompool[i];
- }
- arch & dperc
- & orgleachfrac
- & nmass_avail
- & ninput
- //& anmin
- //& animmob
- //& aminleach
- //& aorgNleach
- //& aorgCleach
- //& anfix
- & anfix_calc
- //& anfix_mean
- & snowpack_nmass
- & solvesomcent_beginyr
- & solvesomcent_endyr
- //& solvesom
- & fnuptake_mean
- & morgleach_mean
- & mminleach_mean
- & msnd
- //& mcLitter
- //& mcLitterCwd
- //& mcLitterSurf
- //& mcLitterSubSurf
- //& mcSoil
- //& mnLitter
- //& mnLitterCwd
- //& mnLitterSurf
- //& mnLitterSubSurf
- //& mnSoil
- //& mnMineralNH4
- //& mnMineralNO3
- ;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Implementation of cropphen_struct member functions
- ////////////////////////////////////////////////////////////////////////////////
- void cropphen_struct::serialize(ArchiveStream& arch) {
- arch & sdate
- & sdate_harv
- & sdate_harvest
- & hdate
- & hlimitdate
- & hucountend
- & sendate
- & bicdate
- & eicdate
- & growingdays
- & growingdays_y
- & lgp
- & tb
- & pvd
- & vdsum
- & vrf
- & prf
- & phu
- & phu_old
- & husum
- & husum_max
- & husum_sampled
- & husum_max_10
- & nyears_hu_sample
- & hu_samplingperiod
- & hu_samplingdays
- & fphu
- & fphu_harv
- & hi
- & fhi_harv
- & demandsum_crop
- & supplysum_crop
- & growingseason
- & growingseason_ystd
- & senescence
- & senescence_ystd
- & intercropseason
- & fertilised
- & vdsum_alloc
- & vd
- & dev_stage;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Implementation of Patchpft member functions
- ////////////////////////////////////////////////////////////////////////////////
- void Patchpft::serialize(ArchiveStream& arch) {
- arch & anetps_ff
- & wscal
- & wscal_mean
- & anetps_ff_est
- & anetps_ff_est_initial
- & wscal_mean_est
- & phen
- & aphen
- & establish
- & nsapling
- & litter_leaf
- & litter_root
- & litter_sap
- & litter_heart
- & litter_repr
- & gcbase
- & gcbase_day
- & wsupply
- & wsupply_leafon
- & fwuptake
- & wstress
- & wstress_day
- & harvested_products_slow
- & nmass_litter_leaf
- & nmass_litter_root
- & nmass_litter_sap
- & nmass_litter_heart
- & harvested_products_slow_nmass
- & swindow
- & water_deficit_y;
- if (pft.landcover==CROPLAND)
- arch & *cropphen;
- }
- cropphen_struct* Patchpft::get_cropphen() {
- if (pft.landcover != CROPLAND) {
- fail("Only crop individuals have cropindiv struct. Re-write code !\n");
- }
- return cropphen;
- }
- cropphen_struct* Patchpft::set_cropphen() {
- if (pft.landcover != CROPLAND) {
- fail("Only crop individuals have cropindiv struct. Re-write code !\n");
- }
- return cropphen;
- }
- /// Gets the growingseason status for crop patch pft. Non-crop patch pft:s always return true.
- bool Patchpft::growingseason() const {
- if(cropphen)
- return cropphen->growingseason;
- else
- return true;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Implementation of Patch member functions
- ////////////////////////////////////////////////////////////////////////////////
- Patch::Patch(int i,Stand& s,Soiltype& st):
- id(i),stand(s),vegetation(*this),soil(*this,st),fluxes(*this) {
- for (unsigned int p = 0; p < pftlist.nobj; p++) {
- pft.createobj(pftlist[p]);
- }
- age = 0;
- disturbed = false;
- managed = false;
- man_strength = 0.0;
- managed_this_year = false;
- plant_this_year = false;
- wdemand = 0.0;
- wdemand_leafon = 0.0;
- growingseasondays = 0;
- fireprob = 0.0;
- ndemand = 0.0;
- dnfert = 0.0;
- anfert = 0.0;
- nharv = 0;
- for (int i = 0; i < NYEARAAET; i++)
- aaet_5.add(0.0);
- deforest_active=false;
- }
- void Patch::serialize(ArchiveStream& arch) {
- if (arch.save()) {
- for (unsigned int i = 0; i < pft.nobj; i++) {
- arch & pft[i];
- }
- }
- else {
- pft.killall();
- for (unsigned int i = 0; i < pftlist.nobj; i++) {
- pft.createobj(pftlist[i]);
- arch & pft[i];
- }
- }
- arch & vegetation
- & soil
- & fluxes
- //& fpar_grass
- //& fpar_ff
- //& par_grass_mean
- //& nday_growingseason
- //& fpc_total
- & disturbed
- & managed
- & age
- //& fireprob
- //& growingseasondays
- //& intercep
- //& aaet
- & aaet_5
- //& aevap
- //& aintercep
- //& arunoff
- //& apet
- //& eet_net_veg
- & wdemand
- //& wdemand_day
- //& wdemand_leafon
- //& fpc_rescale
- //& maet
- //& mevap
- //& mintercep
- //& mrunoff
- //& mrunoff_surf
- //& mpet
- //& ndemand
- //& irrigation_d
- //& irrigation_y
- //& mcVeg
- //& mnVeg
- //& mcLeaf
- //& mnLeaf
- //& mcRoot
- //& mnRoot
- //& mcStem
- //& mnStem
- //& mcOther
- //& mnOther
- //& mcProduct
- //& mnProduct
- //& mcLand
- //& mnLand
- & deforest_active;
- }
- const Climate& Patch::get_climate() const {
- // All patches within a stand share the same climate
- return stand.get_climate();
- }
- bool Patch::has_fires() const {
- return iffire
- && stand.landcover != CROPLAND
- && stand.landcover != URBAN // ecev3
- && stand.landcover != PEATLAND // ecev3
- && !managed
- && (stand.landcover != PASTURE || disturb_pasture);
- }
- bool Patch::has_disturbances() const {
- return ifdisturb && stand.landcover != CROPLAND && !managed &&
- (stand.landcover != PASTURE || disturb_pasture);
- }
- /// C content of patch
- /**
- * INPUT PARAMETERS
- *
- * \param scale_indiv scaling factor for living C
- * \param luc down-scales living C (used in C balance tests)
- */
- double Patch::ccont(double scale_indiv, bool luc) {
- double ccont = 0.0;
- ccont += soil.cpool_fast;
- ccont += soil.cpool_slow;
- for (int i=0; i<NSOMPOOL-1; i++) {
- ccont += soil.sompool[i].cmass;
- }
- for (int i=0; i<npft; i++) {
- Patchpft& ppft = pft[i];
- ccont += ppft.litter_leaf;
- ccont += ppft.litter_root;
- ccont += ppft.litter_sap;
- ccont += ppft.litter_heart;
- ccont += ppft.litter_repr;
- ccont += ppft.harvested_products_slow;
- }
- for (unsigned int i=0; i<vegetation.nobj; i++) {
- Individual& indiv = vegetation[i];
- ccont += indiv.ccont(scale_indiv, luc);
- }
- return ccont;
- }
- /// N content of patch
- /**
- * INPUT PARAMETERS
- *
- * \param scale_indiv scaling factor for living N
- * \param luc down-scales living N (used in N balance tests)
- */
- double Patch::ncont(double scale_indiv, bool luc) {
- double ncont = 0.0;
- ncont += soil.nmass_avail;
- ncont += soil.snowpack_nmass;
- for (int i=0; i<NSOMPOOL-1; i++)
- ncont += soil.sompool[i].nmass;
- for (int i=0; i<npft; i++) {
- Patchpft& ppft = pft[i];
- ncont += ppft.nmass_litter_leaf;
- ncont += ppft.nmass_litter_root;
- ncont += ppft.nmass_litter_sap;
- ncont += ppft.nmass_litter_heart;
- ncont += ppft.harvested_products_slow_nmass;
- }
- for (unsigned int i=0; i<vegetation.nobj; i++) {
- Individual& indiv = vegetation[i];
- ncont += indiv.ncont(scale_indiv, luc);
- }
- return ncont;
- }
- /// C flux of patch
- double Patch::cflux() {
- double cflux = 0.0;
- cflux += soil.aorgCleach;
- cflux += -fluxes.get_annual_flux(Fluxes::NPP);
- cflux += fluxes.get_annual_flux(Fluxes::REPRC);
- cflux += fluxes.get_annual_flux(Fluxes::SOILC);
- cflux += fluxes.get_annual_flux(Fluxes::FIREC);
- cflux += fluxes.get_annual_flux(Fluxes::ESTC);
- cflux += fluxes.get_annual_flux(Fluxes::SEEDC);
- cflux += fluxes.get_annual_flux(Fluxes::HARVESTC);
- cflux += fluxes.get_annual_flux(Fluxes::DEBEXCC);
- return cflux;
- }
- /// N flux of patch
- double Patch::nflux() {
- double nflux = 0.0;
- nflux += -stand.get_climate().andep;
- nflux += -anfert;
- nflux += -soil.anfix;
- nflux += soil.aminleach;
- nflux += soil.aorgNleach;
- nflux += fluxes.get_annual_flux(Fluxes::HARVESTN);
- nflux += fluxes.get_annual_flux(Fluxes::SEEDN);
- nflux += fluxes.get_annual_flux(Fluxes::NH3_FIRE);
- nflux += fluxes.get_annual_flux(Fluxes::NOx_FIRE);
- nflux += fluxes.get_annual_flux(Fluxes::N2O_FIRE);
- nflux += fluxes.get_annual_flux(Fluxes::N2_FIRE);
- nflux += fluxes.get_annual_flux(Fluxes::N_SOIL);
- return nflux;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Implementation of Standpft member functions
- ////////////////////////////////////////////////////////////////////////////////
- void Standpft::serialize(ArchiveStream& arch) {
- arch & cmass_repr
- & anetps_ff_max
- & fpc_total
- & active
- & plant
- & reestab
- & irrigated;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Implementation of Stand member functions
- ////////////////////////////////////////////////////////////////////////////////
- Stand::Stand(int i, Gridcell* gc, Soiltype& st, landcovertype landcoverX, int npatch)
- : id(i),
- gridcell(gc),
- soiltype(st),
- landcover(landcoverX),
- origin(landcoverX),
- frac(1.0),
- //typehigh(0), // ecev3
- //frachigh(0.0), // ecev3
- previousyearsCfluxNat(0.0), // ecev3
- previousyearsCfluxAnt(0.0) { // ecev3
- // Constructor: initialises reference member of climate and
- // builds list array of Standpft objects
- if (landcover >= NLANDCOVERTYPES) {
- fail("Unrecognized landcover type %i of NLANDCOVERTYPES=%i \n",landcover,NLANDCOVERTYPES);
- }
- for (unsigned int p=0;p<pftlist.nobj;p++) {
- pft.createobj(pftlist[p]);
- }
- unsigned int num_patches = 1;
- if (landcover == FOREST || landcover == NATURAL || (disturb_pasture && landcover == PASTURE)) {
- // stands with stochastic events
- if (npatch > 0) {
- num_patches = npatch; // use patch number provided by calling funciton
- }
- else {
- num_patches = ::npatch; // use the global variable npatch
- }
- }
- for (unsigned int p=0;p<num_patches;p++) {
- createobj(*this, soiltype);
- }
- first_year = date.year;
- clone_year = -1;
- transfer_area_st = new double[nst];
- for(int i=0;i<nst;i++)
- transfer_area_st[i] = 0.0;
- seed = 12345678;
- stid = 0;
- pftid = -1;
- current_rot = 0;
- ndays_inrotation = 0;
- infallow = false;
- isrotationday = false;
- isirrigated = false;
- hasgrassintercrop = false;
- gdd0_intercrop = 0.0;
- frac = 1.0;
- frac_old = 0.0;
- frac_temp = 0.0;
- protected_frac = 0.0;
- frac_change = 0.0;
- gross_frac_increase = 0.0;
- gross_frac_decrease = 0.0;
- cloned_fraction = 0.0;
- cloned = false;
- anpp = 0.0;
- cmass = 0.0;
- scale_LC_change = 1.0;
- // ecev3 - initialise
- dcfluxnat_today = 0.0;
- dcfluxant_today = 0.0;
- dnpp_today = 0.0;
- previousyearsCfluxNat = 0.0;
- previousyearsCfluxAnt = 0.0;
- cLand = 0.0;
- cFlux = 0.0;
- /*
- for (int dd=0; dd<366; dd++) {
- //laiphen_grass[dd]=0.0;
- //laiphen_total[dd]=0.0;
- dcflux[dd]=0.0;
- }
- */
- }
- Stand::~Stand() {
- if (transfer_area_st) {
- delete[] transfer_area_st;
- }
- }
- double Stand::get_gridcell_fraction() const {
- return frac;
- }
- /// Initiation of stand variables when run_landcover==true
- /**
- * Rules for which PFT:s are allowed to establish are set in the instruction file by the parameters landcover
- * (allows all active PFT:s with the same landcovertype), naturalveg (allows none, natural grass or all natural pft:s)
- * and intercrop ("naturalgrass" allows dedicated covercrop grass pft:s).
- * If restrictpfts is true, further restriction of pft:s are specified in the management settings.
- * Rules for reestablishment (after sowing or planting) are set by the parameter reestab, "none", "restricted" - only planted pft:s
- */
- void Stand::init_stand_lu(StandType& st, double fraction) {
- landcovertype lc = st.landcover;
- landcover = lc;
- stid = st.id;
- set_gridcell_fraction(fraction);
- frac_old = 0.0;
- frac_change = fraction;
- gross_frac_increase = fraction;
- bool naturalveg = st.naturalveg == "ALL";
- bool naturalgrass = st.naturalveg == "ALL" || st.naturalveg == "GRASSONLY";
- pftlist.firstobj();
- while (pftlist.isobj) {
- Pft& pftx = pftlist.getobj();
- if(!st.restrictpfts && pftx.landcover == lc
- || !st.restrictpfts && naturalveg && pftx.landcover == NATURAL // Allow all natural pft:s to grow in e.g. forests
- || naturalgrass && pftx.landcover == NATURAL && pftx.lifeform == GRASS // Allow natural grass pft:s to grow in e.g. forests
- || pftx.landcover == lc && lc == FOREST && pftx.lifeform == GRASS) { // Always allow forest grass pft:s to grow in forests
- pft[pftx.id].active = true;
- pft[pftx.id].reestab = true;
- // If restrictpfts = false, plant all tree pft:s after clearcut
- if(pftx.lifeform == TREE)
- pft[pftx.id].plant = true;
- }
- else {
- pft[pftx.id].active = false;
- }
- pftlist.nextobj();
- }
- if(date.get_calendar_year() >= st.firstmanageyear) {
- for(unsigned int i=0;i<npatch();i++)
- (*this)[i].managed = true;
- }
- ManagementType& mt0 = st.get_management(0);
- pftid = pftlist.getpftid(mt0.pftname); // First main crop, will change during crop rotation
- current_rot = 0;
- if (mt0.hydrology == IRRIGATED) {
- isirrigated = true; // First main crop, may change during crop rotation
- if (pftid >= 0)
- pft[pftid].irrigated = true;
- }
- if (st.intercrop==NATURALGRASS && ifintercropgrass) {
- hasgrassintercrop = true;
- for (unsigned int i=0; i<pftlist.nobj; i++) {
- if (pftlist[i].isintercropgrass)
- pft[pftlist[i].id].active = true;
- }
- }
- if(pftid > -1) {
- if (!readNfert)
- gridcell->pft[pftid].Nfert_read = mt0.nfert;
- if (!readsowingdates)
- pft[pftid].sdate_force = mt0.sdate;
- if (!readharvestdates)
- pft[pftid].hdate_force = mt0.hdate;
- }
-
- if(!readNfert_st)
- gridcell->st[st.id].nfert = mt0.nfert;
- if(!st.restrictpfts)
- return;
- // Set standpft- and patchpft-variables for active crops
- for (int rot=0; rot<st.rotation.ncrops; rot++) {
- ManagementType& mt = st.get_management(rot);
- if(mt.planting_system == "MONOCULTURE") {
- int id = pftlist.getpftid(mt.pftname);
- if (id >=0) {
- if(lc == CROPLAND) {
- pft[id].active = true;
- if (rot == 0) {
- // Set crop cycle dates to default values only for first crop in a rotation.
- for (unsigned int p = 0; p < nobj; p++) {
- Gridcellpft& gcpft = get_gridcell().pft[id];
- Patchpft& ppft = (*this)[p].pft[id];
- ppft.set_cropphen()->sdate = gcpft.sdate_default;
- ppft.set_cropphen()->hlimitdate = gcpft.hlimitdate_default;
- if (pftlist[id].phenology == ANY)
- ppft.set_cropphen()->growingseason = true;
- else if (pftlist[id].phenology == CROPGREEN) {
- ppft.set_cropphen()->eicdate = Date::stepfromdate(ppft.get_cropphen()->sdate, -15);
- }
- }
- }
- }
- else if(rot == 0) {
- // Only first tree rotation implemented; pft[id].active etc. has to be set anew in stand.crop_rotation()
- pft[id].active = true;
- pft[id].plant = true;
- if(st.reestab == "RESTRICTED") {
- pft[id].reestab = true;
- }
- else if(st.reestab == "ALL") {
- pftlist.firstobj();
- while (pftlist.isobj) {
- Pft& pftx = pftlist.getobj();
- // Options here are only relevant when planted trees (FOREST) and regenerated growth (FOREST and/or NATURAL) needs to be distinguished in the output
- // 1. reestablishment by both forest and natural pfts
- // if(pftx.landcover == lc || st.naturalveg == "ALL" && pftx.landcover == NATURAL) {
- // 2. reestablishment by natural pfts (when active) and planted forest pfts
- // if(pftx.landcover == lc && (st.naturalveg != "ALL" || pft[pftx.id].plant) || st.naturalveg == "ALL" && pftx.landcover == NATURAL) {
- // 3. reestablishment only by natural pfts (when active)
- if(pftx.landcover == lc && st.naturalveg != "ALL" || st.naturalveg == "ALL" && pftx.landcover == NATURAL) {
- pft[pftx.id].active = true;
- pft[pftx.id].reestab = true;
- }
- pftlist.nextobj();
- }
- }
- }
- }
- else if(!mt.fallow) {
- dprintf("Warning: stand type %d pft %s not in pftlist !\n", stid, (char*)mt.pftname);;
- break;
- }
- }
- else if(mt.planting_system == "SELECTION") {
- if(mt.selection != "") {
- pftlist.firstobj();
- while (pftlist.isobj) {
- Pft& pftx = pftlist.getobj();
- if(mt.pftinselection((const char*)pftx.name)) {
- pft[pftx.id].active = true;
- pft[pftx.id].reestab = true;
- if(pftx.lifeform == TREE)
- pft[pftx.id].plant = true;
- }
- else if(pftx.lifeform == TREE) { // Whether grass is allowed is specified in the generic code above
- pft[pftx.id].active = false;
- }
- pftlist.nextobj();
- }
- }
- else {
- dprintf("Warning: stand type %d planting selection not defined !\n", stid);;
- break;
- }
- }
- else if(mt.planting_system != "") {
- // planting systems (pft selections) defined here
- }
- }
- }
- void Stand::rotate() {
- if (pftid >= 0 && stid >= 0) {
- ndays_inrotation = 0;
- int pftid_old = pftid;
- current_rot = (current_rot + 1) % stlist[stid].rotation.ncrops;
- ManagementType& mt = stlist[stid].get_management(current_rot);
- pftid = pftlist.getpftid(mt.pftname);
- // If fallow, use old pftid !
- if(mt.fallow)
- pftid = pftid_old;
- Standpft& standpft = pft[pftid];
- if (mt.hydrology == IRRIGATED) {
- isirrigated = true;
- standpft.irrigated = true;
- }
- else {
- isirrigated = false;
- standpft.irrigated = false;
- }
- if (!readNfert)
- gridcell->pft[pftid].Nfert_read = mt.nfert;
- if (!readsowingdates)
- standpft.sdate_force = mt.sdate;
- if (!readharvestdates)
- standpft.hdate_force = mt.hdate;
- if(!readNfert_st)
- gridcell->st[stid].nfert = mt.nfert;
- }
- }
- double Stand::transfer_area_lc(landcovertype to) {
- double area = 0.0;
- if (transfer_area_st) {
- for (int j=0; j<nst; j++) {
- if (stlist[j].landcover == to)
- area += transfer_area_st[j];
- }
- }
- return area;
- }
- double Stand::ccont(double scale_indiv) {
- double ccont = 0.0;
- for (unsigned int p = 0; p < nobj; p++)
- ccont += (*this)[p].ccont(scale_indiv) / nobj;
- return ccont;
- }
- double Stand::ncont(double scale_indiv) {
- double ncont = 0.0;
- for (unsigned int p = 0; p < nobj; p++)
- ncont += (*this)[p].ncont(scale_indiv) / nobj;
- return ncont;
- }
- double Stand::cflux() {
- double cflux = 0.0;
- for (unsigned int p = 0; p < nobj; p++)
- cflux += (*this)[p].cflux() / nobj;
- return cflux;
- }
- double Stand::nflux() {
- double nflux = 0.0;
- for (unsigned int p = 0; p < nobj; p++)
- nflux += (*this)[p].nflux() / nobj;
- return nflux;
- }
- Stand& Stand::clone(StandType& st, double fraction) {
- // Serialize this stand to an in-memory stream
- std::stringstream ss;
- ArchiveOutStream aos(ss);
- serialize(aos);
- // Create a new stand in the gridcell...
- // NB: the patch number is always that of the old stand, even if the new stand is a pasture or crop stand
- Stand& new_stand = gridcell->create_stand(st.landcover, nobj);
- int new_seed = new_stand.seed;
- // ...and deserialize to that stand
- ArchiveInStream ais(ss);
- new_stand.serialize(ais);
- new_stand.clone_year = date.year;
- // new_stand.seed = new_seed; // ?
- // Set land use settings for new stand
- new_stand.init_stand_lu(st, fraction);
- for (unsigned int p = 0; p < nobj; p++) {
- // new_stand[p].age = 0; // probably not what we want
- new_stand[p].managed = false; // or use value of mother stand ?
- }
- return new_stand;
- }
- double Stand::get_landcover_fraction() const {
- if (get_gridcell().landcover.frac[landcover])
- return frac / get_gridcell().landcover.frac[landcover];
- else
- return 0.0;
- }
- void Stand::set_gridcell_fraction(double fraction) {
- frac = fraction;
- }
- void Stand::serialize(ArchiveStream& arch) {
- if (arch.save()) {
- for (unsigned int i = 0; i < pft.nobj; i++) {
- arch & pft[i];
- }
- arch & nobj;
- for (unsigned int k = 0; k < nobj; k++) {
- arch & (*this)[k];
- }
- }
- else {
- pft.killall();
- for (unsigned int i = 0; i < pftlist.nobj; i++) {
- Standpft& standpft = pft.createobj(pftlist[i]);
- arch & standpft;
- }
- killall();
- unsigned int npatch;
- arch & npatch;
- for (unsigned int k = 0; k < npatch; k++) {
- Patch& patch = createobj(*this, soiltype);
- arch & patch;
- }
- }
- arch & first_year
- & clone_year
- & frac
- & stid
- & pftid
- & current_rot
- & ndays_inrotation
- & infallow
- & isirrigated
- & hasgrassintercrop
- & gdd0_intercrop
- & cloned
- & origin
- & landcover
- & seed
- // ecev3 - serialize these new member variables
- //& typehigh
- //& frachigh
- //& laiphen_grass
- //& laiphen_total
- // dcfluxnat_today and dnpp not needed since updated daily, but we have to keep them for compat.
- & dcfluxnat_today // unused
- & previousyearsCfluxAnt // replaces dnpp_today
- & previousyearsCfluxNat;
- }
- const Climate& Stand::get_climate() const {
- // In this implementation all stands within a grid cell
- // share the same climate. Note that this might not be
- // true in all versions of LPJ-GUESS, some may have
- // different climate per landcover type for instance.
- return get_gridcell().climate;
- }
- Gridcell& Stand::get_gridcell() const {
- assert(gridcell);
- return *gridcell;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Implementation of cropindiv_struct member functions
- ////////////////////////////////////////////////////////////////////////////////
- void cropindiv_struct::serialize(ArchiveStream& arch) {
- arch & grs_cmass_plant
- & grs_cmass_leaf
- & grs_cmass_root
- & grs_cmass_ho
- & grs_cmass_agpool
- & grs_cmass_dead_leaf
- & grs_cmass_stem
- & cmass_leaf_sen
- & nmass_ho
- & nmass_agpool
- & nmass_dead_leaf
- & isintercropgrass;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Implementation of Individual member functions
- ////////////////////////////////////////////////////////////////////////////////
- Individual::Individual(int i,Pft& p,Vegetation& v):pft(p),vegetation(v),id(i) {
- anpp = 0.0;
- fpc = 0.0;
- fpc_daily = 0.0;
- densindiv = 0.0;
- cmass_leaf = 0.0;
- cmass_root = 0.0;
- cmass_sap = 0.0;
- cmass_heart = 0.0;
- cmass_debt = 0.0;
- cmass_leaf_post_turnover = 0.0;
- cmass_root_post_turnover = 0.0;
- cmass_tot_luc = 0.0;
- phen = 0.0;
- aphen = 0.0;
- deltafpc = 0.0;
- nmass_leaf = 0.0;
- nmass_root = 0.0;
- nmass_sap = 0.0;
- nmass_heart = 0.0;
- cton_leaf_aopt = 0.0;
- cton_leaf_aavr = 0.0;
- cton_status = 0.0;
- cmass_veg = 0.0;
- nmass_veg = 0.0;
- nmass_tot_luc = 0.0;
- nactive = 0.0;
- nextin = 1.0;
- nstore_longterm = 0.0;
- nstore_labile = 0.0;
- ndemand = 0.0;
- fnuptake = 1.0;
- anuptake = 0.0;
- max_n_storage = 0.0;
- scale_n_storage = 0.0;
- leafndemand = 0.0;
- rootndemand = 0.0;
- sapndemand = 0.0;
- storendemand = 0.0;
- leaffndemand = 0.0;
- rootfndemand = 0.0;
- sapfndemand = 0.0;
- storefndemand = 0.0;
- leafndemand_store = 0.0;
- rootndemand_store = 0.0;
- nstress = false;
- // additional initialisation
- age = 0.0;
- fpar = 0.0;
- aphen_raingreen = 0;
- intercep = 0.0;
- phen_mean = 0.0;
- wstress = false;
- lai = 0.0;
- lai_layer = 0.0;
- lai_indiv = 0.0;
- lai_daily = 0.0;
- lai_indiv_daily = 0.0;
- alive = false;
- int m;
- for (m=0; m<12; m++) {
- mlai[m] = 0.0;
- mlai_max[m] = 0.0;
- mfpc[m] = 0.0;
- mfpar[m] = 0.0;
- mlambda_gpp[m] = 0.0;
- mgpp[m] = 0.0;
- }
- // bvoc
- iso = 0.;
- fvocseas = 1.;
- for (int im=0; im<NMTCOMPOUNDS; im++){
- mon[im] = 0.;
- monstor[im] = 0.;
- }
- dnpp = 0.0;
- cropindiv = NULL;
- last_turnover_day = -1;
- Stand& stand = vegetation.patch.stand;
- if (pft.landcover==CROPLAND) {
- cropindiv=new cropindiv_struct;
- if (stand.pftid == pft.id) {
- cropindiv->isprimarycrop = true;
- }
- else if (stand.hasgrassintercrop && pft.isintercropgrass) { // grass cover crop growth
- cropindiv->isintercropgrass = true;
- }
- }
- // dprintf("Year %d: Individual in stand %d created:id=%d, pft=%s\n", ::date.year-nyear_spinup+1901,vegetation.patch.stand.id,id,(char*)pft.name);
- }
- void Individual::serialize(ArchiveStream& arch) {
- arch & cmass_leaf
- & cmass_root
- & cmass_sap
- & cmass_heart
- & cmass_debt
- & cmass_leaf_post_turnover
- & cmass_root_post_turnover
- & last_turnover_day
- & fpc
- & fpc_daily
- & fpar
- & densindiv
- & phen
- //& aphen
- //& aphen_raingreen
- //& anpp
- & aet
- //& aaet
- //& ltor
- & height
- & crownarea
- //& deltafpc
- & boleht
- & lai
- & lai_layer
- & lai_indiv
- & lai_daily
- & lai_indiv_daily
- & greff_5
- & age
- //& mlai
- //& mfpc
- //& fpar_leafon
- //& lai_leafon_layer
- //& intercep
- //& phen_mean
- //& wstress
- & alive
- //& iso
- //& mon
- & monstor
- & fvocseas
- & nmass_leaf
- & nmass_root
- & nmass_sap
- & nmass_heart
- //& nactive
- //& nextin
- & nstore_longterm
- & nstore_labile
- //& ndemand
- //& fnuptake
- //& anuptake
- & max_n_storage
- & scale_n_storage
- //& avmaxnlim
- //& cton_leaf_aopt
- //& cton_leaf_aavr
- //& cton_status
- //& cmass_veg // - should be a function returning this value instead of having a variable saving it...
- //& nmass_veg // - should be a function returning this value instead of having a variable saving it...
- //& photosynthesis
- //& nstress
- //& leafndemand
- //& rootndemand
- //& sapndemand
- //& storendemand
- //& leaffndemand
- //& rootfndemand
- //& sapfndemand
- //& storefndemand
- //& leafndemand_store
- //& rootndemand_store
- //& nday_leafon
- ;
- if (pft.landcover==CROPLAND)
- arch & *cropindiv;
- }
- Individual::~Individual() {
- if (cropindiv)
- delete cropindiv;
- }
- /// Access functions for cropindiv
- cropindiv_struct* Individual::get_cropindiv() const {
- if (pft.landcover != CROPLAND) {
- fail("Only crop individuals have cropindiv struct. Re-write code !\n");
- }
- return cropindiv;
- }
- cropindiv_struct* Individual::set_cropindiv() {
- if (pft.landcover != CROPLAND) {
- fail("Only crop individuals have cropindiv struct. Re-write code !\n");
- }
- return cropindiv;
- }
- void Individual::report_flux(Fluxes::PerPFTFluxType flux_type, double value) {
- if (alive || istruecrop_or_intercropgrass()) {
- vegetation.patch.fluxes.report_flux(flux_type, pft.id, value);
- }
- }
- void Individual::report_flux(Fluxes::PerPatchFluxType flux_type, double value) {
- if (alive || istruecrop_or_intercropgrass()) {
- vegetation.patch.fluxes.report_flux(flux_type, value);
- }
- }
- void Individual::report_flux(Fluxes::DailyPerPatchFluxType flux_type, double value) {
- if (alive || istruecrop_or_intercropgrass()) {
- vegetation.patch.fluxes.report_flux(flux_type, value);
- }
- }
- #ifdef CRESCENDO_FACE
- void Individual::report_flux(Fluxes::DailyPerPatchFACEFluxType flux_type, double value) {
- if (alive || istruecrop_or_intercropgrass()) {
- vegetation.patch.fluxes.report_flux(flux_type, value);
- }
- }
- #endif
- /// Help function for reduce_biomass(), partitions nstore into leafs and roots
- /**
- * As leaf and roots can have a very low N concentration after growth and allocation,
- * N in nstore() is split between them to saticfy relationship between their average C:N ratios
- */
- void nstore_adjust(double& cmass_leaf,double& cmass_root, double& nmass_leaf, double& nmass_root,
- double nstore, double cton_leaf, double cton_root) {
- // (1) cmass_leaf / ((nmass_leaf + leaf_ndemand) * cton_leaf) = cmass_root / ((nmass_root + root_ndemand) * cton_root)
- // (2) leaf_ndemand + root_ndemand = nstore
- // (1) + (2) leaf_ndemand = (cmass_leaf * ratio (nmass_root + nstore) - cmass_root * nmass_leaf) / (cmass_root + cmass_leaf * ratio)
- //
- // where ratio = cton_root / cton_leaf
- double ratio = cton_root / cton_leaf;
- double leaf_ndemand = 0.0;
- double root_ndemand = 0.0;
- if (!negligible((cmass_root + cmass_leaf * ratio))) {
- leaf_ndemand = (cmass_leaf * ratio * (nmass_root + nstore) - cmass_root * nmass_leaf) / (cmass_root + cmass_leaf * ratio);
- root_ndemand = nstore - leaf_ndemand;
- }
- nmass_leaf += leaf_ndemand;
- nmass_root += root_ndemand;
- }
- void Individual::reduce_biomass(double mortality, double mortality_fire) {
- // This function needs to be modified if a new lifeform is added,
- // specifically to deal with nstore().
- assert(pft.lifeform == TREE || pft.lifeform == GRASS);
- if (!negligible(mortality)) {
- const double mortality_non_fire = mortality - mortality_fire;
- // Transfer killed biomass to litter
- // (above-ground biomass killed by fire enters atmosphere, not litter)
- Patchpft& ppft = patchpft();
- double cmass_leaf_litter = mortality * cmass_leaf;
- double cmass_root_litter = mortality * cmass_root;
- if (pft.landcover==CROPLAND) {
- if (pft.aboveground_ho)
- cmass_leaf_litter += mortality * cropindiv->cmass_ho;
- else
- cmass_root_litter += mortality * cropindiv->cmass_ho;
- cmass_leaf_litter += mortality * cropindiv->cmass_agpool;
- }
- ppft.litter_leaf += cmass_leaf_litter * mortality_non_fire / mortality;
- ppft.litter_root += cmass_root_litter;
- if (cmass_debt <= cmass_heart + cmass_sap) {
- if (cmass_debt <= cmass_heart) {
- ppft.litter_sap += mortality_non_fire * cmass_sap;
- ppft.litter_heart += mortality_non_fire * (cmass_heart - cmass_debt);
- }
- else {
- ppft.litter_sap += mortality_non_fire * (cmass_sap + cmass_heart - cmass_debt);
- }
- }
- else {
- double debt_excess = mortality_non_fire * (cmass_debt - (cmass_sap + cmass_heart));
- report_flux(Fluxes::DEBEXCC, debt_excess);
- report_flux(Fluxes::RA, -debt_excess);
- }
- double nmass_leaf_litter = mortality * nmass_leaf;
- double nmass_root_litter = mortality * nmass_root;
- if (pft.landcover==CROPLAND) {
- if (pft.aboveground_ho)
- nmass_leaf_litter += mortality * cropindiv->nmass_ho;
- else
- nmass_root_litter += mortality * cropindiv->nmass_ho;
- nmass_leaf_litter += mortality * cropindiv->nmass_agpool;
- }
- // stored N is partioned out to leaf and root biomass as new tissue after growth might have extremely low
- // N content (to get closer to relationship between compartment averages (cton_leaf, cton_root, cton_sap))
- nstore_adjust(cmass_leaf_litter, cmass_root_litter, nmass_leaf_litter, nmass_root_litter,
- mortality * nstore(), pft.cton_leaf_avr,pft.cton_root_avr);
- ppft.nmass_litter_leaf += nmass_leaf_litter * mortality_non_fire / mortality;
- ppft.nmass_litter_root += nmass_root_litter;
- ppft.nmass_litter_sap += mortality_non_fire * nmass_sap;
- ppft.nmass_litter_heart += mortality_non_fire * nmass_heart;
- // Flux to atmosphere from burnt above-ground biomass
- double cflux_fire = mortality_fire * (cmass_leaf_litter / mortality + cmass_wood());
- double nflux_fire = mortality_fire * (nmass_leaf_litter / mortality + nmass_wood());
- report_flux(Fluxes::FIREC, cflux_fire);
- report_flux(Fluxes::FIREVEGC, cflux_fire);
- report_flux(Fluxes::NH3_FIRE, Fluxes::NH3_FIRERATIO * nflux_fire);
- report_flux(Fluxes::NOx_FIRE, Fluxes::NOx_FIRERATIO * nflux_fire);
- report_flux(Fluxes::N2O_FIRE, Fluxes::N2O_FIRERATIO * nflux_fire);
- report_flux(Fluxes::N2_FIRE, Fluxes::N2_FIRERATIO * nflux_fire);
- // Reduce this Individual's biomass values
- const double remaining = 1.0 - mortality;
- if (pft.lifeform != GRASS) {
- densindiv *= remaining;
- }
- cmass_leaf *= remaining;
- cmass_root *= remaining;
- cmass_sap *= remaining;
- cmass_heart *= remaining;
- cmass_debt *= remaining;
- if (pft.landcover==CROPLAND) {
- cropindiv->cmass_ho *= remaining;
- cropindiv->cmass_agpool *= remaining;
- }
- nmass_leaf *= remaining;
- nmass_root *= remaining;
- nmass_sap *= remaining;
- nmass_heart *= remaining;
- nstore_longterm *= remaining;
- nstore_labile *= remaining;
- if (pft.landcover==CROPLAND) {
- cropindiv->nmass_ho *= remaining;
- cropindiv->nmass_agpool *= remaining;
- }
- }
- }
- double Individual::cton_leaf(bool use_phen /* = true*/) const {
- Stand& stand = vegetation.patch.stand;
- if (stand.is_true_crop_stand() && !negligible(cmass_leaf_today()) && !negligible(nmass_leaf)) {
- return cmass_leaf_today() / nmass_leaf;
- }
- else if (!stand.is_true_crop_stand() && !negligible(cmass_leaf) && !negligible(nmass_leaf)) {
- if (use_phen) {
- if (!negligible(phen)) {
- return cmass_leaf_today() / nmass_leaf;
- }
- else {
- return pft.cton_leaf_avr;
- }
- }
- else {
- return cmass_leaf / nmass_leaf;
- }
- }
- else {
- return pft.cton_leaf_max;
- }
- }
- double Individual::cton_root(bool use_phen /* = true*/) const {
- if (!negligible(cmass_root) && !negligible(nmass_root)) {
- if (use_phen) {
- if (!negligible(cmass_root_today())) {
- return cmass_root_today() / nmass_root;
- }
- else {
- return pft.cton_root_avr;
- }
- }
- else {
- return cmass_root / nmass_root;
- }
- }
- else {
- return pft.cton_root_max;
- }
- }
- double Individual::cton_sap() const {
- if (pft.lifeform == TREE) {
- if (!negligible(cmass_sap) && !negligible(nmass_sap))
- return cmass_sap / nmass_sap;
- else
- return pft.cton_sap_max;
- }
- else {
- return 1.0;
- }
- }
- /// C content of individual
- /**
- * INPUT PARAMETERS
- *
- * \param scale_indiv scaling factor for living C
- * \param luc down-scales living C (used in C balance tests)
- */
- double Individual::ccont(double scale_indiv, bool luc) const {
- double ccont = 0.0;
- if (alive || istruecrop_or_intercropgrass()) {
- if (has_daily_turnover()) { // Not taking into account future daily wood allocation/turnover
- if (cropindiv) {
- if (luc) {
- ccont += cropindiv->grs_cmass_leaf - cropindiv->grs_cmass_leaf_luc * (1.0 - scale_indiv);
- ccont += cropindiv->grs_cmass_root - cropindiv->grs_cmass_root_luc * (1.0 - scale_indiv);
- }
- else {
- ccont += cropindiv->grs_cmass_leaf * scale_indiv;
- ccont += cropindiv->grs_cmass_root * scale_indiv;
- }
- if (pft.phenology == CROPGREEN) {
- if (luc) {
- ccont += cropindiv->grs_cmass_ho - cropindiv->grs_cmass_ho_luc * (1.0 - scale_indiv);
- ccont += cropindiv->grs_cmass_agpool - cropindiv->grs_cmass_agpool_luc * (1.0 - scale_indiv);
- ccont += cropindiv->grs_cmass_dead_leaf - cropindiv->grs_cmass_dead_leaf_luc * (1.0 - scale_indiv);
- ccont += cropindiv->grs_cmass_stem - cropindiv->grs_cmass_stem_luc * (1.0 - scale_indiv);
- }
- else {
- ccont += cropindiv->grs_cmass_ho * scale_indiv;
- ccont += cropindiv->grs_cmass_agpool * scale_indiv;
- ccont += cropindiv->grs_cmass_dead_leaf * scale_indiv;
- ccont += cropindiv->grs_cmass_stem * scale_indiv;
- }
- }
- }
- }
- else {
- ccont = cmass_leaf + cmass_root + cmass_sap + cmass_heart - cmass_debt;
- if (pft.landcover == CROPLAND) {
- ccont += cropindiv->cmass_ho + cropindiv->cmass_agpool;
- // Yearly allocation not defined for crops with nlim
- }
- ccont *= scale_indiv;
- }
- }
- return ccont;
- }
- /// N content of individual
- /**
- * INPUT PARAMETERS
- *
- * \param scale_indiv scaling factor for living N
- * \param luc down-scales living N (used in C balance tests)
- */
- double Individual::ncont(double scale_indiv, bool luc) const {
- double ncont = 0.0;
- if (luc) {
- ncont += nmass_leaf - nmass_leaf_luc * (1.0 - scale_indiv);
- ncont += nmass_root - nmass_root_luc * (1.0 - scale_indiv);
- ncont += nmass_sap - nmass_sap_luc * (1.0 - scale_indiv);
- ncont += nmass_heart - nmass_heart_luc * (1.0 - scale_indiv);
- ncont += nstore_longterm - nstore_longterm_luc * (1.0 - scale_indiv);
- ncont += nstore_labile - nstore_labile_luc * (1.0 - scale_indiv);
- }
- else {
- ncont += nmass_leaf * scale_indiv;
- ncont += nmass_root * scale_indiv;
- ncont += nmass_sap * scale_indiv;
- ncont += nmass_heart * scale_indiv;
- ncont += nstore_longterm * scale_indiv;
- ncont += nstore_labile * scale_indiv;
- }
- if (pft.landcover == CROPLAND) {
- if (luc) {
- ncont += cropindiv->nmass_ho - cropindiv->nmass_ho_luc * (1.0 - scale_indiv);
- ncont += cropindiv->nmass_agpool - cropindiv->nmass_agpool_luc * (1.0 - scale_indiv);
- ncont += cropindiv->nmass_dead_leaf - cropindiv->nmass_dead_leaf_luc * (1.0 - scale_indiv);
- }
- else {
- ncont += cropindiv->nmass_ho * scale_indiv;
- ncont += cropindiv->nmass_agpool * scale_indiv;
- ncont += cropindiv->nmass_dead_leaf * scale_indiv;
- }
- }
- return ncont;
- }
- /// Leaf C content of individual
- /**
- * INPUT PARAMETERS
- *
- * \param scale_indiv scaling factor for living C
- * \param luc down-scales living C (used in C balance tests)
- */
- double Individual::cleafcont(double scale_indiv, bool luc) const {
- double cleafcont = 0.0;
- if (alive || istruecrop_or_intercropgrass()) {
- if (has_daily_turnover()) { // Not taking into account future daily wood allocation/turnover
- if (cropindiv) {
- if (luc) {
- cleafcont += cropindiv->grs_cmass_leaf - cropindiv->grs_cmass_leaf_luc * (1.0 - scale_indiv);
- }
- else {
- cleafcont += cropindiv->grs_cmass_leaf * scale_indiv;
- }
- }
- if (pft.phenology == CROPGREEN) {
- if (luc) {
- cleafcont += cropindiv->grs_cmass_dead_leaf - cropindiv->grs_cmass_dead_leaf_luc * (1.0 - scale_indiv);
- }
- else {
- cleafcont += cropindiv->grs_cmass_dead_leaf * scale_indiv;
- }
- }
- }
- else {
- cleafcont = cmass_leaf * scale_indiv;
- }
- }
- return cleafcont;
- }
- ///Leaf N content of individual
- /**
- * INPUT PARAMETERS
- *
- * \param scale_indiv scaling factor for living N
- * \param luc down-scales living N (used in C balance tests)
- */
- double Individual::nleafcont(double scale_indiv, bool luc) const {
- double nleafcont = 0.0;
- if (luc)
- nleafcont += nmass_leaf - nmass_leaf_luc * (1.0 - scale_indiv);
- else
- nleafcont += nmass_leaf * scale_indiv;
- if (pft.landcover == CROPLAND) {
- if (luc) {
- nleafcont += cropindiv->nmass_dead_leaf - cropindiv->nmass_dead_leaf_luc * (1.0 - scale_indiv);
- }
- else {
- nleafcont += cropindiv->nmass_dead_leaf * scale_indiv;
- }
- }
- return nleafcont;
- }
- /// Root C content of individual
- /**
- * INPUT PARAMETERS
- *
- * \param scale_indiv scaling factor for living C
- * \param luc down-scales living C (used in C balance tests)
- */
- double Individual::crootcont(double scale_indiv, bool luc) const {
- double crootcont = 0.0;
- if (alive || istruecrop_or_intercropgrass()) {
- if (has_daily_turnover()) { // Not taking into account future daily wood allocation/turnover
- if (cropindiv) {
- if (luc) {
- crootcont += cropindiv->grs_cmass_root - cropindiv->grs_cmass_root_luc * (1.0 - scale_indiv);
- }
- else {
- crootcont += cropindiv->grs_cmass_root * scale_indiv;
- }
- }
- }
- else {
- crootcont = cmass_root * scale_indiv;
- }
- }
- return crootcont;
- }
- /// Root N content of individual
- /**
- * INPUT PARAMETERS
- *
- * \param scale_indiv scaling factor for living N
- * \param luc down-scales living N (used in C balance tests)
- */
- double Individual::nrootcont(double scale_indiv, bool luc) const {
- double nrootcont = 0.0;
- if (luc) {
- nrootcont += nmass_root - nmass_root_luc * (1.0 - scale_indiv);
- }
- else {
- nrootcont += nmass_root * scale_indiv;
- }
- if (pft.lifeform != TREE) {
- if (luc) {
- nrootcont += nstore_longterm - nstore_longterm_luc * (1.0 - scale_indiv);
- nrootcont += nstore_labile - nstore_labile_luc * (1.0 - scale_indiv);
- }
- else {
- nrootcont += nstore_longterm * scale_indiv;
- nrootcont += nstore_labile * scale_indiv;
- }
- }
- return nrootcont;
- }
- /// Whether grass growth is uninterrupted by crop growth.
- bool Individual::continous_grass() const {
- if (pft.landcover != CROPLAND) {
- return false;
- }
- Stand& stand = vegetation.patch.stand;
- StandType& st = stlist[stand.stid];
- bool sowing_restriction = true;
- for (int i=0; i<st.rotation.ncrops; i++) {
- int pftid = pftlist.getpftid(st.get_management(i).pftname);
- if (pftid > -1 && !stand.get_gridcell().pft[pftid].sowing_restriction) {
- sowing_restriction = false;
- }
- }
- return cropindiv->isintercropgrass && sowing_restriction;
- }
- double Individual::ndemand_storage(double cton_leaf_opt) {
- if (vegetation.patch.stand.is_true_crop_stand() && ifnlim) // only CROPGREEN, only ifnlim ?
- // analogous with root demand
- storendemand = max(0.0, cropindiv->grs_cmass_stem / (cton_leaf_opt * pft.cton_stem_avr / pft.cton_leaf_avr) - cropindiv->nmass_agpool);
- else
- storendemand = max(0.0, min(anpp * scale_n_storage / cton_leaf(), max_n_storage) - nstore());
- return storendemand;
- }
- /// Checks C mass and zeroes any negative value, balancing by adding to npp and reducing respiration
- double Individual::check_C_mass() {
- if (pft.landcover != CROPLAND)
- return 0;
- double negative_cmass = 0.0;
- if (cropindiv->grs_cmass_leaf < 0.0) {
- negative_cmass -= cropindiv->grs_cmass_leaf;
- cropindiv->ycmass_leaf -= cropindiv->grs_cmass_leaf;
- cropindiv->grs_cmass_plant -= cropindiv->grs_cmass_leaf;
- cropindiv->grs_cmass_leaf = 0.0;
- }
- if (cropindiv->grs_cmass_root < 0.0) {
- negative_cmass -= cropindiv->grs_cmass_root;
- cropindiv->ycmass_root -= cropindiv->grs_cmass_root;
- cropindiv->grs_cmass_plant -= cropindiv->grs_cmass_root;
- cropindiv->grs_cmass_root = 0.0;
- }
- if (cropindiv->grs_cmass_ho < 0.0) {
- negative_cmass -= cropindiv->grs_cmass_ho;
- cropindiv->ycmass_ho -= cropindiv->grs_cmass_ho;
- cropindiv->grs_cmass_plant -= cropindiv->grs_cmass_ho;
- cropindiv->grs_cmass_ho = 0.0;
- }
- if (cropindiv->grs_cmass_agpool < 0.0) {
- negative_cmass -= cropindiv->grs_cmass_agpool;
- cropindiv->ycmass_agpool -= cropindiv->grs_cmass_agpool;
- cropindiv->grs_cmass_plant -= cropindiv->grs_cmass_agpool;
- cropindiv->grs_cmass_agpool = 0.0;
- }
- if (cropindiv->grs_cmass_dead_leaf < 0.0) {
- negative_cmass -= cropindiv->grs_cmass_dead_leaf;
- cropindiv->ycmass_dead_leaf -= cropindiv->grs_cmass_dead_leaf;
- cropindiv->grs_cmass_plant -= cropindiv->grs_cmass_dead_leaf;
- cropindiv->grs_cmass_dead_leaf = 0.0;
- }
- if (cropindiv->grs_cmass_stem < 0.0) {
- negative_cmass -= cropindiv->grs_cmass_stem;
- cropindiv->ycmass_stem -= cropindiv->grs_cmass_stem;
- cropindiv->grs_cmass_plant -= cropindiv->grs_cmass_stem;
- cropindiv->grs_cmass_stem = 0.0;
- }
- if (largerthanzero(negative_cmass, -14)) {
- anpp += negative_cmass;
- report_flux(Fluxes::DEBEXCC, negative_cmass);
- report_flux(Fluxes::RA, -negative_cmass);
- }
- return negative_cmass;
- }
- /// Checks N mass and zeroes any negative value, balancing by reducing N mass of other organs and (if needed) reducing anflux_landuse_change
- double Individual::check_N_mass() {
- // ecev3 - added URBAN and PEATLAND to avoid minor, but exceedlingly rare bugs in coupled runs
- if (pft.landcover != CROPLAND && pft.landcover != PASTURE && pft.landcover != URBAN && pft.landcover != PEATLAND)
- return 0;
- double negative_nmass = 0.0;
- if (nmass_leaf < 0.0) {
- negative_nmass -= nmass_leaf;
- if (cropindiv)
- cropindiv->ynmass_leaf -= nmass_leaf;
- nmass_leaf = 0.0;
- }
- if (nmass_root < 0.0) {
- negative_nmass -= nmass_root;
- if (cropindiv)
- cropindiv->ynmass_root -= nmass_root;
- nmass_root = 0.0;
- }
- if (cropindiv) {
- if (cropindiv->nmass_ho < 0.0) {
- negative_nmass -= cropindiv->nmass_ho;
- cropindiv->ynmass_ho -= cropindiv->nmass_ho;
- cropindiv->nmass_ho = 0.0;
- }
- if (cropindiv->nmass_agpool < 0.0) {
- negative_nmass -= cropindiv->nmass_agpool;
- cropindiv->ynmass_agpool -= cropindiv->nmass_agpool;
- cropindiv->nmass_agpool = 0.0;
- }
- if (cropindiv->nmass_dead_leaf < 0.0) {
- negative_nmass -= cropindiv->nmass_dead_leaf;
- cropindiv->ynmass_dead_leaf -= cropindiv->nmass_dead_leaf;
- cropindiv->nmass_dead_leaf = 0.0;
- }
- }
- if (nstore_labile < 0.0) {
- negative_nmass -= nstore_labile;
- nstore_labile = 0.0;
- }
- if (nstore_longterm < 0.0) {
- negative_nmass -= nstore_longterm;
- nstore_longterm = 0.0;
- }
- if (largerthanzero(negative_nmass, -14)) {
- double pos_nmass = ncont();
- if (pos_nmass > negative_nmass) {
- nmass_leaf -= negative_nmass * nmass_leaf / pos_nmass;
- nmass_root -= negative_nmass * nmass_root / pos_nmass;
- if (cropindiv) {
- cropindiv->nmass_ho -= negative_nmass * cropindiv->nmass_ho / pos_nmass;
- cropindiv->nmass_agpool -= negative_nmass * cropindiv->nmass_agpool / pos_nmass;
- cropindiv->nmass_dead_leaf -= negative_nmass * cropindiv->nmass_dead_leaf / pos_nmass;
- }
- }
- else {
- vegetation.patch.stand.get_gridcell().landcover.anflux_landuse_change -= (negative_nmass - pos_nmass) * vegetation.patch.stand.get_gridcell_fraction();
- nmass_leaf = 0.0;
- nmass_leaf = 0.0;
- if (cropindiv) {
- cropindiv->nmass_ho = 0.0;
- cropindiv->nmass_agpool = 0.0;
- cropindiv->nmass_dead_leaf = 0.0;
- }
- }
- }
- return negative_nmass;
- }
- /// Whether resetting of grs_cmass and turnover (if has_daily_turnover() returns true) of continuous grass is to be done this day.
- bool Individual::is_turnover_day() const {
- if (patchpft().cropphen && patchpft().cropphen->growingseason) {
- const Climate& climate = vegetation.patch.get_climate();
- return date.day == climate.testday_prec;
- }
- else {
- return false;
- }
- }
- Patchpft& Individual::patchpft() const {
- return vegetation.patch.pft[pft.id];
- }
- /// Save cmass-values on first day of the year of land cover change in expanding stands
- void Individual::save_cmass_luc() {
- cmass_tot_luc = 0.0;
- if (cropindiv) {
- cropindiv->grs_cmass_leaf_luc = cropindiv->grs_cmass_leaf;
- cropindiv->grs_cmass_root_luc = cropindiv->grs_cmass_root;
- cropindiv->grs_cmass_ho_luc = cropindiv->grs_cmass_ho;
- cropindiv->grs_cmass_agpool_luc = cropindiv->grs_cmass_agpool;
- cropindiv->grs_cmass_dead_leaf_luc = cropindiv->grs_cmass_dead_leaf;
- cropindiv->grs_cmass_stem_luc = cropindiv->grs_cmass_stem;
- }
- cmass_tot_luc = ccont();
- }
- /// Save nmass-values on first day of the year of land cover change in expanding stands
- void Individual::save_nmass_luc() {
- nmass_leaf_luc = nmass_leaf;
- nmass_root_luc = nmass_root;
- nmass_sap_luc = nmass_sap;
- nmass_heart_luc = nmass_heart;
- nstore_longterm_luc = nstore_longterm;
- nstore_labile_luc = nstore_labile;
- if (cropindiv) {
- cropindiv->nmass_ho_luc = cropindiv->nmass_ho;
- cropindiv->nmass_agpool_luc = cropindiv->nmass_agpool;
- cropindiv->nmass_dead_leaf_luc = cropindiv->nmass_dead_leaf;
- }
- nmass_tot_luc = ncont();
- }
- /// Gets the individual's daily cmass_leaf value
- double Individual::cmass_leaf_today() const {
- if (istruecrop_or_intercropgrass())
- return patchpft().cropphen->growingseason ? cropindiv->grs_cmass_leaf : 0;
- else
- return cmass_leaf * phen;
- }
- /// Gets the individual's daily cmass_root value
- double Individual::cmass_root_today() const {
- if (istruecrop_or_intercropgrass())
- return patchpft().cropphen->growingseason ? cropindiv->grs_cmass_root : 0;
- else
- return cmass_root * phen;
- }
- /// Gets the individual's daily fpc value
- double Individual::fpc_today() const {
- if (pft.phenology == CROPGREEN)
- return patchpft().cropphen->growingseason ? fpc_daily : 0;
- else
- return fpc * phen;
- }
- /// Gets the individual's daily lai value
- double Individual::lai_today() const {
- if (pft.phenology == CROPGREEN)
- return patchpft().cropphen->growingseason ? lai_daily : 0;
- else
- return lai * phen;
- }
- /// Gets the individual's daily lai_indiv value
- double Individual::lai_indiv_today() const {
- if (pft.phenology == CROPGREEN)
- return patchpft().cropphen->growingseason ? lai_indiv_daily : 0;
- else
- return lai_indiv * phen;
- }
- /// Gets the Nitrigen limited LAI
- double Individual::lai_nitrogen_today() const{
- if (pft.phenology==CROPGREEN) {
- double Ln = 0.0;
- if (patchpft().cropphen->growingseason && cmass_leaf_today() > 0.0) {
- const double k = 0.5;
- const double ktn = 0.52*k + 0.01; // Yin et al 2003
- double nb = 1/(pft.cton_leaf_max*pft.sla);
- Ln = (1/ktn) * log(1+ktn*nmass_leaf/nb);
- }
- return Ln;
- }
- else {
- return 1.0;
- }
- }
- /// Gets the growingseason status for crop individual. Non-crop individuals always return true.
- bool Individual::growingseason() const {
- return patchpft().cropphen ? patchpft().cropphen->growingseason : true;
- }
- /// Whether harvest and turnover is done on actual C and N on harvest or turnover day, which can occur any day of the year.
- bool Individual::has_daily_turnover() const {
- return istruecrop_or_intercropgrass();
- }
- /// Help function for kill(), partitions wood biomass into litter and harvest
- /**
- * Wood biomass (either C or N) is partitioned into litter pools and
- * harvest, according to PFT specific harvest fractions.
- *
- * Biomass is sent in as sap and heart, any debt should already have been
- * subtracted from these before calling this function.
- *
- * \param mass_sap Sapwood
- * \param mass_heart Heartwood
- * \param harv_eff Harvest efficiency (fraction of biomass harvested)
- * \param harvest_slow_frac Fraction of harvested products that goes into slow depository
- * \param res_outtake Fraction of residue outtake at harvest
- * \param litter_sap Biomass going to sapwood litter pool
- * \param litter_heart Biomass going to heartwood litter pool
- * \param fast_harvest Biomass going to harvest flux
- * \param slow_harvest Biomass going to slow depository
- */
- void partition_wood_biomass(double mass_sap, double mass_heart,
- double harv_eff, double harvest_slow_frac, double res_outtake,
- double& litter_sap, double& litter_heart,
- double& fast_harvest, double& slow_harvest) {
- double sap_left = mass_sap;
- double heart_left = mass_heart;
- // Remove harvest
- double total_wood_harvest = harv_eff * (sap_left + heart_left);
- sap_left *= 1 - harv_eff;
- heart_left *= 1 - harv_eff;
- // Partition wood harvest into slow and fast
- slow_harvest = total_wood_harvest * harvest_slow_frac;
- fast_harvest = total_wood_harvest * (1 - harvest_slow_frac);
- // Remove residue outtake
- fast_harvest += res_outtake * (sap_left + heart_left);
- sap_left *= 1 - res_outtake;
- heart_left *= 1 - res_outtake;
- // The rest goes to litter
- litter_sap = sap_left;
- litter_heart = heart_left;
- }
- void Individual::kill(bool harvest /* = false */) {
- Patchpft& ppft = patchpft();
- double charvest_flux = 0.0;
- double charvested_products_slow = 0.0;
- double nharvest_flux = 0.0;
- double nharvested_products_slow = 0.0;
- double harv_eff = 0.0;
- double harvest_slow_frac = 0.0;
- double res_outtake = 0.0;
- // The function always deals with harvest, but the harvest
- // fractions are zero when there is no harvest.
- if (harvest) {
- harv_eff = pft.harv_eff;
- if (ifslowharvestpool) {
- harvest_slow_frac = pft.harvest_slow_frac;
- }
- res_outtake = pft.res_outtake;
- }
- // C doesn't return to litter/harvest if the Individual isn't alive
- if (alive || istruecrop_or_intercropgrass()) {
- // For leaf and root, catches small, negative values too
- // Leaf: remove residue outtake and send the rest to litter
- if (has_daily_turnover() && cropindiv) {
- if (pft.lifeform == GRASS && pft.phenology != CROPGREEN) {
- charvest_flux += cropindiv->grs_cmass_leaf * harv_eff;
- cropindiv->grs_cmass_leaf *= (1 - harv_eff);
- }
- ppft.litter_leaf += cropindiv->grs_cmass_leaf * (1 - res_outtake);
- charvest_flux += cropindiv->grs_cmass_leaf * res_outtake;
- }
- else {
- if (pft.lifeform == GRASS && pft.phenology != CROPGREEN) {
- charvest_flux += cmass_leaf * harv_eff;
- cmass_leaf *= (1 - harv_eff);
- }
- ppft.litter_leaf += cmass_leaf * (1 - res_outtake);
- charvest_flux += cmass_leaf * res_outtake;
- }
- // Root: all goes to litter
- if (has_daily_turnover() && cropindiv)
- ppft.litter_root += cropindiv->grs_cmass_root;
- else
- ppft.litter_root += cmass_root;
- if (pft.landcover == CROPLAND) {
- if (has_daily_turnover()) {
- charvest_flux += cropindiv->grs_cmass_ho * harv_eff;
- cropindiv->grs_cmass_ho *= (1 - harv_eff);
- if (pft.aboveground_ho) {
- ppft.litter_leaf+=cropindiv->grs_cmass_ho * (1 - res_outtake);
- charvest_flux += cropindiv->grs_cmass_ho * res_outtake;
- }
- else {
- ppft.litter_root+=cropindiv->grs_cmass_ho;
- }
- ppft.litter_leaf+=cropindiv->grs_cmass_agpool * (1 - res_outtake);
- charvest_flux += cropindiv->grs_cmass_agpool * res_outtake;
- ppft.litter_leaf+=cropindiv->grs_cmass_dead_leaf * (1 - res_outtake);
- charvest_flux += cropindiv->grs_cmass_dead_leaf * res_outtake;
- ppft.litter_leaf+=cropindiv->grs_cmass_stem * (1 - res_outtake);
- charvest_flux += cropindiv->grs_cmass_stem * res_outtake;
- }
- else {
- charvest_flux += cropindiv->cmass_ho * harv_eff;
- cropindiv->cmass_ho *= (1 - harv_eff);
- if (pft.aboveground_ho) {
- ppft.litter_leaf+=cropindiv->cmass_ho * (1 - res_outtake);
- charvest_flux += cropindiv->cmass_ho * res_outtake;
- }
- else {
- ppft.litter_root+=cropindiv->cmass_ho;
- }
- ppft.litter_leaf+=cropindiv->cmass_agpool * (1 - res_outtake);
- charvest_flux += cropindiv->cmass_agpool * res_outtake;
- }
- }
- // Deal with the wood biomass and carbon debt for trees
- if (pft.lifeform == TREE) {
- // debt smaller than existing wood biomass
- if (cmass_debt <= cmass_sap + cmass_heart) {
- // before partitioning the biomass into litter and harvest,
- // first get rid of the debt so we're left with only
- // sap and heart
- double to_partition_sap = 0.0;
- double to_partition_heart = 0.0;
- if (cmass_heart >= cmass_debt) {
- to_partition_sap = cmass_sap;
- to_partition_heart = cmass_heart - cmass_debt;
- }
- else {
- to_partition_sap = cmass_sap + cmass_heart - cmass_debt;
- }
- double clitter_sap, clitter_heart, cwood_harvest;
- partition_wood_biomass(to_partition_sap, to_partition_heart,
- harv_eff, harvest_slow_frac, res_outtake,
- clitter_sap, clitter_heart,
- cwood_harvest, charvested_products_slow);
- ppft.litter_sap += clitter_sap;
- ppft.litter_heart += clitter_heart;
- charvest_flux += cwood_harvest;
- }
- // debt larger than existing wood biomass
- else {
- double debt_excess = cmass_debt - (cmass_sap + cmass_heart);
- report_flux(Fluxes::DEBEXCC, debt_excess);
- report_flux(Fluxes::RA, -debt_excess);
- }
- }
- }
- // Nitrogen always return to soil litter
- if (pft.lifeform == TREE) {
- double nlitter_sap, nlitter_heart, nwood_harvest;
- // Transfer nitrogen storage to sapwood nitrogen litter/harvest
- partition_wood_biomass(nmass_sap + nstore(), nmass_heart,
- harv_eff, harvest_slow_frac, res_outtake,
- nlitter_sap, nlitter_heart,
- nwood_harvest, nharvested_products_slow);
- ppft.nmass_litter_sap += nlitter_sap;
- ppft.nmass_litter_heart += nlitter_heart;
- nharvest_flux += nwood_harvest;
- }
- else {
- // Transfer nitrogen storage to root nitrogen litter
- ppft.nmass_litter_root += nstore();
- }
- // Leaf: remove residue outtake and send the rest to litter
- ppft.nmass_litter_leaf += nmass_leaf * (1 - res_outtake);
- nharvest_flux += nmass_leaf * res_outtake;
- // Root: all goes to litter
- ppft.nmass_litter_root += nmass_root;
- if (pft.landcover == CROPLAND) {
- if (pft.aboveground_ho) {
- ppft.nmass_litter_leaf+=cropindiv->nmass_ho * (1 - res_outtake);
- nharvest_flux += cropindiv->nmass_ho * res_outtake;
- }
- else
- ppft.litter_root+=cropindiv->nmass_ho;
- ppft.nmass_litter_leaf+=cropindiv->nmass_agpool * (1 - res_outtake);
- nharvest_flux += cropindiv->nmass_agpool * res_outtake;
- ppft.nmass_litter_leaf += cropindiv->nmass_dead_leaf * (1 - res_outtake);
- nharvest_flux += cropindiv->nmass_dead_leaf * res_outtake;
- }
- // Report harvest fluxes
- report_flux(Fluxes::HARVESTC, charvest_flux);
- report_flux(Fluxes::HARVESTN, nharvest_flux);
- // Add to biomass depositories for long-lived products
- ppft.harvested_products_slow += charvested_products_slow;
- ppft.harvested_products_slow_nmass += nharvested_products_slow;
- }
- double Individual::wscal_mean() const {
- return patchpft().wscal_mean;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Implementation of Gridcellpft member functions
- ////////////////////////////////////////////////////////////////////////////////
- void Gridcellpft::serialize(ArchiveStream& arch) {
- arch & addtw
- & Km
- & autumnoccurred
- & springoccurred
- & vernstartoccurred
- & vernendoccurred
- & first_autumndate
- & first_autumndate20
- & first_autumndate_20
- & last_springdate
- & last_springdate20
- & last_springdate_20
- & last_verndate
- & last_verndate20
- & last_verndate_20
- & sdate_default
- & sdatecalc_temp
- & sdatecalc_prec
- & sdate_force
- & hdate_force
- & Nfert_read
- & hlimitdate_default
- & wintertype
- & swindow
- & swindow_irr
- & sowing_restriction;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Implementation of Gridcellst member functions
- ////////////////////////////////////////////////////////////////////////////////
- void Gridcellst::serialize(ArchiveStream& arch) {
- arch & frac
- & frac_old_orig
- & nstands
- & nfert;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Implementation of Landcover member functions
- ////////////////////////////////////////////////////////////////////////////////
- Landcover::Landcover() {
- updated = false;
- // ecev3 - no need to serialize these
- dcflux_harvest_slow = 0.0;
- dcflux_landuse_change = 0.0;
- acflux_harvest_slow = 0.0;
- harvest_product = 0.0;
- harvest_product_nmass = 0.0;
- acflux_harvest_wood_res = 0.0;
- acflux_landuse_change = 0.0;
- anflux_harvest_slow = 0.0;
- anflux_landuse_change = 0.0;
- for (int i=0; i<NLANDCOVERTYPES; i++) {
- frac[i] = 0.0;
- frac_old[i] = 0.0;
- frac_change[i] = 0.0;
- acflux_harvest_slow_lc[i] = 0.0;
- harvest_product_lc[i] = 0.0;
- harvest_product_nmass_lc[i] = 0.0;
- acflux_harvest_wood_res_lc[i] = 0.0;
- acflux_landuse_change_lc[i] = 0.0;
- anflux_harvest_slow_lc[i] = 0.0;
- anflux_landuse_change_lc[i] = 0.0;
- for(int j=0;j<NLANDCOVERTYPES;j++) {
- frac_transfer[i][j] = 0.0;
- }
- expand_to_new_stand[i] = (i == NATURAL || i == FOREST);
- pool_to_all_landcovers[i] = false; // from a donor landcover; alt.c
- pool_from_all_landcovers[i] = false; // to a receptor landcover; alt.a
- }
- }
- void Landcover::serialize(ArchiveStream& arch) {
- arch & frac;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Implementation of Gridcell member functions
- ////////////////////////////////////////////////////////////////////////////////
- Gridcell::Gridcell():climate(*this) {
- for (unsigned int p=0; p<pftlist.nobj; p++) {
- pft.createobj(pftlist[p]);
- }
- for (unsigned int s=0; s<stlist.nobj; s++) {
- st.createobj(stlist[s]);
- }
- if (!run_landcover) {
- create_stand(NATURAL);
- landcover.frac[NATURAL] = 1.0;
- }
- seed = 12345678;
- // ecev3
- IFStypehigh = 0; // 0 to 20
- IFSfrachigh = 0.0; // 0 to 1
- IFStypelow = 0; // 0 to 20
- IFSfraclow = 0.0; // 0 to 1
- simulationyear = 0;
- isspinup = false;
- ndep_lon_index = -999; // for CMIP6 N dep. data
- ndep_lat_index = -999; // for CMIP6 N dep. data
- // ecev3
- laiphen_high_today = 0.0;
- laiphen_low_today = 0.0;
- for(int ii=0;ii<NLANDCOVERTYPES;ii++) {
- landcover_fpc[ii]=0.0;
- landcover_lai[ii]=0.0;
- }
- naturaltreeFPC = 0.0;
- naturalgrassFPC = 0.0;
- transferhightolow = false;
- // Year from which on Land Use is frozen
- fixedLUafter = -1; // -1 means unfrozen, dynamic LU.
- }
- double Gridcell::get_lon() const {
- return lon;
- }
- double Gridcell::get_lat() const {
- return lat;
- }
- void Gridcell::set_coordinates(double longitude, double latitude) {
- lon = longitude;
- lat = latitude;
- }
- Stand& Gridcell::create_stand_lu(StandType& st, double fraction, int no_patch) {
- Stand& stand = create_stand(st.landcover, no_patch);
- stand.init_stand_lu(st, fraction);
- return stand;
- }
- double Gridcell::ccont() {
- double ccont = 0.0;
- for (unsigned int s = 0; s < nbr_stands(); s++) {
- Stand& stand = (*this)[s];
- ccont += stand.ccont() * stand.get_gridcell_fraction();
- }
- return ccont;
- }
- double Gridcell::ncont() {
- double ncont = 0.0;
- for (unsigned int s = 0; s < nbr_stands(); s++) {
- Stand& stand = (*this)[s];
- ncont += stand.ncont() * stand.get_gridcell_fraction();
- }
- return ncont;
- }
- double Gridcell::cflux() {
- double cflux = 0.0;
- for (unsigned int s = 0; s < nbr_stands(); s++) {
- Stand& stand = (*this)[s];
- cflux += stand.cflux() * stand.get_gridcell_fraction();
- }
- cflux += landcover.acflux_landuse_change;
- cflux += landcover.acflux_harvest_slow;
- return cflux;
- }
- // ecev3
- void Gridcell::set_first_year(int fy) {
- for (unsigned int s = 0; s < nbr_stands(); s++) {
- Stand& stand = (*this)[s];
- stand.first_year=fy;
- }
- }
- double Gridcell::nflux() {
- double nflux = 0.0;
- for (unsigned int s = 0; s < nbr_stands(); s++) {
- Stand& stand = (*this)[s];
- nflux += stand.nflux() * stand.get_gridcell_fraction();
- }
- nflux += landcover.anflux_landuse_change;
- nflux += landcover.anflux_harvest_slow;
- return nflux;
- }
- /// ecev3 - Get nitrogen deposition data for this gridcell
- /**
- * Determine N deposition forcing for this cell. We use the nearest 0.5 degree cell in the
- * Lamarque dataset. Calls
- *
- *
- * \param ndepfile .bin file containing the N dep. data. Read from guess.ins
- * \param rcp Set in guess.ins, with (integer) values 0 to 4, where
- * 0 - historical only
- * 1 - rcp3PD
- * 2 - rcp45
- * 3 - rcp60
- * 4 - rcp85
- */
- bool Gridcell::getndep(const char* ndepfile, double rcp) {
- Lamarque::timeseriestype timeseries;
- switch (int(rcp)) {
- case 0:
- timeseries = Lamarque::HISTORIC;
- break;
- case 1:
- timeseries = Lamarque::RCP26;
- break;
- case 2:
- timeseries = Lamarque::RCP45;
- break;
- case 3:
- timeseries = Lamarque::RCP60;
- break;
- case 4:
- timeseries = Lamarque::RCP85;
- break;
- default:
- // shouldn't happen
- fail("Unexpected timeseriestype/RCP in guess.ins!");
- }
- // Call the EC-Earth version of getndep to determine the NEAREST N dep data
- bool ndepOK = ndepts.getndep_nearest(ndepfile, lon, lat, timeseries);
- return ndepOK;
- }
- bool getmonthlyNdepforcingConserve(const char* varname, int year, double data[12], int ndepindex) {
- // 1st (".nc") or 2nd order remapping file?
- const char* filenametail = "2.nc";
- xtring ndep_cmip6_dir = param["ndep_cmip6_dir"].str;
- const char* filevar = varname;
- if (!strcmp(varname, "drynhx"))
- filevar = "drynhx";
- if (!strcmp(varname, "drynoy"))
- filevar = "drynoy";
- if (!strcmp(varname, "wetnhx"))
- filevar = "wetnhx";
- if (!strcmp(varname, "wetnoy"))
- filevar = "wetnoy";
- // First create NC file name for this data
- std::string full_path((char*)ndep_cmip6_dir);
- // AMIP
- full_path += filevar;
- full_path += filenametail;
- // Open NC file
- int status, ncid;
- status = nc_open(full_path.c_str(), NC_NOWRITE, &ncid);
- if (status != NC_NOERR)
- return false;
- // Get the ID for varname
- int var_id;
- status = nc_inq_varid(ncid, varname, &var_id);
- if (status != NC_NOERR)
- return false;
- // Read data
- for (int mm = 0; mm < 12; mm++) {
- size_t index[] = { (size_t)year * 12 + mm, (size_t)ndepindex };
- double val;
- status = nc_get_var1_double(ncid, var_id, index, &val);
- // < 0?
- val = max(val, 0.0);
- if (status != NC_NOERR)
- return false;
- data[mm] = val * 86400.0; // convert from kg N m-2 s-1 to kg N m-2 day-1
- }
- nc_close(ncid);
- return true;
- } // getmonthlyNdepforcingConserve
- /// ecev3 - Get simulation year
- /**
- * Return simulation year depending on simulation setups
- */
- int Gridcell::getsimulationyear(int year) {
- if (ECEARTH && !ECEARTHWITHCRUNCEP) // ecev3
- return simulationyear;
- else
- return year;
- }
- /// ecev3 - Get nitrogen deposition data for this gridcell
- /**
- * Determine N deposition forcing for this cell and year.
- *
- * \param ndepfile netcdf file containing the N dep. data. Read from guess.ins
- */
- bool Gridcell::getndepCMIP6(const char* ndepfile, int fixedNDepafter) {
- // N deposition data year
- int ndep_year = max(0, date.get_calendar_year() - CMIP6STARTYEAR);
- // if DECK experiments are ON set Ndep to 1850
- if (fixedNDepafter >= 0 && date.get_calendar_year() >= fixedNDepafter) {
- ndep_year = max(0, fixedNDepafter - CMIP6STARTYEAR);
- dprintf("INFO: N-Dep is kept constant from year %i on.\n", ndep_year + CMIP6STARTYEAR);
- dprintf(" as set in the variable 'fixedNDepafter' in config-run.xml.\n");
- }
- // CMIP6 data ends in 2100. Last data-set being repeated thereafter
- else if (date.get_calendar_year() > CMIP6ENDYEAR) {
- ndep_year = CMIP6ENDYEAR - CMIP6STARTYEAR;
- dprintf("INFO: N-Dep is set to last available data-set at year %i \n", CMIP6ENDYEAR);
- }
- // Monthly dry NH4 deposition (kg m-2 s-1)
- const char* vartoread = "drynhx";
- bool dataOK = getmonthlyNdepforcingConserve(vartoread, ndep_year, mdrynhx, ndep_index);
- if (!dataOK) {
- dprintf("Error reading dry NHx deposition data before LPJ-GUESS spinup. Quitting... \n");
- return false;
- }
- // Monthly wet NH4 deposition (kg m-2 s-1)
- vartoread = "wetnhx";
- dataOK = getmonthlyNdepforcingConserve(vartoread, ndep_year, mwetnhx, ndep_index);
- if (!dataOK) {
- dprintf("Error reading wet NHx deposition data before LPJ-GUESS spinup. Quitting... \n");
- return false;
- }
- // Monthly dry NO3 deposition (kg m-2 s-1)
- vartoread = "drynoy";
- dataOK = getmonthlyNdepforcingConserve(vartoread, ndep_year, mdrynoy, ndep_index);
- if (!dataOK) {
- dprintf("Error reading dry NOy deposition data before LPJ-GUESS spinup. Quitting... \n");
- return false;
- }
- // Monthly wet NO3 deposition (kg m-2 s-1)
- vartoread = "wetnoy";
- dataOK = getmonthlyNdepforcingConserve(vartoread, ndep_year, mwetnoy, ndep_index);
- if (!dataOK) {
- dprintf("Error reading wet NOy deposition data before LPJ-GUESS spinup. Quitting... \n");
- return false;
- }
- // Add up dry and wet deposition
- for (int m = 0; m < 12; m++) {
- mndrydep[m] = mdrynhx[m] + mdrynoy[m];
- mnwetdep[m] = mwetnhx[m] + mwetnoy[m];
- }
- return dataOK;
- }
- void Gridcell::serialize(ArchiveStream& arch) {
- arch & climate
- & landcover
- & seed
- & balance
- & id // ecev3
- & ifs_index // ecev3
- & ndep_index // ecev3
- // & mdrynhx // ecev3
- // & mwetnhx // ecev3
- // & mdrynoy // ecev3
- // & mwetnoy // ecev3
- & mndrydep // ecev3
- & mnwetdep // ecev3
- & IFStypehigh // ecev3
- & IFSfrachigh // ecev3
- & IFStypelow // ecev3
- & IFSfraclow // ecev3
- & naturaltreeFPC // ecev3
- & naturalgrassFPC // ecev3
- & transferhightolow // ecev3
- & simulationyear // ecev3
- & ndep_lon_index // ecev3
- & ndep_lat_index // ecev3
- & fixedLUafter // ecev3
- & awcont_5; // ecev3
- if (arch.save()) {
- for (unsigned int i = 0; i < pft.nobj; i++) {
- arch & pft[i];
- }
- for (unsigned int i = 0; i < st.nobj; i++) {
- arch & st[i];
- }
- unsigned int nstands = nbr_stands();
- arch & nstands;
- for (unsigned int s = 0; s < nstands; s++) {
- arch & (*this)[s].landcover
- & (*this)[s];
- }
- }
- else {
- pft.killall();
- for (unsigned int i = 0; i < pftlist.nobj; i++) {
- pft.createobj(pftlist[i]);
- arch & pft[i];
- }
- st.killall();
- for (unsigned int i = 0; i < stlist.nobj; i++) {
- st.createobj(stlist[i]);
- arch & st[i];
- }
- clear();
- unsigned int number_of_stands;
- arch & number_of_stands;
- for (unsigned int s = 0; s < number_of_stands; s++) {
- landcovertype landcover;
- arch & landcover;
- create_stand(landcover);
- arch & (*this)[s];
- }
- }
- }
- Stand& Gridcell::create_stand(landcovertype landcover, int no_patch) {
- Stand* stand = new Stand(get_next_id(), this, soiltype, landcover, no_patch);
- push_back(stand);
- return *stand;
- }
- Gridcell::iterator Gridcell::delete_stand(iterator itr) {
- return erase(itr);
- }
- unsigned int Gridcell::nbr_stands() const {
- return (int) size();
- }
- void Sompool::serialize(ArchiveStream& arch) {
- arch & cmass
- & nmass
- //& cdec
- //& ndec
- //& delta_cmass
- //& delta_nmass
- & ligcfrac
- //& fracremain
- & ntoc
- & litterme
- & fireresist
- & mfracremain_mean;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Implementation of MassBalance member functions
- ////////////////////////////////////////////////////////////////////////////////
- void MassBalance::serialize(ArchiveStream& arch) {
- arch & start_year
- & ccont_zero
- & ccont_zero_scaled
- & cflux_zero
- & ncont_zero
- & ncont_zero_scaled
- & nflux_zero
- & ccont
- & ncont
- & cflux
- & nflux;
- }
- /// Should be used together with check_indiv()
- void MassBalance::init_indiv(Individual& indiv) {
- Patch& patch = indiv.vegetation.patch;
- Stand& stand = patch.stand;
- if (!stand.is_true_crop_stand())
- return;
- Gridcell& gridcell = stand.get_gridcell();
- double scale = 1.0;
- if (patch.stand.get_gridcell().landcover.updated && (patch.nharv == 0 || date.day == 0))
- scale = stand.scale_LC_change;
- ccont_zero = indiv.ccont();
- ccont_zero_scaled = indiv.ccont(scale, true);
- // Add soil C
- ccont_zero += patch.ccont(0.0);
- ccont_zero_scaled += patch.ccont(0.0);
- cflux_zero = patch.cflux();
- ncont_zero = indiv.ncont();
- ncont_zero_scaled = indiv.ncont(scale, true);
- // Add soil N
- ncont_zero += patch.ncont(0.0);
- ncont_zero_scaled += patch.ncont(0.0);
- nflux_zero = patch.nflux();
- }
- bool MassBalance::check_indiv_C(Individual& indiv, bool check_harvest) {
- bool balance = true;
- Patch& patch = indiv.vegetation.patch;
- Stand& stand = patch.stand;
- if(!stand.is_true_crop_stand())
- return balance;
- Gridcell& gridcell = stand.get_gridcell();
- double ccont = indiv.ccont();
- ccont += patch.ccont(0.0);
- double cflux = patch.cflux();
- if(check_harvest && patch.isharvestday)
- ccont_zero = ccont_zero_scaled;
- if (gridcell.getsimulationyear(date.year) >= nyear_spinup && !negligible(ccont - ccont_zero + cflux - cflux_zero, -10)) {
- dprintf("\nStand %d Patch %d Indiv %d C balance year %d day %d: %.10f\n", patch.stand.id, patch.id, indiv.id, date.year, date.day, ccont - ccont_zero + cflux - cflux_zero);
- dprintf("C pool change: %.10f\n", ccont - ccont_zero);
- dprintf("C flux: %.10f\n\n", cflux - cflux_zero);
- balance = false;
- }
- return balance;
- }
- bool MassBalance::check_indiv_N(Individual& indiv, bool check_harvest) {
- bool balance = true;
-
- Patch& patch = indiv.vegetation.patch;
- Stand& stand = patch.stand;
- if (!stand.is_true_crop_stand())
- return balance;
- Gridcell& gridcell = stand.get_gridcell();
- double ncont = indiv.ncont();
- ncont += patch.ncont(0.0);
- double nflux = patch.nflux();
- if (check_harvest && patch.isharvestday)
- ncont_zero = ncont_zero_scaled;
- if (gridcell.getsimulationyear(date.year) >= nyear_spinup && !negligible(ncont - ncont_zero + nflux - nflux_zero, -14)) {
- dprintf("\nStand %d Patch %d Indiv %d N balance year %d day %d: %.10f\n", patch.stand.id, patch.id, indiv.id, date.year, date.day, ncont - ncont_zero + nflux - nflux_zero);
- dprintf("N pool change: %.14f\n", ncont - ncont_zero);
- dprintf("N flux: %.14f\n\n", nflux - nflux_zero);
- balance = false;
- }
- return balance;
- }
- /// Should be preceded by init_indiv()
- /** check_harvest must be true if growth_daily() is tested
- * canopy_exchange() and growth_daily() and functions in between cannot be tested separately
- */
- bool MassBalance::check_indiv(Individual& indiv, bool check_harvest) {
- return check_indiv_C(indiv, check_harvest) && check_indiv_N(indiv, check_harvest);
- }
- /// Should be used together with check_patch() e.g. in framework()
- void MassBalance::init_patch(Patch& patch) {
- Stand& stand = patch.stand;
- if (!stand.is_true_crop_stand())
- return;
- Gridcell& gridcell = stand.get_gridcell();
- double scale = 1.0;
- if (patch.stand.get_gridcell().landcover.updated && (patch.nharv == 0 || date.day == 0))
- scale = stand.scale_LC_change;
- ccont_zero = patch.ccont();
- ccont_zero_scaled = patch.ccont(scale, true);
- cflux_zero = patch.cflux();
- if (stand.get_gridcell_fraction())
- cflux_zero += gridcell.landcover.acflux_harvest_slow / stand.get_gridcell_fraction();
- ncont_zero = patch.ncont();
- ncont_zero_scaled = patch.ncont(scale, true);
- nflux_zero = patch.nflux();
- if (stand.get_gridcell_fraction())
- nflux_zero += gridcell.landcover.anflux_harvest_slow / stand.get_gridcell_fraction();
- }
- bool MassBalance::check_patch_C(Patch& patch, bool check_harvest) {
- bool balance = true;
- Stand& stand = patch.stand;
- if (!stand.is_true_crop_stand())
- return balance;
- Gridcell& gridcell = stand.get_gridcell();
- double ccont = patch.ccont();
- double cflux = patch.cflux();
- if (stand.get_gridcell_fraction())
- cflux += gridcell.landcover.acflux_harvest_slow / stand.get_gridcell_fraction();
- if (check_harvest && patch.isharvestday)
- ccont_zero = ccont_zero_scaled;
- if (gridcell.getsimulationyear(date.year) >= nyear_spinup && !negligible(ccont - ccont_zero + cflux - cflux_zero, -10)) {
- dprintf("\nStand %d Patch %d C balance year %d day %d: %.10f\n", patch.stand.id, patch.id, date.year, date.day, ccont - ccont_zero + cflux - cflux_zero);
- dprintf("C pool change: %.10f\n", ccont - ccont_zero);
- dprintf("C flux: %.10f\n\n", cflux - cflux_zero);
- balance = false;
- }
- return balance;
- }
- bool MassBalance::check_patch_N(Patch& patch, bool check_harvest) {
- bool balance = true;
- Stand& stand = patch.stand;
- if (!stand.is_true_crop_stand())
- return balance;
- Gridcell& gridcell = stand.get_gridcell();
- double ncont = patch.ncont();
- double nflux = patch.nflux();
- if (stand.get_gridcell_fraction())
- nflux += gridcell.landcover.anflux_harvest_slow / stand.get_gridcell_fraction();
- if (check_harvest && patch.isharvestday)
- ncont_zero = ncont_zero_scaled;
- if (gridcell.getsimulationyear(date.year) >= nyear_spinup && date.year >= nyear_spinup && !negligible(ncont - ncont_zero + nflux - nflux_zero, -14)) {
- dprintf("\nStand %d Patch %d N balance year %d day %d: %.14f\n", patch.stand.id, patch.id, date.year, date.day, ncont - ncont_zero + nflux - nflux_zero);
- dprintf("N pool change: %.14f\n", ncont - ncont_zero);
- dprintf("N flux: %.14f\n\n", nflux - nflux_zero);
- balance = false;
- }
- return balance;
- }
- /// Should be preceded by init_patch() e.g. i framework()
- /** check_harvest must be true if growth_daily() is tested
- * canopy_exchange() and growth_daily() and functions in between cannot be tested separately
- * (init_patch() must be before canopy_exchange() and check_patch() after growth_daily()
- */
- bool MassBalance::check_patch(Patch& patch, bool check_harvest) {
- return check_patch_C(patch, check_harvest) && check_patch_N(patch, check_harvest);
- }
- void MassBalance::check_year(Gridcell& gridcell) {
- if (gridcell.getsimulationyear(date.year) < start_year) {
- return;
- }
- double ccont_year = gridcell.ccont();
- double cflux_year = gridcell.cflux();
- double ncont_year = gridcell.ncont();
- double nflux_year = gridcell.nflux();
- if (gridcell.getsimulationyear(date.year) == start_year) {
- ccont_zero = ccont_year;
- ncont_zero = ncont_year;
- }
- else {
- cflux += cflux_year;
- nflux += nflux_year;
- // C balance check:
- if (!negligible(ccont_year - ccont + cflux_year, -9)) {
- dprintf("\n(%.2f, %.2f): C balance year %d: %.10f\n", gridcell.get_lon(), gridcell.get_lat(), date.year, ccont_year - ccont + cflux_year);
- dprintf("C pool change: %.5f\n", ccont_year - ccont);
- dprintf("C flux: %.5f\n", cflux_year);
- }
- // Cropland without N-limitation is not balanced in N, fertilisation gives poorer N-balance
- // For natural vegetation or unfertilised N-limited cropland, the check can be much stricter
- // N balance check:
- if (!negligible(ncont_year - ncont + nflux_year, -9)) {
- dprintf("\n(%.2f, %.2f): N balance year %d: %.9f\n", gridcell.get_lon(), gridcell.get_lat(), date.year, ncont_year - ncont + nflux_year);
- dprintf("N pool change: %.9f\n", ncont_year - ncont);
- dprintf("N flux: %.9f\n", nflux_year);
- }
- }
- ccont = ccont_year;
- ncont = ncont_year;
- }
- void MassBalance::check_period(Gridcell& gridcell) {
- // C balance check:
- if (!negligible(ccont - ccont_zero + cflux, -9)) {
- dprintf("\nWARNING: (%.2f, %.2f): Period C balance: %.10f\n", gridcell.get_lon(), gridcell.get_lat(), ccont - ccont_zero + cflux);
- dprintf("C pool change: %.10f\n", ccont - ccont_zero);
- dprintf("C fluxes: %.10f\n", cflux);
- }
- // Cropland without N-limitation is not balanced in N, fertilisation gives poorer N-balance
- // For natural vegetation or unfertilised N-limited cropland, the check can be much stricter
- // N balance check:
- if (!negligible(ncont - ncont_zero + nflux, -9)) {
- dprintf("\nWARNING: (%.2f, %.2f): Period N balance: %.10f\n", gridcell.get_lon(), gridcell.get_lat(), ncont - ncont_zero + nflux);
- dprintf("N pool change: %.10f\n", ncont - ncont_zero);
- dprintf("N fluxes: %.10f\n", nflux);
- }
- }
- void MassBalance::init(Gridcell& gridcell) {
- // start_year = date.year;
- ccont_zero = gridcell.ccont();
- cflux_zero = gridcell.cflux();
- }
- void MassBalance::check(Gridcell& gridcell) {
- double ccont = gridcell.ccont();
- double cflux = gridcell.cflux();
- if (!negligible(ccont - ccont_zero + cflux, -5)) {
- dprintf("\n(%.2f, %.2f): C balance year %d: %.5f\n", gridcell.get_lon(), gridcell.get_lat(), date.year, ccont - ccont_zero + cflux);
- dprintf("C pool change: %.5f\n", ccont - ccont_zero);
- dprintf("C flux: %.5f\n\n", cflux);
- }
- }
- bool Date::is_leap(int year) {
- if (ECEARTH) {
- if (!ECEARTHWITHCRUNCEP) {
- return (!(year % 4) && (year % 100 | !(year % 400)));
- }
- else {
- int yr = date.year - nyear_spinup + 1901; // should be FIRSTHISTYEAR==1901 for CRUNCEP
- return (!(yr % 4) && (yr % 100 | !(yr % 400)));
- }
- }
- }
- ///////////////////////////////////////////////////////////////////////////////////////
- // REFERENCES
- //
- // LPJF refers to the original FORTRAN implementation of LPJ as described by Sitch
- // et al 2000
- // Delmas, R., Lacaux, J.P., Menaut, J.C., Abbadie, L., Le Roux, X., Helaa, G., Lobert, J., 1995.
- // Nitrogen compound emission from biomass burning in tropical African Savanna FOS/DECAFE 1991
- // experiment. Journal of Atmospheric Chemistry 22, 175-193.
|