Esempio n. 1
0
    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')
Esempio n. 2
0
 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')
Esempio n. 3
0
 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.vstack((x, y)).transpose(),
                          links=None,
                          inds=inds)  # python2.7 nodes=np.array(zip(x, y))
     return self.grid
Esempio n. 4
0
    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
Esempio n. 5
0
    def get_bmi_attrs(self):
        if self.mod == 'GLOFRIM':  # coupled run
            self.config_fn = self.glofrim_config_fn

        else:  # single run
            if not isfile(self.glofrim_config_fn):
                raise IOError('glofrim inifile not found: {}'.format(
                    self.glofrim_config_fn))
            _config = glib.configread(self.glofrim_config_fn)

            if _config.has_option('models', self.mod):
                config_fn = _config.get('models', self.mod)
                self.config_fn = str(
                    join(ddir, 'model_test_data',
                         _config.get('models', self.mod)))
            else:
                msg = 'config filename not found {} model'
                raise ValueError(msg.format(self.mod))

            # check if bmi component requires engine
            self.requires_engine = 'engine' in getattr(
                glofrim, self.mod).__init__.__code__.co_varnames
            if self.requires_engine:
                if _config.has_option('engines', self.mod):
                    self.engine = glib.getabspath(
                        _config.get('engines', self.mod), ddir)
                else:
                    msg = 'engine path not found for {} model'
                    raise ValueError(msg.format(self.mod))
Esempio n. 6
0
 def init_standalone_bmi(self, _loglevel='INFO'):
     self.bmi = getattr(glofrim, self.mod)
     bmi_kwargs = {'loglevel': _loglevel}
     # check if bmi component requires engine
     if 'engine' in self.bmi.__init__.__code__.co_varnames:
         config = glib.configread(self.env_fn)
         if not config.has_option('engines', self.mod):
             msg = 'GLOFRIM ini or environment file misses a "engines" section with {} option'
             raise ValueError(msg.format(self.mod))
         engine_path = glib.getabspath(config.get('engines', self.mod),
                                       dirname(self.env_fn))
         bmi_kwargs.update(engine=engine_path)
     return self.bmi(**bmi_kwargs)
Esempio n. 7
0
 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')
Esempio n. 8
0
    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
Esempio n. 9
0
    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)
            # read proj string from config file
            if not self._config.has_option('coupling', mod):
                msg = 'GLOFRIM ini or environment file misses a "coupling" section {} option for projection string, assuming lat-lon'
                self.logger.error(msg)
                # raise ValueError(msg.format(mod))
            crs = self._config.get(
                'coupling',
                mod,
                fallback='+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')

            # 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)
            # initialize grid
            self.bmimodels[mod].get_grid()
            # if grid does not have a crs, it will be taken from the config file
            if self.bmimodels[mod].grid.crs is None:
                self.bmimodels[mod].grid.crs = crs

        # 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"))
        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()