def add_grids(model, crs, add_lengths): grid_a = grr.RegularGrid(model, extent_kji=(2, 2, 2), crs_uuid=crs.uuid, title='GRID A', set_points_cached=True, as_irregular_grid=True) grid_a.write_hdf5() grid_a.create_xml(write_active=False, add_cell_length_properties=add_lengths, write_geometry=True) grid_b = grr.RegularGrid(model, extent_kji=(3, 3, 3), crs_uuid=crs.uuid, title='GRID B', set_points_cached=True, as_irregular_grid=True) grid_b.write_hdf5() grid_b.create_xml(write_active=False, add_cell_length_properties=add_lengths, write_geometry=True) grid_c = grr.RegularGrid(model, extent_kji=(4, 4, 4), crs_uuid=crs.uuid, title='GRID C', set_points_cached=True, as_irregular_grid=True) grid_c.write_hdf5() grid_c.create_xml(write_active=False, add_cell_length_properties=add_lengths, write_geometry=True) return (grid_a, grid_b, grid_c)
def small_grid_and_surface( tmp_model: Model) -> Tuple[grr.RegularGrid, rqs.Surface]: """Creates a small RegularGrid and a random triangular surface.""" crs = Crs(tmp_model) crs.create_xml() extent = 10 extent_kji = (extent, extent, extent) dxyz = (1.0, 1.0, 1.0) crs_uuid = crs.uuid title = "small_grid" grid = grr.RegularGrid(tmp_model, extent_kji=extent_kji, dxyz=dxyz, crs_uuid=crs_uuid, title=title) grid.create_xml() n_points = 100 points = np.random.rand(n_points, 3) * extent triangles = tri.dt(points) surface = rqs.Surface(tmp_model, crs_uuid=crs_uuid, title="small_surface") surface.set_from_triangles_and_points(triangles, points) surface.triangles_and_points() surface.write_hdf5() surface.create_xml() tmp_model.store_epc() return grid, surface
def test_regular_grid_with_geometry(tmp_path): epc = os.path.join(tmp_path, 'concrete.epc') model = rq.new_model(epc) # create a basic block grid dxyz = (55.0, 65.0, 27.0) grid = grr.RegularGrid(model, extent_kji=(4, 3, 2), title='concrete', origin=(0.0, 0.0, 1000.0), dxyz=dxyz) grid.create_xml(add_cell_length_properties=True) grid_uuid = grid.uuid # store with constant arrays (no hdf5 data) model.store_epc() # check that the grid can be read model = rq.Model(epc) grid = grr.any_grid(model, uuid=grid_uuid) # check that the cell size has been preserved expected_dxyz_dkji = np.zeros((3, 3)) for i in range(3): expected_dxyz_dkji[2 - i, i] = dxyz[i] assert_array_almost_equal(expected_dxyz_dkji, grid.block_dxyz_dkji)
def try_one_half_t_regular(model, extent_kji=(2, 2, 2), dxyz=(1.0, 1.0, 1.0), perm_kji=(1.0, 1.0, 1.0), ntg=1.0, darcy_constant=1.0, rotate=None, dip=None): ones = np.ones(extent_kji) grid = grr.RegularGrid(model, extent_kji=extent_kji, dxyz=dxyz) if dip is not None: # dip positive x axis downwards r_matrix = vec.rotation_matrix_3d_axial(1, dip) p = grid.points_ref(masked=False) p[:] = vec.rotate_array(r_matrix, p) if rotate is not None: # rotate anticlockwise in xy plane (viewed from above) r_matrix = vec.rotation_matrix_3d_axial(2, rotate) p = grid.points_ref(masked=False) p[:] = vec.rotate_array(r_matrix, p) half_t = rqtr.half_cell_t(grid, perm_k=perm_kji[0] * ones, perm_j=perm_kji[1] * ones, perm_i=perm_kji[2] * ones, ntg=ntg * ones, darcy_constant=darcy_constant) expected = 2.0 * darcy_constant * np.array( (perm_kji[0] * dxyz[0] * dxyz[1] / dxyz[2], ntg * perm_kji[1] * dxyz[0] * dxyz[2] / dxyz[1], ntg * perm_kji[2] * dxyz[1] * dxyz[2] / dxyz[0])) assert np.all(np.isclose(half_t, expected.reshape(1, 1, 1, 3)))
def test_dtype_size(tmp_path): filenames = ['dtype_16', 'dtype_32', 'dtype_64'] byte_sizes = [2, 4, 8] dtypes = [np.float16, np.float32, np.float64] hdf5_sizes = [] extent_kji = (1000, 100, 100) a = np.random.random(extent_kji) for filename, dtype in zip(filenames, dtypes): epc = os.path.join(tmp_path, filename + '.epc') h5_file = epc[:-4] + '.h5' model = rq.new_model(epc) grid = grr.RegularGrid(model, extent_kji=extent_kji) grid.create_xml() pc = rqp.PropertyCollection() pc.set_support(support_uuid=grid.uuid, model=model) pc.add_cached_array_to_imported_list( cached_array=a, source_info='random', keyword='NTG', property_kind='net to gross ratio', indexable_element='cells', uom='m3/m3') pc.write_hdf5_for_imported_list(dtype=dtype) model.store_epc() model.h5_release() hdf5_sizes.append(os.path.getsize(h5_file)) assert hdf5_sizes[0] < hdf5_sizes[1] < hdf5_sizes[2] for i, (byte_size, hdf5_size) in enumerate(zip(byte_sizes, hdf5_sizes)): array_size = byte_size * a.size # following may need to be modified if using hdf5 compression assert array_size < hdf5_size < array_size + 100000
def test_actual_pillar_shape(tmp_path): # --------- Arrange---------- epc = os.path.join(tmp_path, 'grid.epc') model = rq.new_model(epc) # create a basic block grid dxyz = (10.0, 10.0, 10.0) vertical_grid = grr.RegularGrid(model, extent_kji=(2, 2, 2), title='vert_grid', origin=(0.0, 0.0, 0.0), dxyz=dxyz) straight_grid = grr.RegularGrid(model, extent_kji=(2, 2, 2), title='straight_grid', origin=(10.0, 10.0, 0.0), dxyz=dxyz, as_irregular_grid=True) curved_grid = grr.RegularGrid(model, extent_kji=(3, 2, 2), title='curved_grid', origin=(10.0, 10.0, 0.0), dxyz=dxyz, as_irregular_grid=True) # shift the corner points of cellkji0 == (0, 0, 0) by - 10 x and -10 y units straight_grid.corner_points()[0][0][0][0][0][0] = np.array([0., 0., 0]) straight_grid.corner_points()[0][0][0][0][0][1] = np.array([10., 0., 0]) # shift 2 corner points of cellkji0 == (1, 0, 0) by -5 x units curved_grid.corner_points()[0][0][0][1][0][0] = np.array([5., 10., 10]) curved_grid.corner_points()[0][0][0][1][0][1] = np.array([15., 10., 10]) # --------- Act---------- pillar_shape_vertical = actual_pillar_shape( pillar_points=vertical_grid.corner_points()) pillar_shape_straight = actual_pillar_shape( pillar_points=straight_grid.corner_points()) pillar_shape_curved = actual_pillar_shape( pillar_points=curved_grid.corner_points()) # --------- Assert---------- assert pillar_shape_vertical == 'vertical' assert pillar_shape_straight == 'straight' assert pillar_shape_curved == 'curved'
def make_epc_with_gcs(tmp_path): epc = os.path.join(tmp_path, 'two_fault.epc') model = rq.new_model(epc) # create a grid g = grr.RegularGrid(model, extent_kji=(5, 4, 3), dxyz=(100.0, 100.0, 10.0)) g.create_xml() # create an empty grid connection set gcs = rqf.GridConnectionSet(model, grid=g) # prepare two named faults as a dataframe data = { 'name': ['F1', 'F2'], 'face': ['I+', 'J-'], 'i1': [1, 0], 'i2': [1, 2], 'j1': [0, 2], 'j2': [3, 2], 'k1': [0, 0], 'k2': [4, 4], 'mult': [0.1, 0.05] } df = pd.DataFrame(data) # set grid connection set from dataframe gcs.set_pairs_from_faces_df(df, create_organizing_objects_where_needed=True, create_mult_prop=True, fault_tmult_dict=None, one_based_indexing=False) # save the grid connection set gcs.write_hdf5() gcs.create_xml(title='two fault gcs') model.store_epc() # add some basic grid properties porosity_uuid = rqdm.add_one_grid_property_array(epc, np.full( g.extent_kji, 0.27), property_kind='porosity', title='porosity', uom='m3/m3') assert porosity_uuid is not None perm_uuid = rqdm.add_one_grid_property_array( epc, np.full(g.extent_kji, 152.0), property_kind='rock permeability', uom='mD', facet_type='direction', facet='IJK', title='permeability') assert perm_uuid is not None return epc
def make_epc_with_abutting_grids(tmp_path): epc = os.path.join(tmp_path, 'abutting_grids.epc') model = rq.new_model(epc) # create a grid g0 = grr.RegularGrid(model, extent_kji=(5, 4, 3), dxyz=(100.0, 100.0, 10.0)) g0.create_xml() g1 = grr.RegularGrid(model, extent_kji=(5, 4, 3), dxyz=(100.0, 100.0, 10.0), origin=(100.0, 400.0, 20.0)) g1.create_xml() # create an empty grid connection set gcs = rqf.GridConnectionSet(model, title='abut') # populate the grid connection set at low level due to lack of multi-grid methods gcs.grid_list = [g0, g1] gcs.count = 6 gcs.grid_index_pairs = np.zeros((6, 2), dtype=int) gcs.grid_index_pairs[:, 1] = 1 gcs.face_index_pairs = np.empty((6, 2), dtype=int) gcs.face_index_pairs[:, 0] = gcs.face_index_map[1, 1] # J+ gcs.face_index_pairs[:, 1] = gcs.face_index_map[1, 0] # J- gcs.cell_index_pairs = np.empty((6, 2), dtype=int) cell = 0 for k in range(3): for i in range(2): gcs.cell_index_pairs[cell, 0] = g0.natural_cell_index( (k + 2, 3, i + 1)) gcs.cell_index_pairs[cell, 1] = g1.natural_cell_index((k, 0, i)) cell += 1 # leave optional feature list & indices as None # save the grid connection set gcs.write_hdf5() gcs.create_xml() model.store_epc() return epc
def example_fine_coarse_model(example_model_and_crs): model, crs = example_model_and_crs coarse_grid = grr.RegularGrid(parent_model=model, origin=(0, 0, 0), extent_kji=(3, 5, 5), crs_uuid=crs.uuid, dxyz=(10, 10, 10)) coarse_grid.cache_all_geometry_arrays() coarse_grid.write_hdf5_from_caches( file=model.h5_file_name(file_must_exist=False), mode='w') coarse_grid.create_xml(ext_uuid=model.h5_uuid(), title='Coarse', write_geometry=True, add_cell_length_properties=True) fine_grid = grr.RegularGrid(parent_model=model, origin=(0, 0, 0), extent_kji=(6, 10, 10), crs_uuid=crs.uuid, dxyz=(5, 5, 5)) fine_grid.cache_all_geometry_arrays() fine_grid.write_hdf5_from_caches( file=model.h5_file_name(file_must_exist=True), mode='a') fine_grid.create_xml(ext_uuid=model.h5_uuid(), title='Fine', write_geometry=True, add_cell_length_properties=True) model.store_epc() model = Model(model.epc_file) coarse = grr.Grid(parent_model=model, uuid=coarse_grid.uuid) fine = grr.Grid(parent_model=model, uuid=fine_grid.uuid) fc = rqfc.FineCoarse(fine_extent_kji=(6, 10, 10), coarse_extent_kji=(3, 5, 5)) fc.set_all_ratios_constant() fc.set_all_proprtions_equal() return model, coarse, fine, fc
def test_random_cell(tmp_path): # --------- Arrange---------- seed(1923877) epc = os.path.join(tmp_path, 'grid.epc') model = rq.new_model(epc) # create a basic block grid dxyz = (10.0, 10.0, 100.0) grid = grr.RegularGrid(model, extent_kji=(4, 2, 2), title='grid_1', origin=(0.0, 10.0, 1000.0), dxyz=dxyz, as_irregular_grid=True) grid_points = grid.points_ref(masked=False) # pinch out cells in the k == 2 layer grid_points[3] = grid_points[2] # collapse cell kji0 == 0,0,0 in the j direction grid_points[0:2, 1, 0:2, 1] = 10. # same as origin y value # store grid grid.write_hdf5() grid.create_xml(add_cell_length_properties=True) grid_uuid = grid.uuid model.store_epc() # check that the grid can be read model = rq.Model(epc) grid_reloaded = grr.any_grid(model, uuid=grid_uuid) corner_points = grid_reloaded.corner_points() # --------- Act---------- # call random_cell function 50 times trial_number = 0 while trial_number < 50: (k, j, i) = random_cell(corner_points=corner_points, border=0.0) # --------- Assert---------- assert 0 <= k < 4 assert 0 <= j < 2 assert 0 <= i < 2 # check that none of the k,j,i combinations that correspond to pinched cells are chosen by the random_cell function assert (k, j, i) not in [(0, 0, 0), (2, 0, 0), (2, 0, 1), (2, 1, 0), (2, 1, 1)] trial_number += 1 # reshape corner get the extent of the new grid corner_points_reshaped = corner_points.reshape(1, 1, 16, 2, 2, 2, 3) new_extent = determine_corp_extent(corner_points=corner_points_reshaped) assert np.all(new_extent == np.array([4, 2, 2], dtype=int))
def test_interface_lengths_kji(model_test: Model, dxyz): # Arrange grid = grr.RegularGrid(model_test, extent_kji=(2, 2, 2), dxyz=dxyz, as_irregular_grid=True) cell_kji0 = (1, 1, 1) # Act interface_length = cp.interface_lengths_kji(grid, cell_kji0=cell_kji0) # Assert np.testing.assert_array_almost_equal(interface_length, dxyz[::-1])
def test_interface_length(model_test: Model, dxyz): # Arrange grid = grr.RegularGrid(model_test, extent_kji=(2, 2, 2), dxyz=dxyz, as_irregular_grid=True) cell_kji0 = (1, 1, 1) # Act & Assert for axis in range(3): interface_length = cp.interface_length(grid, cell_kji0=cell_kji0, axis=axis) assert interface_length == dxyz[2 - axis]
def test_regular_grid_no_geometry(tmp_path): # issue #222 epc = os.path.join(tmp_path, 'abstract.epc') model = rq.new_model(epc) # create a basic block grid grid = grr.RegularGrid(model, extent_kji=(4, 3, 2), title='spaced out') grid.create_xml(add_cell_length_properties=False) grid_uuid = grid.uuid model.store_epc() # check that the grid can be read model = rq.Model(epc) grid = grr.any_grid(model, uuid=grid_uuid)
def test_determine_corp_extent(tmp_path): # --------- Arrange---------- epc = os.path.join(tmp_path, 'grid.epc') model = rq.new_model(epc) # create a basic block grid dxyz = (55.0, 65.0, 27.0) grid = grr.RegularGrid(model, extent_kji=(4, 3, 2), title='concrete', origin=(0.0, 0.0, 1000.0), dxyz=dxyz) grid.create_xml(add_cell_length_properties=True) corner_points = grid.corner_points() corner_points_reshaped = corner_points.reshape(1, 1, 24, 2, 2, 2, 3) # --------- Act---------- [nk, nj, ni] = determine_corp_extent(corner_points=corner_points_reshaped) # --------- Assert---------- assert [nk, nj, ni] == [4, 3, 2]
def _empty_grid(model, source_grid, is_regular, k0_min, k0_max, zone_count): if is_regular: dxyz_dkji = source_grid.block_dxyz_dkji.copy() dxyz_dkji[0] *= k0_max - k0_min + 1 grid = grr.RegularGrid(model, extent_kji = (1, source_grid.nj, source_grid.ni), dxyz_dkji = dxyz_dkji, origin = source_grid.block_origin, crs_uuid = source_grid.crs_uuid, set_points_cached = False) else: grid = grr.Grid(model) # inherit attributes from source grid grid.grid_representation = 'IjkGrid' grid.extent_kji = np.array((zone_count, source_grid.nj, source_grid.ni), dtype = 'int') grid.nk, grid.nj, grid.ni = zone_count, source_grid.nj, source_grid.ni grid.has_split_coordinate_lines = source_grid.has_split_coordinate_lines grid.crs_uuid = source_grid.crs_uuid grid.k_direction_is_down = source_grid.k_direction_is_down grid.grid_is_right_handed = source_grid.grid_is_right_handed grid.pillar_shape = source_grid.pillar_shape return grid
def example_model_and_cellio(example_model_and_crs, tmp_path): model, crs = example_model_and_crs grid = grr.RegularGrid(model, extent_kji=(3, 4, 3), dxyz=(50.0, -50.0, 50.0), origin=(0.0, 0.0, 100.0), crs_uuid=crs.uuid, set_points_cached=True) grid.write_hdf5() grid.create_xml(write_geometry=True) grid_uuid = grid.uuid cellio_file = os.path.join(model.epc_directory, 'cellio.dat') well_name = 'Banoffee' source_df = pd.DataFrame([[2, 2, 1, 25, -25, 125, 26, -26, 126], [2, 2, 2, 26, -26, 126, 27, -27, 127], [2, 2, 3, 27, -27, 127, 28, -28, 128]], columns=[ 'i_index', 'j_index', 'k_index', 'x_in', 'y_in', 'z_in', 'x_out', 'y_out', 'z_out' ]) with open(cellio_file, 'w') as fp: fp.write('1.0\n') fp.write('Undefined\n') fp.write(f'{well_name}\n') fp.write('9\n') for col in source_df.columns: fp.write(f' {col}\n') for row_index in range(len(source_df)): row = source_df.iloc[row_index] for col in source_df.columns: fp.write(f' {int(row[col])}') fp.write('\n') return model, cellio_file, well_name
def example_model_with_prop_ts_rels(tmp_path): """Model with a grid (5x5x3) and properties. Properties: - Zone (discrete) - VPC (discrete) - Fault block (discrete) - Facies (discrete) - NTG (continuous) - POR (continuous) - SW (continuous) (recurrent) """ model_path = str(tmp_path / 'test_model.epc') model = Model(create_basics=True, create_hdf5_ext=True, epc_file=model_path, new_epc=True) model.store_epc(model.epc_file) grid = grr.RegularGrid(parent_model=model, origin=(0, 0, 0), extent_kji=(3, 5, 5), crs_uuid=rqet.uuid_for_part_root(model.crs_root), set_points_cached=True) grid.cache_all_geometry_arrays() grid.write_hdf5_from_caches(file=model.h5_file_name(file_must_exist=False), mode='w') grid.create_xml(ext_uuid=model.h5_uuid(), title='grid', write_geometry=True, add_cell_length_properties=False) model.store_epc() zone = np.ones(shape=(5, 5), dtype='int') zone_array = np.array([zone, zone + 1, zone + 2], dtype='int') vpc = np.array([[1, 1, 1, 2, 2], [1, 1, 1, 2, 2], [1, 1, 1, 2, 2], [1, 1, 1, 2, 2], [1, 1, 1, 2, 2]], dtype='int') vpc_array = np.array([vpc, vpc, vpc], dtype='int') facies = np.array([[1, 1, 1, 2, 2], [1, 1, 2, 2, 2], [1, 2, 2, 2, 3], [2, 2, 2, 3, 3], [2, 2, 3, 3, 3]], dtype='int') facies_array = np.array([facies, facies, facies], dtype='int') perm = np.array([[1, 1, 1, 10, 10], [1, 1, 1, 10, 10], [1, 1, 1, 10, 10], [1, 1, 1, 10, 10], [1, 1, 1, 10, 10]]) perm_array = np.array([perm, perm, perm], dtype='float') fb = np.array([[1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [2, 2, 2, 2, 2], [2, 2, 2, 2, 2]], dtype='int') fb_array = np.array([fb, fb, fb], dtype='int') ntg = np.array([[0, 0.5, 0, 0.5, 0], [0.5, 0, 0.5, 0, 0.5], [0, 0.5, 0, 0.5, 0], [0.5, 0, 0.5, 0, 0.5], [0, 0.5, 0, 0.5, 0]]) ntg1_array = np.array([ntg, ntg, ntg]) ntg2_array = np.array([ntg + 0.1, ntg + 0.1, ntg + 0.1]) por = np.array([[1, 1, 1, 1, 1], [0.5, 0.5, 0.5, 0.5, 0.5], [1, 1, 1, 1, 1], [0.5, 0.5, 0.5, 0.5, 0.5], [1, 1, 1, 1, 1]]) por1_array = np.array([por, por, por]) por2_array = np.array([por - 0.1, por - 0.1, por - 0.1]) sat = np.array([[1, 0.5, 1, 0.5, 1], [1, 0.5, 1, 0.5, 1], [1, 0.5, 1, 0.5, 1], [1, 0.5, 1, 0.5, 1], [1, 0.5, 1, 0.5, 1]]) sat1_array = np.array([sat, sat, sat]) sat2_array = np.array([sat, sat, np.where(sat == 0.5, 0.75, sat)]) sat3_array = np.array([ np.where(sat == 0.5, 0.75, sat), np.where(sat == 0.5, 0.75, sat), np.where(sat == 0.5, 0.75, sat) ]) collection = rqp.GridPropertyCollection() collection.set_grid(grid) ts = rqts.TimeSeries(parent_model=model, first_timestamp='2000-01-01Z') ts.extend_by_days(365) ts.extend_by_days(365) ts.create_xml() lookup = rqp.StringLookup(parent_model=model, int_to_str_dict={ 1: 'channel', 2: 'interbedded', 3: 'shale' }) lookup.create_xml() model.store_epc() # Add non-varying properties for array, name, kind, discrete, facet_type, facet in zip( [zone_array, vpc_array, fb_array, perm_array], ['Zone', 'VPC', 'Fault block', 'Perm'], ['discrete', 'discrete', 'discrete', 'permeability rock'], [True, True, True, False], [None, None, None, 'direction'], [None, None, None, 'J']): collection.add_cached_array_to_imported_list(cached_array=array, source_info='', keyword=name, discrete=discrete, uom=None, time_index=None, null_value=None, property_kind=kind, facet_type=facet_type, facet=facet, realization=None) collection.write_hdf5_for_imported_list() collection.create_xml_for_imported_list_and_add_parts_to_model() # Add realisation varying properties for array, name, kind, rel in zip( [ntg1_array, por1_array, ntg2_array, por2_array], ['NTG', 'POR', 'NTG', 'POR'], ['net to gross ratio', 'porosity', 'net to gross ratio', 'porosity'], [0, 0, 1, 1]): collection.add_cached_array_to_imported_list(cached_array=array, source_info='', keyword=name, discrete=False, uom=None, time_index=None, null_value=None, property_kind=kind, facet_type=None, facet=None, realization=rel) collection.write_hdf5_for_imported_list() collection.create_xml_for_imported_list_and_add_parts_to_model() # Add categorial property collection.add_cached_array_to_imported_list(cached_array=facies_array, source_info='', keyword='Facies', discrete=True, uom=None, time_index=None, null_value=None, property_kind='discrete', facet_type=None, facet=None, realization=None) collection.write_hdf5_for_imported_list() collection.create_xml_for_imported_list_and_add_parts_to_model( string_lookup_uuid=lookup.uuid) # Add time varying properties for array, ts_index in zip([sat1_array, sat2_array, sat3_array], [0, 1, 2]): collection.add_cached_array_to_imported_list( cached_array=array, source_info='', keyword='SW', discrete=False, uom=None, time_index=ts_index, null_value=None, property_kind='saturation', facet_type='what', facet='water', realization=None) collection.write_hdf5_for_imported_list() collection.create_xml_for_imported_list_and_add_parts_to_model( time_series_uuid=ts.uuid) model.store_epc() return model
def example_model_with_properties(tmp_path): """Model with a grid (5x5x3) and properties. Properties: - Zone (discrete) - VPC (discrete) - Fault block (discrete) - Facies (discrete) - NTG (continuous) - POR (continuous) - SW (continuous) """ model_path = str(tmp_path / 'test_no_rels.epc') model = Model(create_basics=True, create_hdf5_ext=True, epc_file=model_path, new_epc=True) model.store_epc(model.epc_file) grid = grr.RegularGrid(parent_model=model, origin=(0, 0, 0), extent_kji=(3, 5, 5), crs_uuid=rqet.uuid_for_part_root(model.crs_root), set_points_cached=True) grid.cache_all_geometry_arrays() grid.write_hdf5_from_caches(file=model.h5_file_name(file_must_exist=False), mode='w') grid.create_xml(ext_uuid=model.h5_uuid(), title='grid', write_geometry=True, add_cell_length_properties=False) model.store_epc() zone = np.ones(shape=(5, 5)) zone_array = np.array([zone, zone + 1, zone + 2], dtype='int') vpc = np.array([[1, 1, 1, 2, 2], [1, 1, 1, 2, 2], [1, 1, 1, 2, 2], [1, 1, 1, 2, 2], [1, 1, 1, 2, 2]]) vpc_array = np.array([vpc, vpc, vpc]) facies = np.array([[1, 1, 1, 2, 2], [1, 1, 2, 2, 2], [1, 2, 2, 2, 3], [2, 2, 2, 3, 3], [2, 2, 3, 3, 3]]) facies_array = np.array([facies, facies, facies]) fb = np.array([[1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [2, 2, 2, 2, 2], [2, 2, 2, 2, 2]]) fb_array = np.array([fb, fb, fb]) ntg = np.array([[0, 0.5, 0, 0.5, 0], [0.5, 0, 0.5, 0, 0.5], [0, 0.5, 0, 0.5, 0], [0.5, 0, 0.5, 0, 0.5], [0, 0.5, 0, 0.5, 0]]) ntg_array = np.array([ntg, ntg, ntg]) por = np.array([[1, 1, 1, 1, 1], [0.5, 0.5, 0.5, 0.5, 0.5], [1, 1, 1, 1, 1], [0.5, 0.5, 0.5, 0.5, 0.5], [1, 1, 1, 1, 1]]) por_array = np.array([por, por, por]) sat = np.array([[1, 0.5, 1, 0.5, 1], [1, 0.5, 1, 0.5, 1], [1, 0.5, 1, 0.5, 1], [1, 0.5, 1, 0.5, 1], [1, 0.5, 1, 0.5, 1]]) sat_array = np.array([sat, sat, sat]) perm = np.array([[1, 10, 10, 100, 100], [1, 10, 10, 100, 100], [1, 10, 10, 100, 100], [1, 10, 10, 100, 100], [1, 10, 10, 100, 100]]) perm_array = np.array([perm, perm, perm], dtype='float') perm_v_array = perm_array * 0.1 collection = rqp.GridPropertyCollection() collection.set_grid(grid) for array, name, kind, discrete, facet_type, facet in zip( [ zone_array, vpc_array, fb_array, facies_array, ntg_array, por_array, sat_array, perm_array, perm_v_array ], [ 'Zone', 'VPC', 'Fault block', 'Facies', 'NTG', 'POR', 'SW', 'Perm', 'PERMZ' ], [ 'discrete', 'discrete', 'discrete', 'discrete', 'net to gross ratio', 'porosity', 'saturation', 'rock permeability', 'permeability rock' ], [True, True, True, True, False, False, False, False, False], [None, None, None, None, None, None, None, 'direction', 'direction'], [None, None, None, None, None, None, None, 'I', 'K']): collection.add_cached_array_to_imported_list(cached_array=array, source_info='', keyword=name, discrete=discrete, uom=None, time_index=None, null_value=None, property_kind=kind, facet_type=facet_type, facet=facet, realization=None) collection.write_hdf5_for_imported_list() collection.create_xml_for_imported_list_and_add_parts_to_model() model.store_epc() return model
def test_gcs_property_inheritance(tmp_path): epc = os.path.join(tmp_path, 'gcs_prop_inherit.epc') model = rq.Model(epc, new_epc=True, create_basics=True, create_hdf5_ext=True) # create a grid g = grr.RegularGrid(model, extent_kji=(5, 3, 3), dxyz=(10.0, 10.0, 1.0)) g.write_hdf5() g.create_xml(title='unsplit grid') # define an L shaped (in plan view) fault j_faces = np.zeros((g.nk, g.nj - 1, g.ni), dtype=bool) j_faces[:, 0, 1:] = True i_faces = np.zeros((g.nk, g.nj, g.ni - 1), dtype=bool) i_faces[:, 1:, 0] = True gcs = rqf.GridConnectionSet( model, grid=g, j_faces=j_faces, i_faces=i_faces, feature_name='L fault', create_organizing_objects_where_needed=True, create_transmissibility_multiplier_property=False) # check that connection set has the right number of cell face pairs assert gcs.count == g.nk * ((g.nj - 1) + (g.ni - 1)) # create a transmissibility multiplier property tm = np.arange(gcs.count).astype(float) if gcs.property_collection is None: gcs.property_collection = rqp.PropertyCollection() gcs.property_collection.set_support(support=gcs) pc = gcs.property_collection pc.add_cached_array_to_imported_list( tm, 'unit test', 'TMULT', uom='Euc', # actually a ratio of transmissibilities property_kind='transmissibility multiplier', local_property_kind_uuid=None, realization=None, indexable_element='faces') # write gcs which should also write property collection and create a local property kind gcs.write_hdf5() gcs.create_xml(write_new_properties=True) # check that a local property kind has materialised pk_uuid = model.uuid(obj_type='PropertyKind', title='transmissibility multiplier') assert pk_uuid is not None # check that we can create a surface object for the gcs surf = gcs.surface() assert surf is not None t, _ = surf.triangles_and_points() assert t.shape == (2 * gcs.count, 3) # create a derived grid connection set using a layer range thin_gcs, thin_indices = gcs.filtered_by_layer_range(min_k0=1, max_k0=3, return_indices=True) assert thin_gcs is not None and thin_indices is not None assert thin_gcs.count == 3 * ((g.nj - 1) + (g.ni - 1)) # inherit the transmissibility multiplier property thin_gcs.inherit_properties_for_selected_indices(gcs, thin_indices) thin_gcs.write_hdf5() thin_gcs.create_xml() # by default will include write of new properties # check that the inheritance has worked assert thin_gcs.property_collection is not None and thin_gcs.property_collection.number_of_parts( ) > 0 thin_pc = thin_gcs.property_collection tm_part = thin_pc.singleton(property_kind='transmissibility multiplier') assert tm_part is not None thin_tm = thin_pc.cached_part_array_ref(tm_part) assert thin_tm is not None and thin_tm.ndim == 1 assert thin_tm.size == thin_gcs.count assert_array_almost_equal(thin_tm, tm[thin_indices]) # check that get_combined...() method can execute using property collection b_a, i_a, f_a = gcs.get_combined_fault_mask_index_value_arrays( min_k=1, max_k=3, property_name='Transmissibility multiplier', ref_k=2) assert b_a is not None and i_a is not None and f_a is not None # check that transmissibility multiplier values have been sampled correctly from property array assert f_a.shape == (g.nj, g.ni, 2, 2) assert np.count_nonzero( np.isnan(f_a)) == 4 * g.nj * g.ni - 2 * ((g.nj - 1) + (g.ni - 1)) assert np.nanmax(f_a) > np.nanmin(f_a) restore = np.seterr(all='ignore') assert np.all(np.logical_or(np.isnan(f_a), f_a >= np.nanmin(thin_tm))) assert np.all(np.logical_or(np.isnan(f_a), f_a <= np.nanmax(thin_tm))) np.seterr(**restore)
def basic_regular_grid(model_test: Model) -> Grid: return grr.RegularGrid(model_test, extent_kji=(2, 2, 2), dxyz=(100.0, 50.0, 20.0), as_irregular_grid=True)
def aligned_regular_grid(model_test: Model) -> Grid: return grr.RegularGrid(model_test, extent_kji=(2, 3, 4), dxyz=(100.0, 50.0, 20.0))
def test_pinchout_and_k_gap_gcs(tmp_path): epc = os.path.join(tmp_path, 'gcs_pinchout_k_gap.epc') model = rq.new_model(epc) # create a grid g = grr.RegularGrid(model, extent_kji=(5, 5, 5), dxyz=(100.0, 100.0, 10.0), as_irregular_grid=True) # patch points to generate a pinchout p = g.points_cached assert p.shape == (6, 6, 6, 3) p[2, :3, :3] = p[1, :3, :3] # convert one layer to a K gap with pinchout p[4, 3:, 3:] = p[3, 3:, 3:] g.nk -= 1 g.extent_kji = np.array((g.nk, g.nj, g.ni), dtype=int) g.k_gaps = 1 g.k_gap_after_array = np.zeros(g.nk - 1, dtype=bool) g.k_gap_after_array[2] = True g._set_k_raw_index_array() g.write_hdf5() g.create_xml(title='pinchout k gap grid') model.store_epc() # reload the grid model = rq.Model(epc) grid = model.grid() assert grid is not None assert grid.k_gaps == 1 assert tuple(grid.extent_kji) == (4, 5, 5) # create a pinchout connection set po_gcs = rqf.pinchout_connection_set(grid) assert po_gcs is not None po_gcs.write_hdf5() po_gcs.create_xml() po_uuid = po_gcs.uuid # create a K gap connection set kg_gcs = rqf.k_gap_connection_set(grid) assert kg_gcs is not None kg_gcs.write_hdf5() kg_gcs.create_xml() kg_uuid = kg_gcs.uuid model.store_epc() # re-open the model and load the connection sets model = rq.Model(epc) po_gcs = rqf.GridConnectionSet(model, uuid=po_uuid) assert po_gcs is not None po_gcs.cache_arrays() kg_gcs = rqf.GridConnectionSet(model, uuid=kg_uuid) assert kg_gcs is not None kg_gcs.cache_arrays() # check face pairs in the pinchout connection set assert po_gcs.count == 4 assert po_gcs.cell_index_pairs.shape == (4, 2) assert po_gcs.face_index_pairs.shape == (4, 2) assert np.all( po_gcs.cell_index_pairs[:, 0] != po_gcs.cell_index_pairs[:, 1]) assert np.all( po_gcs.face_index_pairs[:, 0] != po_gcs.cell_index_pairs[:, 1]) assert np.all( np.logical_or(po_gcs.face_index_pairs == 0, po_gcs.face_index_pairs == 1)) for cell in po_gcs.cell_index_pairs.flatten(): assert cell in [0, 1, 5, 6, 50, 51, 55, 56] assert np.all( np.abs(po_gcs.cell_index_pairs[:, 1] - po_gcs.cell_index_pairs[:, 0]) == 50) # check face pairs in K gap connection set assert kg_gcs.count == 4 assert kg_gcs.cell_index_pairs.shape == (4, 2) assert kg_gcs.face_index_pairs.shape == (4, 2) assert np.all( kg_gcs.cell_index_pairs[:, 0] != kg_gcs.cell_index_pairs[:, 1]) assert np.all( kg_gcs.face_index_pairs[:, 0] != kg_gcs.cell_index_pairs[:, 1]) assert np.all( np.logical_or(kg_gcs.face_index_pairs == 0, kg_gcs.face_index_pairs == 1)) for cell in kg_gcs.cell_index_pairs.flatten(): assert cell in [74, 73, 69, 68, 99, 98, 94, 93] assert np.all( np.abs(kg_gcs.cell_index_pairs[:, 1] - kg_gcs.cell_index_pairs[:, 0]) == 25) # test compact indices method ci = po_gcs.compact_indices() assert ci.shape == (4, 2) for cf in ci.flatten(): assert cf in [1, 7, 31, 37, 300, 306, 330, 336] assert np.all(np.abs(ci[:, 1] - ci[:, 0]) == 299) # test write simulator method files = ('fault_ff.dat', 'fault_tf.dat', 'fault_ft.dat') both_sides = (False, True, False) minus = (False, False, True) for filename, inc_both_sides, use_minus in zip(files, both_sides, minus): dat_path = os.path.join(tmp_path, filename) po_gcs.write_simulator(dat_path, include_both_sides=inc_both_sides, use_minus=use_minus) assert os.path.exists(dat_path)