//////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// \file indata.cpp /// \brief Classes for text input data (used mainly for landcover input). /// File format can be either line 1:lon lat, line 2 etc.: year data-columns OR line 1: header, /// line 2 etc.: lon lat year data-columns. For local static data, use: lon lat data-columns, /// for global static data, use: dummy data-columns (with "static" as first word in header). /// \author Mats Lindeskog /// $Date: $ //////////////////////////////////////////////////////////////////////////////////////////////////////////////// #include "indata.h" #include "config.h" #include "guess.h" using namespace InData; /// Default value for gridlist and text input spatial resolution. /* Input data will be parsed for finer resolution than the default value. For coarser resolutions, raise default value.or set manually */ const double DEFAULT_SPATIAL_RESOLUTION = 0.5; /// Default value for gridlist and text input spatial resolution for EC-EARTH modelling /* ecev3 - Input data will NO LONGER be parsed for finer resolution than the default value! */ const double ECEARTH_SPATIAL_RESOLUTION = 0.02667; /// Default value for number of land cells in the reduced gaussian grid (T255) for EC-EARTH modelling /* ecev3 - Input data will NO LONGER be parsed for this value! */ #ifdef GRID_T255 const int ECEARTH_LAND_CELLS = 25799; #endif #ifdef GRID_T159 const int ECEARTH_LAND_CELLS = 10407; // T159 #endif // const int ECEARTH_LAND_CELLS = 12245; // T159 LGM /// Write land use fraction data to memory; enables efficient usage of randomised gridlists for parallell simulations const bool LUTOMEMORY = false; // ecev3 - was true // Mapping of input file data when LUTOMEMORY not defined const bool MAPFILE = true; // ecev3 - was false const bool ascendinglongitudes = false; //Not true for randomised gridlists; set to false for now // ecev3 ? bool TimeDataD::item_has_data(char* name) { int column = GetColumn(name); if(column == -1) return false; else return checkdata[column]; } bool TimeDataD::item_in_header(char* name) { if(GetColumn(name) == -1) return false; else return true; } void TimeDataD::CheckIfPresent(ListArray_id& gridlist) { //Requires gutil.h if(checkdata) { delete[] checkdata; year = NULL; } checkdata = new bool[nColumns]; for(int i=0;i 0.0) checkdata[j]=1; } } return; } gridlist.firstobj(); while(gridlist.isobj) { Coord& c=gridlist.getobj(); if(Load(c)) { for(int i=0; i 0.0) checkdata[j] = true; } } } gridlist.nextobj(); } gridlist.firstobj(); rewind(ifp); ischeckingdata = false; } bool TimeDataD::GetHeader(char *cropnames[MAXRECORDS]) const { if(ifheader && header_arr) { for(int i=0; i= nYears) year = nYears - 1; else year = calender_year - firstyear; return year; } void TimeDataD::Get(int calender_year, double* dataX) const { int yearX = CalenderYearToPosition(calender_year); memcpy(dataX, &data[yearX * nColumns], nColumns * sizeof(double)); } double TimeDataD::Get(int calender_year, int column) const { if(memory_copy && !(format == GLOBAL_STATIC || format == GLOBAL_YEARLY)) return memory_copy->Get(calender_year, column); int yearX = CalenderYearToPosition(calender_year); if(column >= nColumns) return 0.0; return data[nColumns * yearX + column]; } double TimeDataD::Get(int calender_year, const char* name) const { if(memory_copy && !(format == GLOBAL_STATIC || format == GLOBAL_YEARLY)) return memory_copy->Get(calender_year, name); int column = -1; for(int i=0; i 0.0 && (sum < 0.99 || sum > 1.01)) unity_data = false; } cell++; } Rewind(); return unity_data; } bool TimeDataD::NormalisedData() { return unity_data; } void TimeDataD::CreateFileMap() { if(format == GLOBAL_STATIC || format == GLOBAL_YEARLY) return; long int pos; int i = 0; // ecev3 - to speed up processing if (ECEARTH && !ECEARTHWITHCRUNCEP) nCells = ECEARTH_LAND_CELLS; else // trunk nCells = GetNCells(); filemap = new CoordPos[nCells]; char mapname[300]; strcpy(mapname, fileName); strcat(mapname, ".map.bin"); FILE *ifp_map = fopen(mapname,"rb"); long lSize; if(ifp_map) { fseek(ifp_map, 0 ,SEEK_END); lSize = ftell(ifp_map); rewind(ifp_map); if(lSize != nCells * sizeof(CoordPos)) { dprintf("Text data map file format is not up to date. New mapping started.\n"); fclose(ifp_map); ifp_map = NULL; } } if(!ifp_map) { rewind(ifp); while(LoadNext(&pos) && i < nCells) { Coord c = GetCoord(); filemap[i].lon = c.lon; filemap[i].lat = c.lat; filemap[i].pos = pos; i++; } rewind(ifp); // Save the file map to file if(ifp_map) fclose(ifp_map); FILE *ofp_map = fopen(mapname,"wb"); if(!ofp_map) fail("File could not be opened for output, quitting\n"); fwrite(filemap, sizeof(CoordPos), nCells, ofp_map); fclose(ofp_map); } else { // File is already mapped, read map from file. fread(filemap, sizeof(CoordPos), nCells, ifp_map); fclose(ifp_map); } } bool TimeDataD::Open(const char* name, ListArray_id& gridlist, double gridlist_offset) { if(Open(name)) { SetOffset(gridlist_offset); if(format == GLOBAL_STATIC || format == GLOBAL_YEARLY) { } else if (LUTOMEMORY) { CopyToMemory(gridlist.nobj, gridlist); } else if (MAPFILE) { CreateFileMap(); } return true; } else { return false; } } fileformat TimeDataD::ParseFormat() { //Checks format, sets nColumns, ifheader and header_arr[]. //Desired format must be set beforehand by program at initiation of class TimeDataD objects (if no header) ! char line[MAXLINE], *p=NULL, s1[MAXRECORDS][MAXNAMESIZE]={'\0'}, s2[MAXRECORDS][MAXNAMESIZE]={'\0'}; int count1 = 0, count2 = 0, offset = 0; fileformat format_local = EMPTY; float d[MAXRECORDS] = {0.0}; //First line: do { if(fgets(line,sizeof(line),ifp)) { p = strtok(line, "\t\n "); if(!p) continue; strncpy(s1[count1], p, MAXNAMESIZE-1); count1++; do { p = strtok(NULL, "\t\n "); if(p) { strncpy(s1[count1], p, MAXNAMESIZE-1); count1++; } } while(p); p = NULL; } else { return EMPTY; } } while(!(count1 > 0)); for(int q=0;q0)); rewind(ifp); if(format==EMPTY) { if(ifheader) format = format_local; else printf("Please set data format at initialization !\n"); } switch(format) { case GLOBAL_YEARLY: if(format_local==GLOBAL_YEARLY || count1>1 && count1==count2) { nColumns = count2 - 1; return GLOBAL_YEARLY; } else { printf("Format in input file is incompatible with GLOBAL_YEARLY flag\n"); return EMPTY; } break; case LOCAL_STATIC: if(format_local == LOCAL_STATIC || count1 > 2 && count1 == count2) { nColumns=count2-2; return LOCAL_STATIC; } else { printf("Format in input file is incompatible with LOCAL_STATIC flag\n"); return EMPTY; } break; case LOCAL_YEARLY: if(format_local == LOCAL_YEARLY || count1 == 2 && count2 > 1) { nColumns = count2 - 1 - offset; return LOCAL_YEARLY; } else { printf("Format in input file is incompatible with LOCAL_YEARLY flag\n"); return EMPTY; } break; case GLOBAL_STATIC: if(format_local == GLOBAL_STATIC || count1 > 1 && count1 == count2) { nColumns = count2 - 1; return GLOBAL_STATIC; } default: printf("Format is not set correctly in file %s !\n", fileName); return EMPTY; } } int TimeDataD::ParseNYears() { int n_yearsX = 0; switch(format) { case GLOBAL_YEARLY: n_yearsX = ParseNYearsGlobal(); break; case LOCAL_YEARLY: n_yearsX = ParseNYearsLocal(); break; default: printf("Format in is uncorrectly set by program for file %s !\n", fileName); return 0; } return n_yearsX; } double TimeDataD::ParseSpatialResolution() { double precision = 100; double dif_lon; double dif_lat; const int maxnsample = 200; int nsample = min(maxnsample, GetNCells()); Coord cvect[maxnsample]; for (int i=0; i 0) i++; } if(ifheader) { nCells = i / nYears; if(i % nYears) error = true; } else { nCells = i / (nYears + 1); if(i % (nYears + 1)) error = true; } if(error) dprintf("Unexpected number of lines ! No.lines=%d, No.cells=%d, No.years=%d\n", i, nCells, nYears); fseek(ifp, oldpos, SEEK_SET); // ecev3 - 0 to SEEK_SET } int TimeDataD::ParseNYearsLocal() { int i = 0, count1 = 0, prevLine = 0, nyears1 = 0, nyears2 = 0, n = 0; char line[MAXLINE]; bool new_coord = false; float d1 = 0,d2 = 0,d3 = 0, d1_prevLine = 0, d2_prevLine = 0; for(i=0; i 0) { if(ifheader && (d1 != d1_prevLine || d2 != d2_prevLine)) { // First line of new coordinate nyears2 = i - prevLine; new_coord = true; firstyear = (int)d3; } else if(count1 == 2 && d1 <= 180.0) { nyears2 = i - prevLine - 1; new_coord = true; } if(new_coord) { if((nyears1 != nyears2) && n > 1) { printf("FORMAT ERROR in input file %s !\n", fileName); return 0; } nyears1 = nyears2; //NB. not set if input file has data for only one coordinate ! prevLine = i; n++; new_coord = false; } else if(!ifheader && i == prevLine + 1) { firstyear = (int)d1; } i++; d1_prevLine = d1; d2_prevLine = d2; } } } if(feof(ifp)) { // Last cell if(ifheader) nyears2 = i - prevLine; else nyears2 = i - prevLine - 1; if((nyears1 != nyears2) && n > 1) { printf("FORMAT ERROR in input file %s !\n", fileName); return 0; } } rewind(ifp); return nyears2; } int TimeDataD::ParseNYearsGlobal() { int count = 0, nyears = 0; char line[MAXLINE]; float d1 = 0,d2 = 0,d3 = 0; if(ifheader) fgets(line,sizeof(line),ifp); while(!feof(ifp)) { if(fgets(line,sizeof(line),ifp)) { count=sscanf(line,"%f%f%f", &d1, &d2 ,&d3); if(count > 0) { if(count >= 2) { nyears++; if(nyears == 1) firstyear = (int)d1; } else { printf("FORMAT ERROR in input file %s !\n", fileName); nyears = 0; break; } } } } rewind(ifp); return nyears; } bool TimeDataD::Allocate() { // Allocates memory for dynamic data: format & nYears must be set before ! if(year) { delete[] year; year = NULL; } if(data) { delete[] data; data = NULL; } switch(format) { case EMPTY: break; case GLOBAL_STATIC: year = new int; data = new double[nColumns]; if(year) *year = 0; if(data) *data = 0; break; case GLOBAL_YEARLY: year = new int[nYears]; data = new double[nColumns * nYears]; if(year) { for(int i=0;i 0) { if(count == nColumns) { year[i] = yearX; for(int j=0; j (dif_lon + dif_lat)) { min_dist = dif_lon + dif_lat; found_pos = filemap[i].pos; found_i = i; } } } if(found_pos > -1) { SetPosition(found_pos); LoadNext(); if(currentStand.lon != filemap[found_i].lon || currentStand.lat != filemap[found_i].lat) fail("Error in saved file map for %s. Delete map.bin file and retry\n", fileName); loaded = true; } else { loaded = false; } return loaded; } bool TimeDataD::Load(Coord c) { if(format == GLOBAL_STATIC || format == GLOBAL_YEARLY) { loaded = true; return true; } if(offset) { c.lon += offset; c.lat += offset; } if(memory_copy) return memory_copy->Load(c); else if(filemap) return LoadFromMap(c); char line[MAXLINE], *p=NULL; int i = 0, j = 0, k = 0, count1 = 0, nyears = 0, yearX = 0, yearX_previous; float lonX = 0.0, latX = 0.0; double d[MAXRECORDS] = {0.0}; bool error = false; if(ifp) { if(format==LOCAL_YEARLY) { if(FindRecord(c)) { if(year) { for(int i=0;i spatial_resolution / 2.0 || fabs(latX - c.lat) > spatial_resolution / 2.0) { printf("FORMAT ERROR in input file %s for stand at Coordinate %.2f,%.2f: Load(). Wrong coordinates in data file !\n", fileName, c.lon, c.lat); printf("Make sure file has correct DOS/Unix text format\n"); error = true; break; } else { currentStand.lon = lonX; currentStand.lat = latX; } } else { p = strtok(line, "\t\n "); //year } if(!p) continue; sscanf(p, "%d", &yearX); if(yearX != yearX_previous + 1) { printf("FORMAT ERROR in input file %s for stand at Coordinate %.2f,%.2f: Load(). Wrong year in data file ! Missing line ?\n", fileName, c.lon, c.lat); error=1; } yearX_previous = yearX; do { p = strtok(NULL, "\t\n "); if(p) count1 += sscanf(p, "%lf", &d[k]); k++; } while(p); if(count1 > 0) { if(count1 == nColumns) { year[i] = yearX; for(j=0; j 0) { if(count1 == nColumns) { for(j=0; jisloaded(); else return loaded; } bool TimeDataD::LoadNext(long int *pos) { // To be called after ParseFormat(), ParseNYears() and Allocate() // Only implemented for LOCAL_YEARLY and LOCAL_STATIC // Needs to be modified to handle missing lines in data files with header ! (see Load) if(format == GLOBAL_STATIC || format == GLOBAL_YEARLY) { return 1; } char line[MAXLINE], *p=NULL; double d1, d2, d3, d[MAXRECORDS]={0.0}; bool error = false, firstyear = true; long int fpos; if(ifp && !feof(ifp)) { if(format == LOCAL_YEARLY) { if(year) { for(int i=0;i 0) { // Avoid blank lines at the end of the file if(count == 2 || count > 2 && (format == LOCAL_STATIC || ifheader)) { currentStand.lon = d1; currentStand.lat = d2; } else { printf("FORMAT ERROR in input file %s: LoadNext(), count!=2\n", fileName); error = true; } } else { printf("WARNING: blank line in file %s: LoadNext(), count==0\n", fileName); } } else { error = true; } for(int i=0; i0;) { if(ifheader && firstyear) firstyear = false; else fgets(line, sizeof(line), ifp); if(line) { int k = 0; int count1 = 0; int yearX = 0; for(int q=0;q 0) { if(count1 == nColumns) { year[i] = yearX; for(int j=0; j 0) { // Avoid blank lines at the end of the file if(count == 2 || count > 2 && (format == LOCAL_STATIC || ifheader)) { currentStand.lon = d1; currentStand.lat = d2; } else { printf("FORMAT ERROR in input file %s: LoadNext(), count!=2\n", fileName); error = true; } } else { printf("WARNING: blank line in file %s: LoadNext(), count==0\n", fileName); } } else { error = true; } for(int i=0; i0;) { int k = 0; int count1 = 0; if(ifheader && firstyear) firstyear = false; else fgets(line, sizeof(line), ifp); if(line) { for(int q=0;q 0) { if(count1 == nColumns) { for(int j=0; j0) { // Avoid blank line at the end of the file if(count == 2 || count > 2 && (d3 == firstyear || format == LOCAL_STATIC) && (format == LOCAL_STATIC || ifheader)) { if(fabs(d1 - c.lon) <= spatial_resolution / 2.0 && fabs(d2 - c.lat) <= spatial_resolution / 2.0) { found = true; break; } else if(ascendinglongitudes && c.lon0) { // Avoid blank lines at the end of the file if(count==2 || count>2 && d3==firstyear && (format==LOCAL_STATIC || ifheader)) { if(fabs(d1 - c.lon) <= spatial_resolution / 2.0 && fabs(d2 - c.lat) <= spatial_resolution / 2.0) { found=1; break; } else if(ascendinglongitudes && c.lonClose(); delete memory_copy; } if(filemap) delete[] filemap; for(int i=0;i& lonlatlist) { //Requires gutil.h if(format == GLOBAL_STATIC) ncells = 1; memory_copy = new TimeDataDmem; memory_copy->Open(ncells, this->nColumns, this->nYears); memory_copy->CopyFromTimeDataD(*this, lonlatlist); Rewind(); } int TimeDataDmem::CalenderYearToPosition(int calender_year) const { int yearX = calender_year - firstyear; // Use first or last year's data if calender year is not within data period. if(yearX < 0) yearX = 0; else if(yearX >= nYears) yearX = nYears -1; else yearX = calender_year - firstyear; return yearX; } double TimeDataDmem::Get(int calender_year, int column) const { int yearX = CalenderYearToPosition(calender_year); if(currentCell >= 0 && column < nColumns) return data[currentCell][yearX * nColumns + column]; else if(nCells == 1) return data[0][yearX * nColumns + column]; else return 0.0; } double TimeDataDmem::Get(int calender_year, const char* name) const { int column = -1; for(int i=0; i& gridlistX) { //Requires gutil.h int cell_no = 0; for(int q=0;q=0;i--) { // has data close to the gridlist coord already been saved ? dif_lon_saved = fabs(gridlist[i].lon - (cc.lon + offset)); dif_lat_saved = fabs(gridlist[i].lat - (cc.lat + offset)); if(dif_lon_saved <= searchradius && dif_lat_saved <= searchradius) { // is the new data coord closer to the gridlist coord than the already saved coord is ? if((dif_lon_saved + dif_lat_saved) > (dif_lon + dif_lat)) { // This part is probably not needed SetCoord(i, c); Data.Get(celldata); SetData(i, celldata); } done = true; break; // from saved gridlist loop } } if(!done) { SetCoord(cell_no, c); Data.Get(celldata); SetData(cell_no, celldata); cell_no++; nCells++; break; // from gridlist loop } } gridlistX.nextobj(); no++; if(!gridlistX.isobj) gridlistX.firstobj(); } } delete[] celldata; Data.register_memory_copy(this); } TimeDataDmem::TimeDataDmem() { gridlist = NULL; data = NULL; nCells = 0; ifheader = false; for(int i=0;i