1+ import os
2+ from collections import ChainMap
13from pathlib import Path
4+ from typing import Any
25
36import numpy as np
47import xarray as xr
8+ from lark import Lark
59
6- from flopy4 .mf6 .codec .reader .parser import make_array_parser
7- from flopy4 .mf6 .codec .reader .transformer import ArrayTransformer
10+ from flopy4 .mf6 .codec .reader .transformer import TypedTransformer
11+
12+ PROJ_ROOT_PATH = Path (__file__ ).parents [1 ]
13+ BASE_GRAMMAR_PATH = (
14+ PROJ_ROOT_PATH / "flopy4" / "mf6" / "codec" / "reader" / "grammar" / "typed.lark"
15+ )
16+
17+
18+ def make_typed_parser (grammar : str ):
19+ with open (BASE_GRAMMAR_PATH , "r" ) as f :
20+ return Lark (grammar + os .linesep + f .read (), parser = "lalr" , debug = True )
821
922
1023def test_parse_internal_array ():
11- parser = make_array_parser ( )
24+ parser = make_typed_parser ( "start: array" )
1225 tree = parser .parse ("""
1326INTERNAL FACTOR 1.0 IPRN 3
14271.2 3.7 9.3 4.2 2.2 9.9 1.0
@@ -20,7 +33,7 @@ def test_parse_internal_array():
2033
2134
2235def test_parse_layered_array ():
23- parser = make_array_parser ( )
36+ parser = make_typed_parser ( "start: array" )
2437 tree = parser .parse ("""
2538LAYERED
2639CONSTANT 1.0
@@ -34,32 +47,32 @@ def test_parse_layered_array():
3447
3548
3649def test_parse_constant_array ():
37- parser = make_array_parser ( )
50+ parser = make_typed_parser ( "start: array" )
3851 tree = parser .parse ("""
3952CONSTANT 1.0
4053 """ )
4154 print (tree .pretty ())
4255
4356
4457def test_parse_external_array_no_quotation_marks ():
45- parser = make_array_parser ( )
58+ parser = make_typed_parser ( "start: array" )
4659 tree = parser .parse ("""
4760OPEN/CLOSE some.file
4861 """ )
4962 print (tree .pretty ())
5063
5164
5265def test_parse_external_array_with_quotation_marks ():
53- parser = make_array_parser ( )
66+ parser = make_typed_parser ( "start: array" )
5467 tree = parser .parse ("""
5568OPEN/CLOSE "some.file"
5669 """ )
5770 print (tree .pretty ())
5871
5972
6073def test_transform_internal_array ():
61- parser = make_array_parser ( )
62- transformer = ArrayTransformer ()
74+ parser = make_typed_parser ( "start: array" )
75+ transformer = TypedTransformer ()
6376 result = transformer .transform (
6477 parser .parse ("""
6578INTERNAL FACTOR 1.5 IPRN 3
@@ -76,8 +89,8 @@ def test_transform_internal_array():
7689
7790
7891def test_transform_constant_array ():
79- parser = make_array_parser ( )
80- transformer = ArrayTransformer ()
92+ parser = make_typed_parser ( "start: array" )
93+ transformer = TypedTransformer ()
8194 result = transformer .transform (
8295 parser .parse ("""
8396CONSTANT 42.5
@@ -88,8 +101,8 @@ def test_transform_constant_array():
88101
89102
90103def test_transform_external_array ():
91- parser = make_array_parser ( )
92- transformer = ArrayTransformer ()
104+ parser = make_typed_parser ( "start: array" )
105+ transformer = TypedTransformer ()
93106 result = transformer .transform (
94107 parser .parse ("""
95108OPEN/CLOSE "data/heads.dat" FACTOR 1.0 (BINARY)
@@ -100,8 +113,8 @@ def test_transform_external_array():
100113
101114
102115def test_transform_layered_array ():
103- parser = make_array_parser ( )
104- transformer = ArrayTransformer ()
116+ parser = make_typed_parser ( "start: array" )
117+ transformer = TypedTransformer ()
105118 result = transformer .transform (
106119 parser .parse ("""
107120LAYERED
@@ -119,3 +132,93 @@ def test_transform_layered_array():
119132 assert result ["data" ].shape == (2 , 8 )
120133 assert result ["data" ].dims == ("layer" , "dim_0" )
121134 assert np .array_equal (result ["data" ][0 ], np .ones ((8 ,)))
135+
136+
137+ def test_transform_full_component ():
138+ grammar = """
139+ start: block*
140+ block: options_block | arrays_block
141+ options_block: "begin"i "options"i options_vars "end"i "options"i
142+ options_vars: (r2d2 | b | c | p)*
143+ arrays_block: "begin"i "arrays"i arrays_vars "end"i "arrays"i
144+ arrays_vars: (x | y | z)*
145+ r2d2: "r2d2"i // keyword
146+ b: "b"i string
147+ c: "c"i integer
148+ p: "p"i double
149+ x: "x"i array
150+ y: "y"i array
151+ z: "z"i array
152+ """
153+ parser = make_typed_parser (grammar )
154+
155+ class BlockTransformer (TypedTransformer ):
156+ def start (self , items : list [Any ]) -> dict :
157+ return ChainMap (* items )
158+
159+ def block (self , items : list [Any ]) -> dict :
160+ return items [0 ]
161+
162+ def options_block (self , items : list [Any ]) -> dict :
163+ return {"options" : items [0 ]}
164+
165+ def arrays_block (self , items : list [Any ]) -> dict :
166+ return {"arrays" : items [0 ]}
167+
168+ def options_vars (self , items : list [Any ]) -> dict :
169+ return {item [0 ].lower (): item [1 ] for item in items }
170+
171+ def arrays_vars (self , items : list [Any ]) -> dict :
172+ return {item [0 ].lower (): item [1 ] for item in items }
173+
174+ def r2d2 (self , _ : list [Any ]) -> bool :
175+ return "r2d2" , True
176+
177+ def b (self , items : list [Any ]) -> tuple [str , str ]:
178+ return "b" , items [0 ]
179+
180+ def c (self , items : list [Any ]) -> tuple [str , int ]:
181+ return "c" , items [0 ]
182+
183+ def p (self , items : list [Any ]) -> tuple [str , float ]:
184+ return "p" , items [0 ]
185+
186+ def x (self , items : list [Any ]) -> tuple [str , dict ]:
187+ return "x" , TypedTransformer .try_create_dataarray (items [0 ])
188+
189+ def y (self , items : list [Any ]) -> tuple [str , dict ]:
190+ return "y" , TypedTransformer .try_create_dataarray (items [0 ])
191+
192+ def z (self , items : list [Any ]) -> tuple [str , dict ]:
193+ return "z" , TypedTransformer .try_create_dataarray (items [0 ])
194+
195+ transformer = BlockTransformer ()
196+ result = transformer .transform (
197+ parser .parse ("""
198+ BEGIN OPTIONS
199+ R2D2
200+ B "nice said"
201+ C 3
202+ P 0.
203+ END OPTIONS
204+ BEGIN ARRAYS
205+ X CONSTANT 1.0
206+ Y INTERNAL 4.0 5.0 6.0
207+ Z OPEN/CLOSE "data/z.dat" FACTOR 1.0 (BINARY)
208+ END ARRAYS
209+ """ )
210+ )
211+ assert "options" in result
212+ assert "arrays" in result
213+ assert result ["options" ]["r2d2" ] is True
214+ assert result ["options" ]["b" ] == "nice said"
215+ assert result ["options" ]["c" ] == 3
216+ assert result ["options" ]["p" ] == 0.0
217+ assert result ["arrays" ]["x" ]["control" ]["type" ] == "constant"
218+ assert np .array_equal (result ["arrays" ]["x" ]["data" ], np .array (1.0 ))
219+ assert result ["arrays" ]["y" ]["control" ]["type" ] == "internal"
220+ assert np .array_equal (result ["arrays" ]["y" ]["data" ], np .array ([4.0 , 5.0 , 6.0 ]))
221+ assert result ["arrays" ]["z" ]["control" ]["type" ] == "external"
222+ assert result ["arrays" ]["z" ]["control" ]["factor" ] == 1.0
223+ assert result ["arrays" ]["z" ]["control" ]["binary" ] is True
224+ assert result ["arrays" ]["z" ]["data" ] == Path ("data/z.dat" )
0 commit comments