Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
e51e3bf
Add landice mesh_convergence test case
matthewhoffman Aug 19, 2023
a812a87
Correct passiceTracer to have no vertical dim
matthewhoffman Aug 19, 2023
fcc862a
Remove velo cap to allow prescribed velocity to be used
matthewhoffman Aug 21, 2023
2882850
Add Halfar mesh convergence test
matthewhoffman Aug 21, 2023
8335a2c
Make each test case in the group define its own output stream contents
matthewhoffman Aug 21, 2023
4e27b35
Get both convergence tests working together
matthewhoffman Aug 22, 2023
9224dac
Add dome center error convergence in addition to rmse
matthewhoffman Aug 22, 2023
ef32615
Minor tweaks to configurations
matthewhoffman Aug 23, 2023
42f1207
Add thickness advection version of horizontal_advection test
matthewhoffman Aug 26, 2023
0059100
Fix name of passive tracer variable
andrewdnolan Nov 7, 2023
9e6536f
Update analysis output files
andrewdnolan Nov 7, 2023
10b9f06
Upate tracer field in the streams file
andrewdnolan Nov 7, 2023
1a70fa1
Change restart output interval from 30 days to 30 years.
trhille Nov 9, 2023
8abf2de
Update passiveTracer to passiveTracer2d in analysis.py
trhille Nov 9, 2023
fdb7016
Change clobber mode from truncate to overwrite
trhille Aug 19, 2024
f9c2f07
Fix isort issue from linter
trhille Aug 19, 2024
96e0807
Suppress warnings with decode_timedelta=False
trhille Apr 8, 2026
fb2de39
Make 2, 4, 8, 16km the default resolution for horizontal_advection
trhille Apr 8, 2026
8dfb101
Make third-order space and time default for convergence tests
trhille Apr 8, 2026
c814164
Create documentation for landice/mesh_convergence cases
trhille Apr 9, 2026
688e4bb
Update MALI-Dev submodule to include recent bug fixes to RK
trhille Apr 9, 2026
10006b9
Fix error when building docs
trhille Apr 9, 2026
c347683
Apply suggestions from code review
trhille Apr 9, 2026
a8ad846
Fix typo in landice dome setup
trhille Apr 9, 2026
09c2e82
Raise ValueError instead of sys.exit
trhille Apr 9, 2026
46607bc
Fix bug in landice mesh convergence plots
trhille Apr 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions compass/landice/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from compass.landice.tests.isunnguata_sermia import IsunnguataSermia
from compass.landice.tests.kangerlussuaq import Kangerlussuaq
from compass.landice.tests.koge_bugt_s import KogeBugtS
from compass.landice.tests.mesh_convergence import MeshConvergence
from compass.landice.tests.mesh_modifications import MeshModifications
from compass.landice.tests.mismipplus import MISMIPplus
from compass.landice.tests.slm import Slm
Expand Down Expand Up @@ -48,6 +49,7 @@ def __init__(self):
self.add_test_group(IsunnguataSermia(mpas_core=self))
self.add_test_group(Kangerlussuaq(mpas_core=self))
self.add_test_group(KogeBugtS(mpas_core=self))
self.add_test_group(MeshConvergence(mpas_core=self))
self.add_test_group(MeshModifications(mpas_core=self))
self.add_test_group(MISMIPplus(mpas_core=self))
self.add_test_group(Slm(mpas_core=self))
Expand Down
8 changes: 4 additions & 4 deletions compass/landice/tests/dome/setup_mesh.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,11 @@ def run(self):
make_graph_file(mesh_filename='landice_grid.nc',
graph_filename='graph.info')

_setup_dome_initial_conditions(config, logger,
filename='landice_grid.nc')
setup_dome_initial_conditions(config, logger,
filename='landice_grid.nc')


def _setup_dome_initial_conditions(config, logger, filename):
def setup_dome_initial_conditions(config, logger, filename):
Comment thread
trhille marked this conversation as resolved.
"""
Add the initial condition to the given MPAS mesh file

Expand All @@ -104,7 +104,7 @@ def _setup_dome_initial_conditions(config, logger, filename):
dome_type = section.get('dome_type')
put_origin_on_a_cell = section.getboolean('put_origin_on_a_cell')
shelf = section.getboolean('shelf')
hydro = section.getboolean('hyrdo')
hydro = section.getboolean('hydro')

# Open the file, get needed dimensions
gridfile = NetCDFFile(filename, 'r+')
Expand Down
24 changes: 24 additions & 0 deletions compass/landice/tests/mesh_convergence/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from compass.landice.tests.mesh_convergence.halfar import Halfar
from compass.landice.tests.mesh_convergence.horizontal_advection import (
HorizontalAdvection,
)
from compass.landice.tests.mesh_convergence.horizontal_advection_thickness import ( # noqa
HorizontalAdvectionThickness,
)
from compass.testgroup import TestGroup


class MeshConvergence(TestGroup):
"""
A test group for convergence tests with MALI
"""
def __init__(self, mpas_core):
"""
mpas_core : compass.landice.LandIce
the MPAS core that this test group belongs to
"""
super().__init__(mpas_core=mpas_core, name='mesh_convergence')

self.add_test_case(HorizontalAdvection(test_group=self))
self.add_test_case(HorizontalAdvectionThickness(test_group=self))
self.add_test_case(Halfar(test_group=self))
34 changes: 34 additions & 0 deletions compass/landice/tests/mesh_convergence/conv_analysis.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from compass.step import Step


class ConvAnalysis(Step):
"""
A step for visualizing and/or analyzing the output from a convergence test
case

Attributes
----------
resolutions : list of int
The resolutions of the meshes that have been run
"""
def __init__(self, test_case, resolutions):
"""
Create the step

Parameters
----------
test_case : compass.TestCase
The test case this step belongs to

resolutions : list of int
The resolutions of the meshes that have been run
"""
super().__init__(test_case=test_case, name='analysis')
self.resolutions = resolutions

# typically, the analysis will rely on the output from the forward
# steps
for resolution in resolutions:
self.add_input_file(
filename='{}km_output.nc'.format(resolution),
target='../{}km/forward/output.nc'.format(resolution))
67 changes: 67 additions & 0 deletions compass/landice/tests/mesh_convergence/conv_init.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
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 mpas_tools.translate import center

from compass.model import make_graph_file
from compass.step import Step


class ConvInit(Step):
"""
A step for creating a mesh for a given resolution in a mesh convergence
test case. A child class of this step should then create an appropriate
initial condition.

Attributes
----------
resolution : int
The resolution of the test case
"""
def __init__(self, test_case, resolution):
"""
Create the step

Parameters
----------
test_case : compass.TestCase
The test case this step belongs to

resolution : int
The resolution of the test case
"""
super().__init__(test_case=test_case,
name='{}km_init'.format(resolution),
subdir='{}km/init'.format(resolution))

for file in ['mesh.nc', 'graph.info']:
self.add_output_file(file)

self.resolution = resolution

def run(self):
"""
Run this step of the test case
"""
logger = self.logger
config = self.config
resolution = float(self.resolution)

section = config['mesh_convergence']
nx_1km = section.getint('nx_1km')
ny_1km = section.getint('ny_1km')
nx = int(nx_1km / resolution)
ny = int(ny_1km / resolution)
dc = resolution * 1e3
nonperiodic = section.getboolean('nonperiodic')

ds_mesh = make_planar_hex_mesh(nx=nx, ny=ny, dc=dc,
nonperiodic_x=nonperiodic,
nonperiodic_y=nonperiodic)

ds_mesh = cull(ds_mesh, logger=logger)
ds_mesh = convert(ds_mesh, logger=logger)
center(ds_mesh)

write_netcdf(ds_mesh, 'mesh.nc')
make_graph_file('mesh.nc', 'graph.info')
143 changes: 143 additions & 0 deletions compass/landice/tests/mesh_convergence/conv_test_case.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
from compass.config import CompassConfigParser
from compass.landice.tests.mesh_convergence.forward import Forward
from compass.testcase import TestCase


class ConvTestCase(TestCase):
"""
A test case for various convergence tests on in MALI with planar,
doubly periodic meshes

Attributes
----------
resolutions : list of int
"""
def __init__(self, test_group, name):
"""
Create test case for creating a MALI mesh

Parameters
----------
test_group : compass.ocean.tests.mesh_convergence.MeshConvergence
The test group that this test case belongs to

name : str
The name of the test case
"""
super().__init__(test_group=test_group, name=name)
self.resolutions = None

# add the steps with default resolutions so they can be listed
config = CompassConfigParser()
module = 'compass.landice.tests.mesh_convergence'
config.add_from_package(module, 'mesh_convergence.cfg')
self._setup_steps(config)

def configure(self):
"""
Set config options for the test case
"""
config = self.config
# set up the steps again in case a user has provided new resolutions
self._setup_steps(config)

self.update_cores()

def update_cores(self):
""" Update the number of cores and min_tasks for each forward step """

config = self.config

goal_cells_per_core = config.getfloat('mesh_convergence',
'goal_cells_per_core')
max_cells_per_core = config.getfloat('mesh_convergence',
'max_cells_per_core')

section = config['mesh_convergence']
nx_1km = section.getint('nx_1km')
ny_1km = section.getint('ny_1km')

for resolution in self.resolutions:
nx = int(nx_1km / resolution)
ny = int(ny_1km / resolution)
# a heuristic based on
cell_count = nx * ny
# ideally, about 300 cells per core
# (make it a multiple of 4 because...it looks better?)
ntasks = max(1, 4 * round(cell_count / (4 * goal_cells_per_core)))
# In a pinch, about 3000 cells per core
min_tasks = max(1, round(cell_count / max_cells_per_core))
step = self.steps[f'{resolution}km_forward']
step.ntasks = ntasks
step.min_tasks = min_tasks

config.set('mesh_convergence', f'{resolution}km_ntasks',
str(ntasks))
config.set('mesh_convergence', f'{resolution}km_min_tasks',
str(min_tasks))

def _setup_steps(self, config):
"""
setup steps given resolutions

Parameters
----------
config : compass.config.CompassConfigParser
The config options containing the resolutions
"""

resolutions = config.getlist('mesh_convergence', 'resolutions',
dtype=int)

if self.resolutions is not None and self.resolutions == resolutions:
return

# start fresh with no steps
self.steps = dict()
self.steps_to_run = list()

self.resolutions = resolutions

for resolution in resolutions:
self.add_step(self.create_init(resolution=resolution))
self.add_step(Forward(test_case=self, resolution=resolution))

self.add_step(self.create_analysis(resolutions=resolutions))

def create_init(self, resolution):
"""

Child class must override this to return an instance of a
ConvergenceInit step

Parameters
----------
resolution : int
The resolution of the step

Returns
-------
init : compass.landice.tests.mesh_convergence.convergence_init.ConvergenceInit # noqa
The init step object
"""

pass

def create_analysis(self, resolutions):
"""

Child class must override this to return an instance of a
ConvergenceInit step

Parameters
----------
resolutions : list of int
The resolutions of the other steps in the test case

Returns
-------
analysis : compass.landice.tests.mesh_convergence.conv_analysis.ConvAnalysis # noqa
The init step object
"""

pass
Loading
Loading