def test_swapaxis_rotation(rotation, expected_rotation, default_surface): default_surface["rotation"] = rotation surface = RegularSurface(**default_surface) surface.swapaxes() assert surface.rotation == expected_rotation
def test_swapaxis_xinc_yinc(default_surface): default_surface["yinc"] = 2.0 surface = RegularSurface(**default_surface) surface.swapaxes() assert (surface.xinc, surface.yinc) == (2, 1)
def test_swapaxis_yflip(default_surface, yflip, expected_result): default_surface["yflip"] = yflip surface = RegularSurface(**default_surface) surface.swapaxes() assert surface.yflip == expected_result
def test_swapaxis(default_surface): surface = RegularSurface(**default_surface) assert surface.values.flatten().tolist() == [1, 2, 3, 4] surface.swapaxes() assert surface.values.flatten().tolist() == [1.0, 3.0, 2.0, 4.0]
def test_init_with_surface(): """Initialise points object with surface instance.""" surf = RegularSurface(ncol=4, nrow=5, xori=0, yori=0, xinc=25, yinc=25) poi = Points(surf) poi.zname = "VALUES" pd.testing.assert_frame_equal(poi.dataframe, surf.dataframe())
def test_swapaxis_ncol_nrow(default_surface): default_surface["nrow"] = 3 default_surface["values"] = [1] * 6 surface = RegularSurface(**default_surface) surface.swapaxes() assert (surface.nrow, surface.ncol) == (2, 3)
def test_swapaxis_ilines(default_surface): surface = RegularSurface(**default_surface) assert surface.ilines.tolist() == [1, 2] surface.swapaxes() assert surface.ilines.tolist() == [1, 2]
def test_values_mask_setter(input_val, expected_data, expected_mask): surf = RegularSurface( 2, 2, 0.0, 0.0, values=np.ma.MaskedArray([[2, 2], [2, 2]], mask=[[True, False], [False, True]]), ) surf.values = input_val assert surf.values.mask.tolist() == expected_mask assert list(surf.values.data.flatten()) == expected_data
def get_surface_randomline( surface: xtgeo.RegularSurface, fence_spec: np.ndarray, sampling: Optional[str] = "billinear", ) -> np.ndarray: try: return surface.get_randomline(fence_spec, sampling=sampling) except TypeError: # Attempt to handle vertical wells fence_spec = np.insert(fence_spec, 0, fence_spec[0] - 10, axis=0) fence_spec = np.append(fence_spec, [fence_spec[-1] + 10], axis=0) return surface.get_randomline(fence_spec, sampling=sampling)
def test_simple_io(input_val, expected_result, fformat, engine): if engine == "python" and fformat not in [ "irap_ascii", "irap_binary", "zmap_ascii", ]: pytest.skip("Only one engine available") surf = RegularSurface(ncol=2, nrow=2, xinc=2.0, yinc=2.0, values=input_val) surf.to_file("my_file", fformat=fformat) surf_from_file = RegularSurface._read_file("my_file", fformat=fformat, engine=engine) assert_similar_surfaces(surf, surf_from_file) assert surf_from_file.values.data.tolist() == expected_result
def test_from_simple_surface(): """Create points from a simple surface.""" surf = RegularSurface(ncol=4, nrow=5, xori=0, yori=0, xinc=25, yinc=25) poi = Points() poi.from_surface(surf) poi.zname = "VALUES" pd.testing.assert_frame_equal(poi.dataframe, surf.dataframe()) poi = Points() poi.from_surface(surf, zname="VALUES") pd.testing.assert_frame_equal(poi.dataframe, surf.dataframe())
def add_surface_layer( self, surface: RegularSurface, name: str, tooltip: str = None, color: str = "blue", checked: bool = True, ): """Adds a polyline overlay layer for a given XTGeo surface""" x_arr, y_arr = self.slice_surface(surface.copy()) positions = [[x, y] for x, y in zip(x_arr, y_arr)] self._surface_layers.append({ "name": name, "checked": checked, "base_layer": False, "data": [{ "type": "polyline", "positions": positions, "color": color, "tooltip": tooltip if tooltip else name, }], })
def test_read_grid3d(): grid = Grid( ) # this creates an example Grid (no other way to do it currently) surf = RegularSurface._read_grid3d(grid=grid) # There is some resolution changes between the grid and the surface, so we cant # expect identical sizes, even for regular grids. assert (surf.ncol, surf.nrow) == (3, 3)
def _calc_map_component_bounds_and_rot( surface: xtgeo.RegularSurface, ) -> Tuple[List[float], float]: surf_corners = surface.get_map_xycorners() rptx = surf_corners[2][0] rpty = surf_corners[2][1] min_x = math.inf max_x = -math.inf min_y = math.inf max_y = -math.inf angle = -surface.rotation * math.pi / 180 for coord in surf_corners: xpos = coord[0] ypos = coord[1] x_rotated = ( rptx + ((xpos - rptx) * math.cos(angle)) - ((ypos - rpty) * math.sin(angle)) ) y_rotated = ( rpty + ((xpos - rptx) * math.sin(angle)) + ((ypos - rpty) * math.cos(angle)) ) min_x = min(min_x, x_rotated) max_x = max(max_x, x_rotated) min_y = min(min_y, y_rotated) max_y = max(max_y, y_rotated) bounds = [ min_x, min_y, max_x, max_y, ] return bounds, surface.rotation
def get_surface_arr( surface: RegularSurface, unrotate: bool = True, flip: bool = True, clip_min: Union[float, np.ndarray, None] = None, clip_max: Union[float, np.ndarray, None] = None, ) -> List[np.ndarray]: if clip_min or clip_max: np.ma.clip(surface.values, clip_min, clip_max, out=surface.values) if unrotate: surface.unrotate() x, y, z = surface.get_xyz_values() if flip: x = np.flip(x.transpose(), axis=0) y = np.flip(y.transpose(), axis=0) z = np.flip(z.transpose(), axis=0) z.filled(np.nan) return [x, y, z]
def store(self, address: StatisticalSurfaceAddress, surface: xtgeo.RegularSurface) -> None: surf_fn = _compose_stat_surf_file_name(address, FILE_EXTENSION) full_surf_path = self.cache_dir / surf_fn # Try and go via a temporary file which we don't rename until writing is finished. # to make the cache writing more concurrency-friendly. # One problem here is that we don't control the file handle (xtgeo does) so can't # enforce flush and sync of the file to disk before the rename :-( # Still, we probably need a more robust way of shring the cached surfaces... tmp_surf_path = self.cache_dir / (surf_fn + f"__{uuid.uuid4().hex}.tmp") try: surface.to_file(tmp_surf_path, fformat=FILE_FORMAT_WRITE) os.replace(tmp_surf_path, full_surf_path) # pylint: disable=bare-except except: os.remove(tmp_surf_path)
def calculate_surface_difference( surface: xtgeo.RegularSurface, surface2: xtgeo.RegularSurface, calculation: str = "Difference", ) -> xtgeo.RegularSurface: surface3 = surface.copy() if calculation == "Difference": surface3.values = surface3.values - surface2.values elif calculation == "Sum": surface3.values = surface3.values + surface2.values elif calculation == "Product": surface3.values = surface3.values * surface2.values elif calculation == "Quotient": surface3.values = surface3.values / surface2.values return surface3
def test_complex_io(surf, fformat, output_engine, input_engine): if (input_engine == "python" or output_engine == "python") and fformat not in [ "irap_ascii", "irap_binary", "zmap_ascii", ]: pytest.skip("Only one engine available") if fformat == "petromod": pytest.xfail("Several hypotesis failures (4)") surf.to_file("my_file", fformat=fformat, engine=output_engine) surf_from_file = RegularSurface._read_file("my_file", fformat=fformat, engine=input_engine) assert_similar_surfaces(surf, surf_from_file)
def test_read_cube(data): cube_input = { "xori": 1.0, "yori": 2.0, "zori": 3.0, "ncol": 3, "nrow": 3, "nlay": 2, "xinc": 20.0, "yinc": 25.0, "zinc": 2.0, } cube = Cube(**cube_input) surf_from_cube = RegularSurface._read_cube(cube, data) assert set(surf_from_cube.values.data.flatten().tolist()) == pytest.approx( {data}) cube_input.pop("zinc") cube_input.pop("nlay") cube_input.pop("zori") # Make sure it is properly constructed: result = {key: getattr(surf_from_cube, key) for key in cube_input} assert result == cube_input
def load_surface(surface_path: str) -> RegularSurface: return RegularSurface(surface_path)
def surface_to_png_bytes(surface: xtgeo.RegularSurface) -> bytes: """Converts a xtgeo Surface to RGBA array. Used to set the image when used in a DeckGLMap component""" timer = PerfTimer() # surface.unrotate() LOGGER.debug(f"unrotate: {timer.lap_s():.2f}s") surface.fill(np.nan) values = surface.values values = np.flip(values.transpose(), axis=0) # If all values are masked set to zero if values.mask.all(): values = np.zeros(values.shape) LOGGER.debug(f"fill/flip/mask: {timer.lap_s():.2f}s") min_val = np.nanmin(surface.values) max_val = np.nanmax(surface.values) if min_val == 0.0 and max_val == 0.0: scale_factor = 1.0 else: scale_factor = (256 * 256 * 256 - 1) / (max_val - min_val) LOGGER.debug(f"minmax: {timer.lap_s():.2f}s") z_array = (values.copy() - min_val) * scale_factor z_array = z_array.copy() shape = z_array.shape LOGGER.debug(f"scale and copy: {timer.lap_s():.2f}s") z_array = np.repeat(z_array, 4) # This will flatten the array z_array[0::4][np.isnan(z_array[0::4])] = 0 # Red z_array[1::4][np.isnan(z_array[1::4])] = 0 # Green z_array[2::4][np.isnan(z_array[2::4])] = 0 # Blue z_array[0::4] = np.floor((z_array[0::4] / (256 * 256)) % 256) # Red z_array[1::4] = np.floor((z_array[1::4] / 256) % 256) # Green z_array[2::4] = np.floor(z_array[2::4] % 256) # Blue z_array[3::4] = np.where(np.isnan(z_array[3::4]), 0, 255) # Alpha LOGGER.debug(f"bytestuff: {timer.lap_s():.2f}s") # Back to 2d shape + 1 dimension for the rgba values. z_array = z_array.reshape((shape[0], shape[1], 4)) image = Image.fromarray(np.uint8(z_array), "RGBA") LOGGER.debug(f"create: {timer.lap_s():.2f}s") byte_io = io.BytesIO() # Huge speed benefit from reducing compression level image.save(byte_io, format="png", compress_level=1) LOGGER.debug(f"save png to bytes: {timer.lap_s():.2f}s") byte_io.seek(0) ret_bytes = byte_io.read() LOGGER.debug(f"read bytes: {timer.lap_s():.2f}s") LOGGER.debug(f"Total time: {timer.elapsed_s():.2f}s") return ret_bytes
import numpy as np from xtgeo import RegularSurface, Cube, Grid, GridProperty from webviz_subsurface.datainput.layeredmap._layered_fence import LayeredFence SURFACE = RegularSurface("tests/data/surface.gri") CUBE = Cube("tests/data/seismic.segy") FENCESPEC = np.loadtxt("tests/data/polyline.np.gz") S_SLICE = np.loadtxt("tests/data/surface_slice.np.gz") with open("tests/data/seismic_png.txt", "r") as f: SEISMIC_IMG = f.read() GRID = Grid("tests/data/grid.roff") GRIDPROP = GridProperty("tests/data/prop.roff") with open("tests/data/gridprop_png.txt", "r") as f: GRIDPROP_IMG = f.read() def test_layered_fence_init(): fence = LayeredFence(FENCESPEC) assert np.array_equal(fence.fencespec, FENCESPEC) assert fence._surface_layers == [] assert np.allclose(fence.center, [[0, 0], [0, 0]]) assert np.allclose(fence.center, [0, 0]) def test_slice_surface(): fence = LayeredFence(FENCESPEC) assert np.array_equal(fence.slice_surface(SURFACE.copy()), S_SLICE) def test_set_surface_bounds_and_center(): fence = LayeredFence(FENCESPEC)
def test_default_values(): surf = RegularSurface(2, 2, 0.0, 0.0) assert surf.values.data.tolist() == [[0.0, 0.0], [0.0, 0.0]]
def test_input_numbers(data): surf = RegularSurface(10, 10, 0.0, 0.0, values=data) assert set(surf.values.data.flatten().tolist()) == pytest.approx({data})
def test_wrong_size_input_lists(data): assume(len(data) != 100) with pytest.raises(ValueError, match=r"Cannot reshape array:"): RegularSurface(10, 10, 0.0, 0.0, values=data)
def test_input_lists(data): surf = RegularSurface(5, 5, 0.0, 0.0, values=data) assert surf.values.data.flatten().tolist() == pytest.approx(data)
def get_surface_fence(fence: np.ndarray, surface: RegularSurface) -> np.ndarray: return surface.get_fence(fence)
def test_values_type(input_val, expected_result): surf = RegularSurface(2, 2, 0.0, 0.0, values=input_val) assert isinstance(surf.values, np.ma.MaskedArray) assert surf.values.data.tolist() == expected_result
def load_surface(surface_path): return RegularSurface(surface_path)
def test_values_setter(input_values, input_val, expected_result): surf = RegularSurface(2, 2, 0.0, 0.0, values=input_values) surf.values = input_val assert surf.values.data.tolist() == expected_result