16 KiB
ORIONEVENTS File Format — Version 2.0
Overview
ORIONEVENTS is a compact, human-authored text format describing dated well events (completions and Eclipse schedule keywords) over time. ResInsight reads it through the pure-Python parser in GrpcInterface/Python/rips/orion_events.py and applies the events to a project via the WellEventTimeline API, from which Eclipse schedule text (COMPDAT, WELSEGS, WCONHIST, ...) can be generated.
The implementation has two independent layers:
| Layer | Entry points | Needs ResInsight? |
|---|---|---|
| A — parser | rips.orion_events.parse_orion_events(text) / parse_orion_events_file(path) |
No |
| B — applier | rips.orion_events.apply_orion_document(document, timeline, project) / apply_orion_events_file(path, timeline, project) |
Yes |
A standalone validator runs Layer A only:
python3 -m rips.orion_events myfile.orion
Runnable examples: rips/PythonExamples/experimental/import_orion_events.py (reads the shipped sample rips/example_input_files/well_events.orion) and well_event_schedule_orion.py (full event coverage, generates schedule text).
Quick example
ORIONEVENTS 2.0
UNIT METRIC
# Typed declarations
DATE STARTUP = 2024-01-01
DATE PHASE2 = 2024-03-01 + 9
DURATION RAMP = 31 DAYS
FILTER POROPERM = "PORO > 0.4 AND PERMX > 100.0"
WELL A1 = "55_33-A-1" # alias declaration (has '=')
WELL A1 # opens an event block via the alias
@STARTUP SEGMENT MDSTART=0 MDEND=2500 INNER_DIAMETER=0.15 ROUGHNESS=1.0e-5 PRESSURE_COMPONENTS=HFA
@STARTUP + RAMP PERFORATION MDSTART=2000 MDEND=2200 RADIUS=0.05 SKIN=0.5 COMPLETION_NUMBER=1 FILTER=POROPERM
@2024-05-15T14:45:30.500 PERFORATION MDSTART=2300 MDEND=2350 RADIUS=0.05
@2024-03-01 VALVE MD=2100 TYPE=ICV STATE=OPEN CV=0.7 AREA=0.0001
@STARTUP + RAMP WCONHIST STATUS=OPEN CMODE=ORAT VFP=1
@2024-05-01 WELTARG CMODE=ORAT VALUE=5000.0
@2024-06-01 WRFTPLT OUTPUT_RFT=YES OUTPUT_PLT=NO OUTPUT_SEGMENT=NO
WELL "55_33-A-2" # quoted form: literal well name
@PHASE2 - 1 PERFORATION MDSTART=1692.79 MDEND=1706 RADIUS=0.12065 SKIN=5
SCHEDULE # schedule-level keywords, not tied to a well
@STARTUP RPTRST BASIC=2 FREQ=1
@STARTUP GRUPTREE CHILD=OP PARENT=FIELD
@STARTUP TUNING TSINIT=1 TSMAXZ=30 NEWTMX=12
Grammar (EBNF-ish)
document = header , { statement } ;
header = "ORIONEVENTS" , "2.0" ; (* first meaningful line *)
statement = unit_directive | declaration | report_line | well_block_open
| group_block_open | schedule_block_open | event_line ;
unit_directive = "UNIT" , ( "METRIC" | "FIELD" | "LAB" ) ;
report_line = "REPORT" , date_expr ;
declaration = date_decl | duration_decl | well_decl | filter_decl ;
date_decl = "DATE" , ident , "=" , date_expr ; (* DATE X = 2018-03-01 + 9 *)
duration_decl = "DURATION" , ident , "=" , duration_expr ; (* DURATION RAMP = 5 DAYS *)
well_decl = "WELL" , ident , "=" , quoted_string ; (* WELL A1 = "55_33-A-1" *)
filter_decl = "FILTER" , ident , "=" , '"' , filter_expr , '"' ;
(* FILTER F = "PORO > 0.4 AND PERMX > 100.0" *)
filter_expr = filter_term , { ( "AND" | "OR" ) , filter_term } ;
(* one combine mode; mixing AND and OR is an error *)
filter_term = [ result_type , "." ] , ident , comp_op , number ;
comp_op = ">" | ">=" | "<" | "<=" ;
well_block_open = "WELL" , ( quoted_string | ident ) ; (* no "=" present *)
group_block_open = "GROUP" , quoted_string ; (* group keyword events *)
schedule_block_open = "SCHEDULE" ; (* well-less keyword events *)
event_line = "@" , date_expr , event_type , { attribute } ;
event_type = completion_event_type | eclipse_keyword ;
completion_event_type = "PERFORATION" | "SEGMENT" | "VALVE" | "STATE" | "WELSPECS" ;
segment_attribute = "MDSTART" | "MDEND" | "INNER_DIAMETER" | "ROUGHNESS"
| "PRESSURE_COMPONENTS" | "COMMENT" ;
(* accepted attribute names when event_type is "SEGMENT" *)
date_expr = ( iso_date | iso_datetime | date_ident ) , { sign , term } ;
duration_expr = ( integer | dur_ident ) , { sign , term } , [ "DAYS" | "days" ] ;
term = integer | dur_ident ; (* whole days *)
sign = "+" | "-" ;
iso_date = 4digit , "-" , 2digit , "-" , 2digit ;
iso_datetime = iso_date , "T" , 2digit , ":" , 2digit , ":" , 2digit ,
[ "." , digits ] ; (* 2024-05-15T14:45:30.500 *)
ident = letter_or_underscore , { word_char } ;
attribute = ident , "=" , ( quoted_string | bareword ) ;
comment = "#" , rest-of-line ; (* line or trailing *)
Line types
The format is line-oriented. Every non-blank line is dispatched on its first token; anything else is an error. Keywords are uppercase and case-sensitive (the DAYS suffix is also accepted as days).
| First token | Meaning |
|---|---|
ORIONEVENTS |
Header with version; must be the first meaningful line, exactly once |
UNIT |
Unit system: METRIC, FIELD or LAB (default METRIC) |
DATE |
Declare a typed date variable |
DURATION |
Declare a typed whole-day duration variable |
FILTER |
Declare a typed cell-filter expression |
REPORT |
Add a date that must appear in generated schedule output |
WELL |
With =: declare a well-name alias. Without =: open a well event block |
GROUP |
Open a block of group-level keyword events |
SCHEDULE |
Open a block of schedule-level keyword events (bare keyword, no arguments) |
@ |
An event line, appended to the enclosing WELL, GROUP or SCHEDULE block |
# |
Comment (also allowed trailing on any line, outside double quotes) |
Typed declarations
Variables are typed — DATE, DURATION (whole days), WELL (well-name alias) and FILTER (cell filter expression) — and share one namespace. They must be declared before use (single-pass, no forward references).
DATE STARTUP = 2024-01-01
DURATION RAMP = 31 DAYS # DAYS suffix optional
DATE PHASE2 = STARTUP + RAMP # date arithmetic with variables
WELL A1 = "55_33-A-1"
FILTER POROPERM = "PORO > 0.4 AND PERMX > 100.0"
Using a variable of the wrong type is an error citing both the use and the declaration site:
Line 18: Variable 'RAMP' is a DURATION (declared line 10) but a DATE is required here
Redeclaring a name with the same type warns and the last value wins; redeclaring with a different type is an error.
Date expressions
A date expression is an ISO date, an ISO datetime, or a DATE variable, followed by a chain of signed whole-day terms. Each term is a non-negative integer or a DURATION variable:
@2024-01-01
@STARTUP + 5
@STARTUP + RAMP - 2
@2024-05-15T14:45:30.500 # time-of-day, millisecond precision
Whitespace around +/- is optional but conventional. A time-of-day is preserved through the applier and emitted as the optional TIME field of the generated DATES keyword.
WELL blocks
WELL <ident> opens an event block for a declared WELL alias; WELL "<name>" opens a block for the literal well name and never consults variables — so there is no shadowing ambiguity. Well names containing special characters must use the quoted form. Empty blocks are legal. When applied, the well name must match a well path in the project (see the on_unknown_well policy below).
Event types
Event lines are @<date_expr> <EVENT_TYPE> KEY=VALUE .... Inside a WELL block, the event type is either one of the five built-in completion events or any Eclipse well keyword.
Built-in completion events
PERFORATION → add_perf_event (state is always OPEN)
| Attribute | Required | Maps to |
|---|---|---|
MDSTART |
yes | start_md |
MDEND |
yes | end_md |
RADIUS |
no | diameter = 2 × radius |
SKIN |
no | skin_factor |
COMPLETION_NUMBER |
no | completion_number (COMPLUMP grouping) |
FILTER |
no | case-level combined data filter attached to the perforation: a declared FILTER variable (FILTER=POROPERM) or an inline quoted expression (FILTER="PORO > 0.4") — see Filter expressions |
SEGMENT → add_tubing_event and add_custom_segment_interval
Each event adds the underlying tubing timeline event and a corresponding Custom Segment Interval with the same measured-depth range.
| Attribute | Required | Maps to |
|---|---|---|
MDSTART |
yes | tubing start_md and custom interval start_md |
MDEND |
yes | tubing end_md and custom interval end_md |
INNER_DIAMETER |
no | tubing inner_diameter [m] |
ROUGHNESS |
no | tubing roughness [m] |
PRESSURE_COMPONENTS |
no | MSW pressure_drop: H--, HF- or HFA |
VALVE → add_valve_event (requires an existing perforation at the MD)
| Attribute | Required | Maps to |
|---|---|---|
MD |
yes | measured_depth |
TYPE |
yes | valve_type: ICV, ICD or AICD |
STATE |
no | state: OPEN or SHUT |
CV |
no | flow_coefficient |
AREA |
no | area [m²] |
AICD_STRENGTH, AICD_DENSITY_CALIB_FLUID, AICD_VISCOSITY_CALIB_FLUID, AICD_VOL_FLOW_EXP, AICD_VISC_FUNC_EXP |
no | the corresponding AICD parameters |
STATE → add_state_event
| Attribute | Required | Maps to |
|---|---|---|
STATE |
yes | well_state: OPEN, SHUT or STOP |
Unknown attributes on a completion event are an error and skip the event. On completion events other than PERFORATION, FILTER is ignored with a warning.
Well keyword events
Any other event type in a WELL block is passed through as an Eclipse well keyword via add_well_keyword_event, with the well name injected as the WELL item and all attributes forwarded (type-inferred as int, float or string). Two keywords have convenience attribute translations:
| Event type | Translation |
|---|---|
WCONHIST |
VFP → VFP_TABLE |
WELTARG |
VALUE → NEW_VALUE |
All other keywords (WRFTPLT, WCONPROD, WELOPEN, ...) forward attributes unchanged, so attribute keys must match the Eclipse item names ResInsight uses for that keyword. FILTER is ignored with a warning.
An event type that closely resembles a misspelled built-in (e.g. PERFORATIN) is not passed through as a keyword; it is handled by the on_unknown_event policy with a "did you mean" hint.
SCHEDULE blocks
A bare SCHEDULE line opens a block of schedule-level keyword events applied through add_keyword_event — no well association, no WELL item injected:
SCHEDULE
@STARTUP RPTRST BASIC=2 FREQ=1
@STARTUP GRUPTREE CHILD=OP PARENT=FIELD
@STARTUP TUNING TSINIT=1 TSMAXZ=30 NEWTMX=12
Completion event types (PERFORATION, SEGMENT, VALVE, STATE, WELSPECS) are rejected in a SCHEDULE block. A later WELL line switches back to well events; blocks can be interleaved freely.
Attributes and quoting
Every attribute is KEY=VALUE; bare positional tokens are rejected. Values are type-inferred (int, then float, otherwise string). Double quotes are used everywhere — well names, filter expressions and attribute values — and allow spaces and operators inside a value:
FILTER="SOIL > 0.8 AND PERMX > 200"
Filter expressions
A filter expression — the quoted value of a FILTER declaration or of an inline FILTER="..." attribute — is a list of comparison terms joined by AND or OR (uppercase, one mode per expression; mixing them is an error, since a combined filter has a single combine mode):
FILTER POROPERM = "PORO > 0.4 AND PERMX > 100.0"
FILTER LOWSAT = "dynamic.SOIL < 0.2 OR PRESSURE < 150"
Each term is [TYPE.]NAME <op> NUMBER:
- Operators are
>,>=,<and<=. A term sets only one bound of the generated property filter; the other bound keeps the result's minimum/maximum. Bounds are inclusive, so>behaves as>=(and<as<=). - The result name is case-insensitive (uppercased on parse). An unqualified name is searched in the case's
STATIC_NATIVE, thenDYNAMIC_NATIVE, thenGENERATEDresults; the first type containing it wins. - A
TYPE.qualifier restricts the search to one result type:STATIC/STATIC_NATIVE,DYNAMIC/DYNAMIC_NATIVEorGENERATED, case-insensitive (DYNAMIC_NATIVE.MY_PROPERTYanddynamic.my_propertyare equivalent). - A result that does not exist in the case raises an error. All filter terms are checked up front, before any event is applied.
When applied, each used filter becomes a case-level combined data filter (under the case's Data Filters) holding one property filter per term. A declared filter is created once, named after its declaration, and shared between every perforation that references it; an inline filter gets an auto-derived name from its content (identical inline expressions share one filter). The filter is attached to the perforation event and carried onto the perforation interval when completions are materialized with set_timestamp. Declared-but-unreferenced filters create nothing.
Diagnostics
The parser recovers per line and reports all errors in one pass. The raised OrionParseError carries one ParseIssue (message + source line) per problem, and unknown names get difflib-based "did you mean" suggestions:
Line 3: SET is ORIONEVENTS 1.x syntax; declare a typed variable instead, e.g. DATE NAME = 2018-01-01
Line 5: Malformed WELL line: 'WELL 55_33-A-2' (well names containing special characters must be double-quoted, e.g. WELL "55_33-A-1")
Line 6: Unknown variable 'A1_STRTUP'; did you mean 'A1_STARTUP'?
Line 7: Variable 'RAMP' is a DURATION (declared line 3) but a DATE is required here
The validator CLI prints these and exits non-zero:
$ python3 -m rips.orion_events well_events.orion
well_events.orion: OK (ORIONEVENTS 2.0, units METRIC)
4 variable(s), 2 well block(s), 8 well event(s), 0 schedule event(s)
Applying to a project
import rips
resinsight = rips.Instance.find()
project = resinsight.project
well_path_coll = project.descendants(rips.WellPathCollection)[0]
timeline = well_path_coll.event_timeline()
report = rips.orion_events.apply_orion_events_file(
"well_events.orion", timeline, project, case=case, on_unknown_well="warn"
)
print(report.events_applied, report.events_skipped, report.warnings, report.errors)
timeline.set_timestamp(timestamp="2024-12-24") # materialize completions up to a date
schedule_text = timeline.generate_schedule_text(
eclipse_case=case, export_msw_for_wells=[well_path]
)
apply_orion_document / apply_orion_events_file accept an optional case — the rips.Case used to resolve filter result names and to own the created combined filters. It is only needed when the document uses FILTER and defaults to the project's first case; a RipsError is raised if a filter is used and no case is available, or if a filter references a result missing from the case (checked before any event is applied).
They also accept two policies, each "warn" (default), "error" or "skip":
| Policy | Governs |
|---|---|
on_unknown_well |
A well name with no matching well path in the project |
on_unknown_event |
An event type that looks like a misspelled built-in |
The returned ApplyReport carries events_applied, events_skipped, warnings and errors.
Version history
- 2.0 — current: typed
DATE/DURATION/WELL/FILTERdeclarations,WELL/SCHEDULEblocks, signed day-offset chains, ISO datetimes, built-in completion events (includingSEGMENTcustom intervals and pressure components) plus generic keyword pass-through, perforation data filters, multi-error diagnostics, validator CLI. - 1.x — unsupported. Files using
SETvariables and single-quoted well names are rejected with a migration message pointing at this grammar.