Skip to content

Commit 8d8dd54

Browse files
committed
wip
1 parent 5b94f06 commit 8d8dd54

File tree

6 files changed

+125
-45
lines changed

6 files changed

+125
-45
lines changed

flopy4/mf6/component.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22
from collections.abc import MutableMapping
33

44
from xattree import xattree
5+
from flopy4.io import Writer
56

67
COMPONENTS = {}
78
"""MF6 component registry."""
89

910

1011
@xattree
11-
class Component(ABC, MutableMapping):
12+
class Component(ABC, MutableMapping, Writer):
1213
@classmethod
1314
def __attrs_init_subclass__(cls):
1415
COMPONENTS[cls.__name__.lower()] = cls
@@ -27,8 +28,3 @@ def __iter__(self):
2728

2829
def __len__(self):
2930
return len(self.children) # type: ignore
30-
31-
def write(self) -> None:
32-
# TODO: write with jinja to file
33-
for child in self.children.values(): # type: ignore
34-
child.write()

flopy4/mf6/filters.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from collections.abc import Iterable, Mapping
2+
from inspect import isclass
3+
import types
4+
from typing import Union, get_args, get_origin
5+
import numpy as np
6+
import xarray as xr
7+
from jinja2 import pass_context
8+
9+
from attrs import Attribute
10+
from xattree import Xattribute
11+
12+
13+
@pass_context
14+
def value(ctx, field: Xattribute):
15+
"""Return the kind of the field."""
16+
# TODO
17+
pass
18+
19+
20+
def dask_expand(data: xr.DataArray):
21+
for block in data.data.to_delayed():
22+
block_data = block.compute()
23+
yield block_data
24+
25+
26+
def nparray2string(data: np.ndarray):
27+
return np.array2string(data, separator=" ")[1:-1] # remove brackets

flopy4/mf6/io.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import sys
2+
import numpy as np
3+
from jinja2 import Environment, PackageLoader
4+
from flopy4.mf6 import filters
5+
from flopy4.mf6.spec import blocks_dict
6+
7+
8+
env = Environment(
9+
loader=PackageLoader("flopy4.mf6"),
10+
trim_blocks=True,
11+
lstrip_blocks=True,
12+
)
13+
env.filters["dask_expand"] = filters.dask_expand
14+
env.filters["nparray2string"] = filters.nparray2string
15+
16+
17+
class Writer:
18+
def _write_ascii(self, path) -> None:
19+
# TODO: factor out an ascii writer separately
20+
21+
block_spec = blocks_dict(type(self))
22+
blocks = {}
23+
for block_name, block in block_spec.items():
24+
blocks[block_name] = {}
25+
for field_name, field in block.items():
26+
if field_name == "data":
27+
continue
28+
blocks[block_name][field_name] = {
29+
"spec": field,
30+
"value": getattr(self, field_name),
31+
}
32+
33+
template = env.get_template("blocks.jinja")
34+
iterator = template.generate(blocks=blocks)
35+
with np.printoptions(
36+
precision=4, linewidth=sys.maxsize, threshold=sys.maxsize
37+
):
38+
with open(path, "w") as f:
39+
f.writelines(iterator)
40+
41+
def write(self) -> None:
42+
self._write_ascii()
43+
for child in self.children.values(): # type: ignore
44+
child.write()

flopy4/mf6/templates/blocks.jinja

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,8 @@
11
{% for block in blocks %}
2-
begin {{ block.name }} {{ block.index }}
3-
{% for var in block %}
4-
{% if var.kind in ['keyword', 'integer', 'double precision'] %}
5-
{{ macros.scalar(var) }}
6-
{% elif var.kind == 'keystring' %}
7-
{{ macros.union(var) }}
8-
{% elif var.kind == 'record' %}
9-
{{ macros.record(var) }}
10-
{% elif var.kind == 'array' %}
11-
{{ macros.array(var) }}
12-
{% elif var.kind == 'list' %}
13-
{{ macros.list(var) }}
14-
{% endif %}
2+
BEGIN {{ block.name }} {% if block.index is not none %}{{ block.index }}{% endif %}
3+
{% for field in block %}
4+
{{ macros.field(field) }}
155
{% endfor %}
16-
end {{ block.name }}
6+
END {{ block.name }}
7+
178
{% endfor %}

flopy4/mf6/templates/macros.jinja

Lines changed: 45 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,58 @@
1-
{% macro scalar(var) %}
2-
{{ var.name }} {% endif %}{{ var.value }}
1+
{% macro field(field) %}
2+
{% if field|kind == 'scalar' %}
3+
{{ macros.scalar(field) }}
4+
{% elif field|kind == 'union' %}
5+
{{ macros.union(field) }}
6+
{% elif field|kind == 'record' %}
7+
{{ macros.record(field) }}
8+
{% elif field|kind == 'array' %}
9+
{{ macros.array(field) }}
10+
{% elif field|kind == 'list' %}
11+
{{ macros.list(field) }}
12+
{% endif %}
313
{% endmacro %}
414

5-
{% macro union(var) %}
15+
{% macro scalar(field) %}
16+
{{ field.name }} {% endif %}{{ field.value }}
617
{% endmacro %}
718

8-
{% macro record(var) %}
9-
{% if var.tagged %}{{ var.name }} {% endif %}{{ var.value|join(' ') }}
19+
{% macro union(field) %}
20+
{% for item in field.value.items() %}
21+
{{ macros.field(item) }}
22+
{% endfor %}
1023
{% endmacro %}
1124

12-
{% macro array(var) %}
13-
{% if constant %}{% if layered %}
14-
{# layered constant #}
15-
{{ var.name }} LAYERED
16-
{% for val in var.value %}
25+
{% macro record(field) %}
26+
{% for item in field.values() %}{% if item.tagged %}{{ item.name }} {% endif %}{{ macros.field(field) }}{%
27+
endfor
28+
%}
29+
{% endmacro %}
30+
31+
{% macro array(field, how="internal") %}
32+
{% if how == "layered constant" %}
33+
{{ field.name }} LAYERED
34+
{% for val in field.value %}
1735
CONSTANT
1836
{% endfor %}
19-
{% else %}
20-
{# constant #}
21-
{{ var.name }} CONSTANT {{ var.value }}
22-
{% endif %}
23-
{% else %}
24-
{# layered #}
37+
{% elif how == "constant" %}
38+
{{ field.name }} CONSTANT {{ field.value }}
39+
{% elif how == "layered" %}
2540
{% if layered %}
26-
{{ var.name }}
27-
{% for val in var.value %}{{ val }}{% endfor %}
28-
{% else %}
29-
{# grid-shaped #}
30-
{{ var.name }} {{ var.value }}
31-
{% endif %}
41+
{{ field.name }}
42+
{% for val in field.value %}{{ val }}{% endfor %}
43+
{% elif how == "internal" %}
44+
{{ field.name }} {{ macro.internal_array(field) }}
45+
{% elif how == "external" %}
46+
{{ field.name}} OPEN/CLOSE {{ field.value }}
3247
{% endif %}
3348
{% endmacro %}
3449

35-
{% macro list(var) %}
50+
{% macro internal_array(field) %}
51+
{% for chunk in field.value|dask_expand %}
52+
{{ chunk|nparray2string }}
53+
{% endfor %}
54+
{% endmacro %}
55+
56+
{% macro list(field) %}
57+
{# TODO #}
3658
{% endmacro %}

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ classifiers = [
3434
]
3535
requires-python = ">=3.11"
3636
dependencies = [
37-
"attrs", # todo: bounds?
38-
"cattrs", # todo: bounds?
37+
"attrs",
38+
"cattrs",
3939
"flopy",
4040
"Jinja2>=3.0",
4141
"numpy>=1.20.3",

0 commit comments

Comments
 (0)