From 306526bd46ad7c3989f8dac2fdc5e16a6ef6c197 Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Mon, 27 Jun 2022 11:59:10 +0200 Subject: [PATCH 1/7] Add 80 layer E3SMv1 vertical interfaces --- compass/ocean/vertical/80layerE3SMv1.json | 81 +++++++++++++++++++++++ compass/ocean/vertical/grid_1d.py | 2 +- 2 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 compass/ocean/vertical/80layerE3SMv1.json diff --git a/compass/ocean/vertical/80layerE3SMv1.json b/compass/ocean/vertical/80layerE3SMv1.json new file mode 100644 index 0000000000..9e748828a3 --- /dev/null +++ b/compass/ocean/vertical/80layerE3SMv1.json @@ -0,0 +1,81 @@ +[0.0, + 1.986786469355805, + 4.154119395541748, + 6.518473015615179, + 9.097824574809877, + 11.911737056573685, + 14.981608934309552, + 18.330839881040465, + 21.984828733039574, + 25.971389018482437, + 30.320829117011147, + 35.066198637149725, + 40.24353341642255, + 45.892098753893194, + 52.054713914204456, + 58.778073608483226, + 66.11298212263647, + 74.11483297053151, + 82.84399843035216, + 92.36612734933736, + 102.75259907640329, + 114.08104666296263, + 126.43577878360325, + 139.90834494484784, + 154.5979878835862, + 170.61222402211808, + 188.06721008633497, + 207.08846155392177, + 227.81108029827277, + 250.38029644815975, + 274.95164090923384, + 301.69113003347167, + 330.7752620963125, + 362.3906244929844, + 396.73330941558294, + 434.00792602635505, + 474.42608083399733, + 518.2042060869917, + 565.5607828175309, + 616.7129401252857, + 671.8720767795905, + 731.2388094472287, + 794.9973708678924, + 863.3093165271582, + 936.3071845957666, + 1014.0882623825473, + 1096.7088376639208, + 1184.1797979766206, + 1276.4637610648406, + 1373.474191183026, + 1475.0766739591154, + 1581.0924977739978, + 1691.3042518457269, + 1805.4629509798497, + 1923.2961967654483, + 2044.5166633553195, + 2168.83040784201, + 2295.9444441559367, + 2425.5731465435715, + 2557.443466443468, + 2691.2987229942432, + 2826.9011458061473, + 2964.033287582243, + 3102.4984729509856, + 3242.1205209147015, + 3382.742909836675, + 3524.227580019397, + 3666.4535034604037, + 3809.3151441356854, + 3952.7208868168414, + 4096.591510555103, + 4240.85873802501, + 4385.46388801116, + 4530.356647311017, + 4675.493968648996, + 4820.839083119443, + 4966.360630500305, + 5112.031898664707, + 5257.830157844073, + 5403.736084165608, + 5549.733263212151] \ No newline at end of file diff --git a/compass/ocean/vertical/grid_1d.py b/compass/ocean/vertical/grid_1d.py index 69e02e2019..53dc20f47f 100644 --- a/compass/ocean/vertical/grid_1d.py +++ b/compass/ocean/vertical/grid_1d.py @@ -36,7 +36,7 @@ def generate_1d_grid(config): min_layer_thickness, max_layer_thickness) - elif grid_type in ['60layerPHC', '100layerE3SMv1']: + elif grid_type in ['60layerPHC', '80layerE3SMv1', '100layerE3SMv1']: interfaces = _read_json(grid_type) else: raise ValueError('Unexpected grid type: {}'.format(grid_type)) From 1787d14e8a39c324c00e9f546b3cc4d17d94acca Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Thu, 30 Jun 2022 17:51:53 +0200 Subject: [PATCH 2/7] Write out land locked cells mask for debugging --- compass/ocean/mesh/cull.py | 1 + 1 file changed, 1 insertion(+) diff --git a/compass/ocean/mesh/cull.py b/compass/ocean/mesh/cull.py index 3faf23333d..205e6af2b5 100644 --- a/compass/ocean/mesh/cull.py +++ b/compass/ocean/mesh/cull.py @@ -264,6 +264,7 @@ def _cull_mesh_with_logging(logger, with_cavities, with_critical_passages, dsLandMask = add_land_locked_cells_to_mask(dsLandMask, dsBaseMesh, latitude_threshold=43.0, nSweeps=20) + write_netcdf(dsLandMask, 'land_mask_with_land_locked_cells.nc') # create seed points for a flood fill of the ocean # use all points in the ocean directory, on the assumption that they are, From b7632cb61aed82fdee7540cfd3296e9cf4b390a0 Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Wed, 27 Jul 2022 10:27:37 -0500 Subject: [PATCH 3/7] Update geometric_features to include new critical passages/blockages --- conda/compass_env/spec-file.template | 2 +- conda/recipe/meta.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/conda/compass_env/spec-file.template b/conda/compass_env/spec-file.template index d5159e10fb..f6ab26ab15 100644 --- a/conda/compass_env/spec-file.template +++ b/conda/compass_env/spec-file.template @@ -8,7 +8,7 @@ cartopy_offlinedata cmocean esmf=*={{ mpi_prefix }}_* ffmpeg -geometric_features=0.5.0 +geometric_features=0.7.0 git ipython jigsaw=0.9.14 diff --git a/conda/recipe/meta.yaml b/conda/recipe/meta.yaml index 115ad324f7..3198596dc8 100644 --- a/conda/recipe/meta.yaml +++ b/conda/recipe/meta.yaml @@ -45,7 +45,7 @@ requirements: - cmocean - esmf * {{ mpi_prefix }}_* - ffmpeg - - geometric_features 0.5.0 + - geometric_features 0.7.0 - git - ipython - jigsaw 0.9.14 From d54cc982f5c24d714d5070ba871d85a966d84ee9 Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Sat, 30 Jul 2022 02:39:52 -0500 Subject: [PATCH 4/7] Update to GEBCO 2022 and BedMachine v2 bathymetry --- compass/ocean/tests/global_ocean/configure.py | 4 ++-- compass/ocean/tests/global_ocean/init/initial_state.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compass/ocean/tests/global_ocean/configure.py b/compass/ocean/tests/global_ocean/configure.py index 0d4f30002b..0a6d2ae7d2 100644 --- a/compass/ocean/tests/global_ocean/configure.py +++ b/compass/ocean/tests/global_ocean/configure.py @@ -38,8 +38,8 @@ def configure_global_ocean(test_case, mesh, init=None): # a description of the bathymetry config.set('global_ocean', 'bathy_description', - 'Bathymetry is from GEBCO 2019, combined with BedMachine ' - 'Antarctica around Antarctica.') + 'Bathymetry is from GEBCO 2022, combined with BedMachine ' + 'Antarctica v2 around Antarctica.') if init is not None and init.with_bgc: # todo: this needs to be filled in! diff --git a/compass/ocean/tests/global_ocean/init/initial_state.py b/compass/ocean/tests/global_ocean/init/initial_state.py index 155039f0b4..5564fae49f 100644 --- a/compass/ocean/tests/global_ocean/init/initial_state.py +++ b/compass/ocean/tests/global_ocean/init/initial_state.py @@ -68,7 +68,7 @@ def __init__(self, test_case, mesh, initial_condition, with_bgc): self.add_input_file( filename='topography.nc', - target='BedMachineAntarctica_and_GEBCO_2019_0.05_degree.200128.nc', + target='BedMachineAntarctica_v2_and_GEBCO_2022_0.05_degree_20220729.nc', database='bathymetry_database') self.add_input_file( From a8c4eeb0ef5f497d73073b554f7b31f738087cc8 Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Sat, 30 Jul 2022 02:40:43 -0500 Subject: [PATCH 5/7] Update docs to GEBCO 2022 and BedMachine v2 bathymetry --- docs/developers_guide/organization.rst | 4 ++-- docs/users_guide/config_files.rst | 2 +- docs/users_guide/ocean/test_groups/global_ocean.rst | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/developers_guide/organization.rst b/docs/developers_guide/organization.rst index 28d2bdc9a3..d51bd42927 100644 --- a/docs/developers_guide/organization.rst +++ b/docs/developers_guide/organization.rst @@ -1529,12 +1529,12 @@ To add an input file from a database, call self.add_input_file( filename='topography.nc', - target='BedMachineAntarctica_and_GEBCO_2019_0.05_degree.200128.nc', + target='BedMachineAntarctica_v2_and_GEBCO_2022_0.05_degree_20220729.nc', database='bathymetry_database') In this example from :py:class:`compass.ocean.tests.global_ocean.init.initial_state.InitialState()`, -the file ``BedMachineAntarctica_and_GEBCO_2019_0.05_degree.200128.nc`` is +the file ``BedMachineAntarctica_v2_and_GEBCO_2022_0.05_degree_20220729.nc`` is slated for later downloaded from `MPAS-Ocean's bathymetry database `_. The file will be stored in the subdirectory ``bathymetry_database`` of the path diff --git a/docs/users_guide/config_files.rst b/docs/users_guide/config_files.rst index 936d6f9423..c700bba710 100644 --- a/docs/users_guide/config_files.rst +++ b/docs/users_guide/config_files.rst @@ -362,7 +362,7 @@ looks like: level # source: /home/xylar/code/compass/customize_config_parser/compass/ocean/tests/global_ocean/configure.py - bathy_description = Bathymetry is from GEBCO 2019, combined with BedMachine Antarctica around Antarctica. + bathy_description = Bathymetry is from GEBCO 2022, combined with BedMachine Antarctica v2 around Antarctica. # a description of the mesh with ice-shelf cavities # source: /home/xylar/code/compass/customize_config_parser/compass/ocean/tests/global_ocean/global_ocean.cfg diff --git a/docs/users_guide/ocean/test_groups/global_ocean.rst b/docs/users_guide/ocean/test_groups/global_ocean.rst index 514f818679..7bf3aa525f 100644 --- a/docs/users_guide/ocean/test_groups/global_ocean.rst +++ b/docs/users_guide/ocean/test_groups/global_ocean.rst @@ -191,7 +191,7 @@ is not yet known at the time of mesh creation): :MPAS_Mesh_QU_Maximum_Depth_m = "3000.0" ; :MPAS_Mesh_QU_Number_of_Levels = "16" ; :MPAS_Mesh_Description = "MPAS quasi-uniform mesh for E3SM version 2 at 240-km global resolution with 16 vertical level" ; - :MPAS_Mesh_Bathymetry = "Bathymetry is from GEBCO 2019, combined with BedMachine Antarctica around Antarctica." ; + :MPAS_Mesh_Bathymetry = "Bathymetry is from GEBCO 2022, combined with BedMachine Antarctica v2 around Antarctica." ; :MPAS_Initial_Condition = "Polar science center Hydrographic Climatology (PHC)" ; :MPAS_Mesh_COMPASS_Version = "1.0.0" ; :MPAS_Mesh_JIGSAW_Version = "0.9.12" ; From 964d5fec5b5610d2e2057ddfd5e7a07e7b01565a Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Thu, 30 Jun 2022 17:59:15 +0200 Subject: [PATCH 6/7] Add namelist.init and streams.init for each mesh --- .../ocean/tests/global_ocean/init/initial_state.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/compass/ocean/tests/global_ocean/init/initial_state.py b/compass/ocean/tests/global_ocean/init/initial_state.py index 5564fae49f..39c89acc5b 100644 --- a/compass/ocean/tests/global_ocean/init/initial_state.py +++ b/compass/ocean/tests/global_ocean/init/initial_state.py @@ -1,3 +1,5 @@ +from importlib.resources import contents + from compass.ocean.tests.global_ocean.metadata import \ add_mesh_and_init_metadata from compass.model import run_model @@ -66,6 +68,16 @@ def __init__(self, test_case, mesh, initial_condition, with_bgc): if mesh.with_ice_shelf_cavities: self.add_streams_file(package, 'streams.wisc', mode='init') + mesh_package = mesh.package + mesh_package_contents = list(contents(mesh_package)) + mesh_namelist = 'namelist.init' + if mesh_namelist in mesh_package_contents: + self.add_namelist_file(mesh_package, mesh_namelist, mode='init') + + mesh_streams = 'streams.init' + if mesh_streams in mesh_package_contents: + self.add_streams_file(mesh_package, mesh_streams, mode='init') + self.add_input_file( filename='topography.nc', target='BedMachineAntarctica_v2_and_GEBCO_2022_0.05_degree_20220729.nc', From 4e64c3e718f845bf515a9afe4dc34e0375d6e73d Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Fri, 24 Jun 2022 13:18:33 +0200 Subject: [PATCH 7/7] Add ARRM10to60 mesh The mesh resolution has been ported from legacy COMPASS. --- compass/ocean/tests/global_ocean/__init__.py | 25 ++ .../ocean/tests/global_ocean/mesh/__init__.py | 7 +- .../arrm10to60/Americas_land_mask.geojson | 49 ++++ .../mesh/arrm10to60/Atlantic_region.geojson | 141 ++++++++++ .../Europe_Africa_land_mask.geojson | 69 +++++ .../global_ocean/mesh/arrm10to60/__init__.py | 157 ++++++++++++ .../mesh/arrm10to60/arrm10to60.cfg | 45 ++++ .../arrm10to60/dynamic_adjustment/__init__.py | 240 ++++++++++++++++++ .../dynamic_adjustment/streams.template | 12 + .../mesh/arrm10to60/namelist.init | 1 + .../mesh/arrm10to60/namelist.split_explicit | 10 + 11 files changed, 754 insertions(+), 2 deletions(-) create mode 100644 compass/ocean/tests/global_ocean/mesh/arrm10to60/Americas_land_mask.geojson create mode 100644 compass/ocean/tests/global_ocean/mesh/arrm10to60/Atlantic_region.geojson create mode 100644 compass/ocean/tests/global_ocean/mesh/arrm10to60/Europe_Africa_land_mask.geojson create mode 100644 compass/ocean/tests/global_ocean/mesh/arrm10to60/__init__.py create mode 100644 compass/ocean/tests/global_ocean/mesh/arrm10to60/arrm10to60.cfg create mode 100644 compass/ocean/tests/global_ocean/mesh/arrm10to60/dynamic_adjustment/__init__.py create mode 100644 compass/ocean/tests/global_ocean/mesh/arrm10to60/dynamic_adjustment/streams.template create mode 100644 compass/ocean/tests/global_ocean/mesh/arrm10to60/namelist.init create mode 100644 compass/ocean/tests/global_ocean/mesh/arrm10to60/namelist.split_explicit diff --git a/compass/ocean/tests/global_ocean/__init__.py b/compass/ocean/tests/global_ocean/__init__.py index c6f38cf31e..3bb1eb1b4a 100644 --- a/compass/ocean/tests/global_ocean/__init__.py +++ b/compass/ocean/tests/global_ocean/__init__.py @@ -5,6 +5,8 @@ QU240DynamicAdjustment from compass.ocean.tests.global_ocean.mesh.ec30to60.dynamic_adjustment import \ EC30to60DynamicAdjustment +from compass.ocean.tests.global_ocean.mesh.arrm10to60.dynamic_adjustment \ + import ARRM10to60DynamicAdjustment from compass.ocean.tests.global_ocean.mesh.so12to60.dynamic_adjustment import \ SO12to60DynamicAdjustment from compass.ocean.tests.global_ocean.mesh.wc14.dynamic_adjustment import \ @@ -155,6 +157,29 @@ def __init__(self, mpas_core): test_group=self, mesh=mesh, init=init, dynamic_adjustment=dynamic_adjustment)) + # ARRM10to60: just the version without cavities + for mesh_name in ['ARRM10to60']: + mesh = Mesh(test_group=self, mesh_name=mesh_name) + self.add_test_case(mesh) + + init = Init(test_group=self, mesh=mesh, + initial_condition='PHC', + with_bgc=False) + self.add_test_case(init) + time_integrator = 'split_explicit' + self.add_test_case( + PerformanceTest( + test_group=self, mesh=mesh, init=init, + time_integrator=time_integrator)) + dynamic_adjustment = ARRM10to60DynamicAdjustment( + test_group=self, mesh=mesh, init=init, + time_integrator=time_integrator) + self.add_test_case(dynamic_adjustment) + self.add_test_case( + FilesForE3SM( + test_group=self, mesh=mesh, init=init, + dynamic_adjustment=dynamic_adjustment)) + # SOwISC12to60: just the version with cavities for now for mesh_name in ['SOwISC12to60']: mesh = Mesh(test_group=self, mesh_name=mesh_name) diff --git a/compass/ocean/tests/global_ocean/mesh/__init__.py b/compass/ocean/tests/global_ocean/mesh/__init__.py index 1655aa4d09..2338bd4a51 100644 --- a/compass/ocean/tests/global_ocean/mesh/__init__.py +++ b/compass/ocean/tests/global_ocean/mesh/__init__.py @@ -2,6 +2,7 @@ from compass.mesh.spherical import IcosahedralMeshStep, \ QuasiUniformSphericalMeshStep from compass.ocean.mesh.cull import CullMeshStep +from compass.ocean.tests.global_ocean.mesh.arrm10to60 import ARRM10to60BaseMesh from compass.ocean.tests.global_ocean.mesh.ec30to60 import EC30to60BaseMesh from compass.ocean.tests.global_ocean.mesh.so12to60 import SO12to60BaseMesh from compass.ocean.tests.global_ocean.mesh.wc14 import WC14BaseMesh @@ -37,7 +38,7 @@ def __init__(self, test_group, mesh_name): The name of the mesh """ name = 'mesh' - subdir = '{}/{}'.format(mesh_name, name) + subdir = f'{mesh_name}/{name}' super().__init__(test_group=test_group, name=name, subdir=subdir) with_ice_shelf_cavities = 'wISC' in mesh_name @@ -63,9 +64,11 @@ def __init__(self, test_group, mesh_name): self, name=name, subdir=subdir, cell_width=240) elif mesh_name in ['EC30to60', 'ECwISC30to60']: base_mesh_step = EC30to60BaseMesh(self, name=name, subdir=subdir) + elif mesh_name in ['ARRM10to60']: + base_mesh_step = ARRM10to60BaseMesh(self, name=name, subdir=subdir) elif mesh_name in ['SOwISC12to60']: base_mesh_step = SO12to60BaseMesh(self, name=name, subdir=subdir) - elif mesh_name in 'WC14': + elif mesh_name in ['WC14']: base_mesh_step = WC14BaseMesh(self, name=name, subdir=subdir) else: raise ValueError(f'Unknown mesh name {mesh_name}') diff --git a/compass/ocean/tests/global_ocean/mesh/arrm10to60/Americas_land_mask.geojson b/compass/ocean/tests/global_ocean/mesh/arrm10to60/Americas_land_mask.geojson new file mode 100644 index 0000000000..28e9da4447 --- /dev/null +++ b/compass/ocean/tests/global_ocean/mesh/arrm10to60/Americas_land_mask.geojson @@ -0,0 +1,49 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "name": "Americas land mask", + "component": "ocean", + "object": "region", + "author": "Mark Petersen" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -38.67187499999999, + -55.578344672182055 + ], + [ + -24.960937499999996, + -55.578344672182055 + ], + [ + -34.453125, + 53.12040528310657 + ], + [ + -59.765625, + 53.12040528310657 + ], + [ + -131.8359375, + 49.15296965617042 + ], + [ + -132.1875, + -56.55948248376223 + ], + [ + -38.67187499999999, + -55.578344672182055 + ] + ] + ] + } + } + ] +} diff --git a/compass/ocean/tests/global_ocean/mesh/arrm10to60/Atlantic_region.geojson b/compass/ocean/tests/global_ocean/mesh/arrm10to60/Atlantic_region.geojson new file mode 100644 index 0000000000..7738f9689b --- /dev/null +++ b/compass/ocean/tests/global_ocean/mesh/arrm10to60/Atlantic_region.geojson @@ -0,0 +1,141 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "name": "Atlantic region", + "component": "ocean", + "object": "region", + "author": "Mark Petersen" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -68.203125, + -78.1344931829381 + ], + [ + 26.015625, + -77.8418477505252 + ], + [ + 23.5546875, + -26.431228064506424 + ], + [ + 21.4453125, + 26.745610382199022 + ], + [ + 34.80468749999999, + 30.14512718337613 + ], + [ + 40.078125, + 33.7243396617476 + ], + [ + 37.6171875, + 39.36827914916014 + ], + [ + 28.4765625, + 40.17887331434696 + ], + [ + 25.3125, + 43.58039085560784 + ], + [ + 28.828124999999996, + 54.77534585936447 + ], + [ + 41.8359375, + 64.01449619484472 + ], + [ + 65.7421875, + 76.434603583513 + ], + [ + 67.8515625, + 84.95930495623836 + ], + [ + -70.3125, + 84.89714695160268 + ], + [ + -126.21093749999999, + 75.05035357407698 + ], + [ + -112.5, + 60.58696734225869 + ], + [ + -104.4140625, + 51.39920565355378 + ], + [ + -101.953125, + 29.38217507514529 + ], + [ + -97.734375, + 18.145851771694467 + ], + [ + -93.515625, + 16.97274101999902 + ], + [ + -88.24218749999999, + 14.604847155053898 + ], + [ + -85.25390625, + 11.695272733029402 + ], + [ + -82.6171875, + 9.44906182688142 + ], + [ + -80.5078125, + 8.407168163601076 + ], + [ + -79.1015625, + 8.928487062665504 + ], + [ + -76.9921875, + 7.536764322084078 + ], + [ + -62.22656249999999, + -2.108898659243126 + ], + [ + -70.6640625, + -52.696361078274464 + ], + [ + -64.3359375, + -67.60922060496382 + ], + [ + -68.203125, + -78.1344931829381 + ] + ] + ] + } + } + ] +} diff --git a/compass/ocean/tests/global_ocean/mesh/arrm10to60/Europe_Africa_land_mask.geojson b/compass/ocean/tests/global_ocean/mesh/arrm10to60/Europe_Africa_land_mask.geojson new file mode 100644 index 0000000000..d50ff4c965 --- /dev/null +++ b/compass/ocean/tests/global_ocean/mesh/arrm10to60/Europe_Africa_land_mask.geojson @@ -0,0 +1,69 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "name": "Europe Africa land mask", + "component": "ocean", + "object": "region", + "author": "Mark Petersen" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 15.1171875, + 58.07787626787517 + ], + [ + 8.4375, + 49.61070993807422 + ], + [ + 0.703125, + 43.068887774169625 + ], + [ + -5.2734375, + 39.095962936305476 + ], + [ + -3.1640625, + 20.96143961409684 + ], + [ + 2.109375, + -33.43144133557529 + ], + [ + 55.54687499999999, + -31.653381399663985 + ], + [ + 53.0859375, + 60.58696734225869 + ], + [ + 33.046875, + 63.704722429433225 + ], + [ + 24.2578125, + 68.00757101804004 + ], + [ + 17.2265625, + 65.07213008560697 + ], + [ + 15.1171875, + 58.07787626787517 + ] + ] + ] + } + } + ] +} diff --git a/compass/ocean/tests/global_ocean/mesh/arrm10to60/__init__.py b/compass/ocean/tests/global_ocean/mesh/arrm10to60/__init__.py new file mode 100644 index 0000000000..5858892fa0 --- /dev/null +++ b/compass/ocean/tests/global_ocean/mesh/arrm10to60/__init__.py @@ -0,0 +1,157 @@ +import numpy as np +import matplotlib.pyplot as plt +import cartopy.crs as ccrs +import cartopy.feature as cfeature + +import mpas_tools.mesh.creation.mesh_definition_tools as mdt +from mpas_tools.mesh.creation.signed_distance import \ + signed_distance_from_geojson, mask_from_geojson +from geometric_features import read_feature_collection +from mpas_tools.cime.constants import constants +from mpas_tools.viz.colormaps import register_sci_viz_colormaps + +from compass.mesh import QuasiUniformSphericalMeshStep + + +class ARRM10to60BaseMesh(QuasiUniformSphericalMeshStep): + """ + A step for creating the ARRM10to60 base mesh + """ + def setup(self): + """ + Add some input files + """ + inputs = ['Americas_land_mask.geojson', + 'Atlantic_region.geojson', + 'Europe_Africa_land_mask.geojson'] + for filename in inputs: + self.add_input_file(filename=filename, + package=self.__module__) + super().setup() + + def build_cell_width_lat_lon(self): + """ + Create cell width array for this mesh on a regular latitude-longitude + grid + + Returns + ------- + cellWidth : numpy.array + m x n array of cell width in km + + lon : numpy.array + longitude in degrees (length n and between -180 and 180) + + lat : numpy.array + longitude in degrees (length m and between -90 and 90) + """ + + dlon = 0.1 + dlat = dlon + earth_radius = constants['SHR_CONST_REARTH'] + print('\nCreating cellWidth on a lat-lon grid of: {0:.2f} x {0:.2f} ' + 'degrees'.format(dlon, dlat)) + print('This can be set higher for faster test generation\n') + nlon = int(360. / dlon) + 1 + nlat = int(180. / dlat) + 1 + lon = np.linspace(-180., 180., nlon) + lat = np.linspace(-90., 90., nlat) + km = 1.0e3 + + print('plotting ...') + plt.switch_backend('Agg') + register_sci_viz_colormaps() + fig = plt.figure() + plt.clf() + fig.set_size_inches(10.0, 10.0) + register_sci_viz_colormaps() + + # Create cell width vs latitude for Atlantic and Pacific basins + qu1 = np.ones(lat.size) + ec30to60 = mdt.EC_CellWidthVsLat(lat) + rrs10to30 = mdt.RRS_CellWidthVsLat(lat, 30, 10) + atl_nh = rrs10to30 + atl_vs_lat = mdt.mergeCellWidthVsLat(lat, ec30to60, atl_nh, 0, 6) + pac_nh = mdt.mergeCellWidthVsLat(lat, 30 * qu1, rrs10to30, 50, 10) + pac_vs_lat = mdt.mergeCellWidthVsLat(lat, ec30to60, pac_nh, 0, 6) + + # Expand from 1D to 2D + _, atl_grid = np.meshgrid(lon, atl_vs_lat) + _, pac_grid = np.meshgrid(lon, pac_vs_lat) + + # Signed distance of Atlantic region + fc = read_feature_collection('Atlantic_region.geojson') + signed_distance = signed_distance_from_geojson( + fc, lon, lat, earth_radius, max_length=0.25) + + # Merge Atlantic and Pacific distributions smoothly + transition_width = 500.0 * km + mask_smooth = 0.5 * (1 + np.tanh(signed_distance / transition_width)) + cell_width_smooth = \ + pac_grid * mask_smooth + atl_grid * (1 - mask_smooth) + + # Merge Atlantic and Pacific distributions with step function + mask_sharp = 0.5 * (1 + np.sign(signed_distance)) + cell_width_sharp = pac_grid * mask_sharp + atl_grid * (1 - mask_sharp) + + # Create a land mask that is 1 over land + fc = read_feature_collection('Americas_land_mask.geojson') + americas_land_mask = mask_from_geojson(fc, lon, lat) + fc = read_feature_collection('Europe_Africa_land_mask.geojson') + europe_africa_land_mask = mask_from_geojson(fc, lon, lat) + land_mask = np.fmax(americas_land_mask, europe_africa_land_mask) + + # Merge: step transition over land, smooth transition over water + cell_width = \ + cell_width_sharp * land_mask + cell_width_smooth * (1 - land_mask) + + ax = plt.subplot(4, 2, 1) + ax.plot(lat, atl_vs_lat, label='Atlantic') + ax.plot(lat, pac_vs_lat, label='Pacific') + ax.grid(True) + plt.title('Grid cell size [km] versus latitude') + plt.legend() + + var_names = [ + 'signed_distance', + 'mask_smooth', + 'cell_width_smooth', + 'mask_sharp', + 'cell_width_sharp', + 'land_mask', + 'cell_width'] + j = 2 + for var_name in var_names: + _plot_cartopy(j, var_name, vars()[var_name], '3Wbgy5') + j += 1 + fig.canvas.draw() + plt.tight_layout() + + plt.savefig('mesh_construction.png') + + return cell_width, lon, lat + + +def _plot_cartopy(plot_number, var_name, var, map_name): + ax = plt.subplot(4, 2, plot_number, projection=ccrs.PlateCarree()) + ax.set_global() + im = ax.imshow(var, + origin='lower', + transform=ccrs.PlateCarree(), + extent=[-180, 180, -90, 90], cmap=map_name, + zorder=0) + ax.add_feature(cfeature.LAND, edgecolor='black', zorder=1) + gl = ax.gridlines( + crs=ccrs.PlateCarree(), + draw_labels=True, + linewidth=1, + color='gray', + alpha=0.5, + linestyle='-', zorder=2) + ax.coastlines() + gl.top_labels = False + gl.bottom_labels = False + gl.right_labels = False + gl.left_labels = False + plt.colorbar(im, shrink=.9) + plt.title(var_name) diff --git a/compass/ocean/tests/global_ocean/mesh/arrm10to60/arrm10to60.cfg b/compass/ocean/tests/global_ocean/mesh/arrm10to60/arrm10to60.cfg new file mode 100644 index 0000000000..46b4826918 --- /dev/null +++ b/compass/ocean/tests/global_ocean/mesh/arrm10to60/arrm10to60.cfg @@ -0,0 +1,45 @@ +# Options related to the vertical grid +[vertical_grid] + +# the type of vertical grid +grid_type = 80layerE3SMv1 + + +# options for global ocean testcases +[global_ocean] + +## config options related to the initial_state step +# number of cores to use +init_ntasks = 256 +# minimum of cores, below which the step fails +init_min_tasks = 64 +# maximum memory usage allowed (in MB) +init_max_memory = 1000 + +## config options related to the forward steps +# number of cores to use +forward_ntasks = 2000 +# minimum of cores, below which the step fails +forward_min_tasks = 200 +# maximum memory usage allowed (in MB) +forward_max_memory = 1000 + +## metadata related to the mesh +# the prefix (e.g. QU, EC, WC, SO) +prefix = ARRM +# a description of the mesh and initial condition +mesh_description = MPAS Arctic Regionally Refined Mesh (ARRM) for E3SM version + ${e3sm_version}, with ${min_res}-km resolution in the Arctic + and ${levels} vertical levels + +# E3SM version that the mesh is intended for +e3sm_version = 2 +# The revision number of the mesh, which should be incremented each time the +# mesh is revised +mesh_revision = 1 +# the minimum (finest) resolution in the mesh +min_res = 10 +# the maximum (coarsest) resolution in the mesh, can be the same as min_res +max_res = 60 +# The URL of the pull request documenting the creation of the mesh +pull_request = https://github.com/MPAS-Dev/compass/pull/414 diff --git a/compass/ocean/tests/global_ocean/mesh/arrm10to60/dynamic_adjustment/__init__.py b/compass/ocean/tests/global_ocean/mesh/arrm10to60/dynamic_adjustment/__init__.py new file mode 100644 index 0000000000..a97a76dbb9 --- /dev/null +++ b/compass/ocean/tests/global_ocean/mesh/arrm10to60/dynamic_adjustment/__init__.py @@ -0,0 +1,240 @@ +from compass.ocean.tests.global_ocean.dynamic_adjustment import \ + DynamicAdjustment +from compass.ocean.tests.global_ocean.forward import ForwardStep + + +class ARRM10to60DynamicAdjustment(DynamicAdjustment): + """ + A test case performing dynamic adjustment (dissipating fast-moving waves) + from an initial condition on the ARRM10to60 MPAS-Ocean mesh + + Attributes + ---------- + restart_filenames : list of str + A list of restart files from each dynamic-adjustment step + """ + + def __init__(self, test_group, mesh, init, time_integrator): + """ + Create the test case + + Parameters + ---------- + test_group : compass.ocean.tests.global_ocean.GlobalOcean + The global ocean test group that this test case belongs to + + mesh : compass.ocean.tests.global_ocean.mesh.Mesh + The test case that produces the mesh for this run + + init : compass.ocean.tests.global_ocean.init.Init + The test case that produces the initial condition for this run + + time_integrator : {'split_explicit', 'RK4'} + The time integrator to use for the forward run + """ + if time_integrator != 'split_explicit': + raise ValueError('{} dynamic adjustment not defined for {}'.format( + mesh.mesh_name, time_integrator)) + + restart_times = ['0001-01-01_06:00:00', '0001-01-01_12:00:00', + '0001-01-02_00:00:00', '0001-01-03_00:00:00', + '0001-01-04_00:00:00', '0001-01-07_00:00:00', + '0001-01-31_00:00:00'] + restart_filenames = [ + 'restarts/rst.{}.nc'.format(restart_time.replace(':', '.')) + for restart_time in restart_times] + + super().__init__(test_group=test_group, mesh=mesh, init=init, + time_integrator=time_integrator, + restart_filenames=restart_filenames) + + module = self.__module__ + + shared_options = \ + {'config_AM_globalStats_enable': '.true.', + 'config_AM_globalStats_compute_on_startup': '.true.', + 'config_AM_globalStats_write_on_startup': '.true.', + 'config_use_activeTracers_surface_restoring': '.true.'} + + # first step + step_name = 'damped_adjustment_1' + step = ForwardStep(test_case=self, mesh=mesh, init=init, + time_integrator=time_integrator, name=step_name, + subdir=step_name) + + namelist_options = { + 'config_run_duration': "'00-00-00_06:00:00'", + 'config_dt': "'00:00:30'", + 'config_btr_dt': "'00:00:01.5'", + 'config_Rayleigh_friction': '.true.', + 'config_Rayleigh_damping_coeff': '1.0e-3'} + namelist_options.update(shared_options) + step.add_namelist_options(namelist_options) + + stream_replacements = { + 'output_interval': '00-00-10_00:00:00', + 'restart_interval': '00-00-00_06:00:00'} + step.add_streams_file(module, 'streams.template', + template_replacements=stream_replacements) + + step.add_output_file(filename='../{}'.format(restart_filenames[0])) + self.add_step(step) + + # second step + step_name = 'damped_adjustment_2' + step = ForwardStep(test_case=self, mesh=mesh, init=init, + time_integrator=time_integrator, name=step_name, + subdir=step_name) + + namelist_options = { + 'config_run_duration': "'00-00-00_06:00:00'", + 'config_dt': "'00:01:00'", + 'config_btr_dt': "'00:00:03'", + 'config_Rayleigh_friction': '.true.', + 'config_Rayleigh_damping_coeff': '4.0e-4', + 'config_do_restart': '.true.', + 'config_start_time': "'{}'".format(restart_times[0])} + namelist_options.update(shared_options) + step.add_namelist_options(namelist_options) + + stream_replacements = { + 'output_interval': '00-00-10_00:00:00', + 'restart_interval': '00-00-00_06:00:00'} + step.add_streams_file(module, 'streams.template', + template_replacements=stream_replacements) + + step.add_input_file(filename='../{}'.format(restart_filenames[0])) + step.add_output_file(filename='../{}'.format(restart_filenames[1])) + self.add_step(step) + + # third step + step_name = 'damped_adjustment_3' + step = ForwardStep(test_case=self, mesh=mesh, init=init, + time_integrator=time_integrator, name=step_name, + subdir=step_name) + + namelist_options = { + 'config_run_duration': "'00-00-00_12:00:00'", + 'config_dt': "'00:02:00'", + 'config_btr_dt': "'00:00:06'", + 'config_Rayleigh_friction': '.true.', + 'config_Rayleigh_damping_coeff': '1.0e-4', + 'config_do_restart': '.true.', + 'config_start_time': "'{}'".format(restart_times[1])} + namelist_options.update(shared_options) + step.add_namelist_options(namelist_options) + + stream_replacements = { + 'output_interval': '00-00-10_00:00:00', + 'restart_interval': '00-00-00_12:00:00'} + step.add_streams_file(module, 'streams.template', + template_replacements=stream_replacements) + + step.add_input_file(filename='../{}'.format(restart_filenames[1])) + step.add_output_file(filename='../{}'.format(restart_filenames[2])) + self.add_step(step) + + # fourth step + step_name = 'damped_adjustment_4' + step = ForwardStep(test_case=self, mesh=mesh, init=init, + time_integrator=time_integrator, name=step_name, + subdir=step_name) + + namelist_options = { + 'config_run_duration': "'00-00-01_00:00:00'", + 'config_dt': "'00:03:00'", + 'config_btr_dt': "'00:00:09'", + 'config_Rayleigh_friction': '.true.', + 'config_Rayleigh_damping_coeff': '4.0e-5', + 'config_do_restart': '.true.', + 'config_start_time': "'{}'".format(restart_times[2])} + namelist_options.update(shared_options) + step.add_namelist_options(namelist_options) + + stream_replacements = { + 'output_interval': '00-00-10_00:00:00', + 'restart_interval': '00-00-01_00:00:00'} + step.add_streams_file(module, 'streams.template', + template_replacements=stream_replacements) + + step.add_input_file(filename='../{}'.format(restart_filenames[2])) + step.add_output_file(filename='../{}'.format(restart_filenames[3])) + self.add_step(step) + + # fifth step + step_name = 'damped_adjustment_5' + step = ForwardStep(test_case=self, mesh=mesh, init=init, + time_integrator=time_integrator, name=step_name, + subdir=step_name) + + namelist_options = { + 'config_run_duration': "'00-00-01_00:00:00'", + 'config_dt': "'00:05:00'", + 'config_btr_dt': "'00:00:12'", + 'config_Rayleigh_friction': '.true.', + 'config_Rayleigh_damping_coeff': '2.0e-5', + 'config_do_restart': '.true.', + 'config_start_time': "'{}'".format(restart_times[3])} + namelist_options.update(shared_options) + step.add_namelist_options(namelist_options) + + stream_replacements = { + 'output_interval': '00-00-10_00:00:00', + 'restart_interval': '00-00-01_00:00:00'} + step.add_streams_file(module, 'streams.template', + template_replacements=stream_replacements) + + step.add_input_file(filename='../{}'.format(restart_filenames[3])) + step.add_output_file(filename='../{}'.format(restart_filenames[4])) + self.add_step(step) + + # sixth step + step_name = 'damped_adjustment_6' + step = ForwardStep(test_case=self, mesh=mesh, init=init, + time_integrator=time_integrator, name=step_name, + subdir=step_name) + + namelist_options = { + 'config_run_duration': "'00-00-03_00:00:00'", + 'config_dt': "'00:07:30'", + 'config_btr_dt': "'00:00:15'", + 'config_do_restart': '.true.', + 'config_start_time': "'{}'".format(restart_times[4])} + namelist_options.update(shared_options) + step.add_namelist_options(namelist_options) + + stream_replacements = { + 'output_interval': '00-00-10_00:00:00', + 'restart_interval': '00-00-03_00:00:00'} + step.add_streams_file(module, 'streams.template', + template_replacements=stream_replacements) + + step.add_input_file(filename='../{}'.format(restart_filenames[4])) + step.add_output_file(filename='../{}'.format(restart_filenames[5])) + self.add_step(step) + + # final step + step_name = 'simulation' + step = ForwardStep(test_case=self, mesh=mesh, init=init, + time_integrator=time_integrator, name=step_name, + subdir=step_name) + + namelist_options = { + 'config_run_duration': "'00-00-24_00:00:00'", + 'config_do_restart': '.true.', + 'config_start_time': "'{}'".format(restart_times[5])} + namelist_options.update(shared_options) + step.add_namelist_options(namelist_options) + + stream_replacements = { + 'output_interval': '00-00-10_00:00:00', + 'restart_interval': '00-00-06_00:00:00'} + step.add_streams_file(module, 'streams.template', + template_replacements=stream_replacements) + + step.add_input_file(filename='../{}'.format(restart_filenames[5])) + step.add_output_file(filename='../{}'.format(restart_filenames[6])) + step.add_output_file(filename='output.nc') + self.add_step(step) + + self.restart_filenames = restart_filenames diff --git a/compass/ocean/tests/global_ocean/mesh/arrm10to60/dynamic_adjustment/streams.template b/compass/ocean/tests/global_ocean/mesh/arrm10to60/dynamic_adjustment/streams.template new file mode 100644 index 0000000000..31a4652e75 --- /dev/null +++ b/compass/ocean/tests/global_ocean/mesh/arrm10to60/dynamic_adjustment/streams.template @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/compass/ocean/tests/global_ocean/mesh/arrm10to60/namelist.init b/compass/ocean/tests/global_ocean/mesh/arrm10to60/namelist.init new file mode 100644 index 0000000000..7a72508ff8 --- /dev/null +++ b/compass/ocean/tests/global_ocean/mesh/arrm10to60/namelist.init @@ -0,0 +1 @@ +config_global_ocean_minimum_depth = 10 diff --git a/compass/ocean/tests/global_ocean/mesh/arrm10to60/namelist.split_explicit b/compass/ocean/tests/global_ocean/mesh/arrm10to60/namelist.split_explicit new file mode 100644 index 0000000000..80b5a57595 --- /dev/null +++ b/compass/ocean/tests/global_ocean/mesh/arrm10to60/namelist.split_explicit @@ -0,0 +1,10 @@ +config_time_integrator = 'split_explicit' +config_dt = '00:10:00' +config_btr_dt = '00:00:24' +config_run_duration = '0000_01:00:00' +config_write_output_on_startup = false. +config_mom_del2 = 10.0 +config_mom_del4 = 1.5e10 +config_hmix_scaleWithMesh = .true. +config_use_GM = .true. +config_Redi_min_layers_diag_terms = 15