33from pathlib import Path
44from typing import Any
55
6+ import numpy as np
67import xarray as xr
78import xattree
89from modflow_devtools .dfn .schema .block import block_sort_key
@@ -89,6 +90,51 @@ def _hack_structured_grid_dims(
8990 )
9091
9192
93+ def _hack_period_non_numeric (name : str , value : xr .DataArray ) -> dict [str , dict [int , Any ]]:
94+ from flopy4 .mf6 .gwf import Oc
95+
96+ def oc_setting_data (rec ):
97+ dat = {}
98+ if rec .steps .first :
99+ dat = {kper : "first" for kper in range (value .sizes ["nper" ])}
100+ elif rec .steps .last :
101+ dat = {kper : "last" for kper in range (value .sizes ["nper" ])}
102+ elif rec .steps .steps :
103+ steps = " " .join (str (x - 1 ) for x in rec .steps .steps )
104+ dat = {kper : f"steps { steps } " for kper in range (value .sizes ["nper" ])}
105+ elif rec .steps .all :
106+ # check last as this defaults to True
107+ dat = {kper : "all" for kper in range (value .sizes ["nper" ])}
108+
109+ return dat
110+
111+ data = {}
112+ match value .dtype :
113+ case np .bool :
114+ dat = {kper : "" for kper in range (value .sizes ["nper" ]) if value .values [kper ]} # type: ignore
115+ data [name ] = dat
116+ case np .dtypes .StringDType ():
117+ fname = name .replace ("_" , " " )
118+ dat = {kper : value .values [kper ] for kper in range (value .sizes ["nper" ])}
119+ data [fname ] = dat
120+ case object ():
121+ if isinstance (value .values [0 ], Oc .PrintSaveSetting ):
122+ if hasattr (value .values [0 ], "printrecord" ) and isinstance (
123+ value .values [0 ].printrecord , list
124+ ):
125+ for rec in value .values [0 ].printrecord :
126+ key = f"{ rec .print } { rec .rtype } "
127+ data [key ] = oc_setting_data (rec )
128+ if hasattr (value .values [0 ], "saverecord" ) and isinstance (
129+ value .values [0 ].saverecord , list
130+ ):
131+ for rec in value .values [0 ].saverecord : # type: ignore
132+ key = f"{ rec .save } { rec .rtype } " # type: ignore
133+ data [key ] = oc_setting_data (rec )
134+
135+ return data
136+
137+
92138def unstructure_component (value : Component ) -> dict [str , Any ]:
93139 blockspec = dict (sorted (value .dfn .blocks .items (), key = block_sort_key )) # type: ignore
94140 blocks : dict [str , dict [str , Any ]] = {}
@@ -157,10 +203,15 @@ def unstructure_component(value: Component) -> dict[str, Any]:
157203 structured_grid_dims = value .parent .data .dims , # type: ignore
158204 )
159205 if block_name == "period" :
160- period_data [field_name ] = {
161- kper : field_value .isel (nper = kper )
162- for kper in range (field_value .sizes ["nper" ])
163- }
206+ if not np .issubdtype (field_value .dtype , np .number ):
207+ dat = _hack_period_non_numeric (field_name , field_value )
208+ for n , v in dat .items ():
209+ period_data [n ] = v
210+ else :
211+ period_data [field_name ] = {
212+ kper : field_value .isel (nper = kper ) # type: ignore
213+ for kper in range (field_value .sizes ["nper" ])
214+ }
164215 else :
165216 blocks [block_name ][field_name ] = field_value
166217
@@ -174,11 +225,20 @@ def unstructure_component(value: Component) -> dict[str, Any]:
174225 period_blocks [kper ] = {}
175226 period_blocks [kper ][arr_name ] = arr
176227
228+ # sort kper order
229+ period_blocks = dict (sorted (period_blocks .items ()))
230+
177231 # setup indexed period blocks, combine arrays into datasets
178232 for kper , block in period_blocks .items ():
179- blocks [f"period { kper + 1 } " ] = {
180- "period" : xr .Dataset (block , coords = block [arr_name ].coords )
181- }
233+ blocks [f"period { kper + 1 } " ] = {}
234+ for arr_name , val in block .items ():
235+ match block [arr_name ]:
236+ case str ():
237+ blocks [f"period { kper + 1 } " ][arr_name ] = val
238+ case xr .DataArray ():
239+ blocks [f"period { kper + 1 } " ]["period" ] = xr .Dataset (
240+ block , coords = block [arr_name ].coords
241+ )
182242
183243 # combine "perioddata" block arrays (tdis, ats) into datasets
184244 # so they render as lists. temp hack TODO do this generically
0 commit comments