// Paul Miller, 15 February 2015 // 18 August svn test // #ifdef HAVE_MPI #include #endif #include "config.h" #include #include #include #include #include "gutil.h" #include #include #include "parallel.h" #include #include using namespace GuessParallel; using namespace std; #include "shell.h" #include "oasis-cpp-interface.h" #include "OasisCoupler.h" #include #include "commandlinearguments.h" #include "eceframework.h" #include "framework.h" ////////////////////////////////////////////////////////////////////////////////////// // GLOBAL PARAMETERS // CMIP6 CO2 FORCING static char file_co2[] = "mole_fraction_of_carbon_dioxide_in_air_input4MIPs_lpjg.nc"; // concatenated CO2 file provided by run_script // static char file_co2[] = "co2_histo_cmip6_lpjg.nc"; // version converted from the above using CDO as follows: // cdo -f nc copy -selname,mole_fraction_of_carbon_dioxide_in_air CMIP6_histo_mole_fraction_of_carbon_dioxide_in_air_input4MIPs_gr1-GMNHSH.nc co2_histo_cmip6_lpjg.nc // NETCDF files with associated variable names #ifdef GRID_T159 // ecev3 - T159 // *** Coordinates, masks and gridcell areas static const int MAXGRID = 10407; // 10407 for 6k and PI onwards, 12245 for LGM // number of LAND grid cells at T159 resolution static const int NX_ATMO=35718; // number of GLOBAL grid cells at T159 resolution static char parn_lon[]="L080.lon"; // longitude parameter name in filen_grid static char parn_lat[]="L080.lat"; // latitude parameter name in filen_grid static char parn_mask[]="L080.msk"; // mask parameter name in filen_mask static char parn_areas[] = "L080.srf"; // mask parameter name in filen_areas static char filen_soilcd[]="slt_T159.nc"; // "slt_T159_LGM.nc" for T159 LGM // path to soil data file static char parn_lon_cor[] = "L080.clo"; // corners static char parn_lat_cor[] = "L080.cla"; // corners #endif #ifdef GRID_T255 // ecev3 - T255 // *** Coordinates, masks and gridcell areas static const int MAXGRID=25799; // number of LAND grid cells at T255 resolution static const int NX_ATMO=88838; // number of GLOBAL grid cells at T255 resolution static char parn_lon[]="L128.lon"; // longitude parameter name in filen_grid static char parn_lat[]="L128.lat"; // latitude parameter name in filen_grid static char parn_mask[]="L128.msk"; // mask parameter name in filen_mask static char parn_areas[]="L128.srf"; // mask parameter name in filen_areas static char filen_soilcd[]="slt_T255.nc"; // path to soil data file static char parn_lon_cor[] = "L128.clo"; // corners static char parn_lat_cor[] = "L128.cla"; // corners #endif // *** Grid definition files (common to all resolutions) static char filen_grid[] = "grids.nc"; // path to grid data file static char filen_areas[]="areas.nc"; // path to areas data file static char filen_mask[] = "masks.nc"; // path to mask data file // T159 LGM // static char filen_mask[] = "masks_LGM.nc"; // path to mask data file // *** Paths to and variables in netcdf files extracted from ICMGG*INIT files static char filen_cvl[]="cvl.nc"; // path to LOW cover fraction file static char parn_cvl[]="var27"; // soil code parameter name in filen_cvl static char filen_cvh[]="cvh.nc"; // path to HIGH cover fraction file static char parn_cvh[]="var28"; // soil code parameter name in filen_cvh static char filen_tvl[]="tvl.nc"; // path to LOW cover TYPE file static char parn_tvl[]="var29"; // soil code parameter name in file filen_tvl static char filen_tvh[]="tvh.nc"; // path to HIGH cover TYPE file static char parn_tvh[]="var30"; // soil code parameter name in file filen_tvh static char parn_soilcd[] = "var43"; // soil code parameter name in filen_soilcd // *** Initialisation from .rc files static char file_timesteps[]=".//lpjg_steps.rc"; // path to IFS file that determines the LPJ-GUESS timesteps, resolution and coupling mode int resolution; // 255 or 159 bool activateTM5coupling; // communicate with TM5 if true const int NYEAR_ECEARTH=271; // i.e. 2110 - 1840 + 1 // number of years of historical climate in CRU and files (see below) const int FIRSTHISTYEAR=1840; // Number of years CO2 is availale const int NYEAR_CO2=2501; const int FIRSTYEAR_CO2=0; bool ifs_A4xCO2 = false; // abrupt 4xCO2 after 1850, for DECK Experiments bool bgc_1pctCO2 = false; // 1% / year (exponential) increase from 1850 on, for DECK Experiments int ifs_FIXEDYEARCO2 = -1; // set CO2 values to chosen year for DECK Experiments int fixedNDepafter = -1; // hold NDep constant from this year on int fixedLUafter = -1; // suppress LU from this year on int TIMESTEP = 86400; struct{ int year; int month; int day; } STARTDATE={1850,1,1}; // initialise with default values int NTIMESTEP=1; // *** Date format specification const bool IFLEAPYEARS=true; static int NDAYMONTH[12]={31,28,31,30,31,30,31,31,30,31,30,31}; // if IFLEAPYEARS=true, February will be assigned an extra day when necessary ////////////////////////////////////////////////////////////////////////////////////// // GLOBAL DATA static int ngridcell; // number of grid cells static double co2[NYEAR_CO2]; // CO2 data for each year of historical data set static int soilcode[MAXGRID]; // Soil code for each grid cell // Fields to pass to/from OASIS and i/o fields static const int NY_ATMO=1; static float coup_lsmask[NX_ATMO][NY_ATMO]; // Received FROM IFS static double coup_temper[NX_ATMO*NY_ATMO]; static double coup_precip[NX_ATMO*NY_ATMO]; static double coup_vegl[NX_ATMO*NY_ATMO]; static double coup_vegl_type[NX_ATMO*NY_ATMO]; static double coup_vegh[NX_ATMO*NY_ATMO]; static double coup_snowc[NX_ATMO*NY_ATMO]; static double coup_snowd[NX_ATMO*NY_ATMO]; const int NHTESSELSOILLAYERS = 4; // Number of soil layers in HTESSEL static double coup_st1l[NX_ATMO*NY_ATMO]; static double coup_st2l[NX_ATMO*NY_ATMO]; static double coup_st3l[NX_ATMO*NY_ATMO]; static double coup_st4l[NX_ATMO*NY_ATMO]; static double coup_sm1l[NX_ATMO*NY_ATMO]; static double coup_sm2l[NX_ATMO*NY_ATMO]; static double coup_sm3l[NX_ATMO*NY_ATMO]; static double coup_sm4l[NX_ATMO*NY_ATMO]; static double coup_sw_radiat[NX_ATMO*NY_ATMO]; static double coup_lw_radiat[NX_ATMO*NY_ATMO]; // Sent TO IFS static double coup_lowlai[NX_ATMO*NY_ATMO]; static double coup_highlai[NX_ATMO*NY_ATMO]; static double coup_lpjg_typeh[NX_ATMO*NY_ATMO]; static double coup_lpjg_frach[NX_ATMO*NY_ATMO]; static double coup_lpjg_typel[NX_ATMO*NY_ATMO]; static double coup_lpjg_fracl[NX_ATMO*NY_ATMO]; // Received FROM TM5 (when coupled) static double coup_co2_field[NX_ATMO*NY_ATMO]; // Sent TO TM5 (when coupled) static double coup_dcflux_nat[NX_ATMO*NY_ATMO]; static double coup_dcflux_ant[NX_ATMO*NY_ATMO]; static double coup_dnpp[NX_ATMO*NY_ATMO]; // Store this year's CO2, either from file or TM5 static double coup_co2; ////////////////////////////////////////////////////////////////////////////////////// // GRIDLIST struct EceCoord { // Type for storing grid cell properties // longitude and latitude // ID for the Gridcell // soilcode, area, type and cover fractions int id; float lon; float lat; int soilcode; // soilcode int IFSindex; // record the IFS index float area; // gridcell area in m2 float cvl, cvh; // Cover fractions from GCM ICMGG*INIT files int tvl, tvh; // Cover types from GCM ICMGG*INIT files int ndep_index; // 0 to NX_ATMO-1 - for accessing N deposition data in CMIP6 files // Only used when used when printing grids /* double cornerla[4]; double cornerlo[4]; */ EceCoord() { id=0; lon=0.0; lat=0.0; IFSindex=0; soilcode=0; area=0.0; cvl=0.0; cvh=0.0; tvl=0; tvh=0; ndep_index=-1; }; ~EceCoord() { } }; void handle_error(int status) { if (status != NC_NOERR) { fprintf(stderr, "%s\n", nc_strerror(status)); //CLNexit(-1); } } int opennetcdf(int& ncid, const char* path) { try { int status; status = nc_open(path, NC_NOWRITE, &ncid); if (status != NC_NOERR) { handle_error(status); return 0; } else { return 1; } } catch (...) { cout << "Unknown error in opennetcdf()!" << endl; return 0; } } int readnetcdf_latlon(const int& ncid, double* lat, double* lon) { try{ int status; int lat_id, lon_id; char* lonstr = "lon"; char* latstr = "lat"; // Get the ID for longitude status = nc_inq_varid (ncid, lonstr, &lon_id); if (status != NC_NOERR) handle_error(status); // Get the ID for latitude status = nc_inq_varid (ncid, latstr, &lat_id); if (status != NC_NOERR) handle_error(status); // Get the data for variable longitude status = nc_get_var_double(ncid, lon_id, lon); if (status != NC_NOERR) handle_error(status); // Get the data for variable latitude status = nc_get_var_double(ncid, lat_id, lat); if (status != NC_NOERR) handle_error(status); return 1; } catch(...) { cout << "Unknown error in readnetcdf_latlon()!" << endl; return 0; } } int getglobaldata_double(const int& ncid, const char* varname, double* vardata) { try{ int status; int var_id; // Get the ID for varname status = nc_inq_varid (ncid, varname, &var_id); if (status != NC_NOERR) handle_error(status); //int dims; //nc_inq_vardimid(ncid, var_id, &dims); // Get the data for varname status = nc_get_var_double(ncid, var_id, vardata); if (status != NC_NOERR) handle_error(status); return 1; } catch(...) { cout << "Unknown error in getglobaldata_double()!" << endl; return 0; } } int getglobaldataarray_double(const int& ncid, const char* varname, int corners, int lons, int lats, double* vardata) { try{ int status; int var_id; // Get the ID for varname status = nc_inq_varid (ncid, varname, &var_id); if (status != NC_NOERR) handle_error(status); static size_t start[] = {0, 0, 0}; /* start at first value */ static size_t count[] = {corners, lons, lats}; // Get the data for varname status = nc_get_vara_double(ncid, var_id, start, count, vardata); if (status != NC_NOERR) handle_error(status); return 1; } catch(...) { cout << "Unknown error in getglobaldata_double()!" << endl; return 0; } } int getglobaldata_int(const int& ncid, const char* varname, int* vardata) { try{ int status; int var_id; // Get the ID for varname status = nc_inq_varid (ncid, varname, &var_id); if (status != NC_NOERR) handle_error(status); // Get the data for varname status = nc_get_var_int(ncid, var_id, vardata); if (status != NC_NOERR) handle_error(status); return 1; } catch(...) { cout << "Unknown error in getglobaldata_int()!" << endl; return 0; } } // ecev3 static ListArray_id gridlist; // Will maintain a list of EceCoord objects containing coordinates // and other properties of the grid cells to simulate // Reads lpjg_steps.rc bool read_ifs_timesteps() { dprintf("Experiment Setup =========== \n"); FILE* in_ts=fopen(file_timesteps,"rt"); if (!in_ts) { dprintf("Could not open %s for input\n",file_timesteps); return false; } bool eof=false; bool is_err=false; // Read TIMESTEP eof=!readfor(in_ts,"i",&TIMESTEP); // Validate TIMESTEP if (TIMESTEP>24*3600) { dprintf("Maximum allowable timestep is %d seconds (24 hours)\n",24*3600); fclose(in_ts); return false; } if (!eof) { // Read STARTDATE readfor(in_ts,"i",&STARTDATE.year); readfor(in_ts,"i",&STARTDATE.month); readfor(in_ts,"i",&STARTDATE.day); // Validate STARTDATE bool valid=true; if (STARTDATE.month<1 || STARTDATE.month>12 || STARTDATE.day<1) valid=false; else if (IFLEAPYEARS && STARTDATE.month==2 && !(STARTDATE.year%4) && (STARTDATE.year%400)) { // leap year? if (STARTDATE.day>NDAYMONTH[1]+1) valid=false; } else if (STARTDATE.day>NDAYMONTH[STARTDATE.month-1]) valid=false; if (!valid) { dprintf("ERROR: Invalid start date %d-%02d-%02d\n", STARTDATE.year,STARTDATE.month,STARTDATE.day); fclose(in_ts); is_err = true; return false; } if (STARTDATE.year<0 /* || STARTDATE.year>=FIRSTHISTYEAR+NYEAR_ECEARTH */) { // Larger years can be used in fixed-year experiments dprintf("ERROR: Specified start date %d-%02d-%02d is outside range of available data\n", STARTDATE.year,STARTDATE.month,STARTDATE.day); fclose(in_ts); is_err = true; return false; } // Read NTIMESTEP eof=!readfor(in_ts,"i",&NTIMESTEP); // Read resolution readfor(in_ts,"i",&resolution); if (resolution != 159 && resolution != 255) { dprintf("ERROR: Invalid resolution %d\n", resolution); fclose(in_ts); is_err = true; return false; } // Read TM5 coupling option int TM5couple = -1; readfor(in_ts,"i",&TM5couple); if (TM5couple==1) activateTM5coupling = true; else if (TM5couple==0) activateTM5coupling = false; else { dprintf("ERROR: Invalid TM5 coupling option %d\n", TM5couple); fclose(in_ts); is_err = true; return false; } // Read DECK experiment settings // Abrupt 4 x CO2 xtring sdum[1]; string is_true_l = "t"; string is_true_u = "T"; eof = !readfor(in_ts,"a1",&sdum); if ( eof ) { dprintf("ERROR: Entry for A4xCO2 not found in %s \n", file_timesteps); is_err = true; } else { if ( !is_true_l.compare((char *)sdum[0]) || !is_true_u.compare((char *)sdum[0]) ) { ifs_A4xCO2 = 1; } else { ifs_A4xCO2 = 0; } dprintf("A4xCO2 set to %i \n",ifs_A4xCO2); } // 1 percent CO2 per year eof = !readfor(in_ts,"a1",&sdum); if ( eof ) { dprintf("ERROR: Entry for 1PCTCO2 not found in %s \n", file_timesteps); is_err = true; } else { if ( !is_true_l.compare((char *)sdum[0]) || !is_true_u.compare((char *)sdum[0]) ) { bgc_1pctCO2 = 1; } else { bgc_1pctCO2 = 0; } dprintf("1PCTCO2 set to %i \n",bgc_1pctCO2); } // fixed year CO2 eof = !readfor(in_ts,"i",&ifs_FIXEDYEARCO2); if ( eof ) { dprintf("ERROR: Entry for FIXEDYEARCO2 not found in %s \n", file_timesteps); is_err = true; } else { dprintf("CO2 is set fix at %d \n",ifs_FIXEDYEARCO2); } // fixed NDep from this year on eof = !readfor(in_ts,"i",&fixedNDepafter); if ( eof ) { dprintf("ERROR: Entry for fixedNDepafter year not found in %s \n", file_timesteps); is_err = true; } // fixed Land Use from this year on eof = !readfor(in_ts,"i",&fixedLUafter); if ( eof ) { dprintf("ERROR: Entry for fixedLUafter year not found in %s \n", file_timesteps); is_err = true; } // Only one can be switched on if ( ifs_A4xCO2 && bgc_1pctCO2 ) { dprintf("ERROR: Both ifs_A4xCO2 && bgc_1pctCO2 selected. Please adjust in config-run.xml\n"); is_err = true; } int base_year = CMIP6STARTYEAR; if ( ifs_FIXEDYEARCO2 > 0) { base_year = ifs_FIXEDYEARCO2; } // Override settings for fixed experiments if ( ifs_A4xCO2 || bgc_1pctCO2 ) { fixedNDepafter = base_year; fixedLUafter = base_year; } } dprintf("fixedNDepafter set to %i \n",fixedNDepafter); dprintf("fixedLUafter set to %i \n",fixedLUafter); dprintf("End experiment Setup ======= \n"); fclose(in_ts); if ( is_err ) { return false; } else { return true; } } // Reading grid information from files provided by the atmosphere model // LPJ-GUESS will run on the same grid // This is where to read grid information from IFS-provided masks.nc, grids.nc and areas.nc bool read_grid_info(bool readcorners){ int ix; double* nlon =new double[NX_ATMO]; double* nlat =new double[NX_ATMO]; double* nmask =new double[NX_ATMO]; double* nareas =new double[NX_ATMO]; double* nlon_cor = NULL; double* nlat_cor = NULL; bool ok_flag = true; if (readcorners) { nlon_cor = new double[4*NX_ATMO]; nlat_cor = new double[4*NX_ATMO]; } int ncid = 0; int gridOK = opennetcdf(ncid, filen_grid); int lonsOK = getglobaldata_double(ncid, parn_lon, nlon); int latsOK = getglobaldata_double(ncid, parn_lat, nlat); if (readcorners) { int cloOK = getglobaldataarray_double(ncid, parn_lon_cor, 4, 1, NX_ATMO, nlon_cor); int claOK = getglobaldataarray_double(ncid, parn_lat_cor, 4, 1, NX_ATMO, nlat_cor); if ( ! cloOK || ! claOK ) { dprintf("LPJ-GUESS: Error reading corners from file:%s\n",filen_grid); ok_flag = false; } } nc_close(ncid); int ncid2 = 0; int maskfileOK = opennetcdf(ncid2, filen_mask); int maskOK = getglobaldata_double(ncid2, parn_mask, nmask); nc_close(ncid2); int ncid3 = 0; int areasfileOK = opennetcdf(ncid3, filen_areas); int areasOK = getglobaldata_double(ncid3, parn_areas, nareas); nc_close(ncid3); ngridcell=0; int ifsindex = 0; for(ix=0;ix=180.)c.lon=c.lon-360.; c.lat=nlat[ix]; if (readcorners) { /* UNCOMMENT if corners are needed! c.cornerla[0]=nlat_cor[ix]; c.cornerla[1]=nlat_cor[ix+1*NX_ATMO]; c.cornerla[2]=nlat_cor[ix+2*NX_ATMO]; c.cornerla[3]=nlat_cor[ix+3*NX_ATMO]; c.cornerlo[0]=nlon_cor[ix]; c.cornerlo[1]=nlon_cor[ix+1*NX_ATMO]; c.cornerlo[2]=nlon_cor[ix+2*NX_ATMO]; c.cornerlo[3]=nlon_cor[ix+3*NX_ATMO]; if(c.cornerlo[0]>=180.)c.cornerlo[0]=c.cornerlo[0]-360.; if(c.cornerlo[1]>=180.)c.cornerlo[1]=c.cornerlo[1]-360.; if(c.cornerlo[2]>=180.)c.cornerlo[2]=c.cornerlo[2]-360.; if(c.cornerlo[3]>=180.)c.cornerlo[3]=c.cornerlo[3]-360.; */ } c.IFSindex=ifsindex; // 1 to 35718 (T159) or 88838 (T255) c.area = nareas[ix]; // area in m2 c.ndep_index = ngridcell - 1; } } if (ngridcell>MAXGRID) { dprintf("Too many grid cells in gridlist file %s\nMaximum allowed is %d\n", filen_mask,MAXGRID); delete[] nlon; delete[] nlat; delete[] nmask; delete[] nareas; if (readcorners) { delete[] nlon_cor; delete[] nlat_cor; } ok_flag = false; //CLNexit(99); } delete[] nlon; delete[] nlat; delete[] nmask; delete[] nareas; if (readcorners) { delete[] nlon_cor; delete[] nlat_cor; } // Error handling cheap way if ( ! gridOK ) { dprintf("LPJ-GUESS: Error opening file:%s\n",filen_grid); } else { if ( ! lonsOK ) dprintf("LPJ-GUESS: Error reading lons from file:%s\n",filen_grid); if ( ! latsOK ) dprintf("LPJ-GUESS: Error reading lats from file:%s\n",filen_grid); } if ( ! maskfileOK ) dprintf("LPJ-GUESS: Error opening file:%s\n",filen_mask); else if ( ! maskOK ) dprintf("LPJ-GUESS: Error reading mask from file:%s\n",filen_mask); if ( ! areasfileOK ) dprintf("LPJ-GUESS: Error opening file:%s\n",filen_areas); else if ( ! areasOK ) dprintf("LPJ-GUESS: Error reading areas from file:%s\n",filen_areas); if ( ! gridOK || ! lonsOK || ! latsOK || ! maskfileOK || ! maskOK || ! areasfileOK || ! areasOK ) ok_flag = false; return ok_flag; } bool read_soil_veg_info(bool printgridlist) { // Reading soil and vegetation information from NetCDF input files // Will also print the gridlist if the outcommented code is used. int ix; double* dcoup_soilcd =new double[NX_ATMO]; double* dcvl =new double[NX_ATMO]; double* dcvh =new double[NX_ATMO]; double* dtvl =new double[NX_ATMO]; double* dtvh =new double[NX_ATMO]; int ncid = 0; bool ok_flag = true; // soilcode int soilfileOK = opennetcdf(ncid, filen_soilcd); int soilOK = getglobaldata_double(ncid, parn_soilcd, dcoup_soilcd); nc_close(ncid); if ( ! soilfileOK ) dprintf("LPJ-GUESS: Error opening file:%s\n",filen_soilcd); else if ( ! soilOK ) dprintf("LPJ-GUESS: Error reading from file:%s\n",filen_soilcd); if (printgridlist) { // cvl int cvlfileOK = opennetcdf(ncid, filen_cvl); int cvlOK = getglobaldata_double(ncid, parn_cvl, dcvl); nc_close(ncid); if ( ! cvlfileOK ) dprintf("LPJ-GUESS: Error opening file:%s\n",filen_cvl); else if ( ! cvlOK ) dprintf("LPJ-GUESS: Error reading from file:%s\n",filen_cvl); // cvh int cvhfileOK = opennetcdf(ncid, filen_cvh); int cvhOK = getglobaldata_double(ncid, parn_cvh, dcvh); nc_close(ncid); if ( ! cvhfileOK ) dprintf("LPJ-GUESS: Error opening file:%s\n",filen_cvh); else if ( ! cvhOK ) dprintf("LPJ-GUESS: Error reading from file:%s\n",filen_cvh); // tvl int tvlfileOK = opennetcdf(ncid, filen_tvl); int tvlOK = getglobaldata_double(ncid, parn_tvl, dtvl); nc_close(ncid); if ( ! tvlfileOK ) dprintf("LPJ-GUESS: Error opening file:%s\n",filen_tvl); else if ( ! tvlOK ) dprintf("LPJ-GUESS: Error reading from file:%s\n",filen_tvl); // tvh int tvhfileOK = opennetcdf(ncid, filen_tvh); int tvhOK = getglobaldata_double(ncid, parn_tvh, dtvh); nc_close(ncid); if ( ! tvhfileOK ) dprintf("LPJ-GUESS: Error opening file:%s\n",filen_tvh); else if ( ! tvhOK ) dprintf("LPJ-GUESS: Error reading from file:%s\n",filen_tvh); } // Print out gridlist? FILE *ofp; if (printgridlist) ofp = fopen("ece_gridlist_T255.txt", "w"); // ofp = fopen("ece_gridlist_T159.txt", "w"); // T159 // ofp = fopen("ece_gridlist_LGM.txt", "w"); // T159 - LGM // storing soil code in Coord c gridlist.firstobj(); int mask_index = 0; for(ix=0;ix 7){ dprintf("Bad soil code! \n"); return false; } c.soilcode=cd; if (printgridlist) { c.cvl = dcvl[ix]; c.cvh = dcvh[ix]; c.tvl = (int)dtvl[ix]; c.tvh = (int)dtvh[ix]; } else { c.cvl = 0.0; c.cvh = 0.0; c.tvl = 0; c.tvh = 0; } // print gridlist? if (printgridlist) fprintf(ofp, "%8.5f\t %8.5f\t %8.5f\t %d\t %d\t %d\t %8.5f\t %8.5f\t %d\t %d\t \n", c.lon, c.lat, c.area, c.soilcode, c.IFSindex, mask_index, c.cvl, c.cvh, c.tvl, c.tvh); gridlist.nextobj(); mask_index++; } } delete[] dcoup_soilcd; delete[] dcvl; delete[] dcvh; delete[] dtvl; delete[] dtvh; // print gridlist? if (printgridlist) fclose(ofp); // error handling //if ( ! soilfileOK || ! soilOK || ! cvlfileOK || ! cvlOK || ! cvhfileOK || ! cvhOK || // ! tvlfileOK || ! tvlOK || ! tvhfileOK || ! tvhOK ) if (!soilfileOK || !soilOK) ok_flag = false; return ok_flag; } static void readco2_cmip6(bool& error_flag) { // Reads in atmospheric CO2 concentrations for EC_Earth historical from // Jan 1 0 (1 BC) - to 2014 (see http://www.climate-energy-college.net/cmip6) // from netCDF CMIP6 CO2 file. // netCDF related variables int status; int file_id = 0; status = nc_open(file_co2, NC_NOWRITE, &file_id); //if (status != NC_NOERR) handle_error(status); if (file_id <= 0) { dprintf("!!!ERROR!!! readco_cmip6: could not open CO2 file %s for input\n", file_co2); error_flag = true; } // Get dimension time int time_id; status = nc_inq_unlimdim(file_id, &time_id); if (status != NC_NOERR) { handle_error(status); error_flag = true; } //time_id = ncdimid(file_id, 'time'); size_t time_size; status = nc_inq_dimlen(file_id, time_id, &time_size); if (status != NC_NOERR) { handle_error(status); error_flag = true; } // get variable containing co2 int co2_id; char* dsetname = "mole_fraction_of_carbon_dioxide_in_air"; status = nc_inq_varid(file_id, dsetname, &co2_id); if (status != NC_NOERR) { handle_error(status); error_flag = true; } // define hyperslab to read from netCDF file static size_t start[] = { 0, 0 }; static size_t count[] = { time_size, 1 }; float co2_in[NYEAR_CO2]; // read co2 and assign to global array status = nc_get_vara_float(file_id, co2_id, start, count, co2_in); if (status != NC_NOERR) { handle_error(status); error_flag = true; } for (int i = 0; i < NYEAR_CO2; i++) { co2[i] = (double)co2_in[i]; } // close file status = nc_close(file_id); if (status != NC_NOERR) { handle_error(status); error_flag = true; } } /* if needed when printing cover data too bool read_soil_veg_cover_info() { // Reading soil and vegetation information from NetCDF input files int ix; double* dcoup_soilcd = new double[NX_ATMO]; double* dcvl = new double[NX_ATMO]; double* dcvh = new double[NX_ATMO]; double* dtvl = new double[NX_ATMO]; double* dtvh = new double[NX_ATMO]; int ncid = 0; // soilcode int soilfileOK = opennetcdf(ncid, filen_soilcd); int soilOK = getglobaldata_double(ncid, parn_soilcd, dcoup_soilcd); nc_close(ncid); // cvl int cvfileOK = opennetcdf(ncid, filen_cvl); int cvOK = getglobaldata_double(ncid, parn_cvl, dcvl); nc_close(ncid); // cvh cvfileOK = opennetcdf(ncid, filen_cvh); cvOK = getglobaldata_double(ncid, parn_cvh, dcvh); nc_close(ncid); // tvl int tvfileOK = opennetcdf(ncid, filen_tvl); int tvOK = getglobaldata_double(ncid, parn_tvl, dtvl); nc_close(ncid); // tvh tvfileOK = opennetcdf(ncid, filen_tvh); tvOK = getglobaldata_double(ncid, parn_tvh, dtvh); nc_close(ncid); // vegcover // static char filen_vcf[] = "veginfo_T255_con2.nc"; static char filen_vcf[] = "veginfo_T159_con2.nc"; // static char filen_vcf[] = "veginfo_T159_bilinear.nc"; // bilinear // Categories: bare_ground,Broadleaf,Needleleaf,Evergreen,Decidous,Tree_cover,Herb tvfileOK = opennetcdf(ncid, filen_vcf); double* dvcf1 = new double[NX_ATMO]; double* dvcf2 = new double[NX_ATMO]; double* dvcf3 = new double[NX_ATMO]; double* dvcf4 = new double[NX_ATMO]; double* dvcf5 = new double[NX_ATMO]; double* dvcf6 = new double[NX_ATMO]; double* dvcf7 = new double[NX_ATMO]; tvOK = getglobaldata_double(ncid, "bare_ground", dvcf1); tvOK = getglobaldata_double(ncid, "Broadleaf", dvcf2); tvOK = getglobaldata_double(ncid, "Needleleaf", dvcf3); tvOK = getglobaldata_double(ncid, "Evergreen", dvcf4); tvOK = getglobaldata_double(ncid, "Decidous", dvcf5); tvOK = getglobaldata_double(ncid, "Tree_cover", dvcf6); tvOK = getglobaldata_double(ncid, "Herb", dvcf7); nc_close(ncid); // Print out veg cover FILE *ofp2; ofp2 = fopen("ece_vegcover_T159_con2.txt", "w"); // storing soil code in Coord c gridlist.firstobj(); int mask_index = 0; for (ix = 0; ix 7) { dprintf("Bad soil code! \n"); return false; } c.soilcode = cd; c.cvl = dcvl[ix]; c.cvh = dcvh[ix]; c.tvl = (int)dtvl[ix]; c.tvh = (int)dtvh[ix]; fprintf(ofp2, "%8.5f\t %8.5f\t %8.5f\t %d\t %d\t %d\t %8.5f\t %8.5f\t %d\t %d\t %8.5f\t %8.5f\t %8.5f\t %8.5f\t %8.5f\t %8.5f\t %8.5f \n", c.lon, c.lat, c.area, c.soilcode, c.IFSindex, mask_index, c.cvl, c.cvh, c.tvl, c.tvh, dvcf1[ix], dvcf2[ix], dvcf3[ix], dvcf4[ix], dvcf5[ix], dvcf6[ix], dvcf7[ix]); gridlist.nextobj(); mask_index++; } } delete[] dcoup_soilcd; delete[] dcvl; delete[] dcvh; delete[] dtvl; delete[] dtvh; delete[] dvcf1; delete[] dvcf2; delete[] dvcf3; delete[] dvcf4; delete[] dvcf5; delete[] dvcf6; delete[] dvcf7; // clode vcf file fclose(ofp2); dprintf("Soil and static vegetation and cover data read in and printed\n"); return true; } */ /* // Used for creating files to be used with cdo, remapcon bool print_grid() { // Print the grid if needed for cdo operations! const long int maxpoints = 100000; // For testing. Otherwise set to 100000 // Print out gridlist? FILE *ofp; //ofp = fopen("grids_T255.txt", "w"); ofp = fopen("grids_T159_all.txt", "w"); //fprintf(ofp, "%s\n%s\n%s\n", "gridtype = cell", "gridsize = 25799", "nvertex=4"); // grids_T255 //fprintf(ofp, "%s\n%s\n%s\n", "gridtype = cell", "gridsize = 88838", "nvertex=4"); // grids_T255_all //fprintf(ofp, "%s\n%s\n%s\n", "gridtype = cell", "gridsize = 10407", "nvertex=4"); // grids_T159 fprintf(ofp, "%s\n%s\n%s\n", "gridtype = cell", "gridsize = 35718", "nvertex=4"); // grids_T159_all // storing soil code in Coord c gridlist.firstobj(); fprintf(ofp, "%s\n","xvals ="); int test = 0; while(gridlist.isobj && test < maxpoints) { EceCoord& c=gridlist.getobj(); fprintf(ofp, "%8.6f\n",c.lon); gridlist.nextobj(); test++; } test = 0; fprintf(ofp, "%s\n","xbounds ="); gridlist.firstobj(); while(gridlist.isobj && test < maxpoints) { EceCoord& c=gridlist.getobj(); // Uncomment when needed! fprintf(ofp, "%8.6f %8.6f %8.6f %8.6f\n",c.cornerlo[0],c.cornerlo[1],c.cornerlo[2],c.cornerlo[3]); gridlist.nextobj(); test++; } test = 0; gridlist.firstobj(); fprintf(ofp, "%s\n","yvals ="); while(gridlist.isobj && test < maxpoints) { EceCoord& c=gridlist.getobj(); fprintf(ofp, "%8.6f\n",c.lat); gridlist.nextobj(); test++; } test = 0; fprintf(ofp, "%s\n","ybounds ="); gridlist.firstobj(); while(gridlist.isobj && test < maxpoints) { EceCoord& c=gridlist.getobj(); // Uncomment when needed! fprintf(ofp, "%8.6f %8.6f %8.6f %8.6f\n",c.cornerla[0],c.cornerla[1],c.cornerla[2],c.cornerla[3]); gridlist.nextobj(); test++; } // print gridlist? fclose(ofp); dprintf("Grid printed \n"); return true; } */ /* static void readco2() { // Reads in atmospheric CO2 concentrations for EC_Earth historical period, 1840-2010 // from ascii text file with records in format: [CO2] [CH4] [N2O] [CFC11] [CFC12] int year,calender_year; FILE* in=fopen(file_co2,"rt"); if (!in) { dprintf("readco2 in guessio: could not open CO2 file %s for input\n",file_co2); exit(99); } else { dprintf("readco2 in guessio - CO2 file opened OK\n"); } // I deleted the first read the two header lines readfor(in,""); readfor(in,""); for (year=0;year max_llai) max_llai = (float)coup_lowlai[ix]; if (coup_highlai[ix] > max_hlai) max_hlai = (float)coup_highlai[ix]; mean_hlai += (float)coup_highlai[ix]/MAXGRID; mean_llai += (float)coup_lowlai[ix]/MAXGRID; mean_cflux_nat += (float)coup_dcflux_nat[ix]/MAXGRID; mean_cflux_ant += (float)coup_dcflux_ant[ix]/MAXGRID; mean_npp += (float)coup_dnpp[ix]/MAXGRID; } } dprintf("call_oasis_put - Values on timestep %i - max LOW, max HIGH, mean LOW, mean HIGH LAI, mean CFLUX_NAT, mean CFLUX_ANT, mean NPP are %12.6f, %12.6f, %12.6f, %12.6f, %12.6f, %12.6f, %12.6f\n", timestep,max_llai,max_hlai,mean_llai,mean_hlai,mean_cflux_nat,mean_cflux_ant, mean_npp); } // ecev3 - use activateTM5coupling OasisCoupler::couple_put(timestep*TIMESTEP,NX_ATMO,NY_ATMO,activateTM5coupling,coup_lowlai, coup_highlai, coup_lpjg_typeh, coup_lpjg_frach, coup_lpjg_typel, coup_lpjg_fracl, coup_dcflux_nat, coup_dcflux_ant, coup_dnpp); // dprintf("call_oasis_put - LPJ-GUESS: OASIS communicated!\n"); } void call_coupler_get(int timestep,double temp[MAXGRID],double prec[MAXGRID], double vegl[MAXGRID], int vegl_type[MAXGRID], double vegh[MAXGRID], double snowc[MAXGRID], double snowd[MAXGRID], double stl[MAXGRID][NHTESSELSOILLAYERS], double sml[MAXGRID][NHTESSELSOILLAYERS], double swrad[MAXGRID], double lwrad[MAXGRID],double co2_field[MAXGRID]) { int g; int ix; int iy; const double TEMP_KTOC=-273.15; // This is the point at which to get the fields from OASIS call_oasis_get(timestep); // timestep = timestep number from 0 for start date // temp = temperature (degC instantaneous) // prec = precipitation (mm since last time step) // swrad = net downward shortwave radiation (W/m2 instantaneous) // lwrad = net downward longwave radiation (W/m2 instantaneous) // co2 = atmospheric CO2 concentration (ppmv) // temp, prec and rad are 1-dimensional arrays containing data for all grid cells // reduce complete grid arrays received from OASIS to one-dimensional arrays within GUESS g=0; // Doubles to hold global averages for this timestep. Use in debugging! double temp_avg = 0.0; double prec_avg = 0.0; double swrad_avg = 0.0; double lwrad_avg = 0.0; double vegl_avg = 0.0; double vegh_avg = 0.0; double snowc_avg = 0.0; double snowd_avg = 0.0; double st1l_avg = 0.0; double st2l_avg = 0.0; double st3l_avg = 0.0; double st4l_avg = 0.0; double sm1l_avg = 0.0; double sm2l_avg = 0.0; double sm3l_avg = 0.0; double sm4l_avg = 0.0; double co2_avg = 0.0; for(iy=0;iy (oC) // surface solar radiation (W m-2 s) --> (W m-2) // precipitation (m) --> (mm) temp[g]=coup_temper[ix]+TEMP_KTOC; // Convert from kg m-2 s-1 to mm prec[g]=coup_precip[ix]*1.e3*TIMESTEP/1000; if (prec[g] < 0.000001) prec[g] = 0.0; // For negative or very low values snowc[g] = coup_snowc[ix]; // kg m-2 snowd[g] = coup_snowd[ix]; // kg m-3 stl[g][0] = coup_st1l[ix]+TEMP_KTOC; // all K to degC stl[g][1] = coup_st2l[ix]+TEMP_KTOC; stl[g][2] = coup_st3l[ix]+TEMP_KTOC; stl[g][3] = coup_st4l[ix]+TEMP_KTOC; sml[g][0] = coup_sm1l[ix]; // all m3 m-3 sml[g][1] = coup_sm2l[ix]; sml[g][2] = coup_sm3l[ix]; sml[g][3] = coup_sm4l[ix]; // ECE sends W m-2 swrad[g] = coup_sw_radiat[ix]; lwrad[g] = coup_lw_radiat[ix]; if (swrad[g] < 0.000001) swrad[g] = 0.0; // For negative or very low values co2_field[g] = coup_co2_field[ix]; g++; } } } if (timestep < 20 && g > 0) { // Print checksums dprintf("ECEFRAMEWORK: checksum for timestep %d :\n",timestep); dprintf("ECEFRAMEWORK: (checksum TEMP) %12.6f\n",temp_avg/(double)g); dprintf("ECEFRAMEWORK: (checksum PREC) %g\n",prec_avg/(double)g); dprintf("ECEFRAMEWORK: (checksum SNOWC) %12.6f\n",snowc_avg/(double)g); dprintf("ECEFRAMEWORK: (checksum SNOWD) %12.6f\n",snowd_avg/(double)g); dprintf("ECEFRAMEWORK: (checksum ST1L) %12.6f\n",st1l_avg/(double)g); dprintf("ECEFRAMEWORK: (checksum ST2L) %12.6f\n",st2l_avg/(double)g); dprintf("ECEFRAMEWORK: (checksum ST3L) %12.6f\n",st3l_avg/(double)g); dprintf("ECEFRAMEWORK: (checksum ST4L) %12.6f\n",st4l_avg/(double)g); dprintf("ECEFRAMEWORK: (checksum SM1L) %12.6f\n",sm1l_avg/(double)g); dprintf("ECEFRAMEWORK: (checksum SM2L) %12.6f\n",sm2l_avg/(double)g); dprintf("ECEFRAMEWORK: (checksum SM3L) %12.6f\n",sm3l_avg/(double)g); dprintf("ECEFRAMEWORK: (checksum SM4L) %12.6f\n",sm4l_avg/(double)g); dprintf("ECEFRAMEWORK: (checksum SW RAD) %12.6f\n", swrad_avg/(double)g); dprintf("ECEFRAMEWORK: (checksum LR RAD) %12.6f\n", lwrad_avg/(double)g); dprintf("ECEFRAMEWORK: (checksum CO2) %12.6f\n",co2_avg/(double)g); } return; } void call_coupler_put(int timestep,double lailow[MAXGRID], double laihigh[MAXGRID], // LAI int lpjg_typeh[MAXGRID], double lpjg_frach[MAXGRID], // VEG H int lpjg_typel[MAXGRID], double lpjg_fracl[MAXGRID], // VEG L double dcfluxnat[MAXGRID], double dcfluxant[MAXGRID], double dnpp[MAXGRID]) { // C FLUX int g; int ix; int iy; // Expand one-dimensional arrays within GUESS to complete grid for sending to OASIS g=0; for(iy=0;iy 13) { precip = 1.0; temp_soil = 3.0; swrad_net_inst = 100.0; temp_2m = 22.0; } else { // Amazon point precip = 6.0; temp_soil = 26.0; swrad_net_inst = 170.0; temp_2m = 24.0; } */ /* // ecev3 - TEST DATA for one German gridcell. MUST outcomment!!!! soilw_surf = 0.33; soilw_deep = 0.33; if (monthc < 4 || monthc > 8) { precip = 2.4; temp_soil = 5.0; swrad_net_inst = 90.0; temp_2m = 5.0; } else { precip = 2.4; temp_soil = 15.0; swrad_net_inst = 150.0; temp_2m = 15.0; } */ /* // ecev3 - TEST DATA for one German gridcell. MUST outcomment!!!! soilw_surf = 0.0; soilw_deep = 0.0; if (monthc < 4 || monthc > 8) { precip = 0.1; temp_soil = -1.0; swrad_net_inst = 30.0; temp_2m = -10.0; } else { precip = 0.5; temp_soil = 1.0; swrad_net_inst = 150.0; temp_2m = 1.0; } */ // Call LPJ-GUESS for THIS cell TODAY !!!!! // SEND: Dates, coordinates, climate and CO2 for this cell, today // RECEIVE: LAI for high and low Stands in the Gridcell, fraction and dominant type of high vegetation, as well as carbon fluxes // HERE is where we call the LPJG trunk framework!!!!!!! // Something VERY SIMILAR to a direct call to guess_coupled - see RCA-GUESS for inspiration if (false && timestep < 2) { // ECEtest dprintf("GUESS: before guess_coupled on timestep %i for cell %i with lat %f, lon %f\n",timestep,ifs_index,alat,alon); dprintf("GUESS: temp %f, precip %f, CO2 %f\n",temp_2m, precip, co2); dprintf("GUESS: swrad_net_inst %f, lwrad_net_inst %f, temp_soil %f, soil code %i\n",swrad_net_inst, lwrad_net_inst, temp_soil, ifs_soilcd); dprintf("GUESS: soilw_surf %f, soilw_deep %f, vegl_cell %f, vegl_type_cell %i, vegh_cell %f, vegh_type_cell %i\n",soilw_surf, soilw_deep, vegl_cell, vegl_type_cell, vegh_cell, vegh_type_cell); } guess_coupled(c.id, rank, num_procs, isfinal, alon, alat, ifs_soilcd, ifs_index, ndep_index, yearc, sim_yr, monthc, dayc, hourc, temp_2m, precip, swrad_net_inst, lwrad_net_inst, co2, temp_soil, soilw_surf, soilw_deep, // Arg19 vegl_cell, vegl_type_cell, // Inputs // Updated fields follow... cfluxnattoday, cfluxanttoday, npptoday, laiphen_high, laiphen_low, ifsvegfrachigh, ifsvegtypehigh, ifsvegfraclow, ifsvegtypelow, islpjgspinup, fixedNDepafter, fixedLUafter); // Store lailow and laihigh lailow[gg] = laiphen_low; laihigh[gg] = laiphen_high; if (ifsvegtypehigh == 0) laihigh[gg] = 0.0; if (ifsvegtypelow == 0) lailow[gg] = 0.0; // TYPE is actually only updated once a year lpjg_typeh[gg] = (int)ifsvegtypehigh; lpjg_frach[gg] = (double)ifsvegfrachigh; lpjg_typel[gg] = (int)ifsvegtypelow; lpjg_fracl[gg] = (double)ifsvegfraclow; // Check for errors if (ifsvegtypehigh < 0 || ifsvegtypehigh > 19 || ifsvegfrachigh < 0.0 || ifsvegfrachigh > 1.0 || ifsvegtypelow < 0 || ifsvegtypelow > 19 || ifsvegfraclow < 0.0 || ifsvegfraclow > 1.0) { dprintf("GUESS: Invalid VEG type or fraction after LPJG calls at timestep %i for cell %i \n",timestep, ifs_index); dprintf("GUESS: laiphen_high, VEGH type, and VEGH fraction: %f %i %f\n",laiphen_high, ifsvegtypehigh, ifsvegfrachigh); dprintf("GUESS: laiphen_low, VEGL type, and VEGL fraction: %f %i %f\n",laiphen_low, ifsvegtypelow, ifsvegfraclow); } // Scale the C fluxes before sending them to TM5 - done in guess_coupled dcfluxnat[gg]=cfluxnattoday; dcfluxant[gg]=cfluxanttoday; dnpp[gg]=npptoday; // NB! a positive cfluxtoday implies C RELEASE by this gridcell, a negative value implies C UPTAKE // ECEtest /* dprintf("GUESS: LAIH, FRACH, TYPEH at timestep %i for cell %i: %f, %f, %f\n",timestep,ifs_index,laiphen_high, lpjg_frach[gg],(double)ifsvegtypehigh); dprintf("GUESS: LAIL, FRACL, TYPEL at timestep %i for cell %i: %f, %f, %f\n",timestep,ifs_index,laiphen_low, lpjg_fracl[gg],(double)ifsvegtypelow); */ } // Now get all slave processes to send their information to master process 0 #ifdef HAVE_MPI if (localcomm != MPI_COMM_WORLD && islpjgspinup) dprintf("localcomm != MPI_COMM_WORLD \n"); if (localcomm == MPI_COMM_WORLD && islpjgspinup) dprintf("localcomm == MPI_COMM_WORLD \n"); // Synchronise first //dprintf("Before MPI_Barrier in runlpjguess_today, after guess_coupled on node %i \n",rank); MPI_Barrier(localcomm); //dprintf("After MPI_Barrier in runlpjguess_today on node %i \n",rank); if (!islpjgspinup) { int tag; if (num_procs > 1) { // Synchronise first // MPI_Barrier(localcomm); // Only do this aggregation if we're running with more than one processor double lail[MAXGRID]; double laih[MAXGRID]; double frh[MAXGRID]; int tph[MAXGRID]; double frl[MAXGRID]; int tpl[MAXGRID]; double cfl_nat[MAXGRID]; double cfl_ant[MAXGRID]; double cfl_npp[MAXGRID]; if (rank == 0) { // Master process - receive LPJ-GUESS results from slave processes MPI_Status stat; for (int pr = 1; pr < num_procs; pr++) { // LAIL tag = pr*100+1; MPI_Recv(lail,MAXGRID,MPI_DOUBLE,pr,tag,localcomm,&stat); // LAIH tag = pr*100+2; MPI_Recv(laih,MAXGRID,MPI_DOUBLE,pr,tag,localcomm,&stat); // TYPH tag = pr*100+3; MPI_Recv(tph,MAXGRID,MPI_INT,pr,tag,localcomm,&stat); // FRACH tag = pr*100+4; MPI_Recv(frh,MAXGRID,MPI_DOUBLE,pr,tag,localcomm,&stat); // TYPL tag = pr*100+5; MPI_Recv(tpl,MAXGRID,MPI_INT,pr,tag,localcomm,&stat); // FRACL tag = pr*100+6; MPI_Recv(frl,MAXGRID,MPI_DOUBLE,pr,tag,localcomm,&stat); // DCFLUX tag = pr*100+7; MPI_Recv(cfl_nat,MAXGRID,MPI_DOUBLE,pr,tag,localcomm,&stat); // DCFLUX tag = pr*100+8; MPI_Recv(cfl_ant,MAXGRID,MPI_DOUBLE,pr,tag,localcomm,&stat); // NPP tag = pr*100+9; MPI_Recv(cfl_npp,MAXGRID,MPI_DOUBLE,pr,tag,localcomm,&stat); // Report the cells this node will simulate dprintf("Master node %i has received the results from slave process %i.\n", rank, pr); // T255 - cellspernode goes from 2579 to 2457, but the final node gets more (lastcell is MAXGRID) // as it has less to do on account of Antarctica and always finishes most quickly otherwise. // The cell limits for this process: //CLN int cells = (int)(MAXGRID / (double)(num_procs + 0.5)); //CLN int cell1 = pr * cells; //CLN int cell2 = cell1 + cells; //CLN if (pr == num_procs-1) //CLN cell2 = MAXGRID; //CLN //CLN // Now populate the arrays on process 0 ahead of OASIS SEND calls //CLN for (int cl = cell1; cl < cell2; cl++) { //CLN Longitudinal distribution of HERE SAME translation as above! for (int cl = pr; cl1) MPI_Barrier(localcomm); //dprintf("After MPI_Barrier 0 on node %i \n",myrank); #endif } else { dprintf("LPJ-GUESS: No OASIS initialisation. \n"); localcomm = 0; couplcomm = 0; #ifdef HAVE_MPI localcomm = MPI_COMM_WORLD; #endif } //dprintf("LPJ-GUESS: localcomm %i \n",localcomm); globalprocs = get_num_global_processes(); if (!islpjgspinup) local_procs = get_num_local_processes(localcomm); else local_procs = get_num_processes(); // dprintf("LPJ-GUESS: %i local processes, and %i global processes = %i, myrank %i \n",local_procs, globalprocs, myrank); //if (isparallel && !islpjgspinup) { // now change directory here even if it is a spinpup if (isparallel) { xtring path; path.printf("./run%d", myrank+1); // ecev3 - was rank+1 dprintf("\nMoving directory to %s on node %d\n",(const char*)path, myrank); if (change_directory(path) != 0) { fprintf(stderr, "Failed to change to run directory\n"); return; } } // Wait until all processes, including 0, reach this point, so OASIS data will be available //dprintf("Before MPI_Barrier 1 (after OASIS-MCT initialisation) on node %i \n",myrank); #ifdef HAVE_MPI if (isparallel && !islpjgspinup && local_procs>1) MPI_Barrier(localcomm); #endif //dprintf("After MPI_Barrier 1 on node %i \n",myrank); dprintf("EC-Earth - LPJ-GUESS coupling "); dprintf("\nfor %d timesteps of %d seconds ",NTIMESTEP,TIMESTEP); dprintf("starting from %04d-%02d-%02d 0h00\n\n",STARTDATE.year,STARTDATE.month,STARTDATE.day); // Set date and time for first timestep eceDate.year=STARTDATE.year; eceDate.month=STARTDATE.month; eceDate.day=STARTDATE.day; eceDate.time=0; eceDate.sim_year=0; // MAIN LOOP THROUGH TIMESTEPS int isfinal = 0; // set flag for the final step (used for saving the LPJG state) timestep=0; // Ensure we only run for one timestep when spinning up int timestepstorun = 0; if (islpjgspinup) { timestepstorun = 1; isfinal = 1; } else timestepstorun = NTIMESTEP; // Main time loop while (timestep NYEAR_CO2 ) { fail("No CO2 data available beyond %d \n",NYEAR_CO2); } else { co2curr=co2[eceDate.year]; // from year 0+ } } int base_year = CMIP6STARTYEAR; // reset CO2 for CMIP6 experiments // Fixed CO2 of a certain year if ( ifs_FIXEDYEARCO2 > 0 ) { co2curr = co2[ifs_FIXEDYEARCO2]; base_year = ifs_FIXEDYEARCO2; } // abrupt 4xCo2 in base_year if ( ifs_A4xCO2 ) { if ( eceDate.year >= base_year ) { co2curr = 4. * co2[base_year]; } } // 1% / year (exponential) increase from base_year on if ( bgc_1pctCO2 ) { if ( eceDate.year > base_year ) { co2curr = pow(1.01,eceDate.year-base_year) * co2[base_year]; } } if (timestep < 2) { dprintf("fixedYearCO2 set to %d \n",ifs_FIXEDYEARCO2); dprintf("ifs_A4xCO2 set to %d \n",ifs_A4xCO2); dprintf("bgc_1pctCO2 set to %d \n",bgc_1pctCO2); dprintf("fixedLUafter set to %d \n",fixedLUafter); dprintf("fixedNDepafter set to %d \n",fixedNDepafter); dprintf("runlpjguess: timestep %i of %i (%i s)\n",timestep,NTIMESTEP,timestep*TIMESTEP); } if (timestep < 5) { dprintf("CO2 at timestep %i: %d \n",timestep,co2curr); } // mid-Holocene value - ecev3 - T159 // co2curr = 264.4; // Reset on Jan 1? if (printOutputToFile && eceDate.day-1 == 0 && eceDate.month - 1 == 0) { for (int ii = 0; ii < MAXGRID; ii++) { // reset mLAI for (int mm = 0; mm < 12; mm++) { mlailow[ii * 12 + mm] = 0.0; mlaihigh[ii * 12 + mm] = 0.0; mlpjg_fracl[ii * 12 + mm] = 0.0; mlpjg_frach[ii * 12 + mm] = 0.0; } } } // dprintf("Before OASIS GET on node %i \n",myrank); // Call OASIS GET (if not spinning up) if (!islpjgspinup && myrank==0) { call_coupler_get(timestep,temp,prec,vegl,vegl_type,vegh,snowc,snowd,stl,sml,swrad,lwrad,co2_tm5); if (timestep<20) dprintf("runlpjguess: node %i of %i returned from call_coupler_get \n",myrank,local_procs); } //dprintf("Before MPI_Barrier 2 (after call_coupler_get) on node %i \n",myrank); #ifdef HAVE_MPI if (!islpjgspinup && local_procs>1) MPI_Barrier(localcomm); #endif //dprintf("After MPI_Barrier 2 on node %i \n",myrank); // ecev3 - populate the co2_tm5 file with CO2 values from file if we are not coupled to TM5 if (!activateTM5coupling) for (int jj=0; jj1) MPI_Barrier(localcomm); #endif //dprintf("After MPI_Barrier 3 on node %i \n",myrank); // Call OASIS PUT (if not spinning up) if (!islpjgspinup && myrank==0) { call_coupler_put(timestep,lailow,laihigh,lpjg_typeh,lpjg_frach,lpjg_typel,lpjg_fracl,dcfluxnat,dcfluxant,dnpp); if (timestep<20) dprintf("runlpjguess: node %i of %i returned from call_coupler_put \n",myrank,local_procs); } /////////////////////////////////////////////////////////////////////////////// // Advance clock for next timestep // ecev3 - simplify perhaps??? Or move to a new subroutine if (timestep < 2) dprintf("runlpjguess: before clock advance on timestep %i at time %i on day %i of month % i of year %i\n", timestep,eceDate.time,eceDate.day,eceDate.month,eceDate.year); // Need this in case the FIRST year is a leap year if (IFLEAPYEARS) { int yy = eceDate.year; if (!(yy%400)) NDAYMONTH[1]=29; // e.g. year 2000 else if (!(yy%100)) NDAYMONTH[1]=28; // e.g. year 1900 is not a leap year else if (!(yy%4)) NDAYMONTH[1]=29; // else NDAYMONTH[1]=28; } // Print? Only by rank = 0 on Dec 31 in a parallel run if (printOutputToFile && isparallel && !islpjgspinup && myrank==0) { // Run through this loop each day for (int ii = 0; ii < MAXGRID; ii++) { // Save mLAI mlailow[ii * 12 + eceDate.month - 1] += lailow[ii] / NDAYMONTH[eceDate.month - 1]; mlaihigh[ii * 12 + eceDate.month - 1] += laihigh[ii] / NDAYMONTH[eceDate.month - 1]; mlpjg_frach[ii * 12 + eceDate.month - 1] += lpjg_frach[ii] / NDAYMONTH[eceDate.month - 1]; mlpjg_fracl[ii * 12 + eceDate.month - 1] += lpjg_fracl[ii] / NDAYMONTH[eceDate.month - 1]; // Save veg. type and fraction if (eceDate.day == 1) { // Avoid doing this on Dec 31, as the type and fractions are updated then lpjg_typeh_yesterday[ii] = lpjg_typeh[ii]; lpjg_typel_yesterday[ii] = lpjg_typel[ii]; } // Dec 31st? Print! if (eceDate.month == 12 && eceDate.day==31) { EceCoord& c = gridlist[ii]; double alat = (float)c.lat; double alon = (float)c.lon; fprintf(ofp, "%8.6f\t %8.6f\t %d\t", alon, alat, eceDate.year); int mm; for (mm = 0; mm < 12; mm++) { fprintf(ofp, "%8.5f\t", mlailow[ii * 12 + mm]); } for (mm = 0; mm < 12; mm++) { fprintf(ofp, "%8.5f\t", mlaihigh[ii * 12 + mm]); } for (mm = 0; mm < 12; mm++) { fprintf(ofp, "%8.5f\t", mlpjg_fracl[ii * 12 + mm]); } for (mm = 0; mm < 12; mm++) { fprintf(ofp, "%8.5f\t", mlpjg_frach[ii * 12 + mm]); } fprintf(ofp, "%d\t %d\t\n", lpjg_typel_yesterday[ii], lpjg_typeh_yesterday[ii]); } } // for fflush(ofp); } eceDate.time+=TIMESTEP; if (eceDate.time>=24*3600) { // Next day eceDate.time-=24*3600; eceDate.day+=1; if (eceDate.day>NDAYMONTH[eceDate.month-1]) { eceDate.day=1; eceDate.month+=1; if (eceDate.month>12) { eceDate.month=1; eceDate.year++; eceDate.sim_year++; if (IFLEAPYEARS) { int yy = eceDate.year; if (!(yy%400)) NDAYMONTH[1]=29; // e.g. year 2000 else if (!(yy%100)) NDAYMONTH[1]=28; else if (!(yy%4)) NDAYMONTH[1]=29; else NDAYMONTH[1]=28; } } } } timestep++; } /* HEAP approach delete[] temp; delete[] prec; delete[] swrad; delete[] lwrad; delete[] vegl; delete[] vegh; delete[] snowc; delete[] snowd; delete[] lailow; delete[] laihigh; */ if (printOutputToFile) { delete[] mlailow; delete[] mlaihigh; delete[] mlpjg_frach; delete[] mlpjg_fracl; delete[] lpjg_typeh_yesterday; delete[] lpjg_typel_yesterday; fclose(ofp); } guess_coupled_finish(); if(!islpjgspinup){ // All processes must call OASIS-MCT terminate // termination OASIS dprintf("LPJ-GUESS: OASIS terminating...\n"); OasisCoupler::finalize(); dprintf("LPJ-GUESS: OASIS terminated!\n"); } dprintf ("Terminating ...\n"); } // ecev3 - called from main in trunk // int ecemain(int argc,char* argv[]) { int ecemain(const CommandLineArguments& args) { dprintf("Running LPJ-GUESS - in ecemain() in eceframework.cpp ...\n"); bool error_flag = false; // Read grids.nc, masks.nc, soilcd, timesteps and CO2 read_input_data(error_flag); if (!error_flag) { if (args.get_islpjgspinup()) dprintf("ecemain(): read_input_data OK. Now calling runlpjguess for a spinup...\n"); else dprintf("ecemain(): read_input_data OK. Now calling runlpjguess - NO spinup\n"); } else { dprintf("ecemain(): error in read_input_data. Now calling runlpjguess for a spinup...Aborting after OASIS start\n"); } // Run LPJ-GUESS runlpjguess(args.get_islpjgspinup(), args.get_parallel(),error_flag); dprintf("LPJ-GUESS: exiting - ecemain() in eceframework.cpp...\n"); return 0; }