def initialize_config(self, config_fn): if self.initialized: raise Warning( "model already initialized, it's therefore not longer possible to initialize the config" ) # config settings if basename(config_fn) == 'input_flood.nam': msg = '"input_flood.nam" is protected and not allowed to be used as configuration file name for \ CaMa-Flood. Rename the input configuration file to e.g. "input_flood.temp"' raise Warning(msg) self._config_fn = abspath(config_fn) self._config = glib.configread(self._config_fn, encoding='utf-8', cf=NamConfigParser()) # model time self._dt = self.get_time_step() self._startTime = self.get_start_time() self._endTime = self.get_end_time() self._t = self._startTime # model units rofunit = float( self.get_attribute_value('CONF:DROFUNIT').replace('D', 'e')) self._var_units['roffin'] = {1: 'm', 1e-3: 'mm'}[rofunit] # model files _root = dirname(self._config_fn) # mapdir where nextxy data is found self._mapdir = dirname( glib.getabspath( str(self.get_attribute_value('MAP:CNEXTXY').strip('"')), _root)) self._outdir = glib.getabspath( str(self.get_attribute_value('OUTPUT:COUTDIR').strip('"')), _root) self.logger.info('Config initialized')
def initialize_config(self, config_fn, config_defaults={}): if self.initialized: raise Warning( "model already initialized, it's therefore not longer possible to initialize the config" ) # config settings defaults = { 'refdate': '2000-01-01' } # default refdate as this setting is not mandatory in LFP par settings file defaults.update(**config_defaults) self._config_fn = abspath(config_fn) self._config = glib.configread(self._config_fn, encoding='utf-8', cf=ParConfigParser(defaults=defaults)) self._datefmt = "%Y-%m-%d" # model time self._dt = self.get_time_step() self._startTime = self.get_start_time() self._endTime = self.get_end_time() self._t = self._startTime # model files _root = dirname(self._config_fn) # mapdir where nextxy data is found self._mapdir = dirname( glib.getabspath(str(self.get_attribute_value('DEMfile')), _root)) self._outdir = glib.getabspath( str(self.get_attribute_value('dirroot')), _root) self.logger.info('Config initialized')
def get_grid(self): """Retreving spatial information about model domain from PCR-GLOBWB landmask file using rasterio operations; also retrieving PCR-GLOBWB drainage direction (LDD) information Raises: IOError -- function requires LDD file; if not found, IOerror is raised IOError -- function requires landsmask file; if not found, IOerror is raised Returns: grid -- rasterio grid object """ if not hasattr(self, 'grid') or (self.grid is None): # ldd is used for coupling to routing / flood model _indir = abspath( self.get_attribute_value('globalOptions:inputDir')) _ldd_fn = glib.getabspath( self.get_attribute_value('routingOptions:lddMap'), _indir) if not isfile(_ldd_fn): raise IOError('ldd file not found {}'.format(_ldd_fn)) # landmask used for masking out coordinates outside mask if provided _lm_fn = glib.getabspath( self.get_attribute_value('globalOptions:landmask'), _indir) if isfile(_lm_fn): with rasterio.open(_lm_fn, 'r') as ds: mask = ds.read(1) == 1 mask_name = basename(_lm_fn) # use ldd for masking else: mask = None mask_name = basename(_ldd_fn) self.logger.info( 'Getting rgrid info based on {}; mask based on {}'.format( basename(_ldd_fn), mask_name)) with rasterio.open(_ldd_fn, 'r') as ds: if mask is None: mask = ds.read(1) != ds.nodata self.grid = RGrid(ds.transform, ds.height, ds.width, crs=ds.crs, mask=mask) # read file with pcr readmap self.logger.info('Getting drainage direction from {}'.format( basename(_ldd_fn))) self.grid.set_dd(_ldd_fn, ddtype='ldd') self.grid.get_pits() return self.grid
def get_grid(self, fn_catmxy=r'./hires/reg.catmxy.tif', **kwargs): if not hasattr(self, 'grid') or (self.grid is None): _root = dirname(self._config_fn) # fn_catmx fn may be relative to folder where nextxy is found fn_params = join(self._mapdir, 'params.txt') if not isfile(fn_params): raise IOError("Params.txt file not found {}".format(fn_params)) # fn_catmx fn may be relative to folder where nextxy is found fn_catmxy = glib.getabspath(fn_catmxy, self._mapdir) if not isfile(fn_catmxy): fn_catmxy = None self.logger.warn( "Unit-Catchment file not found {}; indexing not possible". format(fn_catmxy)) # drainage direction _nextxy_fn = glib.getabspath( str(self.get_attribute_value('MAP:CNEXTXY').strip('"')), _root) _nextxy_fn = _nextxy_fn.replace('.bin', '.tif') # get grid info self.logger.info( 'Getting Unit-Catchment Grid info based on {}'.format( basename(fn_params))) params = read_params(fn_params) transform = rasterio.transform.from_origin(params['west'], params['north'], params['res'], params['res']) # TODO: set crs self.grid = UCGrid(transform, params['height'], params['width'], fn_catmxy=fn_catmxy) # with rasterio.open(_nextxy_fn, 'r') as ds: # ds.transform == transform # ds.height == params['height'] # ds.width == params['width'] # add drainage direction if isfile( _nextxy_fn ): #raise IOError('nextxy file {} not found'.format(_nextxy_fn)) self.logger.info('Getting drainage direction from {}'.format( basename(_nextxy_fn))) self.grid.set_dd(_nextxy_fn, ddtype='nextxy', **kwargs) else: self.logger.warn( 'No drainage direction file found {}; getting upstream cells not possible.' .format(basename(_nextxy_fn))) return self.grid
def get_grid(self): if not hasattr(self, 'grid') or (self.grid is None): # dem file used for rgrid and mask of 2D domain _dem_fn = glib.getabspath(str(self.get_attribute_value('DEMfile')), self._mapdir) if not isfile(_dem_fn): raise IOError('DEMfile file not found') self.logger.info('Getting rgrid info based on {}'.format( basename(_dem_fn))) with rasterio.open(_dem_fn, 'r') as ds: self.grid = RGrid(ds.transform, ds.height, ds.width, crs=ds.crs, mask=ds.read(1) != ds.nodata) # riv width file used for "1D coords" _width_fn = glib.getabspath( str(self.get_attribute_value('SGCwidth')), self._mapdir) if not isfile(_width_fn): raise IOError('SGCwidth file not found') with rasterio.open(_width_fn, 'r') as ds: row, col = np.where(ds.read(1) > 0) x, y = self.grid.xy(row=row, col=col) inds = self.grid.ravel_multi_index(row, col) self.grid.set_1d(nodes=np.array(zip(x, y)), links=None, inds=inds) return self.grid
def initialize_config(self, config_fn): if self.initialized: raise Warning( "model already initialized, it's therefore not longer possible to initialize the config" ) # config settings self._config_fn = abspath(config_fn) self._config = glib.configread( self._config_fn, encoding='utf-8', cf=ConfigParser(inline_comment_prefixes=('#'))) self._datefmt = "%Y%m%d" # model time self._timeunit = self.get_time_units() self._dt = self.get_time_step() self._startTime = self.get_start_time() self._endTime = self.get_end_time() self._t = self._startTime # model files _root = dirname(self._config_fn) self._outdir = glib.getabspath( self.get_attribute_value('output:OutputDir'), _root) self.logger.info('Config initialized')
def initialize_config(self, config_fn, env_fn=None): """Initializing the model configuration file. aligning GLOFRIM specifications for coupled runs to be consistent with overall run settings; with environment file (env-file) local paths to model engines can be defined Arguments: config_fn {str} -- path to model configuration file Keyword Arguments: env_fn {str} -- path to environment file (default: {None}) Raises: Warning -- Warning is raised if two-step model initialization is not correctly executed ValueError -- Raised if config-files of models to be coupled are not defined in ini-file ValueError -- Raised if engines (ie executables) for models to be coupled are not specified in ini/env-file """ # log to file add_file_handler(self.logger, abspath(config_fn).replace('.ini', '.log')) if self.initialized: msg = "model already initialized, it's therefore not longer possible to initialize the config" self.logger.warn(msg) raise Warning(msg) # config settings self._config_fn = abspath(config_fn) self._root = dirname(config_fn) self.logger.info('Reading ini file..') self._config = glib.configread( self._config_fn, encoding='utf-8', cf=ConfigParser(inline_comment_prefixes=('#'))) # environment file -> merge with config if given if env_fn is not None and isfile(abspath(env_fn)): env_fn = abspath(env_fn) self.logger.info('Reading env file..') env = glib.configread( env_fn, encoding='utf-8', cf=ConfigParser(inline_comment_prefixes=('#'))) for sect in env.sections(): if sect not in self._config.sections(): self._config.add_section(sect) for opt in env.options(sect): self._config.set( sect, opt, glib.getabspath(env.get(sect, opt), dirname(env_fn))) if self._config.has_option('models', 'root_dir'): self._root = glib.getabspath( self._config.get('models', 'root_dir'), self._root) self._config.remove_option('models', 'root_dir') ## parse glofrim config # initialize bmi component and it's configuration if not self._config.has_section('models'): msg = 'GLOFRIM ini misses a "models" section' self.logger.error(msg) raise ValueError(msg) for mod in self._config.options('models'): bmi_kwargs = {'logger': self.logger, 'loglevel': self._loglevel} _bmi = self._models[mod] # check if bmi component requires engine if 'engine' in _bmi.__init__.__code__.co_varnames: if not self._config.has_option('engines', mod): msg = 'GLOFRIM ini or environment file misses a "engines" section with {} option' self.logger.error(msg) raise ValueError(msg.format(mod)) engine_path = glib.getabspath(self._config.get('engines', mod), self._root) bmi_kwargs.update(engine=engine_path) # initialize bmi component self.bmimodels[mod] = _bmi(**bmi_kwargs) # initialize config of bmi component modconf = glib.getabspath(self._config.get('models', mod), self._root) self.bmimodels[mod].initialize_config(modconf) # parse exchanges section self.exchanges = self.set_exchanges() # create logfile for exchange volumes add_file_handler(self.wb_logger, abspath(config_fn).replace('.ini', '.wb'), formatter=logging.Formatter("%(message)s")) # TODO self._wb_header = ['time'] for mod in self.bmimodels: if hasattr(self.bmimodels[mod], '_get_tot_volume_in'): self._wb_header.append('{}_tot_in'.format(mod)) if hasattr(self.bmimodels[mod], '_get_tot_volume_out'): self._wb_header.append('{}_tot_out'.format(mod)) self._wb_header += [ item[1]['name'] for item in self.exchanges if item[0] == 'exchange' ] self.wb_logger.info(', '.join(self._wb_header)) # combined model time self._dt = timedelta( seconds=int(self._config.get('coupling', 'dt', fallback=86400))) # set start_time & end_time if given if self._config.has_option('coupling', 'start_time'): start_time = datetime.strptime( self._config.get('coupling', 'start_time'), "%Y-%m-%d") self.set_start_time(start_time) if self._config.has_option('coupling', 'end_time'): end_time = datetime.strptime( self._config.get('coupling', 'end_time'), "%Y-%m-%d") self.set_end_time(end_time) self._timeunit = 'sec' self._startTime = self.get_start_time() self._endTime = self.get_end_time() self._t = self._startTime self.initialized = False # check model dt self._check_dt()
def get_grid(self, fn_params=r'params.txt', fn_locs=r'./hires/location.txt', **kwargs): if not hasattr(self, 'grid') or (self.grid is None): _root = dirname(self._config_fn) # read grid definition from params file fn_params = join(self._mapdir, fn_params) if not isfile(fn_params): raise IOError("Params.txt file not found {}".format(fn_params)) self.logger.info( 'Getting Unit-Catchment Grid info based on {}'.format( basename(fn_params))) p = read_params(fn_params) # get hires index info file fn_locs = join(self._mapdir, fn_locs) if not isfile(fn_locs): raise IOError( "locations.txt file for hires index not found {}".format( fn_locs)) # get catchment unit grid instance # TODO: set crs self.grid = UCGrid(p['transform'], p['height'], p['width'], fn_locs) # add drainage direction fn_nextxy = glib.getabspath( str(self.get_attribute_value('MAP:CNEXTXY').strip('"')), _root) if not isfile(fn_locs): raise IOError( "nextxy file for drainage direction data not found {}". format(fn_locs)) self.logger.info('Getting drainage direction from {}'.format( basename(fn_nextxy))) self.grid.set_dd(fn_nextxy, ddtype='nextxy', **kwargs) # set index of pits to calculate total outflow self.grid.get_pits() # set unit catchment mask based on drainage direction mask self.grid.set_mask(self.grid._dd.r.mask[0, :, :] == False) # add 1d network latlon_fn = join(self._mapdir, 'lonlat.bin') if isfile(latlon_fn): ## read data row, col = np.where(self.grid.mask) # get valid row, cols lonlat = np.fromfile(latlon_fn, dtype=np.float32).reshape( 2, self.grid.height, self.grid.width) # read lat lon unit catchment outlets nodes = lonlat[:, row, col].T # outlets at valid cells ## get 1d indices of valid cells inds = self.grid.ravel_multi_index(row, col) ## create links i = np.arange(inds.size) # index of inds id2 = np.ones(self.grid.shape, dtype=np.int32) # 2d index of inds id2[row, col] = i (next_row, next_col), valid = self.grid._dd._nb_downstream_idx(row, col) next_i = id2[next_row, next_col] next_inds = self.grid.ravel_multi_index(next_row, next_col) links = np.vstack([i[valid], next_i]).T # set Network1D object self.grid.set_1d(nodes=nodes, links=links, inds=inds, ds_idx=next_inds, us_idx=inds[valid]) else: Warning( '"lonlat.bin" file not found in map directory. no 1d network created' ) return self.grid