cruinput.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613
  1. ///////////////////////////////////////////////////////////////////////////////////////
  2. /// \file cruinput.cpp
  3. /// \brief LPJ-GUESS input module for CRU-NCEP data set
  4. ///
  5. /// This input module reads in CRU-NCEP climate data in a customised binary format.
  6. /// The binary files contain CRU-NCEP half-degree global historical climate data
  7. /// for 1901-2015.
  8. ///
  9. /// \author Ben Smith
  10. /// $Date: 2013-11-22 10:56:18 +0100 (Fri, 22 Nov 2013) $
  11. ///
  12. ///////////////////////////////////////////////////////////////////////////////////////
  13. #include "config.h"
  14. #include "cruinput.h"
  15. #include "driver.h"
  16. #include "parameters.h"
  17. #include <stdio.h>
  18. #include <utility>
  19. #include <vector>
  20. #include <algorithm>
  21. #include <netcdf.h>
  22. REGISTER_INPUT_MODULE("cru_ncep", CRUInput)
  23. // Anonymous namespace for variables and functions with file scope
  24. namespace {
  25. xtring file_cru;
  26. xtring file_cru_misc;
  27. /// Interpolates monthly data to quasi-daily values.
  28. void interp_climate(double* mtemp, double* mprec, double* msun, double* mdtr,
  29. double* dtemp, double* dprec, double* dsun, double* ddtr) {
  30. interp_monthly_means_conserve(mtemp, dtemp, date.is_leap(date.year));
  31. interp_monthly_totals_conserve(mprec, dprec, date.is_leap(date.year), 0);
  32. interp_monthly_means_conserve(msun, dsun, date.is_leap(date.year), 0);
  33. interp_monthly_means_conserve(mdtr, ddtr, date.is_leap(date.year), 0);
  34. }
  35. } // namespace
  36. CRUInput::CRUInput()
  37. : searchradius(0),
  38. spinup_mtemp(NYEAR_SPINUP_DATA),
  39. spinup_mprec(NYEAR_SPINUP_DATA),
  40. spinup_msun(NYEAR_SPINUP_DATA),
  41. spinup_mfrs(NYEAR_SPINUP_DATA),
  42. spinup_mwet(NYEAR_SPINUP_DATA),
  43. spinup_mdtr(NYEAR_SPINUP_DATA) {
  44. // Declare instruction file parameters
  45. declare_parameter("searchradius", &searchradius, 0, 100,
  46. "If specified, CRU data will be searched for in a circle");
  47. }
  48. void CRUInput::init() {
  49. // DESCRIPTION
  50. // Initialises input (e.g. opening files), and reads in the gridlist
  51. //
  52. // Reads list of grid cells and (optional) description text from grid list file
  53. // This file should consist of any number of one-line records in the format:
  54. // <longitude> <latitude> [<description>]
  55. double dlon,dlat;
  56. bool eof=false;
  57. xtring descrip;
  58. // Read list of grid coordinates and store in global Coord object 'gridlist'
  59. // Retrieve name of grid list file as read from ins file
  60. xtring file_gridlist=param["file_gridlist"].str;
  61. FILE* in_grid=fopen(file_gridlist,"r");
  62. if (!in_grid) fail("initio: could not open %s for input",(char*)file_gridlist);
  63. file_cru=param["file_cru"].str;
  64. file_cru_misc=param["file_cru_misc"].str;
  65. gridlist.killall();
  66. first_call = true;
  67. while (!eof) {
  68. // Read next record in file
  69. eof=!readfor(in_grid,"f,f,a#",&dlon,&dlat,&descrip);
  70. if (!eof && !(dlon==0.0 && dlat==0.0)) { // ignore blank lines at end (if any)
  71. Coord& c=gridlist.createobj(); // add new coordinate to grid list
  72. c.lon=dlon;
  73. c.lat=dlat;
  74. c.descrip=descrip;
  75. }
  76. }
  77. fclose(in_grid);
  78. // Read CO2 data from file
  79. co2.load_file(param["file_co2"].str);
  80. // Open landcover files
  81. landcover_input.init();
  82. // Open management files
  83. management_input.init();
  84. date.set_first_calendar_year(FIRSTHISTYEAR - nyear_spinup);
  85. // Set timers
  86. tprogress.init();
  87. tmute.init();
  88. tprogress.settimer();
  89. tmute.settimer(MUTESEC);
  90. }
  91. void CRUInput::get_monthly_ndep(int calendar_year,
  92. double* mndrydep,
  93. double* mnwetdep) {
  94. ndep.get_one_calendar_year(calendar_year,
  95. mndrydep, mnwetdep);
  96. }
  97. void CRUInput::adjust_raw_forcing_data(double lon,
  98. double lat,
  99. double hist_mtemp[NYEAR_HIST][12],
  100. double hist_mprec[NYEAR_HIST][12],
  101. double hist_msun[NYEAR_HIST][12]) {
  102. // The default (base class) implementation does nothing here.
  103. }
  104. bool CRUInput::getgridcell(Gridcell& gridcell) {
  105. // See base class for documentation about this function's responsibilities
  106. int soilcode;
  107. int elevation;
  108. // Make sure we use the first gridcell in the first call to this function,
  109. // and then step through the gridlist in subsequent calls.
  110. if (first_call) {
  111. gridlist.firstobj();
  112. // Note that first_call is static, so this assignment is remembered
  113. // across function calls.
  114. first_call = false;
  115. }
  116. else gridlist.nextobj();
  117. if (gridlist.isobj) {
  118. bool gridfound = false;
  119. bool LUerror = false;
  120. double lon;
  121. double lat;
  122. while(!gridfound) {
  123. if(gridlist.isobj) {
  124. lon = gridlist.getobj().lon;
  125. lat = gridlist.getobj().lat;
  126. gridfound = CRU_TS30::findnearestCRUdata(searchradius, file_cru, lon, lat, soilcode,
  127. hist_mtemp, hist_mprec, hist_msun);
  128. if (gridfound) // Get more historical CRU data for this grid cell
  129. gridfound = CRU_TS30::searchcru_misc(file_cru_misc, lon, lat, elevation,
  130. hist_mfrs, hist_mwet, hist_mdtr);
  131. // back to gridlist lon lat, since the generated LU input are for the ece lon lats
  132. double lon2 = gridlist.getobj().lon;
  133. double lat2 = gridlist.getobj().lat;
  134. if (run_landcover && gridfound) {
  135. LUerror = landcover_input.loadlandcover(lon2, lat2);
  136. if(!LUerror)
  137. LUerror = management_input.loadmanagement(lon2, lat2);
  138. }
  139. if(!gridfound || LUerror) {
  140. if(!gridfound)
  141. dprintf("\nError: could not find stand at (%g,%g) in climate data files\n\n", gridlist.getobj().lon,gridlist.getobj().lat);
  142. else if(LUerror)
  143. dprintf("\nError: could not find stand at (%g,%g) in landcover/management data file(s)\n\n", gridlist.getobj().lon,gridlist.getobj().lat);
  144. gridfound = false;
  145. gridlist.nextobj();
  146. }
  147. }
  148. else return false;
  149. }
  150. // Give sub-classes a chance to modify the data
  151. adjust_raw_forcing_data(gridlist.getobj().lon,
  152. gridlist.getobj().lat,
  153. hist_mtemp, hist_mprec, hist_msun);
  154. // Build spinup data sets
  155. spinup_mtemp.get_data_from(hist_mtemp);
  156. spinup_mprec.get_data_from(hist_mprec);
  157. spinup_msun.get_data_from(hist_msun);
  158. // Detrend spinup temperature data
  159. spinup_mtemp.detrend_data();
  160. // guess2008 - new spinup data sets
  161. spinup_mfrs.get_data_from(hist_mfrs);
  162. spinup_mwet.get_data_from(hist_mwet);
  163. spinup_mdtr.get_data_from(hist_mdtr);
  164. // We wont detrend dtr for now. Partly because dtr is at the moment only
  165. // used for BVOC, so what happens during the spinup is not affecting
  166. // results in the period thereafter, and partly because the detrending
  167. // can give negative dtr values.
  168. //spinup_mdtr.detrend_data();
  169. dprintf("\nCommencing simulation for stand at (%g,%g)",gridlist.getobj().lon,
  170. gridlist.getobj().lat);
  171. if (gridlist.getobj().descrip!="") dprintf(" (%s)\n\n",
  172. (char*)gridlist.getobj().descrip);
  173. else dprintf("\n\n");
  174. // Tell framework the coordinates of this grid cell
  175. gridcell.set_coordinates(gridlist.getobj().lon, gridlist.getobj().lat);
  176. // Get nitrogen deposition data.
  177. /* Since the historic data set does not reach decade 2010-2019,
  178. * we need to use the RCP data for the last decade. */
  179. ndep.getndep(param["file_ndep"].str, lon, lat, Lamarque::RCP60);
  180. // The insolation data will be sent (in function getclimate, below)
  181. // as incoming shortwave radiation, averages are over 24 hours
  182. gridcell.climate.instype = SWRAD_TS;
  183. // Tell framework the soil type of this grid cell
  184. soilparameters(gridcell.soiltype,soilcode);
  185. // For Windows shell - clear graphical output
  186. // (ignored on other platforms)
  187. clear_all_graphs();
  188. return true; // simulate this stand
  189. }
  190. return false; // no more stands
  191. }
  192. void CRUInput::getlandcover(Gridcell& gridcell) {
  193. landcover_input.getlandcover(gridcell);
  194. landcover_input.get_land_transitions(gridcell);
  195. }
  196. int getndepindex(double lon, double lat) {
  197. xtring ndep_cmip6_dir = param["ndep_cmip6_dir"].str;
  198. const char* filevar = "drynhx2.nc";
  199. // First create NC file name for this data
  200. std::string full_path((char*)ndep_cmip6_dir);
  201. // AMIP
  202. full_path += filevar;
  203. // Open NC file
  204. int status, ncid;
  205. status = nc_open(full_path.c_str(), NC_NOWRITE, &ncid);
  206. if (status != NC_NOERR)
  207. fail("Error reading dry NHx deposition data before LPJ-GUESS spinup. Quitting... \n");
  208. // Get the ID for lon
  209. int lon_id;
  210. status = nc_inq_varid(ncid, "lon", &lon_id);
  211. if (status != NC_NOERR)
  212. fail("Error reading longitude in dry NHx deposition data before LPJ-GUESS spinup. Quitting... \n");
  213. // Get the ID for lat
  214. int lat_id;
  215. status = nc_inq_varid(ncid, "lat", &lat_id);
  216. if (status != NC_NOERR)
  217. fail("Error reading latitude in dry NHx deposition data before LPJ-GUESS spinup. Quitting... \n");
  218. /*size_t latlength;
  219. status = nc_inq_dimlen(ncid, lat_id, &latlength);
  220. if (status != NC_NOERR)
  221. return false;*/
  222. int ndepindex;
  223. // Read data
  224. for (ndepindex = 0; ndepindex < 59191; ndepindex++) {
  225. size_t index[] = { ndepindex };
  226. double latval, lonval;
  227. status = nc_get_var1_double(ncid, lat_id, index, &latval);
  228. status = nc_get_var1_double(ncid, lon_id, index, &lonval);
  229. if (abs(latval-lat) < 0.000001 && abs(lonval-lon) < 0.000001)
  230. break;
  231. }
  232. if (ndepindex == 59191)
  233. fail("Could not find Lon %g and Lat %g in dry NHx deposition data. Quitting... \n", lon, lat);
  234. return ndepindex;
  235. }
  236. bool getmonthlyNdepforcing(const char* varname, int year, double data[12], int ndepindex) {
  237. // 1st (".nc") or 2nd order remapping file?
  238. const char* filenametail = "2.nc";
  239. xtring ndep_cmip6_dir = param["ndep_cmip6_dir"].str;
  240. const char* filevar = varname;
  241. if (!strcmp(varname, "drynhx"))
  242. filevar = "drynhx";
  243. if (!strcmp(varname, "drynoy"))
  244. filevar = "drynoy";
  245. if (!strcmp(varname, "wetnhx"))
  246. filevar = "wetnhx";
  247. if (!strcmp(varname, "wetnoy"))
  248. filevar = "wetnoy";
  249. // First create NC file name for this data
  250. std::string full_path((char*)ndep_cmip6_dir);
  251. // AMIP
  252. full_path += filevar;
  253. full_path += filenametail;
  254. // Open NC file
  255. int status, ncid;
  256. status = nc_open(full_path.c_str(), NC_NOWRITE, &ncid);
  257. if (status != NC_NOERR)
  258. return false;
  259. // Get the ID for varname
  260. int var_id;
  261. status = nc_inq_varid(ncid, varname, &var_id);
  262. if (status != NC_NOERR)
  263. return false;
  264. // Read data
  265. for (int mm = 0; mm < 12; mm++) {
  266. size_t index[] = { year * 12 + mm, ndepindex };
  267. double val;
  268. status = nc_get_var1_double(ncid, var_id, index, &val);
  269. // < 0?
  270. val = max(val, 0.0);
  271. if (status != NC_NOERR)
  272. return false;
  273. data[mm] = val * 86400.0; // convert from kg N m-2 s-1 to kg N m-2 day-1
  274. }
  275. nc_close(ncid);
  276. return true;
  277. } // getmonthlyNdepforcingConserve
  278. /// ecev3 - Get nitrogen deposition data for this gridcell
  279. /**
  280. * Determine N deposition forcing for this cell and year.
  281. *
  282. * \param ndepfile netcdf file containing the N dep. data. Read from guess.ins
  283. */
  284. bool getndepCMIP6(const char* ndepfile, int ndep_index, int calendar_year, double mndrydep[12], double mnwetdep[12]) {
  285. double mdrynhx[12], mdrynoy[12], mwetnhx[12], mwetnoy[12];
  286. int maxyears = CMIP6ENDYEAR - CMIP6STARTYEAR;
  287. int ndep_year = min(maxyears, max(0, calendar_year - CMIP6STARTYEAR));
  288. // Monthly dry NH4 deposition (kg m-2 s-1)
  289. const char* vartoread = "drynhx";
  290. bool dataOK = getmonthlyNdepforcing(vartoread, ndep_year, mdrynhx, ndep_index);
  291. if (!dataOK) {
  292. dprintf("Error reading dry NHx deposition data before LPJ-GUESS spinup. Quitting... \n");
  293. return false;
  294. }
  295. // Monthly wet NH4 deposition (kg m-2 s-1)
  296. vartoread = "wetnhx";
  297. dataOK = getmonthlyNdepforcing(vartoread, ndep_year, mwetnhx, ndep_index);
  298. if (!dataOK) {
  299. dprintf("Error reading wet NHx deposition data before LPJ-GUESS spinup. Quitting... \n");
  300. return false;
  301. }
  302. // Monthly dry NO3 deposition (kg m-2 s-1)
  303. vartoread = "drynoy";
  304. dataOK = getmonthlyNdepforcing(vartoread, ndep_year, mdrynoy, ndep_index);
  305. if (!dataOK) {
  306. dprintf("Error reading dry NOy deposition data before LPJ-GUESS spinup. Quitting... \n");
  307. return false;
  308. }
  309. // Monthly wet NO3 deposition (kg m-2 s-1)
  310. vartoread = "wetnoy";
  311. dataOK = getmonthlyNdepforcing(vartoread, ndep_year, mwetnoy, ndep_index);
  312. if (!dataOK) {
  313. dprintf("Error reading wet NOy deposition data before LPJ-GUESS spinup. Quitting... \n");
  314. return false;
  315. }
  316. // Add up dry and wet deposition
  317. for (int m = 0; m < 12; m++) {
  318. mndrydep[m] = mdrynhx[m] + mdrynoy[m];
  319. mnwetdep[m] = mwetnhx[m] + mwetnoy[m];
  320. }
  321. return dataOK;
  322. }
  323. bool CRUInput::getclimate(Gridcell& gridcell) {
  324. // See base class for documentation about this function's responsibilities
  325. double progress;
  326. Climate& climate = gridcell.climate;
  327. if (date.day == 0) {
  328. // First day of year ...
  329. // Extract N deposition to use for this year,
  330. // monthly means to be distributed into daily values further down
  331. double mndrydep[12], mnwetdep[12];
  332. if (!ECEARTHWITHCRUNCEP) {
  333. ndep.get_one_calendar_year(date.year - nyear_spinup + FIRSTHISTYEAR,
  334. mndrydep, mnwetdep);
  335. }
  336. else {
  337. if (date.year == 0)
  338. gridcell.ndep_index = getndepindex(gridcell.get_lon(), gridcell.get_lat());
  339. bool Ndepdatafound = getndepCMIP6(param["ndep_cmip6_dir"].str, gridcell.ndep_index, date.year - nyear_spinup + FIRSTHISTYEAR, mndrydep, mnwetdep);
  340. if (!Ndepdatafound) {
  341. dprintf("Could not read N deposition files for cell with lon=%f, lat=%f\n", gridcell.get_lon(), gridcell.get_lat());
  342. fail();
  343. }
  344. }
  345. if (date.year < nyear_spinup) {
  346. // During spinup period
  347. if(date.year == state_year && restart) {
  348. int year_offset = state_year % NYEAR_SPINUP_DATA;
  349. for (int y=0;y<year_offset;y++) {
  350. spinup_mtemp.nextyear();
  351. spinup_mprec.nextyear();
  352. spinup_msun.nextyear();
  353. spinup_mfrs.nextyear();
  354. spinup_mwet.nextyear();
  355. spinup_mdtr.nextyear();
  356. }
  357. }
  358. int m;
  359. double mtemp[12],mprec[12],msun[12];
  360. double mfrs[12],mwet[12],mdtr[12];
  361. for (m=0;m<12;m++) {
  362. mtemp[m] = spinup_mtemp[m];
  363. mprec[m] = spinup_mprec[m];
  364. msun[m] = spinup_msun[m];
  365. mfrs[m] = spinup_mfrs[m];
  366. mwet[m] = spinup_mwet[m];
  367. mdtr[m] = spinup_mdtr[m];
  368. }
  369. // Interpolate monthly spinup data to quasi-daily values
  370. interp_climate(mtemp,mprec,msun,mdtr,dtemp,dprec,dsun,ddtr);
  371. // Only recalculate precipitation values using weather generator
  372. // if rainonwetdaysonly is true. Otherwise we assume that it rains a little every day.
  373. if (ifrainonwetdaysonly) {
  374. // (from Dieter Gerten 021121)
  375. prdaily(mprec, dprec, mwet, gridcell.seed);
  376. }
  377. spinup_mtemp.nextyear();
  378. spinup_mprec.nextyear();
  379. spinup_msun.nextyear();
  380. spinup_mfrs.nextyear();
  381. spinup_mwet.nextyear();
  382. spinup_mdtr.nextyear();
  383. }
  384. else if (date.year < nyear_spinup + NYEAR_HIST) {
  385. // Historical period
  386. // Interpolate this year's monthly data to quasi-daily values
  387. interp_climate(hist_mtemp[date.year-nyear_spinup],
  388. hist_mprec[date.year-nyear_spinup],hist_msun[date.year-nyear_spinup],
  389. hist_mdtr[date.year-nyear_spinup],
  390. dtemp,dprec,dsun,ddtr);
  391. // Only recalculate precipitation values using weather generator
  392. // if ifrainonwetdaysonly is true. Otherwise we assume that it rains a little every day.
  393. if (ifrainonwetdaysonly) {
  394. // (from Dieter Gerten 021121)
  395. prdaily(hist_mprec[date.year-nyear_spinup], dprec, hist_mwet[date.year-nyear_spinup], gridcell.seed);
  396. }
  397. }
  398. else {
  399. // Return false if last year was the last for the simulation
  400. return false;
  401. }
  402. for (int dd = 0; dd < Date::MAX_YEAR_LENGTH; dd++) dndep[dd] = 0.0;
  403. // Distribute N deposition
  404. if (!ECEARTHWITHCRUNCEP) {
  405. distribute_ndep(mndrydep, mnwetdep, dprec, date.ndaymonth, dndep);
  406. }
  407. else {
  408. // assuming it rains a bit every day
  409. double drizzle[Date::MAX_YEAR_LENGTH];
  410. for (int dd = 0; dd < Date::MAX_YEAR_LENGTH; dd++) drizzle[dd] = 1.0; // Assume 1 mm/day
  411. distribute_ndep(mndrydep, mnwetdep, drizzle, date.ndaymonth, dndep);
  412. }
  413. }
  414. // Send environmental values for today to framework
  415. climate.co2 = co2[FIRSTHISTYEAR + date.year - nyear_spinup];
  416. if (date.day == 0) {
  417. for (int mth = 0; mth < 12; mth++) {
  418. gridcell.climate.mco2[mth] = 0.0;
  419. }
  420. }
  421. gridcell.climate.mco2[date.month] += climate.co2 / date.ndaymonth[date.month];
  422. climate.temp = dtemp[date.day];
  423. climate.prec = dprec[date.day];
  424. climate.insol = dsun[date.day];
  425. // Nitrogen deposition
  426. climate.dndep = dndep[date.day];
  427. // bvoc
  428. if(ifbvoc){
  429. climate.dtr = ddtr[date.day];
  430. }
  431. // First day of year only ...
  432. if (date.day == 0) {
  433. // Progress report to user and update timer
  434. if (tmute.getprogress()>=1.0) {
  435. progress=(double)(gridlist.getobj().id*(nyear_spinup+NYEAR_HIST)
  436. +date.year)/(double)(gridlist.nobj*(nyear_spinup+NYEAR_HIST));
  437. tprogress.setprogress(progress);
  438. dprintf("%3d%% complete, %s elapsed, %s remaining\n",(int)(progress*100.0),
  439. tprogress.elapsed.str,tprogress.remaining.str);
  440. tmute.settimer(MUTESEC);
  441. }
  442. }
  443. return true;
  444. }
  445. CRUInput::~CRUInput() {
  446. // Performs memory deallocation, closing of files or other "cleanup" functions.
  447. }
  448. ///////////////////////////////////////////////////////////////////////////////////////
  449. // REFERENCES
  450. // Lamarque, J.-F., Kyle, G. P., Meinshausen, M., Riahi, K., Smith, S. J., Van Vuuren,
  451. // D. P., Conley, A. J. & Vitt, F. 2011. Global and regional evolution of short-lived
  452. // radiatively-active gases and aerosols in the Representative Concentration Pathways.
  453. // Climatic Change, 109, 191-212.
  454. // Nakai, T., Sumida, A., Kodama, Y., Hara, T., Ohta, T. (2010). A comparison between
  455. // various definitions of forest stand height and aerodynamic canopy height.
  456. // Agricultural and Forest Meteorology, 150(9), 1225-1233