コード例 #1
0
ファイル: test_lgr.py プロジェクト: TroelsNV/modflow-setup
def pleasant_lgr_stand_alone_parent(pleasant_lgr_test_cfg_path, tmpdir):
    """Stand-alone version of lgr parent model for comparing with LGR results.
    """
    # Edit the configuration file before the file paths within it are converted to absolute
    # (model.load_cfg converts the file paths)
    cfg = load(pleasant_lgr_test_cfg_path)
    del cfg['setup_grid']['lgr']
    cfg['simulation']['sim_ws'] = os.path.join(tmpdir,
                                               'pleasant_lgr_just_parent')

    # save out the edited configuration file
    path, fname = os.path.split(pleasant_lgr_test_cfg_path)
    new_file = os.path.join(path, 'pleasant_lgr_just_parent.yml')
    dump(new_file, cfg)

    # load in the edited configuration file, converting the paths to absolute
    cfg = MF6model.load_cfg(new_file)
    # add some stuff just for the tests
    cfg['gisdir'] = os.path.join(cfg['simulation']['sim_ws'], 'gis')

    m = MF6model.setup_from_cfg(cfg)
    m.write_input()
    #if hasattr(m, 'sfr'):
    #    sfr_package_filename = os.path.join(m.model_ws, m.sfr.filename)
    #    m.sfrdata.write_package(sfr_package_filename,
    #                                version='mf6'
    #                                )
    return m
コード例 #2
0
ファイル: test_grid.py プロジェクト: wkitlasten/modflow-setup
def test_load_modelgrid(tmpdir):
    cfg = {
        'xoff': 100,
        'yoff': 100,
        'angrot': 20.,
        'proj_str': 'epsg:3070',
        'delr': np.ones(10).tolist(),
        'delc': np.ones(2).tolist()
    }
    grid1 = MFsetupGrid(**cfg)
    grid_file = os.path.join(tmpdir, 'test_grid.json')
    dump(grid_file, cfg)

    grid2 = load_modelgrid(grid_file)
    assert grid1 == grid2
コード例 #3
0
def test_solver_defaults(test_data_path, tmpdir):
    """Verify that default values aren't applied to solver
    packages if the simplified settings options are used
    (e.g. simple/moderate/complex)"""

    # modflow-6 IMS package
    mf6_model_config = test_data_path / 'pleasant_mf6_test.yml'
    cfg = MF6model.load_cfg(mf6_model_config)
    keep_keys = {
        'simulation', 'model', 'parent', 'setup_grid', 'dis', 'tdis',
        'intermediate_data', 'postprocessing'
    }
    new_cfg = {k: v for k, v in cfg.items() if k in keep_keys}
    new_cfg['model']['packages'] = ['dis']
    new_cfg['ims'] = {'options': {'complexity': 'moderate'}}
    temp_yaml = Path(tmpdir) / 'junk.yml'
    dump(temp_yaml, new_cfg)
    m = MF6model.setup_from_yaml(temp_yaml)
    assert 'nonlinear' not in m.cfg['ims']
    assert 'linear' not in m.cfg['ims']

    # modflow-nwt NWT package
    mfnwt_model_config = test_data_path / 'pleasant_nwt_test.yml'
    cfg = MFnwtModel.load_cfg(mfnwt_model_config)
    keep_keys = {
        'simulation', 'model', 'parent', 'setup_grid', 'dis', 'bas6',
        'intermediate_data', 'postprocessing'
    }
    new_cfg = {k: v for k, v in cfg.items() if k in keep_keys}
    new_cfg['model']['packages'] = ['dis', 'bas6']
    new_cfg['nwt'] = {'options': 'moderate'}
    temp_yaml = Path(tmpdir) / 'junk.yml'
    dump(temp_yaml, new_cfg)
    m = MFnwtModel.setup_from_yaml(temp_yaml)
    expected_keys = {
        'headtol', 'fluxtol', 'maxiterout', 'thickfact', 'linmeth', 'iprnwt',
        'ibotav', 'Continue', 'use_existing_file', 'options'
    }
    assert not set(m.cfg['nwt'].keys()).difference(expected_keys)
    assert m.cfg['nwt']['options'] == 'moderate'
コード例 #4
0
ファイル: grid.py プロジェクト: surajitdb/modflow-setup
def setup_structured_grid(xoff=None,
                          yoff=None,
                          xul=None,
                          yul=None,
                          nrow=None,
                          ncol=None,
                          nlay=None,
                          dxy=None,
                          delr=None,
                          delc=None,
                          top=None,
                          botm=None,
                          rotation=0.,
                          parent_model=None,
                          snap_to_NHG=False,
                          features=None,
                          features_shapefile=None,
                          id_column=None,
                          include_ids=None,
                          buffer=1000,
                          crs=None,
                          epsg=None,
                          model_length_units=None,
                          grid_file='grid.json',
                          bbox_shapefile=None,
                          **kwargs):
    """"""
    print('setting up model grid...')
    t0 = time.time()

    # conversions for model/parent model units to meters
    # set regular flag for handling delc/delr
    to_meters_inset = convert_length_units(model_length_units, 'meters')
    regular = True
    if dxy is not None:
        delr_m = np.round(dxy * to_meters_inset,
                          4)  # dxy is specified in model units
        delc_m = delr_m
    if delr is not None:
        delr_m = np.round(delr * to_meters_inset,
                          4)  # delr is specified in model units
        if not np.isscalar(delr_m):
            if (set(delr_m)) == 1:
                delr_m = delr_m[0]
            else:
                regular = False
    if delc is not None:
        delc_m = np.round(delc * to_meters_inset,
                          4)  # delc is specified in model units
        if not np.isscalar(delc_m):
            if (set(delc_m)) == 1:
                delc_m = delc_m[0]
            else:
                regular = False
    if parent_model is not None:
        to_meters_parent = convert_length_units(
            get_model_length_units(parent_model), 'meters')
        # parent model grid spacing in meters
        parent_delr_m = np.round(
            parent_model.dis.delr.array[0] * to_meters_parent, 4)
        if not parent_delr_m % delr_m == 0:
            raise ValueError(
                'inset delr spacing of {} must be factor of parent spacing of {}'
                .format(delr_m, parent_delr_m))
        parent_delc_m = np.round(
            parent_model.dis.delc.array[0] * to_meters_parent, 4)
        if not parent_delc_m % delc_m == 0:
            raise ValueError(
                'inset delc spacing of {} must be factor of parent spacing of {}'
                .format(delc_m, parent_delc_m))

    if epsg is not None:
        crs = pyproj.crs.CRS.from_epsg(epsg)
    elif crs is not None:
        from gisutils import get_authority_crs
        crs = get_authority_crs(crs)
    elif parent_model is not None:
        crs = parent_model.modelgrid.crs

    # option 1: make grid from xoff, yoff and specified dimensions
    if xoff is not None and yoff is not None:
        assert nrow is not None and ncol is not None, \
            "Need to specify nrow and ncol if specifying xoffset and yoffset."
        if regular:
            height_m = np.round(delc_m * nrow, 4)
            width_m = np.round(delr_m * ncol, 4)
        else:
            height_m = np.sum(delc_m)
            width_m = np.sum(delr_m)

        # optionally align grid with national hydrologic grid
        # grids snapping to NHD must have spacings that are a factor of 1 km
        if snap_to_NHG:
            assert regular and np.allclose(1000 % delc_m, 0, atol=1e-4)
            x, y = get_point_on_national_hydrogeologic_grid(xoff,
                                                            yoff,
                                                            offset='edge',
                                                            op=np.floor)
            xoff = x
            yoff = y
            rotation = 0.

        # need to specify xul, yul in case snapping to parent
        # todo: allow snapping to parent grid on xoff, yoff
        if rotation != 0:
            raise NotImplementedError('Rotated grids not supported.')
        xul = xoff
        yul = yoff + height_m

    # option 2: make grid using buffered feature bounding box
    else:
        if features is None and features_shapefile is not None:
            # Make sure shapefile and bbox filter are in dest (model) CRS
            # TODO: CRS wrangling could be added to shp2df as a feature
            reproject_filter = False
            try:
                from gisutils import get_shapefile_crs
                features_crs = get_shapefile_crs(features_shapefile)
                if features_crs != crs:
                    reproject_filter = True
            except:
                features_crs = get_proj_str(features_shapefile)
                reproject_filter = True
            filter = None
            if parent_model is not None:
                if reproject_filter:
                    filter = project(parent_model.modelgrid.bbox,
                                     parent_model.modelgrid.crs,
                                     features_crs).bounds
                else:
                    filter = parent_model.modelgrid.bbox.bounds
            shp2df_kwargs = {'dest_crs': crs}
            shp2df_kwargs = get_input_arguments(shp2df_kwargs, shp2df)
            df = shp2df(features_shapefile, filter=filter, **shp2df_kwargs)

            # optionally subset shapefile data to specified features
            if id_column is not None and include_ids is not None:
                df = df.loc[df[id_column].isin(include_ids)]
            # use all features by default
            features = df.geometry.tolist()

            # convert multiple features to a MultiPolygon
            if isinstance(features, list):
                if len(features) > 1:
                    features = MultiPolygon(features)
                else:
                    features = features[0]

            # size the grid based on the bbox for features
            x1, y1, x2, y2 = features.bounds
            L = buffer  # distance from area of interest to boundary
            xul = x1 - L
            yul = y2 + L
            height_m = np.round(yul - (y1 - L),
                                4)  # initial model height from buffer distance
            width_m = np.round((x2 + L) - xul, 4)
            rotation = 0.  # rotation not supported with this option

    # align model with parent grid if there is a parent model
    # (and not snapping to national hydrologic grid)
    if parent_model is not None and not snap_to_NHG:

        # get location of coinciding cell in parent model for upper left
        pi, pj = parent_model.modelgrid.intersect(xul, yul)
        verts = np.array(parent_model.modelgrid.get_cell_vertices(pi, pj))
        xul, yul = verts[:, 0].min(), verts[:, 1].max()

        # adjust the dimensions to align remaining corners
        def roundup(number, increment):
            return int(np.ceil(number / increment) * increment)

        height = roundup(height_m, parent_delr_m)
        width = roundup(width_m, parent_delc_m)

        # update nrow, ncol after snapping to parent grid
        if regular:
            nrow = int(height / delc_m)  # h is in meters
            ncol = int(width / delr_m)

    # set the grid configuration dictionary
    # spacing is in meters (consistent with projected CRS)
    # (modelgrid object will be updated automatically from this dictionary)
    #if rotation == 0.:
    #    xll = xul
    #    yll = yul - model.height
    grid_cfg = {
        'nrow': int(nrow),
        'ncol': int(ncol),
        'nlay': nlay,
        'delr': delr_m,
        'delc': delc_m,
        'xoff': xoff,
        'yoff': yoff,
        'xul': xul,
        'yul': yul,
        'rotation': rotation,
        'lenuni': 2
    }
    if regular:
        grid_cfg['delr'] = np.ones(grid_cfg['ncol'],
                                   dtype=float) * grid_cfg['delr']
        grid_cfg['delc'] = np.ones(grid_cfg['nrow'],
                                   dtype=float) * grid_cfg['delc']
    grid_cfg['delr'] = grid_cfg['delr'].tolist()  # for serializing to json
    grid_cfg['delc'] = grid_cfg['delc'].tolist()

    # renames for flopy modelgrid
    renames = {'rotation': 'angrot'}
    for k, v in renames.items():
        if k in grid_cfg:
            grid_cfg[v] = grid_cfg.pop(k)

    # add epsg or wkt if there isn't an epsg
    if epsg is not None:
        grid_cfg['epsg'] = epsg
    elif crs is not None:
        if 'epsg' in crs.srs.lower():
            grid_cfg['epsg'] = int(crs.srs.split(':')[1])
        else:
            grid_cfg['wkt'] = crs.srs
    else:
        warnings.warn('No coordinate system reference provided for model grid!'
                      'Model input data may not be mapped correctly.')

    # set up the model grid instance
    grid_cfg['top'] = top
    grid_cfg['botm'] = botm
    grid_cfg.update(kwargs)  # update with any kwargs from function call
    kwargs = get_input_arguments(grid_cfg, MFsetupGrid)
    modelgrid = MFsetupGrid(**kwargs)
    modelgrid.cfg = grid_cfg

    # write grid info to json, and shapefile of bbox
    # omit top and botm arrays from json represenation of grid
    # (just for horizontal disc.)
    del grid_cfg['top']
    del grid_cfg['botm']

    fileio.dump(grid_file, grid_cfg)
    if bbox_shapefile is not None:
        write_bbox_shapefile(modelgrid, bbox_shapefile)
    print("finished in {:.2f}s\n".format(time.time() - t0))
    return modelgrid