From fd2571408f25aceb67e14095affd5beb131ffc4a Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Wed, 7 Aug 2024 13:58:50 -0500 Subject: [PATCH 1/2] Fix how yaml model config options are update We treat config options from files (with sections) differently from replacement options provided in a dictionary in code. --- polaris/model_step.py | 20 ++++++++-------- polaris/yaml.py | 54 ++++++++++++++++++++++++++++++++++++++----- 2 files changed, 57 insertions(+), 17 deletions(-) diff --git a/polaris/model_step.py b/polaris/model_step.py index 2819dadc1..0aeeff213 100644 --- a/polaris/model_step.py +++ b/polaris/model_step.py @@ -658,7 +658,12 @@ def _process_yaml(self, quiet): if not self.model_config_data: return - replacements = dict() + if self._yaml is None: + raise ValueError('Trying to update a yaml object but it was ' + 'never created.') + + if not quiet: + print(f'Warning: replacing yaml options in {self.yaml}') for entry in self.model_config_data: if 'namelist' in entry: @@ -666,22 +671,15 @@ def _process_yaml(self, quiet): 'namelist file.') if 'options' in entry: - # this is a dictionary of replacement namelist options + # this is a dictionary of replacement model config options options = entry['options'] + self._yaml.update(options=options, quiet=quiet) else: yaml = PolarisYaml.read(filename=entry['yaml'], package=entry['package'], replacements=entry['replacements']) - options = yaml.configs - replacements.update(options) - - if not quiet: - print(f'Warning: replacing yaml options in {self.yaml}') - if self._yaml is None: - raise ValueError('Trying to update a yaml object but it was ' - 'never created.') - self._yaml = self._yaml.update(replacements, quiet=quiet) + self._yaml.update(configs=yaml.configs, quiet=quiet) def make_graph_file(mesh_filename, graph_filename='graph.info', diff --git a/polaris/yaml.py b/polaris/yaml.py index 8ad18d71a..2d49877c5 100644 --- a/polaris/yaml.py +++ b/polaris/yaml.py @@ -89,23 +89,30 @@ def read(cls, filename, package=None, replacements=None): yaml.configs = configs return yaml - def update(self, configs, quiet=True): + def update(self, configs=None, options=None, quiet=True): """ Add config options from a dictionary Parameters ---------- - configs : dict + configs : dict, optional A nested dictionary of config sections, options and values + options : dict, optional + A flat dictionary of options and values + quiet : bool, optional Whether or not to print the updated config options as they are replaced """ - if self.model in configs: - # we want one layer deeper - configs = configs[self.model] - _update_section(configs, self.configs, quiet) + if configs is not None: + if self.model in configs: + # we want one layer deeper + configs = configs[self.model] + _update_section(configs, self.configs, quiet) + + if options is not None: + _update_options(options, self.configs, quiet) def write(self, filename): """ @@ -275,6 +282,41 @@ def _update_section(src, dst, quiet, print_section=None): dst[name] = src[name] +def _update_options(src, dst, quiet): + """ + Update config options by searching in the destination nested dictionary + """ + for name in src: + success = _update_option(name, src[name], dst, quiet) + if not success: + raise ValueError( + f'Attempting to modify a nonexistent config ' + f'options: {name}') + + +def _update_option(option, value, dst, quiet, print_section=None): + """ + Recursively attempt to find and replace the value of the + given option + """ + for name in dst: + if isinstance(dst[name], (dict, OrderedDict)): + if print_section is not None: + print_subsection = f'{print_section}: {name}' + else: + print_subsection = name + success = _update_option(option, value, dst[name], quiet, + print_subsection) + if success: + return True + elif name == option: + dst[name] = value + if not quiet: + print(f' {print_section}: {name} = {value}') + return True + return False + + def _read_namelist(namelist_template, namelist_filename): """ Read the defaults file """ record_map = _read_namelist_template(namelist_template) From adf207a55a5f091f59d3b418c141ad86ffe79513 Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Wed, 7 Aug 2024 14:04:46 -0500 Subject: [PATCH 2/2] Explicitly convert model config options to float This seems to be necessary because the yaml parser doesn't understand numpy scalars. --- polaris/ocean/tasks/manufactured_solution/forward.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/polaris/ocean/tasks/manufactured_solution/forward.py b/polaris/ocean/tasks/manufactured_solution/forward.py index cd79f3e52..a82d5a375 100644 --- a/polaris/ocean/tasks/manufactured_solution/forward.py +++ b/polaris/ocean/tasks/manufactured_solution/forward.py @@ -76,9 +76,9 @@ def dynamic_model_config(self, at_setup): exact_solution = ExactSolution(self.config) options = {'config_manufactured_solution_amplitude': - exact_solution.eta0, + float(exact_solution.eta0), 'config_manufactured_solution_wavelength_x': - exact_solution.lambda_x, + float(exact_solution.lambda_x), 'config_manufactured_solution_wavelength_y': - exact_solution.lambda_y} + float(exact_solution.lambda_y)} self.add_model_config_options(options)