Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 32 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ usage: em2ex.py [-h] [-o OUTPUT_FILE] [--filetype {eclipse,leapfrog}]
[--pinch-tol PINCH_TOL] [--refine-xy RX RY]
[--extract-i I_LO I_HI] [--extract-j J_LO J_HI]
[--extract-k K_LO K_HI] [--extra-keywords KEY [KEY ...]]
[--fault-sidesets]
[--fault-sidesets] [--convert-to-m]
filename

Converts earth model to Exodus II format
Expand Down Expand Up @@ -146,6 +146,10 @@ options:
"fault_secondary" containing the faces on either side
of every fault (any internal face where adjacent cells
do not share their corner nodes).
--convert-to-m Convert grid coordinates to metres on output, using
the input file's GRIDUNIT keyword as the source unit.
Supported values are METRES (no-op), FEET and CM.
Files without GRIDUNIT are assumed to be in metres.
```

### Lateral refinement (Eclipse only)
Expand Down Expand Up @@ -226,6 +230,33 @@ Detection is purely topological: any internal face where the two adjacent cells

Without `--fault-sidesets`, the output is unchanged and only the six standard boundary sidesets are written.

### Coordinate units (Eclipse only)

The Eclipse `GRIDUNIT` keyword declares the length unit of the grid. em2ex recognises three values:

| `GRIDUNIT` value | Length unit | Factor to metres |
|---|---|---|
| `METRES` (or absent — the Eclipse default) | metres | 1.0 |
| `FEET` | US survey feet | 0.3048 |
| `CM` | centimetres | 0.01 |

By default, em2ex **preserves the input file's units** — the numbers in `COORD` and `ZCORN` are passed through to the Exodus mesh unchanged. The Exodus format itself has no concept of length units, so it's the modeller's responsibility to remember (or document downstream) what units the mesh is in.

To convert to metres on output, pass `--convert-to-m`:

```bash
./em2ex.py --convert-to-m model.grdecl
```

This multiplies every coordinate (`COORD` x/y/z and `ZCORN` z) by the appropriate factor and prints a one-line confirmation. **Per-cell property values are never converted** — `--convert-to-m` only affects geometry.

A few practical notes:

- **Non-metres files trigger an info note** at the start of the run telling you what unit the file is in and reminding you about `--convert-to-m`. The conversion is opt-in — em2ex never silently rescales your data.
- **Files without `GRIDUNIT`** are treated as metres (Eclipse's documented default). No info note, no conversion needed.
- **Unrecognised `GRIDUNIT` values** print an info note saying conversion is not available; the numbers pass through. Asking for `--convert-to-m` on an unrecognised unit is rejected with a clear error.
- **Property units are entirely the modeller's responsibility.** The `GRIDUNIT` keyword only describes the unit of the grid's coordinates. Per-cell properties like `PERMX`, `HEATCR`, `THCONR`, etc. carry their own unit conventions (Eclipse's `METRIC`, `FIELD`, `LAB`, `PVT-M` unit systems each define their own choices for pressure, flow rate, permeability, density, thermal conductivity, etc.). em2ex does not track those conventions and applies no conversion to property values, even when `--convert-to-m` is rescaling the geometry. If your input file is in `FIELD` units (psi, bbl/day, mD, BTU-based thermal quantities, etc.) and you convert the geometry to metres, the property values stay in `FIELD` units; the resulting mesh is internally inconsistent and will need property conversion downstream before it's physically meaningful.

`em2ex` attempts to guess the reservoir model format from the file extension (see supported formats below). If the reservoir model has a non-standard file extension, the user can force
`em2ex` to read the correct format using the `--filetype` commandline option.

Expand Down
2 changes: 2 additions & 0 deletions em2ex.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ def get_parser():
help = 'Additional per-cell property keywords to read from the grdecl file (e.g. PVTNUM EQLNUM FIPNUM). Each must be a per-cell scalar of length NX*NY*NZ. Normalised to uppercase. The reader recognises ACTNUM, SATNUM, PORO, PERMX, PERMY, PERMZ, NTG, HEATCR and THCONR by default.')
parser.add_argument('--fault-sidesets', dest = 'fault_sidesets', action = 'store_true',
help = 'Emit paired sidesets named "fault_primary" and "fault_secondary" containing the faces on either side of every fault (any internal face where adjacent cells do not share their corner nodes).')
parser.add_argument('--convert-to-m', dest = 'convert_to_m', action = 'store_true',
help = 'Convert grid coordinates to metres on output, using the input file\'s GRIDUNIT keyword as the source unit. Supported values are METRES (no-op), FEET and CM. Files without GRIDUNIT are assumed to be in metres.')
return parser

def main():
Expand Down
38 changes: 38 additions & 0 deletions readers/eclipse.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,14 @@ def processData(line):
'PERMX', 'PERMY', 'PERMZ',
'NTG', 'HEATCR', 'THCONR')

# Recognised length units for the GRIDUNIT keyword and the factor that
# converts them to metres. Files that omit GRIDUNIT default to METRES.
GRIDUNIT_TO_METRES = {
'METRES': 1.0,
'FEET': 0.3048,
'CM': 0.01,
}

def readEclipse(f, eclipse, extra_keywords=()):
''' Read an Eclipse grdecl file and store the data in an Eclipse object.
`extra_keywords` is an iterable of additional uppercase keyword names to
Expand Down Expand Up @@ -253,6 +261,25 @@ def parseEclipse(f, args):
# Notify user that parsing has finished
print("Finished parsing Eclipse file")

# Determine the grid's length unit from GRIDUNIT (default METRES if absent).
# Print an info note for any recognised non-METRES unit so the user is aware,
# plus a hint about --convert-to-m if they want the output in SI.
grid_unit = (eclipse.gridunit[0].upper() if eclipse.gridunit else 'METRES')
needs_conversion = grid_unit != 'METRES'
unit_known = grid_unit in GRIDUNIT_TO_METRES
if needs_conversion and unit_known:
print("Note: input grid uses {} (from GRIDUNIT keyword). Output mesh will be in {}.".format(grid_unit, grid_unit))
print(" Pass --convert-to-m to convert to metres on output.")
elif needs_conversion and not unit_known:
print("Note: input grid declares GRIDUNIT {} which is not recognised.".format(grid_unit))
print(" Conversion to metres is not available; output mesh will use the input values.")

# Validate the user's --convert-to-m request up front (before any work).
do_convert = bool(getattr(args, 'convert_to_m', False)) and needs_conversion
if getattr(args, 'convert_to_m', False) and needs_conversion and not unit_known:
print("--convert-to-m: unrecognised GRIDUNIT value {!r}; cannot convert.".format(grid_unit))
exit()

# Now the data can be reshaped and processed for easy use
# The COORD data has six entries for each of the (nx+1)*(ny+1) nodes
coord = np.asarray(eclipse.coord).reshape(ny+1, nx+1, 6)
Expand All @@ -262,6 +289,17 @@ def parseEclipse(f, args):
# flip_z), all of which leave the (k, j, i) cell indexing unchanged.
zcorn = np.asarray(eclipse.zcorn).reshape(2*nz, 2*ny, 2*nx)

# Apply --convert-to-m if requested: rescale every length-valued array by
# the GRIDUNIT->metres factor. coord stores x/y/z for both pillar
# endpoints (all 6 entries are coordinates); zcorn stores z values only.
# Done here, before extract/refine/flip, so the rest of the pipeline
# operates in metres.
if do_convert:
factor = GRIDUNIT_TO_METRES[grid_unit]
coord = coord * factor
zcorn = zcorn * factor
print("Converted {} -> metres on output (factor {}).".format(grid_unit, factor))

# Apply --extract-i/-j/-k subsetting if requested. Indices are 1-based
# inclusive in file order (matching the cells as they appear in the
# grdecl SPECGRID / properties sections), and the slice happens before
Expand Down
Binary file added test/eclipse/gold/simple_cube_feet_converted.e
Binary file not shown.
99 changes: 99 additions & 0 deletions test/eclipse/simple_cube_feet.grdecl
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
SPECGRID
3 3 3 1 F /

GRIDUNIT
FEET /

COORD
0.000 0.000 0.000 0.000 0.000 1.000
0.500 0.000 0.000 0.500 0.000 1.000
1.000 0.000 0.000 1.000 0.000 1.000
1.500 0.000 0.000 1.500 0.000 1.000
0.000 0.500 0.000 0.000 0.500 1.000
0.500 0.500 0.000 0.500 0.500 1.000
1.000 0.500 0.000 1.000 0.500 1.000
1.500 0.500 0.000 1.500 0.500 1.000
0.000 1.000 0.000 0.000 1.000 1.000
0.500 1.000 0.000 0.500 1.000 1.000
1.000 1.000 0.000 1.000 1.000 1.000
1.500 1.000 0.000 1.500 1.000 1.000
0.000 1.500 0.000 0.000 1.500 1.000
0.500 1.500 0.000 0.500 1.500 1.000
1.000 1.500 0.000 1.000 1.500 1.000
1.500 1.500 0.000 1.500 1.500 1.000
/

ZCORN
0.000 0.000 0.000 0.000 0.000 0.000
0.000 0.000 0.000 0.000 0.000 0.000
0.000 0.000 0.000 0.000 0.000 0.000
0.000 0.000 0.000 0.000 0.000 0.000
0.000 0.000 0.000 0.000 0.000 0.000
0.000 0.000 0.000 0.000 0.000 0.000
0.500 0.500 0.500 0.500 0.500 0.500
0.500 0.500 0.500 0.500 0.500 0.500
0.500 0.500 0.500 0.500 0.500 0.500
0.500 0.500 0.500 0.500 0.500 0.500
0.500 0.500 0.500 0.500 0.500 0.500
0.500 0.500 0.500 0.500 0.500 0.500
0.500 0.500 0.500 0.500 0.500 0.500
0.500 0.500 0.500 0.500 0.500 0.500
0.500 0.500 0.500 0.500 0.500 0.500
0.500 0.500 0.500 0.500 0.500 0.500
0.500 0.500 0.500 0.500 0.500 0.500
0.500 0.500 0.500 0.500 0.500 0.500
1.000 1.000 1.000 1.000 1.000 1.000
1.000 1.000 1.000 1.000 1.000 1.000
1.000 1.000 1.000 1.000 1.000 1.000
1.000 1.000 1.000 1.000 1.000 1.000
1.000 1.000 1.000 1.000 1.000 1.000
1.000 1.000 1.000 1.000 1.000 1.000
1.000 1.000 1.000 1.000 1.000 1.000
1.000 1.000 1.000 1.000 1.000 1.000
1.000 1.000 1.000 1.000 1.000 1.000
1.000 1.000 1.000 1.000 1.000 1.000
1.000 1.000 1.000 1.000 1.000 1.000
1.000 1.000 1.000 1.000 1.000 1.000
1.500 1.500 1.500 1.500 1.500 1.500
1.500 1.500 1.500 1.500 1.500 1.500
1.500 1.500 1.500 1.500 1.500 1.500
1.500 1.500 1.500 1.500 1.500 1.500
1.500 1.500 1.500 1.500 1.500 1.500
1.500 1.500 1.500 1.500 1.500 1.500
/

ACTNUM
1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1
/

PERMX
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
/

PERMY
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
/

PERMZ
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
/

PORO
0.2 0.2 0.4 0.4 0.6 0.6 0.8 0.8 0.5
0.2 0.2 0.4 0.4 0.6 0.6 0.8 0.8 0.5
0.2 0.2 0.4 0.4 0.6 0.6 0.8 0.8 0.5
/

SATNUM
1 1 1 1 1 1 1 1 1
2 2 2 2 2 2 2 2 2
3 3 3 3 3 3 3 3 3
/
15 changes: 15 additions & 0 deletions test/eclipse/tests
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,21 @@ faulted_fault_sidesets:
cli_args: --fault-sidesets
gold: faulted_fault_sidesets.e

# Same numbers as simple_cube.grdecl but with GRIDUNIT FEET. Without
# --convert-to-m, the numbers are passed through unchanged, so the output
# is geometrically identical to simple_cube.e (just nominally in feet).
simple_cube_feet:
filename: simple_cube_feet.grdecl
type: exodiff
gold: simple_cube.e

# Same FEET input, now converted: every coord multiplied by 0.3048.
simple_cube_feet_converted:
filename: simple_cube_feet.grdecl
type: exodiff
cli_args: --convert-to-m
gold: simple_cube_feet_converted.e

missing_specgrid:
filename: missing_specgrid.grdecl
type: exception
Expand Down
Loading