From 105f42dd2ca6afa47fc84b82a37f8124cac8a7da Mon Sep 17 00:00:00 2001 From: "Leaf, Andrew T" Date: Thu, 8 Aug 2024 15:25:17 -0500 Subject: [PATCH] fix(mf6model.write_input): handle cases of single model or multi-model LGR simulation by working with the simulation-level model dictionary to implement model write functionality that is not included in the simulation-level write_simulation(). Previously, BCs were presumably not getting removed from inactive cells, auxillary header information such as modflow-setup and model version were not getting written to child model package files, and child model SFR packagedata was not getting written to an external file. --- mfsetup/mf6model.py | 108 ++++++++++++++++++++------------------ mfsetup/tests/test_lgr.py | 12 ++++- 2 files changed, 67 insertions(+), 53 deletions(-) diff --git a/mfsetup/mf6model.py b/mfsetup/mf6model.py index c480f17c..8fc9da71 100644 --- a/mfsetup/mf6model.py +++ b/mfsetup/mf6model.py @@ -970,50 +970,64 @@ def write_input(self): """ # prior to writing output # remove any BCs in inactive cells - pckgs = ['chd', 'drn', 'ghb', 'riv', 'wel'] - for pckg in pckgs: - package_instance = getattr(self, pckg.lower(), None) - if package_instance is not None: - external_files = self.cfg[pckg.lower()]['stress_period_data'] - remove_inactive_bcs(package_instance, - external_files=external_files) - if hasattr(self, 'obs'): - for obs_package_instance in self.obs: - remove_inactive_obs(obs_package_instance) - - # write the model with flopy - # but skip the sfr package - # by monkey-patching the write method - def skip_write(**kwargs): - pass - if hasattr(self, 'sfr'): - self.sfr.write = skip_write + # handle cases of single model or multi-model LGR simulation + # by working with the simulation-level model dictionary + for model_name, model in self.simulation.model_dict.items(): + pckgs = ['chd', 'drn', 'ghb', 'riv', 'wel'] + for pckg in pckgs: + package_instance = getattr(model, pckg.lower(), None) + if package_instance is not None: + external_files = model.cfg[pckg.lower()]['stress_period_data'] + remove_inactive_bcs(package_instance, + external_files=external_files) + if hasattr(model, 'obs'): + for obs_package_instance in model.obs: + remove_inactive_obs(obs_package_instance) + + # write the model with flopy + # but skip the sfr package + # by monkey-patching the write method + def skip_write(**kwargs): + pass + if hasattr(model, 'sfr'): + model.sfr.write = skip_write self.simulation.write_simulation() - # write the sfr package with SFRmaker - if 'SFR' in ' '.join(self.get_package_list()): - options = [] - for k, b in self.cfg['sfr']['options'].items(): - if k == 'mover': - if 'mvr' not in self.simulation.package_key_dict: - continue - options.append(k) - if 'save_flows' in options: - budget_fileout = '{}.{}'.format(self.name, - self.cfg['sfr']['budget_fileout']) - stage_fileout = '{}.{}'.format(self.name, - self.cfg['sfr']['stage_fileout']) - options.append('budget fileout {}'.format(budget_fileout)) - options.append('stage fileout {}'.format(stage_fileout)) - if len(self.sfrdata.observations) > 0: - options.append('obs6 filein {}.{}'.format(self.name, - self.cfg['sfr']['obs6_filein_fmt']) - ) - self.sfrdata.write_package(idomain=self.idomain, - version='mf6', - options=options, - external_files_path=self.external_path - ) + # post-flopy write actions + for model_name, model in self.simulation.model_dict.items(): + # write the sfr package with SFRmaker + if 'SFR' in ' '.join(model.get_package_list()): + options = [] + for k, b in model.cfg['sfr']['options'].items(): + if k == 'mover': + if 'mvr' not in model.simulation.package_key_dict: + continue + options.append(k) + if 'save_flows' in options: + budget_fileout = '{}.{}'.format(model_name, + model.cfg['sfr']['budget_fileout']) + stage_fileout = '{}.{}'.format(model_name, + model.cfg['sfr']['stage_fileout']) + options.append('budget fileout {}'.format(budget_fileout)) + options.append('stage fileout {}'.format(stage_fileout)) + if len(model.sfrdata.observations) > 0: + options.append('obs6 filein {}.{}'.format(model_name, + model.cfg['sfr']['obs6_filein_fmt']) + ) + model.sfrdata.write_package(idomain=model.idomain, + version='mf6', + options=options, + external_files_path=model.external_path + ) + # add version info to package file headers + files = [model.namefile] + files += [p.filename for p in model.packagelist] + files += [p[0].filename for k, p in model.simulation.package_key_dict.items()] + for f in files: + add_version_to_fileheader(f, model_info=model.header) + + if not model.cfg['mfsetup_options']['keep_original_arrays']: + shutil.rmtree(model.tmpdir) # label stress periods in tdis file with comments self.perioddata.sort_values(by='per', inplace=True) @@ -1021,15 +1035,7 @@ def skip_write(**kwargs): self.perioddata.start_datetime, self.perioddata.end_datetime ) - # add version info to file headers - files = [self.namefile] - files += [p.filename for p in self.packagelist] - files += [p[0].filename for k, p in self.simulation.package_key_dict.items()] - for f in files: - add_version_to_fileheader(f, model_info=self.header) - - if not self.cfg['mfsetup_options']['keep_original_arrays']: - shutil.rmtree(self.tmpdir) + @staticmethod diff --git a/mfsetup/tests/test_lgr.py b/mfsetup/tests/test_lgr.py index d1bc298b..deda270f 100644 --- a/mfsetup/tests/test_lgr.py +++ b/mfsetup/tests/test_lgr.py @@ -191,6 +191,8 @@ def test_lgr_grid_setup(lgr_grid_spacing, layer_refinement_input, m.modelgrid.write_shapefile(outfolder / 'pleasant_lgr_parent_grid.shp') inset_model.modelgrid.write_shapefile(outfolder / 'pleasant_lgr_inset_grid.shp') + # convert layer_refinement to a list + # (mimicking what is done internally in modflow-setup) if np.isscalar(layer_refinement): layer_refinement = np.array([1] * m.modelgrid.nlay) elif isinstance(layer_refinement, dict): @@ -289,13 +291,19 @@ def test_lgr_parent_bcs_in_lgr_area(pleasant_vertical_lgr_setup_from_yaml): def test_mover_get_sfr_package_connections(pleasant_lgr_setup_from_yaml): m = pleasant_lgr_setup_from_yaml + inset_model = m.inset['plsnt_lgr_inset'] + + # check that packagedata for both models was written to external files + assert Path(m.external_path, f"{m.name}_packagedata.dat").exists() + assert Path(inset_model.external_path, f"{inset_model.name}_packagedata.dat").exists() + parent_reach_data = m.sfrdata.reach_data - inset_reach_data = m.inset['plsnt_lgr_inset'].sfrdata.reach_data + inset_reach_data = inset_model.sfrdata.reach_data to_inset, to_parent = get_sfr_package_connections(parent_reach_data, inset_reach_data, distance_threshold=200) assert len(to_inset) == 0 # verify that the last reaches in the two segments are keys - last_reaches = m.inset['plsnt_lgr_inset'].sfrdata.reach_data.groupby('iseg').last().rno + last_reaches = inset_model.sfrdata.reach_data.groupby('iseg').last().rno assert not any(set(to_parent.keys()).difference(last_reaches)) # verify that the first reaches are headwaters outreaches = set(m.sfrdata.reach_data.outreach)