Skip to content

Commit 4bc0383

Browse files
EliEli
authored andcommitted
Add imports for polygons at top level of yaml.
1 parent e534813 commit 4bc0383

2 files changed

Lines changed: 63 additions & 23 deletions

File tree

schimpy/prepare_schism.py

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ def create_hgrid(s, inputs, logger):
8484
)
8585
small_area_param = section.get("small_areas")
8686
if small_area_param is not None:
87-
small_area_param["prepro_output_dir"] = inputs["prepro_output_dir"]
87+
small_area_param["prepro_output_dir"] = inputs["diagnostics_dir"]
8888
# This just emits warnings unless the fail threshold is met
8989
small_areas(s.mesh, logger=logger, **small_area_param)
9090

@@ -151,7 +151,7 @@ def create_hgrid(s, inputs, logger):
151151
s.mesh.nodes[:, 2] = stacked_dem_fill(
152152
dem_list,
153153
s.mesh.nodes[:, :2],
154-
inputs["prepro_output_dir"],
154+
inputs["diagnostics_dir"],
155155
require_all=False,
156156
na_fill=default_depth_for_missing_dem,
157157
negate=True,
@@ -173,7 +173,8 @@ def create_hgrid(s, inputs, logger):
173173
smooth = href_spec.get("smooth", None)
174174
# reuse the exact machinery used by the 'gr3' section:
175175
s.create_node_partitioning(
176-
href_path, polygons, default, smooth
176+
href_path, polygons, default, smooth,
177+
global_imports=inputs.get("imports"),
177178
) # writes GR3
178179
href_arg = href_path
179180
else:
@@ -244,7 +245,7 @@ def create_hgrid(s, inputs, logger):
244245
stacked_dem_fill(
245246
dem_list,
246247
s.mesh.nodes[:, :2],
247-
inputs["prepro_output_dir"],
248+
inputs["diagnostics_dir"],
248249
require_all=False,
249250
na_fill=default_depth_for_missing_dem,
250251
)
@@ -259,13 +260,16 @@ def create_hgrid(s, inputs, logger):
259260

260261
depth_enforce_params = section.get("depth_enforcement")
261262
if depth_enforce_params is not None:
263+
global_imports = inputs.get("imports")
262264
if "polygons" in depth_enforce_params:
263265
s.mesh.nodes[:, 2] = s.apply_polygons(
264-
default=None, polygons=depth_enforce_params["polygons"]
266+
default=None, polygons=depth_enforce_params["polygons"],
267+
global_imports=global_imports,
265268
)
266269
if "linestrings" in depth_enforce_params:
267270
s.mesh.nodes[:, 2] = s.apply_linestring_ops(
268-
default=None, linestrings=depth_enforce_params["linestrings"]
271+
default=None, linestrings=depth_enforce_params["linestrings"],
272+
global_imports=global_imports,
269273
)
270274

271275
# Write hgrid.gr3
@@ -295,6 +299,7 @@ def create_vgrid(s, inputs, logger):
295299
return
296300

297301
output_dir = inputs["prepro_output_dir"]
302+
diagnostics_dir = inputs["diagnostics_dir"]
298303

299304
# --- Resolve hgrid (shared by v1 and v2) ---
300305
if "hgrid" in section:
@@ -333,6 +338,7 @@ def create_vgrid(s, inputs, logger):
333338
)
334339
for k in stray:
335340
section.pop(k)
341+
section["diagnostics_dir"] = diagnostics_dir
336342
vgrid_gen(hgrid, **section)
337343

338344
elif gen_version == "v2":
@@ -343,6 +349,10 @@ def create_vgrid(s, inputs, logger):
343349
)
344350
# v2 passes named arguments
345351
section.pop("hgrid", None)
352+
# Route debug_prefix under diagnostics_dir if set
353+
debug_prefix = section.get("debug_prefix")
354+
if debug_prefix:
355+
debug_prefix = os.path.join(diagnostics_dir, debug_prefix)
346356
vgrid_gen_v2(
347357
hgrid=hgrid,
348358
vgrid_out=section["vgrid_out"],
@@ -353,7 +363,7 @@ def create_vgrid(s, inputs, logger):
353363
region_constraints=section.get("region_constraints"),
354364
constraint_taper_rings=int(section.get("constraint_taper_rings", 3)),
355365
dz_scale_gr3=section.get("dz_scale_gr3"),
356-
debug_prefix=section.get("debug_prefix"),
366+
debug_prefix=debug_prefix,
357367
pileup_log=section.get("pileup_log"),
358368
)
359369
else:
@@ -394,6 +404,7 @@ def create_gr3_with_polygons(s, inputs, logger):
394404
if dict_gr3 is None:
395405
return
396406
logger.info("Processing gr3 outputs...")
407+
global_imports = inputs.get("imports")
397408
expected_items = ("polygons", "default", "smooth")
398409
output_dir = inputs["prepro_output_dir"]
399410
for fname, item in dict_gr3.items():
@@ -419,7 +430,7 @@ def create_gr3_with_polygons(s, inputs, logger):
419430
default = item.get("default")
420431
logger.info("Creating %s..." % fname)
421432
smooth = item.get("smooth")
422-
s.create_node_partitioning(fname, polygons, default, smooth)
433+
s.create_node_partitioning(fname, polygons, default, smooth, global_imports=global_imports)
423434

424435

425436
def create_prop_with_polygons(s, inputs, logger):
@@ -428,6 +439,7 @@ def create_prop_with_polygons(s, inputs, logger):
428439
if dict_prop is None:
429440
return
430441
logger.info("Processing prop outputs...")
442+
global_imports = inputs.get("imports")
431443
expected_items = ("default", "polygons")
432444
output_dir = inputs["prepro_output_dir"]
433445
for fname, item in dict_prop.items():
@@ -445,7 +457,7 @@ def create_prop_with_polygons(s, inputs, logger):
445457
polygons = item.get("polygons", [])
446458
default = item.get("default")
447459
logger.info("Creating %s..." % fname)
448-
s.create_prop_partitioning(fname, polygons, default)
460+
s.create_prop_partitioning(fname, polygons, default, global_imports=global_imports)
449461

450462

451463
def create_structures(s, inputs, logger):
@@ -761,6 +773,7 @@ def process_output_dir(inputs):
761773
os.mkdir(outdir)
762774
else:
763775
raise ValueError("Output directory (output_dir) does not exist")
776+
764777
return outdir
765778

766779

@@ -811,6 +824,7 @@ def process_prepare_yaml(in_fname, use_logging=True, write_echo=True, envvar=Non
811824
keys_top_level = [
812825
"config",
813826
"env",
827+
"imports",
814828
"min_schimpy_version",
815829
"prepro_output_dir",
816830
"mesh",
@@ -827,6 +841,11 @@ def process_prepare_yaml(in_fname, use_logging=True, write_echo=True, envvar=Non
827841
logger.info("Processing the top level...")
828842
check_and_suggest(list(inputs.keys()), keys_top_level, logger)
829843

844+
# Create diagnostics subdirectory for intermediate/debug outputs
845+
diagnostics_dir = os.path.join(outdir, "diagnostics")
846+
os.makedirs(diagnostics_dir, exist_ok=True)
847+
inputs["diagnostics_dir"] = diagnostics_dir
848+
830849
if write_echo:
831850
out_fname = (
832851
os.path.splitext(in_fname)[0] + "_echo" + os.path.splitext(in_fname)[1]

schimpy/schism_setup.py

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -507,7 +507,7 @@ def _parse_attribute(self, expr):
507507
expr = re.sub(r"(\b)max(\b)", r"\g<1>numpy.maximum\g<2>", expr)
508508
return expr
509509

510-
def apply_linestring_ops(self, default, linestrings):
510+
def apply_linestring_ops(self, default, linestrings, global_imports=None):
511511
mesh = self.mesh
512512
attr = np.copy(mesh.nodes[:, 2])
513513

@@ -569,8 +569,19 @@ def apply_linestring_ops(self, default, linestrings):
569569
node_local_nds[inode] = set(elnodes)
570570

571571
newglobals = {}
572-
for item in newglobals:
573-
print(newglobals[item])
572+
_ls_imports = ["numpy"] + (global_imports if global_imports else [])
573+
for imp in _ls_imports:
574+
iname = imp.split(".")[-1]
575+
try:
576+
newglobals[iname] = importlib.import_module(imp)
577+
except (ModuleNotFoundError, ImportError):
578+
parent = ".".join(imp.split(".")[:-1])
579+
if parent:
580+
try:
581+
parent_mod = importlib.import_module(parent)
582+
newglobals[iname] = getattr(parent_mod, iname)
583+
except Exception:
584+
pass
574585
for inode in node_local_nds:
575586
# inode is the node being calculated
576587
support_nodes = list(node_local_nds[inode])
@@ -594,7 +605,7 @@ def apply_linestring_ops(self, default, linestrings):
594605
attr[inode] = valreplace
595606
return attr
596607

597-
def apply_polygons(self, polygons, default):
608+
def apply_polygons(self, polygons, default, global_imports=None):
598609
"""Partition the grid with the given polygons.
599610
Each node (not element) will be assigned with an integer ID
600611
which is the index of the polygons.
@@ -607,6 +618,9 @@ def apply_polygons(self, polygons, default):
607618
polygons: list
608619
a list of polygon dict (from YAML most of time)
609620
621+
global_imports: list, optional
622+
list of module paths available to all polygon expressions
623+
610624
Returns
611625
-------
612626
numpy.ndarray
@@ -625,7 +639,7 @@ def apply_polygons(self, polygons, default):
625639
for polygon in polygons:
626640
name = polygon.get("name")
627641
imports_str = polygon.get("imports")
628-
imports = ["numpy"]
642+
imports = ["numpy"] + (global_imports if global_imports else [])
629643
if isinstance(imports_str, str):
630644
imports.extend(imports_str.split())
631645
vertices = np.array(polygon.get("vertices"))
@@ -697,16 +711,23 @@ def _evaluate_in_polygon(self, expr, polygon, globals):
697711
mesh = globals["mesh"]
698712
imports = globals["imports"]
699713
mod_names = {}
700-
# if imports is not None:
701714
for imp in imports:
702715
iname = imp.split(".")[-1]
703-
# ipack = '.'.join(imp.split('.')[0:-1])
704716
try:
705-
# if len(ipack) > 0 else importlib.import_module(iname)
706717
mod = importlib.import_module(imp)
707718
mod_names[iname] = mod
708-
except:
709-
print("Failed to import {}".format(imp))
719+
except (ModuleNotFoundError, ImportError):
720+
# Support "from parent import attr" style, e.g.
721+
# "schimpy.sav_density_raster.sav_density" -> sav_density function
722+
parent = ".".join(imp.split(".")[:-1])
723+
if parent:
724+
try:
725+
parent_mod = importlib.import_module(parent)
726+
mod_names[iname] = getattr(parent_mod, iname)
727+
except Exception:
728+
print("Failed to import {}".format(imp))
729+
else:
730+
print("Failed to import {}".format(imp))
710731
globals.update(mod_names)
711732

712733
box = np.array(polygon.bounds)[[0, 2, 1, 3]]
@@ -720,15 +741,15 @@ def _evaluate_in_polygon(self, expr, polygon, globals):
720741
vals = eval(expr, globals)
721742
return nodes_in_polygon, vals
722743

723-
def create_node_partitioning(self, gr3_fname, polygons, default, smooth):
744+
def create_node_partitioning(self, gr3_fname, polygons, default, smooth, global_imports=None):
724745
"""Create a gr3 file with node partitioning using
725746
polygons in the polygon file.
726747
gr3_fname = output gr3 file name
727748
polygons = polygons
728749
"""
729750
from schimpy.laplace_smooth_data import laplace_smooth_data2
730751

731-
attr = self.apply_polygons(polygons, default)
752+
attr = self.apply_polygons(polygons, default, global_imports=global_imports)
732753
if smooth is not None:
733754
self._logger.info("Smoothing data. This process can take several minutes")
734755
attr = laplace_smooth_data2(self.mesh, data=attr, **smooth)
@@ -737,7 +758,7 @@ def create_node_partitioning(self, gr3_fname, polygons, default, smooth):
737758
else:
738759
self.write_hgrid(gr3_fname, attr)
739760

740-
def create_prop_partitioning(self, prop_fname, polygons, default):
761+
def create_prop_partitioning(self, prop_fname, polygons, default, global_imports=None):
741762
"""Create a prop file with element partitioning using
742763
polygons in the polygon file.
743764
prop_fname = output prop file name
@@ -747,7 +768,7 @@ def create_prop_partitioning(self, prop_fname, polygons, default):
747768
# # default = polygon_data[option_name]
748769
# polygons = polygon_data['polygons']
749770
# attr = self._partition_nodes_with_polygons(polygons, default)
750-
attr = self.apply_polygons(polygons, default)
771+
attr = self.apply_polygons(polygons, default, global_imports=global_imports)
751772
mesh = self.mesh
752773
elementflags = np.empty((mesh.n_elems(), 1))
753774
elementflags.fill(0.0)

0 commit comments

Comments
 (0)