def test_find_remove_isolated_cells():
    idomain = np.zeros((2, 1000, 1000), dtype=int)
    idomain[:, 200:-200, 200:-200] = 1
    idomain[:, 202:203, 202:203] = 0
    idomain[:, 300:330, 300:301] = 0
    idomain[:, 305:306, 305:306] = 0
    idomain[:, 10:13, 10:13] = 1
    idomain[:, 20:22, 20:22] = 1
    idomain[:, -20:-18, -20:-18] = 1

    result = find_remove_isolated_cells(idomain, minimum_cluster_size=10)
    assert result.shape == idomain.shape
    # no inactive cells should have been filled
    assert result.sum() == idomain[:, 200:-200, 200:-200].sum()
    result = find_remove_isolated_cells(idomain, minimum_cluster_size=9)
    # cluster of 9 active cells was not removed
    assert result.sum() == idomain[:, 200:-200, 200:-200].sum() + 9 * 2

    idomain = np.zeros((40, 40), dtype=int)
    idomain[5:-3, 2:7] = 1
    idomain[3:5, 7:8] = 1  # 2 pixels
    idomain[10, 8:11] = 1  # 3 pixels
    idomain[20, 7] = 1  # pixel that has only one connection
    result = find_remove_isolated_cells(idomain, minimum_cluster_size=10)
    assert result.sum() == idomain.sum() - 6
Exemplo n.º 2
0
    def _set_ibound(self):
        """Remake the idomain array from the source data,
        no data values in the top and bottom arrays, and
        so that cells above SFR reaches are inactive."""
        ibound_from_layer_elevations = make_ibound(
            self.dis.top.array,
            self.dis.botm.array,
            nodata=self._nodata_value,
            minimum_layer_thickness=self.cfg['dis'].get(
                'minimum_layer_thickness', 1),
            #drop_thin_cells=self._drop_thin_cells,
            tol=1e-4)

        # include cells that are active in the existing idomain array
        # and cells inactivated on the basis of layer elevations
        ibound = (self.bas6.ibound.array > 0) & (ibound_from_layer_elevations
                                                 == 1)
        ibound = ibound.astype(int)

        # remove cells that conincide with lakes
        ibound[self.isbc == 1] = 0.

        # remove cells that are above stream cells
        if self.get_package('sfr') is not None:
            ibound = deactivate_idomain_above(ibound, self.sfr.reach_data)
        # remove cells that are above ghb cells
        if self.get_package('ghb') is not None:
            ibound = deactivate_idomain_above(ibound,
                                              self.ghb.stress_period_data[0])

        # inactivate any isolated cells that could cause problems with the solution
        ibound = find_remove_isolated_cells(ibound, minimum_cluster_size=20)

        self._ibound = ibound
        # re-write the input files
        self._setup_array('bas6',
                          'ibound',
                          resample_method='nearest',
                          data={i: arr
                                for i, arr in enumerate(ibound)},
                          datatype='array3d',
                          write_fmt='%d',
                          dtype=int)
        self.bas6.ibound = self.cfg['bas6']['ibound']
Exemplo n.º 3
0
def test_ibound(pleasant_nwt_with_dis):
    m = pleasant_nwt_with_dis
    # use pleasant lake extent as ibound
    is_pleasant_lake = m.lakarr[0]
    # clear out lake info, just for this test function
    m.cfg['model']['packages'].remove('lak')
    del m.cfg['lak']['source_data']
    # specify path relative to cfg file
    m.cfg['bas6']['source_data']['ibound'] = {
        'filename':
        '../../../examples/data/pleasant/source_data/shps/all_lakes.shp'
    }
    m._reset_bc_arrays()
    bas6 = m.setup_bas6()
    bas6.write_file()
    assert np.array_equal(m.ibound, m.bas6.ibound.array)
    # find_remove_isolated_cells is run on ibound array but not in Lake setup
    assert np.array_equal(m.ibound[0],
                          find_remove_isolated_cells(is_pleasant_lake))
    ibound = load_array(m.cfg['bas6']['ibound'])
    assert np.array_equal(m.ibound, ibound)
def test_dis_setup(shellmound_model_with_grid):

    m = shellmound_model_with_grid  #deepcopy(model_with_grid)
    # test intermediate array creation
    m.cfg['dis']['remake_top'] = True
    m.cfg['dis']['source_data']['top']['resample_method'] = 'nearest'
    m.cfg['dis']['source_data']['botm']['resample_method'] = 'nearest'
    dis = m.setup_dis()
    botm = m.dis.botm.array.copy()
    assert isinstance(dis, mf6.ModflowGwfdis)
    assert 'DIS' in m.get_package_list()
    # verify that units got conveted correctly
    assert m.dis.top.array.mean() < 100
    assert m.dis.length_units.array == 'meters'

    # verify that modelgrid was reset after building DIS
    mg = m.modelgrid
    assert (mg.nlay, mg.nrow, mg.ncol) == m.dis.botm.array.shape
    assert np.array_equal(mg.top, m.dis.top.array)
    assert np.array_equal(mg.botm, m.dis.botm.array)

    arrayfiles = m.cfg['intermediate_data']['top'] + \
                 m.cfg['intermediate_data']['botm'] + \
                 m.cfg['intermediate_data']['idomain']
    for f in arrayfiles:
        assert os.path.exists(f)
        fname = os.path.splitext(os.path.split(f)[1])[0]
        k = ''.join([s for s in fname if s.isdigit()])
        var = fname.strip(k)
        data = np.loadtxt(f)
        model_array = getattr(m.dis, var).array
        if len(k) > 0:
            k = int(k)
            model_array = model_array[k]
        assert np.array_equal(model_array, data)

# test that written idomain array reflects supplied shapefile of active area
    active_area = rasterize(m.cfg['dis']['source_data']['idomain']['filename'],
                            m.modelgrid)
    isactive = active_area == 1
    written_idomain = load_array(m.cfg['dis']['griddata']['idomain'])
    assert np.all(written_idomain[:, ~isactive] <= 0)

    # test idomain from just layer elevations
    del m.cfg['dis']['griddata']['idomain']
    dis = m.setup_dis()
    top = dis.top.array.copy()
    top[top == m._nodata_value] = np.nan
    botm = dis.botm.array.copy()
    botm[botm == m._nodata_value] = np.nan
    thickness = get_layer_thicknesses(top, botm)
    invalid_botms = np.ones_like(botm)
    invalid_botms[np.isnan(botm)] = 0
    invalid_botms[thickness < 1.0001] = 0
    # these two arrays are not equal
    # because isolated cells haven't been removed from the second one
    # this verifies that _set_idomain is removing them
    assert not np.array_equal(m.idomain[:, isactive].sum(axis=1),
                              invalid_botms[:, isactive].sum(axis=1))
    invalid_botms = find_remove_isolated_cells(invalid_botms,
                                               minimum_cluster_size=20)
    active_cells = m.idomain[:, isactive].copy()
    active_cells[active_cells <
                 0] = 0  # need to do this because some idomain cells are -1
    assert np.array_equal(active_cells.sum(axis=1),
                          invalid_botms[:, isactive].sum(axis=1))

    # test recreating package from external arrays
    m.remove_package('dis')
    assert m.cfg['dis']['griddata']['top'] is not None
    assert m.cfg['dis']['griddata']['botm'] is not None
    dis = m.setup_dis()
    assert np.array_equal(m.dis.botm.array[m.dis.idomain.array == 1],
                          botm[m.dis.idomain.array == 1])

    # test recreating just the top from the external array
    m.remove_package('dis')
    m.cfg['dis']['remake_top'] = False
    m.cfg['dis']['griddata']['botm'] = None
    dis = m.setup_dis()
    dis.write()
    assert np.array_equal(m.dis.botm.array[m.dis.idomain.array == 1],
                          botm[m.dis.idomain.array == 1])
    arrayfiles = m.cfg['dis']['griddata']['top']
    for f in arrayfiles:
        assert os.path.exists(f['filename'])
    assert os.path.exists(os.path.join(m.model_ws, dis.filename))

    # dis package idomain should be consistent with model property
    updated_idomain = m.idomain
    assert np.array_equal(m.dis.idomain.array, updated_idomain)

    # check that units were converted (or not)
    assert np.allclose(dis.top.array[dis.idomain.array[0] == 1].mean(),
                       40,
                       atol=10)
    mcaq = m.cfg['dis']['source_data']['botm']['filenames'][3]
    assert 'mcaq' in mcaq
    with rasterio.open(mcaq) as src:
        mcaq_data = src.read(1)
        mcaq_data[mcaq_data == src.meta['nodata']] = np.nan
    assert np.allclose(m.dis.botm.array[3][dis.idomain.array[3] == 1].mean() /
                       .3048,
                       np.nanmean(mcaq_data),
                       atol=5)
Exemplo n.º 5
0
    def _set_idomain(self):
        """Remake the idomain array from the source data,
        no data values in the top and bottom arrays, and
        so that cells above SFR reaches are inactive.

        Also remakes irch for the recharge package"""
        # loop thru LGR models and inactivate area of parent grid for each one
        lgr_idomain = np.ones(self.dis.idomain.array.shape, dtype=int)
        if isinstance(self.lgr, dict):
            for k, v in self.lgr.items():
                lgr_idomain[v.idomain == 0] = 0
        idomain_from_layer_elevations = make_idomain(self.dis.top.array,
                                                     self.dis.botm.array,
                                                     nodata=self._nodata_value,
                                                     minimum_layer_thickness=self.cfg['dis'].get('minimum_layer_thickness', 1),
                                                     drop_thin_cells=self._drop_thin_cells,
                                                     tol=1e-4)
        # include cells that are active in the existing idomain array
        # and cells inactivated on the basis of layer elevations
        idomain = (self.dis.idomain.array == 1) & \
                  (idomain_from_layer_elevations == 1) & \
                  (lgr_idomain == 1)
        idomain = idomain.astype(int)

        # remove cells that conincide with lakes
        idomain[self.isbc == 1] = 0.

        # remove cells that are above stream cells
        if self.get_package('sfr') is not None:
            idomain = deactivate_idomain_above(idomain, self.sfr.packagedata)

        # inactivate any isolated cells that could cause problems with the solution
        idomain = find_remove_isolated_cells(idomain, minimum_cluster_size=20)

        # create pass-through cells in inactive cells that have an active cell above and below
        # by setting these cells to -1
        idomain = create_vertical_pass_through_cells(idomain)

        self._idomain = idomain

        # take the updated idomain array and set cells != 1 to np.nan in layer botm array
        # including lake cells
        # effect is that the layer thicknesses in these cells will be set to zero
        # fill_cells_vertically will be run in the setup_array routine,
        # to collapse the nan cells to zero-thickness
        # (assign their layer botm to the next valid layer botm above)
        botm = self.dis.botm.array.copy()
        botm[(idomain != 1)] = np.nan

        # re-write the input files
        # todo: integrate this better with setup_dis
        # to reduce the number of times the arrays need to be remade

        self._setup_array('dis', 'botm',
                        data={i: arr for i, arr in enumerate(botm)},
                        datatype='array3d', resample_method='linear',
                        write_fmt='%.2f', dtype=float)
        self.dis.botm = self.cfg['dis']['griddata']['botm']
        self._setup_array('dis', 'idomain',
                          data={i: arr for i, arr in enumerate(idomain)},
                          datatype='array3d', resample_method='nearest',
                          write_fmt='%d', dtype=int)
        self.dis.idomain = self.cfg['dis']['griddata']['idomain']
        self._mg_resync = False
        self.setup_grid()  # reset the model grid

        # rebuild irch to keep it in sync with idomain changes
        irch = make_irch(idomain)
        self._setup_array('rch', 'irch',
                                data={0: irch},
                                datatype='array2d',
                                write_fmt='%d', dtype=int)