-
Notifications
You must be signed in to change notification settings - Fork 6
handle scalars, test component-specific parsing/transformation #179
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
24 changes: 15 additions & 9 deletions
24
flopy4/mf6/codec/reader/grammar/array.lark → flopy4/mf6/codec/reader/grammar/typed.lark
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,14 +1,27 @@ | ||
| import os | ||
| from collections import ChainMap | ||
| from pathlib import Path | ||
| from typing import Any | ||
|
|
||
| import numpy as np | ||
| import xarray as xr | ||
| from lark import Lark | ||
|
|
||
| from flopy4.mf6.codec.reader.parser import make_array_parser | ||
| from flopy4.mf6.codec.reader.transformer import ArrayTransformer | ||
| from flopy4.mf6.codec.reader.transformer import TypedTransformer | ||
|
|
||
| PROJ_ROOT_PATH = Path(__file__).parents[1] | ||
| BASE_GRAMMAR_PATH = ( | ||
| PROJ_ROOT_PATH / "flopy4" / "mf6" / "codec" / "reader" / "grammar" / "typed.lark" | ||
| ) | ||
|
|
||
|
|
||
| def make_typed_parser(grammar: str): | ||
| with open(BASE_GRAMMAR_PATH, "r") as f: | ||
| return Lark(grammar + os.linesep + f.read(), parser="lalr", debug=True) | ||
|
|
||
|
|
||
| def test_parse_internal_array(): | ||
| parser = make_array_parser() | ||
| parser = make_typed_parser("start: array") | ||
| tree = parser.parse(""" | ||
| INTERNAL FACTOR 1.0 IPRN 3 | ||
| 1.2 3.7 9.3 4.2 2.2 9.9 1.0 | ||
|
|
@@ -20,7 +33,7 @@ def test_parse_internal_array(): | |
|
|
||
|
|
||
| def test_parse_layered_array(): | ||
| parser = make_array_parser() | ||
| parser = make_typed_parser("start: array") | ||
| tree = parser.parse(""" | ||
| LAYERED | ||
| CONSTANT 1.0 | ||
|
|
@@ -34,32 +47,32 @@ def test_parse_layered_array(): | |
|
|
||
|
|
||
| def test_parse_constant_array(): | ||
| parser = make_array_parser() | ||
| parser = make_typed_parser("start: array") | ||
| tree = parser.parse(""" | ||
| CONSTANT 1.0 | ||
| """) | ||
| print(tree.pretty()) | ||
|
|
||
|
|
||
| def test_parse_external_array_no_quotation_marks(): | ||
| parser = make_array_parser() | ||
| parser = make_typed_parser("start: array") | ||
| tree = parser.parse(""" | ||
| OPEN/CLOSE some.file | ||
| """) | ||
| print(tree.pretty()) | ||
|
|
||
|
|
||
| def test_parse_external_array_with_quotation_marks(): | ||
| parser = make_array_parser() | ||
| parser = make_typed_parser("start: array") | ||
| tree = parser.parse(""" | ||
| OPEN/CLOSE "some.file" | ||
| """) | ||
| print(tree.pretty()) | ||
|
|
||
|
|
||
| def test_transform_internal_array(): | ||
| parser = make_array_parser() | ||
| transformer = ArrayTransformer() | ||
| parser = make_typed_parser("start: array") | ||
| transformer = TypedTransformer() | ||
| result = transformer.transform( | ||
| parser.parse(""" | ||
| INTERNAL FACTOR 1.5 IPRN 3 | ||
|
|
@@ -76,8 +89,8 @@ def test_transform_internal_array(): | |
|
|
||
|
|
||
| def test_transform_constant_array(): | ||
| parser = make_array_parser() | ||
| transformer = ArrayTransformer() | ||
| parser = make_typed_parser("start: array") | ||
| transformer = TypedTransformer() | ||
| result = transformer.transform( | ||
| parser.parse(""" | ||
| CONSTANT 42.5 | ||
|
|
@@ -88,8 +101,8 @@ def test_transform_constant_array(): | |
|
|
||
|
|
||
| def test_transform_external_array(): | ||
| parser = make_array_parser() | ||
| transformer = ArrayTransformer() | ||
| parser = make_typed_parser("start: array") | ||
| transformer = TypedTransformer() | ||
| result = transformer.transform( | ||
| parser.parse(""" | ||
| OPEN/CLOSE "data/heads.dat" FACTOR 1.0 (BINARY) | ||
|
|
@@ -100,8 +113,8 @@ def test_transform_external_array(): | |
|
|
||
|
|
||
| def test_transform_layered_array(): | ||
| parser = make_array_parser() | ||
| transformer = ArrayTransformer() | ||
| parser = make_typed_parser("start: array") | ||
| transformer = TypedTransformer() | ||
| result = transformer.transform( | ||
| parser.parse(""" | ||
| LAYERED | ||
|
|
@@ -119,3 +132,93 @@ def test_transform_layered_array(): | |
| assert result["data"].shape == (2, 8) | ||
| assert result["data"].dims == ("layer", "dim_0") | ||
| assert np.array_equal(result["data"][0], np.ones((8,))) | ||
|
|
||
|
|
||
| def test_transform_full_component(): | ||
| grammar = """ | ||
| start: block* | ||
| block: options_block | arrays_block | ||
| options_block: "begin"i "options"i options_vars "end"i "options"i | ||
| options_vars: (r2d2 | b | c | p)* | ||
| arrays_block: "begin"i "arrays"i arrays_vars "end"i "arrays"i | ||
| arrays_vars: (x | y | z)* | ||
| r2d2: "r2d2"i // keyword | ||
| b: "b"i string | ||
| c: "c"i integer | ||
| p: "p"i double | ||
| x: "x"i array | ||
| y: "y"i array | ||
| z: "z"i array | ||
| """ | ||
| parser = make_typed_parser(grammar) | ||
|
|
||
| class BlockTransformer(TypedTransformer): | ||
| def start(self, items: list[Any]) -> dict: | ||
| return ChainMap(*items) | ||
|
|
||
| def block(self, items: list[Any]) -> dict: | ||
| return items[0] | ||
|
|
||
| def options_block(self, items: list[Any]) -> dict: | ||
| return {"options": items[0]} | ||
|
|
||
| def arrays_block(self, items: list[Any]) -> dict: | ||
| return {"arrays": items[0]} | ||
|
|
||
| def options_vars(self, items: list[Any]) -> dict: | ||
| return {item[0].lower(): item[1] for item in items} | ||
|
|
||
| def arrays_vars(self, items: list[Any]) -> dict: | ||
| return {item[0].lower(): item[1] for item in items} | ||
|
|
||
| def r2d2(self, _: list[Any]) -> bool: | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. instead of hardcoding these in future, we can inject component class definitions into the transformer, and have a single hook which handles blocks, variables, etc as appropriate based on the class definition |
||
| return "r2d2", True | ||
|
|
||
| def b(self, items: list[Any]) -> tuple[str, str]: | ||
| return "b", items[0] | ||
|
|
||
| def c(self, items: list[Any]) -> tuple[str, int]: | ||
| return "c", items[0] | ||
|
|
||
| def p(self, items: list[Any]) -> tuple[str, float]: | ||
| return "p", items[0] | ||
|
|
||
| def x(self, items: list[Any]) -> tuple[str, dict]: | ||
| return "x", TypedTransformer.try_create_dataarray(items[0]) | ||
|
|
||
| def y(self, items: list[Any]) -> tuple[str, dict]: | ||
| return "y", TypedTransformer.try_create_dataarray(items[0]) | ||
|
|
||
| def z(self, items: list[Any]) -> tuple[str, dict]: | ||
| return "z", TypedTransformer.try_create_dataarray(items[0]) | ||
|
|
||
| transformer = BlockTransformer() | ||
| result = transformer.transform( | ||
| parser.parse(""" | ||
| BEGIN OPTIONS | ||
| R2D2 | ||
| B "nice said" | ||
| C 3 | ||
| P 0. | ||
| END OPTIONS | ||
| BEGIN ARRAYS | ||
| X CONSTANT 1.0 | ||
| Y INTERNAL 4.0 5.0 6.0 | ||
| Z OPEN/CLOSE "data/z.dat" FACTOR 1.0 (BINARY) | ||
| END ARRAYS | ||
| """) | ||
| ) | ||
| assert "options" in result | ||
| assert "arrays" in result | ||
| assert result["options"]["r2d2"] is True | ||
| assert result["options"]["b"] == "nice said" | ||
| assert result["options"]["c"] == 3 | ||
| assert result["options"]["p"] == 0.0 | ||
| assert result["arrays"]["x"]["control"]["type"] == "constant" | ||
| assert np.array_equal(result["arrays"]["x"]["data"], np.array(1.0)) | ||
| assert result["arrays"]["y"]["control"]["type"] == "internal" | ||
| assert np.array_equal(result["arrays"]["y"]["data"], np.array([4.0, 5.0, 6.0])) | ||
| assert result["arrays"]["z"]["control"]["type"] == "external" | ||
| assert result["arrays"]["z"]["control"]["factor"] == 1.0 | ||
| assert result["arrays"]["z"]["control"]["binary"] is True | ||
| assert result["arrays"]["z"]["data"] == Path("data/z.dat") | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
grammars like these, aware of the names/contents of blocks, and the names/types of variables, can be generated for each component