From 9b302910fb26a215201f27add312feaec234fc9d Mon Sep 17 00:00:00 2001 From: Giacomo Capodaglio Date: Tue, 28 Nov 2023 17:20:07 -0800 Subject: [PATCH 01/10] Added LTS option to dam_break and parabolic_bowl --- compass/ocean/tests/dam_break/__init__.py | 11 ++- compass/ocean/tests/dam_break/dam_break.cfg | 5 - .../ocean/tests/dam_break/default/__init__.py | 46 ++++++++-- compass/ocean/tests/dam_break/forward.py | 47 +++++++--- .../ocean/tests/dam_break/initial_state.py | 21 +++-- .../ocean/tests/dam_break/namelist.forward | 2 +- compass/ocean/tests/dam_break/namelist.init | 2 +- .../ocean/tests/dam_break/ramp/__init__.py | 19 +++- compass/ocean/tests/dam_break/streams.forward | 23 ----- compass/ocean/tests/dam_break/streams.init | 25 ----- compass/ocean/tests/dam_break/viz/__init__.py | 21 +++-- .../ocean/tests/parabolic_bowl/__init__.py | 10 +- .../tests/parabolic_bowl/default/__init__.py | 44 ++++++--- compass/ocean/tests/parabolic_bowl/forward.py | 53 +++++++---- .../tests/parabolic_bowl/initial_state.py | 92 ------------------- .../parabolic_bowl/namelist.10km.forward | 1 - .../parabolic_bowl/namelist.20km.forward | 1 - .../tests/parabolic_bowl/namelist.5km.forward | 1 - .../tests/parabolic_bowl/namelist.forward | 13 --- .../ocean/tests/parabolic_bowl/namelist.init | 6 -- .../parabolic_bowl/namelist.ramp.forward | 3 - .../namelist.single_layer.forward | 7 -- .../tests/parabolic_bowl/parabolic_bowl.cfg | 48 ---------- .../tests/parabolic_bowl/streams.forward | 34 ------- .../ocean/tests/parabolic_bowl/streams.init | 32 ------- .../tests/parabolic_bowl/viz/__init__.py | 13 ++- 26 files changed, 204 insertions(+), 376 deletions(-) delete mode 100644 compass/ocean/tests/dam_break/streams.forward delete mode 100644 compass/ocean/tests/dam_break/streams.init delete mode 100644 compass/ocean/tests/parabolic_bowl/initial_state.py delete mode 100644 compass/ocean/tests/parabolic_bowl/namelist.10km.forward delete mode 100644 compass/ocean/tests/parabolic_bowl/namelist.20km.forward delete mode 100644 compass/ocean/tests/parabolic_bowl/namelist.5km.forward delete mode 100644 compass/ocean/tests/parabolic_bowl/namelist.forward delete mode 100644 compass/ocean/tests/parabolic_bowl/namelist.init delete mode 100644 compass/ocean/tests/parabolic_bowl/namelist.ramp.forward delete mode 100644 compass/ocean/tests/parabolic_bowl/namelist.single_layer.forward delete mode 100644 compass/ocean/tests/parabolic_bowl/parabolic_bowl.cfg delete mode 100644 compass/ocean/tests/parabolic_bowl/streams.forward delete mode 100644 compass/ocean/tests/parabolic_bowl/streams.init diff --git a/compass/ocean/tests/dam_break/__init__.py b/compass/ocean/tests/dam_break/__init__.py index c7b365f7fa..c063637b34 100644 --- a/compass/ocean/tests/dam_break/__init__.py +++ b/compass/ocean/tests/dam_break/__init__.py @@ -16,7 +16,10 @@ def __init__(self, mpas_core): super().__init__(mpas_core=mpas_core, name='dam_break') for resolution in [0.04, 0.12]: - self.add_test_case( - Default(test_group=self, resolution=resolution)) - self.add_test_case( - Ramp(test_group=self, resolution=resolution)) + for use_lts in [True, False]: + self.add_test_case( + Default(test_group=self, resolution=resolution, + use_lts=use_lts)) + self.add_test_case( + Ramp(test_group=self, resolution=resolution, + use_lts=use_lts)) diff --git a/compass/ocean/tests/dam_break/dam_break.cfg b/compass/ocean/tests/dam_break/dam_break.cfg index 6849d56ba3..e69de29bb2 100644 --- a/compass/ocean/tests/dam_break/dam_break.cfg +++ b/compass/ocean/tests/dam_break/dam_break.cfg @@ -1,5 +0,0 @@ -# Options related to the vertical grid -[vertical_grid] - -# Number of vertical levels # redundant with config_dam_break_vert_levels -vert_levels = 3 diff --git a/compass/ocean/tests/dam_break/default/__init__.py b/compass/ocean/tests/dam_break/default/__init__.py index 3f400a82f5..95a558ac1e 100644 --- a/compass/ocean/tests/dam_break/default/__init__.py +++ b/compass/ocean/tests/dam_break/default/__init__.py @@ -1,8 +1,10 @@ from math import floor -from compass.testcase import TestCase -from compass.ocean.tests.dam_break.initial_state import InitialState + from compass.ocean.tests.dam_break.forward import Forward +from compass.ocean.tests.dam_break.initial_state import InitialState +from compass.ocean.tests.dam_break.lts.lts_regions import LTSRegions from compass.ocean.tests.dam_break.viz import Viz +from compass.testcase import TestCase from compass.validate import compare_variables @@ -17,7 +19,7 @@ class Default(TestCase): """ - def __init__(self, test_group, resolution): + def __init__(self, test_group, resolution, use_lts): """ Create the test case @@ -29,22 +31,36 @@ def __init__(self, test_group, resolution): resolution : float The resolution of the test case in m + use_lts : bool + Whether local time-stepping is used + """ - name = 'default' + self.use_lts = use_lts + + if use_lts: + name = 'default_lts' + else: + name = 'default' self.resolution = resolution if resolution < 1.: res_name = f'{int(resolution*1e3)}cm' else: res_name = f'{int(resolution)}m' - min_tasks = int(40/(resolution/0.04)**2) - ntasks = 10*min_tasks + min_tasks = int(40 / (resolution / 0.04) ** 2) + ntasks = 10 * min_tasks subdir = f'{res_name}/{name}' super().__init__(test_group=test_group, name=name, subdir=subdir) - self.add_step(InitialState(test_case=self)) + init_step = InitialState(test_case=self, use_lts=use_lts) + self.add_step(init_step) + + if use_lts: + self.add_step(LTSRegions(test_case=self, init_step=init_step)) + self.add_step(Forward(test_case=self, resolution=resolution, + use_lts=use_lts, ntasks=ntasks, min_tasks=min_tasks, openmp_threads=1)) self.add_step(Viz(test_case=self)) @@ -56,11 +72,12 @@ def configure(self): resolution = self.resolution config = self.config + use_lts = self.use_lts dc = resolution # cell width in m dx = 13 # width of the domain in m dy = 28 # length of the domain in m - nx = round(dx/dc) - ny = int(2*floor(dy/(2*dc))) # guarantee that ny is even + nx = round(dx / dc) + ny = int(2 * floor(dy / (2 * dc))) # guarantee that ny is even config.set('dam_break', 'nx', f'{nx}', comment='the number of ' 'mesh cells in the x direction') @@ -69,10 +86,19 @@ def configure(self): config.set('dam_break', 'dc', f'{dc}', comment='the distance ' 'between adjacent cell centers') + if use_lts: + vert_levels = 1 + config.set('vertical_grid', 'vert_levels', f'{vert_levels}', + comment='number of vertical levels') + else: + vert_levels = 3 + config.set('vertical_grid', 'vert_levels', f'{vert_levels}', + comment='number of vertical levels') + def validate(self): """ Validate variables against a baseline """ variables = ['layerThickness', 'normalVelocity', 'ssh'] compare_variables(test_case=self, variables=variables, - filename1=f'forward/output.nc') + filename1=f'{"forward/output.nc"}') diff --git a/compass/ocean/tests/dam_break/forward.py b/compass/ocean/tests/dam_break/forward.py index e7480630e5..b03cc972f2 100644 --- a/compass/ocean/tests/dam_break/forward.py +++ b/compass/ocean/tests/dam_break/forward.py @@ -7,7 +7,8 @@ class Forward(Step): A step for performing forward MPAS-Ocean runs as part of dam break test cases. """ - def __init__(self, test_case, resolution, name='forward', subdir=None, + def __init__(self, test_case, resolution, use_lts, + name='forward', subdir=None, ntasks=1, min_tasks=None, openmp_threads=1): """ Create a new test case @@ -20,6 +21,9 @@ def __init__(self, test_case, resolution, name='forward', subdir=None, resolution : str The resolution of the test case + use_lts : bool + Whether local time-stepping is used + name : str the name of the test case @@ -50,18 +54,37 @@ def __init__(self, test_case, resolution, name='forward', subdir=None, self.add_namelist_file('compass.ocean.tests.dam_break', 'namelist.forward') - self.add_streams_file('compass.ocean.tests.dam_break', - 'streams.forward') - - input_path = '../initial_state' - self.add_input_file(filename='mesh.nc', - target=f'{input_path}/culled_mesh.nc') - - self.add_input_file(filename='init.nc', - target=f'{input_path}/ocean.nc') - self.add_input_file(filename='graph.info', - target=f'{input_path}/culled_graph.info') + if use_lts: + self.add_namelist_options( + {'config_time_integrator': "'LTS'"}) + self.add_namelist_options( + {'config_dt_scaling_LTS': "4"}) + self.add_namelist_options( + {'config_number_of_time_levels': "4"}) + + self.add_streams_file('compass.ocean.tests.dam_break.lts', + 'streams.forward') + input_path = '../lts_regions' + self.add_input_file(filename='mesh.nc', + target=f'{input_path}/lts_mesh.nc') + self.add_input_file(filename='graph.info', + target=f'{input_path}/lts_graph.info') + self.add_input_file(filename='init.nc', + target=f'{input_path}/lts_ocean.nc') + + else: + self.add_streams_file('compass.ocean.tests.dam_break', + 'streams.forward') + input_path = '../initial_state' + self.add_input_file(filename='mesh.nc', + target=f'{input_path}/culled_mesh.nc') + + self.add_input_file(filename='init.nc', + target=f'{input_path}/ocean.nc') + + self.add_input_file(filename='graph.info', + target=f'{input_path}/culled_graph.info') self.add_model_as_input() diff --git a/compass/ocean/tests/dam_break/initial_state.py b/compass/ocean/tests/dam_break/initial_state.py index 94e065f5af..e6bf4cfb38 100644 --- a/compass/ocean/tests/dam_break/initial_state.py +++ b/compass/ocean/tests/dam_break/initial_state.py @@ -1,13 +1,10 @@ import xarray -import numpy -import matplotlib.pyplot as plt - -from mpas_tools.planar_hex import make_planar_hex_mesh from mpas_tools.io import write_netcdf from mpas_tools.mesh.conversion import convert, cull +from mpas_tools.planar_hex import make_planar_hex_mesh -from compass.step import Step from compass.model import run_model +from compass.step import Step class InitialState(Step): @@ -15,7 +12,7 @@ class InitialState(Step): A step for creating a mesh and initial condition for dam break test cases """ - def __init__(self, test_case): + def __init__(self, test_case, use_lts): """ Create the step @@ -27,8 +24,14 @@ def __init__(self, test_case): super().__init__(test_case=test_case, name='initial_state', ntasks=1, min_tasks=1, openmp_threads=1) - self.add_namelist_file('compass.ocean.tests.dam_break', - 'namelist.init', mode='init') + self.use_lts = use_lts + + if use_lts: + self.add_namelist_file('compass.ocean.tests.dam_break.lts', + 'namelist.init', mode='init') + else: + self.add_namelist_file('compass.ocean.tests.dam_break', + 'namelist.init', mode='init') self.add_streams_file('compass.ocean.tests.dam_break', 'streams.init', mode='init') @@ -52,7 +55,7 @@ def run(self): dc = section.getfloat('dc') self.update_namelist_at_runtime( - {'config_dam_break_dc': f'{dc}'}) + {'config_dam_break_dc': f'{dc}'}) logger.info(' * Make planar hex mesh') dsMesh = make_planar_hex_mesh(nx=nx, ny=ny, dc=dc, nonperiodic_x=True, diff --git a/compass/ocean/tests/dam_break/namelist.forward b/compass/ocean/tests/dam_break/namelist.forward index 48bb1d3b8b..bcb3bafa49 100644 --- a/compass/ocean/tests/dam_break/namelist.forward +++ b/compass/ocean/tests/dam_break/namelist.forward @@ -13,4 +13,4 @@ config_drying_min_cell_height=1e-6 config_thickness_flux_type='upwind' config_vert_coord_movement='impermeable_interfaces' config_use_debugTracers=.false. -config_disable_tr_all_tend = .true. +config_disable_tr_all_tend =.true. diff --git a/compass/ocean/tests/dam_break/namelist.init b/compass/ocean/tests/dam_break/namelist.init index e6933120ca..5818bff3b1 100644 --- a/compass/ocean/tests/dam_break/namelist.init +++ b/compass/ocean/tests/dam_break/namelist.init @@ -1,4 +1,4 @@ -config_ocean_run_mode = 'init' +config_ocean_run_mode='init' config_init_configuration='dam_break' config_dam_break_vert_levels=3 config_dam_break_R0=12.0 diff --git a/compass/ocean/tests/dam_break/ramp/__init__.py b/compass/ocean/tests/dam_break/ramp/__init__.py index d72b9234fc..91553be037 100644 --- a/compass/ocean/tests/dam_break/ramp/__init__.py +++ b/compass/ocean/tests/dam_break/ramp/__init__.py @@ -2,6 +2,7 @@ from compass.ocean.tests.dam_break.forward import Forward from compass.ocean.tests.dam_break.initial_state import InitialState +from compass.ocean.tests.dam_break.lts.lts_regions import LTSRegions from compass.ocean.tests.dam_break.viz import Viz from compass.testcase import TestCase from compass.validate import compare_variables @@ -18,7 +19,7 @@ class Ramp(TestCase): """ - def __init__(self, test_group, resolution): + def __init__(self, test_group, resolution, use_lts): """ Create the test case @@ -30,8 +31,14 @@ def __init__(self, test_group, resolution): resolution : float The resolution of the test case in m + use_lts : bool + Whether local time-stepping is used + """ - name = 'ramp' + if use_lts: + name = 'ramp_lts' + else: + name = 'ramp' self.resolution = resolution if resolution < 1.: @@ -44,8 +51,14 @@ def __init__(self, test_group, resolution): super().__init__(test_group=test_group, name=name, subdir=subdir) - self.add_step(InitialState(test_case=self)) + init_step = InitialState(test_case=self, use_lts=use_lts) + self.add_step(init_step) + + if use_lts: + self.add_step(LTSRegions(test_case=self, init_step=init_step)) + forward_step = Forward(test_case=self, resolution=resolution, + use_lts=use_lts, ntasks=ntasks, min_tasks=min_tasks, openmp_threads=1) forward_step.add_namelist_options({'config_zero_drying_velocity_ramp': diff --git a/compass/ocean/tests/dam_break/streams.forward b/compass/ocean/tests/dam_break/streams.forward deleted file mode 100644 index aa1d1ad4b2..0000000000 --- a/compass/ocean/tests/dam_break/streams.forward +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/compass/ocean/tests/dam_break/streams.init b/compass/ocean/tests/dam_break/streams.init deleted file mode 100644 index bd4b466e0e..0000000000 --- a/compass/ocean/tests/dam_break/streams.init +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/compass/ocean/tests/dam_break/viz/__init__.py b/compass/ocean/tests/dam_break/viz/__init__.py index 765c6746a9..ab01f8db8a 100644 --- a/compass/ocean/tests/dam_break/viz/__init__.py +++ b/compass/ocean/tests/dam_break/viz/__init__.py @@ -1,10 +1,11 @@ -import xarray -import numpy +from collections import OrderedDict + import matplotlib.pyplot as plt +import numpy import pandas as pd -from scipy import spatial +import xarray from PIL import Image -from collections import OrderedDict +from scipy import spatial from compass.step import Step @@ -87,22 +88,22 @@ def run(self): ii = 0 - fig = plt.figure() for cell in station: ii += 1 - ax = plt.subplot(3, 2, ii+1) + ax = plt.subplot(3, 2, ii + 1) # MPAS-O simulation results - mpaso = plt.plot(numpy.arange(0, dt*nt, dt), wct[:, station[cell]], + mpaso = plt.plot(numpy.arange(0, dt * nt, dt), + wct[:, station[cell]], color='#228B22', linewidth=2, alpha=0.6) # Measured data - data = pd.read_csv('Station'+cell+'.csv', header=None) + data = pd.read_csv('Station' + cell + '.csv', header=None) measured = plt.scatter(data[0], data[1], 4, marker='o', color='k') # ROMS simulation results (Warner et al., 2013) - roms_data = pd.read_csv(cell+'-sim.csv', header=None) + roms_data = pd.read_csv(cell + '-sim.csv', header=None) roms = plt.scatter(roms_data[0], roms_data[1], 4, marker='v', color='b') @@ -110,7 +111,7 @@ def run(self): plt.xticks(numpy.arange(0, 11, 2)) plt.ylim(0, 0.7) plt.yticks(numpy.arange(0, 0.7, 0.2)) - plt.text(3.5, 0.55, 'Station '+cell) + plt.text(3.5, 0.55, 'Station ' + cell) if ii % 2 == 0: plt.ylabel('h (m)') diff --git a/compass/ocean/tests/parabolic_bowl/__init__.py b/compass/ocean/tests/parabolic_bowl/__init__.py index 167b3842bb..23b24fed93 100644 --- a/compass/ocean/tests/parabolic_bowl/__init__.py +++ b/compass/ocean/tests/parabolic_bowl/__init__.py @@ -15,6 +15,10 @@ def __init__(self, mpas_core): super().__init__(mpas_core=mpas_core, name='parabolic_bowl') for wetdry in ['standard']: # , 'subgrid']: for ramp_type in ['ramp', 'noramp']: - self.add_test_case( - Default(test_group=self, ramp_type=ramp_type, - wetdry=wetdry)) + # note: LTS has only standard W/D + for use_lts in [True, False]: + self.add_test_case( + Default(test_group=self, + ramp_type=ramp_type, + wetdry=wetdry, + use_lts=use_lts)) diff --git a/compass/ocean/tests/parabolic_bowl/default/__init__.py b/compass/ocean/tests/parabolic_bowl/default/__init__.py index ccb7fd437f..c1b48cf8fc 100644 --- a/compass/ocean/tests/parabolic_bowl/default/__init__.py +++ b/compass/ocean/tests/parabolic_bowl/default/__init__.py @@ -3,6 +3,7 @@ from compass.config import CompassConfigParser from compass.ocean.tests.parabolic_bowl.forward import Forward from compass.ocean.tests.parabolic_bowl.initial_state import InitialState +from compass.ocean.tests.parabolic_bowl.lts.lts_regions import LTSRegions from compass.ocean.tests.parabolic_bowl.viz import Viz from compass.testcase import TestCase from compass.validate import compare_variables @@ -18,7 +19,7 @@ class Default(TestCase): The type of vertical coordinate (``ramp``, ``noramp``, etc.) """ - def __init__(self, test_group, ramp_type, wetdry): + def __init__(self, test_group, ramp_type, wetdry, use_lts): """ Create the test case @@ -32,30 +33,41 @@ def __init__(self, test_group, ramp_type, wetdry): wetdry : str The type of wetting and drying used (``standard``, ``subgrid``) - """ - name = f'{wetdry}_{ramp_type}' - subdir = f'{wetdry}/{ramp_type}' + use_lts : bool + Whether local time-stepping is used + """ + if use_lts: + name = f'{wetdry}_{ramp_type}_lts' + else: + name = f'{wetdry}_{ramp_type}' + + if use_lts: + subdir = f'{wetdry}/{ramp_type}_lts' + else: + subdir = f'{wetdry}/{ramp_type}' super().__init__(test_group=test_group, name=name, subdir=subdir) self.resolutions = None self.wetdry = wetdry self.ramp_type = ramp_type + self.use_lts = use_lts # add the steps with default resolutions so they can be listed config = CompassConfigParser() config.add_from_package('compass.ocean.tests.parabolic_bowl', 'parabolic_bowl.cfg') - self._setup_steps(config) + self._setup_steps(config, use_lts) def configure(self): """ Set config options for the test case """ config = self.config + use_lts = self.use_lts # set up the steps again in case a user has provided new resolutions - self._setup_steps(config) + self._setup_steps(config, use_lts) self.update_cores() @@ -97,7 +109,7 @@ def update_cores(self): str(min_tasks), comment=f'Minimum core count for {res_name} mesh') - def _setup_steps(self, config): + def _setup_steps(self, config, use_lts): """ setup steps given resolutions """ default_resolutions = '20, 10, 5' @@ -124,16 +136,24 @@ def _setup_steps(self, config): res_name = f'{resolution}km' - self.add_step(InitialState(test_case=self, - name=f'initial_state_{res_name}', - resolution=resolution, - wetdry=self.wetdry)) + init_step = InitialState(test_case=self, + name=f'initial_state_{res_name}', + resolution=resolution, + wetdry=self.wetdry) + self.add_step(init_step) + if use_lts: + self.add_step(LTSRegions(test_case=self, + init_step=init_step, + name=f'lts_regions_{res_name}', + subdir=f'lts_regions_{res_name}')) self.add_step(Forward(test_case=self, name=f'forward_{res_name}', + use_lts=use_lts, resolution=resolution, ramp_type=self.ramp_type, wetdry=self.wetdry)) - self.add_step(Viz(test_case=self, resolutions=resolutions)) + self.add_step(Viz(test_case=self, resolutions=resolutions, + use_lts=use_lts)) def validate(self): """ diff --git a/compass/ocean/tests/parabolic_bowl/forward.py b/compass/ocean/tests/parabolic_bowl/forward.py index 62fdd4d49d..53ce2908b8 100644 --- a/compass/ocean/tests/parabolic_bowl/forward.py +++ b/compass/ocean/tests/parabolic_bowl/forward.py @@ -9,7 +9,8 @@ class Forward(Step): A step for performing forward MPAS-Ocean runs as part of parabolic bowl test cases. """ - def __init__(self, test_case, resolution, name, + def __init__(self, test_case, resolution, + name, use_lts, ramp_type='ramp', coord_type='single_layer', wetdry='standard'): """ @@ -24,16 +25,19 @@ def __init__(self, test_case, resolution, name, The resolution of the test case name : str - the name of the test case + The name of the test case + + use_lts : bool + Whether local time-stepping is used subdir : str, optional - the subdirectory for the step. The default is ``name`` + The subdirectory for the step. The default is ``name`` coord_type : str, optional - vertical coordinate configuration + Vertical coordinate configuration ramp_type : str, optional - vertical coordinate configuration + Vertical coordinate configuration """ self.resolution = resolution @@ -51,18 +55,33 @@ def __init__(self, test_case, resolution, name, self.add_namelist_file('compass.ocean.tests.parabolic_bowl', 'namelist.ramp.forward') - self.add_streams_file('compass.ocean.tests.parabolic_bowl', - 'streams.forward') - - input_path = f'../initial_state_{res_name}' - self.add_input_file(filename='mesh.nc', - target=f'{input_path}/culled_mesh.nc') - - self.add_input_file(filename='init.nc', - target=f'{input_path}/ocean.nc') - - self.add_input_file(filename='graph.info', - target=f'{input_path}/culled_graph.info') + if use_lts: + self.add_namelist_options( + {'config_time_integrator': "'LTS'"}) + self.add_namelist_options( + {'config_dt_scaling_LTS': "4"}) + self.add_namelist_options( + {'config_number_of_time_levels': "4"}) + self.add_streams_file('compass.ocean.tests.parabolic_bowl.lts', + 'streams.forward') + input_path = f'../lts_regions_{res_name}' + self.add_input_file(filename='mesh.nc', + target=f'{input_path}/lts_mesh.nc') + self.add_input_file(filename='graph.info', + target=f'{input_path}/lts_graph.info') + self.add_input_file(filename='init.nc', + target=f'{input_path}/lts_ocean.nc') + + else: + self.add_streams_file('compass.ocean.tests.parabolic_bowl', + 'streams.forward') + input_path = f'../initial_state_{res_name}' + self.add_input_file(filename='mesh.nc', + target=f'{input_path}/culled_mesh.nc') + self.add_input_file(filename='init.nc', + target=f'{input_path}/ocean.nc') + self.add_input_file(filename='graph.info', + target=f'{input_path}/culled_graph.info') self.add_model_as_input() diff --git a/compass/ocean/tests/parabolic_bowl/initial_state.py b/compass/ocean/tests/parabolic_bowl/initial_state.py deleted file mode 100644 index a182a824ec..0000000000 --- a/compass/ocean/tests/parabolic_bowl/initial_state.py +++ /dev/null @@ -1,92 +0,0 @@ -from mpas_tools.io import write_netcdf -from mpas_tools.mesh.conversion import convert, cull -from mpas_tools.planar_hex import make_planar_hex_mesh - -from compass.model import run_model -from compass.step import Step - - -class InitialState(Step): - """ - A step for creating a mesh and initial condition for drying slope test - cases - """ - def __init__(self, test_case, name, resolution, - coord_type='single_layer', wetdry='standard'): - """ - Create the step - - Parameters - ---------- - test_case : compass.ocean.tests.parabolic_bowl.default.Default - The test case this step belongs to - """ - self.coord_type = coord_type - self.resolution = resolution - - super().__init__(test_case=test_case, name=name, ntasks=1, - min_tasks=1, openmp_threads=1) - - self.add_namelist_file('compass.ocean.tests.parabolic_bowl', - 'namelist.init', mode='init') - - self.add_streams_file('compass.ocean.tests.parabolic_bowl', - 'streams.init', mode='init') - - for file in ['base_mesh.nc', 'culled_mesh.nc', 'culled_graph.info', - 'ocean.nc']: - self.add_output_file(file) - - self.add_model_as_input() - - def run(self): - """ - Run this step of the test case - """ - config = self.config - logger = self.logger - - # Set vertical levels - coord_type = self.coord_type - if coord_type == 'single_layer': - options = {'config_parabolic_bowl_vert_levels': '1'} - else: - vert_levels = config.getint('vertical_grid', 'vert_levels') - options = {'config_parabolic_bowl_vert_levels': f'{vert_levels}'} - self.update_namelist_at_runtime(options) - - # Set test case parameters - eta_max = config.get('parabolic_bowl', 'eta_max') - depth_max = config.get('parabolic_bowl', 'depth_max') - coriolis = config.get('parabolic_bowl', 'coriolis_parameter') - omega = config.get('parabolic_bowl', 'omega') - gravity = config.get('parabolic_bowl', 'gravity') - options = {'config_parabolic_bowl_Coriolis_parameter': coriolis, - 'config_parabolic_bowl_eta0': eta_max, - 'config_parabolic_bowl_b0': depth_max, - 'config_parabolic_bowl_omega': omega, - 'config_parabolic_bowl_gravity': gravity} - self.update_namelist_at_runtime(options) - - # Determine mesh parameters - Lx = config.getint('parabolic_bowl', 'Lx') - Ly = config.getint('parabolic_bowl', 'Ly') - nx = round(Lx / self.resolution) - ny = round(Ly / self.resolution) - dc = 1e3 * self.resolution - - logger.info(' * Make planar hex mesh') - dsMesh = make_planar_hex_mesh(nx=nx, ny=ny, dc=dc, nonperiodic_x=True, - nonperiodic_y=True) - logger.info(' * Completed Make planar hex mesh') - write_netcdf(dsMesh, 'base_mesh.nc') - - logger.info(' * Cull mesh') - dsMesh = cull(dsMesh, logger=logger) - logger.info(' * Convert mesh') - dsMesh = convert(dsMesh, graphInfoFileName='culled_graph.info', - logger=logger) - logger.info(' * Completed Convert mesh') - write_netcdf(dsMesh, 'culled_mesh.nc') - run_model(self, namelist='namelist.ocean', - streams='streams.ocean') diff --git a/compass/ocean/tests/parabolic_bowl/namelist.10km.forward b/compass/ocean/tests/parabolic_bowl/namelist.10km.forward deleted file mode 100644 index 05af815f7e..0000000000 --- a/compass/ocean/tests/parabolic_bowl/namelist.10km.forward +++ /dev/null @@ -1 +0,0 @@ -config_dt='0000_00:00:05' diff --git a/compass/ocean/tests/parabolic_bowl/namelist.20km.forward b/compass/ocean/tests/parabolic_bowl/namelist.20km.forward deleted file mode 100644 index 6594d67a91..0000000000 --- a/compass/ocean/tests/parabolic_bowl/namelist.20km.forward +++ /dev/null @@ -1 +0,0 @@ -config_dt='0000_00:00:10' diff --git a/compass/ocean/tests/parabolic_bowl/namelist.5km.forward b/compass/ocean/tests/parabolic_bowl/namelist.5km.forward deleted file mode 100644 index b6cb4195f9..0000000000 --- a/compass/ocean/tests/parabolic_bowl/namelist.5km.forward +++ /dev/null @@ -1 +0,0 @@ -config_dt='0000_00:00:02.5' diff --git a/compass/ocean/tests/parabolic_bowl/namelist.forward b/compass/ocean/tests/parabolic_bowl/namelist.forward deleted file mode 100644 index a8ec1ff4c4..0000000000 --- a/compass/ocean/tests/parabolic_bowl/namelist.forward +++ /dev/null @@ -1,13 +0,0 @@ -config_run_duration='0003_00:00:00' -config_time_integrator='RK4' -config_vert_coord_movement='impermeable_interfaces' -config_ALE_thickness_proportionality='weights_only' -config_use_wetting_drying=.true. -config_prevent_drying=.true. -config_drying_min_cell_height=2.0e-2 -config_zero_drying_velocity=.true. -config_verify_not_dry=.true. -config_thickness_flux_type='upwind' -config_use_cvmix=.false. -config_check_ssh_consistency=.true. -config_implicit_constant_bottom_drag_coeff = 0.0 diff --git a/compass/ocean/tests/parabolic_bowl/namelist.init b/compass/ocean/tests/parabolic_bowl/namelist.init deleted file mode 100644 index d755143e04..0000000000 --- a/compass/ocean/tests/parabolic_bowl/namelist.init +++ /dev/null @@ -1,6 +0,0 @@ -config_init_configuration = 'parabolic_bowl' -config_ocean_run_mode = 'init' -config_use_wetting_drying = .true. -config_drying_min_cell_height = 2e-2 -config_write_cull_cell_mask = .false. -config_parabolic_bowl_vert_levels = 1 diff --git a/compass/ocean/tests/parabolic_bowl/namelist.ramp.forward b/compass/ocean/tests/parabolic_bowl/namelist.ramp.forward deleted file mode 100644 index 83673b1213..0000000000 --- a/compass/ocean/tests/parabolic_bowl/namelist.ramp.forward +++ /dev/null @@ -1,3 +0,0 @@ -config_zero_drying_velocity_ramp = .true. -config_zero_drying_velocity_ramp_hmin = 2e-2 -config_zero_drying_velocity_ramp_hmax = 4e-2 diff --git a/compass/ocean/tests/parabolic_bowl/namelist.single_layer.forward b/compass/ocean/tests/parabolic_bowl/namelist.single_layer.forward deleted file mode 100644 index 7378b7eee7..0000000000 --- a/compass/ocean/tests/parabolic_bowl/namelist.single_layer.forward +++ /dev/null @@ -1,7 +0,0 @@ -config_disable_thick_vadv = .true. -config_disable_thick_sflux = .true. -config_disable_vel_vmix = .true. -config_disable_vel_vadv = .true. -config_disable_tr_all_tend = .true. -config_disable_vel_hmix = .true. -config_pressure_gradient_type = 'ssh_gradient' diff --git a/compass/ocean/tests/parabolic_bowl/parabolic_bowl.cfg b/compass/ocean/tests/parabolic_bowl/parabolic_bowl.cfg deleted file mode 100644 index 89e7ae2ca2..0000000000 --- a/compass/ocean/tests/parabolic_bowl/parabolic_bowl.cfg +++ /dev/null @@ -1,48 +0,0 @@ -[job] - -wall_time = 2:00:00 - - -# config options for drying slope test cases -[parabolic_bowl] - -# dimensions of domain in x and y directions (km) -Lx = 1440 -Ly = 1560 - -# Coriolis parameter -coriolis_parameter = 1.031e-4 - -# maximum initial ssh magnitude -eta_max = 2.0 - -# maximum water depth -depth_max = 50.0 - -# angular fequency of oscillation -omega = 1.4544e-4 - -# gravitational acceleration -gravity = 9.81 - -# a list of resolutions (km) to test -resolutions = 20, 10, 5 - -# time step per resolution (s/km), since dt is proportional to resolution -dt_per_km = 0.5 - -# the number of cells per core to aim for -goal_cells_per_core = 300 - -# the approximate maximum number of cells per core (the test will fail if too -# few cores are available) -max_cells_per_core = 3000 - -# config options for visualizing drying slope ouptut -[parabolic_bowl_viz] - -# coordinates (in km) for timeseries plot -points = [0,0], [300,0], [610,0] - -# generate contour plots at a specified interval between output timesnaps -plot_interval = 10 diff --git a/compass/ocean/tests/parabolic_bowl/streams.forward b/compass/ocean/tests/parabolic_bowl/streams.forward deleted file mode 100644 index a412ee4c9f..0000000000 --- a/compass/ocean/tests/parabolic_bowl/streams.forward +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/compass/ocean/tests/parabolic_bowl/streams.init b/compass/ocean/tests/parabolic_bowl/streams.init deleted file mode 100644 index 1efd479999..0000000000 --- a/compass/ocean/tests/parabolic_bowl/streams.init +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/compass/ocean/tests/parabolic_bowl/viz/__init__.py b/compass/ocean/tests/parabolic_bowl/viz/__init__.py index 92d8bcad30..26bc2b9de4 100644 --- a/compass/ocean/tests/parabolic_bowl/viz/__init__.py +++ b/compass/ocean/tests/parabolic_bowl/viz/__init__.py @@ -18,7 +18,7 @@ class Viz(Step): Attributes ---------- """ - def __init__(self, test_case, resolutions): + def __init__(self, test_case, resolutions, use_lts): """ Create the step @@ -30,6 +30,7 @@ def __init__(self, test_case, resolutions): super().__init__(test_case=test_case, name='viz') self.resolutions = resolutions + self.use_lts = use_lts for res in resolutions: self.add_input_file(filename=f'output_{res}km.nc', @@ -193,9 +194,15 @@ def rmse_plots(self): Plot convergence curves """ + ramp_name = 'ramp' + noramp_name = 'noramp' + if self.use_lts: + ramp_name = 'ramp_lts' + noramp_name = 'noramp_lts' + comparisons = [] - cases = {'standard_ramp': '../../../standard/ramp/viz', - 'standard_noramp': '../../../standard/noramp/viz'} + cases = {'standard_ramp': f'../../../standard/{ramp_name}/viz', + 'standard_noramp': f'../../../standard/{noramp_name}/viz'} for case in cases: include = True for res in self.resolutions: From d5263fe814253bfd484f6d872cf3c16f2f76fe8f Mon Sep 17 00:00:00 2001 From: Giacomo Capodaglio Date: Tue, 28 Nov 2023 17:21:16 -0800 Subject: [PATCH 02/10] Added files --- compass/ocean/tests/dam_break/lts/__init__.py | 0 .../ocean/tests/dam_break/lts/lts_regions.py | 328 +++++++++++++++++ .../ocean/tests/dam_break/lts/namelist.init | 5 + .../ocean/tests/dam_break/lts/streams.forward | 32 ++ .../tests/parabolic_bowl/lts/__init__.py | 0 .../tests/parabolic_bowl/lts/lts_regions.py | 332 ++++++++++++++++++ .../tests/parabolic_bowl/lts/streams.forward | 43 +++ 7 files changed, 740 insertions(+) create mode 100644 compass/ocean/tests/dam_break/lts/__init__.py create mode 100644 compass/ocean/tests/dam_break/lts/lts_regions.py create mode 100644 compass/ocean/tests/dam_break/lts/namelist.init create mode 100644 compass/ocean/tests/dam_break/lts/streams.forward create mode 100644 compass/ocean/tests/parabolic_bowl/lts/__init__.py create mode 100644 compass/ocean/tests/parabolic_bowl/lts/lts_regions.py create mode 100644 compass/ocean/tests/parabolic_bowl/lts/streams.forward diff --git a/compass/ocean/tests/dam_break/lts/__init__.py b/compass/ocean/tests/dam_break/lts/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/compass/ocean/tests/dam_break/lts/lts_regions.py b/compass/ocean/tests/dam_break/lts/lts_regions.py new file mode 100644 index 0000000000..ffc08ecdb6 --- /dev/null +++ b/compass/ocean/tests/dam_break/lts/lts_regions.py @@ -0,0 +1,328 @@ +import math +import os + +import netCDF4 as nc +import numpy as np +import xarray as xr +from mpas_tools.io import write_netcdf +from mpas_tools.viz.paraview_extractor import extract_vtk + +from compass.step import Step + + +class LTSRegions(Step): + """ + A step for adding LTS regions to a global MPAS-Ocean mesh + + Attributes + ---------- + initial_state_step : + compass.ocean.tests.dam_break.initial_state.InitialState + The initial step containing input files to this step + """ + def __init__(self, test_case, init_step, + name='lts_regions', subdir='lts_regions'): + """ + Create a new step + + Parameters + ---------- + test_case : compass.Testcase + The test case this step belongs to + + init_step : + compass.ocean.tests.dam_break.initial_state.InitialState + The initial state step containing input files to this step + + name : str, optional + the name of the step + + subdir : str, optional + the subdirectory for the step. The default is ``name`` + """ + super().__init__(test_case, name=name, subdir=subdir) + + for file in ['lts_mesh.nc', 'lts_graph.info', 'lts_ocean.nc']: + self.add_output_file(filename=file) + + self.init_step = init_step + + def setup(self): + """ + Set up the test case in the work directory, including downloading any + dependencies. + """ + super().setup() + + init_path = self.init_step.path + tgt1 = os.path.join(init_path, 'culled_mesh.nc') + self.add_input_file(filename='culled_mesh.nc', work_dir_target=tgt1) + + tgt2 = os.path.join(init_path, 'culled_graph.info') + self.add_input_file(filename='culled_graph.info', work_dir_target=tgt2) + + tgt3 = os.path.join(init_path, 'ocean.nc') + self.add_input_file(filename='ocean.nc', work_dir_target=tgt3) + + def run(self): + """ + Run this step of the test case + """ + + use_progress_bar = self.log_filename is None + label_mesh(init='ocean.nc', + mesh='culled_mesh.nc', + graph_info='culled_graph.info', num_interface=2, + logger=self.logger, use_progress_bar=use_progress_bar) + + +def label_mesh(init, mesh, graph_info, num_interface, # noqa: C901 + logger, use_progress_bar): + + # read in mesh data + ds = xr.open_dataset(mesh) + n_cells = ds['nCells'].size + n_edges = ds['nEdges'].size + area_cell = ds['areaCell'].values + cells_on_edge = ds['cellsOnEdge'].values + edges_on_cell = ds['edgesOnCell'].values + x_cell = ds['xCell'] + + # start by setting all cells to coarse + lts_rgn = [2] * n_cells + + # check each cell, if in the fine region, label as fine + logger.info('Labeling fine cells...') + for icell in range(0, n_cells): + if x_cell[icell] > 8.0: + lts_rgn[icell] = 1 + + # first layer of cells with label 5 + changed_cells = [[], []] + for iedge in range(0, n_edges): + cell1 = cells_on_edge[iedge, 0] - 1 + cell2 = cells_on_edge[iedge, 1] - 1 + + if (cell1 != -1 and cell2 != -1): + if (lts_rgn[cell1] == 1 and lts_rgn[cell2] == 2): + + lts_rgn[cell2] = 5 + changed_cells[0].append(cell2) + + elif (lts_rgn[cell1] == 2 and lts_rgn[cell2] == 1): + + lts_rgn[cell1] = 5 + changed_cells[0].append(cell1) + + # second and third layer of cells with label 5 + # only looping over cells changed during loop for previous layer + # at the end of this loop, changed_cells[0] will have the list of cells + # sharing edegs with the coarse cells + logger.info('Labeling interface-adjacent fine cells...') + for i in range(0, 2): # this loop creates 2 layers + changed_cells[(i + 1) % 2] = [] + + for icell in changed_cells[i % 2]: + edges = edges_on_cell[icell] + for iedge in edges: + if iedge != 0: + cell1 = cells_on_edge[iedge - 1, 0] - 1 + cell2 = cells_on_edge[iedge - 1, 1] - 1 + + if (cell1 != -1 and cell2 != -1): + if (lts_rgn[cell1] == 5 and lts_rgn[cell2] == 2): + + lts_rgn[cell2] = 5 + changed_cells[(i + 1) % 2].append(cell2) + + elif (lts_rgn[cell1] == 2 and lts_rgn[cell2] == 5): + + lts_rgn[cell1] = 5 + changed_cells[(i + 1) % 2].append(cell1) + + # n layers of interface region with label 4 + logger.info('Labeling interface cells...') + for i in range(0, num_interface): + changed_cells[(i + 1) % 2] = [] + + for icell in changed_cells[i % 2]: + edges = edges_on_cell[icell] + for iedge in edges: + if iedge != 0: + cell1 = cells_on_edge[iedge - 1, 0] - 1 + cell2 = cells_on_edge[iedge - 1, 1] - 1 + + if (cell1 != -1 and cell2 != -1): + # for the first layer, need to check neighbors are + # 5 and 2 + # for further layers, need to check neighbors are + # 3 and 2 + if (i == 0): + if (lts_rgn[cell1] == 5 and lts_rgn[cell2] == 2): + + lts_rgn[cell2] = 3 + changed_cells[(i + 1) % 2].append(cell2) + + elif (lts_rgn[cell1] == 2 and lts_rgn[cell2] == 5): + + lts_rgn[cell1] = 3 + changed_cells[(i + 1) % 2].append(cell1) + + else: + if (lts_rgn[cell1] == 3 and lts_rgn[cell2] == 2): + + lts_rgn[cell2] = 3 + changed_cells[(i + 1) % 2].append(cell2) + + elif (lts_rgn[cell1] == 2 and lts_rgn[cell2] == 3): + + lts_rgn[cell1] = 3 + changed_cells[(i + 1) % 2].append(cell1) + + changed_cells[0] = changed_cells[num_interface % 2] + + # n layers of interface region with label 3 + for i in range(0, num_interface): + changed_cells[(i + 1) % 2] = [] + + for icell in changed_cells[i % 2]: + edges = edges_on_cell[icell] + for iedge in edges: + if iedge != 0: + cell1 = cells_on_edge[iedge - 1, 0] - 1 + cell2 = cells_on_edge[iedge - 1, 1] - 1 + + if (cell1 != -1 and cell2 != -1): + # for the first layer, need to check neighbors are + # 5 and 2 + # for further layers, need to check neighbors are + # 3 and 2 + if (i == 0): + if (lts_rgn[cell1] == 3 and lts_rgn[cell2] == 2): + + lts_rgn[cell2] = 4 + changed_cells[(i + 1) % 2].append(cell2) + + elif (lts_rgn[cell1] == 2 and lts_rgn[cell2] == 3): + + lts_rgn[cell1] = 4 + changed_cells[(i + 1) % 2].append(cell1) + else: + if (lts_rgn[cell1] == 4 and lts_rgn[cell2] == 2): + + lts_rgn[cell2] = 4 + changed_cells[(i + 1) % 2].append(cell2) + + elif (lts_rgn[cell1] == 2 and lts_rgn[cell2] == 4): + + lts_rgn[cell1] = 4 + changed_cells[(i + 1) % 2].append(cell1) + + # create lts_mesh.nc + + logger.info('Creating lts_mesh...') + + # open mesh nc file to be copied + + ds_msh = xr.open_dataset(mesh) + ds_ltsmsh = ds_msh.copy(deep=True) + ltsmsh_name = 'lts_mesh.nc' + write_netcdf(ds_ltsmsh, ltsmsh_name) + mshnc = nc.Dataset(ltsmsh_name, 'a', format='NETCDF4_64BIT_OFFSET') + + try: + # try to get LTSRegion and assign new value + lts_rgn_NC = mshnc.variables['LTSRegion'] + lts_rgn_NC[:] = lts_rgn[:] + except KeyError: + # create new variable + ncells_NC = mshnc.dimensions['nCells'].name + lts_rgn_NC = mshnc.createVariable('LTSRegion', np.int32, (ncells_NC,)) + + # set new variable + lts_rgn_NC[:] = lts_rgn[:] + + mshnc.close() + + # open init nc file to be copied + + ds_init = xr.open_dataset(init) + ds_ltsinit = ds_init.copy(deep=True) + ltsinit_name = 'lts_ocean.nc' + write_netcdf(ds_ltsinit, ltsinit_name) + initnc = nc.Dataset(ltsinit_name, 'a', format='NETCDF4_64BIT_OFFSET') + + try: + # try to get LTSRegion and assign new value + lts_rgn_NC = initnc.variables['LTSRegion'] + lts_rgn_NC[:] = lts_rgn[:] + except KeyError: + # create new variable + ncells_NC = initnc.dimensions['nCells'].name + lts_rgn_NC = initnc.createVariable('LTSRegion', np.int32, (ncells_NC,)) + + # set new variable + lts_rgn_NC[:] = lts_rgn[:] + + initnc.close() + + extract_vtk(ignore_time=True, lonlat=0, + dimension_list=['maxEdges='], + variable_list=['allOnCells'], + filename_pattern=ltsmsh_name, + out_dir='lts_mesh_vtk', use_progress_bar=use_progress_bar) + + # label cells in graph.info + + logger.info('Weighting ' + graph_info + '...') + + fine_cells = 0 + coarse_cells = 0 + + newf = "" + with open(graph_info, 'r') as f: + lines = f.readlines() + # this is to have fine, coarse and interface be separate for METIS + # newf += lines[0].strip() + " 010 3 \n" + + # this is to have fine, and interface be together for METIS + newf += lines[0].strip() + " 010 2 \n" + for icell in range(1, len(lines)): + if (lts_rgn[icell - 1] == 1 or lts_rgn[icell - 1] == 5): # fine + + # newf+= "0 1 0 " + lines[icell].strip() + "\n" + newf += "0 1 " + lines[icell].strip() + "\n" + fine_cells = fine_cells + 1 + + elif (lts_rgn[icell - 1] == 2): # coarse + # newf+= "1 0 0 " + lines[icell].strip() + "\n" + newf += "1 0 " + lines[icell].strip() + "\n" + coarse_cells = coarse_cells + 1 + + else: # interface 1 and 2 + # newf+= "0 0 1 " + lines[icell].strip() + "\n" + newf += "0 1 " + lines[icell].strip() + "\n" + coarse_cells = coarse_cells + 1 + + with open('lts_graph.info', 'w') as f: + f.write(newf) + + max_area = max(area_cell) + min_area = min(area_cell) + max_width = 2 * np.sqrt(max_area / math.pi) / 1000 + min_width = 2 * np.sqrt(min_area / math.pi) / 1000 + area_ratio = max_area / min_area + width_ratio = max_width / min_width + number_ratio = coarse_cells / fine_cells + + txt = 'number of fine cells = {}\n'.format(fine_cells) + txt += 'number of coarse cells = {}\n'.format(coarse_cells) + txt += 'ratio of coarse to fine cells = {}\n'.format(number_ratio) + txt += 'ratio of largest to smallest cell area = {}\n'.format(area_ratio) + txt += 'ratio of largest to smallest cell width = {}\n'.format(width_ratio) + txt += 'number of interface layers = {}\n'.format(num_interface) + + logger.info(txt) + + with open('lts_mesh_info.txt', 'w') as f: + f.write(txt) diff --git a/compass/ocean/tests/dam_break/lts/namelist.init b/compass/ocean/tests/dam_break/lts/namelist.init new file mode 100644 index 0000000000..e1c69416a7 --- /dev/null +++ b/compass/ocean/tests/dam_break/lts/namelist.init @@ -0,0 +1,5 @@ +config_ocean_run_mode = 'init' +config_init_configuration='dam_break' +config_dam_break_vert_levels=1 +config_dam_break_R0=12.0 +config_drying_min_cell_height=1.0e-2 diff --git a/compass/ocean/tests/dam_break/lts/streams.forward b/compass/ocean/tests/dam_break/lts/streams.forward new file mode 100644 index 0000000000..9ab90e7783 --- /dev/null +++ b/compass/ocean/tests/dam_break/lts/streams.forward @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/compass/ocean/tests/parabolic_bowl/lts/__init__.py b/compass/ocean/tests/parabolic_bowl/lts/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/compass/ocean/tests/parabolic_bowl/lts/lts_regions.py b/compass/ocean/tests/parabolic_bowl/lts/lts_regions.py new file mode 100644 index 0000000000..da5f32496b --- /dev/null +++ b/compass/ocean/tests/parabolic_bowl/lts/lts_regions.py @@ -0,0 +1,332 @@ +import math +import os + +import netCDF4 as nc +import numpy as np +import xarray as xr +from mpas_tools.io import write_netcdf +from mpas_tools.viz.paraview_extractor import extract_vtk + +from compass.step import Step + + +class LTSRegions(Step): + """ + A step for adding LTS regions to a global MPAS-Ocean mesh + + Attributes + ---------- + initial_state_step : + compass.ocean.tests.dam_break.initial_state.InitialState + The initial step containing input files to this step + """ + def __init__(self, test_case, init_step, + name='lts_regions', subdir='lts_regions'): + """ + Create a new step + + Parameters + ---------- + test_case : compass.Testcase + The test case this step belongs to + + init_step : + compass.ocean.tests.dam_break.initial_state.InitialState + The initial state step containing input files to this step + + name : str, optional + the name of the step + + subdir : str, optional + the subdirectory for the step. The default is ``name`` + """ + super().__init__(test_case, name=name, subdir=subdir) + + for file in ['lts_mesh.nc', 'lts_graph.info', 'lts_ocean.nc']: + self.add_output_file(filename=file) + + self.init_step = init_step + + def setup(self): + """ + Set up the test case in the work directory, including downloading any + dependencies. + """ + super().setup() + + init_path = self.init_step.path + tgt1 = os.path.join(init_path, 'culled_mesh.nc') + self.add_input_file(filename='culled_mesh.nc', work_dir_target=tgt1) + + tgt2 = os.path.join(init_path, 'culled_graph.info') + self.add_input_file(filename='culled_graph.info', work_dir_target=tgt2) + + tgt3 = os.path.join(init_path, 'ocean.nc') + self.add_input_file(filename='ocean.nc', work_dir_target=tgt3) + + def run(self): + """ + Run this step of the test case + """ + + use_progress_bar = self.log_filename is None + label_mesh(init='ocean.nc', + mesh='culled_mesh.nc', + graph_info='culled_graph.info', num_interface=2, + logger=self.logger, use_progress_bar=use_progress_bar) + + +def label_mesh(init, mesh, graph_info, num_interface, # noqa: C901 + logger, use_progress_bar): + + # read in mesh data + ds = xr.open_dataset(mesh) + n_cells = ds['nCells'].size + n_edges = ds['nEdges'].size + area_cell = ds['areaCell'].values + cells_on_edge = ds['cellsOnEdge'].values + edges_on_cell = ds['edgesOnCell'].values + x_cell = ds['xCell'] + y_cell = ds['yCell'] + + # start by setting all cells to coarse + lts_rgn = [2] * n_cells + + # check each cell, if in the fine region, label as fine + logger.info('Labeling fine cells...') + for icell in range(0, n_cells): + xC = 745000.0 + yC = 701480.577065 + radius = np.sqrt((x_cell[icell] - xC) ** 2 + (y_cell[icell] - yC) ** 2) + if radius <= 192500.0: + lts_rgn[icell] = 1 + + # first layer of cells with label 5 + changed_cells = [[], []] + for iedge in range(0, n_edges): + cell1 = cells_on_edge[iedge, 0] - 1 + cell2 = cells_on_edge[iedge, 1] - 1 + + if (cell1 != -1 and cell2 != -1): + if (lts_rgn[cell1] == 1 and lts_rgn[cell2] == 2): + + lts_rgn[cell2] = 5 + changed_cells[0].append(cell2) + + elif (lts_rgn[cell1] == 2 and lts_rgn[cell2] == 1): + + lts_rgn[cell1] = 5 + changed_cells[0].append(cell1) + + # second and third layer of cells with label 5 + # only looping over cells changed during loop for previous layer + # at the end of this loop, changed_cells[0] will have the list of cells + # sharing edegs with the coarse cells + logger.info('Labeling interface-adjacent fine cells...') + for i in range(0, 2): # this loop creates 2 layers + changed_cells[(i + 1) % 2] = [] + + for icell in changed_cells[i % 2]: + edges = edges_on_cell[icell] + for iedge in edges: + if iedge != 0: + cell1 = cells_on_edge[iedge - 1, 0] - 1 + cell2 = cells_on_edge[iedge - 1, 1] - 1 + + if (cell1 != -1 and cell2 != -1): + if (lts_rgn[cell1] == 5 and lts_rgn[cell2] == 2): + + lts_rgn[cell2] = 5 + changed_cells[(i + 1) % 2].append(cell2) + + elif (lts_rgn[cell1] == 2 and lts_rgn[cell2] == 5): + + lts_rgn[cell1] = 5 + changed_cells[(i + 1) % 2].append(cell1) + + # n layers of interface region with label 4 + logger.info('Labeling interface cells...') + for i in range(0, num_interface): + changed_cells[(i + 1) % 2] = [] + + for icell in changed_cells[i % 2]: + edges = edges_on_cell[icell] + for iedge in edges: + if iedge != 0: + cell1 = cells_on_edge[iedge - 1, 0] - 1 + cell2 = cells_on_edge[iedge - 1, 1] - 1 + + if (cell1 != -1 and cell2 != -1): + # for the first layer, need to check neighbors are + # 5 and 2 + # for further layers, need to check neighbors are + # 3 and 2 + if (i == 0): + if (lts_rgn[cell1] == 5 and lts_rgn[cell2] == 2): + + lts_rgn[cell2] = 3 + changed_cells[(i + 1) % 2].append(cell2) + + elif (lts_rgn[cell1] == 2 and lts_rgn[cell2] == 5): + + lts_rgn[cell1] = 3 + changed_cells[(i + 1) % 2].append(cell1) + + else: + if (lts_rgn[cell1] == 3 and lts_rgn[cell2] == 2): + + lts_rgn[cell2] = 3 + changed_cells[(i + 1) % 2].append(cell2) + + elif (lts_rgn[cell1] == 2 and lts_rgn[cell2] == 3): + + lts_rgn[cell1] = 3 + changed_cells[(i + 1) % 2].append(cell1) + + changed_cells[0] = changed_cells[num_interface % 2] + + # n layers of interface region with label 3 + for i in range(0, num_interface): + changed_cells[(i + 1) % 2] = [] + + for icell in changed_cells[i % 2]: + edges = edges_on_cell[icell] + for iedge in edges: + if iedge != 0: + cell1 = cells_on_edge[iedge - 1, 0] - 1 + cell2 = cells_on_edge[iedge - 1, 1] - 1 + + if (cell1 != -1 and cell2 != -1): + # for the first layer, need to check neighbors are + # 5 and 2 + # for further layers, need to check neighbors are + # 3 and 2 + if (i == 0): + if (lts_rgn[cell1] == 3 and lts_rgn[cell2] == 2): + + lts_rgn[cell2] = 4 + changed_cells[(i + 1) % 2].append(cell2) + + elif (lts_rgn[cell1] == 2 and lts_rgn[cell2] == 3): + + lts_rgn[cell1] = 4 + changed_cells[(i + 1) % 2].append(cell1) + else: + if (lts_rgn[cell1] == 4 and lts_rgn[cell2] == 2): + + lts_rgn[cell2] = 4 + changed_cells[(i + 1) % 2].append(cell2) + + elif (lts_rgn[cell1] == 2 and lts_rgn[cell2] == 4): + + lts_rgn[cell1] = 4 + changed_cells[(i + 1) % 2].append(cell1) + + # create lts_mesh.nc + + logger.info('Creating lts_mesh...') + + # open mesh nc file to be copied + + ds_msh = xr.open_dataset(mesh) + ds_ltsmsh = ds_msh.copy(deep=True) + ltsmsh_name = 'lts_mesh.nc' + write_netcdf(ds_ltsmsh, ltsmsh_name) + mshnc = nc.Dataset(ltsmsh_name, 'a', format='NETCDF4_64BIT_OFFSET') + + try: + # try to get LTSRegion and assign new value + lts_rgn_NC = mshnc.variables['LTSRegion'] + lts_rgn_NC[:] = lts_rgn[:] + except KeyError: + # create new variable + ncells_NC = mshnc.dimensions['nCells'].name + lts_rgn_NC = mshnc.createVariable('LTSRegion', np.int32, (ncells_NC,)) + + # set new variable + lts_rgn_NC[:] = lts_rgn[:] + + mshnc.close() + + # open init nc file to be copied + + ds_init = xr.open_dataset(init) + ds_ltsinit = ds_init.copy(deep=True) + ltsinit_name = 'lts_ocean.nc' + write_netcdf(ds_ltsinit, ltsinit_name) + initnc = nc.Dataset(ltsinit_name, 'a', format='NETCDF4_64BIT_OFFSET') + + try: + # try to get LTSRegion and assign new value + lts_rgn_NC = initnc.variables['LTSRegion'] + lts_rgn_NC[:] = lts_rgn[:] + except KeyError: + # create new variable + ncells_NC = initnc.dimensions['nCells'].name + lts_rgn_NC = initnc.createVariable('LTSRegion', np.int32, (ncells_NC,)) + + # set new variable + lts_rgn_NC[:] = lts_rgn[:] + + initnc.close() + + extract_vtk(ignore_time=True, lonlat=0, + dimension_list=['maxEdges='], + variable_list=['allOnCells'], + filename_pattern=ltsmsh_name, + out_dir='lts_mesh_vtk', use_progress_bar=use_progress_bar) + + # label cells in graph.info + + logger.info('Weighting ' + graph_info + '...') + + fine_cells = 0 + coarse_cells = 0 + + newf = "" + with open(graph_info, 'r') as f: + lines = f.readlines() + # this is to have fine, coarse and interface be separate for METIS + # newf += lines[0].strip() + " 010 3 \n" + + # this is to have fine, and interface be together for METIS + newf += lines[0].strip() + " 010 2 \n" + for icell in range(1, len(lines)): + if (lts_rgn[icell - 1] == 1 or lts_rgn[icell - 1] == 5): # fine + + # newf+= "0 1 0 " + lines[icell].strip() + "\n" + newf += "0 1 " + lines[icell].strip() + "\n" + fine_cells = fine_cells + 1 + + elif (lts_rgn[icell - 1] == 2): # coarse + # newf+= "1 0 0 " + lines[icell].strip() + "\n" + newf += "1 0 " + lines[icell].strip() + "\n" + coarse_cells = coarse_cells + 1 + + else: # interface 1 and 2 + # newf+= "0 0 1 " + lines[icell].strip() + "\n" + newf += "0 1 " + lines[icell].strip() + "\n" + coarse_cells = coarse_cells + 1 + + with open('lts_graph.info', 'w') as f: + f.write(newf) + + max_area = max(area_cell) + min_area = min(area_cell) + max_width = 2 * np.sqrt(max_area / math.pi) / 1000 + min_width = 2 * np.sqrt(min_area / math.pi) / 1000 + area_ratio = max_area / min_area + width_ratio = max_width / min_width + number_ratio = coarse_cells / fine_cells + + txt = 'number of fine cells = {}\n'.format(fine_cells) + txt += 'number of coarse cells = {}\n'.format(coarse_cells) + txt += 'ratio of coarse to fine cells = {}\n'.format(number_ratio) + txt += 'ratio of largest to smallest cell area = {}\n'.format(area_ratio) + txt += 'ratio of largest to smallest cell width = {}\n'.format(width_ratio) + txt += 'number of interface layers = {}\n'.format(num_interface) + + logger.info(txt) + + with open('lts_mesh_info.txt', 'w') as f: + f.write(txt) diff --git a/compass/ocean/tests/parabolic_bowl/lts/streams.forward b/compass/ocean/tests/parabolic_bowl/lts/streams.forward new file mode 100644 index 0000000000..92f71fac06 --- /dev/null +++ b/compass/ocean/tests/parabolic_bowl/lts/streams.forward @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + From d0709f26b75e779acfa7f235a23679924b9f7ea1 Mon Sep 17 00:00:00 2001 From: Giacomo Capodaglio Date: Thu, 21 Dec 2023 16:29:26 -0800 Subject: [PATCH 03/10] Following Carolyn's suggestions --- compass/ocean/tests/dam_break/forward.py | 8 +++----- compass/ocean/tests/dam_break/lts/lts_regions.py | 5 ++--- compass/ocean/tests/dam_break/namelist.forward | 2 +- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/compass/ocean/tests/dam_break/forward.py b/compass/ocean/tests/dam_break/forward.py index b03cc972f2..99b6b68020 100644 --- a/compass/ocean/tests/dam_break/forward.py +++ b/compass/ocean/tests/dam_break/forward.py @@ -57,11 +57,9 @@ def __init__(self, test_case, resolution, use_lts, if use_lts: self.add_namelist_options( - {'config_time_integrator': "'LTS'"}) - self.add_namelist_options( - {'config_dt_scaling_LTS': "4"}) - self.add_namelist_options( - {'config_number_of_time_levels': "4"}) + {'config_time_integrator': "'LTS'", + 'config_dt_scaling_LTS': "4", + 'config_number_of_time_levels': "4"}) self.add_streams_file('compass.ocean.tests.dam_break.lts', 'streams.forward') diff --git a/compass/ocean/tests/dam_break/lts/lts_regions.py b/compass/ocean/tests/dam_break/lts/lts_regions.py index ffc08ecdb6..d8cd3e304f 100644 --- a/compass/ocean/tests/dam_break/lts/lts_regions.py +++ b/compass/ocean/tests/dam_break/lts/lts_regions.py @@ -1,4 +1,3 @@ -import math import os import netCDF4 as nc @@ -309,8 +308,8 @@ def label_mesh(init, mesh, graph_info, num_interface, # noqa: C901 max_area = max(area_cell) min_area = min(area_cell) - max_width = 2 * np.sqrt(max_area / math.pi) / 1000 - min_width = 2 * np.sqrt(min_area / math.pi) / 1000 + max_width = 2 * np.sqrt(max_area / np.pi) / 1000 + min_width = 2 * np.sqrt(min_area / np.pi) / 1000 area_ratio = max_area / min_area width_ratio = max_width / min_width number_ratio = coarse_cells / fine_cells diff --git a/compass/ocean/tests/dam_break/namelist.forward b/compass/ocean/tests/dam_break/namelist.forward index bcb3bafa49..4ce329af42 100644 --- a/compass/ocean/tests/dam_break/namelist.forward +++ b/compass/ocean/tests/dam_break/namelist.forward @@ -13,4 +13,4 @@ config_drying_min_cell_height=1e-6 config_thickness_flux_type='upwind' config_vert_coord_movement='impermeable_interfaces' config_use_debugTracers=.false. -config_disable_tr_all_tend =.true. +config_disable_tr_all_tend=.true. From 48de79dfc231ae128fdfb7c976684d0ca60f4e4b Mon Sep 17 00:00:00 2001 From: Giacomo Capodaglio Date: Thu, 21 Dec 2023 16:31:32 -0800 Subject: [PATCH 04/10] Restore parabolic_bowl/initial_state.py --- .../tests/parabolic_bowl/initial_state.py | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 compass/ocean/tests/parabolic_bowl/initial_state.py diff --git a/compass/ocean/tests/parabolic_bowl/initial_state.py b/compass/ocean/tests/parabolic_bowl/initial_state.py new file mode 100644 index 0000000000..a182a824ec --- /dev/null +++ b/compass/ocean/tests/parabolic_bowl/initial_state.py @@ -0,0 +1,92 @@ +from mpas_tools.io import write_netcdf +from mpas_tools.mesh.conversion import convert, cull +from mpas_tools.planar_hex import make_planar_hex_mesh + +from compass.model import run_model +from compass.step import Step + + +class InitialState(Step): + """ + A step for creating a mesh and initial condition for drying slope test + cases + """ + def __init__(self, test_case, name, resolution, + coord_type='single_layer', wetdry='standard'): + """ + Create the step + + Parameters + ---------- + test_case : compass.ocean.tests.parabolic_bowl.default.Default + The test case this step belongs to + """ + self.coord_type = coord_type + self.resolution = resolution + + super().__init__(test_case=test_case, name=name, ntasks=1, + min_tasks=1, openmp_threads=1) + + self.add_namelist_file('compass.ocean.tests.parabolic_bowl', + 'namelist.init', mode='init') + + self.add_streams_file('compass.ocean.tests.parabolic_bowl', + 'streams.init', mode='init') + + for file in ['base_mesh.nc', 'culled_mesh.nc', 'culled_graph.info', + 'ocean.nc']: + self.add_output_file(file) + + self.add_model_as_input() + + def run(self): + """ + Run this step of the test case + """ + config = self.config + logger = self.logger + + # Set vertical levels + coord_type = self.coord_type + if coord_type == 'single_layer': + options = {'config_parabolic_bowl_vert_levels': '1'} + else: + vert_levels = config.getint('vertical_grid', 'vert_levels') + options = {'config_parabolic_bowl_vert_levels': f'{vert_levels}'} + self.update_namelist_at_runtime(options) + + # Set test case parameters + eta_max = config.get('parabolic_bowl', 'eta_max') + depth_max = config.get('parabolic_bowl', 'depth_max') + coriolis = config.get('parabolic_bowl', 'coriolis_parameter') + omega = config.get('parabolic_bowl', 'omega') + gravity = config.get('parabolic_bowl', 'gravity') + options = {'config_parabolic_bowl_Coriolis_parameter': coriolis, + 'config_parabolic_bowl_eta0': eta_max, + 'config_parabolic_bowl_b0': depth_max, + 'config_parabolic_bowl_omega': omega, + 'config_parabolic_bowl_gravity': gravity} + self.update_namelist_at_runtime(options) + + # Determine mesh parameters + Lx = config.getint('parabolic_bowl', 'Lx') + Ly = config.getint('parabolic_bowl', 'Ly') + nx = round(Lx / self.resolution) + ny = round(Ly / self.resolution) + dc = 1e3 * self.resolution + + logger.info(' * Make planar hex mesh') + dsMesh = make_planar_hex_mesh(nx=nx, ny=ny, dc=dc, nonperiodic_x=True, + nonperiodic_y=True) + logger.info(' * Completed Make planar hex mesh') + write_netcdf(dsMesh, 'base_mesh.nc') + + logger.info(' * Cull mesh') + dsMesh = cull(dsMesh, logger=logger) + logger.info(' * Convert mesh') + dsMesh = convert(dsMesh, graphInfoFileName='culled_graph.info', + logger=logger) + logger.info(' * Completed Convert mesh') + write_netcdf(dsMesh, 'culled_mesh.nc') + run_model(self, namelist='namelist.ocean', + streams='streams.ocean') From df5970089af65d712f0960263bcc75fe9989974b Mon Sep 17 00:00:00 2001 From: Giacomo Capodaglio Date: Thu, 4 Jan 2024 15:50:01 -0800 Subject: [PATCH 05/10] Added parabolic_bowl.cfg --- .../tests/parabolic_bowl/parabolic_bowl.cfg | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 compass/ocean/tests/parabolic_bowl/parabolic_bowl.cfg diff --git a/compass/ocean/tests/parabolic_bowl/parabolic_bowl.cfg b/compass/ocean/tests/parabolic_bowl/parabolic_bowl.cfg new file mode 100644 index 0000000000..89e7ae2ca2 --- /dev/null +++ b/compass/ocean/tests/parabolic_bowl/parabolic_bowl.cfg @@ -0,0 +1,48 @@ +[job] + +wall_time = 2:00:00 + + +# config options for drying slope test cases +[parabolic_bowl] + +# dimensions of domain in x and y directions (km) +Lx = 1440 +Ly = 1560 + +# Coriolis parameter +coriolis_parameter = 1.031e-4 + +# maximum initial ssh magnitude +eta_max = 2.0 + +# maximum water depth +depth_max = 50.0 + +# angular fequency of oscillation +omega = 1.4544e-4 + +# gravitational acceleration +gravity = 9.81 + +# a list of resolutions (km) to test +resolutions = 20, 10, 5 + +# time step per resolution (s/km), since dt is proportional to resolution +dt_per_km = 0.5 + +# the number of cells per core to aim for +goal_cells_per_core = 300 + +# the approximate maximum number of cells per core (the test will fail if too +# few cores are available) +max_cells_per_core = 3000 + +# config options for visualizing drying slope ouptut +[parabolic_bowl_viz] + +# coordinates (in km) for timeseries plot +points = [0,0], [300,0], [610,0] + +# generate contour plots at a specified interval between output timesnaps +plot_interval = 10 From 205b5cbb98d7a1c3383fcd81fa6a16cfaf3ff93a Mon Sep 17 00:00:00 2001 From: Giacomo Capodaglio Date: Fri, 5 Jan 2024 07:20:46 -0800 Subject: [PATCH 06/10] Added more files --- compass/ocean/tests/dam_break/streams.forward | 23 +++++++++++++++++ compass/ocean/tests/dam_break/streams.init | 25 +++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 compass/ocean/tests/dam_break/streams.forward create mode 100644 compass/ocean/tests/dam_break/streams.init diff --git a/compass/ocean/tests/dam_break/streams.forward b/compass/ocean/tests/dam_break/streams.forward new file mode 100644 index 0000000000..aa1d1ad4b2 --- /dev/null +++ b/compass/ocean/tests/dam_break/streams.forward @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + diff --git a/compass/ocean/tests/dam_break/streams.init b/compass/ocean/tests/dam_break/streams.init new file mode 100644 index 0000000000..bd4b466e0e --- /dev/null +++ b/compass/ocean/tests/dam_break/streams.init @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + From c4e63f266988ee941b7ec17c67a9a0be25dfddc2 Mon Sep 17 00:00:00 2001 From: Giacomo Capodaglio Date: Fri, 5 Jan 2024 07:26:17 -0800 Subject: [PATCH 07/10] Added more files --- .../parabolic_bowl/namelist.10km.forward | 1 + .../parabolic_bowl/namelist.20km.forward | 1 + .../tests/parabolic_bowl/namelist.5km.forward | 1 + .../tests/parabolic_bowl/namelist.forward | 13 +++++++ .../ocean/tests/parabolic_bowl/namelist.init | 6 ++++ .../parabolic_bowl/namelist.ramp.forward | 3 ++ .../namelist.single_layer.forward | 7 ++++ .../tests/parabolic_bowl/streams.forward | 34 +++++++++++++++++++ .../ocean/tests/parabolic_bowl/streams.init | 32 +++++++++++++++++ 9 files changed, 98 insertions(+) create mode 100644 compass/ocean/tests/parabolic_bowl/namelist.10km.forward create mode 100644 compass/ocean/tests/parabolic_bowl/namelist.20km.forward create mode 100644 compass/ocean/tests/parabolic_bowl/namelist.5km.forward create mode 100644 compass/ocean/tests/parabolic_bowl/namelist.forward create mode 100644 compass/ocean/tests/parabolic_bowl/namelist.init create mode 100644 compass/ocean/tests/parabolic_bowl/namelist.ramp.forward create mode 100644 compass/ocean/tests/parabolic_bowl/namelist.single_layer.forward create mode 100644 compass/ocean/tests/parabolic_bowl/streams.forward create mode 100644 compass/ocean/tests/parabolic_bowl/streams.init diff --git a/compass/ocean/tests/parabolic_bowl/namelist.10km.forward b/compass/ocean/tests/parabolic_bowl/namelist.10km.forward new file mode 100644 index 0000000000..05af815f7e --- /dev/null +++ b/compass/ocean/tests/parabolic_bowl/namelist.10km.forward @@ -0,0 +1 @@ +config_dt='0000_00:00:05' diff --git a/compass/ocean/tests/parabolic_bowl/namelist.20km.forward b/compass/ocean/tests/parabolic_bowl/namelist.20km.forward new file mode 100644 index 0000000000..6594d67a91 --- /dev/null +++ b/compass/ocean/tests/parabolic_bowl/namelist.20km.forward @@ -0,0 +1 @@ +config_dt='0000_00:00:10' diff --git a/compass/ocean/tests/parabolic_bowl/namelist.5km.forward b/compass/ocean/tests/parabolic_bowl/namelist.5km.forward new file mode 100644 index 0000000000..b6cb4195f9 --- /dev/null +++ b/compass/ocean/tests/parabolic_bowl/namelist.5km.forward @@ -0,0 +1 @@ +config_dt='0000_00:00:02.5' diff --git a/compass/ocean/tests/parabolic_bowl/namelist.forward b/compass/ocean/tests/parabolic_bowl/namelist.forward new file mode 100644 index 0000000000..a8ec1ff4c4 --- /dev/null +++ b/compass/ocean/tests/parabolic_bowl/namelist.forward @@ -0,0 +1,13 @@ +config_run_duration='0003_00:00:00' +config_time_integrator='RK4' +config_vert_coord_movement='impermeable_interfaces' +config_ALE_thickness_proportionality='weights_only' +config_use_wetting_drying=.true. +config_prevent_drying=.true. +config_drying_min_cell_height=2.0e-2 +config_zero_drying_velocity=.true. +config_verify_not_dry=.true. +config_thickness_flux_type='upwind' +config_use_cvmix=.false. +config_check_ssh_consistency=.true. +config_implicit_constant_bottom_drag_coeff = 0.0 diff --git a/compass/ocean/tests/parabolic_bowl/namelist.init b/compass/ocean/tests/parabolic_bowl/namelist.init new file mode 100644 index 0000000000..d755143e04 --- /dev/null +++ b/compass/ocean/tests/parabolic_bowl/namelist.init @@ -0,0 +1,6 @@ +config_init_configuration = 'parabolic_bowl' +config_ocean_run_mode = 'init' +config_use_wetting_drying = .true. +config_drying_min_cell_height = 2e-2 +config_write_cull_cell_mask = .false. +config_parabolic_bowl_vert_levels = 1 diff --git a/compass/ocean/tests/parabolic_bowl/namelist.ramp.forward b/compass/ocean/tests/parabolic_bowl/namelist.ramp.forward new file mode 100644 index 0000000000..83673b1213 --- /dev/null +++ b/compass/ocean/tests/parabolic_bowl/namelist.ramp.forward @@ -0,0 +1,3 @@ +config_zero_drying_velocity_ramp = .true. +config_zero_drying_velocity_ramp_hmin = 2e-2 +config_zero_drying_velocity_ramp_hmax = 4e-2 diff --git a/compass/ocean/tests/parabolic_bowl/namelist.single_layer.forward b/compass/ocean/tests/parabolic_bowl/namelist.single_layer.forward new file mode 100644 index 0000000000..7378b7eee7 --- /dev/null +++ b/compass/ocean/tests/parabolic_bowl/namelist.single_layer.forward @@ -0,0 +1,7 @@ +config_disable_thick_vadv = .true. +config_disable_thick_sflux = .true. +config_disable_vel_vmix = .true. +config_disable_vel_vadv = .true. +config_disable_tr_all_tend = .true. +config_disable_vel_hmix = .true. +config_pressure_gradient_type = 'ssh_gradient' diff --git a/compass/ocean/tests/parabolic_bowl/streams.forward b/compass/ocean/tests/parabolic_bowl/streams.forward new file mode 100644 index 0000000000..a412ee4c9f --- /dev/null +++ b/compass/ocean/tests/parabolic_bowl/streams.forward @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/compass/ocean/tests/parabolic_bowl/streams.init b/compass/ocean/tests/parabolic_bowl/streams.init new file mode 100644 index 0000000000..1efd479999 --- /dev/null +++ b/compass/ocean/tests/parabolic_bowl/streams.init @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + From f69e1b916676a58ebd33814b6a5a3a88f34fc4e0 Mon Sep 17 00:00:00 2001 From: Giacomo Capodaglio Date: Tue, 9 Jan 2024 08:59:05 -0800 Subject: [PATCH 08/10] Modified comment in lts region creation --- compass/ocean/tests/dam_break/lts/lts_regions.py | 16 ++++++++++++---- .../tests/parabolic_bowl/lts/lts_regions.py | 16 ++++++++++++---- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/compass/ocean/tests/dam_break/lts/lts_regions.py b/compass/ocean/tests/dam_break/lts/lts_regions.py index d8cd3e304f..e3a6101834 100644 --- a/compass/ocean/tests/dam_break/lts/lts_regions.py +++ b/compass/ocean/tests/dam_break/lts/lts_regions.py @@ -281,25 +281,33 @@ def label_mesh(init, mesh, graph_info, num_interface, # noqa: C901 newf = "" with open(graph_info, 'r') as f: lines = f.readlines() - # this is to have fine, coarse and interface be separate for METIS - # newf += lines[0].strip() + " 010 3 \n" + # OLD METIS SETUP: fine and interface are separate for METIS + # CURRENT METIS SETUP: fine and interface are together for METIS - # this is to have fine, and interface be together for METIS + # OLD METIS SETUP: + # newf += lines[0].strip() + " 010 3 \n" + # CURRENT METIS SETUP: newf += lines[0].strip() + " 010 2 \n" + for icell in range(1, len(lines)): if (lts_rgn[icell - 1] == 1 or lts_rgn[icell - 1] == 5): # fine - + # OLD METIS SETUP: # newf+= "0 1 0 " + lines[icell].strip() + "\n" + # CURRENT METIS SETUP: newf += "0 1 " + lines[icell].strip() + "\n" fine_cells = fine_cells + 1 elif (lts_rgn[icell - 1] == 2): # coarse + # OLD METIS SETUP: # newf+= "1 0 0 " + lines[icell].strip() + "\n" + # CURRENT METIS SETUP: newf += "1 0 " + lines[icell].strip() + "\n" coarse_cells = coarse_cells + 1 else: # interface 1 and 2 + # OLD METIS SETUP: # newf+= "0 0 1 " + lines[icell].strip() + "\n" + # CURRENT METIS SETUP: newf += "0 1 " + lines[icell].strip() + "\n" coarse_cells = coarse_cells + 1 diff --git a/compass/ocean/tests/parabolic_bowl/lts/lts_regions.py b/compass/ocean/tests/parabolic_bowl/lts/lts_regions.py index da5f32496b..4885459736 100644 --- a/compass/ocean/tests/parabolic_bowl/lts/lts_regions.py +++ b/compass/ocean/tests/parabolic_bowl/lts/lts_regions.py @@ -286,25 +286,33 @@ def label_mesh(init, mesh, graph_info, num_interface, # noqa: C901 newf = "" with open(graph_info, 'r') as f: lines = f.readlines() - # this is to have fine, coarse and interface be separate for METIS - # newf += lines[0].strip() + " 010 3 \n" + # OLD METIS SETUP: fine and interface are separate for METIS + # CURRENT METIS SETUP: fine and interface are together for METIS - # this is to have fine, and interface be together for METIS + # OLD METIS SETUP: + # newf += lines[0].strip() + " 010 3 \n" + # CURRENT METIS SETUP: newf += lines[0].strip() + " 010 2 \n" + for icell in range(1, len(lines)): if (lts_rgn[icell - 1] == 1 or lts_rgn[icell - 1] == 5): # fine - + # OLD METIS SETUP: # newf+= "0 1 0 " + lines[icell].strip() + "\n" + # CURRENT METIS SETUP: newf += "0 1 " + lines[icell].strip() + "\n" fine_cells = fine_cells + 1 elif (lts_rgn[icell - 1] == 2): # coarse + # OLD METIS SETUP: # newf+= "1 0 0 " + lines[icell].strip() + "\n" + # CURRENT METIS SETUP: newf += "1 0 " + lines[icell].strip() + "\n" coarse_cells = coarse_cells + 1 else: # interface 1 and 2 + # OLD METIS SETUP: # newf+= "0 0 1 " + lines[icell].strip() + "\n" + # CURRENT METIS SETUP: newf += "0 1 " + lines[icell].strip() + "\n" coarse_cells = coarse_cells + 1 From 3e952d858e4cb36a271d561da6d5382268597861 Mon Sep 17 00:00:00 2001 From: Giacomo Capodaglio Date: Mon, 22 Jan 2024 06:22:27 -0800 Subject: [PATCH 09/10] Modified pressure gradient type for forward nmlist --- compass/ocean/tests/dam_break/forward.py | 3 ++- compass/ocean/tests/parabolic_bowl/forward.py | 9 ++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/compass/ocean/tests/dam_break/forward.py b/compass/ocean/tests/dam_break/forward.py index 99b6b68020..ae6d4ba5e9 100644 --- a/compass/ocean/tests/dam_break/forward.py +++ b/compass/ocean/tests/dam_break/forward.py @@ -59,7 +59,8 @@ def __init__(self, test_case, resolution, use_lts, self.add_namelist_options( {'config_time_integrator': "'LTS'", 'config_dt_scaling_LTS': "4", - 'config_number_of_time_levels': "4"}) + 'config_number_of_time_levels': "4", + 'config_pressure_gradient_type': "'ssh_gradient'"}) self.add_streams_file('compass.ocean.tests.dam_break.lts', 'streams.forward') diff --git a/compass/ocean/tests/parabolic_bowl/forward.py b/compass/ocean/tests/parabolic_bowl/forward.py index 53ce2908b8..5863bd9de2 100644 --- a/compass/ocean/tests/parabolic_bowl/forward.py +++ b/compass/ocean/tests/parabolic_bowl/forward.py @@ -57,11 +57,10 @@ def __init__(self, test_case, resolution, if use_lts: self.add_namelist_options( - {'config_time_integrator': "'LTS'"}) - self.add_namelist_options( - {'config_dt_scaling_LTS': "4"}) - self.add_namelist_options( - {'config_number_of_time_levels': "4"}) + {'config_time_integrator': "'LTS'", + 'config_dt_scaling_LTS': "4", + 'config_number_of_time_levels': "4", + 'config_pressure_gradient_type': "'ssh_gradient'"}) self.add_streams_file('compass.ocean.tests.parabolic_bowl.lts', 'streams.forward') input_path = f'../lts_regions_{res_name}' From a0aca48b18bfaf791e595c42053b345f0cf91545 Mon Sep 17 00:00:00 2001 From: Giacomo Capodaglio Date: Thu, 25 Jan 2024 13:54:22 -0800 Subject: [PATCH 10/10] Added lts tests to suites and updated docs --- compass/ocean/suites/lts.txt | 9 +++++++++ compass/ocean/suites/wetdry.txt | 8 ++++++++ docs/users_guide/ocean/test_groups/dam_break.rst | 8 ++++++++ docs/users_guide/ocean/test_groups/parabolic_bowl.rst | 8 ++++++++ 4 files changed, 33 insertions(+) create mode 100644 compass/ocean/suites/lts.txt diff --git a/compass/ocean/suites/lts.txt b/compass/ocean/suites/lts.txt new file mode 100644 index 0000000000..53d10afead --- /dev/null +++ b/compass/ocean/suites/lts.txt @@ -0,0 +1,9 @@ +ocean/dam_break/40cm/default_lts +ocean/dam_break/40cm/ramp_lts +ocean/dam_break/120cm/default_lts +ocean/dam_break/120cm/ramp_lts +ocean/hurricane/DEQU120at30cr10rr2/mesh_lts +ocean/hurricane/DEQU120at30cr10rr2/init_lts +ocean/hurricane/DEQU120at30cr10rr2/sandy_lts +ocean/parabolic_bowl/standard/ramp_lts +ocean/parabolic_bowl/standard/noramp_lts diff --git a/compass/ocean/suites/wetdry.txt b/compass/ocean/suites/wetdry.txt index 0a1307c10c..2577929041 100644 --- a/compass/ocean/suites/wetdry.txt +++ b/compass/ocean/suites/wetdry.txt @@ -20,6 +20,14 @@ ocean/dam_break/40cm/default ocean/dam_break/40cm/ramp ocean/dam_break/120cm/default ocean/dam_break/120cm/ramp +ocean/dam_break/40cm/default_lts +ocean/dam_break/40cm/ramp_lts +ocean/dam_break/120cm/default_lts +ocean/dam_break/120cm/ramp_lts +ocean/parabolic_bowl/standard/ramp +ocean/parabolic_bowl/standard/noramp +ocean/parabolic_bowl/standard/ramp_lts +ocean/parabolic_bowl/standard/noramp_lts ocean/isomip_plus/planar/5km/sigma/thin_film_drying_Ocean0 ocean/isomip_plus/planar/5km/sigma/thin_film_wetting_Ocean0 ocean/isomip_plus/planar/5km/single_layer/thin_film_tidal_forcing_Ocean0 diff --git a/docs/users_guide/ocean/test_groups/dam_break.rst b/docs/users_guide/ocean/test_groups/dam_break.rst index 5c9ace7152..485b6cb818 100644 --- a/docs/users_guide/ocean/test_groups/dam_break.rst +++ b/docs/users_guide/ocean/test_groups/dam_break.rst @@ -51,3 +51,11 @@ ramp the factor that scales velocities and velocity tendencies is ramped over a given layer thickness range rather than a binary switch at the minimum thickness. ``RES`` is either 40cm or 120cm. + +lts +--- + +Both the ``default`` and ``ramp`` test cases can be run with the ``lts`` variant +which uses local time-stepping (LTS) as time integrator. Note that the tests +verify the ability of the LTS scheme to run correctly with wetting and drying +and are not designed to leverage the LTS capability of producing faster runs. diff --git a/docs/users_guide/ocean/test_groups/parabolic_bowl.rst b/docs/users_guide/ocean/test_groups/parabolic_bowl.rst index 8030a395ef..2093f4d677 100644 --- a/docs/users_guide/ocean/test_groups/parabolic_bowl.rst +++ b/docs/users_guide/ocean/test_groups/parabolic_bowl.rst @@ -169,3 +169,11 @@ viz The visualization step can be configured to plot the timeseries for an arbitrary set of coordinates by setting ``points``. Also, the interval between contour plot time snaps can be controlled with ``plot_interval``. + +lts +~~~ + +Both the ``ramp`` and ``noramp`` test cases can be run with the ``lts`` variant +which uses local time-stepping (LTS) as time integrator. Note that the tests +verify the ability of the LTS scheme to run correctly with wetting and drying +and are not designed to leverage the LTS capability of producing faster runs.