Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
9199211
Polynya test case
einola Jun 3, 2024
db69db8
Minor updates to the config file
einola Jun 14, 2024
805e1c0
Create init file with CMake
einola Jun 14, 2024
e510c07
Merge remote-tracking branch 'origin/develop' into issue375_polynya_test
einola Jul 1, 2024
327de33
Merge branch 'develop' into issue375_polynya_test
einola Feb 20, 2025
b99de51
Add open (Neumann zero) boundary conditions
einola Feb 21, 2025
60f876b
Revert "Add open (Neumann zero) boundary conditions"
einola Mar 14, 2025
0584cbf
Merge branch '793landmask_cg' into issue375_polynya_test
einola Mar 24, 2025
0077c28
New boundary handling.
winzerle Apr 7, 2025
02720e1
- Removed old Dirichlet-Info from the mesh.
winzerle Apr 7, 2025
f4b5ebd
Merge branch 'develop' into issue375_polynya_test
einola Apr 28, 2025
eef5a16
Merge branch 'develop' into issue375_polynya_test
einola Apr 29, 2025
1a3c692
Remove VTK output from VPCGDynamicsKernel
einola Apr 30, 2025
be756c3
Add u and v wind direction to ConfiguredAtmosphere
einola Apr 30, 2025
150b21f
Initialise damage to one
einola Apr 30, 2025
21cf14e
Fix open-water flux in FluxConfiguredAtmosphere
einola Apr 30, 2025
4c6a41a
Update config_polynya.cfg
einola Apr 30, 2025
768c4d4
Minor tweaks and fixes
einola Apr 30, 2025
d515e03
Merge branch 'develop' into issue375_polynya_test
einola Apr 30, 2025
e10ccbf
Clang-format fixes
einola Apr 30, 2025
2e06954
Increase the domain size
einola Apr 30, 2025
6bcb88d
Update PrognosticData_test.cpp
einola Apr 30, 2025
437d6d1
Remove commented-out code
einola Apr 30, 2025
cbd56d8
Merge remote-tracking branch 'origin/develop' into issue375_polynya_test
einola May 20, 2025
5781dbf
Minor fixes to get the model to compile and polynya simulation to start
einola May 20, 2025
94e2b63
Merge branch 'develop' into issue375_polynya_test
einola May 22, 2025
0ad9d32
Revert "Minor tweaks and fixes"
einola May 30, 2025
53116d9
Merge remote-tracking branch 'origin/develop' into issue375_polynya_test
einola Jun 3, 2025
be0823c
Merge remote-tracking branch 'origin/develop' into issue375_polynya_test
einola Jun 6, 2025
95c2a86
Change back dates on several files
einola Jun 6, 2025
fad93a1
Fix the date fixing
einola Jun 6, 2025
5356fd1
Merge remote-tracking branch 'origin/develop' into issue375_polynya_test
einola Jun 13, 2025
4c3a1dc
Merge remote-tracking branch 'origin/develop' into issue375_polynya_test
einola Jun 23, 2025
a783559
Fix polynya initialisation
einola Jun 28, 2025
7d4da1f
Make an integration test out of the polynya case
einola Jun 29, 2025
dd519cd
Additional python path for the CI
einola Jun 29, 2025
54919ec
Fix wrong python command on macOS
einola Jun 29, 2025
58d8277
Reduce accuracy of polynya integration test
einola Jun 29, 2025
ee55629
Reduce the accuracy even further
einola Jun 29, 2025
d4be55e
Remove redundant f-string from make_init_polynya.py
einola Jul 21, 2025
17f55a7
Use integer division, instead of type conversion
einola Jul 21, 2025
00270c8
Use the class variable for init_file in PolynyaIntegration_test.py
einola Jul 21, 2025
11ffd45
Document the PolynyaIntegration_test.py with a docstring
einola Jul 21, 2025
ef78f73
Merge remote-tracking branch 'origin/develop' into issue375_polynya_test
einola Jul 23, 2025
e4cec19
Merge branch 'develop' into issue375_polynya_test
einola Jul 28, 2025
8c5962b
Update PolynyaIntegration_test.py "known good values"
einola Jul 28, 2025
040f675
Merge branch 'develop' into issue375_polynya_test
einola Aug 19, 2025
f76e2cf
Update the polynya integration test script
einola Aug 19, 2025
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 .github/workflows/test_suite.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ jobs:
mv ../test .
cd test
python3 ThermoIntegration_test.py
python3 PolynyaIntegration_test.py
./run_test_jan2010_integration.sh python3
./run_test_advection.sh python3

Expand Down Expand Up @@ -182,5 +183,6 @@ jobs:
mv ../test .
cd test
python ThermoIntegration_test.py
python PolynyaIntegration_test.py
./run_test_jan2010_integration.sh python
./run_test_advection.sh python
3 changes: 3 additions & 0 deletions run/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,6 @@ execute_process(
COMMAND "${Python_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/make_init_benchmark.py"
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
)
execute_process(
COMMAND "${Python_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/make_init_polynya.py"
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}")
33 changes: 33 additions & 0 deletions run/config_polynya.cfg
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
49 changes: 49 additions & 0 deletions run/make_init_polynya.py
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
Copy link
Collaborator

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!


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
193 changes: 193 additions & 0 deletions test/PolynyaIntegration_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
import os
import subprocess
import sys
import unittest

import netCDF4
import numpy as np


class Polynya(unittest.TestCase):
"""
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.

NB! This test is very sensitive to small perturbations in the model. If the test fails, run the full-resolution
version, cited below, and compare the results. You may need to adjust the "known good values" of the test
accordingly.

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.variables["cice"][:].data))
cls.hice = np.squeeze(np.array(root.variables["hice"][:].data))
cls.uice = np.array(root.variables["u"][:].data)
cls.vice = np.array(root.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, 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

# 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.1323
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(), 2, "Mean concentration not ~= " + str(mean))

if __name__ == '__main__':
unittest.main()
Loading