Parsing of simulation cases

Parsing of .DATA files

The most significant feature of this module is a parser for .DATA reservoir simulation cases. The format originated with the Eclipse reservoir simulator produced by SLB and is now used by many reservoir simulators. The most useful publicly available description of one such dialect is found in the OPM Flow manual.

GeoEnergyIO.InputParser.parse_data_fileFunction
parse_data_file(filename; units = :si)
parse_data_file(filename; units = :field)
data = parse_data_file("MY_MODEL.DATA")

Parse a .DATA file given by the path in filename (industry standard input file) into a Dict with String keys. Units will be converted to strict SI unless you pass an alternative unit system like units = :field. Setting units = nothing will skip unit conversion. Note that the simulators in JutulDarcy.jl assumes that the unit system is internally consistent. It is highly recommended to parse to the SI units if you want to perform simulations with JutulDarcy.jl.

The best publicly available documentation on this format is available from the Open Porous Media (OPM) project's webpages: OPM Flow manual .

Keyword arguments

  • warn_parsing=true: Produce a warning when keywords are not supported (or partially supported) by the parser.
  • warn_feature=true: Produce a warning when keywords are supported, but have limited or missing support in the numerical solvers in JutulDarcy.jl.
  • units=:si: Symbol that indicates the unit system to be used in the output. Setting this to nothing will return values without conversion, i.e. exactly what is in the input files. :si will use strict SI. Other alternatives are :field and :metric. :lab is currently unsupported.
  • verbose=false: Produce verbose output about parsing progress. For larger files, a lot of output will be generated. Useful when figuring out where a parser fails or spends a lot of time.

Note

This function only covers a small portion of the keywords that exist for various simulators. You will get warnings that indicate the level of support for keywords in both the parser and the numerical solvers when known keywords with limited support. Pull requests for new keywords are welcome!

The SUMMARY section is skipped due to the large volume of available keywords that are not essential to define simulation cases.

source

Let us for example parse the SPE1 dataset, turning into a nested Dict containing all the entries of the data file. We use the unexported test_input_file_path utility to get the path of a test file.

using GeoEnergyIO
spe1_pth = GeoEnergyIO.test_input_file_path("SPE1", "SPE1.DATA")
spe1 = parse_data_file(spe1_pth)
Dict{String, Any} with 6 entries:
  "RUNSPEC"  => OrderedDict{String, Any}("TITLE"=>"SPE1 - CASE 2", "DIMENS"=>[1…
  "GRID"     => OrderedDict{String, Any}("cartDims"=>(10, 10, 3), "CURRENT_BOX"…
  "PROPS"    => OrderedDict{String, Any}("PVTW"=>Any[[2.77e7, 1.038, 4.67022e-1…
  "SUMMARY"  => OrderedDict{String, Any}()
  "SCHEDULE" => Dict{String, Any}("STEPS"=>OrderedDict{String, Any}[OrderedDict…
  "SOLUTION" => OrderedDict{String, Any}("EQUIL"=>Any[[2560.32, 3.30948e7, 2575…

Handling unsupported keywords

Not all keywords are supported by the parser, but not all keywords are important. The input format is such that it is difficult to automatically skip keywords, but you an manually add keywords to the skip list:

GeoEnergyIO.InputParser.skip_kw!Function
skip_kw!(kw, num, msg = nothing)

Add a keyword to list of records that will be skipped on parsing.

kw is the symbol (usually capitalized) of the keyword to skip, num is the number of expected records:

  • 0 means that the keyword to skip has no data (for example "WATER" with no data to follow)
  • 1 means that the keyword has a single record terminated by /
  • Any other number means a fixed number of lines, without termination by empty record.
  • Inf means that the keyword has any number of records, terminated by a record without entries.
source

Adding keywords to the skip list is not persistent across Julia sessions and can be added to the top of your script. Contributions to the global skip list defined in the __init__ function of the parser are welcome.

using GeoEnergyIO
# Skip keyword without data
GeoEnergyIO.InputParser.skip_kw!(:MY_KW, 0)
# Keyword with a single record of data, e.g.
# MY_DATA_KW
# "some data" 1 2 3 /
GeoEnergyIO.InputParser.skip_kw!(:MY_DATA_KW, 1)
# Keyword with many records, terminated by empty record:
# MY_LONG_DATA_KW
# "some data" 1 2 3 /
# "more data" 4 5 6 /
# "even more data" 1 9 /
# /
GeoEnergyIO.InputParser.skip_kw!(:MY_LONG_DATA_KW, Inf)
70-element Vector{Tuple{Symbol, Union{Float64, Int64}, Union{Nothing, GeoEnergyIO.InputParser.PARSER_WARNING}}}:
 (:PETOPTS, 1, nothing)
 (:PARALLEL, 1, nothing)
 (:MULTSAVE, 1, nothing)
 (:VECTABLE, 1, nothing)
 (:MULTSAVE, 1, nothing)
 (:WHISTCTL, 1, GeoEnergyIO.InputParser.PARSER_JUTULDARCY_MISSING_SUPPORT)
 (:MEMORY, 1, nothing)
 (:OPTIONS3, 1, nothing)
 (:TSCRIT, 1, GeoEnergyIO.InputParser.PARSER_JUTULDARCY_MISSING_SUPPORT)
 (:CVCRIT, 1, GeoEnergyIO.InputParser.PARSER_JUTULDARCY_MISSING_SUPPORT)
 ⋮
 (:VFPPROD, Inf, GeoEnergyIO.InputParser.PARSER_MISSING_SUPPORT)
 (:VFPINJ, Inf, GeoEnergyIO.InputParser.PARSER_MISSING_SUPPORT)
 (:WTRACER, Inf, GeoEnergyIO.InputParser.PARSER_MISSING_SUPPORT)
 (:GCONINJE, Inf, GeoEnergyIO.InputParser.PARSER_MISSING_SUPPORT)
 (:WTEST, Inf, GeoEnergyIO.InputParser.PARSER_MISSING_SUPPORT)
 (:WLIST, Inf, GeoEnergyIO.InputParser.PARSER_MISSING_SUPPORT)
 (:MY_KW, 0, nothing)
 (:MY_DATA_KW, 1, nothing)
 (:MY_LONG_DATA_KW, Inf, nothing)

Parsing of .afi files and RESQML

The package includes experimental support for reading the .afi file format used by IX, as well as RESQML files for the dense data. Files that make use of .gsg files for input is not yet supported, but will parse the remainder of the .afi/ixf files.

GeoEnergyIO.IXParser.read_afi_fileFunction
read_afi_file("somefile.afi")
read_afi_file(fpath; verbose = true, convert = false, strict = false)

Read .afi files. The .afi file is the main file of the IX input format and contains references to other files, such as .ixf and .epc files.

Arguments

  • fpath::String: Path to the .afi file.
  • verbose::Bool=true: Whether to print progress messages.
  • convert::Bool=false: Whether to convert the parsed records to more user-friendly with unit conversion applied. The output format is substantially altered by enabling this option.
  • strict::Bool=false: Whether to throw errors on unrecognized keywords or unsupported files.

Notes

For input of dense data (e.g. grid properties), the parser is limited to the RESQML format. This means that .gsg files are not supported.

source

This function is currently unexported and subject to change. To import:

import GeoEnergyIO.IXParser: read_afi_file
afi = read_afi_file("path/to/file.afi")

Example

As an example, we can parse and convert the a OLYMPUS realization from the test suite, process it as a corner-point mesh, and plot the porosity.

using Jutul, GeoEnergyIO, GLMakie
import GeoEnergyIO.IXParser: read_afi_file
fn = GeoEnergyIO.test_input_file_path("OLYMPUS_25_AFI_RESQML", "OLYMPUS_25.afi")
# Set the convert flag to convert data into "processed" format with converted units and keywords that can more easily be fed to other functions:
setup = read_afi_file(fn, convert = true)
Dict{String, Any} with 2 entries:
  "FM" => Dict{String, Any}("MODEL_DEFINITION"=>Any[(keyword = "Units", value =…
  "IX" => Dict{String, Any}("MODEL_DEFINITION"=>Any[(keyword = "StructuredInfo"…
grid_sec = setup["IX"]["RESQML"]["GRID"]
g = mesh_from_grid_section(grid_sec)
poro = vec(setup["IX"]["RESQML"]["POROSITY"]["values"])
actnum = vec(grid_sec["ACTNUM"])
fig, ax, plt = plot_cell_data(g, poro[actnum])
fig
Example block output

Other parsers

OBSH

There is an experimental parser for the observed well data format. This is unexported and subject to change:

GeoEnergyIO.IXParser.read_obsh_fileFunction
obs_data = read_obs_file(pth)
obs_data = read_obs_file(pth, reformat = true)

Read an OBSH file from path pth. If reformat is true, the data is reformatted into a dictionary of wells, each containing a dictionary of data series and a vector of DateTime objects.

source

To make use of it, it must be explicitly imported:

import GeoEnergyIO.IXParser: read_obsh_file
obsh = read_obsh_file("path/to/FILE.OBSH")