def show_stats(): """Get statistics for one realisation, poro/perm filtered on facies. But note that values here are unweighted as total volume is not present. """ # read grid grd = xtgeo.grid_from_file(GRIDFILE) # read facies (to be used as filter) facies = xtgeo.gridproperty_from_file(FACIESFILE, name=FACIES, grid=grd) print("Facies codes are: {}".format(facies.codes)) for propname in PROPS: pfile = ojn(EXPATH1, ROOT + "--" + propname + EXT) pname = "geogrid--" + propname prop = xtgeo.gridproperty_from_file(pfile, name=pname, grid=grd) print("Working with {}".format(prop.name)) # now find statistics for each facies, and all facies for key, fname in facies.codes.items(): avg = prop.values[facies.values == key].mean() std = prop.values[facies.values == key].std() print("For property {} in facies {}, avg is {:10.3f} and " "stddev is {:9.3f}".format(propname, fname, avg, std)) avg = prop.values.mean() std = prop.values.std() print("For property {} in ALL facies, avg is {:10.3f} and " "stddev is {:9.3f}".format(propname, avg, std))
def fixture_create_project(): """Create a tmp RMS project for testing, populate with basic data. After the yield command, the teardown phase will remove the tmp RMS project. """ prj1 = str(PRJ) print("\n******** Setup RMS project!\n") if isdir(prj1): print("Remove existing project! (1)") shutil.rmtree(prj1) project = roxar.Project.create() rox = xtgeo.RoxUtils(project) print("Roxar version is", rox.roxversion) print("RMS version is", rox.rmsversion(rox.roxversion)) assert "1." in rox.roxversion for wfile in WELLS1: wobj = xtgeo.well_from_file(WELLSFOLDER1 / wfile) if "XP_with" in wfile: wobj.name = "OP2_w_repeat" wobj.to_roxar(project, wobj.name, logrun="log", trajectory="My trajectory") # populate with cube data cube = xtgeo.cube_from_file(CUBEDATA1) cube.to_roxar(project, CUBENAME1, domain="depth") # populate with surface data rox.create_horizons_category(SURFCAT1) for num, name in enumerate(SURFNAMES1): srf = xtgeo.surface_from_file(SURFTOPS1[num]) project.horizons.create(name, roxar.HorizonType.interpreted) srf.to_roxar(project, name, SURFCAT1) # populate with grid and props grd = xtgeo.grid_from_file(GRIDDATA1) grd.to_roxar(project, GRIDNAME1) por = xtgeo.gridproperty_from_file(PORODATA1, name=PORONAME1) por.to_roxar(project, GRIDNAME1, PORONAME1) zon = xtgeo.gridproperty_from_file(ZONEDATA1, name=ZONENAME1) zon.values = zon.values.astype(np.uint8) zon.to_roxar(project, GRIDNAME1, ZONENAME1) # save project (both an initla version and a work version) and exit project.save_as(prj1) project.close() yield project print("\n******* Teardown RMS project!\n") if isdir(prj1): print("Remove existing project! (1)") shutil.rmtree(prj1)
def test_import_dualperm_grid_soil(): """Test grid with flag for dual perm setup (will also mean dual poro also)""" grd = xtgeo.grid_from_file(DUALFILE2.with_suffix(".EGRID")) grd._dualactnum.to_file("TMP/dualact.roff") sgas = xtgeo.gridproperty_from_file( DUALFILE2.with_suffix(".UNRST"), grid=grd, name="SGAS", date=20170121, fracture=False, ) sgas.describe() tsetup.assert_almostequal(sgas.values[3, 0, 0], 0.0, 0.001) tsetup.assert_almostequal(sgas.values[0, 1, 0], 0.0, 0.001) soil = xtgeo.gridproperty_from_file( DUALFILE2.with_suffix(".UNRST"), grid=grd, name="SOIL", date=20170121, fracture=False, ) soil.describe() tsetup.assert_almostequal(soil.values[3, 0, 0], 0.44525, 0.001) tsetup.assert_almostequal(soil.values[0, 1, 0], 0.0, 0.001) tsetup.assert_almostequal(soil.values[3, 2, 0], 0.0, 0.0001) # fractures sgas = xtgeo.gridproperty_from_file( DUALFILE2.with_suffix(".UNRST"), grid=grd, name="SGAS", date=20170121, fracture=True, ) tsetup.assert_almostequal(sgas.values[3, 0, 0], 0.0, 0.001) tsetup.assert_almostequal(sgas.values[0, 1, 0], 0.0, 0.0001) soil = xtgeo.gridproperty_from_file( DUALFILE2.with_suffix(".UNRST"), grid=grd, name="SOIL", date=20170121, fracture=True, ) tsetup.assert_almostequal(soil.values[3, 0, 0], 0.0, 0.001) tsetup.assert_almostequal(soil.values[0, 1, 0], 0.011741, 0.0001) tsetup.assert_almostequal(soil.values[3, 2, 0], 0.11676, 0.0001)
def test_import_dualporo_grid(): """Test grid with flag for dual porosity setup, oil water""" grd = xtgeo.grid_from_file(DUALFILE1.with_suffix(".EGRID")) assert grd.dualporo is True assert grd.dualperm is False assert grd.dimensions == (5, 3, 1) poro = xtgeo.gridproperty_from_file(DUALFILE1.with_suffix(".INIT"), grid=grd, name="PORO") tsetup.assert_almostequal(poro.values[0, 0, 0], 0.1, 0.001) tsetup.assert_almostequal(poro.values[1, 1, 0], 0.16, 0.001) tsetup.assert_almostequal(poro.values[4, 2, 0], 0.24, 0.001) assert poro.name == "POROM" poro.describe() poro = xtgeo.gridproperty_from_file(DUALFILE1.with_suffix(".INIT"), grid=grd, name="PORO", fracture=True) tsetup.assert_almostequal(poro.values[0, 0, 0], 0.25, 0.001) tsetup.assert_almostequal(poro.values[4, 2, 0], 0.39, 0.001) assert poro.name == "POROF" poro.describe() swat = xtgeo.gridproperty_from_file( DUALFILE1.with_suffix(".UNRST"), grid=grd, name="SWAT", date=20170121, fracture=False, ) swat.describe() tsetup.assert_almostequal(swat.values[0, 0, 0], 0.60924, 0.001) swat = xtgeo.gridproperty_from_file( DUALFILE1.with_suffix(".UNRST"), grid=grd, name="SWAT", date=20170121, fracture=True, ) swat.describe() tsetup.assert_almostequal(swat.values[0, 0, 0], 0.989687, 0.001) swat.to_file("TMP/swat.roff")
def make_map(): """Make a map of poro or perm in lowermost K layer of the grid""" # read grid grd = xtgeo.grid_from_file(GNAMEROOT + ".EGRID") _ = xtgeo.gridproperty_from_file(GNAMEROOT + ".INIT", name="PORO", grid=grd) df = grd.dataframe() # make a map from the grid geometry to be used as a template surf = xtgeo.RegularSurface() surf.from_grid3d(grd) # get only bottom layer: lastlayer = df["KZ"].max() df = df[df["KZ"] == lastlayer].reset_index() # prepare as input to a Points dataframe (3 columns X Y Z) df = df[["X_UTME", "Y_UTMN", "PORO"]].copy() points = xtgeo.Points() points.zname = "PORO" points.dataframe = df # do gridding: surf.gridding(points) # optional plot surf.quickplot()
def get_property_from_restart(self, name, date, **kwargs): return xtgeo.gridproperty_from_file(self.path + ".UNRST", grid=self.grid, date=date, name=name, **kwargs)
def test_values_samedate(reek_data): """Verify that the same date yields zero change""" ecldiff2roff.ecldiff2roff_main("2_R001_REEK-0", "PRESSURE", [("20000101", "20000101")]) pressure_diff = xtgeo.gridproperty_from_file( "eclgrid--pressure--20000101_20000101.roff") assert np.isclose(pressure_diff.values.mean(), 0.0)
def export_geogrid_parameters(): """Export geogrid assosiated parameters based on user defined lists""" props = PROPS_SEISMIC + PROPS_OTHER print("Write grid properties...") for propname in props: filename = (FOLDER / (GFILE + "_" + propname)).with_suffix(".roff") prop = xtgeo.gridproperty_from_file(filename) ed = dataio.ExportData( name=propname, # parent={"name": GNAME}, config=CFG, content="depth", unit="m", vertical_domain={"depth": "msl"}, timedata=None, is_prediction=True, is_observation=False, verbosity=VERBOSITY, workflow="rms property model", ) out = ed.export(prop) print(f"Stored {propname} as {out}")
def test_convert_grid_format_restart(tmp_path, mocker): """Convert an ECLIPSE SOIL from restart to roff""" outfile = tmp_path / "reek_grid.roff" mocker.patch( "sys.argv", [ "convert_grid_format", "--file", str(RFILE2), "--output", str(outfile), "--mode", "restart", "--propnames", "SOIL", "--dates", "20000701", "--standardfmu", ], ) cgf.main() actual_outfile = tmp_path / "reek_grid--soil--20000701.roff" gprop = xtgeo.gridproperty_from_file(actual_outfile) assert gprop.values.mean() == pytest.approx(0.0857, abs=0.001)
def loop_for_compute( config: dict, sinfo: ScreenInfo, _dryrun: bool = False ) -> EnsembleWellProps: """Collect for computing the ensemble statistics. Args: config: The input configuration dictonary sinfo: Messages to screen instance _dryrun: For testing, skipping computation """ cfg = ConfigData(config) wcase = WellCase( xtgeo.well_from_file(cfg.wellfile, lognames=cfg.lognames), cfg.mdlog, cfg.mdranges, cfg.welldelta, ) grd = None sinfo.oprint("Loop data over realizations...") used_realizations = [] for real in cfg.reals: sinfo.oprint(f"Realization no. {real}") realiterpath = cfg.root / f"realization-{real}" / cfg.itera if not isinstance(grd, xtgeo.Grid) or not cfg.gridreuse: # one may choose to reuse grid if not structural uncertainty sinfo.oprint(f"Read grid geometry for realization {real}") gpath = realiterpath / cfg.gridfilestub try: grd = xtgeo.grid_from_file(gpath) except OSError: sinfo.oprint(f"Not able to read grid {gpath}, skip realization...") continue wcase.well.delete_logs(GCELLNAMES) wcase.well.make_ijk_from_grid(grd) for propcase in cfg.proplist: proppath = realiterpath / propcase.filestub sinfo.oprint(f"Read: {proppath}...") try: theprop = xtgeo.gridproperty_from_file(proppath) except OSError: sinfo.oprint( f"Not able to read property {propcase.name} from {proppath}, " "skip realization..." ) continue theprop.geometry = grd if _dryrun is False: run_compute(real, wcase.well, propcase, theprop) used_realizations.append(real) sinfo.xprint("Delete logs referring to cells...") wcase.well.delete_logs(GCELLNAMES) return EnsembleWellProps(wcase.well, used_realizations, cfg, sinfo)
def test_values_dateorder(reek_data): """Verify the handling of date order in date pairs, that the sign of values gets correct and it negated when dates are reversed""" ecldiff2roff.ecldiff2roff_main("2_R001_REEK-0", "PRESSURE", [("20000101", "20000701")]) pressure_diff1 = xtgeo.gridproperty_from_file( "eclgrid--pressure--20000101_20000701.roff") # This tools works such that a reduction in pressure gives a positive value when # the dates "increase". This test assumes that the Reek dataset declines # in pressure: assert pressure_diff1.values.mean() > 0.0 # Also verify the actual mean value: assert np.isclose(pressure_diff1.values.mean(), 29.6174076) # Check that when the dates are reversed, the difference is negated: ecldiff2roff.ecldiff2roff_main("2_R001_REEK-0", "PRESSURE", [("20000701", "20000101")]) pressure_diff_reverse = xtgeo.gridproperty_from_file( "eclgrid--pressure--20000701_20000101.roff") assert np.isclose(pressure_diff1.values.mean(), -pressure_diff_reverse.values.mean())
def test_create_project(): """Create a tmp RMS project for testing, populate with basic data""" prj1 = PRJ prj2 = PRJ + "_initial" if isdir(prj1): print("Remove existing project! (1)") shutil.rmtree(prj1) if isdir(prj2): print("Remove existing project! (2)") shutil.rmtree(prj2) project = roxar.Project.create() rox = xtgeo.RoxUtils(project) print("Roxar version is", rox.roxversion) print("RMS version is", rox.rmsversion(rox.roxversion)) assert "1." in rox.roxversion # populate with cube data cube = xtgeo.cube_from_file(CUBEDATA1) cube.to_roxar(project, CUBENAME1, domain="depth") # populate with surface data rox.create_horizons_category(SURFCAT1) for num, name in enumerate(SURFNAMES1): srf = xtgeo.surface_from_file(SURFTOPS1[num]) project.horizons.create(name, roxar.HorizonType.interpreted) srf.to_roxar(project, name, SURFCAT1) # populate with grid and props grd = xtgeo.grid_from_file(GRIDDATA1) grd.to_roxar(project, GRIDNAME1) por = xtgeo.gridproperty_from_file(PORODATA1, name=PORONAME1) por.to_roxar(project, GRIDNAME1, PORONAME1) # populate with well data (postponed) # save project (both an initla version and a work version) and exit project.save_as(prj1) project.save_as(prj2) project.close()
def read_gridprops(self, gridprops, gridname=None, reuse=None): """Read 3D grid props, from file or RMS.""" gridname = gridname if self._project is not None else join( self._path, gridname) CMN.print_info("Reading grid properties...") gprops = [] if "gridprops" in reuse: reused_gprops, gridprops = self._reuse_gridprops( gridprops, gridname) gprops = reused_gprops if self._project is None: for gprop in gridprops: if isinstance(gprop, list): pname, pfile = gprop else: pfile = gprop pname = "unknown" gridproppath = join(self._path, pfile) xtg_gprop = xtgeo.gridproperty_from_file(gridproppath, name=pname, grid=self.grid) xtg_gprop.name = pname if pname != "unknown" else pfile gprops.append(xtg_gprop) if isinstance(gprop, list): self._xtgdata["gridprops"][gridname][tuple( gprop)] = xtg_gprop else: self._xtgdata["gridprops"][gridname][gprop] = xtg_gprop else: # read from RMS/ROXAPI for pname in gridprops: xtg_gprop = xtgeo.gridproperty_from_roxar( self._project, gridname, pname) gprops.append(xtg_gprop) self._xtgdata["gridprops"][gridname][pname] = xtg_gprop self._gridprops = xtgeo.GridProperties() self._gridprops.append_props(gprops)
def test_compute_some_props(configdata): """Test the actual compute of one well on one realization.""" cfg = ensemble_well_props.ConfigData(configdata) wcase = ensemble_well_props.WellCase( xtgeo.well_from_file(WELLNAME2, lognames=cfg.lognames), cfg.mdlog, cfg.mdranges) grd = xtgeo.grid_from_file(GFILE1) wcase.well.make_ijk_from_grid(grd) myprops = [FACIESFILE1, POROFILE1] for ncount, pcase in enumerate(myprops): prop = xtgeo.gridproperty_from_file(pcase) prop.geometry = grd ensemble_well_props.run_compute(0, wcase.well, cfg.proplist[ncount], prop) assert "Facies_r0" in wcase.well.dataframe assert wcase.well.dataframe["PHIT_r0"].mean() == pytest.approx(0.171533, abs=0.001)
def test_values_multiple_datepairs(reek_data): """Check that differences for multiple date pairs are handled correctly This was a bug in subscript up to v0.12.0""" # First establish some thruths: ecldiff2roff.ecldiff2roff_main("2_R001_REEK-0", "PRESSURE", [("20000101", "20000701")]) pressure_diff1_singlerun = xtgeo.gridproperty_from_file( "eclgrid--pressure--20000101_20000701.roff") assert np.isclose(pressure_diff1_singlerun.values.mean(), 29.6174076) ecldiff2roff.ecldiff2roff_main("2_R001_REEK-0", "PRESSURE", [("20000701", "20010201")]) pressure_diff2_singlerun = xtgeo.gridproperty_from_file( "eclgrid--pressure--20000701_20010201.roff") assert np.isclose(pressure_diff2_singlerun.values.mean(), 12.570824) ecldiff2roff.ecldiff2roff_main("2_R001_REEK-0", "PRESSURE", [("20000101", "20010201")]) pressure_diff3_singlerun = xtgeo.gridproperty_from_file( "eclgrid--pressure--20000101_20010201.roff") assert np.isclose(pressure_diff3_singlerun.values.mean(), 42.18823213) # Then run with multiple datepairs: ecldiff2roff.ecldiff2roff_main( "2_R001_REEK-0", "PRESSURE", [("20000101", "20000701"), ("20000701", "20010201"), ("20000101", "20010201")], ) pressure_diff1 = xtgeo.gridproperty_from_file( "eclgrid--pressure--20000101_20000701.roff") pressure_diff2 = xtgeo.gridproperty_from_file( "eclgrid--pressure--20000701_20010201.roff") pressure_diff3 = xtgeo.gridproperty_from_file( "eclgrid--pressure--20000101_20010201.roff") assert np.isclose(pressure_diff1.values.mean(), pressure_diff1_singlerun.values.mean()) assert np.isclose(pressure_diff2.values.mean(), pressure_diff2_singlerun.values.mean()) assert np.isclose(pressure_diff3.values.mean(), pressure_diff3_singlerun.values.mean())
def test_import_dualperm_grid(): """Test grid with flag for dual perm setup (hence dual poro also) water/oil""" grd = xtgeo.grid_from_file(DUALFILE2 + ".EGRID") assert grd.dualporo is True assert grd.dualperm is True assert grd.dimensions == (5, 3, 1) grd.to_file(os.path.join(TMPDIR, "dual2.roff")) poro = xtgeo.gridproperty_from_file(DUALFILE2 + ".INIT", grid=grd, name="PORO") print(poro.values) tsetup.assert_almostequal(poro.values[0, 0, 0], 0.1, 0.001) tsetup.assert_almostequal(poro.values[1, 1, 0], 0.16, 0.001) tsetup.assert_almostequal(poro.values[4, 2, 0], 0.24, 0.001) assert poro.name == "POROM" poro.describe() poro = xtgeo.gridproperty_from_file(DUALFILE2 + ".INIT", grid=grd, name="PORO", fracture=True) tsetup.assert_almostequal(poro.values[0, 0, 0], 0.25, 0.001) tsetup.assert_almostequal(poro.values[3, 0, 0], 0.0, 0.001) tsetup.assert_almostequal(poro.values[4, 2, 0], 0.39, 0.001) assert poro.name == "POROF" poro.describe() perm = xtgeo.gridproperty_from_file(DUALFILE2 + ".INIT", grid=grd, name="PERMX") tsetup.assert_almostequal(perm.values[0, 0, 0], 100.0, 0.001) tsetup.assert_almostequal(perm.values[3, 0, 0], 100.0, 0.001) tsetup.assert_almostequal(perm.values[0, 1, 0], 0.0, 0.001) tsetup.assert_almostequal(perm.values[4, 2, 0], 100, 0.001) assert perm.name == "PERMXM" perm.to_file(os.path.join(TMPDIR, "dual2_permxm.roff")) perm = xtgeo.gridproperty_from_file(DUALFILE2 + ".INIT", grid=grd, name="PERMX", fracture=True) tsetup.assert_almostequal(perm.values[0, 0, 0], 100.0, 0.001) tsetup.assert_almostequal(perm.values[3, 0, 0], 0.0, 0.001) tsetup.assert_almostequal(perm.values[0, 1, 0], 100.0, 0.001) tsetup.assert_almostequal(perm.values[4, 2, 0], 100, 0.001) assert perm.name == "PERMXF" perm.to_file(os.path.join(TMPDIR, "dual2_permxf.roff")) swat = xtgeo.gridproperty_from_file(DUALFILE2 + ".UNRST", grid=grd, name="SWAT", date=20170121, fracture=False) tsetup.assert_almostequal(swat.values[3, 0, 0], 0.55475, 0.001) soil = xtgeo.gridproperty_from_file(DUALFILE2 + ".UNRST", grid=grd, name="SOIL", date=20170121, fracture=False) print(soil.values) tsetup.assert_almostequal(soil.values[3, 0, 0], 0.44525, 0.001) tsetup.assert_almostequal(soil.values[0, 1, 0], 0.0, 0.001) assert np.ma.is_masked(soil.values[1, 2, 0]) tsetup.assert_almostequal(soil.values[3, 2, 0], 0.0, 0.001) tsetup.assert_almostequal(soil.values[4, 2, 0], 0.41271, 0.001) swat = xtgeo.gridproperty_from_file(DUALFILE2 + ".UNRST", grid=grd, name="SWAT", date=20170121, fracture=True) swat.describe() assert "SWATF" in swat.name tsetup.assert_almostequal(swat.values[3, 0, 0], 0.0, 0.001) swat.to_file("TMP/swat.roff")
def get_property_from_init(self, name, **kwargs): return xtgeo.gridproperty_from_file(self.path + ".INIT", grid=self.grid, name=name, **kwargs)
def test_import_dualperm_grid_sgas(): """Test grid with flag for dual perm/poro setup gas/water""" grd = xtgeo.grid_from_file(DUALFILE3 + ".EGRID") sgas = xtgeo.gridproperty_from_file(DUALFILE3 + ".UNRST", grid=grd, name="SGAS", date=20170121, fracture=False) sgas.describe() tsetup.assert_almostequal(sgas.values[3, 0, 0], 0.06639, 0.001) tsetup.assert_almostequal(sgas.values[0, 1, 0], 0.0, 0.001) tsetup.assert_almostequal(sgas.values[4, 2, 0], 0.10696, 0.001) assert "SGASM in sgas.name" swat = xtgeo.gridproperty_from_file(DUALFILE3 + ".UNRST", grid=grd, name="SWAT", date=20170121, fracture=False) swat.describe() tsetup.assert_almostequal(swat.values[3, 0, 0], 0.93361, 0.001) tsetup.assert_almostequal(swat.values[0, 1, 0], 0.0, 0.001) tsetup.assert_almostequal(swat.values[4, 2, 0], 0.89304, 0.001) assert "SWATM in swat.name" # shall be not soil actually soil = xtgeo.gridproperty_from_file(DUALFILE3 + ".UNRST", grid=grd, name="SOIL", date=20170121, fracture=False) soil.describe() tsetup.assert_almostequal(soil.values[3, 0, 0], 0.0, 0.001) tsetup.assert_almostequal(soil.values[0, 1, 0], 0.0, 0.001) assert "SOILM" in soil.name # fractures sgas = xtgeo.gridproperty_from_file(DUALFILE3 + ".UNRST", grid=grd, name="SGAS", date=20170121, fracture=True) sgas.describe() tsetup.assert_almostequal(sgas.values[3, 0, 0], 0.0, 0.001) tsetup.assert_almostequal(sgas.values[0, 1, 0], 0.0018198, 0.001) tsetup.assert_almostequal(sgas.values[4, 2, 0], 0.17841, 0.001) assert "SGASF" in sgas.name swat = xtgeo.gridproperty_from_file(DUALFILE3 + ".UNRST", grid=grd, name="SWAT", date=20170121, fracture=True) swat.describe() tsetup.assert_almostequal(swat.values[3, 0, 0], 0.0, 0.001) tsetup.assert_almostequal(swat.values[0, 1, 0], 0.99818, 0.001) tsetup.assert_almostequal(swat.values[4, 2, 0], 0.82159, 0.001) assert "SWATF" in swat.name # shall be not soil actually soil = xtgeo.gridproperty_from_file(DUALFILE3 + ".UNRST", grid=grd, name="SOIL", date=20170121, fracture=True) soil.describe() tsetup.assert_almostequal(soil.values[3, 0, 0], 0.0, 0.001) tsetup.assert_almostequal(soil.values[0, 1, 0], 0.0, 0.001) assert "SOILF" in soil.name
def extract_grid_zone_tops( project: Optional[_roxar.Project] = None, well_list: Optional[list] = None, logrun: str = "log", trajectory: str = "Drilled trajectory", gridzonelog: str = None, mdlogname: str = None, grid: str = None, zone_param: str = None, alias_file: str = None, rms_name: str = "RMS_WELL_NAME", ecl_name: str = "ECLIPSE_WELL_NAME", ) -> pd.DataFrame: """ Function for extracting top and base from gridzones, both in TVD and MD. A pandas dataframe will be returned. Users can either input a pre-generated gridzonelog or a grid and a zone parameter for computing the gridzonelog. The function works both inside RMS and outside with file input. If input from files, and a MD log is not present in the well a quasi md log will be computed and used. """ use_gridzonelog = False if gridzonelog is None else True if not use_gridzonelog: if grid is not None and zone_param is not None: if project is not None: mygrid = xtgeo.grid_from_roxar(project, grid) gridzones = xtgeo.gridproperty_from_roxar(project, grid, zone_param) else: mygrid = xtgeo.grid_from_file(grid) gridzones = xtgeo.gridproperty_from_file(zone_param, grid=mygrid) gridzones.name = "Zone" else: raise ValueError("Specify either 'gridzonelog' or 'grid' and 'zone_param") dfs = [] if well_list is None: well_list = [] for well in well_list: try: if project is not None: xtg_well = xtgeo.well_from_roxar( project, str(well), trajectory=trajectory, logrun=logrun, inclmd=True, ) else: xtg_well = xtgeo.well_from_file(str(well), mdlogname=mdlogname) # quasi md log will be computed xtg_well.geometrics() except (ValueError, KeyError): continue # if no gridzonelog create one from the zone parameter if not use_gridzonelog: xtg_well.get_gridproperties(gridzones, mygrid) gridzonelog = "Zone_model" if xtg_well.dataframe[gridzonelog].isnull().values.all(): continue # Set gridzonelog as zonelog and extract zonation tops from it xtg_well.zonelogname = gridzonelog dframe = xtg_well.get_zonation_points(top_prefix="", use_undef=True) dframe.rename( columns={ "Z_TVDSS": "TOP_TVD", xtg_well.mdlogname: "TOP_MD", "Zone": "ZONE_CODE", "WellName": "WELL", }, inplace=True, ) # find deepest point in well while in grid df_max = ( xtg_well.dataframe[["Z_TVDSS", xtg_well.mdlogname, gridzonelog]] .dropna() .sort_values(by=xtg_well.mdlogname) ) # create base picks also dframe["BASE_TVD"] = dframe["TOP_TVD"].shift(-1) dframe["BASE_MD"] = dframe["TOP_MD"].shift(-1) dframe.at[dframe.index[-1], "BASE_TVD"] = df_max.iloc[-1]["Z_TVDSS"] dframe.at[dframe.index[-1], "BASE_MD"] = df_max.iloc[-1][xtg_well.mdlogname] # adjust zone values to get correct zone information dframe["ZONE_CODE"] = shift_zone_values(dframe["ZONE_CODE"].values.copy()) dframe["ZONE"] = ( dframe["ZONE_CODE"] .map(xtg_well.get_logrecord(xtg_well.zonelogname)) .fillna("Outside") ) dfs.append(dframe.drop(columns=["TopName", "Q_INCL", "Q_AZI"])) df = pd.concat(dfs) if alias_file is not None: well_dict = make_alias_dict(alias_file, rms_name, ecl_name) df["WELL"] = df["WELL"].replace(well_dict) return df
def test_get_cell_volume(): """Test hexahedron (cell) bulk volume valculation""" # box grd = xtgeo.Grid(TESTGRID3) vol1 = grd.get_cell_volume((1, 1, 1)) assert vol1 == pytest.approx(3821600, rel=0.01) # banal6 grd = xtgeo.Grid(TESTGRID2) vol1 = grd.get_cell_volume((1, 1, 1)) vol2 = grd.get_cell_volume((4, 1, 1)) vol3 = grd.get_cell_volume((1, 2, 1)) vol4 = grd.get_cell_volume((3, 1, 2)) assert vol1 == pytest.approx(1679.7, rel=0.01) assert vol2 == pytest.approx(2070.3, rel=0.01) assert vol3 == pytest.approx(1289.1, rel=0.01) assert vol4 == pytest.approx(593.75, rel=0.01) # gridqc1 grd = xtgeo.Grid(TESTGRID) tbulk_rms = xtgeo.gridproperty_from_file(TESTGRID_TBULK) rmean = [] for prec in [1, 2, 4]: ntot = 0 nfail = 0 ratioarr = [] for icol in range(grd.ncol): for jrow in range(grd.nrow): for klay in range(grd.nlay): vol1a = grd.get_cell_volume( (icol, jrow, klay), zerobased=True, precision=prec ) if vol1a is not None: vol1b = tbulk_rms.values[icol, jrow, klay] ratio = vol1a / vol1b ratioarr.append(ratio) ntot += 1 if ratio < 0.98 or ratio > 1.02: nfail += 1 logger.info("%s %s %s: %s", icol, jrow, klay, ratio) logger.info("XTGeo vs RMS %s %s", vol1a, vol1b) if prec > 1: assert vol1a == pytest.approx(vol1b, 0.0001) rarr = np.array(ratioarr) rmean.append(rarr.mean()) logger.info( "Prec: %s, Fails of total %s vs %s, mean/min/max: %s %s %s", prec, nfail, ntot, rarr.mean(), rarr.min(), rarr.max(), ) if prec > 1: assert rarr == pytest.approx(1.0, 0.0001) assert nfail == 0 # ensure that mean difference get closer to 1 with increasing precision? for ravg in rmean: diff = abs(1.0 - ravg) logger.info("Diff from 1: %s", diff)
def load_grid_parameter(grid: Optional[xtgeo.Grid], gridparameterpath: str) -> xtgeo.GridProperty: return xtgeo.gridproperty_from_file(gridparameterpath, grid=grid)
def load_grid_parameter(grid, gridparameterpath): return xtgeo.gridproperty_from_file(gridparameterpath, grid=grid)