Skip to content
Draft
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
4 changes: 2 additions & 2 deletions flopy4/mf6/codec/reader/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from pathlib import Path
from typing import Any

from flopy4.mf6.codec.reader.parser import make_basic_parser
from flopy4.mf6.codec.reader.parser import get_basic_parser
from flopy4.mf6.codec.reader.transformer import BasicTransformer


Expand Down Expand Up @@ -41,6 +41,6 @@ def loads(data: str) -> Any:
Parsed MF6 input file structure
"""

parser = make_basic_parser()
parser = get_basic_parser()
transformer = BasicTransformer()
return transformer.transform(parser.parse(data))
39 changes: 39 additions & 0 deletions flopy4/mf6/codec/reader/dfn2lark.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
"""Convert (TOML/v2) DFNs to Lark grammars."""

import argparse
from os import PathLike
from pathlib import Path

from modflow_devtools.dfn import Dfn

from flopy4.mf6.codec.reader.grammar import make_all_grammars

_GRAMMAR_MODULE = Path(__file__).parent / "grammar"
_GRAMMAR_GEN_DIR = _GRAMMAR_MODULE / "generated"


def generate(dfndir: PathLike, outdir: PathLike):
"""Generate lark grammars from DFNs."""
dfndir = Path(dfndir).expanduser().absolute()
outdir = Path(outdir).expanduser().absolute()
outdir.mkdir(exist_ok=True, parents=True)
dfns = Dfn.load_all(dfndir, version=2)
make_all_grammars(dfns, outdir)


if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Generate lark grammars from DFNs.")
parser.add_argument(
"--dfndir",
"-d",
type=str,
help="Directory containing DFN files.",
)
parser.add_argument(
"--outdir",
"-o",
help="Output directory.",
default=_GRAMMAR_GEN_DIR,
)
args = parser.parse_args()
generate(args.dfndir, args.outdir)
46 changes: 46 additions & 0 deletions flopy4/mf6/codec/reader/grammar/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
from os import PathLike
from pathlib import Path

import jinja2
from modflow_devtools.dfn import Dfn, get_blocks, get_fields

from flopy4.mf6.codec.reader.grammar.filters import (
field_type,
keystring_children,
record_child_type,
)


def _get_template_env():
loader = jinja2.PackageLoader("flopy4", "mf6/codec/reader/grammar/templates/")
env = jinja2.Environment(
loader=loader,
trim_blocks=True,
lstrip_blocks=True,
keep_trailing_newline=True,
)
env.filters["field_type"] = field_type
env.filters["record_child_type"] = record_child_type
env.filters["keystring_children"] = keystring_children
return env


def make_grammar(dfn: Dfn, outdir: PathLike):
"""Generate a Lark grammar file for a single component."""
outdir = Path(outdir).expanduser().resolve().absolute()
env = _get_template_env()
template = env.get_template("component.lark.jinja")
target_path = outdir / f"{dfn['name']}.lark"
with open(target_path, "w") as f:
name = dfn["name"]
blocks = get_blocks(dfn)
fields = get_fields(dfn)
f.write(template.render(name=name, blocks=blocks, fields=fields))


def make_all_grammars(dfns: dict[str, Dfn], outdir: PathLike):
"""Generate grammars for all components."""
outdir = Path(outdir).expanduser().resolve().absolute()
outdir.mkdir(parents=True, exist_ok=True)
for dfn in dfns.values():
make_grammar(dfn, outdir)
39 changes: 39 additions & 0 deletions flopy4/mf6/codec/reader/grammar/filters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
from modflow_devtools.dfn import Field


def field_type(field: Field) -> str:
match field["type"]:
case t if t in ["string", "integer", "double precision"] and "shape" in field:
if "period" in field["block"]:
return "list"
return "array"
case "keyword":
return ""
case "keystring":
return "" # keystrings generate their own union rules
case _:
return field["type"]


def record_child_type(field: Field) -> str:
"""Get the grammar type for a field within a record context."""
match field["type"]:
case "string":
return "string"
case "integer":
return "integer"
case "double precision":
return "double"
case "keyword":
return ""
case "keystring":
return "" # keystrings generate their own union rules
case _:
return field["type"]


def keystring_children(field: Field) -> dict:
"""Get the children of a keystring field for union generation."""
if field["type"] != "keystring":
return {}
return field.get("children", {})
22 changes: 22 additions & 0 deletions flopy4/mf6/codec/reader/grammar/generated/chf-cdb.lark
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Auto-generated grammar for MF6 CHF-CDB
%import "typed.lark"

start: block*
block: options_block | dimensions_block | period_block
options_block: "begin"i "options"i options_fields "end"i "options"i
dimensions_block: "begin"i "dimensions"i dimensions_fields "end"i "dimensions"i
period_block: "begin"i "period"i period_fields "end"i "period"i
options_fields: (auxiliary | boundnames | print_input | print_flows | save_flows | obs_filerecord)*
dimensions_fields: (maxbound)*
period_fields: (idcxs | width | aux | boundname)*
auxiliary: "auxiliary"i array
boundnames: "boundnames"i
print_input: "print_input"i
print_flows: "print_flows"i
save_flows: "save_flows"i
obs_filerecord: "obs6"i "filein"i string
maxbound: "maxbound"i integer
idcxs: "idcxs"i list
width: "width"i list
aux: "aux"i list
boundname: "boundname"i list
23 changes: 23 additions & 0 deletions flopy4/mf6/codec/reader/grammar/generated/chf-chd.lark
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Auto-generated grammar for MF6 CHF-CHD
%import "typed.lark"

start: block*
block: options_block | dimensions_block | period_block
options_block: "begin"i "options"i options_fields "end"i "options"i
dimensions_block: "begin"i "dimensions"i dimensions_fields "end"i "dimensions"i
period_block: "begin"i "period"i period_fields "end"i "period"i
options_fields: (auxiliary | auxmultname | boundnames | print_input | print_flows | save_flows | ts_filerecord | obs_filerecord)*
dimensions_fields: (maxbound)*
period_fields: (head | aux | boundname)*
auxiliary: "auxiliary"i array
auxmultname: "auxmultname"i string
boundnames: "boundnames"i
print_input: "print_input"i
print_flows: "print_flows"i
save_flows: "save_flows"i
ts_filerecord: "ts6"i "filein"i string
obs_filerecord: "obs6"i "filein"i string
maxbound: "maxbound"i integer
head: "head"i list
aux: "aux"i list
boundname: "boundname"i list
18 changes: 18 additions & 0 deletions flopy4/mf6/codec/reader/grammar/generated/chf-cxs.lark
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Auto-generated grammar for MF6 CHF-CXS
%import "typed.lark"

start: block*
block: options_block | dimensions_block | packagedata_block | crosssectiondata_block
options_block: "begin"i "options"i options_fields "end"i "options"i
dimensions_block: "begin"i "dimensions"i dimensions_fields "end"i "dimensions"i
packagedata_block: "begin"i "packagedata"i packagedata_fields "end"i "packagedata"i
crosssectiondata_block: "begin"i "crosssectiondata"i crosssectiondata_fields "end"i "crosssectiondata"i
options_fields: (print_input)*
dimensions_fields: (nsections | npoints)*
packagedata_fields: (packagedata)*
crosssectiondata_fields: (crosssectiondata)*
print_input: "print_input"i
nsections: "nsections"i integer
npoints: "npoints"i integer
packagedata: "packagedata"i recarray
crosssectiondata: "crosssectiondata"i recarray
20 changes: 20 additions & 0 deletions flopy4/mf6/codec/reader/grammar/generated/chf-dfw.lark
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Auto-generated grammar for MF6 CHF-DFW
%import "typed.lark"

start: block*
block: options_block | griddata_block
options_block: "begin"i "options"i options_fields "end"i "options"i
griddata_block: "begin"i "griddata"i griddata_fields "end"i "griddata"i
options_fields: (central_in_space | length_conversion | time_conversion | save_flows | print_flows | save_velocity | obs_filerecord | export_array_ascii | dev_swr_conductance)*
griddata_fields: (manningsn | idcxs)*
central_in_space: "central_in_space"i
length_conversion: "length_conversion"i double precision
time_conversion: "time_conversion"i double precision
save_flows: "save_flows"i
print_flows: "print_flows"i
save_velocity: "save_velocity"i
obs_filerecord: "obs6"i "filein"i string
export_array_ascii: "export_array_ascii"i
dev_swr_conductance: "dev_swr_conductance"i
manningsn: "manningsn"i array
idcxs: "idcxs"i array
30 changes: 30 additions & 0 deletions flopy4/mf6/codec/reader/grammar/generated/chf-disv1d.lark
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Auto-generated grammar for MF6 CHF-DISV1D
%import "typed.lark"

start: block*
block: options_block | dimensions_block | griddata_block | vertices_block | cell1d_block
options_block: "begin"i "options"i options_fields "end"i "options"i
dimensions_block: "begin"i "dimensions"i dimensions_fields "end"i "dimensions"i
griddata_block: "begin"i "griddata"i griddata_fields "end"i "griddata"i
vertices_block: "begin"i "vertices"i vertices_fields "end"i "vertices"i
cell1d_block: "begin"i "cell1d"i cell1d_fields "end"i "cell1d"i
options_fields: (length_units | nogrb | grb_filerecord | xorigin | yorigin | angrot | export_array_ascii | crs)*
dimensions_fields: (nodes | nvert)*
griddata_fields: (width | bottom | idomain)*
vertices_fields: (vertices)*
cell1d_fields: (cell1d)*
length_units: "length_units"i string
nogrb: "nogrb"i
grb_filerecord: "grb6"i "fileout"i string
xorigin: "xorigin"i double precision
yorigin: "yorigin"i double precision
angrot: "angrot"i double precision
export_array_ascii: "export_array_ascii"i
crs: "crs"i array
nodes: "nodes"i integer
nvert: "nvert"i integer
width: "width"i array
bottom: "bottom"i array
idomain: "idomain"i array
vertices: "vertices"i recarray
cell1d: "cell1d"i recarray
23 changes: 23 additions & 0 deletions flopy4/mf6/codec/reader/grammar/generated/chf-evp.lark
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Auto-generated grammar for MF6 CHF-EVP
%import "typed.lark"

start: block*
block: options_block | dimensions_block | period_block
options_block: "begin"i "options"i options_fields "end"i "options"i
dimensions_block: "begin"i "dimensions"i dimensions_fields "end"i "dimensions"i
period_block: "begin"i "period"i period_fields "end"i "period"i
options_fields: (auxiliary | auxmultname | boundnames | print_input | print_flows | save_flows | ts_filerecord | obs_filerecord)*
dimensions_fields: (maxbound)*
period_fields: (evaporation | aux | boundname)*
auxiliary: "auxiliary"i array
auxmultname: "auxmultname"i string
boundnames: "boundnames"i
print_input: "print_input"i
print_flows: "print_flows"i
save_flows: "save_flows"i
ts_filerecord: "ts6"i "filein"i string
obs_filerecord: "obs6"i "filein"i string
maxbound: "maxbound"i integer
evaporation: "evaporation"i list
aux: "aux"i list
boundname: "boundname"i list
23 changes: 23 additions & 0 deletions flopy4/mf6/codec/reader/grammar/generated/chf-flw.lark
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Auto-generated grammar for MF6 CHF-FLW
%import "typed.lark"

start: block*
block: options_block | dimensions_block | period_block
options_block: "begin"i "options"i options_fields "end"i "options"i
dimensions_block: "begin"i "dimensions"i dimensions_fields "end"i "dimensions"i
period_block: "begin"i "period"i period_fields "end"i "period"i
options_fields: (auxiliary | auxmultname | boundnames | print_input | print_flows | save_flows | ts_filerecord | obs_filerecord)*
dimensions_fields: (maxbound)*
period_fields: (q | aux | boundname)*
auxiliary: "auxiliary"i array
auxmultname: "auxmultname"i string
boundnames: "boundnames"i
print_input: "print_input"i
print_flows: "print_flows"i
save_flows: "save_flows"i
ts_filerecord: "ts6"i "filein"i string
obs_filerecord: "obs6"i "filein"i string
maxbound: "maxbound"i integer
q: "q"i list
aux: "aux"i list
boundname: "boundname"i list
11 changes: 11 additions & 0 deletions flopy4/mf6/codec/reader/grammar/generated/chf-ic.lark
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Auto-generated grammar for MF6 CHF-IC
%import "typed.lark"

start: block*
block: options_block | griddata_block
options_block: "begin"i "options"i options_fields "end"i "options"i
griddata_block: "begin"i "griddata"i griddata_fields "end"i "griddata"i
options_fields: (export_array_ascii)*
griddata_fields: (strt)*
export_array_ascii: "export_array_ascii"i
strt: "strt"i array
15 changes: 15 additions & 0 deletions flopy4/mf6/codec/reader/grammar/generated/chf-nam.lark
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Auto-generated grammar for MF6 CHF-NAM
%import "typed.lark"

start: block*
block: options_block | packages_block
options_block: "begin"i "options"i options_fields "end"i "options"i
packages_block: "begin"i "packages"i packages_fields "end"i "packages"i
options_fields: (list | print_input | print_flows | save_flows | newtonoptions)*
packages_fields: (packages)*
list: "list"i string
print_input: "print_input"i
print_flows: "print_flows"i
save_flows: "save_flows"i
newtonoptions: "newtonoptions"i record
packages: "packages"i recarray
23 changes: 23 additions & 0 deletions flopy4/mf6/codec/reader/grammar/generated/chf-oc.lark
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Auto-generated grammar for MF6 CHF-OC
%import "typed.lark"

start: block*
block: options_block | period_block
options_block: "begin"i "options"i options_fields "end"i "options"i
period_block: "begin"i "period"i period_fields "end"i "period"i
options_fields: (budget_filerecord | budgetcsv_filerecord | qoutflow_filerecord | stage_filerecord | qoutflowprintrecord)*
period_fields: (saverecord | printrecord)*
budget_filerecord: "budget"i "fileout"i string
budgetcsv_filerecord: "budgetcsv"i "fileout"i string
qoutflow_filerecord: "qoutflow"i "fileout"i string
stage_filerecord: "stage"i "fileout"i string
qoutflowprintrecord: "qoutflow"i "print_format"i
saverecord: "save"i string ocsetting
printrecord: "print"i string ocsetting
ocsetting: ocsetting_all | ocsetting_first | ocsetting_last | ocsetting_frequency | ocsetting_steps
ocsetting_all: "all"i
ocsetting_first: "first"i
ocsetting_last: "last"i
ocsetting_frequency: "frequency"i integer
ocsetting_steps: "steps"i integer

23 changes: 23 additions & 0 deletions flopy4/mf6/codec/reader/grammar/generated/chf-pcp.lark
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Auto-generated grammar for MF6 CHF-PCP
%import "typed.lark"

start: block*
block: options_block | dimensions_block | period_block
options_block: "begin"i "options"i options_fields "end"i "options"i
dimensions_block: "begin"i "dimensions"i dimensions_fields "end"i "dimensions"i
period_block: "begin"i "period"i period_fields "end"i "period"i
options_fields: (auxiliary | auxmultname | boundnames | print_input | print_flows | save_flows | ts_filerecord | obs_filerecord)*
dimensions_fields: (maxbound)*
period_fields: (precipitation | aux | boundname)*
auxiliary: "auxiliary"i array
auxmultname: "auxmultname"i string
boundnames: "boundnames"i
print_input: "print_input"i
print_flows: "print_flows"i
save_flows: "save_flows"i
ts_filerecord: "ts6"i "filein"i string
obs_filerecord: "obs6"i "filein"i string
maxbound: "maxbound"i integer
precipitation: "precipitation"i list
aux: "aux"i list
boundname: "boundname"i list
13 changes: 13 additions & 0 deletions flopy4/mf6/codec/reader/grammar/generated/chf-sto.lark
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Auto-generated grammar for MF6 CHF-STO
%import "typed.lark"

start: block*
block: options_block | period_block
options_block: "begin"i "options"i options_fields "end"i "options"i
period_block: "begin"i "period"i period_fields "end"i "period"i
options_fields: (save_flows | export_array_ascii)*
period_fields: (steady-state | transient)*
save_flows: "save_flows"i
export_array_ascii: "export_array_ascii"i
steady-state: "steady-state"i
transient: "transient"i
Loading
Loading