-
Notifications
You must be signed in to change notification settings - Fork 19
A polynya test case #797
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
A polynya test case #797
Changes from 44 commits
9199211
db69db8
805e1c0
e510c07
327de33
b99de51
60f876b
0584cbf
0077c28
02720e1
f4b5ebd
eef5a16
1a3c692
be756c3
150b21f
21cf14e
4c6a41a
768c4d4
d515e03
e10ccbf
2e06954
6bcb88d
437d6d1
cbd56d8
5781dbf
94e2b63
0ad9d32
53116d9
be0823c
95c2a86
fad93a1
5356fd1
4c3a1dc
a783559
7d4da1f
dd519cd
54919ec
58d8277
ee55629
d4be55e
17f55a7
00270c8
11ffd45
ef78f73
e4cec19
8c5962b
040f675
f76e2cf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| [model] | ||
| init_file = init_polynya.nc | ||
| start = 2023-01-01T00:00:00Z | ||
| stop = 2023-01-05T00:00:00Z | ||
| time_step = P0-0T00:01:00 | ||
| missing_value = 1e20 | ||
|
|
||
| [Modules] | ||
| DiagnosticOutputModule = Nextsim::ConfigOutput | ||
| DynamicsModule = Nextsim::MEVPDynamics | ||
| AtmosphereBoundaryModule = Nextsim::FluxConfiguredAtmosphere | ||
| OceanBoundaryModule = Nextsim::FluxConfiguredOcean | ||
| IceThermodynamicsModule = Nextsim::ThermoWinton | ||
|
|
||
| [ConfigOutput] | ||
| period = P0-0T04:00:00 | ||
| field_names = hice,cice,u,v | ||
| filename = polynya.diagnostic.nc | ||
|
|
||
| [FluxConfiguredOcean] | ||
| qio = 2.30 | ||
| sss = 28 | ||
| sst = -1.54 | ||
| mld = 10. | ||
| current_u = 0. | ||
| current_v = 0. | ||
|
|
||
| [FluxConfiguredAtmosphere] | ||
| Q_ia = 30 | ||
| Q_ow = 300 | ||
| dQia_dT = 0 | ||
| wind_u = 16 | ||
| wind_v = 12 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| from make_init_base import initMaker | ||
|
|
||
| # Creates initial conditions for the Bjornsson et al. (2001) polynya case | ||
|
|
||
| # Domain size [km] | ||
| x = 100 | ||
| y = 50 | ||
| res = 2 | ||
|
|
||
| nfirst = y // res | ||
| nsecond = x // res | ||
| nLayers = 3 | ||
|
|
||
| fname = "init_polynya.nc" | ||
|
|
||
| # The model expects everything in metres | ||
| initializer = initMaker(fname, nfirst, nsecond, res*1e3, isWinton=True, checkZeros=False) | ||
|
|
||
| # Ice everywhere and all boundaries closed, except the x = 100 km end | ||
| initializer.mask[:, :] = 1. | ||
| initializer.mask[0, :] = 0. | ||
| initializer.mask[-1, :] = 0. | ||
| initializer.mask[:, 0] = 0. | ||
| #initializer.mask[:, -1] = 0. ## right | ||
|
|
||
| # Uniform concentration of 90% | ||
| initializer.cice[:, :] = 0.9 | ||
|
|
||
| # Uniform thickness of 20 cm | ||
| initializer.hice[:, :] = 0.2 | ||
|
|
||
| # Undamaged ice | ||
| initializer.damage[:, :] = 1. | ||
|
|
||
| # Ice and ocean temperature and salinity at the freezing point | ||
| ice_salinity = 5 # should match Ice::s in constants.hpp | ||
| mu: float = -0.055 # should match Water::mu in constants.hpp | ||
| ocean_temperature = -1.54 | ||
| ocean_salinity = ocean_temperature / mu | ||
|
|
||
| initializer.sss[:, :] = ocean_salinity | ||
| initializer.sst[:, :] = ocean_temperature | ||
| initializer.tsurf[:, :] = ice_salinity * mu | ||
| initializer.tbott = initializer.tsurf | ||
| initializer.tintr = initializer.tsurf | ||
|
|
||
| # All other variables are zero or not needed | ||
|
|
||
| # The file is written when initializer goes out of scope | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,191 @@ | ||
| import os | ||
| import subprocess | ||
| import sys | ||
| import unittest | ||
|
|
||
| import netCDF4 | ||
| import numpy as np | ||
|
|
||
|
|
||
| class Polynya(unittest.TestCase): | ||
joewallwork marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| """ | ||
| A test class based on the Bjornsson et al. (2001) polynya case. We run the model for 5 days and check the output | ||
| against known values. The main purpose of this test is to check that the model is running and that the output is | ||
| reasonable. | ||
| See Bjornsson et al. (2001) doi:10.3402/tellusa.v53i2.12184 for details. | ||
| """ | ||
|
|
||
| # A few useful global variables for the class | ||
| executable = "../nextsim" | ||
|
|
||
| init_file = "init_polynya.nc" | ||
| config_file = "PolynyaIntegration.cfg" | ||
| diagnostics_file = "polynya.diagnostic.nc" | ||
|
|
||
| # Load the data once and re-use for all tests | ||
| hice = np.array([]) | ||
| cice = np.array([]) | ||
| uice = np.array([]) | ||
| vice = np.array([]) | ||
|
|
||
| @classmethod | ||
| def setUpClass(cls): | ||
| """ | ||
| A set-up class which, | ||
| - Creates the initialisation file, using make_init_column.py | ||
| - Runs the model | ||
| - Loads the neccesary variables from the output file | ||
| """ | ||
|
|
||
| # Make the init column | ||
| cls.__make_init_column() | ||
|
|
||
| # Create the config file | ||
| cls.__make_cfg_file() | ||
|
|
||
| # Run the model | ||
| subprocess.run(cls.executable + " --config-file " + cls.config_file, shell=True, check=True) | ||
|
|
||
| # Load the basic variables | ||
| root = netCDF4.Dataset(cls.diagnostics_file, "r", format="NETCDF4") | ||
| cls.cice = np.squeeze(np.array(root.groups["data"].variables["cice"][:].data)) | ||
| cls.hice = np.squeeze(np.array(root.groups["data"].variables["hice"][:].data)) | ||
| cls.uice = np.array(root.groups["data"].variables["u"][:].data) | ||
| cls.vice = np.array(root.groups["data"].variables["v"][:].data) | ||
|
|
||
| @classmethod | ||
| def __make_cfg_file(cls): | ||
| cfg = open(cls.config_file, "w") | ||
| cfg.write(""" | ||
| [model] | ||
| init_file = init_polynya.nc | ||
| start = 2023-01-01T00:00:00Z | ||
| stop = 2023-01-05T00:00:00Z | ||
| time_step = P0-0T00:30:00 | ||
| missing_value = 1e20 | ||
|
|
||
| [Modules] | ||
| DiagnosticOutputModule = Nextsim::ConfigOutput | ||
| DynamicsModule = Nextsim::BBMDynamics | ||
| AtmosphereBoundaryModule = Nextsim::FluxConfiguredAtmosphere | ||
| OceanBoundaryModule = Nextsim::FluxConfiguredOcean | ||
| IceThermodynamicsModule = Nextsim::ThermoWinton | ||
|
|
||
| [ConfigOutput] | ||
| period = P0-0T00:01:00 | ||
| field_names = hice,cice,u,v | ||
| filename = polynya.diagnostic.nc | ||
|
|
||
| [FluxConfiguredOcean] | ||
| qio = 2.30 | ||
| sss = 28 | ||
| sst = -1.54 | ||
| mld = 10. | ||
| current_u = 0. | ||
| current_v = 0. | ||
|
|
||
| [FluxConfiguredAtmosphere] | ||
| Q_ia = 30 | ||
| Q_ow = 300 | ||
| dQia_dT = 0 | ||
| wind_u = 16 | ||
| wind_v = 12 | ||
| """) | ||
| cfg.close() | ||
|
|
||
| @classmethod | ||
| def __make_init_column(cls): | ||
| sys.path.append('../run') | ||
| sys.path.append('../../run') | ||
| from make_init_base import initMaker | ||
|
|
||
| # Creates initial conditions for the Bjornsson et al. (2001) polynya case | ||
|
|
||
| # Domain size [km] | ||
| x = 100 | ||
| y = 50 | ||
| res = 4 | ||
|
|
||
| nfirst = y // res | ||
| nsecond = x // res | ||
|
|
||
| fname = cls.init_file | ||
|
|
||
| # The model expects everything in metres | ||
| initializer = initMaker(fname, nfirst, nsecond, res*1e3, isWinton=True, checkZeros=False) | ||
|
|
||
| # Ice everywhere and all boundaries closed, except the x = 100 km end | ||
| initializer.mask[:, :] = 1. | ||
| initializer.mask[0, :] = 0. | ||
| initializer.mask[-1, :] = 0. | ||
| initializer.mask[:, 0] = 0. | ||
| #initializer.mask[:, -1] = 0. ## right | ||
|
|
||
| # Uniform concentration of 90% | ||
| initializer.cice[:, :] = 0.9 | ||
|
|
||
| # Uniform thickness of 20 cm | ||
| initializer.hice[:, :] = 0.2 | ||
|
|
||
| # Undamaged ice | ||
| initializer.damage[:, :] = 1. | ||
|
|
||
| # Ice and ocean temperature and salinity at the freezing point | ||
| ice_salinity = 5 # should match Ice::s in constants.hpp | ||
| mu: float = -0.055 # should match Water::mu in constants.hpp | ||
| ocean_temperature = -1.54 | ||
| ocean_salinity = ocean_temperature / mu | ||
|
|
||
| initializer.sss[:, :] = ocean_salinity | ||
| initializer.sst[:, :] = ocean_temperature | ||
| initializer.tsurf[:, :] = ice_salinity * mu | ||
| initializer.tbott = initializer.tsurf | ||
| initializer.tintr = initializer.tsurf | ||
|
||
|
|
||
| # All other variables are zero or not needed | ||
|
|
||
| # The file is written when initializer goes out of scope | ||
|
|
||
| @classmethod | ||
| def tearDownClass(cls): | ||
| """ | ||
| A tear-down class that deletes the netCDF output and temporary files | ||
| """ | ||
|
|
||
| if os.path.isfile(cls.diagnostics_file): | ||
| os.remove(cls.diagnostics_file) | ||
|
|
||
| if os.path.isfile(cls.init_file): | ||
| os.remove(cls.init_file) | ||
|
|
||
| if os.path.isfile(cls.config_file): | ||
| os.remove(cls.config_file) | ||
|
|
||
| def test_iceThickness(self): | ||
| """ | ||
| Test the ice thickness against standard max, min, and mean values | ||
| The maximum varies by (at least) 3 cm between platforms, making a test of it useless | ||
| """ | ||
|
|
||
| mean = 0.1317 | ||
| min = 0.0000 | ||
| hice = self.hice[:,:,:,0] | ||
| self.assertAlmostEqual(min, hice.min(), 4, "Min ice thickness not ~= " + str(min) + " m") | ||
| self.assertAlmostEqual(mean, hice.mean(), 4, "Mean ice thickness not ~= " + str(mean) + " m") | ||
|
|
||
| def test_concentration(self): | ||
| """ | ||
| Test the ice concentration against standard max, min, and mean values | ||
| The min and max are easy, but the mean is sensitive | ||
| """ | ||
|
|
||
| mean = 0.4402 | ||
| max = 1.0000 | ||
| min = 0.0000 | ||
| cice = self.cice[:,:,:,0] | ||
| self.assertAlmostEqual(max, cice.max(), 4, "Max conentration not ~= " + str(max)) | ||
| self.assertAlmostEqual(min, cice.min(), 4, "Min concentration not ~= " + str(min)) | ||
| self.assertAlmostEqual(mean, cice.mean(), 3, "Mean concentration not ~= " + str(mean)) | ||
|
|
||
| if __name__ == '__main__': | ||
| unittest.main() | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't need this any more!