From 9de03179ec927a148b44e89c5b44ad91e6308b10 Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Thu, 20 Nov 2025 10:31:05 -0600 Subject: [PATCH 01/47] Organize init steps by forcing, sharing as applicable --- polaris/tasks/ocean/single_column/__init__.py | 115 +++++++++++++++++- .../ocean/single_column/cvmix/__init__.py | 22 ++-- .../ocean/single_column/ekman/__init__.py | 8 +- .../ocean/single_column/ideal_age/__init__.py | 14 +-- .../ocean/single_column/inertial/__init__.py | 16 +-- polaris/tasks/ocean/single_column/init.py | 13 +- .../ocean/single_column/single_column.cfg | 2 + 7 files changed, 145 insertions(+), 45 deletions(-) diff --git a/polaris/tasks/ocean/single_column/__init__.py b/polaris/tasks/ocean/single_column/__init__.py index 9999db60f4..580416d55f 100644 --- a/polaris/tasks/ocean/single_column/__init__.py +++ b/polaris/tasks/ocean/single_column/__init__.py @@ -1,7 +1,9 @@ +from polaris.config import PolarisConfigParser as PolarisConfigParser from polaris.tasks.ocean.single_column.cvmix import CVMix as CVMix from polaris.tasks.ocean.single_column.ekman import Ekman as Ekman from polaris.tasks.ocean.single_column.ideal_age import IdealAge as IdealAge from polaris.tasks.ocean.single_column.inertial import Inertial as Inertial +from polaris.tasks.ocean.single_column.init import Init def add_single_column_tasks(component): @@ -11,7 +13,112 @@ def add_single_column_tasks(component): component : polaris.tasks.ocean.Ocean the ocean component that the tasks will be added to """ - component.add_task(Ekman(component=component)) - component.add_task(CVMix(component=component)) - component.add_task(IdealAge(component=component)) - component.add_task(Inertial(component=component)) + group_name = 'single_column' + + forcing = ['wind', 'evap'] + name = 'cvmix' + filepath = f'{component.name}/{group_name}/{name}/{name}.cfg' + config = PolarisConfigParser(filepath=filepath) + config.add_from_package( + 'polaris.tasks.ocean.single_column', f'{group_name}.cfg' + ) + for forcing_name in forcing: + config.add_from_package( + 'polaris.tasks.ocean.single_column', f'{forcing_name}.cfg' + ) + config.add_from_package( + 'polaris.tasks.ocean.single_column', 'stable_stratification.cfg' + ) + init_step = component.get_or_create_shared_step( + step_cls=Init, + subdir=f'{group_name}/{"_".join(forcing)}/init_stable', + config=config, + config_filename=f'{name}.cfg', + ) + for enable_vadv in [True, False]: + component.add_task( + CVMix( + component=component, + config=config, + init=init_step, + indir=f'{group_name}', + enable_vadv=enable_vadv, + ) + ) + + forcing_name = 'wind' + name = 'ekman' + filepath = f'{component.name}/{group_name}/{name}/{name}.cfg' + config = PolarisConfigParser(filepath=filepath) + config.add_from_package( + 'polaris.tasks.ocean.single_column', f'{group_name}.cfg' + ) + config.add_from_package( + 'polaris.tasks.ocean.single_column', f'{forcing_name}.cfg' + ) + init_step = component.get_or_create_shared_step( + step_cls=Init, + subdir=f'{group_name}/{forcing_name}/init', + config=config, + config_filename=f'{name}.cfg', + ) + component.add_task( + Ekman( + component=component, + config=config, + init=init_step, + indir=f'{group_name}', + ) + ) + + name = 'ideal_age' + filepath = f'{component.name}/{group_name}/{name}/{name}.cfg' + config = PolarisConfigParser(filepath=filepath) + config.add_from_package( + 'polaris.tasks.ocean.single_column', f'{group_name}.cfg' + ) + config.add_from_package( + 'polaris.tasks.ocean.single_column', f'{forcing_name}.cfg' + ) + config.add_from_package( + 'polaris.tasks.ocean.single_column', 'stable_stratification.cfg' + ) + init_step = component.get_or_create_shared_step( + step_cls=Init, + subdir=f'{group_name}/{forcing_name}/init_stable', + config=config, + config_filename=f'{name}.cfg', + ) + component.add_task( + IdealAge( + component=component, + init=init_step, + config=config, + indir=f'{group_name}', + ) + ) + + forcing_name = 'no_forcing' + name = 'inertial' + filepath = f'{component.name}/{group_name}/{name}/{name}.cfg' + config = PolarisConfigParser(filepath=filepath) + config.add_from_package( + 'polaris.tasks.ocean.single_column', f'{group_name}.cfg' + ) + config.add_from_package( + 'polaris.tasks.ocean.single_column', 'stable_stratification.cfg' + ) + init_step = component.get_or_create_shared_step( + step_cls=Init, + subdir=f'{group_name}/{forcing_name}/init_stable', + config=config, + config_filename=f'{name}.cfg', + ) + component.add_task( + Inertial( + component=component, + init=init_step, + config=config, + indir=f'{group_name}', + ) + ) diff --git a/polaris/tasks/ocean/single_column/cvmix/__init__.py b/polaris/tasks/ocean/single_column/cvmix/__init__.py index 38349a7113..5198406ffd 100644 --- a/polaris/tasks/ocean/single_column/cvmix/__init__.py +++ b/polaris/tasks/ocean/single_column/cvmix/__init__.py @@ -2,7 +2,6 @@ from polaris import Task from polaris.tasks.ocean.single_column.forward import Forward -from polaris.tasks.ocean.single_column.init import Init from polaris.tasks.ocean.single_column.viz import Viz @@ -12,7 +11,7 @@ class CVMix(Task): then performs a short forward run testing vertical mixing on 1 core. """ - def __init__(self, component): + def __init__(self, component, config, init, indir, enable_vadv=True): """ Create the test case Parameters @@ -21,15 +20,17 @@ def __init__(self, component): The ocean component that this task belongs to """ name = 'cvmix' - subdir = os.path.join('single_column', name) + if not enable_vadv: + subdir = os.path.join(indir, f'{name}_no_vadv') + else: + subdir = os.path.join(indir, name) super().__init__(component=component, name=name, subdir=subdir) + config_filename = 'cvmix.cfg' + self.set_shared_config(config, link=config_filename) self.config.add_from_package( - 'polaris.tasks.ocean.single_column', 'single_column.cfg' + 'polaris.tasks.ocean.single_column.cvmix', config_filename ) - self.config.add_from_package( - 'polaris.tasks.ocean.single_column.cvmix', 'cvmix.cfg' - ) - self.add_step(Init(component=component, indir=self.subdir)) + self.add_step(init, symlink='init') validate_vars = [ 'temperature', @@ -40,16 +41,17 @@ def __init__(self, component): self.add_step( Forward( component=component, - indir=self.subdir, + indir=subdir, ntasks=1, min_tasks=1, openmp_threads=1, validate_vars=validate_vars, task_name=name, + # enable_vadv=enable_vadv, ) ) self.add_step( - Viz(component=component, indir=self.subdir), + Viz(component=component, indir=subdir), run_by_default=False, ) diff --git a/polaris/tasks/ocean/single_column/ekman/__init__.py b/polaris/tasks/ocean/single_column/ekman/__init__.py index 822642265f..17fbf32ad8 100644 --- a/polaris/tasks/ocean/single_column/ekman/__init__.py +++ b/polaris/tasks/ocean/single_column/ekman/__init__.py @@ -3,7 +3,6 @@ from polaris import Task from polaris.tasks.ocean.single_column.ekman.analysis import Analysis from polaris.tasks.ocean.single_column.forward import Forward -from polaris.tasks.ocean.single_column.init import Init from polaris.tasks.ocean.single_column.viz import Viz @@ -13,7 +12,7 @@ class Ekman(Task): then performs a short forward run spinning up an ekman layer on 1 core. """ - def __init__(self, component): + def __init__(self, component, config, init, indir): """ Create the test case Parameters @@ -22,17 +21,18 @@ def __init__(self, component): The ocean component that this task belongs to """ name = 'ekman' - subdir = os.path.join('single_column', name) + subdir = os.path.join(indir, name) super().__init__(component=component, name=name, subdir=subdir) self.config.add_from_package( 'polaris.tasks.ocean.single_column', 'single_column.cfg' ) + self.set_shared_config(config, link='ekman.cfg') self.config.add_from_package( 'polaris.tasks.ocean.single_column.ekman', 'ekman.cfg' ) - self.add_step(Init(component=component, indir=self.subdir)) + self.add_step(init, symlink='init') validate_vars = [ 'temperature', diff --git a/polaris/tasks/ocean/single_column/ideal_age/__init__.py b/polaris/tasks/ocean/single_column/ideal_age/__init__.py index 614eff6da1..6c14f4dd2c 100644 --- a/polaris/tasks/ocean/single_column/ideal_age/__init__.py +++ b/polaris/tasks/ocean/single_column/ideal_age/__init__.py @@ -2,7 +2,6 @@ from polaris import Task as Task from polaris.tasks.ocean.single_column.forward import Forward as Forward -from polaris.tasks.ocean.single_column.init import Init as Init from polaris.tasks.ocean.single_column.viz import Viz as Viz @@ -13,7 +12,7 @@ class IdealAge(Task): on 1 core. """ - def __init__(self, component, ideal_age=True): + def __init__(self, component, config, init, indir, ideal_age=True): """ Create the test case Parameters @@ -22,15 +21,14 @@ def __init__(self, component, ideal_age=True): The ocean component that this task belongs to """ name = 'ideal_age' - subdir = os.path.join('single_column', name) + subdir = os.path.join(indir, name) super().__init__(component=component, name=name, subdir=subdir) + config_filename = 'ideal_age.cfg' + self.set_shared_config(config, link=config_filename) self.config.add_from_package( - 'polaris.tasks.ocean.single_column', 'single_column.cfg' - ) - - self.add_step( - Init(component=component, indir=self.subdir, ideal_age=ideal_age) + 'polaris.tasks.ocean.single_column.ideal_age', config_filename ) + self.add_step(init, symlink='init') validate_vars = ['temperature', 'salinity', 'iAge'] step = Forward( diff --git a/polaris/tasks/ocean/single_column/inertial/__init__.py b/polaris/tasks/ocean/single_column/inertial/__init__.py index fb7bd85ac0..36c0f9f8c4 100644 --- a/polaris/tasks/ocean/single_column/inertial/__init__.py +++ b/polaris/tasks/ocean/single_column/inertial/__init__.py @@ -3,7 +3,6 @@ from polaris import Task from polaris.tasks.ocean.single_column.forward import Forward from polaris.tasks.ocean.single_column.inertial.analysis import Analysis -from polaris.tasks.ocean.single_column.init import Init from polaris.tasks.ocean.single_column.viz import Viz @@ -13,7 +12,7 @@ class Inertial(Task): then performs a short forward run testing inertial oscillations on 1 core. """ - def __init__(self, component): + def __init__(self, component, config, init, indir): """ Create the test case Parameters @@ -22,17 +21,14 @@ def __init__(self, component): The ocean component that this task belongs to """ name = 'inertial' - subdir = os.path.join('single_column', name) + subdir = os.path.join(indir, name) super().__init__(component=component, name=name, subdir=subdir) - - self.config.add_from_package( - 'polaris.tasks.ocean.single_column', 'single_column.cfg' - ) + config_filename = 'inertial.cfg' + self.set_shared_config(config, link=config_filename) self.config.add_from_package( - 'polaris.tasks.ocean.single_column.inertial', 'inertial.cfg' + 'polaris.tasks.ocean.single_column.inertial', config_filename ) - - self.add_step(Init(component=component, indir=self.subdir)) + self.add_step(init, symlink='init') validate_vars = [ 'temperature', diff --git a/polaris/tasks/ocean/single_column/init.py b/polaris/tasks/ocean/single_column/init.py index 4d59e7ac7f..c3c249e4b3 100644 --- a/polaris/tasks/ocean/single_column/init.py +++ b/polaris/tasks/ocean/single_column/init.py @@ -14,7 +14,7 @@ class Init(Step): test cases """ - def __init__(self, component, indir, ideal_age=False): + def __init__(self, component, subdir): """ Create the step @@ -26,12 +26,8 @@ def __init__(self, component, indir, ideal_age=False): indir : str The subdirectory that the task belongs to, that this step will go into a subdirectory of - - ideal_age : bool, optional - Whether the initial condition should include the ideal age tracer """ - super().__init__(component=component, name='init', indir=indir) - self.ideal_age = ideal_age + super().__init__(component=component, name='init', subdir=subdir) for file in [ 'base_mesh.nc', 'culled_mesh.nc', @@ -48,7 +44,6 @@ def run(self): logger = self.logger config = self.config section = config['single_column'] - ideal_age = self.ideal_age resolution = section.getfloat('resolution') nx = section.getint('nx') ny = section.getint('ny') @@ -140,8 +135,8 @@ def run(self): normal_velocity = normal_velocity.transpose('nEdges', 'nVertLevels') normal_velocity = normal_velocity.expand_dims(dim='Time', axis=0) - if ideal_age: - ds['idealAgeTracers'] = xr.zeros_like(x_cell) + # We include this variable in initial conditions even when unused + ds['idealAgeTracers'] = xr.zeros_like(x_cell) ds['temperature'] = temperature ds['salinity'] = salinity diff --git a/polaris/tasks/ocean/single_column/single_column.cfg b/polaris/tasks/ocean/single_column/single_column.cfg index 930d527db3..5eca8e7576 100644 --- a/polaris/tasks/ocean/single_column/single_column.cfg +++ b/polaris/tasks/ocean/single_column/single_column.cfg @@ -71,6 +71,8 @@ meridional_velocity = 0.0 # config options for forcing single column testcases [single_column_forcing] +apply_wind_stress = False + # Piston velocity to control rate of restoring toward temperature_surface_restoring_value temperature_piston_velocity = 4.0e-6 From 9e8d99e6f6f3b4163fe93ab0c9b4fdf44d412d15 Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Mon, 15 Dec 2025 15:10:58 -0600 Subject: [PATCH 02/47] Reorg cfg options for shared init step --- .../tasks/ocean/single_column/cvmix/cvmix.cfg | 36 +------ .../tasks/ocean/single_column/ekman/ekman.cfg | 93 ------------------- polaris/tasks/ocean/single_column/evap.cfg | 18 ++++ .../single_column/ideal_age/ideal_age.cfg | 35 +------ .../ocean/single_column/single_column.cfg | 10 +- .../single_column/stable_stratification.cfg | 12 +++ polaris/tasks/ocean/single_column/wind.cfg | 4 + 7 files changed, 43 insertions(+), 165 deletions(-) create mode 100644 polaris/tasks/ocean/single_column/evap.cfg create mode 100644 polaris/tasks/ocean/single_column/stable_stratification.cfg create mode 100644 polaris/tasks/ocean/single_column/wind.cfg diff --git a/polaris/tasks/ocean/single_column/cvmix/cvmix.cfg b/polaris/tasks/ocean/single_column/cvmix/cvmix.cfg index 0252aced50..7394d9c777 100644 --- a/polaris/tasks/ocean/single_column/cvmix/cvmix.cfg +++ b/polaris/tasks/ocean/single_column/cvmix/cvmix.cfg @@ -1,33 +1,3 @@ -# config options for single column testcases -[single_column] - -# Temperature gradient below the mixed layer -temperature_gradient_interior = 0.01 - -# Depth of the temperature mixed layer -mixed_layer_depth_temperature = 25.0 - -# The salinity below the mixed layer -salinity_difference_across_mixed_layer = 1.0 - -# config options for forcing single column testcases -[single_column_forcing] - -# Net latent heat flux applied when bulk forcing is used. Positive values indicate a net -# input of heat to ocean -latent_heat_flux = -50.0 - -# Net sensible heat flux applied when bulk forcing is used. Positive values indicate a -# net input of heat to ocean -sensible_heat_flux = -25.0 - -# Net solar shortwave heat flux applied when bulk forcing is used. Positive values -# indicate a net input of heat to ocean -shortwave_heat_flux = 200.0 - -# Net surface evaporation when bulk forcing is used. Positive values indicate a net -# input of water to ocean -evaporation_flux = 6.5E-4 - -# Zonal surface wind stress over the domain -wind_stress_zonal = 0.1 +# stable_stratification.cfg +# evap.cfg +# wind.cfg diff --git a/polaris/tasks/ocean/single_column/ekman/ekman.cfg b/polaris/tasks/ocean/single_column/ekman/ekman.cfg index 29aabf77f2..8720d2bb08 100644 --- a/polaris/tasks/ocean/single_column/ekman/ekman.cfg +++ b/polaris/tasks/ocean/single_column/ekman/ekman.cfg @@ -3,99 +3,6 @@ # Bottom depth bottom_depth = 100. -# config options for single column testcases -[single_column] - -# Surface temperature -surface_temperature = 20.0 - -# Temperature gradient in the mixed layer in degC/m -temperature_gradient_mixed_layer = 0.0 - -# The temperature below the mixed layer -temperature_difference_across_mixed_layer = 0.0 - -# Temperature gradient below the mixed layer -temperature_gradient_interior = 0.0 - -# Depth of the temperature mixed layer -mixed_layer_depth_temperature = 0.0 - -# Surface salinity -surface_salinity = 35.0 - -# Salinity gradient in the mixed layer in PSU/m -salinity_gradient_mixed_layer = 0.0 - -# The salinity below the mixed layer -salinity_difference_across_mixed_layer = 0.0 - -# Salinity gradient below the mixed layer -salinity_gradient_interior = 0.0 - -# Depth of the salinity mixed layer -mixed_layer_depth_salinity = 0.0 - -# coriolis parameter -coriolis_parameter = 1.0e-4 - -# config options for forcing single column testcases -[single_column_forcing] - -# Piston velocity to control rate of restoring toward temperature_surface_restoring_value -temperature_piston_velocity = 0.0 - -# Piston velocity to control rate of restoring toward salinity_surface_restoring_value -salinity_piston_velocity = 0.0 - -# Rate at which temperature is restored toward the initial condition -temperature_interior_restoring_rate = 0.0 - -# Rate at which salinity is restored toward the initial condition -salinity_interior_restoring_rate = 0.0 - -# Net latent heat flux applied when bulk forcing is used. Positive values indicate a net -# input of heat to ocean -latent_heat_flux = 0.0 - -# Net sensible heat flux applied when bulk forcing is used. Positive values indicate a -# net input of heat to ocean -sensible_heat_flux = 0.0 - -# Net solar shortwave heat flux applied when bulk forcing is used. Positive values -# indicate a net input of heat to ocean -shortwave_heat_flux = 0.0 - -# Net surface evaporation when bulk forcing is used. Positive values indicate a net -# input of water to ocean -evaporation_flux = 0.0 - -# Net surface rain flux when bulk forcing is used. Positive values indicate a net input -# of water to ocean -rain_flux = 0.0 - -# Net surface river runoff flux when bulk forcing is used. Positive values indicate a net -#flux of water to ocean -river_runoff_flux = 0.0 - -# Net surface subglacial runoff flux when bulk forcing is used. Positive values indicate a net -#flux of water to ocean -subglacial_runoff_flux = 0.0 - -# Net surface ice runoff flux when bulk forcing is used. Positive values indicate a net -#flux of water to ocean -ice_runoff_flux = 0.0 - -# Net iceberg freshwater flux when bulk forcing is used. Positive values indicate a net -#flux of water to ocean -iceberg_flux = 0.0 - -# Zonal surface wind stress over the domain -wind_stress_zonal = 0.1 - -# Meridional surface wind stress over the domain -wind_stress_meridional = 0.0 - [single_column_ekman] # Constant vertical eddy diffusivity diff --git a/polaris/tasks/ocean/single_column/evap.cfg b/polaris/tasks/ocean/single_column/evap.cfg new file mode 100644 index 0000000000..688bae9293 --- /dev/null +++ b/polaris/tasks/ocean/single_column/evap.cfg @@ -0,0 +1,18 @@ +# config options for forcing single column testcases +[single_column_forcing] + +# Net latent heat flux applied when bulk forcing is used. Positive values indicate a net +# input of heat to ocean +latent_heat_flux = -50.0 + +# Net sensible heat flux applied when bulk forcing is used. Positive values indicate a +# net input of heat to ocean +sensible_heat_flux = -25.0 + +# Net solar shortwave heat flux applied when bulk forcing is used. Positive values +# indicate a net input of heat to ocean +shortwave_heat_flux = 200.0 + +# Net surface evaporation when bulk forcing is used. Positive values indicate a net +# input of water to ocean +evaporation_flux = 6.5E-4 diff --git a/polaris/tasks/ocean/single_column/ideal_age/ideal_age.cfg b/polaris/tasks/ocean/single_column/ideal_age/ideal_age.cfg index 0252aced50..54db266069 100644 --- a/polaris/tasks/ocean/single_column/ideal_age/ideal_age.cfg +++ b/polaris/tasks/ocean/single_column/ideal_age/ideal_age.cfg @@ -1,33 +1,2 @@ -# config options for single column testcases -[single_column] - -# Temperature gradient below the mixed layer -temperature_gradient_interior = 0.01 - -# Depth of the temperature mixed layer -mixed_layer_depth_temperature = 25.0 - -# The salinity below the mixed layer -salinity_difference_across_mixed_layer = 1.0 - -# config options for forcing single column testcases -[single_column_forcing] - -# Net latent heat flux applied when bulk forcing is used. Positive values indicate a net -# input of heat to ocean -latent_heat_flux = -50.0 - -# Net sensible heat flux applied when bulk forcing is used. Positive values indicate a -# net input of heat to ocean -sensible_heat_flux = -25.0 - -# Net solar shortwave heat flux applied when bulk forcing is used. Positive values -# indicate a net input of heat to ocean -shortwave_heat_flux = 200.0 - -# Net surface evaporation when bulk forcing is used. Positive values indicate a net -# input of water to ocean -evaporation_flux = 6.5E-4 - -# Zonal surface wind stress over the domain -wind_stress_zonal = 0.1 +# stable_stratification.cfg +# wind.cfg diff --git a/polaris/tasks/ocean/single_column/single_column.cfg b/polaris/tasks/ocean/single_column/single_column.cfg index 5eca8e7576..d034b42fb6 100644 --- a/polaris/tasks/ocean/single_column/single_column.cfg +++ b/polaris/tasks/ocean/single_column/single_column.cfg @@ -71,13 +71,11 @@ meridional_velocity = 0.0 # config options for forcing single column testcases [single_column_forcing] -apply_wind_stress = False - # Piston velocity to control rate of restoring toward temperature_surface_restoring_value -temperature_piston_velocity = 4.0e-6 +temperature_piston_velocity = 0.0 # Piston velocity to control rate of restoring toward salinity_surface_restoring_value -salinity_piston_velocity = 4.0e-6 +salinity_piston_velocity = 0.0 # Temperature to restore towards when surface restoring is turned on temperature_surface_restoring_value = ${single_column:surface_temperature} @@ -86,10 +84,10 @@ temperature_surface_restoring_value = ${single_column:surface_temperature} salinity_surface_restoring_value = ${single_column:surface_salinity} # Rate at which temperature is restored toward the initial condition -temperature_interior_restoring_rate = 1.0e-6 +temperature_interior_restoring_rate = 0.0 # Rate at which salinity is restored toward the initial condition -salinity_interior_restoring_rate = 1.0e-6 +salinity_interior_restoring_rate = 0.0 # Net latent heat flux applied when bulk forcing is used. Positive values indicate a net # input of heat to ocean diff --git a/polaris/tasks/ocean/single_column/stable_stratification.cfg b/polaris/tasks/ocean/single_column/stable_stratification.cfg new file mode 100644 index 0000000000..9f749bd918 --- /dev/null +++ b/polaris/tasks/ocean/single_column/stable_stratification.cfg @@ -0,0 +1,12 @@ + +# config options for single column testcases +[single_column] + +# Temperature gradient below the mixed layer +temperature_gradient_interior = 0.01 + +# Depth of the temperature mixed layer +mixed_layer_depth_temperature = 25.0 + +# The salinity below the mixed layer +salinity_difference_across_mixed_layer = 1.0 diff --git a/polaris/tasks/ocean/single_column/wind.cfg b/polaris/tasks/ocean/single_column/wind.cfg new file mode 100644 index 0000000000..9daa95b973 --- /dev/null +++ b/polaris/tasks/ocean/single_column/wind.cfg @@ -0,0 +1,4 @@ +[single_column_forcing] + +# Zonal surface wind stress over the domain +wind_stress_zonal = 0.1 From b49b9fb1e7005ffeb2b3ee7a3a09a7445a569d1c Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Thu, 20 Nov 2025 10:32:48 -0600 Subject: [PATCH 03/47] Add option to turn vadv off for single column tests --- polaris/tasks/ocean/single_column/cvmix/__init__.py | 2 +- polaris/tasks/ocean/single_column/forward.py | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/polaris/tasks/ocean/single_column/cvmix/__init__.py b/polaris/tasks/ocean/single_column/cvmix/__init__.py index 5198406ffd..43411a55e5 100644 --- a/polaris/tasks/ocean/single_column/cvmix/__init__.py +++ b/polaris/tasks/ocean/single_column/cvmix/__init__.py @@ -47,7 +47,7 @@ def __init__(self, component, config, init, indir, enable_vadv=True): openmp_threads=1, validate_vars=validate_vars, task_name=name, - # enable_vadv=enable_vadv, + enable_vadv=enable_vadv, ) ) diff --git a/polaris/tasks/ocean/single_column/forward.py b/polaris/tasks/ocean/single_column/forward.py index ed9c992aea..1cb40ecea7 100644 --- a/polaris/tasks/ocean/single_column/forward.py +++ b/polaris/tasks/ocean/single_column/forward.py @@ -24,6 +24,7 @@ def __init__( openmp_threads=1, validate_vars=None, task_name='', + enable_vadv=True, ): """ Create a new test case @@ -93,6 +94,8 @@ def __init__( self.task_name = task_name + self.enable_vadv = enable_vadv + def dynamic_model_config(self, at_setup): if self.task_name == 'ekman': nu = self.config.getfloat( @@ -102,3 +105,12 @@ def dynamic_model_config(self, at_setup): options={'config_cvmix_background_viscosity': nu}, config_model='mpas-ocean', ) + if not self.enable_vadv: + self.add_model_config_options( + options={ + 'config_vert_coord_movement': 'impermeable_interfaces', + 'config_disable_vel_vadv': True, + 'config_disable_tr_adv': True, + }, + config_model='mpas-ocean', + ) From 2d4f51988b6db017fdc939f64037d8544ce6b6c7 Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Mon, 15 Dec 2025 13:21:19 -0600 Subject: [PATCH 04/47] Namelist changes in accordance with omega pr#310 --- polaris/ocean/model/mpaso_to_omega.yaml | 21 +++++++++++++++++++++ polaris/suites/ocean/mpaso_pr.txt | 1 + 2 files changed, 22 insertions(+) diff --git a/polaris/ocean/model/mpaso_to_omega.yaml b/polaris/ocean/model/mpaso_to_omega.yaml index 15b5882835..359c02af47 100644 --- a/polaris/ocean/model/mpaso_to_omega.yaml +++ b/polaris/ocean/model/mpaso_to_omega.yaml @@ -114,3 +114,24 @@ config: config_eos_linear_alpha: DRhoDT config_eos_linear_beta: DRhoDS config_eos_linear_densityref: RhoT0S0 + +- section: + cvmix: [VertMix, Background] + options: + config_cvmix_background_diffusion: Diffusivity + config_cvmix_background_viscosity: Viscosity + +- section: + cvmix: [VertMix, Convective] + options: + config_use_cvmix_convection: Enable + config_cvmix_convective_diffusion: Diffusivity + config_cvmix_convective_triggerBVF: TriggerBVF + +- section: + cvmix: [VertMix, Shear] + options: + config_use_cvmix_shear: Enable + config_cvmix_shear_PP_nu_zero: NuZero + config_cvmix_shear_PP_alpha: Alpha + config_cvmix_shear_PP_exp: Exponent diff --git a/polaris/suites/ocean/mpaso_pr.txt b/polaris/suites/ocean/mpaso_pr.txt index 0520e8903c..f7821c9504 100644 --- a/polaris/suites/ocean/mpaso_pr.txt +++ b/polaris/suites/ocean/mpaso_pr.txt @@ -11,6 +11,7 @@ ocean/planar/internal_wave/vlr/default # ocean/planar/merry_go_round/default ocean/planar/overflow/default ocean/single_column/cvmix +ocean/single_column/cvmix_no_vadv ocean/single_column/ekman ocean/single_column/ideal_age ocean/single_column/inertial From 681105b983325d487988fbdc9c0d3c28cb82c463 Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Mon, 15 Dec 2025 15:59:45 -0600 Subject: [PATCH 05/47] Include restoring parameters in cfg and turn restoring on for individual single column tests, not the group --- polaris/tasks/ocean/single_column/cvmix/forward.yaml | 4 ++++ polaris/tasks/ocean/single_column/forward.yaml | 4 ---- polaris/tasks/ocean/single_column/ideal_age/forward.yaml | 4 ++++ polaris/tasks/ocean/single_column/single_column.cfg | 8 ++++---- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/polaris/tasks/ocean/single_column/cvmix/forward.yaml b/polaris/tasks/ocean/single_column/cvmix/forward.yaml index f2a7bd5282..51336d619d 100644 --- a/polaris/tasks/ocean/single_column/cvmix/forward.yaml +++ b/polaris/tasks/ocean/single_column/cvmix/forward.yaml @@ -6,6 +6,10 @@ mpas-ocean: config_mom_del4: 2.0e14 frazil_ice: config_use_frazil_ice_formation: true + tracer_forcing_activeTracers: + config_use_activeTracers_surface_bulk_forcing: true + config_use_activeTracers_surface_restoring: true + config_use_activeTracers_interior_restoring: true cvmix: config_use_cvmix_convection: true config_use_cvmix_shear: true diff --git a/polaris/tasks/ocean/single_column/forward.yaml b/polaris/tasks/ocean/single_column/forward.yaml index bdaab85fb9..8d349a8394 100644 --- a/polaris/tasks/ocean/single_column/forward.yaml +++ b/polaris/tasks/ocean/single_column/forward.yaml @@ -9,10 +9,6 @@ mpas-ocean: config_btr_dt: 0000_00:00:30 forcing: config_use_bulk_wind_stress: true - tracer_forcing_activeTracers: - config_use_activeTracers_surface_bulk_forcing: true - config_use_activeTracers_surface_restoring: true - config_use_activeTracers_interior_restoring: true streams: mesh: filename_template: initial_state.nc diff --git a/polaris/tasks/ocean/single_column/ideal_age/forward.yaml b/polaris/tasks/ocean/single_column/ideal_age/forward.yaml index 487efcc5a1..62e8dbcdf5 100644 --- a/polaris/tasks/ocean/single_column/ideal_age/forward.yaml +++ b/polaris/tasks/ocean/single_column/ideal_age/forward.yaml @@ -1,6 +1,10 @@ mpas-ocean: time_management: config_run_duration: 0010_00:00:00 + tracer_forcing_activeTracers: + config_use_activeTracers_surface_bulk_forcing: true + config_use_activeTracers_surface_restoring: true + config_use_activeTracers_interior_restoring: true tracer_forcing_idealAgeTracers: config_use_idealAgeTracers: true config_use_idealAgeTracers_idealAge_forcing: true diff --git a/polaris/tasks/ocean/single_column/single_column.cfg b/polaris/tasks/ocean/single_column/single_column.cfg index d034b42fb6..930d527db3 100644 --- a/polaris/tasks/ocean/single_column/single_column.cfg +++ b/polaris/tasks/ocean/single_column/single_column.cfg @@ -72,10 +72,10 @@ meridional_velocity = 0.0 [single_column_forcing] # Piston velocity to control rate of restoring toward temperature_surface_restoring_value -temperature_piston_velocity = 0.0 +temperature_piston_velocity = 4.0e-6 # Piston velocity to control rate of restoring toward salinity_surface_restoring_value -salinity_piston_velocity = 0.0 +salinity_piston_velocity = 4.0e-6 # Temperature to restore towards when surface restoring is turned on temperature_surface_restoring_value = ${single_column:surface_temperature} @@ -84,10 +84,10 @@ temperature_surface_restoring_value = ${single_column:surface_temperature} salinity_surface_restoring_value = ${single_column:surface_salinity} # Rate at which temperature is restored toward the initial condition -temperature_interior_restoring_rate = 0.0 +temperature_interior_restoring_rate = 1.0e-6 # Rate at which salinity is restored toward the initial condition -salinity_interior_restoring_rate = 0.0 +salinity_interior_restoring_rate = 1.0e-6 # Net latent heat flux applied when bulk forcing is used. Positive values indicate a net # input of heat to ocean From 6d3b409dca2f7bea1059bb3a51e71b9ff0fc1c9c Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Tue, 16 Dec 2025 18:07:04 -0600 Subject: [PATCH 06/47] Update single_column docs --- docs/users_guide/ocean/tasks/single_column.md | 67 ++++++++++--------- 1 file changed, 37 insertions(+), 30 deletions(-) diff --git a/docs/users_guide/ocean/tasks/single_column.md b/docs/users_guide/ocean/tasks/single_column.md index 9d656dacd3..9f6b2939f6 100644 --- a/docs/users_guide/ocean/tasks/single_column.md +++ b/docs/users_guide/ocean/tasks/single_column.md @@ -14,7 +14,7 @@ the vertical dynamics of the ocean model only. The test cases are: ## suppported models -These tasks support only MPAS-Ocean. +These tasks support MPAS-Ocean and Omega. ## mesh @@ -58,30 +58,8 @@ min_pc_fraction = 0.1 ## initial conditions -The temperature and salinity profiles are defined using the following equations: - -$$ -\Phi(z) = \begin{cases} - \Phi_0 &\text{ if } z = z[0]\\ - \Phi_0 + {d\Phi/dz}_{ML} z & - \text{ if } z > z_{MLD}\\ - (\Phi_0 + {\Delta\Phi}_{ML}) + {d\Phi/dz}_{int} (z - z_{MLD}) & - \text{ if } z \le z_{MLD} -\end{cases} -$$ - -where $\Phi_0 = $`surface_X`, ${d\Phi/dz}_{ML} = $`X_gradient_mixed_layer`, -$z_{MLD} = -$`mixed_layer_depth_X`, ${\Delta\Phi}_{ML} = $ -`X_difference_across_mixed_layer`, and ${d\Phi/dz}_{int} = $ -`X_gradient_interior`. `X` in the config options above is either `temperature` -or `salinity`. - -The initial velocity is vertically uniform and given by -`single_column:zonal_velocity` and `single_column:meridional_velocity`, which -are 0 by default (at rest). - -The Coriolis parameter is spatially constant and set equal to -`coriolis_parameter`. +The initial conditions are either stably stratified or uniform. See each task +below. ### forcing @@ -245,8 +223,35 @@ See {ref}`ocean-single-column`. See {ref}`ocean-single-column`. +(ocean-single-column-stable)= + ### initial conditions +The temperature and salinity profiles are defined using the following equations: + +$$ +\Phi(z) = \begin{cases} + \Phi_0 &\text{ if } z = z[0]\\ + \Phi_0 + {d\Phi/dz}_{ML} z & + \text{ if } z > z_{MLD}\\ + (\Phi_0 + {\Delta\Phi}_{ML}) + {d\Phi/dz}_{int} (z - z_{MLD}) & + \text{ if } z \le z_{MLD} +\end{cases} +$$ + +where $\Phi_0 = $`surface_X`, ${d\Phi/dz}_{ML} = $`X_gradient_mixed_layer`, +$z_{MLD} = -$`mixed_layer_depth_X`, ${\Delta\Phi}_{ML} = $ +`X_difference_across_mixed_layer`, and ${d\Phi/dz}_{int} = $ +`X_gradient_interior`. `X` in the config options above is either `temperature` +or `salinity`. + +The initial velocity is vertically uniform and given by +`single_column:zonal_velocity` and `single_column:meridional_velocity`, which +are 0 by default (at rest). + +The Coriolis parameter is spatially constant and set equal to +`coriolis_parameter`. + These config options overwrite those in {ref}`ocean-single-column`: ```cfg @@ -263,7 +268,7 @@ mixed_layer_depth_temperature = 25.0 salinity_difference_across_mixed_layer = 1.0 ``` -The rest of the config options are given in {ref}`ocean-single-column`. +(ocean-single-column-wind-evap)= ### forcing @@ -301,8 +306,7 @@ days. ### config options -See {ref}`ocean-single-column`. Currently, config options are only given in the -shared framework. +See {ref}`ocean-single-column-wind-evap` and {ref}`ocean-single-column-stable`. ### cores @@ -345,7 +349,8 @@ The rest of the vertical grid features follow {ref}`ocean-single-column`. ### initial conditions The temperature and salinity are constant and the flow is at rest. -See {ref}`ocean-single-column`. + +(ocean-single-column-wind)= ### forcing @@ -378,7 +383,8 @@ viscosity: vertical_viscosity = 1.e-3 ``` -All other config options derive from {ref}`ocean-single-column`. +All other config options derive from {ref}`ocean-single-column` and +{ref}`ocean-single-column-wind`. ### cores @@ -412,6 +418,7 @@ See {ref}`ocean-single-column`. ### initial conditions `idealAgeTracers` is initialized as zero seconds throughout the water column. +See {ref}`ocean-single-column-stable`. ### forcing From 27afbb406e4187bfefa5869fc52f54497366aeaa Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Tue, 16 Dec 2025 18:49:33 -0600 Subject: [PATCH 07/47] Add no_vadv as a forward step --- polaris/tasks/ocean/single_column/__init__.py | 16 ++++---- .../ocean/single_column/cvmix/__init__.py | 39 +++++++++---------- polaris/tasks/ocean/single_column/viz.py | 16 +++++++- 3 files changed, 41 insertions(+), 30 deletions(-) diff --git a/polaris/tasks/ocean/single_column/__init__.py b/polaris/tasks/ocean/single_column/__init__.py index 580416d55f..518eb0dab7 100644 --- a/polaris/tasks/ocean/single_column/__init__.py +++ b/polaris/tasks/ocean/single_column/__init__.py @@ -35,16 +35,14 @@ def add_single_column_tasks(component): config=config, config_filename=f'{name}.cfg', ) - for enable_vadv in [True, False]: - component.add_task( - CVMix( - component=component, - config=config, - init=init_step, - indir=f'{group_name}', - enable_vadv=enable_vadv, - ) + component.add_task( + CVMix( + component=component, + config=config, + init=init_step, + indir=f'{group_name}', ) + ) forcing_name = 'wind' name = 'ekman' diff --git a/polaris/tasks/ocean/single_column/cvmix/__init__.py b/polaris/tasks/ocean/single_column/cvmix/__init__.py index 43411a55e5..d5d48de246 100644 --- a/polaris/tasks/ocean/single_column/cvmix/__init__.py +++ b/polaris/tasks/ocean/single_column/cvmix/__init__.py @@ -1,5 +1,3 @@ -import os - from polaris import Task from polaris.tasks.ocean.single_column.forward import Forward from polaris.tasks.ocean.single_column.viz import Viz @@ -11,7 +9,7 @@ class CVMix(Task): then performs a short forward run testing vertical mixing on 1 core. """ - def __init__(self, component, config, init, indir, enable_vadv=True): + def __init__(self, component, config, init, indir): """ Create the test case Parameters @@ -20,11 +18,7 @@ def __init__(self, component, config, init, indir, enable_vadv=True): The ocean component that this task belongs to """ name = 'cvmix' - if not enable_vadv: - subdir = os.path.join(indir, f'{name}_no_vadv') - else: - subdir = os.path.join(indir, name) - super().__init__(component=component, name=name, subdir=subdir) + super().__init__(component=component, name=name, indir=indir) config_filename = 'cvmix.cfg' self.set_shared_config(config, link=config_filename) self.config.add_from_package( @@ -38,20 +32,25 @@ def __init__(self, component, config, init, indir, enable_vadv=True): 'layerThickness', 'normalVelocity', ] - self.add_step( - Forward( - component=component, - indir=subdir, - ntasks=1, - min_tasks=1, - openmp_threads=1, - validate_vars=validate_vars, - task_name=name, - enable_vadv=enable_vadv, + for enable_vadv in [True, False]: + self.add_step( + Forward( + component=component, + indir=self.subdir, + ntasks=1, + min_tasks=1, + openmp_threads=1, + validate_vars=validate_vars, + task_name=name, + enable_vadv=enable_vadv, + ) ) - ) self.add_step( - Viz(component=component, indir=subdir), + Viz( + component=component, + indir=self.subdir, + comparison_path=f'{self.subdir}/forward_no_vadv', + ), run_by_default=False, ) diff --git a/polaris/tasks/ocean/single_column/viz.py b/polaris/tasks/ocean/single_column/viz.py index 9d02337290..5fcf165026 100644 --- a/polaris/tasks/ocean/single_column/viz.py +++ b/polaris/tasks/ocean/single_column/viz.py @@ -11,7 +11,9 @@ class Viz(Step): A step for plotting the results of a single-column test """ - def __init__(self, component, indir, ideal_age=False): + def __init__( + self, component, indir, ideal_age=False, comparison_path=None + ): """ Create the step @@ -29,12 +31,17 @@ def __init__(self, component, indir, ideal_age=False): """ super().__init__(component=component, name='viz', indir=indir) self.ideal_age = ideal_age + self.comparison_path = comparison_path self.add_input_file( filename='initial_state.nc', target='../init/initial_state.nc' ) self.add_input_file( filename='output.nc', target='../forward/output.nc' ) + if comparison_path is not None: + self.add_input_file( + filename='comparison.nc', target=f'{comparison_path}/output.nc' + ) def run(self): """ @@ -43,6 +50,8 @@ def run(self): use_mplstyle() ideal_age = self.ideal_age ds = xr.load_dataset('output.nc') + if self.comparison_path is not None: + ds_comp = xr.load_dataset('comparison.nc') t_days = ds.daysSinceStartOfSim.values t = t_days.astype('timedelta64[ns]') t = t / np.timedelta64(1, 'D') @@ -64,10 +73,15 @@ def run(self): var = ds[field_name].mean(dim='nCells') var_init = var.isel(Time=0) var_final = var.isel(Time=t_index) + if self.comparison_path is not None: + var_comp = ds_comp[field_name].mean(dim='nCells') + var_comp = var_comp.isel(Time=t_index) plt.figure(figsize=(3, 5)) ax = plt.subplot(111) ax.plot(var_init, z_mid_init, '--k', label='initial') ax.plot(var_final, z_mid_final, '-k', label='final') + if self.comparison_path is not None: + ax.plot(var_comp, z_mid_final, '-r', label='comparison') ax.set_xlabel(f'{field_name} ({field_units})') ax.set_ylabel('z (m)') ax.legend() From 24342f286c5894d78768edd50d348f755fd35f48 Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Tue, 16 Dec 2025 18:51:09 -0600 Subject: [PATCH 08/47] Add omega support --- .../ocean/single_column/cvmix/forward.yaml | 17 +++++--- .../ocean/single_column/ekman/forward.yaml | 17 +++++--- polaris/tasks/ocean/single_column/forward.py | 15 ++++++- .../tasks/ocean/single_column/forward.yaml | 43 +++++++++++++++---- .../ocean/single_column/inertial/forward.yaml | 4 +- polaris/tasks/ocean/single_column/init.py | 6 +-- 6 files changed, 73 insertions(+), 29 deletions(-) diff --git a/polaris/tasks/ocean/single_column/cvmix/forward.yaml b/polaris/tasks/ocean/single_column/cvmix/forward.yaml index 51336d619d..17fa423635 100644 --- a/polaris/tasks/ocean/single_column/cvmix/forward.yaml +++ b/polaris/tasks/ocean/single_column/cvmix/forward.yaml @@ -1,9 +1,18 @@ -mpas-ocean: +ocean: time_management: config_run_duration: 0010_00:00:00 hmix_del4: config_use_mom_del4: true config_mom_del4: 2.0e14 + cvmix: + config_use_cvmix_convection: true + config_use_cvmix_shear: true + eos: + config_eos_type: linear + eos_linear: + config_eos_linear_beta: 0.01 + +mpas-ocean: frazil_ice: config_use_frazil_ice_formation: true tracer_forcing_activeTracers: @@ -11,15 +20,9 @@ mpas-ocean: config_use_activeTracers_surface_restoring: true config_use_activeTracers_interior_restoring: true cvmix: - config_use_cvmix_convection: true - config_use_cvmix_shear: true config_cvmix_shear_mixing_scheme: KPP config_use_cvmix_kpp: true config_cvmix_kpp_matching: MatchBoth config_cvmix_kpp_interpolationOMLType: cubic - eos: - config_eos_type: linear - eos_linear: - config_eos_linear_beta: 0.01 streams: KPP_testing: {} diff --git a/polaris/tasks/ocean/single_column/ekman/forward.yaml b/polaris/tasks/ocean/single_column/ekman/forward.yaml index 85740192a9..51aadb9789 100644 --- a/polaris/tasks/ocean/single_column/ekman/forward.yaml +++ b/polaris/tasks/ocean/single_column/ekman/forward.yaml @@ -1,24 +1,27 @@ -mpas-ocean: +ocean: time_management: config_run_duration: 0005_00:00:00 hmix_del4: config_use_mom_del4: false - frazil_ice: - config_use_frazil_ice_formation: false - bottom_drag: - config_implicit_constant_bottom_drag_coeff: 0.0 cvmix: - config_cvmix_background_scheme: constant config_cvmix_background_diffusion: 0.0 config_use_cvmix_convection: false config_use_cvmix_shear: false - config_use_cvmix_kpp: false eos: config_eos_type: linear eos_linear: config_eos_linear_beta: 0.01 forcing: config_use_bulk_wind_stress: true + +mpas-ocean: + bottom_drag: + config_implicit_constant_bottom_drag_coeff: 0.0 + frazil_ice: + config_use_frazil_ice_formation: false + cvmix: + config_cvmix_background_scheme: constant + config_use_cvmix_kpp: false tracer_forcing_activeTracers: config_use_activeTracers_surface_bulk_forcing: false config_use_activeTracers_surface_restoring: false diff --git a/polaris/tasks/ocean/single_column/forward.py b/polaris/tasks/ocean/single_column/forward.py index 1cb40ecea7..71d3f41799 100644 --- a/polaris/tasks/ocean/single_column/forward.py +++ b/polaris/tasks/ocean/single_column/forward.py @@ -63,6 +63,8 @@ def __init__( task_name : str, optional the name of the test case """ + if not enable_vadv: + name = f'{name}_no_vadv' super().__init__( component=component, name=name, @@ -76,9 +78,8 @@ def __init__( self.add_yaml_file('polaris.ocean.config', 'output.yaml') self.add_input_file( - filename='initial_state.nc', target='../init/initial_state.nc' + filename='init.nc', target='../init/initial_state.nc' ) - self.add_input_file(filename='forcing.nc', target='../init/forcing.nc') self.add_input_file( filename='graph.info', target='../init/culled_graph.info' ) @@ -96,6 +97,16 @@ def __init__( self.enable_vadv = enable_vadv + def setup(self): + """ + TEMP: symlink initial condition to name hard-coded in Omega + """ + super().setup() + model = self.config.get('ocean', 'model') + # TODO: remove as soon as Omega no longer hard-codes this file + if model == 'omega': + self.add_input_file(filename='OmegaMesh.nc', target='init.nc') + def dynamic_model_config(self, at_setup): if self.task_name == 'ekman': nu = self.config.getfloat( diff --git a/polaris/tasks/ocean/single_column/forward.yaml b/polaris/tasks/ocean/single_column/forward.yaml index 8d349a8394..6b8b4af242 100644 --- a/polaris/tasks/ocean/single_column/forward.yaml +++ b/polaris/tasks/ocean/single_column/forward.yaml @@ -1,19 +1,21 @@ -mpas-ocean: - run_modes: - config_ocean_run_mode: forward +ocean: time_management: config_stop_time: none time_integration: config_dt: 00:10:00 - split_explicit_ts: - config_btr_dt: 0000_00:00:30 forcing: config_use_bulk_wind_stress: true + +mpas-ocean: + run_modes: + config_ocean_run_mode: forward + split_explicit_ts: + config_btr_dt: 0000_00:00:30 streams: mesh: - filename_template: initial_state.nc + filename_template: init.nc input: - filename_template: initial_state.nc + filename_template: init.nc restart: {} mixedLayerDepthsOutput: contents: @@ -44,7 +46,7 @@ mpas-ocean: - frazilSalinityTendency forcing_data: type: input - filename_template: forcing.nc + filename_template: init.nc input_interval: initial_only contents: - tracersSurfaceRestoringFields @@ -65,3 +67,28 @@ mpas-ocean: - icebergFreshWaterFlux - riverRunoffFlux - iceRunoffFlux + +Omega: + IOStreams: + InitialVertCoord: + Filename: init.nc + InitialState: + UsePointerFile: false + Filename: init.nc + Contents: + - State + - WindStressZonal + - WindStressMeridional + History: + Filename: output.nc + Freq: 1 + FreqUnits: Seconds + IfExists: append + # effectively never + FileFreq: 9999 + FileFreqUnits: years + Contents: + - AuxiliaryState + - State + - Tracers + - SshCell diff --git a/polaris/tasks/ocean/single_column/inertial/forward.yaml b/polaris/tasks/ocean/single_column/inertial/forward.yaml index ba694874f9..ca5fd87c5a 100644 --- a/polaris/tasks/ocean/single_column/inertial/forward.yaml +++ b/polaris/tasks/ocean/single_column/inertial/forward.yaml @@ -1,6 +1,8 @@ -mpas-ocean: +ocean: time_management: config_run_duration: 0010_00:00:00 + +mpas-ocean: tracer_forcing_activeTracers: config_use_activeTracers_surface_bulk_forcing: false config_use_activeTracers_surface_restoring: false diff --git a/polaris/tasks/ocean/single_column/init.py b/polaris/tasks/ocean/single_column/init.py index c3c249e4b3..be33671986 100644 --- a/polaris/tasks/ocean/single_column/init.py +++ b/polaris/tasks/ocean/single_column/init.py @@ -33,7 +33,6 @@ def __init__(self, component, subdir): 'culled_mesh.nc', 'culled_graph.info', 'initial_state.nc', - 'forcing.nc', ]: self.add_output_file(file) @@ -148,10 +147,9 @@ def run(self): ds.attrs['nx'] = nx ds.attrs['ny'] = ny ds.attrs['dc'] = dc - write_netcdf(ds, 'initial_state.nc') # create forcing stream - ds_forcing = xr.Dataset() + ds_forcing = ds.copy() forcing_array = xr.ones_like(temperature) forcing_array_surface = xr.ones_like(ds.bottomDepth) forcing_array_surface = forcing_array_surface.expand_dims( @@ -234,4 +232,4 @@ def run(self): ds_forcing['icebergFreshWaterFlux'] = ( iceberg_flux * forcing_array_surface ) - write_netcdf(ds_forcing, 'forcing.nc') + write_netcdf(ds_forcing, 'initial_state.nc') From 0a2800918c83284c61b5b29d3535ea737297d15d Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Sun, 4 Jan 2026 16:30:38 -0600 Subject: [PATCH 09/47] Add restart streams to forward.yaml's omega section --- .../tasks/ocean/single_column/forward.yaml | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/polaris/tasks/ocean/single_column/forward.yaml b/polaris/tasks/ocean/single_column/forward.yaml index 6b8b4af242..8161594588 100644 --- a/polaris/tasks/ocean/single_column/forward.yaml +++ b/polaris/tasks/ocean/single_column/forward.yaml @@ -77,6 +77,7 @@ Omega: Filename: init.nc Contents: - State + - Tracers - WindStressZonal - WindStressMeridional History: @@ -92,3 +93,27 @@ Omega: - State - Tracers - SshCell + RestartRead: + UsePointerFile: true + PointerFilename: ocn.pointer + Mode: read + Precision: double + Freq: 1 + FreqUnits: OnStartup + UseStartEnd: true + StartTime: 0001-01-01_00:00:01 + EndTime: 99999-12-31_00:00:00 + Contents: + - Restart + RestartWrite: + UsePointerFile: true + PointerFilename: ocn.pointer + Filename: ocn.restart.$Y-$M-$D_$h.$m.$s + Mode: write + IfExists: replace + Precision: double + Freq: 6 + FreqUnits: months + UseStartEnd: false + Contents: + - Restart From d5f45661c4f3ee46d74e17254d66ff2425b67239 Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Sun, 4 Jan 2026 16:31:11 -0600 Subject: [PATCH 10/47] Add a bunch of tendency configs to cvmix forward.yaml's omega section --- .../ocean/single_column/cvmix/forward.yaml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/polaris/tasks/ocean/single_column/cvmix/forward.yaml b/polaris/tasks/ocean/single_column/cvmix/forward.yaml index 17fa423635..08c8cff604 100644 --- a/polaris/tasks/ocean/single_column/cvmix/forward.yaml +++ b/polaris/tasks/ocean/single_column/cvmix/forward.yaml @@ -26,3 +26,22 @@ mpas-ocean: config_cvmix_kpp_interpolationOMLType: cubic streams: KPP_testing: {} + +Omega: + Tendencies: + ThicknessFluxTendencyEnable: true + PVTendencyEnable: false + KETendencyEnable: false + SSHTendencyEnable: false + VelDiffTendencyEnable: false + VelHyperDiffTendencyEnable: false + VelVertMixTendencyEnable: true + PresForceTendencyEnable: false + PresGradForceTendencyEnable: false + GeoptGradTendencyEnable: false + WindForcingTendencyEnable: true + BottomDragTendencyEnable: false + TracerHorzAdvTendencyEnable: false + TracerDiffTendencyEnable: false + TracerHyperDiffTendencyEnable: false + TracerVertMixTendencyEnable: true From abcdf4e1f8e4e7c490a3e1370a801a838b5d6206 Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Sun, 4 Jan 2026 16:31:56 -0600 Subject: [PATCH 11/47] Remove later: check out hyun's vmix tendency branch --- e3sm_submodules/Omega | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e3sm_submodules/Omega b/e3sm_submodules/Omega index f2e951ac69..1b4057ed7c 160000 --- a/e3sm_submodules/Omega +++ b/e3sm_submodules/Omega @@ -1 +1 @@ -Subproject commit f2e951ac69e0b5667900906ff22ebb1587040d91 +Subproject commit 1b4057ed7c8898d4022b5d10754c76e0dcec780b From f08de5fb82ff8eaaace9919a9d3aedcbbe428cdc Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Thu, 8 Jan 2026 16:01:40 -0600 Subject: [PATCH 12/47] Add mapping for vmix tendency config --- polaris/ocean/model/mpaso_to_omega.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/polaris/ocean/model/mpaso_to_omega.yaml b/polaris/ocean/model/mpaso_to_omega.yaml index 359c02af47..24efc61c90 100644 --- a/polaris/ocean/model/mpaso_to_omega.yaml +++ b/polaris/ocean/model/mpaso_to_omega.yaml @@ -91,6 +91,11 @@ config: options: config_disable_vel_explicit_bottom_drag: BottomDragTendencyEnable +- section: + debug: Tendencies + options: + config_disable_vel_vmix: VelVertMixTendencyEnable + - section: bottom_drag: Tendencies options: From 23325ce10422656481b87ef3fb64c1dedf6ebd6e Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Thu, 8 Jan 2026 16:07:33 -0600 Subject: [PATCH 13/47] WIP add stable and unstable versions of cvmix --- polaris/tasks/ocean/single_column/__init__.py | 34 +++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/polaris/tasks/ocean/single_column/__init__.py b/polaris/tasks/ocean/single_column/__init__.py index 518eb0dab7..3ea3f27b66 100644 --- a/polaris/tasks/ocean/single_column/__init__.py +++ b/polaris/tasks/ocean/single_column/__init__.py @@ -17,7 +17,8 @@ def add_single_column_tasks(component): forcing = ['wind', 'evap'] name = 'cvmix' - filepath = f'{component.name}/{group_name}/{name}/{name}.cfg' + indir = f'{group_name}_stable' + filepath = f'{component.name}/indir/{name}/{name}.cfg' config = PolarisConfigParser(filepath=filepath) config.add_from_package( 'polaris.tasks.ocean.single_column', f'{group_name}.cfg' @@ -40,7 +41,36 @@ def add_single_column_tasks(component): component=component, config=config, init=init_step, - indir=f'{group_name}', + indir=indir, + ) + ) + + name = 'cvmix' + forcing_name = 'wind' + indir = group_name + filepath = f'{component.name}/indir/{name}/{name}_{forcing_name}.cfg' + config = PolarisConfigParser(filepath=filepath) + config.add_from_package( + 'polaris.tasks.ocean.single_column', f'{group_name}.cfg' + ) + config.add_from_package( + 'polaris.tasks.ocean.single_column', f'{forcing_name}.cfg' + ) + config.add_from_package( + 'polaris.tasks.ocean.single_column', 'unstable_stratification.cfg' + ) + init_step = component.get_or_create_shared_step( + step_cls=Init, + subdir=f'{group_name}/{forcing_name}/init_unstable', + config=config, + config_filename=f'{name}_{forcing_name}.cfg', + ) + component.add_task( + CVMix( + component=component, + config=config, + init=init_step, + indir=indir, ) ) From fd4e014fa0749fa111657b3b81a9a3811ac707d1 Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Thu, 8 Jan 2026 16:13:21 -0600 Subject: [PATCH 14/47] Add name argument to cvmix and fixup comparison filepath --- polaris/tasks/ocean/single_column/cvmix/__init__.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/polaris/tasks/ocean/single_column/cvmix/__init__.py b/polaris/tasks/ocean/single_column/cvmix/__init__.py index d5d48de246..3d13fbc9de 100644 --- a/polaris/tasks/ocean/single_column/cvmix/__init__.py +++ b/polaris/tasks/ocean/single_column/cvmix/__init__.py @@ -9,7 +9,7 @@ class CVMix(Task): then performs a short forward run testing vertical mixing on 1 core. """ - def __init__(self, component, config, init, indir): + def __init__(self, component, config, init, indir, name='cvmix'): """ Create the test case Parameters @@ -17,7 +17,6 @@ def __init__(self, component, config, init, indir): component : polaris.tasks.ocean.Ocean The ocean component that this task belongs to """ - name = 'cvmix' super().__init__(component=component, name=name, indir=indir) config_filename = 'cvmix.cfg' self.set_shared_config(config, link=config_filename) @@ -50,7 +49,7 @@ def __init__(self, component, config, init, indir): Viz( component=component, indir=self.subdir, - comparison_path=f'{self.subdir}/forward_no_vadv', + comparison_path='../forward_no_vadv', ), run_by_default=False, ) From d81281d788737566345a6f575af701820a60bd70 Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Fri, 9 Jan 2026 11:40:46 -0600 Subject: [PATCH 15/47] Add utility for daysSinceStartOfSim --- polaris/ocean/time.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 polaris/ocean/time.py diff --git a/polaris/ocean/time.py b/polaris/ocean/time.py new file mode 100644 index 0000000000..38b61858e8 --- /dev/null +++ b/polaris/ocean/time.py @@ -0,0 +1,19 @@ +import numpy as np +import pandas as pd + + +def get_days_since_start(ds): + """ + Ocean model output may or may not include 'daysSinceStartOfSim'. This + routine uses 'daysSinceStartOfSim' if available, otherwise it uses 'Time' + """ + if 'daysSinceStartOfSim' in ds.keys(): + t_arr = ds.daysSinceStartOfSim.values.astype(float) + elif 'Time' in ds.keys(): + t_vals = ds['Time'].values + t_pd = pd.to_datetime(t_vals) + t_arr = 1.0e9 * (t_pd - t_pd[0]) / np.timedelta64(1, 's') + t_arr = t_arr.astype(float) / 86400.0 + else: + raise ValueError('Could not find a time variable in dataset') + return t_arr From fb03b48c67061eae15af8b86d6f693f72e385ab6 Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Fri, 9 Jan 2026 11:46:30 -0600 Subject: [PATCH 16/47] WIP Support omega in single column viz step --- polaris/tasks/ocean/single_column/viz.py | 92 +++++++++++++++--------- 1 file changed, 57 insertions(+), 35 deletions(-) diff --git a/polaris/tasks/ocean/single_column/viz.py b/polaris/tasks/ocean/single_column/viz.py index 5fcf165026..b30e66c24b 100644 --- a/polaris/tasks/ocean/single_column/viz.py +++ b/polaris/tasks/ocean/single_column/viz.py @@ -1,12 +1,13 @@ import matplotlib.pyplot as plt import numpy as np -import xarray as xr -from polaris import Step +from polaris.ocean.model import OceanIOStep +from polaris.ocean.time import get_days_since_start +from polaris.ocean.vertical.diagnostics import depth_from_thickness from polaris.viz import use_mplstyle -class Viz(Step): +class Viz(OceanIOStep): """ A step for plotting the results of a single-column test """ @@ -49,33 +50,53 @@ def run(self): """ use_mplstyle() ideal_age = self.ideal_age - ds = xr.load_dataset('output.nc') + + ds_init = self.open_model_dataset('initial_state.nc') + ds_init = ds_init.isel(Time=0) + + ds = self.open_model_dataset('output.nc') + t_arr = get_days_since_start(ds) + t_index = np.argmin(np.abs(t_arr - 1.0)) # index nearest 1 day + t_days = float(t_arr[t_index]) + ds_final = ds.isel(Time=t_index) + if self.comparison_path is not None: - ds_comp = xr.load_dataset('comparison.nc') - t_days = ds.daysSinceStartOfSim.values - t = t_days.astype('timedelta64[ns]') - t = t / np.timedelta64(1, 'D') - t_index = np.argmin(np.abs(t - 1.0)) # ds.sizes['Time'] - 1 - t_days = t[t_index] + ds_comp = self.open_model_dataset('comparison.nc') + ds_comp = ds_comp.isel(Time=t_index) # Plot temperature and salinity profiles - title = f'final time = {t_days} days' + title = f'final time = {t_days:2.1g} days' fields = {'temperature': 'degC', 'salinity': 'PSU'} if ideal_age: # Include age tracer fields['iAge'] = 'seconds' - z_mid = ds['zMid'].mean(dim='nCells') - z_mid_init = z_mid.isel(Time=0) - z_mid_final = z_mid.isel(Time=t_index) + z_mid_init = depth_from_thickness(ds_init).mean(dim='nCells') + z_mid_final = depth_from_thickness(ds_final).mean(dim='nCells') for field_name, field_units in fields.items(): - if field_name not in ds.keys(): + if field_name not in ds_init.keys(): + raise ValueError( + f'{field_name} not present in initial_state.nc' + ) + if field_name not in ds_final.keys(): raise ValueError(f'{field_name} not present in output.nc') - var = ds[field_name].mean(dim='nCells') - var_init = var.isel(Time=0) - var_final = var.isel(Time=t_index) + var_init = ds_init[field_name].mean(dim='nCells') + var_final = ds_final[field_name].mean(dim='nCells') + print('Size of variables to plot') + print(t_arr) + print(f't_index = {t_index}') + print( + f'Change of {field_name} at the surface: ' + f'{var_final.values[0] - var_init.values[0]}' + ) + print( + f'Change of {field_name} at the bottom: ' + f'{var_final.values[-1] - var_init.values[-1]}' + ) + if self.comparison_path is not None: var_comp = ds_comp[field_name].mean(dim='nCells') - var_comp = var_comp.isel(Time=t_index) + if field_name not in ds_final.keys(): + raise ValueError(f'{field_name} not present in output.nc') plt.figure(figsize=(3, 5)) ax = plt.subplot(111) ax.plot(var_init, z_mid_init, '--k', label='initial') @@ -84,25 +105,26 @@ def run(self): ax.plot(var_comp, z_mid_final, '-r', label='comparison') ax.set_xlabel(f'{field_name} ({field_units})') ax.set_ylabel('z (m)') - ax.legend() + # ax.legend() plt.title(title) plt.tight_layout(pad=0.5) plt.savefig(f'{field_name}.png') plt.close() # Plot velocity profiles - u = ds['velocityZonal'].mean(dim='nCells') - v = ds['velocityMeridional'].mean(dim='nCells') - u_final = u.isel(Time=t_index) - v_final = v.isel(Time=t_index) - plt.figure(figsize=(3, 5)) - ax = plt.subplot(111) - ax.plot(u_final, z_mid_final, '-k', label='u') - ax.plot(v_final, z_mid_final, '-b', label='v') - ax.set_xlabel('Velocity (m/s)') - ax.set_ylabel('z (m)') - ax.legend() - plt.title(title) - plt.tight_layout(pad=0.5) - plt.savefig('velocity.png') - plt.close() + if 'velocityZonal' and 'velocityMeridional' in ds.keys(): + u = ds['velocityZonal'].mean(dim='nCells') + v = ds['velocityMeridional'].mean(dim='nCells') + u_final = u.isel(Time=t_index) + v_final = v.isel(Time=t_index) + plt.figure(figsize=(3, 5)) + ax = plt.subplot(111) + ax.plot(u_final, z_mid_final, '-k', label='u') + ax.plot(v_final, z_mid_final, '-b', label='v') + ax.set_xlabel('Velocity (m/s)') + ax.set_ylabel('z (m)') + ax.legend() + plt.title(title) + plt.tight_layout(pad=0.5) + plt.savefig('velocity.png') + plt.close() From 9f17f492bb67cb1806b35679ea228ad36289b3d2 Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Fri, 9 Jan 2026 11:54:01 -0600 Subject: [PATCH 17/47] Unstable stratification config --- .../ocean/single_column/unstable_stratification.cfg | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 polaris/tasks/ocean/single_column/unstable_stratification.cfg diff --git a/polaris/tasks/ocean/single_column/unstable_stratification.cfg b/polaris/tasks/ocean/single_column/unstable_stratification.cfg new file mode 100644 index 0000000000..0a3102f8b4 --- /dev/null +++ b/polaris/tasks/ocean/single_column/unstable_stratification.cfg @@ -0,0 +1,12 @@ + +# config options for single column testcases +[single_column] + +# Temperature gradient below the mixed layer +temperature_gradient_interior = -0.01 + +# Depth of the temperature mixed layer +mixed_layer_depth_temperature = 25.0 + +# The salinity below the mixed layer +salinity_difference_across_mixed_layer = -1.0 From 494571b408380b3f7e66e29949590d64a10f4635 Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Sat, 10 Jan 2026 14:36:13 -0600 Subject: [PATCH 18/47] Turn del4 off --- polaris/tasks/ocean/single_column/cvmix/forward.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/polaris/tasks/ocean/single_column/cvmix/forward.yaml b/polaris/tasks/ocean/single_column/cvmix/forward.yaml index 08c8cff604..bffa1d70c0 100644 --- a/polaris/tasks/ocean/single_column/cvmix/forward.yaml +++ b/polaris/tasks/ocean/single_column/cvmix/forward.yaml @@ -2,8 +2,7 @@ ocean: time_management: config_run_duration: 0010_00:00:00 hmix_del4: - config_use_mom_del4: true - config_mom_del4: 2.0e14 + config_use_mom_del4: false cvmix: config_use_cvmix_convection: true config_use_cvmix_shear: true From c26f7a41ea30c2552813c17c44c726505b2fbee1 Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Sat, 10 Jan 2026 14:36:48 -0600 Subject: [PATCH 19/47] Run with background diff, visc only --- polaris/tasks/ocean/single_column/cvmix/forward.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/polaris/tasks/ocean/single_column/cvmix/forward.yaml b/polaris/tasks/ocean/single_column/cvmix/forward.yaml index bffa1d70c0..f5bddb4506 100644 --- a/polaris/tasks/ocean/single_column/cvmix/forward.yaml +++ b/polaris/tasks/ocean/single_column/cvmix/forward.yaml @@ -4,8 +4,8 @@ ocean: hmix_del4: config_use_mom_del4: false cvmix: - config_use_cvmix_convection: true - config_use_cvmix_shear: true + config_use_cvmix_convection: false + config_use_cvmix_shear: false eos: config_eos_type: linear eos_linear: From a906b35c80a8ffef4950d42d19a1ec9cea864b39 Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Sun, 11 Jan 2026 15:18:51 -0600 Subject: [PATCH 20/47] Reorganize and rename cvmix tests --- polaris/tasks/ocean/single_column/__init__.py | 76 +++++++++++-------- polaris/tasks/ocean/single_column/forward.py | 22 ++++++ polaris/tasks/ocean/single_column/viz.py | 43 ++++++----- .../single_column/{cvmix => vmix}/__init__.py | 33 +++++--- .../{cvmix => vmix}/forward.yaml | 5 +- .../{cvmix/cvmix.cfg => vmix/vmix.cfg} | 0 6 files changed, 117 insertions(+), 62 deletions(-) rename polaris/tasks/ocean/single_column/{cvmix => vmix}/__init__.py (59%) rename polaris/tasks/ocean/single_column/{cvmix => vmix}/forward.yaml (91%) rename polaris/tasks/ocean/single_column/{cvmix/cvmix.cfg => vmix/vmix.cfg} (100%) diff --git a/polaris/tasks/ocean/single_column/__init__.py b/polaris/tasks/ocean/single_column/__init__.py index 3ea3f27b66..808f791baa 100644 --- a/polaris/tasks/ocean/single_column/__init__.py +++ b/polaris/tasks/ocean/single_column/__init__.py @@ -1,9 +1,9 @@ from polaris.config import PolarisConfigParser as PolarisConfigParser -from polaris.tasks.ocean.single_column.cvmix import CVMix as CVMix from polaris.tasks.ocean.single_column.ekman import Ekman as Ekman from polaris.tasks.ocean.single_column.ideal_age import IdealAge as IdealAge from polaris.tasks.ocean.single_column.inertial import Inertial as Inertial from polaris.tasks.ocean.single_column.init import Init +from polaris.tasks.ocean.single_column.vmix import VMix as VMix def add_single_column_tasks(component): @@ -15,10 +15,10 @@ def add_single_column_tasks(component): """ group_name = 'single_column' - forcing = ['wind', 'evap'] - name = 'cvmix' - indir = f'{group_name}_stable' - filepath = f'{component.name}/indir/{name}/{name}.cfg' + name = 'vmix_stable' + forcing = ['wind'] + forcing_dir = '_'.join(forcing) if forcing else 'no_forcing' + filepath = f'{component.name}/{group_name}/{name}/{name}.cfg' config = PolarisConfigParser(filepath=filepath) config.add_from_package( 'polaris.tasks.ocean.single_column', f'{group_name}.cfg' @@ -32,58 +32,62 @@ def add_single_column_tasks(component): ) init_step = component.get_or_create_shared_step( step_cls=Init, - subdir=f'{group_name}/{"_".join(forcing)}/init_stable', + subdir=f'{group_name}/{forcing_dir}/init_stable', config=config, config_filename=f'{name}.cfg', ) component.add_task( - CVMix( + VMix( component=component, config=config, + name=name, init=init_step, - indir=indir, + indir=group_name, ) ) - name = 'cvmix' - forcing_name = 'wind' - indir = group_name - filepath = f'{component.name}/indir/{name}/{name}_{forcing_name}.cfg' + name = 'vmix_unstable' + forcing = [] + forcing_dir = '_'.join(forcing) if forcing else 'no_forcing' + filepath = f'{component.name}/{group_name}/{name}/{name}.cfg' config = PolarisConfigParser(filepath=filepath) config.add_from_package( 'polaris.tasks.ocean.single_column', f'{group_name}.cfg' ) - config.add_from_package( - 'polaris.tasks.ocean.single_column', f'{forcing_name}.cfg' - ) + for forcing_name in forcing: + config.add_from_package( + 'polaris.tasks.ocean.single_column', f'{forcing_name}.cfg' + ) config.add_from_package( 'polaris.tasks.ocean.single_column', 'unstable_stratification.cfg' ) init_step = component.get_or_create_shared_step( step_cls=Init, - subdir=f'{group_name}/{forcing_name}/init_unstable', + subdir=f'{group_name}/{forcing_dir}/init_unstable', config=config, - config_filename=f'{name}_{forcing_name}.cfg', + config_filename=f'{name}.cfg', ) component.add_task( - CVMix( + VMix( component=component, config=config, + name=name, init=init_step, - indir=indir, + indir=group_name, ) ) - forcing_name = 'wind' + forcing = ['wind'] name = 'ekman' filepath = f'{component.name}/{group_name}/{name}/{name}.cfg' config = PolarisConfigParser(filepath=filepath) config.add_from_package( 'polaris.tasks.ocean.single_column', f'{group_name}.cfg' ) - config.add_from_package( - 'polaris.tasks.ocean.single_column', f'{forcing_name}.cfg' - ) + for forcing_name in forcing: + config.add_from_package( + 'polaris.tasks.ocean.single_column', f'{forcing_name}.cfg' + ) init_step = component.get_or_create_shared_step( step_cls=Init, subdir=f'{group_name}/{forcing_name}/init', @@ -95,25 +99,28 @@ def add_single_column_tasks(component): component=component, config=config, init=init_step, - indir=f'{group_name}', + indir=group_name, ) ) name = 'ideal_age' + forcing = ['evap'] + forcing_dir = '_'.join(forcing) if forcing else 'no_forcing' filepath = f'{component.name}/{group_name}/{name}/{name}.cfg' config = PolarisConfigParser(filepath=filepath) config.add_from_package( 'polaris.tasks.ocean.single_column', f'{group_name}.cfg' ) - config.add_from_package( - 'polaris.tasks.ocean.single_column', f'{forcing_name}.cfg' - ) + for forcing_name in forcing: + config.add_from_package( + 'polaris.tasks.ocean.single_column', f'{forcing_name}.cfg' + ) config.add_from_package( 'polaris.tasks.ocean.single_column', 'stable_stratification.cfg' ) init_step = component.get_or_create_shared_step( step_cls=Init, - subdir=f'{group_name}/{forcing_name}/init_stable', + subdir=f'{group_name}/{forcing_dir}/init_stable', config=config, config_filename=f'{name}.cfg', ) @@ -122,23 +129,28 @@ def add_single_column_tasks(component): component=component, init=init_step, config=config, - indir=f'{group_name}', + indir=group_name, ) ) - forcing_name = 'no_forcing' name = 'inertial' + forcing = [] + forcing_dir = '_'.join(forcing) if forcing else 'no_forcing' filepath = f'{component.name}/{group_name}/{name}/{name}.cfg' config = PolarisConfigParser(filepath=filepath) config.add_from_package( 'polaris.tasks.ocean.single_column', f'{group_name}.cfg' ) + for forcing_name in forcing: + config.add_from_package( + 'polaris.tasks.ocean.single_column', f'{forcing_name}.cfg' + ) config.add_from_package( 'polaris.tasks.ocean.single_column', 'stable_stratification.cfg' ) init_step = component.get_or_create_shared_step( step_cls=Init, - subdir=f'{group_name}/{forcing_name}/init_stable', + subdir=f'{group_name}/{forcing_dir}/init_stable', config=config, config_filename=f'{name}.cfg', ) @@ -147,6 +159,6 @@ def add_single_column_tasks(component): component=component, init=init_step, config=config, - indir=f'{group_name}', + indir=group_name, ) ) diff --git a/polaris/tasks/ocean/single_column/forward.py b/polaris/tasks/ocean/single_column/forward.py index 71d3f41799..0ecc92bb07 100644 --- a/polaris/tasks/ocean/single_column/forward.py +++ b/polaris/tasks/ocean/single_column/forward.py @@ -25,6 +25,7 @@ def __init__( validate_vars=None, task_name='', enable_vadv=True, + constant_diff=False, ): """ Create a new test case @@ -65,6 +66,8 @@ def __init__( """ if not enable_vadv: name = f'{name}_no_vadv' + if constant_diff: + name = f'{name}_constant' super().__init__( component=component, name=name, @@ -97,6 +100,8 @@ def __init__( self.enable_vadv = enable_vadv + self.constant_diff = constant_diff + def setup(self): """ TEMP: symlink initial condition to name hard-coded in Omega @@ -125,3 +130,20 @@ def dynamic_model_config(self, at_setup): }, config_model='mpas-ocean', ) + + if self.constant_diff: + self.add_model_config_options( + options={ + 'config_use_cvmix_convection': False, + 'config_use_cvmix_shear': False, + }, + config_model='ocean', + ) + else: + self.add_model_config_options( + options={ + 'config_use_cvmix_convection': True, + 'config_use_cvmix_shear': True, + }, + config_model='ocean', + ) diff --git a/polaris/tasks/ocean/single_column/viz.py b/polaris/tasks/ocean/single_column/viz.py index b30e66c24b..5da129e6a3 100644 --- a/polaris/tasks/ocean/single_column/viz.py +++ b/polaris/tasks/ocean/single_column/viz.py @@ -13,7 +13,11 @@ class Viz(OceanIOStep): """ def __init__( - self, component, indir, ideal_age=False, comparison_path=None + self, + component, + indir, + ideal_age=False, + comparisons=None, ): """ Create the step @@ -32,16 +36,17 @@ def __init__( """ super().__init__(component=component, name='viz', indir=indir) self.ideal_age = ideal_age - self.comparison_path = comparison_path + self.comparisons = comparisons if comparisons else dict() self.add_input_file( filename='initial_state.nc', target='../init/initial_state.nc' ) self.add_input_file( filename='output.nc', target='../forward/output.nc' ) - if comparison_path is not None: + for comparison_name, comparison_path in self.comparisons.items(): self.add_input_file( - filename='comparison.nc', target=f'{comparison_path}/output.nc' + filename=f'{comparison_name}.nc', + target=f'{comparison_path}/output.nc', ) def run(self): @@ -54,18 +59,15 @@ def run(self): ds_init = self.open_model_dataset('initial_state.nc') ds_init = ds_init.isel(Time=0) - ds = self.open_model_dataset('output.nc') + ds = self.open_model_dataset('output.nc', decode_times=False) t_arr = get_days_since_start(ds) t_index = np.argmin(np.abs(t_arr - 1.0)) # index nearest 1 day t_days = float(t_arr[t_index]) ds_final = ds.isel(Time=t_index) - if self.comparison_path is not None: - ds_comp = self.open_model_dataset('comparison.nc') - ds_comp = ds_comp.isel(Time=t_index) - # Plot temperature and salinity profiles title = f'final time = {t_days:2.1g} days' + print(f't_index = {t_index}, t_days = {t_days}') fields = {'temperature': 'degC', 'salinity': 'PSU'} if ideal_age: # Include age tracer @@ -82,8 +84,6 @@ def run(self): var_init = ds_init[field_name].mean(dim='nCells') var_final = ds_final[field_name].mean(dim='nCells') print('Size of variables to plot') - print(t_arr) - print(f't_index = {t_index}') print( f'Change of {field_name} at the surface: ' f'{var_final.values[0] - var_init.values[0]}' @@ -93,16 +93,25 @@ def run(self): f'{var_final.values[-1] - var_init.values[-1]}' ) - if self.comparison_path is not None: - var_comp = ds_comp[field_name].mean(dim='nCells') - if field_name not in ds_final.keys(): - raise ValueError(f'{field_name} not present in output.nc') plt.figure(figsize=(3, 5)) ax = plt.subplot(111) ax.plot(var_init, z_mid_init, '--k', label='initial') ax.plot(var_final, z_mid_final, '-k', label='final') - if self.comparison_path is not None: - ax.plot(var_comp, z_mid_final, '-r', label='comparison') + for comparison_name, _ in self.comparisons.items(): + ds_comp = self.open_model_dataset( + f'{comparison_name}.nc', decode_times=False + ) + t_arr = get_days_since_start(ds_comp) + t_index = np.argmin(np.abs(t_arr - 1.0)) # index nearest 1 day + t_days = float(t_arr[t_index]) + print(f't_index = {t_index}, t_days = {t_days}') + ds_comp = ds_comp.isel(Time=t_index) + if field_name not in ds_comp.keys(): + raise ValueError( + f'{field_name} not present in {comparison_name}.nc' + ) + var_comp = ds_comp[field_name].mean(dim='nCells') + ax.plot(var_comp, z_mid_final, '-r', label=comparison_name) ax.set_xlabel(f'{field_name} ({field_units})') ax.set_ylabel('z (m)') # ax.legend() diff --git a/polaris/tasks/ocean/single_column/cvmix/__init__.py b/polaris/tasks/ocean/single_column/vmix/__init__.py similarity index 59% rename from polaris/tasks/ocean/single_column/cvmix/__init__.py rename to polaris/tasks/ocean/single_column/vmix/__init__.py index 3d13fbc9de..e1317af197 100644 --- a/polaris/tasks/ocean/single_column/cvmix/__init__.py +++ b/polaris/tasks/ocean/single_column/vmix/__init__.py @@ -3,13 +3,13 @@ from polaris.tasks.ocean.single_column.viz import Viz -class CVMix(Task): +class VMix(Task): """ - The CVMix single-column test case creates the mesh and initial condition, + The VMix single-column test case creates the mesh and initial condition, then performs a short forward run testing vertical mixing on 1 core. """ - def __init__(self, component, config, init, indir, name='cvmix'): + def __init__(self, component, config, init, indir, name='vmix'): """ Create the test case Parameters @@ -18,10 +18,10 @@ def __init__(self, component, config, init, indir, name='cvmix'): The ocean component that this task belongs to """ super().__init__(component=component, name=name, indir=indir) - config_filename = 'cvmix.cfg' + config_filename = 'vmix.cfg' self.set_shared_config(config, link=config_filename) self.config.add_from_package( - 'polaris.tasks.ocean.single_column.cvmix', config_filename + 'polaris.tasks.ocean.single_column.vmix', config_filename ) self.add_step(init, symlink='init') @@ -35,21 +35,36 @@ def __init__(self, component, config, init, indir, name='cvmix'): self.add_step( Forward( component=component, - indir=self.subdir, + indir=f'{indir}/{name}', ntasks=1, min_tasks=1, openmp_threads=1, validate_vars=validate_vars, - task_name=name, + task_name='vmix', enable_vadv=enable_vadv, ) ) + self.add_step( + Forward( + component=component, + indir=f'{indir}/{name}', + ntasks=1, + min_tasks=1, + openmp_threads=1, + validate_vars=validate_vars, + task_name='vmix', + constant_diff=True, + ) + ) self.add_step( Viz( component=component, - indir=self.subdir, - comparison_path='../forward_no_vadv', + indir=f'{indir}/{name}', + comparisons={ + 'no_vadv': '../forward_no_vadv', + 'constant': '../forward_constant', + }, ), run_by_default=False, ) diff --git a/polaris/tasks/ocean/single_column/cvmix/forward.yaml b/polaris/tasks/ocean/single_column/vmix/forward.yaml similarity index 91% rename from polaris/tasks/ocean/single_column/cvmix/forward.yaml rename to polaris/tasks/ocean/single_column/vmix/forward.yaml index f5bddb4506..7002e64b06 100644 --- a/polaris/tasks/ocean/single_column/cvmix/forward.yaml +++ b/polaris/tasks/ocean/single_column/vmix/forward.yaml @@ -3,9 +3,6 @@ ocean: config_run_duration: 0010_00:00:00 hmix_del4: config_use_mom_del4: false - cvmix: - config_use_cvmix_convection: false - config_use_cvmix_shear: false eos: config_eos_type: linear eos_linear: @@ -38,7 +35,7 @@ Omega: PresForceTendencyEnable: false PresGradForceTendencyEnable: false GeoptGradTendencyEnable: false - WindForcingTendencyEnable: true + WindForcingTendencyEnable: false BottomDragTendencyEnable: false TracerHorzAdvTendencyEnable: false TracerDiffTendencyEnable: false diff --git a/polaris/tasks/ocean/single_column/cvmix/cvmix.cfg b/polaris/tasks/ocean/single_column/vmix/vmix.cfg similarity index 100% rename from polaris/tasks/ocean/single_column/cvmix/cvmix.cfg rename to polaris/tasks/ocean/single_column/vmix/vmix.cfg From 4a7083cbbd6441c90304fc5b74b6bd3c8f382921 Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Mon, 12 Jan 2026 14:03:14 -0600 Subject: [PATCH 21/47] Fixup no vertical advection config options --- polaris/tasks/ocean/single_column/forward.py | 1 + 1 file changed, 1 insertion(+) diff --git a/polaris/tasks/ocean/single_column/forward.py b/polaris/tasks/ocean/single_column/forward.py index 0ecc92bb07..083b320651 100644 --- a/polaris/tasks/ocean/single_column/forward.py +++ b/polaris/tasks/ocean/single_column/forward.py @@ -125,6 +125,7 @@ def dynamic_model_config(self, at_setup): self.add_model_config_options( options={ 'config_vert_coord_movement': 'impermeable_interfaces', + 'config_disable_thick_vadv': True, 'config_disable_vel_vadv': True, 'config_disable_tr_adv': True, }, From 3fef2860107454b11eb63e13ceddbd64996cf6ff Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Sun, 11 Jan 2026 15:19:56 -0600 Subject: [PATCH 22/47] WIP fixup yaml --- polaris/tasks/ocean/single_column/forward.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/polaris/tasks/ocean/single_column/forward.yaml b/polaris/tasks/ocean/single_column/forward.yaml index 8161594588..9a3eb770a2 100644 --- a/polaris/tasks/ocean/single_column/forward.yaml +++ b/polaris/tasks/ocean/single_column/forward.yaml @@ -2,9 +2,9 @@ ocean: time_management: config_stop_time: none time_integration: - config_dt: 00:10:00 + config_dt: 0000_00:10:00 forcing: - config_use_bulk_wind_stress: true + config_use_bulk_wind_stress: false mpas-ocean: run_modes: From 9e132de37805cce1f2d548d8e9c89675b59c56b8 Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Sun, 11 Jan 2026 18:13:35 -0600 Subject: [PATCH 23/47] Default duration of 1 day --- polaris/tasks/ocean/single_column/vmix/forward.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polaris/tasks/ocean/single_column/vmix/forward.yaml b/polaris/tasks/ocean/single_column/vmix/forward.yaml index 7002e64b06..0336232ebe 100644 --- a/polaris/tasks/ocean/single_column/vmix/forward.yaml +++ b/polaris/tasks/ocean/single_column/vmix/forward.yaml @@ -1,6 +1,6 @@ ocean: time_management: - config_run_duration: 0010_00:00:00 + config_run_duration: 0001_00:00:00 hmix_del4: config_use_mom_del4: false eos: From 5212ab5cdde35372ae6621c22a1038775db3c8f9 Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Sun, 11 Jan 2026 20:02:59 -0600 Subject: [PATCH 24/47] WIP try different unstable stratification profiles --- .../ocean/single_column/unstable_stratification.cfg | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/polaris/tasks/ocean/single_column/unstable_stratification.cfg b/polaris/tasks/ocean/single_column/unstable_stratification.cfg index 0a3102f8b4..6221f1f66a 100644 --- a/polaris/tasks/ocean/single_column/unstable_stratification.cfg +++ b/polaris/tasks/ocean/single_column/unstable_stratification.cfg @@ -2,8 +2,13 @@ # config options for single column testcases [single_column] -# Temperature gradient below the mixed layer -temperature_gradient_interior = -0.01 +temperature_difference_across_mixed_layer = -1.0 + +# Salinity gradient below the mixed layer +salinity_gradient_interior = 0.01 + +# Depth of the temperature mixed layer +mixed_layer_depth_salinity = 25.0 # Depth of the temperature mixed layer mixed_layer_depth_temperature = 25.0 From 420043e038082bfbf8638192c67e652ed71e935f Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Mon, 12 Jan 2026 14:02:20 -0600 Subject: [PATCH 25/47] Use PP scheme for shear mixing --- polaris/tasks/ocean/single_column/vmix/forward.yaml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/polaris/tasks/ocean/single_column/vmix/forward.yaml b/polaris/tasks/ocean/single_column/vmix/forward.yaml index 0336232ebe..4ccd814ce0 100644 --- a/polaris/tasks/ocean/single_column/vmix/forward.yaml +++ b/polaris/tasks/ocean/single_column/vmix/forward.yaml @@ -16,10 +16,8 @@ mpas-ocean: config_use_activeTracers_surface_restoring: true config_use_activeTracers_interior_restoring: true cvmix: - config_cvmix_shear_mixing_scheme: KPP - config_use_cvmix_kpp: true - config_cvmix_kpp_matching: MatchBoth - config_cvmix_kpp_interpolationOMLType: cubic + config_cvmix_shear_mixing_scheme: PP + config_use_cvmix_kpp: false streams: KPP_testing: {} From 5ae958255854498fd1e8ba6512caa711862e1af7 Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Tue, 13 Jan 2026 09:42:28 -0600 Subject: [PATCH 26/47] Output zMid instead of computing it from layerThickness --- polaris/ocean/model/mpaso_to_omega.yaml | 3 +++ polaris/tasks/ocean/single_column/forward.yaml | 1 + polaris/tasks/ocean/single_column/viz.py | 5 ++--- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/polaris/ocean/model/mpaso_to_omega.yaml b/polaris/ocean/model/mpaso_to_omega.yaml index 24efc61c90..9c7ac493a8 100644 --- a/polaris/ocean/model/mpaso_to_omega.yaml +++ b/polaris/ocean/model/mpaso_to_omega.yaml @@ -22,6 +22,9 @@ variables: cellsOnVertex: CellsOnVertex edgesOnVertex: EdgesOnVertex + # vertical + zMid: ZMid + # tracers temperature: Temperature salinity: Salinity diff --git a/polaris/tasks/ocean/single_column/forward.yaml b/polaris/tasks/ocean/single_column/forward.yaml index 9a3eb770a2..71c8296f0f 100644 --- a/polaris/tasks/ocean/single_column/forward.yaml +++ b/polaris/tasks/ocean/single_column/forward.yaml @@ -91,6 +91,7 @@ Omega: Contents: - AuxiliaryState - State + - ZMid - Tracers - SshCell RestartRead: diff --git a/polaris/tasks/ocean/single_column/viz.py b/polaris/tasks/ocean/single_column/viz.py index 5da129e6a3..4a934b9b6e 100644 --- a/polaris/tasks/ocean/single_column/viz.py +++ b/polaris/tasks/ocean/single_column/viz.py @@ -3,7 +3,6 @@ from polaris.ocean.model import OceanIOStep from polaris.ocean.time import get_days_since_start -from polaris.ocean.vertical.diagnostics import depth_from_thickness from polaris.viz import use_mplstyle @@ -72,8 +71,8 @@ def run(self): if ideal_age: # Include age tracer fields['iAge'] = 'seconds' - z_mid_init = depth_from_thickness(ds_init).mean(dim='nCells') - z_mid_final = depth_from_thickness(ds_final).mean(dim='nCells') + z_mid_init = ds['zMid'].isel(Time=0).mean(dim='nCells') + z_mid_final = ds_final['zMid'].mean(dim='nCells') for field_name, field_units in fields.items(): if field_name not in ds_init.keys(): raise ValueError( From de0ce29aaffafa3d40607dd40022abc7f726a4d1 Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Tue, 13 Jan 2026 17:17:19 -0600 Subject: [PATCH 27/47] Provide ekman forward step path to analysis step --- .../ocean/single_column/ekman/__init__.py | 24 +++++++++++-------- .../ocean/single_column/ekman/analysis.py | 13 +++++++--- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/polaris/tasks/ocean/single_column/ekman/__init__.py b/polaris/tasks/ocean/single_column/ekman/__init__.py index 17fbf32ad8..7c4e704540 100644 --- a/polaris/tasks/ocean/single_column/ekman/__init__.py +++ b/polaris/tasks/ocean/single_column/ekman/__init__.py @@ -40,20 +40,24 @@ def __init__(self, component, config, init, indir): 'layerThickness', 'normalVelocity', ] + forward_step = Forward( + component=component, + indir=self.subdir, + ntasks=1, + min_tasks=1, + openmp_threads=1, + validate_vars=validate_vars, + task_name=name, + constant_diff=True, + ) + self.add_step(forward_step) + self.add_step( - Forward( - component=component, - indir=self.subdir, - ntasks=1, - min_tasks=1, - openmp_threads=1, - validate_vars=validate_vars, - task_name=name, + Analysis( + component=component, indir=self.subdir, forward=forward_step ) ) - self.add_step(Analysis(component=component, indir=self.subdir)) - self.add_step( Viz(component=component, indir=self.subdir), run_by_default=False, diff --git a/polaris/tasks/ocean/single_column/ekman/analysis.py b/polaris/tasks/ocean/single_column/ekman/analysis.py index 299d6ed24e..93498bc4cb 100644 --- a/polaris/tasks/ocean/single_column/ekman/analysis.py +++ b/polaris/tasks/ocean/single_column/ekman/analysis.py @@ -14,7 +14,7 @@ class Analysis(Step): A step for comparing the velocity profile to an analytic solution """ - def __init__(self, component, indir): + def __init__(self, component, indir, forward): """ Create the step @@ -27,13 +27,20 @@ def __init__(self, component, indir): The subdirectory that the task belongs to, that this step will go into a subdirectory of + forward : polaris.Step + The forward step for this test case """ super().__init__(component=component, name='analysis', indir=indir) + self.forward = forward + + def setup(self): self.add_input_file( - filename='init.nc', target='../forward/initial_state.nc' + filename='init.nc', + target=f'{self.base_work_dir}/{self.forward.path}/init.nc', ) self.add_input_file( - filename='output.nc', target='../forward/output.nc' + filename='output.nc', + target=f'{self.base_work_dir}/{self.forward.path}/output.nc', ) def run(self): From 686e68d3bafd5f475c28f34466c2dcaf51ef83b5 Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Tue, 13 Jan 2026 17:23:09 -0600 Subject: [PATCH 28/47] Provide consistent names for stream files --- polaris/tasks/ocean/single_column/ekman/forward.yaml | 4 ++-- polaris/tasks/ocean/single_column/forward.py | 8 ++++++++ polaris/tasks/ocean/single_column/forward.yaml | 4 ++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/polaris/tasks/ocean/single_column/ekman/forward.yaml b/polaris/tasks/ocean/single_column/ekman/forward.yaml index 51aadb9789..bcec302721 100644 --- a/polaris/tasks/ocean/single_column/ekman/forward.yaml +++ b/polaris/tasks/ocean/single_column/ekman/forward.yaml @@ -28,9 +28,9 @@ mpas-ocean: config_use_activeTracers_interior_restoring: false streams: mesh: - filename_template: initial_state.nc + filename_template: mesh.nc input: - filename_template: initial_state.nc + filename_template: init.nc restart: {} KPP_testing: {} mixedLayerDepthsOutput: diff --git a/polaris/tasks/ocean/single_column/forward.py b/polaris/tasks/ocean/single_column/forward.py index 083b320651..6431035ccc 100644 --- a/polaris/tasks/ocean/single_column/forward.py +++ b/polaris/tasks/ocean/single_column/forward.py @@ -80,12 +80,20 @@ def __init__( self.add_yaml_file('polaris.ocean.config', 'output.yaml') + self.add_input_file( + filename='mesh.nc', + target='../init/initial_state.nc', + # filename='mesh.nc', target='../init/culled_mesh.nc' + ) self.add_input_file( filename='init.nc', target='../init/initial_state.nc' ) self.add_input_file( filename='graph.info', target='../init/culled_graph.info' ) + self.add_input_file( + filename='forcing.nc', target='../init/initial_state.nc' + ) self.add_yaml_file('polaris.tasks.ocean.single_column', 'forward.yaml') self.add_yaml_file( diff --git a/polaris/tasks/ocean/single_column/forward.yaml b/polaris/tasks/ocean/single_column/forward.yaml index 71c8296f0f..4cda771245 100644 --- a/polaris/tasks/ocean/single_column/forward.yaml +++ b/polaris/tasks/ocean/single_column/forward.yaml @@ -4,7 +4,7 @@ ocean: time_integration: config_dt: 0000_00:10:00 forcing: - config_use_bulk_wind_stress: false + config_use_bulk_wind_stress: true mpas-ocean: run_modes: @@ -13,7 +13,7 @@ mpas-ocean: config_btr_dt: 0000_00:00:30 streams: mesh: - filename_template: init.nc + filename_template: mesh.nc input: filename_template: init.nc restart: {} From a603d6943a4afedbb0e3d438eb8e9d17ecc856d0 Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Wed, 14 Jan 2026 13:27:01 -0600 Subject: [PATCH 29/47] Use viz argument to designate all output files --- .../ocean/single_column/ekman/__init__.py | 6 +- .../tasks/ocean/single_column/ekman/ekman.cfg | 5 ++ polaris/tasks/ocean/single_column/viz.py | 89 +++++++++---------- .../ocean/single_column/vmix/__init__.py | 1 + .../ocean/single_column/vmix/forward.yaml | 6 +- .../tasks/ocean/single_column/vmix/vmix.cfg | 5 ++ 6 files changed, 63 insertions(+), 49 deletions(-) diff --git a/polaris/tasks/ocean/single_column/ekman/__init__.py b/polaris/tasks/ocean/single_column/ekman/__init__.py index 7c4e704540..85c43af9ee 100644 --- a/polaris/tasks/ocean/single_column/ekman/__init__.py +++ b/polaris/tasks/ocean/single_column/ekman/__init__.py @@ -59,6 +59,10 @@ def __init__(self, component, config, init, indir): ) self.add_step( - Viz(component=component, indir=self.subdir), + Viz( + component=component, + indir=self.subdir, + comparisons={'forward': '../forward_constant'}, + ), run_by_default=False, ) diff --git a/polaris/tasks/ocean/single_column/ekman/ekman.cfg b/polaris/tasks/ocean/single_column/ekman/ekman.cfg index 8720d2bb08..ac837d8541 100644 --- a/polaris/tasks/ocean/single_column/ekman/ekman.cfg +++ b/polaris/tasks/ocean/single_column/ekman/ekman.cfg @@ -3,6 +3,11 @@ # Bottom depth bottom_depth = 100. +[single_column] + +# Run duration in days +run_duration = 5. + [single_column_ekman] # Constant vertical eddy diffusivity diff --git a/polaris/tasks/ocean/single_column/viz.py b/polaris/tasks/ocean/single_column/viz.py index 4a934b9b6e..5de0fdbfd4 100644 --- a/polaris/tasks/ocean/single_column/viz.py +++ b/polaris/tasks/ocean/single_column/viz.py @@ -35,12 +35,13 @@ def __init__( """ super().__init__(component=component, name='viz', indir=indir) self.ideal_age = ideal_age - self.comparisons = comparisons if comparisons else dict() - self.add_input_file( - filename='initial_state.nc', target='../init/initial_state.nc' + self.comparisons = ( + dict(comparisons) + if comparisons + else {'forward': '../forward/output.nc'} ) self.add_input_file( - filename='output.nc', target='../forward/output.nc' + filename='initial_state.nc', target='../init/initial_state.nc' ) for comparison_name, comparison_path in self.comparisons.items(): self.add_input_file( @@ -57,51 +58,39 @@ def run(self): ds_init = self.open_model_dataset('initial_state.nc') ds_init = ds_init.isel(Time=0) + if 'zMid' in ds_init: + z_mid_init = ds_init['zMid'].mean(dim='nCells') + else: + comparison_name = next(iter(self.comparisons)) + ds_comp = self.open_model_dataset( + f'{comparison_name}.nc', decode_times=False + ) + z_mid_init = ds_comp['zMid'].isel(Time=0).mean(dim='nCells') - ds = self.open_model_dataset('output.nc', decode_times=False) - t_arr = get_days_since_start(ds) - t_index = np.argmin(np.abs(t_arr - 1.0)) # index nearest 1 day - t_days = float(t_arr[t_index]) - ds_final = ds.isel(Time=t_index) + section = self.config['single_column'] + t_target = section.getfloat('run_duration') # Plot temperature and salinity profiles - title = f'final time = {t_days:2.1g} days' - print(f't_index = {t_index}, t_days = {t_days}') fields = {'temperature': 'degC', 'salinity': 'PSU'} if ideal_age: # Include age tracer fields['iAge'] = 'seconds' - z_mid_init = ds['zMid'].isel(Time=0).mean(dim='nCells') - z_mid_final = ds_final['zMid'].mean(dim='nCells') for field_name, field_units in fields.items(): if field_name not in ds_init.keys(): raise ValueError( f'{field_name} not present in initial_state.nc' ) - if field_name not in ds_final.keys(): - raise ValueError(f'{field_name} not present in output.nc') var_init = ds_init[field_name].mean(dim='nCells') - var_final = ds_final[field_name].mean(dim='nCells') - print('Size of variables to plot') - print( - f'Change of {field_name} at the surface: ' - f'{var_final.values[0] - var_init.values[0]}' - ) - print( - f'Change of {field_name} at the bottom: ' - f'{var_final.values[-1] - var_init.values[-1]}' - ) plt.figure(figsize=(3, 5)) ax = plt.subplot(111) - ax.plot(var_init, z_mid_init, '--k', label='initial') - ax.plot(var_final, z_mid_final, '-k', label='final') for comparison_name, _ in self.comparisons.items(): ds_comp = self.open_model_dataset( f'{comparison_name}.nc', decode_times=False ) + ax.plot(var_init, z_mid_init, '--k', label='initial') t_arr = get_days_since_start(ds_comp) - t_index = np.argmin(np.abs(t_arr - 1.0)) # index nearest 1 day + t_index = np.argmin(np.abs(t_arr - t_target)) t_days = float(t_arr[t_index]) print(f't_index = {t_index}, t_days = {t_days}') ds_comp = ds_comp.isel(Time=t_index) @@ -110,29 +99,39 @@ def run(self): f'{field_name} not present in {comparison_name}.nc' ) var_comp = ds_comp[field_name].mean(dim='nCells') + z_mid_final = ds_comp['zMid'].mean(dim='nCells') ax.plot(var_comp, z_mid_final, '-r', label=comparison_name) + title = f'final time = {t_days:2.1g} days' ax.set_xlabel(f'{field_name} ({field_units})') ax.set_ylabel('z (m)') - # ax.legend() + ax.legend(loc='lower right') plt.title(title) plt.tight_layout(pad=0.5) plt.savefig(f'{field_name}.png') plt.close() # Plot velocity profiles - if 'velocityZonal' and 'velocityMeridional' in ds.keys(): - u = ds['velocityZonal'].mean(dim='nCells') - v = ds['velocityMeridional'].mean(dim='nCells') - u_final = u.isel(Time=t_index) - v_final = v.isel(Time=t_index) - plt.figure(figsize=(3, 5)) - ax = plt.subplot(111) - ax.plot(u_final, z_mid_final, '-k', label='u') - ax.plot(v_final, z_mid_final, '-b', label='v') - ax.set_xlabel('Velocity (m/s)') - ax.set_ylabel('z (m)') - ax.legend() - plt.title(title) - plt.tight_layout(pad=0.5) - plt.savefig('velocity.png') - plt.close() + plt.figure(figsize=(3, 5)) + ax = plt.subplot(111) + for comparison_name, _ in self.comparisons.items(): + ds_comp = self.open_model_dataset( + f'{comparison_name}.nc', decode_times=False + ) + t_arr = get_days_since_start(ds_comp) + t_index = np.argmin(np.abs(t_arr - t_target)) + t_days = float(t_arr[t_index]) + print(f't_index = {t_index}, t_days = {t_days}') + ds_comp = ds_comp.isel(Time=t_index) + z_mid_final = ds_comp['zMid'].mean(dim='nCells') + if 'velocityZonal' and 'velocityMeridional' in ds_comp.keys(): + u_final = ds_comp['velocityZonal'].mean(dim='nCells') + v_final = ds_comp['velocityMeridional'].mean(dim='nCells') + ax.plot(u_final, z_mid_final, '-k', label='u') + ax.plot(v_final, z_mid_final, '-b', label='v') + ax.set_xlabel('Velocity (m/s)') + ax.set_ylabel('z (m)') + ax.legend() + plt.title(title) + plt.tight_layout(pad=0.5) + plt.savefig('velocity.png') + plt.close() diff --git a/polaris/tasks/ocean/single_column/vmix/__init__.py b/polaris/tasks/ocean/single_column/vmix/__init__.py index e1317af197..11411bd9e9 100644 --- a/polaris/tasks/ocean/single_column/vmix/__init__.py +++ b/polaris/tasks/ocean/single_column/vmix/__init__.py @@ -62,6 +62,7 @@ def __init__(self, component, config, init, indir, name='vmix'): component=component, indir=f'{indir}/{name}', comparisons={ + 'control': '../forward', 'no_vadv': '../forward_no_vadv', 'constant': '../forward_constant', }, diff --git a/polaris/tasks/ocean/single_column/vmix/forward.yaml b/polaris/tasks/ocean/single_column/vmix/forward.yaml index 4ccd814ce0..afd70c527d 100644 --- a/polaris/tasks/ocean/single_column/vmix/forward.yaml +++ b/polaris/tasks/ocean/single_column/vmix/forward.yaml @@ -1,6 +1,6 @@ ocean: time_management: - config_run_duration: 0001_00:00:00 + config_run_duration: 0010_00:00:00 hmix_del4: config_use_mom_del4: false eos: @@ -16,8 +16,8 @@ mpas-ocean: config_use_activeTracers_surface_restoring: true config_use_activeTracers_interior_restoring: true cvmix: - config_cvmix_shear_mixing_scheme: PP config_use_cvmix_kpp: false + config_cvmix_shear_mixing_scheme: PP streams: KPP_testing: {} @@ -33,7 +33,7 @@ Omega: PresForceTendencyEnable: false PresGradForceTendencyEnable: false GeoptGradTendencyEnable: false - WindForcingTendencyEnable: false + WindForcingTendencyEnable: true BottomDragTendencyEnable: false TracerHorzAdvTendencyEnable: false TracerDiffTendencyEnable: false diff --git a/polaris/tasks/ocean/single_column/vmix/vmix.cfg b/polaris/tasks/ocean/single_column/vmix/vmix.cfg index 7394d9c777..937e6966fd 100644 --- a/polaris/tasks/ocean/single_column/vmix/vmix.cfg +++ b/polaris/tasks/ocean/single_column/vmix/vmix.cfg @@ -1,3 +1,8 @@ # stable_stratification.cfg # evap.cfg # wind.cfg + +[single_column] + +# Run duration in days +run_duration = 10. From e086d2565188bf9989d0f9da07ce48b52cfe5988 Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Wed, 14 Jan 2026 13:30:55 -0600 Subject: [PATCH 30/47] WIP troubleshoot vmix config options --- polaris/tasks/ocean/single_column/vmix/forward.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/polaris/tasks/ocean/single_column/vmix/forward.yaml b/polaris/tasks/ocean/single_column/vmix/forward.yaml index afd70c527d..7e63a586f9 100644 --- a/polaris/tasks/ocean/single_column/vmix/forward.yaml +++ b/polaris/tasks/ocean/single_column/vmix/forward.yaml @@ -13,10 +13,11 @@ mpas-ocean: config_use_frazil_ice_formation: true tracer_forcing_activeTracers: config_use_activeTracers_surface_bulk_forcing: true - config_use_activeTracers_surface_restoring: true - config_use_activeTracers_interior_restoring: true + config_use_activeTracers_surface_restoring: false + config_use_activeTracers_interior_restoring: false cvmix: config_use_cvmix_kpp: false + config_cvmix_background_viscosity: 1e-2 config_cvmix_shear_mixing_scheme: PP streams: KPP_testing: {} From 5bf05ee3001fed2f267f80e9b9b6fea053f99958 Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Wed, 14 Jan 2026 13:31:13 -0600 Subject: [PATCH 31/47] WIP troubleshoot vmix stable config options --- .../ocean/single_column/stable_stratification.cfg | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/polaris/tasks/ocean/single_column/stable_stratification.cfg b/polaris/tasks/ocean/single_column/stable_stratification.cfg index 9f749bd918..9e2fe89b92 100644 --- a/polaris/tasks/ocean/single_column/stable_stratification.cfg +++ b/polaris/tasks/ocean/single_column/stable_stratification.cfg @@ -2,11 +2,18 @@ # config options for single column testcases [single_column] -# Temperature gradient below the mixed layer -temperature_gradient_interior = 0.01 +# temperature gradient below the mixed layer +temperature_gradient_interior = 0.005 # Depth of the temperature mixed layer -mixed_layer_depth_temperature = 25.0 +mixed_layer_depth_temperature = 0.0 # The salinity below the mixed layer -salinity_difference_across_mixed_layer = 1.0 +salinity_difference_across_mixed_layer = 0.0 + +# Depth of the temperature mixed layer +mixed_layer_depth_salinity = 0.0 + +# Temperature gradient below the mixed layer +#salinity_gradient_interior = -0.001 +salinity_gradient_interior = 0.0 From 1782615949761e72a3956c9cb72a76986d50fb0c Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Fri, 16 Jan 2026 13:54:43 -0600 Subject: [PATCH 32/47] Use mid-lat settings for stable stratification --- polaris/tasks/ocean/single_column/stable_stratification.cfg | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/polaris/tasks/ocean/single_column/stable_stratification.cfg b/polaris/tasks/ocean/single_column/stable_stratification.cfg index 9e2fe89b92..3c965e67b7 100644 --- a/polaris/tasks/ocean/single_column/stable_stratification.cfg +++ b/polaris/tasks/ocean/single_column/stable_stratification.cfg @@ -3,7 +3,7 @@ [single_column] # temperature gradient below the mixed layer -temperature_gradient_interior = 0.005 +temperature_gradient_interior = 0.1 # Depth of the temperature mixed layer mixed_layer_depth_temperature = 0.0 @@ -15,5 +15,4 @@ salinity_difference_across_mixed_layer = 0.0 mixed_layer_depth_salinity = 0.0 # Temperature gradient below the mixed layer -#salinity_gradient_interior = -0.001 salinity_gradient_interior = 0.0 From 953fc62da4fa750eaa9cda01937606ca0a521cb9 Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Sun, 18 Jan 2026 17:17:29 -0600 Subject: [PATCH 33/47] WIP change unstable stratification settings --- .../tasks/ocean/single_column/unstable_stratification.cfg | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/polaris/tasks/ocean/single_column/unstable_stratification.cfg b/polaris/tasks/ocean/single_column/unstable_stratification.cfg index 6221f1f66a..d3831faafb 100644 --- a/polaris/tasks/ocean/single_column/unstable_stratification.cfg +++ b/polaris/tasks/ocean/single_column/unstable_stratification.cfg @@ -2,10 +2,13 @@ # config options for single column testcases [single_column] -temperature_difference_across_mixed_layer = -1.0 +# Use this to test temperature and salinity +#temperature_difference_across_mixed_layer = 1.0 +#Use this to test salinity only +temperature_difference_across_mixed_layer = 0.0 # Salinity gradient below the mixed layer -salinity_gradient_interior = 0.01 +salinity_gradient_interior = -0.01 # Depth of the temperature mixed layer mixed_layer_depth_salinity = 25.0 From a72f422713c0cf7456ff916d7b6c4ce8c824745f Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Sun, 18 Jan 2026 17:24:55 -0600 Subject: [PATCH 34/47] Make comparison curves more differentiable --- polaris/tasks/ocean/single_column/viz.py | 45 +++++++++++++++++------- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/polaris/tasks/ocean/single_column/viz.py b/polaris/tasks/ocean/single_column/viz.py index 5de0fdbfd4..4709d1af0a 100644 --- a/polaris/tasks/ocean/single_column/viz.py +++ b/polaris/tasks/ocean/single_column/viz.py @@ -82,17 +82,18 @@ def run(self): ) var_init = ds_init[field_name].mean(dim='nCells') - plt.figure(figsize=(3, 5)) - ax = plt.subplot(111) - for comparison_name, _ in self.comparisons.items(): + fig = plt.figure(figsize=(3, 5)) + colors = ['b', 'r', 'darkgreen'] + plt.plot(var_init, z_mid_init, '--k', label='initial') + for comparison_name, color in zip( + self.comparisons.keys(), colors, strict=False + ): ds_comp = self.open_model_dataset( f'{comparison_name}.nc', decode_times=False ) - ax.plot(var_init, z_mid_init, '--k', label='initial') t_arr = get_days_since_start(ds_comp) t_index = np.argmin(np.abs(t_arr - t_target)) t_days = float(t_arr[t_index]) - print(f't_index = {t_index}, t_days = {t_days}') ds_comp = ds_comp.isel(Time=t_index) if field_name not in ds_comp.keys(): raise ValueError( @@ -100,11 +101,17 @@ def run(self): ) var_comp = ds_comp[field_name].mean(dim='nCells') z_mid_final = ds_comp['zMid'].mean(dim='nCells') - ax.plot(var_comp, z_mid_final, '-r', label=comparison_name) + plt.plot( + var_comp, + z_mid_final, + '-', + color=color, + label=comparison_name, + ) title = f'final time = {t_days:2.1g} days' - ax.set_xlabel(f'{field_name} ({field_units})') - ax.set_ylabel('z (m)') - ax.legend(loc='lower right') + plt.xlabel(f'{field_name} ({field_units})') + plt.ylabel('z (m)') + fig.legend(loc='outside lower right') plt.title(title) plt.tight_layout(pad=0.5) plt.savefig(f'{field_name}.png') @@ -113,7 +120,9 @@ def run(self): # Plot velocity profiles plt.figure(figsize=(3, 5)) ax = plt.subplot(111) - for comparison_name, _ in self.comparisons.items(): + for comparison_name, color in zip( + self.comparisons.keys(), colors, strict=False + ): ds_comp = self.open_model_dataset( f'{comparison_name}.nc', decode_times=False ) @@ -126,8 +135,20 @@ def run(self): if 'velocityZonal' and 'velocityMeridional' in ds_comp.keys(): u_final = ds_comp['velocityZonal'].mean(dim='nCells') v_final = ds_comp['velocityMeridional'].mean(dim='nCells') - ax.plot(u_final, z_mid_final, '-k', label='u') - ax.plot(v_final, z_mid_final, '-b', label='v') + ax.plot( + u_final, + z_mid_final, + '-', + color=color, + label=f'u {comparison_name}', + ) + ax.plot( + v_final, + z_mid_final, + '--', + color=color, + label=f'v {comparison_name}', + ) ax.set_xlabel('Velocity (m/s)') ax.set_ylabel('z (m)') ax.legend() From 95591b7e6f043787b55cc0aef1ba8d9cf7a81695 Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Wed, 21 Jan 2026 16:46:00 -0600 Subject: [PATCH 35/47] Update namelist options --- polaris/tasks/ocean/single_column/forward.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/polaris/tasks/ocean/single_column/forward.yaml b/polaris/tasks/ocean/single_column/forward.yaml index 4cda771245..1a995a5fc0 100644 --- a/polaris/tasks/ocean/single_column/forward.yaml +++ b/polaris/tasks/ocean/single_column/forward.yaml @@ -11,6 +11,9 @@ mpas-ocean: config_ocean_run_mode: forward split_explicit_ts: config_btr_dt: 0000_00:00:30 + forcing: + config_bulk_wind_stress_interp_isotropic: true + config_use_bulk_thickness_flux: true streams: mesh: filename_template: mesh.nc From e0a99e3fe2fdaf26bc8d6e1bca3686a04e822004 Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Wed, 21 Jan 2026 16:46:32 -0600 Subject: [PATCH 36/47] Use no_vadv with constant diffusivity tests --- polaris/tasks/ocean/single_column/vmix/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/polaris/tasks/ocean/single_column/vmix/__init__.py b/polaris/tasks/ocean/single_column/vmix/__init__.py index 11411bd9e9..a9d9479c06 100644 --- a/polaris/tasks/ocean/single_column/vmix/__init__.py +++ b/polaris/tasks/ocean/single_column/vmix/__init__.py @@ -54,6 +54,7 @@ def __init__(self, component, config, init, indir, name='vmix'): validate_vars=validate_vars, task_name='vmix', constant_diff=True, + enable_vadv=False, ) ) @@ -64,7 +65,7 @@ def __init__(self, component, config, init, indir, name='vmix'): comparisons={ 'control': '../forward', 'no_vadv': '../forward_no_vadv', - 'constant': '../forward_constant', + 'constant': '../forward_no_vadv_constant', }, ), run_by_default=False, From 1ad256c612d721cc1e1786577a0c975c9f34cfd9 Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Wed, 21 Jan 2026 16:53:51 -0600 Subject: [PATCH 37/47] Make step with vadv optional --- polaris/tasks/ocean/single_column/viz.py | 6 +++ .../ocean/single_column/vmix/__init__.py | 37 ++++++++++++------- 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/polaris/tasks/ocean/single_column/viz.py b/polaris/tasks/ocean/single_column/viz.py index 4709d1af0a..784e06b7bc 100644 --- a/polaris/tasks/ocean/single_column/viz.py +++ b/polaris/tasks/ocean/single_column/viz.py @@ -1,3 +1,5 @@ +import os + import matplotlib.pyplot as plt import numpy as np @@ -88,6 +90,8 @@ def run(self): for comparison_name, color in zip( self.comparisons.keys(), colors, strict=False ): + if not os.path.exists(f'{comparison_name}.nc'): + continue ds_comp = self.open_model_dataset( f'{comparison_name}.nc', decode_times=False ) @@ -123,6 +127,8 @@ def run(self): for comparison_name, color in zip( self.comparisons.keys(), colors, strict=False ): + if not os.path.exists(f'{comparison_name}.nc'): + continue ds_comp = self.open_model_dataset( f'{comparison_name}.nc', decode_times=False ) diff --git a/polaris/tasks/ocean/single_column/vmix/__init__.py b/polaris/tasks/ocean/single_column/vmix/__init__.py index a9d9479c06..8151e15b54 100644 --- a/polaris/tasks/ocean/single_column/vmix/__init__.py +++ b/polaris/tasks/ocean/single_column/vmix/__init__.py @@ -31,19 +31,31 @@ def __init__(self, component, config, init, indir, name='vmix'): 'layerThickness', 'normalVelocity', ] - for enable_vadv in [True, False]: - self.add_step( - Forward( - component=component, - indir=f'{indir}/{name}', - ntasks=1, - min_tasks=1, - openmp_threads=1, - validate_vars=validate_vars, - task_name='vmix', - enable_vadv=enable_vadv, - ) + self.add_step( + Forward( + component=component, + indir=f'{indir}/{name}', + ntasks=1, + min_tasks=1, + openmp_threads=1, + validate_vars=validate_vars, + task_name='vmix', + enable_vadv=True, + ), + run_by_default=False, + ) + self.add_step( + Forward( + component=component, + indir=f'{indir}/{name}', + ntasks=1, + min_tasks=1, + openmp_threads=1, + validate_vars=validate_vars, + task_name='vmix', + enable_vadv=False, ) + ) self.add_step( Forward( component=component, @@ -63,7 +75,6 @@ def __init__(self, component, config, init, indir, name='vmix'): component=component, indir=f'{indir}/{name}', comparisons={ - 'control': '../forward', 'no_vadv': '../forward_no_vadv', 'constant': '../forward_no_vadv_constant', }, From 9d04334fabcf438299bb9430374c2fb4a8bb2de1 Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Wed, 21 Jan 2026 16:54:26 -0600 Subject: [PATCH 38/47] Always run viz step --- polaris/tasks/ocean/single_column/vmix/__init__.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/polaris/tasks/ocean/single_column/vmix/__init__.py b/polaris/tasks/ocean/single_column/vmix/__init__.py index 8151e15b54..86150a02e9 100644 --- a/polaris/tasks/ocean/single_column/vmix/__init__.py +++ b/polaris/tasks/ocean/single_column/vmix/__init__.py @@ -78,6 +78,5 @@ def __init__(self, component, config, init, indir, name='vmix'): 'no_vadv': '../forward_no_vadv', 'constant': '../forward_no_vadv_constant', }, - ), - run_by_default=False, + ) ) From 37ced8a54f67edd1fbc40ff5bdd77a554f43cfb3 Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Mon, 26 Jan 2026 17:17:44 -0600 Subject: [PATCH 39/47] use zmid utility --- polaris/tasks/ocean/single_column/viz.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/polaris/tasks/ocean/single_column/viz.py b/polaris/tasks/ocean/single_column/viz.py index 784e06b7bc..271d1e93b6 100644 --- a/polaris/tasks/ocean/single_column/viz.py +++ b/polaris/tasks/ocean/single_column/viz.py @@ -5,6 +5,7 @@ from polaris.ocean.model import OceanIOStep from polaris.ocean.time import get_days_since_start +from polaris.ocean.vertical.diagnostics import depth_from_thickness from polaris.viz import use_mplstyle @@ -104,11 +105,13 @@ def run(self): f'{field_name} not present in {comparison_name}.nc' ) var_comp = ds_comp[field_name].mean(dim='nCells') - z_mid_final = ds_comp['zMid'].mean(dim='nCells') + # TODO use this line when Omega zMid is correct + # z_mid_final = ds_comp['zMid'].mean(dim='nCells') + z_mid_final = depth_from_thickness(ds_comp).mean(dim='nCells') plt.plot( var_comp, z_mid_final, - '-', + '.', color=color, label=comparison_name, ) From 64a138ad0495fb269853438898abc0c47dc5b04b Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Fri, 30 Jan 2026 12:27:34 -0600 Subject: [PATCH 40/47] Support fetching time from xtime variable --- polaris/ocean/time.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/polaris/ocean/time.py b/polaris/ocean/time.py index 38b61858e8..8f2bf9e5a7 100644 --- a/polaris/ocean/time.py +++ b/polaris/ocean/time.py @@ -1,3 +1,5 @@ +from datetime import datetime + import numpy as np import pandas as pd @@ -9,6 +11,19 @@ def get_days_since_start(ds): """ if 'daysSinceStartOfSim' in ds.keys(): t_arr = ds.daysSinceStartOfSim.values.astype(float) + elif 'xtime' in ds.keys(): + timestamps = [] + for time_str in ds.xtime.values.astype(str): + try: + timestamp = datetime.strptime(time_str, '%Y-%m-%d_%H:%M:%S.%f') + except ValueError: + timestamp = datetime.strptime(time_str, '%Y-%m-%d_%H:%M:%S') + timestamps.append(timestamp) + # Calculate seconds since the first timestamp + seconds_since_start = [ + (ts - timestamps[0]).total_seconds() for ts in timestamps + ] + t_arr = np.array(seconds_since_start, dtype=float) / 86400.0 elif 'Time' in ds.keys(): t_vals = ds['Time'].values t_pd = pd.to_datetime(t_vals) From 4922ae3f69c05bc31b7acafec2609c7b52efe355 Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Fri, 30 Jan 2026 17:22:56 -0600 Subject: [PATCH 41/47] Clean-up and generalize viz step --- polaris/tasks/ocean/single_column/viz.py | 224 ++++++++++++++--------- 1 file changed, 135 insertions(+), 89 deletions(-) diff --git a/polaris/tasks/ocean/single_column/viz.py b/polaris/tasks/ocean/single_column/viz.py index 271d1e93b6..438f55983d 100644 --- a/polaris/tasks/ocean/single_column/viz.py +++ b/polaris/tasks/ocean/single_column/viz.py @@ -8,6 +8,8 @@ from polaris.ocean.vertical.diagnostics import depth_from_thickness from polaris.viz import use_mplstyle +# TODO import rho_0 from constants + class Viz(OceanIOStep): """ @@ -20,6 +22,7 @@ def __init__( indir, ideal_age=False, comparisons=None, + variables=None, ): """ Create the step @@ -35,14 +38,31 @@ def __init__( ideal_age : bool, optional Whether the initial condition should include the ideal age tracer + + comparisons : dict, optional + A dictionary of comparison datasets to use for validation + + variables : dict, optional + A dictionary of variables to plot along with their units """ super().__init__(component=component, name='viz', indir=indir) - self.ideal_age = ideal_age + if ideal_age: + # Include age tracer + variables['iAge'] = 'seconds' self.comparisons = ( dict(comparisons) if comparisons else {'forward': '../forward/output.nc'} ) + self.variables = ( + dict(variables) + if variables + else { + 'temperature': 'degC', + 'salinity': 'PSU', + 'velocity': 'm s$^{-1}$', + } + ) self.add_input_file( filename='initial_state.nc', target='../init/initial_state.nc' ) @@ -51,13 +71,16 @@ def __init__( filename=f'{comparison_name}.nc', target=f'{comparison_path}/output.nc', ) + self.add_input_file( + filename=f'{comparison_name}_diags.nc', + target=f'{comparison_path}/output/KPP_test.0001-01-01_00.00.00.nc', + ) def run(self): """ Run this step of the test case """ use_mplstyle() - ideal_age = self.ideal_age ds_init = self.open_model_dataset('initial_state.nc') ds_init = ds_init.isel(Time=0) @@ -72,96 +95,119 @@ def run(self): section = self.config['single_column'] t_target = section.getfloat('run_duration') + # t_target = 0. # Plot temperature and salinity profiles - fields = {'temperature': 'degC', 'salinity': 'PSU'} - if ideal_age: - # Include age tracer - fields['iAge'] = 'seconds' - for field_name, field_units in fields.items(): - if field_name not in ds_init.keys(): - raise ValueError( - f'{field_name} not present in initial_state.nc' - ) - var_init = ds_init[field_name].mean(dim='nCells') - + for field_name, field_units in self.variables.items(): fig = plt.figure(figsize=(3, 5)) colors = ['b', 'r', 'darkgreen'] - plt.plot(var_init, z_mid_init, '--k', label='initial') - for comparison_name, color in zip( - self.comparisons.keys(), colors, strict=False - ): - if not os.path.exists(f'{comparison_name}.nc'): + if field_name == 'velocity': + if ( + 'velocityZonal' not in ds_comp.keys() + and 'velocityMeridional' not in ds_comp.keys() + ): continue - ds_comp = self.open_model_dataset( - f'{comparison_name}.nc', decode_times=False - ) - t_arr = get_days_since_start(ds_comp) - t_index = np.argmin(np.abs(t_arr - t_target)) - t_days = float(t_arr[t_index]) - ds_comp = ds_comp.isel(Time=t_index) - if field_name not in ds_comp.keys(): - raise ValueError( - f'{field_name} not present in {comparison_name}.nc' + ax = plt.subplot(111) + for comparison_name, color in zip( + self.comparisons.keys(), colors, strict=False + ): + if not os.path.exists(f'{comparison_name}.nc'): + continue + ds_comp = self.open_model_dataset( + f'{comparison_name}.nc', decode_times=False ) - var_comp = ds_comp[field_name].mean(dim='nCells') - # TODO use this line when Omega zMid is correct - # z_mid_final = ds_comp['zMid'].mean(dim='nCells') - z_mid_final = depth_from_thickness(ds_comp).mean(dim='nCells') - plt.plot( - var_comp, - z_mid_final, - '.', - color=color, - label=comparison_name, - ) - title = f'final time = {t_days:2.1g} days' - plt.xlabel(f'{field_name} ({field_units})') - plt.ylabel('z (m)') - fig.legend(loc='outside lower right') - plt.title(title) - plt.tight_layout(pad=0.5) - plt.savefig(f'{field_name}.png') - plt.close() - - # Plot velocity profiles - plt.figure(figsize=(3, 5)) - ax = plt.subplot(111) - for comparison_name, color in zip( - self.comparisons.keys(), colors, strict=False - ): - if not os.path.exists(f'{comparison_name}.nc'): - continue - ds_comp = self.open_model_dataset( - f'{comparison_name}.nc', decode_times=False - ) - t_arr = get_days_since_start(ds_comp) - t_index = np.argmin(np.abs(t_arr - t_target)) - t_days = float(t_arr[t_index]) - print(f't_index = {t_index}, t_days = {t_days}') - ds_comp = ds_comp.isel(Time=t_index) - z_mid_final = ds_comp['zMid'].mean(dim='nCells') - if 'velocityZonal' and 'velocityMeridional' in ds_comp.keys(): - u_final = ds_comp['velocityZonal'].mean(dim='nCells') - v_final = ds_comp['velocityMeridional'].mean(dim='nCells') - ax.plot( - u_final, - z_mid_final, - '-', - color=color, - label=f'u {comparison_name}', - ) - ax.plot( - v_final, - z_mid_final, - '--', - color=color, - label=f'v {comparison_name}', - ) - ax.set_xlabel('Velocity (m/s)') - ax.set_ylabel('z (m)') - ax.legend() - plt.title(title) - plt.tight_layout(pad=0.5) - plt.savefig('velocity.png') - plt.close() + t_arr = get_days_since_start(ds_comp) + t_index = np.argmin(np.abs(t_arr - t_target)) + t_days = float(t_arr[t_index]) + title = f'final time = {t_days:2.1g} days' + self.logger.info( + f'Plot {field_name} for {comparison_name} at {t_days} ' + 'days' + ) + ds_comp = ds_comp.isel(Time=t_index) + z_mid_final = ds_comp['zMid'].mean(dim='nCells') + u_final = ds_comp['velocityZonal'].mean(dim='nCells') + v_final = ds_comp['velocityMeridional'].mean(dim='nCells') + ax.plot( + u_final, + z_mid_final, + '-', + color=color, + label=f'u {comparison_name}', + ) + ax.plot( + v_final, + z_mid_final, + '--', + color=color, + label=f'v {comparison_name}', + ) + ax.set_xlabel('Velocity (m/s)') + ax.set_ylabel('z (m)') + ax.legend() + plt.title(title) + plt.tight_layout(pad=0.5) + plt.savefig('velocity.png') + plt.close() + else: + # Plot initial state if available + if field_name in ds_init.keys(): + var_init = ds_init[field_name].mean(dim='nCells') + plt.plot(var_init, z_mid_init, '--k', label='initial') + + for comparison_name, color in zip( + self.comparisons.keys(), colors, strict=False + ): + if not os.path.exists(f'{comparison_name}.nc'): + continue + # Look for field_name in either output file + ds_comp = self.open_model_dataset( + f'{comparison_name}.nc', decode_times=False + ) + ds_diags = self.open_model_dataset( + f'{comparison_name}_diags.nc', decode_times=False + ) + if field_name in ds_comp.keys(): + ds = ds_comp + elif field_name in ds_diags.keys(): + ds = ds_diags + else: + self.logger.warn( + f'{field_name} not present in {comparison_name}.nc' + ) + continue + t_arr = get_days_since_start(ds) + t_index = np.argmin(np.abs(t_arr - t_target)) + t_days = float(t_arr[t_index]) + ds_final = ds.isel(Time=t_index) + var_comp = ds_final[field_name].mean(dim='nCells') + if 'nVertLevelsP1' in var_comp.dims: + var_comp = var_comp.isel(nVertLevelsP1=slice(0, -1)) + # TODO delete this line when MPAS-O bug is fixed + if field_name == 'RiTopOfCell': + var_comp[0] = np.nan + # TODO use this line when Omega zMid is correct + # z_mid_final = ds_comp['zMid'].mean(dim='nCells') + z_mid_final = depth_from_thickness(ds_final).mean( + dim='nCells' + ) + plt.plot( + var_comp, + z_mid_final, + '-', + color=color, + label=comparison_name, + ) + title = f'final time = {t_days:2.1g} days' + plt.ylim([-100, 0]) + if field_name == 'temperature': + plt.xlim([15, 20]) + else: + plt.xlim(auto=True) + plt.xlabel(f'{field_name} ({field_units})') + plt.ylabel('z (m)') + fig.legend(loc='center right') + plt.title(title) + plt.tight_layout(pad=0.5) + plt.savefig(f'{field_name}.png') + plt.close() From 9585bed75a618ab323b902cf1d65e04a0c761db6 Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Fri, 30 Jan 2026 17:33:28 -0600 Subject: [PATCH 42/47] Add analysis step for wind-driven mixing --- .../ocean/single_column/vmix/__init__.py | 28 ++++++-- .../ocean/single_column/vmix/analysis.py | 72 +++++++++++++++++++ 2 files changed, 96 insertions(+), 4 deletions(-) create mode 100644 polaris/tasks/ocean/single_column/vmix/analysis.py diff --git a/polaris/tasks/ocean/single_column/vmix/__init__.py b/polaris/tasks/ocean/single_column/vmix/__init__.py index 86150a02e9..80be3c36cb 100644 --- a/polaris/tasks/ocean/single_column/vmix/__init__.py +++ b/polaris/tasks/ocean/single_column/vmix/__init__.py @@ -1,6 +1,7 @@ from polaris import Task from polaris.tasks.ocean.single_column.forward import Forward from polaris.tasks.ocean.single_column.viz import Viz +from polaris.tasks.ocean.single_column.vmix.analysis import Analysis class VMix(Task): @@ -35,19 +36,20 @@ def __init__(self, component, config, init, indir, name='vmix'): Forward( component=component, indir=f'{indir}/{name}', + name='forward_kpp', ntasks=1, min_tasks=1, openmp_threads=1, validate_vars=validate_vars, task_name='vmix', - enable_vadv=True, + enable_vadv=False, ), - run_by_default=False, ) self.add_step( Forward( component=component, indir=f'{indir}/{name}', + name='forward_pp', ntasks=1, min_tasks=1, openmp_threads=1, @@ -75,8 +77,26 @@ def __init__(self, component, config, init, indir, name='vmix'): component=component, indir=f'{indir}/{name}', comparisons={ - 'no_vadv': '../forward_no_vadv', - 'constant': '../forward_no_vadv_constant', + 'kpp': '../forward_kpp_no_vadv', + 'pp': '../forward_pp_no_vadv', + }, + variables={ + 'temperature': 'degC', + 'salinity': 'PSU', + 'velocity': 'm s$^{-1}$', + 'RiTopOfCell': '', + 'BruntVaisalaFreqTop': '$s^{-2}$', + }, + ) + ) + + self.add_step( + Analysis( + component=component, + indir=f'{indir}/{name}', + comparisons={ + 'kpp': '../forward_kpp_no_vadv', + 'pp': '../forward_pp_no_vadv', }, ) ) diff --git a/polaris/tasks/ocean/single_column/vmix/analysis.py b/polaris/tasks/ocean/single_column/vmix/analysis.py new file mode 100644 index 0000000000..5a4afb9c0c --- /dev/null +++ b/polaris/tasks/ocean/single_column/vmix/analysis.py @@ -0,0 +1,72 @@ +import numpy as np + +from polaris.ocean.model import OceanIOStep +from polaris.ocean.time import get_days_since_start + +# TODO import rho_0 from constants + + +class Analysis(OceanIOStep): + """ + A step for analyzing the results of a single-column wind-forced test + """ + + def __init__( + self, + component, + indir, + comparisons=None, + ): + super().__init__(component=component, name='analysis', indir=indir) + self.comparisons = ( + dict(comparisons) + if comparisons + else {'forward': '../forward/output.nc'} + ) + for comparison_name, comparison_path in self.comparisons.items(): + self.add_input_file( + filename=f'{comparison_name}_diags.nc', + target=f'{comparison_path}/output/KPP_test.0001-01-01_00.00.00.nc', + ) + + def run(self): + """ + Run this step of the test case + """ + section = self.config['single_column_forcing'] + wind_stress = np.sqrt( + section.getfloat('wind_stress_zonal') ** 2.0 + + section.getfloat('wind_stress_meridional') ** 2.0 + ) + # u_star = 0.01 + rho_0 = 1026.0 + u_star = wind_stress / rho_0 + # TODO why is this 0 + # u_star = ds_diags_1day['surfaceFrictionVelocity'].mean(dim='nCells') + # TODO compute this based on config parameters + N_sq_init = 1.0e-4 + for comparison_name in self.comparisons.keys(): + ds_diags = self.open_model_dataset( + f'{comparison_name}_diags.nc', decode_times=False + ) + t_target = 1.0 # empirical relationship hold for up to 30h + t_arr = get_days_since_start(ds_diags) + t_index = np.argmin(np.abs(t_arr - t_target)) + t_days = float(t_arr[t_index]) + if abs(t_days - t_target) > (1 / 24): + self.logger.warn( + f'{comparison_name}: Time mismatch \n' + f'expected {t_target}, got {t_days}' + ) + bld_theory = u_star * (15.0 * t_days * 86400.0 / N_sq_init) ** ( + 1 / 3 + ) + ds_diags_1day = ds_diags.isel(Time=t_index) + z_top_final = ds_diags_1day['zTop'].mean(dim='nCells') + N_sq = ds_diags_1day['BruntVaisalaFreqTop'].mean(dim='nCells') + index_bld = int(np.nanargmax(N_sq.values)) + bld = z_top_final.isel(nVertLevels=index_bld) + self.logger.info( + f'{comparison_name}: boundary layer depth ' + f'expected {bld_theory}, actual {bld.values}' + ) From 7d587a20e68cc41adbbeb6b8cdb62f694a10abf1 Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Fri, 30 Jan 2026 20:39:12 -0600 Subject: [PATCH 43/47] fixup viz --- polaris/tasks/ocean/single_column/viz.py | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/polaris/tasks/ocean/single_column/viz.py b/polaris/tasks/ocean/single_column/viz.py index 438f55983d..4a05a18393 100644 --- a/polaris/tasks/ocean/single_column/viz.py +++ b/polaris/tasks/ocean/single_column/viz.py @@ -46,9 +46,6 @@ def __init__( A dictionary of variables to plot along with their units """ super().__init__(component=component, name='viz', indir=indir) - if ideal_age: - # Include age tracer - variables['iAge'] = 'seconds' self.comparisons = ( dict(comparisons) if comparisons @@ -63,6 +60,9 @@ def __init__( 'velocity': 'm s$^{-1}$', } ) + if ideal_age: + # Include age tracer + self.variables['iAge'] = 'seconds' self.add_input_file( filename='initial_state.nc', target='../init/initial_state.nc' ) @@ -179,6 +179,11 @@ def run(self): t_arr = get_days_since_start(ds) t_index = np.argmin(np.abs(t_arr - t_target)) t_days = float(t_arr[t_index]) + if abs(t_days - t_target) > (1 / 24): + self.logger.warn( + f'{comparison_name}: Time mismatch \n' + f'expected {t_target}, got {t_days}' + ) ds_final = ds.isel(Time=t_index) var_comp = ds_final[field_name].mean(dim='nCells') if 'nVertLevelsP1' in var_comp.dims: @@ -188,9 +193,16 @@ def run(self): var_comp[0] = np.nan # TODO use this line when Omega zMid is correct # z_mid_final = ds_comp['zMid'].mean(dim='nCells') - z_mid_final = depth_from_thickness(ds_final).mean( - dim='nCells' - ) + if 'layerThickness' not in ds.keys(): + z_mid_final = z_mid_init + self.logger.warn( + 'Using initial zMid values; may not represent ' + 'plotted state' + ) + else: + z_mid_final = depth_from_thickness(ds_final).mean( + dim='nCells' + ) plt.plot( var_comp, z_mid_final, From f7eebbba1e1264f6ea9268f2ba00cba2f9422bc5 Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Fri, 30 Jan 2026 20:39:54 -0600 Subject: [PATCH 44/47] fixup analysis --- polaris/tasks/ocean/single_column/vmix/analysis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polaris/tasks/ocean/single_column/vmix/analysis.py b/polaris/tasks/ocean/single_column/vmix/analysis.py index 5a4afb9c0c..d9f4dc7289 100644 --- a/polaris/tasks/ocean/single_column/vmix/analysis.py +++ b/polaris/tasks/ocean/single_column/vmix/analysis.py @@ -58,7 +58,7 @@ def run(self): f'{comparison_name}: Time mismatch \n' f'expected {t_target}, got {t_days}' ) - bld_theory = u_star * (15.0 * t_days * 86400.0 / N_sq_init) ** ( + bld_theory = -u_star * (15.0 * t_days * 86400.0 / N_sq_init) ** ( 1 / 3 ) ds_diags_1day = ds_diags.isel(Time=t_index) From 417d5e68f63fa22872cd080760ef8d21878a39e6 Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Fri, 30 Jan 2026 20:41:17 -0600 Subject: [PATCH 45/47] Do not use Ri smoothing --- .../ocean/single_column/vmix/forward.yaml | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/polaris/tasks/ocean/single_column/vmix/forward.yaml b/polaris/tasks/ocean/single_column/vmix/forward.yaml index 7e63a586f9..ee492cb073 100644 --- a/polaris/tasks/ocean/single_column/vmix/forward.yaml +++ b/polaris/tasks/ocean/single_column/vmix/forward.yaml @@ -17,10 +17,37 @@ mpas-ocean: config_use_activeTracers_interior_restoring: false cvmix: config_use_cvmix_kpp: false - config_cvmix_background_viscosity: 1e-2 + config_cvmix_background_diffusion: 0. + config_cvmix_background_viscosity: 0. config_cvmix_shear_mixing_scheme: PP + config_cvmix_num_ri_smooth_loops: 0 streams: - KPP_testing: {} + KPP_testing: + contents: + - mesh + - layerThickness + - tracers + - vertNonLocalFlux + - xtime + - zMid + - zTop + - velocityZonal + - velocityMeridional + - bulkRichardsonNumber + - bulkRichardsonNumberBuoy + - potentialDensity + - unresolvedShear + - boundaryLayerDepth + - surfaceFrictionVelocity + - surfaceBuoyancyForcing + - windStressZonal + - windStressMeridional + - transportVelocityZonal + - transportVelocityMeridional + - RiTopOfCell + - BruntVaisalaFreqTop + - vertViscTopOfCell + - vertDiffTopOfCell Omega: Tendencies: From f375266c3318a598639e53089fba2bed17b33006 Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Fri, 30 Jan 2026 20:43:17 -0600 Subject: [PATCH 46/47] Match parameter values from Van Roekel et al 2018 for vmix_stable --- polaris/tasks/ocean/single_column/stable_stratification.cfg | 2 +- polaris/tasks/ocean/single_column/vmix/vmix.cfg | 2 +- polaris/tasks/ocean/single_column/wind.cfg | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/polaris/tasks/ocean/single_column/stable_stratification.cfg b/polaris/tasks/ocean/single_column/stable_stratification.cfg index 3c965e67b7..92de3c84cb 100644 --- a/polaris/tasks/ocean/single_column/stable_stratification.cfg +++ b/polaris/tasks/ocean/single_column/stable_stratification.cfg @@ -3,7 +3,7 @@ [single_column] # temperature gradient below the mixed layer -temperature_gradient_interior = 0.1 +temperature_gradient_interior = 0.05 # Depth of the temperature mixed layer mixed_layer_depth_temperature = 0.0 diff --git a/polaris/tasks/ocean/single_column/vmix/vmix.cfg b/polaris/tasks/ocean/single_column/vmix/vmix.cfg index 937e6966fd..5f68cf311c 100644 --- a/polaris/tasks/ocean/single_column/vmix/vmix.cfg +++ b/polaris/tasks/ocean/single_column/vmix/vmix.cfg @@ -5,4 +5,4 @@ [single_column] # Run duration in days -run_duration = 10. +run_duration = 1. diff --git a/polaris/tasks/ocean/single_column/wind.cfg b/polaris/tasks/ocean/single_column/wind.cfg index 9daa95b973..057c8c1258 100644 --- a/polaris/tasks/ocean/single_column/wind.cfg +++ b/polaris/tasks/ocean/single_column/wind.cfg @@ -1,4 +1,5 @@ [single_column_forcing] # Zonal surface wind stress over the domain -wind_stress_zonal = 0.1 +# corresponding to friction velocity of 0.01 +wind_stress_zonal = 10.26 From e853f41be4183871c24f6a593d450474cc050d8d Mon Sep 17 00:00:00 2001 From: Carolyn Begeman Date: Fri, 30 Jan 2026 20:49:54 -0600 Subject: [PATCH 47/47] fixup analysis to revert to old comparisons --- .../tasks/ocean/single_column/vmix/__init__.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/polaris/tasks/ocean/single_column/vmix/__init__.py b/polaris/tasks/ocean/single_column/vmix/__init__.py index 80be3c36cb..8aa1c4dfe9 100644 --- a/polaris/tasks/ocean/single_column/vmix/__init__.py +++ b/polaris/tasks/ocean/single_column/vmix/__init__.py @@ -36,20 +36,19 @@ def __init__(self, component, config, init, indir, name='vmix'): Forward( component=component, indir=f'{indir}/{name}', - name='forward_kpp', ntasks=1, min_tasks=1, openmp_threads=1, validate_vars=validate_vars, task_name='vmix', - enable_vadv=False, + enable_vadv=True, ), + run_by_default=False, ) self.add_step( Forward( component=component, indir=f'{indir}/{name}', - name='forward_pp', ntasks=1, min_tasks=1, openmp_threads=1, @@ -77,8 +76,9 @@ def __init__(self, component, config, init, indir, name='vmix'): component=component, indir=f'{indir}/{name}', comparisons={ - 'kpp': '../forward_kpp_no_vadv', - 'pp': '../forward_pp_no_vadv', + 'standard': '../forward', + 'no_vadv': '../forward_no_vadv', + 'constant': '../forward_no_vadv_constant', }, variables={ 'temperature': 'degC', @@ -95,8 +95,9 @@ def __init__(self, component, config, init, indir, name='vmix'): component=component, indir=f'{indir}/{name}', comparisons={ - 'kpp': '../forward_kpp_no_vadv', - 'pp': '../forward_pp_no_vadv', + 'standard': '../forward', + 'no_vadv': '../forward_no_vadv', + 'constant': '../forward_no_vadv_constant', }, ) )