diff --git a/polaris/ocean/convergence/__init__.py b/polaris/ocean/convergence/__init__.py index a66abb2e4..0a04e50e7 100644 --- a/polaris/ocean/convergence/__init__.py +++ b/polaris/ocean/convergence/__init__.py @@ -23,10 +23,12 @@ def get_resolution_for_task(config, refinement_factor, The resolution corresponding to the refinement_factor and convergence test type """ + if refinement == 'both': + option = 'refinement_factors_space' + else: + option = f'refinement_factors_{refinement}' base_resolution = config.getfloat('convergence', 'base_resolution') - refinement_factors = config.getlist('convergence', - 'refinement_factors', - dtype=float) + refinement_factors = config.getlist('convergence', option, dtype=float) if refinement_factor not in refinement_factors: raise ValueError( @@ -63,10 +65,12 @@ def get_timestep_for_task(config, refinement_factor, test type """ + if refinement == 'both': + option = 'refinement_factors_space' + else: + option = f'refinement_factors_{refinement}' base_resolution = config.getfloat('convergence', 'base_resolution') - refinement_factors = config.getlist('convergence', - 'refinement_factors', - dtype=float) + refinement_factors = config.getlist('convergence', option, dtype=float) if refinement_factor not in refinement_factors: raise ValueError( @@ -93,7 +97,7 @@ def get_timestep_for_task(config, refinement_factor, else: btr_timestep = btr_dt_per_km * resolution if refinement == 'time': - timestep = dt_per_km * refinement_factor * base_resolution + timestep = dt_per_km * refinement_factor * resolution elif refinement == 'space': timestep = dt_per_km * base_resolution else: diff --git a/polaris/ocean/convergence/analysis.py b/polaris/ocean/convergence/analysis.py index f44f719e1..54d3b5ec4 100644 --- a/polaris/ocean/convergence/analysis.py +++ b/polaris/ocean/convergence/analysis.py @@ -5,11 +5,11 @@ import pandas as pd from polaris.mpas import area_for_field, time_index_from_xtime -from polaris.ocean.model import OceanIOStep from polaris.ocean.convergence import ( get_resolution_for_task, get_timestep_for_task, ) +from polaris.ocean.model import OceanIOStep from polaris.viz import use_mplstyle @@ -123,8 +123,11 @@ def setup(self): """ config = self.config dependencies = self.dependencies_dict - refinement_factors = config.getlist('convergence', - 'refinement_factors', + if self.refinement == 'time': + option = 'refinement_factors_time' + else: + option = 'refinement_factors_space' + refinement_factors = config.getlist('convergence', option, dtype=float) for refinement_factor in refinement_factors: base_mesh = dependencies['mesh'][refinement_factor] @@ -175,8 +178,13 @@ def plot_convergence(self, variable_name, title, zidx): field_name=variable_name) error = [] - refinement_factors = config.getlist('convergence', - 'refinement_factors', + if self.refinement == 'time': + option = 'refinement_factors_time' + header = 'time step' + else: + option = 'refinement_factors_space' + header = 'resolution' + refinement_factors = config.getlist('convergence', option, dtype=float) resolutions = list() timesteps = list() @@ -203,7 +211,7 @@ def plot_convergence(self, variable_name, title, zidx): error_array = np.array(error) filename = f'convergence_{variable_name}.csv' data = np.stack((refinement_array, error_array), axis=1) - df = pd.DataFrame(data, columns=['resolution', error_type]) + df = pd.DataFrame(data, columns=[header, error_type]) df.to_csv(f'convergence_{variable_name}.csv', index=False) convergence_failed = False diff --git a/polaris/ocean/convergence/convergence.cfg b/polaris/ocean/convergence/convergence.cfg index f93d368c4..9957bc0d2 100644 --- a/polaris/ocean/convergence/convergence.cfg +++ b/polaris/ocean/convergence/convergence.cfg @@ -4,19 +4,23 @@ convergence_eval_time = 24.0 # Convergence threshold below which a test fails -convergence_thresh = 1.0 +convergence_thresh_space = 1.0 +convergence_thresh_time = 1.0 # Type of error to compute error_type = l2 -# the base mesh resolution (km) to which refinement_factors -# are applied if refinement is 'space' or 'both' on a planar mesh +# the base mesh resolution (km) to which refinement_factors are applied # base resolutions for spherical meshes are given in section spherical_convergence base_resolution = 120 -# refinement factors for a planar mesh applied to either space or time +# refinement factors for a planar mesh applied to either space or both space and time # refinement factors for a spherical mesh given in section spherical_convergence -refinement_factors = 4., 2., 1., 0.5 +refinement_factors_space = 4., 2., 1., 0.5 + +# refinement factors for a planar mesh applied to time with the base timestep +# determined by base_resolution * dt_per_km +refinement_factors_time = 1., 0.5, 0.25 # config options for convergence forward steps [convergence_forward] diff --git a/polaris/ocean/convergence/forward.py b/polaris/ocean/convergence/forward.py index 1ea1c47e2..7a7ecbc2e 100644 --- a/polaris/ocean/convergence/forward.py +++ b/polaris/ocean/convergence/forward.py @@ -132,6 +132,7 @@ def dynamic_model_config(self, at_setup): btr_dt_str = get_time_interval_string(seconds=btr_timestep) s_per_hour = 3600. + section = config['convergence_forward'] run_duration = section.getfloat('run_duration') run_duration_str = get_time_interval_string( seconds=run_duration * s_per_hour) @@ -140,6 +141,7 @@ def dynamic_model_config(self, at_setup): output_interval_str = get_time_interval_string( seconds=output_interval * s_per_hour) + time_integrator = section.get('time_integrator') time_integrator_map = dict([('RK4', 'RungeKutta4')]) model = config.get('ocean', 'model') if model == 'omega': diff --git a/polaris/ocean/convergence/spherical/spherical.cfg b/polaris/ocean/convergence/spherical/spherical.cfg index fd769f8ba..cb4b8d4fd 100644 --- a/polaris/ocean/convergence/spherical/spherical.cfg +++ b/polaris/ocean/convergence/spherical/spherical.cfg @@ -6,11 +6,13 @@ icos_base_resolution = 60. # The factors by which to scale space or time based on icos_base_resolution -icos_refinement_factors = 8., 4., 2., 1. +icos_refinement_factors_space = 8., 4., 2., 1. +icos_refinement_factors_time = 1., 0.5, 0.25 # The base resolution for the quasi-uniform mesh to which the refinement # factors are applied qu_base_resolution = 120. # The factors by which to scale space or time based on qu_base_resolution -qu_refinement_factors = 0.5, 0.75, 1., 1.25, 1.5, 1.75, 2. +qu_refinement_factors_space = 2., 1.75, 1.5, 1.25, 1., 0.75, 0.5 +qu_refinement_factors_time = 1., 0.5, 0.25 diff --git a/polaris/ocean/tasks/cosine_bell/__init__.py b/polaris/ocean/tasks/cosine_bell/__init__.py index 6e26b2498..a26af8d35 100644 --- a/polaris/ocean/tasks/cosine_bell/__init__.py +++ b/polaris/ocean/tasks/cosine_bell/__init__.py @@ -129,15 +129,16 @@ def _setup_steps(self, refinement): else: prefix = 'qu' + if refinement == 'time': + option = 'refinement_factors_time' + else: + option = 'refinement_factors_space' refinement_factors = config.getlist('spherical_convergence', - f'{prefix}_refinement_factors', - dtype=str) + f'{prefix}_{option}', dtype=str) refinement_factors = ', '.join(refinement_factors) - config.set('convergence', 'refinement_factors', - value=refinement_factors) + config.set('convergence', option, value=refinement_factors) refinement_factors = config.getlist('convergence', - 'refinement_factors', - dtype=float) + option, dtype=float) base_resolution = config.getfloat('spherical_convergence', f'{prefix}_base_resolution') diff --git a/polaris/ocean/tasks/geostrophic/__init__.py b/polaris/ocean/tasks/geostrophic/__init__.py index a3b2e941c..f5cb1ca72 100644 --- a/polaris/ocean/tasks/geostrophic/__init__.py +++ b/polaris/ocean/tasks/geostrophic/__init__.py @@ -130,15 +130,16 @@ def _setup_steps(self, refinement): else: prefix = 'qu' + if refinement == 'time': + option = 'refinement_factors_time' + else: + option = 'refinement_factors_space' refinement_factors = config.getlist('spherical_convergence', - f'{prefix}_refinement_factors', - dtype=str) + f'{prefix}_{option}', dtype=str) refinement_factors = ', '.join(refinement_factors) - config.set('convergence', 'refinement_factors', - value=refinement_factors) + config.set('convergence', option, value=refinement_factors) refinement_factors = config.getlist('convergence', - 'refinement_factors', - dtype=float) + option, dtype=float) base_resolution = config.getfloat('spherical_convergence', f'{prefix}_base_resolution') diff --git a/polaris/ocean/tasks/inertial_gravity_wave/__init__.py b/polaris/ocean/tasks/inertial_gravity_wave/__init__.py index 69f9c6a54..f9b2de3a0 100644 --- a/polaris/ocean/tasks/inertial_gravity_wave/__init__.py +++ b/polaris/ocean/tasks/inertial_gravity_wave/__init__.py @@ -66,8 +66,12 @@ def __init__(self, component, config, refinement='both'): analysis_dependencies: Dict[str, Dict[float, Step]] = ( dict(mesh=dict(), init=dict(), forward=dict())) + if refinement == 'time': + option = 'refinement_factors_time' + else: + option = 'refinement_factors_space' refinement_factors = self.config.getlist( - 'convergence', 'refinement_factors', dtype=float) + 'convergence', option, dtype=float) timesteps = list() resolutions = list() for refinement_factor in refinement_factors: @@ -119,3 +123,8 @@ def __init__(self, component, config, refinement='both'): self.add_step(Viz(component=component, resolutions=resolutions, taskdir=self.subdir), run_by_default=False) + config.add_from_package('polaris.ocean.convergence', + 'convergence.cfg') + config.add_from_package( + 'polaris.ocean.tasks.inertial_gravity_wave', + config_filename) diff --git a/polaris/ocean/tasks/inertial_gravity_wave/inertial_gravity_wave.cfg b/polaris/ocean/tasks/inertial_gravity_wave/inertial_gravity_wave.cfg index b690a3de1..aebb28655 100644 --- a/polaris/ocean/tasks/inertial_gravity_wave/inertial_gravity_wave.cfg +++ b/polaris/ocean/tasks/inertial_gravity_wave/inertial_gravity_wave.cfg @@ -62,7 +62,8 @@ error_type = l2 base_resolution = 100. # refinement factors for a planar mesh applied to either space or time -refinement_factors = 2., 1., 0.5, 0.25 +refinement_factors_space = 2., 1., 0.5, 0.25 +refinement_factors_time = 1., 0.5, 0.25 # config options for spherical convergence tests [convergence_forward] diff --git a/polaris/ocean/tasks/manufactured_solution/__init__.py b/polaris/ocean/tasks/manufactured_solution/__init__.py index 7471602c2..f85917698 100644 --- a/polaris/ocean/tasks/manufactured_solution/__init__.py +++ b/polaris/ocean/tasks/manufactured_solution/__init__.py @@ -26,6 +26,11 @@ def add_manufactured_solution_tasks(component): config_filename = 'manufactured_solution.cfg' filepath = f'{basedir}/{config_filename}' config = PolarisConfigParser(filepath=filepath) + config.add_from_package('polaris.ocean.convergence', + 'convergence.cfg') + config.add_from_package( + 'polaris.ocean.tasks.manufactured_solution', + config_filename) for refinement in ['space', 'time', 'both']: component.add_task(ManufacturedSolution(component=component, config=config, @@ -62,8 +67,12 @@ def __init__(self, component, config, refinement='both'): analysis_dependencies: Dict[str, Dict[float, Step]] = ( dict(mesh=dict(), init=dict(), forward=dict())) + if refinement == 'time': + option = 'refinement_factors_time' + else: + option = 'refinement_factors_space' refinement_factors = self.config.getlist( - 'convergence', 'refinement_factors', dtype=float) + 'convergence', option, dtype=float) timesteps = list() resolutions = list() for refinement_factor in refinement_factors: diff --git a/polaris/ocean/tasks/manufactured_solution/manufactured_solution.cfg b/polaris/ocean/tasks/manufactured_solution/manufactured_solution.cfg index be89113c0..a4edc7e49 100644 --- a/polaris/ocean/tasks/manufactured_solution/manufactured_solution.cfg +++ b/polaris/ocean/tasks/manufactured_solution/manufactured_solution.cfg @@ -70,7 +70,8 @@ error_type = l2 base_resolution = 50. # refinement factors for a planar mesh applied to either space or time -refinement_factors = 4., 2., 1., 0.5 +refinement_factors_space = 4., 2., 1., 0.5 +refinement_factors_time = 1., 0.5, 0.25 # config options for spherical convergence tests [convergence_forward] diff --git a/polaris/ocean/tasks/sphere_transport/__init__.py b/polaris/ocean/tasks/sphere_transport/__init__.py index e1aabb1e1..599bedf7b 100644 --- a/polaris/ocean/tasks/sphere_transport/__init__.py +++ b/polaris/ocean/tasks/sphere_transport/__init__.py @@ -128,7 +128,7 @@ def configure(self): # set up the steps again in case a user has provided new resolutions self._setup_steps(self.refinement) - def _setup_steps(self, refinement): + def _setup_steps(self, refinement): # noqa: C901 """ setup steps given resolutions """ case_name = self.case_name icosahedral = self.icosahedral @@ -140,15 +140,16 @@ def _setup_steps(self, refinement): else: prefix = 'qu' + if refinement == 'time': + option = 'refinement_factors_time' + else: + option = 'refinement_factors_space' refinement_factors = config.getlist('spherical_convergence', - f'{prefix}_refinement_factors', - dtype=str) + f'{prefix}_{option}', dtype=str) refinement_factors = ', '.join(refinement_factors) - config.set('convergence', 'refinement_factors', - value=refinement_factors) + config.set('convergence', option, value=refinement_factors) refinement_factors = config.getlist('convergence', - 'refinement_factors', - dtype=float) + option, dtype=float) base_resolution = config.getfloat('spherical_convergence', f'{prefix}_base_resolution')