├── .clang-format ├── .cmake-lint-config.py ├── .github ├── pull_request_template.md ├── workflows │ ├── docker.yml │ ├── doxygen.yml │ ├── linting.yml │ └── test_suite.yml └── xios_arch │ ├── ubuntu.arch │ ├── ubuntu.env │ └── ubuntu.fcm ├── .gitignore ├── .pre-commit ├── .readthedocs.yaml ├── CMakeLists.txt ├── Dockerfiles ├── Dockerfile.devenv ├── Dockerfile.production ├── install-xios.sh └── spack.yaml ├── LICENSE ├── README.md ├── apptainer ├── README.md └── nextsim_dg.def ├── cmake ├── FindNetCDF.cmake └── Findxios.cmake ├── core ├── CMakeLists.txt ├── src │ ├── CMakeLists.txt │ ├── CommandLineParser.cpp │ ├── CommonRestartMetadata.cpp │ ├── ConfigurationHelpPrinter.cpp │ ├── Configurator.cpp │ ├── ConfiguredModule.cpp │ ├── DevStep.cpp │ ├── FileCallbackCloser.cpp │ ├── Finalizer.cpp │ ├── Iterator.cpp │ ├── Logged.cpp │ ├── Model.cpp │ ├── ModelArray.cpp │ ├── ModelArraySlice.cpp │ ├── ModelComponent.cpp │ ├── ModelConfig.cpp │ ├── ModelMetadata.cpp │ ├── NetcdfMetadataConfiguration.cpp │ ├── PDWriter.cpp │ ├── ParaGridIO.cpp │ ├── ParaGridIO_Xios.cpp │ ├── ParallelNetcdfFile.cpp │ ├── PrognosticData.cpp │ ├── RectGridIO.cpp │ ├── StructureFactory.cpp │ ├── Time.cpp │ ├── Xios.cpp │ ├── discontinuousgalerkin │ │ ├── ModelArrayDetails.cpp │ │ └── include │ │ │ ├── ModelArrayDetails.hpp │ │ │ └── ModelArrayTypedefs.hpp │ ├── finitevolume │ │ ├── ModelArrayDetails.cpp │ │ └── include │ │ │ ├── ModelArrayDetails.hpp │ │ │ └── ModelArrayTypedefs.hpp │ ├── include │ │ ├── Chrono.hpp │ │ ├── CommandLineParser.hpp │ │ ├── CommonRestartMetadata.hpp │ │ ├── ConfigMap.hpp │ │ ├── ConfigurationHelp.hpp │ │ ├── ConfigurationHelpPrinter.hpp │ │ ├── Configurator.hpp │ │ ├── Configured.hpp │ │ ├── ConfiguredModule.hpp │ │ ├── DevStep.hpp │ │ ├── EnumWrapper.hpp │ │ ├── FileCallbackCloser.hpp │ │ ├── Finalizer.hpp │ │ ├── IModelStep.hpp │ │ ├── Iterator.hpp │ │ ├── Logged.hpp │ │ ├── MissingData.hpp │ │ ├── Model.hpp │ │ ├── ModelArray.hpp │ │ ├── ModelArrayRef.hpp │ │ ├── ModelArrayReferenceStore.hpp │ │ ├── ModelArraySlice.hpp │ │ ├── ModelComponent.hpp │ │ ├── ModelConfig.hpp │ │ ├── ModelConfigMapElements.ipp │ │ ├── ModelMetadata.hpp │ │ ├── ModelState.hpp │ │ ├── Module.hpp │ │ ├── MonthlyCubicBSpline.hpp │ │ ├── NetcdfMetadataConfiguration.hpp │ │ ├── NextsimModule.hpp │ │ ├── OutputSpec.hpp │ │ ├── ParaGridIO.hpp │ │ ├── ParallelNetcdfFile.hpp │ │ ├── PrognosticData.hpp │ │ ├── RectGridIO.hpp │ │ ├── Slice.hpp │ │ ├── StructureFactory.hpp │ │ ├── TextTag.hpp │ │ ├── Time.hpp │ │ ├── Xios.hpp │ │ ├── constants.hpp │ │ ├── gridNames.hpp │ │ ├── indexer.hpp │ │ └── xios_c_interface.hpp │ ├── main.cpp │ └── modules │ │ ├── CMakeLists.txt │ │ ├── DiagnosticOutputModule │ │ ├── ConfigOutput.cpp │ │ ├── SimpleOutput.cpp │ │ ├── include │ │ │ ├── ConfigOutput.hpp │ │ │ ├── NoOutput.hpp │ │ │ └── SimpleOutput.hpp │ │ └── module.cfg │ │ ├── DynamicsModule │ │ ├── BBMDynamics.cpp │ │ ├── MEVPDynamics.cpp │ │ ├── include │ │ │ ├── BBMDynamics.hpp │ │ │ ├── DummyDynamics.hpp │ │ │ ├── FreeDriftDynamics.hpp │ │ │ └── MEVPDynamics.hpp │ │ └── module.cfg │ │ ├── FreezingPointModule │ │ ├── include │ │ │ ├── LinearFreezing.hpp │ │ │ └── UnescoFreezing.hpp │ │ └── module.cfg │ │ ├── README.md │ │ ├── StructureModule │ │ ├── ParametricGrid.cpp │ │ ├── RectangularGrid.cpp │ │ ├── include │ │ │ ├── ParametricGrid.hpp │ │ │ └── RectangularGrid.hpp │ │ └── module.cfg │ │ ├── include │ │ ├── IDiagnosticOutput.hpp │ │ ├── IDynamics.hpp │ │ ├── IFreezingPoint.hpp │ │ ├── IStructure.hpp │ │ ├── ProtectedArrayNames.ipp │ │ └── SharedArrayNames.ipp │ │ └── module_maker.py └── test │ ├── ArgV.cpp │ ├── ArgV.hpp │ ├── CMakeLists.txt │ ├── CommandLineParser_test.cpp │ ├── ConfigOutput_test.cpp │ ├── Configurator_test.cpp │ ├── ConfiguredModule_test.cpp │ ├── DynamicsModuleForPDtest.cpp │ ├── FileCallbackCloser_test.cpp │ ├── Finalizer_test.cpp │ ├── Iterator_test.cpp │ ├── Logged_test.cpp │ ├── MainMPI.cpp │ ├── ModelArrayRefDebug_test.cpp │ ├── ModelArrayRef_test.cpp │ ├── ModelArraySlice_test.cpp │ ├── ModelArray_test.cpp │ ├── ModelComponent_test.cpp │ ├── MonthlyCubicBSpline_test.cpp │ ├── PDTestDynamics.hpp │ ├── ParaGridIO_input_test.nc │ ├── ParaGridIO_input_test.py │ ├── ParaGrid_test.cpp │ ├── PrognosticDataIO_test.cpp │ ├── PrognosticDataTestModules │ ├── moduleLoaderAssignments.ipp │ ├── moduleLoaderFunctions.ipp │ ├── moduleLoaderHeaders.ipp │ ├── moduleLoaderNames.ipp │ └── modules.json │ ├── PrognosticData_test.cpp │ ├── RectGrid_test.cpp │ ├── Slice_test.cpp │ ├── Time_test.cpp │ ├── XiosAxis_test.cpp │ ├── XiosCalendar_test.cpp │ ├── XiosDomain_test.cpp │ ├── XiosField_test.cpp │ ├── XiosFile_test.cpp │ ├── XiosGrid_test.cpp │ ├── XiosRead_test.cpp │ ├── XiosWrite_test.cpp │ ├── iodef.xml │ ├── old_names.py │ ├── partition_metadata_2.cdl │ ├── partition_metadata_3.cdl │ ├── testHelpConfig.sh │ ├── testmodelarraydetails │ ├── ModelArrayDetails.cpp │ └── include │ │ ├── ModelArrayDetails.hpp │ │ └── ModelArrayTypedefs.hpp │ ├── xios_test_input.cdl │ └── xios_test_partition_metadata_2.cdl ├── docs ├── Doxyfile ├── api │ ├── class.rst │ ├── counttimercpp.rst │ ├── function.rst │ ├── index.rst │ ├── num.rst │ ├── structure.rst │ └── typedef.rst ├── changelog.rst ├── changelog │ ├── CHANGELOG.md │ ├── README.md │ ├── clog.py │ └── run_changelog.sh ├── conda.svg ├── conf.py ├── data_storage.rst ├── environment.yml ├── getting_help.rst ├── getting_started.rst ├── index.rst ├── installation.rst ├── model-components.rst ├── model_array.rst ├── modules.rst ├── numerical-implementation.rst ├── outputs-diagnostics.rst ├── overview.rst ├── slab_ocean.rst ├── source │ └── installation.rst └── xios.rst ├── dynamics ├── CMakeLists.txt ├── ParametricMesh │ ├── createdistortedboxmesh.py │ ├── createdistortedrectanglemesh.py │ ├── netcdf2dynamics.py │ ├── netcdf2dynamics2.py │ └── readme.txt ├── codegeneration │ ├── basisfunctions.py │ ├── codeGenerationCGToDG.py │ ├── codeGenerationCGinGauss.py │ ├── codeGenerationDGinGauss.py │ ├── codeGenerationParametricMesh.py │ ├── dgbasisfunctions.py │ ├── gaussquadrature.py │ └── run.sh ├── src │ ├── CGDynamicsKernel.cpp │ ├── CMakeLists.txt │ ├── DGTransport.cpp │ ├── DummyDynamicsKernel.cpp │ ├── DynamicsKernel.cpp │ ├── Interpolations.cpp │ ├── MEVPStressUpdateStep.cpp │ ├── ParametricMap.cpp │ ├── ParametricMesh.cpp │ ├── ParametricTools.cpp │ ├── VectorManipulations.cpp │ ├── include │ │ ├── BBMDynamicsKernel.hpp │ │ ├── BBMParameters.hpp │ │ ├── BBMStressUpdateStep.hpp │ │ ├── BrittleCGDynamicsKernel.hpp │ │ ├── CGDynamicsKernel.hpp │ │ ├── CGModelArray.hpp │ │ ├── CheckPoints.hpp │ │ ├── DGModelArray.hpp │ │ ├── DGTransport.hpp │ │ ├── DummyDynamicsKernel.hpp │ │ ├── DynamicsKernel.hpp │ │ ├── DynamicsParameters.hpp │ │ ├── FreeDriftDynamicsKernel.hpp │ │ ├── IDynamicsUpdate.hpp │ │ ├── Interpolations.hpp │ │ ├── MEVPDynamicsKernel.hpp │ │ ├── MEVPStressUpdateStep.hpp │ │ ├── NextsimDynamics.hpp │ │ ├── ParametricMap.hpp │ │ ├── ParametricMesh.hpp │ │ ├── ParametricTools.hpp │ │ ├── StressUpdateStep.hpp │ │ ├── Tools.hpp │ │ ├── VPCGDynamicsKernel.hpp │ │ ├── VPParameters.hpp │ │ ├── VectorManipulations.hpp │ │ ├── cgVector.hpp │ │ ├── codeGenerationCGToDG.hpp │ │ ├── codeGenerationCGinGauss.hpp │ │ ├── codeGenerationDGinGauss.hpp │ │ ├── dgBasisFunctionsGaussPoints.hpp │ │ ├── dgInitial.hpp │ │ ├── dgLimit.hpp │ │ ├── dgLimiters.hpp │ │ ├── dgVector.hpp │ │ ├── dgVectorHolder.hpp │ │ ├── dgVisu.hpp │ │ └── stopwatch.hpp │ └── stopwatch.cpp └── test │ ├── 25km_NH.smesh │ ├── AdvectionPeriodicBC_test.cpp │ ├── Advection_test.cpp │ ├── CGModelArray_test.cpp │ ├── CMakeLists.txt │ ├── DGModelArray_test.cpp │ ├── FakeSmeshData.cpp │ ├── FakeSmeshData.hpp │ ├── ParametricMeshArea_test.cpp │ ├── ParametricMesh_test.cpp │ ├── README.md │ └── dgVectorHolder_test.cpp ├── lib └── doctest │ ├── LICENSE.txt │ ├── doctest.h │ └── extensions │ ├── doctest_mpi.h │ ├── doctest_util.h │ ├── mpi_reporter.h │ └── mpi_sub_comm.h ├── physics ├── CMakeLists.txt ├── src │ ├── BenchmarkCoordinates.cpp │ ├── CMakeLists.txt │ ├── IceGrowth.cpp │ ├── IceMinima.cpp │ ├── SlabOcean.cpp │ ├── include │ │ ├── BenchmarkCoordinates.hpp │ │ ├── IceGrowth.hpp │ │ ├── IceMinima.hpp │ │ └── SlabOcean.hpp │ └── modules │ │ ├── AtmosphereBoundaryModule │ │ ├── BenchmarkAtmosphere.cpp │ │ ├── ConfiguredAtmosphere.cpp │ │ ├── ConstantAtmosphereBoundary.cpp │ │ ├── ERA5Atmosphere.cpp │ │ ├── FluxConfiguredAtmosphere.cpp │ │ ├── MU71Atmosphere.cpp │ │ ├── include │ │ │ ├── BenchmarkAtmosphere.hpp │ │ │ ├── ConfiguredAtmosphere.hpp │ │ │ ├── ConstantAtmosphereBoundary.hpp │ │ │ ├── ERA5Atmosphere.hpp │ │ │ ├── FluxConfiguredAtmosphere.hpp │ │ │ └── MU71Atmosphere.hpp │ │ └── module.cfg │ │ ├── CMakeLists.txt │ │ ├── DamageHealingModule │ │ ├── ConstantHealing.cpp │ │ ├── include │ │ │ ├── ConstantHealing.hpp │ │ │ └── NoHealing.hpp │ │ └── module.cfg │ │ ├── FluxCalculationModule │ │ ├── FiniteElementFluxes.cpp │ │ ├── FiniteElementSpecHum.cpp │ │ ├── include │ │ │ ├── FiniteElementFluxes.hpp │ │ │ ├── FiniteElementSpecHum.hpp │ │ │ └── ISpecificHumidity.hpp │ │ └── module.cfg │ │ ├── IceAlbedoModule │ │ ├── CCSMIceAlbedo.cpp │ │ ├── MU71Albedo.cpp │ │ ├── SMU2IceAlbedo.cpp │ │ ├── SMUIceAlbedo.cpp │ │ ├── WintonAlbedo.cpp │ │ ├── include │ │ │ ├── CCSMIceAlbedo.hpp │ │ │ ├── MU71Albedo.hpp │ │ │ ├── SMU2IceAlbedo.hpp │ │ │ ├── SMUIceAlbedo.hpp │ │ │ └── WintonAlbedo.hpp │ │ └── module.cfg │ │ ├── IceOceanHeatFluxModule │ │ ├── BasicIceOceanHeatFlux.cpp │ │ ├── include │ │ │ └── BasicIceOceanHeatFlux.hpp │ │ └── module.cfg │ │ ├── IceThermodynamicsModule │ │ ├── ThermoIce0.cpp │ │ ├── ThermoWinton.cpp │ │ ├── include │ │ │ ├── DummyIceThermodynamics.hpp │ │ │ ├── ThermoIce0.hpp │ │ │ └── ThermoWinton.hpp │ │ └── module.cfg │ │ ├── LateralIceSpreadModule │ │ ├── HiblerSpread.cpp │ │ ├── include │ │ │ ├── DummyIceSpread.hpp │ │ │ └── HiblerSpread.hpp │ │ └── module.cfg │ │ ├── OceanBoundaryModule │ │ ├── BenchmarkOcean.cpp │ │ ├── ConfiguredOcean.cpp │ │ ├── ConstantOceanBoundary.cpp │ │ ├── FluxConfiguredOcean.cpp │ │ ├── TOPAZOcean.cpp │ │ ├── UniformOcean.cpp │ │ ├── include │ │ │ ├── BenchmarkOcean.hpp │ │ │ ├── ConfiguredOcean.hpp │ │ │ ├── ConstantOceanBoundary.hpp │ │ │ ├── FluxConfiguredOcean.hpp │ │ │ ├── TOPAZOcean.hpp │ │ │ └── UniformOcean.hpp │ │ └── module.cfg │ │ └── include │ │ ├── IAtmosphereBoundary.hpp │ │ ├── IDamageHealing.hpp │ │ ├── IFluxCalculation.hpp │ │ ├── IIceAlbedo.hpp │ │ ├── IIceOceanHeatFlux.hpp │ │ ├── IIceThermodynamics.hpp │ │ ├── ILateralIceSpread.hpp │ │ └── IOceanBoundary.hpp └── test │ ├── BasicIceOceanFlux_test.cpp │ ├── BenchmarkBoundaries_test.cpp │ ├── CMakeLists.txt │ ├── ConstantOceanBoundary_test.cpp │ ├── DamageHealing_test.cpp │ ├── ERA5Atm_test.cpp │ ├── FiniteElementFluxes_test.cpp │ ├── IceGrowth_test.cpp │ ├── IceMinima_test.cpp │ ├── SlabOcean_test.cpp │ ├── SpecificHumidity_test.cpp │ ├── TOPAZOcn_test.cpp │ ├── ThermoIce0Temperature_test.cpp │ ├── ThermoIce0_test.cpp │ ├── ThermoWintonTemperature_test.cpp │ ├── UniformOcean_test.cpp │ ├── era5_test_data.py │ └── topaz_test_data.py ├── requirements.txt ├── run ├── CMakeLists.txt ├── column_pp.py ├── config_benchmark.cfg ├── config_column.cfg ├── config_configoutput.cfg ├── config_dynamics.cfg ├── config_june23.cfg ├── config_nares.cfg ├── config_para24x30.cfg ├── config_rect10x10.cfg ├── config_rect20x30.cfg ├── config_simple_example.cfg ├── config_topaz128x128.cfg ├── era5_topaz4_maker.py ├── init_para128x128.py ├── init_topaz128x128.py ├── make_init.py ├── make_init25kmNH_test.py ├── make_initNH.py ├── make_init_base.py ├── make_init_benchmark.py ├── make_init_column.py ├── make_init_nares.py ├── make_init_para24x30.py ├── make_init_rect20x30.py ├── partition.cdl ├── partition_metadata_2.cdl ├── run_dynamics.sh ├── run_june23.sh ├── run_rect20x30.sh ├── run_simple_example.sh └── run_topaz128x128.sh ├── scripts ├── module_builder.py └── module_strings.py ├── spack.yaml └── test ├── ThermoIntegration_test.py ├── era5_topaz4_test_data.py ├── integration_test.cfg ├── make_init25kmNH_test_data.py ├── run_integration_test.sh ├── run_test_jan2010_integration_test.sh └── test_integration_test.py /.github/workflows/docker.yml: -------------------------------------------------------------------------------- 1 | name: Periodic Docker build 2 | 3 | on: 4 | # Build the Docker container whenever commits are pushed to an open PR that changes one of the files listed 5 | pull_request: 6 | paths: 7 | - .github/workflows/docker.yml 8 | - Dockerfiles/Dockerfile.devenv 9 | - Dockerfiles/install-xios.sh 10 | - Dockerfiles/spack.yaml 11 | 12 | # Build the Docker container at 00:00 on the first day of every 3 months 13 | schedule: 14 | - cron: '0 0 1 */3 *' 15 | 16 | jobs: 17 | docker: 18 | name: Build Docker container 19 | runs-on: ubuntu-latest 20 | 21 | timeout-minutes: 120 22 | 23 | permissions: 24 | contents: read 25 | packages: write 26 | steps: 27 | - name: Checkout the repo 28 | uses: actions/checkout@v4 29 | 30 | - name: Setup Docker buildx 31 | uses: docker/setup-buildx-action@v3 32 | 33 | - name: Log into GitHub Container Repository 34 | uses: docker/login-action@v3 35 | with: 36 | registry: ghcr.io 37 | username: ${{ github.actor }} 38 | password: ${{ secrets.GITHUB_TOKEN }} 39 | logout: true 40 | 41 | - name: Build container and push to ghcr 42 | uses: docker/build-push-action@v5 43 | with: 44 | push: true 45 | file: Dockerfiles/Dockerfile.devenv 46 | tags: ghcr.io/nextsimhub/nextsimdg-dev-env:latest 47 | -------------------------------------------------------------------------------- /.github/workflows/doxygen.yml: -------------------------------------------------------------------------------- 1 | # This is a basic workflow to help you get started with Actions 2 | 3 | name: Doxygen Action 4 | 5 | # Controls when the action will run. Triggers the workflow on push or pull request 6 | # events but only for the master branch 7 | on: 8 | push: 9 | branches: [ main, docs ] 10 | 11 | 12 | 13 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 14 | jobs: 15 | # This workflow contains a single job called "build" 16 | build: 17 | # The type of runner that the job will run on 18 | runs-on: ubuntu-latest 19 | 20 | timeout-minutes: 5 21 | 22 | # Steps represent a sequence of tasks that will be executed as part of the job 23 | steps: 24 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 25 | - uses: actions/checkout@v2 26 | 27 | - name: Doxygen Action 28 | uses: mattnotmitt/doxygen-action@v1.1.0 29 | with: 30 | # Path to Doxyfile 31 | doxyfile-path: "./Doxyfile" # default is ./Doxyfile 32 | # Working directory 33 | working-directory: "./docs" # default is . 34 | 35 | - name: Deploy to GitHub Pages 36 | if: success() 37 | uses: crazy-max/ghaction-github-pages@v2 38 | with: 39 | target_branch: gh-pages 40 | build_dir: docs/html 41 | jekyll: false 42 | keep_history: false 43 | env: 44 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 45 | -------------------------------------------------------------------------------- /.github/workflows/linting.yml: -------------------------------------------------------------------------------- 1 | name: Check formatting 2 | 3 | on: 4 | push: 5 | branches: [ main, develop ] 6 | pull_request: 7 | branches: [ main, develop ] 8 | paths: 9 | - '.github/workflows/linting.yml' 10 | - '**.cpp' 11 | - '**.hpp' 12 | - '**CMakeLists.txt' 13 | pull_request_review: 14 | branches: [ main, develop ] 15 | 16 | jobs: 17 | clang-format: 18 | runs-on: ubuntu-latest 19 | 20 | timeout-minutes: 5 21 | 22 | steps: 23 | - uses: actions/checkout@v2 24 | - name: clang-format 25 | run: | 26 | sudo apt update 27 | sudo apt install clang-format 28 | for component in core dynamics physics 29 | do 30 | cd $component/src 31 | clang-format --dry-run -Werror *cpp include/*hpp 32 | cd - 33 | done 34 | 35 | cmake-lint: 36 | runs-on: ubuntu-latest 37 | 38 | timeout-minutes: 5 39 | 40 | steps: 41 | - uses: actions/checkout@v2 42 | - name: cmake-format 43 | run: | 44 | pip install cmakelang 45 | cmake-lint $(find . -name CMakeLists.txt) -c .cmake-lint-config.py 46 | # NOTE: We ignore C0103, which would enforce that variables are all-caps 47 | # NOTE: We ignore C0113, which would enforce that comments are used 48 | # NOTE: We set the tab size to 4 49 | # NOTE: We set the maximum line length to 100 50 | -------------------------------------------------------------------------------- /.github/xios_arch/ubuntu.arch: -------------------------------------------------------------------------------- 1 | NETCDF_INCDIR="-I $(pkg-config --cflags-only-I netcdf)" 2 | NETCDF_LIBDIR="-L $(pkg-config --libs-only-L netcdf)" 3 | NETCDF_LIB="-lnetcdff -lnetcdf" 4 | 5 | MPI_INCDIR="" 6 | MPI_LIBDIR="" 7 | MPI_LIB="-lcurl" 8 | 9 | HDF5_INCDIR="-I $(pkg-config --cflags-only-I hdf5)" 10 | HDF5_LIBDIR="-L $(pkg-config --libs-only-L hdf5)" 11 | HDF5_LIB="-lhdf5_hl -lhdf5 -lhdf5 -lz" 12 | 13 | BOOST_INCDIR="-I $BOOST_INC_DIR" 14 | BOOST_LIBDIR="-L $BOOST_LIB_DIR" 15 | BOOST_LIB="" 16 | 17 | OASIS_INCDIR="-I$PWD/../../oasis3-mct/BLD/build/lib/psmile.MPI1" 18 | OASIS_LIBDIR="-L$PWD/../../oasis3-mct/BLD/lib" 19 | OASIS_LIB="-lpsmile.MPI1 -lscrip -lmct -lmpeu" 20 | -------------------------------------------------------------------------------- /.github/xios_arch/ubuntu.env: -------------------------------------------------------------------------------- 1 | export HDF5_INC_DIR=$(pkg-config --variable=prefix hdf5)/include 2 | export HDF5_LIB_DIR=$(pkg-config --variable=prefix hdf5)/lib 3 | 4 | export NETCDF_INC_DIR=$(pkg-config --variable=prefix netcdf)/include 5 | export NETCDF_LIB_DIR=$(pkg-config --variable=prefix netcdf)/lib 6 | 7 | export BOOST_INC_DIR=$HOME/boost 8 | export BOOST_LIB_DIR=$HOME/boost 9 | -------------------------------------------------------------------------------- /.github/xios_arch/ubuntu.fcm: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | ################### Projet XIOS ################### 3 | ################################################################################ 4 | 5 | %CCOMPILER mpicc 6 | %FCOMPILER mpif90 7 | %LINKER mpif90 8 | 9 | %BASE_CFLAGS -w -std=c++11 -D__XIOS_EXCEPTION 10 | %PROD_CFLAGS -fPIC -O3 -DBOOST_DISABLE_ASSERTS 11 | %DEV_CFLAGS -g -O2 12 | %DEBUG_CFLAGS -fPIC -g 13 | 14 | %BASE_FFLAGS -D__NONE__ 15 | %PROD_FFLAGS -fPIC -O3 16 | %DEV_FFLAGS -g -O2 17 | %DEBUG_FFLAGS -fPIC -g 18 | 19 | %BASE_INC -D__NONE__ 20 | %BASE_LD -lstdc++ 21 | 22 | %CPP cpp 23 | %FPP cpp -P 24 | %MAKE gmake 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /build* 2 | */build 3 | Results 4 | /.cproject 5 | /.project 6 | /.pydevproject 7 | /.settings/* 8 | /*/src/modules/include/*Module.hpp 9 | /*/src/modules/*/module.cpp 10 | /run/*.nc 11 | /run/nextsim 12 | /run/.DS_Store 13 | /run/*.log 14 | /run/applications/* 15 | *.vtk 16 | *.smesh 17 | *.DS_Store 18 | *.nc 19 | __pycache__/ 20 | *.sif 21 | .*sw? 22 | /run/*.cdl 23 | -------------------------------------------------------------------------------- /.pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # An example pre-commit file for nextSIM-DG development 4 | # 5 | # To use this pre-commit hook, you will need to install: 6 | # * clang-format (see https://clang.llvm.org/docs/ClangFormat.html) 7 | # * cmake-lint (see https://github.com/cheshirekow/cmake_format) 8 | # 9 | # Then copy this file as `.git/hooks/pre-commit` to set the pre-commit hook up. 10 | # 11 | # If changes are made by the pre-commit hook then the commit will abort and you 12 | # will need to re-run the commit command. 13 | 14 | BEFORE=$(mktemp) 15 | git diff >${BEFORE} 16 | 17 | for FILE in $(git diff --cached --name-only | grep -iE '\.(cpp|cc|h|hpp)$'); do 18 | # Apply clang-format for linting 19 | clang-format -i ${FILE} --verbose 20 | # Update date stamp to today's date 21 | LINE=$(grep '@date' ${FILE}) 22 | let SPACES=$(echo "${LINE}" | tr -cd ' \t' | wc -c)-4 23 | NEWLINE=$(printf "%s%$((SPACES))s%s\n" " @date" " " "$(date '+%d %b %Y')") 24 | sed -i~ "s/${LINE}/${NEWLINE}/" ${FILE} 25 | done 26 | 27 | # Apply cmake-lint for linting 28 | for FILE in $(git diff --cached --name-only | grep -i 'CMakeLists.txt'); do 29 | cmake-lint ${FILE} -c .cmake-lint-config.py 30 | done 31 | 32 | # Abort commit if formatting was applied 33 | AFTER=$(mktemp) 34 | git diff >${AFTER} 35 | if [ "$(diff ${BEFORE} ${AFTER})" ]; then 36 | echo "Aborting git commit because the pre-commit hook made changes." 37 | rm ${BEFORE} ${AFTER} 38 | exit 1 39 | fi 40 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yaml 2 | # Read the Docs configuration file 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | # Required 6 | version: 2 7 | 8 | # Set the version of Python and other tools you might need 9 | build: 10 | os: "ubuntu-22.04" 11 | tools: 12 | python: "3.8" 13 | 14 | # Build documentation in the docs/ directory with Sphinx 15 | sphinx: 16 | configuration: docs/conf.py 17 | builder: html 18 | fail_on_warning: false 19 | 20 | # Optionally declare the Python requirements required to build your docs 21 | python: 22 | install: 23 | - requirements: requirements.txt 24 | 25 | ###conda: 26 | ### environment: docs/environment.yml 27 | -------------------------------------------------------------------------------- /Dockerfiles/Dockerfile.production: -------------------------------------------------------------------------------- 1 | FROM ghcr.io/nextsimhub/nextsimdg-dev-env:latest 2 | 3 | RUN git clone https://github.com/nextsimhub/nextsimdg.git /nextsimdg 4 | 5 | WORKDIR /nextsimdg/build 6 | 7 | ARG mpi=OFF 8 | ARG xios=OFF 9 | ARG jobs=1 10 | 11 | RUN . /opt/spack-environment/activate.sh && cmake -DENABLE_MPI=$mpi -DENABLE_XIOS=$xios -Dxios_DIR=/xios .. && make -j $jobs 12 | 13 | WORKDIR /nextsimdg/run 14 | RUN ln -sf /nextsimdg/build/nextsim 15 | 16 | ENTRYPOINT [ "/entrypoint.sh" ] 17 | CMD [ "/bin/bash" ] 18 | -------------------------------------------------------------------------------- /Dockerfiles/spack.yaml: -------------------------------------------------------------------------------- 1 | spack: 2 | packages: 3 | all: 4 | compiler: [gcc@11.4.0] 5 | specs: 6 | - boost@1.80.0+log+program_options 7 | - catch2 8 | - 'cmake@3.20:' 9 | - eigen@3.4.0 10 | - gmake 11 | - hdf5@1.14.3 12 | - netcdf-c@4.9.2+mpi+parallel-netcdf 13 | - netcdf-cxx4@4.3.1 14 | - netcdf-fortran 15 | - openmpi@4.1.6 16 | - trilinos 17 | - zlib-ng@2.1.4 18 | - zoltan 19 | concretizer: 20 | unify: true 21 | config: 22 | install_missing_compilers: true 23 | install_tree: /opt/software 24 | view: /opt/views/view 25 | -------------------------------------------------------------------------------- /apptainer/README.md: -------------------------------------------------------------------------------- 1 | # Build apptainer container for neXtSIM-DG 2 | These can be used to compile and run neXtSIM on HPC computers 3 | 4 | ## Build the container 5 | The input file is `nextsim_dg.def`. We use it to build an image file `nextsim_dg.sif`. 6 | In the `apptainer` directory, type 7 | ``` 8 | sudo apptainer build nextsim_dg.sif nextsim_dg.def 9 | ``` 10 | You can save the image file anywhere 11 | 12 | ## Run the container 13 | To run a command inside the container, type 14 | ``` 15 | apptainer exec --cleanenv nextsim_dg.sif COMMAND 16 | ``` 17 | To open an ubuntu shell inside the container, type 18 | ``` 19 | apptainer shell --cleanenv nextsim_dg.sif 20 | ``` 21 | 22 | ## Compile the code 23 | In the root directory of `nextsimdg`, do (can change the options passed to cmake) 24 | ``` 25 | apptainer shell --cleanenv apptainer/nextsim_dg.sif 26 | mkdir -p build 27 | cd build 28 | cmake .. \ 29 | -DCMAKE_BUILD_TYPE=Release \ 30 | -DWITH_THREADS=ON 31 | make -j [NUM_JOBS] 32 | ``` 33 | 34 | # Run the model 35 | ``` 36 | cd ../run 37 | ``` 38 | Link `./nextsim` from `build` 39 | ``` 40 | ln -s ../build/nextsim 41 | ``` 42 | Run with 43 | ``` 44 | ./nextsim --config-file config_benchmark.cfg 45 | ``` 46 | Can also run a more realistic case, by downloading some initial conditions 47 | ``` 48 | wget ftp://ftp.nersc.no/nextsim/netCDF/init_25km_NH.nc 49 | ``` 50 | and running with the config file 51 | ``` 52 | ./nextsim --config-file config_column.cfg 53 | ``` 54 | -------------------------------------------------------------------------------- /apptainer/nextsim_dg.def: -------------------------------------------------------------------------------- 1 | Bootstrap: docker 2 | From: ubuntu:22.04 3 | Stage: build 4 | 5 | 6 | %post 7 | # install apt libraries 8 | apt-get update --fix-missing 9 | apt-get install -y --no-install-recommends \ 10 | build-essential \ 11 | ca-certificates \ 12 | cmake \ 13 | libnetcdf-c++4-dev \ 14 | libboost-all-dev \ 15 | libeigen3-dev \ 16 | netcdf-bin \ 17 | python3-pip \ 18 | wget 19 | 20 | # install python packages 21 | pip install \ 22 | matplotlib \ 23 | netcdf4 \ 24 | numpy 25 | 26 | # update certificates and clean up 27 | update-ca-certificates 28 | apt-get clean 29 | rm -rf /var/lib/apt/lists/* 30 | 31 | %test 32 | grep -q NAME=\"Ubuntu\" /etc/os-release 33 | if [ $? -eq 0 ] 34 | then 35 | echo "Container base is Ubuntu as expected." 36 | else 37 | echo "Container base is not Ubuntu." 38 | exit 1 39 | fi 40 | 41 | %labels 42 | Author Timothy Williams 43 | Version v0.0.1 44 | 45 | %help 46 | This is an ubuntu container with required external libraries 47 | to compile and run nextsimdg 48 | -------------------------------------------------------------------------------- /cmake/Findxios.cmake: -------------------------------------------------------------------------------- 1 | # Find xios 2 | # 3 | # Please pass the -Dxios_DIR variable to cmake (location of the xios 4 | # executable). This is /xios/trunk/ if you followed the instructions in 5 | # the user/reference guide. 6 | 7 | find_library (xios_LIBRARIES NAMES xios HINTS ${xios_DIR}/lib ENV LD_LIBRARY_PATH) 8 | 9 | get_filename_component (xios_LIBRARIES "${xios_LIBRARIES}" PATH) 10 | 11 | set (xios_DIR "${xios_LIBRARIES}/../") 12 | cmake_path(NORMAL_PATH xios_DIR) 13 | 14 | find_path (xios_INCLUDES NAMES xios.hpp HINTS ${xios_DIR}/inc) 15 | 16 | set (xios_EXTERNS "${xios_DIR}/extern") 17 | cmake_path(NORMAL_PATH xios_EXTERNS) 18 | 19 | # handle the QUIETLY and REQUIRED arguments and set xios_FOUND to TRUE if all listed variables are TRUE 20 | include (FindPackageHandleStandardArgs) 21 | find_package_handle_standard_args(xios DEFAULT_MSG 22 | xios_LIBRARIES xios_INCLUDES xios_EXTERNS) 23 | 24 | message (STATUS "xios_LIBRARIES: ${xios_LIBRARIES}") 25 | message (STATUS "xios_INCLUDES: ${xios_INCLUDES}") 26 | message (STATUS "xios_EXTERNS: ${xios_EXTERNS}") 27 | # message (STATUS "xios_DIR: ${xios_DIR}") 28 | -------------------------------------------------------------------------------- /core/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(src) 2 | if(BUILD_TESTS) #(NOT(CMAKE_BUILD_TYPE STREQUAL "Release")) 3 | enable_testing() 4 | add_subdirectory(test) 5 | endif() 6 | 7 | set(NextsimSources "${NextsimSources}" PARENT_SCOPE) 8 | 9 | set(NextsimIncludeDirs "${NextsimIncludeDirs}" PARENT_SCOPE) 10 | -------------------------------------------------------------------------------- /core/src/ConfiguredModule.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file ConfiguredModule.cpp 3 | * 4 | * @date Oct 29, 2021 5 | * @author Tim Spain 6 | */ 7 | 8 | #include "include/ConfiguredModule.hpp" 9 | 10 | #include "include/Configurator.hpp" 11 | #include "include/NextsimModule.hpp" 12 | 13 | #include 14 | #include 15 | 16 | namespace Nextsim { 17 | 18 | const std::string ConfiguredModule::MODULE_PREFIX = "Modules"; 19 | 20 | std::string ConfiguredModule::addPrefix(const std::string& moduleName) 21 | { 22 | return MODULE_PREFIX + "." + moduleName; 23 | } 24 | 25 | std::string ConfiguredModule::getImpl(const std::string& module) 26 | { 27 | boost::program_options::options_description opt; 28 | 29 | opt.add_options()(addPrefix(module).c_str(), 30 | boost::program_options::value()->default_value(""), 31 | ("Load an implementation of " + module).c_str()); 32 | 33 | std::string implString = Configurator::parse(opt)[addPrefix(module)].as(); 34 | // Only do anything if the retrieved option is not the default value 35 | return implString; 36 | } 37 | 38 | ConfigMap ConfiguredModule::getAllModuleConfigurations() 39 | { 40 | ConfigMap iiMap; 41 | for (const auto& moduleImpl : Module::ImplementationNames::getAll()) { 42 | iiMap[moduleImpl.first] = moduleImpl.second; 43 | } 44 | return iiMap; 45 | } 46 | } /* namespace Nextsim */ 47 | -------------------------------------------------------------------------------- /core/src/FileCallbackCloser.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file FileCallbackCloser.cpp 3 | * 4 | * @date 15 May 2023 5 | * @author Tim Spain 6 | */ 7 | 8 | #include "include/FileCallbackCloser.hpp" 9 | 10 | namespace Nextsim { 11 | 12 | void FileCallbackCloser::onClose(FileCallbackCloser::ClosingFn fn) { closingFns().push_back(fn); } 13 | 14 | void FileCallbackCloser::close(const std::string& filename) 15 | { 16 | for (auto& fn : closingFns()) { 17 | fn(filename); 18 | } 19 | } 20 | 21 | void FileCallbackCloser::clearAllClose() { closingFns().clear(); } 22 | } /* namespace Nextsim */ 23 | -------------------------------------------------------------------------------- /core/src/Finalizer.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file Finalizer.cpp 3 | * 4 | * @date Sep 11, 2024 5 | * @author Tim Spain 6 | */ 7 | 8 | #include "include/Finalizer.hpp" 9 | 10 | namespace Nextsim { 11 | 12 | void Finalizer::registerFunc(const FinalFn& fn) 13 | { 14 | auto& fns = functions(); 15 | fns.push_back(fn); 16 | } 17 | 18 | bool Finalizer::registerUnique(const FinalFn& fn) 19 | { 20 | if (contains(fn)) 21 | return false; 22 | registerFunc(fn); 23 | return true; 24 | } 25 | 26 | bool Finalizer::contains(const FinalFn& fn) 27 | { 28 | auto& fns = functions(); 29 | for (const auto& stored : fns) { 30 | // Compare function addresses 31 | if (*stored.target() == *fn.target()) 32 | return true; 33 | } 34 | return false; 35 | } 36 | 37 | void Finalizer::finalize() 38 | { 39 | while (!functions().empty()) { 40 | try { 41 | // Execute the last function in the list 42 | functions().back()(); 43 | } catch (const std::exception& e) { 44 | // Remove the function from the finalization list even if an exception was thrown. 45 | functions().pop_back(); 46 | throw; 47 | } 48 | // Remove the function from the finalization list. 49 | functions().pop_back(); 50 | } 51 | } 52 | 53 | size_t Finalizer::count() { return functions().size(); } 54 | 55 | Finalizer::FinalFnContainer& Finalizer::functions() 56 | { 57 | static FinalFnContainer set; 58 | return set; 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /core/src/Iterator.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file Iterator.cpp 3 | * @date 11 Aug 2021 4 | * @author Tim Spain 5 | */ 6 | 7 | #include "include/Iterator.hpp" 8 | 9 | #include 10 | 11 | namespace Nextsim { 12 | 13 | void Iterator::setStartStopStep(TimePoint startTime, TimePoint stopTime, Duration timestep) 14 | { 15 | this->startTime = startTime; 16 | this->stopTime = stopTime; 17 | this->timestep = timestep; 18 | } 19 | 20 | TimePoint Iterator::parseAndSet(const std::string& startTimeStr, const std::string& stopTimeStr, 21 | const std::string& durationStr, const std::string& stepStr) 22 | { 23 | std::stringstream ss(startTimeStr); 24 | ss >> startTime; 25 | ss = std::stringstream(stepStr); 26 | ss >> timestep; 27 | if (!durationStr.empty()) { 28 | ss = std::stringstream(durationStr); 29 | Duration duration; 30 | ss >> duration; 31 | stopTime = startTime + duration; 32 | } else { 33 | ss = std::stringstream(stopTimeStr); 34 | ss >> stopTime; 35 | } 36 | 37 | return startTime; 38 | } 39 | 40 | void Iterator::run() 41 | { 42 | iterant.start(startTime); 43 | 44 | for (auto t = startTime; t < stopTime; t += timestep) { 45 | TimestepTime tsTime = { t, timestep }; 46 | iterant.iterate(tsTime); 47 | } 48 | 49 | iterant.stop(stopTime); 50 | } 51 | 52 | } /* namespace Nextsim */ 53 | -------------------------------------------------------------------------------- /core/src/ModelConfig.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file ModelConfig.cpp 3 | * 4 | * @date 14 Apr 2023 5 | * @author Tim Spain 6 | */ 7 | 8 | #include "include/ModelConfig.hpp" 9 | #include "include/MissingData.hpp" 10 | 11 | namespace Nextsim { 12 | 13 | std::string ModelConfig::startTimeStr; 14 | std::string ModelConfig::stopTimeStr; 15 | std::string ModelConfig::durationStr; 16 | std::string ModelConfig::stepStr; 17 | 18 | const std::map ModelConfig::keyMap = { 19 | #include "include/ModelConfigMapElements.ipp" 20 | }; 21 | 22 | ConfigMap ModelConfig::getConfig() 23 | { 24 | ConfigMap cMap = { 25 | { keyMap.at(STARTTIME_KEY), startTimeStr }, 26 | { keyMap.at(STOPTIME_KEY), stopTimeStr }, 27 | { keyMap.at(RUNLENGTH_KEY), durationStr }, 28 | { keyMap.at(TIMESTEP_KEY), stepStr }, 29 | { keyMap.at(MISSINGVALUE_KEY), MissingData::value() }, 30 | }; 31 | return cMap; 32 | } 33 | } /* namespace Nextsim */ 34 | -------------------------------------------------------------------------------- /core/src/PDWriter.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file PDWriter.cpp 3 | * 4 | * @date 14 Apr 2023 5 | * @author Tim Spain 6 | */ 7 | 8 | #include "include/PrognosticData.hpp" 9 | 10 | #include "include/ConfiguredModule.hpp" 11 | #include "include/ModelConfig.hpp" 12 | #include "include/ModelMetadata.hpp" 13 | #include "include/StructureFactory.hpp" 14 | 15 | namespace Nextsim { 16 | void PrognosticData::writeRestartFile( 17 | const std::string& filePath, const ModelMetadata& metadata) const 18 | { 19 | Logged::notice(std::string(" Writing state-based restart file: ") + filePath + '\n'); 20 | 21 | ModelState state = getStatePrognostic(); 22 | state.merge(ModelConfig::getConfig()); 23 | 24 | ModelMetadata meta(metadata); 25 | meta.affixCoordinates(state); 26 | 27 | StructureFactory::fileFromState(state, meta, filePath, true); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /core/src/ParallelNetcdfFile.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "include/ParallelNetcdfFile.hpp" 6 | 7 | using namespace netCDF; 8 | 9 | // Not sure why it is needed but let's replicate netCDF::ncFile::open 10 | // in this respect 11 | extern int g_ncid; 12 | 13 | NcFilePar::NcFilePar( 14 | const std::string& filePath, const FileMode fMode, MPI_Comm comm, MPI_Info mpiInfo) 15 | { 16 | open_par(filePath, fMode, comm, mpiInfo); 17 | } 18 | 19 | void NcFilePar::open_par( 20 | const std::string& filePath, const FileMode fMode, MPI_Comm comm, MPI_Info mpiInfo) 21 | { 22 | if (!nullObject) 23 | close(); 24 | 25 | switch (fMode) { 26 | case NcFile::write: 27 | ncCheck(nc_open_par(filePath.c_str(), NC_WRITE, comm, mpiInfo, &myId), __FILE__, __LINE__); 28 | break; 29 | case NcFile::read: 30 | ncCheck( 31 | nc_open_par(filePath.c_str(), NC_NOWRITE, comm, mpiInfo, &myId), __FILE__, __LINE__); 32 | break; 33 | case NcFile::newFile: 34 | ncCheck(nc_create_par(filePath.c_str(), NC_NETCDF4 | NC_NOCLOBBER, comm, mpiInfo, &myId), 35 | __FILE__, __LINE__); 36 | break; 37 | case NcFile::replace: 38 | ncCheck(nc_create_par(filePath.c_str(), NC_NETCDF4 | NC_CLOBBER, comm, mpiInfo, &myId), 39 | __FILE__, __LINE__); 40 | break; 41 | } 42 | 43 | g_ncid = myId; 44 | 45 | nullObject = false; 46 | } 47 | 48 | void netCDF::setVariableCollective(NcVar var, NcGroup group) 49 | { 50 | // This function will change the parallel access of a variable from independent to collective. 51 | // This is required to write to a variable in parallel when using MPI. 52 | ncCheck(nc_var_par_access(group.getId(), var.getId(), NC_COLLECTIVE), __FILE__, __LINE__); 53 | } 54 | -------------------------------------------------------------------------------- /core/src/discontinuousgalerkin/include/ModelArrayDetails.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file ModelArrayDetails.hpp 3 | * 4 | * @date Oct 19, 2022 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef MODELARRAYDETAILS_HPP 9 | #define MODELARRAYDETAILS_HPP 10 | 11 | // An inclusion file to detail the ModelArray dimensions and types for 12 | // Discontinuous Galerkin models. 13 | 14 | // Should be grouped with a consistent ModelArrayTypedefs.hpp and 15 | // ModelArrayDetails.cpp 16 | 17 | enum class Dimension { X, Y, XVERTEX, YVERTEX, XCG, YCG, DG, DGSTRESS, NCOORDS, COUNT }; 18 | 19 | enum class Type { 20 | H, 21 | VERTEX, 22 | U, 23 | V, 24 | DG, 25 | DGSTRESS, 26 | CG, 27 | }; 28 | 29 | static const Type AdvectionType = Type::DG; 30 | 31 | static ModelArray HField() { return ModelArray(Type::H); } 32 | static ModelArray VertexField() { return ModelArray(Type::VERTEX); } 33 | static ModelArray UField() { return ModelArray(Type::U); } 34 | static ModelArray VField() { return ModelArray(Type::V); } 35 | static ModelArray DGField() { return ModelArray(Type::DG); } 36 | static ModelArray DGSField() { return ModelArray(Type::DGSTRESS); } 37 | static ModelArray CGField() { return ModelArray(Type::CG); } 38 | 39 | const static size_t nCoords; 40 | 41 | #endif /* MODELARRAYDETAILS_HPP */ 42 | -------------------------------------------------------------------------------- /core/src/discontinuousgalerkin/include/ModelArrayTypedefs.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file ModelArrayTypedefs.hpp 3 | * 4 | * @date Oct 19, 2022 5 | * @author Tim Spain 6 | */ 7 | 8 | // An inclusion file of ModelArray typedefs for Discontinuous Galerkin models. 9 | 10 | // Should be grouped with a consistent ModelArrayDetails.hpp and 11 | // ModelArrayDetails.cpp 12 | 13 | typedef ModelArray HField; 14 | typedef ModelArray VertexField; 15 | typedef ModelArray UField; 16 | typedef ModelArray VField; 17 | typedef ModelArray DGField; 18 | typedef ModelArray DGSField; 19 | typedef ModelArray CGField; 20 | -------------------------------------------------------------------------------- /core/src/finitevolume/include/ModelArrayDetails.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file ModelArrayDetails.hpp 3 | * 4 | * @date Oct 19, 2022 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef MODELARRAYDETAILS_HPP 9 | #define MODELARRAYDETAILS_HPP 10 | 11 | // An inclusion file to detail the ModelArray dimensions and types for 12 | // finite volume models. 13 | 14 | // Should be grouped with a consistent ModelArrayTypedefs.hpp and 15 | // ModelArrayDetails.cpp 16 | 17 | enum class Dimension { X, Y, XVERTEX, YVERTEX, COUNT }; 18 | 19 | enum class Type { 20 | H, 21 | U, 22 | V, 23 | VERTEX, 24 | }; 25 | 26 | static const Type AdvectionType = Type::H; 27 | 28 | static ModelArray HField() { return ModelArray(Type::H); } 29 | static ModelArray UField() { return ModelArray(Type::U); } 30 | static ModelArray VField() { return ModelArray(Type::V); } 31 | static ModelArray VertexField() { return ModelArray(Type::VERTEX); } 32 | 33 | const static size_t nCoords; 34 | 35 | #endif /* MODELARRAYDETAILS_HPP */ 36 | -------------------------------------------------------------------------------- /core/src/finitevolume/include/ModelArrayTypedefs.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file ModelArrayTypedefs.hpp 3 | * 4 | * @date Oct 19, 2022 5 | * @author Tim Spain 6 | */ 7 | 8 | // An inclusion file of ModelArray typedefs for finite volume models. 9 | 10 | // Should be grouped with a consistent ModelArrayDetails.hpp and 11 | // ModelArrayDetails.cpp 12 | 13 | typedef ModelArray HField; 14 | typedef ModelArray UField; 15 | typedef ModelArray VField; 16 | typedef ModelArray VertexField; 17 | -------------------------------------------------------------------------------- /core/src/include/CommandLineParser.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file CommandLineParser.hpp 3 | * 4 | * @date Oct 8, 2021 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef COMMANDLINEPARSER_HPP 9 | #define COMMANDLINEPARSER_HPP 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | namespace Nextsim { 16 | 17 | /*! 18 | * A class to parse the neXtSIM_DG command line. 19 | */ 20 | class CommandLineParser { 21 | public: 22 | /*! 23 | * Parse the command line for command line options. 24 | * 25 | * @param argc the count of passed arguments. 26 | * @param argv The array of C strings passed as arguments. 27 | */ 28 | CommandLineParser(int argc, char* argv[]); 29 | virtual ~CommandLineParser() = default; 30 | 31 | /*! 32 | * Return a std::vector of the file names declared as config files on the 33 | * command line, in order. 34 | */ 35 | std::vector getConfigFileNames(); 36 | 37 | /*! 38 | * Returns the name of any module for which help was requested. 39 | */ 40 | std::string configHelp() { return m_configHelp; } 41 | 42 | /*! 43 | * The special string denoting help for all available modules. 44 | */ 45 | const static std::string allModuleString; 46 | 47 | /*! 48 | * The special string denoting a request for listing available modules. 49 | */ 50 | const static std::string availableModuleString; 51 | 52 | private: 53 | CommandLineParser() = default; 54 | 55 | boost::program_options::variables_map m_arguments; 56 | std::vector m_configFilenames; 57 | std::string m_configHelp; 58 | }; 59 | 60 | } /* namespace Nextsim */ 61 | 62 | #endif /* COMMANDLINEPARSER_HPP */ 63 | -------------------------------------------------------------------------------- /core/src/include/CommonRestartMetadata.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file CommonRestartMetadata.hpp 3 | * 4 | * @date Jun 30, 2022 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef COMMONRESTARTMETADATA_HPP 9 | #define COMMONRESTARTMETADATA_HPP 10 | 11 | #include "include/IStructure.hpp" 12 | #include "include/ModelMetadata.hpp" 13 | 14 | #include 15 | #include 16 | 17 | namespace Nextsim { 18 | 19 | class CommonRestartMetadata { 20 | public: 21 | //! Writes the structure type to the root of the restart file for future 22 | //! retrieval. 23 | static netCDF::NcGroup& writeStructureType( 24 | netCDF::NcFile& rootGroup, const ModelMetadata& metadata); 25 | //! Writes the standard restart file metadata to a metadata node. 26 | static netCDF::NcGroup& writeRestartMetadata( 27 | netCDF::NcGroup& metaGroup, const ModelMetadata& metadata); 28 | 29 | static const std::string timeNodeName() { return "time"; } 30 | 31 | static const std::string formattedName() { return "formatted"; } 32 | 33 | static const std::string unformattedName() { return "time"; } 34 | 35 | static const std::string configurationNode() { return "configuration"; } 36 | }; 37 | 38 | } /* namespace Nextsim */ 39 | 40 | #endif /* COMMONRESTARTMETADATA_HPP */ 41 | -------------------------------------------------------------------------------- /core/src/include/ConfigMap.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file ConfigMap.hpp 3 | * 4 | * @date Aug 19, 2022 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef CONFIGMAP_HPP 9 | #define CONFIGMAP_HPP 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | namespace Nextsim { 16 | 17 | typedef std::variant Fusi; 18 | typedef std::map ConfigMap; 19 | 20 | // clang-format off 21 | enum ConfigMapType { 22 | DOUBLE, 23 | UNSIGNED, 24 | INT, 25 | STRING, 26 | N_TYPES 27 | }; 28 | // clang-format on 29 | } 30 | #endif /* CONFIGMAP_HPP */ 31 | -------------------------------------------------------------------------------- /core/src/include/ConfigurationHelp.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file ConfigurationHelp.hpp 3 | * 4 | * @date 20 Nov 2024 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef CONFIGURATIONHELP_HPP 9 | #define CONFIGURATIONHELP_HPP 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | namespace Nextsim { 19 | 20 | class ConfigurationHelp { 21 | public: 22 | typedef std::list OptionList; 23 | typedef std::map HelpMap; 24 | 25 | enum class ConfigType { STRING, NUMERIC, INTEGER, MODULE, BOOLEAN }; 26 | 27 | std::string name; 28 | ConfigType type; 29 | std::vector range; 30 | std::string defaultValue; 31 | std::string units; 32 | std::string text; 33 | 34 | // Ever so slightly better formatting than std::to_string 35 | template static std::string toString(const T input, const int n = 6) 36 | { 37 | std::ostringstream output; 38 | output << std::setprecision(n) << input; 39 | return output.str(); 40 | } 41 | }; 42 | 43 | } /* namespace Nextsim */ 44 | 45 | #endif /* CONFIGURATIONHELP_HPP */ 46 | -------------------------------------------------------------------------------- /core/src/include/ConfigurationHelpPrinter.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file ConfigurationHelpPrinter.hpp 3 | * 4 | * @date Aug 18, 2022 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef CONFIGURATIONHELPPRINTER_HPP 9 | #define CONFIGURATIONHELPPRINTER_HPP 10 | 11 | #include "include/ConfigurationHelp.hpp" 12 | 13 | #include 14 | #include 15 | 16 | static std::string b; 17 | 18 | namespace Nextsim { 19 | 20 | class ConfigurationHelpPrinter { 21 | public: 22 | typedef ConfigurationHelp::ConfigType ConfigType; 23 | 24 | enum class Output { 25 | ANSI, 26 | MARKDOWN, 27 | }; 28 | 29 | static const std::string allStr; 30 | static const std::string availStr; 31 | 32 | static void setOutput(Output out); 33 | 34 | static std::ostream& print( 35 | std::ostream& os, const ConfigurationHelp::HelpMap& map, const std::string& target); 36 | static std::ostream& print(std::ostream& os, const ConfigurationHelp& help); 37 | 38 | protected: 39 | static std::ostream& printString(std::ostream& os, const ConfigurationHelp& help); 40 | static std::ostream& printNumeric(std::ostream& os, const ConfigurationHelp& help); 41 | static std::ostream& printInteger(std::ostream& os, const ConfigurationHelp& help); 42 | static std::ostream& printModule(std::ostream& os, const ConfigurationHelp& help); 43 | static std::ostream& printBoolean(std::ostream& os, const ConfigurationHelp& help); 44 | }; 45 | 46 | inline std::ostream& operator<<(std::ostream& os, const ConfigurationHelp& help) 47 | { 48 | return ConfigurationHelpPrinter::print(os, help); 49 | } 50 | } /* namespace Nextsim */ 51 | 52 | #endif /* CONFIGURATIONHELPPRINTER_HPP */ 53 | -------------------------------------------------------------------------------- /core/src/include/ConfiguredModule.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file ConfiguredModule.hpp 3 | * 4 | * @date Oct 29, 2021 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef CONFIGUREDMODULE_HPP 9 | #define CONFIGUREDMODULE_HPP 10 | 11 | #include "include/ConfigMap.hpp" 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | namespace Nextsim { 20 | 21 | /*! 22 | * @brief A helper class to load modules based on the configuration. 23 | */ 24 | class ConfiguredModule { 25 | public: 26 | ConfiguredModule() = default; 27 | virtual ~ConfiguredModule() = default; 28 | 29 | /*! 30 | * Gets the implementation name for a named module. 31 | * Returns an empty string if there is no such module. 32 | * 33 | * @param interface the name of the module to be checked. 34 | */ 35 | static std::string getImpl(const std::string& interface); 36 | 37 | /*! 38 | * Returns a map from interface name to implementation name for all modules 39 | * configured in this class. 40 | * 41 | */ 42 | static ConfigMap getAllModuleConfigurations(); 43 | /*! 44 | * @brief Transforms a module name into a configuration option name. 45 | * 46 | * @param moduleName The module name to be prefixed. 47 | */ 48 | static std::string addPrefix(const std::string& moduleName); 49 | 50 | //! The configuration options section name for modules. 51 | static const std::string MODULE_PREFIX; 52 | }; 53 | 54 | } /* namespace Nextsim */ 55 | 56 | #endif /* CONFIGUREDMODULE_HPP */ 57 | -------------------------------------------------------------------------------- /core/src/include/DevStep.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file DevStep.hpp 3 | * 4 | * @date Jan 12, 2022 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef DEVSTEP_HPP 9 | #define DEVSTEP_HPP 10 | 11 | #include "include/IModelStep.hpp" 12 | #include "include/IStructure.hpp" 13 | 14 | #include 15 | 16 | namespace Nextsim { 17 | 18 | //! A class providing a simple implementation of Iterator. 19 | class DevStep : public IModelStep { 20 | public: 21 | DevStep(); 22 | virtual ~DevStep() = default; 23 | 24 | // Member functions inherited from IModelStep 25 | void writeRestartFile(const std::string& filePath) override {}; 26 | 27 | void setData(PrognosticData& pDat) override { pData = &pDat; } 28 | void setMetadata(ModelMetadata& metadata) override { mData = &metadata; } 29 | 30 | /*! 31 | * Sets the period with which restart files are created. 32 | * 33 | * @param restartPeriod The Duration between writing out restart files. 34 | * @param filename The file name pattern to be used for the restart files. 35 | * The string will be used as a format for the time string, based on 36 | * the syntax of strftime. 37 | */ 38 | void setRestartDetails(const Duration& restartPeriod, const std::string& fileName); 39 | // Member functions inherited from Iterant 40 | void init() override; 41 | void start(const TimePoint& startTime) override; 42 | void iterate(const TimestepTime& dt) override; 43 | void stop(const TimePoint& stopTime) override {}; 44 | 45 | private: 46 | PrognosticData* pData; 47 | ModelMetadata* mData; 48 | Duration m_restartPeriod; 49 | TimePoint lastOutput; // The time a restart file was last output 50 | std::string m_restartFileName; 51 | }; 52 | 53 | } /* namespace Nextsim */ 54 | 55 | #endif /* DEVSTEP_HPP */ 56 | -------------------------------------------------------------------------------- /core/src/include/FileCallbackCloser.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file FileCallbackCloser.hpp 3 | * 4 | * @date 15 May 2023 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef FILECALLBACKCLOSER_HPP 9 | #define FILECALLBACKCLOSER_HPP 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | namespace Nextsim { 16 | 17 | /*! 18 | * A class to provide callback-based file closure, to avoid passing filenames 19 | * though classes where they don't belong. 20 | */ 21 | class FileCallbackCloser { 22 | 23 | public: 24 | typedef std::function ClosingFn; 25 | 26 | /*! 27 | * Adds a callback function which will be executed when the close function is called. 28 | * @param fn the function to be called on file closure 29 | */ 30 | static void onClose(ClosingFn fn); 31 | 32 | /*! 33 | * Closes the given filename be calling all onClose callbacks. 34 | * @param filename the filename to be closed. 35 | */ 36 | static void close(const std::string& fileName); 37 | 38 | /*! 39 | * Clears all onClose functions 40 | */ 41 | static void clearAllClose(); 42 | 43 | private: 44 | static std::list& closingFns() 45 | { 46 | static std::list fns; 47 | return fns; 48 | } 49 | }; 50 | } /* namespace Nextsim */ 51 | 52 | #endif /* FILECALLBACKCLOSER_HPP */ 53 | -------------------------------------------------------------------------------- /core/src/include/MissingData.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file MissingData.hpp 3 | * 4 | * @date Jun 14, 2022 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef MISSINGDATA_HPP 9 | #define MISSINGDATA_HPP 10 | 11 | #include "include/Configured.hpp" 12 | 13 | namespace Nextsim { 14 | 15 | class MissingData : public Configured { 16 | public: 17 | static constexpr double defaultValue = 1.7e38; 18 | inline static double value() { return getValue(); } 19 | inline static void setValue(double mdi) { getValue() = mdi; } 20 | 21 | private: 22 | inline static double& getValue() 23 | { 24 | static double value = defaultValue; 25 | return value; 26 | } 27 | }; 28 | 29 | } /* namespace Nextsim */ 30 | 31 | #endif /* MISSINGDATA_HPP */ 32 | -------------------------------------------------------------------------------- /core/src/include/ModelConfig.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file ModelConfig.hpp 3 | * 4 | * @date 14 Apr 2023 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef MODELCONFIG_HPP 9 | #define MODELCONFIG_HPP 10 | 11 | #include "include/ModelMetadata.hpp" 12 | #include "include/Time.hpp" 13 | 14 | #include 15 | #include 16 | 17 | namespace Nextsim { 18 | 19 | class Model; 20 | 21 | /*! 22 | * A class to store model configuration that is to be written to the restart file. 23 | */ 24 | class ModelConfig { 25 | public: 26 | const static std::map keyMap; 27 | static ConfigMap getConfig(); 28 | 29 | enum { 30 | DUMMY_KEY, 31 | STARTTIME_KEY, 32 | STOPTIME_KEY, 33 | RUNLENGTH_KEY, 34 | TIMESTEP_KEY, 35 | MISSINGVALUE_KEY, 36 | }; 37 | 38 | private: 39 | // Cached values of the start-step-stop/duration times 40 | static std::string startTimeStr; 41 | static std::string stopTimeStr; 42 | static std::string durationStr; 43 | static std::string stepStr; 44 | 45 | friend Model; 46 | }; 47 | 48 | } /* namespace Nextsim */ 49 | 50 | #endif /* MODELCONFIG_HPP */ 51 | -------------------------------------------------------------------------------- /core/src/include/ModelConfigMapElements.ipp: -------------------------------------------------------------------------------- 1 | { ModelConfig::STARTTIME_KEY, "model.start" }, 2 | { ModelConfig::STOPTIME_KEY, "model.stop" }, 3 | { ModelConfig::RUNLENGTH_KEY, "model.run_length" }, 4 | { ModelConfig::TIMESTEP_KEY, "model.time_step" }, 5 | { ModelConfig::MISSINGVALUE_KEY, "model.missing_value" }, 6 | -------------------------------------------------------------------------------- /core/src/include/ModelState.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file ModelState.hpp 3 | * 4 | * @date Feb 28, 2022 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef MODELSTATE_HPP 9 | #define MODELSTATE_HPP 10 | 11 | #include "ModelArray.hpp" 12 | 13 | #include "include/ConfigMap.hpp" 14 | 15 | #include 16 | #include 17 | 18 | namespace Nextsim { 19 | 20 | struct ModelState { 21 | private: 22 | public: 23 | typedef std::map DataMap; 24 | 25 | DataMap data; 26 | ConfigMap config; 27 | 28 | inline ModelState& merge(ModelState& source) 29 | { 30 | data.merge(source.data); 31 | config.merge(source.config); 32 | return *this; 33 | } 34 | 35 | inline ModelState& merge(ModelState&& source) 36 | { 37 | data.merge(source.data); 38 | config.merge(source.config); 39 | return *this; 40 | } 41 | 42 | inline ModelState& merge(ConfigMap& configSrc) 43 | { 44 | config.merge(configSrc); 45 | return *this; 46 | } 47 | 48 | inline ModelState& merge(ConfigMap&& configSrc) 49 | { 50 | config.merge(configSrc); 51 | return *this; 52 | } 53 | 54 | inline ModelState& merge(DataMap& dataSrc) 55 | { 56 | data.merge(dataSrc); 57 | return *this; 58 | } 59 | 60 | inline ModelState& merge(DataMap&& dataSrc) 61 | { 62 | data.merge(dataSrc); 63 | return *this; 64 | } 65 | }; 66 | 67 | } /* namespace Nextsim */ 68 | 69 | #endif /* MODELSTATE_HPP */ 70 | -------------------------------------------------------------------------------- /core/src/include/NetcdfMetadataConfiguration.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file NetcdfMetadataConfiguration.hpp 3 | * 4 | * @date Aug 29, 2022 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef NETCDFMETADATACONFIGURATION_HPP 9 | #define NETCDFMETADATACONFIGURATION_HPP 10 | 11 | #include "include/ConfigMap.hpp" 12 | #include "include/Configurator.hpp" 13 | 14 | namespace Nextsim { 15 | 16 | /*! 17 | * An implementation of Configurator::AdditionalConfiguration which fetches 18 | * configuration from the /metadata/configuration node of the named netCDF file. 19 | */ 20 | class NetcdfMetadataConfiguration : public Configurator::AdditionalConfiguration { 21 | public: 22 | std::stringstream read(const std::string& source) override; 23 | }; 24 | 25 | } /* namespace Nextsim */ 26 | 27 | #endif /* NETCDFMETADATACONFIGURATION_HPP */ 28 | -------------------------------------------------------------------------------- /core/src/include/NextsimModule.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file NextsimModule.hpp 3 | * 4 | * @date Sep 13, 2024 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef NEXTSIMMODULE_HPP 9 | #define NEXTSIMMODULE_HPP 10 | 11 | #include "include/ConfigurationHelp.hpp" 12 | #include "include/ConfiguredModule.hpp" 13 | 14 | // Define the types the module should use (HelpMap and Config) 15 | namespace Module { 16 | using OptionMap = std::list; 17 | using HelpMap = std::map; 18 | 19 | using Config = Nextsim::ConfiguredModule; 20 | } 21 | 22 | #include "include/Module.hpp" 23 | 24 | #endif /* NEXTSIMMODULE_HPP */ 25 | -------------------------------------------------------------------------------- /core/src/include/OutputSpec.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file OutputSpec.hpp 3 | * 4 | * @date Aug 25, 2022 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef OUTPUTSPEC_HPP 9 | #define OUTPUTSPEC_HPP 10 | 11 | #include 12 | 13 | namespace Nextsim { 14 | // TODO: Replace this with a more fine grained output specification class 15 | class OutputSpec { 16 | public: 17 | OutputSpec() { bitVector.reset(); } 18 | OutputSpec(bool activate) 19 | : OutputSpec() 20 | { 21 | if (!activate) 22 | bitVector.set(SUPPRESS_OUTPUT); 23 | } 24 | 25 | void setSuppressOutput() { bitVector.set(SUPPRESS_OUTPUT); } 26 | bool suppressOutput() const { return bitVector.test(SUPPRESS_OUTPUT); } 27 | operator bool() const { return !suppressOutput(); } 28 | void setAllComponents() { bitVector.set(ALL_COMPONENTS); } 29 | bool allComponents() const { return bitVector.test(ALL_COMPONENTS); } 30 | 31 | private: 32 | // clang-format off 33 | enum { 34 | SUPPRESS_OUTPUT, 35 | ALL_COMPONENTS, 36 | OUTPUTSPEC_COUNT 37 | }; 38 | // clang-format on 39 | 40 | std::bitset bitVector; 41 | }; 42 | } 43 | 44 | #endif /* OUTPUTSPEC_HPP */ 45 | -------------------------------------------------------------------------------- /core/src/include/ParallelNetcdfFile.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | namespace netCDF { 6 | 7 | class NcFilePar : public netCDF::NcFile { 8 | public: 9 | NcFilePar() = default; 10 | 11 | NcFilePar(const std::string& filePath, const FileMode fMode, MPI_Comm comm, 12 | MPI_Info info = MPI_INFO_NULL); 13 | 14 | void open_par(const std::string& path, const FileMode fMode, MPI_Comm comm, MPI_Info info); 15 | }; 16 | 17 | void setVariableCollective(NcVar var, NcGroup group); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /core/src/include/RectGridIO.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file RectGridIO.hpp 3 | * 4 | * @date Feb 8, 2022 5 | * @author Tim Spain 6 | * @author Kacper Kornet 7 | */ 8 | 9 | #ifndef RECTGRIDIO_HPP 10 | #define RECTGRIDIO_HPP 11 | 12 | #include "StructureModule/include/RectangularGrid.hpp" 13 | 14 | namespace Nextsim { 15 | 16 | class RectGridIO : public RectangularGrid::IRectGridIO { 17 | public: 18 | RectGridIO(RectangularGrid& grid) 19 | : IRectGridIO(grid) 20 | { 21 | } 22 | virtual ~RectGridIO() = default; 23 | 24 | typedef RectangularGrid::GridDimensions GridDimensions; 25 | 26 | #ifdef USE_MPI 27 | ModelState getModelState(const std::string& filePath, ModelMetadata& metadata) override; 28 | #else 29 | ModelState getModelState(const std::string& filePath) override; 30 | #endif 31 | 32 | void dumpModelState(const ModelState& state, const ModelMetadata& metadata, 33 | const std::string& filePath, bool isRestart) const override; 34 | 35 | private: 36 | RectGridIO() = default; 37 | }; 38 | 39 | } /* namespace Nextsim */ 40 | 41 | #endif /* RECTGRIDIO_HPP */ 42 | -------------------------------------------------------------------------------- /core/src/include/StructureFactory.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file StructureFactory.hpp 3 | * 4 | * @date Jan 18, 2022 5 | * @author Tim Spain 6 | * @author Kacper Kornet 7 | */ 8 | 9 | #ifndef STRUCTUREFACTORY_HPP 10 | #define STRUCTUREFACTORY_HPP 11 | 12 | #include "include/IStructure.hpp" 13 | 14 | #include "include/ModelMetadata.hpp" 15 | #include "include/ModelState.hpp" 16 | 17 | #include 18 | 19 | namespace Nextsim { 20 | 21 | class StructureFactory { 22 | public: 23 | #ifdef USE_MPI 24 | /*! 25 | * @brief Returns the ModelState of the named restart file. 26 | * 27 | * @param filePath the name of the file to be read. 28 | * @param partitionFile name of file with data for MPI domain decomposition 29 | * @param metadata ModelMedata to be used to get MPI parameters 30 | */ 31 | static ModelState stateFromFile(const std::string& filePath, ModelMetadata& metadata); 32 | #else 33 | /*! 34 | * @brief Returns the ModelState of the named restart file. 35 | * 36 | * @param filePath the name of the file to be read. 37 | */ 38 | static ModelState stateFromFile(const std::string& filePath); 39 | #endif 40 | 41 | /*! 42 | * @brief Takes a ModelState and a template file name to write the state 43 | * out to a target file path. 44 | * 45 | * @param state the ModelState to be written. 46 | * @param filePath the path for the file to be written to. 47 | */ 48 | static void fileFromState(const ModelState& state, const ModelMetadata& meta, 49 | const std::string& filePath, bool isRestart = false); 50 | 51 | static void finaliseAllFiles(); 52 | 53 | private: 54 | StructureFactory() = default; 55 | }; 56 | 57 | } /* namespace Nextsim */ 58 | 59 | #endif /* CORE_SRC_INCLUDE_STRUCTUREFACTORY_HPP */ 60 | -------------------------------------------------------------------------------- /core/src/include/TextTag.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file TextTag.hpp 3 | * 4 | * @date 27 Feb 2023 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef TEXTTAG_HPP 9 | #define TEXTTAG_HPP 10 | 11 | #include 12 | 13 | /*! 14 | * A transparent class to wrap string literals such that they can be used as 15 | * template parameters. Based on the TextTag struct created by Ben Earhart at 16 | * https://stackoverflow.com/a/49338542 17 | */ 18 | struct TextTag { 19 | constexpr TextTag(const char* textIn) 20 | : text(textIn) 21 | { 22 | } 23 | template 24 | constexpr TextTag(const char (&a)[N]) 25 | : text(a) 26 | { 27 | } 28 | operator std::string() const { return std::string(text); }; 29 | const char* text; 30 | }; 31 | 32 | #endif /* TEXTTAG_HPP */ 33 | -------------------------------------------------------------------------------- /core/src/include/gridNames.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file gridNames.hpp 3 | * 4 | * @date 19 May 2025 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef GRIDNAMES_HPP 9 | #define GRIDNAMES_HPP 10 | 11 | #include 12 | 13 | namespace Nextsim { 14 | 15 | // A set of canonical names for fields used in file reading and writing. 16 | static const std::string hiceName = "hice"; 17 | static const std::string ciceName = "cice"; 18 | static const std::string hsnowName = "hsnow"; 19 | static const std::string ticeName = "tice"; 20 | static const std::string tsurfName = "tsurf"; 21 | static const std::string maskName = "mask"; 22 | static const std::string uName = "u"; 23 | static const std::string vName = "v"; 24 | static const std::string sstName = "sst"; 25 | static const std::string sssName = "sss"; 26 | static const std::string damageName = "damage"; 27 | static const std::string shearName = "shear"; 28 | static const std::string divergenceName = "divergence"; 29 | static const std::string sigmaIName = "sigmaI"; 30 | static const std::string sigmaIIName = "sigmaII"; 31 | 32 | static const std::string uWindName = "uwind"; 33 | static const std::string vWindName = "vwind"; 34 | static const std::string uOceanName = "uocean"; 35 | static const std::string vOceanName = "vocean"; 36 | static const std::string sshName = "ssh"; 37 | // Mixed layer depth 38 | static const std::string mldName = "mld"; 39 | 40 | static const std::string uIOStressName = "uiostress"; 41 | static const std::string vIOStressName = "viostress"; 42 | 43 | static const std::string coordsName = "coords"; 44 | static const std::string latitudeName = "latitude"; 45 | static const std::string longitudeName = "longitude"; 46 | static const std::string xName = "x"; 47 | static const std::string yName = "y"; 48 | static const std::string gridAzimuthName = "grid_azimuth"; 49 | 50 | static const std::string mdiName = "missing_value"; 51 | 52 | static const std::string timeName = "time"; 53 | 54 | } 55 | 56 | #endif /* GRIDNAMES_HPP */ 57 | -------------------------------------------------------------------------------- /core/src/modules/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(AllModuleSources "") 2 | 3 | # Get all module subdirectories. These must be suffix with "Module", and 4 | # nothing else in this directory can be. 5 | file(GLOB ModuleSubDirs LIST_DIRECTORIES TRUE "*Module") 6 | 7 | foreach(ModuleSubDir IN LISTS ModuleSubDirs) 8 | # Ignore directories without a module.cfg file 9 | if(NOT EXISTS "${ModuleSubDir}/module.cfg") 10 | continue() 11 | endif() 12 | 13 | # Run the source python script 14 | execute_process( 15 | COMMAND "${Python_EXECUTABLE}" "${ModuleBuilderScript}" 16 | WORKING_DIRECTORY "${ModuleSubDir}" 17 | ) 18 | 19 | # List all sources in the subdirectory 20 | file(GLOB ThisModuleSources LIST_DIRECTORIES FALSE "${ModuleSubDir}/*.cpp") 21 | 22 | set(AllModuleSources "${AllModuleSources}" "${ThisModuleSources}") 23 | endforeach() 24 | 25 | set(NextsimSources "${NextsimSources}" "${AllModuleSources}" PARENT_SCOPE) 26 | -------------------------------------------------------------------------------- /core/src/modules/DiagnosticOutputModule/SimpleOutput.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file SimpleOutput.cpp 3 | * 4 | * @date 24 Sep 2024 5 | * @author Tim Spain 6 | */ 7 | 8 | #include "include/SimpleOutput.hpp" 9 | 10 | #include "include/Logged.hpp" 11 | #include "include/ModelArrayRef.hpp" 12 | #include "include/StructureFactory.hpp" 13 | 14 | #include 15 | 16 | namespace Nextsim { 17 | 18 | void SimpleOutput::outputState(const ModelState& diagState, const ModelMetadata& meta) 19 | { 20 | std::stringstream startStream; 21 | startStream << meta.time(); 22 | std::string timeFileName = m_filePrefix + "." + startStream.str() + ".nc"; 23 | // Some MPI-IO implemenetations does not like colon in file names 24 | std::replace(timeFileName.begin(), timeFileName.end(), ':', '_'); 25 | Logged::info( 26 | "Outputting " + std::to_string(externalNames.size()) + " fields to " + timeFileName + "\n"); 27 | 28 | // Take the passed state, and add the files in the data store 29 | ModelState state = diagState; 30 | // Create the output by iterating over all fields referenced in ModelState 31 | auto storeData = ModelComponent::getStore().getAllData(); 32 | for (auto entry : storeData) { 33 | if (entry.second) 34 | state.data.at(entry.first) = *entry.second; 35 | } 36 | StructureFactory::fileFromState(state, meta, timeFileName); 37 | } 38 | } /* namespace Nextsim */ 39 | -------------------------------------------------------------------------------- /core/src/modules/DiagnosticOutputModule/include/NoOutput.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file NoOutput.hpp 3 | * 4 | * @date 23 Oct 2024 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef NOOUTPUT_HPP 9 | #define NOOUTPUT_HPP 10 | 11 | #include "include/IDiagnosticOutput.hpp" 12 | 13 | namespace Nextsim { 14 | 15 | class NoOutput : public IDiagnosticOutput { 16 | public: 17 | NoOutput() = default; 18 | 19 | void setFilenamePrefix(const std::string& filePrefix) override {}; 20 | 21 | void outputState(const ModelState& state, const ModelMetadata& meta) override {}; 22 | 23 | // ModelComponent functions 24 | std::string getName() const override { return "NoOutput"; } 25 | }; 26 | 27 | } /* namespace Nextsim */ 28 | 29 | #endif /* NOOUTPUT_HPP */ 30 | -------------------------------------------------------------------------------- /core/src/modules/DiagnosticOutputModule/include/SimpleOutput.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file SimpleOutput.hpp 3 | * 4 | * @date 24 Sep 2024 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef SIMPLEOUTPUT_HPP 9 | #define SIMPLEOUTPUT_HPP 10 | 11 | #include "include/IDiagnosticOutput.hpp" 12 | 13 | namespace Nextsim { 14 | 15 | class SimpleOutput : public IDiagnosticOutput { 16 | public: 17 | SimpleOutput() = default; 18 | 19 | void setFilenamePrefix(const std::string& filePrefix) override { m_filePrefix = filePrefix; } 20 | 21 | void outputState(const ModelState& state, const ModelMetadata& meta) override; 22 | 23 | // ModelComponent functions 24 | std::string getName() const override { return "SimpleOutput"; } 25 | 26 | private: 27 | std::string m_filePrefix; 28 | }; 29 | 30 | } /* namespace Nextsim */ 31 | 32 | #endif /* SIMPLEOUTPUT_HPP */ 33 | -------------------------------------------------------------------------------- /core/src/modules/DiagnosticOutputModule/module.cfg: -------------------------------------------------------------------------------- 1 | [module] 2 | name = Nextsim::IDiagnosticOutput 3 | file_prefix = DiagnosticOutput 4 | interface_prefix = I 5 | header_path = include 6 | external_header_path = ../include 7 | description = The module providing diagnostic output capabilities. 8 | 9 | [Nextsim::NoOutput] 10 | file_prefix = NoOutput 11 | description = Produces no diagnostic output. 12 | has_help = no 13 | is_default = true 14 | 15 | [Nextsim::SimpleOutput] 16 | file_prefix = SimpleOutput 17 | description = All the fields every timestep. 18 | has_help = no 19 | 20 | [Nextsim::ConfigOutput] 21 | file_prefix = ConfigOutput 22 | description = Blocking output with configuration. 23 | has_help = true 24 | -------------------------------------------------------------------------------- /core/src/modules/DynamicsModule/include/BBMDynamics.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file BBMDynamics.hpp 3 | * 4 | * @date 27 Mar 2025 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef BBMDYNAMICS_HPP 9 | #define BBMDYNAMICS_HPP 10 | 11 | #include "include/BBMDynamicsKernel.hpp" 12 | #include "include/BBMParameters.hpp" 13 | #include "include/IDynamics.hpp" 14 | 15 | #ifndef DGCOMP 16 | #define DGCOMP 3 // Define to prevent errors from static analysis tools 17 | #error "Number of DG components (DGCOMP) not defined" // But throw an error anyway 18 | #endif 19 | 20 | namespace Nextsim { 21 | 22 | class BBMDynamics : public IDynamics, public Configured { 23 | public: 24 | BBMDynamics(); 25 | 26 | std::string getName() const override { return "BBMDynamics"; } 27 | void update(const TimestepTime& tst) override; 28 | 29 | void setData(const ModelState::DataMap&) override; 30 | void configure() override; 31 | ConfigMap getConfiguration() const override; 32 | 33 | enum { 34 | C_KEY, 35 | NU_KEY, 36 | YOUNG_KEY, 37 | P0_KEY, 38 | LAMBDA0_KEY, 39 | ALPHA_KEY, 40 | EXPPMAX_KEY, 41 | MU_KEY, 42 | NMAX_KEY, 43 | CLAB_KEY, 44 | NSTEPS_KEY, 45 | RHOI_KEY, 46 | RHOA_KEY, 47 | RHOO_KEY, 48 | CATM_KEY, 49 | COCEAN_KEY, 50 | FC_KEY, 51 | ANGLE_KEY, 52 | }; 53 | 54 | static HelpMap& getHelpText(HelpMap& map, bool getAll); 55 | static HelpMap& getHelpRecursive(HelpMap&, bool getAll); 56 | 57 | private: 58 | BBMParameters params; 59 | BBMDynamicsKernel kernel; 60 | }; 61 | 62 | } /* namespace Nextsim */ 63 | 64 | #endif /* BBMDYNAMICS_HPP */ 65 | -------------------------------------------------------------------------------- /core/src/modules/DynamicsModule/include/DummyDynamics.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file DummyDynamics.hpp 3 | * 4 | * @date 24 Sep 2024 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef DUMMYDYNAMICS_HPP 9 | #define DUMMYDYNAMICS_HPP 10 | 11 | #include "include/IDynamics.hpp" 12 | 13 | #include "include/ModelArray.hpp" 14 | #include "include/ModelComponent.hpp" 15 | 16 | namespace Nextsim { 17 | class DummyDynamics : public IDynamics { 18 | public: 19 | DummyDynamics() = default; 20 | 21 | std::string getName() const override { return "DummyDynamics"; } 22 | void update(const TimestepTime& tst) override {}; 23 | }; 24 | } 25 | 26 | #endif /* DUMMYDYNAMICS_HPP */ 27 | -------------------------------------------------------------------------------- /core/src/modules/DynamicsModule/include/MEVPDynamics.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file MEVPDynamics.hpp 3 | * 4 | * @date 27 Mar 2025 5 | * @author Tim Spain 6 | * @author Piotr Minakowski 7 | * @author Einar Ólason 8 | */ 9 | 10 | #ifndef MEVPDYNAMICS_HPP 11 | #define MEVPDYNAMICS_HPP 12 | 13 | #include "include/IDamageHealing.hpp" 14 | #include "include/IDynamics.hpp" 15 | #include "include/MEVPDynamicsKernel.hpp" 16 | #include "include/NextsimModule.hpp" 17 | 18 | #include "include/ModelArray.hpp" 19 | #include "include/ModelComponent.hpp" 20 | 21 | #ifndef DGCOMP 22 | #define DGCOMP 3 // Define to prevent errors from static analysis tools 23 | #error "Number of DG components (DGCOMP) not defined" // But throw an error anyway 24 | #endif 25 | 26 | extern template class Module::Module; 27 | 28 | namespace Nextsim { 29 | class MEVPDynamics : public IDynamics, public Configured { 30 | public: 31 | MEVPDynamics(); 32 | 33 | std::string getName() const override { return "MEVPDynamics"; } 34 | void update(const TimestepTime& tst) override; 35 | 36 | void setData(const ModelState::DataMap&) override; 37 | void configure() override; 38 | ConfigMap getConfiguration() const override; 39 | 40 | enum { 41 | PSTAR_KEY, 42 | DELTA_KEY, 43 | C_KEY, 44 | NSTEPS_KEY, 45 | RHOI_KEY, 46 | RHOA_KEY, 47 | RHOO_KEY, 48 | CATM_KEY, 49 | COCEAN_KEY, 50 | FC_KEY, 51 | ANGLE_KEY, 52 | }; 53 | 54 | static HelpMap& getHelpText(HelpMap& map, bool getAll); 55 | static HelpMap& getHelpRecursive(HelpMap&, bool getAll); 56 | 57 | private: 58 | VPParameters params; 59 | MEVPDynamicsKernel kernel; 60 | }; 61 | } 62 | 63 | #endif /* MEVPDYNAMICS_HPP */ 64 | -------------------------------------------------------------------------------- /core/src/modules/DynamicsModule/module.cfg: -------------------------------------------------------------------------------- 1 | [module] 2 | name = Nextsim::IDynamics 3 | file_prefix = Dynamics 4 | interface_prefix = I 5 | header_path = include 6 | external_header_path = ../include 7 | description = The module providing rheology and ice dynamics. 8 | 9 | [Nextsim::DummyDynamics] 10 | file_prefix = DummyDynamics 11 | description = No dynamics calculations. 12 | has_help = false 13 | is_default = true 14 | 15 | [Nextsim::MEVPDynamics] 16 | file_prefix = MEVPDynamics 17 | description = Discontinuous Galerkin dynamics with mEVP rheology. 18 | has_help = true 19 | 20 | [Nextsim::BBMDynamics] 21 | file_prefix = BBMDynamics 22 | description = Discontinuous Galerkin dynamics with BBM rheology. 23 | has_help = true 24 | 25 | [Nextsim::FreeDriftDynamics] 26 | file_prefix = FreeDriftDynamics 27 | description = Free drift dynamics. 28 | has_help = false -------------------------------------------------------------------------------- /core/src/modules/FreezingPointModule/include/LinearFreezing.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file LinearFreezing.hpp 3 | * 4 | * @date Nov 10, 2021 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef LINEARFREEZING_HPP 9 | #define LINEARFREEZING_HPP 10 | 11 | #include "include/IFreezingPoint.hpp" 12 | #include "include/constants.hpp" 13 | 14 | namespace Nextsim { 15 | 16 | //! The implementation class of the linear model of seawater freezing point. 17 | class LinearFreezing : public IFreezingPoint { 18 | public: 19 | // ~LinearFreezing() = default; 20 | 21 | /*! 22 | * @brief Calculates the freezing point of 23 | * seawater. 24 | * 25 | * @details Freezing point in ˚C of water with the given salinity at 26 | * standard pressure. 27 | * 28 | * @param sss Sea surface salinity [PSU] 29 | */ 30 | inline double operator()(double sss) const override 31 | { 32 | // μ is positive, so a negative sign is needed so that the freezing point is below zero. 33 | return -Water::mu * sss; 34 | } 35 | }; 36 | } 37 | 38 | #endif /* LINEARFREEZING_HPP */ 39 | -------------------------------------------------------------------------------- /core/src/modules/FreezingPointModule/include/UnescoFreezing.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file UnescoFreezing.hpp 3 | * 4 | * @date Nov 10, 2021 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef UNESCOFREEZING_HPP 9 | #define UNESCOFREEZING_HPP 10 | 11 | #include 12 | 13 | #include "include/IFreezingPoint.hpp" 14 | 15 | namespace Nextsim { 16 | 17 | //! The implementation class of the UNESCO model of the freezing point of 18 | // seawater. 19 | class UnescoFreezing : public IFreezingPoint { 20 | public: 21 | /*! 22 | * @brief Calculates the freezing point of seawater. 23 | * 24 | * @details Freezing point in ˚C of water with the given salinity at 25 | * standard pressure. 26 | * 27 | * @param sss Sea surface salinity [PSU] 28 | */ 29 | inline double operator()(double sss) const override 30 | { 31 | // Fofonoff and Millard, Unesco technical papers in marine science 44, (1983) 32 | const double a0 = -0.0575; 33 | const double a1 = +1.710523e-3; 34 | const double a2 = -2.154996e-4; 35 | const double b = -7.53e-4; 36 | const double p0 = 0; // Zero hydrostatic pressure 37 | 38 | return sss * (a0 + a1 * std::sqrt(sss) + a2 * sss) + b * p0; 39 | } 40 | }; 41 | } 42 | 43 | #endif /* UNESCOFREEZING_HPP */ 44 | -------------------------------------------------------------------------------- /core/src/modules/FreezingPointModule/module.cfg: -------------------------------------------------------------------------------- 1 | [module] 2 | name = Nextsim::IFreezingPoint 3 | file_prefix = FreezingPoint 4 | interface_prefix = I 5 | header_path = include 6 | external_header_path = ../include 7 | description = The module providing the calculation of freezing point from salinity. 8 | 9 | [Nextsim::LinearFreezing] 10 | file_prefix = LinearFreezing 11 | description = Freezing point exactly proportional to salinity with constant μ = 0.055. 12 | has_help = no 13 | is_default = true 14 | 15 | [Nextsim::UnescoFreezing] 16 | file_prefix = UnescoFreezing 17 | description = Freezing point after Fofonoff and Millard, Unesco technical papers in marine science 44, (1983). 18 | has_help = false 19 | -------------------------------------------------------------------------------- /core/src/modules/StructureModule/ParametricGrid.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file ParametricGrid.cpp 3 | * 4 | * @date Oct 24, 2022 5 | * @author Tim Spain 6 | */ 7 | 8 | #include "include/ParametricGrid.hpp" 9 | 10 | namespace Nextsim { 11 | 12 | const std::string ParametricGrid::structureName = "parametric_rectangular"; 13 | 14 | } /* namespace Nextsim */ 15 | -------------------------------------------------------------------------------- /core/src/modules/StructureModule/RectangularGrid.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file RectangularGrid.cpp 3 | * 4 | * @date Feb 7, 2022 5 | * @author Tim Spain 6 | */ 7 | 8 | #include "include/RectangularGrid.hpp" 9 | 10 | namespace Nextsim { 11 | 12 | const std::string RectangularGrid::structureName = "simple_rectangular"; 13 | const std::string RectangularGrid::xDimName = "x"; 14 | const std::string RectangularGrid::yDimName = "y"; 15 | 16 | } /* namespace Nextsim */ 17 | -------------------------------------------------------------------------------- /core/src/modules/StructureModule/module.cfg: -------------------------------------------------------------------------------- 1 | [module] 2 | name = Nextsim::IStructure 3 | file_prefix = Structure 4 | interface_prefix = I 5 | header_path = include 6 | external_header_path = ../include 7 | description = The module providing functions related to the grid structure. 8 | 9 | [Nextsim::RectangularGrid] 10 | file_prefix = RectangularGrid 11 | description = A simple n x m rectangular grid. 12 | has_help = false 13 | is_default = true 14 | 15 | [Nextsim::ParametricGrid] 16 | file_prefix = ParametricGrid 17 | description = A parameterized rectangular grid for discontinuous Galerkin numerics. 18 | has_help = false 19 | -------------------------------------------------------------------------------- /core/src/modules/include/IFreezingPoint.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file IFreezingPoint.hpp 3 | * 4 | * @date Nov 9, 2021 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef SRC_INCLUDE_IFREEZINGPOINT_HPP_ 9 | #define SRC_INCLUDE_IFREEZINGPOINT_HPP_ 10 | 11 | namespace Nextsim { 12 | 13 | //! The interface class for calculation of the freezing point of seawater. 14 | class IFreezingPoint { 15 | public: 16 | virtual ~IFreezingPoint() = default; 17 | 18 | /*! 19 | * @brief A virtual function that calculates the freezing point of 20 | * seawater. 21 | * 22 | * @details Freezing point in ˚C of water with the given salinity at 23 | * standard pressure. 24 | * 25 | * @param sss Sea surface salinity [PSU] 26 | */ 27 | virtual double operator()(double sss) const = 0; 28 | }; 29 | } 30 | #endif /* SRC_INCLUDE_IFREEZINGPOINT_HPP_ */ 31 | -------------------------------------------------------------------------------- /core/src/modules/include/SharedArrayNames.ipp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file SharedArrayNames.ipp 3 | * 4 | * @date 1 Jul 2024 5 | * @author Tim Spain 6 | * @author Einar Ólason 7 | */ 8 | 9 | // External SharedArray names must be unique wrt to the external ProtectedArray names as well 10 | { "damage_upd", "DAMAGE" }, // Updated ice thickness, ice average, m 11 | { "hice_true", "H_ICE" }, // Updated ice thickness, ice average, m 12 | { "cice_upd", "C_ICE" }, // Updated ice concentration 13 | { "hsnow_true", "H_SNOW" }, // Updated snow depth, ice average, m 14 | { "tice_upd", "T_ICE" }, // Updated ice temperatures, ˚C 15 | { "qia", "Q_IA" }, // Ice to atmosphere heat flux W m⁻² 16 | { "qic", "Q_IC" }, // Ice conduction heat flux W m⁻² 17 | { "qio", "Q_IO" }, // Ice to ocean heat flux W m⁻² 18 | { "qow", "Q_OW" }, // Open water heat flux W m⁻² 19 | { "dqia_dt", "DQIA_DT" }, // Derivative of Qᵢₐ w.r.t. ice surface temperature W m⁻² K⁻¹ 20 | { "qpen_sw", "Q_PEN_SW" }, // Penetrating shortwave flux W m⁻² 21 | { "hsnow_melt", "HSNOW_MELT" }, // Thickness of snow that melted, m 22 | { "sublim", "SUBLIM" }, // Upward sublimation rate kg m⁻² s⁻¹ 23 | { "delta_hice", "DELTA_HICE" }, // Change in sea ice thickness, m 24 | { "delta_cice", "DELTA_CICE" }, // Change in sea ice concentration 25 | { "new_ice", "NEW_ICE" }, // Volume of new ice formed [m] 26 | -------------------------------------------------------------------------------- /core/test/ArgV.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file ArgV.cpp 3 | * 4 | * @date Oct 11, 2021 5 | * @author Tim Spain 6 | */ 7 | 8 | #include "ArgV.hpp" 9 | 10 | namespace Nextsim { 11 | 12 | ArgV::ArgV(std::vector vs) 13 | { 14 | nStrings = vs.size(); 15 | ppc = new char*[nStrings + 1]; // Add 1 for the conventional final \0 16 | for (int i = 0; i < nStrings; ++i) { 17 | int len = vs[i].size(); 18 | char* pc = new char[len + 1]; 19 | for (int j = 0; j < len; ++j) { 20 | pc[j] = vs[i][j]; 21 | } 22 | pc[len] = '\0'; 23 | ppc[i] = pc; 24 | } 25 | // Ensure argv[argc] = "\0", as required by the standard. 26 | char* pnull = new char[1]; 27 | pnull[0] = '\0'; 28 | ppc[nStrings] = pnull; 29 | } 30 | 31 | ArgV::~ArgV() 32 | { 33 | for (int i = 0; i < nStrings; ++i) { 34 | delete[] ppc[i]; 35 | } 36 | delete[] ppc; 37 | } 38 | 39 | char** ArgV::operator()() { return ppc; } 40 | 41 | int ArgV::argc() { return nStrings; } 42 | } 43 | -------------------------------------------------------------------------------- /core/test/ArgV.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file ArgV.hpp 3 | * 4 | * @date Oct 11, 2021 5 | * @author Tim Spain 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | #ifndef TEST_ARGV_HPP 12 | #define TEST_ARGV_HPP 13 | 14 | namespace Nextsim { 15 | // A class to work around the limitations on casting string literals to char*. 16 | class ArgV { 17 | public: 18 | ArgV(std::vector vs); 19 | ~ArgV(); 20 | 21 | char** operator()(); 22 | int argc(); 23 | 24 | private: 25 | int nStrings; 26 | char** ppc; 27 | }; 28 | 29 | } 30 | 31 | #endif /* TEST_ARGV_HPP */ 32 | -------------------------------------------------------------------------------- /core/test/CommandLineParser_test.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file CommandLineParser_test.cpp 3 | * 4 | * @date Oct 8, 2021 5 | * @author Tim Spain 6 | */ 7 | 8 | #include "ArgV.hpp" 9 | #include "CommandLineParser.hpp" 10 | 11 | #include 12 | #include 13 | 14 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 15 | #include 16 | 17 | namespace Nextsim { 18 | 19 | TEST_SUITE_BEGIN("CommandLineParser"); 20 | TEST_CASE("Parse config file names") 21 | { 22 | // Parse one file 23 | ArgV argv1({ "nextsimdg", "--config-file", "config.cfg" }); 24 | 25 | CommandLineParser clp1(argv1.argc(), argv1()); 26 | std::vector cfgs = clp1.getConfigFileNames(); 27 | 28 | REQUIRE(cfgs.size() == 1); 29 | REQUIRE(cfgs[0] == std::string(argv1()[argv1.argc() - 1])); 30 | 31 | cfgs.clear(); 32 | std::string finalFileName = "final.cfg"; 33 | ArgV argv2({ "nextsimdg", "--config-file", "config.cfg", "--config-files", "test.cfg", 34 | "more.cfg", finalFileName }); 35 | 36 | CommandLineParser clp2(argv2.argc(), argv2()); 37 | cfgs = clp2.getConfigFileNames(); 38 | 39 | REQUIRE(cfgs.size() == 4); 40 | REQUIRE(cfgs[cfgs.size() - 1] == finalFileName); 41 | } 42 | TEST_SUITE_END(); 43 | 44 | } /* namespace Nextsim */ 45 | -------------------------------------------------------------------------------- /core/test/DynamicsModuleForPDtest.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file DynamicsModuleForPDtest.cpp 3 | * 4 | * @date 5 May 2023 5 | * @author Tim Spain 6 | */ 7 | 8 | #include "include/IDynamics.hpp" 9 | #include "include/NextsimModule.hpp" 10 | 11 | #include "PDTestDynamics.hpp" 12 | 13 | #include 14 | 15 | namespace Module { 16 | const std::string PDTESTDYNAMICS = "Nextsim::PDTestDynamics"; 17 | 18 | template <> 19 | const Module::Map& Module::functionMap() 20 | { 21 | static const Map theMap = { 22 | { PDTESTDYNAMICS, newImpl }, 23 | }; 24 | return theMap; 25 | } 26 | 27 | template <> 28 | Module::Fn& Module::getGenerationFunction() 29 | { 30 | static Fn thePtr = functionMap().at(PDTESTDYNAMICS); 31 | return thePtr; 32 | } 33 | 34 | template <> std::string Module::moduleName() { return "Nextsim::IDynamics"; } 35 | 36 | template <> Nextsim::IDynamics& getImplementation() 37 | { 38 | return Module::getImplementation(); 39 | } 40 | 41 | template <> HelpMap& getHelpRecursive(HelpMap& map, bool getAll) { return map; } 42 | 43 | } /* namespace Module */ 44 | -------------------------------------------------------------------------------- /core/test/FileCallbackCloser_test.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file FileCallbackCloser_test.cpp 3 | * 4 | * @date 15 May 2023 5 | * @author Tim Spain 6 | */ 7 | 8 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 9 | #include 10 | 11 | #include "include/FileCallbackCloser.hpp" 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | namespace Nextsim { 18 | 19 | const std::string testFileName = "testFileName.nc"; 20 | 21 | class FileHolder { 22 | public: 23 | static void open(const std::string& fileName) { openFiles.emplace(fileName, fileName); } 24 | static void close(const std::string& fileName) 25 | { 26 | openFiles[fileName].close(); 27 | openFiles.erase(fileName); 28 | } 29 | static bool isOpen(const std::string& fileName) { return openFiles.count(fileName) > 0; } 30 | 31 | private: 32 | static std::map openFiles; 33 | }; 34 | 35 | std::map FileHolder::openFiles; 36 | 37 | TEST_SUITE_BEGIN("FileCallbackCloser"); 38 | TEST_CASE("Test the FileHolder class") 39 | { 40 | FileHolder::open(testFileName); 41 | REQUIRE(FileHolder::isOpen(testFileName)); 42 | FileHolder::close(testFileName); 43 | REQUIRE(!FileHolder::isOpen(testFileName)); 44 | std::filesystem::remove(testFileName); 45 | } 46 | 47 | TEST_CASE("Close a file") 48 | { 49 | FileCallbackCloser::onClose(FileHolder::close); 50 | 51 | FileHolder::open(testFileName); 52 | REQUIRE(FileHolder::isOpen(testFileName)); 53 | FileCallbackCloser::close(testFileName); 54 | REQUIRE(!FileHolder::isOpen(testFileName)); 55 | std::filesystem::remove(testFileName); 56 | } 57 | TEST_SUITE_END(); 58 | } /* namespace Nextsim */ 59 | -------------------------------------------------------------------------------- /core/test/Iterator_test.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file Iterator_test.cpp 3 | * @date 24 Sep 2024 4 | * @author Tim Spain 5 | */ 6 | 7 | #include "Iterator.hpp" 8 | 9 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 10 | #include 11 | 12 | namespace Nextsim { 13 | 14 | // An iterant that counts the number of times it is started, iterated 15 | // and stopped 16 | class Counterant : public Iterator::Iterant { 17 | public: 18 | void init() 19 | { 20 | count = 0; 21 | startCount = 0; 22 | stopCount = 0; 23 | }; 24 | void start(const TimePoint& startTime) { startCount++; }; 25 | void iterate(const TimestepTime& tst) { count++; }; 26 | void stop(const TimePoint& stopTime) { stopCount++; }; 27 | 28 | int getCount() { return count; }; 29 | 30 | int count; 31 | int startCount; 32 | int stopCount; 33 | }; 34 | 35 | template T zeroTime(); 36 | 37 | template <> 38 | std::chrono::time_point zeroTime>() 39 | { 40 | return Iterator::Clock::now(); 41 | } 42 | template <> size_t zeroTime() { return 0; } 43 | 44 | TEST_SUITE_BEGIN("Iterator"); 45 | TEST_CASE("Count iterator testing") 46 | { 47 | Counterant cant = Counterant(); 48 | Iterator iterator(cant); 49 | 50 | int nSteps = 5; 51 | 52 | TimePoint start; 53 | Duration dt("P0-0T0:0:1"); 54 | Duration overall(dt); 55 | overall *= nSteps; 56 | TimePoint stop = start + overall; 57 | iterator.setStartStopStep(start, start + overall, dt); 58 | iterator.run(); 59 | 60 | REQUIRE(dt.seconds() == 1); 61 | REQUIRE(overall.seconds() == nSteps * 1); 62 | REQUIRE(stop > start); 63 | REQUIRE((stop - start).seconds() == nSteps * 1); 64 | REQUIRE(cant.count == nSteps); 65 | REQUIRE(cant.startCount == 1); 66 | REQUIRE(cant.stopCount == 1); 67 | } 68 | TEST_SUITE_END(); 69 | 70 | } /* namespace Nextsim */ 71 | -------------------------------------------------------------------------------- /core/test/Logged_test.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file Logged_test.cpp 3 | * @date 12 Aug 2021 4 | * @author Tim Spain 5 | */ 6 | 7 | #include "Logged.hpp" 8 | 9 | namespace Nextsim { 10 | // TODO: write tests when there is something in the class to test. 11 | } /* namespace Nextsim */ 12 | -------------------------------------------------------------------------------- /core/test/MainMPI.cpp: -------------------------------------------------------------------------------- 1 | #define DOCTEST_CONFIG_IMPLEMENT 2 | 3 | #include 4 | 5 | int main(int argc, char** argv) 6 | { 7 | doctest::mpi_init_thread(argc, argv, MPI_THREAD_MULTIPLE); 8 | 9 | doctest::Context ctx; 10 | ctx.setOption("reporters", "MpiConsoleReporter"); 11 | ctx.setOption("reporters", "MpiFileReporter"); 12 | ctx.setOption("force-colors", true); 13 | ctx.applyCommandLine(argc, argv); 14 | 15 | int test_result = ctx.run(); 16 | 17 | doctest::mpi_finalize(); 18 | 19 | return test_result; 20 | } 21 | -------------------------------------------------------------------------------- /core/test/PDTestDynamics.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file PDTestDynamics.hpp 3 | * 4 | * @date Jan 21, 2025 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef PDTESTDYNAMICS_HPP 9 | #define PDTESTDYNAMICS_HPP 10 | 11 | #include "include/DummyDynamics.hpp" 12 | 13 | namespace Nextsim { 14 | class PDTestDynamics : public DummyDynamics { 15 | public: 16 | std::string getName() const override { return "PDTestDynamics"; } 17 | 18 | void setData (const ModelState::DataMap& ms) override 19 | { 20 | dataMap = ms; 21 | } 22 | ModelState getStateDiagnostic() const override 23 | { 24 | return { dataMap, {} }; 25 | } 26 | 27 | ModelState getStatePrognostic() const override 28 | { 29 | return { dataMap, {} }; 30 | } 31 | private: 32 | ModelState::DataMap dataMap; 33 | }; 34 | } 35 | 36 | #endif /* PDTESTDYNAMICS_HPP */ 37 | -------------------------------------------------------------------------------- /core/test/ParaGridIO_input_test.nc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nextsimhub/nextsimdg/e058710be13d326489b4c1774e79136a76b405fc/core/test/ParaGridIO_input_test.nc -------------------------------------------------------------------------------- /core/test/PrognosticDataTestModules/moduleLoaderAssignments.ipp: -------------------------------------------------------------------------------- 1 | if (module == "Nextsim::IFreezingPoint") { 2 | if (impl == "Nextsim::LinearFreezing") { 3 | p_IFreezingPoint = &i_LinearFreezing; 4 | pf_IFreezingPoint = &newLinearFreezing; 5 | } else if (impl == "Nextsim::UnescoFreezing") { 6 | p_IFreezingPoint = &i_UnescoFreezing; 7 | pf_IFreezingPoint = &newUnescoFreezing; 8 | } else { 9 | throwup(module, impl); 10 | } 11 | 12 | } else { 13 | } 14 | -------------------------------------------------------------------------------- /core/test/PrognosticDataTestModules/moduleLoaderFunctions.ipp: -------------------------------------------------------------------------------- 1 | static Nextsim::IFreezingPoint* p_IFreezingPoint; 2 | template <> Nextsim::IFreezingPoint& ModuleLoader::getImplementation() { return *p_IFreezingPoint; } 3 | std::unique_ptr (*pf_IFreezingPoint)(); 4 | template <> std::unique_ptr ModuleLoader::getInstance() const 5 | { 6 | return (*pf_IFreezingPoint)(); 7 | } 8 | static Nextsim::LinearFreezing i_LinearFreezing; 9 | std::unique_ptr newLinearFreezing() 10 | { 11 | return std::unique_ptr(new Nextsim::LinearFreezing); 12 | } 13 | static Nextsim::UnescoFreezing i_UnescoFreezing; 14 | std::unique_ptr newUnescoFreezing() 15 | { 16 | return std::unique_ptr(new Nextsim::UnescoFreezing); 17 | } 18 | -------------------------------------------------------------------------------- /core/test/PrognosticDataTestModules/moduleLoaderHeaders.ipp: -------------------------------------------------------------------------------- 1 | #include "include/IFreezingPoint.hpp" 2 | #include "include/LinearFreezing.hpp" 3 | #include "include/UnescoFreezing.hpp" 4 | -------------------------------------------------------------------------------- /core/test/PrognosticDataTestModules/moduleLoaderNames.ipp: -------------------------------------------------------------------------------- 1 | m_availableImplementationNames = { 2 | { "Nextsim::IFreezingPoint", 3 | { 4 | "Nextsim::LinearFreezing", 5 | "Nextsim::UnescoFreezing", 6 | } }, 7 | }; 8 | -------------------------------------------------------------------------------- /core/test/PrognosticDataTestModules/modules.json: -------------------------------------------------------------------------------- 1 | // Illustrative only. The ipp files in this subdirectory were not generated 2 | // using the moduleloader_builder.py script 3 | [ 4 | { 5 | "name": "IFreezingPoint", 6 | "implementations": [ 7 | "LinearFreezing", 8 | "UnescoFreezing" 9 | ] 10 | } 11 | ] -------------------------------------------------------------------------------- /core/test/iodef.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | true 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /core/test/partition_metadata_2.cdl: -------------------------------------------------------------------------------- 1 | netcdf partition_metadata_2 { 2 | dimensions: 3 | NX = 10 ; 4 | NY = 9 ; 5 | P = 2 ; 6 | T = 1 ; 7 | B = 1 ; 8 | L = UNLIMITED ; // (0 currently) 9 | R = UNLIMITED ; // (0 currently) 10 | 11 | group: bounding_boxes { 12 | variables: 13 | int domain_x(P) ; 14 | int domain_y(P) ; 15 | int domain_extent_x(P) ; 16 | int domain_extent_y(P) ; 17 | data: 18 | 19 | domain_x = 0, 4 ; 20 | 21 | domain_y = 0, 0 ; 22 | 23 | domain_extent_x = 4, 6 ; 24 | 25 | domain_extent_y = 9, 9 ; 26 | } // group bounding_boxes 27 | 28 | group: connectivity { 29 | variables: 30 | int top_neighbors(P) ; 31 | int top_neighbor_ids(T) ; 32 | int top_neighbor_halos(T) ; 33 | int bottom_neighbors(P) ; 34 | int bottom_neighbor_ids(B) ; 35 | int bottom_neighbor_halos(B) ; 36 | int left_neighbors(P) ; 37 | int left_neighbor_ids(L) ; 38 | int left_neighbor_halos(L) ; 39 | int right_neighbors(P) ; 40 | int right_neighbor_ids(R) ; 41 | int right_neighbor_halos(R) ; 42 | data: 43 | 44 | top_neighbors = 0, 1 ; 45 | 46 | top_neighbor_ids = 0 ; 47 | 48 | top_neighbor_halos = 9 ; 49 | 50 | bottom_neighbors = 1, 0 ; 51 | 52 | bottom_neighbor_ids = 1 ; 53 | 54 | bottom_neighbor_halos = 9 ; 55 | 56 | left_neighbors = 0, 0 ; 57 | 58 | right_neighbors = 0, 0 ; 59 | } // group connectivity 60 | } 61 | -------------------------------------------------------------------------------- /core/test/partition_metadata_3.cdl: -------------------------------------------------------------------------------- 1 | netcdf partition_metadata_3 { 2 | dimensions: 3 | NX = 5 ; 4 | NY = 7 ; 5 | P = 3 ; 6 | T = 2 ; 7 | B = 2 ; 8 | L = 1 ; 9 | R = 1 ; 10 | 11 | group: bounding_boxes { 12 | variables: 13 | int domain_x(P) ; 14 | int domain_y(P) ; 15 | int domain_extent_x(P) ; 16 | int domain_extent_y(P) ; 17 | data: 18 | 19 | domain_x = 0, 0, 3 ; 20 | 21 | domain_y = 0, 3, 0 ; 22 | 23 | domain_extent_x = 3, 3, 2 ; 24 | 25 | domain_extent_y = 3, 4, 7 ; 26 | } // group bounding_boxes 27 | 28 | group: connectivity { 29 | variables: 30 | int top_neighbors(P) ; 31 | int top_neighbor_ids(T) ; 32 | int top_neighbor_halos(T) ; 33 | int bottom_neighbors(P) ; 34 | int bottom_neighbor_ids(B) ; 35 | int bottom_neighbor_halos(B) ; 36 | int left_neighbors(P) ; 37 | int left_neighbor_ids(L) ; 38 | int left_neighbor_halos(L) ; 39 | int right_neighbors(P) ; 40 | int right_neighbor_ids(R) ; 41 | int right_neighbor_halos(R) ; 42 | data: 43 | 44 | top_neighbors = 0, 0, 2 ; 45 | 46 | top_neighbor_ids = 0, 1 ; 47 | 48 | top_neighbor_halos = 3, 4 ; 49 | 50 | bottom_neighbors = 1, 1, 0 ; 51 | 52 | bottom_neighbor_ids = 2, 2 ; 53 | 54 | bottom_neighbor_halos = 3, 4 ; 55 | 56 | left_neighbors = 0, 1, 0 ; 57 | 58 | left_neighbor_ids = 0 ; 59 | 60 | left_neighbor_halos = 3 ; 61 | 62 | right_neighbors = 1, 0, 0 ; 63 | 64 | right_neighbor_ids = 1 ; 65 | 66 | right_neighbor_halos = 3 ; 67 | } // group connectivity 68 | } 69 | -------------------------------------------------------------------------------- /core/test/testHelpConfig.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # Test the output of the NextSIM configuration help 4 | 5 | # Check that nextsim exists 6 | if [ ! -f nextsim ]; then 7 | echo "nextsim binary not found!" 8 | pwd 9 | exit 1 10 | fi 11 | 12 | # Get the help text. This will be produced in the case of unrecognized command 13 | # line arguments. 14 | HELP_TEXT=`./nextsim --help 2>&1` 15 | 16 | # Check that the --help-config option exists. That is, doesn't produce the same 17 | # output as HELP_TEXT. 18 | HELPCFG_TEXT=`./nextsim --help-config 2>&1` 19 | 20 | if [ "$HELP_TEXT" == "$HELPCFG_TEXT" ]; then 21 | echo "Test failed: --help-config option not recognized." 22 | exit 1 23 | else 24 | echo "Test passed: --help-config option recognized." 25 | fi 26 | 27 | # Check the text produced by an implicit argument and by an argument of 'all' 28 | # are the same 29 | 30 | HELPALL_TEXT=`./nextsim --help-config all 2>&1` 31 | 32 | if [ "$HELPALL_TEXT" == "$HELPCFG_TEXT" ]; then 33 | echo "Test passed: implicit value accepted." 34 | else 35 | echo "Test failed: implicit value not accepted." 36 | exit 1 37 | fi 38 | 39 | # Check that CCSMIceAlbedo is listed in the 'avail'able configurable classes 40 | 41 | HELPAVAIL_TEXT=`./nextsim --help-config avail 2>&1` 42 | 43 | if [[ "$HELPAVAIL_TEXT" == *"CCSMIceAlbedo"* ]]; then 44 | echo "Test passed: CCSMIceAlbedo has configuration help." 45 | else 46 | echo "Test failed: CCSMIceAlbedo is not listed as having configuration help." 47 | exit 1 48 | fi 49 | 50 | # Check the CCSMIceAlbedo help. This does depend on the CCSMIceAlbedo class not 51 | # being changed too much 52 | HELPCCSM_TEXT=`./nextsim --help-config CCSMIceAlbedo 2>&1` 53 | 54 | if [[ "$HELPCCSM_TEXT" == *"CCSMIceAlbedo.iceAlbedo"* ]] && 55 | [[ "$HELPCCSM_TEXT" == *"CCSMIceAlbedo.snowAlbedo"* ]]; then 56 | echo "Test passed: CCSMIceAlbedo configuration help contains the expected fields." 57 | else 58 | echo "Test failed: CCSMIceAlbedo configuration help does not contain the expected fields." 59 | exit 1 60 | fi -------------------------------------------------------------------------------- /core/test/testmodelarraydetails/include/ModelArrayDetails.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file ModelArrayDetails.hpp 3 | * 4 | * @date 24 Sep 2024 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef MODELARRAYDETAILS_HPP 9 | #define MODELARRAYDETAILS_HPP 10 | 11 | enum class Dimension { X, Y, Z, U, COMP, COUNT }; 12 | 13 | enum class Type { 14 | ONED, 15 | TWOD, 16 | ZUFIELD, 17 | THREED, 18 | FOURD, 19 | TWOCOMP, 20 | }; 21 | 22 | static const Type AdvectionType = Type::TWOCOMP; 23 | 24 | static ModelArray OneDField() { return ModelArray(Type::ONED); } 25 | static ModelArray TwoDField() { return ModelArray(Type::TWOD); } 26 | static ModelArray ZUField() { return ModelArray(Type::ZUFIELD); } 27 | static ModelArray ThreeDField() { return ModelArray(Type::THREED); } 28 | static ModelArray FourDField() { return ModelArray(Type::FOURD); } 29 | 30 | #endif /* MODELARRAYDETAILS_HPP */ 31 | -------------------------------------------------------------------------------- /core/test/testmodelarraydetails/include/ModelArrayTypedefs.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file ModelArrayTypedefs.hpp 3 | * 4 | * @date Oct 19, 2022 5 | * @author Tim Spain 6 | */ 7 | 8 | typedef ModelArray OneDField; 9 | typedef ModelArray TwoDField; 10 | typedef ModelArray ZUField; 11 | typedef ModelArray ThreeDField; 12 | typedef ModelArray FourDField; 13 | -------------------------------------------------------------------------------- /core/test/xios_test_partition_metadata_2.cdl: -------------------------------------------------------------------------------- 1 | netcdf xios_test_partition_metadata_2 { 2 | dimensions: 3 | NX = 4 ; 4 | NY = 2 ; 5 | P = 2 ; 6 | T = UNLIMITED ; // (0 currently) 7 | B = UNLIMITED ; // (0 currently) 8 | L = 1 ; 9 | R = 1 ; 10 | 11 | group: bounding_boxes { 12 | variables: 13 | int domain_x(P) ; 14 | int domain_y(P) ; 15 | int domain_extent_x(P) ; 16 | int domain_extent_y(P) ; 17 | data: 18 | 19 | domain_x = 0, 2 ; 20 | 21 | domain_y = 0, 0 ; 22 | 23 | domain_extent_x = 2, 2 ; 24 | 25 | domain_extent_y = 2, 2 ; 26 | } // group bounding_boxes 27 | 28 | group: connectivity { 29 | variables: 30 | int top_neighbors(P) ; 31 | int top_neighbor_ids(T) ; 32 | int top_neighbor_halos(T) ; 33 | int bottom_neighbors(P) ; 34 | int bottom_neighbor_ids(B) ; 35 | int bottom_neighbor_halos(B) ; 36 | int left_neighbors(P) ; 37 | int left_neighbor_ids(L) ; 38 | int left_neighbor_halos(L) ; 39 | int right_neighbors(P) ; 40 | int right_neighbor_ids(R) ; 41 | int right_neighbor_halos(R) ; 42 | data: 43 | 44 | top_neighbors = 0, 0 ; 45 | 46 | bottom_neighbors = 0, 0 ; 47 | 48 | left_neighbors = 0, 1 ; 49 | 50 | left_neighbor_ids = 0 ; 51 | 52 | left_neighbor_halos = 2 ; 53 | 54 | right_neighbors = 1, 0 ; 55 | 56 | right_neighbor_ids = 1 ; 57 | 58 | right_neighbor_halos = 2 ; 59 | } // group connectivity 60 | } 61 | -------------------------------------------------------------------------------- /docs/api/class.rst: -------------------------------------------------------------------------------- 1 | .. Copyright (c) 2021, Nansen Environmental and Remote Sensing Center 2 | 3 | Classes 4 | ------- 5 | 6 | .. doxygenclass:: nextsim::model 7 | :project: nextsimdg 8 | :members: 9 | -------------------------------------------------------------------------------- /docs/api/counttimercpp.rst: -------------------------------------------------------------------------------- 1 | .. Copyright (c) 2021, Nansen Environmental and Remote Sensing Center 2 | 3 | CountTimer.cpp 4 | -------------- 5 | 6 | 7 | .. doxygenfile:: CountTimer.cpp 8 | :project: nextsimdg 9 | :members: 10 | -------------------------------------------------------------------------------- /docs/api/function.rst: -------------------------------------------------------------------------------- 1 | .. Copyright (c) 2021, Nansen Environmental and Remote Sensing Center 2 | 3 | Functions 4 | --------- 5 | 6 | .. doxygenfunction:: 7 | -------------------------------------------------------------------------------- /docs/api/index.rst: -------------------------------------------------------------------------------- 1 | .. Copyright (c) 2021, Nansen Environmental and Remote Sensing Center 2 | 3 | Index 4 | ----- 5 | 6 | .. doxygenindex:: 7 | :project: nextsimdg 8 | :outline: 9 | :no-link: 10 | -------------------------------------------------------------------------------- /docs/api/num.rst: -------------------------------------------------------------------------------- 1 | .. Copyright (c) 2021, Nansen Environmental and Remote Sensing Center 2 | 3 | Enumerator 4 | ---------- 5 | 6 | .. doxygenenum:: 7 | -------------------------------------------------------------------------------- /docs/api/structure.rst: -------------------------------------------------------------------------------- 1 | .. Copyright (c) 2021, Nansen Environmental and Remote Sensing Center 2 | 3 | Structure 4 | --------- 5 | 6 | .. doxygenstruct:: 7 | -------------------------------------------------------------------------------- /docs/api/typedef.rst: -------------------------------------------------------------------------------- 1 | .. Copyright (c) 2021, Nansen Environmental and Remote Sensing Center 2 | 3 | Typedef 4 | ------- 5 | 6 | .. doxygentypedef:: 7 | -------------------------------------------------------------------------------- /docs/changelog.rst: -------------------------------------------------------------------------------- 1 | .. Copyright (c) 2021, Nansen Environmental and Remote Sensing Center 2 | 3 | .. raw:: html 4 | 5 | 6 | 7 | Changelog 8 | ========= 9 | 10 | Have a look at neXtSIM_DG's `releases list`_. 11 | 12 | For more details, check neXtSIM_DG's `changelog`_. 13 | 14 | .. _releases list: https://github.com/nextsimdg/nextsimdg/releases 15 | .. _changelog: 16 | -------------------------------------------------------------------------------- /docs/changelog/README.md: -------------------------------------------------------------------------------- 1 | # Changelog generation 2 | 3 | A description of all the changes made to the nextsimdg code can automatically be generated anytime and is visible [here](CHANGELOG.md) 4 | 5 | To generate it, you need to download the code locally on your computer and you need to install the [github-changelog-generator](https://github.com/github-changelog-generator/github-changelog-generator). 6 | 7 | As described [here](https://github.com/Ic3fr0g/autochangelog-hook) you will also need the scripts gathered here : 8 | - the bash script [run_changelog.sh](run_changelog.sh) 9 | - the python script [clog.py](clog.py) 10 | 11 | When everything is ready, you run the run_changelog.sh script and it will produce the [changelog file](CHANGELOG.md) 12 | -------------------------------------------------------------------------------- /docs/changelog/clog.py: -------------------------------------------------------------------------------- 1 | import os 2 | import re 3 | import string 4 | 5 | # Prerequisites: 6 | # 7 | # github_changelog_generator repo -t token --date-format '%Y-%m-%d %H:%M' -o 'CHANGELOG.md' 8 | # git tag -l -n9 > a.txt 9 | # All tags should be of type 'v\d[\.\w]*' 10 | 11 | if __name__ == '__main__': 12 | with open('a.txt', 'r') as foo: 13 | data = foo.readlines() 14 | foo.close() 15 | tags_title_annotation = {} 16 | matched = None 17 | for line in data: 18 | if re.search('v\d[\.\w]*', line): 19 | matched = re.findall('v\d[\.\w]*', line)[0] 20 | tags_title_annotation[matched] = { 21 | 'title': '', 22 | 'annotation': [] 23 | } 24 | title = line.replace(matched, '').strip() 25 | title = title[0].upper() + title[1:] 26 | tags_title_annotation[matched]['title'] = title 27 | elif matched is not None: 28 | line = line.strip() 29 | annotation = line.replace(matched, '') 30 | tags_title_annotation[matched]['annotation'].append(annotation) 31 | 32 | with open('CHANGELOG.md', 'r') as fil: 33 | data = fil.readlines() 34 | fil.close() 35 | matched = None 36 | data_w = data 37 | for index, line in enumerate(data): 38 | if re.search('## \[v\d[\.\w]*\]', line): 39 | matched = re.findall('v\d[\.\w]*', line)[0] 40 | 41 | insert_data = [ 42 | "**Description:**", 43 | tags_title_annotation[matched]['title'] 44 | ] 45 | values = "\n" + \ 46 | "\n".join(insert_data) + \ 47 | "\n" + \ 48 | "\n".join(tags_title_annotation[matched]['annotation']) + \ 49 | "\n" 50 | data_w.insert(index + 1, values) 51 | 52 | with open('CHANGELOG.md', 'w') as fin: 53 | fin.writelines(data_w) 54 | fin.close() 55 | 56 | -------------------------------------------------------------------------------- /docs/changelog/run_changelog.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo "Generating CHANGELOG" && 3 | github_changelog_generator -u nextsimdg -p nextsimdg autochangelog-hook -t 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 && 4 | echo "Running python script" && 5 | git tag -l -n9 > a.txt && 6 | python3 clog.py && 7 | rm a.txt && 8 | echo "Done! Check CHANGELOG.md" 9 | -------------------------------------------------------------------------------- /docs/conda.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import os 5 | import subprocess 6 | 7 | on_rtd = os.environ.get('READTHEDOCS', None) == 'True' 8 | 9 | if on_rtd: 10 | subprocess.call('doxygen', shell=True) 11 | 12 | import sphinx_rtd_theme 13 | 14 | html_theme = "sphinx_rtd_theme" 15 | 16 | html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] 17 | 18 | def setup(app): 19 | app.add_css_file("main_stylesheet.css") 20 | 21 | extensions = ['breathe','exhale'] 22 | breathe_projects = { 'nextsimdg': 'xml' } 23 | breathe_default_project = "nextsimdg" 24 | # Setup the exhale extension 25 | exhale_args = { 26 | # These arguments are required 27 | "containmentFolder": "./api", 28 | "rootFileName": "library_root.rst", 29 | "rootFileTitle": "Library API", 30 | "doxygenStripFromPath": "..", 31 | "createTreeView": True, 32 | } 33 | templates_path = ['_templates'] 34 | html_extra_path = ['xml'] 35 | source_suffix = '.rst' 36 | master_doc = 'index' 37 | project = 'nextsimdg' 38 | copyright = '2023, Nansen Environmental and Remote Sensing Center' 39 | author = 'Nansen Environmental and Remote Sensing Center' 40 | 41 | exclude_patterns = [] 42 | highlight_language = 'c++' 43 | pygments_style = 'sphinx' 44 | todo_include_todos = False 45 | htmlhelp_basename = 'nextsimdgdoc' 46 | -------------------------------------------------------------------------------- /docs/environment.yml: -------------------------------------------------------------------------------- 1 | name: netxsimdg-docs 2 | 3 | channels: 4 | - conda-forge 5 | 6 | dependencies: 7 | - breathe 8 | - Jinja2<3.1 9 | - pip : 10 | - exhale 11 | -------------------------------------------------------------------------------- /docs/model-components.rst: -------------------------------------------------------------------------------- 1 | .. Copyright (c) 2021, Nansen Environmental and Remote Sensing Center 2 | 3 | .. raw:: html 4 | 5 | 6 | 7 | Model Components 8 | ================ 9 | 10 | Page under construction 11 | 12 | Ice dynamics 13 | ------------ 14 | 15 | Ice thermodynamics 16 | ------------------ 17 | 18 | Ice-atmosphere interface 19 | ------------------------ 20 | 21 | Ice-ocean interface 22 | ------------------- 23 | 24 | Coupling interface 25 | ------------------ 26 | -------------------------------------------------------------------------------- /docs/modules.rst: -------------------------------------------------------------------------------- 1 | Modules 2 | ======= 3 | 4 | Rationale 5 | --------- 6 | 7 | One of the key features of nextSIM-DG is the run-time modularity of the code. This is designed to allow a user to change the parameterizations the model uses without having to recompile. Instead, many parameterizations and model components can be changed by changing the configuration, either in the config file or by providing overrides on the command line. The nextSIM-DG module system is designed to do this with a minimal impact on the performance of the model. 8 | 9 | Usage 10 | ----- 11 | 12 | To use the module system to change the model configuration from its defaults, the user needs to provide additional configuration values to the model. These can be permanently edited into the initial config file or provided as override on the command line. The modules section of the config file starts with the section title ``[Modules]``. Below this are key-value pairs, one per line with the format ``key = value``. The key is the name of the directory that contains the module. This will be a subdirectory of one of the ``modules`` subdirectories in the nextSIM-DG code tree. An example of this is the subdirectory ``core/src/modules/DiagnosticOutputModule`` which would be in the config file as the key ``DiagnosticOutputModule =``. The value following the equals sign is then one of the implementations of the module. The names of these can be obtained from the online help system accessible using the command line argument ``--config-help`` as well as the relevant file in this documentation directory. 13 | 14 | -------------------------------------------------------------------------------- /docs/numerical-implementation.rst: -------------------------------------------------------------------------------- 1 | .. Copyright (c) 2021, Nansen Environmental and Remote Sensing Center 2 | 3 | .. raw:: html 4 | 5 | 6 | Numerical Implementation 7 | ======================== 8 | 9 | Page under construction 10 | 11 | 12 | Discretization and algorithms 13 | ----------------------------- 14 | 15 | Coding rules 16 | ------------ 17 | -------------------------------------------------------------------------------- /docs/outputs-diagnostics.rst: -------------------------------------------------------------------------------- 1 | .. Copyright (c) 2021, Nansen Environmental and Remote Sensing Center 2 | 3 | .. raw:: html 4 | 5 | 6 | 7 | Outputs and diagnostics 8 | ======================= 9 | 10 | Page under construction 11 | -------------------------------------------------------------------------------- /docs/overview.rst: -------------------------------------------------------------------------------- 1 | .. Copyright (c) 2021, Nansen Environmental and Remote Sensing Center 2 | 3 | .. raw:: html 4 | 5 | 6 | 7 | Model Overview 8 | ============== 9 | Page under construction 10 | -------------------------------------------------------------------------------- /docs/slab_ocean.rst: -------------------------------------------------------------------------------- 1 | .. Copyright (c) 2023, Nansen Environmental and Remote Sensing Center 2 | 3 | The neXtSIM_DG Slab Ocean Model 4 | =============================== 5 | 6 | Introduction 7 | ------------ 8 | 9 | The slab ocean of neXtSIM_DG exists to ensure consistency between the 10 | conditions that the ice is experiencing and the ocean forcing applied to the model. 11 | 12 | The slab ocean was first implemented in the Lagrangian version of neXtSIM 13 | `(Rampal et al., 2016)`_ where the implementation benefitted from the monolithic 14 | nature of the model core, allowing values to be calculated in whatever order 15 | they needed to be. The modular design of neXtSIM_DG necessitated a close look 16 | at the flow of data through the parts of the model that interact with the slab 17 | ocean. These, along with the overall slab model, are described in this document. 18 | 19 | .. (Rampal et al., 2016) Rampal, P., Bouillon, S., Ólason, E., and 20 | Morlighem, M., neXtSIM: a new Lagrangian sea ice model, *Cryosphere*, 21 | **10** 1055—1073 (2016) 22 | 23 | Definitions 24 | ----------- 25 | 26 | The model timestep begins at time *t₀* and integrates the model for a 27 | period *δt* to the end of the timestep at *t₁*. The previous iteration of the 28 | model, along with the forcing or coupling, provides the values of several 29 | variables at *t* = *t₀*. The dynamics component of the model then advects these 30 | values to time *t₁*, whereupon the physics part of the model attempts to update 31 | the prognostic data fields to new values consistent with the motion due to the 32 | dynamics and the effect of the passage of time on the model state. 33 | 34 | .. The slab ocean functions by having two timescales over which the corrections apply, timeT and timeS -------------------------------------------------------------------------------- /docs/source/installation.rst: -------------------------------------------------------------------------------- 1 | .. Copyright (c) 2021, Nansen Environmental and Remote Sensing Center 2 | 3 | Installation 4 | ============ 5 | 6 | You can install neXtSIM_DG using the following methods 7 | 8 | 9 | .. image:: conda.svg 10 | 11 | Using the conda-forge package 12 | ----------------------------- 13 | 14 | A package for xtensor is available on the mamba (or conda) package manager. 15 | 16 | .. code:: 17 | 18 | mamba install -c conda-forge xtensor 19 | -------------------------------------------------------------------------------- /dynamics/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(src) 2 | 3 | if(BUILD_TESTS) 4 | enable_testing() 5 | add_subdirectory(test) 6 | endif() 7 | 8 | set(NextsimSources "${NextsimSources}" PARENT_SCOPE) 9 | 10 | set(NextsimIncludeDirs "${NextsimIncludeDirs}" PARENT_SCOPE) 11 | -------------------------------------------------------------------------------- /dynamics/ParametricMesh/createdistortedboxmesh.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Sat Jul 9 14:53:04 2022 5 | 6 | Creates a simple mesh of size [0,Lx] x [0,Ly] 7 | with Nx x Ny elements 8 | 9 | The mesh is slightly distorted 10 | 11 | @author: richter 12 | """ 13 | 14 | # Size of the domain 15 | Lx = 1000000 16 | Ly = 1000000 17 | 18 | # Number of elements 19 | nx = 32 20 | ny = 32 21 | 22 | 23 | import numpy as np 24 | 25 | def distx(x,y): 26 | return np.sin(3.0*np.pi*x/Lx)*np.sin(2.0*np.pi*y/Ly) 27 | 28 | def disty(x,y): 29 | return np.sin(np.pi*x/Lx)*np.sin(3.0*np.pi*y/Ly) 30 | 31 | 32 | 33 | sx = 0.05*Lx 34 | sy = 0.05*Ly 35 | 36 | #sx,sy = 0,0 37 | 38 | f = open("distortedbox.smesh", "w") 39 | f.write("ParametricMesh 1.0\n") 40 | f.write('{0}\t{1}\n'.format(nx,ny)) 41 | for y in np.linspace(0,Ly,ny+1): 42 | for x in np.linspace(0,Lx,nx+1): 43 | f.write('{0}\t{1}\n'.format(x+sx*distx(x,y),y+sy*disty(x,y))) 44 | 45 | f.close() 46 | -------------------------------------------------------------------------------- /dynamics/ParametricMesh/createdistortedrectanglemesh.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Sat Jul 9 14:53:04 2022 5 | 6 | Creates a simple mesh of size [0,Lx] x [0,Ly] 7 | with Nx x Ny elements 8 | 9 | The mesh is slightly distorted 10 | 11 | @author: richter 12 | """ 13 | 14 | # Size of the domain 15 | Lx = 512000 16 | Ly = 512000 17 | 18 | # Number of elements 19 | 20 | nx = ny = 256 21 | 22 | import numpy as np 23 | 24 | def distx(x,y): 25 | return np.sin(3.0*np.pi*x/Lx)*np.sin(2.0*np.pi*y/Ly) 26 | 27 | def disty(x,y): 28 | return np.sin(np.pi*x/Lx)*np.sin(3.0*np.pi*y/Ly) 29 | 30 | 31 | 32 | sx = 0.05*Lx 33 | sy = 0.05*Ly 34 | 35 | sx,sy = 0,0 36 | 37 | 38 | 39 | 40 | for i in range(5): 41 | 42 | nx = ny = 2**(i+5) 43 | 44 | f = open(f"distortedrectangle_{nx}x{ny}.smesh", "w") 45 | f.write("ParametricMesh 1.0\n") 46 | f.write('{0}\t{1}\n'.format(nx,ny)) 47 | for y in np.linspace(0,Ly,ny+1): 48 | for x in np.linspace(0,Lx,nx+1): 49 | f.write('{0}\t{1}\n'.format(x+sx*distx(x,y),y+sy*disty(x,y))) 50 | 51 | f.close() 52 | 53 | -------------------------------------------------------------------------------- /dynamics/ParametricMesh/readme.txt: -------------------------------------------------------------------------------- 1 | python scripts to generate example meshes and mesh files 2 | -------------------------------------------------------------------------------- /dynamics/codegeneration/gaussquadrature.py: -------------------------------------------------------------------------------- 1 | ## module used in the code-generation scripts 2 | 3 | import numpy as np 4 | 5 | 6 | ### Gauss quadrature 7 | gausspoints = np.array([ 8 | [0.5,0,0,0], 9 | [0.5-np.sqrt(1./12.),0.5+np.sqrt(1./12.),0,0], 10 | [0.5-np.sqrt(3./20.),0.5,0.5+np.sqrt(3./20.),0], 11 | [0.5-0.5*np.sqrt(3./7.+2./7.*np.sqrt(6./5.)), 12 | 0.5-0.5*np.sqrt(3./7.-2./7.*np.sqrt(6./5.)), 13 | 0.5+0.5*np.sqrt(3./7.-2./7.*np.sqrt(6./5.)), 14 | 0.5+0.5*np.sqrt(3./7.+2./7.*np.sqrt(6./5.))]]) 15 | 16 | gaussweights = np.array([ 17 | [1.0,0,0,0], 18 | [0.5,0.5,0,0], 19 | [5./18.,8./18.,5./18.,0], 20 | [(18.-np.sqrt(30.0))/72., 21 | (18.+np.sqrt(30.0))/72., 22 | (18.+np.sqrt(30.0))/72., 23 | (18.-np.sqrt(30.0))/72.]]) 24 | 25 | ### LagrangeQuadrature (Trapez / Simpson) 26 | lagrangepoints = np.array([ 27 | [0.0,1.0,0,0], 28 | [0.0,0.5,1,0]]) 29 | 30 | lagrangeweights = np.array([ 31 | [0.5,0.5,0.0], 32 | [1./6.,2./3.,1./5.]]) 33 | 34 | def sanitycheck_gauss(): 35 | for p in range(10): # integrate x^p for p=0,1,2,...,9 36 | ex = 1.0/(1.0+p) 37 | # print("Integrate x^{0} over [0,1]: ".format(p),end='') 38 | 39 | for q in range(4): # gauss 1,2,3,4 40 | gi = 0.0 41 | for k in range(q+1): 42 | gi = gi + gaussweights[q,k] * gausspoints[q,k]**p 43 | if np.fabs(gi-ex)>1.e-14: 44 | assert p>=2*(q+1), 'Gauss rule should be exact' 45 | -------------------------------------------------------------------------------- /dynamics/codegeneration/run.sh: -------------------------------------------------------------------------------- 1 | python3 codeGenerationDGinGauss.py > ../src/include/codeGenerationDGinGauss.hpp 2 | python3 codeGenerationCGToDG.py > ../src/include/codeGenerationCGToDG.hpp 3 | 4 | python3 codeGenerationParametricMesh.py > ../src/include/codeGenerationParametricMesh.hpp 5 | python3 codeGenerationCGinGauss.py > ../src/include/codeGenerationCGinGauss.hpp 6 | 7 | 8 | -------------------------------------------------------------------------------- /dynamics/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(ModuleDir "${CMAKE_CURRENT_SOURCE_DIR}/modules") 2 | 3 | set(IncludeDir "${CMAKE_CURRENT_SOURCE_DIR}/include") 4 | 5 | ### Set the list of all cpp files 6 | file(GLOB DynamicsSources *.cpp) 7 | 8 | set(NextsimSources 9 | "${NextsimSources}" 10 | "${Sources}" 11 | "${ModuleSources}" 12 | "${DynamicsSources}" 13 | PARENT_SCOPE 14 | ) 15 | 16 | set(NextsimIncludeDirs 17 | "${NextsimIncludeDirs}" 18 | "${ModuleDir}" 19 | "${IncludeDir}" 20 | "${CMAKE_CURRENT_SOURCE_DIR}" 21 | PARENT_SCOPE 22 | ) 23 | -------------------------------------------------------------------------------- /dynamics/src/DummyDynamicsKernel.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file DummyDynamicsKernel.cpp 3 | * 4 | * @date 17 Feb 2023 5 | * @author Tim Spain 6 | */ 7 | 8 | #include "include/DummyDynamicsKernel.hpp" 9 | 10 | namespace Nextsim { 11 | 12 | template 13 | const std::unordered_map 14 | DummyDynamicsKernel::fieldType = { 15 | 16 | }; 17 | 18 | } /* namespace Nextsim */ 19 | -------------------------------------------------------------------------------- /dynamics/src/DynamicsKernel.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file DynamicsKernel.cpp 3 | * 4 | * @date Jan 31, 2024 5 | * @author Tim Spain 6 | */ 7 | 8 | #include "include/DynamicsKernel.hpp" 9 | 10 | namespace Nextsim { 11 | 12 | template class DynamicsKernel<1, 3>; 13 | template class DynamicsKernel<1, 8>; 14 | 15 | template class DynamicsKernel<3, 3>; 16 | template class DynamicsKernel<3, 8>; 17 | 18 | template class DynamicsKernel<6, 3>; 19 | template class DynamicsKernel<6, 8>; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /dynamics/src/MEVPStressUpdateStep.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file MEVPStressUpdateStep.cpp 3 | * 4 | * @date Feb 1, 2024 5 | * @author Tim Spain 6 | */ 7 | 8 | #include "MEVPStressUpdateStep.hpp" 9 | 10 | namespace Nextsim { 11 | 12 | } /* namespace Nextsim */ 13 | -------------------------------------------------------------------------------- /dynamics/src/VectorManipulations.cpp: -------------------------------------------------------------------------------- 1 | #include "VectorManipulations.hpp" 2 | 3 | template void Nextsim::VectorManipulations::CGAveragePeriodic(const ParametricMesh&, CGVector<1>&); 4 | template void Nextsim::VectorManipulations::CGAveragePeriodic(const ParametricMesh&, CGVector<2>&); 5 | template void Nextsim::VectorManipulations::CGAddPeriodic(const ParametricMesh&, CGVector<1>&); 6 | template void Nextsim::VectorManipulations::CGAddPeriodic(const ParametricMesh&, CGVector<2>&); 7 | -------------------------------------------------------------------------------- /dynamics/src/include/BBMDynamicsKernel.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file BBMDynamicsKernel.hpp 3 | * 4 | * @date 09 Nov 2024 5 | * @author Tim Spain 6 | * @author Piotr Minakowski 7 | */ 8 | 9 | #ifndef BBMDYNAMICSKERNEL_HPP 10 | #define BBMDYNAMICSKERNEL_HPP 11 | 12 | #include "BrittleCGDynamicsKernel.hpp" 13 | 14 | #include "BBMStressUpdateStep.hpp" 15 | 16 | namespace Nextsim { 17 | 18 | template class BBMDynamicsKernel : public BrittleCGDynamicsKernel { 19 | public: 20 | // using DynamicsKernel::momentum; 21 | using DynamicsKernel::hice; 22 | using DynamicsKernel::cice; 23 | using CGDynamicsKernel::pmap; 24 | using BrittleCGDynamicsKernel::damage; 25 | using CGDynamicsKernel::initialise; 26 | BBMDynamicsKernel(const BBMParameters& paramsIn) 27 | : BrittleCGDynamicsKernel(bbmStressStep, paramsIn) 28 | { 29 | } 30 | 31 | void initialise(const ModelArray& coords, bool isSpherical, const ModelArray& mask) override 32 | { 33 | BrittleCGDynamicsKernel::initialise(coords, isSpherical, mask); 34 | bbmStressStep.setPMap(pmap.get()); 35 | bbmStressStep.setDamage(damage); 36 | } 37 | 38 | private: 39 | // BBM stress update class 40 | BBMStressUpdateStep bbmStressStep; 41 | }; 42 | 43 | } /* namespace Nextsim */ 44 | 45 | #endif /* BBMDYNAMICSKERNEL_HPP */ 46 | -------------------------------------------------------------------------------- /dynamics/src/include/BBMParameters.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file BBMParameters.hpp 3 | * @date 19 Nov 2024 4 | * @author Tim Spain 5 | * @author Piotr Minakowski 6 | */ 7 | 8 | #ifndef __MEBPARAMETERS_HPP 9 | #define __MEBPARAMETERS_HPP 10 | 11 | #include "DynamicsParameters.hpp" 12 | 13 | namespace Nextsim { 14 | 15 | // static double compactionParamDefault = -20.; //!< Compation parameter 16 | static double nu0Default = 1. / 3.; //!< \param Poisson's ratio 17 | static double youngDefault = 5.96e8; //!< \param Young's modulus 18 | static double P0Default = 10e3; //! < \param Constant to parametrize Pmax 19 | static double lambda0Default = 1e7; //!< \param lambda 20 | static int alphaDefault = 5; 21 | static double expPMaxDefault = 1.5; //! \param Power of ice thickness in the pressure coefficient 22 | static double muDefault = 0.7; //!< \param tan_phi (double) Internal friction coefficient (mu) 23 | static double comprCapDefault 24 | = 1e10; //! \param compr_strength (double) Maximum compressive strength [N/m2] 25 | static double cLabDefault = 2e6; //! \param C_lab (double) Test [Pa] 26 | // static const int nStepsDefault = 120; //!< Number of sub-steps 27 | 28 | class BBMParameters : public DynamicsParameters { 29 | 30 | public: 31 | BBMParameters() = default; 32 | 33 | double compactionParam = compactionParamDefault; 34 | double nu0 = nu0Default; 35 | double young = youngDefault; 36 | double P0 = P0Default; 37 | double lambda0 = lambda0Default; 38 | int alpha = alphaDefault; 39 | double expPMax = expPMaxDefault; 40 | double mu = muDefault; 41 | double comprCap = comprCapDefault; 42 | double cLab = cLabDefault; 43 | int nSteps = nStepsDefault; 44 | 45 | double c0 = 10e3; //! \param 46 | }; 47 | 48 | } /* namespace Nextsim */ 49 | 50 | #endif /* __MEB_HPP */ 51 | -------------------------------------------------------------------------------- /dynamics/src/include/CGModelArray.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file CGModelArray.hpp 3 | * 4 | * @date Oct 13, 2022 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef CGMODELARRAY_HPP 9 | #define CGMODELARRAY_HPP 10 | 11 | #include "Interpolations.hpp" 12 | #include "cgVector.hpp" 13 | 14 | #include "include/ModelArray.hpp" 15 | 16 | namespace Nextsim { 17 | 18 | class CGModelArray { 19 | public: 20 | template static CGVector& ma2cg(const ModelArray& ma, CGVector& cg) 21 | { 22 | cg = ma.data().matrix(); 23 | //! Interpolation of DG0 to CGVector 24 | // Nextsim::Interpolations::DG2CG(smesh, cg, ma); 25 | return cg; 26 | } 27 | 28 | template static ModelArray& cg2ma(const CGVector& cg, ModelArray& ma) 29 | { 30 | ma.setData(cg.data()); 31 | return ma; 32 | } 33 | 34 | template static ModelArray::MultiDim cgDimensions(const ModelArray::MultiDim& hDims) 35 | { 36 | ModelArray::MultiDim cgDims(hDims); 37 | for (size_t i = 0; i < cgDims.size(); ++i) { 38 | cgDims[i] *= CG; 39 | ++cgDims[i]; 40 | } 41 | return cgDims; 42 | } 43 | }; 44 | } 45 | 46 | #endif /* CGMODELARRAY_HPP */ 47 | -------------------------------------------------------------------------------- /dynamics/src/include/DGModelArray.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file DGModelArray.hpp 3 | * 4 | * @date Oct 6, 2022 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef DGMODELARRAY_HPP 9 | #define DGMODELARRAY_HPP 10 | 11 | #include "dgVector.hpp" 12 | #include "include/ModelArray.hpp" 13 | 14 | #include 15 | 16 | namespace Nextsim { 17 | 18 | class DGModelArray { 19 | public: 20 | template static DGVector& ma2dg(const ModelArray& ma, DGVector& dg) 21 | { 22 | if (N == ma.components(0).size()) { 23 | dg = ma.data().matrix(); 24 | } else { 25 | // Assign only to the 0 component. 26 | dg.col(0) = ma.data().matrix(); 27 | } 28 | return dg; 29 | } 30 | 31 | template static ModelArray& dg2ma(const DGVector& dg, ModelArray& ma) 32 | { 33 | if (N == ma.components(0).size()) { 34 | ma.setData(dg.data()); 35 | } else { 36 | /* Assign the zero component as data. Since the setData function 37 | * takes a pointer to continuous data, the data needs to be copied 38 | * from the DGVector initially. 39 | */ 40 | ma.setData(dg.col(0)); 41 | } 42 | return ma; 43 | } 44 | 45 | template static DGVector& hField2dg(const HField& h, DGVector& dg) 46 | { 47 | dg.col(0) = h.data(); 48 | return dg; 49 | } 50 | 51 | template static HField& dg2hField(const DGVector& dg, HField& h) 52 | { 53 | h.setData(dg.col(0)); 54 | return h; 55 | } 56 | }; 57 | 58 | template <> inline DGVector<1>& DGModelArray::hField2dg(const HField& h, DGVector<1>& dg) 59 | { 60 | return ma2dg(h, dg); 61 | } 62 | 63 | template <> inline HField& DGModelArray::dg2hField(const DGVector<1>& dg, HField& h) 64 | { 65 | return dg2ma(dg, h); 66 | } 67 | } /* namespace Nextsim */ 68 | 69 | #endif /* DGMODELARRAY_HPP */ 70 | -------------------------------------------------------------------------------- /dynamics/src/include/DynamicsParameters.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file DynamicsParameters.hpp 3 | * 4 | * @date 19 Nov 2024 5 | * @author Tim Spain 6 | * @author Thomas Richter 7 | * 8 | */ 9 | 10 | #ifndef DYNAMICSPARAMETERS_HPP 11 | #define DYNAMICSPARAMETERS_HPP 12 | 13 | namespace Nextsim { 14 | 15 | static const double rhoIceDefault = 900.; //!< Sea ice density 16 | static const double rhoAtmDefault = 1.3; //!< Air density 17 | static const double rhoOceanDefault = 1026.; //!< Ocean density 18 | static const double CAtmDefault = 1.2e-3; //!< Air drag coefficient 19 | static const double COceanDefault = 5.5e-3; //!< Ocean drag coefficient 20 | static const double fcDefault = 1.45842e-4; //!< Coriolis 21 | static const double oceanTurningAngleDefault = 25.; //!< Ocean turning angle 22 | 23 | static const int nStepsDefault = 120; //!< number of sub-cycling steps 24 | static const double compactionParamDefault 25 | = -20.; //!< Compation parameter: Hibler's C in exp(-C(1-a)) 26 | 27 | class DynamicsParameters { 28 | 29 | public: 30 | DynamicsParameters() = default; 31 | 32 | double rhoIce = rhoIceDefault; 33 | double rhoAtm = rhoAtmDefault; 34 | double rhoOcean = rhoOceanDefault; 35 | 36 | double CAtm = CAtmDefault; 37 | double COcean = COceanDefault; 38 | 39 | double fc = fcDefault; 40 | 41 | double oceanTurningAngle = oceanTurningAngleDefault; 42 | }; 43 | } 44 | 45 | #endif /* DYNAMICSPARAMETERS_HPP */ 46 | -------------------------------------------------------------------------------- /dynamics/src/include/IDynamicsUpdate.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file IDynamicsUpdate.hpp 3 | * 4 | * @date Jan 19, 2024 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef IDYNAMICSUPDATE_HPP 9 | #define IDYNAMICSUPDATE_HPP 10 | 11 | #include "DynamicsParameters.hpp" 12 | #include "ParametricMesh.hpp" 13 | #include "dgVector.hpp" 14 | 15 | #include 16 | 17 | namespace Nextsim { 18 | 19 | class IDynamicsUpdate { 20 | protected: 21 | // static const size_t nSymMatrixEl = 3; 22 | public: 23 | enum SymMatrixEl { _11, _12, _22, nSymMatrixEl }; 24 | template 25 | void stressUpdateHighOrder(std::array, nSymMatrixEl> S, 26 | const std::array, nSymMatrixEl> E, const DGVector& A, 27 | DGVector& D, const double dt_mom) 28 | = 0; 29 | 30 | protected: 31 | inline constexpr double SQR(double x) { return x * x; } 32 | const DynamicsParameters& params; 33 | const ParametricMesh& smesh; 34 | }; 35 | 36 | } 37 | 38 | #endif /* IDYNAMICSUPDATE_HPP */ 39 | -------------------------------------------------------------------------------- /dynamics/src/include/MEVPDynamicsKernel.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file MEVPDynamicsKernel.hpp 3 | * 4 | * @date 17 Feb 2023 5 | * @author Tim Spain 6 | * @author Piotr Minakowski 7 | */ 8 | 9 | #ifndef MEVPDYNAMICSKERNEL_HPP 10 | #define MEVPDYNAMICSKERNEL_HPP 11 | 12 | #include "VPCGDynamicsKernel.hpp" 13 | 14 | #include "MEVPStressUpdateStep.hpp" 15 | 16 | namespace Nextsim { 17 | 18 | template class MEVPDynamicsKernel : public VPCGDynamicsKernel { 19 | public: 20 | using CGDynamicsKernel::pmap; 21 | using CGDynamicsKernel::initialise; 22 | MEVPDynamicsKernel(const VPParameters& paramsIn) 23 | : VPCGDynamicsKernel(MEVPStressStep, paramsIn) 24 | { 25 | } 26 | 27 | void initialise(const ModelArray& coords, bool isSpherical, const ModelArray& mask) override 28 | { 29 | CGDynamicsKernel::initialise(coords, isSpherical, mask); 30 | MEVPStressStep.setPMap(pmap.get()); 31 | } 32 | 33 | private: 34 | MEVPStressUpdateStep MEVPStressStep; 35 | }; 36 | 37 | } /* namespace Nextsim */ 38 | 39 | #endif /* MEVPDYNAMICSKERNEL_HPP */ 40 | -------------------------------------------------------------------------------- /dynamics/src/include/StressUpdateStep.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file StressUpdateStep.hpp 3 | * 4 | * @date Feb 1, 2024 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef STRESSUPDATESTEP_HPP 9 | #define STRESSUPDATESTEP_HPP 10 | 11 | #include 12 | #include 13 | 14 | #include "DynamicsParameters.hpp" 15 | #include "ParametricMesh.hpp" 16 | #include "dgVector.hpp" 17 | 18 | namespace Nextsim { 19 | 20 | template class StressUpdateStep { 21 | public: 22 | typedef std::array>, N_TENSOR_ELEMENTS> 23 | SymmetricTensorVector; 24 | 25 | static const int nGauss = (((DGstress == 8) || (DGstress == 6)) ? 3 : (DGstress == 3 ? 2 : -1)); 26 | StressUpdateStep() = default; 27 | virtual ~StressUpdateStep() = default; 28 | virtual void stressUpdateHighOrder(const DynamicsParameters& params, 29 | const ParametricMesh& smesh, SymmetricTensorVector& stress, 30 | const SymmetricTensorVector& strain, const DGVector& h, 31 | const DGVector& a, const double deltaT) 32 | = 0; 33 | }; 34 | 35 | } /* namespace Nextsim */ 36 | 37 | #endif /* STRESSUPDATESTEP_HPP */ 38 | -------------------------------------------------------------------------------- /dynamics/src/include/VPParameters.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file VPParameters.hpp 3 | * @date 19 Nov 2024 4 | * @author Tim Spain 5 | * @author Thomas Richter 6 | */ 7 | 8 | #ifndef __VPPARAMETERS_HPP 9 | #define __VPPARAMETERS_HPP 10 | 11 | #include "DynamicsParameters.hpp" 12 | 13 | namespace Nextsim { 14 | 15 | // static const int nStepsDefault = 100; //!< number of sub-cycling steps 16 | // static const double compactionParamDefault = -20.; //!< Compation parameter: Hibler's C in 17 | // exp(-C(1-a)) 18 | static const double pStarDefault = 27.5e3; //!< Ice strength 19 | static const double deltaMinDefault = 2e-9; //!< Viscous regime 20 | 21 | class VPParameters : public DynamicsParameters { 22 | 23 | public: 24 | VPParameters() = default; 25 | 26 | double compactionParam = compactionParamDefault; 27 | double pStar = pStarDefault; 28 | double deltaMin = deltaMinDefault; 29 | int nSteps = nStepsDefault; 30 | }; 31 | 32 | } /* namespace Nextsim */ 33 | 34 | #endif /* __VP_HPP */ 35 | -------------------------------------------------------------------------------- /dynamics/src/include/cgVector.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file cgVector.hpp 3 | * @date 1 Mar 2022 4 | * @author Thomas Richter 5 | */ 6 | 7 | #ifndef __CGVECTOR_HPP 8 | #define __CGVECTOR_HPP 9 | 10 | #include "ParametricMesh.hpp" 11 | #include 12 | #include 13 | 14 | namespace Nextsim { 15 | 16 | /*! 17 | * Stores a CG vector in std. Lagrangian Basis, e.g. having 18 | * (CGdegree*nx+1)*(CGdegree*ny+1) elements 19 | * Sorting lower left -> lower right -> ... -> upper right 20 | */ 21 | template class CGVector : public Eigen::Matrix { 22 | public: 23 | typedef Eigen::Matrix EigenCGVector; 24 | 25 | //! empty constructor 26 | CGVector() { } 27 | //! constructor setting size by mesh 28 | CGVector(const ParametricMesh& smesh) 29 | : EigenCGVector((CGdegree * smesh.nx + 1) * (CGdegree * smesh.ny + 1)) 30 | { 31 | } 32 | 33 | //! resizes the vector and sets it to the mesh size 34 | void resize_by_mesh(const ParametricMesh& smesh) 35 | { 36 | EigenCGVector::resize((CGdegree * smesh.nx + 1) * (CGdegree * smesh.ny + 1)); 37 | } 38 | 39 | // operations 40 | void zero() { EigenCGVector::setZero(); } 41 | 42 | // This method allows you to assign Eigen expressions to MyVectorType 43 | template 44 | CGVector& operator=(const Eigen::MatrixBase& other) 45 | { 46 | this->Eigen::Matrix::operator=(other); 47 | return *this; 48 | } 49 | }; 50 | 51 | } /* namespace Nextsim */ 52 | 53 | #endif /* __CGVECTOR_HPP */ 54 | -------------------------------------------------------------------------------- /dynamics/src/include/dgInitial.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file dgInitial.hpp 3 | * @date July 10 2022 4 | * @author Thomas Richter 5 | */ 6 | 7 | #ifndef __DGINITIAL_HPP 8 | #define __DGINITIAL_HPP 9 | 10 | #include "cgVector.hpp" 11 | #include "dgVector.hpp" 12 | 13 | #include "ParametricTools.hpp" 14 | 15 | namespace Nextsim { 16 | 17 | typedef std::function InitialOp; 18 | 19 | struct SmoothInitial { 20 | public: 21 | double operator()(double x, double y) const 22 | { 23 | double r2 = ((x - 0.7) * (x - 0.7) + (y - 0.7) * (y - 0.7)); 24 | return exp(-200.0 * r2); 25 | } 26 | }; 27 | 28 | struct PyramidInitial { 29 | public: 30 | double operator()(double x, double y) const 31 | { 32 | double r2 = ((x - 0.3) * (x - 0.3) + (y - 0.6) * (y - 0.6)); 33 | return std::max(0.0, 1.0 - 10.0 * sqrt(r2)); 34 | } 35 | }; 36 | 37 | struct BoxInitial { 38 | public: 39 | double operator()(double x, double y) const 40 | { 41 | double r2 = ((x - 0.65) * (x - 0.65) + (y - 0.3) * (y - 0.3)); 42 | if (sqrt(r2) < 0.1) 43 | return 1.0; 44 | return 0.0; 45 | } 46 | }; 47 | 48 | struct MixedInitial { 49 | public: 50 | double operator()(double x, double y) const 51 | { 52 | return SmoothInitial()(x, y) + BoxInitial()(x, y) + PyramidInitial()(x, y); 53 | } 54 | }; 55 | 56 | ////////////////////////////////////////////////// New Interface - ParametricMesh 57 | 58 | ////////////////////////////////////////////////// OLD Interfvace 59 | 60 | } /* namespace Nextsim */ 61 | 62 | #endif /* __DGINITIAL_H */ 63 | -------------------------------------------------------------------------------- /dynamics/src/include/dgVectorHolder.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file dgVectorHolder.hpp 3 | * 4 | * @date Feb 4, 2025 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef DGVECTORHOLDER_HPP 9 | #define DGVECTORHOLDER_HPP 10 | 11 | #include "dgVector.hpp" 12 | #include "include/ModelArray.hpp" 13 | 14 | namespace Nextsim { 15 | 16 | template class DGVectorHolder { 17 | public: 18 | using EigenDGVector = typename DGVector::EigenDGVector; 19 | DGVectorHolder() 20 | : ref(nullptr) 21 | { 22 | } 23 | DGVectorHolder(ModelArray& ma) 24 | : DGVectorHolder(static_cast(ma)) 25 | { 26 | } 27 | DGVectorHolder(ModelArray::DataType& madt) 28 | : DGVectorHolder(reinterpret_cast(madt)) 29 | { 30 | } 31 | DGVectorHolder(EigenDGVector& edgv) 32 | : ref(&edgv) 33 | { 34 | } 35 | DGVectorHolder(DGVector& dgv) 36 | : ref(&dgv) 37 | { 38 | } 39 | 40 | operator DGVector&() { return reinterpret_cast&>(*ref); } 41 | operator const DGVector&() const { return reinterpret_cast&>(*ref); } 42 | 43 | double& operator()(size_t i, size_t j) { return (*ref)(i, j); } 44 | 45 | void zero() { ref->setZero(); } 46 | 47 | private: 48 | EigenDGVector* ref; 49 | }; 50 | } 51 | 52 | #endif /* DGVECTORHOLDER_HPP */ 53 | -------------------------------------------------------------------------------- /dynamics/src/stopwatch.cpp: -------------------------------------------------------------------------------- 1 | #include "stopwatch.hpp" 2 | 3 | namespace Nextsim { 4 | 5 | Timer GlobalTimer; 6 | 7 | } -------------------------------------------------------------------------------- /dynamics/test/FakeSmeshData.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file FakeSmeshData.hpp 3 | * 4 | * @date Dec 14, 2023 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef FAKESMESHDATA_HPP 9 | #define FAKESMESHDATA_HPP 10 | 11 | #include "include/ModelState.hpp" 12 | 13 | #include 14 | 15 | namespace Nextsim { 16 | 17 | //! A class providing ModelArrays equivalent to those obtained from a restart file. 18 | class FakeSmeshData { 19 | public: 20 | static ModelState getData(); 21 | 22 | private: 23 | static std::vector landmask25km_NH(); 24 | }; 25 | 26 | } 27 | 28 | #endif /* FAKESMESHDATA_HPP */ 29 | -------------------------------------------------------------------------------- /dynamics/test/README.md: -------------------------------------------------------------------------------- 1 | # Testcases for the Dynamics Core 2 | 3 | ## Model Array Test Cases 4 | 5 | There are three tests checking that the ModelArray framework works correctly: 6 | 7 | - CGModelArray_test tests the conversion between the dynamics code CGVector and ModelArray. 8 | - DGModelArray_test tests the conversion between the dynamics code DGVector and ModelArray. 9 | - ParametricMesh_test tests the processing of ModelArray in the ParametricMesh class, as well as the reading of `.smesh` files. 10 | 11 | ## Linear Advection Test Cases 12 | 13 | These test cases test the DG transport scheme for dG0, dG1 and dG2 14 | 15 | ### Advection_test 16 | 17 | A smooth initial function is transported for times [0,2pi] in the domain [0,1]^2 using the rotational velocity field v = (y-1/2, x-1/2) 18 | 19 | We print out the final mass (for testing mass conservation) and the error after one revolution (numerical solution compared to initial solution). 20 | 21 | 22 | ### AdvectionPeriodicBC_test 23 | 24 | Here we test the implementation of the boundary handling: A smooth initial density f(x,y) = exp(-50 (x-1/2)^2 - 50 (y-1/2)^2 ) is transported to the upper right corner then to the lower left and back to the middle. 25 | 26 | When 'hitting' the corners, parts of the smooth function are transported out of the domain. This tests 'free outflow behavior'. When transporting back, the boundary value is zero. 27 | 28 | We check the mass at final time: 29 | 30 | - We compare it to the exact value (integrating f(x,y)) over the remaining part for measuring convergence 31 | - We compare it to previously stored reference values for automatic checking of failure. 32 | 33 | The three test cases are using different domains / discretizations: 34 | 35 | - Uniform discretization of [0,1] x [0,1] consisting of N x N elements with mesh size h x h 36 | - Uniform discretization of [0,2] x [0,1] consisting of 2N x N elements with mesh size h x h 37 | - Non-uniform discretization of [0,2] x [0,1] consisting of N x N elements using mesh size (2h) x h 38 | -------------------------------------------------------------------------------- /dynamics/test/dgVectorHolder_test.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file DGVectorHolder_test.cpp 3 | * 4 | * @date Feb 4, 2025 5 | * @author Tim Spain 6 | */ 7 | 8 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 9 | #include 10 | 11 | #include "include/dgVectorHolder.hpp" 12 | 13 | namespace Nextsim { 14 | 15 | COORDINATES CoordinateSystem = CARTESIAN; 16 | 17 | TEST_SUITE_BEGIN("DGVectorHolder"); 18 | TEST_CASE("Cast to and from") 19 | { 20 | static const int DG = 3; 21 | const size_t nx = 32; 22 | const size_t ny = 32; 23 | 24 | ParametricMesh smesh(CoordinateSystem); 25 | smesh.nx = nx; 26 | smesh.ny = ny; 27 | smesh.nelements = nx * ny; 28 | 29 | DGVector::EigenDGVector edgv(smesh.nelements, DG); 30 | double e0 = 3.; 31 | edgv.setConstant(e0); 32 | DGVectorHolder eHolder(edgv); 33 | REQUIRE(eHolder(0, 1) == e0); 34 | 35 | DGVector dgv; 36 | dgv.resize_by_mesh(smesh); 37 | double d0 = 4.; 38 | dgv.setConstant(d0); 39 | DGVectorHolder dHolder(dgv); 40 | REQUIRE(dHolder(0, 1) == d0); 41 | 42 | ModelArray::setDimension(ModelArray::Dimension::X, nx); 43 | ModelArray::setDimension(ModelArray::Dimension::Y, ny); 44 | ModelArray::setDimension(ModelArray::Dimension::DG, DG); 45 | 46 | ModelArray ma(ModelArray::Type::DG); 47 | ma.resize(); 48 | double ma0 = 2.; 49 | ma = ma0; 50 | DGVectorHolder mHolder(ma); 51 | ModelArray::DataType& ema = static_cast(ma); 52 | REQUIRE(ma.components(0)[1] == ma0); 53 | REQUIRE(ema(0, 1) == ma0); 54 | REQUIRE(mHolder(0, 1) == ma0); 55 | 56 | } 57 | } 58 | 59 | -------------------------------------------------------------------------------- /lib/doctest/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016-2023 Viktor Kirilov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /lib/doctest/extensions/doctest_util.h: -------------------------------------------------------------------------------- 1 | // 2 | // doctest_util.h - an accompanying extensions header to the main doctest.h header 3 | // 4 | // Copyright (c) 2016-2023 Viktor Kirilov 5 | // 6 | // Distributed under the MIT Software License 7 | // See accompanying file LICENSE.txt or copy at 8 | // https://opensource.org/licenses/MIT 9 | // 10 | // The documentation can be found at the library's page: 11 | // https://github.com/doctest/doctest/blob/master/doc/markdown/readme.md 12 | // 13 | 14 | #ifndef DOCTEST_UTIL_H 15 | #define DOCTEST_UTIL_H 16 | 17 | #ifndef DOCTEST_LIBRARY_INCLUDED 18 | #include "../doctest.h" 19 | #endif 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | namespace doctest { 26 | 27 | inline void applyCommandLine(doctest::Context& ctx, const std::vector& args) { 28 | auto doctest_args = std::make_unique(args.size()); 29 | for (size_t i = 0; i < args.size(); ++i) { 30 | doctest_args[i] = args[i].c_str(); 31 | } 32 | ctx.applyCommandLine(args.size(), doctest_args.get()); 33 | } 34 | 35 | } // namespace doctest 36 | 37 | #endif // DOCTEST_UTIL_H 38 | -------------------------------------------------------------------------------- /physics/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(src) 2 | if(BUILD_TESTS) 3 | enable_testing() 4 | add_subdirectory(test) 5 | endif() 6 | 7 | set(NextsimSources "${NextsimSources}" PARENT_SCOPE) 8 | 9 | set(NextsimIncludeDirs "${NextsimIncludeDirs}" PARENT_SCOPE) 10 | -------------------------------------------------------------------------------- /physics/src/BenchmarkCoordinates.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file BenchmarkCoordinates.cpp 3 | * 4 | * @date 26 Sept 2023 5 | * @author Tim Spain 6 | */ 7 | 8 | #include "include/BenchmarkCoordinates.hpp" 9 | 10 | namespace Nextsim { 11 | 12 | bool BenchmarkCoordinates::isInitialized = false; 13 | double BenchmarkCoordinates::dx = 25000.; 14 | double BenchmarkCoordinates::dy = 25000.; 15 | size_t BenchmarkCoordinates::m_nx; 16 | size_t BenchmarkCoordinates::m_ny; 17 | HField BenchmarkCoordinates::m_x(ModelArray::Type::H); 18 | HField BenchmarkCoordinates::m_y(ModelArray::Type::H); 19 | 20 | void BenchmarkCoordinates::setData() 21 | { 22 | if (!isInitialized) { 23 | m_nx = ModelArray::dimensions(ModelArray::Type::H)[0]; 24 | m_ny = ModelArray::dimensions(ModelArray::Type::H)[1]; 25 | 26 | m_x.resize(); 27 | m_y.resize(); 28 | 29 | dx = 512e3 / m_nx; 30 | dy = 512e3 / m_ny; 31 | 32 | for (size_t j = 0; j < m_ny; ++j) { 33 | double yVal = j * dy; 34 | for (size_t i = 0; i < m_nx; ++i) { 35 | double xVal = i * dx; 36 | m_x(i, j) = xVal; 37 | m_y(i, j) = yVal; 38 | } 39 | } 40 | isInitialized = true; 41 | } 42 | } 43 | } /* namespace Nextsim */ 44 | -------------------------------------------------------------------------------- /physics/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(ModuleDir "${CMAKE_CURRENT_SOURCE_DIR}/modules") 2 | 3 | add_subdirectory("${ModuleDir}") 4 | 5 | set(Sources "IceGrowth.cpp" "IceMinima.cpp" "SlabOcean.cpp" "BenchmarkCoordinates.cpp") 6 | 7 | list(TRANSFORM Sources PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/") 8 | 9 | set(NextsimSources "${NextsimSources}" "${Sources}" PARENT_SCOPE) 10 | 11 | set(NextsimIncludeDirs 12 | "${NextsimIncludeDirs}" 13 | "${ModuleDir}" 14 | "${CMAKE_CURRENT_SOURCE_DIR}" 15 | PARENT_SCOPE 16 | ) 17 | -------------------------------------------------------------------------------- /physics/src/IceMinima.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file IceMinima.cpp 3 | * 4 | * @date 8 Feb 2023 5 | * @author Tim Spain 6 | */ 7 | 8 | #include "include/IceMinima.hpp" 9 | 10 | namespace Nextsim { 11 | 12 | const double IceMinima::hMinDefault = 0.01; 13 | const double IceMinima::cMinDefault = 1e-12; 14 | 15 | double IceMinima::hMin = hMinDefault; 16 | double IceMinima::cMin = cMinDefault; 17 | 18 | } /* namespace Nextsim */ 19 | -------------------------------------------------------------------------------- /physics/src/include/BenchmarkCoordinates.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file BenchmarkCoordinates.hpp 3 | * 4 | * @date 26 Sept 2023 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef BENCHMARKCOORDINATES_HPP 9 | #define BENCHMARKCOORDINATES_HPP 10 | 11 | #include "include/ModelArray.hpp" 12 | 13 | namespace Nextsim { 14 | 15 | //! A class to calculate and store the coordinates used in the BenchmarkOcean and 16 | //! BenchmarkAtmosphere classes 17 | class BenchmarkCoordinates { 18 | public: 19 | static double dx; 20 | static double dy; 21 | 22 | //! Sets the data for the benchmark after the initial restart file has been read 23 | static void setData(); 24 | 25 | //! Returns the x dimension of the benchmark coordinate arrays 26 | static size_t nx() { return m_nx; } 27 | //! Returns the y dimension of the benchmark coordinate arrays 28 | static size_t ny() { return m_ny; } 29 | 30 | /*! 31 | * Returns the benchmark x coordinate array 32 | */ 33 | static const ModelArray& x() { return m_x; } 34 | /*! 35 | * Returns the benchmark y coordinate array 36 | */ 37 | static const ModelArray& y() { return m_y; } 38 | 39 | /*! 40 | * Returns the benchmark fractional x coordinate array x/(nx dx) 41 | */ 42 | static const ModelArray fx() { return m_x / (m_nx * dx); } 43 | /*! 44 | * Returns the benchmark fractional y coordinate array y/(ny dy) 45 | */ 46 | static const ModelArray fy() { return m_y / (m_ny * dy); } 47 | 48 | private: 49 | BenchmarkCoordinates() = default; 50 | ~BenchmarkCoordinates() = default; 51 | 52 | static bool isInitialized; 53 | 54 | // Size of the array dimensions 55 | static size_t m_nx; 56 | static size_t m_ny; 57 | 58 | // x and y coordinate arrays 59 | static HField m_x; 60 | static HField m_y; 61 | }; 62 | 63 | } /* namespace Nextsim */ 64 | 65 | #endif /* BENCHMARKCOORDINATES_HPP */ 66 | -------------------------------------------------------------------------------- /physics/src/include/IceMinima.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file IceMinima.hpp 3 | * 4 | * @date 8 Feb 2023 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef ICEMINIMA_HPP 9 | #define ICEMINIMA_HPP 10 | 11 | namespace Nextsim { 12 | 13 | class IceGrowth; 14 | //! A class to hold the minimum ice thresholds without having to pull in 15 | //! IceGrowth and its dependencies. 16 | class IceMinima { 17 | public: 18 | static inline double h() { return hMin; }; 19 | static inline double c() { return cMin; }; 20 | 21 | private: 22 | static double hMin; 23 | static double cMin; 24 | static const double hMinDefault; 25 | static const double cMinDefault; 26 | 27 | friend IceGrowth; 28 | }; 29 | 30 | } /* namespace Nextsim */ 31 | 32 | #endif /* ICEMINIMA_HPP */ 33 | -------------------------------------------------------------------------------- /physics/src/modules/AtmosphereBoundaryModule/ConstantAtmosphereBoundary.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file ConstantAtmosphereBoundary.cpp 3 | * 4 | * @date Sep 22, 2022 5 | * @author Tim Spain 6 | */ 7 | 8 | #include "include/ConstantAtmosphereBoundary.hpp" 9 | 10 | namespace Nextsim { 11 | 12 | ConstantAtmosphereBoundary::ConstantAtmosphereBoundary() 13 | : IAtmosphereBoundary() 14 | { 15 | } 16 | 17 | void ConstantAtmosphereBoundary::setData(const ModelState::DataMap& ms) 18 | { 19 | // Directly set the array values 20 | qia = 305.288; // Pulled from IceGrowth_test.cpp: New Ice Formation 21 | dqia_dt = 4.5036; 22 | qow = 307.546; 23 | subl = 0.; // Seems unlikely… 24 | snow = 0.; 25 | rain = 0.; 26 | evap = 0; // somehow... 27 | uwind = 0; 28 | vwind = 0; 29 | penSW = 0.; 30 | } 31 | 32 | void ConstantAtmosphereBoundary::update(const TimestepTime& tst) 33 | { 34 | IAtmosphereBoundary::update(tst); 35 | } 36 | 37 | } /* namespace Nextsim */ 38 | -------------------------------------------------------------------------------- /physics/src/modules/AtmosphereBoundaryModule/include/BenchmarkAtmosphere.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file BenchmarkAtmosphere.hpp 3 | * 4 | * @date 24 Sep 2024 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef BENCHMARKATMOSPHERE_HPP 9 | #define BENCHMARKATMOSPHERE_HPP 10 | 11 | #include "include/IAtmosphereBoundary.hpp" 12 | 13 | namespace Nextsim { 14 | 15 | class BenchmarkAtmosphere : public IAtmosphereBoundary { 16 | public: 17 | BenchmarkAtmosphere() 18 | : IAtmosphereBoundary() 19 | { 20 | } 21 | ~BenchmarkAtmosphere() = default; 22 | 23 | void setData(const ModelState::DataMap&) override; 24 | std::string getName() const override { return "BenchmarkAtmosphere"; } 25 | 26 | void update(const TimestepTime& tst) override; 27 | 28 | private: 29 | TimePoint t0; 30 | bool t0Set = false; 31 | }; 32 | 33 | } /* namespace Nextsim */ 34 | 35 | #endif /* BENCHMARKATMOSPHERE_HPP */ 36 | -------------------------------------------------------------------------------- /physics/src/modules/AtmosphereBoundaryModule/include/ConfiguredAtmosphere.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file ConfiguredAtmosphere.hpp 3 | * 4 | * @date Aug 31, 2022 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef CONFIGUREDATMOSPHERE_HPP 9 | #define CONFIGUREDATMOSPHERE_HPP 10 | 11 | #include "include/IAtmosphereBoundary.hpp" 12 | 13 | #include "include/IFluxCalculation.hpp" 14 | 15 | namespace Nextsim { 16 | 17 | //! A class to provide constant atmospheric forcings that can be configured at run time. 18 | class ConfiguredAtmosphere : public IAtmosphereBoundary, public Configured { 19 | public: 20 | ConfiguredAtmosphere(); 21 | ~ConfiguredAtmosphere() = default; 22 | 23 | enum { 24 | TAIR_KEY, 25 | TDEW_KEY, 26 | PAIR_KEY, 27 | SW_KEY, 28 | LW_KEY, 29 | SNOW_KEY, 30 | RAIN_KEY, 31 | WIND_KEY, 32 | }; 33 | 34 | void setData(const ModelState::DataMap&) override; 35 | std::string getName() const override { return "ConfiguredAtmosphere"; } 36 | 37 | static HelpMap& getHelpRecursive(HelpMap& map, bool getAll); 38 | 39 | void configure() override; 40 | ConfigMap getConfiguration() const override; 41 | 42 | //! Calculates the fluxes from the given values 43 | void update(const TimestepTime&) override; 44 | 45 | private: 46 | static double tair0; 47 | static double tdew0; 48 | static double pair0; 49 | static double sw0; 50 | static double lw0; 51 | static double snowfall0; 52 | static double rain0; 53 | static double windspeed0; 54 | 55 | HField tair; 56 | HField tdew; 57 | HField pair; 58 | HField sw_in; 59 | HField lw_in; 60 | HField wind; 61 | 62 | IFluxCalculation* fluxImpl; 63 | }; 64 | 65 | } /* namespace Nextsim */ 66 | 67 | #endif /* CONFIGUREDATMOSPHERE_HPP */ 68 | -------------------------------------------------------------------------------- /physics/src/modules/AtmosphereBoundaryModule/include/ConstantAtmosphereBoundary.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file ConstantAtmosphereBoundary.hpp 3 | * 4 | * @date Sep 22, 2022 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef CONSTANTATMOSPHEREBOUNDARY_HPP 9 | #define CONSTANTATMOSPHEREBOUNDARY_HPP 10 | 11 | #include "include/IAtmosphereBoundary.hpp" 12 | 13 | namespace Nextsim { 14 | 15 | //* A set of atmospheric inputs that are fixed at compile time. 16 | class ConstantAtmosphereBoundary : public IAtmosphereBoundary { 17 | public: 18 | ConstantAtmosphereBoundary(); 19 | 20 | std::string getName() const override { return "ConstantAtmosphereBoundary"; } 21 | void setData(const ModelState::DataMap&) override; 22 | void update(const TimestepTime& tst) override; 23 | }; 24 | 25 | } /* namespace Nextsim */ 26 | 27 | #endif /* CONSTANTATMOSPHEREBOUNDARY_HPP */ 28 | -------------------------------------------------------------------------------- /physics/src/modules/AtmosphereBoundaryModule/include/ERA5Atmosphere.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file ERA5Atmosphere.hpp 3 | * 4 | * @date Nov 25, 2022 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef ERA5ATMOSPHERE_HPP 9 | #define ERA5ATMOSPHERE_HPP 10 | 11 | #include "include/IAtmosphereBoundary.hpp" 12 | 13 | #include "include/Configured.hpp" 14 | #include "include/IFluxCalculation.hpp" 15 | 16 | namespace Nextsim { 17 | 18 | /*! 19 | * A class to provided forcings from pre-processed forcings files based on ERA5 20 | * data. 21 | */ 22 | class ERA5Atmosphere : public IAtmosphereBoundary, public Configured { 23 | public: 24 | ERA5Atmosphere(); 25 | ~ERA5Atmosphere() = default; 26 | 27 | enum { 28 | FILEPATH_KEY, 29 | }; 30 | 31 | void setData(const ModelState::DataMap&) override; 32 | std::string getName() const override { return "ERA5Atmosphere"; } 33 | 34 | static HelpMap& getHelpRecursive(HelpMap& map, bool getAll); 35 | 36 | void configure() override; 37 | ConfigMap getConfiguration() const override; 38 | 39 | //! Calculates the fluxes from the given values 40 | void update(const TimestepTime&) override; 41 | 42 | void setFilePath(const std::string& filePathIn); 43 | 44 | private: 45 | // Since the configuration is global, it makes sense for the file path to 46 | // be static. 47 | static std::string filePath; 48 | 49 | HField tair; 50 | HField tdew; 51 | HField pair; 52 | HField sw_in; 53 | HField lw_in; 54 | HField wind; 55 | 56 | IFluxCalculation* fluxImpl; 57 | }; 58 | 59 | } /* namespace Nextsim */ 60 | 61 | #endif /* ERA5ATMOSPHERE_HPP_ */ 62 | -------------------------------------------------------------------------------- /physics/src/modules/AtmosphereBoundaryModule/include/FluxConfiguredAtmosphere.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file FluxConfiguredAtmosphere.hpp 3 | * 4 | * @date Sep 29, 2022 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef FLUXCONFIGUREDATMOSPHERE_HPP 9 | #define FLUXCONFIGUREDATMOSPHERE_HPP 10 | 11 | #include "include/IAtmosphereBoundary.hpp" 12 | 13 | #include "include/Configured.hpp" 14 | 15 | namespace Nextsim { 16 | 17 | //! A class to provide constant atmospheric forcings that can be configured at run time. 18 | class FluxConfiguredAtmosphere : public IAtmosphereBoundary, 19 | public Configured { 20 | public: 21 | FluxConfiguredAtmosphere() = default; 22 | ~FluxConfiguredAtmosphere() = default; 23 | 24 | enum { 25 | QIA_KEY, 26 | DQIA_DT_KEY, 27 | QOW_KEY, 28 | SUBL_KEY, 29 | SNOW_KEY, 30 | RAIN_KEY, 31 | EVAP_KEY, 32 | WINDU_KEY, 33 | WINDV_KEY, 34 | }; 35 | 36 | void setData(const ModelState::DataMap&) override; 37 | std::string getName() const override { return "FluxConfiguredAtmosphere"; } 38 | 39 | static HelpMap& getHelpRecursive(HelpMap& map, bool getAll); 40 | 41 | void configure() override; 42 | ConfigMap getConfiguration() const override; 43 | 44 | protected: 45 | //! Performs the implementation specific updates. Does nothing. 46 | void update(const TimestepTime&) override { } 47 | 48 | private: 49 | static double qia0; 50 | static double dqia_dt0; 51 | static double qow0; 52 | static double subl0; 53 | static double snowfall0; 54 | static double rain0; 55 | static double evap0; 56 | static double u0; 57 | static double v0; 58 | }; 59 | 60 | } /* namespace Nextsim */ 61 | 62 | #endif /* FLUXCONFIGUREDATMOSPHERE_HPP */ 63 | -------------------------------------------------------------------------------- /physics/src/modules/AtmosphereBoundaryModule/module.cfg: -------------------------------------------------------------------------------- 1 | [module] 2 | name = Nextsim::IAtmosphereBoundary 3 | file_prefix = AtmosphereBoundary 4 | interface_prefix = I 5 | header_path = include 6 | external_header_path = ../include 7 | description = The module providing the atmospheric boundary conditions. 8 | 9 | [Nextsim::BenchmarkAtmosphere] 10 | file_prefix = BenchmarkAtmosphere 11 | description = Calculated cyclonic atmosphere for the DG dynamics benchmark. 12 | has_help = false 13 | 14 | [Nextsim::ConfiguredAtmosphere] 15 | file_prefix = ConfiguredAtmosphere 16 | description = An atmospheric boundary with constant values fixed by configuration. 17 | has_help = true 18 | 19 | [Nextsim::ConstantAtmosphereBoundary] 20 | file_prefix = ConstantAtmosphereBoundary 21 | description = An atmospheric boundary with constant values fixed at compile time. 22 | has_help = false 23 | is_default = true 24 | 25 | [Nextsim::ERA5Atmosphere] 26 | file_prefix = ERA5Atmosphere 27 | description = Atmospheric boundary conditions taken from the ERA5 reanalysis. 28 | has_help = true 29 | 30 | [Nextsim::FluxConfiguredAtmosphere] 31 | file_prefix = FluxConfiguredAtmosphere 32 | description = An atmospheric boundary with constant flux values fixed by configuration. 33 | has_help = true 34 | 35 | [Nextsim::MU71Atmosphere] 36 | file_prefix = MU71Atmosphere 37 | description = A seasonally varying atmosphere derived from Maykut and Untersteiener (1971) table 1. 38 | has_help = false 39 | -------------------------------------------------------------------------------- /physics/src/modules/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(AllModuleSources "") 2 | 3 | # Get all module subdirectories. These must be suffix with "Module", and 4 | # nothing else in this directory can be. 5 | file(GLOB ModuleSubDirs LIST_DIRECTORIES TRUE "*Module") 6 | 7 | foreach(ModuleSubDir IN LISTS ModuleSubDirs) 8 | # Ignore directories without a module.cfg file 9 | if(NOT EXISTS "${ModuleSubDir}/module.cfg") 10 | continue() 11 | endif() 12 | 13 | # Run the source python script 14 | execute_process( 15 | COMMAND "${Python_EXECUTABLE}" "${ModuleBuilderScript}" 16 | WORKING_DIRECTORY "${ModuleSubDir}" 17 | ) 18 | 19 | # List all sources in the subdirectory 20 | file(GLOB ThisModuleSources LIST_DIRECTORIES FALSE "${ModuleSubDir}/*.cpp") 21 | 22 | set(AllModuleSources "${AllModuleSources}" "${ThisModuleSources}") 23 | endforeach() 24 | 25 | set(NextsimSources "${NextsimSources}" "${AllModuleSources}" PARENT_SCOPE) 26 | -------------------------------------------------------------------------------- /physics/src/modules/DamageHealingModule/include/ConstantHealing.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file ConstantHealing.hpp 3 | * 4 | * @date Jun 3, 2024 5 | * @author Einar Ólason 6 | */ 7 | 8 | #ifndef CONSTANTHEALING_HPP 9 | #define CONSTANTHEALING_HPP 10 | 11 | #include "include/Configured.hpp" 12 | #include "include/IDamageHealing.hpp" 13 | 14 | namespace Nextsim { 15 | 16 | //! A class implementing constant healing of damage following Dansereau et al. (2016) and Rampal et 17 | //! al. (2019) 18 | class ConstantHealing : public IDamageHealing, public Configured { 19 | public: 20 | ConstantHealing() 21 | : IDamageHealing() 22 | { 23 | } 24 | virtual ~ConstantHealing() = default; 25 | 26 | void configure() override; 27 | enum { TD_KEY }; 28 | 29 | ConfigMap getConfiguration() const override; 30 | 31 | static HelpMap& getHelpText(HelpMap& map, bool getAll); 32 | static HelpMap& getHelpRecursive(HelpMap&, bool getAll); 33 | 34 | void update(const TimestepTime& tstep) override; 35 | 36 | private: 37 | static double tD; 38 | void updateElement(size_t i, const TimestepTime& tstep); 39 | }; 40 | 41 | } 42 | 43 | #endif // CONSTANTHEALING_HPP 44 | -------------------------------------------------------------------------------- /physics/src/modules/DamageHealingModule/include/NoHealing.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file HoHealing.hpp 3 | * 4 | * This class has no corresponding implementation, just this header file 5 | * 6 | * @date 21 Nov 2024 7 | * @author Einar Ólason 8 | */ 9 | 10 | #ifndef NOHEALING_HPP 11 | #define NOHEALING_HPP 12 | 13 | #include "include/IDamageHealing.hpp" 14 | 15 | namespace Nextsim { 16 | 17 | //! A class implementing no healing of damage 18 | class NoHealing : public IDamageHealing { 19 | public: 20 | NoHealing() 21 | : IDamageHealing() 22 | { 23 | } 24 | virtual ~NoHealing() = default; 25 | 26 | // Do nothing when update is called. 27 | void update(const TimestepTime& tstep) override { damage = oldDamage; } 28 | }; 29 | 30 | } 31 | 32 | #endif // NOHEALING_HPP 33 | -------------------------------------------------------------------------------- /physics/src/modules/DamageHealingModule/module.cfg: -------------------------------------------------------------------------------- 1 | [module] 2 | name = Nextsim::IDamageHealing 3 | file_prefix = DamageHealing 4 | interface_prefix = I 5 | header_path = include 6 | external_header_path = ../include 7 | description = A module for healing damage in the brittle rheologies 8 | 9 | [Nextsim::ConstantHealing] 10 | file_prefix = ConstantHealing 11 | description = Constant healing rate following Dansereau et al. (2016) and Rampal et al. (2019) 12 | has_help = true 13 | is_default = true 14 | 15 | [Nextsim::NoHealing] 16 | file_prefix = NoHealing 17 | description = Damage does not increase (heal). 18 | has_help = false 19 | -------------------------------------------------------------------------------- /physics/src/modules/FluxCalculationModule/module.cfg: -------------------------------------------------------------------------------- 1 | [module] 2 | name = Nextsim::IFluxCalculation 3 | file_prefix = FluxCalculation 4 | interface_prefix = I 5 | header_path = include 6 | external_header_path = ../include 7 | description = The module providing the calculations of atmospheric fluxes. 8 | 9 | [Nextsim::FiniteElementFluxes] 10 | file_prefix = FiniteElementFluxes 11 | description = Flux calculations ported from finiteelement.cpp in Lagrangian nextSIM. 12 | has_help = true 13 | is_default = true 14 | -------------------------------------------------------------------------------- /physics/src/modules/IceAlbedoModule/MU71Albedo.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file MU71Albedo.cpp 3 | * 4 | * @date Wed 24 Aug 2022 08:05:49 CEST 5 | * @author Einar Örn Ólason 6 | */ 7 | 8 | #include "include/MU71Albedo.hpp" 9 | 10 | namespace Nextsim { 11 | 12 | MU71Albedo::MU71Albedo() 13 | : snowAlbedo(albedoTable) 14 | { 15 | } 16 | 17 | std::tuple MU71Albedo::surfaceShortWaveBalance( 18 | double temperature, double snowThickness, double i0) 19 | { 20 | double albedo, penSW; 21 | 22 | // Fixed ice albedo 23 | if (snowThickness == 0.) { 24 | albedo = iceAlbedo; 25 | penSW = i0; 26 | } else { 27 | albedo = snowAlbedo(dayOfYear, isLeap); 28 | penSW = 0.; 29 | } 30 | 31 | return std::make_tuple(albedo, penSW); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /physics/src/modules/IceAlbedoModule/SMU2IceAlbedo.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file SMU2IceAlbedo.cpp 3 | * 4 | * @date 24 Sep 2024 5 | * @author Tim Spain 6 | */ 7 | 8 | #include "include/SMU2IceAlbedo.hpp" 9 | 10 | #include 11 | 12 | namespace Nextsim { 13 | 14 | /* This scheme mimics Semtner 76 and Maykut and Untersteiner 71 when 15 | * alb_ice = 0.64 and alb_sn = 0.85 */ 16 | 17 | const double ICE_ALBEDO = 0.64; 18 | const double SNOW_ALBEDO = 0.85; 19 | 20 | std::tuple SMU2IceAlbedo::surfaceShortWaveBalance( 21 | double temperature, double snowThickness, double i0) 22 | { 23 | double albedo, penSW; 24 | if (snowThickness > 0.) { 25 | albedo 26 | = std::fmin(SNOW_ALBEDO, ICE_ALBEDO + (SNOW_ALBEDO - ICE_ALBEDO) * snowThickness / 0.4); 27 | penSW = 0; 28 | } else { 29 | albedo = ICE_ALBEDO; 30 | penSW = i0; 31 | } 32 | return { albedo, penSW }; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /physics/src/modules/IceAlbedoModule/SMUIceAlbedo.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file SMUIceAlbedo.cpp 3 | * 4 | * @date 24 Sep 2024 5 | * @author Tim Spain 6 | */ 7 | 8 | #include "include/SMUIceAlbedo.hpp" 9 | 10 | namespace Nextsim { 11 | 12 | /* This scheme mimics Semtner 76 and Maykut and Untersteiner 71 when 13 | * alb_ice = 0.64 and alb_sn = 0.85 */ 14 | 15 | const double ICE_ALBEDO = 0.64; 16 | const double SNOW_ALBEDO = 0.85; 17 | 18 | std::tuple SMUIceAlbedo::surfaceShortWaveBalance( 19 | double temperature, double snowThickness, double i0) 20 | { 21 | double albedo, penSW; 22 | if (snowThickness > 0.) { 23 | albedo = SNOW_ALBEDO; 24 | penSW = 0.; 25 | } else { 26 | albedo = ICE_ALBEDO; 27 | penSW = i0; 28 | } 29 | return { albedo, penSW }; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /physics/src/modules/IceAlbedoModule/include/CCSMIceAlbedo.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file CCSMIceAlbedo.hpp 3 | * 4 | * @date 24 Sep 2024 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef CCSMICEALBEDO_HPP 9 | #define CCSMICEALBEDO_HPP 10 | 11 | #include "include/Configured.hpp" 12 | #include "include/IIceAlbedo.hpp" 13 | 14 | namespace Nextsim { 15 | 16 | //! The implementation class for the CCSM calculation of ice surface albedo. 17 | class CCSMIceAlbedo : public IIceAlbedo, public Configured { 18 | public: 19 | /*! 20 | * @brief Calculates the CCSM3 ice surface short wave albedo and fraction of penetrating 21 | * short-wave radiation. 22 | * @param temperature The temperature of the ice surface. 23 | * @param snowThickness The true snow thickness on top of the ice. 24 | * @param i0 The fraction of short-wave radiation that can penetrate bare ice (not taking snow 25 | * cover into account). 26 | */ 27 | std::tuple surfaceShortWaveBalance( 28 | double temperature, double snowThickness, double i0) override; 29 | 30 | void configure() override; 31 | 32 | ConfigMap getConfiguration() const override; 33 | 34 | static HelpMap& getHelpText(HelpMap& map, bool getAll); 35 | static HelpMap& getHelpRecursive(HelpMap& map, bool getAll); 36 | 37 | private: 38 | static double iceAlbedo; 39 | static double snowAlbedo; 40 | }; 41 | 42 | } 43 | 44 | #endif /* CCSMICEALBEDO_HPP */ 45 | -------------------------------------------------------------------------------- /physics/src/modules/IceAlbedoModule/include/MU71Albedo.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file MU71Albedo.hpp 3 | * 4 | * @date Wed 24 Aug 2022 08:00:31 CEST 5 | * @author Einar Örn Ólason 6 | */ 7 | 8 | #ifndef SEASONALICEALBEDO_HPP 9 | #define SEASONALICEALBEDO_HPP 10 | 11 | #include "include/IIceAlbedo.hpp" 12 | #include "include/MonthlyCubicBSpline.hpp" 13 | #include 14 | 15 | namespace Nextsim { 16 | 17 | /*! 18 | * @brief The implementation class for the a seasonal albedo following Maykut and Untersteiener's 19 | * (1971) table 1. Only useful for comparison with that paper and derived setups. 20 | */ 21 | class MU71Albedo : public IIceAlbedo { 22 | 23 | public: 24 | MU71Albedo(); 25 | 26 | /*! 27 | * @brief Returns the tabulated ice surface short wave albedo from Maykut and Untersteiner 28 | * (1971) 29 | * @param temperature The surface (ice or snow) temperature 30 | * @param snowThickness Show thickness 31 | * @return 32 | */ 33 | std::tuple surfaceShortWaveBalance( 34 | double temperature, double snowThickness, double i0) override; 35 | 36 | private: 37 | TimePoint M_tp; 38 | double dayOfYear; 39 | bool isLeap; 40 | 41 | void setTime(const TimePoint& tp) override 42 | { 43 | M_tp = tp; 44 | dayOfYear = M_tp.gmtime()->tm_yday; 45 | isLeap = ((M_tp.gmtime()->tm_year % 4 == 0) && (M_tp.gmtime()->tm_year % 100 != 0)) 46 | || (M_tp.gmtime()->tm_year % 400 == 0); 47 | } 48 | 49 | // Monthly snow albedo from Maykut and Untersteiner (1971) 50 | const std::vector albedoTable 51 | = { 0.85, 0.85, 0.83, 0.81, 0.82, 0.78, 0.64, 0.69, 0.84, 0.85, 0.85, 0.85 }; 52 | // Jan, Feb, Mar, Apr, Mai, Jun, Jul, Aug, Sept, Oct, Nov, Dec 53 | 54 | monthlyCubicBSpline snowAlbedo; 55 | const double iceAlbedo = 0.64; 56 | }; 57 | 58 | } 59 | 60 | #endif /* SEASONALICEALBEDO_HPP */ 61 | -------------------------------------------------------------------------------- /physics/src/modules/IceAlbedoModule/include/SMU2IceAlbedo.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file SMU2IceAlbedo.hpp 3 | * 4 | * @date 24 Sep 2024 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef SRC_INCLUDE_SMU2ICEALBEDO_HPP 9 | #define SRC_INCLUDE_SMU2ICEALBEDO_HPP 10 | 11 | #include "include/IIceAlbedo.hpp" 12 | 13 | namespace Nextsim { 14 | 15 | //! The implementation class for the SMU calculation of ice surface albedo 16 | // with variable snow albedo. 17 | class SMU2IceAlbedo : public IIceAlbedo { 18 | /*! 19 | * @brief Calculates the SMU ice surface short wave albedo with constant 20 | * snow albedo. 21 | * 22 | * @param temperature The temperature of the ice surface. 23 | * @param snowThickness The true snow thickness on top of the ice. 24 | * @param i0 The fraction of short-wave radiation that can penetrate bare ice (not taking snow 25 | * cover into account). 26 | */ 27 | std::tuple surfaceShortWaveBalance( 28 | double temperature, double snowThickness, double i0); 29 | }; 30 | 31 | } 32 | 33 | #endif /* SRC_INCLUDE_SMU2ICEALBEDO_HPP */ 34 | -------------------------------------------------------------------------------- /physics/src/modules/IceAlbedoModule/include/SMUIceAlbedo.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file SMUIceAlbedo.hpp 3 | * 4 | * @date 24 Sep 2024 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef SRC_INCLUDE_SMUICEALBEDO_HPP 9 | #define SRC_INCLUDE_SMUICEALBEDO_HPP 10 | 11 | #include "include/IIceAlbedo.hpp" 12 | 13 | namespace Nextsim { 14 | 15 | //! The implementation class for the SMU calculation of ice surface albedo 16 | // with constant snow albedo. 17 | class SMUIceAlbedo : public IIceAlbedo { 18 | /*! 19 | * @brief Calculates the SMU ice surface short wave albedo with constant 20 | * snow albedo. 21 | * 22 | * @param temperature The temperature of the ice surface. 23 | * @param snowThickness The true snow thickness on top of the ice. 24 | * @param i0 The fraction of short-wave radiation that can penetrate bare ice (not taking snow 25 | * cover into account). 26 | */ 27 | std::tuple surfaceShortWaveBalance( 28 | double temperature, double snowThickness, double i0); 29 | }; 30 | 31 | } 32 | 33 | #endif /* SRC_INCLUDE_SMUICEALBEDO_HPP */ 34 | -------------------------------------------------------------------------------- /physics/src/modules/IceAlbedoModule/include/WintonAlbedo.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file WintonAlbedo.hpp 3 | * 4 | * @date Sep 11, 2024 5 | * @author Tim Spain 6 | * @author Einar Ólason 7 | */ 8 | 9 | #ifndef WINTONALBEDO_HPP 10 | #define WINTONALBEDO_HPP 11 | 12 | #include "include/Configured.hpp" 13 | #include "include/IIceAlbedo.hpp" 14 | 15 | namespace Nextsim { 16 | 17 | //! The implementation class for the Winton (2000) calculation of ice surface albedo. 18 | class WintonAlbedo : public IIceAlbedo, public Configured { 19 | public: 20 | /*! 21 | * @brief Calculates the ice surface short wave albedo and fraction of penetrating 22 | * short-wave radiation following Winton (2000). 23 | * @param temperature The temperature of the ice surface. 24 | * @param snowThickness The true snow thickness on top of the ice. 25 | * @param i0 The fraction of short-wave radiation that can penetrate bare ice (not taking snow 26 | * cover into account). 27 | */ 28 | std::tuple surfaceShortWaveBalance( 29 | double temperature, double snowThickness, double i0) override; 30 | 31 | void configure() override; 32 | 33 | ConfigMap getConfiguration() const override; 34 | 35 | static HelpMap& getHelpText(HelpMap& map, bool getAll); 36 | static HelpMap& getHelpRecursive(HelpMap& map, bool getAll); 37 | 38 | private: 39 | static double iceAlbedo; 40 | static double snowAlbedo; 41 | static double meltAlbedo; 42 | }; 43 | 44 | } 45 | 46 | #endif /* WINTONALBEDO_HPP */ 47 | -------------------------------------------------------------------------------- /physics/src/modules/IceAlbedoModule/module.cfg: -------------------------------------------------------------------------------- 1 | [module] 2 | name = Nextsim::IIceAlbedo 3 | file_prefix = IceAlbedo 4 | interface_prefix = I 5 | header_path = include 6 | external_header_path = ../include 7 | description = The module for calculating the albedo of the ice surface. 8 | 9 | [Nextsim::SMUIceAlbedo] 10 | file_prefix = SMUIceAlbedo 11 | description = Ice albedo implementation after Semtner (1976) and Maykut and Untersteiner (1971). 12 | has_help = false 13 | is_default = true 14 | 15 | [Nextsim::SMU2IceAlbedo] 16 | file_prefix = SMU2IceAlbedo 17 | description = Ice albedo implementation after Semtner (1976) and Maykut and Untersteiner (1971) with decreased albedo for thinner snow. 18 | has_help = false 19 | 20 | [Nextsim::CCSMIceAlbedo] 21 | file_prefix = CCSMIceAlbedo 22 | description = Ice albedo scheme from CCSM3. 23 | has_help = true 24 | 25 | [Nextsim::MU71Albedo] 26 | file_prefix = MU71Albedo 27 | description = Tabulated seasonal albedo from Maykut and Untersteiener (1971) table 1. 28 | has_help = false 29 | 30 | [Nextsim::WintonAlbedo] 31 | file_prefix = WintonAlbedo 32 | description = Very simplified albedo scheme of Winton (2000). 33 | has_help = true 34 | -------------------------------------------------------------------------------- /physics/src/modules/IceOceanHeatFluxModule/BasicIceOceanHeatFlux.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file BasicIceOceanHeatFlux.cpp 3 | * 4 | * @date 02 May 2025 5 | * @author Tim Spain 6 | */ 7 | 8 | #include "include/BasicIceOceanHeatFlux.hpp" 9 | 10 | namespace Nextsim { 11 | 12 | static inline double doOne(double tBot, double sst, double mlBulkCp, double timeT) 13 | { 14 | // Transfer rate depends on the mixed layer depth and the relaxation time scale 15 | return (sst - tBot) * mlBulkCp / timeT; 16 | } 17 | 18 | void BasicIceOceanHeatFlux::update(const TimestepTime& tst) 19 | { 20 | overElements( 21 | [this](size_t i, const TimestepTime& tsTime) { this->updateElement(i, tsTime); }, tst); 22 | } 23 | 24 | void BasicIceOceanHeatFlux::updateElement(size_t i, const TimestepTime& tst) 25 | { 26 | // Use the timestep length as the relaxation time scale 27 | if (cice[i] > 0.) { 28 | qio[i] = doOne(tf[i], sst[i], mlBulkCp[i], tst.step.seconds()); 29 | } else { 30 | qio[i] = 0.; 31 | } 32 | } 33 | 34 | } /* namespace Nextsim */ 35 | -------------------------------------------------------------------------------- /physics/src/modules/IceOceanHeatFluxModule/include/BasicIceOceanHeatFlux.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file BasicIceOceanHeatFlux.hpp 3 | * 4 | * @date Oct 19, 2021 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef BASICICEOCEANHEATFLUX_HPP 9 | #define BASICICEOCEANHEATFLUX_HPP 10 | 11 | #include "include/IIceOceanHeatFlux.hpp" 12 | 13 | namespace Nextsim { 14 | 15 | //! The implementation class for the basic ice-ocean heat flux. 16 | class BasicIceOceanHeatFlux : public IIceOceanHeatFlux { 17 | public: 18 | BasicIceOceanHeatFlux() 19 | : IIceOceanHeatFlux() 20 | , mlBulkCp(getStore()) 21 | { 22 | } 23 | virtual ~BasicIceOceanHeatFlux() = default; 24 | 25 | std::string getName() const override { return "BasicIceOceanHeatFlux"; } 26 | 27 | void update(const TimestepTime&) override; 28 | void updateElement(size_t i, const TimestepTime&); 29 | 30 | protected: 31 | ModelArrayRef mlBulkCp; 32 | }; 33 | 34 | } /* namespace Nextsim */ 35 | 36 | #endif /* BASICICEOCEANHEATFLUX_HPP */ 37 | -------------------------------------------------------------------------------- /physics/src/modules/IceOceanHeatFluxModule/module.cfg: -------------------------------------------------------------------------------- 1 | [module] 2 | name = Nextsim::IIceOceanHeatFlux 3 | file_prefix = IceOceanHeatFlux 4 | interface_prefix = I 5 | header_path = include 6 | external_header_path = ../include 7 | description = The module for calculating the heat flux between the ice and the ocean. 8 | 9 | [Nextsim::BasicIceOceanHeatFlux] 10 | file_prefix = BasicIceOceanHeatFlux 11 | description = A simplistic ice-ocean heat flux scheme. 12 | has_help = false 13 | is_default = true 14 | -------------------------------------------------------------------------------- /physics/src/modules/IceThermodynamicsModule/include/DummyIceThermodynamics.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file DummyIceThermodynamics.hpp 3 | * 4 | * @date 24 Sep 2024 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef DUMMYICETHERMODYNAMICS_HPP 9 | #define DUMMYICETHERMODYNAMICS_HPP 10 | 11 | #include "include/IIceThermodynamics.hpp" 12 | 13 | namespace Nextsim { 14 | 15 | class DummyIceThermodynamics : public IIceThermodynamics { 16 | public: 17 | DummyIceThermodynamics() 18 | : IIceThermodynamics() 19 | { 20 | } 21 | ~DummyIceThermodynamics() = default; 22 | 23 | void setData(const ModelState::DataMap& ms) override { IIceThermodynamics::setData(ms); } 24 | void update(const TimestepTime& tsTime) override { } 25 | }; 26 | 27 | } /* namespace Nextsim */ 28 | 29 | #endif /* DUMMYICETHERMODYNAMICS_HPP */ 30 | -------------------------------------------------------------------------------- /physics/src/modules/IceThermodynamicsModule/include/ThermoIce0.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file ThermoIce0.hpp 3 | * 4 | * @date 24 Sep 2024 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef THERMOICE0HPP 9 | #define THERMOICE0HPP 10 | 11 | #include "include/Configured.hpp" 12 | #include "include/IIceThermodynamics.hpp" 13 | #include "include/ModelArrayRef.hpp" 14 | namespace Nextsim { 15 | 16 | //! A class implementing IIceThermodynamics as the ThermoIce0 model. 17 | class ThermoIce0 : public IIceThermodynamics, public Configured { 18 | public: 19 | ThermoIce0(); 20 | virtual ~ThermoIce0() = default; 21 | 22 | enum { 23 | KS_KEY, 24 | }; 25 | void configure() override; 26 | ConfigMap getConfiguration() const override; 27 | 28 | ModelState getStateDiagnostic() const override; 29 | ModelState getStatePrognostic() const override; 30 | 31 | static HelpMap& getHelpText(HelpMap& map, bool getAll); 32 | static HelpMap& getHelpRecursive(HelpMap& map, bool getAll); 33 | 34 | void setData(const ModelState::DataMap&) override; 35 | void update(const TimestepTime& tsTime) override; 36 | 37 | private: 38 | void calculateElement(size_t i, const TimestepTime& tst); 39 | 40 | HField snowMelt; 41 | HField topMelt; 42 | HField botMelt; 43 | HField qic; 44 | ModelArrayRef oldHi; 45 | 46 | static const double freezingPointIce; 47 | static double kappa_s; 48 | 49 | bool doFlooding = true; // TODO: read from configuration 50 | }; 51 | 52 | } /* namespace Nextsim */ 53 | 54 | #endif /* THERMOICE0HPP */ 55 | -------------------------------------------------------------------------------- /physics/src/modules/IceThermodynamicsModule/module.cfg: -------------------------------------------------------------------------------- 1 | [module] 2 | name = Nextsim::IIceThermodynamics 3 | file_prefix = IceThermodynamics 4 | interface_prefix = I 5 | header_path = include 6 | external_header_path = ../include 7 | description = The module providing thermodynamic calculations for the ice. 8 | 9 | [Nextsim::ThermoIce0] 10 | file_prefix = ThermoIce0 11 | description = Zero layer ice model of Semtner. 12 | has_help = true 13 | is_default = true 14 | 15 | [Nextsim::ThermoWinton] 16 | file_prefix = ThermoWinton 17 | description = Three layer ice model of Winton. 18 | has_help = true 19 | 20 | [Nextsim::DummyIceThermodynamics] 21 | file_prefix = DummyIceThermodynamics 22 | description = An implementation of the ice thermodynamics that does nothing. 23 | has_help = false 24 | -------------------------------------------------------------------------------- /physics/src/modules/LateralIceSpreadModule/include/DummyIceSpread.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file DummyIceSpread.hpp 3 | * 4 | * @date 04 Jun 2025 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef DUMMYICESPREAD_HPP 9 | #define DUMMYICESPREAD_HPP 10 | 11 | #include "include/ILateralIceSpread.hpp" 12 | 13 | namespace Nextsim { 14 | 15 | class DummyIceSpread : public ILateralIceSpread { 16 | public: 17 | DummyIceSpread() 18 | : ILateralIceSpread() 19 | { 20 | } 21 | ~DummyIceSpread() = default; 22 | 23 | void update(const TimestepTime& tstep) override { 24 | // No-op for dummy implementation 25 | }; 26 | }; 27 | 28 | } /* namespace Nextsim */ 29 | 30 | #endif /* DUMMYICESPREAD_HPP */ 31 | -------------------------------------------------------------------------------- /physics/src/modules/LateralIceSpreadModule/module.cfg: -------------------------------------------------------------------------------- 1 | [module] 2 | name = Nextsim::ILateralIceSpread 3 | file_prefix = LateralIceSpread 4 | interface_prefix = I 5 | header_path = include 6 | external_header_path = ../include 7 | description = The module calculating how freezing changes the ice concentration. 8 | 9 | [Nextsim::DummyIceSpread] 10 | file_prefix = DummyIceSpread 11 | description = No change in concentration. 12 | has_help = false 13 | 14 | [Nextsim::HiblerSpread] 15 | file_prefix = HiblerSpread 16 | description = Concentration changes after the scheme of Hibler (1979). 17 | has_help = true 18 | is_default = true 19 | -------------------------------------------------------------------------------- /physics/src/modules/OceanBoundaryModule/BenchmarkOcean.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file BenchmarkOcean.cpp 3 | * 4 | * @date 23 Aug 2024 5 | * @author Tim Spain 6 | */ 7 | 8 | #include "include/BenchmarkOcean.hpp" 9 | 10 | #include "include/BenchmarkCoordinates.hpp" 11 | #include "include/constants.hpp" 12 | 13 | namespace Nextsim { 14 | 15 | void BenchmarkOcean::setData(const ModelState::DataMap& ms) 16 | { 17 | IOceanBoundary::setData(ms); 18 | BenchmarkCoordinates::setData(); 19 | // The material parameters of the ocean are fixed to ensure no 20 | // thermodynamics occurs 21 | sst = -1.; 22 | sss = 32; 23 | tf = -1.8; 24 | mld = 10.; 25 | cpml = Water::rho * Water::cp * mld[0]; 26 | qio = 0; 27 | ssh = 0.; 28 | 29 | // The time and length scales of the current generation function 30 | constexpr double L = 512000.; // Size of the domain in km 31 | constexpr double vMaxOcean = 0.01; // 1 cm/s in m/s 32 | constexpr double T = 8 * 86400; // 8 days in seconds 33 | 34 | // The currents are constant wrt time and space 35 | u = vMaxOcean * (2 * BenchmarkCoordinates::fy() - 1); 36 | v = vMaxOcean * (1 - 2 * BenchmarkCoordinates::fx()); 37 | } 38 | 39 | } /* namespace Nextsim */ 40 | -------------------------------------------------------------------------------- /physics/src/modules/OceanBoundaryModule/ConstantOceanBoundary.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file ConstantOceanBoundary.cpp 3 | * 4 | * @date Aug 23, 2024 5 | * @author Tim Spain 6 | */ 7 | 8 | #include "include/ConstantOceanBoundary.hpp" 9 | 10 | #include "include/Finalizer.hpp" 11 | #include "include/IIceOceanHeatFlux.hpp" 12 | #include "include/NextsimModule.hpp" 13 | #include "include/constants.hpp" 14 | 15 | namespace Nextsim { 16 | ConstantOceanBoundary::ConstantOceanBoundary() 17 | : IOceanBoundary() 18 | { 19 | } 20 | 21 | void ConstantOceanBoundary::setData(const ModelState::DataMap& ms) 22 | { 23 | Finalizer::registerUnique(Module::finalize); 24 | 25 | IOceanBoundary::setData(ms); 26 | // Directly set the array values 27 | sss = 32.; 28 | u = 0; 29 | v = 0; 30 | mld = 10.; 31 | double tf32 = -1.751; // Hand calculated from S = 32 using UNESCO 32 | tf = tf32; 33 | sst = tf32; // Tf == SST ensures that there is no ice-ocean heat flux 34 | cpml = Water::cp * Water::rho * mld; 35 | qio = 0.; 36 | ssh = 0.; 37 | } 38 | 39 | void ConstantOceanBoundary::updateBefore(const TimestepTime& tst) 40 | { 41 | Module::getImplementation().update(tst); 42 | } 43 | 44 | void ConstantOceanBoundary::updateAfter(const TimestepTime& tst) { } 45 | } /* namespace Nextsim */ 46 | -------------------------------------------------------------------------------- /physics/src/modules/OceanBoundaryModule/UniformOcean.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file UniformOcean.cpp 3 | * 4 | * @date 06 Dec 2024 5 | * @author Tim Spain 6 | */ 7 | 8 | #include "include/UniformOcean.hpp" 9 | 10 | #include "include/IFreezingPoint.hpp" 11 | #include "include/NextsimModule.hpp" 12 | #include "include/constants.hpp" 13 | 14 | namespace Nextsim { 15 | 16 | void UniformOcean::setData(const ModelState::DataMap& ms) 17 | { 18 | IOceanBoundary::setData(ms); 19 | sst = sst0; 20 | sss = sss0; 21 | mld = mld0; 22 | u = u0; 23 | v = v0; 24 | tf = Module::getImplementation()(sss[0]); 25 | cpml = Water::rho * Water::cp * mld[0]; 26 | qio = qio0; 27 | 28 | /* It's only the SSH gradient which has an effect, so being able to set a constant SSH is 29 | * useless. */ 30 | ssh = 0.; 31 | } 32 | 33 | UniformOcean& UniformOcean::setSST(double sstIn) 34 | { 35 | sst0 = sstIn; 36 | return *this; 37 | } 38 | UniformOcean& UniformOcean::setSSS(double sssIn) 39 | { 40 | sss0 = sssIn; 41 | return *this; 42 | } 43 | UniformOcean& UniformOcean::setMLD(double mldIn) 44 | { 45 | mld0 = mldIn; 46 | return *this; 47 | } 48 | UniformOcean& UniformOcean::setU(double uIn) 49 | { 50 | u0 = uIn; 51 | return *this; 52 | } 53 | UniformOcean& UniformOcean::setV(double vIn) 54 | { 55 | v0 = vIn; 56 | return *this; 57 | } 58 | UniformOcean& UniformOcean::setQio(double qioIn) 59 | { 60 | qio0 = qioIn; 61 | return *this; 62 | } 63 | 64 | } /* namespace Nextsim */ 65 | -------------------------------------------------------------------------------- /physics/src/modules/OceanBoundaryModule/include/BenchmarkOcean.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file BenchmarkOcean.hpp 3 | * 4 | * @date 24 Sep 2024 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef BENCHMARKOCEAN_HPP 9 | #define BENCHMARKOCEAN_HPP 10 | 11 | #include "include/IOceanBoundary.hpp" 12 | 13 | namespace Nextsim { 14 | 15 | class BenchmarkOcean : public IOceanBoundary { 16 | public: 17 | BenchmarkOcean() 18 | : IOceanBoundary() 19 | { 20 | } 21 | ~BenchmarkOcean() = default; 22 | 23 | void setData(const ModelState::DataMap&) override; 24 | std::string getName() const override { return "BenchmarkOcean"; } 25 | 26 | void updateBefore(const TimestepTime& tst) override {}; 27 | void updateAfter(const TimestepTime& tst) override { } 28 | }; 29 | 30 | } /* namespace Nextsim */ 31 | 32 | #endif /* BENCHMARKOCEAN_HPP */ 33 | -------------------------------------------------------------------------------- /physics/src/modules/OceanBoundaryModule/include/ConfiguredOcean.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file ConfiguredOcean.hpp 3 | * 4 | * @date Aug 31, 2022 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef CONFIGUREDOCEAN_HPP 9 | #define CONFIGUREDOCEAN_HPP 10 | 11 | #include "include/IOceanBoundary.hpp" 12 | 13 | #include "include/Configured.hpp" 14 | #include "include/SlabOcean.hpp" 15 | 16 | namespace Nextsim { 17 | 18 | //! A class to provide constant oceanic forcings that can be configured at run 19 | //! time as physical variables. 20 | class ConfiguredOcean : public IOceanBoundary, public Configured { 21 | public: 22 | ConfiguredOcean(); 23 | ~ConfiguredOcean() = default; 24 | 25 | enum { 26 | SST_KEY, 27 | SSS_KEY, 28 | MLD_KEY, 29 | CURRENTU_KEY, 30 | CURRENTV_KEY, 31 | }; 32 | 33 | void setData(const ModelState::DataMap&) override; 34 | std::string getName() const override { return "ConfiguredOcean"; } 35 | 36 | static HelpMap& getHelpRecursive(HelpMap& map, bool getAll); 37 | 38 | void configure() override; 39 | ConfigMap getConfiguration() const override; 40 | 41 | ModelState getStatePrognostic() const override; 42 | ModelState getStateDiagnostic() const override; 43 | void updateBefore(const TimestepTime& tst) override; 44 | void updateAfter(const TimestepTime& tst) override; 45 | 46 | private: 47 | static double sst0; 48 | static double sss0; 49 | static double mld0; 50 | static double u0; 51 | static double v0; 52 | 53 | // External SS* fields to feed the slab ocean 54 | HField sstExt; 55 | HField sssExt; 56 | 57 | // We need a slab ocean in this implementation 58 | SlabOcean slabOcean; 59 | }; 60 | 61 | } /* namespace Nextsim */ 62 | 63 | #endif /* CONFIGUREDOCEAN_HPP */ 64 | -------------------------------------------------------------------------------- /physics/src/modules/OceanBoundaryModule/include/ConstantOceanBoundary.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file ConstantOceanBoundary.hpp 3 | * 4 | * @date Sep 26, 2022 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef CONSTANTOCEANBOUNDARY_HPP 9 | #define CONSTANTOCEANBOUNDARY_HPP 10 | 11 | #include "include/IOceanBoundary.hpp" 12 | 13 | namespace Nextsim { 14 | 15 | //* Ocean boundary data values that are hardcoded. 16 | class ConstantOceanBoundary : public IOceanBoundary { 17 | public: 18 | ConstantOceanBoundary(); 19 | 20 | std::string getName() const override { return "ConstantOceanBoundary"; } 21 | void setData(const ModelState::DataMap&) override; 22 | void updateBefore(const TimestepTime& tst) override; 23 | void updateAfter(const TimestepTime& tst) override; 24 | }; 25 | 26 | } /* namespace Nextsim */ 27 | 28 | #endif /* CONSTANTOCEANBOUNDARY_HPP */ 29 | -------------------------------------------------------------------------------- /physics/src/modules/OceanBoundaryModule/include/FluxConfiguredOcean.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file FluxConfiguredOcean.hpp 3 | * 4 | * @date Sep 29, 2022 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef FLUXCONFIGUREDOCEAN_HPP 9 | #define FLUXCONFIGUREDOCEAN_HPP 10 | 11 | #include "include/IOceanBoundary.hpp" 12 | 13 | #include "include/Configured.hpp" 14 | 15 | namespace Nextsim { 16 | 17 | //! A class to provide constant oceanic forcings that can be configured at run time. 18 | class FluxConfiguredOcean : public IOceanBoundary, public Configured { 19 | public: 20 | FluxConfiguredOcean() = default; 21 | ~FluxConfiguredOcean() = default; 22 | 23 | enum { 24 | QIO_KEY, 25 | SST_KEY, 26 | SSS_KEY, 27 | MLD_KEY, 28 | CURRENTU_KEY, 29 | CURRENTV_KEY, 30 | }; 31 | 32 | void setData(const ModelState::DataMap&) override; 33 | std::string getName() const override { return "FluxConfiguredOcean"; } 34 | 35 | static HelpMap& getHelpRecursive(HelpMap& map, bool getAll); 36 | 37 | void configure() override; 38 | ConfigMap getConfiguration() const override; 39 | 40 | void updateBefore(const TimestepTime& tst) override { } 41 | void updateAfter(const TimestepTime& tst) override { } 42 | 43 | private: 44 | static double qio0; 45 | static double sst0; 46 | static double sss0; 47 | static double mld0; 48 | static double u0; 49 | static double v0; 50 | }; 51 | 52 | } /* namespace Nextsim */ 53 | 54 | #endif /* FLUXCONFIGUREDOCEAN_HPP */ 55 | -------------------------------------------------------------------------------- /physics/src/modules/OceanBoundaryModule/include/TOPAZOcean.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file TOPAZOcean.hpp 3 | * 4 | * @date 03 Jun 2025 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef TOPAZOCEAN_HPP 9 | #define TOPAZOCEAN_HPP 10 | 11 | #include "include/IOceanBoundary.hpp" 12 | 13 | #include "include/Configured.hpp" 14 | #include "include/SlabOcean.hpp" 15 | 16 | namespace Nextsim { 17 | 18 | /*! 19 | * A class to provided forcings from pre-processed forcings files based on ERA5 20 | * data. 21 | */ 22 | class TOPAZOcean : public IOceanBoundary, public Configured { 23 | public: 24 | TOPAZOcean(); 25 | ~TOPAZOcean() = default; 26 | 27 | enum { 28 | FILEPATH_KEY, 29 | }; 30 | 31 | void setData(const ModelState::DataMap&) override; 32 | std::string getName() const override { return "TOPAZOcean"; } 33 | 34 | static HelpMap& getHelpRecursive(HelpMap& map, bool getAll); 35 | 36 | void configure() override; 37 | ConfigMap getConfiguration() const override; 38 | 39 | void updateBefore(const TimestepTime&) override; 40 | void updateAfter(const TimestepTime&) override; 41 | ModelState getStatePrognostic() const override; 42 | ModelState getStateDiagnostic() const override; 43 | 44 | void setFilePath(const std::string& filePathIn); 45 | 46 | private: 47 | // Updates the freezing point of an element 48 | void updateTf(size_t i, const TimestepTime& tst); 49 | // Since the configuration is global, it makes sense for the file path to 50 | // be static. 51 | static std::string filePath; 52 | 53 | HField sstExt; 54 | HField sssExt; 55 | 56 | SlabOcean slabOcean; 57 | }; 58 | 59 | } /* namespace Nextsim */ 60 | 61 | #endif /* TOPAZOCEAN_HPP_ */ 62 | -------------------------------------------------------------------------------- /physics/src/modules/OceanBoundaryModule/include/UniformOcean.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file UniformOcean.hpp 3 | * 4 | * @date 30 Mar 2023 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef UNIFORMOCEAN_HPP 9 | #define UNIFORMOCEAN_HPP 10 | 11 | #include "include/IOceanBoundary.hpp" 12 | 13 | namespace Nextsim { 14 | 15 | //* Ocean boundary values that are constant with space and time. 16 | class UniformOcean : public IOceanBoundary { 17 | public: 18 | UniformOcean() 19 | // The same defaults as ConstantOceanBoundary 20 | : UniformOcean(-1.5, 32., 10, 0., 0.) 21 | { 22 | } 23 | UniformOcean(double sstIn, double sssIn, double mldIn, double uIn = 0., double vIn = 0., 24 | double qioIn = 0.) 25 | : sst0(sstIn) 26 | , sss0(sssIn) 27 | , mld0(mldIn) 28 | , u0(uIn) 29 | , v0(vIn) 30 | , qio0(qioIn) 31 | { 32 | } 33 | 34 | std::string getName() const override { return "UniformOcean"; } 35 | void setData(const ModelState::DataMap&) override; 36 | void updateBefore(const TimestepTime&) override { } 37 | void updateAfter(const TimestepTime&) override { } 38 | // TODO ^add the SlabOcean when it becomes available 39 | 40 | UniformOcean& setSST(double); 41 | UniformOcean& setSSS(double); 42 | UniformOcean& setMLD(double); 43 | UniformOcean& setQio(double); 44 | UniformOcean& setU(double); 45 | UniformOcean& setV(double); 46 | 47 | private: 48 | double sst0; 49 | double sss0; 50 | double mld0; 51 | double u0; 52 | double v0; 53 | double qio0; 54 | }; 55 | 56 | } /* namespace Nextsim */ 57 | 58 | #endif /* UNIFORMOCEAN_HPP */ 59 | -------------------------------------------------------------------------------- /physics/src/modules/OceanBoundaryModule/module.cfg: -------------------------------------------------------------------------------- 1 | [module] 2 | name = Nextsim::IOceanBoundary 3 | file_prefix = OceanBoundary 4 | interface_prefix = I 5 | header_path = include 6 | external_header_path = ../include 7 | description = The module providing the ocean boundary conditions. 8 | 9 | [Nextsim::ConstantOceanBoundary] 10 | file_prefix = ConstantOceanBoundary 11 | description = An ocean boundary with constant values fixed at compile time. 12 | has_help = false 13 | is_default = true 14 | 15 | [Nextsim::ConfiguredOcean] 16 | file_prefix = ConfiguredOcean 17 | description = An ocean boundary with values fixed by configuration. 18 | has_help = true 19 | 20 | [Nextsim::FluxConfiguredOcean] 21 | file_prefix = FluxConfiguredOcean 22 | description = An ocean boundary with constant flux values fixed by configuration. 23 | has_help = true 24 | 25 | [Nextsim::TOPAZOcean] 26 | file_prefix = TOPAZOcean 27 | description = Ocean boundary conditions taken from the TOPAZ4 reanalysis. 28 | has_help = true 29 | 30 | [Nextsim::BenchmarkOcean] 31 | file_prefix = BenchmarkOcean 32 | description = Calculated ocean for the DG dynamics benchmark. 33 | has_help = false 34 | -------------------------------------------------------------------------------- /physics/src/modules/include/IDamageHealing.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file IDamageHealing.hpp 3 | * 4 | * @date 21 Nov 2024 5 | * @author Einar Ólason 6 | */ 7 | 8 | #ifndef IDAMAGEHEALING_HPP 9 | #define IDAMAGEHEALING_HPP 10 | 11 | #include "include/ModelArrayRef.hpp" 12 | #include "include/ModelComponent.hpp" 13 | 14 | namespace Nextsim { 15 | //! An interface class for modules controlling damage healing 16 | class IDamageHealing : public ModelComponent { 17 | public: 18 | virtual ~IDamageHealing() = default; 19 | 20 | std::string getName() const override { return "DamageHealing"; } 21 | void setData(const ModelState::DataMap& ms) override { } 22 | /*! 23 | * Updates the ice damage based on lateral ice growth and healing 24 | * 25 | * @param tStep The object containing the timestep start and duration times. 26 | */ 27 | virtual void update(const TimestepTime& tsTime) = 0; 28 | 29 | protected: 30 | IDamageHealing() 31 | : cice(getStore()) 32 | , deltaCi(getStore()) 33 | , damage(getStore()) 34 | , oldDamage(getStore()) 35 | { 36 | } 37 | 38 | ModelArrayRef cice; // From prognostic data 39 | ModelArrayRef deltaCi; // From LateralIceSpread 40 | ModelArrayRef damage; // From prognostic data 41 | ModelArrayRef oldDamage; // From prognostic data 42 | }; 43 | 44 | } /* namespace Nextsim */ 45 | 46 | #endif // IDAMAGEHEALING_HPP 47 | -------------------------------------------------------------------------------- /physics/src/modules/include/IIceAlbedo.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @file IIceAlbedo.hpp 3 | * 4 | * @date Aug 10, 2023 5 | * @author Tim Spain 6 | * @author Einar Örn Ólason 7 | */ 8 | 9 | #ifndef IICEALBEDO_HPP 10 | #define IICEALBEDO_HPP 11 | 12 | #include "include/Time.hpp" 13 | #include 14 | 15 | namespace Nextsim { 16 | //! The interface class for ice albedo calculation. 17 | class IIceAlbedo { 18 | public: 19 | virtual ~IIceAlbedo() = default; 20 | /*! 21 | * @brief A virtual function that calculates the ice surface short-wave 22 | * albedo and fraction of penetrating short-wave radiation. 23 | * 24 | * @param temperature The temperature of the ice surface. 25 | * @param snowThickness The true snow thickness on top of the ice. 26 | * @param i0 The fraction of short-wave radiation that can penetrate bare ice (not taking snow 27 | * cover into account). 28 | */ 29 | virtual std::tuple surfaceShortWaveBalance( 30 | double temperature, double snowThickness, double i0) 31 | = 0; 32 | 33 | /*! 34 | * Sets the time parameter for the implementation, if it is time dependent. 35 | * @param time The desired TimePoint. 36 | */ 37 | virtual void setTime(const TimePoint& tp) { } 38 | }; 39 | } 40 | #endif /* IICEALBEDO_HPP */ 41 | -------------------------------------------------------------------------------- /physics/src/modules/include/IIceOceanHeatFlux.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @file IIceOceanHeatFlux.hpp 3 | * 4 | * @date 24 Sep 2024 5 | * @author Tim Spain 6 | */ 7 | 8 | #ifndef IICEOCEANHEATFLUX_HPP 9 | #define IICEOCEANHEATFLUX_HPP 10 | 11 | #include "include/ModelArray.hpp" 12 | #include "include/ModelArrayRef.hpp" 13 | #include "include/ModelComponent.hpp" 14 | #include "include/Time.hpp" 15 | 16 | namespace Nextsim { 17 | 18 | //! The interface class for the ice-ocean heat flux calculation. 19 | class IIceOceanHeatFlux : public ModelComponent { 20 | public: 21 | IIceOceanHeatFlux() 22 | : sst(getStore()) 23 | , tf(getStore()) 24 | , cice(getStore()) 25 | , qio(getStore()) 26 | { 27 | } 28 | virtual ~IIceOceanHeatFlux() = default; 29 | 30 | // This superclass has no state 31 | void setData(const ModelState::DataMap&) override {}; 32 | std::string getName() const override { return "IIceOceanHeatFlux"; } 33 | 34 | /*! 35 | * Updates the ice ocean heat flux calculation for the timestep. 36 | * 37 | * @param tStep The object containing the timestep start and duration times. 38 | */ 39 | virtual void update(const TimestepTime&) = 0; 40 | 41 | protected: 42 | ModelArrayRef sst; 43 | ModelArrayRef tf; 44 | ModelArrayRef cice; 45 | 46 | ModelArrayRef qio; 47 | }; 48 | } 49 | #endif /* IICEOCEANHEATFLUX_HPP_ */ 50 | -------------------------------------------------------------------------------- /physics/test/ConstantOceanBoundary_test.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file ConstantOceanBoundary_test.cpp 3 | * 4 | * @date 7 Sep 2023 5 | * @author Tim Spain 6 | */ 7 | 8 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 9 | #include 10 | 11 | #include "include/ConstantOceanBoundary.hpp" 12 | 13 | #include "include/ModelArrayRef.hpp" 14 | #include "include/ModelState.hpp" 15 | 16 | namespace Nextsim { 17 | 18 | TEST_SUITE_BEGIN("ConstantOceanBoundary"); 19 | TEST_CASE("ConstantOcean Qio calculation") 20 | { 21 | ModelArray::setDimensions(ModelArray::Type::H, { 1, 1 }); 22 | 23 | HField cice(ModelArray::Type::H); 24 | cice = 1.0; // Need some ice if Qio is to be calculated 25 | ModelComponent::getStore().registerArray(Protected::C_ICE, &cice, RO); 26 | ConstantOceanBoundary cob; 27 | 28 | cob.setData(ModelState::DataMap()); 29 | cob.updateBefore(TimestepTime()); 30 | ModelArrayRef qio(ModelComponent::getStore()); 31 | 32 | REQUIRE(qio[0] != 0.); 33 | } 34 | TEST_SUITE_END(); 35 | } 36 | -------------------------------------------------------------------------------- /physics/test/IceMinima_test.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file IceMinima_test.cpp 3 | * 4 | * @date 25 May 2023 5 | * @author Tim Spain 6 | */ 7 | 8 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 9 | #include 10 | 11 | #include "include/IceMinima.hpp" 12 | 13 | namespace Nextsim { 14 | 15 | class IceGrowth { 16 | public: 17 | inline static void setMinima(double hMin, double cMin) 18 | { 19 | IceMinima::hMin = hMin; 20 | IceMinima::cMin = cMin; 21 | } 22 | }; 23 | 24 | TEST_SUITE_BEGIN("IceMinima"); 25 | TEST_CASE("Set and retrieve ice minima values") 26 | { 27 | // IceGrowth is a friend of IceMinima. Here is a class IceGrowth that 28 | // directly sets the minimum values without configuration. 29 | const double hMinTest = 0.1; 30 | const double cMinTest = 1e-6; 31 | 32 | IceGrowth::setMinima(hMinTest, cMinTest); 33 | REQUIRE(IceMinima::h() == hMinTest); 34 | REQUIRE(IceMinima::c() == cMinTest); 35 | } 36 | TEST_SUITE_END(); 37 | } 38 | -------------------------------------------------------------------------------- /physics/test/SpecificHumidity_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @file SpecificHumidity_test.cpp 3 | * 4 | * @date 24 Sep 2024 5 | * @author Tim Spain 6 | */ 7 | 8 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 9 | #include 10 | 11 | #include "include/FiniteElementSpecHum.hpp" 12 | 13 | namespace Nextsim { 14 | 15 | TEST_SUITE_BEGIN("FiniteElementSpecHum"); 16 | TEST_CASE("Specific humidity test") 17 | { 18 | double tair = -3; 19 | double tdew = 0.1; 20 | double pair = 100000; // Slightly low pressure 21 | double sst = -1; 22 | double sss = 32; // PSU 23 | std::vector tice = { -2., -2, -2 }; 24 | 25 | FiniteElementSpecHum& feshw = FiniteElementSpecHum::water(); 26 | FiniteElementSpecHum& feshi = FiniteElementSpecHum::ice(); 27 | double water = feshw(sst, pair, sss); 28 | double air = feshw(tdew, pair); 29 | double ice = feshi(tice[0], pair); 30 | 31 | double prec = 1e-4; 32 | REQUIRE(0.00385326 == doctest::Approx(air).epsilon(prec)); 33 | REQUIRE(0.00349446 == doctest::Approx(water).epsilon(prec)); 34 | REQUIRE(0.00323958 == doctest::Approx(ice).epsilon(prec)); 35 | } 36 | TEST_SUITE_END(); 37 | 38 | } /* namespace Nextsim */ 39 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | sphinx>=4.4.0 2 | myst_parser>=0.15.2 3 | sphinx_rtd_theme 4 | breathe 5 | Jinja2<3.1 6 | exhale 7 | -------------------------------------------------------------------------------- /run/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Generate the example restart files that don't depend on external data 2 | execute_process( 3 | COMMAND "${Python_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/make_init_rect20x30.py" 4 | WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" 5 | ) 6 | execute_process( 7 | COMMAND "${Python_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/make_init.py" 8 | WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" 9 | ) 10 | execute_process( 11 | COMMAND "${Python_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/make_init_column.py" 12 | WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" 13 | ) 14 | execute_process( 15 | COMMAND "${Python_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/make_init_para24x30.py" 16 | WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" 17 | ) 18 | execute_process( 19 | COMMAND "${Python_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/make_init_benchmark.py" 20 | WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" 21 | ) 22 | -------------------------------------------------------------------------------- /run/config_benchmark.cfg: -------------------------------------------------------------------------------- 1 | [model] 2 | init_file = init_benchmark_32x32.nc 3 | start = 2023-01-01T00:00:00Z 4 | stop = 2023-01-03T00:00:00Z 5 | time_step = P0-0T00:02:00 6 | 7 | [Modules] 8 | DiagnosticOutputModule = Nextsim::ConfigOutput 9 | DynamicsModule = Nextsim::MEVPDynamics 10 | IceThermodynamicsModule = Nextsim::DummyIceThermodynamics 11 | LateralIceSpreadModule = Nextsim::DummyIceSpread 12 | AtmosphereBoundaryModule = Nextsim::BenchmarkAtmosphere 13 | OceanBoundaryModule = Nextsim::BenchmarkOcean 14 | 15 | [ConfigOutput] 16 | period = P0-0T04:00:00 17 | start = 2010-01-01T12:00:00Z 18 | field_names = hsnow,hice,cice,u,v,shear 19 | filename = benchmark_32x32.diagnostic.nc 20 | -------------------------------------------------------------------------------- /run/config_column.cfg: -------------------------------------------------------------------------------- 1 | [model] 2 | init_file = init_column.nc 3 | start = 1900-01-01T00:00:00Z 4 | stop = 2011-01-01T00:00:00Z 5 | time_step = P0-1T00:00:00 6 | 7 | [Modules] 8 | DiagnosticOutputModule = Nextsim::ConfigOutput 9 | IceAlbedoModule = Nextsim::WintonAlbedo 10 | AtmosphereBoundaryModule = Nextsim::MU71Atmosphere 11 | OceanBoundaryModule = Nextsim::FluxConfiguredOcean 12 | IceThermodynamicsModule = Nextsim::ThermoWinton 13 | 14 | [ConfigOutput] 15 | start = 2010-01-01T00:00:00Z 16 | field_names = hsnow,hice,tsurf,tinterior,tbottom 17 | 18 | [FluxConfiguredOcean] 19 | # qio = 1.5 * 4.184e7 / (365.2425 * 24. * 3600.) = 1.9887852286874852 20 | # Convert from 1.5 kcal/cm^2/year to W/m^2 21 | qio = 2.30 22 | sss = 28 23 | sst = -1.54 24 | mld = 10. 25 | current_u = 0. 26 | current_v = 0. 27 | 28 | [nextsim_thermo] 29 | I_0 = 0.3 30 | ks = 0.31 31 | 32 | [WintonAlbedo] 33 | iceAlbedo = 0.65 -------------------------------------------------------------------------------- /run/config_configoutput.cfg: -------------------------------------------------------------------------------- 1 | [model] 2 | init_file = init_rect30x30.nc 3 | start = 2010-04-01T00:00:00Z 4 | stop = 2010-04-02T00:00:00Z 5 | time_step = P0-0T0:10:0 6 | 7 | [Modules] 8 | DiagnosticOutputModule = Nextsim::ConfigOutput 9 | 10 | [ConfigOutput] 11 | period = P0-0T1:0:0 12 | start = 2010-04-01T12:00:00Z 13 | field_names = hice,cice,tsurf 14 | -------------------------------------------------------------------------------- /run/config_dynamics.cfg: -------------------------------------------------------------------------------- 1 | [model] 2 | #init_file = init_topaz128x128.nc 3 | init_file = init_25km_NH.nc 4 | start = 2023-01-01T00:00:00Z 5 | stop = 2023-01-03T00:00:00Z 6 | time_step = P0-0T00:02:00 7 | 8 | [Modules] 9 | DiagnosticOutputModule = Nextsim::ConfigOutput 10 | DynamicsModule = Nextsim::Dynamics 11 | IceThermodynamicsModule = Nextsim::DummyIceThermodynamics 12 | LateralIceSpreadModule = Nextsim::DummyIceSpread 13 | 14 | [ConfigOutput] 15 | period = P0-0T04:00:00 16 | start = 2010-01-01T12:00:00Z 17 | field_names = hsnow,hice,tsurf,cice 18 | 19 | [ERA5Atmosphere] 20 | file = 25km_NH.ERA5_2010-01-01_2011-01-01.nc 21 | 22 | [TOPAZOcean] 23 | file = 25km_NH.TOPAZ4_2010-01-01_2011-01-01.nc 24 | 25 | -------------------------------------------------------------------------------- /run/config_june23.cfg: -------------------------------------------------------------------------------- 1 | [model] 2 | init_file = init_25km_NH.nc 3 | start = 2010-01-01T00:00:00Z 4 | stop = 2011-01-01T00:00:00Z 5 | time_step = P0-0T00:15:00 6 | 7 | 8 | [Modules] 9 | DiagnosticOutputModule = Nextsim::ConfigOutput 10 | DynamicsModule = Nextsim::BBMDynamics 11 | IceThermodynamicsModule = Nextsim::ThermoWinton 12 | AtmosphereBoundaryModule = Nextsim::ERA5Atmosphere 13 | OceanBoundaryModule = Nextsim::TOPAZOcean 14 | 15 | [ConfigOutput] 16 | period = P0-1T0:00:00 17 | start = 2010-01-01T00:00:00Z 18 | field_names = hsnow,hice,tsurf,tinterior,tbottom,cice 19 | filename = june23.diagnostic.nc 20 | 21 | [ERA5Atmosphere] 22 | file = 25km_NH.ERA5_2010-01-01_2011-01-01.nc 23 | 24 | [TOPAZOcean] 25 | file = 25km_NH.TOPAZ4_2010-01-01_2011-01-01.nc 26 | -------------------------------------------------------------------------------- /run/config_nares.cfg: -------------------------------------------------------------------------------- 1 | [model] 2 | init_file = init_nares_128x64.nc 3 | start = 2023-01-01T00:00:00Z 4 | stop = 2023-01-03T00:00:00Z 5 | time_step = P0-0T00:02:00 6 | 7 | [Modules] 8 | DiagnosticOutputModule = Nextsim::ConfigOutput 9 | DynamicsModule = Nextsim::BBMDynamics 10 | IceThermodynamicsModule = Nextsim::DummyIceThermodynamics 11 | LateralIceSpreadModule = Nextsim::DummyIceSpread 12 | AtmosphereBoundaryModule = Nextsim::BenchmarkAtmosphere 13 | OceanBoundaryModule = Nextsim::ConstantOceanBoundary 14 | 15 | [ConfigOutput] 16 | period = P0-0T01:00:00 17 | start = 2010-01-01T12:00:00Z 18 | field_names = hsnow,hice,cice,damage,u,v 19 | filename = nares_128x64.diagnostic.nc 20 | -------------------------------------------------------------------------------- /run/config_para24x30.cfg: -------------------------------------------------------------------------------- 1 | [model] 2 | init_file = init_para24x30.nc 3 | start = 2020-01-01T00:00:00Z 4 | stop = 2020-01-06T00:00:00Z 5 | time_step = P0-0T00:15:00 6 | 7 | 8 | [Modules] 9 | DiagnosticOutputModule = Nextsim::ConfigOutput 10 | DynamicsModule = Nextsim::MEVPDynamics 11 | IceThermodynamicsModule = Nextsim::ThermoIce0 12 | AtmosphereBoundaryModule = Nextsim::FluxConfiguredAtmosphere 13 | OceanBoundaryModule = Nextsim::FluxConfiguredOcean 14 | 15 | [ConfigOutput] 16 | period = P0-1T0:00:00 17 | start = 2010-01-01T00:00:00Z 18 | field_names = hsnow,hice,tsurf,cice 19 | filename = para24x30.diagnostic.nc 20 | -------------------------------------------------------------------------------- /run/config_rect10x10.cfg: -------------------------------------------------------------------------------- 1 | [model] 2 | init_file = init_rect10x10.nc 3 | start = 1999-01-01T00:00:00Z 4 | stop = 1999-01-01T00:00:01Z 5 | time_step = P0-0T0:0:1 6 | -------------------------------------------------------------------------------- /run/config_rect20x30.cfg: -------------------------------------------------------------------------------- 1 | [model] 2 | init_file = init_rect20x30.nc 3 | start = 1999-01-01T00:00:00Z 4 | stop = 1999-01-01T00:00:01Z 5 | time_step = P0-0T0:0:1 6 | -------------------------------------------------------------------------------- /run/config_simple_example.cfg: -------------------------------------------------------------------------------- 1 | [model] 2 | init_file = init_rect30x30.nc 3 | start = 2010-04-01T00:00:00Z 4 | stop = 2010-04-02T00:00:00Z 5 | time_step = P0-0T0:10:0 6 | missing_value = -3.40282346638e+38 7 | -------------------------------------------------------------------------------- /run/config_topaz128x128.cfg: -------------------------------------------------------------------------------- 1 | [model] 2 | init_file = init_topaz128x128.nc 3 | start = 2010-01-01T00:00:00Z 4 | stop = 2011-01-01T00:00:00Z 5 | time_step = P0-0T0:10:0 6 | 7 | [Modules] 8 | DiagnosticOutputModule = Nextsim::ConfigOutput 9 | AtmosphereBoundaryModule = Nextsim::ERA5Atmosphere 10 | OceanBoundaryModule = Nextsim::TOPAZOcean 11 | 12 | [ConfigOutput] 13 | period = P0-1T0:0:0 14 | start = 2010-01-01T00:00:00Z 15 | field_names = hice_true,cice,tsurf,hsnow_true,sst,sss 16 | 17 | [ERA5Atmosphere] 18 | file = ERA5_2010-01-01_2011-01-01.nc 19 | 20 | [TOPAZOcean] 21 | file = TOPAZ4_2010-01-01_2011-01-01.nc -------------------------------------------------------------------------------- /run/make_init_benchmark.py: -------------------------------------------------------------------------------- 1 | from make_init_base import initMaker 2 | from math import sin 3 | 4 | # Creates initial conditions for the Mehlmann et al. (2021) benchmark case, at 2, 4, 8, and 16 km resolutions. 5 | 6 | # Domain size [km] 7 | L = 512 8 | for res in [2, 4, 8, 16]: 9 | 10 | nfirst = int(L / res) 11 | nsecond = int(L / res) 12 | 13 | fname = f"init_benchmark_{nfirst}x{nsecond}.nc" 14 | 15 | initializer = initMaker(fname, nfirst, nsecond, res*1e3, checkZeros=False) 16 | # The model expects everything in metres, while the benchmark problem in Mehlman et al. (2021) is defined in km. 17 | 18 | # Ice everywhere and all boundaries closed 19 | initializer.mask[:, :] = 1. 20 | initializer.mask[0, :] = 0. 21 | initializer.mask[-1, :] = 0. 22 | initializer.mask[:, 0] = 0. 23 | initializer.mask[:, -1] = 0. 24 | 25 | # Uniform concentration of 100% 26 | initializer.cice[:, :] = 1. 27 | 28 | # Loop over ice thickness to construct the initial conditions. This should be a pattern of undulating ice. 29 | for ix in range(nfirst): 30 | x = ix * res 31 | for iy in range(nsecond): 32 | y = iy * res 33 | initializer.hice[ix, iy] = 0.3 + 0.005 * (sin(60e-3 * x) + sin(30e-3 * y)) 34 | 35 | initializer.damage[:, :] = 1. 36 | 37 | # All other variables are zero or not needed 38 | 39 | # The file is written when initializer goes out of scope 40 | -------------------------------------------------------------------------------- /run/make_init_column.py: -------------------------------------------------------------------------------- 1 | from make_init_base import initMaker 2 | 3 | nfirst = 1 4 | nsecond = 1 5 | resolution = 50 6 | 7 | initializer = initMaker("init_column.nc", nfirst, nsecond, resolution, isWinton=True, checkZeros=False) 8 | 9 | ice_salinity = 5 # should match Ice::s in constants.hpp 10 | mu: float = -0.055 # should match Water::mu in constants.hpp 11 | ocean_temperature = -1.54 12 | ocean_salinity = ocean_temperature / mu 13 | 14 | initializer.mask[:, :] = 1 15 | initializer.cice[:, :] = 1. 16 | initializer.hice[:, :] = 2. 17 | initializer.hsnow[:, :] = 0.3 18 | initializer.sss[:, :] = ocean_salinity 19 | initializer.sst[:, :] = ocean_temperature 20 | initializer.tsurf[:, :] = ice_salinity * mu 21 | initializer.tintr[:, :] = ice_salinity * mu 22 | initializer.tbott[:, :] = ice_salinity * mu -------------------------------------------------------------------------------- /run/partition.cdl: -------------------------------------------------------------------------------- 1 | // partition.cdl 2 | netcdf partition { 3 | dimensions: 4 | P = 1 ; 5 | L = 1 ; 6 | NX = 30 ; 7 | NY = 30 ; 8 | 9 | group: bounding_boxes { 10 | variables: 11 | int domain_x(P) ; 12 | int domain_y(P) ; 13 | int domain_extent_x(P) ; 14 | int domain_extent_y(P) ; 15 | data: 16 | 17 | domain_x = 0 ; 18 | 19 | domain_y = 0 ; 20 | 21 | domain_extent_x = 30 ; 22 | 23 | domain_extent_y = 30 ; 24 | } // group bounding_boxes 25 | } 26 | 27 | -------------------------------------------------------------------------------- /run/partition_metadata_2.cdl: -------------------------------------------------------------------------------- 1 | // partition_metadata_2.cdl 2 | netcdf partition_metadata_2 { 3 | dimensions: 4 | NX = 30 ; 5 | NY = 30 ; 6 | P = 2 ; 7 | T = UNLIMITED ; // (0 currently) 8 | B = UNLIMITED ; // (0 currently) 9 | L = 1 ; 10 | R = 1 ; 11 | 12 | group: bounding_boxes { 13 | variables: 14 | int domain_x(P) ; 15 | int domain_y(P) ; 16 | int domain_extent_x(P) ; 17 | int domain_extent_y(P) ; 18 | data: 19 | 20 | domain_x = 0, 0 ; 21 | 22 | domain_y = 0, 16 ; 23 | 24 | domain_extent_x = 30, 30 ; 25 | 26 | domain_extent_y = 16, 14 ; 27 | } // group bounding_boxes 28 | 29 | group: connectivity { 30 | variables: 31 | int top_neighbors(P) ; 32 | int top_neighbor_ids(T) ; 33 | int top_neighbor_halos(T) ; 34 | int bottom_neighbors(P) ; 35 | int bottom_neighbor_ids(B) ; 36 | int bottom_neighbor_halos(B) ; 37 | int left_neighbors(P) ; 38 | int left_neighbor_ids(L) ; 39 | int left_neighbor_halos(L) ; 40 | int right_neighbors(P) ; 41 | int right_neighbor_ids(R) ; 42 | int right_neighbor_halos(R) ; 43 | data: 44 | 45 | top_neighbors = 0, 0 ; 46 | 47 | bottom_neighbors = 0, 0 ; 48 | 49 | left_neighbors = 0, 1 ; 50 | 51 | left_neighbor_ids = 0 ; 52 | 53 | left_neighbor_halos = 30 ; 54 | 55 | right_neighbors = 1, 0 ; 56 | 57 | right_neighbor_ids = 1 ; 58 | 59 | right_neighbor_halos = 30 ; 60 | } // group connectivity 61 | } 62 | 63 | -------------------------------------------------------------------------------- /run/run_dynamics.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | if [ ! -f nextsim ]; then 3 | echo "Copy or link the nextsim executable here from the build directory" 4 | fi 5 | ./nextsim --config-file config_dynamics.cfg 6 | -------------------------------------------------------------------------------- /run/run_june23.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | if [ ! -f nextsim ]; then 3 | echo "Copy or link the nextsim executable here from the build directory" 4 | fi 5 | ./nextsim --config-file config_june23.cfg "$@" 6 | -------------------------------------------------------------------------------- /run/run_rect20x30.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | if [ ! -f nextsim ]; then 3 | echo "Copy or link the nextsim executable here from the build directory" 4 | fi 5 | ./nextsim --config-file config_rect20x30.cfg 6 | -------------------------------------------------------------------------------- /run/run_simple_example.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | if [ ! -f nextsim ]; then 3 | echo "Copy or link the nextsim executable here from the build directory" 4 | fi 5 | ./nextsim --config-file config_simple_example.cfg 6 | -------------------------------------------------------------------------------- /run/run_topaz128x128.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | if [ ! -f nextsim ]; then 3 | echo "Copy or link the nextsim executable here from the build directory" 4 | fi 5 | ./nextsim --config-file config_topaz128x128.cfg "$@" 6 | -------------------------------------------------------------------------------- /spack.yaml: -------------------------------------------------------------------------------- 1 | spack: 2 | packages: 3 | all: 4 | compiler: [gcc@10:] 5 | specs: 6 | - boost@1.80.0+log+program_options 7 | - catch2 8 | - 'cmake@3.20:' 9 | - eigen@3.4.0 10 | - gmake 11 | - hdf5@1.14.3 12 | - netcdf-c@4.9.2+mpi+parallel-netcdf 13 | - netcdf-cxx4@4.3.1 14 | - netcdf-fortran 15 | - openmpi@4.1.6 16 | - trilinos 17 | - zlib-ng@2.1.4 18 | - zoltan 19 | concretizer: 20 | unify: true 21 | reuse: true 22 | view: true 23 | -------------------------------------------------------------------------------- /test/integration_test.cfg: -------------------------------------------------------------------------------- 1 | [model] 2 | init_file = init_25km_NH.nc 3 | start = 2010-01-01T00:00:00Z 4 | stop = 2010-01-01T01:00:00Z 5 | time_step = P0-0T00:20:00 6 | restart_file = out.integration_test.nc 7 | 8 | 9 | [Modules] 10 | DiagnosticOutputModule = Nextsim::NoOutput 11 | DynamicsModule = Nextsim::BBMDynamics 12 | IceThermodynamicsModule = Nextsim::ThermoWinton 13 | AtmosphereBoundaryModule = Nextsim::ERA5Atmosphere 14 | OceanBoundaryModule = Nextsim::TOPAZOcean 15 | 16 | [ERA5Atmosphere] 17 | file = 25km_NH.ERA5_2010-01-01T000000_test_data.nc 18 | 19 | [TOPAZOcean] 20 | file = 25km_NH.TOPAZ4_2010-01-01T000000_test_data.nc 21 | 22 | -------------------------------------------------------------------------------- /test/run_integration_test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | if [ ! -f ../nextsim ]; then 3 | echo "Copy or link the nextsim executableinto the parent directory from the build directory" 4 | fi 5 | ../nextsim --config-file integration_test.cfg "$@" 6 | -------------------------------------------------------------------------------- /test/run_test_jan2010_integration_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Get the name of the python executable 4 | if [ $# -lt 1 ] 5 | then 6 | PYTHON=python 7 | else 8 | PYTHON=$1 9 | fi 10 | 11 | 12 | # Prepares, executes and test the nextSIM-DG integration test based on the 13 | # January 2010 Arctic simulation 14 | 15 | restart_file=init_25km_NH.nc 16 | era5_file=25km_NH.ERA5_2010-01-01T000000_test_data.nc 17 | topaz_file=25km_NH.TOPAZ4_2010-01-01T000000_test_data.nc 18 | out_file=out.integration_test.nc 19 | 20 | $PYTHON make_init25kmNH_test_data.py 21 | $PYTHON era5_topaz4_test_data.py 22 | echo run_integration_test.sh 23 | ./run_integration_test.sh 24 | $PYTHON test_integration_test.py 25 | test_return_value=$? 26 | rm $restart_file $era5_file $topaz_file $out_file 27 | rm nextsim.*.log 28 | 29 | exit $test_return_value 30 | --------------------------------------------------------------------------------