def test_parse_modflowgwf_kwargs(shellmound_cfg):
    cfg = deepcopy(shellmound_cfg)
    cfg = MF6model._parse_model_kwargs(cfg)
    kwargs = get_input_arguments(cfg['model'],
                                 mf6.ModflowGwf,
                                 exclude='packages')
    m = MF6model(cfg=cfg, **kwargs)
    sim_path = os.path.normpath(
        m.simulation.simulation_data.mfpath._sim_path).lower()
    assert sim_path == cfg['simulation']['sim_ws'].lower()
    m.write()

    # verify that options were written correctly to namefile
    # newton solver, but without underrelaxation
    nampath = os.path.join(m.model_ws, m.model_nam_file)
    options = read_mf6_block(nampath, 'options')
    assert os.path.normpath(options['list'][0]).lower() == \
           os.path.normpath(cfg['model']['list']).lower()
    for option in ['print_input', 'print_flows', 'save_flows']:
        if cfg['model'][option]:
            assert option in options
    assert len(options['newton']) == 0

    # newton solver, with underrelaxation
    cfg['model']['options']['newton_under_relaxation'] = True
    cfg = MF6model._parse_model_kwargs(cfg)
    assert cfg['model']['options']['newtonoptions'] == ['under_relaxation']
    kwargs = get_input_arguments(cfg['model'],
                                 mf6.ModflowGwf,
                                 exclude='packages')
    m = MF6model(cfg=cfg, **kwargs)
    m.write()
    options = read_mf6_block(nampath, 'options')
    assert options['newton'] == ['under_relaxation']
def test_init(shellmound_cfg):
    cfg = deepcopy(shellmound_cfg)

    sim = mf6.MFSimulation()
    assert isinstance(sim, mf6.MFSimulation)

    kwargs = get_input_arguments(cfg['simulation'],
                                 mf6.MFSimulation,
                                 warn=False)
    sim = mf6.MFSimulation(**kwargs)
    assert isinstance(sim, mf6.MFSimulation)

    cfg['model']['packages'] = []
    cfg['model']['simulation'] = sim
    cfg = MF6model._parse_model_kwargs(cfg)
    kwargs = get_input_arguments(cfg['model'],
                                 mf6.ModflowGwf,
                                 exclude='packages')
    # test initialization with no packages
    m = MF6model(cfg=cfg, **kwargs)
    assert isinstance(m, MF6model)

    # test initialization with no arguments
    m = MF6model(simulation=sim)
    assert isinstance(m, MF6model)
def test_packagelist(shellmound_cfg_path):

    cfg = load_cfg(shellmound_cfg_path, default_file='/mf6_defaults.yml')

    packages = cfg['model']['packages']
    kwargs = get_input_arguments(cfg['simulation'], mf6.MFSimulation)
    sim = mf6.MFSimulation(**kwargs)
    cfg['model']['simulation'] = sim

    cfg = MF6model._parse_model_kwargs(cfg)
    kwargs = get_input_arguments(cfg['model'], mf6.ModflowGwf,
                                 exclude='packages')
    m = MF6model(cfg=cfg, **kwargs)
    assert m.package_list == [p for p in m._package_setup_order if p in packages]
def test_rotated_grid(shellmound_cfg, shellmound_simulation):
    cfg = deepcopy(shellmound_cfg)
    #simulation = deepcopy(simulation)
    cfg['model']['simulation'] = shellmound_simulation
    cfg['setup_grid']['snap_to_NHG'] = False
    cfg['setup_grid']['rotation'] = 18.
    cfg['setup_grid']['xoff'] += 8000
    cfg['dis']['dimensions']['nrow'] = 20
    cfg['dis']['dimensions']['ncol'] = 25

    cfg = MF6model._parse_model_kwargs(cfg)
    kwargs = get_input_arguments(cfg['model'],
                                 mf6.ModflowGwf,
                                 exclude='packages')
    m = MF6model(cfg=cfg, **kwargs)
    m.setup_grid()

    assert m.modelgrid.angrot == 18.
    assert m.modelgrid.xoffset == cfg['setup_grid']['xoff']
    assert m.modelgrid.yoffset == cfg['setup_grid']['yoff']

    m.setup_dis()
    #m.setup_tdis()
    #m.setup_solver()
    #m.setup_packages(reset_existing=False)
    #m.write_input()
    j = 2
Beispiel #5
0
def get_pleasant_mf6(pleasant_mf6_cfg, pleasant_simulation):
    print('creating Pleasant Lake MF6model instance from cfgfile...')
    cfg = copy.deepcopy(pleasant_mf6_cfg)
    cfg['model']['simulation'] = pleasant_simulation
    kwargs = get_input_arguments(cfg['model'], mf6.ModflowGwf, exclude='packages')
    m = MF6model(cfg=cfg, **kwargs)
    return m
Beispiel #6
0
    def setup_dis(self):
        """"""
        package = 'dis'
        print('\nSetting up {} package...'.format(package.upper()))
        t0 = time.time()

        # resample the top from the DEM
        if self.cfg['dis']['remake_top']:
            self._setup_array(package,
                              'top',
                              datatype='array2d',
                              resample_method='linear',
                              write_fmt='%.2f')

        # make the botm array
        self._setup_array(package,
                          'botm',
                          datatype='array3d',
                          resample_method='linear',
                          write_fmt='%.2f')

        # set number of layers to length of the created bottom array
        # this needs to be set prior to setting up the idomain,
        # otherwise idomain may have wrong number of layers
        self.cfg['dis']['dimensions']['nlay'] = len(
            self.cfg['dis']['griddata']['botm'])

        # initial idomain input for creating a dis package instance
        self._setup_array(package,
                          'idomain',
                          datatype='array3d',
                          write_fmt='%d',
                          resample_method='nearest',
                          dtype=int)

        # put together keyword arguments for dis package
        kwargs = self.cfg['grid'].copy()  # nrow, ncol, delr, delc
        kwargs.update(self.cfg['dis'])
        kwargs.update(self.cfg['dis']['dimensions'])  # nper, nlay, etc.
        kwargs.update(self.cfg['dis']['griddata'])

        # modelgrid: dis arguments
        remaps = {'xoff': 'xorigin', 'yoff': 'yorigin', 'rotation': 'angrot'}

        for k, v in remaps.items():
            if v not in kwargs:
                kwargs[v] = kwargs.pop(k)
        kwargs['length_units'] = self.length_units
        # get the arguments for the flopy version of ModflowGwfdis
        # but instantiate with modflow-setup subclass of ModflowGwfdis
        kwargs = get_input_arguments(kwargs, mf6.ModflowGwfdis)
        dis = ModflowGwfdis(model=self, **kwargs)
        self._perioddata = None  # reset perioddata
        #if not isinstance(self._modelgrid, MFsetupGrid):
        #    self._modelgrid = None  # override DIS package grid setup
        self._mg_resync = False
        self._reset_bc_arrays()
        self._set_idomain()
        print("finished in {:.2f}s\n".format(time.time() - t0))
        return dis
Beispiel #7
0
    def setup_rch(self):
        """
        Sets up the RCH package.

        Parameters
        ----------

        Notes
        -----

        """
        package = 'rch'
        print('\nSetting up {} package...'.format(package.upper()))
        t0 = time.time()

        # make the irch array
        irch = make_irch(self.idomain)

        self._setup_array('rch', 'irch',
                          data={0: irch},
                          datatype='array2d',
                          write_fmt='%d', dtype=int)

        # make the rech array
        self._setup_array(package, 'recharge', datatype='transient2d',
                          resample_method='nearest', write_fmt='%.6e',
                          write_nodata=0.)


        kwargs = self.cfg[package].copy()
        kwargs.update(self.cfg[package]['options'])
        kwargs = get_input_arguments(kwargs, mf6.ModflowGwfrcha)
        rch = mf6.ModflowGwfrcha(self, **kwargs)
        print("finished in {:.2f}s\n".format(time.time() - t0))
        return rch
Beispiel #8
0
    def setup_ic(self):
        """
        Sets up the IC package.

        Parameters
        ----------

        Notes
        -----

        """
        package = 'ic'
        print('\nSetting up {} package...'.format(package.upper()))
        t0 = time.time()

        # make the starting heads array
        self._setup_array(package, 'strt', datatype='array3d',
                          resample_method='linear',
                          write_fmt='%.2f')

        kwargs = self.cfg[package]['griddata'].copy()
        kwargs = get_input_arguments(kwargs, mf6.ModflowGwfic)
        ic = mf6.ModflowGwfic(self, **kwargs)
        print("finished in {:.2f}s\n".format(time.time() - t0))
        return ic
Beispiel #9
0
    def _parse_model_kwargs(cfg):

        if isinstance(cfg['model']['simulation'], str):
            # assume that simulation for model
            # is the one simulation specified in configuration
            # (regardless of the name specified in model configuration)
            cfg['model']['simulation'] = cfg['simulation']
        if isinstance(cfg['model']['simulation'], dict):
            # create simulation from simulation block in config dict
            kwargs = cfg['simulation'].copy()
            kwargs.update(cfg['simulation']['options'])
            kwargs = get_input_arguments(kwargs, mf6.MFSimulation)
            sim = flopy.mf6.MFSimulation(**kwargs)
            cfg['model']['simulation'] = sim
            sim_ws = cfg['simulation']['sim_ws']
        # if a simulation has already been created, get the path from the instance
        elif isinstance(cfg['model']['simulation'], mf6.MFSimulation):
            sim_ws = cfg['model']['simulation'].simulation_data.mfpath._sim_path
        else:
            raise TypeError('unrecognized configuration input for simulation.')

        # listing file
        cfg['model']['list'] = os.path.join(cfg['model']['list_filename_fmt']
                                            .format(cfg['model']['modelname']))

        # newton options
        if cfg['model']['options'].get('newton', False):
            cfg['model']['options']['newtonoptions'] = ['']
        if cfg['model']['options'].get('newton_under_relaxation', False):
            cfg['model']['options']['newtonoptions'] = ['under_relaxation']
        cfg['model'].update(cfg['model']['options'])
        return cfg
def test_snap_to_NHG(shellmound_cfg, shellmound_simulation):
    cfg = deepcopy(shellmound_cfg)
    #simulation = deepcopy(simulation)
    cfg['model']['simulation'] = shellmound_simulation
    cfg['setup_grid']['snap_to_NHG'] = True

    cfg = MF6model._parse_model_kwargs(cfg)
    kwargs = get_input_arguments(cfg['model'],
                                 mf6.ModflowGwf,
                                 exclude='packages')
    m = MF6model(cfg=cfg, **kwargs)
    m.setup_grid()

    # national grid parameters
    xul, yul = -2553045.0, 3907285.0  # upper left corner
    ngrows = 4000
    ngcols = 4980
    natCellsize = 1000

    # locations of left and top cell edges
    ngx = np.arange(ngcols) * natCellsize + xul
    ngy = np.arange(ngrows) * -natCellsize + yul

    x0, x1, y0, y1 = m.modelgrid.extent
    assert np.min(np.abs(ngx - x0)) == 0
    assert np.min(np.abs(ngy - y0)) == 0
    assert np.min(np.abs(ngx - x1)) == 0
    assert np.min(np.abs(ngy - y1)) == 0
Beispiel #11
0
    def setup_obs(self):
        """
        Sets up the OBS utility.

        Parameters
        ----------

        Notes
        -----

        """
        package = 'obs'
        print('\nSetting up {} package...'.format(package.upper()))
        t0 = time.time()

        # munge the observation data
        df = setup_head_observations(self,
                                     format=package,
                                     obsname_column='obsname')

        # reformat to flopy input format
        obsdata = df[['obsname', 'obstype', 'id']].to_records(index=False)
        filename = self.cfg[package]['filename_fmt'].format(self.name)
        obsdata = {filename: obsdata}

        kwargs = self.cfg[package].copy()
        kwargs.update(self.cfg[package]['options'])
        kwargs['continuous'] = obsdata
        kwargs = get_input_arguments(kwargs, mf6.ModflowUtlobs)
        obs = mf6.ModflowUtlobs(self,  **kwargs)
        print("finished in {:.2f}s\n".format(time.time() - t0))
        return obs
Beispiel #12
0
    def setup_wel(self):
        """
        Sets up the WEL package.

        Parameters
        ----------

        Notes
        -----

        """
        package = 'wel'
        print('\nSetting up {} package...'.format(package.upper()))
        t0 = time.time()

        # option to write stress_period_data to external files
        external_files = self.cfg[package]['external_files']

        # munge well package input
        # returns dataframe with information to populate stress_period_data
        df = setup_wel_data(self, for_external_files=external_files)
        if len(df) == 0:
            print('No wells in active model area')
            return

        # set up stress_period_data
        if external_files:
            # get the file path (allowing for different external file locations, specified name format, etc.)
            filename_format = package + '_{:03d}.dat'  # stress period suffix
            filepaths = self.setup_external_filepaths(package, 'stress_period_data',
                                                      filename_format=filename_format,
                                                      file_numbers=sorted(df.per.unique().tolist()))
        spd = {}
        period_groups = df.groupby('per')
        for kper in range(self.nper):
            if kper in period_groups.groups:
                group = period_groups.get_group(kper)
                group.drop('per', axis=1, inplace=True)
                if external_files:
                    group.to_csv(filepaths[kper]['filename'], index=False, sep=' ')
                    # make a copy for the intermediate data folder, for consistency with mf-2005
                    shutil.copy(filepaths[kper]['filename'], self.cfg['intermediate_data']['output_folder'])
                else:
                    kspd = mf6.ModflowGwfwel.stress_period_data.empty(self,
                                                                      len(group),
                                                                      boundnames=True)[0]
                    kspd['cellid'] = list(zip(group.k, group.i, group.j))
                    kspd['q'] = group['q']
                    kspd['boundname'] = group['boundname']
                    spd[kper] = kspd
            else:
                pass  # spd[kper] = None
        kwargs = self.cfg[package].copy()
        kwargs.update(self.cfg[package]['options'])
        if not external_files:
            kwargs['stress_period_data'] = spd
        kwargs = get_input_arguments(kwargs, mf6.ModflowGwfwel)
        wel = mf6.ModflowGwfwel(self, **kwargs)
        print("finished in {:.2f}s\n".format(time.time() - t0))
        return wel
Beispiel #13
0
def make_lakarr2d(grid, lakesdata, include_ids, id_column='hydroid'):
    """
    Make a nrow x ncol array with lake package extent for each lake,
    using the numbers in the 'id' column in the lakes shapefile.
    """
    if isinstance(lakesdata, str):
        # implement automatic reprojection in gis-utils
        # maintaining backwards compatibility
        kwargs = {'dest_crs': grid.crs}
        kwargs = get_input_arguments(kwargs, shp2df)
        lakes = shp2df(lakesdata, **kwargs)
    elif isinstance(lakesdata, pd.DataFrame):
        lakes = lakesdata.copy()
    else:
        raise ValueError(
            'unrecognized input for "lakesdata": {}'.format(lakesdata))
    id_column = id_column.lower()
    lakes.columns = [c.lower() for c in lakes.columns]
    lakes.index = lakes[id_column]
    lakes = lakes.loc[include_ids]
    lakes['lakid'] = np.arange(1, len(lakes) + 1)
    lakes['geometry'] = [Polygon(g.exterior) for g in lakes.geometry]
    arr = rasterize(lakes, grid=grid, id_column='lakid')

    # ensure that order of hydroids is unchanged
    # (used to match features to lake IDs in lake package)
    assert lakes[id_column].tolist() == include_ids
    return arr
Beispiel #14
0
    def setup_npf(self):
        """
        Sets up the NPF package.

        Parameters
        ----------

        Notes
        -----

        """
        package = 'npf'
        print('\nSetting up {} package...'.format(package.upper()))
        t0 = time.time()
        hiKlakes_value = float(self.cfg['parent'].get('hiKlakes_value', 1e4))

        # make the k array
        self._setup_array(package, 'k', vmin=0, vmax=hiKlakes_value,
                          resample_method='linear',
                          datatype='array3d', write_fmt='%.6e')

        # make the k33 array (kv)
        self._setup_array(package, 'k33', vmin=0, vmax=hiKlakes_value,
                          resample_method='linear',
                          datatype='array3d', write_fmt='%.6e')

        kwargs = self.cfg[package]['options'].copy()
        kwargs.update(self.cfg[package]['griddata'].copy())
        kwargs = get_input_arguments(kwargs, mf6.ModflowGwfnpf)
        npf = mf6.ModflowGwfnpf(self, **kwargs)
        print("finished in {:.2f}s\n".format(time.time() - t0))
        return npf
Beispiel #15
0
def shellmound_simulation(shellmound_cfg):
    cfg = shellmound_cfg.copy()
    kwargs = shellmound_cfg['simulation'].copy()
    kwargs.update(cfg['simulation']['options'])
    kwargs = get_input_arguments(kwargs, mf6.MFSimulation)
    sim = mf6.MFSimulation(**kwargs)
    return sim
Beispiel #16
0
    def load(cls, yamlfile, load_only=None, verbose=False, forgive=False, check=False):
        """Load a model from a config file and set of MODFLOW files.
        """
        print('\nLoading simulation in {}\n'.format(yamlfile))
        t0 = time.time()

        cfg = load_cfg(yamlfile, verbose=verbose, default_file=cls.default_file) # '/mf6_defaults.yml')
        cfg = cls._parse_model_kwargs(cfg)
        kwargs = get_input_arguments(cfg['model'], mf6.ModflowGwf,
                                     exclude='packages')
        model = cls(cfg=cfg, **kwargs)
        model._load = True
        if 'grid' not in model.cfg.keys():
            model.setup_grid()
        sim = model.cfg['model']['simulation']  # should be a flopy.mf6.MFSimulation instance
        models = [model]
        if isinstance(model.inset, dict):
            for inset_name, inset in model.inset.items():
                models.append(inset)

        # execute the flopy load code on the pre-defined simulation and model instances
        # (so that the end result is a MFsetup.MF6model instance)
        # (kludgy)
        sim = flopy_mfsimulation_load(sim, models)

        # just return the parent model (inset models should be attached through the inset attribute,
        # in addition to through the .simulation flopy attribute)
        m = sim.get_model(model_name=model.name)
        print('finished loading model in {:.2f}s'.format(time.time() - t0))
        return m
Beispiel #17
0
def shellmound_model(shellmound_cfg, shellmound_simulation):
    cfg = shellmound_cfg.copy()
    cfg['model']['simulation'] = shellmound_simulation
    cfg = MF6model._parse_model_kwargs(cfg)
    kwargs = get_input_arguments(cfg['model'], mf6.ModflowGwf, exclude='packages')
    m = MF6model(cfg=cfg, **kwargs)
    return m
Beispiel #18
0
    def setup_bas6(self):
        """"""
        package = 'bas6'
        print('\nSetting up {} package...'.format(package.upper()))
        t0 = time.time()

        # make the strt array
        self._setup_array(package,
                          'strt',
                          datatype='array3d',
                          resample_method='linear',
                          write_fmt='%.2f')

        # initial ibound input for creating a bas6 package instance
        self._setup_array(package,
                          'ibound',
                          datatype='array3d',
                          write_fmt='%d',
                          resample_method='nearest',
                          dtype=int)

        kwargs = get_input_arguments(self.cfg['bas6'], fm.ModflowBas)
        bas = fm.ModflowBas(model=self, **kwargs)
        print("finished in {:.2f}s\n".format(time.time() - t0))
        self._set_ibound()
        return bas
def test_packagelist(pfl_nwt_test_cfg_path):
    cfg = load_cfg(pfl_nwt_test_cfg_path, default_file='/mfnwt_defaults.yml')

    assert len(cfg['model']['packages']) > 0
    kwargs = get_input_arguments(cfg['model'], MFnwtModel)
    m = MFnwtModel(cfg=cfg, **kwargs)
    assert m.package_list == [p for p in m._package_setup_order
                              if p in cfg['model']['packages']]
Beispiel #20
0
    def setup_perimeter_boundary(self):
        """Set up constant head package for perimeter boundary.
        TODO: integrate perimeter boundary with wel package setup
        """
        package = 'chd'
        print(
            'setting up specified head perimeter boundary with CHD package...')
        t0 = time.time()

        # option to write stress_period_data to external files
        external_files = self.cfg[package]['external_files']

        tmr = Tmr(self.parent,
                  self,
                  parent_head_file=self.cfg['parent']['headfile'],
                  inset_parent_layer_mapping=self.parent_layers,
                  inset_parent_period_mapping=self.parent_stress_periods)

        df = tmr.get_inset_boundary_heads(for_external_files=external_files)

        if external_files:
            # get the file path (allowing for different external file locations, specified name format, etc.)
            filename_format = package + '_{:03d}.dat'  # stress period suffix
            filepaths = self.setup_external_filepaths(
                package,
                'stress_period_data',
                filename_format=filename_format,
                file_numbers=sorted(df.per.unique().tolist()))

        spd = {}
        by_period = df.groupby('per')
        for kper, df_per in by_period:
            if external_files:
                df_per.rename(columns={'bhead': 'head'}, inplace=True)
                df_per.drop('per', axis=1, inplace=True)
                df_per.to_csv(filepaths[kper]['filename'],
                              index=False,
                              sep=' ',
                              float_format='%g')
                # make a copy for the intermediate data folder, for consistency with mf-2005
                shutil.copy(filepaths[kper]['filename'],
                            self.cfg['intermediate_data']['output_folder'])
            else:
                maxbound = len(df_per)
                spd[kper] = mf6.ModflowGwfchd.stress_period_data.empty(
                    self, maxbound=maxbound)[0]
                spd[kper]['cellid'] = list(
                    zip(df_per['k'], df_per['i'], df_per['j']))
                spd[kper]['head'] = df_per['bhead']

        kwargs = self.cfg['chd']
        kwargs.update(self.cfg['chd']['options'])
        kwargs = get_input_arguments(kwargs, mf6.ModflowGwfchd)
        if not external_files:
            kwargs['stress_period_data'] = spd
        chd = mf6.ModflowGwfchd(self, **kwargs)
        print("finished in {:.2f}s\n".format(time.time() - t0))
        return chd
Beispiel #21
0
def make_bdlknc_zones(grid,
                      lakesshp,
                      include_ids,
                      feat_id_column='feat_id',
                      lake_package_id_column='lak_id'):
    """
    Make zones for populating with lakebed leakance values. Same as
    lakarr, but with a buffer around each lake so that horizontal
    connections have non-zero values of bdlknc, and near-shore
    areas can be assigend higher leakance values.
    """
    print('setting up lakebed leakance zones...')
    t0 = time.time()
    if isinstance(lakesshp, str):
        # implement automatic reprojection in gis-utils
        # maintaining backwards compatibility
        kwargs = {'dest_crs': grid.crs}
        kwargs = get_input_arguments(kwargs, shp2df)
        lakes = shp2df(lakesshp, **kwargs)
    elif isinstance(lakesshp, pd.DataFrame):
        lakes = lakesshp.copy()
    else:
        raise ValueError(
            'unrecognized input for "lakesshp": {}'.format(lakesshp))
    # Exterior buffer
    id_column = feat_id_column.lower()
    lakes.columns = [c.lower() for c in lakes.columns]
    exterior_buffer = 30  # m
    lakes.index = lakes[id_column]
    lakes = lakes.loc[include_ids]
    if lake_package_id_column not in lakes.columns:
        lakes[lake_package_id_column] = np.arange(1, len(lakes) + 1)
    # speed up buffer construction by getting exteriors once
    # and probably more importantly,
    # simplifying possibly complex geometries of lakes generated from 2ft lidar
    unbuffered_exteriors = [
        Polygon(g.exterior).simplify(5) for g in lakes.geometry
    ]
    lakes['geometry'] = [
        g.buffer(exterior_buffer) for g in unbuffered_exteriors
    ]
    arr = rasterize(lakes, grid=grid, id_column=lake_package_id_column)

    # Interior buffer for lower leakance, assumed to be 20 m around the lake
    interior_buffer = -20  # m
    lakes['geometry'] = [
        g.buffer(interior_buffer) for g in unbuffered_exteriors
    ]
    arr2 = rasterize(lakes, grid=grid, id_column=lake_package_id_column)
    arr2 = arr2 * 100  # Create new ids for the interior, as multiples of 10

    arr[arr2 > 0] = arr2[arr2 > 0]
    # ensure that order of hydroids is unchanged
    # (used to match features to lake IDs in lake package)
    assert lakes[id_column].tolist() == list(include_ids)
    print('finished in {:.2f}s'.format(time.time() - t0))
    return arr
Beispiel #22
0
    def setup_riv(self, rivdata=None):
        """Set up River package.
        TODO: riv package input through configuration file
        """
        package = 'riv'
        print('\nSetting up {} package...'.format(package.upper()))
        t0 = time.time()

        if rivdata is None:
            raise NotImplementedError("River package input through configuration file;"
                                      "currently only supported through to_riv option"
                                      "in sfr configuration block.")
        df = rivdata.stress_period_data
        if len(df) == 0:
            print('No input specified or streams not in model.')
            return

        # option to write stress_period_data to external files
        external_files = self.cfg[package].get('external_files', True)

        if external_files:
            # get the file path (allowing for different external file locations, specified name format, etc.)
            filename_format = package + '_{:03d}.dat'  # stress period suffix
            filepaths = self.setup_external_filepaths(package, 'stress_period_data',
                                                      filename_format=filename_format,
                                                      file_numbers=sorted(df.per.unique().tolist()))

        spd = {}
        by_period = df.groupby('per')
        for kper, df_per in by_period:
            if external_files:
                df_per = df_per[['k', 'i', 'j', 'stage', 'cond', 'rbot']].copy()
                for col in 'k', 'i', 'j':
                    df_per[col] += 1
                df_per.rename(columns={'k': '#k'}, inplace=True)
                df_per.to_csv(filepaths[kper]['filename'], index=False, sep=' ')
                # make a copy for the intermediate data folder, for consistency with mf-2005
                shutil.copy(filepaths[kper]['filename'], self.cfg['intermediate_data']['output_folder'])
            else:
                maxbound = len(df_per)
                spd[kper] = mf6.ModflowGwfchd.stress_period_data.empty(self, maxbound=maxbound,
                                                                       boundnames=True)[0]
                spd[kper]['cellid'] = list(zip(df_per['k'], df_per['i'], df_per['j']))
                for col in 'cond', 'stage', 'rbot':
                    spd[kper][col] = df_per[col]
                spd[kper]['boundname'] = ["'{}'".format(s) for s in df_per['name']]

        kwargs = self.cfg['riv']
        # need default options from rivdata instance or cfg defaults
        kwargs.update(self.cfg['riv']['options'])
        kwargs = get_input_arguments(kwargs, mf6.ModflowGwfriv)
        if not external_files:
            kwargs['stress_period_data'] = spd
        riv = mf6.ModflowGwfriv(self, **kwargs)
        print("finished in {:.2f}s\n".format(time.time() - t0))
        return riv
Beispiel #23
0
    def create_lgr_models(self):
        for k, v in self.cfg['setup_grid']['lgr'].items():
            # load the config file for lgr inset model
            inset_cfg = load_cfg(v['filename'],
                                 default_file='/mf6_defaults.yml')
            # if lgr inset has already been created
            if inset_cfg['model']['modelname'] in self.simulation._models:
                return
            inset_cfg['model']['simulation'] = self.simulation
            if 'ims' in inset_cfg['model']['packages']:
                inset_cfg['model']['packages'].remove('ims')
            # set parent configuation dictionary here
            # (even though parent model is explicitly set below)
            # so that the LGR grid is snapped to the parent grid
            inset_cfg['parent'] = {
                'namefile': self.namefile,
                'model_ws': self.model_ws,
                'version': 'mf6',
                'hiKlakes_value': self.cfg['model']['hiKlakes_value'],
                'default_source_data': True,
                'length_units': self.length_units,
                'time_units': self.time_units
            }
            inset_cfg = MF6model._parse_model_kwargs(inset_cfg)
            kwargs = get_input_arguments(inset_cfg['model'],
                                         mf6.ModflowGwf,
                                         exclude='packages')
            kwargs['parent'] = self  # otherwise will try to load parent model
            inset_model = MF6model(cfg=inset_cfg, lgr=True, **kwargs)
            inset_model._load = self._load  # whether model is being made or loaded from existing files
            inset_model.setup_grid()
            del inset_model.cfg['ims']
            inset_model.cfg['tdis'] = self.cfg['tdis']
            if self.inset is None:
                self.inset = {}
                self.lgr = {}

            self.inset[inset_model.name] = inset_model
            #self.inset[inset_model.name]._is_lgr = True

            # create idomain indicating area of parent grid that is LGR
            lgr_idomain = make_lgr_idomain(
                self.modelgrid, self.inset[inset_model.name].modelgrid)

            ncpp = int(self.modelgrid.delr[0] /
                       self.inset[inset_model.name].modelgrid.delr[0])
            ncppl = v.get('layer_refinement', 1)
            self.lgr[inset_model.name] = Lgr(self.nlay, self.nrow, self.ncol,
                                             self.dis.delr.array,
                                             self.dis.delc.array,
                                             self.dis.top.array,
                                             self.dis.botm.array, lgr_idomain,
                                             ncpp, ncppl)
            inset_model._perioddata = self.perioddata
            self._set_idomain()
Beispiel #24
0
def parse_perioddata_groups(perioddata_dict, defaults={}):
    """Reorganize input in perioddata dict into
    a list of groups (dicts).
    """
    #perioddata = perioddata_dict.copy()
    perioddata_groups = []
    group0 = defaults.copy()

    valid_txt = "if transient: perlen specified or 3 of start_date_time, " \
                "end_date_time, nper or freq;\n" \
                "if steady: nper or perlen specified. Default perlen " \
                "for steady-state periods is 1."
    for k, v in perioddata_dict.items():
        if 'group' in k.lower():
            data = defaults.copy()
            data.update(v)
            if is_valid_perioddata(data):
                data = get_input_arguments(data, setup_perioddata_group)
                perioddata_groups.append(data)
            else:
                print_item(k, data)
                prefix = "perioddata input for {} must have".format(k)
                raise Exception(prefix + valid_txt)
        elif 'perioddata' in k.lower():
            perioddata_groups += parse_perioddata_groups(perioddata_dict[k],
                                                         defaults=defaults)
        else:
            group0[k] = v
    if len(perioddata_groups) == 0:
        if not is_valid_perioddata(group0):
            print_item('perioddata:', group0)
            prefix = "perioddata input must have"
            raise Exception(prefix + valid_txt)
        data = get_input_arguments(group0, setup_perioddata_group)
        perioddata_groups = [data]
    for group in perioddata_groups:
        if 'steady' in group:
            if np.isscalar(group['steady']):
                group['steady'] = {0: group['steady']}
            elif not isinstance(group['steady'], dict):
                group['steady'] = {i: s for i, s in enumerate(group['steady'])}
    return perioddata_groups
Beispiel #25
0
    def setup_sto(self):
        """
        Sets up the STO package.

        Parameters
        ----------

        Notes
        -----

        """

        if np.all(self.perioddata['steady']):
            print('Skipping STO package, no transient stress periods...')
            return

        package = 'sto'
        print('\nSetting up {} package...'.format(package.upper()))
        t0 = time.time()

        # make the sy array
        self._setup_array(package,
                          'sy',
                          datatype='array3d',
                          resample_method='linear',
                          write_fmt='%.6e')

        # make the ss array
        self._setup_array(package,
                          'ss',
                          datatype='array3d',
                          resample_method='linear',
                          write_fmt='%.6e')

        kwargs = self.cfg[package]['options'].copy()
        kwargs.update(self.cfg[package]['griddata'].copy())
        # get steady/transient info from perioddata table
        # which parses it from either DIS or STO input (to allow consistent input structure with mf2005)
        kwargs['steady_state'] = {
            k: v
            for k, v in zip(self.perioddata['per'], self.perioddata['steady'])
        }
        kwargs['transient'] = {
            k: not v
            for k, v in zip(self.perioddata['per'], self.perioddata['steady'])
        }
        kwargs = get_input_arguments(kwargs, mf6.ModflowGwfsto)
        sto = mf6.ModflowGwfsto(self, **kwargs)
        print("finished in {:.2f}s\n".format(time.time() - t0))
        return sto
Beispiel #26
0
def load_modelgrid(filename):
    """Create a MFsetupGrid instance from model config json file."""
    cfg = load(filename)
    rename = {'xll': 'xoff',
              'yll': 'yoff',
              }
    for k, v in rename.items():
        if k in cfg:
            cfg[v] = cfg.pop(k)
    if np.isscalar(cfg['delr']):
        cfg['delr'] = np.ones(cfg['ncol'])* cfg['delr']
    if np.isscalar(cfg['delc']):
        cfg['delc'] = np.ones(cfg['nrow']) * cfg['delc']
    kwargs = get_input_arguments(cfg, MFsetupGrid)
    return MFsetupGrid(**kwargs)
Beispiel #27
0
    def setup_oc(self):

        package = 'oc'
        print('\nSetting up {} package...'.format(package.upper()))
        t0 = time.time()
        stress_period_data = {}
        for i, r in self.perioddata.iterrows():
            stress_period_data[(r.per, r.nstp - 1)] = r.oc

        kwargs = self.cfg['oc']
        kwargs['stress_period_data'] = stress_period_data
        kwargs = get_input_arguments(kwargs, fm.ModflowOc)
        oc = fm.ModflowOc(model=self, **kwargs)
        print("finished in {:.2f}s\n".format(time.time() - t0))
        return oc
Beispiel #28
0
    def setup_simulation_mover(self):
        """Set up the MODFLOW-6 water mover package at the simulation level.
        Automate set-up of the mover between SFR packages in LGR parent and inset models.
        todo: automate set-up of mover between SFR and lakes (within a model).

        Other uses of the water mover need to be configured manually using flopy.
        """
        package = 'mvr'
        print('\nSetting up the simulation water mover package...')
        t0 = time.time()

        perioddata_dfs = []
        if self.get_package('sfr') is not None:
            if self.inset is not None:
                for inset_name, inset in self.inset.items():
                    if inset.get_package('sfr'):
                        inset_perioddata = get_mover_sfr_package_input(
                            self, inset)
                        perioddata_dfs.append(inset_perioddata)
        if len(perioddata_dfs) > 0:
            perioddata = pd.concat(perioddata_dfs)
            if len(perioddata) > 0:
                kwargs = flatten(self.cfg[package])
                # modelnames (boolean) keyword to indicate that all package names will
                # be preceded by the model name for the package. Model names are
                # required when the Mover Package is used with a GWF-GWF Exchange. The
                # MODELNAME keyword should not be used for a Mover Package that is for
                # a single GWF Model.
                # this argument will need to be adapted for implementing a mover package within a model
                # (between lakes and sfr)
                kwargs['modelnames'] = True
                kwargs['maxmvr'] = len(
                    perioddata
                )  # assumes that input for period 0 applies to all periods
                packages = set(
                    list(zip(perioddata.mname1, perioddata.pname1)) +
                    list(zip(perioddata.mname2, perioddata.pname2)))
                kwargs['maxpackages'] = len(packages)
                kwargs['packages'] = list(packages)
                kwargs['perioddata'] = {
                    0: perioddata.values.tolist()
                }  # assumes that input for period 0 applies to all periods
                kwargs = get_input_arguments(kwargs, mf6.ModflowGwfmvr)
                mvr = mf6.ModflowMvr(self.simulation, **kwargs)
                print("finished in {:.2f}s\n".format(time.time() - t0))
                return mvr
        else:
            print("no packages with mover information\n")
Beispiel #29
0
    def setup_dis(self):
        """"""
        package = 'dis'
        print('\nSetting up {} package...'.format(package.upper()))
        t0 = time.time()

        # resample the top from the DEM
        if self.cfg['dis']['remake_top']:
            self._setup_array(package,
                              'top',
                              datatype='array2d',
                              resample_method='linear',
                              write_fmt='%.2f')

        # make the botm array
        self._setup_array(package,
                          'botm',
                          datatype='array3d',
                          resample_method='linear',
                          write_fmt='%.2f')

        # put together keyword arguments for dis package
        kwargs = self.cfg['grid'].copy()  # nrow, ncol, delr, delc
        kwargs.update(self.cfg['dis'])  # nper, nlay, etc.
        kwargs = get_input_arguments(kwargs, fm.ModflowDis)
        # we need flopy to read the intermediate files
        # (it will write the files in cfg)
        lmult = convert_length_units('meters', self.length_units)
        kwargs.update({
            'top': self.cfg['intermediate_data']['top'][0],
            'botm': self.cfg['intermediate_data']['botm'],
            'nper': self.nper,
            'delc': self.modelgrid.delc * lmult,
            'delr': self.modelgrid.delr * lmult
        })
        for arg in ['perlen', 'nstp', 'tsmult', 'steady']:
            kwargs[arg] = self.perioddata[arg].values

        dis = fm.ModflowDis(model=self, **kwargs)
        self._perioddata = None  # reset perioddata
        #if not isinstance(self._modelgrid, MFsetupGrid):
        #    self._modelgrid = None  # override DIS package grid setup
        self.setup_grid()  # reset the model grid
        self._reset_bc_arrays()
        #self._isbc = None  # reset BC property arrays
        print("finished in {:.2f}s\n".format(time.time() - t0))
        return dis
Beispiel #30
0
    def setup_lgr_exchanges(self):
        for inset_name, inset_model in self.inset.items():
            # get the exchange data
            exchangelist = self.lgr[inset_name].get_exchange_data(
                angldegx=True, cdist=True)

            # make a dataframe for concise unpacking of cellids
            columns = [
                'cellidm1', 'cellidm2', 'ihc', 'cl1', 'cl2', 'hwva',
                'angldegx', 'cdist'
            ]
            exchangedf = pd.DataFrame(exchangelist, columns=columns)

            # unpack the cellids and get their respective ibound values
            k1, i1, j1 = zip(*exchangedf['cellidm1'])
            k2, i2, j2 = zip(*exchangedf['cellidm2'])
            active1 = self.idomain[k1, i1, j1] == 1
            active2 = inset_model.idomain[k2, i2, j2] == 1

            # screen out connections involving an inactive cell
            active_connections = active1 & active2
            nexg = active_connections.sum()
            active_exchangelist = [
                l for i, l in enumerate(exchangelist) if active_connections[i]
            ]

            # arguments to ModflowGwfgwf
            kwargs = {
                'exgtype': 'gwf6-gwf6',
                'exgmnamea': self.name,
                'exgmnameb': inset_name,
                'nexg': nexg,
                'auxiliary': [('angldegx', 'cdist')],
                'exchangedata': active_exchangelist
            }
            # add water mover files if there's a mover package
            # not sure if one mover file can be used for multiple exchange files or not
            # if separate (simulation) water mover files are needed,
            # than this would have to be restructured
            if 'mvr' in self.simulation.package_key_dict:
                if inset_name in self.simulation.mvr.packages.array['mname']:
                    kwargs['mvr_filerecord'] = self.simulation.mvr.filename

            # set up the exchange package
            kwargs = get_input_arguments(kwargs, mf6.ModflowGwfgwf)
            gwfe = mf6.ModflowGwfgwf(self.simulation, **kwargs)