Skip to content

Commit 2657659

Browse files
wpbonellimjreno
andauthored
jinja improvements (#211)
jinja template/filter improvements. introduce an array2const filter for constant arrays. and revise the array_how filter to determine how to write arrays (later it will be possible for the user to set this at the simulation or subcomponent level and override this automatic determination). Co-authored-by: mjreno <[email protected]>
1 parent 4729eb9 commit 2657659

File tree

3 files changed

+32
-10
lines changed

3 files changed

+32
-10
lines changed

flopy4/mf6/codec/writer/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
)
1414
_JINJA_ENV.filters["field_type"] = filters.field_type
1515
_JINJA_ENV.filters["array_how"] = filters.array_how
16-
_JINJA_ENV.filters["array_chunks"] = filters.array_chunks
16+
_JINJA_ENV.filters["array2const"] = filters.array2const
17+
_JINJA_ENV.filters["array2chunks"] = filters.array2chunks
1718
_JINJA_ENV.filters["array2string"] = filters.array2string
1819
_JINJA_ENV.filters["data2list"] = filters.data2list
1920
_JINJA_TEMPLATE_NAME = "blocks.jinja"

flopy4/mf6/codec/writer/filters.py

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
from collections.abc import Hashable, Mapping
22
from io import StringIO
3-
from typing import Any
3+
from typing import Any, Literal
44

55
import numpy as np
66
import xarray as xr
77
from modflow_devtools.dfn.schema.v2 import FieldType
88
from numpy.typing import NDArray
9+
from xattree import Scalar
910

1011
from flopy4.mf6.constants import FILL_DNODATA
1112

@@ -32,14 +33,34 @@ def field_type(value: Any) -> FieldType:
3233
raise ValueError(f"Unsupported field type: {type(value)}")
3334

3435

35-
def array_how(value: xr.DataArray) -> str:
36-
# TODO
37-
# - detect constant arrays?
38-
# - above certain size, use external?
36+
ArrayHow = Literal["constant", "internal", "external"]
37+
38+
39+
def array_how(value: xr.DataArray) -> ArrayHow:
40+
"""
41+
Determine how an array should be represented in MF6 input.
42+
Options are "constant", "internal", or "external". If the
43+
array dask-backed, assumed it's big and return "external".
44+
Otherwise there is no materialization cost to check if all
45+
values are the same, so return "constant" or "internal" as
46+
appropriate.
47+
"""
48+
if hasattr(value.data, "blocks"):
49+
return "external"
50+
if value.max() == value.min():
51+
return "constant"
3952
return "internal"
4053

4154

42-
def array_chunks(value: xr.DataArray, chunks: Mapping[Hashable, int] | None = None):
55+
def array2const(value: xr.DataArray) -> Scalar:
56+
if np.issubdtype(value.dtype, np.integer):
57+
return value.max().item()
58+
if np.issubdtype(value.dtype, np.floating):
59+
return f"{value.max().item():.8f}"
60+
return value.ravel()[0]
61+
62+
63+
def array2chunks(value: xr.DataArray, chunks: Mapping[Hashable, int] | None = None):
4364
"""
4465
Yield chunks from a dask-backed array of up to 3 dimensions.
4566
If it's not already chunked, split it into chunks of the

flopy4/mf6/codec/writer/templates/macros.jinja

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,14 @@
3232
{{ inset ~ name.upper() }}{% if "layered" in how %} LAYERED{% endif %}
3333

3434
{% if how == "constant" %}
35-
CONSTANT {{ value.item() }}
35+
CONSTANT {{ value|array2const }}
3636
{% elif how == "layered constant" %}
3737
{% for layer in value -%}
38-
CONSTANT {{ layer.item() }}
38+
CONSTANT {{ layer|array2const }}
3939
{%- endfor %}
4040
{% elif how == "internal" %}
4141
INTERNAL
42-
{% for chunk in value|array_chunks -%}
42+
{% for chunk in value|array2chunks -%}
4343
{{ (2 * inset) ~ chunk|array2string }}
4444
{%- endfor %}
4545
{% elif how == "external" %}

0 commit comments

Comments
 (0)