//////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// \file externalinput.cpp /// \brief Input code for land cover area fractions from text files /// \author Mats Lindeskog /// $Date: $ //////////////////////////////////////////////////////////////////////////////////////////////////////////////// #include "externalinput.h" #include "eceframework.h" // ecev3 #include "config.h" // ecev3 - for ECEARTH boolean void read_gridlist(ListArray_id& gridlist, const char* file_gridlist) { // Reads list of grid cells and (optional) description text from grid list file // This file should consist of any number of one-line records in the format: // [] double dlon, dlat; bool eof = false; xtring descrip; // Read list of grid coordinates and store in Coord object 'gridlist' FILE* in_grid = fopen(file_gridlist,"r"); if (!in_grid) fail("initio: could not open %s for input", (char*)file_gridlist); while (!eof) { // Read next record in file eof =! readfor(in_grid, "f,f,a#", &dlon, &dlat, &descrip); if (!eof && !(dlon == 0.0 && dlat == 0.0)) { // ignore blank lines at end (if any) Coord& c = gridlist.createobj(); // add new coordinate to grid list c.lon = dlon; c.lat = dlat; c.descrip = descrip; } } fclose(in_grid); gridlist.firstobj(); } LandcoverInput::LandcoverInput() : nyears_cropland_ramp(0) { declare_parameter("minimizecftlist", &minimizecftlist, "Whether pfts not in crop fraction input file are removed from pftlist (0,1)"); declare_parameter("nyears_cropland_ramp", &nyears_cropland_ramp, 0, 10000, "Number of years to increase cropland fraction linearly from 0 to first year's value"); declare_parameter("frac_fixed_default_crops", &frac_fixed_default_crops, " whether to use all active crop stand types (0) or only stand types with suitable rainfed crops (based on crop pft tb and gridcell latitude) (1) when using fixed crop fractions"); } void LandcoverInput::init() { if(!run_landcover) return; ListArray_id gridlist; read_gridlist(gridlist, param["file_gridlist"].str); all_fracs_const=true; //If any of the opened files have yearly data, all_fracs_const will be set to false and landcover_dynamics will call get_landcover() each year //Retrieve file names for landcover files and open them if static values from ins-file are not used bool openLUfile = false; for(int i=0; i 50) printseparatestands = false; } } } if (!lcfrac_fixed) { //Read LUC transitions if(gross_land_transfer == 2) { file_grossLUC=param["file_grossLUC"].str; if(!grossLUC.Open(file_grossLUC, gridlist)) fail("initio: could not open %s for input",(char*)file_grossLUC); } } //Retrieve file name for stand type fraction files and open them if static equal-size values are not used. file_lu_st[CROPLAND] = param["file_lucrop"].str; file_lu_st[PASTURE] = param["file_lupasture"].str; file_lu_st[NATURAL] = param["file_lunatural"].str; file_lu_st[FOREST] = param["file_luforest"].str; for(int lc=0; lc= 0) { found = true; break; } stlist.nextobj(); } if(!found) remove = true; } if(remove && !(pft.isintercropgrass && ifintercropgrass)) { n += 1; pftlist.killobj(); npft--; } else { pft.id -= n; pftlist.nextobj(); } } // Remove mt:s from mtlist that are not used in simulated stand types int m = 0; mtlist.firstobj(); while(mtlist.isobj) { bool remove = false; ManagementType& mt = mtlist.getobj(); bool found = false; stlist.firstobj(); while(stlist.isobj) { StandType& st = stlist.getobj(); if(st.mtinrotation(mt.name) >= 0) { found = true; break; } stlist.nextobj(); } if(!found) remove = true; if(remove) { dprintf("Removing mt %s\n", (char*)mt.name); m += 1; mtlist.killobj(); nmt--; } else { mt.id -= m; mtlist.nextobj(); } } gridlist.killall(); } bool LandcoverInput::loadlandcover(double lon, double lat) { Coord c; c.lon = lon; c.lat = lat; bool LUerror = false; // Landcover fraction data: read from land use fraction file; dynamic, so data for all years are loaded to LUdata object and // transferred to gridcell.landcoverfrac each year in getlandcover() if (!lcfrac_fixed) { bool loadLU = false; for(int i=0; i= 0 && year >= gridcell.fixedLUafter ) { year = gridcell.fixedLUafter; dprintf("landcover fixed to year %d \n", year); } else dprintf("landcover dynamic at year %d \n", year); //Save old fraction values: for(int i=0; i= LUdata.GetFirstyear() && LUdata.GetFirstyear() >= 0; bool getLU = false; double sum = 0.0; for(int i=0; i 1.01) { // discard unreasonable values if(printyear) dprintf("WARNING ! %d landcover %d %s fraction size %f out of limits, set to 1.0\n", date.get_calendar_year(), i, lcnames[i], lcfrac); lcfrac = 1.0; } lc.frac[i] = lcfrac; sum_tot += lcfrac; sum_active += run[i] * lc.frac[i]; } } if (grassforcrop) { lc.frac[PASTURE]+=lc.frac[CROPLAND]; lc.frac[CROPLAND]=0.0; } if(sum_tot != 1.0 && sum_tot != 0.0) { // Check input data, rescale if sum !=1.0 sum_active = 0.0; // reset sum of active landcover fractions if(sum_tot < 0.99 || sum_tot > 1.01) { if(printyear) { dprintf("WARNING ! landcover fraction sum is %4.2f for input year %d\n", sum_tot, year); dprintf("Rescaling landcover fractions !\n"); } } for(int i=0; i1.0 again lc.frac[NATURAL] = 0.0; for(int i=0; i= 0) { if(year < LUdata.GetFirstyear()) { doramp = true; firstyear = LUdata.GetFirstyear(); } } else { if(year < first_historic_year) { doramp = true; firstyear = first_historic_year; } } if(doramp) { int first_reduction_year = first_historic_year - nyear_spinup + (int)(SOLVESOMCENT_SPINEND * (nyear_spinup - freenyears) + freenyears) + 1; int max_ramp_years = firstyear - first_reduction_year; if(nyears_cropland_ramp > max_ramp_years) dprintf("Requested cropland ramp period too long for given nyear_spinup. Maximum is %d.\n", max_ramp_years); double reduce_cropland = min((double)(firstyear - year) / min(nyears_cropland_ramp, max_ramp_years), 1.0) * lc.frac[CROPLAND]; lc.frac[CROPLAND] -= reduce_cropland; lc.frac[NATURAL] += reduce_cropland; } } } // Set fractions for static stand types stlist.firstobj(); while (stlist.isobj) { StandType& st = stlist.getobj(); Gridcellst& gcst = gridcell.st[st.id]; gcst.frac = 0.0; if(nst_lc[st.landcover] == 1) gcst.frac = 1.0; else if(frac_fixed[st.landcover] && (st.landcover != CROPLAND || !frac_fixed_default_crops)) gcst.frac = 1.0 / (double)nst_lc[st.landcover]; stlist.nextobj(); } // Get fractions for dynamic stand types within a land cover for(int lc=0; lc= st_data[lc].GetFirstyear() && st_data[lc].GetFirstyear() >= 0; if(lc == CROPLAND) { sum = get_crop_fractions(gridcell, year, st_data[CROPLAND], sum_tot); } else { if(year == st_data[lc].GetFirstyear() + st_data[lc].GetnYears()) dprintf("Last year of %s st fraction data used from year %d and onwards\n", lcnames[lc], year); for(int i=0; i 1.01) { // correct unreasonable values if(printyear) dprintf("WARNING ! %s fraction size out of limits, set to 1.0\n", lcnames[lc]); frac = 1.0; } if(!st_data[lc].NormalisedData()) frac /= sum_tot; // Scale by same factor as land cover fractions ! sum += gridcell.st[i].frac = frac; } } if(sum == 0.0) { fail("%s st fraction sum is zero. Check input data\n", lcnames[lc]); } } if(sum > 0.0 && st_data[lc].NormalisedData()) { // rescale active fractions so sum is 1.0 stlist.firstobj(); while(stlist.isobj) { StandType& st = stlist.getobj(); Gridcellst& gcst = gridcell.st[st.id]; if(st.landcover == lc) { gcst.frac_old_orig = gcst.frac; gcst.frac /= sum; } stlist.nextobj(); } if((sum < 0.99 || sum > 1.01) && printyear) { // warn if sum is significantly different from 1.0 dprintf("WARNING ! lc %d fraction sum is %5.3f for input year %d\n", lc, sum, year); dprintf("Rescaling lc %d fractions !\n", lc); } } } } // Update landcover frac_change arrays for(int i=0; i INPUT_RESOLUTION) && !(gcst.frac < INPUT_RESOLUTION)) gcst.frac = gcst.frac_old; if(gcst.frac < INPUT_RESOLUTION) gcst.frac = 0.0; gcst.frac_change = gcst.frac - gcst.frac_old ; stlist.nextobj(); } } double LandcoverInput::get_crop_fractions(Gridcell& gridcell, int year, TimeDataD& CFTdata, double sum_tot) { if(!run[CROPLAND] || !gridcell.landcover.frac[CROPLAND] || frac_fixed[CROPLAND] && !frac_fixed_default_crops) return 0.0; bool printyear = year >= CFTdata.GetFirstyear() && CFTdata.GetFirstyear() >= 0; double sum=0.0; Landcover& lc = gridcell.landcover; if(!(frac_fixed[CROPLAND] && frac_fixed_default_crops)) { // sum fractions for active crop pft:s and discard unreasonable values // if crop fraction sum is 0 this year, first try last year's values, then try the following years int first_data_year = CFTdata.GetFirstyear(); int last_data_year = first_data_year + CFTdata.GetnYears() - 1; // first_data_year is -1 for static data if(first_data_year == -1) { first_data_year = year; last_data_year = year; } if(first_data_year != -1 && year == last_data_year + 1) dprintf("Last year of cropland fraction data used from year %d and onwards\n", year); for(int y=year;y<=max(year,last_data_year) + 1;y++) { for(int i=0; i= 0 && year >= gridcell.fixedLUafter) dprintf("Fixed year used is %d, in get_crop_fractions\n", y); if(cropfrac == NOTFOUND) { // crop not found in input file cropfrac = 0.0; } else if(cropfrac < 0.0) { // correct unreasonable values if(printyear && gridcell.landcover.frac[CROPLAND]) dprintf("WARNING ! crop fraction size out of limits, set to 0.0\n"); cropfrac = 0.0; } else if(cropfrac > 1.01) { // correct unreasonable values if(printyear) dprintf("WARNING ! crop fraction size out of limits, set to 1.0\n"); cropfrac = 1.0; } if(!st_data[CROPLAND].NormalisedData()) cropfrac /= sum_tot; sum += gridcell.st[i].frac = cropfrac; } } if(sum) { if(y != year && (printyear || !date.year)) { dprintf("WARNING ! crop fraction sum is 0.0 for year %d while LU[CROPLAND] is > 0 !\n", year); dprintf("Using values for year %d.\n", y); } break; } else if(y == year) { // If no crop values for this year, first try to use last year's values for(int i=0; i 0 !\n", year); dprintf("Using previous values.\n"); } break; } } } if(printyear && !sum) { dprintf("WARNING ! crop fraction sum is 0.0 for year %d while LU[CROPLAND] is > 0 !\n", year); } } // If crop fraction data are missing or if fixed default crops are used, try to find suitable stand types to use. if(sum==0.0) { if(lc.frac[CROPLAND]) { // Use equal areas of rainfed stand types with tropical or temperate crop pft:s based on base temperatures int nsts = 0; stlist.firstobj(); while(stlist.isobj) { StandType& st = stlist.getobj(); Gridcellst& gcst = gridcell.st[st.id]; if(st.landcover == CROPLAND) { if(st.rotation.ncrops == 1 && st.get_management(0).hydrology == RAINFED) { if(gridcell.get_lat() > 30 || gridcell.get_lat() < -30) { if(pftlist[pftlist.getpftid(st.get_management(0).pftname)].tb <= 5) { gcst.frac = 1.0; nsts++; } } else { if(pftlist[pftlist.getpftid(st.get_management(0).pftname)].tb > 5) { gcst.frac = 1.0; nsts++; } } } } stlist.nextobj(); } if(nsts) { if(lc.frac[CROPLAND] && (printyear || !date.year) && !(frac_fixed[CROPLAND] && frac_fixed_default_crops)) dprintf("Missing crop fraction data. Using available suitable stand types for year %d\n", year); } else { fail("No suitable default stand types available for filling missing data. Check crop fraction input data\n\n"); } stlist.firstobj(); while(stlist.isobj) { StandType& st = stlist.getobj(); Gridcellst& gcst = gridcell.st[st.id]; if(st.landcover == CROPLAND) { gcst.frac /= nsts; gcst.frac_old_orig = gcst.frac; } stlist.nextobj(); } } } return sum; } bool LandcoverInput::get_land_transitions(Gridcell& gridcell) { // ecev3 - override to force the use of (usually 1850) landuse data during spinup or during fixed year experiments if (ECEARTH && (gridcell.isspinup || gridcell.fixedLUafter >= 0)) return false; bool result = false; if(gross_land_transfer == 3) { // Read stand type transfer fractions from file here and put them into the st_frac_transfer array. // Landcover and stand type net fractions still need to be read from file as previously. // return get_st_transfer(gridcell); dprintf("Currently no code for option gross_land_transfer==3\n"); } else if(gross_land_transfer == 2) { // Read landcover transfer fractions from file here and put them into the st_frac_transfer array. // Landcover and stand type net fractions still need to be read from file as previously. result = get_lc_transfer(gridcell); } return result; } /// Read LUC transitions bool LandcoverInput::get_lc_transfer(Gridcell& gridcell) { double tot_frac_ch = 0.0; Landcover& lc = gridcell.landcover; if(!grossLUC.isloaded() || date.get_calendar_year() < getfirsthistyear() + 1) return false; // Before second year of net land cover input gross_lc_change_frac must be zero. int year = date.get_calendar_year() - 1; // Assume that transitions in file are correct at end of year, therefore want to get // "last year's" transitions, as landcover_dynamics is called at the beginning of the year. // Transfers from primary (v) and secondary (s) land preferentially reduces the oldest and the // youngest stands, respectively. Transitions from primary to secondary NATURAL land result // in killing of vegetation and creating a new NATURAL stand. const bool use_barren_transfers = false; const bool use_urban_transfers = true; double frac_transfer; lc.frac_transfer[CROPLAND][PASTURE] += (frac_transfer = grossLUC.Get(year,"cp")) != NOTFOUND ? frac_transfer : 0.0; lc.frac_transfer[PASTURE][CROPLAND] += (frac_transfer = grossLUC.Get(year,"pc")) != NOTFOUND ? frac_transfer : 0.0; lc.frac_transfer[PASTURE][NATURAL] += (frac_transfer = grossLUC.Get(year,"pv")) != NOTFOUND ? frac_transfer : 0.0; lc.frac_transfer[NATURAL][PASTURE] += (frac_transfer = grossLUC.Get(year,"vp")) != NOTFOUND ? frac_transfer : 0.0; lc.frac_transfer[NATURAL][CROPLAND] += (frac_transfer = grossLUC.Get(year,"vc")) != NOTFOUND ? frac_transfer : 0.0; lc.frac_transfer[CROPLAND][NATURAL] += (frac_transfer = grossLUC.Get(year,"cv")) != NOTFOUND ? frac_transfer : 0.0; lc.frac_transfer[NATURAL][CROPLAND] += (frac_transfer = grossLUC.Get(year,"sc")) != NOTFOUND ? frac_transfer : 0.0; lc.frac_transfer[CROPLAND][NATURAL] += (frac_transfer = grossLUC.Get(year,"cs")) != NOTFOUND ? frac_transfer : 0.0; lc.frac_transfer[NATURAL][PASTURE] += (frac_transfer = grossLUC.Get(year,"sp")) != NOTFOUND ? frac_transfer : 0.0; lc.frac_transfer[PASTURE][NATURAL] += (frac_transfer = grossLUC.Get(year,"ps")) != NOTFOUND ? frac_transfer : 0.0; if(use_barren_transfers) { lc.frac_transfer[BARREN][CROPLAND] += (frac_transfer = grossLUC.Get(year,"bc")) != NOTFOUND ? frac_transfer : 0.0; lc.frac_transfer[CROPLAND][BARREN] += (frac_transfer = grossLUC.Get(year,"cb")) != NOTFOUND ? frac_transfer : 0.0; lc.frac_transfer[BARREN][PASTURE] += (frac_transfer = grossLUC.Get(year,"bp")) != NOTFOUND ? frac_transfer : 0.0; lc.frac_transfer[PASTURE][BARREN] += (frac_transfer = grossLUC.Get(year,"pb")) != NOTFOUND ? frac_transfer : 0.0; lc.frac_transfer[BARREN][NATURAL] += (frac_transfer = grossLUC.Get(year,"bs")) != NOTFOUND ? frac_transfer : 0.0; lc.frac_transfer[NATURAL][BARREN] += (frac_transfer = grossLUC.Get(year,"sb")) != NOTFOUND ? frac_transfer : 0.0; lc.frac_transfer[NATURAL][BARREN] += (frac_transfer = grossLUC.Get(year,"vb")) != NOTFOUND ? frac_transfer : 0.0; } if(use_urban_transfers) { lc.frac_transfer[URBAN][CROPLAND] += (frac_transfer = grossLUC.Get(year,"uc")) != NOTFOUND ? frac_transfer : 0.0; lc.frac_transfer[CROPLAND][URBAN] += (frac_transfer = grossLUC.Get(year,"cu")) != NOTFOUND ? frac_transfer : 0.0; lc.frac_transfer[URBAN][PASTURE] += (frac_transfer = grossLUC.Get(year,"up")) != NOTFOUND ? frac_transfer : 0.0; lc.frac_transfer[PASTURE][URBAN] += (frac_transfer = grossLUC.Get(year,"pu")) != NOTFOUND ? frac_transfer : 0.0; lc.frac_transfer[URBAN][NATURAL] += (frac_transfer = grossLUC.Get(year,"us")) != NOTFOUND ? frac_transfer : 0.0; lc.frac_transfer[NATURAL][URBAN] += (frac_transfer = grossLUC.Get(year,"su")) != NOTFOUND ? frac_transfer : 0.0; lc.frac_transfer[NATURAL][URBAN] += (frac_transfer = grossLUC.Get(year,"vu")) != NOTFOUND ? frac_transfer : 0.0; } if(ifprimary_lc_transfer) { lc.forest_lc_frac_transfer_s.primary[NATURAL][PASTURE] += (frac_transfer = grossLUC.Get(year,"vp")) != NOTFOUND ? frac_transfer : 0.0; lc.forest_lc_frac_transfer_s.primary[NATURAL][CROPLAND] += (frac_transfer = grossLUC.Get(year,"vc")) != NOTFOUND ? frac_transfer : 0.0; if(use_barren_transfers) lc.forest_lc_frac_transfer_s.primary[NATURAL][BARREN] += (frac_transfer = grossLUC.Get(year,"vb")) != NOTFOUND ? frac_transfer : 0.0; if(use_urban_transfers) lc.forest_lc_frac_transfer_s.primary[NATURAL][URBAN] += (frac_transfer = grossLUC.Get(year,"vu")) != NOTFOUND ? frac_transfer : 0.0; // Use transitions from virgin to secondary natural land. if(ifprimary_to_secondary_transfer) { lc.frac_transfer[NATURAL][NATURAL] += (frac_transfer = grossLUC.Get(year,"vs")) != NOTFOUND ? frac_transfer : 0.0; lc.forest_lc_frac_transfer_s.primary[NATURAL][NATURAL] += (frac_transfer = grossLUC.Get(year,"vs")) != NOTFOUND ? frac_transfer : 0.0; } } for(int from=0; from 1.0e-15) { error = true; if(print_adjustment_info) { dprintf("\nYear %d: In get_lc_transfer: lc_change_array sum not equal to landcoverfrac_change value for landcover %d\n", date.year, from); dprintf("dif=%.15f\n", net_lc_change[from] - landcoverfrac_change[from]); dprintf("lc_change_array sum=%.15f\n", net_lc_change[from]); dprintf("landcoverfrac_change=%.15f\n", landcoverfrac_change[from]); } } } } // Save forest class percentages before correcting transitions double prim_ratio[NLANDCOVERTYPES][NLANDCOVERTYPES]; double sec_young_ratio[NLANDCOVERTYPES][NLANDCOVERTYPES]; memset(prim_ratio, 0, NLANDCOVERTYPES * NLANDCOVERTYPES * sizeof(double)); memset(sec_young_ratio, 0, NLANDCOVERTYPES * NLANDCOVERTYPES * sizeof(double)); for(int from=0; from 1.0e-15) { for(int second=0; second= twoway_overshoot && lc_frac_transfer[third][second] >= twoway_overshoot && lc_frac_transfer[third][first] >= twoway_overshoot && first != second && first != third) { if(print_adjustment_info) { dprintf("\nYear %d: Trying to balance two-way overshoot %.18f of lc %d.\n", date.year, twoway_overshoot, first); dprintf("lc_frac_transfer[%d][%d] before: %.15f\n", first, second, lc_frac_transfer[first][second]); dprintf("lc_frac_transfer[%d][%d] before: %.15f\n", third, second, lc_frac_transfer[third][second]); dprintf("lc_frac_transfer[%d][%d] before: %.15f\n", third, first, lc_frac_transfer[third][first]); } lc_frac_transfer[first][second] -= twoway_overshoot; lc_frac_transfer[third][second] += twoway_overshoot; lc_frac_transfer[third][first] -= twoway_overshoot; gross_lc_decrease[first] -= twoway_overshoot; gross_lc_increase[second] -= twoway_overshoot; gross_lc_decrease[third] += twoway_overshoot; gross_lc_increase[second] += twoway_overshoot; gross_lc_decrease[third] -= twoway_overshoot; gross_lc_increase[first] -= twoway_overshoot; if(print_adjustment_info) { dprintf("\nYear %d: After balancing lc %d.\n", date.year, first); dprintf("lc_frac_transfer[%d][%d] after: %.15f\n", first, second, lc_frac_transfer[first][second]); dprintf("lc_frac_transfer[%d][%d] after: %.15f\n", third, second, lc_frac_transfer[third][second]); dprintf("lc_frac_transfer[%d][%d] after: %.15f\n", third, first, lc_frac_transfer[third][first]); } } } } } } for(int from=0; from 1.0e-15) dprintf("\nYear %d: remaining undershoot %.18f of lc %d.\n\n", date.year, balance, from); balance = gross_lc_increase[from] - gridcell.landcover.frac[from]; if(balance > 1.0e-15) dprintf("\nYear %d: remaining overshoot %.18f of lc %d.\n\n", date.year, balance, from); } } // 2 for(int from=0; from gridcell.landcover.frac[to]) { double balance = gross_lc_increase[to] - gridcell.landcover.frac[to]; if(print_adjustment_info) { dprintf("\nYear %d: Trying to balance overshoot %.18f of lc %d.\n", date.year, balance, to); dprintf("lc_frac_transfer[%d][%d] before: %.15f\n", from, to, lc_frac_transfer[from][to]); dprintf("lc_frac_transfer[%d][%d] before: %.15f\n", to, from, lc_frac_transfer[to][from]); } balance = min(balance, lc_frac_transfer[from][to]); balance = min(balance, lc_frac_transfer[to][from]); lc_frac_transfer[from][to] -= balance; gross_lc_decrease[from] -= balance; gross_lc_increase[from] -= balance; if(from != to) { lc_frac_transfer[to][from] -= balance; gross_lc_decrease[to] -= balance; gross_lc_increase[to] -= balance; } if(print_adjustment_info) { dprintf("lc_frac_transfer[%d][%d] after: %.15f\n", from, to, lc_frac_transfer[from][to]); dprintf("lc_frac_transfer[%d][%d] after: %.15f\n\n", to, from, lc_frac_transfer[to][from]); } } if(gridcell.landcover.frac_old[from] - gross_lc_decrease[from] < 0.0) { double balance = gross_lc_decrease[from] - gridcell.landcover.frac_old[from]; if(print_adjustment_info) { dprintf("\nYear %d: Trying to balance overshoot %.18f of lc %d.\n", date.year, balance, from); dprintf("lc_frac_transfer[%d][%d] before: %.15f\n", from, to, lc_frac_transfer[from][to]); dprintf("lc_frac_transfer[%d][%d] before: %.15f\n", to, from, lc_frac_transfer[to][from]); } balance = min(balance, lc_frac_transfer[from][to]); balance = min(balance, lc_frac_transfer[to][from]); lc_frac_transfer[from][to] -= balance; gross_lc_decrease[from] -= balance; gross_lc_increase[from] -= balance; if(from != to) { lc_frac_transfer[to][from] -= balance; gross_lc_decrease[to] -= balance; gross_lc_increase[to] -= balance; } if(print_adjustment_info) { dprintf("lc_frac_transfer[%d][%d] after: %.15f\n", from, to, lc_frac_transfer[from][to]); dprintf("lc_frac_transfer[%d][%d] after: %.15f\n\n", to, from, lc_frac_transfer[to][from]); } } } } } for(int from=0; from 1.0e-15) dprintf("\nYear %d: remaining undershoot %.18f of lc %d.\n\n", date.year, balance, from); balance = gross_lc_increase[from] - gridcell.landcover.frac[from]; if(balance > 1.0e-15) dprintf("\nYear %d: remaining overshoot %.18f of lc %d.\n\n", date.year, balance, from); } } // Discard obvious artefacts for(int from=0; from frac_remain_old[from] || lc_frac_transfer[from][to] > frac_remain[to]) { if(print_adjustment_info) { dprintf("\nYear %d: Adjusting transfer %.18f from lc %d to %d\n", date.year, lc_frac_transfer[from][to], from, to); dprintf("frac_old[%d]=%.15f, frac[%d]=%.15f\n\n", from, gridcell.landcover.frac_old[from], to, gridcell.landcover.frac[to]); } double transfer = min(lc_frac_transfer[from][to], min(frac_remain_old[from], frac_remain[to])); gross_lc_decrease[from] -= lc_frac_transfer[from][to] - transfer; gross_lc_increase[to] -= lc_frac_transfer[from][to] - transfer; net_lc_change[from] += lc_frac_transfer[from][to] - transfer; net_lc_change[to] -= lc_frac_transfer[from][to] - transfer; tot_frac_ch -= lc_frac_transfer[from][to] - transfer; lc_frac_transfer[from][to] = transfer; frac_remain_old[from] -= transfer; frac_remain[to] -= transfer; } } } } // Adjust transitions for lc:s with net changes deviating from the landcover fractions if(error) { double partition_adjustment[NLANDCOVERTYPES][NLANDCOVERTYPES]; double original_error[NLANDCOVERTYPES] = {0.0}; for(int from=0; from 0.0) partition_adjustment[from][to] = lc_frac_transfer[from][to] / (lc_frac_transfer[from][to] + lc_frac_transfer[to][from]); } if(run[from]) original_error[from] = net_lc_change[from] - landcoverfrac_change[from]; if(original_error[from] > 0.0) pos_error += original_error[from]; else if(original_error[from] < 0.0) neg_error += original_error[from]; } if(fabs(pos_error + neg_error) > 1.0e-15) fail("\nYear %d: pos_error + neg_error = %.15f\n\n", date.year, pos_error + neg_error); // 1. Only lc:s with existing opposing errors are altered. double residual_error[NLANDCOVERTYPES] = {0.0}; for(int from=0; from 1.0e-15) { if(print_adjustment_info) dprintf("\nresidual_error[%d] before = %.15f\n", from, residual_error[from]); for(int to=0; to 1.0e-15 && run[to] && fabs(residual_error[to]) > 1.0e-15 && from != to) { // Errors must have opposite signs if(fabs(residual_error[from] + residual_error[to]) - (fabs(residual_error[from]) + fabs(residual_error[to])) < -1.0e-15) { if(print_adjustment_info) dprintf("Trying with lc %d and %d\n", from, to); // Correct transfer between two lc:s if((lc_frac_transfer[from][to] + lc_frac_transfer[to][from]) > 0.0) { if(print_adjustment_info) { dprintf("Before: transfer lc %d to %d: %.15f\n", from, to, lc_frac_transfer[from][to]); dprintf("Before: transfer lc %d to %d: %.15f\n", to, from, lc_frac_transfer[to][from]); } double effective_corr; if(residual_error[from] >= 0.0) { effective_corr = min(residual_error[from], fabs(residual_error[to])); // Make sure lc_frac_transfer[to][from] not negative if(partition_adjustment[to][from]) effective_corr = min(effective_corr, lc_frac_transfer[to][from] / partition_adjustment[to][from]); // Make sure resulting frac[to] not overshot and frac[from] not depleted if(partition_adjustment[from][to]) { effective_corr = min(effective_corr, max(0.0, gridcell.landcover.frac[to] - gross_lc_increase[to]) / partition_adjustment[from][to]); effective_corr = min(effective_corr, max(0.0, gridcell.landcover.frac_old[from] - gross_lc_decrease[from]) / partition_adjustment[from][to]); } } else { effective_corr = max(residual_error[from], -residual_error[to]); // Make sure lc_frac_transfer[from][to] not negative if(partition_adjustment[from][to]) effective_corr = max(effective_corr, -lc_frac_transfer[from][to] / partition_adjustment[from][to]); // Make sure resulting frac[from] not overshot and frac[to] not depleted if(partition_adjustment[to][from]) { effective_corr = max(effective_corr, -max(0.0, gridcell.landcover.frac[from] - gross_lc_increase[from]) / partition_adjustment[to][from]); effective_corr = max(effective_corr, -max(0.0, gridcell.landcover.frac_old[to] - gross_lc_decrease[to]) / partition_adjustment[to][from]); } } lc_frac_transfer[from][to] += effective_corr * partition_adjustment[from][to]; lc_frac_transfer[to][from] -= effective_corr * partition_adjustment[to][from]; residual_error[from] -= effective_corr; residual_error[to] += effective_corr; gross_lc_decrease[from] += effective_corr * partition_adjustment[from][to]; gross_lc_increase[from] -= effective_corr * partition_adjustment[to][from]; gross_lc_decrease[to] -= effective_corr * partition_adjustment[to][from]; gross_lc_increase[to] += effective_corr * partition_adjustment[from][to]; if(print_adjustment_info) { dprintf("After: transfer lc %d to %d: %.15f\n", from, to, lc_frac_transfer[from][to]); dprintf("After: transfer lc %d to %d: %.15f\n", to, from, lc_frac_transfer[to][from]); } } } } } if(print_adjustment_info) dprintf("residual_error[%d] after = %.15f\n", from, residual_error[from]); } } // 2. Using third lc for(int from=0; from 1.0e-15) { if(print_adjustment_info) dprintf("\nresidual_error[%d] before = %.15f\n", from, residual_error[from]); for(int to=0; to 1.0e-15 && run[to] && fabs(residual_error[to]) > 1.0e-15 && from != to) { // Errors must have opposite signs if(fabs(residual_error[from] + residual_error[to]) - (fabs(residual_error[from]) + fabs(residual_error[to])) < -1.0e-15) { if(print_adjustment_info) dprintf("Trying with lc %d and %d\n", from, to); if(print_adjustment_info) dprintf("\nUsing third land cover type\n"); for(int third=0; third 0.0 && lc_frac_transfer[to][third] + lc_frac_transfer[third][to] && third != from && third != to) { if(print_adjustment_info) { dprintf("Before: transfer lc %d to %d: %.15f\n", from, third, lc_frac_transfer[from][third]); dprintf("Before: transfer lc %d to %d: %.15f\n", third, from, lc_frac_transfer[third][from]); dprintf("Before: transfer lc %d to %d: %.15f\n", to, third, lc_frac_transfer[to][third]); dprintf("Before: transfer lc %d to %d: %.15f\n", third, to, lc_frac_transfer[third][to]); } double effective_corr; if(residual_error[from] >= 0.0) { effective_corr = min(residual_error[from], fabs(residual_error[to])); // Make sure lc_frac_transfer[third][from] not negative if(partition_adjustment[third][from]) effective_corr = min(effective_corr, lc_frac_transfer[third][from] / partition_adjustment[third][from]); // Make sure resulting frac[third] not overshot and frac[from] not depleted if(partition_adjustment[from][third]) { effective_corr = min(effective_corr, max(0.0, gridcell.landcover.frac[third] - (gross_lc_increase[third] + effective_corr * partition_adjustment[to][third])) / partition_adjustment[from][third]); effective_corr = min(effective_corr, max(0.0, gridcell.landcover.frac_old[from] - gross_lc_decrease[from]) / partition_adjustment[from][third]); } // Make sure lc_frac_transfer[to][third] not negative if(partition_adjustment[to][third]) effective_corr = min(effective_corr, lc_frac_transfer[to][third] / partition_adjustment[to][third]); // Make sure resulting frac[to] not overshot and frac[third] not depleted if(partition_adjustment[third][to]) { effective_corr = min(effective_corr, max(0.0, gridcell.landcover.frac[to] - gross_lc_increase[to]) / partition_adjustment[third][to]); effective_corr = min(effective_corr, max(0.0, gridcell.landcover.frac_old[third] - (gross_lc_decrease[third] + effective_corr * partition_adjustment[third][from])) / partition_adjustment[third][to]); } } else { effective_corr = max(residual_error[from], -residual_error[to]); // Make sure lc_frac_transfer[from][third] not negative if(partition_adjustment[from][third]) effective_corr = max(effective_corr, -lc_frac_transfer[from][third] / partition_adjustment[from][third]); // Make sure resulting frac[from] not overshot and frac[third] not depleted if(partition_adjustment[third][from]) { effective_corr = max(effective_corr, -max(0.0, gridcell.landcover.frac[from] - gross_lc_increase[from]) / partition_adjustment[third][from]); effective_corr = max(effective_corr, -max(0.0, gridcell.landcover.frac_old[third] - (gross_lc_decrease[third] - effective_corr * partition_adjustment[third][to])) / partition_adjustment[third][from]); } // Make sure lc_frac_transfer[third][to] not negative if(partition_adjustment[third][to]) effective_corr = max(effective_corr, -lc_frac_transfer[third][to] / partition_adjustment[third][to]); // Make sure resulting frac[third] not overshot and frac[to] not depleted if(partition_adjustment[to][third]) { effective_corr = max(effective_corr, -max(0.0, gridcell.landcover.frac[third] - (gross_lc_increase[third] - effective_corr * partition_adjustment[from][third])) / partition_adjustment[to][third]); effective_corr = max(effective_corr, -max(0.0, gridcell.landcover.frac_old[to] - gross_lc_decrease[to]) / partition_adjustment[to][third]); } } lc_frac_transfer[from][third] += effective_corr * partition_adjustment[from][third]; lc_frac_transfer[third][from] -= effective_corr * partition_adjustment[third][from]; residual_error[from] -= effective_corr; residual_error[third] += effective_corr; lc_frac_transfer[to][third] -= effective_corr * partition_adjustment[to][third]; lc_frac_transfer[third][to] += effective_corr * partition_adjustment[third][to]; residual_error[to] += effective_corr; residual_error[third] -= effective_corr; gross_lc_decrease[from] += effective_corr * partition_adjustment[from][third]; gross_lc_increase[from] -= effective_corr * partition_adjustment[third][from]; gross_lc_decrease[third] -= effective_corr * partition_adjustment[third][from]; gross_lc_increase[third] += effective_corr * partition_adjustment[from][third]; gross_lc_decrease[to] -= effective_corr * partition_adjustment[to][third]; gross_lc_increase[to] += effective_corr * partition_adjustment[third][to]; gross_lc_decrease[third] += effective_corr * partition_adjustment[third][to]; gross_lc_increase[third] -= effective_corr * partition_adjustment[to][third]; if(print_adjustment_info) { dprintf("After: transfer lc %d to %d: %.15f\n", from, third, lc_frac_transfer[from][third]); dprintf("After: transfer lc %d to %d: %.15f\n", third, from, lc_frac_transfer[third][from]); dprintf("After: transfer lc %d to %d: %.15f\n", to, third, lc_frac_transfer[to][third]); dprintf("After: transfer lc %d to %d: %.15f\n", third, to, lc_frac_transfer[third][to]); } } } } } } if(print_adjustment_info) dprintf("residual_error[%d] after = %.15f\n", from, residual_error[from]); } } // 3. New direct transfer if(print_adjustment_info) dprintf("\nDealing with rounding artefacts with new direct transfer\n"); for(int from=0; from 1.0e-15) { if(print_adjustment_info) dprintf("\nresidual_error[%d] before = %.15f\n", from, residual_error[from]); for(int to=0; to 1.0e-15 && run[to] && fabs(residual_error[to]) > 1.0e-15 && from != to) { // Errors must have opposite signs if(fabs(residual_error[from] + residual_error[to]) - (fabs(residual_error[from]) + fabs(residual_error[to])) < -1.0e-15) { if(print_adjustment_info) { dprintf("\nDealing with rounding artefacts with new direct transfer\n"); dprintf("Before: transfer lc %d to %d: %.15f\n", from, to, lc_frac_transfer[from][to]); dprintf("Before: transfer lc %d to %d: %.15f\n", to, from, lc_frac_transfer[to][from]); } double effective_corr; if(residual_error[from] >= 0.0) { effective_corr = min(residual_error[from], fabs(residual_error[to])); effective_corr = min(effective_corr, max(0.0, gridcell.landcover.frac_old[from] - gross_lc_decrease[from])); effective_corr = min(effective_corr, max(0.0, gridcell.landcover.frac[to] - gross_lc_increase[to])); } else { effective_corr = max(residual_error[from], -residual_error[to]); effective_corr = max(effective_corr, -max(0.0, gridcell.landcover.frac_old[to] - gross_lc_decrease[to])); effective_corr = max(effective_corr, -max(0.0, gridcell.landcover.frac[from] - gross_lc_increase[from])); } if(effective_corr >= 0.0) { lc_frac_transfer[from][to] += effective_corr; gross_lc_decrease[from] += effective_corr; gross_lc_increase[to] += effective_corr; } else { lc_frac_transfer[to][from] -= effective_corr; gross_lc_decrease[to] -= effective_corr; gross_lc_increase[from] -= effective_corr; } residual_error[from] -= effective_corr; residual_error[to] += effective_corr; if(print_adjustment_info) { dprintf("After: transfer lc %d to %d: %.15f\n", from, to, lc_frac_transfer[from][to]); dprintf("After: transfer lc %d to %d: %.15f\n", to, from, lc_frac_transfer[to][from]); } } } } if(print_adjustment_info) dprintf("residual_error[%d] after = %.15f\n", from, residual_error[from]); } } // 4. Third lc used, relaxed rules if(print_adjustment_info) dprintf("\nUsing third land cover type, relaxed rules\n"); for(int from=0; from 1.0e-15) { if(print_adjustment_info) dprintf("\nresidual_error[%d] before = %.15f\n", from, residual_error[from]); for(int to=0; to 1.0e-15 && run[to] && fabs(residual_error[to]) > 1.0e-15 && from != to) { // Errors must have opposite signs if(fabs(residual_error[from] + residual_error[to]) - (fabs(residual_error[from]) + fabs(residual_error[to])) < -1.0e-15) { if(print_adjustment_info) dprintf("\nUsing third land cover type, relaxed rules\n"); if(print_adjustment_info) dprintf("Trying again with lc %d and %d\n", from, to); for(int third=0; third 0.0 && third != from && third != to) { if(print_adjustment_info) { dprintf("Before: transfer lc %d to %d: %.15f\n", from, third, lc_frac_transfer[from][third]); dprintf("Before: transfer lc %d to %d: %.15f\n", third, from, lc_frac_transfer[third][from]); dprintf("Before: transfer lc %d to %d: %.15f\n", to, third, lc_frac_transfer[to][third]); dprintf("Before: transfer lc %d to %d: %.15f\n", third, to, lc_frac_transfer[third][to]); } double effective_corr; // Transfer between from and third: if(residual_error[from] >= 0.0) { effective_corr = min(residual_error[from], fabs(residual_error[to])); // Make sure lc_frac_transfer[third][from] not negative if(partition_adjustment[third][from]) effective_corr = min(effective_corr, lc_frac_transfer[third][from] / partition_adjustment[third][from]); // Make sure resulting frac[third] not overshot and frac[from] not depleted if(partition_adjustment[from][third]) { effective_corr = min(effective_corr, max(0.0, gridcell.landcover.frac[third] - gross_lc_increase[third] + effective_corr) / partition_adjustment[from][third]); effective_corr = min(effective_corr, max(0.0, gridcell.landcover.frac_old[from] - gross_lc_decrease[from]) / partition_adjustment[from][third]); } // Make sure resulting frac[to] not overshot and frac[third] not depleted effective_corr = min(effective_corr, max(0.0, gridcell.landcover.frac[to] - gross_lc_increase[to])); effective_corr = min(effective_corr, max(0.0, gridcell.landcover.frac_old[third] - gross_lc_decrease[third] + effective_corr)); } else { effective_corr = max(residual_error[from], -residual_error[to]); // Make sure lc_frac_transfer[from][third] not negative if(partition_adjustment[from][third]) effective_corr = max(effective_corr, -lc_frac_transfer[from][third] / partition_adjustment[from][third]); // Make sure resulting frac[from] not overshot and frac[third] not depleted if(partition_adjustment[third][from]) { effective_corr = max(effective_corr, -max(0.0, gridcell.landcover.frac[from] - gross_lc_increase[from]) / partition_adjustment[third][from]); effective_corr = max(effective_corr, -max(0.0, gridcell.landcover.frac_old[third] - gross_lc_decrease[third] - effective_corr) / partition_adjustment[third][from]); } // Balancing [to][third] transfer: make sure resulting frac[third] not overshot and frac[to] not depleted effective_corr = max(effective_corr, -max(0.0, gridcell.landcover.frac[third] - gross_lc_increase[third] - effective_corr)); effective_corr = max(effective_corr, -max(0.0, gridcell.landcover.frac_old[to] - gross_lc_decrease[to])); } lc_frac_transfer[from][third] += effective_corr * partition_adjustment[from][third]; lc_frac_transfer[third][from] -= effective_corr * partition_adjustment[third][from]; residual_error[from] -= effective_corr; residual_error[third] += effective_corr; gross_lc_decrease[from] += effective_corr * partition_adjustment[from][third]; gross_lc_increase[from] -= effective_corr * partition_adjustment[third][from]; gross_lc_decrease[third] -= effective_corr * partition_adjustment[third][from]; gross_lc_increase[third] += effective_corr * partition_adjustment[from][third]; effective_corr = -effective_corr; if(effective_corr >= 0.0) { effective_corr = min(effective_corr, fabs(residual_error[third])); } else { effective_corr = max(effective_corr, -residual_error[third]); } if(residual_error[to] >= 0.0) { lc_frac_transfer[to][third] += effective_corr; gross_lc_decrease[to] += effective_corr; gross_lc_increase[third] += effective_corr; } else { lc_frac_transfer[third][to] -= effective_corr; gross_lc_decrease[third] -= effective_corr; gross_lc_increase[to] -= effective_corr; } residual_error[to] -= effective_corr; residual_error[third] += effective_corr; if(print_adjustment_info) { dprintf("After: transfer lc %d to %d: %.15f\n", from, third, lc_frac_transfer[from][third]); dprintf("After: transfer lc %d to %d: %.15f\n", third, from, lc_frac_transfer[third][from]); dprintf("After: transfer lc %d to %d: %.15f\n", to, third, lc_frac_transfer[to][third]); dprintf("After: transfer lc %d to %d: %.15f\n", third, to, lc_frac_transfer[third][to]); } } } } } } if(print_adjustment_info) dprintf("residual_error[%d] after = %.15f\n", from, residual_error[from]); } } // Correcting negative transfer fraction if(print_adjustment_info) dprintf("\nCorrecting negative transfer fraction:\n"); for(int from=0; from 1.0e-30) { // Reset "Negative zeros" from equations above silently. dprintf("\nCorrecting negative transfer fraction:\n"); dprintf("Before: transfer lc %d to %d: %.20f\n", from, to, lc_frac_transfer[from][to]); dprintf("Before: transfer lc %d to %d: %.20f\n", to, from, lc_frac_transfer[to][from]); } lc_frac_transfer[to][from] -= lc_frac_transfer[from][to]; lc_frac_transfer[from][to] = 0.0; if(lc_frac_transfer[from][to] > 1.0e-30) { dprintf("After: transfer lc %d to %d: %.20f\n", from, to, lc_frac_transfer[from][to]); dprintf("After: transfer lc %d to %d: %.20f\n\n", to, from, lc_frac_transfer[to][from]); } } } } bool stop = false; for(int from=0; from 1.0e-15) { dprintf("\noriginal_error[%d] before = %.15f\n", from, original_error[from]); dprintf("residual_error[%d] after = %.15f\n", from, residual_error[from]); } if(residual_error[from] > 1.0e-14) stop = true; } if(print_adjustment_info) dprintf("\n"); if(stop) fail("Failing to balance lc transitions"); } // Adjust primary land fractions for(int from=0; from gridlist; read_gridlist(gridlist, param["file_gridlist"].str); if(run[CROPLAND]) { file_sdates=param["file_sdates"].str; if(file_sdates != "") { if(!sdates.Open(file_sdates, gridlist)) fail("initio: could not open %s for input",(char*)file_sdates); readsowingdates = true; } file_hdates=param["file_hdates"].str; if(file_hdates != "") { if(!hdates.Open(file_hdates, gridlist)) fail("initio: could not open %s for input",(char*)file_hdates); readharvestdates = true; } file_Nfert=param["file_Nfert"].str; if( file_Nfert != "") { if(!Nfert.Open(file_Nfert, gridlist)) fail("initio: could not open %s for input",(char*)file_Nfert); readNfert = true; } } if(run_landcover) { file_Nfert_st=param["file_Nfert_st"].str; if( file_Nfert_st != "") { if(!Nfert_st.Open(file_Nfert_st, gridlist)) fail("initio: could not open %s for input",(char*)file_Nfert_st); readNfert_st = true; } file_woodharv_frac = param["file_woodharv_frac"].str; if( file_woodharv_frac != "") { if(!woodharv_frac.Open(file_woodharv_frac, gridlist)) fail("initio: could not open %s for input",(char*)file_woodharv_frac); readwoodharvest_frac = true; } file_woodharv_vol = param["file_woodharv_vol"].str; if( file_woodharv_vol != "") { if(!woodharv_vol.Open(file_woodharv_vol, gridlist)) fail("initio: could not open %s for input",(char*)file_woodharv_vol); readwoodharvest_vol = true; } } gridlist.killall(); } bool ManagementInput::loadmanagement(double lon, double lat) { Coord c; c.lon = lon; c.lat = lat; bool LUerror = false; if(readsowingdates) { if(!sdates.Load(c)) { dprintf("Problems with sowing date input file. EXCLUDING STAND at %.3f,%.3f from simulation.\n\n", c.lon, c.lat); LUerror = true; // skip this stand } } if(readharvestdates && !LUerror) { if(!hdates.Load(c)) { dprintf("Problems with harvest date input file. EXCLUDING STAND at %.3f,%.3f from simulation.\n\n", c.lon, c.lat); LUerror = true; // skip this stand } } if(readNfert && !LUerror) { if(!Nfert.Load(c)) { dprintf("Problems with N fertilization input file. EXCLUDING STAND at %.3f,%.3f from simulation.\n\n", c.lon, c.lat); LUerror = true; // skip this stand dprintf("N fertilization data not found in input file for %.2f,%.2f.\n\n", c.lon, c.lat); } } if(readNfert_st && !LUerror) { if(!Nfert_st.Load(c)) { dprintf("Problems with N fertilization input file. EXCLUDING STAND at %.3f,%.3f from simulation.\n\n", c.lon, c.lat); LUerror = true; // skip this stand dprintf("N fertilization data for stand types not found in input file for %.2f,%.2f.\n\n", c.lon, c.lat); } } if(readwoodharvest_frac && !LUerror) { if(!woodharv_frac.Load(c)) { dprintf("Problems with wood harvest fraction input file. EXCLUDING STAND at %.3f,%.3f from simulation.\n\n", c.lon, c.lat); LUerror = true; // skip this stand dprintf("Wood harvest fraction data for stand types not found in input file for %.2f,%.2f.\n\n", c.lon, c.lat); } } if(readwoodharvest_vol && !LUerror) { if(!woodharv_vol.Load(c)) { dprintf("Problems with wood harvest volume input file. EXCLUDING STAND at %.3f,%.3f from simulation.\n\n", c.lon, c.lat); LUerror = true; // skip this stand dprintf("Wood harvest volume data for stand types not found in input file for %.2f,%.2f.\n\n", c.lon, c.lat); } } return LUerror; } void ManagementInput::getsowingdates(Gridcell& gridcell) { if(!sdates.isloaded()) return; int year = date.get_calendar_year(); int sdates_year = year; // ecev3 - override to force the use of 1850 landuse data during spinup if (ECEARTH && gridcell.isspinup) sdates_year = CMIP6STARTYEAR; // ecev3 - override to force the use of fixed N fert data if (ECEARTH && gridcell.fixedLUafter >= 0 && year >= gridcell.fixedLUafter) { // Override year if fixedLUafter activated sdates_year = gridcell.fixedLUafter; dprintf("Sowing dates fixed to year %i \n",sdates_year); } for(int i=0; i= 0 && year >= gridcell.fixedLUafter) { // Override year if fixedLUafter activated hdates_year = gridcell.fixedLUafter; dprintf("Harvest dates fixed to year %i \n",hdates_year); } for(int i=0; i= 0 && year >= gridcell.fixedLUafter) { // Override year if fixedLUafter activated nfert_year = gridcell.fixedLUafter; dprintf("Nitrogen fertilization fixed to year %i \n",nfert_year); } if(Nfert.isloaded()) { for(int i=0; i= firsthistyear + 1)) { double frac_transfer; int year = calender_year - 1; if(woodharv_frac.isloaded()) { // Avoid using same data twice if(!ifprimary_to_secondary_transfer) { gridcell.landcover.wood_harvest.prim_frac += (frac_transfer = woodharv_frac.Get(year,"primf_harv")) != NOTFOUND ? frac_transfer : 0.0; gridcell.landcover.wood_harvest.prim_frac += (frac_transfer = woodharv_frac.Get(year,"primn_harv")) != NOTFOUND ? frac_transfer : 0.0; } gridcell.landcover.wood_harvest.sec_mature_frac += (frac_transfer = woodharv_frac.Get(year,"secmf_harv")) != NOTFOUND ? frac_transfer : 0.0; gridcell.landcover.wood_harvest.sec_young_frac += (frac_transfer = woodharv_frac.Get(year,"secyf_harv")) != NOTFOUND ? frac_transfer : 0.0; gridcell.landcover.wood_harvest.sec_young_frac += (frac_transfer = woodharv_frac.Get(year,"secnf_harv")) != NOTFOUND ? frac_transfer : 0.0; } if(woodharv_vol.isloaded()) { gridcell.landcover.wood_harvest.prim_vol += (frac_transfer = woodharv_frac.Get(year,"primf_bioh")) != NOTFOUND ? frac_transfer : 0.0; gridcell.landcover.wood_harvest.prim_vol += (frac_transfer = woodharv_frac.Get(year,"primn_bioh")) != NOTFOUND ? frac_transfer : 0.0; gridcell.landcover.wood_harvest.sec_mature_vol += (frac_transfer = woodharv_frac.Get(year,"secmf_bioh")) != NOTFOUND ? frac_transfer : 0.0; gridcell.landcover.wood_harvest.sec_young_vol += (frac_transfer = woodharv_frac.Get(year,"secyf_bioh")) != NOTFOUND ? frac_transfer : 0.0; gridcell.landcover.wood_harvest.sec_young_vol += (frac_transfer = woodharv_frac.Get(year,"secnf_bioh")) != NOTFOUND ? frac_transfer : 0.0; } } } void ManagementInput::getmanagement(Gridcell& gridcell, LandcoverInput& landcover_input) { if(run[CROPLAND]) { //Read sowing dates from input file, put into gridcellpft.sdate_force if(readsowingdates) getsowingdates(gridcell); //Read harvest dates from input file, put into gridcellpft.hdate_force if(readharvestdates) getharvestdates(gridcell); //Read N fertilization from input file, put into gridcellpft.Nfert_read if(readNfert || readNfert_st) getNfert(gridcell); } // Read wood harvest from input file, put into gridcell.landcover.wood_harvest struct if(readwoodharvest_frac || readwoodharvest_vol) getwoodharvest(gridcell, landcover_input); }