From c08a7a6d918bbeec2e896f5b535321723a4db021 Mon Sep 17 00:00:00 2001 From: Tony Craig Date: Wed, 6 Aug 2025 09:49:33 -0700 Subject: [PATCH 01/21] Update Icepack to #6a5c51e9e6c64, including bug fix in zap_small_areas Adds vicen, vsnon to zap_small_areas. This helps eliminate some sub-puny ice, but does not changes answers in a full test suite run on derecho with 4 compilers. Also cleans up some kind statements in the forcing module. --- icepack | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/icepack b/icepack index b91f1dd73..6a5c51e9e 160000 --- a/icepack +++ b/icepack @@ -1 +1 @@ -Subproject commit b91f1dd73d6c8475e6d94611f592b8036623bf78 +Subproject commit 6a5c51e9e6c643da0760a315e452755661d7d745 From 997835d667d5e0186b4c65d3fd21ec0c0cc9a176 Mon Sep 17 00:00:00 2001 From: Robert Grumbine Date: Fri, 8 Aug 2025 14:07:39 -0400 Subject: [PATCH 02/21] port for gaeac6 (#1043) Update the gaea port Support gaeac5 and gaeac6 as separate machines with the intel icx/ifort compiler. Remove the "gaea" port in favor of "gaeac5" and "gaeac6". Required some workaround for the intel/hdf5 compiler issues with the check uninit and fpe0. --------- Co-authored-by: apcraig --- configuration/scripts/cice.batch.csh | 4 +- .../scripts/machines/Macros.gaea_cray | 57 ------------------- .../scripts/machines/Macros.gaeac5_intel | 8 ++- ...{Macros.gaea_intel => Macros.gaeac6_intel} | 10 ++-- configuration/scripts/machines/env.gaea_cray | 44 -------------- .../scripts/machines/env.gaeac5_intel | 24 ++++---- .../{env.gaea_intel => env.gaeac6_intel} | 27 +++++---- 7 files changed, 36 insertions(+), 138 deletions(-) delete mode 100644 configuration/scripts/machines/Macros.gaea_cray rename configuration/scripts/machines/{Macros.gaea_intel => Macros.gaeac6_intel} (76%) delete mode 100644 configuration/scripts/machines/env.gaea_cray rename configuration/scripts/machines/{env.gaea_intel => env.gaeac6_intel} (53%) diff --git a/configuration/scripts/cice.batch.csh b/configuration/scripts/cice.batch.csh index 220313bfa..1de12f5ce 100755 --- a/configuration/scripts/cice.batch.csh +++ b/configuration/scripts/cice.batch.csh @@ -371,7 +371,7 @@ cat >> ${jobfile} << EOFB #SBATCH -J ${ICE_CASENAME} #SBATCH --partition=batch #SBATCH --qos=${queue} -#SBATCH --account=nggps_emc +#SBATCH --account=${acct} #SBATCH --clusters=c5 #SBATCH --time=${batchtime} #SBATCH --nodes=${nnodes} @@ -388,7 +388,7 @@ cat >> ${jobfile} << EOFB #SBATCH -J ${ICE_CASENAME} #SBATCH --partition=batch #SBATCH --qos=${queue} -#SBATCH --account=sfs_emc +#SBATCH --account=${acct} #SBATCH --clusters=c6 #SBATCH --time=${batchtime} #SBATCH --nodes=${nnodes} diff --git a/configuration/scripts/machines/Macros.gaea_cray b/configuration/scripts/machines/Macros.gaea_cray deleted file mode 100644 index 851134514..000000000 --- a/configuration/scripts/machines/Macros.gaea_cray +++ /dev/null @@ -1,57 +0,0 @@ -#============================================================================== -# Makefile macros for NOAA hera, intel compiler -#============================================================================== - -CPP := fpp -CPPDEFS := -DFORTRANUNDERSCORE ${ICE_CPPDEFS} -CFLAGS := -c -O2 - -FIXEDFLAGS := -132 -FREEFLAGS := -FFLAGS := -hbyteswapio -FFLAGS_NOOPT:= -O0 -LDLAGS := -hbyteswapio - -ifeq ($(ICE_BLDDEBUG), true) - FFLAGS += -O0 -hfp0 -g -Rbcdps -Ktrap=fp -else - FFLAGS += -O2 -hfp0 -endif - -SCC := cc -SFC := ftn -MPICC := cc -MPIFC := ftn - -ifeq ($(ICE_COMMDIR), mpi) - FC := $(MPIFC) - CC := $(MPICC) -else - FC := $(SFC) - CC := $(SCC) -endif -LD:= $(FC) - -NETCDF_PATH := $(NETCDF) - -#PIO_CONFIG_OPTS:= --enable-filesystem-hints=gpfs - -#PNETCDF_PATH := $(PNETCDF) -#PNETCDF_PATH := /glade/u/apps/ch/opt/pio/2.2/mpt/2.15f/intel/17.0.1/lib - -INC_NETCDF := $(NETCDF_PATH)/include -LIB_NETCDF := $(NETCDF_PATH)/lib - -#LIB_PNETCDF := $(PNETCDF_PATH)/lib -#LIB_MPI := $(IMPILIBDIR) - -INCLDIR := $(INCLDIR) -I$(INC_NETCDF) -#SLIBS := -L$(LIB_NETCDF) -lnetcdf -lnetcdff -L$(LIB_PNETCDF) -lpnetcdf -lgptl -SLIBS := -L$(LIB_NETCDF) -lnetcdf -lnetcdff - -ifeq ($(ICE_THREADED), true) - LDFLAGS += -fopenmp - CFLAGS += -fopenmp - FFLAGS += -fopenmp -endif - diff --git a/configuration/scripts/machines/Macros.gaeac5_intel b/configuration/scripts/machines/Macros.gaeac5_intel index 794070214..5a4c384fc 100644 --- a/configuration/scripts/machines/Macros.gaeac5_intel +++ b/configuration/scripts/machines/Macros.gaeac5_intel @@ -4,15 +4,17 @@ CPP := fpp CPPDEFS := -DFORTRANUNDERSCORE ${ICE_CPPDEFS} -CFLAGS := -c -O2 -fp-model precise -xHost +CFLAGS := -c -O2 -fp-model precise -march=core-avx2 FIXEDFLAGS := -132 FREEFLAGS := -FR -FFLAGS := -fp-model precise -convert big_endian -assume byterecl -ftz -traceback -align array64byte -xHost +FFLAGS := -fp-model precise -convert big_endian -assume byterecl -ftz -traceback -align array64byte -march=core-avx2 FFLAGS_NOOPT:= -O0 ifeq ($(ICE_BLDDEBUG), true) - FFLAGS += -O0 -g -check uninit -check bounds -check pointers -fpe0 -check noarg_temp_created -link_mpi=dbg + # 7/2025: cannot use -check uninit + # 7/2025: must use fpe1 rather than fpe0 + FFLAGS += -O0 -g -check bounds -check pointers -fpe1 -check noarg_temp_created -link_mpi=dbg else FFLAGS += -O2 endif diff --git a/configuration/scripts/machines/Macros.gaea_intel b/configuration/scripts/machines/Macros.gaeac6_intel similarity index 76% rename from configuration/scripts/machines/Macros.gaea_intel rename to configuration/scripts/machines/Macros.gaeac6_intel index f4c4d2cbe..9ba174738 100644 --- a/configuration/scripts/machines/Macros.gaea_intel +++ b/configuration/scripts/machines/Macros.gaeac6_intel @@ -1,18 +1,20 @@ #============================================================================== -# Makefile macros for NOAA hera, intel compiler +# Makefile macros for NOAA gaeac6, intel compiler #============================================================================== CPP := fpp CPPDEFS := -DFORTRANUNDERSCORE ${ICE_CPPDEFS} -CFLAGS := -c -O2 -fp-model precise -xHost +CFLAGS := -c -O2 -fp-model precise -march=core-avx2 FIXEDFLAGS := -132 FREEFLAGS := -FR -FFLAGS := -fp-model precise -convert big_endian -assume byterecl -ftz -traceback -align array64byte -xHost +FFLAGS := -fp-model precise -convert big_endian -assume byterecl -ftz -traceback -align array64byte -march=core-avx2 FFLAGS_NOOPT:= -O0 ifeq ($(ICE_BLDDEBUG), true) - FFLAGS += -O0 -g -check uninit -check bounds -check pointers -fpe0 -check noarg_temp_created -link_mpi=dbg +# no -check uninit 25 Jul 2025 +# fpe1 rather than fpe0 due to bug in hdf library 25 Jul 2025 + FFLAGS += -O0 -g -check bounds -check pointers -fpe1 -check noarg_temp_created -link_mpi=dbg else FFLAGS += -O2 endif diff --git a/configuration/scripts/machines/env.gaea_cray b/configuration/scripts/machines/env.gaea_cray deleted file mode 100644 index db62615ee..000000000 --- a/configuration/scripts/machines/env.gaea_cray +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/csh -f - -set inp = "undefined" -if ($#argv == 1) then - set inp = $1 -endif - -if ("$inp" != "-nomodules") then - -#source /lustre/f2/pdata/esrl/gsd/contrib/lua-5.1.4.9/init/init_lmod.csh -source $MODULESHOME/init/csh -module purge -module load PrgEnv-cray -module load cce/18.0.0 -module load cray-libsci/24.07.0 -module load cray-hdf5/1.14.3.1 -module load cray-netcdf/4.9.0.13 -setenv NETCDF $NETCDF_DIR -module list - -# May be needed for OpenMP memory -#setenv OMP_STACKSIZE 64M - -endif - -# May be needed for OpenMP memory -#setenv OMP_STACKSIZE 64M - -endif - -setenv ICE_MACHINE_MACHNAME gaea -setenv ICE_MACHINE_MACHINFO "Cray XC40 Intel Haswell/Broadwell 2.3GHz, Gemini Interconnect" -setenv ICE_MACHINE_ENVNAME intel -setenv ICE_MACHINE_ENVINFO "ifort 18.0.5 20180823, cray-mpich, cray-netcdf" -setenv ICE_MACHINE_MAKE gmake -setenv ICE_MACHINE_WKDIR $HOME/scratch/CICE_RUNS -setenv ICE_MACHINE_INPUTDATA /ncrc/home1/Robert.Grumbine/rgdev/CICE_INPUTDATA -setenv ICE_MACHINE_BASELINE $HOME/scratch/CICE_BASELINE -setenv ICE_MACHINE_SUBMIT "sbatch" -setenv ICE_MACHINE_TPNODE 40 -setenv ICE_MACHINE_ACCT P0000000 -setenv ICE_MACHINE_QUEUE "normal" -setenv ICE_MACHINE_BLDTHRDS 1 -setenv ICE_MACHINE_QSTAT "squeue --jobs=" diff --git a/configuration/scripts/machines/env.gaeac5_intel b/configuration/scripts/machines/env.gaeac5_intel index 69bddb428..2fbbffef8 100644 --- a/configuration/scripts/machines/env.gaeac5_intel +++ b/configuration/scripts/machines/env.gaeac5_intel @@ -7,37 +7,33 @@ endif if ("$inp" != "-nomodules") then -#source /lustre/f2/pdata/esrl/gsd/contrib/lua-5.1.4.9/init/init_lmod.csh source $MODULESHOME/init/csh -#module list -module load PrgEnv-intel -module load intel -#module load intel/2023.2.0 -#module load cce/18.0.0 +module load PrgEnv-intel/8.6.0 +module load intel/2025.0 +module load cray-mpich/8.1.32 module load cray-hdf5/1.14.3.1 module load cray-netcdf/4.9.0.13 setenv NETCDF $NETCDF_DIR -echo zzz final module list -module list -#module avail intel +#echo zzz final module list +#module list # May be needed for OpenMP memory setenv OMP_STACKSIZE 64M endif -env | grep NETCDF +#env | grep NETCDF setenv ICE_MACHINE_MACHNAME gaea -setenv ICE_MACHINE_MACHINFO "Cray XC40 Intel Haswell/Broadwell 2.3GHz, Gemini Interconnect" +setenv ICE_MACHINE_MACHINFO "HPE-EX Cray X3000, AMD EPYC 7H12 2.6 GHz, HPE Slingshot interconnect" setenv ICE_MACHINE_ENVNAME intel -setenv ICE_MACHINE_ENVINFO "ifort 18.0.5 20180823, cray-mpich, cray-netcdf" +setenv ICE_MACHINE_ENVINFO "ifort 2025.0, cray-mpich 8.1.32, cray-netcdf 4.9.0.13" setenv ICE_MACHINE_MAKE gmake setenv ICE_MACHINE_WKDIR $HOME/scratch/CICE_RUNS -setenv ICE_MACHINE_INPUTDATA /ncrc/home1/Robert.Grumbine/rgdev/CICE_INPUTDATA +setenv ICE_MACHINE_INPUTDATA /ncrc/home1/Anthony.Craig/scratch setenv ICE_MACHINE_BASELINE $HOME/scratch/CICE_BASELINE setenv ICE_MACHINE_SUBMIT "sbatch" -setenv ICE_MACHINE_TPNODE 40 +setenv ICE_MACHINE_TPNODE 128 setenv ICE_MACHINE_ACCT P0000000 setenv ICE_MACHINE_QUEUE "normal" setenv ICE_MACHINE_BLDTHRDS 1 diff --git a/configuration/scripts/machines/env.gaea_intel b/configuration/scripts/machines/env.gaeac6_intel similarity index 53% rename from configuration/scripts/machines/env.gaea_intel rename to configuration/scripts/machines/env.gaeac6_intel index 69bddb428..0963ecc69 100644 --- a/configuration/scripts/machines/env.gaea_intel +++ b/configuration/scripts/machines/env.gaeac6_intel @@ -10,15 +10,14 @@ if ("$inp" != "-nomodules") then #source /lustre/f2/pdata/esrl/gsd/contrib/lua-5.1.4.9/init/init_lmod.csh source $MODULESHOME/init/csh #module list -module load PrgEnv-intel -module load intel -#module load intel/2023.2.0 -#module load cce/18.0.0 +module load PrgEnv-intel/8.6.0 +module load intel/2025.0 +module load cray-mpich/8.1.32 module load cray-hdf5/1.14.3.1 module load cray-netcdf/4.9.0.13 setenv NETCDF $NETCDF_DIR -echo zzz final module list -module list +#echo zzz final module list +#module list #module avail intel # May be needed for OpenMP memory @@ -26,19 +25,19 @@ setenv OMP_STACKSIZE 64M endif -env | grep NETCDF +#env | grep NETCDF setenv ICE_MACHINE_MACHNAME gaea -setenv ICE_MACHINE_MACHINFO "Cray XC40 Intel Haswell/Broadwell 2.3GHz, Gemini Interconnect" +setenv ICE_MACHINE_MACHINFO "HPE-EX Cray3000, AMD EPYC 9654 2.4GHz, HPE Slingshot interconnect" setenv ICE_MACHINE_ENVNAME intel -setenv ICE_MACHINE_ENVINFO "ifort 18.0.5 20180823, cray-mpich, cray-netcdf" +setenv ICE_MACHINE_ENVINFO "intel 2025.0, cray-mpich 8.1.32, cray-netcdf 4.9.0.13" setenv ICE_MACHINE_MAKE gmake -setenv ICE_MACHINE_WKDIR $HOME/scratch/CICE_RUNS -setenv ICE_MACHINE_INPUTDATA /ncrc/home1/Robert.Grumbine/rgdev/CICE_INPUTDATA -setenv ICE_MACHINE_BASELINE $HOME/scratch/CICE_BASELINE +setenv ICE_MACHINE_WKDIR $HOME/scratch6/CICE_RUNS +setenv ICE_MACHINE_INPUTDATA /ncrc/home1/Anthony.Craig/scratch6 +setenv ICE_MACHINE_BASELINE $HOME/scratch6/CICE_BASELINE setenv ICE_MACHINE_SUBMIT "sbatch" -setenv ICE_MACHINE_TPNODE 40 -setenv ICE_MACHINE_ACCT P0000000 +setenv ICE_MACHINE_TPNODE 192 +setenv ICE_MACHINE_ACCT A00000 setenv ICE_MACHINE_QUEUE "normal" setenv ICE_MACHINE_BLDTHRDS 1 setenv ICE_MACHINE_QSTAT "squeue --jobs=" From 67cf13903b5620c9ec85b36b68d5df4e529e8c35 Mon Sep 17 00:00:00 2001 From: Anton Steketee <79179784+anton-seaice@users.noreply.github.com> Date: Fri, 15 Aug 2025 08:28:02 +1000 Subject: [PATCH 03/21] NaN Debug failures when reading files (#1045) This PR address #1044 Resolve issues with nans / accessing arrays out of range There are a couple of spots in the code when loading files which fail when building with checks for floating point exceptions (-fpe0 in intel land). This addresses those issues This change max sure that CICE is not trying to use array indeces which don't have values associated with them, and puts a value in _FillValue when it's not set (to avoid a nan). When creating ULAT, don't create the work_mom array on tasks other than master task because it is not used. When loading _FillValue, reset the value to spval_dbl if _FillValue is a nan. --- cicecore/cicedyn/infrastructure/ice_grid.F90 | 37 +++++++------- .../cicedyn/infrastructure/ice_read_write.F90 | 50 ++++++++++++++----- 2 files changed, 56 insertions(+), 31 deletions(-) diff --git a/cicecore/cicedyn/infrastructure/ice_grid.F90 b/cicecore/cicedyn/infrastructure/ice_grid.F90 index d6f306c90..eb2d22411 100644 --- a/cicecore/cicedyn/infrastructure/ice_grid.F90 +++ b/cicecore/cicedyn/infrastructure/ice_grid.F90 @@ -369,27 +369,26 @@ subroutine init_grid1 if (my_task == master_task) then allocate(work_mom(nx_global*2+1, ny_global*2+1), stat=ierr) - else - allocate(work_mom(1, 1), stat=ierr) - endif - if (ierr/=0) call abort_ice(subname//' ERROR: Out of memory', file=__FILE__, line=__LINE__) - - fieldname='y' ! use mom y field to fill cice ULAT - call ice_open_nc(grid_file,fid_grid) - call ice_read_global_nc(fid_grid,1,fieldname,work_mom,.true.) - call ice_close_nc(fid_grid) - im = 3 - do i = 1, nx_global - jm = 3 - do j = 1, ny_global - work_g1(i,j) = work_mom(im, jm) - jm = jm + 2 + if (ierr/=0) call abort_ice(subname//' ERROR: Out of memory', file=__FILE__, line=__LINE__) + + fieldname='y' ! use mom y field to fill cice ULAT + call ice_open_nc(grid_file,fid_grid) + call ice_read_global_nc(fid_grid,1,fieldname,work_mom,.true.) + call ice_close_nc(fid_grid) + im = 3 + do i = 1, nx_global + jm = 3 + do j = 1, ny_global + work_g1(i,j) = work_mom(im, jm) + jm = jm + 2 + enddo + im = im + 2 enddo - im = im + 2 - enddo - deallocate(work_mom, stat=ierr) - if (ierr/=0) call abort_ice(subname//' ERROR: Dealloc error', file=__FILE__, line=__LINE__) + deallocate(work_mom, stat=ierr) + if (ierr/=0) call abort_ice(subname//' ERROR: Dealloc error', file=__FILE__, line=__LINE__) + + endif case('pop_nc', 'geosnc') diff --git a/cicecore/cicedyn/infrastructure/ice_read_write.F90 b/cicecore/cicedyn/infrastructure/ice_read_write.F90 index 784f54f07..a6489473c 100644 --- a/cicecore/cicedyn/infrastructure/ice_read_write.F90 +++ b/cicecore/cicedyn/infrastructure/ice_read_write.F90 @@ -13,6 +13,7 @@ module ice_read_write + use,intrinsic :: ieee_arithmetic use ice_kinds_mod use ice_constants, only: c0, spval_dbl, & field_loc_noupdate, field_type_noupdate @@ -1139,6 +1140,8 @@ subroutine ice_read_nc_xy(fid, nrec, varname, work, diag, & real (kind=dbl_kind), dimension(:,:), allocatable :: & work_g1 + logical, dimension(:,:), allocatable :: mask + integer (kind=int_kind) :: nx, ny integer (kind=int_kind) :: lnrec ! local value of nrec @@ -1222,10 +1225,17 @@ subroutine ice_read_nc_xy(fid, nrec, varname, work, diag, & ! call ice_check_nc(status, subname//' ERROR: Missing _FillValue', & ! file=__FILE__, line=__LINE__) ! write(nu_diag,*) subname,' missingvalue= ',missingvalue - amin = minval(work_g1) - amax = maxval(work_g1, mask = work_g1 /= missingvalue) - asum = sum (work_g1, mask = work_g1 /= missingvalue) + allocate(mask(nx,ny)) + if ( ieee_is_nan(missingvalue) ) then + mask = ieee_is_nan(work_g1) + else + mask = work_g1 /= missingvalue + endif + amin = minval(work_g1, mask = mask ) + amax = maxval(work_g1, mask = mask ) + asum = sum (work_g1, mask = mask ) write(nu_diag,*) subname,' min, max, sum =', amin, amax, asum, trim(varname) + deallocate(mask) endif !------------------------------------------------------------------- @@ -1320,6 +1330,8 @@ subroutine ice_read_nc_xyz(fid, nrec, varname, work, diag, & real (kind=dbl_kind), dimension(:,:,:), allocatable :: & work_g1 + logical, dimension(:,:), allocatable :: mask + integer (kind=int_kind) :: nx, ny integer (kind=int_kind) :: lnrec ! local value of nrec @@ -1400,13 +1412,19 @@ subroutine ice_read_nc_xyz(fid, nrec, varname, work, diag, & status = nf90_get_att(fid, varid, "_FillValue", missingvalue) ! call ice_check_nc(status, subname//' ERROR: Missing _FillValue', & ! file=__FILE__, line=__LINE__) -! write(nu_diag,*) subname,' missingvalue= ',missingvalue + allocate(mask(nx,ny)) do n=1,ncat - amin = minval(work_g1(:,:,n)) - amax = maxval(work_g1(:,:,n), mask = work_g1(:,:,n) /= missingvalue) - asum = sum (work_g1(:,:,n), mask = work_g1(:,:,n) /= missingvalue) + if ( ieee_is_nan(missingvalue) ) then + mask = ieee_is_nan(work_g1(:,:,n)) + else + mask = work_g1(:,:,n) /= missingvalue + endif + amin = minval(work_g1(:,:,n), mask = mask ) + amax = maxval(work_g1(:,:,n), mask = mask ) + asum = sum (work_g1(:,:,n), mask = mask ) write(nu_diag,*) subname,' min, max, sum =', amin, amax, asum, trim(varname) enddo + deallocate(mask) endif !------------------------------------------------------------------- @@ -1508,6 +1526,8 @@ subroutine ice_read_nc_xyf(fid, nrec, varname, work, diag, & real (kind=dbl_kind), dimension(:,:,:), allocatable :: & work_g1 + logical, dimension(:,:), allocatable :: mask + integer (kind=int_kind) :: nx, ny integer (kind=int_kind) :: lnrec ! local value of nrec @@ -1592,13 +1612,19 @@ subroutine ice_read_nc_xyf(fid, nrec, varname, work, diag, & status = nf90_get_att(fid, varid, "_FillValue", missingvalue) ! call ice_check_nc(status, subname//' ERROR: Missing _FillValue', & ! file=__FILE__, line=__LINE__) -! write(nu_diag,*) subname,' missingvalue= ',missingvalue - do n = 1, nfreq - amin = minval(work_g1(:,:,n)) - amax = maxval(work_g1(:,:,n), mask = work_g1(:,:,n) /= missingvalue) - asum = sum (work_g1(:,:,n), mask = work_g1(:,:,n) /= missingvalue) + allocate(mask(nx,ny)) + do n=1,ncat + if ( ieee_is_nan(missingvalue) ) then + mask = ieee_is_nan(work_g1(:,:,n)) + else + mask = work_g1(:,:,n) /= missingvalue + endif + amin = minval(work_g1(:,:,n), mask = mask ) + amax = maxval(work_g1(:,:,n), mask = mask ) + asum = sum (work_g1(:,:,n), mask = mask ) write(nu_diag,*) subname,' min, max, sum =', amin, amax, asum, trim(varname) enddo + deallocate(mask) endif !------------------------------------------------------------------- From fd0d85eda573bd19e25105a0e1248b71900fc4b5 Mon Sep 17 00:00:00 2001 From: Tony Craig Date: Wed, 20 Aug 2025 13:05:56 -0700 Subject: [PATCH 04/21] Update Copyright, Version, Icepack (#1049) * Update Copyright Update version number in preparation for minor release Clean up trailing blanks Update Icepack to #f9789c2f325993c0af - Update Copyright and version number * Update Copyright in zenodo json file in CICE and Icepack --- .zenodo.json | 8 ++++---- COPYRIGHT.pdf | Bin 53225 -> 20755 bytes cicecore/cicedyn/infrastructure/ice_grid.F90 | 4 ++-- cicecore/drivers/direct/hadgem3/CICE.F90 | 2 +- cicecore/drivers/mapl/geos/CICE_copyright.txt | 2 +- cicecore/drivers/mct/cesm1/CICE_copyright.txt | 2 +- .../drivers/nuopc/cmeps/CICE_copyright.txt | 2 +- cicecore/drivers/nuopc/dmi/CICE.F90 | 2 +- cicecore/drivers/standalone/cice/CICE.F90 | 2 +- cicecore/drivers/unittest/opticep/CICE.F90 | 2 +- cicecore/version.txt | 2 +- doc/source/conf.py | 6 +++--- doc/source/intro/copyright.rst | 2 +- icepack | 2 +- 14 files changed, 19 insertions(+), 19 deletions(-) diff --git a/.zenodo.json b/.zenodo.json index f5b00f1f8..d96cfb9bb 100644 --- a/.zenodo.json +++ b/.zenodo.json @@ -1,22 +1,22 @@ { "license": "BSD-3-Clause", - "copyright": "Copyright (c) 1998, 2017 Triad National Security, LLC", + "copyright": "Copyright 1998-2025 Triad National Security, LLC", "description": "View detailed release notes at https://github.com/CICE-Consortium/CICE/releases", "language": "eng", - "title": "CICE-Consortium/CICE: CICE Version 6.6.1", + "title": "CICE-Consortium/CICE: CICE Version 6.6.2", "keywords": [ "sea ice model", "CICE", "Icepack" ], - "version": "6.6.1", + "version": "6.6.2", "upload_type": "software", "communities": [ { "identifier": "cice-consortium" } ], - "publication_date": "2025-07-21", + "publication_date": "2025-08-15", "creators": [ { "affiliation": "Los Alamos National Laboratory", diff --git a/COPYRIGHT.pdf b/COPYRIGHT.pdf index 55132ca5e9ade12f27491a5fb238239bc75b5fc3..2f37e495f02302a72c6b7943cf05b5ecfe3dfb19 100644 GIT binary patch literal 20755 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 literal 53225 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 Date: Fri, 29 Aug 2025 13:11:38 +0200 Subject: [PATCH 05/21] Add DMI computer Boreas (#1050) Co-authored-by: Till Rasmussen --- configuration/scripts/cice.batch.csh | 9 +++ configuration/scripts/cice.launch.csh | 13 ++++ .../scripts/machines/Macros.boreas_intel | 70 +++++++++++++++++++ .../scripts/machines/env.boreas_intel | 52 ++++++++++++++ 4 files changed, 144 insertions(+) create mode 100644 configuration/scripts/machines/Macros.boreas_intel create mode 100644 configuration/scripts/machines/env.boreas_intel diff --git a/configuration/scripts/cice.batch.csh b/configuration/scripts/cice.batch.csh index 1de12f5ce..abb64e25c 100755 --- a/configuration/scripts/cice.batch.csh +++ b/configuration/scripts/cice.batch.csh @@ -366,6 +366,15 @@ cat >> ${jobfile} << EOFB #PBS -l walltime=${batchtime} EOFB +else if (${ICE_MACHINE} =~ boreas* ) then +cat >> ${jobfile} << EOFB +#PBS -N ${ICE_CASENAME} +#PBS -j oe +#PBS -q ${queue} +#PBS -l select=${nnodes}:ncpus=${corespernode}:mpiprocs=${taskpernodelimit}:ompthreads=${nthrds} +#PBS -l walltime=${batchtime} +EOFB + else if (${ICE_MACHINE} =~ gaeac5*) then cat >> ${jobfile} << EOFB #SBATCH -J ${ICE_CASENAME} diff --git a/configuration/scripts/cice.launch.csh b/configuration/scripts/cice.launch.csh index bc68a7ce1..73af50d1b 100755 --- a/configuration/scripts/cice.launch.csh +++ b/configuration/scripts/cice.launch.csh @@ -272,6 +272,19 @@ aprun -n ${ntasks} -N ${taskpernodelimit} -d ${nthrds} ./cice >&! \$ICE_RUNLOG_F EOFR endif +#======= +else if (${ICE_MACHCOMP} =~ boreas*) then +if (${ICE_COMMDIR} =~ serial*) then +cat >> ${jobfile} << EOFR +aprun -n 1 -N 1 -d 1 ./cice >&! \$ICE_RUNLOG_FILE +EOFR +else +cat >> ${jobfile} << EOFR +aprun -n ${ntasks} -N ${taskpernodelimit} -d ${nthrds} ./cice >&! \$ICE_RUNLOG_FILE +EOFR +endif + + #======= else if (${ICE_MACHCOMP} =~ gaea*) then cat >> ${jobfile} << EOFR diff --git a/configuration/scripts/machines/Macros.boreas_intel b/configuration/scripts/machines/Macros.boreas_intel new file mode 100644 index 000000000..0fe33a1bf --- /dev/null +++ b/configuration/scripts/machines/Macros.boreas_intel @@ -0,0 +1,70 @@ +#============================================================================== +# Makefile macros for DMI Freya based on ECCC banting +#============================================================================== +# For use with intel compiler +#============================================================================== + +#INCLDIR := -I. -I/usr/include +#SLIBS := + +#--- Compiler/preprocessor --- +FC := ftn +CC := cc +CXX := CC +CPP := /usr/bin/cpp +CPPFLAGS := -P -traditional # ALLOW fortran double backslash "\\" +SCC := gcc +SFC := ftn + +CPPDEFS := -DFORTRANUNDERSCORE ${ICE_CPPDEFS} +CFLAGS := -c -O2 -fp-model precise +# Additional flags +FIXEDFLAGS := -132 +FREEFLAGS := -FR +FFLAGS := -convert big_endian -assume byterecl +#-xHost + +ifeq ($(ICE_BLDDEBUG), true) + FFLAGS += -O0 -g -check -fpe0 -ftrapuv -fp-model except -check noarg_temp_created -fp-model source -ftz -traceback -no-wrap-margin +# -heap-arrays 1024 +else +# FFLAGS += -O3 -xCORE-AVX512 -qopt-zmm-usage=high -finline-functions -finline -parallel + FFLAGS += -O2 -qopt-zmm-usage=high -finline-functions -finline -parallel +endif +LD := $(FC) +LDFLAGS := $(FFLAGS) -v +#ifeq ($(ICE_BLDDEBUG), true) +#FFLAGS := -O0 -g -check uninit -check bounds -check pointers -fpe0 -check noarg_temp_created +#FFLAGS := -g -O0 -traceback -fp-model precise -fp-stack-check -fpe0 +#else +#FFLAGS := -r8 -i4 -O2 -align all -w -ftz -assume byterecl +# FFLAGS := -O2 -fp-model precise -assume byterecl -ftz -traceback -xHost +#endif +# Preprocessor flags +#CPPDEFS := -DLINUX $(ICE_CPPDEFS) + +# Linker flags + +# Additional flags + +ifeq ($(ICE_THREADED), true) + LDFLAGS += -qopenmp + CFLAGS += -qopenmp + FFLAGS += -qopenmp +endif + +#--- NetCDF --- +#ifeq ($(IO_TYPE), netcdf) +# +#endif +# +#ifeq ($(IO_TYPE), netcdf_bin) +# CPPDEFS := $(CPPDEFS) -Dncdf +#endif + +### if using parallel I/O, load all 3 libraries. PIO must be first! +#ifeq ($(ICE_IOTYPE), pio) +# PIO_PATH:=/usr/projects/climate/SHARED_CLIMATE/software/conejo/pio/1.7.2/intel-13.0.1/openmpi-1.6.3/netcdf-3.6.3-parallel-netcdf-1.3.1/include +# INCLDIR += -I$(PIO_PATH) +# SLIBS := $(SLIBS) -L$(PIO_PATH) -lpio +#endif diff --git a/configuration/scripts/machines/env.boreas_intel b/configuration/scripts/machines/env.boreas_intel new file mode 100644 index 000000000..5525e08eb --- /dev/null +++ b/configuration/scripts/machines/env.boreas_intel @@ -0,0 +1,52 @@ +#!/bin/csh -f + +set inp = "undefined" +if ($#argv == 1) then + set inp = $1 +endif + +if ("$inp" != "-nomodules") then +alias module 'eval `/opt/cray/pe/modules/3.2.11.7/bin/modulecmd tcsh \!*`' +module purge +module load craype-x86-milan +module load PrgEnv-intel +module load cray-hdf5-parallel +module load cray-netcdf-hdf5parallel +module swap intel/2022.2.1 intel-classic/2022.2.1 +module load gcc/12.2.0 +module load jasper-3.0.3-cce-14.0.3-dqhpvpm +module load cray-pals/1.2.12 +#asetenv NETCDF_PATH ${NETCDF_DIR} +setenv LD_LIBRARY_PATH /opt/cray/pe/netcdf-hdf5parallel/4.9.0.5/intel/2022.2/lib:${LD_LIBRARY_PATH} +###source /opt/modules/default/init/csh # Initialize modules for csh +##source /opt/cray/pe/modules/3.2.11.7/init/csh +### Clear environment +##module rm PrgEnv-intel +##module rm PrgEnv-cray +##module rm PrgEnv-gnu +##module add PrgEnv-intel +###module load PrgEnv-intel # Intel compiler +###module load cray-mpich # MPI (Cray MPICH) +#module add cray-hdf5 # HDF5 +#module add cray-netcdf # NetCDF +#module load cray-pals +#setenv HDF5_USE_FILE_LOCKING FALSE # necessary since data is on an NFS filesystem + +endif + +setenv ICE_MACHINE_MACHNAME Boreas +setenv ICE_MACHINE_MACHINFO "Cray XC50, Intel Xeon Gold 6148 (Skylake) NOT SURE-TILL" +setenv ICE_MACHINE_ENVNAME intel +setenv ICE_MACHINE_ENVINFO "Intel 18.0.0.128, cray-mpich/7.7.0, cray-netcdf/4.4.1.1.6" +setenv ICE_MACHINE_MAKE make +setenv ICE_MACHINE_WKDIR /data/${USER}/cice_original/run/ +setenv ICE_MACHINE_INPUTDATA /data/${USER}/cice_original/ +setenv ICE_MACHINE_BASELINE /data/${USER}/cice_original/dbaselines/ +setenv ICE_MACHINE_SUBMIT "qsub" +setenv ICE_MACHINE_TPNODE 128 # tasks per node +#setenv ICE_MACHINE_MAXRUNLENGTH 9 +setenv ICE_MACHINE_ACCT P0000000 +setenv ICE_MACHINE_QUEUE "hpc" +setenv ICE_MACHINE_BLDTHRDS 18 +setenv ICE_MACHINE_QSTAT "qstat " +setenv OMP_STACKSIZE 64M From b4a6c4439ed325fc7e85ee8402b75e732b1a9bfe Mon Sep 17 00:00:00 2001 From: Tony Craig Date: Wed, 10 Sep 2025 08:54:12 -0700 Subject: [PATCH 06/21] Update the qstat job completion checks to use (#1052) Update the qstat job completion checks to use set qstatus = `${ICE_MACHINE_QSTAT} $job | grep $job | wc -l` Some recent changes made the return status of "${ICE_MACHINE_QSTAT} $job" no longer robust as a way to check if a job was in the queue or not. --- configuration/scripts/tests/baseline.script | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/configuration/scripts/tests/baseline.script b/configuration/scripts/tests/baseline.script index 9fd2fe001..168824010 100644 --- a/configuration/scripts/tests/baseline.script +++ b/configuration/scripts/tests/baseline.script @@ -136,17 +136,17 @@ if (${ICE_BFBCOMP} != ${ICE_SPVAL}) then set cnt = 0 if (${job} =~ [0-9]*) then while ($qstatjob) - ${ICE_MACHINE_QSTAT} $job >&/dev/null - set qstatus = $status + set qstatus = `${ICE_MACHINE_QSTAT} $job | grep $job | wc -l` +# ${ICE_MACHINE_QSTAT} $job # echo $job $qstatus - if ($qstatus != 0) then + if ($qstatus == 0) then echo "Job $job completed" set qstatjob = 0 else @ cnt = $cnt + 1 echo "Waiting for $job to complete $cnt" sleep 60 # Sleep for 1 minute, so as not to overwhelm the queue manager - if ($cnt > 30) then + if ($cnt > 5) then echo "No longer waiting for $job to complete" set qstatjob = 0 # Abandon check after cnt sleep 60 checks endif From b01032506d71d86ca51cef8c3c28c1ab87532833 Mon Sep 17 00:00:00 2001 From: Anton Steketee <79179784+anton-seaice@users.noreply.github.com> Date: Thu, 11 Sep 2025 20:32:44 +1000 Subject: [PATCH 07/21] NUOPC/CMEPS only: Make datestamps in pointer filenames configurable (#9) (#1031) This adds support in NUOPC/CMEPS driver for the addition of datestamps to the pointer filenames to be configurable through the nuopc option restart_pointer_append_date . This is a companion change to ESCOMP/CESM_share#70, and does not impact any current default behaviour. * Make datestamps in pointer filenames configurable (#9) * set across all io options consistently * use ice_restart_shared consistently across all 3 methods --------- Co-authored-by: Andrew Kiss <31054815+aekiss@users.noreply.github.com> Co-authored-by: Dougie Squire <42455466+dougiesquire@users.noreply.github.com> --- .../infrastructure/io/io_binary/ice_restart.F90 | 13 +++++++++---- .../infrastructure/io/io_netcdf/ice_restart.F90 | 14 +++++++++----- .../infrastructure/io/io_pio2/ice_restart.F90 | 12 ++++++++---- cicecore/drivers/nuopc/cmeps/ice_comp_nuopc.F90 | 12 +++++++++++- cicecore/shared/ice_restart_shared.F90 | 3 +++ 5 files changed, 40 insertions(+), 14 deletions(-) diff --git a/cicecore/cicedyn/infrastructure/io/io_binary/ice_restart.F90 b/cicecore/cicedyn/infrastructure/io/io_binary/ice_restart.F90 index d8931866a..9ae19f1d9 100644 --- a/cicecore/cicedyn/infrastructure/io/io_binary/ice_restart.F90 +++ b/cicecore/cicedyn/infrastructure/io/io_binary/ice_restart.F90 @@ -9,9 +9,7 @@ module ice_restart use ice_broadcast use ice_kinds_mod - use ice_restart_shared, only: & - restart, restart_ext, restart_dir, restart_file, pointer_file, & - runid, runtype, use_restart_time, lenstr + use ice_restart_shared use ice_communicate, only: my_task, master_task use ice_fileunits, only: nu_diag, nu_rst_pointer use ice_fileunits, only: nu_dump, nu_dump_eap, nu_dump_FY, nu_dump_age @@ -396,6 +394,7 @@ subroutine init_restart_write(filename_spec) nbtrcr ! number of bgc tracers character(len=char_len_long) :: filename + character(len=char_len_long) :: lpointer_file character(len=*), parameter :: subname = '(init_restart_write)' @@ -422,7 +421,13 @@ subroutine init_restart_write(filename_spec) ! write pointer (path/file) if (my_task == master_task) then - open(nu_rst_pointer,file=pointer_file) + lpointer_file = pointer_file + if (pointer_date) then + ! append date to pointer filename + write(lpointer_file,'(a,i4.4,a,i2.2,a,i2.2,a,i5.5)') & + trim(lpointer_file)//'.',myear,'-',mmonth,'-',mday,'-',msec + end if + open(nu_rst_pointer,file=lpointer_file) write(nu_rst_pointer,'(a)') filename close(nu_rst_pointer) if (restart_ext) then diff --git a/cicecore/cicedyn/infrastructure/io/io_netcdf/ice_restart.F90 b/cicecore/cicedyn/infrastructure/io/io_netcdf/ice_restart.F90 index 33fd0cd1f..db6aa80bf 100644 --- a/cicecore/cicedyn/infrastructure/io/io_netcdf/ice_restart.F90 +++ b/cicecore/cicedyn/infrastructure/io/io_netcdf/ice_restart.F90 @@ -16,10 +16,7 @@ module ice_restart use netcdf #endif use ice_read_write, only: ice_check_nc - use ice_restart_shared, only: & - restart_ext, restart_dir, restart_file, pointer_file, & - runid, use_restart_time, lenstr, restart_coszen, restart_format, & - restart_chunksize, restart_deflate + use ice_restart_shared use ice_fileunits, only: nu_diag, nu_rst_pointer use ice_exit, only: abort_ice use icepack_intfc, only: icepack_query_parameters @@ -168,6 +165,7 @@ subroutine init_restart_write(filename_spec) nbtrcr ! number of bgc tracers character(len=char_len_long) :: filename + character(len=char_len_long) :: lpointer_file integer (kind=int_kind), allocatable :: dims(:) @@ -215,7 +213,13 @@ subroutine init_restart_write(filename_spec) ! write pointer (path/file) if (my_task == master_task) then filename = trim(filename) // '.nc' - open(nu_rst_pointer,file=pointer_file) + lpointer_file = pointer_file + if (pointer_date) then + ! append date to pointer filename + write(lpointer_file,'(a,i4.4,a,i2.2,a,i2.2,a,i5.5)') & + trim(lpointer_file)//'.',myear,'-',mmonth,'-',mday,'-',msec + end if + open(nu_rst_pointer,file=lpointer_file) write(nu_rst_pointer,'(a)') filename close(nu_rst_pointer) diff --git a/cicecore/cicedyn/infrastructure/io/io_pio2/ice_restart.F90 b/cicecore/cicedyn/infrastructure/io/io_pio2/ice_restart.F90 index b06501483..11f0fb803 100644 --- a/cicecore/cicedyn/infrastructure/io/io_pio2/ice_restart.F90 +++ b/cicecore/cicedyn/infrastructure/io/io_pio2/ice_restart.F90 @@ -220,16 +220,20 @@ subroutine init_restart_write(filename_spec) myear,'-',mmonth,'-',mday,'-',msec end if - if (restart_format(1:3) /= 'bin') filename = trim(filename) // '.nc' + filename = trim(filename) // '.nc' ! write pointer (path/file) if (my_task == master_task) then -#ifdef CESMCOUPLED - write(lpointer_file,'(a,i4.4,a,i2.2,a,i2.2,a,i5.5)') & - 'rpointer.ice'//trim(inst_suffix)//'.',myear,'-',mmonth,'-',mday,'-',msec +#ifdef CESMCOUPLED + lpointer_file = 'rpointer.ice'//trim(inst_suffix) #else lpointer_file = pointer_file #endif + if (pointer_date) then + ! append date to pointer filename + write(lpointer_file,'(a,i4.4,a,i2.2,a,i2.2,a,i5.5)') & + trim(lpointer_file)//'.',myear,'-',mmonth,'-',mday,'-',msec + end if open(nu_rst_pointer,file=lpointer_file) write(nu_rst_pointer,'(a)') filename close(nu_rst_pointer) diff --git a/cicecore/drivers/nuopc/cmeps/ice_comp_nuopc.F90 b/cicecore/drivers/nuopc/cmeps/ice_comp_nuopc.F90 index e8f019343..f2b2e2833 100644 --- a/cicecore/drivers/nuopc/cmeps/ice_comp_nuopc.F90 +++ b/cicecore/drivers/nuopc/cmeps/ice_comp_nuopc.F90 @@ -30,7 +30,8 @@ module ice_comp_nuopc use ice_kinds_mod , only : dbl_kind, int_kind, char_len, char_len_long use ice_fileunits , only : nu_diag, nu_diag_set, inst_index, inst_name use ice_fileunits , only : inst_suffix, release_all_fileunits, flush_fileunit - use ice_restart_shared , only : runid, runtype, restart, use_restart_time, restart_dir, restart_file, restart_format, restart_chunksize + use ice_restart_shared , only : runid, runtype, restart, use_restart_time, restart_dir, restart_file, & + restart_format, restart_chunksize, pointer_date use ice_history , only : accum_hist use ice_history_shared , only : history_format, history_chunksize use ice_exit , only : abort_ice @@ -329,6 +330,15 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) if (trim(cvalue) .eq. '.true.') restart_eor = .true. endif +#ifdef CESMCOUPLED + pointer_date = .true. +#endif + + ! set CICE internal pointer_date variable based on nuopc settings + ! this appends a datestamp to the "rpointer" file + call NUOPC_CompAttributeGet(gcomp, name="restart_pointer_append_date", value=cvalue, isPresent=isPresent, isSet=isSet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (isPresent .and. isSet) pointer_date = (trim(cvalue) .eq. ".true.") !---------------------------------------------------------------------------- ! generate local mpi comm !---------------------------------------------------------------------------- diff --git a/cicecore/shared/ice_restart_shared.F90 b/cicecore/shared/ice_restart_shared.F90 index c022d77ba..32d78e82f 100644 --- a/cicecore/shared/ice_restart_shared.F90 +++ b/cicecore/shared/ice_restart_shared.F90 @@ -25,6 +25,9 @@ module ice_restart_shared character (len=char_len_long), public :: & pointer_file ! input pointer file for restarts + logical (kind=log_kind), public :: & + pointer_date = .false. ! if true, append datestamp to pointer file + character (len=char_len), public :: & restart_format , & ! format of restart files 'nc' restart_rearranger ! restart file rearranger, box or subset for pio From bd30d63f3166b5dc1906cb31072ebb932fc9435a Mon Sep 17 00:00:00 2001 From: Tony Craig Date: Tue, 7 Oct 2025 09:14:56 -0700 Subject: [PATCH 08/21] Fix bug in ice_restoring, indexing of trcrn_rest Fix bug in ice_restoring with respect to indexing of trcrn_rest. This will change answers when ice restoring is turned on. The CICE restoring feature is not generally used, and we currently have no tests to cover that feature. This bug was discovered as part of an ongoing effort to improve regional grid capability with additional PRs to come in the future. A full test suite run on derecho with the intel compiler confirmed this, no answers changed. --- cicecore/cicedyn/infrastructure/ice_restoring.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cicecore/cicedyn/infrastructure/ice_restoring.F90 b/cicecore/cicedyn/infrastructure/ice_restoring.F90 index b7f1b3971..71c236a8a 100644 --- a/cicecore/cicedyn/infrastructure/ice_restoring.F90 +++ b/cicecore/cicedyn/infrastructure/ice_restoring.F90 @@ -215,7 +215,7 @@ subroutine ice_HaloRestore_init vicen_rest(i,j,n,iblk) = vicen(i,jlo,n,iblk) vsnon_rest(i,j,n,iblk) = vsnon(i,jlo,n,iblk) do nt = 1, ntrcr - trcrn_rest(i,j,nt,n,iblk) = trcrn(ilo,j,nt,n,iblk) + trcrn_rest(i,j,nt,n,iblk) = trcrn(i,jlo,nt,n,iblk) enddo enddo enddo @@ -246,7 +246,7 @@ subroutine ice_HaloRestore_init vicen_rest(i,j,n,iblk) = vicen(i,jhi,n,iblk) vsnon_rest(i,j,n,iblk) = vsnon(i,jhi,n,iblk) do nt = 1, ntrcr - trcrn_rest(i,j,nt,n,iblk) = trcrn(ihi,j,nt,n,iblk) + trcrn_rest(i,j,nt,n,iblk) = trcrn(i,jhi,nt,n,iblk) enddo enddo enddo From 61701f029fe0a454dd536525250ebdafe8317e57 Mon Sep 17 00:00:00 2001 From: Santha Akella <18061653+sanAkel@users.noreply.github.com> Date: Wed, 5 Nov 2025 16:03:00 -0500 Subject: [PATCH 09/21] Add an option to be able to update ice concentration (from data assimilation or retrievals/products) (#1060) Add an option to be able to update ice concentration (from data assimilation or retrievals/products) at restart. - This feature is being ported from CICE4, that is used in RTOFS: - We use the sea ice concentration from data assimilation (DA), performed using RTOFS-DA. - In this (CICE6) version usage is turned ON (default: OFF) via restart_mod="adjust_aice". - See similar/same implementation in the old (CICE4) version of ice_restart.F90, search for insert_ssmi. - @awallcraft ported the code he wrote (and is used in CICE4) to CICE6. - This PR was originally sent to the NOAA-EMC/CICE fork and following @NickSzapiro-NOAA's recommendation, being redirected here; that PR is now closed. - All the comments and conversations (@NickSzapiro-NOAA and @awallcraft) can be read via https://github.com/NOAA-EMC/CICE/pull/104, however, for the sake of self-completeness A brief text/description follows: One of the main goals of a data assimilation (DA)/prediction system that strives to provide close to observed sea ice concentrations and ice edge is to be able to reconcile the differences in modeled and observed sea ice concentrations derived from space borne instruments. Posey et al., 2025 implemented such a method with CICE4, it is hereby ported to CICE6. By default this feature is turned OFF. To turn it ON, set restart_mod='adjust_aice' in ice_in (input) namelist file and provide sic.nc to be able to nudge the modeled ice concentration to that from data assimilated (or observed) concentration. By default, restart_mod='none'. There is also a test mode, restart_mod='adjust_aice_test' which modifies aice read on restart to the nearest 5/100ths just to test the algorithm. - With this proposed addition, an ability to insert data assimilated sea ice concentration is provided. Implementation is similar/same as in CICE4; see https://github.com/NOAA-EMC/RTOFS_GLO/blob/develop/sorc/rtofs_hycom.fd/src_2.2.99DHMTi-dist2B_relo_cice_v4.0e/source/ice_restart.F90 ; search for insert_ssmi. @awallcraft ported the code he wrote (and is used in CICE4) to CICE6. - There is an acknowledgement that the coupler and/or MOM6 will need some modifications, but that is beyond the scope of this (CICE) repository. Such work will be taken up in future. Co-authored-by: Nicholas Szapiro <149816583+NickSzapiro-NOAA@users.noreply.github.com> Co-authored-by: Nick Szapiro Co-authored-by: Till Rasmussen Co-authored-by: apcraig --- cicecore/cicedyn/general/ice_init.F90 | 7 +- .../infrastructure/ice_restart_driver.F90 | 387 +++++++++++++++++- cicecore/shared/ice_restart_shared.F90 | 1 + configuration/scripts/ice_in | 1 + .../scripts/options/set_nml.restaicetest | 2 + configuration/scripts/tests/base_suite.ts | 1 + doc/source/cice_index.rst | 1 + doc/source/developer_guide/dg_assim.rst | 37 ++ doc/source/developer_guide/index.rst | 1 + doc/source/master_list.bib | 12 +- doc/source/user_guide/ug_case_settings.rst | 3 + 11 files changed, 448 insertions(+), 5 deletions(-) create mode 100644 configuration/scripts/options/set_nml.restaicetest create mode 100644 doc/source/developer_guide/dg_assim.rst diff --git a/cicecore/cicedyn/general/ice_init.F90 b/cicecore/cicedyn/general/ice_init.F90 index 92580a512..1c6f0fec3 100644 --- a/cicecore/cicedyn/general/ice_init.F90 +++ b/cicecore/cicedyn/general/ice_init.F90 @@ -84,7 +84,7 @@ subroutine input_data restart, restart_ext, restart_coszen, use_restart_time, & runtype, restart_file, restart_dir, runid, pointer_file, & restart_format, restart_rearranger, restart_iotasks, restart_root, & - restart_stride, restart_deflate, restart_chunksize + restart_stride, restart_deflate, restart_chunksize, restart_mod use ice_history_shared, only: & history_precision, hist_avg, history_format, history_file, incond_file, & history_dir, incond_dir, version_name, history_rearranger, & @@ -196,7 +196,7 @@ subroutine input_data ice_ic, restart, restart_dir, restart_file, & restart_ext, use_restart_time, restart_format, lcdf64, & restart_root, restart_stride, restart_iotasks, restart_rearranger, & - restart_deflate, restart_chunksize, & + restart_deflate, restart_chunksize, restart_mod, & pointer_file, dumpfreq, dumpfreq_n, dump_last, & diagfreq, diag_type, diag_file, history_format,& history_root, history_stride, history_iotasks, history_rearranger, & @@ -573,6 +573,7 @@ subroutine input_data restore_ocn = .false. ! restore sst if true trestore = 90 ! restoring timescale, days (0 instantaneous) restore_ice = .false. ! restore ice state on grid edges if true + restart_mod = 'none' ! restart modification option debug_forcing = .false. ! true writes diagnostics for input forcing latpnt(1) = 90._dbl_kind ! latitude of diagnostic point 1 (deg) @@ -991,6 +992,7 @@ subroutine input_data call broadcast_scalar(restart_rearranger, master_task) call broadcast_scalar(restart_deflate, master_task) call broadcast_array(restart_chunksize, master_task) + call broadcast_scalar(restart_mod, master_task) call broadcast_scalar(lcdf64, master_task) call broadcast_scalar(pointer_file, master_task) call broadcast_scalar(ice_ic, master_task) @@ -2620,6 +2622,7 @@ subroutine input_data write(nu_diag,1011) ' restart = ', restart write(nu_diag,1031) ' restart_dir = ', trim(restart_dir) write(nu_diag,1011) ' restart_ext = ', restart_ext + write(nu_diag,1031) ' restart_mod = ', trim(restart_mod) write(nu_diag,1011) ' restart_coszen = ', restart_coszen write(nu_diag,1031) ' restart_format = ', trim(restart_format) write(nu_diag,1021) ' restart_deflate = ', restart_deflate diff --git a/cicecore/cicedyn/infrastructure/ice_restart_driver.F90 b/cicecore/cicedyn/infrastructure/ice_restart_driver.F90 index 8f11f7f5e..1f6f00591 100644 --- a/cicecore/cicedyn/infrastructure/ice_restart_driver.F90 +++ b/cicecore/cicedyn/infrastructure/ice_restart_driver.F90 @@ -25,7 +25,7 @@ module ice_restart_driver field_loc_Eface, field_loc_Nface, & field_type_scalar, field_type_vector use ice_restart_shared, only: restart_dir, pointer_file, & - runid, use_restart_time, lenstr, restart_coszen + runid, use_restart_time, lenstr, restart_coszen, restart_mod use ice_restart use ice_exit, only: abort_ice use ice_fileunits, only: nu_diag, nu_rst_pointer, nu_restart, nu_dump @@ -33,6 +33,8 @@ module ice_restart_driver use icepack_intfc, only: icepack_warnings_flush, icepack_warnings_aborted use icepack_intfc, only: icepack_aggregate use icepack_intfc, only: icepack_query_tracer_indices, icepack_query_tracer_sizes + use icepack_intfc, only: icepack_query_parameters + use icepack_intfc, only: icepack_query_tracer_flags implicit none private @@ -297,6 +299,11 @@ subroutine restartfile (ice_ic) aice0, aicen, vicen, vsnon, trcrn, aice_init, uvel, vvel, & uvelE, vvelE, uvelN, vvelN, & trcr_base, nt_strata, n_trcr_strata + use icepack_itd, only: cleanup_itd !for restart_mod + use ice_arrays_column, only: first_ice, hin_max + use ice_flux, only: fpond, fresh, fsalt, fhocn + use ice_flux_bgc, only: faero_ocn, fiso_ocn, flux_bio + use ice_calendar, only: dt character (*), optional :: ice_ic @@ -308,7 +315,8 @@ subroutine restartfile (ice_ic) nt_Tsfc, nt_sice, nt_qice, nt_qsno logical (kind=log_kind) :: & - diag + diag, & + tr_aero, tr_pond_topo real (kind=dbl_kind), dimension (nx_block,ny_block,max_blocks) :: & work1 @@ -324,6 +332,7 @@ subroutine restartfile (ice_ic) call icepack_query_tracer_indices(nt_Tsfc_out=nt_Tsfc, nt_sice_out=nt_sice, & nt_qice_out=nt_qice, nt_qsno_out=nt_qsno) + call icepack_query_tracer_flags(tr_aero_out=tr_aero, tr_pond_topo_out=tr_pond_topo) call icepack_warnings_flush(nu_diag) if (icepack_warnings_aborted()) call abort_ice(error_message=subname, & file=__FILE__, line=__LINE__) @@ -717,6 +726,76 @@ subroutine restartfile (ice_ic) npt = npt - istep0 endif + !----------------------------------------------------------------- + ! update concentration from a file + !----------------------------------------------------------------- + if (restart_mod /= "none") then + + select case (trim(restart_mod)) + + case('adjust_aice') + call direct_adjust_aice + + case('adjust_aice_test') + call direct_adjust_aice(test=.true.) + + case default + call abort_ice(subname//'ERROR: unsupported restart_mod='//trim(restart_mod), & + file=__FILE__, line=__LINE__) + + end select + + !----------------------------------------------------------------- + ! Ensure ice is binned in correct categories + !----------------------------------------------------------------- + do iblk = 1, nblocks + do j = 1, ny_block + do i = 1, nx_block + if (tmask(i,j,iblk)) then + + call cleanup_itd(dt, hin_max, & + aicen(i,j,:,iblk), trcrn(i,j,:,:,iblk), & + vicen(i,j,:,iblk), vsnon(i,j,:, iblk), & + aice0(i,j, iblk), aice(i,j, iblk), & + tr_aero, tr_pond_topo, & + first_ice(i,j,:,iblk), & + trcr_depend, trcr_base, & + n_trcr_strata, nt_strata, & + fpond = fpond(i,j, iblk), & + fresh = fresh(i,j, iblk), & + fsalt = fsalt(i,j, iblk), & + fhocn = fhocn(i,j, iblk), & + faero_ocn = faero_ocn(i,j,:,iblk), & + fiso_ocn = fiso_ocn(i,j,:,iblk), & + flux_bio = flux_bio(i,j,:,iblk), & + Tf = Tf(i,j, iblk), & + limit_aice = .true. ) + + call icepack_aggregate( & + aicen = aicen(i,j,:,iblk), & + trcrn = trcrn(i,j,:,:,iblk), & + vicen = vicen(i,j,:,iblk), & + vsnon = vsnon(i,j,:,iblk), & + aice = aice (i,j, iblk), & + trcr = trcr (i,j,:,iblk), & + vice = vice (i,j, iblk), & + vsno = vsno (i,j, iblk), & + aice0 = aice0(i,j, iblk), & + trcr_depend = trcr_depend, & + trcr_base = trcr_base, & + n_trcr_strata = n_trcr_strata, & + nt_strata = nt_strata, & + Tf = Tf(i,j,iblk)) + + aice_init(i,j,iblk) = aice(i,j,iblk) + + endif ! tmask + enddo ! i + enddo ! j + enddo ! iblk + + endif !restart_mod + end subroutine restartfile !======================================================================= @@ -1091,6 +1170,310 @@ subroutine restartfile_v4 (ice_ic) end subroutine restartfile_v4 +!======================================================================= + +!======================================================================= +! Direct insertion of ice concentration read from file. +! +! Posey, et. al. 2015: Improving Arctic sea ice edge forecasts by +! assimilating high horizontal resolution sea ice concentration +! data into the US Navy's ice forecast systems. +! The Cryosphere. doi:10.5194/tc-9-1735-2015 +! +! Alan J. Wallcraft, COAPS/FSU, Nov 2024 + + subroutine direct_adjust_aice(test) + + use ice_blocks, only: nghost, nx_block, ny_block + use ice_domain, only: nblocks + use ice_domain_size, only: nilyr, nslyr, ncat, max_blocks + use ice_grid, only: tmask + use ice_communicate, only: my_task, master_task + use ice_constants, only: c0, c1, c4, c20, c100, & + p5, p2, p1, p01, p001, & + field_loc_center, field_loc_NEcorner, & + field_type_scalar, field_type_vector + use ice_fileunits, only: nu_diag + use ice_flux, only: & + Tair, Tf, salinz, Tmltz, sst, & + stressp_1, stressp_2, stressp_3, stressp_4, & + stressm_1, stressm_2, stressm_3, stressm_4, & + stress12_1, stress12_2, stress12_3, stress12_4 + use ice_state, only: & + aice, aicen, vicen, vsnon, trcrn + use ice_read_write, only: ice_check_nc, ice_read_nc, & + ice_open_nc, ice_close_nc + use ice_arrays_column, only: hin_max + ! use icepack_mushy_physics, only: enthalpy_mush + use icepack_intfc, only: icepack_init_trcr + + logical(kind=log_kind), optional, intent(in) :: & + test ! use internally generated aice + + ! --- local variables + real(kind=dbl_kind) :: & + q , & ! scale factor + aice_m, & ! model aice + aice_o, & ! observation aice + aice_t, & ! target aice + aice_i, & ! insert ice + slope, & ! used to compute surf Temp + Ti, & ! target surface temperature + edge_om, & ! nominal ice edge zone + diff_om, & ! allowed model vs obs difference + hin_om, & ! new ice thickness + aicen_old, & ! old value of aice to check when adding ice + vsnon_old, & ! old value of snow volume to check when adding ice + Tsfc ! surface temp. + integer (kind=int_kind) :: & + fid ! file id for netCDF file + integer (kind=int_kind) :: & + i, j, k, n, iblk ! counting indices + logical (kind=log_kind) :: & + diag, & ! diagnostic output + ltest ! local value of test argument + real (kind=dbl_kind), dimension (nx_block,ny_block,max_blocks) :: & + work1 + real (kind=dbl_kind), dimension(nilyr) :: & + qin ! ice enthalpy (J/m3) + real (kind=dbl_kind), dimension(nslyr) :: & + qsn ! snow enthalpy (J/m3) + character(len=char_len_long) :: & + aice_filename, &! filename to read in + aice_fldname ! fieldname to read in + + ! parameters from icepack + real (kind=dbl_kind) :: & + puny, Tffresh, Tsmelt, Lfresh, cp_ice, cp_ocn, & + rhos, rhoi + integer (kind=int_kind) :: & + nt_Tsfc, nt_sice, nt_qice, nt_qsno, & + ktherm + character(len=*), parameter :: subname = '(direct_adjust_aice)' + + diag = .true. + ltest = .false. + if (present(test)) then + ltest = test + endif + aice_filename = trim(restart_dir)//'/sic.nc' + aice_fldname = 'sic' + + ! get parameters from icepack + call icepack_query_parameters( & + puny_out=puny, & + Tffresh_out=Tffresh, & + Tsmelt_out=Tsmelt, & + Lfresh_out=Lfresh, & + cp_ice_out=cp_ice, & + cp_ocn_out=cp_ocn, & + rhos_out=rhos, & + rhoi_out=rhoi, & + ktherm_out=ktherm ) + + call icepack_query_tracer_indices( & + nt_Tsfc_out=nt_Tsfc, & + nt_sice_out=nt_sice, & + nt_qice_out=nt_qice, & + nt_qsno_out=nt_qsno ) + + call icepack_warnings_flush(nu_diag) + if (icepack_warnings_aborted()) call abort_ice(error_message=subname, & + file=__FILE__, line=__LINE__) + + if (ltest) then + if (my_task == master_task) then + write(nu_diag,*) subname//" direct_adjust_aice rounding to nearest 1/20th" + endif + work1 = nint(aice*c20)/c20 ! round to nearest 5/100th + else + if (my_task == master_task) then + write(nu_diag,*) subname//" direct_adjust_aice from "//trim(aice_filename) + endif + + call ice_open_nc(trim(aice_filename), fid) + call ice_read_nc(fid,1,trim(aice_fldname),work1,diag, & + field_loc=field_loc_center, & + field_type=field_type_scalar) + call ice_close_nc(fid) + endif + + edge_om = p2 ! nominal ice edge zone + diff_om = p1 ! allowed model vs obs difference + hin_om = hin_max(1)*0.9_dbl_kind !new ice thickness + + do iblk = 1, nblocks + do j = 1, ny_block + do i = 1, nx_block + + aice_o = work1(i,j,iblk) ! obs. ice concentration + aice_m = aice(i,j,iblk) ! model ice concentration + + if (.not.tmask(i,j,iblk)) then + ! land - do nothing + elseif (aice_o.gt.p01 .and. & + abs(aice_o-aice_m).le.p01) then + ! model and obs are very close - do nothing + elseif (min(aice_o,aice_m).ge.edge_om .and. & + abs(aice_o-aice_m).le.diff_om) then + ! model and obs are close enough - do nothing + elseif (aice_o.eq.aice_m) then + elseif (aice_o.lt.aice_m) then + if (aice_o.lt.p01)then + ! --- remove all ice --- + ! warm sst so the ice won't grow immediately + sst(i,j,iblk) = sst(i,j,iblk) + p2 + do n=1,ncat + aicen(i,j,n,iblk) = c0 + vicen(i,j,n,iblk) = c0 + vsnon(i,j,n,iblk) = c0 + call icepack_init_trcr( & + Tair = Tair(i,j, iblk), & + Tf = Tf(i,j, iblk), & + Sprofile = salinz(i,j,:,iblk), & + Tprofile = Tmltz(i,j,:,iblk), & + Tsfc = Tsfc, & + qin = qin(:), & + qsn = qsn(:) ) + ! surface temperature + trcrn(i,j,nt_Tsfc,n,iblk) = Tsfc ! deg C + ! ice enthalpy, salinity + do k = 1, nilyr + trcrn(i,j,nt_qice+k-1,n,iblk) = qin(k) + trcrn(i,j,nt_sice+k-1,n,iblk) = salinz(i,j,k,iblk) + enddo ! nilyr + ! snow enthalpy + do k = 1, nslyr + trcrn(i,j,nt_qsno+k-1,n,iblk) = qsn(k) + enddo ! nslyr + enddo !n + else !aice_o.ge.p01 + if (aice_o.lt.edge_om) then + ! --- target ice conc. is obs. + aice_t = aice_o + else !aice_m-aice_o.gt.diff_om + ! --- target ice conc. is obs.+diff_om + aice_t = aice_o + diff_om + endif + ! --- reduce ice to the target concentration, + ! completely exhasting ice categories in order --- + aice_i = aice_m - aice_t !>=0.0 + do n=1,ncat + if (aice_i.le.p001) then + exit + elseif (aice_i.ge.aicen(i,j,n,iblk)) then + ! --- remove all of this category + aice_i = aice_i - aicen(i,j,n,iblk) + aicen(i,j,n,iblk) = c0 + vicen(i,j,n,iblk) = c0 + vsnon(i,j,n,iblk) = c0 + call icepack_init_trcr( & + Tair = Tair(i,j, iblk), & + Tf = Tf(i,j, iblk), & + Sprofile = salinz(i,j,:,iblk), & + Tprofile = Tmltz(i,j,:,iblk), & + Tsfc = Tsfc, & + qin = qin(:), & + qsn = qsn(:) ) + ! surface temperature + trcrn(i,j,nt_Tsfc,n,iblk) = Tsfc ! deg C + ! ice enthalpy, salinity + do k = 1, nilyr + trcrn(i,j,nt_qice+k-1,n,iblk) = qin(k) + trcrn(i,j,nt_sice+k-1,n,iblk) = salinz(i,j,k,iblk) + enddo ! nilyr + ! snow enthalpy + do k = 1, nslyr + trcrn(i,j,nt_qsno+k-1,n,iblk) = qsn(k) + enddo ! nslyr + else !aice_i.lt.aicen(i,j,n,iblk) + ! --- remove part of this category + q = (aicen(i,j,n,iblk) - aice_i) & + /aicen(i,j,n,iblk) !<1 + aice_i = c0 + + ! reduce aicen, vicen, vsnon by q + ! do not alter Tsfc since there is already + ! ice here. + aicen(i,j,n,iblk) = q*aicen(i,j,n,iblk) + vicen(i,j,n,iblk) = q*vicen(i,j,n,iblk) + vsnon(i,j,n,iblk) = q*vsnon(i,j,n,iblk) + endif ! aice_i.gt.p001 and aice_i.lt.aicen + enddo ! n + endif ! aice_o.lt.p01 + elseif (aice_o.gt.p01) then ! .and. aice_o.gt.aicen + if (aice_m.lt.edge_om) then + ! --- target ice conc. is obs. + aice_t = aice_o + else !aice_o-aice_m.gt.diff_om + ! --- target ice conc. is obs.-diff_om + aice_t = aice_o - diff_om + endif + q = (aice_t-aice_m) + ! --- add ice to the target concentration, + ! --- with all new ice in category 1 + ! --- cool sst so the ice won't melt immediately + sst( i,j, iblk) = sst( i,j, iblk) - q ! 0 <= q <= 1 + aicen_old = aicen(i,j,1,iblk) ! store to check for zero ice later + vsnon_old = vsnon(i,j,1,iblk) ! store to check for zero snow later + aicen(i,j,1,iblk) = aicen(i,j,1,iblk) + q + vicen(i,j,1,iblk) = vicen(i,j,1,iblk) + q*hin_om + vsnon(i,j,1,iblk) = vsnon(i,j,1,iblk) + q*hin_om*p2 + + ! ------------------------------------------------------ + ! check for zero snow in 1st category. + ! It is possible that there was ice + ! but no snow. This would skip the loop below and an + ! error in snow thermo would occur. If snow was zero + ! specify enthalpy here + ! ------------------------------------------------------ + if (vsnon_old < puny) then + do n=1,1 ! only do 1st category + ! --- snow layers + trcrn(i,j,nt_Tsfc,n,iblk) = & ! Tsfc + min(Tsmelt,Tair(i,j,iblk) - Tffresh) + Ti = min(c0,trcrn(i,j,nt_Tsfc,n,iblk)) + do k=1,nslyr + trcrn(i,j,nt_qsno+k-1,n,iblk) = -rhos*(Lfresh - cp_ice*Ti) + enddo ! k + enddo ! n = 1,1 + endif + + ! ------------------------------------------------------ + ! check for zero aice in 1st category. + ! if adding to an initially zero ice, we must define + ! qice, qsno, sice so thermo does not blow up. + ! ------------------------------------------------------ + if (aicen_old < puny) then + do n =1,1 ! only do 1st category + call icepack_init_trcr( & + Tair = Tair(i,j, iblk), & + Tf = Tf(i,j, iblk), & + Sprofile = salinz(i,j,:,iblk), & + Tprofile = Tmltz(i,j,:,iblk), & + Tsfc = Tsfc, & + qin = qin(:), & + qsn = qsn(:) ) + ! surface temperature + trcrn(i,j,nt_Tsfc,n,iblk) = Tsfc ! deg C + ! ice enthalpy, salinity + do k = 1, nilyr + trcrn(i,j,nt_qice+k-1,n,iblk) = qin(k) + trcrn(i,j,nt_sice+k-1,n,iblk) = salinz(i,j,k,iblk) + enddo + ! snow enthalpy + do k = 1, nslyr + trcrn(i,j,nt_qsno+k-1,n,iblk) = qsn(k) + enddo ! nslyr + enddo ! n + endif ! qice == c0 + endif ! aice_o vs aice_m or tmask + enddo ! j + enddo ! i + enddo ! iblk + + end subroutine direct_adjust_aice + !======================================================================= end module ice_restart_driver diff --git a/cicecore/shared/ice_restart_shared.F90 b/cicecore/shared/ice_restart_shared.F90 index 32d78e82f..409d0cb16 100644 --- a/cicecore/shared/ice_restart_shared.F90 +++ b/cicecore/shared/ice_restart_shared.F90 @@ -30,6 +30,7 @@ module ice_restart_shared character (len=char_len), public :: & restart_format , & ! format of restart files 'nc' + restart_mod , & ! restart modification option, "none", "adjust_aice" restart_rearranger ! restart file rearranger, box or subset for pio integer (kind=int_kind), public :: & diff --git a/configuration/scripts/ice_in b/configuration/scripts/ice_in index 776f9f966..4c1ed4111 100644 --- a/configuration/scripts/ice_in +++ b/configuration/scripts/ice_in @@ -21,6 +21,7 @@ restart_stride = -99 restart_deflate = 0 restart_chunksize = 0, 0 + restart_mod = 'none' lcdf64 = .false. numin = 21 numax = 89 diff --git a/configuration/scripts/options/set_nml.restaicetest b/configuration/scripts/options/set_nml.restaicetest new file mode 100644 index 000000000..3d779d732 --- /dev/null +++ b/configuration/scripts/options/set_nml.restaicetest @@ -0,0 +1,2 @@ +restart_mod = "adjust_aice_test" + diff --git a/configuration/scripts/tests/base_suite.ts b/configuration/scripts/tests/base_suite.ts index 46f2c1900..4af813211 100644 --- a/configuration/scripts/tests/base_suite.ts +++ b/configuration/scripts/tests/base_suite.ts @@ -86,3 +86,4 @@ restart gx3 4x4 diag1,gx3ncarbulk,short smoke gx3 4x1 calcdragio restart gx3 4x2 atmbndyconstant restart gx3 4x2 atmbndymixed +smoke gx3 12x2 diag1,run5day,restaicetest,debug diff --git a/doc/source/cice_index.rst b/doc/source/cice_index.rst index 949ab80b6..f46fbaa8d 100644 --- a/doc/source/cice_index.rst +++ b/doc/source/cice_index.rst @@ -595,6 +595,7 @@ section :ref:`tabnamelist`. "restart_file", "restart file prefix", "" "restart_format", "restart file format", "" "restart_iotasks", "restart output total number of tasks used", "" + "restart_mod", "restart modification mode", "" "restart_rearranger", "restart output io rearranger method", "" "restart_root", "restart output io root task id", "" "restart_stride", "restart output io task stride", "" diff --git a/doc/source/developer_guide/dg_assim.rst b/doc/source/developer_guide/dg_assim.rst new file mode 100644 index 000000000..cdcfb9eaa --- /dev/null +++ b/doc/source/developer_guide/dg_assim.rst @@ -0,0 +1,37 @@ +:tocdepth: 3 + +.. _dataassimilation: + +Data Assimilation +====================== + +Data assimilation (DA) is the scientific process of combining external +data with numerical model forecasts. There are several ways this can +be done including by adjusting the model initial conditions (internally +or externally) or adjusting the model solution as it evolves in time. +Various data assimilation options are being introduced in CICE and are +described below. + +.. _restartmod: + +Data Assimilation on restart +------------------------------------ + +The namelist variable, ``restart_mod``, specifies the restart DA mode. +By default, this namelist value is set to ``none`` which disables the feature. +The current active options are ``adjust_aice`` and ``adjust_aice_test``. + +With ``adjust_aice`` and ``adjust_aice_test``, the category averaged aice +value is modified at restart to specified values using the method implemented in +**cicecore/cicedyn/infrastructure/ice_restart_driver.F90** subroutine +**direct_adjust_aice**. This method adjusts aice, vice, vsno, qice, and +sice in all categories to be consistent with the category average aice +specified. It also adjusts several thermodynamic variables such as +temperature and salinity (see :cite:`Posey15`). +``adjust_aice`` reads in a sea ice concentration +field from an external file. The field is currently hardwired to 'sic' and the +file is currently hardwired to 'sic.nc'. The field must be on the model grid. +``adjust_aice_test`` modifies the +aice field read on restart internally. The current implementation rounds +the aice values read at restart to the nearest 1/100th. This mode exists +primarily to test the feature. diff --git a/doc/source/developer_guide/index.rst b/doc/source/developer_guide/index.rst index 680746beb..e8ed32408 100644 --- a/doc/source/developer_guide/index.rst +++ b/doc/source/developer_guide/index.rst @@ -16,6 +16,7 @@ Developer Guide dg_infra.rst dg_driver.rst dg_forcing.rst + dg_assim.rst dg_icepack.rst dg_scripts.rst dg_tools.rst diff --git a/doc/source/master_list.bib b/doc/source/master_list.bib index 6e3bb9b40..a91511ccd 100644 --- a/doc/source/master_list.bib +++ b/doc/source/master_list.bib @@ -1041,7 +1041,7 @@ @incollection{Arakawa77 @article{Horvat15, author = "C. Horvat and E. Tziperman", - journal = {The Cryosphere}, + journal = TC, number = {6}, pages = {2119-2134}, title = "{A prognostic model of the sea-ice floe size and thickness distribution}", @@ -1113,6 +1113,16 @@ @Article{Tsujino18 pages = {79-139}, url = {http://dx.doi.org/10.1016/j.ocemod.2018.07.002} } + +@Article{Posey15, + author = "P.G. Posey and E.J. Metzger and A.J. Wallcraft and D.A. Hebert and R.A. Allard and O.M. Smedstad and M.W. Phelps and F. Fetterer and J.S. Stewart and W.N. Meier and S.R. Helfrich", + title = "{Improving Arctic sea ice edge forecasts by assimilating high horizontal resolution sea ice concentration data into the US Navy's ice forecast system}", + journal = TC, + year = {2015}, + volume = {9}, + pages = {1735-1745}, + url = {https://doi.org/10.5194/tc-9-1735-2015} +} % ********************************************** % For new entries, see example entry in BIB_TEMPLATE.txt % ********************************************** diff --git a/doc/source/user_guide/ug_case_settings.rst b/doc/source/user_guide/ug_case_settings.rst index 2f705e64c..e2b271776 100644 --- a/doc/source/user_guide/ug_case_settings.rst +++ b/doc/source/user_guide/ug_case_settings.rst @@ -266,6 +266,9 @@ setup_nml "", "``pnetcdf2``", "write restart files with pnetcdf cdf2 (netcdf3-64bit-offset) format", "" "", "``pnetcdf5``", "write restart files with pnetcdf cdf5 (netcdf3-64bit-data) format", "" "``restart_iotasks``", "integer", "pe io tasks for restart output with restart_root and restart_stride (PIO only), -99=internal default", "-99" + "``restart_mod``", "``adjust_aice``", "adjust aice on restart read from file", "none" + "", "``adjust_aice_test``", "adjust aice on restart read rounding", "" + "", "``none``", "no modification of restart at read", "" "``restart_rearranger``", "``box``", "box io rearranger option for restart output (PIO only)", "default" "", "``default``", "internal default io rearranger option for restart output", "" "", "``subset``", "subset io rearranger option for restart output", "" From 8e3ef7c4cb657705ceff5bfec3e12b49dec4973e Mon Sep 17 00:00:00 2001 From: Tony Craig Date: Wed, 5 Nov 2025 13:09:31 -0800 Subject: [PATCH 10/21] Update outer boundary implementation to support open boundary conditions (#1062) Refactor CICE to support open boundary conditions where values may be imposed on the outer boundary. Prior to this update, the HaloUpdate was zeroing out the halo before updating the halo. This meant any values set on the halo were lost anytime a HaloUpdate was executed. Several other issues upstream and downstream were found as this was implemented. In particular, the global index set on the outer boundary for open and closed boundary conditions was "special", a zero global index was used internally as a flag, and both the scatter_global and haloUpdate was covering up some issues with uninitialized data. Update the i_glob and j_glob indexing for open and closed boundary conditions on the outer boundary. For open, closed, and tripole (south) boundaries, now extrapolate index values on the outer boundary. This might mean indices are less than 0 or greater than n[x,y]_global+2*nghost. In the original implementation, these outer boundary indices were either set to some internal values so they would be set with the scatter_global method or to zero which was treated as a special value. The zero special value feature has been removed and the scatter_global implementation has been refactored to fill all gridpoints with valid global indices and leave others unset. The only special case remaining in the global indexing is for tripole grids on the north boundary where the j global index is set to a negative value. - Refactor HaloUpdate in ice_boundary in serial and mpi to avoid zeroing out the halo. The ew and ns directions are handled separately. The new implementation will always zero the internal halo points. It will also zero the outer halo if cyclic or tripole is specified or if a fillvalue is passed into the haloUpdate. Otherwise, the outer halo is left unchanged. - Added ewBoundaryType and nsBoundaryType to halo datatype to keep track of the boundary conditions for each halo datatype. - Zero out the outer boundary during HaloUpdate only under certain conditions including cyclic or tripole bcs or if a fillValue is explicitly passed - Add a few fillvalue=c0 arguments to HaloUpdate calls during initialization to force the outer boundary values to zero, mostly during initialization of grid data and similar cases. - Add several HaloExtrapolate calls to initialize boundary values for grid fields. This replaces those fields being set by the incorrect global indices and the scatter. - Explicitly zero out all allocated variables at initialization - Explicitly zero out restart fields before reading to be extra careful - Explicitly zero out some arrays in the evp1d before use - Replace the G_HTN and G_HTE initialization with a call to gather_global_ext on HTN and HTE respectively after HTN and HTE are set and the halos updated. - Move the closed boundary condition abort to initialization in ice_domain.F90 - Refactor halochk unit test, add explicit fill tests - Update documentation Additional Features - Update ice_HaloExtrapolate to support more than 1 ghost cell - Add support for kmt_type = none with in subroutine rectgrid for rectangular grids. This allows a user to setup a rectangular grid with no land. - Update the restart_ext implementation in ice_read_write. There was a bug if restart_ext=.false. was passed, nothing would happen. The update also allows some extra restart_ext logic in io_netcdf/ice_restart.F90 to be cleaned up. - Carry out some code cleanup in init_domain_distribution and init_grid2 - Rename iglb/jglb to isrc/jsrc consistent in scatter_global_ext to be consistent with other scatter methods. All tests are bit-for-bit except the halochk unittest which was refactored and passes. There is an issue in the evp1d implementation where on some compilers when the debug flag is on, the code will trap on a floating point error. If the floating point error isn't trapped, the cases run to completion and are bit-for-bit with the current trunk. This suggests there is something like a 0/0 calculation being trapped in the evp1d which has no impact on the solution, is only caught by a subset of compilers, and probably requires an if test to avoid. I spent some time trying to track down the error without any success. --- cicecore/cicedyn/dynamics/ice_dyn_evp1d.F90 | 39 +- cicecore/cicedyn/dynamics/ice_dyn_shared.F90 | 26 + cicecore/cicedyn/general/ice_flux.F90 | 309 +++++- cicecore/cicedyn/general/ice_flux_bgc.F90 | 43 + cicecore/cicedyn/general/ice_forcing.F90 | 86 +- cicecore/cicedyn/general/ice_forcing_bgc.F90 | 5 + cicecore/cicedyn/general/ice_init.F90 | 16 +- cicecore/cicedyn/general/ice_state.F90 | 32 +- .../infrastructure/comm/mpi/ice_boundary.F90 | 883 +++++++++++++--- .../comm/mpi/ice_gather_scatter.F90 | 860 +++++----------- .../comm/serial/ice_boundary.F90 | 943 ++++++++++++++---- .../comm/serial/ice_gather_scatter.F90 | 441 +++----- .../cicedyn/infrastructure/ice_blocks.F90 | 56 +- .../cicedyn/infrastructure/ice_domain.F90 | 107 +- cicecore/cicedyn/infrastructure/ice_grid.F90 | 192 +++- .../cicedyn/infrastructure/ice_read_write.F90 | 162 +-- .../io/io_netcdf/ice_restart.F90 | 43 +- .../infrastructure/io/io_pio2/ice_restart.F90 | 1 + .../unittest/gridavgchk/gridavgchk.F90 | 1 - cicecore/drivers/unittest/halochk/halochk.F90 | 359 +++---- cicecore/shared/ice_arrays_column.F90 | 124 ++- configuration/scripts/ice_in | 1 - configuration/scripts/options/set_nml.box2001 | 5 +- configuration/scripts/options/set_nml.boxchan | 1 - .../scripts/options/set_nml.boxchan1e | 1 - .../scripts/options/set_nml.boxchan1n | 1 - .../scripts/options/set_nml.boxclosed | 5 +- configuration/scripts/options/set_nml.boxopen | 1 - .../scripts/options/set_nml.boxslotcyl | 5 +- .../scripts/options/set_nml.boxwallblock | 1 - doc/source/user_guide/ug_case_settings.rst | 8 +- doc/source/user_guide/ug_implementation.rst | 52 +- 32 files changed, 3030 insertions(+), 1779 deletions(-) diff --git a/cicecore/cicedyn/dynamics/ice_dyn_evp1d.F90 b/cicecore/cicedyn/dynamics/ice_dyn_evp1d.F90 index 223ef2849..18316640e 100644 --- a/cicecore/cicedyn/dynamics/ice_dyn_evp1d.F90 +++ b/cicecore/cicedyn/dynamics/ice_dyn_evp1d.F90 @@ -94,7 +94,7 @@ subroutine dyn_evp1d_init endif ! gather from blks to global - call gather_static(G_uarear, G_dxT, G_dyT, G_tmask) + call gather_static(G_uarear, G_dxT, G_dyT, G_tmask) ! calculate number of water points (T and U). Only needed for the static version ! tmask in ocean/ice @@ -349,7 +349,6 @@ subroutine evp1d_alloc_static_na(na0) call abort_ice(subname//' ERROR: allocating', file=__FILE__, line=__LINE__) endif - allocate(indxTi(1:na0), & indxTj(1:na0), & stat=ierr) @@ -628,6 +627,11 @@ subroutine gather_static(G_uarear, G_dxT, G_dyT, G_Tmask) character(len=*), parameter :: subname = '(gather_static)' + G_uarear = c0 + G_dyT = c0 + G_dxT = c0 + G_tmask = .false. + ! copy from distributed I_* to G_* call gather_global_ext(G_uarear, uarear, master_task, distrb_info) call gather_global_ext(G_dxT , dxT , master_task, distrb_info) @@ -977,6 +981,37 @@ subroutine convert_1d_2d_dyn(na0 , navel0 , integer(kind=int_kind) :: lo, up, iw, i, j character(len=*), parameter :: subname = '(convert_1d_2d_dyn)' + G_stressp_1 = c0 + G_stressp_2 = c0 + G_stressp_3 = c0 + G_stressp_4 = c0 + G_stressm_1 = c0 + G_stressm_2 = c0 + G_stressm_3 = c0 + G_stressm_4 = c0 + G_stress12_1 = c0 + G_stress12_2 = c0 + G_stress12_3 = c0 + G_stress12_4 = c0 + G_strength = c0 + G_cdn_ocn = c0 + G_aiu = c0 + G_uocn = c0 + G_vocn = c0 + G_waterxU = c0 + G_wateryU = c0 + G_forcexU = c0 + G_forceyU = c0 + G_umassdti = c0 + G_fmU = c0 + G_strintxU = c0 + G_strintyU = c0 + G_Tbu = c0 + G_uvel = c0 + G_vvel = c0 + G_taubxU = c0 + G_taubyU = c0 + lo=1 up=na0 do iw = lo, up diff --git a/cicecore/cicedyn/dynamics/ice_dyn_shared.F90 b/cicecore/cicedyn/dynamics/ice_dyn_shared.F90 index 40f49877d..81d603124 100644 --- a/cicecore/cicedyn/dynamics/ice_dyn_shared.F90 +++ b/cicecore/cicedyn/dynamics/ice_dyn_shared.F90 @@ -193,6 +193,13 @@ subroutine alloc_dyn_shared stat=ierr) if (ierr/=0) call abort_ice(subname//': Out of memory') + uvel_init = c0 + vvel_init = c0 + iceTmask = .false. + iceUmask = .false. + fcor_blk = c0 + DminTarea = c0 + allocate( & fld2(nx_block,ny_block,2,max_blocks), & fld3(nx_block,ny_block,3,max_blocks), & @@ -200,6 +207,10 @@ subroutine alloc_dyn_shared stat=ierr) if (ierr/=0) call abort_ice(subname//': Out of memory') + fld2 = c0 + fld3 = c0 + fld4 = c0 + allocate( & cyp(nx_block,ny_block,max_blocks), & ! 1.5*HTE - 0.5*HTW cxp(nx_block,ny_block,max_blocks), & ! 1.5*HTN - 0.5*HTS @@ -208,12 +219,19 @@ subroutine alloc_dyn_shared stat=ierr) if (ierr/=0) call abort_ice(subname//': Out of memory') + cyp = c0 + cxp = c0 + cym = c0 + cxm = c0 + if (grid_ice == 'B' .and. evp_algorithm == "standard_2d") then allocate( & dxhy(nx_block,ny_block,max_blocks), & ! 0.5*(HTE - HTW) dyhx(nx_block,ny_block,max_blocks), & ! 0.5*(HTN - HTS) stat=ierr) if (ierr/=0) call abort_ice(subname//': Out of memory') + dxhy = c0 + dyhx = c0 endif if (grid_ice == 'CD' .or. grid_ice == 'C') then @@ -228,6 +246,14 @@ subroutine alloc_dyn_shared fcorN_blk (nx_block,ny_block,max_blocks), & ! Coriolis stat=ierr) if (ierr/=0) call abort_ice(subname//': Out of memory') + uvelE_init = c0 + vvelE_init = c0 + uvelN_init = c0 + vvelN_init = c0 + iceEmask = .false. + iceNmask = .false. + fcorE_blk = c0 + fcorN_blk = c0 endif end subroutine alloc_dyn_shared diff --git a/cicecore/cicedyn/general/ice_flux.F90 b/cicecore/cicedyn/general/ice_flux.F90 index ff71a4a4d..16d3a6edc 100644 --- a/cicecore/cicedyn/general/ice_flux.F90 +++ b/cicecore/cicedyn/general/ice_flux.F90 @@ -625,40 +625,270 @@ subroutine alloc_flux stat=ierr) if (ierr/=0) call abort_ice('(alloc_flux): Out of memory') - if (grid_ice == "CD" .or. grid_ice == "C") & + strax = c0 + stray = c0 + uocn = c0 + vocn = c0 + ss_tltx = c0 + ss_tlty = c0 + hwater = c0 + strairxT = c0 + strairyT = c0 + strocnxT_iavg= c0 + strocnyT_iavg= c0 + sig1 = c0 + sig2 = c0 + sigP = c0 + taubxU = c0 + taubyU = c0 + strairxU = c0 + strairyU = c0 + strocnxU = c0 + strocnyU = c0 + strtltxU = c0 + strtltyU = c0 + strintxU = c0 + strintyU = c0 + daidtd = c0 + dvidtd = c0 + dvsdtd = c0 + dagedtd = c0 + dardg1dt = c0 + dardg2dt = c0 + dvirdgdt = c0 + opening = c0 + stressp_1 = c0 + stressp_2 = c0 + stressp_3 = c0 + stressp_4 = c0 + stressm_1 = c0 + stressm_2 = c0 + stressm_3 = c0 + stressm_4 = c0 + stress12_1 = c0 + stress12_2 = c0 + stress12_3 = c0 + stress12_4 = c0 + fmU = c0 + TbU = c0 + zlvl = c0 + zlvs = c0 + uatm = c0 + vatm = c0 + wind = c0 + potT = c0 + Tair = c0 + Qa = c0 + rhoa = c0 + swvdr = c0 + swvdf = c0 + swidr = c0 + swidf = c0 + swuvrdr = c0 + swuvrdf = c0 + swpardr = c0 + swpardf = c0 + flw = c0 + frain = c0 + fsnow = c0 + sss = c0 + sst = c0 + frzmlt = c0 + frzmlt_init= c0 + Tf = c0 + qdp = c0 + hmix = c0 + daice_da = c0 + fsens = c0 + flat = c0 + fswabs = c0 + fswint_ai = c0 + flwout = c0 + Tref = c0 + Qref = c0 + Uref = c0 + evap = c0 + evaps = c0 + evapi = c0 + alvdr = c0 + alidr = c0 + alvdf = c0 + alidf = c0 + alvdr_ai = c0 + alidr_ai = c0 + alvdf_ai = c0 + alidf_ai = c0 + albice = c0 + albsno = c0 + albpnd = c0 + apeff_ai = c0 + snowfrac = c0 + alvdr_init = c0 + alidr_init = c0 + alvdf_init = c0 + alidf_init = c0 + fpond = c0 + fresh = c0 + fsalt = c0 + fhocn = c0 + fsloss = c0 + fswthru = c0 + fswthru_vdr= c0 + fswthru_vdf= c0 + fswthru_idr= c0 + fswthru_idf= c0 + fswthru_uvrdr = c0 + fswthru_uvrdf = c0 + fswthru_pardr = c0 + fswthru_pardf = c0 + scale_factor = c0 + strairx_ocn= c0 + strairy_ocn= c0 + fsens_ocn = c0 + flat_ocn = c0 + flwout_ocn = c0 + evap_ocn = c0 + alvdr_ocn = c0 + alidr_ocn = c0 + alvdf_ocn = c0 + alidf_ocn = c0 + Tref_ocn = c0 + Qref_ocn = c0 + fsurf = c0 + fcondtop = c0 + fcondbot = c0 + fbot = c0 + Tbot = c0 + Tsnice = c0 + congel = c0 + frazil = c0 + snoice = c0 + meltt = c0 + melts = c0 + meltb = c0 + meltl = c0 + dsnow = c0 + daidtt = c0 + dvidtt = c0 + dvsdtt = c0 + dagedtt = c0 + mlt_onset = c0 + frz_onset = c0 + frazil_diag= c0 + fresh_ai = c0 + fsalt_ai = c0 + fhocn_ai = c0 + fswthru_ai = c0 + fresh_da = c0 + fsalt_da = c0 + uatmT = c0 + vatmT = c0 + wlat = c0 + fsw = c0 + coszen = c0 + rdg_conv = c0 + rdg_shear = c0 + rsiden = c0 + dardg1ndt = c0 + dardg2ndt = c0 + dvirdgndt = c0 + aparticn = c0 + krdgn = c0 + ardgn = c0 + vrdgn = c0 + araftn = c0 + vraftn = c0 + aredistn = c0 + vredistn = c0 + fsurfn_f = c0 + fcondtopn_f= c0 + fsensn_f = c0 + flatn_f = c0 + evapn_f = c0 + dflatndTsfc_f = c0 + dfsurfndTsfc_f= c0 + meltsn = c0 + melttn = c0 + meltbn = c0 + congeln = c0 + snoicen = c0 + keffn_top = c0 + fsurfn = c0 + fcondtopn = c0 + fcondbotn = c0 + fsensn = c0 + flatn = c0 + albcnt = c0 + snwcnt = c0 + salinz = c0 + Tmltz = c0 + + if (grid_ice == "CD" .or. grid_ice == "C") then allocate( & - taubxN (nx_block,ny_block,max_blocks), & ! seabed stress (x) at N points (N/m^2) - taubyN (nx_block,ny_block,max_blocks), & ! seabed stress (y) at N points (N/m^2) - strairxN (nx_block,ny_block,max_blocks), & ! stress on ice by air, x-direction at N points - strairyN (nx_block,ny_block,max_blocks), & ! stress on ice by air, y-direction at N points - strocnxN (nx_block,ny_block,max_blocks), & ! ice-ocean stress, x-direction at N points - strocnyN (nx_block,ny_block,max_blocks), & ! ice-ocean stress, y-direction at N points - strtltxN (nx_block,ny_block,max_blocks), & ! stress due to sea surface slope, x-direction at N points - strtltyN (nx_block,ny_block,max_blocks), & ! stress due to sea surface slope, y-direction at N points - strintxN (nx_block,ny_block,max_blocks), & ! divergence of internal ice stress, x at N points (N/m^2) - strintyN (nx_block,ny_block,max_blocks), & ! divergence of internal ice stress, y at N points (N/m^2) - fmN (nx_block,ny_block,max_blocks), & ! Coriolis param. * mass in N-cell (kg/s) - TbN (nx_block,ny_block,max_blocks), & ! factor for seabed stress (landfast ice) - taubxE (nx_block,ny_block,max_blocks), & ! seabed stress (x) at E points (N/m^2) - taubyE (nx_block,ny_block,max_blocks), & ! seabed stress (y) at E points (N/m^2) - strairxE (nx_block,ny_block,max_blocks), & ! stress on ice by air, x-direction at E points - strairyE (nx_block,ny_block,max_blocks), & ! stress on ice by air, y-direction at E points - strocnxE (nx_block,ny_block,max_blocks), & ! ice-ocean stress, x-direction at E points - strocnyE (nx_block,ny_block,max_blocks), & ! ice-ocean stress, y-direction at E points - strtltxE (nx_block,ny_block,max_blocks), & ! stress due to sea surface slope, x-direction at E points - strtltyE (nx_block,ny_block,max_blocks), & ! stress due to sea surface slope, y-direction at E points - strintxE (nx_block,ny_block,max_blocks), & ! divergence of internal ice stress, x at E points (N/m^2) - strintyE (nx_block,ny_block,max_blocks), & ! divergence of internal ice stress, y at E points (N/m^2) - fmE (nx_block,ny_block,max_blocks), & ! Coriolis param. * mass in E-cell (kg/s) - TbE (nx_block,ny_block,max_blocks), & ! factor for seabed stress (landfast ice) - stresspT (nx_block,ny_block,max_blocks), & ! sigma11+sigma22 - stressmT (nx_block,ny_block,max_blocks), & ! sigma11-sigma22 - stress12T (nx_block,ny_block,max_blocks), & ! sigma12 - stresspU (nx_block,ny_block,max_blocks), & ! sigma11+sigma22 - stressmU (nx_block,ny_block,max_blocks), & ! sigma11-sigma22 - stress12U (nx_block,ny_block,max_blocks), & ! sigma12 - stat=ierr) - if (ierr/=0) call abort_ice('(alloc_flux): Out of memory (C or CD grid)') + taubxN (nx_block,ny_block,max_blocks), & ! seabed stress (x) at N points (N/m^2) + taubyN (nx_block,ny_block,max_blocks), & ! seabed stress (y) at N points (N/m^2) + strairxN (nx_block,ny_block,max_blocks), & ! stress on ice by air, x-direction at N points + strairyN (nx_block,ny_block,max_blocks), & ! stress on ice by air, y-direction at N points + strocnxN (nx_block,ny_block,max_blocks), & ! ice-ocean stress, x-direction at N points + strocnyN (nx_block,ny_block,max_blocks), & ! ice-ocean stress, y-direction at N points + strtltxN (nx_block,ny_block,max_blocks), & ! stress due to sea surface slope, x-direction at N points + strtltyN (nx_block,ny_block,max_blocks), & ! stress due to sea surface slope, y-direction at N points + strintxN (nx_block,ny_block,max_blocks), & ! divergence of internal ice stress, x at N points (N/m^2) + strintyN (nx_block,ny_block,max_blocks), & ! divergence of internal ice stress, y at N points (N/m^2) + fmN (nx_block,ny_block,max_blocks), & ! Coriolis param. * mass in N-cell (kg/s) + TbN (nx_block,ny_block,max_blocks), & ! factor for seabed stress (landfast ice) + taubxE (nx_block,ny_block,max_blocks), & ! seabed stress (x) at E points (N/m^2) + taubyE (nx_block,ny_block,max_blocks), & ! seabed stress (y) at E points (N/m^2) + strairxE (nx_block,ny_block,max_blocks), & ! stress on ice by air, x-direction at E points + strairyE (nx_block,ny_block,max_blocks), & ! stress on ice by air, y-direction at E points + strocnxE (nx_block,ny_block,max_blocks), & ! ice-ocean stress, x-direction at E points + strocnyE (nx_block,ny_block,max_blocks), & ! ice-ocean stress, y-direction at E points + strtltxE (nx_block,ny_block,max_blocks), & ! stress due to sea surface slope, x-direction at E points + strtltyE (nx_block,ny_block,max_blocks), & ! stress due to sea surface slope, y-direction at E points + strintxE (nx_block,ny_block,max_blocks), & ! divergence of internal ice stress, x at E points (N/m^2) + strintyE (nx_block,ny_block,max_blocks), & ! divergence of internal ice stress, y at E points (N/m^2) + fmE (nx_block,ny_block,max_blocks), & ! Coriolis param. * mass in E-cell (kg/s) + TbE (nx_block,ny_block,max_blocks), & ! factor for seabed stress (landfast ice) + stresspT (nx_block,ny_block,max_blocks), & ! sigma11+sigma22 + stressmT (nx_block,ny_block,max_blocks), & ! sigma11-sigma22 + stress12T (nx_block,ny_block,max_blocks), & ! sigma12 + stresspU (nx_block,ny_block,max_blocks), & ! sigma11+sigma22 + stressmU (nx_block,ny_block,max_blocks), & ! sigma11-sigma22 + stress12U (nx_block,ny_block,max_blocks), & ! sigma12 + stat=ierr) + if (ierr/=0) call abort_ice('(alloc_flux): Out of memory (C or CD grid)') + + taubxN = c0 + taubyN = c0 + strairxN = c0 + strairyN = c0 + strocnxN = c0 + strocnyN = c0 + strtltxN = c0 + strtltyN = c0 + strintxN = c0 + strintyN = c0 + fmN = c0 + TbN = c0 + taubxE = c0 + taubyE = c0 + strairxE = c0 + strairyE = c0 + strocnxE = c0 + strocnyE = c0 + strtltxE = c0 + strtltyE = c0 + strintxE = c0 + strintyE = c0 + fmE = c0 + TbE = c0 + stresspT = c0 + stressmT = c0 + stress12T = c0 + stresspU = c0 + stressmU = c0 + stress12U = c0 + endif ! Pond diagnostics allocate( & @@ -677,6 +907,19 @@ subroutine alloc_flux stat=ierr) if (ierr/=0) call abort_ice('(alloc_flux): Out of memory (ponds)') + dpnd_flush = c0 + dpnd_expon = c0 + dpnd_freebd = c0 + dpnd_initial = c0 + dpnd_dlid = c0 + dpnd_melt = c0 + dpnd_ridge = c0 + dpnd_flushn = c0 + dpnd_exponn = c0 + dpnd_freebdn = c0 + dpnd_initialn= c0 + dpnd_dlidn = c0 + end subroutine alloc_flux !======================================================================= diff --git a/cicecore/cicedyn/general/ice_flux_bgc.F90 b/cicecore/cicedyn/general/ice_flux_bgc.F90 index 9c07971ff..7aaaf2baa 100644 --- a/cicecore/cicedyn/general/ice_flux_bgc.F90 +++ b/cicecore/cicedyn/general/ice_flux_bgc.F90 @@ -7,6 +7,7 @@ module ice_flux_bgc use ice_kinds_mod + use ice_constants, only: c0 use ice_blocks, only: nx_block, ny_block use ice_domain_size, only: max_blocks, ncat use ice_fileunits, only: nu_diag @@ -161,6 +162,48 @@ subroutine alloc_flux_bgc stat=ierr) if (ierr/=0) call abort_ice('(alloc_flux_bgc): Out of memory') + nit = c0 + amm = c0 + sil = c0 + dmsp = c0 + dms = c0 + hum = c0 + fnit = c0 + famm = c0 + fsil = c0 + fdmsp = c0 + fdms = c0 + fhum = c0 + fdust = c0 + hin_old = c0 + dsnown = c0 + HDO_ocn = c0 + H2_16O_ocn = c0 + H2_18O_ocn = c0 + Qa_iso = c0 + Qref_iso = c0 + fiso_atm = c0 + fiso_evap = c0 + fiso_ocn = c0 + faero_atm = c0 + faero_ocn = c0 + zaeros = c0 + flux_bio_atm= c0 + flux_bio = c0 + flux_bio_ai = c0 + algalN = c0 + falgalN = c0 + doc = c0 + fdoc = c0 + don = c0 + fdon = c0 + dic = c0 + fdic = c0 + fed = c0 + fep = c0 + ffed = c0 + ffep = c0 + end subroutine alloc_flux_bgc !======================================================================= diff --git a/cicecore/cicedyn/general/ice_forcing.F90 b/cicecore/cicedyn/general/ice_forcing.F90 index e0f1b736a..d165b612a 100755 --- a/cicecore/cicedyn/general/ice_forcing.F90 +++ b/cicecore/cicedyn/general/ice_forcing.F90 @@ -209,37 +209,59 @@ subroutine alloc_forcing if (local_debug .and. my_task == master_task) write(nu_diag,*) subname,'fdbg start' allocate ( & - cldf(nx_block,ny_block, max_blocks), & ! cloud fraction - fsw_data(nx_block,ny_block,2,max_blocks), & ! field values at 2 temporal data points - cldf_data(nx_block,ny_block,2,max_blocks), & - fsnow_data(nx_block,ny_block,2,max_blocks), & - Tair_data(nx_block,ny_block,2,max_blocks), & - uatm_data(nx_block,ny_block,2,max_blocks), & - vatm_data(nx_block,ny_block,2,max_blocks), & - wind_data(nx_block,ny_block,2,max_blocks), & - strax_data(nx_block,ny_block,2,max_blocks), & - stray_data(nx_block,ny_block,2,max_blocks), & - Qa_data(nx_block,ny_block,2,max_blocks), & - rhoa_data(nx_block,ny_block,2,max_blocks), & - flw_data(nx_block,ny_block,2,max_blocks), & - sst_data(nx_block,ny_block,2,max_blocks), & - sss_data(nx_block,ny_block,2,max_blocks), & - uocn_data(nx_block,ny_block,2,max_blocks), & - vocn_data(nx_block,ny_block,2,max_blocks), & - sublim_data(nx_block,ny_block,2,max_blocks), & - frain_data(nx_block,ny_block,2,max_blocks), & - topmelt_data(nx_block,ny_block,2,max_blocks,ncat), & - botmelt_data(nx_block,ny_block,2,max_blocks,ncat), & - ocn_frc_m(nx_block,ny_block, max_blocks,nfld,12), & ! ocn data for 12 months - topmelt_file(ncat), & - botmelt_file(ncat), & - wave_spectrum_data(nx_block,ny_block,nfreq,2,max_blocks), & + cldf (nx_block,ny_block, max_blocks), & ! cloud fraction + fsw_data (nx_block,ny_block,2,max_blocks), & ! field values at 2 temporal data points + cldf_data (nx_block,ny_block,2,max_blocks), & + fsnow_data (nx_block,ny_block,2,max_blocks), & + Tair_data (nx_block,ny_block,2,max_blocks), & + uatm_data (nx_block,ny_block,2,max_blocks), & + vatm_data (nx_block,ny_block,2,max_blocks), & + wind_data (nx_block,ny_block,2,max_blocks), & + strax_data (nx_block,ny_block,2,max_blocks), & + stray_data (nx_block,ny_block,2,max_blocks), & + Qa_data (nx_block,ny_block,2,max_blocks), & + rhoa_data (nx_block,ny_block,2,max_blocks), & + flw_data (nx_block,ny_block,2,max_blocks), & + sst_data (nx_block,ny_block,2,max_blocks), & + sss_data (nx_block,ny_block,2,max_blocks), & + uocn_data (nx_block,ny_block,2,max_blocks), & + vocn_data (nx_block,ny_block,2,max_blocks), & + sublim_data (nx_block,ny_block,2,max_blocks), & + frain_data (nx_block,ny_block,2,max_blocks), & + topmelt_data(nx_block,ny_block,2,max_blocks,ncat), & + botmelt_data(nx_block,ny_block,2,max_blocks,ncat), & + ocn_frc_m (nx_block,ny_block, max_blocks,nfld,12), & ! ocn data for 12 months + topmelt_file(ncat), & + botmelt_file(ncat), & + wave_spectrum_data(nx_block,ny_block,nfreq,2,max_blocks), & stat=ierr) if (ierr/=0) call abort_ice('(alloc_forcing): Out of Memory') -! initialize this, not set in box2001 (and some other forcings?) - - cldf = c0 + cldf = c0 + fsw_data = c0 + cldf_data = c0 + fsnow_data = c0 + Tair_data = c0 + uatm_data = c0 + vatm_data = c0 + wind_data = c0 + strax_data = c0 + stray_data = c0 + Qa_data = c0 + rhoa_data = c0 + flw_data = c0 + sst_data = c0 + sss_data = c0 + uocn_data = c0 + vocn_data = c0 + sublim_data = c0 + frain_data = c0 + topmelt_data = c0 + botmelt_data = c0 + ocn_frc_m = c0 + topmelt_file = '' + botmelt_file = '' + wave_spectrum_data = c0 end subroutine alloc_forcing @@ -711,13 +733,13 @@ subroutine get_forcing_atmo call ice_timer_start(timer_bound) call ice_HaloUpdate (swvdr, halo_info, & - field_loc_center, field_type_scalar) + field_loc_center, field_type_scalar, fillvalue=c0) call ice_HaloUpdate (swvdf, halo_info, & - field_loc_center, field_type_scalar) + field_loc_center, field_type_scalar, fillvalue=c0) call ice_HaloUpdate (swidr, halo_info, & - field_loc_center, field_type_scalar) + field_loc_center, field_type_scalar, fillvalue=c0) call ice_HaloUpdate (swidf, halo_info, & - field_loc_center, field_type_scalar) + field_loc_center, field_type_scalar, fillvalue=c0) call ice_timer_stop(timer_bound) call ice_timer_stop(timer_forcing) diff --git a/cicecore/cicedyn/general/ice_forcing_bgc.F90 b/cicecore/cicedyn/general/ice_forcing_bgc.F90 index 69c3ea311..d12df6417 100644 --- a/cicecore/cicedyn/general/ice_forcing_bgc.F90 +++ b/cicecore/cicedyn/general/ice_forcing_bgc.F90 @@ -65,6 +65,11 @@ subroutine alloc_forcing_bgc stat=ierr) if (ierr/=0) call abort_ice('(alloc_forcing_bgc): Out of memory') + nitdat = c0 + sildat = c0 + nit_data= c0 + sil_data= c0 + end subroutine alloc_forcing_bgc !======================================================================= diff --git a/cicecore/cicedyn/general/ice_init.F90 b/cicecore/cicedyn/general/ice_init.F90 index 1c6f0fec3..aa78c398d 100644 --- a/cicecore/cicedyn/general/ice_init.F90 +++ b/cicecore/cicedyn/general/ice_init.F90 @@ -1445,6 +1445,14 @@ subroutine input_data endif endif + if (close_boundaries) then + if (my_task == master_task) then + write(nu_diag,*) subname//' ERROR: close_boundaries deprecated, '// & + 'use ew_boundary_type=closed and/or ns_boundary_type=closed' + endif + abort_list = trim(abort_list)//":49" + endif + if (grid_ice == 'CD') then if (my_task == master_task) then write(nu_diag,*) subname//' ERROR: grid_ice = CD not supported yet' @@ -3071,14 +3079,14 @@ subroutine init_state ! Halo update on North, East faces call ice_HaloUpdate(uvelN, halo_info, & - field_loc_Nface, field_type_scalar) + field_loc_Nface, field_type_scalar, fillvalue=c0) call ice_HaloUpdate(vvelN, halo_info, & - field_loc_Nface, field_type_scalar) + field_loc_Nface, field_type_scalar, fillvalue=c0) call ice_HaloUpdate(uvelE, halo_info, & - field_loc_Eface, field_type_scalar) + field_loc_Eface, field_type_scalar, fillvalue=c0) call ice_HaloUpdate(vvelE, halo_info, & - field_loc_Eface, field_type_scalar) + field_loc_Eface, field_type_scalar, fillvalue=c0) endif diff --git a/cicecore/cicedyn/general/ice_state.F90 b/cicecore/cicedyn/general/ice_state.F90 index 82b03f2cb..92066d038 100644 --- a/cicecore/cicedyn/general/ice_state.F90 +++ b/cicecore/cicedyn/general/ice_state.F90 @@ -172,6 +172,32 @@ subroutine alloc_state stat=ierr) if (ierr/=0) call abort_ice('(alloc_state): Out of memory1') + aice = c0 + aiU = c0 + vice = c0 + vsno = c0 + aice0 = c0 + uvel = c0 + vvel = c0 + uvelE = c0 + vvelE = c0 + uvelN = c0 + vvelN = c0 + divu = c0 + shear = c0 + vort = c0 + strength = c0 + aice_init = c0 + aicen = c0 + vicen = c0 + vsnon = c0 + aicen_init = c0 + vicen_init = c0 + vsnon_init = c0 + Tsfcn_init = c0 + trcr = c0 + trcrn = c0 + allocate ( & trcr_depend(ntrcr) , & ! n_trcr_strata(ntrcr) , & ! number of underlying tracer layers @@ -184,12 +210,6 @@ subroutine alloc_state n_trcr_strata = 0 nt_strata = 0 trcr_base = c0 - aicen = c0 - aicen_init = c0 - vicen = c0 - vicen_init = c0 - vsnon = c0 - vsnon_init = c0 end subroutine alloc_state diff --git a/cicecore/cicedyn/infrastructure/comm/mpi/ice_boundary.F90 b/cicecore/cicedyn/infrastructure/comm/mpi/ice_boundary.F90 index 11cd0d2e1..5a690d490 100644 --- a/cicecore/cicedyn/infrastructure/comm/mpi/ice_boundary.F90 +++ b/cicecore/cicedyn/infrastructure/comm/mpi/ice_boundary.F90 @@ -64,7 +64,7 @@ module ice_boundary use icepack_intfc, only: icepack_warnings_flush, icepack_warnings_aborted use ice_blocks, only: nx_block, ny_block, nghost, & - nblocks_tot, ice_blocksNorth, & + nblocks_tot, nblocks_x, nblocks_y, ice_blocksNorth, & ice_blocksSouth, ice_blocksEast, ice_blocksWest, & ice_blocksEast2, ice_blocksWest2, & ice_blocksNorthEast, ice_blocksNorthWest, & @@ -106,6 +106,10 @@ module ice_boundary sendAddr, &! src addresses for each sent message recvAddr ! dst addresses for each recvd message + character (char_len) :: & + nsBoundaryType, &! type of boundary to use in logical ns dir + ewBoundaryType ! type of boundary to use in logical ew dir + end type public :: ice_HaloCreate, & @@ -252,6 +256,8 @@ function ice_HaloCreate(dist, nsBoundaryType, ewBoundaryType, & if (my_task >= numProcs) return halo%communicator = communicator + halo%ewBoundaryType = ewBoundaryType + halo%nsBoundaryType = nsBoundaryType blockSizeX = nx_block - 2*nghost blockSizeY = ny_block - 2*nghost @@ -1239,6 +1245,7 @@ subroutine ice_HaloUpdate2DR8(array, halo, & integer (int_kind) :: & i,j,n,nmsg, &! dummy loop indices iblk,ilo,ihi,jlo,jhi, &! block sizes for fill + iblock,jblock, &! global block indices ierr, &! error or status flag for MPI,alloc nxGlobal, &! global domain size in x (tripole) iSrc,jSrc, &! source addresses for message @@ -1261,6 +1268,8 @@ subroutine ice_HaloUpdate2DR8(array, halo, & x1,x2,xavg ! scalars for enforcing symmetry at U pts logical (log_kind) :: & + ewfillouter, &! fill outer boundary ew + nsfillouter, &! fill outer boundary ns ltripoleOnly ! local tripoleOnly value integer (int_kind) :: len ! length of messages @@ -1290,8 +1299,20 @@ subroutine ice_HaloUpdate2DR8(array, halo, & ! !----------------------------------------------------------------------- + ewfillouter = .false. + nsfillouter = .false. + + ! fill outer boundary if cyclic + if (halo%ewBoundaryType == 'cyclic') ewfillouter=.true. + if (halo%nsBoundaryType == 'tripole' .or. & + halo%nsBoundaryType == 'tripoleT' .or. & + halo%nsBoundaryType == 'cyclic') nsfillouter=.true. + if (present(fillValue)) then fill = fillValue + ! always fill outer boundary if fillValue is passed + ewfillouter = .true. + nsfillouter = .true. else fill = 0.0_dbl_kind endif @@ -1367,29 +1388,77 @@ subroutine ice_HaloUpdate2DR8(array, halo, & !----------------------------------------------------------------------- ! -! while messages are being communicated, fill out halo region +! While messages are being communicated, fill out halo region ! needed for masked halos to ensure halo values are filled for -! halo grid cells that are not updated +! halo grid cells that are not updated except in cases where +! you don't want to overwrite those halos ! !----------------------------------------------------------------------- - if (ltripoleOnly) then - ! skip fill, not needed since tripole seam always exists if running - ! on tripole grid and set tripoleOnly flag - else + if (.not. ltripoleOnly) then + ! tripoleOnly skip fill, do not overwrite any values in interior as they may + ! already be set and filling tripole is not necessary + + ! fill outer boundary as needed + ! only fill corners if both edges are being filled do iblk = 1, halo%numLocalBlocks - call get_block_parameter(halo%blockGlobalID(iblk), & - ilo=ilo, ihi=ihi, & - jlo=jlo, jhi=jhi) - do j = 1,nghost - array(1:nx_block, jlo-j,iblk) = fill - array(1:nx_block, jhi+j,iblk) = fill - enddo - do i = 1,nghost - array(ilo-i, 1:ny_block,iblk) = fill - array(ihi+i, 1:ny_block,iblk) = fill - enddo - enddo + call get_block_parameter(halo%blockGlobalID(iblk), & + ilo=ilo, ihi=ihi, & + jlo=jlo, jhi=jhi, & + iblock=iblock, jblock=jblock) + if (ewfillouter .or. iblock > 1) then ! west edge + do i = 1,nghost + array(ilo-i, jlo:jhi, iblk) = fill + enddo + endif + if (ewfillouter .or. iblock < nblocks_x) then ! east edge + do i = 1,nghost + array(ihi+i, jlo:jhi, iblk) = fill + enddo + endif + if (nsfillouter .or. jblock > 1) then ! south edge + do j = 1,nghost + array(ilo:ihi, jlo-j, iblk) = fill + enddo + endif + if (nsfillouter .or. jblock < nblocks_y) then ! north edge + do j = 1,nghost + array(ilo:ihi, jhi+j, iblk) = fill + enddo + endif + if ((ewfillouter .or. iblock > 1) .and. & ! southwest corner + (nsfillouter .or. jblock > 1)) then + do j = 1,nghost + do i = 1,nghost + array(ilo-i, jlo-j, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock > 1) .and. & ! northwest corner + (nsfillouter .or. jblock < nblocks_y)) then + do j = 1,nghost + do i = 1,nghost + array(ilo-i, jhi+j, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock < nblocks_x) .and. & ! southeast corner + (nsfillouter .or. jblock > 1)) then + do j = 1,nghost + do i = 1,nghost + array(ihi+i, jlo-j, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock < nblocks_x) .and. & ! northeast corner + (nsfillouter .or. jblock < nblocks_y)) then + do j = 1,nghost + do i = 1,nghost + array(ihi+i, jhi+j, iblk) = fill + enddo + enddo + endif + enddo ! iblk endif !----------------------------------------------------------------------- @@ -1683,6 +1752,7 @@ subroutine ice_HaloUpdate2DR4(array, halo, & integer (int_kind) :: & i,j,n,nmsg, &! dummy loop indices iblk,ilo,ihi,jlo,jhi, &! block sizes for fill + iblock,jblock, &! global block indices ierr, &! error or status flag for MPI,alloc nxGlobal, &! global domain size in x (tripole) iSrc,jSrc, &! source addresses for message @@ -1704,6 +1774,10 @@ subroutine ice_HaloUpdate2DR4(array, halo, & fill, &! value to use for unknown points x1,x2,xavg ! scalars for enforcing symmetry at U pts + logical (log_kind) :: & + ewfillouter, &! fill outer boundary ew + nsfillouter ! fill outer boundary ns + integer (int_kind) :: len ! length of messages character(len=*), parameter :: subname = '(ice_HaloUpdate2DR4)' @@ -1731,8 +1805,20 @@ subroutine ice_HaloUpdate2DR4(array, halo, & ! !----------------------------------------------------------------------- + ewfillouter = .false. + nsfillouter = .false. + + ! fill outer boundary if cyclic + if (halo%ewBoundaryType == 'cyclic') ewfillouter=.true. + if (halo%nsBoundaryType == 'tripole' .or. & + halo%nsBoundaryType == 'tripoleT' .or. & + halo%nsBoundaryType == 'cyclic') nsfillouter=.true. + if (present(fillValue)) then fill = fillValue + ! always fill outer boundary if fillValue is passed + ewfillouter = .true. + nsfillouter = .true. else fill = 0.0_real_kind endif @@ -1804,23 +1890,71 @@ subroutine ice_HaloUpdate2DR4(array, halo, & ! ! while messages are being communicated, fill out halo region ! needed for masked halos to ensure halo values are filled for -! halo grid cells that are not updated +! halo grid cells that are not updated except in cases where +! you don't want to overwrite those halos ! !----------------------------------------------------------------------- + ! fill outer boundary as needed + ! only fill corners if both edges are being filled do iblk = 1, halo%numLocalBlocks - call get_block_parameter(halo%blockGlobalID(iblk), & - ilo=ilo, ihi=ihi, & - jlo=jlo, jhi=jhi) - do j = 1,nghost - array(1:nx_block, jlo-j,iblk) = fill - array(1:nx_block, jhi+j,iblk) = fill - enddo - do i = 1,nghost - array(ilo-i, 1:ny_block,iblk) = fill - array(ihi+i, 1:ny_block,iblk) = fill - enddo - enddo + call get_block_parameter(halo%blockGlobalID(iblk), & + ilo=ilo, ihi=ihi, & + jlo=jlo, jhi=jhi, & + iblock=iblock, jblock=jblock) + if (ewfillouter .or. iblock > 1) then ! west edge + do i = 1,nghost + array(ilo-i, jlo:jhi, iblk) = fill + enddo + endif + if (ewfillouter .or. iblock < nblocks_x) then ! east edge + do i = 1,nghost + array(ihi+i, jlo:jhi, iblk) = fill + enddo + endif + if (nsfillouter .or. jblock > 1) then ! south edge + do j = 1,nghost + array(ilo:ihi, jlo-j, iblk) = fill + enddo + endif + if (nsfillouter .or. jblock < nblocks_y) then ! north edge + do j = 1,nghost + array(ilo:ihi, jhi+j, iblk) = fill + enddo + endif + if ((ewfillouter .or. iblock > 1) .and. & ! southwest corner + (nsfillouter .or. jblock > 1)) then + do j = 1,nghost + do i = 1,nghost + array(ilo-i, jlo-j, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock > 1) .and. & ! northwest corner + (nsfillouter .or. jblock < nblocks_y)) then + do j = 1,nghost + do i = 1,nghost + array(ilo-i, jhi+j, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock < nblocks_x) .and. & ! southeast corner + (nsfillouter .or. jblock > 1)) then + do j = 1,nghost + do i = 1,nghost + array(ihi+i, jlo-j, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock < nblocks_x) .and. & ! northeast corner + (nsfillouter .or. jblock < nblocks_y)) then + do j = 1,nghost + do i = 1,nghost + array(ihi+i, jhi+j, iblk) = fill + enddo + enddo + endif + enddo ! iblk !----------------------------------------------------------------------- ! @@ -2098,6 +2232,7 @@ subroutine ice_HaloUpdate2DI4(array, halo, & integer (int_kind) :: & i,j,n,nmsg, &! dummy loop indices iblk,ilo,ihi,jlo,jhi, &! block sizes for fill + iblock,jblock, &! global block indices ierr, &! error or status flag for MPI,alloc nxGlobal, &! global domain size in x (tripole) iSrc,jSrc, &! source addresses for message @@ -2119,6 +2254,10 @@ subroutine ice_HaloUpdate2DI4(array, halo, & fill, &! value to use for unknown points x1,x2,xavg ! scalars for enforcing symmetry at U pts + logical (log_kind) :: & + ewfillouter, &! fill outer boundary ew + nsfillouter ! fill outer boundary ns + integer (int_kind) :: len ! length of messages character(len=*), parameter :: subname = '(ice_HaloUpdate2DI4)' @@ -2146,8 +2285,20 @@ subroutine ice_HaloUpdate2DI4(array, halo, & ! !----------------------------------------------------------------------- + ewfillouter = .false. + nsfillouter = .false. + + ! fill outer boundary if cyclic + if (halo%ewBoundaryType == 'cyclic') ewfillouter=.true. + if (halo%nsBoundaryType == 'tripole' .or. & + halo%nsBoundaryType == 'tripoleT' .or. & + halo%nsBoundaryType == 'cyclic') nsfillouter=.true. + if (present(fillValue)) then fill = fillValue + ! always fill outer boundary if fillValue is passed + ewfillouter = .true. + nsfillouter = .true. else fill = 0_int_kind endif @@ -2219,23 +2370,71 @@ subroutine ice_HaloUpdate2DI4(array, halo, & ! ! while messages are being communicated, fill out halo region ! needed for masked halos to ensure halo values are filled for -! halo grid cells that are not updated +! halo grid cells that are not updated except in cases where +! you don't want to overwrite those halos ! !----------------------------------------------------------------------- + ! fill outer boundary as needed + ! only fill corners if both edges are being filled do iblk = 1, halo%numLocalBlocks - call get_block_parameter(halo%blockGlobalID(iblk), & - ilo=ilo, ihi=ihi, & - jlo=jlo, jhi=jhi) - do j = 1,nghost - array(1:nx_block, jlo-j,iblk) = fill - array(1:nx_block, jhi+j,iblk) = fill - enddo - do i = 1,nghost - array(ilo-i, 1:ny_block,iblk) = fill - array(ihi+i, 1:ny_block,iblk) = fill - enddo - enddo + call get_block_parameter(halo%blockGlobalID(iblk), & + ilo=ilo, ihi=ihi, & + jlo=jlo, jhi=jhi, & + iblock=iblock, jblock=jblock) + if (ewfillouter .or. iblock > 1) then ! west edge + do i = 1,nghost + array(ilo-i, jlo:jhi, iblk) = fill + enddo + endif + if (ewfillouter .or. iblock < nblocks_x) then ! east edge + do i = 1,nghost + array(ihi+i, jlo:jhi, iblk) = fill + enddo + endif + if (nsfillouter .or. jblock > 1) then ! south edge + do j = 1,nghost + array(ilo:ihi, jlo-j, iblk) = fill + enddo + endif + if (nsfillouter .or. jblock < nblocks_y) then ! north edge + do j = 1,nghost + array(ilo:ihi, jhi+j, iblk) = fill + enddo + endif + if ((ewfillouter .or. iblock > 1) .and. & ! southwest corner + (nsfillouter .or. jblock > 1)) then + do j = 1,nghost + do i = 1,nghost + array(ilo-i, jlo-j, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock > 1) .and. & ! northwest corner + (nsfillouter .or. jblock < nblocks_y)) then + do j = 1,nghost + do i = 1,nghost + array(ilo-i, jhi+j, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock < nblocks_x) .and. & ! southeast corner + (nsfillouter .or. jblock > 1)) then + do j = 1,nghost + do i = 1,nghost + array(ihi+i, jlo-j, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock < nblocks_x) .and. & ! northeast corner + (nsfillouter .or. jblock < nblocks_y)) then + do j = 1,nghost + do i = 1,nghost + array(ihi+i, jhi+j, iblk) = fill + enddo + enddo + endif + enddo ! iblk !----------------------------------------------------------------------- ! @@ -2593,6 +2792,7 @@ subroutine ice_HaloUpdate3DR8(array, halo, & integer (int_kind) :: & i,j,k,n,nmsg, &! dummy loop indices iblk,ilo,ihi,jlo,jhi, &! block sizes for fill + iblock,jblock, &! global block indices ierr, &! error or status flag for MPI,alloc nxGlobal, &! global domain size in x (tripole) nz, &! size of array in 3rd dimension @@ -2615,6 +2815,10 @@ subroutine ice_HaloUpdate3DR8(array, halo, & fill, &! value to use for unknown points x1,x2,xavg ! scalars for enforcing symmetry at U pts + logical (log_kind) :: & + ewfillouter, &! fill outer boundary ew + nsfillouter ! fill outer boundary ns + real (dbl_kind), dimension(:,:), allocatable :: & bufSend, bufRecv ! 3d send,recv buffers @@ -2648,8 +2852,20 @@ subroutine ice_HaloUpdate3DR8(array, halo, & ! !----------------------------------------------------------------------- + ewfillouter = .false. + nsfillouter = .false. + + ! fill outer boundary if cyclic + if (halo%ewBoundaryType == 'cyclic') ewfillouter=.true. + if (halo%nsBoundaryType == 'tripole' .or. & + halo%nsBoundaryType == 'tripoleT' .or. & + halo%nsBoundaryType == 'cyclic') nsfillouter=.true. + if (present(fillValue)) then fill = fillValue + ! always fill outer boundary if fillValue is passed + ewfillouter = .true. + nsfillouter = .true. else fill = 0.0_dbl_kind endif @@ -2742,23 +2958,71 @@ subroutine ice_HaloUpdate3DR8(array, halo, & ! ! while messages are being communicated, fill out halo region ! needed for masked halos to ensure halo values are filled for -! halo grid cells that are not updated +! halo grid cells that are not updated except in cases where +! you don't want to overwrite those halos ! !----------------------------------------------------------------------- + ! fill outer boundary as needed + ! only fill corners if both edges are being filled do iblk = 1, halo%numLocalBlocks - call get_block_parameter(halo%blockGlobalID(iblk), & - ilo=ilo, ihi=ihi, & - jlo=jlo, jhi=jhi) - do j = 1,nghost - array(1:nx_block, jlo-j,:,iblk) = fill - array(1:nx_block, jhi+j,:,iblk) = fill - enddo - do i = 1,nghost - array(ilo-i, 1:ny_block,:,iblk) = fill - array(ihi+i, 1:ny_block,:,iblk) = fill - enddo - enddo + call get_block_parameter(halo%blockGlobalID(iblk), & + ilo=ilo, ihi=ihi, & + jlo=jlo, jhi=jhi, & + iblock=iblock, jblock=jblock) + if (ewfillouter .or. iblock > 1) then ! west edge + do i = 1,nghost + array(ilo-i, jlo:jhi, :, iblk) = fill + enddo + endif + if (ewfillouter .or. iblock < nblocks_x) then ! east edge + do i = 1,nghost + array(ihi+i, jlo:jhi, :, iblk) = fill + enddo + endif + if (nsfillouter .or. jblock > 1) then ! south edge + do j = 1,nghost + array(ilo:ihi, jlo-j, :, iblk) = fill + enddo + endif + if (nsfillouter .or. jblock < nblocks_y) then ! north edge + do j = 1,nghost + array(ilo:ihi, jhi+j, :, iblk) = fill + enddo + endif + if ((ewfillouter .or. iblock > 1) .and. & ! southwest corner + (nsfillouter .or. jblock > 1)) then + do j = 1,nghost + do i = 1,nghost + array(ilo-i, jlo-j, :, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock > 1) .and. & ! northwest corner + (nsfillouter .or. jblock < nblocks_y)) then + do j = 1,nghost + do i = 1,nghost + array(ilo-i, jhi+j, :, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock < nblocks_x) .and. & ! southeast corner + (nsfillouter .or. jblock > 1)) then + do j = 1,nghost + do i = 1,nghost + array(ihi+i, jlo-j, :, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock < nblocks_x) .and. & ! northeast corner + (nsfillouter .or. jblock < nblocks_y)) then + do j = 1,nghost + do i = 1,nghost + array(ihi+i, jhi+j, :, iblk) = fill + enddo + enddo + endif + enddo ! iblk !----------------------------------------------------------------------- ! @@ -3067,6 +3331,7 @@ subroutine ice_HaloUpdate3DR4(array, halo, & integer (int_kind) :: & i,j,k,n,nmsg, &! dummy loop indices iblk,ilo,ihi,jlo,jhi, &! block sizes for fill + iblock,jblock, &! global block indices ierr, &! error or status flag for MPI,alloc nxGlobal, &! global domain size in x (tripole) nz, &! size of array in 3rd dimension @@ -3089,6 +3354,10 @@ subroutine ice_HaloUpdate3DR4(array, halo, & fill, &! value to use for unknown points x1,x2,xavg ! scalars for enforcing symmetry at U pts + logical (log_kind) :: & + ewfillouter, &! fill outer boundary ew + nsfillouter ! fill outer boundary ns + real (real_kind), dimension(:,:), allocatable :: & bufSend, bufRecv ! 3d send,recv buffers @@ -3122,8 +3391,20 @@ subroutine ice_HaloUpdate3DR4(array, halo, & ! !----------------------------------------------------------------------- + ewfillouter = .false. + nsfillouter = .false. + + ! fill outer boundary if cyclic + if (halo%ewBoundaryType == 'cyclic') ewfillouter=.true. + if (halo%nsBoundaryType == 'tripole' .or. & + halo%nsBoundaryType == 'tripoleT' .or. & + halo%nsBoundaryType == 'cyclic') nsfillouter=.true. + if (present(fillValue)) then fill = fillValue + ! always fill outer boundary if fillValue is passed + ewfillouter = .true. + nsfillouter = .true. else fill = 0.0_real_kind endif @@ -3216,23 +3497,71 @@ subroutine ice_HaloUpdate3DR4(array, halo, & ! ! while messages are being communicated, fill out halo region ! needed for masked halos to ensure halo values are filled for -! halo grid cells that are not updated +! halo grid cells that are not updated except in cases where +! you don't want to overwrite those halos ! !----------------------------------------------------------------------- + ! fill outer boundary as needed + ! only fill corners if both edges are being filled do iblk = 1, halo%numLocalBlocks - call get_block_parameter(halo%blockGlobalID(iblk), & - ilo=ilo, ihi=ihi, & - jlo=jlo, jhi=jhi) - do j = 1,nghost - array(1:nx_block, jlo-j,:,iblk) = fill - array(1:nx_block, jhi+j,:,iblk) = fill - enddo - do i = 1,nghost - array(ilo-i, 1:ny_block,:,iblk) = fill - array(ihi+i, 1:ny_block,:,iblk) = fill - enddo - enddo + call get_block_parameter(halo%blockGlobalID(iblk), & + ilo=ilo, ihi=ihi, & + jlo=jlo, jhi=jhi, & + iblock=iblock, jblock=jblock) + if (ewfillouter .or. iblock > 1) then ! west edge + do i = 1,nghost + array(ilo-i, jlo:jhi, :, iblk) = fill + enddo + endif + if (ewfillouter .or. iblock < nblocks_x) then ! east edge + do i = 1,nghost + array(ihi+i, jlo:jhi, :, iblk) = fill + enddo + endif + if (nsfillouter .or. jblock > 1) then ! south edge + do j = 1,nghost + array(ilo:ihi, jlo-j, :, iblk) = fill + enddo + endif + if (nsfillouter .or. jblock < nblocks_y) then ! north edge + do j = 1,nghost + array(ilo:ihi, jhi+j, :, iblk) = fill + enddo + endif + if ((ewfillouter .or. iblock > 1) .and. & ! southwest corner + (nsfillouter .or. jblock > 1)) then + do j = 1,nghost + do i = 1,nghost + array(ilo-i, jlo-j, :, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock > 1) .and. & ! northwest corner + (nsfillouter .or. jblock < nblocks_y)) then + do j = 1,nghost + do i = 1,nghost + array(ilo-i, jhi+j, :, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock < nblocks_x) .and. & ! southeast corner + (nsfillouter .or. jblock > 1)) then + do j = 1,nghost + do i = 1,nghost + array(ihi+i, jlo-j, :, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock < nblocks_x) .and. & ! northeast corner + (nsfillouter .or. jblock < nblocks_y)) then + do j = 1,nghost + do i = 1,nghost + array(ihi+i, jhi+j, :, iblk) = fill + enddo + enddo + endif + enddo ! iblk !----------------------------------------------------------------------- ! @@ -3541,6 +3870,7 @@ subroutine ice_HaloUpdate3DI4(array, halo, & integer (int_kind) :: & i,j,k,n,nmsg, &! dummy loop indices iblk,ilo,ihi,jlo,jhi, &! block sizes for fill + iblock,jblock, &! global block indices ierr, &! error or status flag for MPI,alloc nxGlobal, &! global domain size in x (tripole) nz, &! size of array in 3rd dimension @@ -3563,6 +3893,10 @@ subroutine ice_HaloUpdate3DI4(array, halo, & fill, &! value to use for unknown points x1,x2,xavg ! scalars for enforcing symmetry at U pts + logical (log_kind) :: & + ewfillouter, &! fill outer boundary ew + nsfillouter ! fill outer boundary ns + integer (int_kind), dimension(:,:), allocatable :: & bufSend, bufRecv ! 3d send,recv buffers @@ -3596,8 +3930,20 @@ subroutine ice_HaloUpdate3DI4(array, halo, & ! !----------------------------------------------------------------------- + ewfillouter = .false. + nsfillouter = .false. + + ! fill outer boundary if cyclic + if (halo%ewBoundaryType == 'cyclic') ewfillouter=.true. + if (halo%nsBoundaryType == 'tripole' .or. & + halo%nsBoundaryType == 'tripoleT' .or. & + halo%nsBoundaryType == 'cyclic') nsfillouter=.true. + if (present(fillValue)) then fill = fillValue + ! always fill outer boundary if fillValue is passed + ewfillouter = .true. + nsfillouter = .true. else fill = 0_int_kind endif @@ -3690,23 +4036,71 @@ subroutine ice_HaloUpdate3DI4(array, halo, & ! ! while messages are being communicated, fill out halo region ! needed for masked halos to ensure halo values are filled for -! halo grid cells that are not updated +! halo grid cells that are not updated except in cases where +! you don't want to overwrite those halos ! !----------------------------------------------------------------------- + ! fill outer boundary as needed + ! only fill corners if both edges are being filled do iblk = 1, halo%numLocalBlocks - call get_block_parameter(halo%blockGlobalID(iblk), & - ilo=ilo, ihi=ihi, & - jlo=jlo, jhi=jhi) - do j = 1,nghost - array(1:nx_block, jlo-j,:,iblk) = fill - array(1:nx_block, jhi+j,:,iblk) = fill - enddo - do i = 1,nghost - array(ilo-i, 1:ny_block,:,iblk) = fill - array(ihi+i, 1:ny_block,:,iblk) = fill - enddo - enddo + call get_block_parameter(halo%blockGlobalID(iblk), & + ilo=ilo, ihi=ihi, & + jlo=jlo, jhi=jhi, & + iblock=iblock, jblock=jblock) + if (ewfillouter .or. iblock > 1) then ! west edge + do i = 1,nghost + array(ilo-i, jlo:jhi, :, iblk) = fill + enddo + endif + if (ewfillouter .or. iblock < nblocks_x) then ! east edge + do i = 1,nghost + array(ihi+i, jlo:jhi, :, iblk) = fill + enddo + endif + if (nsfillouter .or. jblock > 1) then ! south edge + do j = 1,nghost + array(ilo:ihi, jlo-j, :, iblk) = fill + enddo + endif + if (nsfillouter .or. jblock < nblocks_y) then ! north edge + do j = 1,nghost + array(ilo:ihi, jhi+j, :, iblk) = fill + enddo + endif + if ((ewfillouter .or. iblock > 1) .and. & ! southwest corner + (nsfillouter .or. jblock > 1)) then + do j = 1,nghost + do i = 1,nghost + array(ilo-i, jlo-j, :, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock > 1) .and. & ! northwest corner + (nsfillouter .or. jblock < nblocks_y)) then + do j = 1,nghost + do i = 1,nghost + array(ilo-i, jhi+j, :, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock < nblocks_x) .and. & ! southeast corner + (nsfillouter .or. jblock > 1)) then + do j = 1,nghost + do i = 1,nghost + array(ihi+i, jlo-j, :, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock < nblocks_x) .and. & ! northeast corner + (nsfillouter .or. jblock < nblocks_y)) then + do j = 1,nghost + do i = 1,nghost + array(ihi+i, jhi+j, :, iblk) = fill + enddo + enddo + endif + enddo ! iblk !----------------------------------------------------------------------- ! @@ -4015,6 +4409,7 @@ subroutine ice_HaloUpdate4DR8(array, halo, & integer (int_kind) :: & i,j,k,l,n,nmsg, &! dummy loop indices iblk,ilo,ihi,jlo,jhi, &! block sizes for fill + iblock,jblock, &! global block indices ierr, &! error or status flag for MPI,alloc nxGlobal, &! global domain size in x (tripole) nz, nt, &! size of array in 3rd,4th dimensions @@ -4037,6 +4432,10 @@ subroutine ice_HaloUpdate4DR8(array, halo, & fill, &! value to use for unknown points x1,x2,xavg ! scalars for enforcing symmetry at U pts + logical (log_kind) :: & + ewfillouter, &! fill outer boundary ew + nsfillouter ! fill outer boundary ns + real (dbl_kind), dimension(:,:), allocatable :: & bufSend, bufRecv ! 4d send,recv buffers @@ -4070,8 +4469,20 @@ subroutine ice_HaloUpdate4DR8(array, halo, & ! !----------------------------------------------------------------------- + ewfillouter = .false. + nsfillouter = .false. + + ! fill outer boundary if cyclic + if (halo%ewBoundaryType == 'cyclic') ewfillouter=.true. + if (halo%nsBoundaryType == 'tripole' .or. & + halo%nsBoundaryType == 'tripoleT' .or. & + halo%nsBoundaryType == 'cyclic') nsfillouter=.true. + if (present(fillValue)) then fill = fillValue + ! always fill outer boundary if fillValue is passed + ewfillouter = .true. + nsfillouter = .true. else fill = 0.0_dbl_kind endif @@ -4168,23 +4579,71 @@ subroutine ice_HaloUpdate4DR8(array, halo, & ! ! while messages are being communicated, fill out halo region ! needed for masked halos to ensure halo values are filled for -! halo grid cells that are not updated +! halo grid cells that are not updated except in cases where +! you don't want to overwrite those halos ! !----------------------------------------------------------------------- + ! fill outer boundary as needed + ! only fill corners if both edges are being filled do iblk = 1, halo%numLocalBlocks - call get_block_parameter(halo%blockGlobalID(iblk), & - ilo=ilo, ihi=ihi, & - jlo=jlo, jhi=jhi) - do j = 1,nghost - array(1:nx_block, jlo-j,:,:,iblk) = fill - array(1:nx_block, jhi+j,:,:,iblk) = fill - enddo - do i = 1,nghost - array(ilo-i, 1:ny_block,:,:,iblk) = fill - array(ihi+i, 1:ny_block,:,:,iblk) = fill - enddo - enddo + call get_block_parameter(halo%blockGlobalID(iblk), & + ilo=ilo, ihi=ihi, & + jlo=jlo, jhi=jhi, & + iblock=iblock, jblock=jblock) + if (ewfillouter .or. iblock > 1) then ! west edge + do i = 1,nghost + array(ilo-i, jlo:jhi, :, :, iblk) = fill + enddo + endif + if (ewfillouter .or. iblock < nblocks_x) then ! east edge + do i = 1,nghost + array(ihi+i, jlo:jhi, :, :, iblk) = fill + enddo + endif + if (nsfillouter .or. jblock > 1) then ! south edge + do j = 1,nghost + array(ilo:ihi, jlo-j, :, :, iblk) = fill + enddo + endif + if (nsfillouter .or. jblock < nblocks_y) then ! north edge + do j = 1,nghost + array(ilo:ihi, jhi+j, :, :, iblk) = fill + enddo + endif + if ((ewfillouter .or. iblock > 1) .and. & ! southwest corner + (nsfillouter .or. jblock > 1)) then + do j = 1,nghost + do i = 1,nghost + array(ilo-i, jlo-j, :, :, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock > 1) .and. & ! northwest corner + (nsfillouter .or. jblock < nblocks_y)) then + do j = 1,nghost + do i = 1,nghost + array(ilo-i, jhi+j, :, :, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock < nblocks_x) .and. & ! southeast corner + (nsfillouter .or. jblock > 1)) then + do j = 1,nghost + do i = 1,nghost + array(ihi+i, jlo-j, :, :, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock < nblocks_x) .and. & ! northeast corner + (nsfillouter .or. jblock < nblocks_y)) then + do j = 1,nghost + do i = 1,nghost + array(ihi+i, jhi+j, :, :, iblk) = fill + enddo + enddo + endif + enddo ! iblk !----------------------------------------------------------------------- ! @@ -4513,6 +4972,7 @@ subroutine ice_HaloUpdate4DR4(array, halo, & integer (int_kind) :: & i,j,k,l,n,nmsg, &! dummy loop indices iblk,ilo,ihi,jlo,jhi, &! block sizes for fill + iblock,jblock, &! global block indices ierr, &! error or status flag for MPI,alloc nxGlobal, &! global domain size in x (tripole) nz, nt, &! size of array in 3rd,4th dimensions @@ -4535,6 +4995,10 @@ subroutine ice_HaloUpdate4DR4(array, halo, & fill, &! value to use for unknown points x1,x2,xavg ! scalars for enforcing symmetry at U pts + logical (log_kind) :: & + ewfillouter, &! fill outer boundary ew + nsfillouter ! fill outer boundary ns + real (real_kind), dimension(:,:), allocatable :: & bufSend, bufRecv ! 4d send,recv buffers @@ -4568,8 +5032,20 @@ subroutine ice_HaloUpdate4DR4(array, halo, & ! !----------------------------------------------------------------------- + ewfillouter = .false. + nsfillouter = .false. + + ! fill outer boundary if cyclic + if (halo%ewBoundaryType == 'cyclic') ewfillouter=.true. + if (halo%nsBoundaryType == 'tripole' .or. & + halo%nsBoundaryType == 'tripoleT' .or. & + halo%nsBoundaryType == 'cyclic') nsfillouter=.true. + if (present(fillValue)) then fill = fillValue + ! always fill outer boundary if fillValue is passed + ewfillouter = .true. + nsfillouter = .true. else fill = 0.0_real_kind endif @@ -4666,23 +5142,71 @@ subroutine ice_HaloUpdate4DR4(array, halo, & ! ! while messages are being communicated, fill out halo region ! needed for masked halos to ensure halo values are filled for -! halo grid cells that are not updated +! halo grid cells that are not updated except in cases where +! you don't want to overwrite those halos ! !----------------------------------------------------------------------- + ! fill outer boundary as needed + ! only fill corners if both edges are being filled do iblk = 1, halo%numLocalBlocks - call get_block_parameter(halo%blockGlobalID(iblk), & - ilo=ilo, ihi=ihi, & - jlo=jlo, jhi=jhi) - do j = 1,nghost - array(1:nx_block, jlo-j,:,:,iblk) = fill - array(1:nx_block, jhi+j,:,:,iblk) = fill - enddo - do i = 1,nghost - array(ilo-i, 1:ny_block,:,:,iblk) = fill - array(ihi+i, 1:ny_block,:,:,iblk) = fill - enddo - enddo + call get_block_parameter(halo%blockGlobalID(iblk), & + ilo=ilo, ihi=ihi, & + jlo=jlo, jhi=jhi, & + iblock=iblock, jblock=jblock) + if (ewfillouter .or. iblock > 1) then ! west edge + do i = 1,nghost + array(ilo-i, jlo:jhi, :, :, iblk) = fill + enddo + endif + if (ewfillouter .or. iblock < nblocks_x) then ! east edge + do i = 1,nghost + array(ihi+i, jlo:jhi, :, :, iblk) = fill + enddo + endif + if (nsfillouter .or. jblock > 1) then ! south edge + do j = 1,nghost + array(ilo:ihi, jlo-j, :, :, iblk) = fill + enddo + endif + if (nsfillouter .or. jblock < nblocks_y) then ! north edge + do j = 1,nghost + array(ilo:ihi, jhi+j, :, :, iblk) = fill + enddo + endif + if ((ewfillouter .or. iblock > 1) .and. & ! southwest corner + (nsfillouter .or. jblock > 1)) then + do j = 1,nghost + do i = 1,nghost + array(ilo-i, jlo-j, :, :, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock > 1) .and. & ! northwest corner + (nsfillouter .or. jblock < nblocks_y)) then + do j = 1,nghost + do i = 1,nghost + array(ilo-i, jhi+j, :, :, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock < nblocks_x) .and. & ! southeast corner + (nsfillouter .or. jblock > 1)) then + do j = 1,nghost + do i = 1,nghost + array(ihi+i, jlo-j, :, :, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock < nblocks_x) .and. & ! northeast corner + (nsfillouter .or. jblock < nblocks_y)) then + do j = 1,nghost + do i = 1,nghost + array(ihi+i, jhi+j, :, :, iblk) = fill + enddo + enddo + endif + enddo ! iblk !----------------------------------------------------------------------- ! @@ -5011,6 +5535,7 @@ subroutine ice_HaloUpdate4DI4(array, halo, & integer (int_kind) :: & i,j,k,l,n,nmsg, &! dummy loop indices iblk,ilo,ihi,jlo,jhi, &! block sizes for fill + iblock,jblock, &! global block indices ierr, &! error or status flag for MPI,alloc nxGlobal, &! global domain size in x (tripole) nz, nt, &! size of array in 3rd,4th dimensions @@ -5033,6 +5558,10 @@ subroutine ice_HaloUpdate4DI4(array, halo, & fill, &! value to use for unknown points x1,x2,xavg ! scalars for enforcing symmetry at U pts + logical (log_kind) :: & + ewfillouter, &! fill outer boundary ew + nsfillouter ! fill outer boundary ns + integer (int_kind), dimension(:,:), allocatable :: & bufSend, bufRecv ! 4d send,recv buffers @@ -5066,8 +5595,20 @@ subroutine ice_HaloUpdate4DI4(array, halo, & ! !----------------------------------------------------------------------- + ewfillouter = .false. + nsfillouter = .false. + + ! fill outer boundary if cyclic + if (halo%ewBoundaryType == 'cyclic') ewfillouter=.true. + if (halo%nsBoundaryType == 'tripole' .or. & + halo%nsBoundaryType == 'tripoleT' .or. & + halo%nsBoundaryType == 'cyclic') nsfillouter=.true. + if (present(fillValue)) then fill = fillValue + ! always fill outer boundary if fillValue is passed + ewfillouter = .true. + nsfillouter = .true. else fill = 0_int_kind endif @@ -5164,23 +5705,71 @@ subroutine ice_HaloUpdate4DI4(array, halo, & ! ! while messages are being communicated, fill out halo region ! needed for masked halos to ensure halo values are filled for -! halo grid cells that are not updated +! halo grid cells that are not updated except in cases where +! you don't want to overwrite those halos ! !----------------------------------------------------------------------- + ! fill outer boundary as needed + ! only fill corners if both edges are being filled do iblk = 1, halo%numLocalBlocks - call get_block_parameter(halo%blockGlobalID(iblk), & - ilo=ilo, ihi=ihi, & - jlo=jlo, jhi=jhi) - do j = 1,nghost - array(1:nx_block, jlo-j,:,:,iblk) = fill - array(1:nx_block, jhi+j,:,:,iblk) = fill - enddo - do i = 1,nghost - array(ilo-i, 1:ny_block,:,:,iblk) = fill - array(ihi+i, 1:ny_block,:,:,iblk) = fill - enddo - enddo + call get_block_parameter(halo%blockGlobalID(iblk), & + ilo=ilo, ihi=ihi, & + jlo=jlo, jhi=jhi, & + iblock=iblock, jblock=jblock) + if (ewfillouter .or. iblock > 1) then ! west edge + do i = 1,nghost + array(ilo-i, jlo:jhi, :, :, iblk) = fill + enddo + endif + if (ewfillouter .or. iblock < nblocks_x) then ! east edge + do i = 1,nghost + array(ihi+i, jlo:jhi, :, :, iblk) = fill + enddo + endif + if (nsfillouter .or. jblock > 1) then ! south edge + do j = 1,nghost + array(ilo:ihi, jlo-j, :, :, iblk) = fill + enddo + endif + if (nsfillouter .or. jblock < nblocks_y) then ! north edge + do j = 1,nghost + array(ilo:ihi, jhi+j, :, :, iblk) = fill + enddo + endif + if ((ewfillouter .or. iblock > 1) .and. & ! southwest corner + (nsfillouter .or. jblock > 1)) then + do j = 1,nghost + do i = 1,nghost + array(ilo-i, jlo-j, :, :, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock > 1) .and. & ! northwest corner + (nsfillouter .or. jblock < nblocks_y)) then + do j = 1,nghost + do i = 1,nghost + array(ilo-i, jhi+j, :, :, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock < nblocks_x) .and. & ! southeast corner + (nsfillouter .or. jblock > 1)) then + do j = 1,nghost + do i = 1,nghost + array(ihi+i, jlo-j, :, :, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock < nblocks_x) .and. & ! northeast corner + (nsfillouter .or. jblock < nblocks_y)) then + do j = 1,nghost + do i = 1,nghost + array(ihi+i, jhi+j, :, :, iblk) = fill + enddo + enddo + endif + enddo ! iblk !----------------------------------------------------------------------- ! @@ -7027,15 +7616,15 @@ end subroutine ice_HaloMsgCreate subroutine ice_HaloExtrapolate2DR8(ARRAY,dist,ew_bndy_type,ns_bndy_type) -! This subroutine extrapolates ARRAY values into the first row or column -! of ghost cells, and is intended for grid variables whose ghost cells +! This subroutine extrapolates ARRAY values into the ghost cells, +! and is intended for grid variables whose ghost cells ! would otherwise be set using the default boundary conditions (Dirichlet ! or Neumann). -! Note: This routine will need to be modified for nghost > 1. -! We assume padding occurs only on east and north edges. ! ! This is the specific interface for double precision arrays ! corresponding to the generic interface ice_HaloExtrapolate +! +! T.Craig, Oct 2025 - extend to nghost > 1 use ice_blocks, only: block, nblocks_x, nblocks_y, get_block use ice_constants, only: c2 @@ -7058,8 +7647,9 @@ subroutine ice_HaloExtrapolate2DR8(ARRAY,dist,ew_bndy_type,ns_bndy_type) !----------------------------------------------------------------------- integer (int_kind) :: & - i,j,iblk, &! dummy loop indices - numBlocks, &! number of local blocks + i,j,n,iblk,ii,jj, &! dummy loop indices + ilo,ihi,jlo,jhi, &! active block indices + numBlocks, &! number of local blocks blockID, &! block location ibc ! ghost cell column or row @@ -7067,6 +7657,7 @@ subroutine ice_HaloExtrapolate2DR8(ARRAY,dist,ew_bndy_type,ns_bndy_type) this_block ! block info for current block character(len=*), parameter :: subname = '(ice_HaloExtrapolate2DR8)' + !----------------------------------------------------------------------- ! ! Linear extrapolation @@ -7079,32 +7670,40 @@ subroutine ice_HaloExtrapolate2DR8(ARRAY,dist,ew_bndy_type,ns_bndy_type) do iblk = 1, numBlocks call ice_distributionGetBlockID(dist, iblk, blockID) this_block = get_block(blockID, blockID) + ilo = this_block%ilo + ihi = this_block%ihi + jlo = this_block%jlo + jhi = this_block%jhi if (this_block%iblock == 1) then ! west edge if (trim(ew_bndy_type) /= 'cyclic') then + do n = 1, nghost + ii = ilo - n ! gridcell to extrapolate to do j = 1, ny_block - ARRAY(1,j,iblk) = c2*ARRAY(2,j,iblk) - ARRAY(3,j,iblk) + ARRAY(ii,j,iblk) = c2*ARRAY(ii+1,j,iblk) - ARRAY(ii+2,j,iblk) + enddo enddo endif endif if (this_block%iblock == nblocks_x) then ! east edge if (trim(ew_bndy_type) /= 'cyclic') then - ! locate ghost cell column (avoid padding) - ibc = nx_block - do i = nx_block, nghost + 1, -1 - if (this_block%i_glob(i) == 0) ibc = ibc - 1 - enddo + do n = 1, nghost + ii = ihi + n ! gridcell to extrapolate to do j = 1, ny_block - ARRAY(ibc,j,iblk) = c2*ARRAY(ibc-1,j,iblk) - ARRAY(ibc-2,j,iblk) + ARRAY(ii,j,iblk) = c2*ARRAY(ii-1,j,iblk) - ARRAY(ii-2,j,iblk) + enddo enddo endif endif if (this_block%jblock == 1) then ! south edge if (trim(ns_bndy_type) /= 'cyclic') then + do n = 1, nghost + jj = jlo - n ! gridcell to extrapolate to do i = 1, nx_block - ARRAY(i,1,iblk) = c2*ARRAY(i,2,iblk) - ARRAY(i,3,iblk) + ARRAY(i,jj,iblk) = c2*ARRAY(i,jj+1,iblk) - ARRAY(i,jj+2,iblk) + enddo enddo endif endif @@ -7113,13 +7712,11 @@ subroutine ice_HaloExtrapolate2DR8(ARRAY,dist,ew_bndy_type,ns_bndy_type) if (trim(ns_bndy_type) /= 'cyclic' .and. & trim(ns_bndy_type) /= 'tripole' .and. & trim(ns_bndy_type) /= 'tripoleT' ) then - ! locate ghost cell column (avoid padding) - ibc = ny_block - do j = ny_block, nghost + 1, -1 - if (this_block%j_glob(j) == 0) ibc = ibc - 1 - enddo + do n = 1, nghost + jj = jhi + n ! gridcell to extrapolate to do i = 1, nx_block - ARRAY(i,ibc,iblk) = c2*ARRAY(i,ibc-1,iblk) - ARRAY(i,ibc-2,iblk) + ARRAY(i,jj,iblk) = c2*ARRAY(i,jj-1,iblk) - ARRAY(i,jj-2,iblk) + enddo enddo endif endif diff --git a/cicecore/cicedyn/infrastructure/comm/mpi/ice_gather_scatter.F90 b/cicecore/cicedyn/infrastructure/comm/mpi/ice_gather_scatter.F90 index cfb98befe..1c0191aee 100644 --- a/cicecore/cicedyn/infrastructure/comm/mpi/ice_gather_scatter.F90 +++ b/cicecore/cicedyn/infrastructure/comm/mpi/ice_gather_scatter.F90 @@ -1643,74 +1643,35 @@ subroutine scatter_global_dbl(ARRAY, ARRAY_G, src_task, dst_dist, & msg_buffer = c0 this_block = get_block(n,n) - !*** if this is an interior block, then there is no - !*** padding or update checking required - - if (this_block%iblock > 1 .and. & - this_block%iblock < nblocks_x .and. & - this_block%jblock > 1 .and. & - this_block%jblock < nblocks_y) then - - do j=1,ny_block - do i=1,nx_block - msg_buffer(i,j) = ARRAY_G(this_block%i_glob(i),& - this_block%j_glob(j)) - end do - end do - - !*** if this is an edge block but not a northern edge - !*** we only need to check for closed boundaries and - !*** padding (global index = 0) - - else if (this_block%jblock /= nblocks_y) then - - do j=1,ny_block - if (this_block%j_glob(j) /= 0) then - do i=1,nx_block - if (this_block%i_glob(i) /= 0) then - msg_buffer(i,j) = ARRAY_G(this_block%i_glob(i),& - this_block%j_glob(j)) - endif - end do - endif - end do - - !*** if this is a northern edge block, we need to check - !*** for and properly deal with tripole boundaries - - else - - do j=1,ny_block - if (this_block%j_glob(j) > 0) then ! normal boundary - - do i=1,nx_block - if (this_block%i_glob(i) /= 0) then - msg_buffer(i,j) = ARRAY_G(this_block%i_glob(i),& - this_block%j_glob(j)) - endif - end do - - else if (this_block%j_glob(j) < 0) then ! tripole - - ! for yoffset=0 or 1, yoffset2=0,0 - ! for yoffset=-1, yoffset2=0,1, for u-rows on T-fold grid - do yoffset2=0,max(yoffset,0)-yoffset - jsrc = ny_global + yoffset + yoffset2 + & - (this_block%j_glob(j) + ny_global) - do i=1,nx_block - if (this_block%i_glob(i) /= 0) then - isrc = nx_global + xoffset - this_block%i_glob(i) - if (isrc < 1) isrc = isrc + nx_global - if (isrc > nx_global) isrc = isrc - nx_global - msg_buffer(i,j-yoffset2) = isign * ARRAY_G(isrc,jsrc) - endif - end do - end do - - endif - end do - - endif + do j=1,ny_block + if (this_block%jblock == nblocks_y .and. this_block%j_glob(j) < 0) then + ! tripole is top block with j_glob < 0 + ! for yoffset=0 or 1, yoffset2=0,0 + ! for yoffset=-1, yoffset2=0,1, for u-rows on T-fold grid + do yoffset2=0,max(yoffset,0)-yoffset + jsrc = ny_global + yoffset + yoffset2 + & + (this_block%j_glob(j) + ny_global) + do i=1,nx_block + if (this_block%i_glob(i) /= 0) then + isrc = nx_global + xoffset - this_block%i_glob(i) + if (isrc < 1) isrc = isrc + nx_global + if (isrc > nx_global) isrc = isrc - nx_global + msg_buffer(i,j-yoffset2) & + = isign * ARRAY_G(isrc,jsrc) + endif + end do + end do + else + ! normal block + do i=1,nx_block + isrc = this_block%i_glob(i) + jsrc = this_block%j_glob(j) + if (isrc >=1 .and. isrc <= nx_global .and. & + jsrc >=1 .and. jsrc <= ny_global) & + msg_buffer(i,j) = ARRAY_G(isrc,jsrc) + end do + endif + end do call MPI_SEND(msg_buffer, nx_block*ny_block, & mpiR8, dst_dist%blockLocation(n)-1, 3*mpitag_gs+n, & @@ -1728,75 +1689,35 @@ subroutine scatter_global_dbl(ARRAY, ARRAY_G, src_task, dst_dist, & dst_block = dst_dist%blockLocalID(n) this_block = get_block(n,n) - !*** if this is an interior block, then there is no - !*** padding or update checking required - - if (this_block%iblock > 1 .and. & - this_block%iblock < nblocks_x .and. & - this_block%jblock > 1 .and. & - this_block%jblock < nblocks_y) then - - do j=1,ny_block - do i=1,nx_block - ARRAY(i,j,dst_block) = ARRAY_G(this_block%i_glob(i),& - this_block%j_glob(j)) - end do - end do - - !*** if this is an edge block but not a northern edge - !*** we only need to check for closed boundaries and - !*** padding (global index = 0) - - else if (this_block%jblock /= nblocks_y) then - - do j=1,ny_block - if (this_block%j_glob(j) /= 0) then - do i=1,nx_block - if (this_block%i_glob(i) /= 0) then - ARRAY(i,j,dst_block) = ARRAY_G(this_block%i_glob(i),& - this_block%j_glob(j)) - endif - end do - endif - end do - - !*** if this is a northern edge block, we need to check - !*** for and properly deal with tripole boundaries - - else - - do j=1,ny_block - if (this_block%j_glob(j) > 0) then ! normal boundary - - do i=1,nx_block - if (this_block%i_glob(i) /= 0) then - ARRAY(i,j,dst_block) = ARRAY_G(this_block%i_glob(i),& - this_block%j_glob(j)) - endif - end do - - else if (this_block%j_glob(j) < 0) then ! tripole - - ! for yoffset=0 or 1, yoffset2=0,0 - ! for yoffset=-1, yoffset2=0,1, for u-rows on T-fold grid - do yoffset2=0,max(yoffset,0)-yoffset - jsrc = ny_global + yoffset + yoffset2 + & - (this_block%j_glob(j) + ny_global) - do i=1,nx_block - if (this_block%i_glob(i) /= 0) then - isrc = nx_global + xoffset - this_block%i_glob(i) - if (isrc < 1) isrc = isrc + nx_global - if (isrc > nx_global) isrc = isrc - nx_global - ARRAY(i,j-yoffset2,dst_block) & - = isign * ARRAY_G(isrc,jsrc) - endif - end do - end do - - endif - end do - - endif + do j=1,ny_block + if (this_block%jblock == nblocks_y .and. this_block%j_glob(j) < 0) then + ! tripole is top block with j_glob < 0 + ! for yoffset=0 or 1, yoffset2=0,0 + ! for yoffset=-1, yoffset2=0,1, for u-rows on T-fold grid + do yoffset2=0,max(yoffset,0)-yoffset + jsrc = ny_global + yoffset + yoffset2 + & + (this_block%j_glob(j) + ny_global) + do i=1,nx_block + if (this_block%i_glob(i) /= 0) then + isrc = nx_global + xoffset - this_block%i_glob(i) + if (isrc < 1) isrc = isrc + nx_global + if (isrc > nx_global) isrc = isrc - nx_global + ARRAY(i,j-yoffset2,dst_block) & + = isign * ARRAY_G(isrc,jsrc) + endif + end do + end do + else + ! normal block + do i=1,nx_block + isrc = this_block%i_glob(i) + jsrc = this_block%j_glob(j) + if (isrc >=1 .and. isrc <= nx_global .and. & + jsrc >=1 .and. jsrc <= ny_global) & + ARRAY(i,j,dst_block) = ARRAY_G(isrc,jsrc) + end do + endif + end do endif end do @@ -1832,7 +1753,7 @@ subroutine scatter_global_dbl(ARRAY, ARRAY_G, src_task, dst_dist, & endif !----------------------------------------------------------------- - ! Ensure unused ghost cell values are 0 + ! Set ghost cell values to 0 for noupdate !----------------------------------------------------------------- if (field_loc == field_loc_noupdate) then @@ -2029,74 +1950,35 @@ subroutine scatter_global_real(ARRAY, ARRAY_G, src_task, dst_dist, & msg_buffer = 0._real_kind this_block = get_block(n,n) - !*** if this is an interior block, then there is no - !*** padding or update checking required - - if (this_block%iblock > 1 .and. & - this_block%iblock < nblocks_x .and. & - this_block%jblock > 1 .and. & - this_block%jblock < nblocks_y) then - - do j=1,ny_block - do i=1,nx_block - msg_buffer(i,j) = ARRAY_G(this_block%i_glob(i),& - this_block%j_glob(j)) - end do - end do - - !*** if this is an edge block but not a northern edge - !*** we only need to check for closed boundaries and - !*** padding (global index = 0) - - else if (this_block%jblock /= nblocks_y) then - - do j=1,ny_block - if (this_block%j_glob(j) /= 0) then - do i=1,nx_block - if (this_block%i_glob(i) /= 0) then - msg_buffer(i,j) = ARRAY_G(this_block%i_glob(i),& - this_block%j_glob(j)) - endif - end do - endif - end do - - !*** if this is a northern edge block, we need to check - !*** for and properly deal with tripole boundaries - - else - - do j=1,ny_block - if (this_block%j_glob(j) > 0) then ! normal boundary - - do i=1,nx_block - if (this_block%i_glob(i) /= 0) then - msg_buffer(i,j) = ARRAY_G(this_block%i_glob(i),& - this_block%j_glob(j)) - endif - end do - - else if (this_block%j_glob(j) < 0) then ! tripole - - ! for yoffset=0 or 1, yoffset2=0,0 - ! for yoffset=-1, yoffset2=0,1, for u-rows on T-fold grid - do yoffset2=0,max(yoffset,0)-yoffset - jsrc = ny_global + yoffset + yoffset2 + & - (this_block%j_glob(j) + ny_global) - do i=1,nx_block - if (this_block%i_glob(i) /= 0) then - isrc = nx_global + xoffset - this_block%i_glob(i) - if (isrc < 1) isrc = isrc + nx_global - if (isrc > nx_global) isrc = isrc - nx_global - msg_buffer(i,j-yoffset2) = isign * ARRAY_G(isrc,jsrc) - endif - end do - end do - - endif - end do - - endif + do j=1,ny_block + if (this_block%jblock == nblocks_y .and. this_block%j_glob(j) < 0) then + ! tripole is top block with j_glob < 0 + ! for yoffset=0 or 1, yoffset2=0,0 + ! for yoffset=-1, yoffset2=0,1, for u-rows on T-fold grid + do yoffset2=0,max(yoffset,0)-yoffset + jsrc = ny_global + yoffset + yoffset2 + & + (this_block%j_glob(j) + ny_global) + do i=1,nx_block + if (this_block%i_glob(i) /= 0) then + isrc = nx_global + xoffset - this_block%i_glob(i) + if (isrc < 1) isrc = isrc + nx_global + if (isrc > nx_global) isrc = isrc - nx_global + msg_buffer(i,j-yoffset2) & + = isign * ARRAY_G(isrc,jsrc) + endif + end do + end do + else + ! normal block + do i=1,nx_block + isrc = this_block%i_glob(i) + jsrc = this_block%j_glob(j) + if (isrc >=1 .and. isrc <= nx_global .and. & + jsrc >=1 .and. jsrc <= ny_global) & + msg_buffer(i,j) = ARRAY_G(isrc,jsrc) + end do + endif + end do call MPI_SEND(msg_buffer, nx_block*ny_block, & mpiR4, dst_dist%blockLocation(n)-1, 3*mpitag_gs+n, & @@ -2114,75 +1996,35 @@ subroutine scatter_global_real(ARRAY, ARRAY_G, src_task, dst_dist, & dst_block = dst_dist%blockLocalID(n) this_block = get_block(n,n) - !*** if this is an interior block, then there is no - !*** padding or update checking required - - if (this_block%iblock > 1 .and. & - this_block%iblock < nblocks_x .and. & - this_block%jblock > 1 .and. & - this_block%jblock < nblocks_y) then - - do j=1,ny_block - do i=1,nx_block - ARRAY(i,j,dst_block) = ARRAY_G(this_block%i_glob(i),& - this_block%j_glob(j)) - end do - end do - - !*** if this is an edge block but not a northern edge - !*** we only need to check for closed boundaries and - !*** padding (global index = 0) - - else if (this_block%jblock /= nblocks_y) then - - do j=1,ny_block - if (this_block%j_glob(j) /= 0) then - do i=1,nx_block - if (this_block%i_glob(i) /= 0) then - ARRAY(i,j,dst_block) = ARRAY_G(this_block%i_glob(i),& - this_block%j_glob(j)) - endif - end do - endif - end do - - !*** if this is a northern edge block, we need to check - !*** for and properly deal with tripole boundaries - - else - - do j=1,ny_block - if (this_block%j_glob(j) > 0) then ! normal boundary - - do i=1,nx_block - if (this_block%i_glob(i) /= 0) then - ARRAY(i,j,dst_block) = ARRAY_G(this_block%i_glob(i),& - this_block%j_glob(j)) - endif - end do - - else if (this_block%j_glob(j) < 0) then ! tripole - - ! for yoffset=0 or 1, yoffset2=0,0 - ! for yoffset=-1, yoffset2=0,1, for u-rows on T-fold grid - do yoffset2=0,max(yoffset,0)-yoffset - jsrc = ny_global + yoffset + yoffset2 + & - (this_block%j_glob(j) + ny_global) - do i=1,nx_block - if (this_block%i_glob(i) /= 0) then - isrc = nx_global + xoffset - this_block%i_glob(i) - if (isrc < 1) isrc = isrc + nx_global - if (isrc > nx_global) isrc = isrc - nx_global - ARRAY(i,j-yoffset2,dst_block) & - = isign * ARRAY_G(isrc,jsrc) - endif - end do - end do - - endif - end do - - endif + do j=1,ny_block + if (this_block%jblock == nblocks_y .and. this_block%j_glob(j) < 0) then + ! tripole is top block with j_glob < 0 + ! for yoffset=0 or 1, yoffset2=0,0 + ! for yoffset=-1, yoffset2=0,1, for u-rows on T-fold grid + do yoffset2=0,max(yoffset,0)-yoffset + jsrc = ny_global + yoffset + yoffset2 + & + (this_block%j_glob(j) + ny_global) + do i=1,nx_block + if (this_block%i_glob(i) /= 0) then + isrc = nx_global + xoffset - this_block%i_glob(i) + if (isrc < 1) isrc = isrc + nx_global + if (isrc > nx_global) isrc = isrc - nx_global + ARRAY(i,j-yoffset2,dst_block) & + = isign * ARRAY_G(isrc,jsrc) + endif + end do + end do + else + ! normal block + do i=1,nx_block + isrc = this_block%i_glob(i) + jsrc = this_block%j_glob(j) + if (isrc >=1 .and. isrc <= nx_global .and. & + jsrc >=1 .and. jsrc <= ny_global) & + ARRAY(i,j,dst_block) = ARRAY_G(isrc,jsrc) + end do + endif + end do endif end do @@ -2218,7 +2060,7 @@ subroutine scatter_global_real(ARRAY, ARRAY_G, src_task, dst_dist, & endif !----------------------------------------------------------------- - ! Ensure unused ghost cell values are 0 + ! Set ghost cell values to 0 for noupdate !----------------------------------------------------------------- if (field_loc == field_loc_noupdate) then @@ -2415,74 +2257,35 @@ subroutine scatter_global_int(ARRAY, ARRAY_G, src_task, dst_dist, & msg_buffer = 0 this_block = get_block(n,n) - !*** if this is an interior block, then there is no - !*** padding or update checking required - - if (this_block%iblock > 1 .and. & - this_block%iblock < nblocks_x .and. & - this_block%jblock > 1 .and. & - this_block%jblock < nblocks_y) then - - do j=1,ny_block - do i=1,nx_block - msg_buffer(i,j) = ARRAY_G(this_block%i_glob(i),& - this_block%j_glob(j)) - end do - end do - - !*** if this is an edge block but not a northern edge - !*** we only need to check for closed boundaries and - !*** padding (global index = 0) - - else if (this_block%jblock /= nblocks_y) then - - do j=1,ny_block - if (this_block%j_glob(j) /= 0) then - do i=1,nx_block - if (this_block%i_glob(i) /= 0) then - msg_buffer(i,j) = ARRAY_G(this_block%i_glob(i),& - this_block%j_glob(j)) - endif - end do - endif - end do - - !*** if this is a northern edge block, we need to check - !*** for and properly deal with tripole boundaries - - else - - do j=1,ny_block - if (this_block%j_glob(j) > 0) then ! normal boundary - - do i=1,nx_block - if (this_block%i_glob(i) /= 0) then - msg_buffer(i,j) = ARRAY_G(this_block%i_glob(i),& - this_block%j_glob(j)) - endif - end do - - else if (this_block%j_glob(j) < 0) then ! tripole - - ! for yoffset=0 or 1, yoffset2=0,0 - ! for yoffset=-1, yoffset2=0,1, for u-rows on T-fold grid - do yoffset2=0,max(yoffset,0)-yoffset - jsrc = ny_global + yoffset + yoffset2 + & - (this_block%j_glob(j) + ny_global) - do i=1,nx_block - if (this_block%i_glob(i) /= 0) then - isrc = nx_global + xoffset - this_block%i_glob(i) - if (isrc < 1) isrc = isrc + nx_global - if (isrc > nx_global) isrc = isrc - nx_global - msg_buffer(i,j-yoffset2) = isign * ARRAY_G(isrc,jsrc) - endif - end do - end do - - endif - end do - - endif + do j=1,ny_block + if (this_block%jblock == nblocks_y .and. this_block%j_glob(j) < 0) then + ! tripole is top block with j_glob < 0 + ! for yoffset=0 or 1, yoffset2=0,0 + ! for yoffset=-1, yoffset2=0,1, for u-rows on T-fold grid + do yoffset2=0,max(yoffset,0)-yoffset + jsrc = ny_global + yoffset + yoffset2 + & + (this_block%j_glob(j) + ny_global) + do i=1,nx_block + if (this_block%i_glob(i) /= 0) then + isrc = nx_global + xoffset - this_block%i_glob(i) + if (isrc < 1) isrc = isrc + nx_global + if (isrc > nx_global) isrc = isrc - nx_global + msg_buffer(i,j-yoffset2) & + = isign * ARRAY_G(isrc,jsrc) + endif + end do + end do + else + ! normal block + do i=1,nx_block + isrc = this_block%i_glob(i) + jsrc = this_block%j_glob(j) + if (isrc >=1 .and. isrc <= nx_global .and. & + jsrc >=1 .and. jsrc <= ny_global) & + msg_buffer(i,j) = ARRAY_G(isrc,jsrc) + end do + endif + end do call MPI_SEND(msg_buffer, nx_block*ny_block, & mpi_integer, dst_dist%blockLocation(n)-1, 3*mpitag_gs+n, & @@ -2500,75 +2303,35 @@ subroutine scatter_global_int(ARRAY, ARRAY_G, src_task, dst_dist, & dst_block = dst_dist%blockLocalID(n) this_block = get_block(n,n) - !*** if this is an interior block, then there is no - !*** padding or update checking required - - if (this_block%iblock > 1 .and. & - this_block%iblock < nblocks_x .and. & - this_block%jblock > 1 .and. & - this_block%jblock < nblocks_y) then - - do j=1,ny_block - do i=1,nx_block - ARRAY(i,j,dst_block) = ARRAY_G(this_block%i_glob(i),& - this_block%j_glob(j)) - end do - end do - - !*** if this is an edge block but not a northern edge - !*** we only need to check for closed boundaries and - !*** padding (global index = 0) - - else if (this_block%jblock /= nblocks_y) then - - do j=1,ny_block - if (this_block%j_glob(j) /= 0) then - do i=1,nx_block - if (this_block%i_glob(i) /= 0) then - ARRAY(i,j,dst_block) = ARRAY_G(this_block%i_glob(i),& - this_block%j_glob(j)) - endif - end do - endif - end do - - !*** if this is a northern edge block, we need to check - !*** for and properly deal with tripole boundaries - - else - - do j=1,ny_block - if (this_block%j_glob(j) > 0) then ! normal boundary - - do i=1,nx_block - if (this_block%i_glob(i) /= 0) then - ARRAY(i,j,dst_block) = ARRAY_G(this_block%i_glob(i),& - this_block%j_glob(j)) - endif - end do - - else if (this_block%j_glob(j) < 0) then ! tripole - - ! for yoffset=0 or 1, yoffset2=0,0 - ! for yoffset=-1, yoffset2=0,1, for u-rows on T-fold grid - do yoffset2=0,max(yoffset,0)-yoffset - jsrc = ny_global + yoffset + yoffset2 + & - (this_block%j_glob(j) + ny_global) - do i=1,nx_block - if (this_block%i_glob(i) /= 0) then - isrc = nx_global + xoffset - this_block%i_glob(i) - if (isrc < 1) isrc = isrc + nx_global - if (isrc > nx_global) isrc = isrc - nx_global - ARRAY(i,j-yoffset2,dst_block) & - = isign * ARRAY_G(isrc,jsrc) - endif - end do - end do - - endif - end do - - endif + do j=1,ny_block + if (this_block%jblock == nblocks_y .and. this_block%j_glob(j) < 0) then + ! tripole is top block with j_glob < 0 + ! for yoffset=0 or 1, yoffset2=0,0 + ! for yoffset=-1, yoffset2=0,1, for u-rows on T-fold grid + do yoffset2=0,max(yoffset,0)-yoffset + jsrc = ny_global + yoffset + yoffset2 + & + (this_block%j_glob(j) + ny_global) + do i=1,nx_block + if (this_block%i_glob(i) /= 0) then + isrc = nx_global + xoffset - this_block%i_glob(i) + if (isrc < 1) isrc = isrc + nx_global + if (isrc > nx_global) isrc = isrc - nx_global + ARRAY(i,j-yoffset2,dst_block) & + = isign * ARRAY_G(isrc,jsrc) + endif + end do + end do + else + ! normal block + do i=1,nx_block + isrc = this_block%i_glob(i) + jsrc = this_block%j_glob(j) + if (isrc >=1 .and. isrc <= nx_global .and. & + jsrc >=1 .and. jsrc <= ny_global) & + ARRAY(i,j,dst_block) = ARRAY_G(isrc,jsrc) + end do + endif + end do endif end do @@ -2604,7 +2367,7 @@ subroutine scatter_global_int(ARRAY, ARRAY_G, src_task, dst_dist, & endif !----------------------------------------------------------------- - ! Ensure unused ghost cell values are 0 + ! Set ghost cell values to 0 for noupdate !----------------------------------------------------------------- if (field_loc == field_loc_noupdate) then @@ -2681,7 +2444,7 @@ subroutine scatter_global_ext(ARRAY, ARRAY_G, src_task, dst_dist) integer (int_kind) :: & i,j,n, &! dummy loop indices iblk, jblk, &! block indices - iglb, jglb, &! global indices + isrc, jsrc, &! global indices nrecvs, &! actual number of messages received dst_block, &! location of block in dst array ierr ! MPI error flag @@ -2748,13 +2511,13 @@ subroutine scatter_global_ext(ARRAY, ARRAY_G, src_task, dst_dist) ! southwest corner iblk = i jblk = j - iglb = this_block%i_glob(this_block%ilo)+i-1 - jglb = j - msg_buffer(iblk,jblk) = ARRAY_G(iglb,jglb) + isrc = this_block%i_glob(this_block%ilo)+i-1 + jsrc = j + msg_buffer(iblk,jblk) = ARRAY_G(isrc,jsrc) ! southeast corner iblk = this_block%ihi+i - iglb = this_block%i_glob(this_block%ihi)+nghost+i - msg_buffer(iblk,jblk) = ARRAY_G(iglb,jglb) + isrc = this_block%i_glob(this_block%ihi)+nghost+i + msg_buffer(iblk,jblk) = ARRAY_G(isrc,jsrc) enddo enddo endif @@ -2769,13 +2532,13 @@ subroutine scatter_global_ext(ARRAY, ARRAY_G, src_task, dst_dist) ! northwest corner iblk = i jblk = this_block%jhi+j - iglb = this_block%i_glob(this_block%ilo)+i-1 - jglb = ny_global+nghost+j - msg_buffer(iblk,jblk) = ARRAY_G(iglb,jglb) + isrc = this_block%i_glob(this_block%ilo)+i-1 + jsrc = ny_global+nghost+j + msg_buffer(iblk,jblk) = ARRAY_G(isrc,jsrc) ! northeast corner iblk = this_block%ihi+i - iglb = this_block%i_glob(this_block%ihi)+nghost+i - msg_buffer(iblk,jblk) = ARRAY_G(iglb,jglb) + isrc = this_block%i_glob(this_block%ihi)+nghost+i + msg_buffer(iblk,jblk) = ARRAY_G(isrc,jsrc) enddo enddo endif @@ -2791,13 +2554,13 @@ subroutine scatter_global_ext(ARRAY, ARRAY_G, src_task, dst_dist) ! northwest corner iblk = i jblk = this_block%jhi+j - iglb = i - jglb = this_block%j_glob(this_block%jhi)+nghost+j - msg_buffer(iblk,jblk) = ARRAY_G(iglb,jglb) + isrc = i + jsrc = this_block%j_glob(this_block%jhi)+nghost+j + msg_buffer(iblk,jblk) = ARRAY_G(isrc,jsrc) ! southwest corner jblk = j - jglb = this_block%j_glob(this_block%jlo)+j-1 - msg_buffer(iblk,jblk) = ARRAY_G(iglb,jglb) + jsrc = this_block%j_glob(this_block%jlo)+j-1 + msg_buffer(iblk,jblk) = ARRAY_G(isrc,jsrc) enddo enddo endif @@ -2814,13 +2577,13 @@ subroutine scatter_global_ext(ARRAY, ARRAY_G, src_task, dst_dist) ! northeast corner iblk = this_block%ihi+i jblk = this_block%jhi+j - iglb = nx_global+nghost+i - jglb = this_block%j_glob(this_block%jhi)+nghost+j - msg_buffer(iblk,jblk) = ARRAY_G(iglb,jglb) + isrc = nx_global+nghost+i + jsrc = this_block%j_glob(this_block%jhi)+nghost+j + msg_buffer(iblk,jblk) = ARRAY_G(isrc,jsrc) ! southeast corner jblk = j - jglb = this_block%j_glob(this_block%jlo)+j-1 - msg_buffer(iblk,jblk) = ARRAY_G(iglb,jglb) + jsrc = this_block%j_glob(this_block%jlo)+j-1 + msg_buffer(iblk,jblk) = ARRAY_G(isrc,jsrc) enddo enddo endif @@ -2861,13 +2624,13 @@ subroutine scatter_global_ext(ARRAY, ARRAY_G, src_task, dst_dist) ! southwest corner iblk = i jblk = j - iglb = this_block%i_glob(this_block%ilo)+i-1 - jglb = j - ARRAY(iblk,jblk,dst_block) = ARRAY_G(iglb,jglb) + isrc = this_block%i_glob(this_block%ilo)+i-1 + jsrc = j + ARRAY(iblk,jblk,dst_block) = ARRAY_G(isrc,jsrc) ! southeast corner iblk = this_block%ihi+i - iglb = this_block%i_glob(this_block%ihi)+nghost+i - ARRAY(iblk,jblk,dst_block) = ARRAY_G(iglb,jglb) + isrc = this_block%i_glob(this_block%ihi)+nghost+i + ARRAY(iblk,jblk,dst_block) = ARRAY_G(isrc,jsrc) enddo enddo endif @@ -2882,13 +2645,13 @@ subroutine scatter_global_ext(ARRAY, ARRAY_G, src_task, dst_dist) ! northwest corner iblk = i jblk = this_block%jhi+j - iglb = this_block%i_glob(this_block%ilo)+i-1 - jglb = ny_global+nghost+j - ARRAY(iblk,jblk,dst_block) = ARRAY_G(iglb,jglb) + isrc = this_block%i_glob(this_block%ilo)+i-1 + jsrc = ny_global+nghost+j + ARRAY(iblk,jblk,dst_block) = ARRAY_G(isrc,jsrc) ! northeast corner iblk = this_block%ihi+i - iglb = this_block%i_glob(this_block%ihi)+nghost+i - ARRAY(iblk,jblk,dst_block) = ARRAY_G(iglb,jglb) + isrc = this_block%i_glob(this_block%ihi)+nghost+i + ARRAY(iblk,jblk,dst_block) = ARRAY_G(isrc,jsrc) enddo enddo endif @@ -2904,13 +2667,13 @@ subroutine scatter_global_ext(ARRAY, ARRAY_G, src_task, dst_dist) ! northwest corner iblk = i jblk = this_block%jhi+j - iglb = i - jglb = this_block%j_glob(this_block%jhi)+nghost+j - ARRAY(iblk,jblk,dst_block) = ARRAY_G(iglb,jglb) + isrc = i + jsrc = this_block%j_glob(this_block%jhi)+nghost+j + ARRAY(iblk,jblk,dst_block) = ARRAY_G(isrc,jsrc) ! southwest corner jblk = j - jglb = this_block%j_glob(this_block%jlo)+j-1 - ARRAY(iblk,jblk,dst_block) = ARRAY_G(iglb,jglb) + jsrc = this_block%j_glob(this_block%jlo)+j-1 + ARRAY(iblk,jblk,dst_block) = ARRAY_G(isrc,jsrc) enddo enddo endif @@ -2927,17 +2690,16 @@ subroutine scatter_global_ext(ARRAY, ARRAY_G, src_task, dst_dist) ! northeast corner iblk = this_block%ihi+i jblk = this_block%jhi+j - iglb = nx_global+nghost+i - jglb = this_block%j_glob(this_block%jhi)+nghost+j - ARRAY(iblk,jblk,dst_block) = ARRAY_G(iglb,jglb) + isrc = nx_global+nghost+i + jsrc = this_block%j_glob(this_block%jhi)+nghost+j + ARRAY(iblk,jblk,dst_block) = ARRAY_G(isrc,jsrc) ! southeast corner jblk = j - jglb = this_block%j_glob(this_block%jlo)+j-1 - ARRAY(iblk,jblk,dst_block) = ARRAY_G(iglb,jglb) + jsrc = this_block%j_glob(this_block%jlo)+j-1 + ARRAY(iblk,jblk,dst_block) = ARRAY_G(isrc,jsrc) enddo enddo endif - endif end do @@ -3071,70 +2833,30 @@ subroutine scatter_global_stress(ARRAY, ARRAY_G1, ARRAY_G2, & msg_buffer = c0 this_block = get_block(n,n) - !*** if this is an interior block, then there is no - !*** padding or update checking required - - if (this_block%iblock > 1 .and. & - this_block%iblock < nblocks_x .and. & - this_block%jblock > 1 .and. & - this_block%jblock < nblocks_y) then - - do j=1,ny_block - do i=1,nx_block - msg_buffer(i,j) = ARRAY_G1(this_block%i_glob(i),& - this_block%j_glob(j)) - end do - end do - - !*** if this is an edge block but not a northern edge - !*** we only need to check for closed boundaries and - !*** padding (global index = 0) - - else if (this_block%jblock /= nblocks_y) then - - do j=1,ny_block - if (this_block%j_glob(j) /= 0) then - do i=1,nx_block - if (this_block%i_glob(i) /= 0) then - msg_buffer(i,j) = ARRAY_G1(this_block%i_glob(i),& - this_block%j_glob(j)) - endif - end do - endif - end do - - !*** if this is a northern edge block, we need to check - !*** for and properly deal with tripole boundaries - - else - - do j=1,ny_block - if (this_block%j_glob(j) > 0) then ! normal boundary - - do i=1,nx_block - if (this_block%i_glob(i) /= 0) then - msg_buffer(i,j) = ARRAY_G1(this_block%i_glob(i),& - this_block%j_glob(j)) - endif - end do - - else if (this_block%j_glob(j) < 0) then ! tripole - - jsrc = ny_global + yoffset + & - (this_block%j_glob(j) + ny_global) - do i=1,nx_block - if (this_block%i_glob(i) /= 0) then - isrc = nx_global + xoffset - this_block%i_glob(i) - if (isrc < 1) isrc = isrc + nx_global - if (isrc > nx_global) isrc = isrc - nx_global - msg_buffer(i,j) = isign * ARRAY_G2(isrc,jsrc) - endif - end do - - endif - end do - - endif + do j=1,ny_block + if (this_block%jblock == nblocks_y .and. this_block%j_glob(j) < 0) then + ! tripole is top block with j_glob < 0 + jsrc = ny_global + yoffset + & + (this_block%j_glob(j) + ny_global) + do i=1,nx_block + if (this_block%i_glob(i) /= 0) then + isrc = nx_global + xoffset - this_block%i_glob(i) + if (isrc < 1) isrc = isrc + nx_global + if (isrc > nx_global) isrc = isrc - nx_global + msg_buffer(i,j) = isign * ARRAY_G2(isrc,jsrc) + endif + end do + else + ! normal block + do i=1,nx_block + isrc = this_block%i_glob(i) + jsrc = this_block%j_glob(j) + if (isrc >=1 .and. isrc <= nx_global .and. & + jsrc >=1 .and. jsrc <= ny_global) & + msg_buffer(i,j) = ARRAY_G1(isrc,jsrc) + end do + endif + end do call MPI_SEND(msg_buffer, nx_block*ny_block, & mpiR8, dst_dist%blockLocation(n)-1, 3*mpitag_gs+n, & @@ -3152,75 +2874,35 @@ subroutine scatter_global_stress(ARRAY, ARRAY_G1, ARRAY_G2, & dst_block = dst_dist%blockLocalID(n) this_block = get_block(n,n) - !*** if this is an interior block, then there is no - !*** padding or update checking required - - if (this_block%iblock > 1 .and. & - this_block%iblock < nblocks_x .and. & - this_block%jblock > 1 .and. & - this_block%jblock < nblocks_y) then - - do j=1,ny_block - do i=1,nx_block - ARRAY(i,j,dst_block) = ARRAY_G1(this_block%i_glob(i),& - this_block%j_glob(j)) - end do - end do - - !*** if this is an edge block but not a northern edge - !*** we only need to check for closed boundaries and - !*** padding (global index = 0) - - else if (this_block%jblock /= nblocks_y) then - - do j=1,ny_block - if (this_block%j_glob(j) /= 0) then - do i=1,nx_block - if (this_block%i_glob(i) /= 0) then - ARRAY(i,j,dst_block) = ARRAY_G1(this_block%i_glob(i),& - this_block%j_glob(j)) - endif - end do - endif - end do - - !*** if this is a northern edge block, we need to check - !*** for and properly deal with tripole boundaries - - else - - do j=1,ny_block - if (this_block%j_glob(j) > 0) then ! normal boundary - - do i=1,nx_block - if (this_block%i_glob(i) /= 0) then - ARRAY(i,j,dst_block) = ARRAY_G1(this_block%i_glob(i),& - this_block%j_glob(j)) - endif - end do - - else if (this_block%j_glob(j) < 0) then ! tripole - - ! for yoffset=0 or 1, yoffset2=0,0 - ! for yoffset=-1, yoffset2=0,1, for u-rows on T-fold grid - do yoffset2=0,max(yoffset,0)-yoffset - jsrc = ny_global + yoffset + yoffset2 + & - (this_block%j_glob(j) + ny_global) - do i=1,nx_block - if (this_block%i_glob(i) /= 0) then - isrc = nx_global + xoffset - this_block%i_glob(i) - if (isrc < 1) isrc = isrc + nx_global - if (isrc > nx_global) isrc = isrc - nx_global - ARRAY(i,j-yoffset2,dst_block) & - = isign * ARRAY_G2(isrc,jsrc) - endif - end do - end do - - endif - end do - - endif + do j=1,ny_block + if (this_block%jblock == nblocks_y .and. this_block%j_glob(j) < 0) then + ! tripole is top block with j_glob < 0 + ! for yoffset=0 or 1, yoffset2=0,0 + ! for yoffset=-1, yoffset2=0,1, for u-rows on T-fold grid + do yoffset2=0,max(yoffset,0)-yoffset + jsrc = ny_global + yoffset + yoffset2 + & + (this_block%j_glob(j) + ny_global) + do i=1,nx_block + if (this_block%i_glob(i) /= 0) then + isrc = nx_global + xoffset - this_block%i_glob(i) + if (isrc < 1) isrc = isrc + nx_global + if (isrc > nx_global) isrc = isrc - nx_global + ARRAY(i,j-yoffset2,dst_block) & + = isign * ARRAY_G2(isrc,jsrc) + endif + end do + end do + else + ! normal block + do i=1,nx_block + isrc = this_block%i_glob(i) + jsrc = this_block%j_glob(j) + if (isrc >=1 .and. isrc <= nx_global .and. & + jsrc >=1 .and. jsrc <= ny_global) & + ARRAY(i,j,dst_block) = ARRAY_G1(isrc,jsrc) + end do + endif + end do endif end do diff --git a/cicecore/cicedyn/infrastructure/comm/serial/ice_boundary.F90 b/cicecore/cicedyn/infrastructure/comm/serial/ice_boundary.F90 index b9ac8fe33..f185da3c5 100644 --- a/cicecore/cicedyn/infrastructure/comm/serial/ice_boundary.F90 +++ b/cicecore/cicedyn/infrastructure/comm/serial/ice_boundary.F90 @@ -31,7 +31,7 @@ module ice_boundary use icepack_intfc, only: icepack_warnings_flush, icepack_warnings_aborted use ice_blocks, only: nx_block, ny_block, nghost, & - nblocks_tot, ice_blocksNorth, & + nblocks_tot, ice_blocksNorth, nblocks_x, nblocks_y, & ice_blocksSouth, ice_blocksEast, ice_blocksWest, & ice_blocksEast2, ice_blocksWest2, & ice_blocksNorthEast, ice_blocksNorthWest, & @@ -61,6 +61,10 @@ module ice_boundary srcLocalAddr, &! src addresses for each local copy dstLocalAddr ! dst addresses for each local copy + character (char_len) :: & + nsBoundaryType, &! type of boundary to use in logical ns dir + ewBoundaryType ! type of boundary to use in logical ew dir + end type public :: ice_HaloCreate, & @@ -177,6 +181,8 @@ function ice_HaloCreate(dist, nsBoundaryType, ewBoundaryType, & if (my_task >= numProcs) return halo%communicator = communicator + halo%ewBoundaryType = ewBoundaryType + halo%nsBoundaryType = nsBoundaryType blockSizeX = nx_block - 2*nghost blockSizeY = ny_block - 2*nghost @@ -659,7 +665,7 @@ subroutine ice_HaloUpdate2DR8(array, halo, & ! This routine updates ghost cells for an input array and is a ! member of a group of routines under the generic interface -! POP\_HaloUpdate. This routine is the specific interface +! ice\_HaloUpdate. This routine is the specific interface ! for 2d horizontal arrays of double precision. type (ice_halo), intent(in) :: & @@ -690,9 +696,10 @@ subroutine ice_HaloUpdate2DR8(array, halo, & ! !----------------------------------------------------------------------- - integer (int_kind) :: & + integer (int_kind) :: & i,j,nmsg, &! dummy loop indices iblk,ilo,ihi,jlo,jhi, &! block sizes for fill + iblock,jblock, &! global block indices nxGlobal, &! global domain size in x (tripole) iSrc,jSrc, &! source addresses for message iDst,jDst, &! dest addresses for message @@ -706,6 +713,8 @@ subroutine ice_HaloUpdate2DR8(array, halo, & x1,x2,xavg ! scalars for enforcing symmetry at U pts logical (log_kind) :: & + ewfillouter, &! fill outer boundary ew + nsfillouter, &! fill outer boundary ns ltripoleOnly ! local tripoleOnly value character(len=*), parameter :: subname = '(ice_HaloUpdate2DR8)' @@ -733,8 +742,20 @@ subroutine ice_HaloUpdate2DR8(array, halo, & ! !----------------------------------------------------------------------- + ewfillouter = .false. + nsfillouter = .false. + + ! fill outer boundary if cyclic or tripole + if (halo%ewBoundaryType == 'cyclic') ewfillouter=.true. + if (halo%nsBoundaryType == 'tripole' .or. & + halo%nsBoundaryType == 'tripoleT' .or. & + halo%nsBoundaryType == 'cyclic') nsfillouter=.true. + if (present(fillValue)) then fill = fillValue + ! always fill outer boundary if fillValue is passed + ewfillouter = .true. + nsfillouter = .true. else fill = 0.0_dbl_kind endif @@ -753,29 +774,78 @@ subroutine ice_HaloUpdate2DR8(array, halo, & !----------------------------------------------------------------------- ! -! fill out halo region -! needed for masked halos to ensure halo values are filled for +! Fill out halo region +! Needed for masked halos to ensure halo values are filled for ! halo grid cells that are not updated +! In general, do NOT fill outer boundary for open boundary conditions +! because do not want to overwrite existing data ! !----------------------------------------------------------------------- - if (ltripoleOnly) then - ! skip fill, not needed since tripole seam always exists if running - ! on tripole grid and set tripoleOnly flag - else + if (.not. ltripoleOnly) then + ! tripoleOnly skip fill, do not overwrite any values in interior as they may + ! already be set and filling tripole is not necessary + + ! fill outer boundary as needed + ! only fill corners if both edges are being filled do iblk = 1, halo%numLocalBlocks - call get_block_parameter(halo%blockGlobalID(iblk), & - ilo=ilo, ihi=ihi, & - jlo=jlo, jhi=jhi) - do j = 1,nghost - array(1:nx_block, jlo-j,iblk) = fill - array(1:nx_block, jhi+j,iblk) = fill - enddo - do i = 1,nghost - array(ilo-i, 1:ny_block,iblk) = fill - array(ihi+i, 1:ny_block,iblk) = fill - enddo - enddo + call get_block_parameter(halo%blockGlobalID(iblk), & + ilo=ilo, ihi=ihi, & + jlo=jlo, jhi=jhi, & + iblock=iblock, jblock=jblock) + if (ewfillouter .or. iblock > 1) then ! west edge + do i = 1,nghost + array(ilo-i, jlo:jhi, iblk) = fill + enddo + endif + if (ewfillouter .or. iblock < nblocks_x) then ! east edge + do i = 1,nghost + array(ihi+i, jlo:jhi, iblk) = fill + enddo + endif + if (nsfillouter .or. jblock > 1) then ! south edge + do j = 1,nghost + array(ilo:ihi, jlo-j, iblk) = fill + enddo + endif + if (nsfillouter .or. jblock < nblocks_y) then ! north edge + do j = 1,nghost + array(ilo:ihi, jhi+j, iblk) = fill + enddo + endif + if ((ewfillouter .or. iblock > 1) .and. & ! southwest corner + (nsfillouter .or. jblock > 1)) then + do j = 1,nghost + do i = 1,nghost + array(ilo-i, jlo-j, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock > 1) .and. & ! northwest corner + (nsfillouter .or. jblock < nblocks_y)) then + do j = 1,nghost + do i = 1,nghost + array(ilo-i, jhi+j, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock < nblocks_x) .and. & ! southeast corner + (nsfillouter .or. jblock > 1)) then + do j = 1,nghost + do i = 1,nghost + array(ihi+i, jlo-j, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock < nblocks_x) .and. & ! northeast corner + (nsfillouter .or. jblock < nblocks_y)) then + do j = 1,nghost + do i = 1,nghost + array(ihi+i, jhi+j, iblk) = fill + enddo + enddo + endif + enddo ! iblk endif !----------------------------------------------------------------------- @@ -994,7 +1064,7 @@ subroutine ice_HaloUpdate2DR4(array, halo, & ! This routine updates ghost cells for an input array and is a ! member of a group of routines under the generic interface -! POP\_HaloUpdate. This routine is the specific interface +! ice\_HaloUpdate. This routine is the specific interface ! for 2d horizontal arrays of single precision. type (ice_halo), intent(in) :: & @@ -1022,9 +1092,10 @@ subroutine ice_HaloUpdate2DR4(array, halo, & ! !----------------------------------------------------------------------- - integer (int_kind) :: & + integer (int_kind) :: & i,j,nmsg, &! dummy loop indices iblk,ilo,ihi,jlo,jhi, &! block sizes for fill + iblock,jblock, &! global block indices nxGlobal, &! global domain size in x (tripole) iSrc,jSrc, &! source addresses for message iDst,jDst, &! dest addresses for message @@ -1037,6 +1108,10 @@ subroutine ice_HaloUpdate2DR4(array, halo, & fill, &! value to use for unknown points x1,x2,xavg ! scalars for enforcing symmetry at U pts + logical (log_kind) :: & + ewfillouter, &! fill outer boundary ew + nsfillouter ! fill outer boundary ns + character(len=*), parameter :: subname = '(ice_HaloUpdate2DR4)' !----------------------------------------------------------------------- @@ -1062,8 +1137,20 @@ subroutine ice_HaloUpdate2DR4(array, halo, & ! !----------------------------------------------------------------------- + ewfillouter = .false. + nsfillouter = .false. + + ! fill outer boundary if cyclic + if (halo%ewBoundaryType == 'cyclic') ewfillouter=.true. + if (halo%nsBoundaryType == 'tripole' .or. & + halo%nsBoundaryType == 'tripoleT' .or. & + halo%nsBoundaryType == 'cyclic') nsfillouter=.true. + if (present(fillValue)) then fill = fillValue + ! always fill outer boundary if fillValue is passed + ewfillouter = .true. + nsfillouter = .true. else fill = 0.0_real_kind endif @@ -1076,25 +1163,74 @@ subroutine ice_HaloUpdate2DR4(array, halo, & !----------------------------------------------------------------------- ! -! fill out halo region -! needed for masked halos to ensure halo values are filled for +! Fill out halo region +! Needed for masked halos to ensure halo values are filled for ! halo grid cells that are not updated +! In general, do NOT fill outer boundary for open boundary conditions +! because do not want to overwrite existing data ! !----------------------------------------------------------------------- + ! fill outer boundary as needed + ! only fill corners if both edges are being filled do iblk = 1, halo%numLocalBlocks - call get_block_parameter(halo%blockGlobalID(iblk), & - ilo=ilo, ihi=ihi, & - jlo=jlo, jhi=jhi) - do j = 1,nghost - array(1:nx_block, jlo-j,iblk) = fill - array(1:nx_block, jhi+j,iblk) = fill - enddo - do i = 1,nghost - array(ilo-i, 1:ny_block,iblk) = fill - array(ihi+i, 1:ny_block,iblk) = fill - enddo - enddo + call get_block_parameter(halo%blockGlobalID(iblk), & + ilo=ilo, ihi=ihi, & + jlo=jlo, jhi=jhi, & + iblock=iblock, jblock=jblock) + if (ewfillouter .or. iblock > 1) then ! west edge + do i = 1,nghost + array(ilo-i, jlo:jhi, iblk) = fill + enddo + endif + if (ewfillouter .or. iblock < nblocks_x) then ! east edge + do i = 1,nghost + array(ihi+i, jlo:jhi, iblk) = fill + enddo + endif + if (nsfillouter .or. jblock > 1) then ! south edge + do j = 1,nghost + array(ilo:ihi, jlo-j, iblk) = fill + enddo + endif + if (nsfillouter .or. jblock < nblocks_y) then ! north edge + do j = 1,nghost + array(ilo:ihi, jhi+j, iblk) = fill + enddo + endif + if ((ewfillouter .or. iblock > 1) .and. & ! southwest corner + (nsfillouter .or. jblock > 1)) then + do j = 1,nghost + do i = 1,nghost + array(ilo-i, jlo-j, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock > 1) .and. & ! northwest corner + (nsfillouter .or. jblock < nblocks_y)) then + do j = 1,nghost + do i = 1,nghost + array(ilo-i, jhi+j, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock < nblocks_x) .and. & ! southeast corner + (nsfillouter .or. jblock > 1)) then + do j = 1,nghost + do i = 1,nghost + array(ihi+i, jlo-j, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock < nblocks_x) .and. & ! northeast corner + (nsfillouter .or. jblock < nblocks_y)) then + do j = 1,nghost + do i = 1,nghost + array(ihi+i, jhi+j, iblk) = fill + enddo + enddo + endif + enddo ! iblk !----------------------------------------------------------------------- ! @@ -1303,7 +1439,7 @@ subroutine ice_HaloUpdate2DI4(array, halo, & ! This routine updates ghost cells for an input array and is a ! member of a group of routines under the generic interface -! POP\_HaloUpdate. This routine is the specific interface +! ice\_HaloUpdate. This routine is the specific interface ! for 2d horizontal integer arrays. type (ice_halo), intent(in) :: & @@ -1331,9 +1467,10 @@ subroutine ice_HaloUpdate2DI4(array, halo, & ! !----------------------------------------------------------------------- - integer (int_kind) :: & + integer (int_kind) :: & i,j,nmsg, &! dummy loop indices iblk,ilo,ihi,jlo,jhi, &! block sizes for fill + iblock,jblock, &! global block indices nxGlobal, &! global domain size in x (tripole) iSrc,jSrc, &! source addresses for message iDst,jDst, &! dest addresses for message @@ -1346,6 +1483,10 @@ subroutine ice_HaloUpdate2DI4(array, halo, & fill, &! value to use for unknown points x1,x2,xavg ! scalars for enforcing symmetry at U pts + logical (log_kind) :: & + ewfillouter, &! fill outer boundary ew + nsfillouter ! fill outer boundary ns + character(len=*), parameter :: subname = '(ice_HaloUpdate2DI4)' !----------------------------------------------------------------------- @@ -1371,8 +1512,20 @@ subroutine ice_HaloUpdate2DI4(array, halo, & ! !----------------------------------------------------------------------- + ewfillouter = .false. + nsfillouter = .false. + + ! fill outer boundary if cyclic + if (halo%ewBoundaryType == 'cyclic') ewfillouter=.true. + if (halo%nsBoundaryType == 'tripole' .or. & + halo%nsBoundaryType == 'tripoleT' .or. & + halo%nsBoundaryType == 'cyclic') nsfillouter=.true. + if (present(fillValue)) then fill = fillValue + ! always fill outer boundary if fillValue is passed + ewfillouter = .true. + nsfillouter = .true. else fill = 0_int_kind endif @@ -1385,25 +1538,74 @@ subroutine ice_HaloUpdate2DI4(array, halo, & !----------------------------------------------------------------------- ! -! fill out halo region -! needed for masked halos to ensure halo values are filled for +! Fill out halo region +! Needed for masked halos to ensure halo values are filled for ! halo grid cells that are not updated +! In general, do NOT fill outer boundary for open boundary conditions +! because do not want to overwrite existing data ! !----------------------------------------------------------------------- + ! fill outer boundary as needed + ! only fill corners if both edges are being filled do iblk = 1, halo%numLocalBlocks - call get_block_parameter(halo%blockGlobalID(iblk), & - ilo=ilo, ihi=ihi, & - jlo=jlo, jhi=jhi) - do j = 1,nghost - array(1:nx_block, jlo-j,iblk) = fill - array(1:nx_block, jhi+j,iblk) = fill - enddo - do i = 1,nghost - array(ilo-i, 1:ny_block,iblk) = fill - array(ihi+i, 1:ny_block,iblk) = fill - enddo - enddo + call get_block_parameter(halo%blockGlobalID(iblk), & + ilo=ilo, ihi=ihi, & + jlo=jlo, jhi=jhi, & + iblock=iblock, jblock=jblock) + if (ewfillouter .or. iblock > 1) then ! west edge + do i = 1,nghost + array(ilo-i, jlo:jhi, iblk) = fill + enddo + endif + if (ewfillouter .or. iblock < nblocks_x) then ! east edge + do i = 1,nghost + array(ihi+i, jlo:jhi, iblk) = fill + enddo + endif + if (nsfillouter .or. jblock > 1) then ! south edge + do j = 1,nghost + array(ilo:ihi, jlo-j, iblk) = fill + enddo + endif + if (nsfillouter .or. jblock < nblocks_y) then ! north edge + do j = 1,nghost + array(ilo:ihi, jhi+j, iblk) = fill + enddo + endif + if ((ewfillouter .or. iblock > 1) .and. & ! southwest corner + (nsfillouter .or. jblock > 1)) then + do j = 1,nghost + do i = 1,nghost + array(ilo-i, jlo-j, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock > 1) .and. & ! northwest corner + (nsfillouter .or. jblock < nblocks_y)) then + do j = 1,nghost + do i = 1,nghost + array(ilo-i, jhi+j, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock < nblocks_x) .and. & ! southeast corner + (nsfillouter .or. jblock > 1)) then + do j = 1,nghost + do i = 1,nghost + array(ihi+i, jlo-j, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock < nblocks_x) .and. & ! northeast corner + (nsfillouter .or. jblock < nblocks_y)) then + do j = 1,nghost + do i = 1,nghost + array(ihi+i, jhi+j, iblk) = fill + enddo + enddo + endif + enddo ! iblk !----------------------------------------------------------------------- ! @@ -1692,7 +1894,7 @@ subroutine ice_HaloUpdate3DR8(array, halo, & ! This routine updates ghost cells for an input array and is a ! member of a group of routines under the generic interface -! POP\_HaloUpdate. This routine is the specific interface +! ice\_HaloUpdate. This routine is the specific interface ! for 3d horizontal arrays of double precision. type (ice_halo), intent(in) :: & @@ -1720,9 +1922,10 @@ subroutine ice_HaloUpdate3DR8(array, halo, & ! !----------------------------------------------------------------------- - integer (int_kind) :: & + integer (int_kind) :: & i,j,k,nmsg, &! dummy loop indices iblk,ilo,ihi,jlo,jhi, &! block sizes for fill + iblock,jblock, &! global block indices nxGlobal, &! global domain size in x (tripole) nz, &! size of array in 3rd dimension iSrc,jSrc, &! source addresses for message @@ -1736,6 +1939,10 @@ subroutine ice_HaloUpdate3DR8(array, halo, & fill, &! value to use for unknown points x1,x2,xavg ! scalars for enforcing symmetry at U pts + logical (log_kind) :: & + ewfillouter, &! fill outer boundary ew + nsfillouter ! fill outer boundary ns + real (dbl_kind), dimension(:,:,:), allocatable :: & bufTripole ! 3d tripole buffer @@ -1764,8 +1971,20 @@ subroutine ice_HaloUpdate3DR8(array, halo, & ! !----------------------------------------------------------------------- + ewfillouter = .false. + nsfillouter = .false. + + ! fill outer boundary if cyclic + if (halo%ewBoundaryType == 'cyclic') ewfillouter=.true. + if (halo%nsBoundaryType == 'tripole' .or. & + halo%nsBoundaryType == 'tripoleT' .or. & + halo%nsBoundaryType == 'cyclic') nsfillouter=.true. + if (present(fillValue)) then fill = fillValue + ! always fill outer boundary if fillValue is passed + ewfillouter = .true. + nsfillouter = .true. else fill = 0.0_dbl_kind endif @@ -1781,25 +2000,74 @@ subroutine ice_HaloUpdate3DR8(array, halo, & !----------------------------------------------------------------------- ! -! fill out halo region -! needed for masked halos to ensure halo values are filled for +! Fill out halo region +! Needed for masked halos to ensure halo values are filled for ! halo grid cells that are not updated +! In general, do NOT fill outer boundary for open boundary conditions +! because do not want to overwrite existing data ! !----------------------------------------------------------------------- + ! fill outer boundary as needed + ! only fill corners if both edges are being filled do iblk = 1, halo%numLocalBlocks - call get_block_parameter(halo%blockGlobalID(iblk), & - ilo=ilo, ihi=ihi, & - jlo=jlo, jhi=jhi) - do j = 1,nghost - array(1:nx_block, jlo-j,:,iblk) = fill - array(1:nx_block, jhi+j,:,iblk) = fill - enddo - do i = 1,nghost - array(ilo-i, 1:ny_block,:,iblk) = fill - array(ihi+i, 1:ny_block,:,iblk) = fill - enddo - enddo + call get_block_parameter(halo%blockGlobalID(iblk), & + ilo=ilo, ihi=ihi, & + jlo=jlo, jhi=jhi, & + iblock=iblock, jblock=jblock) + if (ewfillouter .or. iblock > 1) then ! west edge + do i = 1,nghost + array(ilo-i, jlo:jhi, :, iblk) = fill + enddo + endif + if (ewfillouter .or. iblock < nblocks_x) then ! east edge + do i = 1,nghost + array(ihi+i, jlo:jhi, :, iblk) = fill + enddo + endif + if (nsfillouter .or. jblock > 1) then ! south edge + do j = 1,nghost + array(ilo:ihi, jlo-j, :, iblk) = fill + enddo + endif + if (nsfillouter .or. jblock < nblocks_y) then ! north edge + do j = 1,nghost + array(ilo:ihi, jhi+j, :, iblk) = fill + enddo + endif + if ((ewfillouter .or. iblock > 1) .and. & ! southwest corner + (nsfillouter .or. jblock > 1)) then + do j = 1,nghost + do i = 1,nghost + array(ilo-i, jlo-j, :, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock > 1) .and. & ! northwest corner + (nsfillouter .or. jblock < nblocks_y)) then + do j = 1,nghost + do i = 1,nghost + array(ilo-i, jhi+j, :, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock < nblocks_x) .and. & ! southeast corner + (nsfillouter .or. jblock > 1)) then + do j = 1,nghost + do i = 1,nghost + array(ihi+i, jlo-j, :, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock < nblocks_x) .and. & ! northeast corner + (nsfillouter .or. jblock < nblocks_y)) then + do j = 1,nghost + do i = 1,nghost + array(ihi+i, jhi+j, :, iblk) = fill + enddo + enddo + endif + enddo ! iblk !----------------------------------------------------------------------- ! @@ -2027,7 +2295,7 @@ subroutine ice_HaloUpdate3DR4(array, halo, & ! This routine updates ghost cells for an input array and is a ! member of a group of routines under the generic interface -! POP\_HaloUpdate. This routine is the specific interface +! ice\_HaloUpdate. This routine is the specific interface ! for 3d horizontal arrays of single precision. type (ice_halo), intent(in) :: & @@ -2055,9 +2323,10 @@ subroutine ice_HaloUpdate3DR4(array, halo, & ! !----------------------------------------------------------------------- - integer (int_kind) :: & + integer (int_kind) :: & i,j,k,nmsg, &! dummy loop indices iblk,ilo,ihi,jlo,jhi, &! block sizes for fill + iblock,jblock, &! global block indices nxGlobal, &! global domain size in x (tripole) nz, &! size of array in 3rd dimension iSrc,jSrc, &! source addresses for message @@ -2071,6 +2340,10 @@ subroutine ice_HaloUpdate3DR4(array, halo, & fill, &! value to use for unknown points x1,x2,xavg ! scalars for enforcing symmetry at U pts + logical (log_kind) :: & + ewfillouter, &! fill outer boundary ew + nsfillouter ! fill outer boundary ns + real (real_kind), dimension(:,:,:), allocatable :: & bufTripole ! 3d tripole buffer @@ -2099,8 +2372,20 @@ subroutine ice_HaloUpdate3DR4(array, halo, & ! !----------------------------------------------------------------------- + ewfillouter = .false. + nsfillouter = .false. + + ! fill outer boundary if cyclic + if (halo%ewBoundaryType == 'cyclic') ewfillouter=.true. + if (halo%nsBoundaryType == 'tripole' .or. & + halo%nsBoundaryType == 'tripoleT' .or. & + halo%nsBoundaryType == 'cyclic') nsfillouter=.true. + if (present(fillValue)) then fill = fillValue + ! always fill outer boundary if fillValue is passed + ewfillouter = .true. + nsfillouter = .true. else fill = 0.0_real_kind endif @@ -2116,25 +2401,74 @@ subroutine ice_HaloUpdate3DR4(array, halo, & !----------------------------------------------------------------------- ! -! fill out halo region -! needed for masked halos to ensure halo values are filled for +! Fill out halo region +! Needed for masked halos to ensure halo values are filled for ! halo grid cells that are not updated +! In general, do NOT fill outer boundary for open boundary conditions +! because do not want to overwrite existing data ! !----------------------------------------------------------------------- + ! fill outer boundary as needed + ! only fill corners if both edges are being filled do iblk = 1, halo%numLocalBlocks - call get_block_parameter(halo%blockGlobalID(iblk), & - ilo=ilo, ihi=ihi, & - jlo=jlo, jhi=jhi) - do j = 1,nghost - array(1:nx_block, jlo-j,:,iblk) = fill - array(1:nx_block, jhi+j,:,iblk) = fill - enddo - do i = 1,nghost - array(ilo-i, 1:ny_block,:,iblk) = fill - array(ihi+i, 1:ny_block,:,iblk) = fill - enddo - enddo + call get_block_parameter(halo%blockGlobalID(iblk), & + ilo=ilo, ihi=ihi, & + jlo=jlo, jhi=jhi, & + iblock=iblock, jblock=jblock) + if (ewfillouter .or. iblock > 1) then ! west edge + do i = 1,nghost + array(ilo-i, jlo:jhi, :, iblk) = fill + enddo + endif + if (ewfillouter .or. iblock < nblocks_x) then ! east edge + do i = 1,nghost + array(ihi+i, jlo:jhi, :, iblk) = fill + enddo + endif + if (nsfillouter .or. jblock > 1) then ! south edge + do j = 1,nghost + array(ilo:ihi, jlo-j, :, iblk) = fill + enddo + endif + if (nsfillouter .or. jblock < nblocks_y) then ! north edge + do j = 1,nghost + array(ilo:ihi, jhi+j, :, iblk) = fill + enddo + endif + if ((ewfillouter .or. iblock > 1) .and. & ! southwest corner + (nsfillouter .or. jblock > 1)) then + do j = 1,nghost + do i = 1,nghost + array(ilo-i, jlo-j, :, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock > 1) .and. & ! northwest corner + (nsfillouter .or. jblock < nblocks_y)) then + do j = 1,nghost + do i = 1,nghost + array(ilo-i, jhi+j, :, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock < nblocks_x) .and. & ! southeast corner + (nsfillouter .or. jblock > 1)) then + do j = 1,nghost + do i = 1,nghost + array(ihi+i, jlo-j, :, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock < nblocks_x) .and. & ! northeast corner + (nsfillouter .or. jblock < nblocks_y)) then + do j = 1,nghost + do i = 1,nghost + array(ihi+i, jhi+j, :, iblk) = fill + enddo + enddo + endif + enddo ! iblk !----------------------------------------------------------------------- ! @@ -2362,7 +2696,7 @@ subroutine ice_HaloUpdate3DI4(array, halo, & ! This routine updates ghost cells for an input array and is a ! member of a group of routines under the generic interface -! POP\_HaloUpdate. This routine is the specific interface +! ice\_HaloUpdate. This routine is the specific interface ! for 3d horizontal arrays of double precision. type (ice_halo), intent(in) :: & @@ -2390,9 +2724,10 @@ subroutine ice_HaloUpdate3DI4(array, halo, & ! !----------------------------------------------------------------------- - integer (int_kind) :: & + integer (int_kind) :: & i,j,k,nmsg, &! dummy loop indices iblk,ilo,ihi,jlo,jhi, &! block sizes for fill + iblock,jblock, &! global block indices nxGlobal, &! global domain size in x (tripole) nz, &! size of array in 3rd dimension iSrc,jSrc, &! source addresses for message @@ -2406,6 +2741,10 @@ subroutine ice_HaloUpdate3DI4(array, halo, & fill, &! value to use for unknown points x1,x2,xavg ! scalars for enforcing symmetry at U pts + logical (log_kind) :: & + ewfillouter, &! fill outer boundary ew + nsfillouter ! fill outer boundary ns + integer (int_kind), dimension(:,:,:), allocatable :: & bufTripole ! 3d tripole buffer @@ -2434,8 +2773,20 @@ subroutine ice_HaloUpdate3DI4(array, halo, & ! !----------------------------------------------------------------------- + ewfillouter = .false. + nsfillouter = .false. + + ! fill outer boundary if cyclic + if (halo%ewBoundaryType == 'cyclic') ewfillouter=.true. + if (halo%nsBoundaryType == 'tripole' .or. & + halo%nsBoundaryType == 'tripoleT' .or. & + halo%nsBoundaryType == 'cyclic') nsfillouter=.true. + if (present(fillValue)) then fill = fillValue + ! always fill outer boundary if fillValue is passed + ewfillouter = .true. + nsfillouter = .true. else fill = 0_int_kind endif @@ -2451,25 +2802,74 @@ subroutine ice_HaloUpdate3DI4(array, halo, & !----------------------------------------------------------------------- ! -! fill out halo region -! needed for masked halos to ensure halo values are filled for +! Fill out halo region +! Needed for masked halos to ensure halo values are filled for ! halo grid cells that are not updated +! In general, do NOT fill outer boundary for open boundary conditions +! because do not want to overwrite existing data ! !----------------------------------------------------------------------- + ! fill outer boundary as needed + ! only fill corners if both edges are being filled do iblk = 1, halo%numLocalBlocks - call get_block_parameter(halo%blockGlobalID(iblk), & - ilo=ilo, ihi=ihi, & - jlo=jlo, jhi=jhi) - do j = 1,nghost - array(1:nx_block, jlo-j,:,iblk) = fill - array(1:nx_block, jhi+j,:,iblk) = fill - enddo - do i = 1,nghost - array(ilo-i, 1:ny_block,:,iblk) = fill - array(ihi+i, 1:ny_block,:,iblk) = fill - enddo - enddo + call get_block_parameter(halo%blockGlobalID(iblk), & + ilo=ilo, ihi=ihi, & + jlo=jlo, jhi=jhi, & + iblock=iblock, jblock=jblock) + if (ewfillouter .or. iblock > 1) then ! west edge + do i = 1,nghost + array(ilo-i, jlo:jhi, :, iblk) = fill + enddo + endif + if (ewfillouter .or. iblock < nblocks_x) then ! east edge + do i = 1,nghost + array(ihi+i, jlo:jhi, :, iblk) = fill + enddo + endif + if (nsfillouter .or. jblock > 1) then ! south edge + do j = 1,nghost + array(ilo:ihi, jlo-j, :, iblk) = fill + enddo + endif + if (nsfillouter .or. jblock < nblocks_y) then ! north edge + do j = 1,nghost + array(ilo:ihi, jhi+j, :, iblk) = fill + enddo + endif + if ((ewfillouter .or. iblock > 1) .and. & ! southwest corner + (nsfillouter .or. jblock > 1)) then + do j = 1,nghost + do i = 1,nghost + array(ilo-i, jlo-j, :, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock > 1) .and. & ! northwest corner + (nsfillouter .or. jblock < nblocks_y)) then + do j = 1,nghost + do i = 1,nghost + array(ilo-i, jhi+j, :, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock < nblocks_x) .and. & ! southeast corner + (nsfillouter .or. jblock > 1)) then + do j = 1,nghost + do i = 1,nghost + array(ihi+i, jlo-j, :, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock < nblocks_x) .and. & ! northeast corner + (nsfillouter .or. jblock < nblocks_y)) then + do j = 1,nghost + do i = 1,nghost + array(ihi+i, jhi+j, :, iblk) = fill + enddo + enddo + endif + enddo ! iblk !----------------------------------------------------------------------- ! @@ -2697,7 +3097,7 @@ subroutine ice_HaloUpdate4DR8(array, halo, & ! This routine updates ghost cells for an input array and is a ! member of a group of routines under the generic interface -! POP\_HaloUpdate. This routine is the specific interface +! ice\_HaloUpdate. This routine is the specific interface ! for 4d horizontal arrays of double precision. type (ice_halo), intent(in) :: & @@ -2725,9 +3125,10 @@ subroutine ice_HaloUpdate4DR8(array, halo, & ! !----------------------------------------------------------------------- - integer (int_kind) :: & + integer (int_kind) :: & i,j,k,l,nmsg, &! dummy loop indices iblk,ilo,ihi,jlo,jhi, &! block sizes for fill + iblock,jblock, &! global block indices nxGlobal, &! global domain size in x (tripole) nz, nt, &! size of array in 3rd,4th dimensions iSrc,jSrc, &! source addresses for message @@ -2741,6 +3142,10 @@ subroutine ice_HaloUpdate4DR8(array, halo, & fill, &! value to use for unknown points x1,x2,xavg ! scalars for enforcing symmetry at U pts + logical (log_kind) :: & + ewfillouter, &! fill outer boundary ew + nsfillouter ! fill outer boundary ns + real (dbl_kind), dimension(:,:,:,:), allocatable :: & bufTripole ! 4d tripole buffer @@ -2769,8 +3174,20 @@ subroutine ice_HaloUpdate4DR8(array, halo, & ! !----------------------------------------------------------------------- + ewfillouter = .false. + nsfillouter = .false. + + ! fill outer boundary if cyclic + if (halo%ewBoundaryType == 'cyclic') ewfillouter=.true. + if (halo%nsBoundaryType == 'tripole' .or. & + halo%nsBoundaryType == 'tripoleT' .or. & + halo%nsBoundaryType == 'cyclic') nsfillouter=.true. + if (present(fillValue)) then fill = fillValue + ! always fill outer boundary if fillValue is passed + ewfillouter = .true. + nsfillouter = .true. else fill = 0.0_dbl_kind endif @@ -2787,25 +3204,74 @@ subroutine ice_HaloUpdate4DR8(array, halo, & !----------------------------------------------------------------------- ! -! fill out halo region -! needed for masked halos to ensure halo values are filled for +! Fill out halo region +! Needed for masked halos to ensure halo values are filled for ! halo grid cells that are not updated +! In general, do NOT fill outer boundary for open boundary conditions +! because do not want to overwrite existing data ! !----------------------------------------------------------------------- + ! fill outer boundary as needed + ! only fill corners if both edges are being filled do iblk = 1, halo%numLocalBlocks - call get_block_parameter(halo%blockGlobalID(iblk), & - ilo=ilo, ihi=ihi, & - jlo=jlo, jhi=jhi) - do j = 1,nghost - array(1:nx_block, jlo-j,:,:,iblk) = fill - array(1:nx_block, jhi+j,:,:,iblk) = fill - enddo - do i = 1,nghost - array(ilo-i, 1:ny_block,:,:,iblk) = fill - array(ihi+i, 1:ny_block,:,:,iblk) = fill - enddo - enddo + call get_block_parameter(halo%blockGlobalID(iblk), & + ilo=ilo, ihi=ihi, & + jlo=jlo, jhi=jhi, & + iblock=iblock, jblock=jblock) + if (ewfillouter .or. iblock > 1) then ! west edge + do i = 1,nghost + array(ilo-i, jlo:jhi, :, :, iblk) = fill + enddo + endif + if (ewfillouter .or. iblock < nblocks_x) then ! east edge + do i = 1,nghost + array(ihi+i, jlo:jhi, :, :, iblk) = fill + enddo + endif + if (nsfillouter .or. jblock > 1) then ! south edge + do j = 1,nghost + array(ilo:ihi, jlo-j, :, :, iblk) = fill + enddo + endif + if (nsfillouter .or. jblock < nblocks_y) then ! north edge + do j = 1,nghost + array(ilo:ihi, jhi+j, :, :, iblk) = fill + enddo + endif + if ((ewfillouter .or. iblock > 1) .and. & ! southwest corner + (nsfillouter .or. jblock > 1)) then + do j = 1,nghost + do i = 1,nghost + array(ilo-i, jlo-j, :, :, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock > 1) .and. & ! northwest corner + (nsfillouter .or. jblock < nblocks_y)) then + do j = 1,nghost + do i = 1,nghost + array(ilo-i, jhi+j, :, :, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock < nblocks_x) .and. & ! southeast corner + (nsfillouter .or. jblock > 1)) then + do j = 1,nghost + do i = 1,nghost + array(ihi+i, jlo-j, :, :, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock < nblocks_x) .and. & ! northeast corner + (nsfillouter .or. jblock < nblocks_y)) then + do j = 1,nghost + do i = 1,nghost + array(ihi+i, jhi+j, :, :, iblk) = fill + enddo + enddo + endif + enddo ! iblk !----------------------------------------------------------------------- ! @@ -3049,7 +3515,7 @@ subroutine ice_HaloUpdate4DR4(array, halo, & ! This routine updates ghost cells for an input array and is a ! member of a group of routines under the generic interface -! POP\_HaloUpdate. This routine is the specific interface +! ice\_HaloUpdate. This routine is the specific interface ! for 4d horizontal arrays of single precision. type (ice_halo), intent(in) :: & @@ -3077,9 +3543,10 @@ subroutine ice_HaloUpdate4DR4(array, halo, & ! !----------------------------------------------------------------------- - integer (int_kind) :: & + integer (int_kind) :: & i,j,k,l,nmsg, &! dummy loop indices iblk,ilo,ihi,jlo,jhi, &! block sizes for fill + iblock,jblock, &! global block indices nxGlobal, &! global domain size in x (tripole) nz, nt, &! size of array in 3rd,4th dimensions iSrc,jSrc, &! source addresses for message @@ -3093,6 +3560,10 @@ subroutine ice_HaloUpdate4DR4(array, halo, & fill, &! value to use for unknown points x1,x2,xavg ! scalars for enforcing symmetry at U pts + logical (log_kind) :: & + ewfillouter, &! fill outer boundary ew + nsfillouter ! fill outer boundary ns + real (real_kind), dimension(:,:,:,:), allocatable :: & bufTripole ! 4d tripole buffer @@ -3121,8 +3592,20 @@ subroutine ice_HaloUpdate4DR4(array, halo, & ! !----------------------------------------------------------------------- + ewfillouter = .false. + nsfillouter = .false. + + ! fill outer boundary if cyclic + if (halo%ewBoundaryType == 'cyclic') ewfillouter=.true. + if (halo%nsBoundaryType == 'tripole' .or. & + halo%nsBoundaryType == 'tripoleT' .or. & + halo%nsBoundaryType == 'cyclic') nsfillouter=.true. + if (present(fillValue)) then fill = fillValue + ! always fill outer boundary if fillValue is passed + ewfillouter = .true. + nsfillouter = .true. else fill = 0.0_real_kind endif @@ -3139,25 +3622,74 @@ subroutine ice_HaloUpdate4DR4(array, halo, & !----------------------------------------------------------------------- ! -! fill out halo region -! needed for masked halos to ensure halo values are filled for +! Fill out halo region +! Needed for masked halos to ensure halo values are filled for ! halo grid cells that are not updated +! In general, do NOT fill outer boundary for open boundary conditions +! because do not want to overwrite existing data ! !----------------------------------------------------------------------- + ! fill outer boundary as needed + ! only fill corners if both edges are being filled do iblk = 1, halo%numLocalBlocks - call get_block_parameter(halo%blockGlobalID(iblk), & - ilo=ilo, ihi=ihi, & - jlo=jlo, jhi=jhi) - do j = 1,nghost - array(1:nx_block, jlo-j,:,:,iblk) = fill - array(1:nx_block, jhi+j,:,:,iblk) = fill - enddo - do i = 1,nghost - array(ilo-i, 1:ny_block,:,:,iblk) = fill - array(ihi+i, 1:ny_block,:,:,iblk) = fill - enddo - enddo + call get_block_parameter(halo%blockGlobalID(iblk), & + ilo=ilo, ihi=ihi, & + jlo=jlo, jhi=jhi, & + iblock=iblock, jblock=jblock) + if (ewfillouter .or. iblock > 1) then ! west edge + do i = 1,nghost + array(ilo-i, jlo:jhi, :, :, iblk) = fill + enddo + endif + if (ewfillouter .or. iblock < nblocks_x) then ! east edge + do i = 1,nghost + array(ihi+i, jlo:jhi, :, :, iblk) = fill + enddo + endif + if (nsfillouter .or. jblock > 1) then ! south edge + do j = 1,nghost + array(ilo:ihi, jlo-j, :, :, iblk) = fill + enddo + endif + if (nsfillouter .or. jblock < nblocks_y) then ! north edge + do j = 1,nghost + array(ilo:ihi, jhi+j, :, :, iblk) = fill + enddo + endif + if ((ewfillouter .or. iblock > 1) .and. & ! southwest corner + (nsfillouter .or. jblock > 1)) then + do j = 1,nghost + do i = 1,nghost + array(ilo-i, jlo-j, :, :, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock > 1) .and. & ! northwest corner + (nsfillouter .or. jblock < nblocks_y)) then + do j = 1,nghost + do i = 1,nghost + array(ilo-i, jhi+j, :, :, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock < nblocks_x) .and. & ! southeast corner + (nsfillouter .or. jblock > 1)) then + do j = 1,nghost + do i = 1,nghost + array(ihi+i, jlo-j, :, :, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock < nblocks_x) .and. & ! northeast corner + (nsfillouter .or. jblock < nblocks_y)) then + do j = 1,nghost + do i = 1,nghost + array(ihi+i, jhi+j, :, :, iblk) = fill + enddo + enddo + endif + enddo ! iblk !----------------------------------------------------------------------- ! @@ -3401,7 +3933,7 @@ subroutine ice_HaloUpdate4DI4(array, halo, & ! This routine updates ghost cells for an input array and is a ! member of a group of routines under the generic interface -! POP\_HaloUpdate. This routine is the specific interface +! ice\_HaloUpdate. This routine is the specific interface ! for 4d horizontal integer arrays. type (ice_halo), intent(in) :: & @@ -3429,9 +3961,10 @@ subroutine ice_HaloUpdate4DI4(array, halo, & ! !----------------------------------------------------------------------- - integer (int_kind) :: & + integer (int_kind) :: & i,j,k,l,nmsg, &! dummy loop indices iblk,ilo,ihi,jlo,jhi, &! block sizes for fill + iblock,jblock, &! global block indices nxGlobal, &! global domain size in x (tripole) nz, nt, &! size of array in 3rd,4th dimensions iSrc,jSrc, &! source addresses for message @@ -3445,6 +3978,10 @@ subroutine ice_HaloUpdate4DI4(array, halo, & fill, &! value to use for unknown points x1,x2,xavg ! scalars for enforcing symmetry at U pts + logical (log_kind) :: & + ewfillouter, &! fill outer boundary ew + nsfillouter ! fill outer boundary ns + integer (int_kind), dimension(:,:,:,:), allocatable :: & bufTripole ! 4d tripole buffer @@ -3473,8 +4010,20 @@ subroutine ice_HaloUpdate4DI4(array, halo, & ! !----------------------------------------------------------------------- + ewfillouter = .false. + nsfillouter = .false. + + ! fill outer boundary if cyclic + if (halo%ewBoundaryType == 'cyclic') ewfillouter=.true. + if (halo%nsBoundaryType == 'tripole' .or. & + halo%nsBoundaryType == 'tripoleT' .or. & + halo%nsBoundaryType == 'cyclic') nsfillouter=.true. + if (present(fillValue)) then fill = fillValue + ! always fill outer boundary if fillValue is passed + ewfillouter = .true. + nsfillouter = .true. else fill = 0_int_kind endif @@ -3491,25 +4040,74 @@ subroutine ice_HaloUpdate4DI4(array, halo, & !----------------------------------------------------------------------- ! -! fill out halo region -! needed for masked halos to ensure halo values are filled for +! Fill out halo region +! Needed for masked halos to ensure halo values are filled for ! halo grid cells that are not updated +! In general, do NOT fill outer boundary for open boundary conditions +! because do not want to overwrite existing data ! !----------------------------------------------------------------------- + ! fill outer boundary as needed + ! only fill corners if both edges are being filled do iblk = 1, halo%numLocalBlocks - call get_block_parameter(halo%blockGlobalID(iblk), & - ilo=ilo, ihi=ihi, & - jlo=jlo, jhi=jhi) - do j = 1,nghost - array(1:nx_block, jlo-j,:,:,iblk) = fill - array(1:nx_block, jhi+j,:,:,iblk) = fill - enddo - do i = 1,nghost - array(ilo-i, 1:ny_block,:,:,iblk) = fill - array(ihi+i, 1:ny_block,:,:,iblk) = fill - enddo - enddo + call get_block_parameter(halo%blockGlobalID(iblk), & + ilo=ilo, ihi=ihi, & + jlo=jlo, jhi=jhi, & + iblock=iblock, jblock=jblock) + if (ewfillouter .or. iblock > 1) then ! west edge + do i = 1,nghost + array(ilo-i, jlo:jhi, :, :, iblk) = fill + enddo + endif + if (ewfillouter .or. iblock < nblocks_x) then ! east edge + do i = 1,nghost + array(ihi+i, jlo:jhi, :, :, iblk) = fill + enddo + endif + if (nsfillouter .or. jblock > 1) then ! south edge + do j = 1,nghost + array(ilo:ihi, jlo-j, :, :, iblk) = fill + enddo + endif + if (nsfillouter .or. jblock < nblocks_y) then ! north edge + do j = 1,nghost + array(ilo:ihi, jhi+j, :, :, iblk) = fill + enddo + endif + if ((ewfillouter .or. iblock > 1) .and. & ! southwest corner + (nsfillouter .or. jblock > 1)) then + do j = 1,nghost + do i = 1,nghost + array(ilo-i, jlo-j, :, :, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock > 1) .and. & ! northwest corner + (nsfillouter .or. jblock < nblocks_y)) then + do j = 1,nghost + do i = 1,nghost + array(ilo-i, jhi+j, :, :, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock < nblocks_x) .and. & ! southeast corner + (nsfillouter .or. jblock > 1)) then + do j = 1,nghost + do i = 1,nghost + array(ihi+i, jlo-j, :, :, iblk) = fill + enddo + enddo + endif + if ((ewfillouter .or. iblock < nblocks_x) .and. & ! northeast corner + (nsfillouter .or. jblock < nblocks_y)) then + do j = 1,nghost + do i = 1,nghost + array(ihi+i, jhi+j, :, :, iblk) = fill + enddo + enddo + endif + enddo ! iblk !----------------------------------------------------------------------- ! @@ -4778,15 +5376,15 @@ end subroutine ice_HaloMsgCreate subroutine ice_HaloExtrapolate2DR8(ARRAY,dist,ew_bndy_type,ns_bndy_type) -! This subroutine extrapolates ARRAY values into the first row or column -! of ghost cells, and is intended for grid variables whose ghost cells +! This subroutine extrapolates ARRAY values into the ghost cells, +! and is intended for grid variables whose ghost cells ! would otherwise be set using the default boundary conditions (Dirichlet ! or Neumann). -! Note: This routine will need to be modified for nghost > 1. -! We assume padding occurs only on east and north edges. ! ! This is the specific interface for double precision arrays ! corresponding to the generic interface ice_HaloExtrapolate +! +! T.Craig, Oct 2025 - extend to nghost > 1 use ice_blocks, only: block, nblocks_x, nblocks_y, get_block use ice_constants, only: c2 @@ -4809,8 +5407,9 @@ subroutine ice_HaloExtrapolate2DR8(ARRAY,dist,ew_bndy_type,ns_bndy_type) !----------------------------------------------------------------------- integer (int_kind) :: & - i,j,iblk, &! dummy loop indices - numBlocks, &! number of local blocks + i,j,n,iblk,ii,jj, &! dummy loop indices + ilo,ihi,jlo,jhi, &! active block indices + numBlocks, &! number of local blocks blockID, &! block location ibc ! ghost cell column or row @@ -4831,32 +5430,40 @@ subroutine ice_HaloExtrapolate2DR8(ARRAY,dist,ew_bndy_type,ns_bndy_type) do iblk = 1, numBlocks call ice_distributionGetBlockID(dist, iblk, blockID) this_block = get_block(blockID, blockID) + ilo = this_block%ilo + ihi = this_block%ihi + jlo = this_block%jlo + jhi = this_block%jhi if (this_block%iblock == 1) then ! west edge if (trim(ew_bndy_type) /= 'cyclic') then + do n = 1, nghost + ii = ilo - n ! gridcell to extrapolate to do j = 1, ny_block - ARRAY(1,j,iblk) = c2*ARRAY(2,j,iblk) - ARRAY(3,j,iblk) + ARRAY(ii,j,iblk) = c2*ARRAY(ii+1,j,iblk) - ARRAY(ii+2,j,iblk) + enddo enddo endif endif if (this_block%iblock == nblocks_x) then ! east edge if (trim(ew_bndy_type) /= 'cyclic') then - ! locate ghost cell column (avoid padding) - ibc = nx_block - do i = nx_block, nghost + 1, -1 - if (this_block%i_glob(i) == 0) ibc = ibc - 1 - enddo + do n = 1, nghost + ii = ihi + n ! gridcell to extrapolate to do j = 1, ny_block - ARRAY(ibc,j,iblk) = c2*ARRAY(ibc-1,j,iblk) - ARRAY(ibc-2,j,iblk) + ARRAY(ii,j,iblk) = c2*ARRAY(ii-1,j,iblk) - ARRAY(ii-2,j,iblk) + enddo enddo endif endif if (this_block%jblock == 1) then ! south edge if (trim(ns_bndy_type) /= 'cyclic') then + do n = 1, nghost + jj = jlo - n ! gridcell to extrapolate to do i = 1, nx_block - ARRAY(i,1,iblk) = c2*ARRAY(i,2,iblk) - ARRAY(i,3,iblk) + ARRAY(i,jj,iblk) = c2*ARRAY(i,jj+1,iblk) - ARRAY(i,jj+2,iblk) + enddo enddo endif endif @@ -4865,13 +5472,11 @@ subroutine ice_HaloExtrapolate2DR8(ARRAY,dist,ew_bndy_type,ns_bndy_type) if (trim(ns_bndy_type) /= 'cyclic' .and. & trim(ns_bndy_type) /= 'tripole' .and. & trim(ns_bndy_type) /= 'tripoleT' ) then - ! locate ghost cell column (avoid padding) - ibc = ny_block - do j = ny_block, nghost + 1, -1 - if (this_block%j_glob(j) == 0) ibc = ibc - 1 - enddo + do n = 1, nghost + jj = jhi + n ! gridcell to extrapolate to do i = 1, nx_block - ARRAY(i,ibc,iblk) = c2*ARRAY(i,ibc-1,iblk) - ARRAY(i,ibc-2,iblk) + ARRAY(i,jj,iblk) = c2*ARRAY(i,jj-1,iblk) - ARRAY(i,jj-2,iblk) + enddo enddo endif endif diff --git a/cicecore/cicedyn/infrastructure/comm/serial/ice_gather_scatter.F90 b/cicecore/cicedyn/infrastructure/comm/serial/ice_gather_scatter.F90 index 5f4938281..be1845e56 100644 --- a/cicecore/cicedyn/infrastructure/comm/serial/ice_gather_scatter.F90 +++ b/cicecore/cicedyn/infrastructure/comm/serial/ice_gather_scatter.F90 @@ -925,80 +925,40 @@ subroutine scatter_global_dbl(ARRAY, ARRAY_G, src_task, dst_dist, & this_block = get_block(n,n) dst_block = dst_dist%blockLocalID(n) - !*** if this is an interior block, then there is no - !*** padding or update checking required - - if (this_block%iblock > 1 .and. & - this_block%iblock < nblocks_x .and. & - this_block%jblock > 1 .and. & - this_block%jblock < nblocks_y) then - - do j=1,ny_block - do i=1,nx_block - ARRAY(i,j,dst_block) = ARRAY_G(this_block%i_glob(i),& - this_block%j_glob(j)) - end do - end do - - !*** if this is an edge block but not a northern edge - !*** we only need to check for closed boundaries and - !*** padding (global index = 0) - - else if (this_block%jblock /= nblocks_y) then - - do j=1,ny_block - if (this_block%j_glob(j) /= 0) then - do i=1,nx_block - if (this_block%i_glob(i) /= 0) then - ARRAY(i,j,dst_block) = ARRAY_G(this_block%i_glob(i),& - this_block%j_glob(j)) - endif - end do - endif - end do - - !*** if this is a northern edge block, we need to check - !*** for and properly deal with tripole boundaries - - else - - do j=1,ny_block - if (this_block%j_glob(j) > 0) then ! normal boundary - - do i=1,nx_block - if (this_block%i_glob(i) /= 0) then - ARRAY(i,j,dst_block) = ARRAY_G(this_block%i_glob(i),& - this_block%j_glob(j)) - endif - end do - - else if (this_block%j_glob(j) < 0) then ! tripole - - ! for yoffset=0 or 1, yoffset2=0,0 - ! for yoffset=-1, yoffset2=0,1, for u-rows on T-fold grid - do yoffset2=0,max(yoffset,0)-yoffset - jsrc = ny_global + yoffset + yoffset2 + & - (this_block%j_glob(j) + ny_global) - do i=1,nx_block - if (this_block%i_glob(i) /= 0) then - isrc = nx_global + xoffset - this_block%i_glob(i) - if (isrc < 1) isrc = isrc + nx_global - if (isrc > nx_global) isrc = isrc - nx_global - ARRAY(i,j-yoffset2,dst_block) & - = isign * ARRAY_G(isrc,jsrc) - endif - end do - end do - - endif - end do - - endif + do j=1,ny_block + if (this_block%jblock == nblocks_y .and. this_block%j_glob(j) < 0) then + ! tripole is top block with j_glob < 0 + ! for yoffset=0 or 1, yoffset2=0,0 + ! for yoffset=-1, yoffset2=0,1, for u-rows on T-fold grid + do yoffset2=0,max(yoffset,0)-yoffset + jsrc = ny_global + yoffset + yoffset2 + & + (this_block%j_glob(j) + ny_global) + do i=1,nx_block + if (this_block%i_glob(i) /= 0) then + isrc = nx_global + xoffset - this_block%i_glob(i) + if (isrc < 1) isrc = isrc + nx_global + if (isrc > nx_global) isrc = isrc - nx_global + ARRAY(i,j-yoffset2,dst_block) & + = isign * ARRAY_G(isrc,jsrc) + endif + end do + end do + else + ! normal block + do i=1,nx_block + isrc = this_block%i_glob(i) + jsrc = this_block%j_glob(j) + if (isrc >=1 .and. isrc <= nx_global .and. & + jsrc >=1 .and. jsrc <= ny_global) & + ARRAY(i,j,dst_block) = ARRAY_G(isrc,jsrc) + end do + endif + end do endif ! dst block not land end do ! block loop !----------------------------------------------------------------- - ! Ensure unused ghost cell values are 0 + ! Set ghost cell values to 0 for noupdate !----------------------------------------------------------------- if (field_loc == field_loc_noupdate) then @@ -1173,80 +1133,40 @@ subroutine scatter_global_real(ARRAY, ARRAY_G, src_task, dst_dist, & this_block = get_block(n,n) dst_block = dst_dist%blockLocalID(n) - !*** if this is an interior block, then there is no - !*** padding or update checking required - - if (this_block%iblock > 1 .and. & - this_block%iblock < nblocks_x .and. & - this_block%jblock > 1 .and. & - this_block%jblock < nblocks_y) then - - do j=1,ny_block - do i=1,nx_block - ARRAY(i,j,dst_block) = ARRAY_G(this_block%i_glob(i),& - this_block%j_glob(j)) - end do - end do - - !*** if this is an edge block but not a northern edge - !*** we only need to check for closed boundaries and - !*** padding (global index = 0) - - else if (this_block%jblock /= nblocks_y) then - - do j=1,ny_block - if (this_block%j_glob(j) /= 0) then - do i=1,nx_block - if (this_block%i_glob(i) /= 0) then - ARRAY(i,j,dst_block) = ARRAY_G(this_block%i_glob(i),& - this_block%j_glob(j)) - endif - end do - endif - end do - - !*** if this is a northern edge block, we need to check - !*** for and properly deal with tripole boundaries - - else - - do j=1,ny_block - if (this_block%j_glob(j) > 0) then ! normal boundary - - do i=1,nx_block - if (this_block%i_glob(i) /= 0) then - ARRAY(i,j,dst_block) = ARRAY_G(this_block%i_glob(i),& - this_block%j_glob(j)) - endif - end do - - else if (this_block%j_glob(j) < 0) then ! tripole - - ! for yoffset=0 or 1, yoffset2=0,0 - ! for yoffset=-1, yoffset2=0,1, for u-rows on T-fold grid - do yoffset2=0,max(yoffset,0)-yoffset - jsrc = ny_global + yoffset + yoffset2 + & - (this_block%j_glob(j) + ny_global) - do i=1,nx_block - if (this_block%i_glob(i) /= 0) then - isrc = nx_global + xoffset - this_block%i_glob(i) - if (isrc < 1) isrc = isrc + nx_global - if (isrc > nx_global) isrc = isrc - nx_global - ARRAY(i,j-yoffset2,dst_block) & - = isign * ARRAY_G(isrc,jsrc) - endif - end do - end do - - endif - end do - - endif + do j=1,ny_block + if (this_block%jblock == nblocks_y .and. this_block%j_glob(j) < 0) then + ! tripole is top block with j_glob < 0 + ! for yoffset=0 or 1, yoffset2=0,0 + ! for yoffset=-1, yoffset2=0,1, for u-rows on T-fold grid + do yoffset2=0,max(yoffset,0)-yoffset + jsrc = ny_global + yoffset + yoffset2 + & + (this_block%j_glob(j) + ny_global) + do i=1,nx_block + if (this_block%i_glob(i) /= 0) then + isrc = nx_global + xoffset - this_block%i_glob(i) + if (isrc < 1) isrc = isrc + nx_global + if (isrc > nx_global) isrc = isrc - nx_global + ARRAY(i,j-yoffset2,dst_block) & + = isign * ARRAY_G(isrc,jsrc) + endif + end do + end do + else + ! normal block + do i=1,nx_block + isrc = this_block%i_glob(i) + jsrc = this_block%j_glob(j) + if (isrc >=1 .and. isrc <= nx_global .and. & + jsrc >=1 .and. jsrc <= ny_global) & + ARRAY(i,j,dst_block) = ARRAY_G(isrc,jsrc) + end do + endif + end do endif ! dst block not land end do ! block loop !----------------------------------------------------------------- - ! Ensure unused ghost cell values are 0 + ! Set ghost cell values to 0 for noupdate !----------------------------------------------------------------- if (field_loc == field_loc_noupdate) then @@ -1421,80 +1341,40 @@ subroutine scatter_global_int(ARRAY, ARRAY_G, src_task, dst_dist, & this_block = get_block(n,n) dst_block = dst_dist%blockLocalID(n) - !*** if this is an interior block, then there is no - !*** padding or update checking required - - if (this_block%iblock > 1 .and. & - this_block%iblock < nblocks_x .and. & - this_block%jblock > 1 .and. & - this_block%jblock < nblocks_y) then - - do j=1,ny_block - do i=1,nx_block - ARRAY(i,j,dst_block) = ARRAY_G(this_block%i_glob(i),& - this_block%j_glob(j)) - end do - end do - - !*** if this is an edge block but not a northern edge - !*** we only need to check for closed boundaries and - !*** padding (global index = 0) - - else if (this_block%jblock /= nblocks_y) then - - do j=1,ny_block - if (this_block%j_glob(j) /= 0) then - do i=1,nx_block - if (this_block%i_glob(i) /= 0) then - ARRAY(i,j,dst_block) = ARRAY_G(this_block%i_glob(i),& - this_block%j_glob(j)) - endif - end do - endif - end do - - !*** if this is a northern edge block, we need to check - !*** for and properly deal with tripole boundaries - - else - - do j=1,ny_block - if (this_block%j_glob(j) > 0) then ! normal boundary - - do i=1,nx_block - if (this_block%i_glob(i) /= 0) then - ARRAY(i,j,dst_block) = ARRAY_G(this_block%i_glob(i),& - this_block%j_glob(j)) - endif - end do - - else if (this_block%j_glob(j) < 0) then ! tripole - - ! for yoffset=0 or 1, yoffset2=0,0 - ! for yoffset=-1, yoffset2=0,1, for u-rows on T-fold grid - do yoffset2=0,max(yoffset,0)-yoffset - jsrc = ny_global + yoffset + yoffset2 + & - (this_block%j_glob(j) + ny_global) - do i=1,nx_block - if (this_block%i_glob(i) /= 0) then - isrc = nx_global + xoffset - this_block%i_glob(i) - if (isrc < 1) isrc = isrc + nx_global - if (isrc > nx_global) isrc = isrc - nx_global - ARRAY(i,j-yoffset2,dst_block) & - = isign * ARRAY_G(isrc,jsrc) - endif - end do - end do - - endif - end do - - endif + do j=1,ny_block + if (this_block%jblock == nblocks_y .and. this_block%j_glob(j) < 0) then + ! tripole is top block with j_glob < 0 + ! for yoffset=0 or 1, yoffset2=0,0 + ! for yoffset=-1, yoffset2=0,1, for u-rows on T-fold grid + do yoffset2=0,max(yoffset,0)-yoffset + jsrc = ny_global + yoffset + yoffset2 + & + (this_block%j_glob(j) + ny_global) + do i=1,nx_block + if (this_block%i_glob(i) /= 0) then + isrc = nx_global + xoffset - this_block%i_glob(i) + if (isrc < 1) isrc = isrc + nx_global + if (isrc > nx_global) isrc = isrc - nx_global + ARRAY(i,j-yoffset2,dst_block) & + = isign * ARRAY_G(isrc,jsrc) + endif + end do + end do + else + ! normal block + do i=1,nx_block + isrc = this_block%i_glob(i) + jsrc = this_block%j_glob(j) + if (isrc >=1 .and. isrc <= nx_global .and. & + jsrc >=1 .and. jsrc <= ny_global) & + ARRAY(i,j,dst_block) = ARRAY_G(isrc,jsrc) + end do + endif + end do endif ! dst block not land end do ! block loop !----------------------------------------------------------------- - ! Ensure unused ghost cell values are 0 + ! Set ghost cell values to 0 for noupdate !----------------------------------------------------------------- if (field_loc == field_loc_noupdate) then @@ -1570,8 +1450,8 @@ subroutine scatter_global_ext(ARRAY, ARRAY_G, src_task, dst_dist) integer (int_kind) :: & i,j,n, &! dummy loop indices + isrc, jsrc, &! source addresses iblk, jblk, &! source addresses - iglb, jglb, &! global indices dst_block ! local block index in dest distribution type (block) :: & @@ -1618,13 +1498,13 @@ subroutine scatter_global_ext(ARRAY, ARRAY_G, src_task, dst_dist) ! southwest corner iblk = i jblk = j - iglb = this_block%i_glob(this_block%ilo)+i-1 - jglb = j - ARRAY(iblk,jblk,dst_block) = ARRAY_G(iglb,jglb) + isrc = this_block%i_glob(this_block%ilo)+i-1 + jsrc = j + ARRAY(iblk,jblk,dst_block) = ARRAY_G(isrc,jsrc) ! southeast corner iblk = this_block%ihi+i - iglb = this_block%i_glob(this_block%ihi)+nghost+i - ARRAY(iblk,jblk,dst_block) = ARRAY_G(iglb,jglb) + isrc = this_block%i_glob(this_block%ihi)+nghost+i + ARRAY(iblk,jblk,dst_block) = ARRAY_G(isrc,jsrc) enddo enddo endif @@ -1639,13 +1519,13 @@ subroutine scatter_global_ext(ARRAY, ARRAY_G, src_task, dst_dist) ! northwest corner iblk = i jblk = this_block%jhi+j - iglb = this_block%i_glob(this_block%ilo)+i-1 - jglb = ny_global+nghost+j - ARRAY(iblk,jblk,dst_block) = ARRAY_G(iglb,jglb) + isrc = this_block%i_glob(this_block%ilo)+i-1 + jsrc = ny_global+nghost+j + ARRAY(iblk,jblk,dst_block) = ARRAY_G(isrc,jsrc) ! northeast corner iblk = this_block%ihi+i - iglb = this_block%i_glob(this_block%ihi)+nghost+i - ARRAY(iblk,jblk,dst_block) = ARRAY_G(iglb,jglb) + isrc = this_block%i_glob(this_block%ihi)+nghost+i + ARRAY(iblk,jblk,dst_block) = ARRAY_G(isrc,jsrc) enddo enddo endif @@ -1661,13 +1541,13 @@ subroutine scatter_global_ext(ARRAY, ARRAY_G, src_task, dst_dist) ! northwest corner iblk = i jblk = this_block%jhi+j - iglb = i - jglb = this_block%j_glob(this_block%jhi)+nghost+j - ARRAY(iblk,jblk,dst_block) = ARRAY_G(iglb,jglb) + isrc = i + jsrc = this_block%j_glob(this_block%jhi)+nghost+j + ARRAY(iblk,jblk,dst_block) = ARRAY_G(isrc,jsrc) ! southwest corner jblk = j - jglb = this_block%j_glob(this_block%jlo)+j-1 - ARRAY(iblk,jblk,dst_block) = ARRAY_G(iglb,jglb) + jsrc = this_block%j_glob(this_block%jlo)+j-1 + ARRAY(iblk,jblk,dst_block) = ARRAY_G(isrc,jsrc) enddo enddo endif @@ -1684,17 +1564,16 @@ subroutine scatter_global_ext(ARRAY, ARRAY_G, src_task, dst_dist) ! northeast corner iblk = this_block%ihi+i jblk = this_block%jhi+j - iglb = nx_global+nghost+i - jglb = this_block%j_glob(this_block%jhi)+nghost+j - ARRAY(iblk,jblk,dst_block) = ARRAY_G(iglb,jglb) + isrc = nx_global+nghost+i + jsrc = this_block%j_glob(this_block%jhi)+nghost+j + ARRAY(iblk,jblk,dst_block) = ARRAY_G(isrc,jsrc) ! southeast corner jblk = j - jglb = this_block%j_glob(this_block%jlo)+j-1 - ARRAY(iblk,jblk,dst_block) = ARRAY_G(iglb,jglb) + jsrc = this_block%j_glob(this_block%jlo)+j-1 + ARRAY(iblk,jblk,dst_block) = ARRAY_G(isrc,jsrc) enddo enddo endif - endif ! dst block not land end do ! block loop @@ -1775,75 +1654,35 @@ subroutine scatter_global_stress(ARRAY, ARRAY_G1, ARRAY_G2, & this_block = get_block(n,n) dst_block = dst_dist%blockLocalID(n) - !*** if this is an interior block, then there is no - !*** padding or update checking required - - if (this_block%iblock > 1 .and. & - this_block%iblock < nblocks_x .and. & - this_block%jblock > 1 .and. & - this_block%jblock < nblocks_y) then - - do j=1,ny_block - do i=1,nx_block - ARRAY(i,j,dst_block) = ARRAY_G1(this_block%i_glob(i),& - this_block%j_glob(j)) - end do - end do - - !*** if this is an edge block but not a northern edge - !*** we only need to check for closed boundaries and - !*** padding (global index = 0) - - else if (this_block%jblock /= nblocks_y) then - - do j=1,ny_block - if (this_block%j_glob(j) /= 0) then - do i=1,nx_block - if (this_block%i_glob(i) /= 0) then - ARRAY(i,j,dst_block) = ARRAY_G1(this_block%i_glob(i),& - this_block%j_glob(j)) - endif - end do - endif - end do - - !*** if this is a northern edge block, we need to check - !*** for and properly deal with tripole boundaries - - else - - do j=1,ny_block - if (this_block%j_glob(j) > 0) then ! normal boundary - - do i=1,nx_block - if (this_block%i_glob(i) /= 0) then - ARRAY(i,j,dst_block) = ARRAY_G1(this_block%i_glob(i),& - this_block%j_glob(j)) - endif - end do - - else if (this_block%j_glob(j) < 0) then ! tripole - - ! for yoffset=0 or 1, yoffset2=0,0 - ! for yoffset=-1, yoffset2=0,1, for u-rows on T-fold grid - do yoffset2=0,max(yoffset,0)-yoffset - jsrc = ny_global + yoffset + yoffset2 + & - (this_block%j_glob(j) + ny_global) - do i=1,nx_block - if (this_block%i_glob(i) /= 0) then - isrc = nx_global + xoffset - this_block%i_glob(i) - if (isrc < 1) isrc = isrc + nx_global - if (isrc > nx_global) isrc = isrc - nx_global - ARRAY(i,j-yoffset2,dst_block) & - = isign * ARRAY_G2(isrc,jsrc) - endif - end do - end do - - endif - end do - - endif + do j=1,ny_block + if (this_block%jblock == nblocks_y .and. this_block%j_glob(j) < 0) then + ! tripole is top block with j_glob < 0 + ! for yoffset=0 or 1, yoffset2=0,0 + ! for yoffset=-1, yoffset2=0,1, for u-rows on T-fold grid + do yoffset2=0,max(yoffset,0)-yoffset + jsrc = ny_global + yoffset + yoffset2 + & + (this_block%j_glob(j) + ny_global) + do i=1,nx_block + if (this_block%i_glob(i) /= 0) then + isrc = nx_global + xoffset - this_block%i_glob(i) + if (isrc < 1) isrc = isrc + nx_global + if (isrc > nx_global) isrc = isrc - nx_global + ARRAY(i,j-yoffset2,dst_block) & + = isign * ARRAY_G2(isrc,jsrc) + endif + end do + end do + else + ! normal block + do i=1,nx_block + isrc = this_block%i_glob(i) + jsrc = this_block%j_glob(j) + if (isrc >=1 .and. isrc <= nx_global .and. & + jsrc >=1 .and. jsrc <= ny_global) & + ARRAY(i,j,dst_block) = ARRAY_G1(isrc,jsrc) + end do + endif + end do endif ! dst block not land end do ! block loop diff --git a/cicecore/cicedyn/infrastructure/ice_blocks.F90 b/cicecore/cicedyn/infrastructure/ice_blocks.F90 index ccaf23999..513f3c06f 100644 --- a/cicecore/cicedyn/infrastructure/ice_blocks.F90 +++ b/cicecore/cicedyn/infrastructure/ice_blocks.F90 @@ -31,7 +31,13 @@ module ice_blocks tripoleTFlag ! tripole boundary is a T-fold integer (int_kind), dimension(:), pointer :: & - i_glob, j_glob ! global domain location for each point + i_glob, j_glob ! global domain location for each point. + ! valid values between 1:nx_global, 1:ny_global. + ! outside that range may occur in the halo with + ! open or closed bcs or on the tripole. + ! by definition, tripole is only on the north + ! boundary and in that case, the j_glob values + ! will be valid j_glob values with minus sign. end type public :: create_blocks ,& @@ -140,9 +146,23 @@ subroutine create_blocks(nx_global, ny_global, ew_boundary_type, & !---------------------------------------------------------------------- ! -! compute number of blocks and cartesian decomposition -! if the requested block size does not divide the global domain -! size evenly, add additional block space to accomodate padding +! Compute number of blocks and cartesian decomposition. +! If the requested block size does not divide the global domain +! size evenly, add additional block space to accomodate padding. +! +! Compute the global indices for each block including on the halo. +! The global indices go from 1:nx_global and 1:ny_global for +! most of the domain including the halo that's in the internal part +! of the domain. On the outer boundaries, the global indices will +! be wrapped around for the 'cyclic' option and will be given a +! negative value on the north tripole. Padded gridcells will be +! given a global index of zero (0). All other cases will extrapolate +! the global index outside of 1:nx_global, 1:ny_global. That means +! the global index will go from -nghost+1:0 on the lower boundary +! and n*_global+1:n*_global+nghost on the upper boundary and the +! haloUpdate and scatter, for instance, will not fill those values +! in those cases. Other boundary condition methods will fill the +! outer halo values in cases where ice exists on those boundaries. ! !---------------------------------------------------------------------- @@ -206,7 +226,7 @@ subroutine create_blocks(nx_global, ny_global, ew_boundary_type, & all_blocks_ij(iblock,jblock) = n do j=1,ny_block - j_global(j,n) = js - nghost + j - 1 + j_global(j,n) = js - nghost + j - 1 ! simple lower to upper counting !*** southern ghost cells @@ -215,13 +235,13 @@ subroutine create_blocks(nx_global, ny_global, ew_boundary_type, & case ('cyclic') j_global(j,n) = j_global(j,n) + ny_global case ('open') - j_global(j,n) = nghost - j + 1 + ! lower to upper case ('closed') - j_global(j,n) = 0 + ! lower to upper case ('tripole') - j_global(j,n) = nghost - j + 1 ! open + ! lower to upper case ('tripoleT') - j_global(j,n) = -j_global(j,n) + 1 ! open + ! lower to upper case default call abort_ice(subname//' ERROR: unknown n-s bndy type') end select @@ -239,13 +259,13 @@ subroutine create_blocks(nx_global, ny_global, ew_boundary_type, & case ('cyclic') j_global(j,n) = j_global(j,n) - ny_global case ('open') - j_global(j,n) = 2*ny_global - j_global(j,n) + 1 + ! lower to upper case ('closed') - j_global(j,n) = 0 + ! lower to upper case ('tripole') - j_global(j,n) = -j_global(j,n) + j_global(j,n) = -j_global(j,n) ! negative case ('tripoleT') - j_global(j,n) = -j_global(j,n) + j_global(j,n) = -j_global(j,n) ! negative case default call abort_ice(subname//' ERROR: unknown n-s bndy type') end select @@ -262,7 +282,7 @@ subroutine create_blocks(nx_global, ny_global, ew_boundary_type, & all_blocks(n)%j_glob => j_global(:,n) do i=1,nx_block - i_global(i,n) = is - nghost + i - 1 + i_global(i,n) = is - nghost + i - 1 ! left to right counting !*** western ghost cells @@ -271,9 +291,9 @@ subroutine create_blocks(nx_global, ny_global, ew_boundary_type, & case ('cyclic') i_global(i,n) = i_global(i,n) + nx_global case ('open') - i_global(i,n) = nghost - i + 1 + ! left to right case ('closed') - i_global(i,n) = 0 + ! left to right case default call abort_ice(subname//' ERROR: unknown e-w bndy type') end select @@ -291,9 +311,9 @@ subroutine create_blocks(nx_global, ny_global, ew_boundary_type, & case ('cyclic') i_global(i,n) = i_global(i,n) - nx_global case ('open') - i_global(i,n) = 2*nx_global - i_global(i,n) + 1 + ! left to right case ('closed') - i_global(i,n) = 0 + ! left to right case default call abort_ice(subname//' ERROR: unknown e-w bndy type') end select diff --git a/cicecore/cicedyn/infrastructure/ice_domain.F90 b/cicecore/cicedyn/infrastructure/ice_domain.F90 index 86d6a1939..9a0941e19 100644 --- a/cicecore/cicedyn/infrastructure/ice_domain.F90 +++ b/cicecore/cicedyn/infrastructure/ice_domain.F90 @@ -44,7 +44,7 @@ module ice_domain nblocks ! actual number of blocks on this processor logical (kind=log_kind), public :: & - close_boundaries + close_boundaries ! deprecated Nov, 2025 integer (int_kind), dimension(:), pointer, public :: & blocks_ice => null() ! block ids for local blocks @@ -371,100 +371,11 @@ subroutine init_domain_distribution(KMTG,ULATG,grid_ice) character(len=*), parameter :: subname = '(init_domain_distribution)' -!---------------------------------------------------------------------- -! -! check that there are at least nghost+1 rows or columns of land cells -! for closed boundary conditions (otherwise grid lengths are zero in -! cells neighboring ocean points). -! -!---------------------------------------------------------------------- - call icepack_query_parameters(puny_out=puny, rad_to_deg_out=rad_to_deg) call icepack_warnings_flush(nu_diag) if (icepack_warnings_aborted()) call abort_ice(error_message=subname, & file=__FILE__, line=__LINE__) - if (trim(ns_boundary_type) == 'closed') then - call abort_ice(subname//' ERROR: ns_boundary_type = closed not supported', file=__FILE__, line=__LINE__) - allocate(nocn(nblocks_tot)) - nocn = 0 - do n=1,nblocks_tot - this_block = get_block(n,n) - if (this_block%jblock == nblocks_y) then ! north edge - do j = this_block%jhi-1, this_block%jhi - if (this_block%j_glob(j) > 0) then - do i = 1, nx_block - if (this_block%i_glob(i) > 0) then - ig = this_block%i_glob(i) - jg = this_block%j_glob(j) - if (KMTG(ig,jg) > puny) nocn(n) = nocn(n) + 1 - endif - enddo - endif - enddo - endif - if (this_block%jblock == 1) then ! south edge - do j = this_block%jlo, this_block%jlo+1 - if (this_block%j_glob(j) > 0) then - do i = 1, nx_block - if (this_block%i_glob(i) > 0) then - ig = this_block%i_glob(i) - jg = this_block%j_glob(j) - if (KMTG(ig,jg) > puny) nocn(n) = nocn(n) + 1 - endif - enddo - endif - enddo - endif - if (nocn(n) > 0) then - write(nu_diag,*) subname,'ns closed, Not enough land cells along ns edge' - call abort_ice(subname//' ERROR: Not enough land cells along ns edge for ns closed', & - file=__FILE__, line=__LINE__) - endif - enddo - deallocate(nocn) - endif - if (trim(ew_boundary_type) == 'closed') then - call abort_ice(subname//' ERROR: ew_boundary_type = closed not supported', file=__FILE__, line=__LINE__) - allocate(nocn(nblocks_tot)) - nocn = 0 - do n=1,nblocks_tot - this_block = get_block(n,n) - if (this_block%iblock == nblocks_x) then ! east edge - do j = 1, ny_block - if (this_block%j_glob(j) > 0) then - do i = this_block%ihi-1, this_block%ihi - if (this_block%i_glob(i) > 0) then - ig = this_block%i_glob(i) - jg = this_block%j_glob(j) - if (KMTG(ig,jg) > puny) nocn(n) = nocn(n) + 1 - endif - enddo - endif - enddo - endif - if (this_block%iblock == 1) then ! west edge - do j = 1, ny_block - if (this_block%j_glob(j) > 0) then - do i = this_block%ilo, this_block%ilo+1 - if (this_block%i_glob(i) > 0) then - ig = this_block%i_glob(i) - jg = this_block%j_glob(j) - if (KMTG(ig,jg) > puny) nocn(n) = nocn(n) + 1 - endif - enddo - endif - enddo - endif - if (nocn(n) > 0) then - write(nu_diag,*) subname,'ew closed, Not enough land cells along ew edge' - call abort_ice(subname//' ERROR: Not enough land cells along ew edge for ew closed', & - file=__FILE__, line=__LINE__) - endif - enddo - deallocate(nocn) - endif - !---------------------------------------------------------------------- ! ! estimate the amount of work per processor using the topography @@ -519,11 +430,11 @@ subroutine init_domain_distribution(KMTG,ULATG,grid_ice) do n=1,nblocks_tot this_block = get_block(n,n) do j=this_block%jlo,this_block%jhi - if (this_block%j_glob(j) > 0) then + jg = this_block%j_glob(j) + if (jg > 0) then do i=this_block%ilo,this_block%ihi - if (this_block%i_glob(i) > 0) then - ig = this_block%i_glob(i) - jg = this_block%j_glob(j) + ig = this_block%i_glob(i) + if (ig > 0) then ! if (KMTG(ig,jg) > puny) & ! nocn(n) = max(nocn(n),nint(wght(ig,jg)+1.0_dbl_kind)) if (KMTG(ig,jg) > puny) then @@ -544,11 +455,11 @@ subroutine init_domain_distribution(KMTG,ULATG,grid_ice) do n=1,nblocks_tot this_block = get_block(n,n) do j=this_block%jlo,this_block%jhi - if (this_block%j_glob(j) > 0) then + jg = this_block%j_glob(j) + if (jg > 0) then do i=this_block%ilo,this_block%ihi - if (this_block%i_glob(i) > 0) then - ig = this_block%i_glob(i) - jg = this_block%j_glob(j) + ig = this_block%i_glob(i) + if (ig > 0) then if (grid_ice == 'C' .or. grid_ice == 'CD') then ! Have to be careful about block elimination with C/CD ! Use a bigger stencil diff --git a/cicecore/cicedyn/infrastructure/ice_grid.F90 b/cicecore/cicedyn/infrastructure/ice_grid.F90 index 4ae5448f5..406cff6d2 100644 --- a/cicecore/cicedyn/infrastructure/ice_grid.F90 +++ b/cicecore/cicedyn/infrastructure/ice_grid.F90 @@ -33,11 +33,10 @@ module ice_grid use ice_blocks, only: block, get_block, nx_block, ny_block, nghost use ice_domain_size, only: nx_global, ny_global, max_blocks use ice_domain, only: blocks_ice, nblocks, halo_info, distrb_info, & - ew_boundary_type, ns_boundary_type, init_domain_distribution, & - close_boundaries + ew_boundary_type, ns_boundary_type, init_domain_distribution use ice_fileunits, only: nu_diag, nu_grid, nu_kmt, & get_fileunit, release_fileunit, flush_fileunit - use ice_gather_scatter, only: gather_global, scatter_global + use ice_gather_scatter, only: gather_global, scatter_global, gather_global_ext use ice_read_write, only: ice_read, ice_read_nc, ice_read_global, & ice_read_global_nc, ice_open, ice_open_nc, ice_close_nc, ice_check_nc use ice_timers, only: timer_bound, ice_timer_start, ice_timer_stop @@ -253,7 +252,62 @@ subroutine alloc_grid stat=ierr) if (ierr/=0) call abort_ice(subname//' ERROR: Out of memory1', file=__FILE__, line=__LINE__) + dxT = c0 + dyT = c0 + dxU = c0 + dyU = c0 + dxN = c0 + dyN = c0 + dxE = c0 + dyE = c0 + HTE = c0 + HTN = c0 + tarea = c0 + uarea = c0 + narea = c0 + earea = c0 + tarear = c0 + uarear = c0 + narear = c0 + earear = c0 + tarean = c0 + tareas = c0 + ULON = c0 + ULAT = c0 + TLON = c0 + TLAT = c0 + NLON = c0 + NLAT = c0 + ELON = c0 + ELAT = c0 + ANGLE = c0 + ANGLET = c0 + bathymetry = c0 ocn_gridcell_frac(:,:,:) = -c1 ! special value to start, will be ignored unless set elsewhere + hm = c0 + bm = c0 + uvm = c0 + npm = c0 + epm = c0 + kmt = c0 + tmask = .false. + umask = .false. + umaskCD = .false. + nmask = .false. + emask = .false. + opmask = .false. + lmask_n = .false. + lmask_s = .false. + rndex_global = c0 + lont_bounds = c0 + latt_bounds = c0 + lonu_bounds = c0 + latu_bounds = c0 + lonn_bounds = c0 + latn_bounds = c0 + lone_bounds = c0 + late_bounds = c0 + if (save_ghte_ghtn) then if (my_task == master_task) then @@ -268,6 +322,8 @@ subroutine alloc_grid stat=ierr) endif if (ierr/=0) call abort_ice(subname//' ERROR: Out of memory3', file=__FILE__, line=__LINE__) + G_HTE = c0 + G_HTN = c0 endif end subroutine alloc_grid @@ -595,14 +651,8 @@ subroutine init_grid2 !----------------------------------------------------------------- if (trim(grid_format) /= 'mom_nc') then - !$OMP PARALLEL DO PRIVATE(iblk,i,j,ilo,ihi,jlo,jhi,this_block) + !$OMP PARALLEL DO PRIVATE(iblk,i,j) do iblk = 1, nblocks - this_block = get_block(blocks_ice(iblk),iblk) - ilo = this_block%ilo - ihi = this_block%ihi - jlo = this_block%jlo - jhi = this_block%jhi - do j = 1,ny_block do i = 1,nx_block tarea(i,j,iblk) = dxT(i,j,iblk)*dyT(i,j,iblk) @@ -615,13 +665,8 @@ subroutine init_grid2 !$OMP END PARALLEL DO endif - !$OMP PARALLEL DO PRIVATE(iblk,i,j,ilo,ihi,jlo,jhi,this_block) + !$OMP PARALLEL DO PRIVATE(iblk,i,j) do iblk = 1, nblocks - this_block = get_block(blocks_ice(iblk),iblk) - ilo = this_block%ilo - ihi = this_block%ihi - jlo = this_block%jlo - jhi = this_block%jhi do j = 1,ny_block do i = 1,nx_block @@ -959,6 +1004,8 @@ subroutine popgrid call ice_read_global(nu_grid,7,work_g1,'rda8',.true.) ! ANGLE call scatter_global(ANGLE, work_g1, master_task, distrb_info, & field_loc_NEcorner, field_type_angle) + call ice_HaloExtrapolate(ANGLE, distrb_info, & + ew_boundary_type, ns_boundary_type) !----------------------------------------------------------------- ! cell dimensions @@ -1061,6 +1108,8 @@ subroutine popgrid_nc call ice_read_global_nc(fid_grid,1,fieldname,work_g1,diag) ! ANGLE call scatter_global(ANGLE, work_g1, master_task, distrb_info, & field_loc_NEcorner, field_type_angle) + call ice_HaloExtrapolate(ANGLE, distrb_info, & + ew_boundary_type, ns_boundary_type) ! fix ANGLE: roundoff error due to single precision where (ANGLE > pi) ANGLE = pi where (ANGLE < -pi) ANGLE = -pi @@ -1081,16 +1130,22 @@ subroutine popgrid_nc call ice_read_global_nc(fid_grid,1,fieldname,work_g1,diag) call scatter_global(ANGLET, work_g1, master_task, distrb_info, & field_loc_center, field_type_angle) + call ice_HaloExtrapolate(ANGLET, distrb_info, & + ew_boundary_type, ns_boundary_type) where (ANGLET > pi) ANGLET = pi where (ANGLET < -pi) ANGLET = -pi fieldname="tlon" call ice_read_global_nc(fid_grid,1,fieldname,work_g1,diag) call scatter_global(TLON, work_g1, master_task, distrb_info, & field_loc_center, field_type_scalar) + call ice_HaloExtrapolate(TLON, distrb_info, & + ew_boundary_type, ns_boundary_type) fieldname="tlat" call ice_read_global_nc(fid_grid,1,fieldname,work_g1,diag) call scatter_global(TLAT, work_g1, master_task, distrb_info, & field_loc_center, field_type_scalar) + call ice_HaloExtrapolate(TLAT, distrb_info, & + ew_boundary_type, ns_boundary_type) endif !----------------------------------------------------------------- ! cell dimensions @@ -1487,9 +1542,13 @@ subroutine mom_grid call mom_grid_rotation_angle(G_ULON, G_ULAT, G_TLON(1:nx_global,1:ny_global), work_g1) ! anglet call scatter_global(ANGLET, work_g1, master_task, distrb_info, & field_loc_center, field_type_angle) + call ice_HaloExtrapolate(ANGLET, distrb_info, & + ew_boundary_type, ns_boundary_type) call mom_grid_rotation_angle(G_TLON, G_TLAT, G_ULON(2:nx_global+1,2:ny_global+1), work_g1) ! angle call scatter_global(ANGLE, work_g1, master_task, distrb_info, & field_loc_NEcorner, field_type_angle) + call ice_HaloExtrapolate(ANGLE, distrb_info, & + ew_boundary_type, ns_boundary_type) deallocate(work_g1, G_ULAT, G_TLAT, G_TLON, G_ULON, stat=ierr) if (ierr/=0) call abort_ice(subname//' ERROR: Dealloc error', file=__FILE__, line=__LINE__) @@ -1792,26 +1851,28 @@ subroutine mom_dx(work_mom) jm1 = jm1 + 2 ; jm2 = jm2 + 2 enddo endif - - if (save_ghte_ghtn) then - do j = 1, ny_global - do i = 1, nx_global - G_HTN(i+nghost,j+nghost) = G_dxN(i,j) - enddo - enddo - call global_ext_halo(G_HTN) - endif endif call scatter_global(dxT, G_dxT, master_task, distrb_info, & field_loc_center, field_type_scalar) + call ice_HaloExtrapolate(dxT, distrb_info, & + ew_boundary_type, ns_boundary_type) call scatter_global(HTN, G_dxN, master_task, distrb_info, & field_loc_Nface, field_type_scalar) + call ice_HaloExtrapolate(HTN, distrb_info, & + ew_boundary_type, ns_boundary_type) + if (save_ghte_ghtn) then + call gather_global_ext(G_HTN, HTN, master_task, distrb_info) + endif dxN(:,:,:) = HTN(:,:,:) call scatter_global(dxE, G_dxE, master_task, distrb_info, & field_loc_center, field_type_scalar) + call ice_HaloExtrapolate(dxE, distrb_info, & + ew_boundary_type, ns_boundary_type) call scatter_global(dxU, G_dxU, master_task, distrb_info, & field_loc_NEcorner, field_type_scalar) + call ice_HaloExtrapolate(dxU, distrb_info, & + ew_boundary_type, ns_boundary_type) deallocate(G_dxT, G_dxE, G_dxU, G_dxN, stat=ierr) if (ierr/=0) call abort_ice(subname//' ERROR: Dealloc error', file=__FILE__, line=__LINE__) @@ -1890,26 +1951,28 @@ subroutine mom_dy(work_mom) im1 = im1 + 2 ; im2 = im2 + 2 enddo endif - - if (save_ghte_ghtn) then - do j = 1, ny_global - do i = 1, nx_global - G_HTE(i+nghost,j+nghost) = G_dyE(i,j) - enddo - enddo - call global_ext_halo(G_HTE) - endif endif call scatter_global(dyT, G_dyT, master_task, distrb_info, & - field_loc_center, field_type_scalar) + field_loc_center, field_type_scalar) + call ice_HaloExtrapolate(dyT, distrb_info, & + ew_boundary_type, ns_boundary_type) call scatter_global(dyN, G_dyN, master_task, distrb_info, & field_loc_Nface, field_type_scalar) + call ice_HaloExtrapolate(dyN, distrb_info, & + ew_boundary_type, ns_boundary_type) call scatter_global(HTE, G_dyE, master_task, distrb_info, & field_loc_center, field_type_scalar) + call ice_HaloExtrapolate(HTE, distrb_info, & + ew_boundary_type, ns_boundary_type) + if (save_ghte_ghtn) then + call gather_global_ext(G_HTE, HTE, master_task, distrb_info) + endif dyE(:,:,:) = HTE(:,:,:) call scatter_global(dyU, G_dyU, master_task, distrb_info, & field_loc_NEcorner, field_type_scalar) + call ice_HaloExtrapolate(dyU, distrb_info, & + ew_boundary_type, ns_boundary_type) deallocate(G_dyT, G_dyN, G_dyE, G_dyU) if (ierr/=0) call abort_ice(subname//' ERROR: Dealloc error', file=__FILE__, line=__LINE__) @@ -2189,6 +2252,8 @@ subroutine geosgrid_nc call ice_read_global_nc(fid_grid,1,fieldname,work_g1,diag) ! ANGLE call scatter_global(ANGLE, work_g1, master_task, distrb_info, & field_loc_NEcorner, field_type_angle) + call ice_HaloExtrapolate(ANGLE, distrb_info, & + ew_boundary_type, ns_boundary_type) ! fix ANGLE: roundoff error due to single precision where (ANGLE > pi) ANGLE = pi where (ANGLE < -pi) ANGLE = -pi @@ -2209,16 +2274,22 @@ subroutine geosgrid_nc call ice_read_global_nc(fid_grid,1,fieldname,work_g1,diag) call scatter_global(ANGLET, work_g1, master_task, distrb_info, & field_loc_center, field_type_angle) + call ice_HaloExtrapolate(ANGLET, distrb_info, & + ew_boundary_type, ns_boundary_type) where (ANGLET > pi) ANGLET = pi where (ANGLET < -pi) ANGLET = -pi fieldname="tlon" call ice_read_global_nc(fid_grid,1,fieldname,work_g1,diag) call scatter_global(TLON, work_g1, master_task, distrb_info, & field_loc_center, field_type_scalar) + call ice_HaloExtrapolate(TLON, distrb_info, & + ew_boundary_type, ns_boundary_type) fieldname="tlat" call ice_read_global_nc(fid_grid,1,fieldname,work_g1,diag) call scatter_global(TLAT, work_g1, master_task, distrb_info, & field_loc_center, field_type_scalar) + call ice_HaloExtrapolate(TLAT, distrb_info, & + ew_boundary_type, ns_boundary_type) endif !----------------------------------------------------------------- ! cell dimensions @@ -2358,6 +2429,10 @@ subroutine rectgrid call grid_boxislands_kmt(work_g1) + elseif (trim(kmt_type) == 'none') then + + work_g1(:,:) = c1 ! initialize hm as ocean + elseif (trim(kmt_type) == 'channel') then do j = 3,ny_global-2 ! closed top and bottom @@ -2426,12 +2501,14 @@ subroutine rectgrid endif ! kmt_type - if (close_boundaries) then - work_g1(:, 1:2) = c0 - work_g1(:, ny_global-1:ny_global) = c0 + if (ew_boundary_type == 'closed') then work_g1(1:2, :) = c0 work_g1(nx_global-1:nx_global, :) = c0 endif + if (ns_boundary_type == 'closed') then + work_g1(:, 1:2) = c0 + work_g1(:, ny_global-1:ny_global) = c0 + endif endif @@ -2597,7 +2674,6 @@ subroutine rectgrid_scale_dxdy call ice_HaloExtrapolate(ULAT, distrb_info, & ew_boundary_type, ns_boundary_type) - deallocate(work_g1) end subroutine rectgrid_scale_dxdy @@ -2775,19 +2851,18 @@ subroutine primary_grid_lengths_HTN(work_g) work_g2(i,j) = p5*(work_g(i,j) + work_g(ip1,j)) ! dxU enddo enddo - if (save_ghte_ghtn) then - do j = 1, ny_global - do i = 1,nx_global - G_HTN(i+nghost,j+nghost) = work_g(i,j) - enddo - enddo - call global_ext_halo(G_HTN) - endif endif call scatter_global(HTN, work_g, master_task, distrb_info, & field_loc_Nface, field_type_scalar) + call ice_HaloExtrapolate(HTN, distrb_info, & + ew_boundary_type, ns_boundary_type) + if (save_ghte_ghtn) then + call gather_global_ext(G_HTN, HTN, master_task, distrb_info) + endif call scatter_global(dxU, work_g2, master_task, distrb_info, & field_loc_NEcorner, field_type_scalar) + call ice_HaloExtrapolate(dxU, distrb_info, & + ew_boundary_type, ns_boundary_type) ! dxT = average of 2 neighbor HTNs in j @@ -2804,6 +2879,8 @@ subroutine primary_grid_lengths_HTN(work_g) endif call scatter_global(dxT, work_g2, master_task, distrb_info, & field_loc_center, field_type_scalar) + call ice_HaloExtrapolate(dxT, distrb_info, & + ew_boundary_type, ns_boundary_type) ! dxN = HTN @@ -2831,6 +2908,8 @@ subroutine primary_grid_lengths_HTN(work_g) endif call scatter_global(dxE, work_g2, master_task, distrb_info, & field_loc_center, field_type_scalar) + call ice_HaloExtrapolate(dxE, distrb_info, & + ew_boundary_type, ns_boundary_type) deallocate(work_g2, stat=ierr) if (ierr/=0) call abort_ice(subname//' ERROR: Dealloc error', file=__FILE__, line=__LINE__) @@ -2886,19 +2965,18 @@ subroutine primary_grid_lengths_HTE(work_g) work_g2(i,ny_global) = c2*work_g(i,ny_global-1) - work_g(i,ny_global-2) ! dyU enddo endif - if (save_ghte_ghtn) then - do j = 1, ny_global - do i = 1, nx_global - G_HTE(i+nghost,j+nghost) = work_g(i,j) - enddo - enddo - call global_ext_halo(G_HTE) - endif endif call scatter_global(HTE, work_g, master_task, distrb_info, & field_loc_Eface, field_type_scalar) + call ice_HaloExtrapolate(HTE, distrb_info, & + ew_boundary_type, ns_boundary_type) + if (save_ghte_ghtn) then + call gather_global_ext(G_HTE, HTE, master_task, distrb_info) + endif call scatter_global(dyU, work_g2, master_task, distrb_info, & field_loc_NEcorner, field_type_scalar) + call ice_HaloExtrapolate(dyU, distrb_info, & + ew_boundary_type, ns_boundary_type) ! dyT = average of 2 neighbor HTE in i @@ -2914,6 +2992,8 @@ subroutine primary_grid_lengths_HTE(work_g) endif call scatter_global(dyT, work_g2, master_task, distrb_info, & field_loc_center, field_type_scalar) + call ice_HaloExtrapolate(dyT, distrb_info, & + ew_boundary_type, ns_boundary_type) ! dyN = average of 4 neighbor HTEs @@ -2939,6 +3019,8 @@ subroutine primary_grid_lengths_HTE(work_g) endif call scatter_global(dyN, work_g2, master_task, distrb_info, & field_loc_center, field_type_scalar) + call ice_HaloExtrapolate(dyN, distrb_info, & + ew_boundary_type, ns_boundary_type) ! dyE = HTE diff --git a/cicecore/cicedyn/infrastructure/ice_read_write.F90 b/cicecore/cicedyn/infrastructure/ice_read_write.F90 index a6489473c..62545c3f3 100644 --- a/cicecore/cicedyn/infrastructure/ice_read_write.F90 +++ b/cicecore/cicedyn/infrastructure/ice_read_write.F90 @@ -1146,18 +1146,23 @@ subroutine ice_read_nc_xy(fid, nrec, varname, work, diag, & integer (kind=int_kind) :: lnrec ! local value of nrec - lnrec = nrec + logical (kind=log_kind) :: lrestart_ext ! local value of restart_ext - nx = nx_global - ny = ny_global + lnrec = nrec work = c0 ! to satisfy intent(out) attribute + lrestart_ext = .false. if (present(restart_ext)) then - if (restart_ext) then - nx = nx_global + 2*nghost - ny = ny_global + 2*nghost - endif + lrestart_ext = restart_ext + endif + + if (lrestart_ext) then + nx = nx_global + 2*nghost + ny = ny_global + 2*nghost + else + nx = nx_global + ny = ny_global endif if (my_task == master_task) then @@ -1243,10 +1248,8 @@ subroutine ice_read_nc_xy(fid, nrec, varname, work, diag, & ! NOTE: Ghost cells are not updated unless field_loc is present. !------------------------------------------------------------------- - if (present(restart_ext)) then - if (restart_ext) then - call scatter_global_ext(work, work_g1, master_task, distrb_info) - endif + if (lrestart_ext) then + call scatter_global_ext(work, work_g1, master_task, distrb_info) else if (present(field_loc)) then call scatter_global(work, work_g1, master_task, distrb_info, & @@ -1336,16 +1339,21 @@ subroutine ice_read_nc_xyz(fid, nrec, varname, work, diag, & integer (kind=int_kind) :: lnrec ! local value of nrec - lnrec = nrec + logical (kind=log_kind) :: lrestart_ext ! local value of restart_ext - nx = nx_global - ny = ny_global + lnrec = nrec + lrestart_ext = .false. if (present(restart_ext)) then - if (restart_ext) then - nx = nx_global + 2*nghost - ny = ny_global + 2*nghost - endif + lrestart_ext = restart_ext + endif + + if (lrestart_ext) then + nx = nx_global + 2*nghost + ny = ny_global + 2*nghost + else + nx = nx_global + ny = ny_global endif if (my_task == master_task) then @@ -1432,13 +1440,11 @@ subroutine ice_read_nc_xyz(fid, nrec, varname, work, diag, & ! NOTE: Ghost cells are not updated unless field_loc is present. !------------------------------------------------------------------- - if (present(restart_ext)) then - if (restart_ext) then - do n=1,ncat - call scatter_global_ext(work(:,:,n,:), work_g1(:,:,n), & - master_task, distrb_info) - enddo - endif + if (lrestart_ext) then + do n=1,ncat + call scatter_global_ext(work(:,:,n,:), work_g1(:,:,n), & + master_task, distrb_info) + enddo else if (present(field_loc)) then do n=1,ncat @@ -1532,20 +1538,25 @@ subroutine ice_read_nc_xyf(fid, nrec, varname, work, diag, & integer (kind=int_kind) :: lnrec ! local value of nrec + logical (kind=log_kind) :: lrestart_ext ! local value of restart_ext + character(len=*), parameter :: subname = '(ice_read_nc_xyf)' #ifdef USE_NETCDF lnrec = nrec - nx = nx_global - ny = ny_global - + lrestart_ext = .false. if (present(restart_ext)) then - if (restart_ext) then - nx = nx_global + 2*nghost - ny = ny_global + 2*nghost - endif + lrestart_ext = restart_ext + endif + + if (lrestart_ext) then + nx = nx_global + 2*nghost + ny = ny_global + 2*nghost + else + nx = nx_global + ny = ny_global endif if (my_task == master_task) then @@ -1632,13 +1643,11 @@ subroutine ice_read_nc_xyf(fid, nrec, varname, work, diag, & ! NOTE: Ghost cells are not updated unless field_loc is present. !------------------------------------------------------------------- - if (present(restart_ext)) then - if (restart_ext) then - do n = 1, nfreq - call scatter_global_ext(work(:,:,n,1,:), work_g1(:,:,n), & - master_task, distrb_info) - enddo - endif + if (lrestart_ext) then + do n = 1, nfreq + call scatter_global_ext(work(:,:,n,1,:), work_g1(:,:,n), & + master_task, distrb_info) + enddo else if (present(field_loc)) then do n = 1, nfreq @@ -2214,14 +2223,19 @@ subroutine ice_write_nc_xy(fid, nrec, varid, work, diag, & integer (kind=int_kind) :: nx, ny - nx = nx_global - ny = ny_global + logical (kind=log_kind) :: lrestart_ext ! local value of restart_ext + lrestart_ext = .false. if (present(restart_ext)) then - if (restart_ext) then - nx = nx_global + 2*nghost - ny = ny_global + 2*nghost - endif + lrestart_ext = restart_ext + endif + + if (lrestart_ext) then + nx = nx_global + 2*nghost + ny = ny_global + 2*nghost + else + nx = nx_global + ny = ny_global endif if (present(varname)) then @@ -2236,10 +2250,8 @@ subroutine ice_write_nc_xy(fid, nrec, varid, work, diag, & allocate(work_g1(1,1)) ! to save memory endif - if (present(restart_ext)) then - if (restart_ext) then - call gather_global_ext(work_g1, work, master_task, distrb_info, spc_val=c0) - endif + if (lrestart_ext) then + call gather_global_ext(work_g1, work, master_task, distrb_info, spc_val=c0) else call gather_global(work_g1, work, master_task, distrb_info, spc_val=c0) endif @@ -2338,14 +2350,19 @@ subroutine ice_write_nc_xyz(fid, nrec, varid, work, diag, & integer (kind=int_kind) :: nx, ny - nx = nx_global - ny = ny_global + logical (kind=log_kind) :: lrestart_ext ! local value of restart_ext + lrestart_ext = .false. if (present(restart_ext)) then - if (restart_ext) then - nx = nx_global + 2*nghost - ny = ny_global + 2*nghost - endif + lrestart_ext = restart_ext + endif + + if (lrestart_ext) then + nx = nx_global + 2*nghost + ny = ny_global + 2*nghost + else + nx = nx_global + ny = ny_global endif if (my_task == master_task) then @@ -2354,13 +2371,11 @@ subroutine ice_write_nc_xyz(fid, nrec, varid, work, diag, & allocate(work_g1(1,1,ncat)) ! to save memory endif - if (present(restart_ext)) then - if (restart_ext) then - do n=1,ncat - call gather_global_ext(work_g1(:,:,n), work(:,:,n,:), & - master_task, distrb_info, spc_val=c0) - enddo - endif + if (lrestart_ext) then + do n=1,ncat + call gather_global_ext(work_g1(:,:,n), work(:,:,n,:), & + master_task, distrb_info, spc_val=c0) + enddo else do n=1,ncat call gather_global(work_g1(:,:,n), work(:,:,n,:), & @@ -2664,14 +2679,19 @@ subroutine ice_read_nc_uv(fid, nrec, nzlev, varname, work, diag, & integer (kind=int_kind) :: nx, ny - nx = nx_global - ny = ny_global + logical (kind=log_kind) :: lrestart_ext ! local value of restart_ext + lrestart_ext = .false. if (present(restart_ext)) then - if (restart_ext) then - nx = nx_global + 2*nghost - ny = ny_global + 2*nghost - endif + lrestart_ext = restart_ext + endif + + if (lrestart_ext) then + nx = nx_global + 2*nghost + ny = ny_global + 2*nghost + else + nx = nx_global + ny = ny_global endif if (my_task == master_task) then @@ -2717,10 +2737,8 @@ subroutine ice_read_nc_uv(fid, nrec, nzlev, varname, work, diag, & ! NOTE: Ghost cells are not updated unless field_loc is present. !------------------------------------------------------------------- - if (present(restart_ext)) then - if (restart_ext) then - call scatter_global_ext(work, work_g1, master_task, distrb_info) - endif + if (lrestart_ext) then + call scatter_global_ext(work, work_g1, master_task, distrb_info) else if (present(field_loc)) then call scatter_global(work, work_g1, master_task, distrb_info, & diff --git a/cicecore/cicedyn/infrastructure/io/io_netcdf/ice_restart.F90 b/cicecore/cicedyn/infrastructure/io/io_netcdf/ice_restart.F90 index db6aa80bf..1c25e3f30 100644 --- a/cicecore/cicedyn/infrastructure/io/io_netcdf/ice_restart.F90 +++ b/cicecore/cicedyn/infrastructure/io/io_netcdf/ice_restart.F90 @@ -10,6 +10,7 @@ module ice_restart use ice_broadcast + use ice_constants, only: c0 use ice_communicate, only: my_task, master_task use ice_kinds_mod #ifdef USE_NETCDF @@ -748,39 +749,25 @@ subroutine read_restart_field(nu,nrec,work,atype,vname,ndim3, & character(len=*), parameter :: subname = '(read_restart_field)' + work (:,:,:,:) = c0 + work2(:,:,:) = c0 #ifdef USE_NETCDF if (present(field_loc)) then if (ndim3 == ncat) then - if (restart_ext) then - call ice_read_nc(ncid,1,vname,work,diag, & - field_loc=field_loc,field_type=field_type,restart_ext=restart_ext) - else - call ice_read_nc(ncid,1,vname,work,diag,field_loc,field_type) - endif + call ice_read_nc(ncid,1,vname,work,diag, & + field_loc=field_loc,field_type=field_type,restart_ext=restart_ext) elseif (ndim3 == 1) then - if (restart_ext) then - call ice_read_nc(ncid,1,vname,work2,diag, & - field_loc=field_loc,field_type=field_type,restart_ext=restart_ext) - else - call ice_read_nc(ncid,1,vname,work2,diag,field_loc,field_type) - endif + call ice_read_nc(ncid,1,vname,work2,diag, & + field_loc=field_loc,field_type=field_type,restart_ext=restart_ext) work(:,:,1,:) = work2(:,:,:) else write(nu_diag,*) 'ndim3 not supported ',ndim3 endif else if (ndim3 == ncat) then - if (restart_ext) then - call ice_read_nc(ncid, 1, vname, work, diag, restart_ext=restart_ext) - else - call ice_read_nc(ncid, 1, vname, work, diag) - endif + call ice_read_nc(ncid, 1, vname, work, diag, restart_ext=restart_ext) elseif (ndim3 == 1) then - if (restart_ext) then - call ice_read_nc(ncid, 1, vname, work2, diag, restart_ext=restart_ext) - else - call ice_read_nc(ncid, 1, vname, work2, diag) - endif + call ice_read_nc(ncid, 1, vname, work2, diag, restart_ext=restart_ext) work(:,:,1,:) = work2(:,:,:) else write(nu_diag,*) 'ndim3 not supported ',ndim3 @@ -841,18 +828,10 @@ subroutine write_restart_field(nu,nrec,work,atype,vname,ndim3,diag) call ice_check_nc(status, subname//' ERROR: inq varid '//trim(vname), file=__FILE__, line=__LINE__) endif if (ndim3 == ncat) then - if (restart_ext) then - call ice_write_nc(ncid, 1, varid, work, diag, restart_ext, varname=trim(vname)) - else - call ice_write_nc(ncid, 1, varid, work, diag, varname=trim(vname)) - endif + call ice_write_nc(ncid, 1, varid, work, diag, restart_ext, varname=trim(vname)) elseif (ndim3 == 1) then work2(:,:,:) = work(:,:,1,:) - if (restart_ext) then - call ice_write_nc(ncid, 1, varid, work2, diag, restart_ext, varname=trim(vname)) - else - call ice_write_nc(ncid, 1, varid, work2, diag, varname=trim(vname)) - endif + call ice_write_nc(ncid, 1, varid, work2, diag, restart_ext, varname=trim(vname)) else write(nu_diag,*) 'ndim3 not supported',ndim3 endif diff --git a/cicecore/cicedyn/infrastructure/io/io_pio2/ice_restart.F90 b/cicecore/cicedyn/infrastructure/io/io_pio2/ice_restart.F90 index 11f0fb803..37cf4d985 100644 --- a/cicecore/cicedyn/infrastructure/io/io_pio2/ice_restart.F90 +++ b/cicecore/cicedyn/infrastructure/io/io_pio2/ice_restart.F90 @@ -756,6 +756,7 @@ subroutine read_restart_field(nu,nrec,work,atype,vname,ndim3,diag, & subname// " ERROR: missing varndims "//trim(vname),file=__FILE__,line=__LINE__) call pio_seterrorhandling(File, PIO_INTERNAL_ERROR) + work (:,:,:,:) = c0 if (ndim3 == ncat .and. ndims == 3) then call pio_read_darray(File, vardesc, iodesc3d_ncat, work, status) #ifdef CESMCOUPLED diff --git a/cicecore/drivers/unittest/gridavgchk/gridavgchk.F90 b/cicecore/drivers/unittest/gridavgchk/gridavgchk.F90 index bd7ed3165..02e51fbba 100644 --- a/cicecore/drivers/unittest/gridavgchk/gridavgchk.F90 +++ b/cicecore/drivers/unittest/gridavgchk/gridavgchk.F90 @@ -16,7 +16,6 @@ program gridavgchk use CICE_InitMod use ice_kinds_mod, only: int_kind, dbl_kind use ice_blocks, only: block, get_block, nx_block, ny_block, nblocks_tot - use ice_boundary, only: ice_HaloUpdate use ice_constants, only: c0, c1, c2, p25, & field_loc_center, field_loc_NEcorner, & field_loc_Nface, field_loc_Eface, field_type_scalar diff --git a/cicecore/drivers/unittest/halochk/halochk.F90 b/cicecore/drivers/unittest/halochk/halochk.F90 index 29eaa8150..2fecaf31e 100644 --- a/cicecore/drivers/unittest/halochk/halochk.F90 +++ b/cicecore/drivers/unittest/halochk/halochk.F90 @@ -40,11 +40,12 @@ program halochk implicit none - integer(int_kind) :: nn, nl, nt, i, j, k1, k2, n, ib, ie, jb, je + integer(int_kind) :: nn, nl, nt, nf, i, j, k1, k2, n, ib, ie, jb, je integer(int_kind) :: iblock, itrip, ioffset, joffset integer(int_kind) :: blockID, numBlocks, jtrip type (block) :: this_block + ! fields sent to the haloupdate real(dbl_kind) , allocatable :: darrayi1(:,:,:) , darrayj1(:,:,:) real(dbl_kind) , allocatable :: darrayi2(:,:,:,:) , darrayj2(:,:,:,:) real(dbl_kind) , allocatable :: darrayi3(:,:,:,:,:), darrayj3(:,:,:,:,:) @@ -58,25 +59,27 @@ program halochk real(dbl_kind) , allocatable :: darrayi1str(:,:,:) , darrayj1str(:,:,:) real(dbl_kind) , allocatable :: darrayi10(:,:,:) , darrayj10(:,:,:) - real(dbl_kind), allocatable :: cidata_bas(:,:,:,:,:),cjdata_bas(:,:,:,:,:) - real(dbl_kind), allocatable :: cidata_nup(:,:,:,:,:),cjdata_nup(:,:,:,:,:) - real(dbl_kind), allocatable :: cidata_std(:,:,:,:,:),cjdata_std(:,:,:,:,:) + ! expected results + real(dbl_kind), allocatable :: cidata_bas(:,:,:,:,:),cjdata_bas(:,:,:,:,:) ! baseline integer(int_kind), parameter :: maxtests = 11 integer(int_kind), parameter :: maxtypes = 4 integer(int_kind), parameter :: maxlocs = 5 + integer(int_kind), parameter :: maxfills = 2 integer(int_kind), parameter :: nz1 = 3 integer(int_kind), parameter :: nz2 = 4 real(dbl_kind) :: aichk,ajchk,cichk,cjchk,rival,rjval,rsign - character(len=16) :: locs_name(maxlocs), types_name(maxtypes) + real(dbl_kind) :: fillexpected + character(len=16) :: locs_name(maxlocs), types_name(maxtypes), fill_name(maxfills) integer(int_kind) :: field_loc(maxlocs), field_type(maxtypes) + logical :: halofill integer(int_kind) :: npes, ierr, ntask, testcnt, tottest, tpcnt, tfcnt integer(int_kind) :: errorflag0, gflag, k1m, k2m, ptcntsum, failcntsum integer(int_kind), allocatable :: errorflag(:) integer(int_kind), allocatable :: ptcnt(:), failcnt(:) character(len=128), allocatable :: teststring(:) character(len=32) :: halofld - logical :: tripole_average, tripole_pole, spvalL1 + logical :: tripole_average, tripole_pole logical :: first_call = .true. real(dbl_kind) , parameter :: fillval = -88888.0_dbl_kind @@ -94,6 +97,7 @@ program halochk locs_name (:) = 'unknown' types_name(:) = 'unknown' + fill_name (:) = 'unknown' field_type(:) = field_type_unknown field_loc (:) = field_loc_unknown @@ -110,7 +114,7 @@ program halochk locs_name (1) = 'center' field_loc (1) = field_loc_center - locs_name (2) = 'NEcorner' + locs_name (2) = 'NEcorn' field_loc (2) = field_loc_NEcorner locs_name (3) = 'Nface' field_loc (3) = field_loc_Nface @@ -121,7 +125,10 @@ program halochk ! locs_name (6) = 'unknown' ! field_loc (6) = field_loc_unknown ! aborts in CICE, as expected - tottest = maxtests * maxlocs * maxtypes + fill_name (1) = 'fill' + fill_name (2) = 'nofill' + + tottest = maxtests * maxlocs * maxtypes * maxfills allocate(errorflag(tottest)) allocate(teststring(tottest)) allocate(ptcnt(tottest)) @@ -187,10 +194,6 @@ program halochk allocate(cidata_bas(nx_block,ny_block,nz1,nz2,max_blocks)) allocate(cjdata_bas(nx_block,ny_block,nz1,nz2,max_blocks)) - allocate(cidata_std(nx_block,ny_block,nz1,nz2,max_blocks)) - allocate(cjdata_std(nx_block,ny_block,nz1,nz2,max_blocks)) - allocate(cidata_nup(nx_block,ny_block,nz1,nz2,max_blocks)) - allocate(cjdata_nup(nx_block,ny_block,nz1,nz2,max_blocks)) darrayi1 = fillval darrayj1 = fillval @@ -218,14 +221,14 @@ program halochk darrayj10 = fillval cidata_bas = fillval cjdata_bas = fillval - cidata_std = fillval - cjdata_std = fillval - cidata_nup = fillval - cjdata_nup = fillval call ice_distributionGet(distrb_info, numLocalBlocks = numBlocks) !--- baseline data --- + ! set to the global index + ! i/j valid everywhere for "cyclic" + ! i/j valid for "open" with extrapolation on outer boundary + ! i/j zero on outer boundary for "closed" do iblock = 1,numBlocks call ice_distributionGetBlockID(distrb_info, iblock, blockID) @@ -244,102 +247,32 @@ program halochk enddo enddo - !--- setup nup (noupdate) solution, set halo/pad will fillval --- - - cidata_nup(:,:,:,:,:) = cidata_bas(:,:,:,:,:) - cjdata_nup(:,:,:,:,:) = cjdata_bas(:,:,:,:,:) - - do iblock = 1,numBlocks - call ice_distributionGetBlockID(distrb_info, iblock, blockID) - this_block = get_block(blockID, blockID) - ib = this_block%ilo - ie = this_block%ihi - jb = this_block%jlo - je = this_block%jhi - cidata_nup(1:ib-1 ,: ,:,:,iblock) = fillval - cjdata_nup(1:ib-1 ,: ,:,:,iblock) = fillval - cidata_nup(ie+1:nx_block,: ,:,:,iblock) = fillval - cjdata_nup(ie+1:nx_block,: ,:,:,iblock) = fillval - cidata_nup(: ,1:jb-1 ,:,:,iblock) = fillval - cjdata_nup(: ,1:jb-1 ,:,:,iblock) = fillval - cidata_nup(: ,je+1:ny_block,:,:,iblock) = fillval - cjdata_nup(: ,je+1:ny_block,:,:,iblock) = fillval - enddo - - !--- setup std solution for cyclic, closed, open, tripole solution --- - - cidata_std(:,:,:,:,:) = cidata_bas(:,:,:,:,:) - cjdata_std(:,:,:,:,:) = cjdata_bas(:,:,:,:,:) - - !--- halo off on east and west boundary --- - if (ew_boundary_type == 'closed' .or. & - ew_boundary_type == 'open' ) then - do iblock = 1,numBlocks - call ice_distributionGetBlockID(distrb_info, iblock, blockID) - this_block = get_block(blockID, blockID) - ib = this_block%ilo - ie = this_block%ihi - jb = this_block%jlo - je = this_block%jhi - if (this_block%i_glob(ib) == 1) then - cidata_std(1:ib-1 ,:,:,:,iblock) = dhalofillval - cjdata_std(1:ib-1 ,:,:,:,iblock) = dhalofillval - endif - if (this_block%i_glob(ie) == nx_global) then - cidata_std(ie+1:nx_block,:,:,:,iblock) = dhalofillval - cjdata_std(ie+1:nx_block,:,:,:,iblock) = dhalofillval - endif - enddo - endif - - !--- halo off on south boundary --- - if (ns_boundary_type == 'closed' .or. & - ns_boundary_type == 'open' .or. & - ns_boundary_type == 'tripole' .or. & - ns_boundary_type == 'tripoleT' ) then - do iblock = 1,numBlocks - call ice_distributionGetBlockID(distrb_info, iblock, blockID) - this_block = get_block(blockID, blockID) - ib = this_block%ilo - ie = this_block%ihi - jb = this_block%jlo - je = this_block%jhi - if (this_block%j_glob(jb) == 1) then - cidata_std(:,1:jb-1,:,:,iblock) = dhalofillval - cjdata_std(:,1:jb-1,:,:,iblock) = dhalofillval - endif - enddo - endif - - !--- halo off on north boundary, tripole handled later --- - if (ns_boundary_type == 'closed' .or. & - ns_boundary_type == 'open' .or. & - ns_boundary_type == 'tripole' .or. & - ns_boundary_type == 'tripoleT' ) then - do iblock = 1,numBlocks - call ice_distributionGetBlockID(distrb_info, iblock, blockID) - this_block = get_block(blockID, blockID) - ib = this_block%ilo - ie = this_block%ihi - jb = this_block%jlo - je = this_block%jhi - if (this_block%j_glob(je) == ny_global) then - cidata_std(:,je+1:ny_block,:,:,iblock) = dhalofillval - cjdata_std(:,je+1:ny_block,:,:,iblock) = dhalofillval - endif - enddo - endif - !--------------------------------------------------------------- testcnt = 0 do nn = 1, maxtests do nl = 1, maxlocs do nt = 1, maxtypes + do nf = 1, maxfills !--- setup test --- first_call = .true. testcnt = testcnt + 1 + if (nf == 1) then + halofill = .true. + fillexpected = dhalofillval + elseif (nf == 2) then + halofill = .false. + fillexpected = fillval + else + write(6,*) subname,' nf = ',nf + if (my_task == master_task) then + write(6,*) ' ' + write(6,*) 'HALOCHK FAILED' + write(6,*) ' ' + endif + call abort_ice(subname//' invalid value of nf',file=__FILE__,line=__LINE__) + endif if (testcnt > tottest) then if (my_task == master_task) then write(6,*) ' ' @@ -388,35 +321,54 @@ program halochk darrayi10 = darrayi1 darrayj10 = darrayj1 - !--- halo update --- if (nn == 1) then k1m = 1 k2m = 1 halofld = '2DR8' - call ice_haloUpdate(darrayi1, halo_info, field_loc(nl), field_type(nt), fillvalue=dhalofillval) - call ice_haloUpdate(darrayj1, halo_info, field_loc(nl), field_type(nt), fillvalue=dhalofillval) + if (halofill) then + call ice_haloUpdate(darrayi1, halo_info, field_loc(nl), field_type(nt), fillvalue=dhalofillval) + call ice_haloUpdate(darrayj1, halo_info, field_loc(nl), field_type(nt), fillvalue=dhalofillval) + else + call ice_haloUpdate(darrayi1, halo_info, field_loc(nl), field_type(nt)) + call ice_haloUpdate(darrayj1, halo_info, field_loc(nl), field_type(nt)) + endif elseif (nn == 2) then k1m = nz1 k2m = 1 halofld = '3DR8' - call ice_haloUpdate(darrayi2, halo_info, field_loc(nl), field_type(nt), fillvalue=dhalofillval) - call ice_haloUpdate(darrayj2, halo_info, field_loc(nl), field_type(nt), fillvalue=dhalofillval) + if (halofill) then + call ice_haloUpdate(darrayi2, halo_info, field_loc(nl), field_type(nt), fillvalue=dhalofillval) + call ice_haloUpdate(darrayj2, halo_info, field_loc(nl), field_type(nt), fillvalue=dhalofillval) + else + call ice_haloUpdate(darrayi2, halo_info, field_loc(nl), field_type(nt)) + call ice_haloUpdate(darrayj2, halo_info, field_loc(nl), field_type(nt)) + endif elseif (nn == 3) then k1m = nz1 k2m = nz2 halofld = '4DR8' - call ice_haloUpdate(darrayi3, halo_info, field_loc(nl), field_type(nt), fillvalue=dhalofillval) - call ice_haloUpdate(darrayj3, halo_info, field_loc(nl), field_type(nt), fillvalue=dhalofillval) + if (halofill) then + call ice_haloUpdate(darrayi3, halo_info, field_loc(nl), field_type(nt), fillvalue=dhalofillval) + call ice_haloUpdate(darrayj3, halo_info, field_loc(nl), field_type(nt), fillvalue=dhalofillval) + else + call ice_haloUpdate(darrayi3, halo_info, field_loc(nl), field_type(nt)) + call ice_haloUpdate(darrayj3, halo_info, field_loc(nl), field_type(nt)) + endif elseif (nn == 4) then k1m = 1 k2m = 1 halofld = '2DR4' rarrayi1 = real(darrayi1,kind=real_kind) rarrayj1 = real(darrayj1,kind=real_kind) - call ice_haloUpdate(rarrayi1, halo_info, field_loc(nl), field_type(nt), fillvalue=rhalofillval) - call ice_haloUpdate(rarrayj1, halo_info, field_loc(nl), field_type(nt), fillvalue=rhalofillval) + if (halofill) then + call ice_haloUpdate(rarrayi1, halo_info, field_loc(nl), field_type(nt), fillvalue=rhalofillval) + call ice_haloUpdate(rarrayj1, halo_info, field_loc(nl), field_type(nt), fillvalue=rhalofillval) + else + call ice_haloUpdate(rarrayi1, halo_info, field_loc(nl), field_type(nt)) + call ice_haloUpdate(rarrayj1, halo_info, field_loc(nl), field_type(nt)) + endif darrayi1 = real(rarrayi1,kind=dbl_kind) darrayj1 = real(rarrayj1,kind=dbl_kind) elseif (nn == 5) then @@ -425,8 +377,13 @@ program halochk halofld = '3DR4' rarrayi2 = real(darrayi2,kind=real_kind) rarrayj2 = real(darrayj2,kind=real_kind) - call ice_haloUpdate(rarrayi2, halo_info, field_loc(nl), field_type(nt), fillvalue=rhalofillval) - call ice_haloUpdate(rarrayj2, halo_info, field_loc(nl), field_type(nt), fillvalue=rhalofillval) + if (halofill) then + call ice_haloUpdate(rarrayi2, halo_info, field_loc(nl), field_type(nt), fillvalue=rhalofillval) + call ice_haloUpdate(rarrayj2, halo_info, field_loc(nl), field_type(nt), fillvalue=rhalofillval) + else + call ice_haloUpdate(rarrayi2, halo_info, field_loc(nl), field_type(nt)) + call ice_haloUpdate(rarrayj2, halo_info, field_loc(nl), field_type(nt)) + endif darrayi2 = real(rarrayi2,kind=dbl_kind) darrayj2 = real(rarrayj2,kind=dbl_kind) elseif (nn == 6) then @@ -435,8 +392,13 @@ program halochk halofld = '4DR4' rarrayi3 = real(darrayi3,kind=real_kind) rarrayj3 = real(darrayj3,kind=real_kind) - call ice_haloUpdate(rarrayi3, halo_info, field_loc(nl), field_type(nt), fillvalue=rhalofillval) - call ice_haloUpdate(rarrayj3, halo_info, field_loc(nl), field_type(nt), fillvalue=rhalofillval) + if (halofill) then + call ice_haloUpdate(rarrayi3, halo_info, field_loc(nl), field_type(nt), fillvalue=rhalofillval) + call ice_haloUpdate(rarrayj3, halo_info, field_loc(nl), field_type(nt), fillvalue=rhalofillval) + else + call ice_haloUpdate(rarrayi3, halo_info, field_loc(nl), field_type(nt)) + call ice_haloUpdate(rarrayj3, halo_info, field_loc(nl), field_type(nt)) + endif darrayi3 = real(rarrayi3,kind=dbl_kind) darrayj3 = real(rarrayj3,kind=dbl_kind) elseif (nn == 7) then @@ -445,8 +407,13 @@ program halochk halofld = '2DI4' iarrayi1 = nint(darrayi1) iarrayj1 = nint(darrayj1) - call ice_haloUpdate(iarrayi1, halo_info, field_loc(nl), field_type(nt), fillvalue=ihalofillval) - call ice_haloUpdate(iarrayj1, halo_info, field_loc(nl), field_type(nt), fillvalue=ihalofillval) + if (halofill) then + call ice_haloUpdate(iarrayi1, halo_info, field_loc(nl), field_type(nt), fillvalue=ihalofillval) + call ice_haloUpdate(iarrayj1, halo_info, field_loc(nl), field_type(nt), fillvalue=ihalofillval) + else + call ice_haloUpdate(iarrayi1, halo_info, field_loc(nl), field_type(nt)) + call ice_haloUpdate(iarrayj1, halo_info, field_loc(nl), field_type(nt)) + endif darrayi1 = real(iarrayi1,kind=dbl_kind) darrayj1 = real(iarrayj1,kind=dbl_kind) elseif (nn == 8) then @@ -455,8 +422,13 @@ program halochk halofld = '3DI4' iarrayi2 = nint(darrayi2) iarrayj2 = nint(darrayj2) - call ice_haloUpdate(iarrayi2, halo_info, field_loc(nl), field_type(nt), fillvalue=ihalofillval) - call ice_haloUpdate(iarrayj2, halo_info, field_loc(nl), field_type(nt), fillvalue=ihalofillval) + if (halofill) then + call ice_haloUpdate(iarrayi2, halo_info, field_loc(nl), field_type(nt), fillvalue=ihalofillval) + call ice_haloUpdate(iarrayj2, halo_info, field_loc(nl), field_type(nt), fillvalue=ihalofillval) + else + call ice_haloUpdate(iarrayi2, halo_info, field_loc(nl), field_type(nt)) + call ice_haloUpdate(iarrayj2, halo_info, field_loc(nl), field_type(nt)) + endif darrayi2 = real(iarrayi2,kind=dbl_kind) darrayj2 = real(iarrayj2,kind=dbl_kind) elseif (nn == 9) then @@ -465,20 +437,36 @@ program halochk halofld = '4DI4' iarrayi3 = nint(darrayi3) iarrayj3 = nint(darrayj3) - call ice_haloUpdate(iarrayi3, halo_info, field_loc(nl), field_type(nt), fillvalue=ihalofillval) - call ice_haloUpdate(iarrayj3, halo_info, field_loc(nl), field_type(nt), fillvalue=ihalofillval) + if (halofill) then + call ice_haloUpdate(iarrayi3, halo_info, field_loc(nl), field_type(nt), fillvalue=ihalofillval) + call ice_haloUpdate(iarrayj3, halo_info, field_loc(nl), field_type(nt), fillvalue=ihalofillval) + else + call ice_haloUpdate(iarrayi3, halo_info, field_loc(nl), field_type(nt)) + call ice_haloUpdate(iarrayj3, halo_info, field_loc(nl), field_type(nt)) + endif darrayi3 = real(iarrayi3,kind=dbl_kind) darrayj3 = real(iarrayj3,kind=dbl_kind) elseif (nn == 10) then k1m = 1 k2m = 1 halofld = '2DL1' - larrayi1 = .true. - where (darrayi1 == fillval) larrayi1 = .false. - larrayj1 = .false. - where (darrayj1 == fillval) larrayj1 = .true. - call ice_haloUpdate(larrayi1, halo_info, field_loc(nl), field_type(nt), fillvalue=0) - call ice_haloUpdate(larrayj1, halo_info, field_loc(nl), field_type(nt), fillvalue=1) + where (darrayi1 == fillval) + larrayi1 = .false. + elsewhere + larrayi1 = (mod(nint(darrayi1),2) == 1) + endwhere + where (darrayj1 == fillval) + larrayj1 = .true. + elsewhere + larrayj1 = (mod(nint(darrayj1),2) == 1) + endwhere + if (halofill) then + call ice_haloUpdate(larrayi1, halo_info, field_loc(nl), field_type(nt), fillvalue=0) + call ice_haloUpdate(larrayj1, halo_info, field_loc(nl), field_type(nt), fillvalue=1) + else + call ice_haloUpdate(larrayi1, halo_info, field_loc(nl), field_type(nt)) + call ice_haloUpdate(larrayj1, halo_info, field_loc(nl), field_type(nt)) + endif darrayi1 = c0 where (larrayi1) darrayi1 = c1 darrayj1 = c0 @@ -489,11 +477,16 @@ program halochk halofld = 'STRESS' darrayi1str = -darrayi1 ! flip sign for testing darrayj1str = -darrayj1 - call ice_haloUpdate_stress(darrayi1, darrayi1str, halo_info, field_loc(nl), field_type(nt), fillvalue=dhalofillval) - call ice_haloUpdate_stress(darrayj1, darrayj1str, halo_info, field_loc(nl), field_type(nt), fillvalue=dhalofillval) + if (halofill) then + call ice_haloUpdate_stress(darrayi1, darrayi1str, halo_info, field_loc(nl), field_type(nt), fillvalue=dhalofillval) + call ice_haloUpdate_stress(darrayj1, darrayj1str, halo_info, field_loc(nl), field_type(nt), fillvalue=dhalofillval) + else + call ice_haloUpdate_stress(darrayi1, darrayi1str, halo_info, field_loc(nl), field_type(nt)) + call ice_haloUpdate_stress(darrayj1, darrayj1str, halo_info, field_loc(nl), field_type(nt)) + endif endif - write(teststring(testcnt),'(5a10)') trim(halofld),trim(locs_name(nl)),trim(types_name(nt)), & + write(teststring(testcnt),'(6a8)') trim(halofld),trim(locs_name(nl)),trim(types_name(nt)),trim(fill_name(nf)), & trim(ew_boundary_type),trim(ns_boundary_type) do iblock = 1,numBlocks @@ -504,15 +497,12 @@ program halochk jb = this_block%jlo je = this_block%jhi ! just check non-padded gridcells -! do j = 1,ny_block -! do i = 1,nx_block do j = jb-nghost, je+nghost do i = ib-nghost, ie+nghost do k1 = 1,k1m do k2 = 1,k2m tripole_average = .false. tripole_pole = .false. - spvalL1 = .false. if (index(halofld,'2D') > 0) then aichk = darrayi1(i,j,iblock) ajchk = darrayj1(i,j,iblock) @@ -534,14 +524,46 @@ program halochk call abort_ice(subname//' halofld not matched '//trim(halofld),file=__FILE__,line=__LINE__) endif + cichk = cidata_bas(i,j,k1,k2,iblock) + cjchk = cjdata_bas(i,j,k1,k2,iblock) + + ! halo special cases if (field_loc (nl) == field_loc_noupdate .or. & field_type(nt) == field_type_noupdate) then - cichk = cidata_nup(i,j,k1,k2,iblock) - cjchk = cjdata_nup(i,j,k1,k2,iblock) + if (i < ib .or. j < jb .or. i > ie .or. j > je) then + ! no halo update anywhere, doesn't even see fillvalue passed in + cichk = fillval + cjchk = fillval + endif + else - cichk = cidata_std(i,j,k1,k2,iblock) - cjchk = cjdata_std(i,j,k1,k2,iblock) + ! if ew_boundary_type is not cyclic we expect just fill values on outer boundary + if (ew_boundary_type /= 'cyclic' .and. & + ((this_block%i_glob(ib) == 1 .and. i < ib) .or. & ! west outer face + (this_block%i_glob(ie) == nx_global .and. i > ie))) then ! east outer face + cichk = fillexpected + cjchk = fillexpected + endif + + ! if ns_boundary_type is not cyclic we expect just fill values on outer boundary except + ! - tripole north edge will be haloed and is updated below, default to fill value for now + ! - tripole south edge will be set to the fillvalue or to haloupdate internal default (c0) + ! tripole basically assumes south edge is land or always ice free in CICE + if (ns_boundary_type /= 'cyclic' .and. & + ((this_block%j_glob(jb) == 1 .and. j < jb) .or. & ! south outer face + (this_block%j_glob(je) == ny_global .and. j > je))) then ! north outer face + ! ns_boundary_type is not cyclic and on outer boundary + if ((ns_boundary_type == 'tripole' .or. & + ns_boundary_type == 'tripoleT') .and. & + .not. halofill) then + cichk = c0 + cjchk = c0 + else + cichk = fillexpected + cjchk = fillexpected + endif + endif if (index(halofld,'STRESS') > 0) then ! only updates on tripole zipper for tripole grids @@ -560,11 +582,11 @@ program halochk (ns_boundary_type == 'tripoleT' .and. & (j >= je)))) then - ! flip sign for vector/angle - if (field_type(nt) == field_type_vector .or. field_type(nt) == field_type_angle ) then + ! flip sign for vector/angle except for logical halo updates + rsign = c1 + if ((field_type(nt) == field_type_vector .or. field_type(nt) == field_type_angle) .and. & + .not. (index(halofld,'L1') > 0)) then rsign = -c1 - else - rsign = c1 endif ! for tripole @@ -650,44 +672,40 @@ program halochk if (index(halofld,'STRESS') > 0) then ! only updates on tripole zipper for tripole grids, not tripoleT + ! note: L1 and STRESS never overlap so don't worry about L1 here if (tripole_pole) then ! flip sign due to sign of darrayi1str ! ends of tripole seam not averaged in CICE - cichk = -rsign * cidata_std(i,j,k1,k2,iblock) - cjchk = -rsign * cjdata_std(i,j,k1,k2,iblock) + cichk = -rsign * cidata_bas(i,j,k1,k2,iblock) + cjchk = -rsign * cjdata_bas(i,j,k1,k2,iblock) else cichk = -rsign * rival cjchk = -rsign * rjval endif - elseif (index(halofld,'L1') > 0 .and. j == je) then - ! force cichk and cjchk to match on tripole average index, calc not well defined - spvalL1 = .true. - cichk = aichk - cjchk = ajchk + elseif (tripole_pole) then ! ends of tripole seam not averaged in CICE - cichk = rsign * cidata_std(i,j,k1,k2,iblock) - cjchk = rsign * cjdata_std(i,j,k1,k2,iblock) + cichk = rsign * cidata_bas(i,j,k1,k2,iblock) + cjchk = rsign * cjdata_bas(i,j,k1,k2,iblock) + elseif (tripole_average) then - ! tripole average - cichk = p5 * (cidata_std(i,j,k1,k2,iblock) + rsign * rival) - cjchk = p5 * (cjdata_std(i,j,k1,k2,iblock) + rsign * rjval) + if (index(halofld,'L1') > 0) then + ! logical math doesn't work this way, force to correct answer + cichk = aichk ! p5 * (mod(nint(cidata_bas(i,j,k1,k2,iblock)),2) + rsign * mod(nint(rival),2)) + cjchk = ajchk ! p5 * (mod(nint(cidata_bas(i,j,k1,k2,iblock)),2) + rsign * mod(nint(rjval),2)) + else + cichk = p5 * (cidata_bas(i,j,k1,k2,iblock) + rsign * rival) + cjchk = p5 * (cjdata_bas(i,j,k1,k2,iblock) + rsign * rjval) + endif + else ! standard tripole fold cichk = rsign * rival cjchk = rsign * rjval endif -! if (testcnt == 6 .and. j == 61 .and. i < 3) then -! if (testcnt == 186 .and. j == 61 .and. i<4) then -! if (testcnt == 13 .and. j > 61 .and. (i < 3 .or. i > 89)) then -! if (testcnt == 5 .and. j >= 61 .and. (i < 3 .or. i > 90)) then -! write(100+my_task,'(a,5i6,2l3,f6.2,i6)') 'tcx1 ',i,j,iblock,itrip,jtrip, & -! tripole_average,tripole_pole,rsign,this_block%i_glob(i) -! write(100+my_task,'(a,4f12.2)') 'tcx2 ',cidata_std(i,j,k1,k2,iblock),rival,cichk,aichk -! write(100+my_task,'(a,4f12.2)') 'tcx3 ',cjdata_std(i,j,k1,k2,iblock),rjval,cjchk,ajchk -! endif endif ! tripole or tripoleT + endif if (index(halofld,'I4') > 0) then @@ -695,16 +713,16 @@ program halochk cjchk = real(nint(cjchk),kind=dbl_kind) endif - if (index(halofld,'L1') > 0 .and. .not.spvalL1) then + if (index(halofld,'L1') > 0) then if (cichk == dhalofillval .or. cichk == fillval) then cichk = c0 else - cichk = c1 + cichk = mod(nint(cichk),2) endif if (cjchk == dhalofillval .or. cjchk == fillval) then cjchk = c1 else - cjchk = c0 + cjchk = mod(nint(cjchk),2) endif endif @@ -719,6 +737,7 @@ program halochk enddo ! j enddo ! iblock + enddo ! maxfills enddo ! maxtypes enddo ! maxlocs enddo ! maxtests @@ -746,10 +765,10 @@ program halochk do n = 1,tottest if (errorflag(n) == passflag) then tpcnt = tpcnt + 1 - write(6,*) 'PASS ',trim(teststring(n)),ptcnt(n),failcnt(n) + write(6,'(2a,2i8)') 'PASS ',trim(teststring(n)),ptcnt(n),failcnt(n) else tfcnt = tfcnt + 1 - write(6,*) 'FAIL ',trim(teststring(n)),ptcnt(n),failcnt(n) + write(6,'(2a,2i8)') 'FAIL ',trim(teststring(n)),ptcnt(n),failcnt(n) endif enddo write(6,*) ' ' @@ -793,8 +812,10 @@ subroutine chkresults(a1,r1,errorflag,testcnt,failcnt,i,j,k1,k2,iblock,first_cal character(len=*) , parameter :: subname='(chkresults)' if (a1 /= r1 .or. print_always) then - errorflag = failflag - failcnt = failcnt + 1 + if (a1 /= r1) then + errorflag = failflag + failcnt = failcnt + 1 + endif if (first_call) then write(100+my_task,*) ' ' write(100+my_task,'(a,i4,2a)') '------- TEST = ',testcnt,' ',trim(teststring) diff --git a/cicecore/shared/ice_arrays_column.F90 b/cicecore/shared/ice_arrays_column.F90 index 38f3ee0f7..8dee4aef3 100644 --- a/cicecore/shared/ice_arrays_column.F90 +++ b/cicecore/shared/ice_arrays_column.F90 @@ -9,6 +9,7 @@ module ice_arrays_column use ice_kinds_mod + use ice_constants, only : c0 use ice_fileunits, only: nu_diag use ice_blocks, only: nx_block, ny_block use ice_domain_size, only: max_blocks, ncat, nilyr, nslyr, & @@ -25,8 +26,7 @@ module ice_arrays_column ! icepack_atmo.F90 ! Cdn variables on the T-grid - real (kind=dbl_kind), public, & - dimension (:,:,:), allocatable :: & + real (kind=dbl_kind), public, dimension (:,:,:), allocatable :: & Cdn_atm , & ! atm drag coefficient Cdn_ocn , & ! ocn drag coefficient ! form drag @@ -64,16 +64,17 @@ module ice_arrays_column ! icepack_itd.F90 real (kind=dbl_kind), public, allocatable :: & - hin_max(:) ! category limits (m) + hin_max(:) ! category limits (m) - character (len=35), public, allocatable :: c_hi_range(:) + character (len=35), public, allocatable :: & + c_hi_range(:)! string for history output ! icepack_snow.F90 real (kind=dbl_kind), public, dimension (:,:,:), allocatable :: & meltsliq ! snow melt mass (kg/m^2/step-->kg/m^2/day) real (kind=dbl_kind), public, dimension (:,:,:,:), allocatable :: & - meltsliqn ! snow melt mass in category n (kg/m^2) + meltsliqn ! snow melt mass in category n (kg/m^2) ! icepack_meltpond_lvl.F90 real (kind=dbl_kind), public, dimension (:,:,:,:), allocatable :: & @@ -83,10 +84,10 @@ module ice_arrays_column ! icepack_shortwave.F90 ! category albedos real (kind=dbl_kind), dimension (:,:,:,:), allocatable, public :: & - alvdrn , & ! visible direct albedo (fraction) - alidrn , & ! near-ir direct albedo (fraction) - alvdfn , & ! visible diffuse albedo (fraction) - alidfn ! near-ir diffuse albedo (fraction) + alvdrn, & ! visible direct albedo (fraction) + alidrn, & ! near-ir direct albedo (fraction) + alvdfn, & ! visible diffuse albedo (fraction) + alidfn ! near-ir diffuse albedo (fraction) ! albedo components for history real (kind=dbl_kind), dimension (:,:,:,:), allocatable, public :: & @@ -100,14 +101,14 @@ module ice_arrays_column ! shortwave components real (kind=dbl_kind), dimension (:,:,:,:,:), allocatable, public :: & - Iswabsn ! SW radiation absorbed in ice layers (W m-2) + Iswabsn ! SW radiation absorbed in ice layers (W m-2) real (kind=dbl_kind), dimension (:,:,:,:,:), allocatable, public :: & - Sswabsn ! SW radiation absorbed in snow layers (W m-2) + Sswabsn ! SW radiation absorbed in snow layers (W m-2) real (kind=dbl_kind), dimension (:,:,:,:), allocatable, public :: & - fswsfcn , & ! SW absorbed at ice/snow surface (W m-2) - fswthrun , & ! SW through ice to ocean (W/m^2) + fswsfcn , & ! SW absorbed at ice/snow surface (W m-2) + fswthrun , & ! SW through ice to ocean (W/m^2) fswthrun_vdr , & ! vis dir SW through ice to ocean (W/m^2) fswthrun_vdf , & ! vis dif SW through ice to ocean (W/m^2) fswthrun_idr , & ! nir dir SW through ice to ocean (W/m^2) @@ -119,7 +120,7 @@ module ice_arrays_column fswintn ! SW absorbed in ice interior, below surface (W m-2) real (kind=dbl_kind), dimension (:,:,:,:,:), allocatable, public :: & - fswpenln ! visible SW entering ice layers (W m-2) + fswpenln ! visible SW entering ice layers (W m-2) ! biogeochemistry components @@ -348,6 +349,71 @@ subroutine alloc_arrays_column stat=ierr) if (ierr/=0) call abort_ice(subname//': Out of Memory1') + Cdn_atm = c0 + Cdn_ocn = c0 + hfreebd = c0 + hdraft = c0 + hridge = c0 + distrdg = c0 + hkeel = c0 + dkeel = c0 + lfloe = c0 + dfloe = c0 + Cdn_atm_skin = c0 + Cdn_atm_floe = c0 + Cdn_atm_pond = c0 + Cdn_atm_rdg = c0 + Cdn_ocn_skin = c0 + Cdn_ocn_floe = c0 + Cdn_ocn_keel = c0 + Cdn_atm_ratio = c0 + grow_net = c0 + PP_net = c0 + hbri = c0 + chl_net = c0 + NO_net = c0 + upNO = c0 + upNH = c0 + meltsliq = c0 + meltsliqn = c0 + dhsn = c0 + ffracn = c0 + alvdrn = c0 + alidrn = c0 + alvdfn = c0 + alidfn = c0 + albicen = c0 + albsnon = c0 + albpndn = c0 + apeffn = c0 + snowfracn = c0 + fswsfcn = c0 + fswthrun = c0 + fswthrun_vdr = c0 + fswthrun_vdf = c0 + fswthrun_idr = c0 + fswthrun_idf = c0 + fswthrun_uvrdr= c0 + fswthrun_uvrdf= c0 + fswthrun_pardr= c0 + fswthrun_pardf= c0 + fswintn = c0 + first_ice_real= c0 + first_ice = .false. + dhbr_top = c0 + dhbr_bot = c0 + darcy_V = c0 + sice_rho = c0 + Iswabsn = c0 + Sswabsn = c0 + fswpenln = c0 + Zoo = c0 + zfswin = c0 + iDi = c0 + iki = c0 + bphi = c0 + bTiz = c0 + allocate( & ocean_bio (nx_block,ny_block,max_nbtrcr,max_blocks), & ! contains all the ocean bgc tracer concentrations fbio_snoice (nx_block,ny_block,max_nbtrcr,max_blocks), & ! fluxes from snow to ice @@ -359,6 +425,14 @@ subroutine alloc_arrays_column stat=ierr) if (ierr/=0) call abort_ice(subname//': Out of Memory2') + ocean_bio = c0 + fbio_snoice = c0 + fbio_atmice = c0 + ocean_bio_all= c0 + ice_bio_net = c0 + snow_bio_net = c0 + algal_peak = 0 + allocate( & hin_max(0:ncat) , & ! category limits (m) c_hi_range(ncat) , & ! @@ -370,6 +444,14 @@ subroutine alloc_arrays_column stat=ierr) if (ierr/=0) call abort_ice(subname//' Out of Memory3') + hin_max = c0 + c_hi_range = '' + bgrid = c0 + igrid = c0 + cgrid = c0 + icgrid = c0 + swgrid = c0 + ! floe size distribution allocate( & floe_rad_l (nfsd) , & ! fsd size lower bound in m (radius) @@ -388,6 +470,20 @@ subroutine alloc_arrays_column stat=ierr) if (ierr/=0) call abort_ice(subname//' Out of Memory5') + floe_rad_l = c0 + floe_rad_c = c0 + floe_binwidth = c0 + c_fsd_range = '' + wavefreq = c0 + dwavefreq = c0 + wave_sig_ht = c0 + wave_spectrum = c0 + d_afsd_newi = c0 + d_afsd_latg = c0 + d_afsd_latm = c0 + d_afsd_wave = c0 + d_afsd_weld = c0 + end subroutine alloc_arrays_column !======================================================================= diff --git a/configuration/scripts/ice_in b/configuration/scripts/ice_in index 4c1ed4111..0c9c7ffe5 100644 --- a/configuration/scripts/ice_in +++ b/configuration/scripts/ice_in @@ -96,7 +96,6 @@ scale_dxdy = .false. dxscale = 1.d0 dyscale = 1.d0 - close_boundaries = .false. ncat = 5 nfsd = 1 nilyr = 7 diff --git a/configuration/scripts/options/set_nml.box2001 b/configuration/scripts/options/set_nml.box2001 index ad42a4236..1c2fc3683 100644 --- a/configuration/scripts/options/set_nml.box2001 +++ b/configuration/scripts/options/set_nml.box2001 @@ -11,9 +11,8 @@ grid_type = 'rectangular' kmt_type = 'default' dxrect = 16.e5 dyrect = 16.e5 -close_boundaries = .true. -ew_boundary_type = 'open' -ns_boundary_type = 'open' +ew_boundary_type = 'closed' +ns_boundary_type = 'closed' tr_iage = .false. tr_FY = .false. tr_lvl = .false. diff --git a/configuration/scripts/options/set_nml.boxchan b/configuration/scripts/options/set_nml.boxchan index a3f0fd191..67fdaff9c 100644 --- a/configuration/scripts/options/set_nml.boxchan +++ b/configuration/scripts/options/set_nml.boxchan @@ -9,7 +9,6 @@ grid_type = 'rectangular' kmt_type = 'channel' dxrect = 16.e5 dyrect = 16.e5 -close_boundaries = .false. ew_boundary_type = 'cyclic' ns_boundary_type = 'open' tr_iage = .false. diff --git a/configuration/scripts/options/set_nml.boxchan1e b/configuration/scripts/options/set_nml.boxchan1e index cf8b0d314..0a4e92bef 100644 --- a/configuration/scripts/options/set_nml.boxchan1e +++ b/configuration/scripts/options/set_nml.boxchan1e @@ -9,7 +9,6 @@ grid_type = 'rectangular' kmt_type = 'channel_oneeast' dxrect = 16.e5 dyrect = 16.e5 -close_boundaries = .false. ew_boundary_type = 'cyclic' ns_boundary_type = 'open' tr_iage = .false. diff --git a/configuration/scripts/options/set_nml.boxchan1n b/configuration/scripts/options/set_nml.boxchan1n index f90d4da0c..a342f811c 100644 --- a/configuration/scripts/options/set_nml.boxchan1n +++ b/configuration/scripts/options/set_nml.boxchan1n @@ -9,7 +9,6 @@ grid_type = 'rectangular' kmt_type = 'channel_onenorth' dxrect = 16.e5 dyrect = 16.e5 -close_boundaries = .false. ew_boundary_type = 'open' ns_boundary_type = 'cyclic' tr_iage = .false. diff --git a/configuration/scripts/options/set_nml.boxclosed b/configuration/scripts/options/set_nml.boxclosed index d55faa302..ba9d9b4d7 100644 --- a/configuration/scripts/options/set_nml.boxclosed +++ b/configuration/scripts/options/set_nml.boxclosed @@ -9,9 +9,8 @@ grid_type = 'rectangular' kmt_type = 'default' dxrect = 16.e5 dyrect = 16.e5 -close_boundaries = .true. -ew_boundary_type = 'open' -ns_boundary_type = 'open' +ew_boundary_type = 'closed' +ns_boundary_type = 'closed' tr_iage = .false. tr_FY = .false. tr_lvl = .false. diff --git a/configuration/scripts/options/set_nml.boxopen b/configuration/scripts/options/set_nml.boxopen index 84badd373..081865d7a 100644 --- a/configuration/scripts/options/set_nml.boxopen +++ b/configuration/scripts/options/set_nml.boxopen @@ -6,7 +6,6 @@ histfreq = 'd','x','x','x','x' grid_type = 'rectangular' dxrect = 16.e5 dyrect = 16.e5 -close_boundaries = .false. ew_boundary_type = 'cyclic' ns_boundary_type = 'open' ktherm = -1 diff --git a/configuration/scripts/options/set_nml.boxslotcyl b/configuration/scripts/options/set_nml.boxslotcyl index 10f0518c8..de35e21e9 100644 --- a/configuration/scripts/options/set_nml.boxslotcyl +++ b/configuration/scripts/options/set_nml.boxslotcyl @@ -11,9 +11,8 @@ kmt_type = 'default' dxrect = 10.e5 dyrect = 10.e5 kcatbound = 2 -ew_boundary_type = 'open' -ns_boundary_type = 'open' -close_boundaries = .true. +ew_boundary_type = 'closed' +ns_boundary_type = 'closed' tr_lvl = .false. tr_pond_lvl = .false. ktherm = -1 diff --git a/configuration/scripts/options/set_nml.boxwallblock b/configuration/scripts/options/set_nml.boxwallblock index 2e9a34728..352f4c4ad 100644 --- a/configuration/scripts/options/set_nml.boxwallblock +++ b/configuration/scripts/options/set_nml.boxwallblock @@ -9,7 +9,6 @@ grid_type = 'rectangular' kmt_type = 'wall' dxrect = 16.e5 dyrect = 16.e5 -close_boundaries = .false. ew_boundary_type = 'cyclic' ns_boundary_type = 'cyclic' tr_iage = .false. diff --git a/doc/source/user_guide/ug_case_settings.rst b/doc/source/user_guide/ug_case_settings.rst index e2b271776..98bc7268f 100644 --- a/doc/source/user_guide/ug_case_settings.rst +++ b/doc/source/user_guide/ug_case_settings.rst @@ -297,7 +297,7 @@ grid_nml "``bathymetry_file``", "string", "name of bathymetry file to be read", "'unknown_bathymetry_file'" "``bathymetry_format``", "``default``", "NetCDF depth field", "'default'" "", "``pop``", "POP thickness file in cm in ascii format", "" - "``close_boundaries``", "logical", "force two gridcell wide land mask on boundaries for rectangular grids", "``.false.``" + "``close_boundaries``", "logical", "deprecated Nov, 2025, use ew_boundary_type and ns_boundary_type", "``.false.``" "``dxrect``", "real", "x-direction grid spacing for rectangular grid in cm", "0.0" "``dxscale``", "real", "user defined rectgrid x-grid scale factor", "1.0" "``dyrect``", "real", "y-direction grid spacing for rectangular grid in cm", "0.0" @@ -376,7 +376,8 @@ domain_nml "", "``blockfull``", "block method with NO land block elimination and full weight given to land blocks", "" "", "``latitude``", "latitude/ocean sets ``work_per_block``", "" "``distribution_wght_file``", "string", "distribution weight file when distribution_type is ``wghtfile``", "'unknown'" - "``ew_boundary_type``", "``cyclic``", "periodic boundary conditions in x-direction", "``cyclic``" + "``ew_boundary_type``", "``closed``", "force two gridcell wide land mask on x-direction boundaries for rectangular grids", "``cyclic``" + "", "``cyclic``", "periodic boundary conditions in x-direction", "" "", "``open``", "Dirichlet boundary conditions in x", "" "``maskhalo_dyn``", "logical", "mask unused halo cells for dynamics", "``.false.``" "``maskhalo_remap``", "logical", "mask unused halo cells for transport", "``.false.``" @@ -385,7 +386,8 @@ domain_nml "", "``-1``", "find number of blocks per MPI task automatically", "" "``nprocs``", "integer", "number of MPI tasks to use", "-1" "", "``-1``", "find number of MPI tasks automatically", "" - "``ns_boundary_type``", "``cyclic``", "periodic boundary conditions in y-direction", "``open``" + "``ns_boundary_type``", "``closed``", "force two gridcell wide land mask on y-direction boundaries for rectangular grids", "``cyclic``" + "", "``cyclic``", "periodic boundary conditions in y-direction", "" "", "``open``", "Dirichlet boundary conditions in y", "" "", "``tripole``", "U-fold tripole boundary conditions in y", "" "", "``tripoleT``", "T-fold tripole boundary conditions in y", "" diff --git a/doc/source/user_guide/ug_implementation.rst b/doc/source/user_guide/ug_implementation.rst index 69c288ee8..17b1f618e 100644 --- a/doc/source/user_guide/ug_implementation.rst +++ b/doc/source/user_guide/ug_implementation.rst @@ -421,7 +421,7 @@ Tinz and Tsnz, and the ice salinity profile, Sinz. These variables also include category as a fourth dimension. ******************* -Boundary conditions +Boundary Conditions ******************* Much of the infrastructure used in CICE, including the boundary @@ -430,33 +430,39 @@ communications among processors when MPI is in use and among blocks whenever there is more than one block per processor. Boundary conditions are defined by the ``ns_boundary_type`` and ``ew_boundary_type`` -namelist inputs. Valid values are ``open`` and ``cyclic``. In addition, +namelist inputs. Valid values are ``open``, ``closed``, and ``cyclic``. In addition, ``tripole`` and ``tripoleT`` are options for the ``ns_boundary_type``. -Closed boundary conditions are not supported currently. -The domain can be physically closed with the ``close_boundaries`` -namelist which forces a land mask on the boundary with a two gridcell depth. -Where the boundary is land, the boundary_type settings play no role. -For example, in the displaced-pole grids, at least one row of grid cells along the north -and south boundaries is land. Along the east/west domain boundaries not -masked by land, periodic conditions wrap the domain around the globe. In +``closed`` imposes a land mask on the boundary with a two gridcell depth +and is only supported for rectangular grids. In general, +where the boundary is land or where there is no ice on the boundary, +the boundary_type settings and boundary conditions play no role. + +In the displaced-pole global grids, the mask (kmt) file has at least one row of +grid cells along the north and south boundaries that is land. Along the east/west +domain boundaries, periodic conditions wrap the domain around the globe. In this example, -the appropriate namelist settings are ``nsboundary_type`` = ``open``, -``ew_boundary_type`` = ``cyclic``, and ``close_boundaries`` = ``.false.``. - -CICE can be run on regional grids with open boundary conditions; except -for variables describing grid lengths, non-land halo cells along the -grid edge must be filled by restoring them to specified values. The -namelist variable ``restore_ice`` turns this functionality on and off; the +the appropriate namelist settings are ``ns_boundary_type`` = ``open``, +``ew_boundary_type`` = ``cyclic``. + +CICE can be run on regional grids with ``open``, ``closed``, or ``cyclic`` +boundary conditions. +Except for variables describing grid lengths, non-land halo cells along the +grid edge must be filled with some boundary conditions +if ice is present at that location. The outside halo is handled automatically +with ``closed`` or ``cyclic`` conditions. With open boundary conditions, one can imagine +several different ways to set the outside boundary including reading values from +an external file or deriving values on that halo based on the interior +solution while specifying zero gradient, constant gradient, specified state, +zero flux, or other boundary conditions. Mathematically specified boundary +conditions are currently not supported in the CICE model. + +The namelist variable ``restore_ice`` turns on a restoring capability on the +boundary by setting the boundary halo to values read from a file. The restoring timescale ``trestore`` may be used (it is also used for restoring ocean sea surface temperature in stand-alone ice runs). This implementation is only intended to provide the “hooks" for a more -sophisticated treatment; the rectangular grid option can be used to test -this configuration. The ‘displaced_pole’ grid option should not be used -unless the regional grid contains land all along the north and south -boundaries. The current form of the boundary condition routines does not -allow Neumann boundary conditions, which must be set explicitly. This -has been done in an unreleased branch of the code; contact Elizabeth for -more information. +sophisticated treatment. The rectangular grid option can be used to test +this configuration. For exact restarts using restoring, set ``restart_ext`` = true in namelist to use the extended-grid subroutines. From ec2e2bdc17bb453e7d8c11d37b86c058bb27655c Mon Sep 17 00:00:00 2001 From: "David A. Bailey" Date: Thu, 13 Nov 2025 00:50:03 -0700 Subject: [PATCH 11/21] Fixes for sitemptop, sitempbot, and sitempsnic. (#1054) Changes in CICE: - move conversion to K into the define_hist_field call - fix the accumulation of sitemptop, sitempsnic, and sitempbot to reflect the "intrinsic" versus "extrinsic" definitions. - redo the avg_ice_present division by aice, so that conb is added at the end - also undo the ravgct multiplication and division for the case of avg_ice_present - add cell_methods as "area: time: mean where sea ice (mask=siconc)" - Update icepack hash to bug fix version of "Tsnice", https://github.com/CICE-Consortium/Icepack/pull/542 --- cicecore/cicedyn/analysis/ice_history.F90 | 112 +++++++++--------- .../io/io_netcdf/ice_history_write.F90 | 12 +- .../io/io_pio2/ice_history_write.F90 | 10 +- icepack | 2 +- 4 files changed, 77 insertions(+), 59 deletions(-) diff --git a/cicecore/cicedyn/analysis/ice_history.F90 b/cicecore/cicedyn/analysis/ice_history.F90 index a6eabe2db..99b04afb9 100644 --- a/cicecore/cicedyn/analysis/ice_history.F90 +++ b/cicecore/cicedyn/analysis/ice_history.F90 @@ -1535,17 +1535,17 @@ subroutine init_hist (dt) call define_hist_field(n_sitemptop,"sitemptop","K",tstr2D, tcstr, & "sea ice surface temperature", & - "none", c1, c0, & + "none", c1, Tffresh, & ns1, f_sitemptop, avg_ice_present=.true., mask_ice_free_points=.true.) call define_hist_field(n_sitempsnic,"sitempsnic","K",tstr2D, tcstr, & "snow ice interface temperature", & - "surface temperature when no snow present", c1, c0, & + "surface temperature when no snow present", c1, Tffresh, & ns1, f_sitempsnic, avg_ice_present=.true., mask_ice_free_points=.true.) call define_hist_field(n_sitempbot,"sitempbot","K",tstr2D, tcstr, & "sea ice bottom temperature", & - "none", c1, c0, & + "none", c1, Tffresh, & ns1, f_sitempbot, avg_ice_present=.true., mask_ice_free_points=.true.) call define_hist_field(n_siu,"siu","m/s",ustr2D, ucstr, & @@ -2753,22 +2753,18 @@ subroutine accum_hist (dt) worka(:,:) = c0 do j = jlo, jhi do i = ilo, ihi - if (aice(i,j,iblk) > puny) & - worka(i,j) = aice(i,j,iblk)*(trcr(i,j,nt_Tsfc,iblk)+Tffresh) + worka(i,j) = aice(i,j,iblk)*trcr(i,j,nt_Tsfc,iblk) enddo enddo call accum_hist_field(n_sitemptop, iblk, worka(:,:), a2D) endif + ! Tsnice is already multiplied by aicen in icepack. if (f_sitempsnic(1:1) /= 'x') then worka(:,:) = c0 do j = jlo, jhi do i = ilo, ihi - if (vsno(i,j,iblk) > puny .and. aice_init(i,j,iblk) > puny) then - worka(i,j) = aice(i,j,iblk)*(Tsnice(i,j,iblk)/aice_init(i,j,iblk)+Tffresh) - else - worka(i,j) = aice(i,j,iblk)*(trcr(i,j,nt_Tsfc,iblk)+Tffresh) - endif + worka(i,j) = Tsnice(i,j,iblk) enddo enddo call accum_hist_field(n_sitempsnic, iblk, worka(:,:), a2D) @@ -2778,8 +2774,7 @@ subroutine accum_hist (dt) worka(:,:) = c0 do j = jlo, jhi do i = ilo, ihi - if (aice_init(i,j,iblk) > puny) & - worka(i,j) = aice(i,j,iblk)*(Tbot(i,j,iblk)/aice_init(i,j,iblk)+Tffresh) + worka(i,j) = aice(i,j,iblk)*Tbot(i,j,iblk) enddo enddo call accum_hist_field(n_sitempbot, iblk, worka(:,:), a2D) @@ -3705,33 +3700,40 @@ subroutine accum_hist (dt) do n = 1, num_avail_hist_fields_2D if (avail_hist_fields(n)%vhistfreq == histfreq(ns)) then - do j = jlo, jhi - do i = ilo, ihi - if (.not. tmask(i,j,iblk)) then ! mask out land points - a2D(i,j,n,iblk) = spval_dbl - else ! convert units - a2D(i,j,n,iblk) = avail_hist_fields(n)%cona*a2D(i,j,n,iblk) & - * ravgct + avail_hist_fields(n)%conb - endif - enddo ! i - enddo ! j - - ! Only average for timesteps when ice present + ! Only average when/where ice present if (avail_hist_fields(n)%avg_ice_present) then do j = jlo, jhi do i = ilo, ihi - if (tmask(i,j,iblk)) then - a2D(i,j,n,iblk) = & - a2D(i,j,n,iblk)*avgct(ns)*ravgip(i,j) + if (.not. tmask(i,j,iblk)) then + a2D(i,j,n,iblk) = spval_dbl + else ! convert units + a2D(i,j,n,iblk) = avail_hist_fields(n)%cona*a2D(i,j,n,iblk) & + * ravgip(i,j) + avail_hist_fields(n)%conb endif - ! Mask ice-free points - if (avail_hist_fields(n)%mask_ice_free_points) then - if (ravgip(i,j) == c0) a2D(i,j,n,iblk) = spval_dbl + enddo ! i + enddo ! j + else + do j = jlo, jhi + do i = ilo, ihi + if (.not. tmask(i,j,iblk)) then ! mask out land points + a2D(i,j,n,iblk) = spval_dbl + else ! convert units + a2D(i,j,n,iblk) = avail_hist_fields(n)%cona*a2D(i,j,n,iblk) & + * ravgct + avail_hist_fields(n)%conb endif enddo ! i enddo ! j endif + ! Mask ice-free points + if (avail_hist_fields(n)%mask_ice_free_points) then + do j = jlo, jhi + do i = ilo, ihi + if (ravgip(i,j) == c0) a2D(i,j,n,iblk) = spval_dbl + enddo ! i + enddo ! j + endif + ! CMIP albedo: also mask points below horizon if (index(avail_hist_fields(n)%vname,'sialb') /= 0) then do j = jlo, jhi @@ -3838,30 +3840,33 @@ subroutine accum_hist (dt) nn = n2D + n if (avail_hist_fields(nn)%vhistfreq == histfreq(ns)) then - do k = 1, ncat_hist - do j = jlo, jhi - do i = ilo, ihi - if (.not. tmask(i,j,iblk)) then ! mask out land points - a3Dc(i,j,k,n,iblk) = spval_dbl - else ! convert units - a3Dc(i,j,k,n,iblk) = avail_hist_fields(nn)%cona*a3Dc(i,j,k,n,iblk) & - * ravgct + avail_hist_fields(nn)%conb + if (avail_hist_fields(nn)%avg_ice_present) then + do k = 1, ncat_hist + do j = jlo, jhi + do i = ilo, ihi + if (.not. tmask(i,j,iblk)) then ! mask out land points + a3Dc(i,j,k,n,iblk) = spval_dbl + else ! convert units + a3Dc(i,j,k,n,iblk) = avail_hist_fields(nn)%cona*a3Dc(i,j,k,n,iblk) & + * ravgipn(i,j,k) + avail_hist_fields(nn)%conb + endif + enddo ! i + enddo ! j + enddo ! k + else + do k = 1, ncat_hist + do j = jlo, jhi + do i = ilo, ihi + if (.not. tmask(i,j,iblk)) then ! mask out land points + a3Dc(i,j,k,n,iblk) = spval_dbl + else ! convert units + a3Dc(i,j,k,n,iblk) = avail_hist_fields(nn)%cona*a3Dc(i,j,k,n,iblk) & + * ravgct + avail_hist_fields(nn)%conb + endif + enddo ! i + enddo ! j + enddo ! k endif - enddo ! i - enddo ! j - enddo ! k - if (avail_hist_fields(nn)%avg_ice_present) then - do k = 1, ncat_hist - do j = jlo, jhi - do i = ilo, ihi - if (tmask(i,j,iblk)) then - a3Dc(i,j,k,n,iblk) = & - a3Dc(i,j,k,n,iblk)*avgct(ns)*ravgipn(i,j,k) - endif - enddo ! i - enddo ! j - enddo ! k - endif endif @@ -3885,6 +3890,7 @@ subroutine accum_hist (dt) enddo ! k endif enddo ! n + do n = 1, num_avail_hist_fields_3Db nn = n3Dzcum + n if (avail_hist_fields(nn)%vhistfreq == histfreq(ns)) then diff --git a/cicecore/cicedyn/infrastructure/io/io_netcdf/ice_history_write.F90 b/cicecore/cicedyn/infrastructure/io/io_netcdf/ice_history_write.F90 index d7720cd1e..2d6c5915a 100644 --- a/cicecore/cicedyn/infrastructure/io/io_netcdf/ice_history_write.F90 +++ b/cicecore/cicedyn/infrastructure/io/io_netcdf/ice_history_write.F90 @@ -1287,9 +1287,15 @@ subroutine ice_hist_field_def(ncid, hfield, lprecision, dimids, ns) .and.TRIM(hfield%vname(1:9))/='sistreave' & .and.TRIM(hfield%vname(1:9))/='sistremax' & .and.TRIM(hfield%vname(1:4))/='sigP') then - status = nf90_put_att(ncid,varid,'cell_methods','time: mean') - call ice_check_nc(status, subname// ' ERROR: defining cell methods for '//hfield%vname, & - file=__FILE__, line=__LINE__) + if (hfield%avg_ice_present) then + status = nf90_put_att(ncid,varid,'cell_methods','area: time: mean where sea ice (mask=siconc)') + call ice_check_nc(status, subname// ' ERROR: defining cell methods for '//hfield%vname, & + file=__FILE__, line=__LINE__) + else + status = nf90_put_att(ncid,varid,'cell_methods','time: mean') + call ice_check_nc(status, subname// ' ERROR: defining cell methods for '//hfield%vname, & + file=__FILE__, line=__LINE__) + endif endif endif diff --git a/cicecore/cicedyn/infrastructure/io/io_pio2/ice_history_write.F90 b/cicecore/cicedyn/infrastructure/io/io_pio2/ice_history_write.F90 index d935f2577..f4c6e51db 100644 --- a/cicecore/cicedyn/infrastructure/io/io_pio2/ice_history_write.F90 +++ b/cicecore/cicedyn/infrastructure/io/io_pio2/ice_history_write.F90 @@ -1428,8 +1428,14 @@ subroutine ice_hist_field_def(File, hfield,lprecision, dimids, ns) .and.TRIM(hfield%vname(1:9))/='sistreave' & .and.TRIM(hfield%vname(1:9))/='sistremax' & .and.TRIM(hfield%vname(1:4))/='sigP') then - call ice_pio_check(pio_put_att(File,varid,'cell_methods','time: mean'), & - subname//' ERROR: defining att cell_methods',file=__FILE__,line=__LINE__) + if (hfield%avg_ice_present) then + call ice_pio_check(pio_put_att(File,varid,'cell_methods', & + 'area: time: mean where sea ice (mask=siconc)'), & + subname//' ERROR: defining att cell_methods',file=__FILE__,line=__LINE__) + else + call ice_pio_check(pio_put_att(File,varid,'cell_methods','time: mean'), & + subname//' ERROR: defining att cell_methods',file=__FILE__,line=__LINE__) + endif endif endif diff --git a/icepack b/icepack index a5b5ebe63..4954a6f90 160000 --- a/icepack +++ b/icepack @@ -1 +1 @@ -Subproject commit a5b5ebe63f986dbda86d5b2ef91426811619d018 +Subproject commit 4954a6f9033f78e5c32bf33780384cbf2d0843e6 From fa682b31785269a3a67590ad1fbe6d6055bb97f6 Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Wed, 26 Nov 2025 12:15:21 -0700 Subject: [PATCH 12/21] change dynamics minimum area and mass values and add Icepack parameters to remove residual ice (#1067) Removes residual amounts of ice that are not otherwise handled by the numerics. The controlling parameters (itd_area_min and itd_mass_min, implemented in Icepack) set minimum ice area and mass values below which all ice is removed following the thermodynamics and ridging calculations. For the B-grid, these parameters are currently set to the dynamics stability minima, which are being reduced to extremely small values based on testing in multiple modeling systems. If needed, users can revert these parameters to the original, larger values by adding them to ice_in. Setting them to 0 turns off the new zapping completely. These parameters are set to the larger, original values in the C-grid test scripts, pending further work. This updates Icepack and changes answers. --- cicecore/cicedyn/general/ice_init.F90 | 45 ++++++++++++++++---- configuration/scripts/ice_in | 4 +- configuration/scripts/options/set_nml.gridc | 2 + configuration/scripts/options/set_nml.gridcd | 2 + doc/source/cice_index.rst | 8 ++-- doc/source/science_guide/sg_dynamics.rst | 9 ++-- doc/source/science_guide/sg_fundvars.rst | 13 +++++- doc/source/user_guide/ug_case_settings.rst | 6 ++- icepack | 2 +- 9 files changed, 71 insertions(+), 20 deletions(-) diff --git a/cicecore/cicedyn/general/ice_init.F90 b/cicecore/cicedyn/general/ice_init.F90 index aa78c398d..8a139883f 100644 --- a/cicecore/cicedyn/general/ice_init.F90 +++ b/cicecore/cicedyn/general/ice_init.F90 @@ -157,7 +157,7 @@ subroutine input_data phi_c_slow_mode, phi_i_mushy, kalg, atmiter_conv, Pstar, Cstar, & sw_frac, sw_dtemp, floediam, hfrazilmin, iceruf, iceruf_ocn, & rsnw_fall, rsnw_tmax, rhosnew, rhosmin, rhosmax, Tliquidus_max, & - windmin, drhosdwind, snwlvlfac, tscale_pnd_drain + windmin, drhosdwind, snwlvlfac, tscale_pnd_drain, itd_area_min, itd_mass_min integer (kind=int_kind) :: ktherm, kstrength, krdg_partic, krdg_redist, natmiter, & kitd, kcatbound, ktransport @@ -178,6 +178,7 @@ subroutine input_data integer (kind=int_kind) :: rplvl, rptopo, rpsealvl real (kind=dbl_kind) :: Cf, ksno, puny, ice_ref_salinity, Tocnfrz + real (kind=dbl_kind), parameter :: ice_init_spval = -999._dbl_kind character (len=char_len) :: abort_list character (len=char_len) :: nml_name ! namelist name @@ -203,7 +204,7 @@ subroutine input_data hist_time_axis, & print_global, print_points, latpnt, lonpnt, & debug_forcing, histfreq, histfreq_n, hist_avg, & - hist_suffix, history_deflate, history_chunksize, & + hist_suffix, history_deflate, history_chunksize, & history_dir, history_file, history_precision, cpl_bgc, & histfreq_base, dumpfreq_base, timer_stats, memory_stats, & conserv_check, debug_model, debug_model_step, & @@ -240,8 +241,7 @@ subroutine input_data a_rapid_mode, Rac_rapid_mode, aspect_rapid_mode, & dSdt_slow_mode, phi_c_slow_mode, phi_i_mushy, & floediam, hfrazilmin, Tliquidus_max, hi_min, & - tscale_pnd_drain - + itd_area_min, itd_mass_min, tscale_pnd_drain namelist /dynamics_nml/ & kdyn, ndte, revised_evp, yield_curve, & @@ -419,8 +419,8 @@ subroutine input_data kstrength = 1 ! 1 = Rothrock 75 strength, 0 = Hibler 79 Pstar = 2.75e4_dbl_kind ! constant in Hibler strength formula (kstrength = 0) Cstar = 20._dbl_kind ! constant in Hibler strength formula (kstrength = 0) - dyn_area_min = p001 ! minimum ice area concentration to activate dynamics - dyn_mass_min = p01 ! minimum ice mass to activate dynamics (kg/m^2) + dyn_area_min = 1.e-11_dbl_kind ! minimum ice area concentration to activate dynamics + dyn_mass_min = 1.e-10_dbl_kind ! minimum ice mass to activate dynamics (kg/m^2) krdg_partic = 1 ! 1 = new participation, 0 = Thorndike et al 75 krdg_redist = 1 ! 1 = new redistribution, 0 = Hibler 80 mu_rdg = 3 ! e-folding scale of ridged ice, krdg_partic=1 (m^0.5) @@ -487,6 +487,8 @@ subroutine input_data cpl_frazil = 'fresh_ice_correction' ! type of coupling for frazil ice ustar_min = 0.005 ! minimum friction velocity for ocean heat flux (m/s) hi_min = p01 ! minimum ice thickness allowed (m) + itd_area_min = ice_init_spval ! zap residual ice below a minimum area + itd_mass_min = ice_init_spval ! zap residual ice below a minimum mass iceruf = 0.0005_dbl_kind ! ice surface roughness at atmosphere interface (m) iceruf_ocn = 0.03_dbl_kind ! under-ice roughness (m) calc_dragio = .false. ! compute dragio from iceruf_ocn and thickness of first ocean level @@ -922,6 +924,24 @@ subroutine input_data if (trim(diag_type) == 'file') call get_fileunit(nu_diag) #endif + ! To remove small amounts of residual ice that are not handled by either dynamics or + ! column physics, the minimum area and mass parameters should be set to the same values + ! in both places. The default sets the column physics (itd) parameters to the dynamics + ! values (available in namelist). itd_area_min and itd_mass_min can be added to the + ! namelist file ice_in and set to different values, if desired. Setting them to + ! zero turns off residual zapping completely. + if (itd_area_min /= ice_init_spval .or. itd_mass_min /= ice_init_spval) then + ! allow itd and dyn parameters to be different + write(nu_diag,*) subname//' WARNING: zap_residual parameters are reset in namelist' + elseif (itd_area_min == c0 .or. itd_mass_min == c0) then + ! turn off residual zapping in Icepack + write(nu_diag,*) subname//' WARNING: zap_residual is turned off' + else + ! itd and dyn parameters are the same by default + itd_area_min = dyn_area_min ! zap residual ice below dynamics minimum area + itd_mass_min = dyn_mass_min ! zap residual ice below dynamics minimum mass + endif + !----------------------------------------------------------------- ! broadcast namelist settings !----------------------------------------------------------------- @@ -1145,6 +1165,8 @@ subroutine input_data call broadcast_scalar(l_mpond_fresh, master_task) call broadcast_scalar(ustar_min, master_task) call broadcast_scalar(hi_min, master_task) + call broadcast_scalar(itd_area_min, master_task) + call broadcast_scalar(itd_mass_min, master_task) call broadcast_scalar(iceruf, master_task) call broadcast_scalar(iceruf_ocn, master_task) call broadcast_scalar(calc_dragio, master_task) @@ -2400,6 +2422,10 @@ subroutine input_data write(nu_diag,1030) ' fbot_xfer_type = ', trim(fbot_xfer_type),trim(tmpstr2) write(nu_diag,1000) ' ustar_min = ', ustar_min,' : minimum value of ocean friction velocity' write(nu_diag,1000) ' hi_min = ', hi_min,' : minimum ice thickness allowed (m)' + write(nu_diag,1000) ' puny = ', puny,' : general-use minimum value' + write(nu_diag,*) ' Ice thickness category areas smaller than puny are always removed.' + write(nu_diag,1003) ' itd_area_min = ', itd_area_min,' : zap residual ice below a minimum area' + write(nu_diag,1003) ' itd_mass_min = ', itd_mass_min,' : zap residual ice below a minimum mass' if (calc_dragio) then tmpstr2 = ' : dragio computed from iceruf_ocn' else @@ -2410,8 +2436,11 @@ subroutine input_data write(nu_diag,1002) ' iceruf_ocn = ', iceruf_ocn,' : under-ice roughness length' endif + write(nu_diag,*) ' ' + write(nu_diag,*) ' Floe size distribution and waves' + write(nu_diag,*) '---------------------------------' + write(nu_diag,1002) ' floediam = ', floediam, ' : constant floe diameter' if (tr_fsd) then - write(nu_diag,1002) ' floediam = ', floediam, ' constant floe diameter' if (wave_spec) then tmpstr2 = ' : use wave spectrum for floe size distribution' else @@ -2799,7 +2828,7 @@ subroutine input_data atmbndy_in=atmbndy, calc_strair_in=calc_strair, formdrag_in=formdrag, highfreq_in=highfreq, & kitd_in=kitd, kcatbound_in=kcatbound, hs0_in=hs0, dpscale_in=dpscale, frzpnd_in=frzpnd, & rfracmin_in=rfracmin, rfracmax_in=rfracmax, pndaspect_in=pndaspect, hs1_in=hs1, hp1_in=hp1, & - apnd_sl_in=apnd_sl, & + apnd_sl_in=apnd_sl, itd_area_min_in=itd_area_min, itd_mass_min_in=itd_mass_min, & ktherm_in=ktherm, calc_Tsfc_in=calc_Tsfc, conduct_in=conduct, semi_implicit_Tsfc_in=semi_implicit_Tsfc, & a_rapid_mode_in=a_rapid_mode, Rac_rapid_mode_in=Rac_rapid_mode, vapor_flux_correction_in=vapor_flux_correction, & floediam_in=floediam, hfrazilmin_in=hfrazilmin, Tliquidus_max_in=Tliquidus_max, & diff --git a/configuration/scripts/ice_in b/configuration/scripts/ice_in index 0c9c7ffe5..2d0cffaab 100644 --- a/configuration/scripts/ice_in +++ b/configuration/scripts/ice_in @@ -201,8 +201,8 @@ reltol_pgmres = 1e-6 algo_nonlin = 'picard' use_mean_vrel = .true. - dyn_area_min = 0.001d0 - dyn_mass_min = 0.01d0 + dyn_area_min = 1.e-11 + dyn_mass_min = 1.e-10 / &shortwave_nml diff --git a/configuration/scripts/options/set_nml.gridc b/configuration/scripts/options/set_nml.gridc index a04fab4fd..63c5af2bb 100644 --- a/configuration/scripts/options/set_nml.gridc +++ b/configuration/scripts/options/set_nml.gridc @@ -1,2 +1,4 @@ grid_ice = 'C' +dyn_area_min = 0.001d0 +dyn_mass_min = 0.01d0 diff --git a/configuration/scripts/options/set_nml.gridcd b/configuration/scripts/options/set_nml.gridcd index 7889e64f4..4cf521a4b 100644 --- a/configuration/scripts/options/set_nml.gridcd +++ b/configuration/scripts/options/set_nml.gridcd @@ -1,4 +1,6 @@ grid_ice = 'C_override_D' +dyn_area_min = 0.001d0 +dyn_mass_min = 0.01d0 # visc_method=avg_zeta causes some gridcd tests to abort, use avg_strength for now visc_method = 'avg_strength' diff --git a/doc/source/cice_index.rst b/doc/source/cice_index.rst index f46fbaa8d..479c0a18c 100644 --- a/doc/source/cice_index.rst +++ b/doc/source/cice_index.rst @@ -120,7 +120,7 @@ section :ref:`tabnamelist`. "cosw", "cosine of the turning angle in water", "1." "coszen", "cosine of the zenith angle", "" "Cp", "proportionality constant for potential energy", "kg/m\ :math:`^2`/s\ :math:`^2`" - "cpl_frazil", ":math:`\bullet` type of frazil ice coupling", "" + "cpl_frazil", "type of frazil ice coupling", "" "cp_air", "specific heat of air", "1005.0 J/kg/K" "cp_ice", "specific heat of fresh ice", "2106. J/kg/K" "cp_ocn", "specific heat of sea water", "4218. J/kg/K" @@ -208,8 +208,8 @@ section :ref:`tabnamelist`. "dvidtd", "ice volume tendency due to dynamics/transport", "m/s" "dvidtt", "ice volume tendency due to thermodynamics", "m/s" "dvirdg(n)dt", "ice volume ridging rate (category n)", "m/s" - "dyn_area_min", "minimum area concentration for computing velocity", "0.001" - "dyn_mass_min", "minimum mass for computing velocity", "0.01 kg/m\ :math:`^2`" + "dyn_area_min", "minimum area concentration for computing velocity", "1.e-11" + "dyn_mass_min", "minimum mass for computing velocity", "1.e-10 kg/m\ :math:`^2`" "**E**", "", "" "e11, e12, e22", "strain rate tensor components", "" "earea", "area of E-cell", "m\ :math:`^2`" @@ -390,6 +390,8 @@ section :ref:`tabnamelist`. "istep0", "number of steps taken in previous run", "0" "istep1", "total number of steps at current time step", "" "Iswabs", "shortwave radiation absorbed in ice layers", "W/m\ :math:`^2`" + "itd_area_min", "zap residual ice below a minimum area", "dyn_area_min" + "itd_mass_min", "zap residual ice below a minimum mass", "dyn_mass_min" "**J**", "", "" "**K**", "", "" "kalg", "absorption coefficient for algae", "" diff --git a/doc/source/science_guide/sg_dynamics.rst b/doc/source/science_guide/sg_dynamics.rst index ce9c3c4ee..23d1fbc33 100644 --- a/doc/source/science_guide/sg_dynamics.rst +++ b/doc/source/science_guide/sg_dynamics.rst @@ -96,9 +96,12 @@ Note that the VP solver has not yet been tested on the ``tx1`` grid. The EVP, rEVP, EAP and VP approaches are all available with the B grid. However, at the moment, only the EVP and rEVP schemes are possible with the C grid. -The dynamics are solved for all gridcells with area concentration greater than ``dyn_area_min`` and mass -greater than ``dyn_mass_min``. These parameters are respectively 0.001 and 0.01 by default but can be set in -namelist. Lower values can improve the solution but also lead to instabilities. +The dynamics are solved for all grid cells with area concentration greater than ``dyn_area_min`` +and mass greater than ``dyn_mass_min``. These parameters can be set in namelist. Lower +values can improve the solution with increased computational expense due to additional +calculations in grid cells with small amounts of ice, but can also lead to instabilities. +For this reason, default values in the code and base namelist file are set for the B-grid, +with different values provided for C-grid tests. Here we summarize the equations and direct the reader to the above references for details. diff --git a/doc/source/science_guide/sg_fundvars.rst b/doc/source/science_guide/sg_fundvars.rst index 2d6f50328..89b095c70 100644 --- a/doc/source/science_guide/sg_fundvars.rst +++ b/doc/source/science_guide/sg_fundvars.rst @@ -13,7 +13,6 @@ modeling is to describe the evolution of the ice thickness distribution (ITD) in time and space. In addition to an ice thickness distribution, CICE includes an optional capability for a floe size distribution. - Ice floe horizontal size may change through vertical and lateral growth and melting of existing floes, freezing of new ice, wave breaking, and welding of floes in freezing conditions. The floe size distribution (FSD) is a probability function that characterizes this variability. The scheme is based on the theoretical framework described in :cite:`Horvat15` for a joint floe size and thickness distribution (FSTD), and was implemented by :cite:`Roach18` and :cite:`Roach19`. The joint floe size distribution is carried as an area-weighted tracer, defined as the fraction of ice belonging to a given thickness category with lateral floe size belong to a given floe size class. This development includes interactions between sea ice and ocean surface waves. Input data on ocean surface wave spectra at a single time is provided for testing, but as with the other CICE datasets, it should not be used for production runs or publications. It is not recommended to use the FSD without ocean surface waves. Additional information about the ITD and joint FSTD for CICE can be found in the @@ -113,3 +112,15 @@ the beginning of the timestep. Rather than recompute the albedo and shortwave components at the beginning of the next timestep using new values of the downwelling shortwave forcing, the shortwave components computed at the end of the last timestep are scaled for the new forcing. + +In Icepack, residual amounts of ice may be conservatively removed based +on minimum area and mass parameters ``itd_area_min`` and ``itd_mass_min``. +Initializing these parameters to CICE's ``dyn_area_min`` and ``dyn_mass_min`` +namelist values ensures consistency between Icepack's column physics and +CICE's dynamic calculations by avoiding residual ice not handled in either +place. However, ``dyn_area_min`` and ``dyn_mass_min`` should be relatively +small to avoid removing too much ice. The default behavior sets the column +physics (itd) parameters to the dynamics values (from namelist). +``itd_area_min`` and ``itd_mass_min`` can be added to the namelist file +**ice_in** and set to different values, if desired. Setting them to zero +turns off residual zapping completely. diff --git a/doc/source/user_guide/ug_case_settings.rst b/doc/source/user_guide/ug_case_settings.rst index 98bc7268f..3882073de 100644 --- a/doc/source/user_guide/ug_case_settings.rst +++ b/doc/source/user_guide/ug_case_settings.rst @@ -466,6 +466,8 @@ thermo_nml "``ktherm``", "``-1``", "thermodynamic model disabled", "1" "", "``1``", "Bitz and Lipscomb thermodynamic model", "" "", "``2``", "mushy-layer thermodynamic model", "" + "``itd_area_min``", "real", "area below which ice is zapped", "1.e-11" + "``itd_mass_min``", "real", "mass below which ice is zapped", "1.e-10" "``phi_c_slow_mode``", ":math:`0<\phi_c < 1`", "critical liquid fraction", "0.05" "``phi_i_mushy``", ":math:`0<\phi_i < 1`", "solid fraction at lower boundary", "0.85" "``Rac_rapid_mode``", "real", "critical Rayleigh number", "10.0" @@ -512,8 +514,8 @@ dynamics_nml "``deltaminVP``", "real", "minimum delta for viscosities", "2e-9" "``dim_fgmres``", "integer", "maximum number of Arnoldi iterations for FGMRES solver", "50" "``dim_pgmres``", "integer", "maximum number of Arnoldi iterations for PGMRES preconditioner", "5" - "``dyn_area_min``", "real", "min ice area concentration to activate dynamics", "0.001" - "``dyn_mass_min``", "real", "min ice mass to activate dynamics (kg/m\ :math:`^2`)", "0.01" + "``dyn_area_min``", "real", "min ice area concentration to activate dynamics", "1.e-11" + "``dyn_mass_min``", "real", "min ice mass to activate dynamics (kg/m\ :math:`^2`)", "1.e-10" "``e_plasticpot``", "real", "aspect ratio of elliptical plastic potential", "2.0" "``e_yieldcurve``", "real", "aspect ratio of elliptical yield curve", "2.0" "``elasticDamp``", "real", "elastic damping parameter", "0.36" diff --git a/icepack b/icepack index 4954a6f90..eedb51924 160000 --- a/icepack +++ b/icepack @@ -1 +1 @@ -Subproject commit 4954a6f9033f78e5c32bf33780384cbf2d0843e6 +Subproject commit eedb519247f48bce9fa1d1b275b5cc3dc07643e4 From 25ce26d562ee1d4bba6414677bccdbdbd6adce70 Mon Sep 17 00:00:00 2001 From: Tony Craig Date: Thu, 18 Dec 2025 11:26:19 -0800 Subject: [PATCH 13/21] Update Carpenter Port (#1076) After an upgrade, several of Carpenter's modules were removed. These changes update the modules and software versions used to compiler and run CICE. --- configuration/scripts/machines/Macros.carpenter_gnu | 3 ++- .../scripts/machines/Macros.carpenter_gnuimpi | 3 ++- configuration/scripts/machines/env.carpenter_cray | 12 ++++++------ configuration/scripts/machines/env.carpenter_gnu | 12 ++++++------ configuration/scripts/machines/env.carpenter_gnuimpi | 12 ++++++------ configuration/scripts/machines/env.carpenter_intel | 12 ++++++------ .../scripts/machines/env.carpenter_intelimpi | 12 ++++++------ .../scripts/machines/env.carpenter_inteloneapi | 12 ++++++------ 8 files changed, 40 insertions(+), 38 deletions(-) diff --git a/configuration/scripts/machines/Macros.carpenter_gnu b/configuration/scripts/machines/Macros.carpenter_gnu index 61efa80c2..a1fe056fb 100644 --- a/configuration/scripts/machines/Macros.carpenter_gnu +++ b/configuration/scripts/machines/Macros.carpenter_gnu @@ -12,7 +12,8 @@ FFLAGS := -fconvert=big-endian -fbacktrace -ffree-line-length-none -fallow-a FFLAGS_NOOPT:= -O0 ifeq ($(ICE_BLDDEBUG), true) - FFLAGS += -O0 -g -fcheck=bounds -finit-real=nan -fimplicit-none -ffpe-trap=invalid,zero,overflow +# FFLAGS += -O0 -g -fcheck=bounds -finit-real=nan -fimplicit-none -ffpe-trap=invalid,zero,overflow + FFLAGS += -O0 -g -fcheck=bounds -finit-real=nan -fimplicit-none -ffpe-trap=zero,overflow CFLAGS += -O0 endif diff --git a/configuration/scripts/machines/Macros.carpenter_gnuimpi b/configuration/scripts/machines/Macros.carpenter_gnuimpi index ef0c5e96a..d57dfda2b 100644 --- a/configuration/scripts/machines/Macros.carpenter_gnuimpi +++ b/configuration/scripts/machines/Macros.carpenter_gnuimpi @@ -12,7 +12,8 @@ FFLAGS := -fconvert=big-endian -fbacktrace -ffree-line-length-none -fallow-a FFLAGS_NOOPT:= -O0 ifeq ($(ICE_BLDDEBUG), true) - FFLAGS += -O0 -g -fcheck=bounds -finit-real=nan -fimplicit-none -ffpe-trap=invalid,zero,overflow +# FFLAGS += -O0 -g -fcheck=bounds -finit-real=nan -fimplicit-none -ffpe-trap=invalid,zero,overflow + FFLAGS += -O0 -g -fcheck=bounds -finit-real=nan -fimplicit-none -ffpe-trap=zero,overflow CFLAGS += -O0 endif diff --git a/configuration/scripts/machines/env.carpenter_cray b/configuration/scripts/machines/env.carpenter_cray index d2c832d8f..0d70e7f54 100644 --- a/configuration/scripts/machines/env.carpenter_cray +++ b/configuration/scripts/machines/env.carpenter_cray @@ -13,21 +13,21 @@ module unload PrgEnv-cray module unload PrgEnv-gnu module unload PrgEnv-intel module unload PrgEnv-pgi -module load PrgEnv-cray/8.4.0 +module load PrgEnv-cray/8.6.0 module unload cce -module load cce/16.0.0 +module load cce/19.0.0 module unload cray-mpich -module load cray-mpich/8.1.26 +module load cray-mpich/8.1.32 module unload cray-hdf5 module unload cray-hdf5-parallel module unload cray-netcdf-hdf5parallel module unload cray-parallel-netcdf module unload netcdf -module load cray-netcdf/4.9.0.3 -module load cray-hdf5/1.12.2.3 +module load cray-netcdf/4.9.0.17 +module load cray-hdf5/1.14.3.5 setenv NETCDF_PATH ${NETCDF_DIR} limit coredumpsize unlimited @@ -41,7 +41,7 @@ endif setenv ICE_MACHINE_MACHNAME carpenter setenv ICE_MACHINE_MACHINFO "Cray EX4000 AMD 9654 Genoa 2.1GHz, Slingshot Interconnect" setenv ICE_MACHINE_ENVNAME cray -setenv ICE_MACHINE_ENVINFO "Cray Fortran/Clang 16.0.0, cray-mpich/8.1.26, netcdf/4.9.0.3" +setenv ICE_MACHINE_ENVINFO "Cray Fortran/Clang 19.0.0, cray-mpich/8.1.32, netcdf/4.9.0.17" setenv ICE_MACHINE_MAKE gmake setenv ICE_MACHINE_WKDIR $WORKDIR/CICE_RUNS setenv ICE_MACHINE_INPUTDATA /p/app/unsupported/RASM/cice_consortium diff --git a/configuration/scripts/machines/env.carpenter_gnu b/configuration/scripts/machines/env.carpenter_gnu index 96a04072f..9c8e4df4e 100644 --- a/configuration/scripts/machines/env.carpenter_gnu +++ b/configuration/scripts/machines/env.carpenter_gnu @@ -13,15 +13,15 @@ module unload PrgEnv-cray module unload PrgEnv-gnu module unload PrgEnv-intel module unload PrgEnv-pgi -module load PrgEnv-gnu/8.4.0 +module load PrgEnv-gnu/8.6.0 module unload gcc -module load gcc/12.2.0 +module load gcc/14.2.0 module unload cray-mpich module unload mpi module unload openmpi -module load cray-mpich/8.1.26 +module load cray-mpich/8.1.32 #module load openmpi/4.1.6 #module load mpi/2021.11 @@ -30,8 +30,8 @@ module unload cray-hdf5-parallel module unload cray-netcdf-hdf5parallel module unload cray-parallel-netcdf module unload netcdf -module load cray-netcdf/4.9.0.3 -module load cray-hdf5/1.12.2.3 +module load cray-netcdf/4.9.0.17 +module load cray-hdf5/1.14.3.5 setenv NETCDF_PATH ${NETCDF_DIR} limit coredumpsize unlimited @@ -45,7 +45,7 @@ endif setenv ICE_MACHINE_MACHNAME carpenter setenv ICE_MACHINE_MACHINFO "Cray EX4000 AMD 9654 Genoa 2.1GHz, Slingshot Interconnect" setenv ICE_MACHINE_ENVNAME gnu -setenv ICE_MACHINE_ENVINFO "gnu gcc 12.2.0 20220819, mpich/8.1.26, netcdf/4.9.0.3" +setenv ICE_MACHINE_ENVINFO "gnu gcc 14.3.0, mpich/8.1.32, netcdf/4.9.0.17" setenv ICE_MACHINE_MAKE gmake setenv ICE_MACHINE_WKDIR $WORKDIR/CICE_RUNS setenv ICE_MACHINE_INPUTDATA /p/app/unsupported/RASM/cice_consortium diff --git a/configuration/scripts/machines/env.carpenter_gnuimpi b/configuration/scripts/machines/env.carpenter_gnuimpi index f21bf97a5..900494b3b 100644 --- a/configuration/scripts/machines/env.carpenter_gnuimpi +++ b/configuration/scripts/machines/env.carpenter_gnuimpi @@ -13,25 +13,25 @@ module unload PrgEnv-cray module unload PrgEnv-gnu module unload PrgEnv-intel module unload PrgEnv-pgi -module load PrgEnv-gnu/8.4.0 +module load PrgEnv-gnu/8.6.0 module unload gcc -module load gcc/11.2.0 +module load gcc/14.2.0 module unload cray-mpich module unload mpi module unload openmpi #module load cray-mpich/8.1.26 #module load openmpi/4.1.6 -module load mpi/2021.11 +module load mpi/2021.16 module unload cray-hdf5 module unload cray-hdf5-parallel module unload cray-netcdf-hdf5parallel module unload cray-parallel-netcdf module unload netcdf -module load cray-netcdf/4.9.0.3 -module load cray-hdf5/1.12.2.3 +module load cray-netcdf/4.9.0.17 +module load cray-hdf5/1.14.3.5 setenv NETCDF_PATH ${NETCDF_DIR} limit coredumpsize unlimited @@ -45,7 +45,7 @@ endif setenv ICE_MACHINE_MACHNAME carpenter setenv ICE_MACHINE_MACHINFO "Cray EX4000 AMD 9654 Genoa 2.1GHz, Slingshot Interconnect" setenv ICE_MACHINE_ENVNAME gnuimpi -setenv ICE_MACHINE_ENVINFO "gnu gcc 11.2.0 20210728, intel mpi 2021.11, netcdf/4.9.0.3" +setenv ICE_MACHINE_ENVINFO "gnu gcc 14.2.0, intel mpi 2021.16, netcdf/4.9.0.17" setenv ICE_MACHINE_MAKE gmake setenv ICE_MACHINE_WKDIR $WORKDIR/CICE_RUNS setenv ICE_MACHINE_INPUTDATA /p/app/unsupported/RASM/cice_consortium diff --git a/configuration/scripts/machines/env.carpenter_intel b/configuration/scripts/machines/env.carpenter_intel index 141a5a82a..577d9642f 100644 --- a/configuration/scripts/machines/env.carpenter_intel +++ b/configuration/scripts/machines/env.carpenter_intel @@ -12,15 +12,15 @@ module unload PrgEnv-cray module unload PrgEnv-gnu module unload PrgEnv-intel module unload PrgEnv-pgi -module load PrgEnv-intel/8.5.0 +module load PrgEnv-intel/8.6.0 module unload intel -module load intel/2023.0.0 +module load intel/2024.2 module unload cray-mpich module unload mpi module unload openmpi -module load cray-mpich/8.1.30 +module load cray-mpich/8.1.32 #module load mpi/2021.11 #module load openmpi/4.1.6 @@ -29,8 +29,8 @@ module unload cray-hdf5-parallel module unload cray-netcdf-hdf5parallel module unload cray-parallel-netcdf module unload netcdf -module load cray-netcdf/4.9.0.3 -module load cray-hdf5/1.14.3.1 +module load cray-netcdf/4.9.0.17 +module load cray-hdf5/1.14.3.5 setenv NETCDF_PATH ${NETCDF_DIR} limit coredumpsize unlimited @@ -44,7 +44,7 @@ endif setenv ICE_MACHINE_MACHNAME carpenter setenv ICE_MACHINE_MACHINFO "Cray EX4000 AMD 9654 Genoa 2.1GHz, Slingshot Interconnect" setenv ICE_MACHINE_ENVNAME intel -setenv ICE_MACHINE_ENVINFO "ifort 2021.8.0 20221119, cray-mpich/8.1.30, netcdf/4.9.0.3" +setenv ICE_MACHINE_ENVINFO "ifort 2021.13.0 20240602, cray-mpich/8.1.32, netcdf/4.9.0.17" setenv ICE_MACHINE_MAKE gmake setenv ICE_MACHINE_WKDIR $WORKDIR/CICE_RUNS setenv ICE_MACHINE_INPUTDATA /p/app/unsupported/RASM/cice_consortium diff --git a/configuration/scripts/machines/env.carpenter_intelimpi b/configuration/scripts/machines/env.carpenter_intelimpi index ef43363cd..80f696772 100644 --- a/configuration/scripts/machines/env.carpenter_intelimpi +++ b/configuration/scripts/machines/env.carpenter_intelimpi @@ -12,16 +12,16 @@ module unload PrgEnv-cray module unload PrgEnv-gnu module unload PrgEnv-intel module unload PrgEnv-pgi -module load PrgEnv-intel/8.5.0 +module load PrgEnv-intel/8.6.0 module unload intel -module load intel/2023.0.0 +module load intel/2023.2.0 module unload cray-mpich module unload mpi module unload openmpi #module load cray-mpich/8.1.26 -module load mpi/2021.13 +module load mpi/2021.16 #module load openmpi/4.1.6 module unload cray-hdf5 @@ -29,8 +29,8 @@ module unload cray-hdf5-parallel module unload cray-netcdf-hdf5parallel module unload cray-parallel-netcdf module unload netcdf -module load cray-netcdf/4.9.0.3 -module load cray-hdf5/1.14.3.1 +module load cray-netcdf/4.9.0.17 +module load cray-hdf5/1.14.3.5 setenv NETCDF_PATH ${NETCDF_DIR} limit coredumpsize unlimited @@ -44,7 +44,7 @@ endif setenv ICE_MACHINE_MACHNAME carpenter setenv ICE_MACHINE_MACHINFO "Cray EX4000 AMD 9654 Genoa 2.1GHz, Slingshot Interconnect" setenv ICE_MACHINE_ENVNAME intelimpi -setenv ICE_MACHINE_ENVINFO "ifort 2021.8.0 20221119, intel mpi 2021.13, netcdf/4.9.0.3" +setenv ICE_MACHINE_ENVINFO "ifort 2021.13.0 20240602, intel mpi 2021.16, netcdf/4.9.0.17" setenv ICE_MACHINE_MAKE gmake setenv ICE_MACHINE_WKDIR $WORKDIR/CICE_RUNS setenv ICE_MACHINE_INPUTDATA /p/app/unsupported/RASM/cice_consortium diff --git a/configuration/scripts/machines/env.carpenter_inteloneapi b/configuration/scripts/machines/env.carpenter_inteloneapi index 2480918c1..62ba8b3c8 100644 --- a/configuration/scripts/machines/env.carpenter_inteloneapi +++ b/configuration/scripts/machines/env.carpenter_inteloneapi @@ -12,15 +12,15 @@ module unload PrgEnv-cray module unload PrgEnv-gnu module unload PrgEnv-intel module unload PrgEnv-pgi -module load PrgEnv-intel/8.5.0 +module load PrgEnv-intel/8.6.0 module unload intel -module load intel-oneapi/2024.2 +module load intel-oneapi/2025.2 module unload cray-mpich module unload mpi module unload openmpi -module load cray-mpich/8.1.30 +module load cray-mpich/8.1.32 #module load mpi/2021.11 #module load openmpi/4.1.6 @@ -29,8 +29,8 @@ module unload cray-hdf5-parallel module unload cray-netcdf-hdf5parallel module unload cray-parallel-netcdf module unload netcdf -module load cray-netcdf/4.9.0.13 -module load cray-hdf5/1.14.3.1 +module load cray-netcdf/4.9.0.17 +module load cray-hdf5/1.14.3.5 setenv NETCDF_PATH ${NETCDF_DIR} limit coredumpsize unlimited @@ -44,7 +44,7 @@ endif setenv ICE_MACHINE_MACHNAME carpenter setenv ICE_MACHINE_MACHINFO "Cray EX4000 AMD 9654 Genoa 2.1GHz, Slingshot Interconnect" setenv ICE_MACHINE_ENVNAME inteloneapi -setenv ICE_MACHINE_ENVINFO "Intel oneAPI DPC++/C++/icx/ifx 2024.2.0 20240602, cray-mpich/8.1.30, netcdf/4.9.0.13" +setenv ICE_MACHINE_ENVINFO "Intel oneAPI DPC++/C++/icx/ifx 2025.2.1 20250806, cray-mpich/8.1.32, netcdf/4.9.0.17" setenv ICE_MACHINE_MAKE gmake setenv ICE_MACHINE_WKDIR $WORKDIR/CICE_RUNS setenv ICE_MACHINE_INPUTDATA /p/app/unsupported/RASM/cice_consortium From 3ed08000a588d24b11257bbb660853df9816259f Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Fri, 19 Dec 2025 15:46:31 -0700 Subject: [PATCH 14/21] documentation for averaging (#1056) There is a great deal of confusion about how various history variables are time-averaged, e.g. SIMIP history output implementation https://github.com/CICE-Consortium/CICE/pull/1038, Fixes for sitemptop, sitempbot, and sitempsnic. https://github.com/CICE-Consortium/CICE/pull/1054. This PR attempts to clarify the situation. These averages are also relevant for conservative coupling. --- doc/source/developer_guide/dg_other.rst | 241 ++++++++++++++++++++++++ 1 file changed, 241 insertions(+) diff --git a/doc/source/developer_guide/dg_other.rst b/doc/source/developer_guide/dg_other.rst index a8f6e8b15..2819fa0eb 100644 --- a/doc/source/developer_guide/dg_other.rst +++ b/doc/source/developer_guide/dg_other.rst @@ -81,6 +81,247 @@ This is very likely to be bfb, but is not as fast or accurate as the reprosum implementation. See :cite:`He01` +.. _averages: + +Averages +----------------- + +Coupling and history output quantities may be averaged in different forms, depending on +whether the quantity represents a value averaged over the entire grid cell, the sea ice fraction, +or a subset of the sea ice fraction such as a thickness category or the ponded area. These +distinctions must also be considered for time averaging. + +The SIMIP Project :cite:`Notz16` +categorizes output variables as 'intensive' and 'extensive' based on their characteristics +relative to ice area. Extensive variables are proportional to area fraction, and their time +averages include zeroes when and where there is no ice. Intensive variables are not +proportional to area fraction, and their time averages should not include zeroes when and +where there is no ice. This is accomplished by summing area-weighted intensive values across categories +then dividing by the sum of the category areas. Tracers such as ice thickness, surface temperature, +and biogeochemical tracers are examples of intensive variables. + +The following formulas ignore subtleties such as some fluxes being computed on the initial ice area, which then +changes due to frazil ice formation, lateral melting and transport. The ice area used for both averaging and coupling should be carefully +considered in light of the model timestepping. Edge cases such as the complete disappearance or new appearance of ice +cause averaging errors. To address these cases, we could consider interpolating all quantities to the middle of the +timestep, but that is not currently done. + +Ice area +~~~~~~~~~~~~~~~~~ + +If :math:`\mathbf{X}=(x,y)`, :math:`A` is the cell area (:math:`m^2`) and :math:`g` represents +the ice thickness distribution discretized as :math:`a_n` for :math:`n=1,\, ncat`, then the +ice area (:math:`m^2`) is the sum of the thickness category areas :math:`a_n A`: + +.. math:: + A_{i}(t) = \int_{ice} g(\mathbf{X},t) \, d\mathbf{X} \sim \sum_{n=1}^{ncat} a_n(t) \, A + +and the (unitless) ice area fraction is + +.. math:: + a_{ice}(t) = {\int_{ice} g(\mathbf{X},t) \, d\mathbf{X} \over \int_{cell} d\mathbf{X} \, dt} \sim \sum_{n=1}^{ncat} a_n(t). + + +The time-averaged ice area over an interval of length :math:`N\Delta t` is + +.. math:: + \bar{A}_{i} = {\int_t A_{i}(t) \, dt \over \int_t \, dt} + \sim {\sum_{\Delta t} \sum_{n=1}^{ncat} a_n \, A \, \Delta t \over N \, \Delta t} + = {A \over N} \sum_{\Delta t} \sum_{n=1}^{ncat} a_n + +and the time-averaged ice area fraction is extensive (by definition): + +.. math:: + \bar{a}_{ice} = {\int_t \int_{ice} g(\mathbf{X},t) \, d\mathbf{X} \, dt \over \int_t \int_{cell} d\mathbf{X} \, dt} + \sim {\sum_{\Delta t} \sum_{n=1}^{ncat} a_n \, A \Delta t \over A \, N \, \Delta t} + = {1 \over N} \sum_{\Delta t} \sum_{n=1}^{ncat} a_n. + +Ice volume +~~~~~~~~~~~~~~~~~ + +Likewise for time averages of ice volume :math:`V_i` (:math:`m^3`), + +.. math:: + \bar{V}_{i} = {\int_t \int_{cell} \int_{0}^{h} g(\mathbf{X},t) \, dz \, d\mathbf{X} \, dt \over \int_{t} dt} + \sim {\sum_{\Delta t} \sum_{n=1}^{ncat} h_n \, a_n \, A \, \Delta t \over N \, \Delta t} + = {A \over N} \sum_{\Delta t} \sum_{n=1}^{ncat} h_n \, a_n + +for ice thickness :math:`h` assumed to be 0 in open water. Then the time-average ice volume per square meter of grid cell (:math:`m`) is + +.. math:: + \bar{v}_{ice} = {\int_t \int_{cell} \int_{0}^{h} g(\mathbf{X},t) \, dz \, d\mathbf{X} \, dt \over \int_{t} \int_{cell} d\mathbf{X} \, dt} + \sim {\sum_{\Delta t} \sum_{n=1}^{ncat} h_n \, a_n \, A \, \Delta t \over A \, N \, \Delta t} + = {1 \over N} \sum_{\Delta t} \sum_{n=1}^{ncat} h_n \, a_n = {1 \over N} \sum_{\Delta t} \sum_{n=1}^{ncat} v_n. + +where :math:`v_n = h_n a_n`. :math:`v_{ice}` is the quantity labeled `hi` in history, which can be thought of as the mean ice thickness averaged over the entire +grid cell. The time-averaged ice volume per square meter of ice (mean 'actual' ice thickness, :math:`m`) is + +.. math:: + \bar{h}_{i} = {\int_t \int_{ice} \int_{0}^{h} g(\mathbf{X},t) \, dz \, d\mathbf{X} \, dt \over \int_{t} \int_{ice} d\mathbf{X} \, dt} + \sim {\sum_{\Delta t} \sum_{n=1}^{ncat} h_n \, a_n \, A \, \Delta t \over \sum_{\Delta t} \sum_{n=1}^{ncat} a_n \, A \, \Delta t} + = {\sum_{\Delta t} \sum_{n=1}^{ncat} v_n \over \sum_{\Delta t} \sum_{n=1}^{ncat} a_n}. + +Snow volume is treated similarly. Ice and snow volumes are extensive, while thicknesses are +intensive. + +The form used here for time-averaging the average 'actual' thickness produces the average over all ice present +during the averaging interval. For intensive variables in particular, this form is slightly different from +the time-average of the category-averaged quantity per time step. The latter, two-step averaging process +requires additional divisions and re-multiplications by ice area, introducing errors where ice areas +are very small or cells change from ice-free to having ice or vice versa. The same is true for other tracers +and intensive variables. While both approaches are valid, averages as written here are preferred when +conservation is important. + +Volume content +~~~~~~~~~~~~~~~~~ + +Total content of tracers such as salt and enthalpy are necessary for conservative coupling. The time-average content +of a volume tracer :math:`b` (with units per :math:`m^3`) is + +.. math:: + \bar{B}_{i} = {\int_t \int_{cell} \int_{0}^{h} b(\mathbf{X},z,t) g(\mathbf{X},t) \, dz \, d\mathbf{X} \, dt \over \int_{t} dt} + \sim {\sum_{\Delta t} \sum_{n=1}^{ncat} b_n \, h_n \, a_n \, A \, \Delta t \over N \, \Delta t} + = {A \over N} \sum_{\Delta t} \sum_{n=1}^{ncat} b_n \, v_n + +and the time-averaged content per square meter of grid cell is + +.. math:: + \bar{b}_{ice} \sim {1 \over N} \sum_{\Delta t} \sum_{n=1}^{ncat} b_n \, v_n. + +The mean tracer value in sea ice is + +.. math:: + \bar{b}_{i} = {\int_t \int_{cell} \int_{0}^{h} b(\mathbf{X},z,t) g(\mathbf{X},t) \, dz \, d\mathbf{X} \, dt \over \int_{t} \int_{cell} \int_{0}^{h} dz \, d\mathbf{X} \, dt} + \sim {\sum_{\Delta t} \sum_{n=1}^{ncat} b_n \, h_n \, a_n \, A \, \Delta t \over \sum_{\Delta t} \sum_{n=1}^{ncat} h_n \, a_n \, A \, \Delta t} + = {\sum_{\Delta t} \sum_{n=1}^{ncat} b_n \, v_n \over \sum_{\Delta t} \sum_{n=1}^{ncat} v_n} + +Thus, volume content variables are extensive, while the tracers themselves are intensive. + +Surface quantities +~~~~~~~~~~~~~~~~~ + +Surface quantities such as temperature are intensive and treated similarly to volume tracers, with integrals taken over +the desired surface area rather than the volume. For example, + +.. math:: + T_{ice}(t) = {\int_{ice} T(\mathbf{X},t) g(\mathbf{X},t) \, d\mathbf{X} \over \int_{ice} g(\mathbf{X},t) \, d\mathbf{X}} + +and the time average is simply + +.. math:: + \bar{T}_{ice} = {\sum_{\Delta t} \sum_{n=1}^{ncat} T_n \, a_n \over \sum_{\Delta t} \sum_{n=1}^{ncat} \, a_n}. + +Note that since :math:`\sum_{n=0}^{ncat} \, a_n \,=\, 1`, a category-merged quantity can be considered the average over the cell area, assuming +the quantity is zero over open water: + +.. math:: + T_{cell} = {\sum_{n=0}^{ncat} T_n \, a_n \over \sum_{n=0}^{ncat} \, a_n} = \sum_{n=1}^{ncat} \, T_n \, a_n, + +and the average value over the ice is then + +.. math:: + T_{ice} = {\sum_{n=1}^{ncat} T_n \, a_n \over \sum_{n=1}^{ncat} \, a_n} = {T_{cell} \over a_{ice}}. + +This simplification is applicable for tracers carried on the ice area (or volume, similarly), which are zero over open water by definition. +When time-averaging CICE's history fields, the category-merged value in the numerator is saved (usually in Icepack), then accumulated in time and +later divided by the accumulated ice area fraction (or volume) in CICE. + + + +Tracer hierarchies +~~~~~~~~~~~~~~~~~ + +For tracers that are carried on other tracers, such as melt ponds, averages over different areas of a given cell differ in the denominator. +For melt ponds not carried on the level-ice area, for example, the average pond depths over the grid cell area, the ice area, and the ponded +area are, respectively, + +.. math:: + h_{p\,cell} = \frac{ \int_{cell} h_p \, a_p \, g \, d\mathbf{X} } + { \int_{cell} d\mathbf{X} } + \sim \sum_{n=1}^{ncat} h_{pn} \, a_{pn} \, a_n + +.. math:: + h_{p\,ice} = \frac{ \int_{ice} h_p \, a_p \, g \, d\mathbf{X} } + { \int_{ice} g \, d\mathbf{X} } + = \frac{ \int_{cell} h_p \, a_p \, g \, d\mathbf{X} } + { \int_{ice} g \, d\mathbf{X} } + \sim \frac{ \sum_{n=1}^{ncat} h_{pn} \, a_{pn} \, a_n }{ \sum_{n=1}^{ncat} a_n } + +.. math:: + h_{p\,pond} = \frac{ \int_{pond} h_p \, a_p \, g \, d\mathbf{X} } + { \int_{pond} a_p \, g \, d\mathbf{X} } + = \frac{ \int_{cell} h_p \, a_p \, g \, d\mathbf{X} } + { \int_{ice} a_p \, g \, d\mathbf{X} } + \sim \frac{ \sum_{n=1}^{ncat} h_{pn} \, a_{pn} \, a_n }{ \sum_{n=1}^{ncat} a_{pn} \, a_n }. + +For level-ice ponds, there is an extra factor of :math:`a_{lvl}`. The level-ice pond depth averaged over the grid cell area, total ice area, level ice area and pond area are + +.. math:: + h_{p\,cell} = \frac{ \int_{cell} h_p \, a_p \, a_{lvl} \, g \, d\mathbf{X} } + { \int_{cell} d\mathbf{X} } + \sim \sum_{n=1}^{ncat} h_{pn} \, a_{pn} \, a_{lvln} \, a_n + +.. math:: + h_{p\,ice} = \frac{ \int_{ice} h_p \, a_p \, a_{lvl} \, g \, d\mathbf{X} } + { \int_{ice} g \, d\mathbf{X} } + = \frac{ \int_{cell} h_p \, a_p \, a_{lvl} \, g \, d\mathbf{X} } + { \int_{ice} g \, d\mathbf{X} } + \sim \frac{ \sum_{n=1}^{ncat} h_{pn} \, a_{pn} \, a_{lvln} \, a_n }{ \sum_{n=1}^{ncat} a_n } + +.. math:: + h_{p\,lvl} = \frac{ \int_{lvl} h_p \, a_p \, a_{lvl} \, g \, d\mathbf{X} } + { \int_{lvl} a_{lvl} \, g \, d\mathbf{X} } + = \frac{ \int_{cell} h_p \, a_p \, a_{lvl} \, g \, d\mathbf{X} } + { \int_{ice} a_{lvl} \, a_{pn} \, g \, d\mathbf{X} } + \sim \frac{ \sum_{n=1}^{ncat} h_{pn} \, a_{pn} \, a_{lvln} \, a_n }{ \sum_{n=1}^{ncat} a_{lvln} \, a_n } + +.. math:: + h_{p\,pond} = \frac{ \int_{pond} h_p \, a_p \, a_{lvl} \, g \, d\mathbf{X} } + { \int_{pond} a_p \, a_{lvl} \, g \, d\mathbf{X} } + = \frac{ \int_{cell} h_p \, a_p \, a_{lvl} \, g \, d\mathbf{X} } + { \int_{ice} a_p \, a_{lvl} \, g \, d\mathbf{X} } + \sim \frac{ \sum_{n=1}^{ncat} h_{pn} \, a_{pn} \, a_{lvln} \, a_n }{ \sum_{n=1}^{ncat} a_{pn} \, a_{lvln} \, a_n }. + +Time averages follow analogously as above. + +Ridged-ice area and volume are handled slightly differently, since they are diagnostic based on +level-ice area and volume. Level-ice area is a tracer on ice area, and level-ice volume is a +tracer on ice volume. The tracer values are fractions of the total ice, and ridged (deformed) ice is +diagnosed as the remainder of the ice fraction or volume: +:math:`T_{ardg} = 1 - T_{alvl}` and :math:`T_{vrdg} = 1 - T_{vlvl}` for the area and volume tracers. +Thus the mean level and ridged ice area fractions of the ice area are + +.. math:: + a_{lvl\,ice} = \frac{ \int_{ice} T_{alvl} \, g \, d\mathbf{X} } + { \int_{ice} g \, d\mathbf{X} } + \sim \frac{ \sum_{n=1}^{ncat} a_{lvln} \, a_n }{ \sum_{n=1}^{ncat} a_n } + +.. math:: + a_{rdg\,ice} = \frac{ \int_{ice} (1 - T_{alvl}) \, g \, d\mathbf{X} } + { \int_{ice} g \, d\mathbf{X} } + \sim \frac{ \sum_{n=1}^{ncat} (1 - a_{lvln}) \, a_n }{ \sum_{n=1}^{ncat} a_n }. + +The mean thickness of level ice, averaging over just the level-ice areas from all categories, is + +.. math:: + h_{lvl} = \frac{ \int_{ice} \int_{0}^{h} T_{vlvl} \, g \, dz \, d\mathbf{X} } + { \int_{ice} T_{alvl} \, g \, d\mathbf{X} } + \sim \frac{ \sum_{n=1}^{ncat} T_{vlvln} \, a_n \, h_n } + { \sum_{n=1}^{ncat} T_{alvln} \, a_n } + \sim \frac{ \sum_{n=1}^{ncat} T_{vlvln} \, v_n } + { \sum_{n=1}^{ncat} T_{alvln} \, a_n } + +and the mean thickness of deformed ice (averaging over just the ridged-ice +areas from all categories) is + +.. math:: + h_{rdg} = \frac{ \int_{ice} \int_{0}^{h} (1 - T_{vlvl}) \, g \, dz \, d\mathbf{X} } + { \int_{ice} (1 - T_{alvl}) \, g \, d\mathbf{X} } + \sim \frac{ \sum_{n=1}^{ncat} (1 - T_{vlvln}) \, a_n \, h_n } + { \sum_{n=1}^{ncat} (1 - T_{alvln}) \, a_n } + \sim \frac{ \sum_{n=1}^{ncat} (1 - T_{vlvln}) \, v_n } + { \sum_{n=1}^{ncat} (1 - T_{alvln}) \, a_n }. + .. _addtimer: Adding Timers From 26a5cfeaf9794a63396fbf3b6e8b91d9724f5334 Mon Sep 17 00:00:00 2001 From: Tony Craig Date: Thu, 8 Jan 2026 14:50:54 -0800 Subject: [PATCH 15/21] Add ability to read an extended grid (supported for pop netcdf file format) (#1079) Add ability to read an extended grid (supported for pop netcdf file format) Add subroutine popgrid_nc_ext to read an extended grid pop netcdf file Add 'nc_ext' option to grid_format namelist The extended grid will apply to the kmt file as well as these are specified by the same grid_format namelist Modify gridbox_verts to operate on a local array instead of a global array, this should improve performance and removes redundant extrapolation calculations. This approach also supports both regular and extended grid reads. The implementation largely duplicates subroutine popgrid_nc but for an extended grid in subroutine popgrid_nc_ext. The extended grid represents the active points plus the full halo. As much as possible, the extended grid (LON, LAT, ANGLE, KMT) is read in on the halo instead of being computed. For some grid metrics (DXT, DYT, DXU, DYU, etc), extrapolation is still required onto the halo. Remove some trailing blanks is other places as needed. --- cicecore/cicedyn/general/ice_init.F90 | 4 +- .../comm/serial/ice_boundary.F90 | 2 +- .../cicedyn/infrastructure/ice_blocks.F90 | 2 +- cicecore/cicedyn/infrastructure/ice_grid.F90 | 389 +++++++++++++----- .../infrastructure/io/io_pio2/ice_restart.F90 | 2 +- cicecore/drivers/unittest/halochk/halochk.F90 | 8 +- doc/source/user_guide/ug_case_settings.rst | 1 + 7 files changed, 290 insertions(+), 118 deletions(-) diff --git a/cicecore/cicedyn/general/ice_init.F90 b/cicecore/cicedyn/general/ice_init.F90 index 8a139883f..15e35ba0e 100644 --- a/cicecore/cicedyn/general/ice_init.F90 +++ b/cicecore/cicedyn/general/ice_init.F90 @@ -1259,7 +1259,8 @@ subroutine input_data if (trim(ice_data_type) == 'default') ice_data_type = 'latsst' ! For backward compatibility - if (grid_format == 'nc') grid_format = 'pop_nc' + if (grid_format == 'nc' ) grid_format = 'pop_nc' + if (grid_format == 'nc_ext') grid_format = 'pop_nc_ext' !----------------------------------------------------------------- ! verify inputs @@ -2757,6 +2758,7 @@ subroutine input_data endif ! my_task = master_task if (grid_format /= 'pop_nc' .and. & + grid_format /= 'pop_nc_ext' .and. & grid_format /= 'mom_nc' .and. & grid_format /= 'geosnc' .and. & grid_format /= 'meshnc' .and. & diff --git a/cicecore/cicedyn/infrastructure/comm/serial/ice_boundary.F90 b/cicecore/cicedyn/infrastructure/comm/serial/ice_boundary.F90 index f185da3c5..205f2150b 100644 --- a/cicecore/cicedyn/infrastructure/comm/serial/ice_boundary.F90 +++ b/cicecore/cicedyn/infrastructure/comm/serial/ice_boundary.F90 @@ -783,7 +783,7 @@ subroutine ice_HaloUpdate2DR8(array, halo, & !----------------------------------------------------------------------- if (.not. ltripoleOnly) then - ! tripoleOnly skip fill, do not overwrite any values in interior as they may + ! tripoleOnly skip fill, do not overwrite any values in interior as they may ! already be set and filling tripole is not necessary ! fill outer boundary as needed diff --git a/cicecore/cicedyn/infrastructure/ice_blocks.F90 b/cicecore/cicedyn/infrastructure/ice_blocks.F90 index 513f3c06f..245f77bc7 100644 --- a/cicecore/cicedyn/infrastructure/ice_blocks.F90 +++ b/cicecore/cicedyn/infrastructure/ice_blocks.F90 @@ -161,7 +161,7 @@ subroutine create_blocks(nx_global, ny_global, ew_boundary_type, & ! the global index will go from -nghost+1:0 on the lower boundary ! and n*_global+1:n*_global+nghost on the upper boundary and the ! haloUpdate and scatter, for instance, will not fill those values -! in those cases. Other boundary condition methods will fill the +! in those cases. Other boundary condition methods will fill the ! outer halo values in cases where ice exists on those boundaries. ! !---------------------------------------------------------------------- diff --git a/cicecore/cicedyn/infrastructure/ice_grid.F90 b/cicecore/cicedyn/infrastructure/ice_grid.F90 index 406cff6d2..13a1aa098 100644 --- a/cicecore/cicedyn/infrastructure/ice_grid.F90 +++ b/cicecore/cicedyn/infrastructure/ice_grid.F90 @@ -36,7 +36,7 @@ module ice_grid ew_boundary_type, ns_boundary_type, init_domain_distribution use ice_fileunits, only: nu_diag, nu_grid, nu_kmt, & get_fileunit, release_fileunit, flush_fileunit - use ice_gather_scatter, only: gather_global, scatter_global, gather_global_ext + use ice_gather_scatter, only: gather_global, scatter_global, gather_global_ext, scatter_global_ext use ice_read_write, only: ice_read, ice_read_nc, ice_read_global, & ice_read_global_nc, ice_open, ice_open_nc, ice_close_nc, ice_check_nc use ice_timers, only: timer_bound, ice_timer_start, ice_timer_stop @@ -366,7 +366,7 @@ subroutine init_grid1 fieldname ! field name in netCDF file real (kind=dbl_kind), dimension(:,:), allocatable :: & - work_g1, work_g2, work_mom + work_g1, work_g2, work_g1x, work_mom integer (kind=int_kind) :: & max_blocks_min, & ! min value of max_blocks across procs @@ -453,6 +453,17 @@ subroutine init_grid1 call ice_read_global_nc(fid_grid,1,fieldname,work_g1,.true.) call ice_close_nc(fid_grid) + case('pop_nc_ext') + + fieldname='ulat' + call ice_open_nc(grid_file,fid_grid) + allocate(work_g1x(nx_global+2*nghost, ny_global+2*nghost), stat=ierr) + if (ierr/=0) call abort_ice(subname//' ERROR: Out of memory', file=__FILE__, line=__LINE__) + call ice_read_global_nc(fid_grid,1,fieldname,work_g1x,.true.) + work_g1(1:nx_global,1:ny_global) = work_g1x(1+nghost:nx_global+nghost,1+nghost:ny_global+nghost) + deallocate(work_g1x) + call ice_close_nc(fid_grid) + case default call ice_open(nu_grid,grid_file,64) @@ -468,7 +479,7 @@ subroutine init_grid1 ! Fill kmt if (trim(kmt_type) =='file') then select case(trim(grid_format)) - case ('mom_nc', 'pop_nc', 'geosnc') + case ('mom_nc', 'pop_nc', 'pop_nc_ext', 'geosnc') ! mask variable name might be kmt or mask, check both call ice_open_nc(kmt_file,fid_kmt) @@ -487,7 +498,15 @@ subroutine init_grid1 #endif call broadcast_scalar(mask_fieldname, master_task) - call ice_read_global_nc(fid_kmt,1,mask_fieldname,work_g2,.true.) + if (trim(grid_format) == 'pop_nc_ext') then + allocate(work_g1x(nx_global+2*nghost, ny_global+2*nghost), stat=ierr) + if (ierr/=0) call abort_ice(subname//' ERROR: Out of memory', file=__FILE__, line=__LINE__) + call ice_read_global_nc(fid_kmt,1,mask_fieldname,work_g1x,.true.) + work_g2(1:nx_global,1:ny_global) = work_g1x(1+nghost:nx_global+nghost,1+nghost:ny_global+nghost) + deallocate(work_g1x) + else + call ice_read_global_nc(fid_kmt,1,mask_fieldname,work_g2,.true.) + endif call ice_close_nc(fid_kmt) case default @@ -593,6 +612,8 @@ subroutine init_grid2 call mom_grid ! derive cice grid from MOM supergrid nc file case ('pop_nc') call popgrid_nc ! read POP grid lengths from nc file + case ('pop_nc_ext') + call popgrid_nc_ext ! read POP extended grid lengths from nc file case ('geosnc') call geosgrid_nc ! read GEOS MOM grid used from nc file case default @@ -614,6 +635,8 @@ subroutine init_grid2 select case (trim(grid_format)) case('mom_nc', 'pop_nc' ,'geosnc') call kmtmask('nc') + case('pop_nc_ext') + call kmtmask('nc_ext') case default call kmtmask('bin') end select @@ -922,8 +945,14 @@ subroutine kmtmask(filetype) elseif (filetype == 'nc') then call ice_open_nc(kmt_file,fid_kmt) call ice_read_nc(fid_kmt,1,mask_fieldname,kmt,diag, & - field_loc=field_loc_center, & - field_type=field_type_scalar) + field_loc=field_loc_center, & + field_type=field_type_scalar) + call ice_close_nc(fid_kmt) + elseif (filetype == 'nc_ext') then + call ice_open_nc(kmt_file,fid_kmt) + call ice_read_nc(fid_kmt,1,mask_fieldname,kmt,diag,restart_ext=.true., & + field_loc=field_loc_center, & + field_type=field_type_scalar) call ice_close_nc(fid_kmt) else call abort_ice(subname//' ERROR: invalid filetype='//trim(filetype), file=__FILE__, line=__LINE__) @@ -936,7 +965,6 @@ subroutine kmtmask(filetype) ihi = this_block%ihi jlo = this_block%jlo jhi = this_block%jhi - do j = jlo, jhi do i = ilo, ihi ! force grid cells to land if ocn_gridcell_frac is defined @@ -944,6 +972,10 @@ subroutine kmtmask(filetype) ocn_gridcell_frac(i,j,iblk) < puny) then kmt(i,j,iblk) = c0 endif + enddo + enddo + do j = 1,ny_block + do i = 1,nx_block if (kmt(i,j,iblk) >= p5) hm(i,j,iblk) = c1 enddo enddo @@ -988,18 +1020,18 @@ subroutine popgrid if (ierr/=0) call abort_ice(subname//' ERROR: Out of memory', file=__FILE__, line=__LINE__) call ice_read_global(nu_grid,1,work_g1,'rda8',.true.) ! ULAT - call gridbox_verts(work_g1,latt_bounds) call scatter_global(ULAT, work_g1, master_task, distrb_info, & field_loc_NEcorner, field_type_scalar) call ice_HaloExtrapolate(ULAT, distrb_info, & ew_boundary_type, ns_boundary_type) + call gridbox_verts(ULAT,latt_bounds) call ice_read_global(nu_grid,2,work_g1,'rda8',.true.) ! ULON - call gridbox_verts(work_g1,lont_bounds) call scatter_global(ULON, work_g1, master_task, distrb_info, & field_loc_NEcorner, field_type_scalar) call ice_HaloExtrapolate(ULON, distrb_info, & ew_boundary_type, ns_boundary_type) + call gridbox_verts(ULON,lont_bounds) call ice_read_global(nu_grid,7,work_g1,'rda8',.true.) ! ANGLE call scatter_global(ANGLE, work_g1, master_task, distrb_info, & @@ -1090,19 +1122,19 @@ subroutine popgrid_nc fieldname='ulat' call ice_read_global_nc(fid_grid,1,fieldname,work_g1,diag) ! ULAT - call gridbox_verts(work_g1,latt_bounds) call scatter_global(ULAT, work_g1, master_task, distrb_info, & field_loc_NEcorner, field_type_scalar) call ice_HaloExtrapolate(ULAT, distrb_info, & ew_boundary_type, ns_boundary_type) + call gridbox_verts(ULAT,latt_bounds) fieldname='ulon' call ice_read_global_nc(fid_grid,1,fieldname,work_g1,diag) ! ULON - call gridbox_verts(work_g1,lont_bounds) call scatter_global(ULON, work_g1, master_task, distrb_info, & field_loc_NEcorner, field_type_scalar) call ice_HaloExtrapolate(ULON, distrb_info, & ew_boundary_type, ns_boundary_type) + call gridbox_verts(ULON,lont_bounds) fieldname='angle' call ice_read_global_nc(fid_grid,1,fieldname,work_g1,diag) ! ANGLE @@ -1172,6 +1204,210 @@ subroutine popgrid_nc end subroutine popgrid_nc +!======================================================================= +! POP extended displaced pole grid and land mask. +! Grid record number, field and units are: \\ +! (1) ULAT (radians) \\ +! (2) ULON (radians) \\ +! (3) HTN (cm) \\ +! (4) HTE (cm) \\ +! (5) HUS (cm) \\ +! (6) HUW (cm) \\ +! (7) ANGLE (radians) +! +! author: T. Craig +! Revised for netcdf input: Ann Keen, Met Office, May 2007 + + subroutine popgrid_nc_ext + +#ifdef USE_NETCDF + use netcdf, only : nf90_inq_varid , nf90_inq_dimid, & + nf90_inquire_dimension, nf90_get_var, nf90_noerr +#endif + + integer (kind=int_kind) :: & + i, j, iblk, & + ilo,ihi,jlo,jhi, & ! beginning and end of physical domain + fid_grid , & ! file id for netCDF grid file + ierr + + logical (kind=log_kind) :: diag + + character (char_len) :: & + fieldname ! field name in netCDF file + + real (kind=dbl_kind) :: & + pi + + real (kind=dbl_kind), dimension(:,:), allocatable :: & + work_g1x ! temporary global extended array + + integer(kind=int_kind) :: & + varid, status + + type (block) :: & + this_block ! block information for current block + + character(len=*), parameter :: subname = '(popgrid_nc_ext)' + +#ifdef USE_NETCDF + call icepack_query_parameters(pi_out=pi) + call icepack_warnings_flush(nu_diag) + if (icepack_warnings_aborted()) call abort_ice(error_message=subname, & + file=__FILE__, line=__LINE__) + + call ice_open_nc(grid_file,fid_grid) + + diag = .true. ! write diagnostic info + + !----------------------------------------------------------------- + ! lat, lon, angle + !----------------------------------------------------------------- + + allocate(work_g1x(nx_global+2*nghost,ny_global+2*nghost), stat=ierr) + if (ierr/=0) call abort_ice(subname//' ERROR: Out of memory', file=__FILE__, line=__LINE__) + work_g1x = c0 + + fieldname='ulat' + call ice_read_global_nc(fid_grid,1,fieldname,work_g1x,diag) ! ULAT + call scatter_global_ext(ULAT, work_g1x, master_task, distrb_info) + call gridbox_verts(ULAT,latt_bounds) + + fieldname='ulon' + call ice_read_global_nc(fid_grid,1,fieldname,work_g1x,diag) ! ULON + call scatter_global_ext(ULON, work_g1x, master_task, distrb_info) + call gridbox_verts(ULON,lont_bounds) + + fieldname='angle' + call ice_read_global_nc(fid_grid,1,fieldname,work_g1x,diag) ! ANGLE + call scatter_global_ext(ANGLE, work_g1x, master_task, distrb_info) + ! fix ANGLE: roundoff error due to single precision + where (ANGLE > pi) ANGLE = pi + where (ANGLE < -pi) ANGLE = -pi + + ! if grid file includes anglet then read instead + fieldname='anglet' + if (my_task == master_task) then + status = nf90_inq_varid(fid_grid, fieldname , varid) + if (status /= nf90_noerr) then + write(nu_diag,*) subname//' CICE will calculate angleT, TLON and TLAT' + else + write(nu_diag,*) subname//' angleT, TLON and TLAT is read from grid file' + l_readCenter = .true. + endif + endif + call broadcast_scalar(l_readCenter,master_task) + if (l_readCenter) then + call ice_read_global_nc(fid_grid,1,fieldname,work_g1x,diag) + call scatter_global_ext(ANGLET, work_g1x, master_task, distrb_info) + where (ANGLET > pi) ANGLET = pi + where (ANGLET < -pi) ANGLET = -pi + + fieldname="tlon" + call ice_read_global_nc(fid_grid,1,fieldname,work_g1x,diag) + call scatter_global_ext(TLON, work_g1x, master_task, distrb_info) + + fieldname="tlat" + call ice_read_global_nc(fid_grid,1,fieldname,work_g1x,diag) + call scatter_global_ext(TLAT, work_g1x, master_task, distrb_info) + endif + !----------------------------------------------------------------- + ! cell dimensions + ! calculate derived quantities from global arrays to preserve + ! information on boundaries + !----------------------------------------------------------------- + + fieldname='htn' + call ice_read_global_nc(fid_grid,1,fieldname,work_g1x,diag) ! HTN + if (my_task == master_task) then + work_g1x(:,:) = work_g1x(:,:) * cm_to_m ! HTN + endif +! call primary_grid_lengths_HTN(work_g1) ! dxU, dxT, dxN, dxE + if (save_ghte_ghtn) then + if (my_task == master_task) then + G_HTN = work_g1x + endif + endif + call scatter_global_ext(HTN, work_g1x, master_task, distrb_info) + + dxN(:,:,:) = HTN(:,:,:) + do iblk = 1, nblocks + this_block = get_block(blocks_ice(iblk),iblk) + ilo = this_block%ilo + ihi = this_block%ihi + jlo = this_block%jlo + jhi = this_block%jhi + do j = jlo, jhi + do i = ilo, ihi + dxU(i,j,iblk) = p5*(HTN(i,j,iblk)+HTN(i+1,j,iblk)) + dxT(i,j,iblk) = p5*(HTN(i,j,iblk)+HTN(i,j-1,iblk)) + dxE(i,j,iblk) = p25*(HTN(i,j,iblk)+HTN(i+1,j,iblk)+HTN(i,j-1,iblk)+HTN(i+1,j-1,iblk)) + enddo + enddo + enddo + call ice_HaloUpdate (dxU, halo_info, & + field_loc_center, field_type_scalar) + call ice_HaloExtrapolate(dxU, distrb_info, & + ew_boundary_type, ns_boundary_type) + call ice_HaloUpdate (dxT, halo_info, & + field_loc_center, field_type_scalar) + call ice_HaloExtrapolate(dxT, distrb_info, & + ew_boundary_type, ns_boundary_type) + call ice_HaloUpdate (dxE, halo_info, & + field_loc_center, field_type_scalar) + call ice_HaloExtrapolate(dxE, distrb_info, & + ew_boundary_type, ns_boundary_type) + + fieldname='hte' + call ice_read_global_nc(fid_grid,1,fieldname,work_g1x,diag) ! HTE + if (my_task == master_task) then + work_g1x(:,:) = work_g1x(:,:) * cm_to_m ! HTN + endif +! call primary_grid_lengths_HTE(work_g1) ! dyU, dyT, dyN, dyE + if (save_ghte_ghtn) then + G_HTE = work_g1x + endif + call scatter_global_ext(HTE, work_g1x, master_task, distrb_info) + dyE(:,:,:) = HTE(:,:,:) + do iblk = 1, nblocks + this_block = get_block(blocks_ice(iblk),iblk) + ilo = this_block%ilo + ihi = this_block%ihi + jlo = this_block%jlo + jhi = this_block%jhi + do j = jlo, jhi + do i = ilo, ihi + dyU(i,j,iblk) = p5*(HTE(i,j,iblk)+HTE(i,j+1,iblk)) + dyT(i,j,iblk) = p5*(HTE(i,j,iblk)+HTE(i-1,j,iblk)) + dyN(i,j,iblk) = p25*(HTE(i,j,iblk)+HTE(i-1,j,iblk)+HTE(i,j+1,iblk)+HTE(i-1,j+1,iblk)) + enddo + enddo + enddo + call ice_HaloUpdate (dyU, halo_info, & + field_loc_center, field_type_scalar) + call ice_HaloExtrapolate(dyU, distrb_info, & + ew_boundary_type, ns_boundary_type) + call ice_HaloUpdate (dyT, halo_info, & + field_loc_center, field_type_scalar) + call ice_HaloExtrapolate(dyT, distrb_info, & + ew_boundary_type, ns_boundary_type) + call ice_HaloUpdate (dyN, halo_info, & + field_loc_center, field_type_scalar) + call ice_HaloExtrapolate(dyN, distrb_info, & + ew_boundary_type, ns_boundary_type) + + deallocate(work_g1x, stat=ierr) + if (ierr/=0) call abort_ice(subname//' ERROR: Dealloc error', file=__FILE__, line=__LINE__) + + call ice_close_nc(fid_grid) + +#else + call abort_ice(subname//' ERROR: USE_NETCDF cpp not defined', & + file=__FILE__, line=__LINE__) +#endif + + end subroutine popgrid_nc_ext + #ifdef CESMCOUPLED !======================================================================= ! Read in kmt file that matches CAM lat-lon grid and has single column @@ -2234,19 +2470,19 @@ subroutine geosgrid_nc fieldname='ulat' call ice_read_global_nc(fid_grid,1,fieldname,work_g1,diag) ! ULAT - call gridbox_verts(work_g1,latt_bounds) call scatter_global(ULAT, work_g1, master_task, distrb_info, & field_loc_NEcorner, field_type_scalar) call ice_HaloExtrapolate(ULAT, distrb_info, & ew_boundary_type, ns_boundary_type) + call gridbox_verts(ULAT,latt_bounds) fieldname='ulon' call ice_read_global_nc(fid_grid,1,fieldname,work_g1,diag) ! ULON - call gridbox_verts(work_g1,lont_bounds) call scatter_global(ULON, work_g1, master_task, distrb_info, & field_loc_NEcorner, field_type_scalar) call ice_HaloExtrapolate(ULON, distrb_info, & ew_boundary_type, ns_boundary_type) + call gridbox_verts(ULON,lont_bounds) fieldname='angle' call ice_read_global_nc(fid_grid,1,fieldname,work_g1,diag) ! ANGLE @@ -2845,7 +3081,7 @@ subroutine primary_grid_lengths_HTN(work_g) enddo do j = 1, ny_global do i = 1, nx_global - ! assume cyclic; noncyclic will be handled during scatter + ! assume cyclic; noncyclic will be handled during extrapolate ip1 = i+1 if (i == nx_global) ip1 = 1 work_g2(i,j) = p5*(work_g(i,j) + work_g(ip1,j)) ! dxU @@ -2891,7 +3127,7 @@ subroutine primary_grid_lengths_HTN(work_g) if (my_task == master_task) then do j = 2, ny_global do i = 1, nx_global - ! assume cyclic; noncyclic will be handled during scatter + ! assume cyclic; noncyclic will be handled during extrapolate ip1 = i+1 if (i == nx_global) ip1 = 1 work_g2(i,j) = p25*(work_g(i,j)+work_g(ip1,j)+work_g(i,j-1)+work_g(ip1,j-1)) ! dxE @@ -2899,7 +3135,7 @@ subroutine primary_grid_lengths_HTN(work_g) enddo ! extrapolate to obtain dxT along j=1 do i = 1, nx_global - ! assume cyclic; noncyclic will be handled during scatter + ! assume cyclic; noncyclic will be handled during extrapolate ip1 = i+1 if (i == nx_global) ip1 = 1 work_g2(i,1) = p5*(c2*work_g(i ,2) - work_g(i ,3) + & @@ -2983,7 +3219,7 @@ subroutine primary_grid_lengths_HTE(work_g) if (my_task == master_task) then do j = 1, ny_global do i = 1, nx_global - ! assume cyclic; noncyclic will be handled during scatter + ! assume cyclic; noncyclic will be handled during extrapolate im1 = i-1 if (i == 1) im1 = nx_global work_g2(i,j) = p5*(work_g(i,j) + work_g(im1,j)) ! dyT @@ -3000,7 +3236,7 @@ subroutine primary_grid_lengths_HTE(work_g) if (my_task == master_task) then do j = 1, ny_global-1 do i = 1, nx_global - ! assume cyclic; noncyclic will be handled during scatter + ! assume cyclic; noncyclic will be handled during extrapolate im1 = i-1 if (i == 1) im1 = nx_global work_g2(i,j) = p25*(work_g(i,j) + work_g(im1,j) + work_g(i,j+1) + work_g(im1,j+1)) ! dyN @@ -3009,7 +3245,7 @@ subroutine primary_grid_lengths_HTE(work_g) ! extrapolate to obtain dyN along j=ny_global if (ny_global > 1) then do i = 1, nx_global - ! assume cyclic; noncyclic will be handled during scatter + ! assume cyclic; noncyclic will be handled during extrapolate im1 = i-1 if (i == 1) im1 = nx_global work_g2(i,ny_global) = p5*(c2*work_g(i ,ny_global-1) - work_g(i ,ny_global-2) + & @@ -5267,27 +5503,25 @@ end subroutine gridbox_edges ! ! authors: A. McLaren, Met Office ! E. Hunke, LANL +! T. Craig - subroutine gridbox_verts(work_g,vbounds) + subroutine gridbox_verts(work,vbounds) - real (kind=dbl_kind), dimension(:,:), intent(in) :: & - work_g + real (kind=dbl_kind), dimension(:,:,:), intent(in) :: & + work real (kind=dbl_kind), dimension(4,nx_block,ny_block,max_blocks), intent(out) :: & - vbounds + vbounds integer (kind=int_kind) :: & - i,j , & ! index counters + iblk,i,j,ilo,ihi,jlo,jhi, & ! index counters ierr - real (kind=dbl_kind) :: & - rad_to_deg - - real (kind=dbl_kind), dimension(:,:), allocatable :: & - work_g2 + type (block) :: & + this_block ! block information for current block - real (kind=dbl_kind), dimension (nx_block,ny_block,max_blocks) :: & - work1 + real (kind=dbl_kind) :: & + rad_to_deg character(len=*), parameter :: subname = '(gridbox_verts)' @@ -5296,87 +5530,22 @@ subroutine gridbox_verts(work_g,vbounds) if (icepack_warnings_aborted()) call abort_ice(error_message=subname, & file=__FILE__, line=__LINE__) - if (my_task == master_task) then - allocate(work_g2(nx_global,ny_global), stat=ierr) - else - allocate(work_g2(1,1), stat=ierr) - endif - if (ierr/=0) call abort_ice(subname//' ERROR: Out of memory', file=__FILE__, line=__LINE__) - - !------------------------------------------------------------- - ! Get coordinates of grid boxes for each block as follows: - ! (1) SW corner, (2) SE corner, (3) NE corner, (4) NW corner - !------------------------------------------------------------- - - work_g2(:,:) = c0 - if (my_task == master_task) then - do j = 2, ny_global - do i = 2, nx_global - work_g2(i,j) = work_g(i-1,j-1) * rad_to_deg - enddo - enddo - ! extrapolate - do j = 1, ny_global - work_g2(1,j) = c2*work_g2(2,j) - work_g2(3,j) - enddo - do i = 1, nx_global - work_g2(i,1) = c2*work_g2(i,2) - work_g2(i,3) - enddo - endif - call scatter_global(work1, work_g2, & - master_task, distrb_info, & - field_loc_NEcorner, field_type_scalar) - vbounds(1,:,:,:) = work1(:,:,:) - - work_g2(:,:) = c0 - if (my_task == master_task) then - do j = 2, ny_global - do i = 1, nx_global - work_g2(i,j) = work_g(i,j-1) * rad_to_deg - enddo - enddo - ! extrapolate - do i = 1, nx_global - work_g2(i,1) = (c2*work_g2(i,2) - work_g2(i,3)) - enddo - endif - call scatter_global(work1, work_g2, & - master_task, distrb_info, & - field_loc_NEcorner, field_type_scalar) - vbounds(2,:,:,:) = work1(:,:,:) - - work_g2(:,:) = c0 - if (my_task == master_task) then - do j = 1, ny_global - do i = 1, nx_global - work_g2(i,j) = work_g(i,j) * rad_to_deg - enddo - enddo - endif - call scatter_global(work1, work_g2, & - master_task, distrb_info, & - field_loc_NEcorner, field_type_scalar) - vbounds(3,:,:,:) = work1(:,:,:) - - work_g2(:,:) = c0 - if (my_task == master_task) then - do j = 1, ny_global - do i = 2, nx_global - work_g2(i,j) = work_g(i-1,j ) * rad_to_deg - enddo + vbounds = c0 + do iblk = 1, nblocks + this_block = get_block(blocks_ice(iblk),iblk) + ilo = this_block%ilo + ihi = this_block%ihi + jlo = this_block%jlo + jhi = this_block%jhi + do j = jlo, jhi + do i = ilo, ihi + vbounds(1,i,j,iblk) = work(i-1,j-1,iblk)*rad_to_deg + vbounds(2,i,j,iblk) = work(i ,j-1,iblk)*rad_to_deg + vbounds(3,i,j,iblk) = work(i ,j ,iblk)*rad_to_deg + vbounds(4,i,j,iblk) = work(i-1,j ,iblk)*rad_to_deg enddo - ! extrapolate - do j = 1, ny_global - work_g2(1,j) = c2*work_g2(2,j) - work_g2(3,j) enddo - endif - call scatter_global(work1, work_g2, & - master_task, distrb_info, & - field_loc_NEcorner, field_type_scalar) - vbounds(4,:,:,:) = work1(:,:,:) - - deallocate (work_g2, stat=ierr) - if (ierr/=0) call abort_ice(subname//' ERROR: Dealloc error', file=__FILE__, line=__LINE__) + enddo end subroutine gridbox_verts diff --git a/cicecore/cicedyn/infrastructure/io/io_pio2/ice_restart.F90 b/cicecore/cicedyn/infrastructure/io/io_pio2/ice_restart.F90 index 37cf4d985..0186d73f2 100644 --- a/cicecore/cicedyn/infrastructure/io/io_pio2/ice_restart.F90 +++ b/cicecore/cicedyn/infrastructure/io/io_pio2/ice_restart.F90 @@ -224,7 +224,7 @@ subroutine init_restart_write(filename_spec) ! write pointer (path/file) if (my_task == master_task) then -#ifdef CESMCOUPLED +#ifdef CESMCOUPLED lpointer_file = 'rpointer.ice'//trim(inst_suffix) #else lpointer_file = pointer_file diff --git a/cicecore/drivers/unittest/halochk/halochk.F90 b/cicecore/drivers/unittest/halochk/halochk.F90 index 2fecaf31e..6e7ff4173 100644 --- a/cicecore/drivers/unittest/halochk/halochk.F90 +++ b/cicecore/drivers/unittest/halochk/halochk.F90 @@ -450,15 +450,15 @@ program halochk k1m = 1 k2m = 1 halofld = '2DL1' - where (darrayi1 == fillval) + where (darrayi1 == fillval) larrayi1 = .false. elsewhere - larrayi1 = (mod(nint(darrayi1),2) == 1) + larrayi1 = (mod(nint(darrayi1),2) == 1) endwhere - where (darrayj1 == fillval) + where (darrayj1 == fillval) larrayj1 = .true. elsewhere - larrayj1 = (mod(nint(darrayj1),2) == 1) + larrayj1 = (mod(nint(darrayj1),2) == 1) endwhere if (halofill) then call ice_haloUpdate(larrayi1, halo_info, field_loc(nl), field_type(nt), fillvalue=0) diff --git a/doc/source/user_guide/ug_case_settings.rst b/doc/source/user_guide/ug_case_settings.rst index 3882073de..486dfdfc1 100644 --- a/doc/source/user_guide/ug_case_settings.rst +++ b/doc/source/user_guide/ug_case_settings.rst @@ -311,6 +311,7 @@ grid_nml "``grid_format``", "``bin``", "read direct access grid and kmt files", "``bin``" "", "``geosnc``", "read grid and kmt file in GEOS netcdf format", "" "", "``pop_nc``", "read grid and kmt files in POP netcdf format", "" + "", "``pop_nc_ext``", "read extended grid and kmt files in POP netcdf format", "" "", "``meshnc``", "coupled model grid option, no CICE code support", "" "", "``mom_nc``", "read grid in MOM (supergrid) format and kmt files", "" "``grid_ice``", "``B``", "use B grid structure with T at center and U at NE corner", "``B``" From a4f8ba9e6859c4c6adbb0467c71429713a41dc4d Mon Sep 17 00:00:00 2001 From: Elizabeth Hunke Date: Fri, 9 Jan 2026 16:47:47 -0700 Subject: [PATCH 16/21] Add wave_height_type options (#1071) Adds a namelist flag to allow significant wave height to be passed into the ice model from a coupler. In addition, this PR moves wave_spec_height out of icepack interface argument lists, since it is initialized via icepack_init_parameters. See CICE-Consortium/Icepack#545 Update Icepack to #0bcde255637a594 Update ice_step_mod.F90 in opticep unit test to be consistent with latest changes --------- Co-authored-by: apcraig --- cicecore/cicedyn/general/ice_init.F90 | 38 +++++- cicecore/cicedyn/general/ice_step_mod.F90 | 26 ++-- .../drivers/unittest/opticep/ice_step_mod.F90 | 129 +++++++++--------- cicecore/shared/ice_arrays_column.F90 | 2 +- cicecore/shared/ice_init_column.F90 | 2 +- configuration/scripts/ice_in | 1 + configuration/scripts/options/set_nml.fsd1 | 1 + configuration/scripts/options/set_nml.fsd12 | 1 + .../scripts/options/set_nml.fsd12ww3 | 1 + icepack | 2 +- 10 files changed, 118 insertions(+), 85 deletions(-) diff --git a/cicecore/cicedyn/general/ice_init.F90 b/cicecore/cicedyn/general/ice_init.F90 index 15e35ba0e..634bb759a 100644 --- a/cicecore/cicedyn/general/ice_init.F90 +++ b/cicecore/cicedyn/general/ice_init.F90 @@ -163,7 +163,8 @@ subroutine input_data kitd, kcatbound, ktransport character (len=char_len) :: shortwave, albedo_type, conduct, fbot_xfer_type, & - tfrz_option, saltflux_option, frzpnd, atmbndy, wave_spec_type, snwredist, snw_aging_table, & + tfrz_option, saltflux_option, frzpnd, atmbndy, wave_spec_type, wave_height_type, & + snwredist, snw_aging_table, & congel_freeze, capping_method, snw_ssp_table logical (kind=log_kind) :: calc_Tsfc, formdrag, highfreq, calc_strair, wave_spec, & @@ -287,7 +288,8 @@ subroutine input_data fbot_xfer_type, update_ocn_f, l_mpond_fresh, tfrz_option, & saltflux_option,ice_ref_salinity,cpl_frazil, congel_freeze, & oceanmixed_ice, restore_ice, restore_ocn, trestore, & - precip_units, default_season, wave_spec_type,nfreq, & + precip_units, default_season, & + wave_spec_type, nfreq, wave_height_type, & atm_data_type, ocn_data_type, bgc_data_type, fe_data_type, & ice_data_type, ice_data_conc, ice_data_dist, & fyear_init, ycycle, wave_spec_file,restart_coszen, & @@ -559,6 +561,7 @@ subroutine input_data saltflux_option = 'constant' ! saltflux calculation ice_ref_salinity = 4.0_dbl_kind ! Ice reference salinity for coupling oceanmixed_ice = .false. ! if true, use internal ocean mixed layer + wave_height_type= 'internal'! type of wave height forcing wave_spec_type = 'none' ! type of wave spectrum forcing nfreq = 25 ! number of wave frequencies wave_spec_file = ' ' ! wave forcing file name @@ -1174,6 +1177,7 @@ subroutine input_data call broadcast_scalar(fbot_xfer_type, master_task) call broadcast_scalar(precip_units, master_task) call broadcast_scalar(oceanmixed_ice, master_task) + call broadcast_scalar(wave_height_type, master_task) call broadcast_scalar(wave_spec_type, master_task) call broadcast_scalar(wave_spec_file, master_task) call broadcast_scalar(nfreq, master_task) @@ -1916,12 +1920,23 @@ subroutine input_data file=__FILE__, line=__LINE__) wave_spec = .false. - if (tr_fsd .and. (trim(wave_spec_type) /= 'none')) wave_spec = .true. - if (tr_fsd .and. (trim(wave_spec_type) == 'none')) then - if (my_task == master_task) then - write(nu_diag,*) subname//' WARNING: tr_fsd=T but wave_spec=F - not recommended' + if (tr_fsd) then + if (trim(wave_spec_type) /= 'none') then + if (trim(wave_height_type) /= 'none') wave_spec = .true. + if (trim(wave_height_type) /= 'internal') then + ! wave_height_type=coupled is not yet implemented in CICE + write (nu_diag,*) 'WARNING: set wave_height_type=internal' + call abort_ice(error_message=subname//'Wave configuration', & + file=__FILE__, line=__LINE__) endif - end if + endif + if (.not.(wave_spec)) then + write (nu_diag,*) 'WARNING: tr_fsd=T but wave_spec=F - not recommended' + if (trim(wave_height_type) /= 'none') then + write (nu_diag,*) 'WARNING: Wave_spec=F, wave_height_type/=none, wave_sig_ht = 0' + endif + endif + endif ! compute grid locations for thermo, u and v fields @@ -2466,6 +2481,14 @@ subroutine input_data write(nu_diag,1030) ' wave_spec_type = ', trim(wave_spec_type),trim(tmpstr2) endif write(nu_diag,1020) ' nfreq = ', nfreq,' : number of wave spectral forcing frequencies' + if (trim(wave_height_type) == 'internal') then + tmpstr2 = ' : use internally generated wave height' + elseif (trim(wave_height_type) == 'coupled') then + tmpstr2 = ' : use wave height from external coupled model' + elseif (trim(wave_height_type) == 'none') then + tmpstr2 = ' : no wave height data available, default==0' + endif + write(nu_diag,1030) ' wave_height_type = ', trim(wave_height_type),trim(tmpstr2) endif write(nu_diag,*) ' ' @@ -2837,6 +2860,7 @@ subroutine input_data aspect_rapid_mode_in=aspect_rapid_mode, dSdt_slow_mode_in=dSdt_slow_mode, & phi_c_slow_mode_in=phi_c_slow_mode, phi_i_mushy_in=phi_i_mushy, conserv_check_in=conserv_check, & wave_spec_type_in = wave_spec_type, wave_spec_in=wave_spec, nfreq_in=nfreq, & + wave_height_type_in = wave_height_type, & update_ocn_f_in=update_ocn_f, cpl_frazil_in=cpl_frazil, congel_freeze_in=congel_freeze, & tfrz_option_in=tfrz_option, kalg_in=kalg, fbot_xfer_type_in=fbot_xfer_type, & saltflux_option_in=saltflux_option, ice_ref_salinity_in=ice_ref_salinity, & diff --git a/cicecore/cicedyn/general/ice_step_mod.F90 b/cicecore/cicedyn/general/ice_step_mod.F90 index b7aff0779..26faa27df 100644 --- a/cicecore/cicedyn/general/ice_step_mod.F90 +++ b/cicecore/cicedyn/general/ice_step_mod.F90 @@ -673,12 +673,16 @@ subroutine step_therm2 (dt, iblk) tr_fsd, & ! floe size distribution tracers z_tracers ! vertical biogeochemistry + character (len=char_len) :: & + wave_height_type ! type of significant wave height forcing + type (block) :: & this_block ! block information for current block character(len=*), parameter :: subname = '(step_therm2)' - call icepack_query_parameters(z_tracers_out=z_tracers) + call icepack_query_parameters(z_tracers_out=z_tracers, & + wave_height_type_out=wave_height_type) call icepack_query_tracer_sizes(ntrcr_out=ntrcr, nbtrcr_out=nbtrcr) call icepack_query_tracer_flags(tr_fsd_out=tr_fsd) call icepack_warnings_flush(nu_diag) @@ -703,9 +707,11 @@ subroutine step_therm2 (dt, iblk) if (tmask(i,j,iblk) .or. opmask(i,j,iblk)) then - ! significant wave height for FSD - if (tr_fsd) & - wave_sig_ht(i,j,iblk) = c4*SQRT(SUM(wave_spectrum(i,j,:,iblk)*dwavefreq(:))) + ! significant wave height + if (tr_fsd .and. trim(wave_height_type) == 'internal') then + wave_sig_ht(i,j,iblk) = c4*SQRT(SUM(wave_spectrum(i,j,:,iblk)*dwavefreq(:))) + ! else wave_sig_ht = 0 unless provided by coupler or other external data + endif call icepack_step_therm2(dt=dt, & hin_max = hin_max (:), & @@ -749,7 +755,6 @@ subroutine step_therm2 (dt, iblk) wave_spectrum = & wave_spectrum(i,j,:,iblk), & wavefreq = wavefreq (:), & - dwavefreq = dwavefreq (:), & d_afsd_latg = d_afsd_latg(i,j,:,iblk), & d_afsd_newi = d_afsd_newi(i,j,:,iblk), & d_afsd_latm = d_afsd_latm(i,j,:,iblk), & @@ -890,7 +895,7 @@ end subroutine update_state subroutine step_dyn_wave (dt) - use ice_arrays_column, only: wave_spectrum, & + use ice_arrays_column, only: wave_spectrum, wave_sig_ht, & d_afsd_wave, wavefreq, dwavefreq use ice_domain_size, only: ncat, nfsd, nfreq use ice_state, only: trcrn, aicen, aice, vice @@ -910,14 +915,11 @@ subroutine step_dyn_wave (dt) iblk, & ! block index i, j ! horizontal indices - character (len=char_len) :: wave_spec_type - character(len=*), parameter :: subname = '(step_dyn_wave)' call ice_timer_start(timer_column) call ice_timer_start(timer_fsd) - call icepack_query_parameters(wave_spec_type_out=wave_spec_type) call icepack_warnings_flush(nu_diag) if (icepack_warnings_aborted()) call abort_ice(error_message=subname, & file=__FILE__, line=__LINE__) @@ -934,8 +936,7 @@ subroutine step_dyn_wave (dt) do j = jlo, jhi do i = ilo, ihi d_afsd_wave(i,j,:,iblk) = c0 - call icepack_step_wavefracture(wave_spec_type = wave_spec_type, & - dt = dt, nfreq = nfreq, & + call icepack_step_wavefracture(dt = dt, nfreq = nfreq, & aice = aice (i,j, iblk), & vice = vice (i,j, iblk), & aicen = aicen (i,j,:, iblk), & @@ -943,7 +944,8 @@ subroutine step_dyn_wave (dt) wavefreq = wavefreq (:), & dwavefreq = dwavefreq (:), & trcrn = trcrn (i,j,:,:,iblk), & - d_afsd_wave = d_afsd_wave (i,j,:, iblk)) + d_afsd_wave = d_afsd_wave (i,j,:, iblk), & + wave_height = wave_sig_ht (i,j, iblk)) end do ! i end do ! j end do ! iblk diff --git a/cicecore/drivers/unittest/opticep/ice_step_mod.F90 b/cicecore/drivers/unittest/opticep/ice_step_mod.F90 index 6d8fff7f9..6e775a3c0 100644 --- a/cicecore/drivers/unittest/opticep/ice_step_mod.F90 +++ b/cicecore/drivers/unittest/opticep/ice_step_mod.F90 @@ -566,7 +566,7 @@ subroutine step_therm1 (dt, iblk) !opt dpnd_initialn=dpnd_initialn(i,j,:,iblk), & !opt dpnd_dlidn = dpnd_dlidn (i,j,:,iblk), & yday=yday) -!opt prescribed_ice=prescribed_ice) +!opt prescribed_ice=prescribed_ice) !----------------------------------------------------------------- ! handle per-category i2x fields, no merging @@ -674,12 +674,16 @@ subroutine step_therm2 (dt, iblk) tr_fsd, & ! floe size distribution tracers z_tracers ! vertical biogeochemistry + character (len=char_len) :: & + wave_height_type ! type of significant wave height forcing + type (block) :: & this_block ! block information for current block character(len=*), parameter :: subname = '(step_therm2)' - call icepack_query_parameters(z_tracers_out=z_tracers) + call icepack_query_parameters(z_tracers_out=z_tracers, & + wave_height_type_out=wave_height_type) call icepack_query_tracer_sizes(ntrcr_out=ntrcr, nbtrcr_out=nbtrcr) call icepack_query_tracer_flags(tr_fsd_out=tr_fsd) call icepack_warnings_flush(nu_diag) @@ -704,57 +708,59 @@ subroutine step_therm2 (dt, iblk) if (tmask(i,j,iblk) .or. opmask(i,j,iblk)) then - ! significant wave height for FSD - if (tr_fsd) & - wave_sig_ht(i,j,iblk) = c4*SQRT(SUM(wave_spectrum(i,j,:,iblk)*dwavefreq(:))) - - call icepack_step_therm2(dt=dt, & - hin_max = hin_max (:), & - aicen = aicen (i,j,:,iblk), & - vicen = vicen (i,j,:,iblk), & - vsnon = vsnon (i,j,:,iblk), & - aicen_init = aicen_init(i,j,:,iblk), & - vicen_init = vicen_init(i,j,:,iblk), & - trcrn = trcrn (i,j,:,:,iblk), & - aice0 = aice0 (i,j, iblk), & - aice = aice (i,j, iblk), & - trcr_depend= trcr_depend(:), & - trcr_base = trcr_base(:,:), & - n_trcr_strata = n_trcr_strata(:), & - nt_strata = nt_strata(:,:), & - Tf = Tf (i,j, iblk), & - sss = sss (i,j, iblk), & - salinz = salinz (i,j,:,iblk), & - rsiden = rsiden (i,j,:,iblk), & - meltl = meltl (i,j, iblk), & -!opt wlat = wlat (i,j, iblk), & - frzmlt = frzmlt (i,j, iblk), & - frazil = frazil (i,j, iblk), & - frain = frain (i,j, iblk), & - fpond = fpond (i,j, iblk), & - fresh = fresh (i,j, iblk), & - fsalt = fsalt (i,j, iblk), & - fhocn = fhocn (i,j, iblk), & - faero_ocn = faero_ocn (i,j,:,iblk), & - first_ice = first_ice (i,j,:,iblk), & - flux_bio = flux_bio (i,j,1:nbtrcr,iblk), & - ocean_bio = ocean_bio (i,j,1:nbtrcr,iblk), & - frazil_diag= frazil_diag(i,j,iblk) & -!opt frz_onset = frz_onset (i,j, iblk), & -!opt yday = yday, & -!opt fiso_ocn = fiso_ocn (i,j,:,iblk), & -!opt HDO_ocn = HDO_ocn (i,j, iblk), & -!opt H2_16O_ocn = H2_16O_ocn(i,j, iblk), & -!opt H2_18O_ocn = H2_18O_ocn(i,j, iblk), & -!opt wave_sig_ht= wave_sig_ht(i,j, iblk), & -!opt wave_spectrum=wave_spectrum(i,j,:,iblk), & -!opt wavefreq = wavefreq (:), & -!opt dwavefreq = dwavefreq (:), & -!opt d_afsd_latg=d_afsd_latg(i,j,:,iblk), & -!opt d_afsd_newi=d_afsd_newi(i,j,:,iblk), & -!opt d_afsd_latm=d_afsd_latm(i,j,:,iblk), & -!opt d_afsd_weld=d_afsd_weld(i,j,:,iblk), & -!opt dpnd_melt = dpnd_melt( i,j, iblk)) + ! significant wave height + if (tr_fsd .and. trim(wave_height_type) == 'internal') then + wave_sig_ht(i,j,iblk) = c4*SQRT(SUM(wave_spectrum(i,j,:,iblk)*dwavefreq(:))) + ! else wave_sig_ht = 0 unless provided by coupler or other external data + endif + + call icepack_step_therm2(dt=dt, & + hin_max = hin_max (:), & + aicen = aicen (i,j,:,iblk), & + vicen = vicen (i,j,:,iblk), & + vsnon = vsnon (i,j,:,iblk), & + aicen_init = aicen_init (i,j,:,iblk), & + vicen_init = vicen_init (i,j,:,iblk), & + trcrn = trcrn (i,j,:,:,iblk), & + aice0 = aice0 (i,j, iblk), & + aice = aice (i,j, iblk), & + trcr_depend = trcr_depend(:), & + trcr_base = trcr_base (:,:), & + n_trcr_strata = n_trcr_strata(:), & + nt_strata = nt_strata (:,:), & + Tf = Tf (i,j, iblk), & + sss = sss (i,j, iblk), & + salinz = salinz (i,j,:,iblk), & + rsiden = rsiden (i,j,:,iblk), & + meltl = meltl (i,j, iblk), & +!opt wlat = wlat (i,j, iblk), & + frzmlt = frzmlt (i,j, iblk), & + frazil = frazil (i,j, iblk), & + frain = frain (i,j, iblk), & + fpond = fpond (i,j, iblk), & + fresh = fresh (i,j, iblk), & + fsalt = fsalt (i,j, iblk), & + fhocn = fhocn (i,j, iblk), & + faero_ocn = faero_ocn (i,j,:,iblk), & + first_ice = first_ice (i,j,:,iblk), & + flux_bio = flux_bio (i,j,1:nbtrcr,iblk), & + ocean_bio = ocean_bio (i,j,1:nbtrcr,iblk), & + frazil_diag = frazil_diag(i,j, iblk) & +!opt frz_onset = frz_onset (i,j, iblk), & +!opt yday = yday, & +!opt fiso_ocn = fiso_ocn (i,j,:,iblk), & +!opt HDO_ocn = HDO_ocn (i,j, iblk), & +!opt H2_16O_ocn = H2_16O_ocn (i,j, iblk), & +!opt H2_18O_ocn = H2_18O_ocn (i,j, iblk), & +!opt wave_sig_ht = wave_sig_ht(i,j, iblk), & +!opt wave_spectrum = & +!opt wave_spectrum(i,j,:,iblk), & +!opt wavefreq = wavefreq (:), & +!opt d_afsd_latg = d_afsd_latg(i,j,:,iblk), & +!opt d_afsd_newi = d_afsd_newi(i,j,:,iblk), & +!opt d_afsd_latm = d_afsd_latm(i,j,:,iblk), & +!opt d_afsd_weld = d_afsd_weld(i,j,:,iblk), & +!opt dpnd_melt = dpnd_melt (i,j, iblk)) ) endif ! tmask @@ -891,7 +897,7 @@ end subroutine update_state subroutine step_dyn_wave (dt) - use ice_arrays_column, only: wave_spectrum, & + use ice_arrays_column, only: wave_spectrum, wave_sig_ht, & d_afsd_wave, wavefreq, dwavefreq use ice_domain_size, only: ncat, nfsd, nfreq use ice_state, only: trcrn, aicen, aice, vice @@ -911,14 +917,11 @@ subroutine step_dyn_wave (dt) iblk, & ! block index i, j ! horizontal indices - character (len=char_len) :: wave_spec_type - character(len=*), parameter :: subname = '(step_dyn_wave)' call ice_timer_start(timer_column) call ice_timer_start(timer_fsd) - call icepack_query_parameters(wave_spec_type_out=wave_spec_type) call icepack_warnings_flush(nu_diag) if (icepack_warnings_aborted()) call abort_ice(error_message=subname, & file=__FILE__, line=__LINE__) @@ -935,8 +938,7 @@ subroutine step_dyn_wave (dt) do j = jlo, jhi do i = ilo, ihi d_afsd_wave(i,j,:,iblk) = c0 - call icepack_step_wavefracture(wave_spec_type = wave_spec_type, & - dt = dt, nfreq = nfreq, & + call icepack_step_wavefracture(dt = dt, nfreq = nfreq, & aice = aice (i,j, iblk), & vice = vice (i,j, iblk), & aicen = aicen (i,j,:, iblk), & @@ -944,7 +946,8 @@ subroutine step_dyn_wave (dt) wavefreq = wavefreq (:), & dwavefreq = dwavefreq (:), & trcrn = trcrn (i,j,:,:,iblk), & - d_afsd_wave = d_afsd_wave (i,j,:, iblk)) + d_afsd_wave = d_afsd_wave (i,j,:, iblk), & + wave_height = wave_sig_ht (i,j, iblk)) end do ! i end do ! j end do ! iblk @@ -1156,8 +1159,8 @@ subroutine step_dyn_ridge (dt, ndtd, iblk) fsalt = fsalt (i,j, iblk), & first_ice = first_ice(i,j,:,iblk), & flux_bio = flux_bio (i,j,1:nbtrcr,iblk), & - Tf = Tf (i,j, iblk) & -!opt dpnd_ridge=dpnd_ridge(i,j,iblk)) + Tf = Tf (i,j, iblk) & +!opt dpnd_ridge=dpnd_ridge(i,j, iblk)) ) endif ! tmask @@ -1446,7 +1449,7 @@ subroutine step_radiation (dt, iblk) albpndn =albpndn (i,j,: ,iblk), apeffn =apeffn (i,j,: ,iblk), & snowfracn=snowfracn(i,j,: ,iblk), & dhsn =dhsn (i,j,: ,iblk), ffracn =ffracn(i,j,:,iblk), & -!opt rsnow =rsnow (:,:), +!opt rsnow =rsnow (:,:), & l_print_point=l_print_point) endif diff --git a/cicecore/shared/ice_arrays_column.F90 b/cicecore/shared/ice_arrays_column.F90 index 8dee4aef3..d72ed63de 100644 --- a/cicecore/shared/ice_arrays_column.F90 +++ b/cicecore/shared/ice_arrays_column.F90 @@ -244,7 +244,7 @@ module ice_arrays_column floe_binwidth ! fsd size bin width in m (radius) real (kind=dbl_kind), dimension (:,:,:), allocatable, public :: & - wave_sig_ht ! significant height of waves (m) + wave_sig_ht ! significant height of waves (m) real (kind=dbl_kind), dimension (:), allocatable, public :: & wavefreq, & ! wave frequencies diff --git a/cicecore/shared/ice_init_column.F90 b/cicecore/shared/ice_init_column.F90 index 5f04a49d6..8abc21c3d 100644 --- a/cicecore/shared/ice_init_column.F90 +++ b/cicecore/shared/ice_init_column.F90 @@ -677,7 +677,7 @@ subroutine init_fsd(floesize) ! initialize floe size distribution the same in every column and category call icepack_init_fsd(ice_ic = ice_ic, & - afsd = afsd) ! floe size distribution + afsd = afsd) ! floe size distribution do iblk = 1, max_blocks do j = 1, ny_block diff --git a/configuration/scripts/ice_in b/configuration/scripts/ice_in index 2d0cffaab..04f7c0d41 100644 --- a/configuration/scripts/ice_in +++ b/configuration/scripts/ice_in @@ -281,6 +281,7 @@ saltflux_option = 'constant' ice_ref_salinity = 4.0 oceanmixed_ice = .true. + wave_height_type = 'none' wave_spec_type = 'none' wave_spec_file = 'unknown_wave_spec_file' nfreq = 25 diff --git a/configuration/scripts/options/set_nml.fsd1 b/configuration/scripts/options/set_nml.fsd1 index 042ed5f25..4c59704da 100644 --- a/configuration/scripts/options/set_nml.fsd1 +++ b/configuration/scripts/options/set_nml.fsd1 @@ -1,5 +1,6 @@ tr_fsd = .true. nfsd = 1 wave_spec_type = 'none' +wave_height_type = 'none' nfreq = 25 diff --git a/configuration/scripts/options/set_nml.fsd12 b/configuration/scripts/options/set_nml.fsd12 index 620b2e96b..796125e0d 100644 --- a/configuration/scripts/options/set_nml.fsd12 +++ b/configuration/scripts/options/set_nml.fsd12 @@ -1,5 +1,6 @@ tr_fsd = .true. nfsd = 12 wave_spec_type = 'profile' +wave_height_type = 'internal' nfreq = 25 diff --git a/configuration/scripts/options/set_nml.fsd12ww3 b/configuration/scripts/options/set_nml.fsd12ww3 index a8d5d06ac..18a904160 100644 --- a/configuration/scripts/options/set_nml.fsd12ww3 +++ b/configuration/scripts/options/set_nml.fsd12ww3 @@ -1,5 +1,6 @@ tr_fsd = .true. nfsd = 12 wave_spec_type = 'constant' +wave_height_type = 'internal' nfreq = 25 wave_spec_file = 'ICE_MACHINE_INPUTDATA/CICE_data/forcing/gx3/ww3.20100101_efreq_remapgx3.nc' diff --git a/icepack b/icepack index eedb51924..0bcde2556 160000 --- a/icepack +++ b/icepack @@ -1 +1 @@ -Subproject commit eedb519247f48bce9fa1d1b275b5cc3dc07643e4 +Subproject commit 0bcde255637a5947b1b7a4e4fc8dccd77803cb65 From 27a49820b592b8079003de9b782e575d6eea0400 Mon Sep 17 00:00:00 2001 From: "David A. Bailey" Date: Fri, 16 Jan 2026 14:50:02 -0700 Subject: [PATCH 17/21] Updates for CMIP7 (#1066) Updated all of the variable names, long names, and units to correspond to the CMIP7 data request. Added new variables requested in the CMIP7 data request. Added documentation about the CMIP6 to CMIP7 update. Simplified the accumulation of some fields where possible and added prognostic sea ice density. Added accumulation of variables relative to aice_init or aice. Bug fix for flwout (sifllwutop) where aice_init = 0, but aice > 0. Bug fix for shortwave abosrbed and albedo computation (more coming later) Bug fix: Some variables that were scaled by aice, should be multiplied by aice (not aice_init) to get the _ai quantities, including fswabs, fsens, flat, etc. Removed f_CMIP flag and added set_nml.cmip option instead. Added comment field for SIMIP variables that uses part of the description field in the CMIP data request table. Added long_name field to address issue: time_bounds, lat?_bounds, lon?_bounds attributes #1057 Partly addresses aice versus aice_init aice vs. aice/aice_init factor in ice_history #1033 Partial fix for albedo variables [albedo]_ai history variables over 100% #1051 Addresses issue: Some CMIP variables are computed using a mix of U and T quantities #904 --- cicecore/cicedyn/analysis/ice_history.F90 | 2364 ++++++++--------- .../cicedyn/analysis/ice_history_mechred.F90 | 73 +- .../cicedyn/analysis/ice_history_pond.F90 | 170 +- .../cicedyn/analysis/ice_history_shared.F90 | 189 +- .../cicedyn/analysis/ice_history_snow.F90 | 22 +- cicecore/cicedyn/general/ice_flux.F90 | 11 +- .../io/io_binary/ice_history_write.F90 | 3 +- .../io/io_netcdf/ice_history_write.F90 | 55 +- .../io/io_pio2/ice_history_write.F90 | 47 +- .../drivers/direct/hadgem3/CICE_RunMod.F90 | 4 +- .../direct/nemo_concepts/CICE_RunMod.F90 | 4 +- cicecore/drivers/mapl/geos/CICE_RunMod.F90 | 4 +- cicecore/drivers/mct/cesm1/CICE_RunMod.F90 | 4 +- cicecore/drivers/nuopc/cmeps/CICE_RunMod.F90 | 4 +- .../drivers/nuopc/cmeps/ice_import_export.F90 | 22 +- cicecore/drivers/nuopc/dmi/CICE_RunMod.F90 | 7 +- .../drivers/standalone/cice/CICE_RunMod.F90 | 13 +- .../drivers/unittest/opticep/CICE_RunMod.F90 | 7 +- cicecore/shared/ice_calendar.F90 | 5 + configuration/scripts/ice_in | 83 +- configuration/scripts/options/set_nml.cmip | 143 + configuration/scripts/options/set_nml.histall | 83 +- configuration/scripts/options/set_nml.histdbg | 1 - configuration/scripts/tests/io_suite.ts | 1 + doc/source/user_guide/ug_case_settings.rst | 4 +- doc/source/user_guide/ug_implementation.rst | 35 +- 26 files changed, 1854 insertions(+), 1504 deletions(-) create mode 100644 configuration/scripts/options/set_nml.cmip diff --git a/cicecore/cicedyn/analysis/ice_history.F90 b/cicecore/cicedyn/analysis/ice_history.F90 index 99b04afb9..72939f31a 100644 --- a/cicecore/cicedyn/analysis/ice_history.F90 +++ b/cicecore/cicedyn/analysis/ice_history.F90 @@ -273,7 +273,7 @@ subroutine init_hist (dt) do ns = 1, max_nstrm if (histfreq(ns) == '1' .or. histfreq(ns) == 'h' .or. & histfreq(ns) == 'd' .or. histfreq(ns) == 'm' .or. & - histfreq(ns) == 'y') then + histfreq(ns) == 'y' .or. histfreq(ns) == 'n') then nstreams = nstreams + 1 if (ns >= 2) then if (histfreq(ns-1) == 'x') then @@ -337,90 +337,6 @@ subroutine init_hist (dt) ! to prevent array-out-of-bounds when aggregating if (f_fmeltt_ai(1:1) /= 'x') f_fmelttn_ai = f_fmeltt_ai - ! Turn on all CMIP fields in one go. - - if (f_CMIP(1:1) /= 'x') then - f_sithick = 'mxxxx' - f_sisnthick = 'mxxxx' - f_siage = 'mxxxx' - f_sitemptop = 'mxxxx' - f_sitempsnic = 'mxxxx' - f_sitempbot = 'mxxxx' - f_sispeed = 'mxxxx' - f_siu = 'mxxxx' - f_siv = 'mxxxx' - f_sidmasstranx = 'mxxxx' - f_sidmasstrany = 'mxxxx' - f_sistrxdtop = 'mxxxx' - f_sistrydtop = 'mxxxx' - f_sistrxubot = 'mxxxx' - f_sistryubot = 'mxxxx' - f_sicompstren = 'mxxxx' - f_sialb = 'mxxxx' - f_sihc = 'mxxxx' - f_sisnhc = 'mxxxx' - f_sidconcth = 'mxxxx' - f_sidconcdyn = 'mxxxx' - f_sidmassth = 'mxxxx' - f_sidmassdyn = 'mxxxx' - f_sidmassgrowthwat = 'mxxxx' - f_sidmassgrowthbot = 'mxxxx' - f_sidmasssi = 'mxxxx' - f_sidmassevapsubl = 'mxxxx' - f_sndmasssubl = 'mxxxx' - f_sidmassmelttop = 'mxxxx' - f_sidmassmeltbot = 'mxxxx' - f_sidmasslat = 'mxxxx' - f_sndmasssnf = 'mxxxx' - f_sndmassmelt = 'mxxxx' - f_sndmassdyn = 'mxxxx' - f_siflswdtop = 'mxxxx' - f_siflswutop = 'mxxxx' - f_siflswdbot = 'mxxxx' - f_sifllwdtop = 'mxxxx' - f_sifllwutop = 'mxxxx' - f_siflsenstop = 'mxxxx' - f_siflsensupbot = 'mxxxx' - f_sifllatstop = 'mxxxx' - f_siflcondtop = 'mxxxx' - f_siflcondbot = 'mxxxx' - f_sipr = 'mxxxx' - f_sifb = 'mxxxx' - f_siflsaltbot = 'mxxxx' - f_siflfwbot = 'mxxxx' - f_siflfwdrain = 'mxxxx' - f_siforcetiltx = 'mxxxx' - f_siforcetilty = 'mxxxx' - f_siforcecoriolx = 'mxxxx' - f_siforcecorioly = 'mxxxx' - f_siforceintstrx = 'mxxxx' - f_siforceintstry = 'mxxxx' - f_sidragtop = 'mxxxx' - f_sistreave = 'mxxxx' - f_sistremax = 'mxxxx' - f_sirdgthick = 'mxxxx' - f_siitdconc = 'mxxxx' - f_siitdthick = 'mxxxx' - f_siitdsnthick = 'mxxxx' - f_aicen = 'mxxxx' - endif - - if (f_CMIP(2:2) == 'd') then - f_icepresent = f_CMIP - f_aice = f_CMIP - f_sithick = f_CMIP - f_sisnthick = f_CMIP - f_sitemptop = f_CMIP - f_siu = f_CMIP - f_siv = f_CMIP - f_sispeed = f_CMIP - f_sndmasssubl = f_CMIP - f_sndmasssnf = f_CMIP - f_sndmassmelt = f_CMIP - f_sndmassdyn = f_CMIP - f_sidmasssi = f_CMIP - endif - if (grid_ice == 'CD' .or. grid_ice == 'C') then f_uvelE = f_uvel f_vvelE = f_vvel @@ -494,12 +410,14 @@ subroutine init_hist (dt) call broadcast_scalar (f_NFSD, master_task) ! call broadcast_scalar (f_example, master_task) + call broadcast_scalar (f_CMIP, master_task) call broadcast_scalar (f_hi, master_task) call broadcast_scalar (f_hs, master_task) call broadcast_scalar (f_snowfrac, master_task) call broadcast_scalar (f_snowfracn, master_task) call broadcast_scalar (f_Tsfc, master_task) call broadcast_scalar (f_aice, master_task) + call broadcast_scalar (f_aice_init, master_task) call broadcast_scalar (f_uvel, master_task) call broadcast_scalar (f_vvel, master_task) call broadcast_scalar (f_icespd, master_task) @@ -629,8 +547,15 @@ subroutine init_hist (dt) call broadcast_scalar (f_frz_onset, master_task) call broadcast_scalar (f_aisnap, master_task) call broadcast_scalar (f_hisnap, master_task) + call broadcast_scalar (f_sitimefrac, master_task) call broadcast_scalar (f_sithick, master_task) call broadcast_scalar (f_siage, master_task) + call broadcast_scalar (f_siconc, master_task) + call broadcast_scalar (f_sisnconc, master_task) + call broadcast_scalar (f_sisnmass, master_task) + call broadcast_scalar (f_sivol, master_task) + call broadcast_scalar (f_simass, master_task) + call broadcast_scalar (f_sisaltmass, master_task) call broadcast_scalar (f_sisnthick, master_task) call broadcast_scalar (f_sitemptop, master_task) call broadcast_scalar (f_sitempsnic, master_task) @@ -645,8 +570,8 @@ subroutine init_hist (dt) call broadcast_scalar (f_sistryubot, master_task) call broadcast_scalar (f_sicompstren, master_task) call broadcast_scalar (f_sispeed, master_task) - call broadcast_scalar (f_sidir, master_task) - call broadcast_scalar (f_sialb, master_task) +! call broadcast_scalar (f_sidir, master_task) + call broadcast_scalar (f_sisali, master_task) call broadcast_scalar (f_sihc, master_task) call broadcast_scalar (f_sisnhc, master_task) call broadcast_scalar (f_sidconcth, master_task) @@ -655,23 +580,24 @@ subroutine init_hist (dt) call broadcast_scalar (f_sidmassdyn, master_task) call broadcast_scalar (f_sidmassgrowthwat, master_task) call broadcast_scalar (f_sidmassgrowthbot, master_task) - call broadcast_scalar (f_sidmasssi, master_task) + call broadcast_scalar (f_sidmassgrowthsi, master_task) call broadcast_scalar (f_sidmassevapsubl, master_task) - call broadcast_scalar (f_sndmasssubl, master_task) + call broadcast_scalar (f_sisndmasssubl, master_task) call broadcast_scalar (f_sidmassmelttop, master_task) call broadcast_scalar (f_sidmassmeltbot, master_task) - call broadcast_scalar (f_sidmasslat, master_task) - call broadcast_scalar (f_sndmasssnf, master_task) - call broadcast_scalar (f_sndmassmelt, master_task) - call broadcast_scalar (f_sndmassdyn, master_task) + call broadcast_scalar (f_sidmassmeltlat, master_task) + call broadcast_scalar (f_sisndmasssnf, master_task) + call broadcast_scalar (f_sisndmassmelt, master_task) + call broadcast_scalar (f_sisndmassdyn, master_task) + call broadcast_scalar (f_sisndmasssi, master_task) call broadcast_scalar (f_siflswdtop, master_task) call broadcast_scalar (f_siflswutop, master_task) call broadcast_scalar (f_siflswdbot, master_task) call broadcast_scalar (f_sifllwdtop, master_task) call broadcast_scalar (f_sifllwutop, master_task) call broadcast_scalar (f_siflsenstop, master_task) - call broadcast_scalar (f_siflsensupbot, master_task) - call broadcast_scalar (f_sifllatstop, master_task) + call broadcast_scalar (f_siflsensbot, master_task) + call broadcast_scalar (f_sifllattop, master_task) call broadcast_scalar (f_siflcondtop, master_task) call broadcast_scalar (f_siflcondbot, master_task) call broadcast_scalar (f_sipr, master_task) @@ -686,12 +612,15 @@ subroutine init_hist (dt) call broadcast_scalar (f_siforceintstrx, master_task) call broadcast_scalar (f_siforceintstry, master_task) call broadcast_scalar (f_siitdconc, master_task) + call broadcast_scalar (f_siitdsnconc, master_task) call broadcast_scalar (f_siitdthick, master_task) call broadcast_scalar (f_siitdsnthick, master_task) call broadcast_scalar (f_sidragtop, master_task) - call broadcast_scalar (f_sistreave, master_task) - call broadcast_scalar (f_sistremax, master_task) - call broadcast_scalar (f_sirdgthick, master_task) + call broadcast_scalar (f_sidragbot, master_task) + call broadcast_scalar (f_sistressave, master_task) + call broadcast_scalar (f_sistressmax, master_task) + call broadcast_scalar (f_sidivvel, master_task) + call broadcast_scalar (f_sishearvel, master_task) call broadcast_scalar (f_aicen, master_task) call broadcast_scalar (f_vicen, master_task) @@ -728,6 +657,11 @@ subroutine init_hist (dt) call broadcast_scalar (f_yieldstress12, master_task) call broadcast_scalar (f_yieldstress22, master_task) + if (f_CMIP(1:1) /= 'x') then + if (my_task == master_task) write(nu_diag,*) subname, & + 'WARNING: f_CMIP has been deprecated. Please use the set_nml.cmip namelist option' + endif + ! 2D variables do ns1 = 1, nstreams if (histfreq(ns1) /= 'x') then @@ -739,189 +673,194 @@ subroutine init_hist (dt) ! ns1, f_example) !!!!! end example - call define_hist_field(n_hi,"hi","m",tstr2D, tcstr, & - "grid cell mean ice thickness", & - "ice volume per unit grid cell area", c1, c0, & + call define_hist_field(n_hi,"hi","m",tstr2D, tcstr, & + "grid cell mean ice thickness", & + "ice volume per unit grid cell area", c1, c0, & ns1, f_hi) - call define_hist_field(n_hs,"hs","m",tstr2D, tcstr, & - "grid cell mean snow thickness", & - "snow volume per unit grid cell area", c1, c0, & + call define_hist_field(n_hs,"hs","m",tstr2D, tcstr, & + "grid cell mean snow thickness", & + "snow volume per unit grid cell area", c1, c0, & ns1, f_hs) call define_hist_field(n_snowfrac,"snowfrac","1",tstr2D, tcstr, & - "grid cell mean snow fraction", & - "snow fraction per unit grid cell area", c1, c0, & + "snow fraction of sea ice", & + "none", c1, c0, & ns1, f_snowfrac) - call define_hist_field(n_Tsfc,"Tsfc","C",tstr2D, tcstr, & - "snow/ice surface temperature", & - "averaged with Tf if no ice is present", c1, c0, & + call define_hist_field(n_Tsfc,"Tsfc","C",tstr2D, tcstr, & + "snow/ice surface temperature", & + "averaged with Tf if no ice is present", c1, c0, & ns1, f_Tsfc) - call define_hist_field(n_aice,"aice","1",tstr2D, tcstr, & - "ice area (aggregate)", & - "none", c1, c0, & + call define_hist_field(n_aice,"aice","1",tstr2D, tcstr, & + "ice area (aggregate)", & + "none", c1, c0, & ns1, f_aice) - call define_hist_field(n_uvelE,"uvelE","m/s",estr2D, ecstr, & - "ice velocity (x)", & - "positive is x direction on E grid", c1, c0, & + call define_hist_field(n_aice_init,"aice_init","1",tstr2D, tcstr, & + "ice area (aggregate) initial", & + "none", c1, c0, & + ns1, f_aice_init) + + call define_hist_field(n_uvelE,"uvelE","m/s",estr2D, ecstr, & + "ice velocity (x)", & + "positive is x direction on E grid", c1, c0, & ns1, f_uvelE) - call define_hist_field(n_vvelE,"vvelE","m/s",estr2D, ecstr, & - "ice velocity (y)", & - "positive is y direction on E grid", c1, c0, & + call define_hist_field(n_vvelE,"vvelE","m/s",estr2D, ecstr, & + "ice velocity (y)", & + "positive is y direction on E grid", c1, c0, & ns1, f_vvelE) call define_hist_field(n_icespdE,"icespdE","m/s",estr2D, ecstr, & - "sea ice speed", & + "sea ice speed", & "vector magnitude on E grid", c1, c0, & ns1, f_icespdE) call define_hist_field(n_icedirE,"icedirE","deg",estr2D, ecstr, & - "sea ice direction", & + "sea ice direction", & "vector direction - coming from on E grid", c1, c0, & ns1, f_icedirE) - call define_hist_field(n_uvelN,"uvelN","m/s",nstr2D, ncstr, & - "ice velocity (x)", & - "positive is x direction on N grid", c1, c0, & + call define_hist_field(n_uvelN,"uvelN","m/s",nstr2D, ncstr, & + "ice velocity (x)", & + "positive is x direction on N grid", c1, c0, & ns1, f_uvelN) - call define_hist_field(n_vvelN,"vvelN","m/s",nstr2D, ncstr, & - "ice velocity (y)", & - "positive is y direction on N grid", c1, c0, & + call define_hist_field(n_vvelN,"vvelN","m/s",nstr2D, ncstr, & + "ice velocity (y)", & + "positive is y direction on N grid", c1, c0, & ns1, f_vvelN) call define_hist_field(n_icespdN,"icespdN","m/s",nstr2D, ncstr, & - "sea ice speed", & + "sea ice speed", & "vector magnitude on N grid", c1, c0, & ns1, f_icespdN) call define_hist_field(n_icedirN,"icedirN","deg",nstr2D, ncstr, & - "sea ice direction", & + "sea ice direction", & "vector direction - coming from on N grid", c1, c0, & ns1, f_icedirN) - call define_hist_field(n_uvel,"uvel","m/s",ustr2D, ucstr, & - "ice velocity (x)", & - "positive is x direction on U grid", c1, c0, & + call define_hist_field(n_uvel,"uvel","m/s",ustr2D, ucstr, & + "ice velocity (x)", & + "positive is x direction on U grid", c1, c0, & ns1, f_uvel) - call define_hist_field(n_vvel,"vvel","m/s",ustr2D, ucstr, & - "ice velocity (y)", & - "positive is y direction on U grid", c1, c0, & + call define_hist_field(n_vvel,"vvel","m/s",ustr2D, ucstr, & + "ice velocity (y)", & + "positive is y direction on U grid", c1, c0, & ns1, f_vvel) call define_hist_field(n_icespd,"icespd","m/s",ustr2D, ucstr, & - "sea ice speed", & + "sea ice speed", & "vector magnitude", c1, c0, & ns1, f_icespd) call define_hist_field(n_icedir,"icedir","deg",ustr2D, ucstr, & - "sea ice direction", & + "sea ice direction", & "vector direction - coming from", c1, c0, & ns1, f_icedir) - call define_hist_field(n_uatm,"uatm","m/s",str2D_gau, cstr_gau, & - "atm velocity (x)", & - "positive is x direction on U grid", c1, c0, & + call define_hist_field(n_uatm,"uatm","m/s",str2D_gau, cstr_gau, & + "atm velocity (x)", & + "positive is x direction on U grid", c1, c0, & ns1, f_uatm) - call define_hist_field(n_vatm,"vatm","m/s",str2D_gav, cstr_gav, & - "atm velocity (y)", & - "positive is y direction on U grid", c1, c0, & + call define_hist_field(n_vatm,"vatm","m/s",str2D_gav, cstr_gav, & + "atm velocity (y)", & + "positive is y direction on U grid", c1, c0, & ns1, f_vatm) call define_hist_field(n_atmspd,"atmspd","m/s",str2D_gau, cstr_gau, & - "atmosphere wind speed", & - "vector magnitude", c1, c0, & + "atmosphere wind speed", & + "vector magnitude", c1, c0, & ns1, f_atmspd) call define_hist_field(n_atmdir,"atmdir","deg",str2D_gau, cstr_gau, & - "atmosphere wind direction", & - "vector direction - coming from", c1, c0, & + "atmosphere wind direction", & + "vector direction - coming from", c1, c0, & ns1, f_atmdir) - call define_hist_field(n_sice,"sice","ppt",tstr2D, tcstr, & - "bulk ice salinity", & - "none", c1, c0, & + call define_hist_field(n_sice,"sice","ppt",tstr2D, tcstr, & + "bulk ice salinity", & + "none", c1, c0, & ns1, f_sice) call define_hist_field(n_fswup,"fswup","W/m^2",tstr2D, tcstr, & "upward solar flux", & - "positive upward", c1, c0, & + "positive upward", c1, c0, & ns1, f_fswup) call define_hist_field(n_fswdn,"fswdn","W/m^2",tstr2D, tcstr, & - "down solar flux", & - "positive downward", c1, c0, & + "down solar flux", & + "positive downward", c1, c0, & ns1, f_fswdn) call define_hist_field(n_flwdn,"flwdn","W/m^2",tstr2D, tcstr, & - "down longwave flux", & - "positive downward", c1, c0, & + "down longwave flux", & + "positive downward", c1, c0, & ns1, f_flwdn) call define_hist_field(n_snow,"snow","cm/day",tstr2D, tcstr, & - "snowfall rate (cpl)", & - "none", mps_to_cmpdy/rhofresh, c0, & + "snowfall rate (cpl)", & + "none", mps_to_cmpdy/rhofresh, c0, & ns1, f_snow) call define_hist_field(n_snow_ai,"snow_ai","cm/day",tstr2D, tcstr, & - "snowfall rate", & - "weighted by ice area", mps_to_cmpdy/rhofresh, c0, & + "snowfall rate", & + "weighted by ice area", mps_to_cmpdy/rhofresh, c0, & ns1, f_snow_ai) call define_hist_field(n_rain,"rain","cm/day",tstr2D, tcstr, & - "rainfall rate (cpl)", & - "none", mps_to_cmpdy/rhofresh, c0, & + "rainfall rate (cpl)", & + "none", mps_to_cmpdy/rhofresh, c0, & ns1, f_rain) call define_hist_field(n_rain_ai,"rain_ai","cm/day",tstr2D, tcstr, & - "rainfall rate", & - "weighted by ice area", mps_to_cmpdy/rhofresh, c0, & + "rainfall rate", & + "weighted by ice area", mps_to_cmpdy/rhofresh, c0, & ns1, f_rain_ai) call define_hist_field(n_sst,"sst","C",tstr2D, tcstr, & - "sea surface temperature", & - "none", c1, c0, & + "sea surface temperature", & + "none", c1, c0, & ns1, f_sst) call define_hist_field(n_sss,"sss","ppt",tstr2D, tcstr, & - "sea surface salinity", & - "none", c1, c0, & + "sea surface salinity", & + "none", c1, c0, & ns1, f_sss) call define_hist_field(n_uocn,"uocn","m/s",str2D_gou, cstr_gou, & - "ocean current (x)", & - "positive is x direction on U grid", c1, c0, & + "ocean current (x)", & + "positive is x direction on U grid", c1, c0, & ns1, f_uocn) call define_hist_field(n_vocn,"vocn","m/s",str2D_gov, cstr_gov, & - "ocean current (y)", & - "positive is y direction on U grid", c1, c0, & + "ocean current (y)", & + "positive is y direction on U grid", c1, c0, & ns1, f_vocn) call define_hist_field(n_ocnspd,"ocnspd","m/s",str2D_gou, cstr_gou, & - "ocean current speed", & - "vector magnitude", c1, c0, & + "ocean current speed", & + "vector magnitude", c1, c0, & ns1, f_ocnspd) call define_hist_field(n_ocndir,"ocndir","deg",str2D_gou, cstr_gou, & - "ocean current direction", & - "vector direction - going to", c1, c0, & + "ocean current direction", & + "vector direction - going to", c1, c0, & ns1, f_ocndir) call define_hist_field(n_frzmlt,"frzmlt","W/m^2",tstr2D, tcstr, & - "freeze/melt potential", & - "if >0, new ice forms; if <0, ice melts", c1, c0, & + "freeze/melt potential", & + "if >0, new ice forms; if <0, ice melts", c1, c0, & ns1, f_frzmlt) call define_hist_field(n_fswfac,"scale_factor","1",tstr2D, tcstr, & - "shortwave scaling factor", & - "ratio of netsw new:old", c1, c0, & + "shortwave scaling factor", & + "ratio of netsw new:old", c1, c0, & ns1, f_fswfac) call define_hist_field(n_fswint_ai,"fswint_ai","W/m^2",tstr2D, tcstr, & @@ -930,194 +869,194 @@ subroutine init_hist (dt) ns1, f_fswint_ai) call define_hist_field(n_fswabs,"fswabs","W/m^2",tstr2D, tcstr, & - "snow/ice/ocn absorbed solar flux (cpl)", & - "positive downward", c1, c0, & + "snow/ice/ocn absorbed solar flux (cpl)", & + "positive downward", c1, c0, & ns1, f_fswabs) call define_hist_field(n_fswabs_ai,"fswabs_ai","W/m^2",tstr2D, tcstr, & - "snow/ice/ocn absorbed solar flux", & - "weighted by ice area", c1, c0, & + "snow/ice/ocn absorbed solar flux", & + "weighted by ice area", c1, c0, & ns1, f_fswabs_ai) call define_hist_field(n_albsni,"albsni","%",tstr2D, tcstr, & - "snow/ice broad band albedo", & - "averaged for coszen>0, weighted by aice", c100, c0, & + "snow/ice broad band albedo", & + "averaged for coszen>0, weighted by aice", c100, c0, & ns1, f_albsni) call define_hist_field(n_alvdr,"alvdr","%",tstr2D, tcstr, & - "visible direct albedo", & - "scaled (divided) by aice", c100, c0, & + "visible direct albedo", & + "scaled (divided) by aice", c100, c0, & ns1, f_alvdr) call define_hist_field(n_alidr,"alidr","%",tstr2D, tcstr, & - "near IR direct albedo", & - "scaled (divided) by aice", c100, c0, & + "near IR direct albedo", & + "scaled (divided) by aice", c100, c0, & ns1, f_alidr) call define_hist_field(n_alvdf,"alvdf","%",tstr2D, tcstr, & - "visible diffuse albedo", & - "scaled (divided) by aice", c100, c0, & + "visible diffuse albedo", & + "scaled (divided) by aice", c100, c0, & ns1, f_alvdf) call define_hist_field(n_alidf,"alidf","%",tstr2D, tcstr, & - "near IR diffuse albedo", & - "scaled (divided) by aice", c100, c0, & + "near IR diffuse albedo", & + "scaled (divided) by aice", c100, c0, & ns1, f_alidf) call define_hist_field(n_alvdr_ai,"alvdr_ai","%",tstr2D, tcstr, & - "visible direct albedo", & - " ", c100, c0, & + "visible direct albedo", & + " ", c100, c0, & ns1, f_alvdr_ai) call define_hist_field(n_alidr_ai,"alidr_ai","%",tstr2D, tcstr, & - "near IR direct albedo", & - " ", c100, c0, & + "near IR direct albedo", & + " ", c100, c0, & ns1, f_alidr_ai) call define_hist_field(n_alvdf_ai,"alvdf_ai","%",tstr2D, tcstr, & - "visible diffuse albedo", & - " ", c100, c0, & + "visible diffuse albedo", & + " ", c100, c0, & ns1, f_alvdf_ai) call define_hist_field(n_alidf_ai,"alidf_ai","%",tstr2D, tcstr, & - "near IR diffuse albedo", & - " ", c100, c0, & + "near IR diffuse albedo", & + " ", c100, c0, & ns1, f_alidf_ai) call define_hist_field(n_albice,"albice","%",tstr2D, tcstr, & - "bare ice albedo", & - "averaged for coszen>0, weighted by aice", c100, c0, & + "bare ice albedo", & + "averaged for coszen>0, weighted by aice", c100, c0, & ns1, f_albice) call define_hist_field(n_albsno,"albsno","%",tstr2D, tcstr, & - "snow albedo", & - "averaged for coszen>0, weighted by aice", c100, c0, & + "snow albedo", & + "averaged for coszen>0, weighted by aice", c100, c0, & ns1, f_albsno) call define_hist_field(n_albpnd,"albpnd","%",tstr2D, tcstr, & - "melt pond albedo", & - "averaged for coszen>0, weighted by aice", c100, c0, & + "melt pond albedo", & + "averaged for coszen>0, weighted by aice", c100, c0, & ns1, f_albpnd) call define_hist_field(n_coszen,"coszen","radian",tstr2D, tcstr, & - "cosine of the zenith angle", & - "negative below horizon", c1, c0, & + "cosine of the zenith angle", & + "negative below horizon", c1, c0, & ns1, f_coszen) call define_hist_field(n_flat,"flat","W/m^2",tstr2D, tcstr, & - "latent heat flux (cpl)", & - "positive downward", c1, c0, & + "latent heat flux (cpl)", & + "positive downward", c1, c0, & ns1, f_flat) call define_hist_field(n_flat_ai,"flat_ai","W/m^2",tstr2D, tcstr, & - "latent heat flux", & - "weighted by ice area", c1, c0, & + "latent heat flux", & + "weighted by ice area", c1, c0, & ns1, f_flat_ai) call define_hist_field(n_fsens,"fsens","W/m^2",tstr2D, tcstr, & - "sensible heat flux (cpl)", & - "positive downward", c1, c0, & + "sensible heat flux (cpl)", & + "positive downward", c1, c0, & ns1, f_fsens) call define_hist_field(n_fsens_ai,"fsens_ai","W/m^2",tstr2D, tcstr, & - "sensible heat flux", & - "weighted by ice area", c1, c0, & + "sensible heat flux", & + "weighted by ice area", c1, c0, & ns1, f_fsens_ai) call define_hist_field(n_flwup,"flwup","W/m^2",tstr2D, tcstr, & - "upward longwave flux (cpl)", & - "positive downward", c1, c0, & + "upward longwave flux (cpl)", & + "positive downward", c1, c0, & ns1, f_flwup) call define_hist_field(n_flwup_ai,"flwup_ai","W/m^2",tstr2D, tcstr, & - "upward longwave flux", & - "weighted by ice area", c1, c0, & + "upward longwave flux", & + "weighted by ice area", c1, c0, & ns1, f_flwup_ai) call define_hist_field(n_evap,"evap","cm/day",tstr2D, tcstr, & - "evaporative water flux (cpl)", & - "none", mps_to_cmpdy/rhofresh, c0, & + "evaporative water flux (cpl)", & + "none", mps_to_cmpdy/rhofresh, c0, & ns1, f_evap) call define_hist_field(n_evap_ai,"evap_ai","cm/day",tstr2D, tcstr, & - "evaporative water flux", & - "weighted by ice area", mps_to_cmpdy/rhofresh, c0, & + "evaporative water flux", & + "weighted by ice area", mps_to_cmpdy/rhofresh, c0, & ns1, f_evap_ai) call define_hist_field(n_Tair,"Tair","C",tstr2D, tcstr, & - "air temperature", & - "none", c1, -Tffresh, & + "air temperature", & + "none", c1, -Tffresh, & ns1, f_Tair) call define_hist_field(n_Tref,"Tref","C",tstr2D, tcstr, & - "2m reference temperature", & - "none", c1, -Tffresh, & + "2m reference temperature", & + "none", c1, -Tffresh, & ns1, f_Tref) call define_hist_field(n_Qref,"Qref","g/kg",tstr2D, tcstr, & - "2m reference specific humidity", & - "none", kg_to_g, c0, & + "2m reference specific humidity", & + "none", kg_to_g, c0, & ns1, f_Qref) call define_hist_field(n_congel,"congel","cm/day",tstr2D, tcstr, & - "congelation ice growth", & - "none", mps_to_cmpdy/dt, c0, & + "congelation ice growth", & + "none", mps_to_cmpdy/dt, c0, & ns1, f_congel) call define_hist_field(n_frazil,"frazil","cm/day",tstr2D, tcstr, & - "frazil ice growth", & - "none", mps_to_cmpdy/dt, c0, & + "frazil ice growth", & + "none", mps_to_cmpdy/dt, c0, & ns1, f_frazil) call define_hist_field(n_snoice,"snoice","cm/day",tstr2D, tcstr, & - "snow-ice formation", & - "none", mps_to_cmpdy/dt, c0, & + "snow-ice formation", & + "none", mps_to_cmpdy/dt, c0, & ns1, f_snoice) call define_hist_field(n_dsnow,"dsnow","cm/day",tstr2D, tcstr, & - "snow formation", & + "snow formation", & "none", mps_to_cmpdy/dt, c0, & ns1, f_dsnow) call define_hist_field(n_meltt,"meltt","cm/day",tstr2D, tcstr, & - "top ice melt", & - "none", mps_to_cmpdy/dt, c0, & + "top ice melt", & + "none", mps_to_cmpdy/dt, c0, & ns1, f_meltt) call define_hist_field(n_melts,"melts","cm/day",tstr2D, tcstr, & - "top snow melt", & - "none", mps_to_cmpdy/dt, c0, & + "top snow melt", & + "none", mps_to_cmpdy/dt, c0, & ns1, f_melts) call define_hist_field(n_meltb,"meltb","cm/day",tstr2D, tcstr, & - "basal ice melt", & - "none", mps_to_cmpdy/dt, c0, & + "basal ice melt", & + "none", mps_to_cmpdy/dt, c0, & ns1, f_meltb) call define_hist_field(n_meltl,"meltl","cm/day",tstr2D, tcstr, & - "lateral ice melt", & - "none", mps_to_cmpdy/dt, c0, & + "lateral ice melt", & + "none", mps_to_cmpdy/dt, c0, & ns1, f_meltl) call define_hist_field(n_fresh,"fresh","cm/day",tstr2D, tcstr, & - "freshwtr flx ice to ocn (cpl)", & - "if positive, ocean gains fresh water", & - mps_to_cmpdy/rhofresh, c0, & + "freshwtr flx ice to ocn (cpl)", & + "if positive, ocean gains fresh water", & + mps_to_cmpdy/rhofresh, c0, & ns1, f_fresh) call define_hist_field(n_fresh_ai,"fresh_ai","cm/day",tstr2D, tcstr, & - "freshwtr flx ice to ocn", & - "weighted by ice area", mps_to_cmpdy/rhofresh, c0, & + "freshwtr flx ice to ocn", & + "weighted by ice area", mps_to_cmpdy/rhofresh, c0, & ns1, f_fresh_ai) call define_hist_field(n_fsalt,"fsalt","kg/m^2/s",tstr2D, tcstr, & - "salt flux ice to ocn (cpl)", & - "if positive, ocean gains salt", c1, c0, & + "salt flux ice to ocn (cpl)", & + "if positive, ocean gains salt", c1, c0, & ns1, f_fsalt) call define_hist_field(n_fsalt_ai,"fsalt_ai","kg/m^2/s",tstr2D, tcstr, & - "salt flux ice to ocean", & - "weighted by ice area", c1, c0, & + "salt flux ice to ocean", & + "weighted by ice area", c1, c0, & ns1, f_fsalt_ai) call define_hist_field(n_fbot,"fbot","W/m^2",tstr2D, tcstr, & @@ -1126,223 +1065,223 @@ subroutine init_hist (dt) ns1, f_fbot) call define_hist_field(n_fhocn,"fhocn","W/m^2",tstr2D, tcstr, & - "heat flux ice to ocn (cpl)", & - "if positive, ocean gains heat", c1, c0, & + "heat flux ice to ocn (cpl)", & + "if positive, ocean gains heat", c1, c0, & ns1, f_fhocn) call define_hist_field(n_fhocn_ai,"fhocn_ai","W/m^2",tstr2D, tcstr, & - "heat flux ice to ocean (fhocn_ai)", & - "weighted by ice area", c1, c0, & + "heat flux ice to ocean (fhocn_ai)", & + "weighted by ice area", c1, c0, & ns1, f_fhocn_ai) call define_hist_field(n_fswthru,"fswthru","W/m^2",tstr2D, tcstr, & - "SW thru ice to ocean (cpl)", & - "if positive, ocean gains heat", c1, c0, & + "SW thru ice to ocean (cpl)", & + "if positive, ocean gains heat", c1, c0, & ns1, f_fswthru) call define_hist_field(n_fswthru_ai,"fswthru_ai","W/m^2",tstr2D, tcstr,& - "SW flux thru ice to ocean", & - "weighted by ice area", c1, c0, & + "SW flux thru ice to ocean", & + "weighted by ice area", c1, c0, & ns1, f_fswthru_ai) call define_hist_field(n_strairx,"strairx","N/m^2",ustr2D, ucstr, & - "atm/ice stress (x)", & - "positive is x direction on U grid", c1, c0, & + "atm/ice stress (x)", & + "positive is x direction on U grid", c1, c0, & ns1, f_strairx) call define_hist_field(n_strairy,"strairy","N/m^2",ustr2D, ucstr, & - "atm/ice stress (y)", & - "positive is y direction on U grid", c1, c0, & + "atm/ice stress (y)", & + "positive is y direction on U grid", c1, c0, & ns1, f_strairy) call define_hist_field(n_strtltx,"strtltx","N/m^2",ustr2D, ucstr, & - "sea sfc tilt stress (x)", & - "none", c1, c0, & + "sea sfc tilt stress (x)", & + "none", c1, c0, & ns1, f_strtltx) call define_hist_field(n_strtlty,"strtlty","N/m^2",ustr2D, ucstr, & - "sea sfc tilt stress (y)", & - "none", c1, c0, & + "sea sfc tilt stress (y)", & + "none", c1, c0, & ns1, f_strtlty) call define_hist_field(n_strcorx,"strcorx","N/m^2",ustr2D, ucstr, & - "coriolis stress (x)", & - "positive is x direction on U grid", c1, c0, & + "coriolis stress (x)", & + "positive is x direction on U grid", c1, c0, & ns1, f_strcorx) call define_hist_field(n_strcory,"strcory","N/m^2",ustr2D, ucstr, & - "coriolis stress (y)", & - "positive is y direction on U grid", c1, c0, & + "coriolis stress (y)", & + "positive is y direction on U grid", c1, c0, & ns1, f_strcory) call define_hist_field(n_strocnx,"strocnx","N/m^2",ustr2D, ucstr, & - "ocean/ice stress (x)", & - "positive is x direction on U grid", c1, c0, & + "ocean/ice stress (x)", & + "positive is x direction on U grid", c1, c0, & ns1, f_strocnx) call define_hist_field(n_strocny,"strocny","N/m^2",ustr2D, ucstr, & - "ocean/ice stress (y)", & - "positive is y direction on U grid", c1, c0, & + "ocean/ice stress (y)", & + "positive is y direction on U grid", c1, c0, & ns1, f_strocny) call define_hist_field(n_strintx,"strintx","N/m^2",ustr2D, ucstr, & - "internal ice stress (x)", & - "positive is x direction on U grid", c1, c0, & + "internal ice stress (x)", & + "positive is x direction on U grid", c1, c0, & ns1, f_strintx) call define_hist_field(n_strinty,"strinty","N/m^2",ustr2D, ucstr, & - "internal ice stress (y)", & - "positive is y direction on U grid", c1, c0, & + "internal ice stress (y)", & + "positive is y direction on U grid", c1, c0, & ns1, f_strinty) - call define_hist_field(n_taubx,"taubx","N/m^2",ustr2D, ucstr, & - "seabed (basal) stress (x)", & - "positive is x direction on U grid", c1, c0, & + call define_hist_field(n_taubx,"taubx","N/m^2",ustr2D, ucstr, & + "seabed (basal) stress (x)", & + "positive is x direction on U grid", c1, c0, & ns1, f_taubx) - call define_hist_field(n_tauby,"tauby","N/m^2",ustr2D, ucstr, & - "seabed (basal) stress (y)", & - "positive is y direction on U grid", c1, c0, & + call define_hist_field(n_tauby,"tauby","N/m^2",ustr2D, ucstr, & + "seabed (basal) stress (y)", & + "positive is y direction on U grid", c1, c0, & ns1, f_tauby) call define_hist_field(n_strairxN,"strairxN","N/m^2",nstr2D, ncstr, & - "atm/ice stress (x)", & - "positive is x direction on N grid", c1, c0, & + "atm/ice stress (x)", & + "positive is x direction on N grid", c1, c0, & ns1, f_strairxN) call define_hist_field(n_strairyN,"strairyN","N/m^2",nstr2D, ncstr, & - "atm/ice stress (y)", & - "positive is y direction on N grid", c1, c0, & + "atm/ice stress (y)", & + "positive is y direction on N grid", c1, c0, & ns1, f_strairyN) call define_hist_field(n_strairxE,"strairxE","N/m^2",estr2D, ecstr, & - "atm/ice stress (x)", & - "positive is x direction on E grid", c1, c0, & + "atm/ice stress (x)", & + "positive is x direction on E grid", c1, c0, & ns1, f_strairxE) call define_hist_field(n_strairyE,"strairyE","N/m^2",estr2D, ecstr, & - "atm/ice stress (y)", & - "positive is y direction on E grid", c1, c0, & + "atm/ice stress (y)", & + "positive is y direction on E grid", c1, c0, & ns1, f_strairyE) call define_hist_field(n_strtltxN,"strtltxN","N/m^2",nstr2D, ncstr, & - "sea sfc tilt stress (x)", & - "positive is x direction on N grid", c1, c0, & + "sea sfc tilt stress (x)", & + "positive is x direction on N grid", c1, c0, & ns1, f_strtltxN) call define_hist_field(n_strtltyN,"strtltyN","N/m^2",nstr2D, ncstr, & - "sea sfc tilt stress (y)", & - "positive is y direction on N grid", c1, c0, & + "sea sfc tilt stress (y)", & + "positive is y direction on N grid", c1, c0, & ns1, f_strtltyN) call define_hist_field(n_strtltxE,"strtltxE","N/m^2",estr2D, ecstr, & - "sea sfc tilt stress (x)", & - "positive is x direction on E grid", c1, c0, & + "sea sfc tilt stress (x)", & + "positive is x direction on E grid", c1, c0, & ns1, f_strtltxE) call define_hist_field(n_strtltyE,"strtltyE","N/m^2",estr2D, ecstr, & - "sea sfc tilt stress (y)", & - "positive is y direction on E grid", c1, c0, & + "sea sfc tilt stress (y)", & + "positive is y direction on E grid", c1, c0, & ns1, f_strtltyE) call define_hist_field(n_strcorxN,"strcorxN","N/m^2",nstr2D, ncstr, & - "coriolis stress (x)", & - "positive is x direction on N grid", c1, c0, & + "coriolis stress (x)", & + "positive is x direction on N grid", c1, c0, & ns1, f_strcorxN) call define_hist_field(n_strcoryN,"strcoryN","N/m^2",nstr2D, ncstr, & - "coriolis stress (y)", & - "positive is y direction on N grid", c1, c0, & + "coriolis stress (y)", & + "positive is y direction on N grid", c1, c0, & ns1, f_strcoryN) call define_hist_field(n_strcorxE,"strcorxE","N/m^2",estr2D, ecstr, & - "coriolis stress (x)", & - "positive is x direction on E grid", c1, c0, & + "coriolis stress (x)", & + "positive is x direction on E grid", c1, c0, & ns1, f_strcorxE) call define_hist_field(n_strcoryE,"strcoryE","N/m^2",estr2D, ecstr, & - "coriolis stress (y)", & - "positive is y direction on E grid", c1, c0, & + "coriolis stress (y)", & + "positive is y direction on E grid", c1, c0, & ns1, f_strcoryE) call define_hist_field(n_strocnxN,"strocnxN","N/m^2",nstr2D, ncstr, & - "ocean/ice stress (x)", & - "positive is x direction on N grid", c1, c0, & + "ocean/ice stress (x)", & + "positive is x direction on N grid", c1, c0, & ns1, f_strocnxN) call define_hist_field(n_strocnyN,"strocnyN","N/m^2",nstr2D, ncstr, & - "ocean/ice stress (y)", & - "positive is y direction on N grid", c1, c0, & + "ocean/ice stress (y)", & + "positive is y direction on N grid", c1, c0, & ns1, f_strocnyN) call define_hist_field(n_strocnxE,"strocnxE","N/m^2",estr2D, ecstr, & - "ocean/ice stress (x)", & - "positive is x direction on E grid", c1, c0, & + "ocean/ice stress (x)", & + "positive is x direction on E grid", c1, c0, & ns1, f_strocnxE) call define_hist_field(n_strocnyE,"strocnyE","N/m^2",estr2D, ecstr, & - "ocean/ice stress (y)", & - "positive is y direction on E grid", c1, c0, & + "ocean/ice stress (y)", & + "positive is y direction on E grid", c1, c0, & ns1, f_strocnyE) call define_hist_field(n_strintxN,"strintxN","N/m^2",nstr2D, ncstr, & - "internal ice stress (x)", & - "positive is x direction on N grid", c1, c0, & + "internal ice stress (x)", & + "positive is x direction on N grid", c1, c0, & ns1, f_strintxN) call define_hist_field(n_strintyN,"strintyN","N/m^2",nstr2D, ncstr, & - "internal ice stress (y)", & - "positive is y direction on N grid", c1, c0, & + "internal ice stress (y)", & + "positive is y direction on N grid", c1, c0, & ns1, f_strintyN) call define_hist_field(n_strintxE,"strintxE","N/m^2",estr2D, ecstr, & - "internal ice stress (x)", & - "positive is x direction on E grid", c1, c0, & + "internal ice stress (x)", & + "positive is x direction on E grid", c1, c0, & ns1, f_strintxE) call define_hist_field(n_strintyE,"strintyE","N/m^2",estr2D, ecstr, & - "internal ice stress (y)", & - "positive is y direction on E grid", c1, c0, & + "internal ice stress (y)", & + "positive is y direction on E grid", c1, c0, & ns1, f_strintyE) - call define_hist_field(n_taubxN,"taubxN","N/m^2",nstr2D, ncstr, & + call define_hist_field(n_taubxN,"taubxN","N/m^2",nstr2D, ncstr, & "seabed (basal) stress (x)", & "positive is x direction on N grid", c1, c0, & ns1, f_taubxN) - call define_hist_field(n_taubyN,"taubyN","N/m^2",nstr2D, ncstr, & + call define_hist_field(n_taubyN,"taubyN","N/m^2",nstr2D, ncstr, & "seabed (basal) stress (y)", & "positive is y direction on N grid", c1, c0, & ns1, f_taubyN) - call define_hist_field(n_taubxE,"taubxE","N/m^2",estr2D, ecstr, & + call define_hist_field(n_taubxE,"taubxE","N/m^2",estr2D, ecstr, & "seabed (basal) stress (x)", & "positive is x direction on E grid", c1, c0, & ns1, f_taubxE) - call define_hist_field(n_taubyE,"taubyE","N/m^2",estr2D, ecstr, & + call define_hist_field(n_taubyE,"taubyE","N/m^2",estr2D, ecstr, & "seabed (basal) stress (y)", & "positive is y direction on E grid", c1, c0, & ns1, f_taubyE) call define_hist_field(n_strength,"strength","N/m",tstr2D, tcstr, & - "compressive ice strength", & - "none", c1, c0, & + "compressive ice strength", & + "none", c1, c0, & ns1, f_strength) call define_hist_field(n_divu,"divu","%/day",tstr2D, tcstr, & - "strain rate (divergence)", & - "divu is instantaneous, on T grid", secday*c100, c0, & + "strain rate (divergence)", & + "divu is instantaneous, on T grid", secday*c100, c0, & ns1, f_divu) call define_hist_field(n_shear,"shear","%/day",tstr2D, tcstr, & - "strain rate (shear)", & - "shear is instantaneous, on T grid", secday*c100, c0, & + "strain rate (shear)", & + "shear is instantaneous, on T grid", secday*c100, c0, & ns1, f_shear) call define_hist_field(n_vort,"vort","%/day",tstr2D, tcstr, & - "strain rate (vorticity)", & - "vort is instantaneous, on T grid", secday*c100, c0, & + "strain rate (vorticity)", & + "vort is instantaneous, on T grid", secday*c100, c0, & ns1, f_vort) select case (grid_ice) @@ -1357,68 +1296,68 @@ subroutine init_hist (dt) end select call define_hist_field(n_sig1,"sig1","1",gridstr2d, gridstr, & - "norm. principal stress 1", & - "sig1 is instantaneous" // trim(description), c1, c0, & + "norm. principal stress 1", & + "sig1 is instantaneous" // trim(description), c1, c0, & ns1, f_sig1) call define_hist_field(n_sig2,"sig2","1",gridstr2d, gridstr, & - "norm. principal stress 2", & - "sig2 is instantaneous" // trim(description), c1, c0, & + "norm. principal stress 2", & + "sig2 is instantaneous" // trim(description), c1, c0, & ns1, f_sig2) call define_hist_field(n_sigP,"sigP","N/m",gridstr2d, gridstr, & - "ice pressure", & - "sigP is instantaneous" // trim(description), c1, c0, & + "ice pressure", & + "sigP is instantaneous" // trim(description), c1, c0, & ns1, f_sigP) call define_hist_field(n_dvidtt,"dvidtt","cm/day",tstr2D, tcstr, & - "volume tendency thermo", & - "none", mps_to_cmpdy, c0, & + "volume tendency thermo", & + "none", mps_to_cmpdy, c0, & ns1, f_dvidtt) call define_hist_field(n_dvidtd,"dvidtd","cm/day",tstr2D, tcstr, & - "volume tendency dynamics", & - "none", mps_to_cmpdy, c0, & + "volume tendency dynamics", & + "none", mps_to_cmpdy, c0, & ns1, f_dvidtd) call define_hist_field(n_daidtt,"daidtt","%/day",tstr2D, tcstr, & - "area tendency thermo", & - "none", secday*c100, c0, & + "area tendency thermo", & + "none", secday*c100, c0, & ns1, f_daidtt) call define_hist_field(n_daidtd,"daidtd","%/day",tstr2D, tcstr, & - "area tendency dynamics", & - "none", secday*c100, c0, & + "area tendency dynamics", & + "none", secday*c100, c0, & ns1, f_daidtd) call define_hist_field(n_dagedtt,"dagedtt","day/day",tstr2D, tcstr, & - "age tendency thermo", & - "excludes time step increment", c1, c0, & + "age tendency thermo", & + "excludes time step increment", c1, c0, & ns1, f_dagedtt) call define_hist_field(n_dagedtd,"dagedtd","day/day",tstr2D, tcstr, & - "age tendency dynamics", & - "excludes time step increment", c1, c0, & + "age tendency dynamics", & + "excludes time step increment", c1, c0, & ns1, f_dagedtd) call define_hist_field(n_mlt_onset,"mlt_onset","day of year", & - tstr2D, tcstr,"melt onset date", & + tstr2D, tcstr,"melt onset date", & "midyear restart gives erroneous dates", c1, c0, & ns1, f_mlt_onset) call define_hist_field(n_frz_onset,"frz_onset","day of year", & - tstr2D, tcstr,"freeze onset date", & + tstr2D, tcstr,"freeze onset date", & "midyear restart gives erroneous dates", c1, c0, & ns1, f_frz_onset) call define_hist_field(n_hisnap,"hisnap","m",tstr2D, tcstr, & - "ice volume snapshot", & - "none", c1, c0, & + "ice volume snapshot", & + "none", c1, c0, & ns1, f_hisnap) call define_hist_field(n_aisnap,"aisnap","1",tstr2D, tcstr, & - "ice area snapshot", & - "none", c1, c0, & + "ice area snapshot", & + "none", c1, c0, & ns1, f_aisnap) call define_hist_field(n_trsig,"trsig","N/m",tstr2D, tcstr, & @@ -1427,396 +1366,492 @@ subroutine init_hist (dt) ns1, f_trsig) call define_hist_field(n_icepresent,"ice_present","1",tstr2D, tcstr, & - "fraction of time-avg interval that ice is present", & - "ice extent flag", c1, c0, & + "fraction of time-avg interval that ice is present", & + "ice extent flag", c1, c0, & ns1, f_icepresent) - call define_hist_field(n_fsurf_ai,"fsurf_ai","W/m^2",tstr2D, tcstr, & - "net surface heat flux", & + call define_hist_field(n_fsurf_ai,"fsurf_ai","W/m^2",tstr2D, tcstr, & + "net surface heat flux", & "positive downward, excludes conductive flux, weighted by ice area", & c1, c0, & ns1, f_fsurf_ai) call define_hist_field(n_fcondtop_ai,"fcondtop_ai","W/m^2", & - tstr2D, tcstr,"top surface conductive heat flux", & + tstr2D, tcstr,"top surface conductive heat flux", & "positive downward, weighted by ice area", c1, c0, & ns1, f_fcondtop_ai) call define_hist_field(n_fmeltt_ai,"fmeltt_ai","W/m^2",tstr2D, tcstr, & - "net surface heat flux causing melt", & - "always >= 0, weighted by ice area", c1, c0, & + "net surface heat flux causing melt", & + "always >= 0, weighted by ice area", c1, c0, & ns1, f_fmeltt_ai) call define_hist_field(n_a11,"a11"," ",tstr2D, tcstr, & "a11: component a11 of the structure tensor", & - "none", c1, c0, & + "none", c1, c0, & ns1, f_a11) call define_hist_field(n_a12,"a12"," ",tstr2D, tcstr, & "a12: component a12 of the structure tensor", & - "none", c1, c0, & + "none", c1, c0, & ns1, f_a12) call define_hist_field(n_e11,"e11","1/s",tstr2D, tcstr, & "e11: component e11 of the strain rate tensor", & - "none", c1, c0, & + "none", c1, c0, & ns1, f_e11) call define_hist_field(n_e12,"e12","1/s",tstr2D, tcstr, & "e12: component e12 of the strain rate tensor", & - "none", c1, c0, & + "none", c1, c0, & ns1, f_e12) call define_hist_field(n_e22,"e22","1/s",tstr2D, tcstr, & "e22: component e22 of the strain rate tensor", & - "none", c1, c0, & + "none", c1, c0, & ns1, f_e22) call define_hist_field(n_s11,"s11","kg/s^2",tstr2D, tcstr, & "s11: component s11 of the stress tensor", & - "none", c1, c0, & + "none", c1, c0, & ns1, f_s11) call define_hist_field(n_s12,"s12","kg/s^2",tstr2D, tcstr, & "s12: component s12 of the stress tensor", & - "none", c1, c0, & + "none", c1, c0, & ns1, f_s12) call define_hist_field(n_s22,"s22","kg/s^2",tstr2D, tcstr, & "s22: component s12 of the stress tensor", & - "none", c1, c0, & + "none", c1, c0, & ns1, f_s22) call define_hist_field(n_yieldstress11,"yieldstress11","kg/s^2",tstr2D, tcstr, & "yieldstress11: component 11 of the yieldstress tensor", & - "none", c1, c0, & + "none", c1, c0, & ns1, f_yieldstress11) call define_hist_field(n_yieldstress12,"yieldstress12","kg/s^2",tstr2D, tcstr, & "yieldstress12: component 12 of the yieldstress tensor", & - "none", c1, c0, & + "none", c1, c0, & ns1, f_yieldstress12) call define_hist_field(n_yieldstress22,"yieldstress22","kg/s^2",tstr2D, tcstr, & "yieldstress22: component 12 of the yieldstress tensor", & - "none", c1, c0, & + "none", c1, c0, & ns1, f_yieldstress22) ! Tracers ! Ice Age call define_hist_field(n_iage,"iage","years",tstr2D, tcstr, & - "sea ice age", & - "none", c1/(secday*days_per_year), c0, & + "sea ice age", & + "none", c1/(secday*days_per_year), c0, & ns1, f_iage) ! First Year Ice Area call define_hist_field(n_FY,"FYarea"," ",tstr2D, tcstr, & - "first-year ice area", & - "weighted by ice area", c1, c0, & + "first-year ice area", & + "weighted by ice area", c1, c0, & ns1, f_FY) - ! CMIP 2D variables + ! CMIP 2D variables (for "intensive" variables per Notz et al 2016 definition, + ! that is a weighted time average when ice is present) + ! Use avg_ice_present = 'init', 'final', 'pond', or 'ridge' to divide by + ! sum(aice), sum(apond), or sum(ardg) over time + ! aice is at the start of the timestep ('init') or the end of the timestep ('final') + ! avg_ice_present = 'none' produces a time average including zeroes when ice is not present + + call define_hist_field(n_siage,"siage","s",tstr2D, tcstr, & + "age of sea ice", & + "age of sea ice since its formation in open water", c1, c0, & + ns1, f_siage, avg_ice_present='final', mask_ice_free_points=.true.) + + call define_hist_field(n_sicompstren,"sicompstren","N m-1",tstr2D, tcstr, & + "compressive sea-ice strength", & + "computed strength of the ice pack", c1, c0, & + ns1, f_sicompstren, avg_ice_present='final', mask_ice_free_points=.true.) + + call define_hist_field(n_sidragbot,"sidragbot","1",tstr2D, tcstr, & + "ocean drag coefficient", & + "drag coefficient that is used to calculate the oceanic momentum drag on sea ice", & + c1, c0, & + ns1, f_sidragbot, avg_ice_present='init', mask_ice_free_points=.true.) + + call define_hist_field(n_sidragtop,"sidragtop","1",tstr2D, tcstr, & + "atmospheric drag coefficient", & + "drag coefficient that is used to calculate the atmospheric momentum drag on sea ice", & + c1, c0, & + ns1, f_sidragtop, avg_ice_present='init', mask_ice_free_points=.true.) - call define_hist_field(n_sithick,"sithick","m",tstr2D, tcstr, & - "sea ice thickness", & - "volume divided by area", c1, c0, & - ns1, f_sithick, avg_ice_present=.true., mask_ice_free_points=.true.) - - call define_hist_field(n_siage,"siage","s",tstr2D, tcstr, & - "sea ice age", & - "none", c1, c0, & - ns1, f_siage, avg_ice_present=.true., mask_ice_free_points=.true.) - - call define_hist_field(n_sisnthick,"sisnthick","m",tstr2D, tcstr, & - "sea ice snow thickness", & - "snow volume divided by area", c1, c0, & - ns1, f_sisnthick, avg_ice_present=.true., mask_ice_free_points=.true.) - - call define_hist_field(n_sitemptop,"sitemptop","K",tstr2D, tcstr, & - "sea ice surface temperature", & - "none", c1, Tffresh, & - ns1, f_sitemptop, avg_ice_present=.true., mask_ice_free_points=.true.) - - call define_hist_field(n_sitempsnic,"sitempsnic","K",tstr2D, tcstr, & - "snow ice interface temperature", & - "surface temperature when no snow present", c1, Tffresh, & - ns1, f_sitempsnic, avg_ice_present=.true., mask_ice_free_points=.true.) - - call define_hist_field(n_sitempbot,"sitempbot","K",tstr2D, tcstr, & - "sea ice bottom temperature", & - "none", c1, Tffresh, & - ns1, f_sitempbot, avg_ice_present=.true., mask_ice_free_points=.true.) - - call define_hist_field(n_siu,"siu","m/s",ustr2D, ucstr, & - "ice x velocity component", & - "none", c1, c0, & - ns1, f_siu, avg_ice_present=.true., mask_ice_free_points=.true.) - - call define_hist_field(n_siv,"siv","m/s",ustr2D, ucstr, & - "ice y velocity component", & - "none", c1, c0, & - ns1, f_siv, avg_ice_present=.true., mask_ice_free_points=.true.) - - call define_hist_field(n_sidmasstranx,"sidmasstranx","kg/s",ustr2D, ucstr, & - "x component of snow and sea ice mass transport", & - "none", c1, c0, & - ns1, f_sidmasstranx) - - call define_hist_field(n_sidmasstrany,"sidmasstrany","kg/s",ustr2D, ucstr, & - "y component of snow and sea ice mass transport", & - "none", c1, c0, & - ns1, f_sidmasstrany) - - call define_hist_field(n_sistrxdtop,"sistrxdtop","N m-2",ustr2D, ucstr, & - "x component of atmospheric stress on sea ice", & - "none", c1, c0, & - ns1, f_sistrxdtop, avg_ice_present=.true., mask_ice_free_points=.true.) - - call define_hist_field(n_sistrydtop,"sistrydtop","N m-2",ustr2D, ucstr, & - "y component of atmospheric stress on sea ice", & - "none", c1, c0, & - ns1, f_sistrydtop, avg_ice_present=.true., mask_ice_free_points=.true.) - - call define_hist_field(n_sistrxubot,"sistrxubot","N m-2",ustr2D, ucstr, & - "x component of ocean stress on sea ice", & - "none", c1, c0, & - ns1, f_sistrxubot, avg_ice_present=.true., mask_ice_free_points=.true.) - - call define_hist_field(n_sistryubot,"sistryubot","N m-2",ustr2D, ucstr, & - "y component of ocean stress on sea ice", & - "none", c1, c0, & - ns1, f_sistryubot, avg_ice_present=.true., mask_ice_free_points=.true.) - - call define_hist_field(n_sicompstren,"sicompstren","N m-1",tstr2D, tcstr, & - "compressive sea ice strength", & - "none", c1, c0, & - ns1, f_sicompstren, avg_ice_present=.true., mask_ice_free_points=.true.) + call define_hist_field(n_sifb,"sifb","m",tstr2D, tcstr, & + "sea-ice freeboard", & + "mean height of sea-ice surface above sea level", & + c1, c0, & + ns1, f_sifb, avg_ice_present='final', mask_ice_free_points=.true.) + + call define_hist_field(n_siflcondbot,"siflcondbot","W/m2",tstr2D, tcstr, & + "net conductive heat flux in sea-ice at the base", & + "conductive heat flux from the centre of the lowermost vertical sea-ice grid box", & + c1, c0, & + ns1, f_siflcondbot, avg_ice_present='init', mask_ice_free_points=.true.) + + call define_hist_field(n_siflcondtop,"siflcondtop","W/m2",tstr2D, tcstr, & + "net conductive heat flux in sea-ice at the surface", & + "conductive heat flux from the centre of the uppermost vertical sea-ice grid box", & + c1, c0, & + ns1, f_siflcondtop, avg_ice_present='init', mask_ice_free_points=.true.) - call define_hist_field(n_sispeed,"sispeed","m/s",ustr2D, ucstr, & - "ice speed", & - "none", c1, c0, & - ns1, f_sispeed, avg_ice_present=.true., mask_ice_free_points=.true.) + call define_hist_field(n_siflfwbot,"siflfwbot","kg m-2 s-1",tstr2D, tcstr, & + "freshwater flux from sea-ice", & + "total flux of fresh water between ocean and sea ice", c1, c0, & + ns1, f_siflfwbot, avg_ice_present='final', mask_ice_free_points=.true.) - call define_hist_field(n_sidir,"sidir","deg",ustr2D, ucstr, & - "ice direction", & - "vector direction - going to", c1, c0, & - ns1, f_sidir) + call define_hist_field(n_siflfwdrain,"siflfwdrain","kg m-2 s-1",tstr2D, tcstr, & + "freshwater flux from sea-ice surface", & + "total flux of fresh water from sea-ice surface into underlying ocean", & + c1, c0, & + ns1, f_siflfwdrain, avg_ice_present='final', mask_ice_free_points=.true.) + + call define_hist_field(n_sifllattop,"sifllattop","W/m2",tstr2D, tcstr, & + "net latent heat flux over sea ice", & + "positive downward", c1, c0, & + ns1, f_sifllattop, avg_ice_present='init', mask_ice_free_points=.true.) + + call define_hist_field(n_sifllwdtop,"sifllwdtop","W/m2",tstr2D, tcstr, & + "downwelling longwave flux over sea ice", & + "downwelling longwave flux from the atmosphere to the sea-ice surface ", & + c1, c0, & + ns1, f_sifllwdtop, avg_ice_present='init', mask_ice_free_points=.true.) - call define_hist_field(n_sialb,"sialb","1",tstr2D, tcstr, & - "sea ice albedo", & - "none", c1, c0, & - ns1, f_sialb, avg_ice_present=.true., mask_ice_free_points=.true.) + call define_hist_field(n_sifllwutop,"sifllwutop","W/m2",tstr2D, tcstr, & + "upwelling longwave flux over sea ice", & + "upward longwave flux from the sea-ice surface to the atmosphere", & + c1, c0, & + ns1, f_sifllwutop, avg_ice_present='init', mask_ice_free_points=.true.) - call define_hist_field(n_sihc,"sihc","J m-2",tstr2D, tcstr, & - "sea ice heat content", & - "none", c1, c0, & - ns1, f_sihc) + call define_hist_field(n_siflsaltbot,"siflsaltbot","kg m-2 s-1",tstr2D, tcstr, & + "salt flux from sea ice", & + "total flux of salt between ocean and sea ice", c1, c0, & + ns1, f_siflsaltbot, avg_ice_present='final', mask_ice_free_points=.true.) - call define_hist_field(n_sisnhc,"sisnhc","J m-2",tstr2D, tcstr, & - "snow heat content", & - "none", c1, c0, & - ns1, f_sisnhc) - - call define_hist_field(n_sidconcth,"sidconcth","1/s",tstr2D, tcstr, & - "sea ice area change from thermodynamics", & - "none", c1, c0, & - ns1, f_sidconcth) - - call define_hist_field(n_sidconcdyn,"sidconcdyn","1/s",tstr2D, tcstr, & - "sea ice area change from dynamics", & - "none", c1, c0, & - ns1, f_sidconcdyn) - - call define_hist_field(n_sidmassth,"sidmassth","kg m-2 s-1",tstr2D, tcstr, & - "sea ice mass change from thermodynamics", & - "none", c1, c0, & - ns1, f_sidmassth) - - call define_hist_field(n_sidmassdyn,"sidmassdyn","kg m-2 s-1",tstr2D, tcstr, & - "sea ice mass change from dynamics", & - "none", c1, c0, & - ns1, f_sidmassdyn) - - call define_hist_field(n_sidmassgrowthwat,"sidmassgrowthwat","kg m-2 s-1",tstr2D, tcstr, & - "sea ice mass change from frazil", & - "none", c1, c0, & - ns1, f_sidmassgrowthwat) - - call define_hist_field(n_sidmassgrowthbot,"sidmassgrowthbot","kg m-2 s-1",tstr2D, tcstr, & - "sea ice mass change from basal growth", & - "none", c1, c0, & - ns1, f_sidmassgrowthbot) - - call define_hist_field(n_sidmasssi,"sidmasssi","kg m-2 s-1",tstr2D, tcstr, & - "sea ice mass change from snow-ice formation", & - "none", c1, c0, & - ns1, f_sidmasssi) - - call define_hist_field(n_sidmassevapsubl,"sidmassevapsubl","kg m-2 s-1",tstr2D, tcstr, & - "sea ice mass change from evaporation and sublimation", & - "none", c1, c0, & - ns1, f_sidmassevapsubl) - - call define_hist_field(n_sndmasssubl,"sndmasssubl","kg m-2 s-1",tstr2D, tcstr, & - "snow mass change from evaporation and sublimation", & - "none", c1, c0, & - ns1, f_sndmasssubl) - - call define_hist_field(n_sidmassmelttop,"sidmassmelttop","kg m-2 s-1",tstr2D, tcstr, & - "sea ice mass change top melt", & - "none", c1, c0, & - ns1, f_sidmassmelttop) - - call define_hist_field(n_sidmassmeltbot,"sidmassmeltbot","kg m-2 s-1",tstr2D, tcstr, & - "sea ice mass change bottom melt", & - "none", c1, c0, & - ns1, f_sidmassmeltbot) - - call define_hist_field(n_sidmasslat,"sidmasslat","kg m-2 s-1",tstr2D, tcstr, & - "sea ice mass change lateral melt", & - "none", c1, c0, & - ns1, f_sidmasslat) - - call define_hist_field(n_sndmasssnf,"sndmasssnf","kg m-2 s-1",tstr2D, tcstr, & - "snow mass change from snow fall", & - "none", c1, c0, & - ns1, f_sndmasssnf) - - call define_hist_field(n_sndmassmelt,"sndmassmelt","kg m-2 s-1",tstr2D, tcstr, & - "snow mass change from snow melt", & - "none", c1, c0, & - ns1, f_sndmassmelt) - - call define_hist_field(n_sndmassdyn,"sndmassdyn","kg m-2 s-1",tstr2D, tcstr, & - "snow mass change from dynamics ridging", & - "none", c1, c0, & - ns1, f_sndmassdyn) - - call define_hist_field(n_siflswdtop,"siflswdtop","W/m2",tstr2D, tcstr, & - "down shortwave flux over sea ice", & - "positive downward", c1, c0, & - ns1, f_siflswdtop, avg_ice_present=.true., mask_ice_free_points=.true.) + call define_hist_field(n_siflsensbot,"siflsensbot","W/m2",tstr2D, tcstr, & + "net upward sensible heat flux under sea ice", & + "net sensible heat flux under sea ice from or to the ocean", c1, c0, & + ns1, f_siflsensbot, avg_ice_present='init', mask_ice_free_points=.true.) - call define_hist_field(n_siflswutop,"siflswutop","W/m2",tstr2D, tcstr, & - "upward shortwave flux over sea ice", & - "positive downward", c1, c0, & - ns1, f_siflswutop, avg_ice_present=.true., mask_ice_free_points=.true.) + call define_hist_field(n_siflsenstop,"siflsenstop","W/m2",tstr2D, tcstr, & + "net downward sensible heat flux over sea ice", & + "positive downward", c1, c0, & + ns1, f_siflsenstop, avg_ice_present='init', mask_ice_free_points=.true.) call define_hist_field(n_siflswdbot,"siflswdbot","W/m2",tstr2D, tcstr, & - "down shortwave flux at bottom of ice", & - "positive downward", c1, c0, & - ns1, f_siflswdbot, avg_ice_present=.true., mask_ice_free_points=.true.) - - call define_hist_field(n_sifllwdtop,"sifllwdtop","W/m2",tstr2D, tcstr, & - "down longwave flux over sea ice", & - "positive downward", c1, c0, & - ns1, f_sifllwdtop, avg_ice_present=.true., mask_ice_free_points=.true.) - - call define_hist_field(n_sifllwutop,"sifllwutop","W/m2",tstr2D, tcstr, & - "upward longwave flux over sea ice", & - "positive downward", c1, c0, & - ns1, f_sifllwutop, avg_ice_present=.true., mask_ice_free_points=.true.) - - call define_hist_field(n_siflsenstop,"siflsenstop","W/m2",tstr2D, tcstr, & - "sensible heat flux over sea ice", & - "positive downward", c1, c0, & - ns1, f_siflsenstop, avg_ice_present=.true., mask_ice_free_points=.true.) + "downwelling shortwave flux underneath sea ice", & + "amount of shortwave radiation that penetrates the sea ice", & + c1, c0, & + ns1, f_siflswdbot, avg_ice_present='init', mask_ice_free_points=.true.) + + call define_hist_field(n_siflswdtop,"siflswdtop","W/m2",tstr2D, tcstr, & + "downwelling shortwave flux over sea ice", & + "downwelling shortwave flux from the atmosphere to the sea-ice surface", & + c1, c0, & + ns1, f_siflswdtop, avg_ice_present='init', mask_ice_free_points=.true.) + + call define_hist_field(n_siflswutop,"siflswutop","W/m2",tstr2D, tcstr, & + "upwelling shortwave flux over sea ice", & + "upward shortwave flux from the sea-ice surface to the atmosphere", & + c1, c0, & + ns1, f_siflswutop, avg_ice_present='init', mask_ice_free_points=.true.) - call define_hist_field(n_siflsensupbot,"siflsensupbot","W/m2",tstr2D, tcstr, & - "sensible heat flux at bottom of sea ice", & - "positive downward", c1, c0, & - ns1, f_siflsensupbot, avg_ice_present=.true., mask_ice_free_points=.true.) + call define_hist_field(n_siforcecoriolx,"siforcecoriolx","N m-2",tstr2D, tcstr, & + "coriolis force term in force balance (x-component)", & + "x-component of the force on sea ice caused by the Coriolis force", & + c1, c0, & + ns1, f_siforcecoriolx, avg_ice_present='final', mask_ice_free_points=.true.) - call define_hist_field(n_sifllatstop,"sifllatstop","W/m2",tstr2D, tcstr, & - "latent heat flux over sea ice", & - "positive downward", c1, c0, & - ns1, f_sifllatstop, avg_ice_present=.true., mask_ice_free_points=.true.) + call define_hist_field(n_siforcecorioly,"siforcecorioly","N m-2",tstr2D, tcstr, & + "coriolis force term in force balance (y-component)", & + "y-component of the force on sea ice caused by the Coriolis force", & + c1, c0, & + ns1, f_siforcecorioly, avg_ice_present='final', mask_ice_free_points=.true.) + + call define_hist_field(n_siforceintstrx,"siforceintstrx","N m-2",tstr2D, tcstr, & + "internal stress force term in force balance (x-component)", & + "x-component of the force on sea ice caused by internal stress (divergence of sigma)", & + c1, c0, & + ns1, f_siforceintstrx, avg_ice_present='final', mask_ice_free_points=.true.) + + call define_hist_field(n_siforceintstry,"siforceintstry","N m-2",tstr2D, tcstr, & + "internal stress force term in force balance (y-component)", & + "y-component of the force on sea ice caused by internal stress (divergence of sigma)", & + c1, c0, & + ns1, f_siforceintstry, avg_ice_present='final', mask_ice_free_points=.true.) - call define_hist_field(n_siflcondtop,"siflcondtop","W/m2",tstr2D, tcstr, & - "conductive heat flux at top of sea ice", & - "positive downward", c1, c0, & - ns1, f_siflcondtop, avg_ice_present=.true., mask_ice_free_points=.true.) + call define_hist_field(n_siforcetiltx,"siforcetiltx","N m-2",tstr2D, tcstr, & + "sea-surface tilt term in force balance (x-component)", & + "x-component of the force on sea ice caused by sea-surface tilt", & + c1, c0, & + ns1, f_siforcetiltx, avg_ice_present='init', mask_ice_free_points=.true.) - call define_hist_field(n_siflcondbot,"siflcondbot","W/m2",tstr2D, tcstr, & - "conductive heat flux at bottom of sea ice", & - "positive downward", c1, c0, & - ns1, f_siflcondbot, avg_ice_present=.true., mask_ice_free_points=.true.) + call define_hist_field(n_siforcetilty,"siforcetilty","N m-2",tstr2D, tcstr, & + "sea surface tilt term in force balance (y-component)", & + "y-component of the force on sea ice caused by sea-surface tilt", & + c1, c0, & + ns1, f_siforcetilty, avg_ice_present='init', mask_ice_free_points=.true.) call define_hist_field(n_sipr,"sipr","kg m-2 s-1",tstr2D, tcstr, & - "rainfall over sea ice", & - "none", c1, c0, & - ns1, f_sipr, avg_ice_present=.true., mask_ice_free_points=.true.) - - call define_hist_field(n_sifb,"sifb","m",tstr2D, tcstr, & - "sea ice freeboard above sea level", & - "none", c1, c0, & - ns1, f_sifb, avg_ice_present=.true., mask_ice_free_points=.true.) - - call define_hist_field(n_siflsaltbot,"siflsaltbot","kg m-2 s-1",tstr2D, tcstr, & - "salt flux from sea ice", & - "positive downward", c1, c0, & - ns1, f_siflsaltbot, avg_ice_present=.true., mask_ice_free_points=.true.) - - call define_hist_field(n_siflfwbot,"siflfwbot","kg m-2 s-1",tstr2D, tcstr, & - "fresh water flux from sea ice", & - "positive downward", c1, c0, & - ns1, f_siflfwbot, avg_ice_present=.true., mask_ice_free_points=.true.) - - call define_hist_field(n_siflfwdrain,"siflfwdrain","kg m-2 s-1",tstr2D, tcstr, & - "fresh water drainage through sea ice", & - "positive downward", c1, c0, & - ns1, f_siflfwdrain, avg_ice_present=.true., mask_ice_free_points=.true.) - - call define_hist_field(n_sidragtop,"sidragtop","1",tstr2D, tcstr, & - "atmospheric drag over sea ice", & - "none", c1, c0, & - ns1, f_sidragtop, avg_ice_present=.true., mask_ice_free_points=.true.) + "rainfall rate over sea ice", & + "mass of liquid precipitation falling onto sea ice", c1, c0, & + ns1, f_sipr, avg_ice_present='init', mask_ice_free_points=.true.) - call define_hist_field(n_sirdgthick,"sirdgthick","m",tstr2D, tcstr, & - "sea ice ridge thickness", & - "vrdg divided by ardg", c1, c0, & - ns1, f_sirdgthick, avg_ice_present=.true., mask_ice_free_points=.true.) - - call define_hist_field(n_siforcetiltx,"siforcetiltx","N m-2",tstr2D, tcstr, & - "sea surface tilt term", & - "none", c1, c0, & - ns1, f_siforcetiltx, avg_ice_present=.true., mask_ice_free_points=.true.) + call define_hist_field(n_sisali,"sisali","ppt",tstr2D, tcstr, & + "sea-ice salinity", & + "mean sea-ice salinity of all sea ice in grid cell", & + c1, c0, & + ns1, f_sisali, avg_ice_present='final', mask_ice_free_points=.true.) - call define_hist_field(n_siforcetilty,"siforcetilty","N m-2",tstr2D, tcstr, & - "sea surface tile term", & - "none", c1, c0, & - ns1, f_siforcetilty, avg_ice_present=.true., mask_ice_free_points=.true.) + call define_hist_field(n_sispeed,"sispeed","m/s",ustr2D, ucstr, & + "sea-ice speed", & + "speed of ice (i.e. mean absolute velocity)", c1, c0, & + ns1, f_sispeed, avg_ice_present='final', mask_ice_free_points=.true.) + +! sidir is not actually in the CMIP7 table +! call define_hist_field(n_sidir,"sidir","deg",ustr2D, ucstr, & +! "ice direction", & +! "vector direction - going to", c1, c0, & +! ns1, f_sidir) + + call define_hist_field(n_sisnthick,"sisnthick","m",tstr2D, tcstr, & + "snow thickness", & + "snow volume divided by sea-ice area", c1, c0, & + ns1, f_sisnthick, avg_ice_present='final', mask_ice_free_points=.true.) + + call define_hist_field(n_sistrxdtop,"sistrxdtop","N m-2",ustr2D, ucstr, & + "x-component of atmospheric stress on sea ice", & + "x-component of the atmospheric stress on the surface of sea ice", & + c1, c0, & + ns1, f_sistrxdtop, avg_ice_present='final', mask_ice_free_points=.true.) + + call define_hist_field(n_sistrydtop,"sistrydtop","N m-2",ustr2D, ucstr, & + "y-component of atmospheric stress on sea ice", & + "y-component of the atmospheric stress on the surface of sea ice", & + c1, c0, & + ns1, f_sistrydtop, avg_ice_present='final', mask_ice_free_points=.true.) + + call define_hist_field(n_sistrxubot,"sistrxubot","N m-2",ustr2D, ucstr, & + "x-component of ocean stress on sea ice", & + "x-component of the ocean stress on the sea ice bottom ", c1, c0, & + ns1, f_sistrxubot, avg_ice_present='final', mask_ice_free_points=.true.) + + call define_hist_field(n_sistryubot,"sistryubot","N m-2",ustr2D, ucstr, & + "y-component of ocean stress on sea ice", & + "y-component of the ocean stress on the sea ice bottom ", c1, c0, & + ns1, f_sistryubot, avg_ice_present='final', mask_ice_free_points=.true.) + + call define_hist_field(n_sitempbot,"sitempbot","K",tstr2D, tcstr, & + "temperature at ice-ocean interface", & + "mean temperature at the base of the sea ice", c1, Tffresh, & + ns1, f_sitempbot, avg_ice_present='init', mask_ice_free_points=.true.) + + call define_hist_field(n_sitempsnic,"sitempsnic","K",tstr2D, tcstr, & + "temperature at snow-ice interface", & + "surface temperature when no snow present", c1, Tffresh, & + ns1, f_sitempsnic, avg_ice_present='init', mask_ice_free_points=.true.) + + call define_hist_field(n_sitemptop,"sitemptop","K",tstr2D, tcstr, & + "surface temperature of sea ice", & + "mean surface temperature of the sea-ice covered part of the grid cell", & + c1, Tffresh, & + ns1, f_sitemptop, avg_ice_present='final', mask_ice_free_points=.true.) - call define_hist_field(n_siforcecoriolx,"siforcecoriolx","N m-2",tstr2D, tcstr, & - "coriolis term", & - "none", c1, c0, & - ns1, f_siforcecoriolx, avg_ice_present=.true., mask_ice_free_points=.true.) + call define_hist_field(n_sithick,"sithick","m",tstr2D, tcstr, & + "sea-ice thickness", & + "volume divided by sea-ice area", c1, c0, & + ns1, f_sithick, avg_ice_present='final', mask_ice_free_points=.true.) + + call define_hist_field(n_siu,"siu","m/s",ustr2D, ucstr, & + "x-component of sea-ice velocity", & + "on native model grid", c1, c0, & + ns1, f_siu, avg_ice_present='final', mask_ice_free_points=.true.) + + call define_hist_field(n_siv,"siv","m/s",ustr2D, ucstr, & + "y-component of sea-ice velocity", & + "on native model grid", c1, c0, & + ns1, f_siv, avg_ice_present='final', mask_ice_free_points=.true.) + + ! CMIP 2D extensive variables + + call define_hist_field(n_siconc,"siconc","%",tstr2D, tcstr, & + "sea-ice area percentage (ocean grid)", & + "percentage of a given grid cell that is covered by sea ice on the ocean grid", & + c100, c0, & + ns1, f_siconc, avg_ice_present='none', mask_ice_free_points=.false.) + + call define_hist_field(n_sidconcdyn,"sidconcdyn","1/s",tstr2D, tcstr, & + "sea-ice area fraction tendency due to dynamics", & + "total rate of change in sea-ice area fraction through dynamics-related processes", & + c1, c0, & + ns1, f_sidconcdyn, avg_ice_present='none', mask_ice_free_points=.false.) + + call define_hist_field(n_sidconcth,"sidconcth","1/s",tstr2D, tcstr, & + "sea-ice area fraction tendency due to thermodynamics", & + "total rate of change in sea-ice area fraction through thermodynamic processes", & + c1, c0, & + ns1, f_sidconcth, avg_ice_present='none', mask_ice_free_points=.false.) + + call define_hist_field(n_sidmassdyn,"sidmassdyn","kg m-2 s-1",tstr2D, tcstr, & + "sea-ice mass change from dynamics", & + "total rate of change in sea-ice mass through dynamics-related processes", & + c1, c0, & + ns1, f_sidmassdyn, avg_ice_present='none', mask_ice_free_points=.false.) + + call define_hist_field(n_sidmassevapsubl,"sidmassevapsubl","kg m-2 s-1",tstr2D, tcstr, & + "sea-ice mass change through evaporation and sublimation", & + "rate of change of sea-ice mass through evaporation and sublimation", & + c1, c0, & + ns1, f_sidmassevapsubl, avg_ice_present='none', mask_ice_free_points=.false.) + + call define_hist_field(n_sidmassgrowthbot,"sidmassgrowthbot","kg m-2 s-1",tstr2D, tcstr, & + "sea-ice mass change through basal growth", & + "rate of change of sea-ice mass due to vertical growth of existing sea ice at its base", & + c1, c0, & + ns1, f_sidmassgrowthbot, avg_ice_present='none', mask_ice_free_points=.false.) + + call define_hist_field(n_sidmassgrowthsi,"sidmassgrowthsi","kg m-2 s-1",tstr2D, tcstr, & + "sea-ice mass change from snow-to-ice conversion", & + "rate of change of sea-ice mass due to transformation of snow to sea ice", & + c1, c0, & + ns1, f_sidmassgrowthsi, avg_ice_present='none', mask_ice_free_points=.false.) + + call define_hist_field(n_sidmassgrowthwat,"sidmassgrowthwat","kg m-2 s-1",tstr2D, tcstr, & + "sea-ice mass change through growth in supercooled open water (frazil)", & + "always positive or zero", c1, c0, & + ns1, f_sidmassgrowthwat, avg_ice_present='none', mask_ice_free_points=.false.) + + call define_hist_field(n_sidmassmeltbot,"sidmassmeltbot","kg m-2 s-1",tstr2D, tcstr, & + "sea-ice mass change through bottom melting", & + "rate of change of sea-ice mass through melting/dissolution at the ice bottom", & + c1, c0, & + ns1, f_sidmassmeltbot, avg_ice_present='none', mask_ice_free_points=.false.) + + call define_hist_field(n_sidmassmeltlat,"sidmassmeltlat","kg m-2 s-1",tstr2D, tcstr, & + "sea-ice mass change through lateral melting", & + "rate of change of sea-ice mass through lateral melting/dissolution", c1, c0, & + ns1, f_sidmassmeltlat, avg_ice_present='none', mask_ice_free_points=.false.) + + call define_hist_field(n_sidmassmelttop,"sidmassmelttop","kg m-2 s-1",tstr2D, tcstr, & + "sea-ice mass change through surface melting", & + "rate of change of sea-ice mass through melting at the ice surface", c1, c0, & + ns1, f_sidmassmelttop, avg_ice_present='none', mask_ice_free_points=.false.) + + call define_hist_field(n_sidmassth,"sidmassth","kg m-2 s-1",tstr2D, tcstr, & + "sea-ice mass change from thermodynamics", & + "total rate of change in sea-ice mass from thermodynamic processes", & + c1, c0, & + ns1, f_sidmassth, avg_ice_present='none', mask_ice_free_points=.false.) + + call define_hist_field(n_sidmasstranx,"sidmasstranx","kg/s",ustr2D, ucstr, & + "x-component of sea-ice mass transport", & + "x-component of the sea-ice drift-induced transport of snow and sea ice mass", & + c1, c0, & + ns1, f_sidmasstranx, avg_ice_present='none', mask_ice_free_points=.false.) + + call define_hist_field(n_sidmasstrany,"sidmasstrany","kg/s",ustr2D, ucstr, & + "y-component of sea-ice mass transport", & + "y-component of the sea-ice drift-induced transport of snow and sea ice mass", & + c1, c0, & + ns1, f_sidmasstrany, avg_ice_present='none', mask_ice_free_points=.false.) + + call define_hist_field(n_sihc,"sihc","J m-2",tstr2D, tcstr, & + "sea-ice heat content", & + "heat content of all ice in grid cell", c1, c0, & + ns1, f_sihc, avg_ice_present='none', mask_ice_free_points=.false.) + + call define_hist_field(n_simass,"simass","kg m-2",tstr2D, tcstr, & + "sea-ice mass per area", & + "total mass of sea ice", c1, c0, & + ns1, f_simass, avg_ice_present='none', mask_ice_free_points=.false.) + + call define_hist_field(n_sisaltmass,"sisaltmass","kg m-2",tstr2D, tcstr, & + "mass of salt in sea-ice per area", & + "total mass of all salt in sea ice", c1, c0, & + ns1, f_sisaltmass, avg_ice_present='none', mask_ice_free_points=.false.) + + call define_hist_field(n_sisnconc,"sisnconc","%",tstr2D, tcstr, & + "snow area percentage", & + "percentage of the sea-ice surface that is covered by snow", & + c100, c0, & + ns1, f_sisnconc, avg_ice_present='none', mask_ice_free_points=.false.) + + call define_hist_field(n_sisndmassdyn,"sisndmassdyn","kg m-2 s-1",tstr2D, tcstr, & + "snow mass rate of change through advection by sea-ice dynamics", & + "rate of change of snow mass due to sea ice dynamics", c1, c0, & + ns1, f_sisndmassdyn, avg_ice_present='none', mask_ice_free_points=.false.) + + call define_hist_field(n_sisndmassmelt,"sisndmassmelt","kg m-2 s-1",tstr2D, tcstr, & + "snow mass rate of change through melt", & + "always negative or zero", c1, c0, & + ns1, f_sisndmassmelt, avg_ice_present='none', mask_ice_free_points=.false.) + + call define_hist_field(n_sisndmasssi,"sisndmasssi","kg m-2 s-1",tstr2D, tcstr, & + "snow mass rate of change through snow-to-ice conversion", & + "always negative or zero", c1, c0, & + ns1, f_sisndmasssi, avg_ice_present='none', mask_ice_free_points=.false.) + + call define_hist_field(n_sisndmasssnf,"sisndmasssnf","kg m-2 s-1",tstr2D, tcstr, & + "snow mass change through snowfall", & + "rate of change of snow mass due to solid precipitation falling onto sea ice", & + c1, c0, & + ns1, f_sisndmasssnf, avg_ice_present='none', mask_ice_free_points=.false.) + + call define_hist_field(n_sisndmasssubl,"sisndmasssubl","kg m-2 s-1",tstr2D, tcstr, & + "snow mass rate of change through evaporation or sublimation", & + "none", c1, c0, & + ns1, f_sisndmasssubl, avg_ice_present='none', mask_ice_free_points=.false.) - call define_hist_field(n_siforcecorioly,"siforcecorioly","N m-2",tstr2D, tcstr, & - "coriolis term", & - "none", c1, c0, & - ns1, f_siforcecorioly, avg_ice_present=.true., mask_ice_free_points=.true.) - - call define_hist_field(n_siforceintstrx,"siforceintstrx","N m-2",tstr2D, tcstr, & - "internal stress term", & - "none", c1, c0, & - ns1, f_siforceintstrx, avg_ice_present=.true., mask_ice_free_points=.true.) - - call define_hist_field(n_siforceintstry,"siforceintstry","N m-2",tstr2D, tcstr, & - "internal stress term", & - "none", c1, c0, & - ns1, f_siforceintstry, avg_ice_present=.true., mask_ice_free_points=.true.) - - call define_hist_field(n_sistreave,"sistreave","N m-1",ustr2D, ucstr, & - "average normal stress", & - "sistreave is instantaneous", c1, c0, & - ns1, f_sistreave) - - call define_hist_field(n_sistremax,"sistremax","N m-1",ustr2D, ucstr, & - "maximum shear stress", & - "sistremax is instantaneous", c1, c0, & - ns1, f_sistremax) + call define_hist_field(n_sisnhc,"sisnhc","J m-2",tstr2D, tcstr, & + "snow heat content", & + "heat content of all snow in grid cell", c1, c0, & + ns1, f_sisnhc, avg_ice_present='none', mask_ice_free_points=.false.) + + call define_hist_field(n_sisnmass,"sisnmass","kg m-2",tstr2D, tcstr, & + "snow mass per area", & + "total mass of snow on sea ice", c1, c0, & + ns1, f_sisnmass, avg_ice_present='none', mask_ice_free_points=.false.) + + call define_hist_field(n_sitimefrac,"sitimefrac","1",tstr2D, tcstr, & + "fraction of time steps with sea ice", & + "averaging period during which sea ice is present (siconc > 0) in a grid cell", & + c1, c0, & + ns1, f_icepresent, avg_ice_present='none', mask_ice_free_points=.false.) + + call define_hist_field(n_sivol,"sivol","m",tstr2D, tcstr, & + "sea-ice volume per area", & + "total volume of sea ice divided by grid-cell area (equivalent thickness)", & + c1, c0, & + ns1, f_sivol, avg_ice_present='none', mask_ice_free_points=.false.) + + ! CMIP 2D instantaneous fields + + call define_hist_field(n_sidivvel,"sidivvel","s-1",ustr2D, ucstr, & + "divergence of the sea-ice velocity field", & + "sidivvel is instantaneous", c1, c0, & + ns1, f_sidivvel, avg_ice_present='none', mask_ice_free_points=.false.) + + call define_hist_field(n_sishearvel,"sishearvel","s-1",ustr2D, ucstr, & + "maximum shear of the sea-ice velocity field", & + "sishearvel is instantaneous", c1, c0, & + ns1, f_sishearvel, avg_ice_present='none', mask_ice_free_points=.false.) + + call define_hist_field(n_sistressave,"sistressave","N m-1",ustr2D, ucstr, & + "average normal stress in sea ice", & + "sistressave is instantaneous", c1, c0, & + ns1, f_sistressave, avg_ice_present='none', mask_ice_free_points=.false.) + + call define_hist_field(n_sistressmax,"sistressmax","N m-1",ustr2D, ucstr, & + "maximum shear stress in sea ice", & + "sistressmax is instantaneous", c1, c0, & + ns1, f_sistressmax, avg_ice_present='none', mask_ice_free_points=.false.) endif ! if (histfreq(ns1) /= 'x') then enddo ! ns1 @@ -1890,17 +1925,29 @@ subroutine init_hist (dt) ns1, f_keffn_top) ! CMIP 3D - call define_hist_field(n_siitdconc,"siitdconc","1",tstr3Dc, tcstr, & - "ice area, categories","none", c1, c0, & - ns1, f_siitdconc) - - call define_hist_field(n_siitdthick,"siitdthick","m",tstr3Dc, tcstr, & - "ice thickness, categories","none", c1, c0, & - ns1, f_siitdthick, avg_ice_present=.true.) + call define_hist_field(n_siitdconc,"siitdconc","%",tstr3Dc, tcstr, & + "sea-ice area percentages in ice thickness categories", & + "percentage of grid cell covered by each ice thickness category", & + c100, c0, & + ns1, f_siitdconc, avg_ice_present='none', mask_ice_free_points=.false.) + + call define_hist_field(n_siitdsnconc,"siitdsnconc","%",tstr3Dc, tcstr, & + "snow area percentages in ice thickness categories", & + "percentage of grid cell covered by snow in each ice thickness category", & + c100, c0, & + ns1, f_siitdsnconc, avg_ice_present='none', mask_ice_free_points=.false.) call define_hist_field(n_siitdsnthick,"siitdsnthick","m",tstr3Dc, tcstr, & - "snow thickness, categories","none", c1, c0, & - ns1, f_siitdsnthick, avg_ice_present=.true.) + "snow thickness in ice thickness categories", & + "actual thickness of snow in each ice thickness category", & + c1, c0, & + ns1, f_siitdsnthick, avg_ice_present='final', mask_ice_free_points=.false.) + + call define_hist_field(n_siitdthick,"siitdthick","m",tstr3Dc, tcstr, & + "sea-ice thickness in ice thickness categories", & + "actual (floe) thickness of sea ice in each thickness category", & + c1, c0, & + ns1, f_siitdthick, avg_ice_present='final', mask_ice_free_points=.false.) endif ! if (histfreq(ns1) /= 'x') then enddo ! ns1 @@ -2164,7 +2211,7 @@ subroutine accum_hist (dt) yieldstress11, yieldstress12, yieldstress22 use ice_dyn_shared, only: kdyn, principal_stress use ice_flux, only: fsw, flw, fsnow, frain, sst, sss, uocn, vocn, & - frzmlt_init, scale_factor, fswabs, fswthru, alvdr, alvdf, alidr, alidf, & + frzmlt_init, scale_factor, fswabs, fswup, fswthru, alvdr, alvdf, alidr, alidf, & albice, albsno, albpnd, coszen, flat, fsens, flwout, evap, evaps, evapi, & Tair, Tref, Qref, congel, frazil, frazil_diag, snoice, dsnow, & melts, meltb, meltt, meltl, fresh, fsalt, fresh_ai, fsalt_ai, & @@ -2183,17 +2230,17 @@ subroutine accum_hist (dt) mlt_onset, frz_onset, dagedtt, dagedtd, fswint_ai, keffn_top, & snowfrac, alvdr_ai, alvdf_ai, alidr_ai, alidf_ai, update_ocn_f, & cpl_frazil - use ice_arrays_column, only: snowfracn, Cdn_atm + use ice_arrays_column, only: snowfracn, Cdn_atm, Cdn_ocn use ice_history_shared ! almost everything use ice_history_write, only: ice_write_hist use ice_history_bgc, only: accum_hist_bgc use ice_history_mechred, only: accum_hist_mechred + use ice_history_mechred, only: n_alvl, n_ardg, f_ardg use ice_history_pond, only: accum_hist_pond + use ice_history_pond, only: n_apond_ai, f_apond_ai use ice_history_snow, only: accum_hist_snow, & f_rhos_cmp, f_rhos_cnt, n_rhos_cmp, n_rhos_cnt use ice_history_drag, only: accum_hist_drag - use icepack_intfc, only: icepack_mushy_density_brine, icepack_mushy_liquid_fraction - use icepack_intfc, only: icepack_mushy_temperature_mush use ice_history_fsd, only: accum_hist_fsd use ice_state ! almost everything use ice_timers, only: ice_timer_start, ice_timer_stop, timer_readwrite @@ -2219,19 +2266,19 @@ subroutine accum_hist (dt) sn ! temporary variable for salinity real (kind=dbl_kind), dimension (nx_block,ny_block) :: & - worka, workb, ravgip + worka, workb, ravgip, ravgip_init, ravgip_pond, ravgip_ridge, rho_ice, rho_ocn, sal_ice real (kind=dbl_kind), dimension (nx_block,ny_block,ncat_hist) :: & - ravgipn, worka3 + ravgipn real (kind=dbl_kind) :: awtvdr, awtidr, awtvdf, awtidf, puny, secday, rad_to_deg real (kind=dbl_kind) :: Tffresh, rhoi, rhos, rhow, ice_ref_salinity - real (kind=dbl_kind) :: rho_ice, rho_ocn, Tice, Sbr, phi, rhob, dfresh, dfsalt, sicen + real (kind=dbl_kind) :: dfresh, dfsalt, sicen logical (kind=log_kind) :: formdrag, skl_bgc - logical (kind=log_kind) :: tr_pond, tr_aero, tr_brine, tr_snow + logical (kind=log_kind) :: tr_pond, tr_aero, tr_brine, tr_snow, tr_pond_topo integer (kind=int_kind) :: ktherm integer (kind=int_kind) :: nt_sice, nt_qice, nt_qsno, nt_iage, nt_FY, nt_Tsfc, & - nt_alvl, nt_vlvl + nt_alvl, nt_apnd character (len=char_len) :: saltflux_option type (block) :: & @@ -2245,11 +2292,11 @@ subroutine accum_hist (dt) rhow_out=rhow, ice_ref_salinity_out=ice_ref_salinity) call icepack_query_parameters(formdrag_out=formdrag, skl_bgc_out=skl_bgc, ktherm_out=ktherm) call icepack_query_parameters(saltflux_option_out=saltflux_option) - call icepack_query_tracer_flags(tr_pond_out=tr_pond, tr_aero_out=tr_aero, & - tr_brine_out=tr_brine, tr_snow_out=tr_snow) + call icepack_query_tracer_flags(tr_aero_out=tr_aero, tr_brine_out=tr_brine, tr_snow_out=tr_snow, & + tr_pond_out=tr_pond, tr_pond_topo_out=tr_pond_topo) call icepack_query_tracer_indices(nt_sice_out=nt_sice, nt_qice_out=nt_qice, & nt_qsno_out=nt_qsno, nt_iage_out=nt_iage, nt_FY_out=nt_FY, nt_Tsfc_out=nt_Tsfc, & - nt_alvl_out=nt_alvl, nt_vlvl_out=nt_vlvl) + nt_alvl_out=nt_alvl, nt_apnd_out=nt_apnd) call icepack_warnings_flush(nu_diag) if (icepack_warnings_aborted()) call abort_ice(error_message=subname, & file=__FILE__, line=__LINE__) @@ -2330,8 +2377,8 @@ subroutine accum_hist (dt) #ifndef __INTEL_LLVM_COMPILER !$OMP PARALLEL DO PRIVATE(iblk,i,j,ilo,ihi,jlo,jhi,this_block, & - !$OMP k,n,qn,ns,sn,rho_ocn,rho_ice,Tice,Sbr,phi,rhob,dfresh,dfsalt,sicen, & - !$OMP worka,workb,worka3,Tinz4d,Sinz4d,Tsnz4d) + !$OMP k,n,qn,ns,sn,rho_ocn,rho_ice,sal_ice,dfresh,dfsalt,sicen, & + !$OMP worka,workb,Tinz4d,Sinz4d,Tsnz4d) #endif do iblk = 1, nblocks @@ -2357,6 +2404,8 @@ subroutine accum_hist (dt) call accum_hist_field(n_Tsfc, iblk, trcr(:,:,nt_Tsfc,iblk), a2D) if (f_aice (1:1) /= 'x') & call accum_hist_field(n_aice, iblk, aice(:,:,iblk), a2D) + if (f_aice_init (1:1) /= 'x') & + call accum_hist_field(n_aice_init, iblk, aice_init(:,:,iblk), a2D) if (f_uvel (1:1) /= 'x') & call accum_hist_field(n_uvel, iblk, uvel(:,:,iblk), a2D) if (f_vvel (1:1) /= 'x') & @@ -2447,8 +2496,7 @@ subroutine accum_hist (dt) endif if (f_fswup(1:1) /= 'x') & - call accum_hist_field(n_fswup, iblk, & - (fsw(:,:,iblk)-fswabs(:,:,iblk)*workb(:,:)), a2D) + call accum_hist_field(n_fswup, iblk, fswup(:,:,iblk), a2D) if (f_fswdn (1:1) /= 'x') & call accum_hist_field(n_fswdn, iblk, fsw(:,:,iblk), a2D) if (f_flwdn (1:1) /= 'x') & @@ -2501,14 +2549,16 @@ subroutine accum_hist (dt) call accum_hist_field(n_fswint_ai, iblk, fswint_ai(:,:,iblk), a2D) if (f_fswabs_ai(1:1)/= 'x') & - call accum_hist_field(n_fswabs_ai, iblk, fswabs(:,:,iblk)*workb(:,:), a2D) + call accum_hist_field(n_fswabs_ai, iblk, fswabs(:,:,iblk)*aice(:,:,iblk), a2D) - if (f_albsni (1:1) /= 'x') & + if (f_albsni(1:1) /= 'x') then call accum_hist_field(n_albsni, iblk, & - (awtvdr*alvdr(:,:,iblk) & - + awtidr*alidr(:,:,iblk) & - + awtvdf*alvdf(:,:,iblk) & - + awtidf*alidf(:,:,iblk))*workb(:,:), a2D) + (awtvdr*alvdr_ai(:,:,iblk) & + + awtidr*alidr_ai(:,:,iblk) & + + awtvdf*alvdf_ai(:,:,iblk) & + + awtidf*alidf_ai(:,:,iblk)), a2D) + endif + if (f_alvdr (1:1) /= 'x') & call accum_hist_field(n_alvdr, iblk, alvdr(:,:,iblk), a2D) if (f_alidr (1:1) /= 'x') & @@ -2538,19 +2588,19 @@ subroutine accum_hist (dt) if (f_flat (1:1) /= 'x') & call accum_hist_field(n_flat, iblk, flat(:,:,iblk), a2D) if (f_flat_ai(1:1) /= 'x') & - call accum_hist_field(n_flat_ai,iblk, flat(:,:,iblk)*workb(:,:), a2D) + call accum_hist_field(n_flat_ai,iblk, flat(:,:,iblk)*aice(:,:,iblk), a2D) if (f_fsens (1:1) /= 'x') & call accum_hist_field(n_fsens, iblk, fsens(:,:,iblk), a2D) if (f_fsens_ai(1:1)/= 'x') & - call accum_hist_field(n_fsens_ai,iblk, fsens(:,:,iblk)*workb(:,:), a2D) + call accum_hist_field(n_fsens_ai,iblk, fsens(:,:,iblk)*aice(:,:,iblk), a2D) if (f_flwup (1:1) /= 'x') & call accum_hist_field(n_flwup, iblk, flwout(:,:,iblk), a2D) if (f_flwup_ai(1:1)/= 'x') & - call accum_hist_field(n_flwup_ai,iblk, flwout(:,:,iblk)*workb(:,:), a2D) + call accum_hist_field(n_flwup_ai,iblk, flwout(:,:,iblk)*aice(:,:,iblk), a2D) if (f_evap (1:1) /= 'x') & call accum_hist_field(n_evap, iblk, evap(:,:,iblk), a2D) if (f_evap_ai(1:1) /= 'x') & - call accum_hist_field(n_evap_ai,iblk, evap(:,:,iblk)*workb(:,:), a2D) + call accum_hist_field(n_evap_ai,iblk, evap(:,:,iblk)*aice(:,:,iblk), a2D) if (f_Tair (1:1) /= 'x') & call accum_hist_field(n_Tair, iblk, Tair(:,:,iblk), a2D) @@ -2701,10 +2751,10 @@ subroutine accum_hist (dt) call accum_hist_field(n_dagedtd, iblk, dagedtd(:,:,iblk), a2D) if (f_fsurf_ai(1:1)/= 'x') & - call accum_hist_field(n_fsurf_ai,iblk, fsurf(:,:,iblk)*workb(:,:), a2D) + call accum_hist_field(n_fsurf_ai,iblk, fsurf(:,:,iblk)*aice(:,:,iblk), a2D) if (f_fcondtop_ai(1:1)/= 'x') & call accum_hist_field(n_fcondtop_ai, iblk, & - fcondtop(:,:,iblk)*workb(:,:), a2D) + fcondtop(:,:,iblk)*aice(:,:,iblk), a2D) if (f_icepresent(1:1) /= 'x') then worka(:,:) = c0 @@ -2718,121 +2768,124 @@ subroutine accum_hist (dt) ! 2D CMIP fields - if (f_sithick(1:1) /= 'x') then + if (f_sitimefrac(1:1) /= 'x') then worka(:,:) = c0 do j = jlo, jhi do i = ilo, ihi - if (aice(i,j,iblk) > puny) worka(i,j) = vice(i,j,iblk) + if (aice(i,j,iblk) > puny) worka(i,j) = c1 enddo enddo - call accum_hist_field(n_sithick, iblk, worka(:,:), a2D) + call accum_hist_field(n_sitimefrac, iblk, worka(:,:), a2D) + endif + + if (f_sithick(1:1) /= 'x') then + call accum_hist_field(n_sithick, iblk, vice(:,:,iblk), a2D) + endif + + if (f_sivol(1:1) /= 'x') then + call accum_hist_field(n_sivol, iblk, vice(:,:,iblk), a2D) + endif + + rho_ice(:,:) = rhoi + rho_ocn(:,:) = rhow + sal_ice(:,:) = ice_ref_salinity + + if (ktherm == 2) then + do j = jlo, jhi + do i = ilo, ihi + call ice_brine_density(trcr(i,j,nt_qice:nt_qice+nzilyr-1,iblk),trcr(i,j,nt_sice:nt_sice+nzilyr-1,iblk), & + sss(i,j,iblk), rho_ice(i,j), rho_ocn(i,j), sal_ice(i,j)) + enddo + enddo + endif + + if (f_simass(1:1) /= 'x') then + call accum_hist_field(n_simass, iblk, rho_ice(:,:)*vice(:,:,iblk), a2D) + endif + + if (f_sisaltmass(1:1) /= 'x') then + call accum_hist_field(n_sisaltmass, iblk, rho_ice(:,:)*sal_ice(:,:)*vice(:,:,iblk), a2D) + endif + + if (f_sisali(1:1) /= 'x') then + call accum_hist_field(n_sisali, iblk, aice(:,:,iblk)*sal_ice(:,:), a2D) + endif + + if (f_siconc(1:1) /= 'x') then + call accum_hist_field(n_siconc, iblk, aice(:,:,iblk), a2D) + endif + + if (f_sisnconc(1:1) /= 'x') then + call accum_hist_field(n_sisnconc, iblk, snowfrac(:,:,iblk), a2D) + endif + + if (f_sisnmass(1:1) /= 'x') then + call accum_hist_field(n_sisnmass, iblk, rhos*vsno(:,:,iblk), a2D) endif if (f_siage(1:1) /= 'x') then - worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - if (aice(i,j,iblk) > puny) worka(i,j) = aice(i,j,iblk)*trcr(i,j,nt_iage,iblk) - enddo - enddo - call accum_hist_field(n_siage, iblk, worka(:,:), a2D) + call accum_hist_field(n_siage, iblk, aice(:,:,iblk)*trcr(:,:,nt_iage,iblk), a2D) endif if (f_sisnthick(1:1) /= 'x') then - worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - if (vsno(i,j,iblk) > puny) & - worka(i,j) = vsno(i,j,iblk) - enddo - enddo - call accum_hist_field(n_sisnthick, iblk, worka(:,:), a2D) + call accum_hist_field(n_sisnthick, iblk, vsno(:,:,iblk), a2D) endif if (f_sitemptop(1:1) /= 'x') then - worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - worka(i,j) = aice(i,j,iblk)*trcr(i,j,nt_Tsfc,iblk) - enddo - enddo - call accum_hist_field(n_sitemptop, iblk, worka(:,:), a2D) + call accum_hist_field(n_sitemptop, iblk, aice(:,:,iblk)*trcr(:,:,nt_Tsfc,iblk), a2D) endif ! Tsnice is already multiplied by aicen in icepack. if (f_sitempsnic(1:1) /= 'x') then - worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - worka(i,j) = Tsnice(i,j,iblk) - enddo - enddo - call accum_hist_field(n_sitempsnic, iblk, worka(:,:), a2D) + call accum_hist_field(n_sitempsnic, iblk, Tsnice(:,:,iblk), a2D) endif if (f_sitempbot(1:1) /= 'x') then - worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - worka(i,j) = aice(i,j,iblk)*Tbot(i,j,iblk) - enddo - enddo - call accum_hist_field(n_sitempbot, iblk, worka(:,:), a2D) + call accum_hist_field(n_sitempbot, iblk, aice_init(:,:,iblk)*Tbot(:,:,iblk), a2D) endif if (f_siu(1:1) /= 'x') then - worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - if (aice(i,j,iblk) > puny) worka(i,j) = aice(i,j,iblk)*uvel(i,j,iblk) - enddo - enddo - call accum_hist_field(n_siu, iblk, worka(:,:), a2D) + call accum_hist_field(n_siu, iblk, aice(:,:,iblk)*uvel(:,:,iblk), a2D) endif if (f_siv(1:1) /= 'x') then - worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - if (aice(i,j,iblk) > puny) worka(i,j) = aice(i,j,iblk)*vvel(i,j,iblk) - enddo - enddo - call accum_hist_field(n_siv, iblk, worka(:,:), a2D) + call accum_hist_field(n_siv, iblk, aice(:,:,iblk)*vvel(:,:,iblk), a2D) endif if (f_sispeed(1:1) /= 'x') then worka(:,:) = c0 do j = jlo, jhi do i = ilo, ihi - if (aice(i,j,iblk) > puny) worka(i,j) = aice(i,j,iblk) & + worka(i,j) = aice(i,j,iblk) & * sqrt(uvel(i,j,iblk)*uvel(i,j,iblk)+vvel(i,j,iblk)*vvel(i,j,iblk)) enddo enddo call accum_hist_field(n_sispeed, iblk, worka(:,:), a2D) endif - if (f_sidir(1:1) /= 'x') then - worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - if (abs(uvel(i,j,iblk)) > puny .or. abs(vvel(i,j,iblk)) > puny) & - worka(i,j) = atan2(uvel(i,j,iblk),vvel(i,j,iblk))*rad_to_deg - if (worka(i,j) < 0.0 ) then - worka(i,j) = worka(i,j) + c360 - else - worka(i,j) = worka(i,j) * c1 - endif - enddo - enddo - call accum_hist_field(n_sidir, iblk, worka(:,:), a2D) - endif + +! if (f_sidir(1:1) /= 'x') then +! worka(:,:) = c0 +! do j = jlo, jhi +! do i = ilo, ihi +! if (abs(uvel(i,j,iblk)) > puny .or. abs(vvel(i,j,iblk)) > puny) & +! worka(i,j) = atan2(uvel(i,j,iblk),vvel(i,j,iblk))*rad_to_deg +! if (worka(i,j) < 0.0 ) then +! worka(i,j) = worka(i,j) + c360 +! else +! worka(i,j) = worka(i,j) * c1 +! endif +! enddo +! enddo +! call accum_hist_field(n_sidir, iblk, worka(:,:), a2D) +! endif + if (f_sidmasstranx(1:1) /= 'x') then worka(:,:) = c0 do j = jlo, jhi do i = ilo, ihi - if (aice(i,j,iblk) > puny) & - worka(i,j) = (rhoi*p5*(vice(i+1,j,iblk)+vice(i,j,iblk))*dyU(i,j,iblk) & - + rhos*p5*(vsno(i+1,j,iblk)+vsno(i,j,iblk))*dyU(i,j,iblk)) & - * p5*(uvel(i,j-1,iblk)+uvel(i,j,iblk)) + worka(i,j) = (rho_ice(i,j)*p5*(vice(i+1,j,iblk)+vice(i,j,iblk))*dyU(i,j,iblk) & + + rhos*p5*(vsno(i+1,j,iblk)+vsno(i,j,iblk))*dyU(i,j,iblk)) & + * p5*(uvel(i,j-1,iblk)+uvel(i,j,iblk)) enddo enddo call accum_hist_field(n_sidmasstranx, iblk, worka(:,:), a2D) @@ -2842,81 +2895,32 @@ subroutine accum_hist (dt) worka(:,:) = c0 do j = jlo, jhi do i = ilo, ihi - if (aice(i,j,iblk) > puny) & - worka(i,j) = (rhoi*p5*(vice(i,j+1,iblk)+vice(i,j,iblk))*dxU(i,j,iblk) & - + rhos*p5*(vsno(i,j+1,iblk)+vsno(i,j,iblk))*dxU(i,j,iblk)) & - * p5*(vvel(i-1,j,iblk)+vvel(i,j,iblk)) + worka(i,j) = (rho_ice(i,j)*p5*(vice(i,j+1,iblk)+vice(i,j,iblk))*dxU(i,j,iblk) & + + rhos*p5*(vsno(i,j+1,iblk)+vsno(i,j,iblk))*dxU(i,j,iblk)) & + * p5*(vvel(i-1,j,iblk)+vvel(i,j,iblk)) enddo enddo call accum_hist_field(n_sidmasstrany, iblk, worka(:,:), a2D) endif if (f_sistrxdtop(1:1) /= 'x') then - worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - if (aice_init(i,j,iblk) > puny) & - worka(i,j) = aice(i,j,iblk)*(aice(i,j,iblk)*strairxU(i,j,iblk)/aice_init(i,j,iblk)) - enddo - enddo - call accum_hist_field(n_sistrxdtop, iblk, worka(:,:), a2D) + call accum_hist_field(n_sistrxdtop, iblk, aice(:,:,iblk)*strairxU(:,:,iblk), a2D) endif if (f_sistrydtop(1:1) /= 'x') then - worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - if (aice_init(i,j,iblk) > puny) & - worka(i,j) = aice(i,j,iblk)*(aice(i,j,iblk)*strairyU(i,j,iblk)/aice_init(i,j,iblk)) - enddo - enddo - call accum_hist_field(n_sistrydtop, iblk, worka(:,:), a2D) + call accum_hist_field(n_sistrydtop, iblk, aice(:,:,iblk)*strairyU(:,:,iblk), a2D) endif if (f_sistrxubot(1:1) /= 'x') then - worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - if (aice(i,j,iblk) > puny) & - worka(i,j) = aice(i,j,iblk)*strocnxU(i,j,iblk) - enddo - enddo - call accum_hist_field(n_sistrxubot, iblk, worka(:,:), a2D) + call accum_hist_field(n_sistrxubot, iblk, aice(:,:,iblk)*strocnxU(:,:,iblk), a2D) endif if (f_sistryubot(1:1) /= 'x') then - worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - if (aice(i,j,iblk) > puny) & - worka(i,j) = aice(i,j,iblk)*strocnyU(i,j,iblk) - enddo - enddo - call accum_hist_field(n_sistryubot, iblk, worka(:,:), a2D) + call accum_hist_field(n_sistryubot, iblk, aice(:,:,iblk)*strocnyU(:,:,iblk), a2D) endif if (f_sicompstren(1:1) /= 'x') then - worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - if (aice(i,j,iblk) > puny) & - worka(i,j) = aice(i,j,iblk)*strength(i,j,iblk) - enddo - enddo - call accum_hist_field(n_sicompstren, iblk, worka(:,:), a2D) - endif - - if (f_sialb(1:1) /= 'x') then - worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - if (fsw(i,j,iblk) > puny .and. aice_init(i,j,iblk) > puny) then - worka(i,j) = aice(i,j,iblk)*(fsw(i,j,iblk)-fswabs(i,j,iblk) & - * aice(i,j,iblk)/aice_init(i,j,iblk)) / fsw(i,j,iblk) - endif - enddo - enddo - call accum_hist_field(n_sialb, iblk, worka(:,:), a2D) + call accum_hist_field(n_sicompstren, iblk, aice(:,:,iblk)*strength(:,:,iblk), a2D) endif if (f_sihc(1:1) /= 'x') then @@ -2944,342 +2948,127 @@ subroutine accum_hist (dt) endif if (f_sidconcth(1:1) /= 'x') then - worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - if (aice(i,j,iblk) > puny) then - worka(i,j) = daidtt(i,j,iblk) - endif - enddo - enddo - call accum_hist_field(n_sidconcth, iblk, worka(:,:), a2D) + call accum_hist_field(n_sidconcth, iblk, daidtt(:,:,iblk), a2D) endif if (f_sidconcdyn(1:1) /= 'x') then - worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - if (aice(i,j,iblk) > puny) then - worka(i,j) = daidtd(i,j,iblk) - endif - enddo - enddo - call accum_hist_field(n_sidconcdyn, iblk, worka(:,:), a2D) + call accum_hist_field(n_sidconcdyn, iblk, daidtd(:,:,iblk), a2D) endif if (f_sidmassth(1:1) /= 'x') then - worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - if (aice(i,j,iblk) > puny) then - worka(i,j) = dvidtt(i,j,iblk) * rhoi - endif - enddo - enddo - call accum_hist_field(n_sidmassth, iblk, worka(:,:), a2D) + call accum_hist_field(n_sidmassth, iblk, rho_ice(:,:)*dvidtt(:,:,iblk), a2D) endif if (f_sidmassdyn(1:1) /= 'x') then - worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - if (aice(i,j,iblk) > puny) then - worka(i,j) = dvidtd(i,j,iblk) * rhoi - endif - enddo - enddo - call accum_hist_field(n_sidmassdyn, iblk, worka(:,:), a2D) + call accum_hist_field(n_sidmassdyn, iblk, rho_ice(:,:)*dvidtd(:,:,iblk), a2D) endif if (f_sidmassgrowthwat(1:1) /= 'x') then - worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - if (aice_init(i,j,iblk) > puny) then - worka(i,j) = frazil(i,j,iblk)*rhoi/dt - endif - enddo - enddo - call accum_hist_field(n_sidmassgrowthwat, iblk, worka(:,:), a2D) + call accum_hist_field(n_sidmassgrowthwat, iblk, rho_ice(:,:)*frazil(:,:,iblk)/dt, a2D) endif if (f_sidmassgrowthbot(1:1) /= 'x') then - worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - if (aice(i,j,iblk) > puny) then - worka(i,j) = congel(i,j,iblk)*rhoi/dt - endif - enddo - enddo - call accum_hist_field(n_sidmassgrowthbot, iblk, worka(:,:), a2D) + call accum_hist_field(n_sidmassgrowthbot, iblk, rho_ice(:,:)*congel(:,:,iblk)/dt, a2D) endif - if (f_sidmasssi(1:1) /= 'x') then - worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - if (aice(i,j,iblk) > puny) then - worka(i,j) = snoice(i,j,iblk)*rhoi/dt - endif - enddo - enddo - call accum_hist_field(n_sidmasssi, iblk, worka(:,:), a2D) + if (f_sidmassgrowthsi(1:1) /= 'x') then + call accum_hist_field(n_sidmassgrowthsi, iblk, rho_ice(:,:)*snoice(:,:,iblk)/dt, a2D) + endif + + if (f_sisndmasssi(1:1) /= 'x') then + call accum_hist_field(n_sisndmasssi, iblk, -snoice(:,:,iblk)*rhos/dt, a2D) endif if (f_sidmassevapsubl(1:1) /= 'x') then - worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - if (aice(i,j,iblk) > puny) then - worka(i,j) = evapi(i,j,iblk)*rhoi - endif - enddo - enddo - call accum_hist_field(n_sidmassevapsubl, iblk, worka(:,:), a2D) + call accum_hist_field(n_sidmassevapsubl, iblk, rho_ice(:,:)*evapi(:,:,iblk), a2D) endif if (f_sidmassmelttop(1:1) /= 'x') then - worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - if (aice(i,j,iblk) > puny) then - worka(i,j) = meltt(i,j,iblk)*rhoi/dt - endif - enddo - enddo - call accum_hist_field(n_sidmassmelttop, iblk, worka(:,:), a2D) + call accum_hist_field(n_sidmassmelttop, iblk, -rho_ice(:,:)*meltt(:,:,iblk)/dt, a2D) endif if (f_sidmassmeltbot(1:1) /= 'x') then - worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - if (aice(i,j,iblk) > puny) then - worka(i,j) = meltb(i,j,iblk)*rhoi/dt - endif - enddo - enddo - call accum_hist_field(n_sidmassmeltbot, iblk, worka(:,:), a2D) + call accum_hist_field(n_sidmassmeltbot, iblk, -rho_ice(:,:)*meltb(:,:,iblk)/dt, a2D) endif - if (f_sidmasslat(1:1) /= 'x') then - worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - if (aice(i,j,iblk) > puny) then - worka(i,j) = meltl(i,j,iblk)*rhoi/dt - endif - enddo - enddo - call accum_hist_field(n_sidmasslat, iblk, worka(:,:), a2D) + if (f_sidmassmeltlat(1:1) /= 'x') then + call accum_hist_field(n_sidmassmeltlat, iblk, -rho_ice(:,:)*meltl(:,:,iblk)/dt, a2D) endif - if (f_sndmasssubl(1:1) /= 'x') then - worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - if (aice(i,j,iblk) > puny) then - worka(i,j) = evaps(i,j,iblk) - endif - enddo - enddo - call accum_hist_field(n_sndmasssubl, iblk, worka(:,:), a2D) + if (f_sisndmasssubl(1:1) /= 'x') then + call accum_hist_field(n_sisndmasssubl, iblk, evaps(:,:,iblk), a2D) endif - if (f_sndmasssnf(1:1) /= 'x') then - worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - if (aice(i,j,iblk) > puny) then - worka(i,j) = aice(i,j,iblk)*fsnow(i,j,iblk) - endif - enddo - enddo - call accum_hist_field(n_sndmasssnf, iblk, worka(:,:), a2D) + if (f_sisndmasssnf(1:1) /= 'x') then + call accum_hist_field(n_sisndmasssnf, iblk, fsnow(:,:,iblk), a2D) endif - if (f_sndmassmelt(1:1) /= 'x') then - worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - if (aice(i,j,iblk) > puny) then - worka(i,j) = melts(i,j,iblk)*rhos/dt - endif - enddo - enddo - call accum_hist_field(n_sndmassmelt, iblk, worka(:,:), a2D) + if (f_sisndmassmelt(1:1) /= 'x') then + call accum_hist_field(n_sisndmassmelt, iblk, -melts(:,:,iblk)*rhos/dt, a2D) endif - if (f_sndmassdyn(1:1) /= 'x') then - worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - if (aice(i,j,iblk) > puny) then - worka(i,j) = dvsdtd(i,j,iblk)*rhos - endif - enddo - enddo - call accum_hist_field(n_sndmassdyn, iblk, worka(:,:), a2D) + if (f_sisndmassdyn(1:1) /= 'x') then + call accum_hist_field(n_sisndmassdyn, iblk, dvsdtd(:,:,iblk)*rhos, a2D) endif if (f_siflswdtop(1:1) /= 'x') then - worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - if (fsw(i,j,iblk) > puny .and. aice(i,j,iblk) > puny) then - worka(i,j) = aice(i,j,iblk)*fsw(i,j,iblk) - endif - enddo - enddo - call accum_hist_field(n_siflswdtop, iblk, worka(:,:), a2D) + call accum_hist_field(n_siflswdtop, iblk, aice_init(:,:,iblk)*fsw(:,:,iblk), a2D) endif if (f_siflswutop(1:1) /= 'x') then - worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - if (fsw(i,j,iblk) > puny .and. aice_init(i,j,iblk) > puny) then - worka(i,j) = aice(i,j,iblk)*(fsw(i,j,iblk)-fswabs(i,j,iblk) & - * aice(i,j,iblk)/aice_init(i,j,iblk)) - endif - enddo - enddo - call accum_hist_field(n_siflswutop, iblk, worka(:,:), a2D) + call accum_hist_field(n_siflswutop, iblk, fswup(:,:,iblk), a2D) endif if (f_siflswdbot(1:1) /= 'x') then - worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - if (aice(i,j,iblk) > puny) then - worka(i,j) = aice(i,j,iblk)*fswthru(i,j,iblk) - endif - enddo - enddo - call accum_hist_field(n_siflswdbot, iblk, worka(:,:), a2D) + call accum_hist_field(n_siflswdbot, iblk, aice_init(:,:,iblk)*fswthru(:,:,iblk), a2D) endif if (f_sifllwdtop(1:1) /= 'x') then - worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - if (aice(i,j,iblk) > puny) then - worka(i,j) = aice(i,j,iblk)*flw(i,j,iblk) - endif - enddo - enddo - call accum_hist_field(n_sifllwdtop, iblk, worka(:,:), a2D) + call accum_hist_field(n_sifllwdtop, iblk, aice_init(:,:,iblk)*flw(:,:,iblk), a2D) endif if (f_sifllwutop(1:1) /= 'x') then - worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - if (aice(i,j,iblk) > puny) then - worka(i,j) = aice(i,j,iblk)*flwout(i,j,iblk) - endif - enddo - enddo - call accum_hist_field(n_sifllwutop, iblk, worka(:,:), a2D) + call accum_hist_field(n_sifllwutop, iblk, aice(:,:,iblk)*flwout(:,:,iblk), a2D) endif if (f_siflsenstop(1:1) /= 'x') then worka(:,:) = c0 do j = jlo, jhi do i = ilo, ihi - if (aice(i,j,iblk) > puny) then - worka(i,j) = aice(i,j,iblk)*fsens(i,j,iblk) - endif + worka(i,j) = aice(i,j,iblk)*fsens(i,j,iblk) enddo enddo - call accum_hist_field(n_siflsenstop, iblk, worka(:,:), a2D) + call accum_hist_field(n_siflsenstop, iblk, aice(:,:,iblk)*fsens(:,:,iblk), a2D) endif - if (f_siflsensupbot(1:1) /= 'x') then - worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - if (aice(i,j,iblk) > puny) then - worka(i,j) = aice(i,j,iblk)*fhocn(i,j,iblk) - endif - enddo - enddo - call accum_hist_field(n_siflsensupbot, iblk, worka(:,:), a2D) + if (f_siflsensbot(1:1) /= 'x') then + call accum_hist_field(n_siflsensbot, iblk, aice(:,:,iblk)*fhocn(:,:,iblk), a2D) endif - if (f_sifllatstop(1:1) /= 'x') then - worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - if (aice(i,j,iblk) > puny) then - worka(i,j) = aice(i,j,iblk)*flat(i,j,iblk) - endif - enddo - enddo - call accum_hist_field(n_sifllatstop, iblk, worka(:,:), a2D) + if (f_sifllattop(1:1) /= 'x') then + call accum_hist_field(n_sifllattop, iblk, aice(:,:,iblk)*flat(:,:,iblk), a2D) endif if (f_siflcondtop(1:1) /= 'x') then - worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - if (aice(i,j,iblk) > puny) then - worka(i,j) = aice(i,j,iblk)*fcondtop(i,j,iblk) - endif - enddo - enddo - call accum_hist_field(n_siflcondtop, iblk, worka(:,:), a2D) + call accum_hist_field(n_siflcondtop, iblk, aice(:,:,iblk)*fcondtop(:,:,iblk), a2D) endif if (f_siflcondbot(1:1) /= 'x') then - worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - if (aice_init(i,j,iblk) > puny) then - worka(i,j) = aice(i,j,iblk)*fcondbot(i,j,iblk)/aice_init(i,j,iblk) - endif - enddo - enddo - call accum_hist_field(n_siflcondbot, iblk, worka(:,:), a2D) + call accum_hist_field(n_siflcondbot, iblk, aice(:,:,iblk)*fcondbot(:,:,iblk), a2D) endif if (f_sipr(1:1) /= 'x') then worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - if (aice(i,j,iblk) > puny) then - worka(i,j) = aice(i,j,iblk)*frain(i,j,iblk) - endif - enddo - enddo + if (tr_pond_topo) worka(:,:) = aice_init(:,:,iblk)*frain(:,:,iblk) call accum_hist_field(n_sipr, iblk, worka(:,:), a2D) endif if (f_sifb(1:1) /= 'x') then - worka(:,:) = c0 - rho_ice = rhoi - rho_ocn = rhow do j = jlo, jhi do i = ilo, ihi if (aice(i,j,iblk) > puny) then - if (ktherm == 2) then - rho_ocn = icepack_mushy_density_brine(sss(i,j,iblk)) - rho_ice = c0 - do k = 1, nzilyr - Tice = icepack_mushy_temperature_mush(trcr(i,j,nt_qice+k-1,iblk),trcr(i,j,nt_sice+k-1,iblk)) - Sbr = trcr(i,j,nt_sice+k-1,iblk) - phi = icepack_mushy_liquid_fraction(Tice,Sbr) - rhob = icepack_mushy_density_brine(Sbr) - rho_ice = rho_ice + min(phi*rhob+(c1-phi)*rhoi,rho_ocn) - enddo - rho_ice = rho_ice / real(nzilyr,kind=dbl_kind) - endif - worka(i,j) = ((rho_ocn-rho_ice)*vice(i,j,iblk) - rhos*vsno(i,j,iblk))/rho_ocn -! if (worka(i,j) < c0) then -! write(nu_diag,*) 'negative fb',rho_ocn,rho_ice,rhos -! write(nu_diag,*) vice(i,j,iblk),vsno(i,j,iblk) -! endif + worka(i,j) = max(((rho_ocn(i,j)-rho_ice(i,j))*vice(i,j,iblk)-rhos*vsno(i,j,iblk)) & + / rho_ocn(i,j), c0) endif enddo enddo @@ -3340,70 +3129,33 @@ subroutine accum_hist (dt) worka(:,:) = c0 do j = jlo, jhi do i = ilo, ihi - if (aice(i,j,iblk) > puny) then - worka(i,j) = aice(i,j,iblk)*(frain(i,j,iblk)+melts(i,j,iblk)+meltt(i,j,iblk)) - endif + worka(i,j) = aice(i,j,iblk)*(melts(i,j,iblk)+meltt(i,j,iblk)) enddo enddo call accum_hist_field(n_siflfwdrain, iblk, worka(:,:), a2D) endif if (f_sidragtop(1:1) /= 'x') then - worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - if (aice(i,j,iblk) > puny) then - worka(i,j) = aice(i,j,iblk)*Cdn_atm(i,j,iblk) - endif - enddo - enddo - call accum_hist_field(n_sidragtop, iblk, worka(:,:), a2D) + call accum_hist_field(n_sidragtop, iblk, aice_init(:,:,iblk)*Cdn_atm(:,:,iblk), a2D) endif - if (f_sirdgthick(1:1) /= 'x') then - worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - if (aice(i,j,iblk)*(c1 - trcr(i,j,nt_alvl,iblk)) > puny) then - worka(i,j) = vice(i,j,iblk) * (c1 - trcr(i,j,nt_vlvl,iblk)) & - / (aice(i,j,iblk) * (c1 - trcr(i,j,nt_alvl,iblk))) - endif - enddo - enddo - call accum_hist_field(n_sirdgthick, iblk, worka(:,:), a2D) + if (f_sidragbot(1:1) /= 'x') then + call accum_hist_field(n_sidragbot, iblk, aice_init(:,:,iblk)*Cdn_ocn(:,:,iblk), a2D) endif if (f_siforcetiltx(1:1) /= 'x') then - worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - if (aice(i,j,iblk) > puny) then - worka(i,j) = aice(i,j,iblk)*strtltxU(i,j,iblk) - endif - enddo - enddo - call accum_hist_field(n_siforcetiltx, iblk, worka(:,:), a2D) + call accum_hist_field(n_siforcetiltx, iblk, aice_init(:,:,iblk)*strtltxU(:,:,iblk), a2D) endif if (f_siforcetilty(1:1) /= 'x') then - worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - if (aice(i,j,iblk) > puny) then - worka(i,j) = aice(i,j,iblk)*strtltyU(i,j,iblk) - endif - enddo - enddo - call accum_hist_field(n_siforcetilty, iblk, worka(:,:), a2D) + call accum_hist_field(n_siforcetilty, iblk, aice_init(:,:,iblk)*strtltyU(:,:,iblk), a2D) endif if (f_siforcecoriolx(1:1) /= 'x') then worka(:,:) = c0 do j = jlo, jhi do i = ilo, ihi - if (aice(i,j,iblk) > puny) then - worka(i,j) = aice(i,j,iblk)*fmU(i,j,iblk)*vvel(i,j,iblk) - endif + worka(i,j) = aice(i,j,iblk)*fmU(i,j,iblk)*vvel(i,j,iblk) enddo enddo call accum_hist_field(n_siforcecoriolx, iblk, worka(:,:), a2D) @@ -3413,36 +3165,18 @@ subroutine accum_hist (dt) worka(:,:) = c0 do j = jlo, jhi do i = ilo, ihi - if (aice(i,j,iblk) > puny) then - worka(i,j) = -aice(i,j,iblk)*fmU(i,j,iblk)*uvel(i,j,iblk) - endif + worka(i,j) = -aice(i,j,iblk)*fmU(i,j,iblk)*uvel(i,j,iblk) enddo enddo call accum_hist_field(n_siforcecorioly, iblk, worka(:,:), a2D) endif if (f_siforceintstrx(1:1) /= 'x') then - worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - if (aice(i,j,iblk) > puny) then - worka(i,j) = aice(i,j,iblk)*strintxU(i,j,iblk) - endif - enddo - enddo - call accum_hist_field(n_siforceintstrx, iblk, worka(:,:), a2D) + call accum_hist_field(n_siforceintstrx, iblk, aice(:,:,iblk)*strintxU(:,:,iblk), a2D) endif if (f_siforceintstry(1:1) /= 'x') then - worka(:,:) = c0 - do j = jlo, jhi - do i = ilo, ihi - if (aice(i,j,iblk) > puny) then - worka(i,j) = aice(i,j,iblk)*strintyU(i,j,iblk) - endif - enddo - enddo - call accum_hist_field(n_siforceintstry, iblk, worka(:,:), a2D) + call accum_hist_field(n_siforceintstry, iblk, aice(:,:,iblk)*strintyU(:,:,iblk), a2D) endif endif ! if (allocated(a2D)) @@ -3488,45 +3222,19 @@ subroutine accum_hist (dt) *aicen_init(:,:,1:ncat_hist,iblk), a3Dc) if (f_siitdconc (1:1) /= 'x') then - worka3(:,:,:) = c0 - do n = 1,ncat_hist - do j = jlo, jhi - do i = ilo, ihi - if (aicen(i,j,n,iblk) > puny) then - worka3(i,j,n) = aicen(i,j,n,iblk) - endif - enddo - enddo - enddo - call accum_hist_field(n_siitdconc-n2D, iblk, ncat_hist, worka3(:,:,:), a3Dc) + call accum_hist_field(n_siitdconc-n2D, iblk, ncat_hist, aicen(:,:,:,iblk), a3Dc) + endif + + if (f_siitdsnconc (1:1) /= 'x') then + call accum_hist_field(n_siitdsnconc-n2D, iblk, ncat_hist, snowfracn(:,:,:,iblk), a3Dc) endif if (f_siitdthick (1:1) /= 'x') then - worka3(:,:,:) = c0 - do n = 1,ncat_hist - do j = jlo, jhi - do i = ilo, ihi - if (aicen(i,j,n,iblk) > puny) then - worka3(i,j,n) = vicen(i,j,n,iblk) - endif - enddo - enddo - enddo - call accum_hist_field(n_siitdthick-n2D, iblk, ncat_hist, worka3(:,:,:), a3Dc) + call accum_hist_field(n_siitdthick-n2D, iblk, ncat_hist, vicen(:,:,:,iblk), a3Dc) endif if (f_siitdsnthick (1:1) /= 'x') then - worka3(:,:,:) = c0 - do n = 1,ncat_hist - do j = jlo, jhi - do i = ilo, ihi - if (aicen(i,j,n,iblk) > puny) then - worka3(i,j,n) = vsnon(i,j,n,iblk) - endif - enddo - enddo - enddo - call accum_hist_field(n_siitdsnthick-n2D, iblk, ncat_hist, worka3(:,:,:), a3Dc) + call accum_hist_field(n_siitdsnthick-n2D, iblk, ncat_hist, vsnon(:,:,:,iblk), a3Dc) endif endif ! if (allocated(a3Dc)) @@ -3661,7 +3369,8 @@ subroutine accum_hist (dt) ravgct = c1/avgct(ns) !$OMP PARALLEL DO PRIVATE(iblk,i,j,ilo,ihi,jlo,jhi,this_block, & - !$OMP n,nn,ravgctz,ravgip,ravgipn) + !$OMP n,nn,ravgctz,ravgip,ravgip_init,ravgip_pond, & + !$OMP ravgip_ridge,ravgipn) do iblk = 1, nblocks this_block = get_block(blocks_ice(iblk),iblk) ilo = this_block%ilo @@ -3672,36 +3381,79 @@ subroutine accum_hist (dt) ! Ice fraction really needs to be on one of the history ! streams, but in case it is not. - if (n_aice(ns) > 0) then - do j = jlo, jhi - do i = ilo, ihi - if (a2D(i,j,n_aice(ns),iblk) > puny) then - ravgip(i,j) = c1/(a2D(i,j,n_aice(ns),iblk)) - else - ravgip(i,j) = c0 - endif - enddo ! i - enddo ! j + if (n_aice(ns) > 0 .and. any(avail_hist_fields(:)%avg_ice_present == 'final')) then + do j = jlo, jhi + do i = ilo, ihi + if (a2D(i,j,n_aice(ns),iblk) > puny) then + ravgip(i,j) = c1/(a2D(i,j,n_aice(ns),iblk)) + else + ravgip(i,j) = c0 + endif + enddo ! i + enddo ! j + elseif (f_aice(1:1) == 'x' .and. any(avail_hist_fields(:)%avg_ice_present == 'final')) then + call abort_ice(subname//' ERROR: f_aice must be defined', file=__FILE__, line=__LINE__) endif - if (n_aicen(ns) > n2D) then - do k=1,ncat_hist - do j = jlo, jhi - do i = ilo, ihi - if (a3Dc(i,j,k,n_aicen(ns)-n2D,iblk) > puny) then - ravgipn(i,j,k) = c1/(a3Dc(i,j,k,n_aicen(ns)-n2D,iblk)) - else - ravgipn(i,j,k) = c0 - endif - enddo ! i - enddo ! j - enddo ! k + if (n_aice_init(ns) > 0 .and. any(avail_hist_fields(:)%avg_ice_present == 'init')) then + do j = jlo, jhi + do i = ilo, ihi + if (a2D(i,j,n_aice_init(ns),iblk) > puny) then + ravgip_init(i,j) = c1/(a2D(i,j,n_aice_init(ns),iblk)) + else + ravgip_init(i,j) = c0 + endif + enddo ! i + enddo ! j + elseif (f_aice_init(1:1) == 'x' .and. any(avail_hist_fields(:)%avg_ice_present == 'init')) then + call abort_ice(subname//' ERROR: f_aice_init must be defined', file=__FILE__, line=__LINE__) + endif + if (n_apond_ai(ns) > 0 .and. any(avail_hist_fields(:)%avg_ice_present == 'pond')) then + do j = jlo, jhi + do i = ilo, ihi + if (a2D(i,j,n_apond_ai(ns),iblk) > puny) then + ravgip_pond(i,j) = c1/a2D(i,j,n_apond_ai(ns),iblk) + else + ravgip_pond(i,j) = c0 + endif + enddo ! i + enddo ! j + elseif (f_apond_ai(1:1) == 'x' .and. any(avail_hist_fields(:)%avg_ice_present == 'pond')) then + call abort_ice(subname//' ERROR: f_apond_ai must be defined', file=__FILE__, line=__LINE__) + endif + if (n_ardg(ns) > 0 .and. any(avail_hist_fields(:)%avg_ice_present == 'ridge')) then + do j = jlo, jhi + do i = ilo, ihi + if (a2D(i,j,n_ardg(ns),iblk) > puny) then + ravgip_ridge(i,j) = c1/a2D(i,j,n_ardg(ns),iblk) + else + ravgip_ridge(i,j) = c0 + endif + enddo ! i + enddo ! j + elseif (f_ardg(1:1) == 'x' .and. any(avail_hist_fields(:)%avg_ice_present == 'ridge')) then + call abort_ice(subname//' ERROR: f_ardg must be defined', file=__FILE__, line=__LINE__) + endif + if (n_aicen(ns) > n2D .and. any(avail_hist_fields(:)%avg_ice_present == 'final')) then + do k=1,ncat_hist + do j = jlo, jhi + do i = ilo, ihi + if (a3Dc(i,j,k,n_aicen(ns)-n2D,iblk) > puny) then + ravgipn(i,j,k) = c1/(a3Dc(i,j,k,n_aicen(ns)-n2D,iblk)) + else + ravgipn(i,j,k) = c0 + endif + enddo ! i + enddo ! j + enddo ! k + elseif (f_aicen(1:1) == 'x' .and. any(avail_hist_fields(:)%avg_ice_present == 'final')) then + call abort_ice(subname//' ERROR: f_aicen must be defined', file=__FILE__, line=__LINE__) endif do n = 1, num_avail_hist_fields_2D if (avail_hist_fields(n)%vhistfreq == histfreq(ns)) then ! Only average when/where ice present - if (avail_hist_fields(n)%avg_ice_present) then + if (trim(avail_hist_fields(n)%avg_ice_present) == 'final') then do j = jlo, jhi do i = ilo, ihi if (.not. tmask(i,j,iblk)) then @@ -3712,6 +3464,39 @@ subroutine accum_hist (dt) endif enddo ! i enddo ! j + elseif (trim(avail_hist_fields(n)%avg_ice_present) == 'init') then + do j = jlo, jhi + do i = ilo, ihi + if (.not. tmask(i,j,iblk)) then + a2D(i,j,n,iblk) = spval_dbl + else ! convert units + a2D(i,j,n,iblk) = avail_hist_fields(n)%cona*a2D(i,j,n,iblk) & + * ravgip_init(i,j) + avail_hist_fields(n)%conb + endif + enddo ! i + enddo ! j + elseif (trim(avail_hist_fields(n)%avg_ice_present) == 'pond') then + do j = jlo, jhi + do i = ilo, ihi + if (.not. tmask(i,j,iblk)) then + a2D(i,j,n,iblk) = spval_dbl + else ! convert units + a2D(i,j,n,iblk) = avail_hist_fields(n)%cona*a2D(i,j,n,iblk) & + * ravgip_pond(i,j) + avail_hist_fields(n)%conb + endif + enddo ! i + enddo ! j + elseif (trim(avail_hist_fields(n)%avg_ice_present) == 'ridge') then + do j = jlo, jhi + do i = ilo, ihi + if (.not. tmask(i,j,iblk)) then + a2D(i,j,n,iblk) = spval_dbl + else ! convert units + a2D(i,j,n,iblk) = avail_hist_fields(n)%cona*a2D(i,j,n,iblk) & + * ravgip_ridge(i,j) + avail_hist_fields(n)%conb + endif + enddo ! i + enddo ! j else do j = jlo, jhi do i = ilo, ihi @@ -3726,7 +3511,8 @@ subroutine accum_hist (dt) endif ! Mask ice-free points - if (avail_hist_fields(n)%mask_ice_free_points) then + if (avail_hist_fields(n)%mask_ice_free_points .and. & + trim(avail_hist_fields(n)%avg_ice_present) == 'final') then do j = jlo, jhi do i = ilo, ihi if (ravgip(i,j) == c0) a2D(i,j,n,iblk) = spval_dbl @@ -3734,73 +3520,74 @@ subroutine accum_hist (dt) enddo ! j endif - ! CMIP albedo: also mask points below horizon - if (index(avail_hist_fields(n)%vname,'sialb') /= 0) then - do j = jlo, jhi - do i = ilo, ihi - if (albcnt(i,j,iblk,ns) <= puny) a2D(i,j,n,iblk) = spval_dbl - enddo ! i - enddo ! j + if (avail_hist_fields(n)%mask_ice_free_points .and. & + trim(avail_hist_fields(n)%avg_ice_present) == 'init') then + do j = jlo, jhi + do i = ilo, ihi + if (ravgip_init(i,j) == c0) a2D(i,j,n,iblk) = spval_dbl + enddo ! i + enddo ! j + endif endif ! back out albedo/zenith angle dependence - if (avail_hist_fields(n)%vname(1:6) == 'albice') then - do j = jlo, jhi - do i = ilo, ihi - if (tmask(i,j,iblk)) then - ravgctz = c0 - if (albcnt(i,j,iblk,ns) > puny) & - ravgctz = c1/albcnt(i,j,iblk,ns) - if (f_albice (1:1) /= 'x' .and. n_albice(ns) /= 0) & - a2D(i,j,n_albice(ns),iblk) = & - a2D(i,j,n_albice(ns),iblk)*avgct(ns)*ravgctz - if (f_albsno (1:1) /= 'x' .and. n_albsno(ns) /= 0) & - a2D(i,j,n_albsno(ns),iblk) = & - a2D(i,j,n_albsno(ns),iblk)*avgct(ns)*ravgctz - if (f_albpnd (1:1) /= 'x' .and. n_albpnd(ns) /= 0) & - a2D(i,j,n_albpnd(ns),iblk) = & - a2D(i,j,n_albpnd(ns),iblk)*avgct(ns)*ravgctz - endif - enddo ! i - enddo ! j - endif - if (avail_hist_fields(n)%vname(1:6) == 'albsni') then - do j = jlo, jhi - do i = ilo, ihi - if (tmask(i,j,iblk)) then - ravgctz = c0 - if (albcnt(i,j,iblk,ns) > puny) & - ravgctz = c1/albcnt(i,j,iblk,ns) - if (f_albsni (1:1) /= 'x' .and. n_albsni(ns) /= 0) & - a2D(i,j,n_albsni(ns),iblk) = & - a2D(i,j,n_albsni(ns),iblk)*avgct(ns)*ravgctz - endif - enddo ! i - enddo ! j - endif - if (avail_hist_fields(n)%vname(1:8) == 'alvdr_ai') then - do j = jlo, jhi - do i = ilo, ihi - if (tmask(i,j,iblk)) then - ravgctz = c0 - if (albcnt(i,j,iblk,ns) > puny) & - ravgctz = c1/albcnt(i,j,iblk,ns) - if (f_alvdr_ai (1:1) /= 'x' .and. n_alvdr_ai(ns) /= 0) & - a2D(i,j,n_alvdr_ai(ns),iblk) = & - a2D(i,j,n_alvdr_ai(ns),iblk)*avgct(ns)*ravgctz - if (f_alvdf_ai (1:1) /= 'x' .and. n_alvdf_ai(ns) /= 0) & - a2D(i,j,n_alvdf_ai(ns),iblk) = & - a2D(i,j,n_alvdf_ai(ns),iblk)*avgct(ns)*ravgctz - if (f_alidr_ai (1:1) /= 'x' .and. n_alidr_ai(ns) /= 0) & - a2D(i,j,n_alidr_ai(ns),iblk) = & - a2D(i,j,n_alidr_ai(ns),iblk)*avgct(ns)*ravgctz - if (f_alidf_ai (1:1) /= 'x' .and. n_alidf_ai(ns) /= 0) & - a2D(i,j,n_alidf_ai(ns),iblk) = & - a2D(i,j,n_alidf_ai(ns),iblk)*avgct(ns)*ravgctz - endif - enddo ! i - enddo ! j - endif +! if (avail_hist_fields(n)%vname(1:6) == 'albice') then +! do j = jlo, jhi +! do i = ilo, ihi +! if (tmask(i,j,iblk)) then +! ravgctz = c0 +! if (albcnt(i,j,iblk,ns) > puny) & +! ravgctz = c1/albcnt(i,j,iblk,ns) +! if (f_albice (1:1) /= 'x' .and. n_albice(ns) /= 0) & +! a2D(i,j,n_albice(ns),iblk) = & +! a2D(i,j,n_albice(ns),iblk)*avgct(ns)*ravgctz +! if (f_albsno (1:1) /= 'x' .and. n_albsno(ns) /= 0) & +! a2D(i,j,n_albsno(ns),iblk) = & +! a2D(i,j,n_albsno(ns),iblk)*avgct(ns)*ravgctz +! if (f_albpnd (1:1) /= 'x' .and. n_albpnd(ns) /= 0) & +! a2D(i,j,n_albpnd(ns),iblk) = & +! a2D(i,j,n_albpnd(ns),iblk)*avgct(ns)*ravgctz +! endif +! enddo ! i +! enddo ! j +! endif +! if (avail_hist_fields(n)%vname(1:6) == 'albsni') then +! do j = jlo, jhi +! do i = ilo, ihi +! if (tmask(i,j,iblk)) then +! ravgctz = c0 +! if (albcnt(i,j,iblk,ns) > puny) & +! ravgctz = c1/albcnt(i,j,iblk,ns) +! if (f_albsni (1:1) /= 'x' .and. n_albsni(ns) /= 0) & +! a2D(i,j,n_albsni(ns),iblk) = & +! a2D(i,j,n_albsni(ns),iblk)*avgct(ns)*ravgctz +! endif +! enddo ! i +! enddo ! j +! endif +! if (avail_hist_fields(n)%vname(1:8) == 'alvdr_ai') then +! do j = jlo, jhi +! do i = ilo, ihi +! if (tmask(i,j,iblk)) then +! ravgctz = c0 +! if (albcnt(i,j,iblk,ns) > puny) & +! ravgctz = c1/albcnt(i,j,iblk,ns) +! if (f_alvdr_ai (1:1) /= 'x' .and. n_alvdr_ai(ns) /= 0) & +! a2D(i,j,n_alvdr_ai(ns),iblk) = & +! a2D(i,j,n_alvdr_ai(ns),iblk)*avgct(ns)*ravgctz +! if (f_alvdf_ai (1:1) /= 'x' .and. n_alvdf_ai(ns) /= 0) & +! a2D(i,j,n_alvdf_ai(ns),iblk) = & +! a2D(i,j,n_alvdf_ai(ns),iblk)*avgct(ns)*ravgctz +! if (f_alidr_ai (1:1) /= 'x' .and. n_alidr_ai(ns) /= 0) & +! a2D(i,j,n_alidr_ai(ns),iblk) = & +! a2D(i,j,n_alidr_ai(ns),iblk)*avgct(ns)*ravgctz +! if (f_alidf_ai (1:1) /= 'x' .and. n_alidf_ai(ns) /= 0) & +! a2D(i,j,n_alidf_ai(ns),iblk) = & +! a2D(i,j,n_alidf_ai(ns),iblk)*avgct(ns)*ravgctz +! endif +! enddo ! i +! enddo ! j +! endif ! snwcnt averaging is not working correctly ! for now, these history fields will have zeroes includes in the averages @@ -3833,14 +3620,13 @@ subroutine accum_hist (dt) ! enddo ! j ! endif - endif ! avail_hist_fields(n)%vhistfreq == histfreq(ns) enddo ! n do n = 1, num_avail_hist_fields_3Dc nn = n2D + n if (avail_hist_fields(nn)%vhistfreq == histfreq(ns)) then - if (avail_hist_fields(nn)%avg_ice_present) then + if (trim(avail_hist_fields(nn)%avg_ice_present) /= 'none') then do k = 1, ncat_hist do j = jlo, jhi do i = ilo, ihi @@ -4040,8 +3826,10 @@ subroutine accum_hist (dt) if (n_sig1 (ns) /= 0) a2D(i,j,n_sig1(ns), iblk) = spval_dbl if (n_sig2 (ns) /= 0) a2D(i,j,n_sig2(ns), iblk) = spval_dbl if (n_sigP (ns) /= 0) a2D(i,j,n_sigP(ns), iblk) = spval_dbl - if (n_sistreave(ns) /= 0) a2D(i,j,n_sistreave(ns),iblk) = spval_dbl - if (n_sistremax(ns) /= 0) a2D(i,j,n_sistremax(ns),iblk) = spval_dbl + if (n_sistressave(ns) /= 0) a2D(i,j,n_sistressave(ns),iblk) = spval_dbl + if (n_sistressmax(ns) /= 0) a2D(i,j,n_sistressmax(ns),iblk) = spval_dbl + if (n_sidivvel(ns) /= 0) a2D(i,j,n_sidivvel(ns),iblk) = spval_dbl + if (n_sishearvel(ns) /= 0) a2D(i,j,n_sishearvel(ns),iblk) = spval_dbl if (n_mlt_onset(ns) /= 0) a2D(i,j,n_mlt_onset(ns),iblk) = spval_dbl if (n_frz_onset(ns) /= 0) a2D(i,j,n_frz_onset(ns),iblk) = spval_dbl if (n_hisnap (ns) /= 0) a2D(i,j,n_hisnap(ns), iblk) = spval_dbl @@ -4074,10 +3862,14 @@ subroutine accum_hist (dt) sig2 (i,j,iblk)*avail_hist_fields(n_sig2(ns))%cona if (n_sigP (ns) /= 0) a2D(i,j,n_sigP(ns),iblk) = & sigP (i,j,iblk)*avail_hist_fields(n_sigP(ns))%cona - if (n_sistreave(ns) /= 0) a2D(i,j,n_sistreave(ns),iblk) = & - p5*(sig1(i,j,iblk)+sig2(i,j,iblk))*avail_hist_fields(n_sistreave(ns))%cona - if (n_sistremax(ns) /= 0) a2D(i,j,n_sistremax(ns),iblk) = & - p5*(sig1(i,j,iblk)-sig2(i,j,iblk))*avail_hist_fields(n_sistremax(ns))%cona + if (n_sistressave(ns) /= 0) a2D(i,j,n_sistressave(ns),iblk) = & + p5*(sig1(i,j,iblk)+sig2(i,j,iblk))*avail_hist_fields(n_sistressave(ns))%cona + if (n_sistressmax(ns) /= 0) a2D(i,j,n_sistressmax(ns),iblk) = & + p5*(sig1(i,j,iblk)-sig2(i,j,iblk))*avail_hist_fields(n_sistressmax(ns))%cona + if (n_sidivvel(ns) /= 0) a2D(i,j,n_sidivvel(ns),iblk) = & + divu (i,j,iblk)*avail_hist_fields(n_sidivvel(ns))%cona + if (n_sishearvel(ns) /= 0) a2D(i,j,n_sishearvel(ns),iblk) = & + shear (i,j,iblk)*avail_hist_fields(n_sishearvel(ns))%cona if (n_mlt_onset(ns) /= 0) a2D(i,j,n_mlt_onset(ns),iblk) = & mlt_onset(i,j,iblk) if (n_frz_onset(ns) /= 0) a2D(i,j,n_frz_onset(ns),iblk) = & diff --git a/cicecore/cicedyn/analysis/ice_history_mechred.F90 b/cicecore/cicedyn/analysis/ice_history_mechred.F90 index e0d15fcf2..f3707f6f6 100644 --- a/cicecore/cicedyn/analysis/ice_history_mechred.F90 +++ b/cicecore/cicedyn/analysis/ice_history_mechred.F90 @@ -37,6 +37,11 @@ module ice_history_mechred f_aredistn = 'x', f_vredistn = 'x', & f_araftn = 'x', f_vraftn = 'x' + ! CMIP ridging variables. + + character (len=max_nstrm), public :: & + f_sirdgconc = 'm', f_sirdgthick = 'm' + !--------------------------------------------------------------- ! namelist variables !--------------------------------------------------------------- @@ -51,13 +56,14 @@ module ice_history_mechred f_dvirdgndt, & f_aparticn, f_krdgn , & f_aredistn, f_vredistn , & - f_araftn, f_vraftn + f_araftn, f_vraftn , & + f_sirdgconc, f_sirdgthick !--------------------------------------------------------------- ! field indices !--------------------------------------------------------------- - integer (kind=int_kind), dimension(max_nstrm) :: & + integer (kind=int_kind), dimension(max_nstrm), public :: & n_ardg , n_vrdg , & n_alvl , n_vlvl , & n_dardg1dt , n_dardg2dt , & @@ -69,6 +75,9 @@ module ice_history_mechred n_aredistn , n_vredistn , & n_araftn , n_vraftn + integer (kind=int_kind), dimension(max_nstrm) :: & + n_sirdgconc, n_sirdgthick + !======================================================================= contains @@ -152,6 +161,8 @@ subroutine init_hist_mechred_2D f_vrdgn = 'x' f_araftn = 'x' f_vraftn = 'x' + f_sirdgconc = 'x' + f_sirdgthick = 'x' endif if (f_araftn /= 'x' .or. f_vraftn /= 'x') f_ardgn = f_araftn @@ -174,6 +185,8 @@ subroutine init_hist_mechred_2D call broadcast_scalar (f_vredistn, master_task) call broadcast_scalar (f_araftn, master_task) call broadcast_scalar (f_vraftn, master_task) + call broadcast_scalar (f_sirdgconc, master_task) + call broadcast_scalar (f_sirdgthick, master_task) ! 2D variables @@ -182,49 +195,63 @@ subroutine init_hist_mechred_2D if (f_alvl(1:1) /= 'x') & call define_hist_field(n_alvl,"alvl","1",tstr2D, tcstr, & - "level ice area fraction", & - "none", c1, c0, & + "level ice area fraction", & + "none", c1, c0, & ns, f_alvl) if (f_vlvl(1:1) /= 'x') & call define_hist_field(n_vlvl,"vlvl","m",tstr2D, tcstr, & - "level ice volume", & - "grid cell mean level ice thickness", c1, c0, & + "level ice volume", & + "grid cell mean level ice thickness", c1, c0, & ns, f_vlvl) if (f_ardg(1:1) /= 'x') & call define_hist_field(n_ardg,"ardg","1",tstr2D, tcstr, & - "ridged ice area fraction", & - "none", c1, c0, & + "ridged ice area fraction", & + "none", c1, c0, & ns, f_ardg) if (f_vrdg(1:1) /= 'x') & call define_hist_field(n_vrdg,"vrdg","m",tstr2D, tcstr, & - "ridged ice volume", & - "grid cell mean level ridged thickness", c1, c0, & + "ridged ice volume", & + "grid cell mean level ridged thickness", c1, c0, & ns, f_vrdg) if (f_dardg1dt(1:1) /= 'x') & call define_hist_field(n_dardg1dt,"dardg1dt","%/day",tstr2D, tcstr, & - "ice area ridging rate", & - "none", secday*c100, c0, & + "ice area ridging rate", & + "none", secday*c100, c0, & ns, f_dardg1dt) if (f_dardg2dt(1:1) /= 'x') & call define_hist_field(n_dardg2dt,"dardg2dt","%/day",tstr2D, tcstr, & - "ridge area formation rate", & - "none", secday*c100, c0, & + "ridge area formation rate", & + "none", secday*c100, c0, & ns, f_dardg2dt) if (f_dvirdgdt(1:1) /= 'x') & call define_hist_field(n_dvirdgdt,"dvirdgdt","cm/day",tstr2D, tcstr, & - "ice volume ridging rate", & - "none", mps_to_cmpdy, c0, & + "ice volume ridging rate", & + "none", mps_to_cmpdy, c0, & ns, f_dvirdgdt) if (f_opening(1:1) /= 'x') & call define_hist_field(n_opening,"opening","%/day",tstr2D, tcstr, & - "lead area opening rate", & - "none", secday*c100, c0, & + "lead area opening rate", & + "none", secday*c100, c0, & ns, f_opening) + if (f_sirdgconc(1:1) /= 'x') & + call define_hist_field(n_sirdgconc,"sirdgconc","%",tstr2D, tcstr, & + "percentage of ridged sea ice", & + "area percentage of sea ice surface that is ridged sea ice", & + c100, c0, & + ns, f_sirdgconc, avg_ice_present='none', mask_ice_free_points=.false.) + + if (f_sirdgthick(1:1) /= 'x') & + call define_hist_field(n_sirdgthick,"sirdgthick","m",tstr2D, tcstr, & + "ridged ice thickness", & + "total volume of ridged sea ice divided by area of ridges", & + c1, c0, & + ns, f_sirdgthick, avg_ice_present='ridge', mask_ice_free_points=.true.) + endif ! histfreq(ns) /= 'x' enddo ! nstreams @@ -331,6 +358,7 @@ end subroutine init_hist_mechred_3Dc subroutine accum_hist_mechred (iblk) + use ice_blocks, only: nx_block, ny_block use ice_history_shared, only: n2D, a2D, a3Dc, ncat_hist, & accum_hist_field use ice_state, only: aice, vice, trcr, aicen, vicen, trcrn @@ -380,6 +408,15 @@ subroutine accum_hist_mechred (iblk) if (f_opening(1:1) /= 'x') & call accum_hist_field(n_opening, iblk, opening(:,:,iblk), a2D) + if (f_sirdgconc(1:1)/= 'x') & + call accum_hist_field(n_sirdgconc, iblk, & + aice(:,:,iblk) * (c1 - trcr(:,:,nt_alvl,iblk)), a2D) + + if (f_sirdgthick(1:1)/= 'x') then + call accum_hist_field(n_sirdgthick, iblk, & + vice(:,:,iblk) * (c1 - trcr(:,:,nt_vlvl,iblk)), a2D) + endif + endif ! allocated(a2D) ! 3D category fields diff --git a/cicecore/cicedyn/analysis/ice_history_pond.F90 b/cicecore/cicedyn/analysis/ice_history_pond.F90 index 88b5fa899..17d1c50b3 100644 --- a/cicecore/cicedyn/analysis/ice_history_pond.F90 +++ b/cicecore/cicedyn/analysis/ice_history_pond.F90 @@ -8,7 +8,7 @@ module ice_history_pond use ice_kinds_mod use ice_domain_size, only: max_nstrm - use ice_constants, only: c0, c1 + use ice_constants, only: c0, c1, c100 use ice_fileunits, only: nu_nml, nml_filename, & get_fileunit, release_fileunit use ice_fileunits, only: nu_diag @@ -40,6 +40,11 @@ module ice_history_pond f_dpnd_freebdn= 'x', f_dpnd_initialn= 'x', & f_dpnd_dlidn = 'x' + ! CMIP related pond variables + character (len=max_nstrm), public :: & + f_simpconc = 'm', f_simpeffconc = 'm', & + f_simpthick = 'm', f_simprefrozen = 'm' + !--------------------------------------------------------------- ! namelist variables !--------------------------------------------------------------- @@ -62,13 +67,17 @@ module ice_history_pond f_dpnd_exponn , & f_dpnd_freebdn , & f_dpnd_initialn , & - f_dpnd_dlidn + f_dpnd_dlidn , & + f_simpconc , & + f_simpeffconc , & + f_simpthick , & + f_simprefrozen !--------------------------------------------------------------- ! field indices !--------------------------------------------------------------- - integer (kind=int_kind), dimension(max_nstrm) :: & + integer (kind=int_kind), dimension(max_nstrm), public :: & n_apondn , n_apeffn , & n_hpondn , & n_apond , n_apond_ai, & @@ -83,6 +92,11 @@ module ice_history_pond n_dpnd_freebdn, n_dpnd_initialn, & n_dpnd_dlidn + ! CMIP related melt pond variables + integer (kind=int_kind), dimension(max_nstrm) :: & + n_simpconc , n_simpeffconc, & + n_simpthick , n_simprefrozen + !======================================================================= contains @@ -177,6 +191,10 @@ subroutine init_hist_pond_2D f_dpnd_freebdn = 'x' f_dpnd_initialn= 'x' f_dpnd_dlidn = 'x' + f_simpconc = 'x' + f_simpeffconc = 'x' + f_simpthick = 'x' + f_simprefrozen = 'x' endif if (tr_pond_topo) then @@ -203,6 +221,10 @@ subroutine init_hist_pond_2D call broadcast_scalar (f_hpond, master_task) call broadcast_scalar (f_ipond, master_task) call broadcast_scalar (f_apeff, master_task) + call broadcast_scalar (f_simpconc, master_task) + call broadcast_scalar (f_simpeffconc, master_task) + call broadcast_scalar (f_simpthick, master_task) + call broadcast_scalar (f_simprefrozen, master_task) call broadcast_scalar (f_apond_ai, master_task) call broadcast_scalar (f_hpond_ai, master_task) call broadcast_scalar (f_ipond_ai, master_task) @@ -234,8 +256,8 @@ subroutine init_hist_pond_2D if (f_apond_ai(1:1) /= 'x') & call define_hist_field(n_apond_ai,"apond_ai","1",tstr2D, tcstr, & - "melt pond fraction of grid cell", & - "weighted by ice area", c1, c0, & + "melt pond fraction of grid cell", & + "weighted by ice area", c1, c0, & ns, f_apond_ai) if (f_hpond(1:1) /= 'x') & @@ -246,8 +268,8 @@ subroutine init_hist_pond_2D if (f_hpond_ai(1:1) /= 'x') & call define_hist_field(n_hpond_ai,"hpond_ai","m",tstr2D, tcstr, & - "mean melt pond depth over grid cell", & - "weighted by ice area", c1, c0, & + "mean melt pond depth over grid cell", & + "weighted by ice area", c1, c0, & ns, f_hpond) if (f_ipond(1:1) /= 'x') & @@ -258,64 +280,93 @@ subroutine init_hist_pond_2D if (f_ipond_ai(1:1) /= 'x') & call define_hist_field(n_ipond_ai,"ipond_ai","m",tstr2D, tcstr, & - "mean pond ice thickness over grid cell", & - "weighted by ice area", c1, c0, & + "mean pond ice thickness over grid cell", & + "weighted by ice area", c1, c0, & ns, f_ipond_ai) if (f_apeff(1:1) /= 'x') & call define_hist_field(n_apeff,"apeff","1",tstr2D, tcstr, & "radiation-effective pond area fraction of sea ice", & - "none", c1, c0, & + "none", c1, c0, & ns, f_apeff) if (f_apeff_ai(1:1) /= 'x') & call define_hist_field(n_apeff_ai,"apeff_ai","1",tstr2D, tcstr, & - "radiation-effective pond area fraction over grid cell", & - "weighted by ice area", c1, c0, & + "radiation-effective pond area fraction over grid cell", & + "weighted by ice area", c1, c0, & ns, f_apeff_ai) if (f_dpnd_flush(1:1) /= 'x') & call define_hist_field(n_dpnd_flush,"dpnd_flush","m/s",tstr2D, tcstr, & - "pond flushing rate due to ice permeability", & - "none", c1, c0, & + "pond flushing rate due to ice permeability", & + "none", c1, c0, & ns, f_dpnd_flush) if (f_dpnd_expon(1:1) /= 'x') & call define_hist_field(n_dpnd_expon,"dpnd_expon","m/s",tstr2D, tcstr, & - "exponential pond drainage rate", & - "none", c1, c0, & + "exponential pond drainage rate", & + "none", c1, c0, & ns, f_dpnd_expon) if (f_dpnd_freebd(1:1) /= 'x') & call define_hist_field(n_dpnd_freebd,"dpnd_freebd","m/s",tstr2D, tcstr, & - "pond drainage rate due to freeboard constraint", & - "none", c1, c0, & + "pond drainage rate due to freeboard constraint", & + "none", c1, c0, & ns, f_dpnd_freebd) if (f_dpnd_initial(1:1) /= 'x') & call define_hist_field(n_dpnd_initial,"dpnd_initial","m/s",tstr2D, tcstr, & - "runoff rate due to rfrac", & - "none", c1, c0, & + "runoff rate due to rfrac", & + "none", c1, c0, & ns, f_dpnd_initial) if (f_dpnd_dlid(1:1) /= 'x') & call define_hist_field(n_dpnd_dlid,"dpnd_dlid","m/s",tstr2D, tcstr, & - "pond loss / gain to ice lid freezing / melting", & - "none", c1, c0, & + "pond loss / gain to ice lid freezing / melting", & + "none", c1, c0, & ns, f_dpnd_dlid) if (f_dpnd_melt(1:1) /= 'x') & call define_hist_field(n_dpnd_melt,"dpnd_melt","m/s",tstr2D, tcstr, & - "pond drainage due to ice melting", & - "none", c1, c0, & + "pond drainage due to ice melting", & + "none", c1, c0, & ns, f_dpnd_melt) if (f_dpnd_ridge(1:1) /= 'x') & call define_hist_field(n_dpnd_ridge,"dpnd_ridge","m",tstr2D, tcstr, & - "pond drainage due to ridging", & - "none", c1, c0, & + "pond drainage due to ridging", & + "none", c1, c0, & ns, f_dpnd_ridge) + ! CMIP melt pond variables + if (f_simpconc(1:1) /= 'x') & + call define_hist_field(n_simpconc,"simpconc","%",tstr2D, tcstr, & + "percentage of sea ice covered by melt ponds", & + "area percentage of sea-ice surface that is covered by melt ponds", & + c100, c0, & + ns, f_simpconc, avg_ice_present='none', mask_ice_free_points=.false.) + + if (f_simpeffconc(1:1) /= 'x') & + call define_hist_field(n_simpeffconc,"simpeffconc","%",tstr2D, tcstr, & + "percentage of sea ice covered by effective melt ponds", & + "area percentage of sea-ice surface that is covered by open melt ponds", & + c100, c0, & + ns, f_simpeffconc, avg_ice_present='none', mask_ice_free_points=.false.) + + if (f_simprefrozen(1:1) /= 'x') & + call define_hist_field(n_simprefrozen,"simprefrozen","m",tstr2D, tcstr, & + "thickness of refrozen ice on melt ponds", & + "volume of refrozen ice on melt ponds divided by melt pond covered area", & + c1, c0, & + ns, f_simprefrozen, avg_ice_present='pond', mask_ice_free_points=.true.) + + if (f_simpthick(1:1) /= 'x') & + call define_hist_field(n_simpthick,"simpthick","m",tstr2D, tcstr, & + "melt pond depth", & + "average depth of melt ponds on sea ice, that is melt pond volume divided by melt pond area", & + c1, c0, & + ns, f_simpthick, avg_ice_present='pond', mask_ice_free_points=.true.) + endif ! histfreq(ns) /= 'x' enddo ! nstreams @@ -413,7 +464,7 @@ subroutine accum_hist_pond (iblk) use ice_flux, only: dpnd_flushn, dpnd_exponn, dpnd_freebdn, dpnd_initialn use ice_history_shared, only: n2D, a2D, a3Dc, ncat_hist, & accum_hist_field - use ice_state, only: aice, trcr, trcrn + use ice_state, only: aice, aice_init, trcr, trcrn integer (kind=int_kind), intent(in) :: & iblk ! block index @@ -455,59 +506,38 @@ subroutine accum_hist_pond (iblk) if (allocated(a2D)) then + worka(:,:) = c0 if (tr_pond_lvl) then + worka(:,:) = trcr(:,:,nt_alvl,iblk) * trcr(:,:,nt_apnd,iblk) + elseif (tr_pond_sealvl .or. tr_pond_topo) then + worka(:,:) = trcr(:,:,nt_apnd,iblk) + endif if (f_apond(1:1)/= 'x') & - call accum_hist_field(n_apond, iblk, & - trcr(:,:,nt_alvl,iblk) * trcr(:,:,nt_apnd,iblk), a2D) + call accum_hist_field(n_apond, iblk, worka(:,:), a2D) if (f_apond_ai(1:1)/= 'x') & - call accum_hist_field(n_apond_ai, iblk, & - aice(:,:,iblk) & - * trcr(:,:,nt_alvl,iblk) * trcr(:,:,nt_apnd,iblk), a2D) + call accum_hist_field(n_apond_ai, iblk, aice_init(:,:,iblk)*worka(:,:), a2D) if (f_hpond(1:1)/= 'x') & - call accum_hist_field(n_hpond, iblk, & - trcr(:,:,nt_alvl,iblk) * trcr(:,:,nt_apnd,iblk) & - * trcr(:,:,nt_hpnd,iblk), a2D) + call accum_hist_field(n_hpond, iblk, worka(:,:)*trcr(:,:,nt_hpnd,iblk), a2D) if (f_hpond_ai(1:1)/= 'x') & - call accum_hist_field(n_hpond_ai, iblk, & - aice(:,:,iblk) & - * trcr(:,:,nt_alvl,iblk) * trcr(:,:,nt_apnd,iblk) & - * trcr(:,:,nt_hpnd,iblk), a2D) + call accum_hist_field(n_hpond_ai, iblk, aice_init(:,:,iblk)*worka(:,:)*trcr(:,:,nt_hpnd,iblk), a2D) if (f_ipond(1:1)/= 'x') & - call accum_hist_field(n_ipond, iblk, & - trcr(:,:,nt_alvl,iblk) * trcr(:,:,nt_apnd,iblk) & - * trcr(:,:,nt_ipnd,iblk), a2D) + call accum_hist_field(n_ipond, iblk, worka(:,:)*trcr(:,:,nt_ipnd,iblk), a2D) if (f_ipond_ai(1:1)/= 'x') & - call accum_hist_field(n_ipond_ai, iblk, & - aice(:,:,iblk) & - * trcr(:,:,nt_alvl,iblk) * trcr(:,:,nt_apnd,iblk) & - * trcr(:,:,nt_ipnd,iblk), a2D) + call accum_hist_field(n_ipond_ai, iblk, aice_init(:,:,iblk)*worka(:,:)*trcr(:,:,nt_ipnd,iblk), a2D) - elseif (tr_pond_topo .or. tr_pond_sealvl) then + ! CMIP pond related variables + if (f_simpeffconc (1:1) /= 'x') & + call accum_hist_field(n_simpeffconc, iblk, apeff_ai(:,:,iblk), a2D) - if (f_apond(1:1)/= 'x') & - call accum_hist_field(n_apond, iblk, & - trcr(:,:,nt_apnd,iblk), a2D) - if (f_apond_ai(1:1)/= 'x') & - call accum_hist_field(n_apond_ai, iblk, & - aice(:,:,iblk) * trcr(:,:,nt_apnd,iblk), a2D) - if (f_hpond(1:1)/= 'x') & - call accum_hist_field(n_hpond, iblk, & - trcr(:,:,nt_apnd,iblk) & - * trcr(:,:,nt_hpnd,iblk), a2D) - if (f_hpond_ai(1:1)/= 'x') & - call accum_hist_field(n_hpond_ai, iblk, & - aice(:,:,iblk) * trcr(:,:,nt_apnd,iblk) & - * trcr(:,:,nt_hpnd,iblk), a2D) - if (f_ipond(1:1)/= 'x') & - call accum_hist_field(n_ipond, iblk, & - trcr(:,:,nt_apnd,iblk) & - * trcr(:,:,nt_ipnd,iblk), a2D) - if (f_ipond_ai(1:1)/= 'x') & - call accum_hist_field(n_ipond_ai, iblk, & - aice(:,:,iblk) * trcr(:,:,nt_apnd,iblk) & - * trcr(:,:,nt_ipnd,iblk), a2D) - endif ! ponds + if (f_simpconc(1:1)/= 'x') & + call accum_hist_field(n_simpconc, iblk, worka(:,:), a2D) + + if (f_simpthick(1:1)/= 'x') & + call accum_hist_field(n_simpthick, iblk, aice_init(:,:,iblk)*worka(:,:)*trcr(:,:,nt_hpnd,iblk), a2D) + + if (f_simprefrozen(1:1)/= 'x') & + call accum_hist_field(n_simprefrozen, iblk, aice_init(:,:,iblk)*worka(:,:)*trcr(:,:,nt_ipnd,iblk), a2D) this_block = get_block(blocks_ice(iblk),iblk) ilo = this_block%ilo diff --git a/cicecore/cicedyn/analysis/ice_history_shared.F90 b/cicecore/cicedyn/analysis/ice_history_shared.F90 index 83b8d8eca..2d2c500e8 100644 --- a/cicecore/cicedyn/analysis/ice_history_shared.F90 +++ b/cicecore/cicedyn/analysis/ice_history_shared.F90 @@ -1,4 +1,4 @@ -!======================================================================= +! ======================================================================= ! ! Output files: netCDF or binary data, Fortran unformatted dumps ! @@ -34,7 +34,7 @@ module ice_history_shared implicit none private - public :: define_hist_field, accum_hist_field, icefields_nml, construct_filename + public :: define_hist_field, accum_hist_field, icefields_nml, construct_filename, ice_brine_density integer (kind=int_kind), public :: history_precision @@ -80,22 +80,22 @@ module ice_history_shared !--------------------------------------------------------------- type, public :: ice_hist_field - character (len=16) :: vname ! variable name + character (len=20) :: vname ! variable name character (len=16) :: vunit ! variable units character (len=25) :: vcoord ! variable coordinates character (len=16) :: vcellmeas ! variable cell measures - character (len=55) :: vdesc ! variable description - character (len=55) :: vcomment ! variable description + character (len=80) :: vdesc ! variable description + character (len=80) :: vcomment ! variable description real (kind=dbl_kind) :: cona ! multiplicative conversion factor real (kind=dbl_kind) :: conb ! additive conversion factor character (len=1) :: vhistfreq ! frequency of history output integer (kind=int_kind) :: vhistfreq_n ! number of vhistfreq intervals - logical (kind=log_kind) :: avg_ice_present ! only average where ice is present + character (len=16) :: avg_ice_present ! only average where ice is present 'init', 'final', 'none' logical (kind=log_kind) :: mask_ice_free_points ! mask ice-free points end type integer (kind=int_kind), parameter, public :: & - max_avail_hist_fields = 800 ! Max number of history fields + max_avail_hist_fields = 1200 ! Max number of history fields integer (kind=int_kind), public :: & num_avail_hist_fields_tot = 0, & ! Current, total number of defined fields @@ -218,9 +218,11 @@ module ice_history_shared character (len=max_nstrm), public :: & ! f_example = 'md', & + f_CMIP = 'x', & f_hi = 'm', f_hs = 'm', & f_snowfrac = 'x', f_snowfracn = 'x', & f_Tsfc = 'm', f_aice = 'm', & + f_aice_init = 'x', & f_uvel = 'm', f_vvel = 'm', & f_icespd = 'm', f_icedir = 'm', & f_uvelE = 'x', f_vvelE = 'x', & @@ -289,40 +291,43 @@ module ice_history_shared f_mlt_onset = 'm', f_frz_onset = 'm', & f_iage = 'm', f_FY = 'm', & f_hisnap = 'm', f_aisnap = 'm', & - f_CMIP = 'x' , & f_sithick = 'x', f_sisnthick = 'x', & - f_siage = 'x', & + f_siage = 'x', f_siconc = 'x', & + f_sisnconc = 'x', f_sisnmass = 'x', & f_sitemptop = 'x', f_sitempsnic = 'x', & - f_sitempbot = 'x', & + f_sitempbot = 'x', f_sivol = 'x', & f_sispeed = 'x', f_sidir = 'x', & f_siu = 'x', f_siv = 'x', & f_sidmasstranx = 'x', f_sidmasstrany = 'x', & f_sistrxdtop = 'x', f_sistrydtop = 'x', & f_sistrxubot = 'x', f_sistryubot = 'x', & f_sicompstren = 'x', & - f_sialb = 'x', & + f_sisali = 'x', & f_sihc = 'x', f_sisnhc = 'x', & f_sidconcth = 'x', f_sidconcdyn = 'x', & f_sidmassth = 'x', f_sidmassdyn = 'x', & f_sidmassgrowthwat = 'x', & f_sidmassgrowthbot = 'x', & - f_sidmasssi = 'x', & + f_simass = 'x', & + f_sisaltmass = 'x', & + f_sidmassgrowthsi = 'x', & f_sidmassevapsubl = 'x', & - f_sndmasssubl = 'x', & + f_sisndmasssubl = 'x', & f_sidmassmelttop = 'x', & f_sidmassmeltbot = 'x', & - f_sidmasslat = 'x', & - f_sndmasssnf = 'x', & - f_sndmassmelt = 'x', & - f_sndmassdyn = 'x', & + f_sidmassmeltlat = 'x', & + f_sisndmasssnf = 'x', & + f_sisndmassmelt = 'x', & + f_sisndmassdyn = 'x', & + f_sisndmasssi = 'x', & f_siflswdtop = 'x', & f_siflswutop = 'x', & f_siflswdbot = 'x', & f_sifllwdtop = 'x', & f_sifllwutop = 'x', & f_siflsenstop = 'x', & - f_siflsensupbot = 'x', & - f_sifllatstop = 'x', & + f_siflsensbot = 'x', & + f_sifllattop = 'x', & f_siflcondtop = 'x', & f_siflcondbot = 'x', & f_sipr = 'x', & @@ -337,12 +342,16 @@ module ice_history_shared f_siforceintstrx = 'x', & f_siforceintstry = 'x', & f_siitdconc = 'x', & + f_siitdsnconc = 'x', & f_siitdthick = 'x', & f_siitdsnthick = 'x', & + f_sidragbot = 'x', & f_sidragtop = 'x', & - f_sirdgthick = 'x', & - f_sistreave = 'x', & - f_sistremax = 'x', & + f_sistressave = 'x', & + f_sistressmax = 'x', & + f_sidivvel = 'x', & + f_sishearvel = 'x', & + f_sitimefrac = 'x', & f_aicen = 'x', f_vicen = 'x', & f_vsnon = 'x', & f_trsig = 'm', f_icepresent = 'm', & @@ -389,9 +398,11 @@ module ice_history_shared f_VGRDb , f_VGRDa , & f_NFSD , & ! f_example , & + f_CMIP , & f_hi, f_hs , & f_snowfrac, f_snowfracn, & f_Tsfc, f_aice , & + f_aice_init, & f_uvel, f_vvel , & f_icespd, f_icedir , & ! For now, C and CD grid quantities are controlled by the generic (originally B-grid) namelist flag @@ -461,40 +472,43 @@ module ice_history_shared f_mlt_onset, f_frz_onset, & f_iage, f_FY , & f_hisnap, f_aisnap , & - f_CMIP, & f_sithick, f_sisnthick, & - f_siage, & + f_siage, f_siconc , & + f_sisnconc, f_sisnmass , & f_sitemptop, f_sitempsnic,& - f_sitempbot, & + f_sitempbot, f_sivol, & f_sispeed, f_sidir, & f_siu, f_siv, & f_sidmasstranx, f_sidmasstrany, & f_sistrxdtop, f_sistrydtop, & f_sistrxubot, f_sistryubot, & f_sicompstren, & - f_sialb, & + f_sisali, & f_sihc, f_sisnhc, & f_sidconcth, f_sidconcdyn,& f_sidmassth, f_sidmassdyn,& f_sidmassgrowthwat, & f_sidmassgrowthbot, & - f_sidmasssi, & + f_simass, & + f_sisaltmass, & + f_sidmassgrowthsi, & f_sidmassevapsubl, & - f_sndmasssubl, & + f_sisndmasssubl, & f_sidmassmelttop, & f_sidmassmeltbot, & - f_sidmasslat, & - f_sndmasssnf, & - f_sndmassmelt, & - f_sndmassdyn, & + f_sidmassmeltlat, & + f_sisndmasssnf, & + f_sisndmassmelt, & + f_sisndmassdyn, & + f_sisndmasssi, & f_siflswdtop, & f_siflswutop, & f_siflswdbot, & f_sifllwdtop, & f_sifllwutop, & f_siflsenstop, & - f_siflsensupbot, & - f_sifllatstop, & + f_siflsensbot, & + f_sifllattop, & f_siflcondtop, & f_siflcondbot, & f_sipr, & @@ -509,12 +523,16 @@ module ice_history_shared f_siforceintstrx, & f_siforceintstry, & f_siitdconc, & + f_siitdsnconc, & f_siitdthick, & f_siitdsnthick, & + f_sidragbot, & f_sidragtop, & - f_sirdgthick, & - f_sistreave, & - f_sistremax, & + f_sistressave, & + f_sistressmax, & + f_sidivvel, & + f_sishearvel, & + f_sitimefrac, & f_aicen, f_vicen , & f_vsnon, & f_trsig, f_icepresent,& @@ -593,6 +611,7 @@ module ice_history_shared n_hi , n_hs , & n_snowfrac , n_snowfracn , & n_Tsfc , n_aice , & + n_aice_init , & n_uvel , n_vvel , & n_icespd , n_icedir , & n_uvelE , n_vvelE , & @@ -663,38 +682,42 @@ module ice_history_shared n_mlt_onset , n_frz_onset , & n_hisnap , n_aisnap , & n_sithick , n_sisnthick , & - n_siage, & + n_siage , n_siconc , & + n_sisnconc , n_sisnmass , & n_sitemptop , n_sitempsnic , & - n_sitempbot , & + n_sitempbot , n_sivol , & n_sispeed , n_sidir , & - n_siu, n_siv, & + n_siu , n_siv , & n_sidmasstranx, n_sidmasstrany, & n_sistrxdtop, n_sistrydtop, & n_sistrxubot, n_sistryubot, & n_sicompstren, & - n_sialb, & + n_sisali, & n_sihc , n_sisnhc, & n_sidconcth , n_sidconcdyn, & n_sidmassth , n_sidmassdyn, & n_sidmassgrowthwat, & n_sidmassgrowthbot, & - n_sidmasssi, & + n_simass, & + n_sisaltmass, & + n_sidmassgrowthsi, & n_sidmassevapsubl, & - n_sndmasssubl, & + n_sisndmasssubl, & n_sidmassmelttop, & n_sidmassmeltbot, & - n_sidmasslat, & - n_sndmasssnf, & - n_sndmassmelt, & - n_sndmassdyn, & + n_sidmassmeltlat, & + n_sisndmasssnf, & + n_sisndmassmelt, & + n_sisndmassdyn, & + n_sisndmasssi, & n_siflswdtop, & n_siflswutop, & n_siflswdbot, & n_sifllwdtop, & n_sifllwutop, & n_siflsenstop, & - n_siflsensupbot, & - n_sifllatstop, & + n_siflsensbot, & + n_sifllattop, & n_siflcondtop, & n_siflcondbot, & n_sipr, & @@ -709,12 +732,16 @@ module ice_history_shared n_siforceintstrx, & n_siforceintstry, & n_siitdconc, & + n_siitdsnconc, & n_siitdthick, & n_siitdsnthick, & + n_sidragbot, & n_sidragtop, & - n_sirdgthick, & - n_sistreave, & - n_sistremax, & + n_sistressave, & + n_sistressmax, & + n_sidivvel, & + n_sishearvel, & + n_sitimefrac, & n_trsig , n_icepresent , & n_iage , n_FY , & n_fsurf_ai , & @@ -888,6 +915,9 @@ subroutine define_hist_field(id, vname, vunit, vcoord, vcellmeas, & vdesc , & ! variable descriptions vcomment ! variable comments + character (len=*), optional, intent(in) :: & + avg_ice_present ! compute average only when ice is present + real (kind=dbl_kind), intent(in) :: & cona , & ! multiplicative conversion factor conb ! additive conversion factor @@ -899,7 +929,6 @@ subroutine define_hist_field(id, vname, vunit, vcoord, vcellmeas, & ns ! history file stream index logical (kind=log_kind), optional, intent(in) :: & - avg_ice_present , & ! compute average only when ice is present mask_ice_free_points ! mask ice-free points integer (kind=int_kind) :: & @@ -908,13 +937,14 @@ subroutine define_hist_field(id, vname, vunit, vcoord, vcellmeas, & character (len=40) :: stmp + character (len=16) :: l_avg_ice_present ! compute average only when ice is present + logical (kind=log_kind) :: & - l_avg_ice_present , & ! compute average only when ice is present l_mask_ice_free_points ! mask ice-free points character(len=*), parameter :: subname = '(define_hist_field)' - l_avg_ice_present = .false. + l_avg_ice_present = 'none' l_mask_ice_free_points = .false. if(present(avg_ice_present)) l_avg_ice_present = avg_ice_present @@ -1199,6 +1229,55 @@ end subroutine accum_hist_field_4D !======================================================================= +! Computes total density of brine plus fresh ice. Used for mass +! related CMIP variables. +! +! 2025 Created by D. Bailey + + subroutine ice_brine_density (qice,sice,sss,rho_ice,rho_ocn,salt_ice) + + use ice_constants, only: c0, c1 + use icepack_intfc, only: icepack_mushy_density_brine, icepack_mushy_liquid_fraction + use icepack_intfc, only: icepack_mushy_temperature_mush, icepack_query_parameters + + real (kind=dbl_kind), intent(in), dimension(:) :: & + qice, & ! sea ice enthalpy of each layer (J m-3) + sice ! sea ice salinity in each layer (psu) + + real (kind=dbl_kind), intent(in) :: & + sss ! sea surface (ocean) salinity (psu) + + real (kind=dbl_kind), intent(out) :: & + rho_ice, & ! combined brine + ice density (kg m-3) + rho_ocn, & ! ocean density from sss (kg m-3) + salt_ice ! bulk salinity of brine + ice (psu) + + integer (kind=int_kind) :: k + real (kind=dbl_kind) :: rhoi ! constant fresh ice density (kg m-3) + real (kind=dbl_kind) :: & + Tice, & ! sea ice temperature in each layer (C) + Sbr, & ! salinity of brine in each layer (psu) + phi, & ! brine fraction in each layer + rhob ! density of brine (kg m-3) + + call icepack_query_parameters(rhoi_out=rhoi) + + rho_ocn = icepack_mushy_density_brine(sss) + rho_ice = c0 + salt_ice = c0 + do k = 1, nzilyr + Sbr = sice(k) + Tice = icepack_mushy_temperature_mush(qice(k),Sbr) + salt_ice = salt_ice + Sbr / real(nzilyr,kind=dbl_kind) + phi = icepack_mushy_liquid_fraction(Tice,Sbr) + rhob = icepack_mushy_density_brine(Sbr) + rho_ice = rho_ice + min(phi*rhob+(c1-phi)*rhoi,rho_ocn) + enddo + rho_ice = rho_ice / real(nzilyr,kind=dbl_kind) + + end subroutine ice_brine_density +!======================================================================= + end module ice_history_shared !======================================================================= diff --git a/cicecore/cicedyn/analysis/ice_history_snow.F90 b/cicecore/cicedyn/analysis/ice_history_snow.F90 index 19722b014..bb702defa 100644 --- a/cicecore/cicedyn/analysis/ice_history_snow.F90 +++ b/cicecore/cicedyn/analysis/ice_history_snow.F90 @@ -31,6 +31,9 @@ module ice_history_snow f_rsnw = 'm', f_rsnwn = 'x', & f_meltsliq = 'm', f_fsloss = 'x' + character (len=max_nstrm), public :: & + f_sisndmasswind = 'm' + !--------------------------------------------------------------- ! namelist variables !--------------------------------------------------------------- @@ -41,7 +44,8 @@ module ice_history_snow f_rhos_cmp, f_rhos_cmpn, & f_rhos_cnt, f_rhos_cntn, & f_rsnw, f_rsnwn, & - f_meltsliq, f_fsloss + f_meltsliq, f_fsloss, & + f_sisndmasswind !--------------------------------------------------------------- ! field indices @@ -55,6 +59,9 @@ module ice_history_snow n_rsnw, n_rsnwn, & n_meltsliq, n_fsloss + integer (kind=int_kind), dimension(max_nstrm), public :: & + n_sisndmasswind + !======================================================================= contains @@ -147,6 +154,7 @@ subroutine init_hist_snow_2D (dt) f_rsnwn = 'x' f_meltsliq = 'x' f_fsloss = 'x' + f_sisndmasswind = 'x' endif call broadcast_scalar (f_smassice, master_task) @@ -161,6 +169,7 @@ subroutine init_hist_snow_2D (dt) call broadcast_scalar (f_rsnwn, master_task) call broadcast_scalar (f_meltsliq, master_task) call broadcast_scalar (f_fsloss, master_task) + call broadcast_scalar (f_sisndmasswind, master_task) if (tr_snow) then @@ -210,6 +219,13 @@ subroutine init_hist_snow_2D (dt) "none", c1, c0, & ns, f_fsloss) + if (f_sisndmasswind(1:1) /= 'x') & + call define_hist_field(n_sisndmasswind,"sisndmasswind","kg/m^2/s",tstr2D, tcstr, & + "snow mass rate of change through wind drift of snow", & + "rate of change of snow mass due to wind-driven transport into the ocean", & + c1, c0, & + ns, f_sisndmasswind, avg_ice_present='none', mask_ice_free_points=.false.) + endif ! histfreq(ns) /= 'x' enddo ! nstreams endif ! tr_snow @@ -376,6 +392,10 @@ subroutine accum_hist_snow (iblk) call accum_hist_field(n_fsloss, iblk, & fsloss(:,:,iblk), a2D) + if (f_sisndmasswind(1:1)/= 'x') & + call accum_hist_field(n_sisndmasswind, iblk, & + fsloss(:,:,iblk), a2D) + endif ! allocated(a2D) ! 3D category fields diff --git a/cicecore/cicedyn/general/ice_flux.F90 b/cicecore/cicedyn/general/ice_flux.F90 index 16d3a6edc..e6f38acda 100644 --- a/cicecore/cicedyn/general/ice_flux.F90 +++ b/cicecore/cicedyn/general/ice_flux.F90 @@ -400,6 +400,7 @@ module ice_flux vatmT , & ! vatm on T grid (m/s) wlat , & ! lateral heat rate (m/s) fsw , & ! incoming shortwave radiation (W/m^2) + fswup , & ! outgoing shortwave radiation (W/m^2) coszen , & ! cosine solar zenith angle, < 0 for sun below horizon rdg_conv, & ! convergence term for ridging (1/s) rdg_shear ! shear term for ridging (1/s) @@ -585,6 +586,7 @@ subroutine alloc_flux vatmT (nx_block,ny_block,max_blocks), & ! vatm on T grid wlat (nx_block,ny_block,max_blocks), & ! lateral melt rate (m/s) fsw (nx_block,ny_block,max_blocks), & ! incoming shortwave radiation (W/m^2) + fswup (nx_block,ny_block,max_blocks), & ! outgoing shortwave radiation (W/m^2) coszen (nx_block,ny_block,max_blocks), & ! cosine solar zenith angle, < 0 for sun below horizon rdg_conv (nx_block,ny_block,max_blocks), & ! convergence term for ridging (1/s) rdg_shear (nx_block,ny_block,max_blocks), & ! shear term for ridging (1/s) @@ -785,6 +787,7 @@ subroutine alloc_flux vatmT = c0 wlat = c0 fsw = c0 + fswup = c0 coszen = c0 rdg_conv = c0 rdg_shear = c0 @@ -1070,8 +1073,6 @@ subroutine init_coupler_flux flat (:,:,:) = c0 fswabs (:,:,:) = c0 fswint_ai(:,:,:) = c0 - flwout (:,:,:) = -stefan_boltzmann*Tffresh**4 - ! in case atm model diagnoses Tsfc from flwout evap (:,:,:) = c0 evaps (:,:,:) = c0 evapi (:,:,:) = c0 @@ -1128,6 +1129,7 @@ subroutine init_coupler_flux coszen (:,:,:) = c0 ! Cosine of the zenith angle fsw (:,:,:) = c0 ! shortwave radiation (W/m^2) + fswup (:,:,:) = c0 ! shortwave radiation (W/m^2) scale_factor(:,:,:) = c1 ! shortwave scaling factor wind (:,:,:) = sqrt(uatm(:,:,:)**2 & + vatm(:,:,:)**2) ! wind speed, (m/s) @@ -1170,6 +1172,8 @@ subroutine init_flux_atm fswabs (:,:,:) = c0 flwout (:,:,:) = c0 evap (:,:,:) = c0 + evaps (:,:,:) = c0 + evapi (:,:,:) = c0 Tref (:,:,:) = c0 Qref (:,:,:) = c0 Uref (:,:,:) = c0 @@ -1563,9 +1567,6 @@ subroutine scale_fluxes (nx_block, ny_block, & fsens (i,j) = fsens (i,j) * ar flat (i,j) = flat (i,j) * ar fswabs (i,j) = fswabs (i,j) * ar - ! Special case where aice_init was zero and aice > 0. - if (flwout(i,j) > -puny) & - flwout (i,j) = -stefan_boltzmann *(Tf(i,j) + Tffresh)**4 flwout (i,j) = flwout (i,j) * ar evap (i,j) = evap (i,j) * ar Tref (i,j) = Tref (i,j) * ar diff --git a/cicecore/cicedyn/infrastructure/io/io_binary/ice_history_write.F90 b/cicecore/cicedyn/infrastructure/io/io_binary/ice_history_write.F90 index af4a88007..030977ccc 100644 --- a/cicecore/cicedyn/infrastructure/io/io_binary/ice_history_write.F90 +++ b/cicecore/cicedyn/infrastructure/io/io_binary/ice_history_write.F90 @@ -163,7 +163,8 @@ subroutine ice_write_hist(ns) .or. n==n_vort(ns) & ! snapshots .or. n==n_sig1(ns) .or. n==n_sig2(ns) & .or. n==n_sigP(ns) .or. n==n_trsig(ns) & - .or. n==n_sistreave(ns) .or. n==n_sistremax(ns) & + .or. n==n_sidivvel(ns) .or. n==n_sishearvel(ns) & + .or. n==n_sistressave(ns) .or. n==n_sistressmax(ns) & .or. n==n_mlt_onset(ns) .or. n==n_frz_onset(ns) & .or. n==n_hisnap(ns) .or. n==n_aisnap(ns)) then write (nu_hdr, 996) nrec,trim(avail_hist_fields(n)%vname), & diff --git a/cicecore/cicedyn/infrastructure/io/io_netcdf/ice_history_write.F90 b/cicecore/cicedyn/infrastructure/io/io_netcdf/ice_history_write.F90 index 2d6c5915a..668badb14 100644 --- a/cicecore/cicedyn/infrastructure/io/io_netcdf/ice_history_write.F90 +++ b/cicecore/cicedyn/infrastructure/io/io_netcdf/ice_history_write.F90 @@ -270,14 +270,15 @@ subroutine ice_write_hist (ns) endif ! Define coord time_bounds if hist_avg is true - ! bounds inherit attributes if (hist_avg(ns) .and. .not. write_ic) then - time_coord = coord_attributes('time_bounds', 'undefined', 'undefined', 'undefined') + time_coord = coord_attributes('time_bounds', 'time interval endpoints', trim(cal_units), 'undefined') dimid(1) = boundid dimid(2) = timid call ice_hist_coord_def(ncid, time_coord, nf90_double, dimid(1:2), varid) + status = nf90_put_att(ncid,varid,'calendar',cal_att) !extra attribute + call ice_check_nc(status, subname//' ERROR: defining att calendar: '//cal_att,file=__FILE__,line=__LINE__) endif endif ! histfreq(ns)/='g' @@ -406,15 +407,22 @@ subroutine ice_write_hist (ns) ! bounds fields are required for CF compliance ! dimensions (nx,ny,nverts) - ! bounds inherit attributes - var_nverts(n_lont_bnds) = coord_attributes('lont_bounds','und','und','und') - var_nverts(n_latt_bnds) = coord_attributes('latt_bounds','und','und','und') - var_nverts(n_lonu_bnds) = coord_attributes('lonu_bounds','und','und','und') - var_nverts(n_latu_bnds) = coord_attributes('latu_bounds','und','und','und') - var_nverts(n_lonn_bnds) = coord_attributes('lonn_bounds','und','und','und') - var_nverts(n_latn_bnds) = coord_attributes('latn_bounds','und','und','und') - var_nverts(n_lone_bnds) = coord_attributes('lone_bounds','und','und','und') - var_nverts(n_late_bnds) = coord_attributes('late_bounds','und','und','und') + var_nverts(n_lont_bnds) = coord_attributes('lont_bounds', & + 'longitude of gridbox corners for T points','degrees_east','und') + var_nverts(n_latt_bnds) = coord_attributes('latt_bounds', & + 'latitude of gridbox corners for T points','degrees_north','und') + var_nverts(n_lonu_bnds) = coord_attributes('lonu_bounds', & + 'longitude of gridbox corners for U points','degrees_east','und') + var_nverts(n_latu_bnds) = coord_attributes('latu_bounds', & + 'latitude of gridbox corners for U points','degrees_north','und') + var_nverts(n_lonn_bnds) = coord_attributes('lonn_bounds', & + 'longitude of gridbox corners for N points','degrees_east','und') + var_nverts(n_latn_bnds) = coord_attributes('latn_bounds', & + 'latitude of gridbox corners for N points','degrees_north','und') + var_nverts(n_lone_bnds) = coord_attributes('lone_bounds', & + 'longitude of gridbox corners for E points','degrees_east','und') + var_nverts(n_late_bnds) = coord_attributes('late_bounds', & + 'latitude of gridbox corners for E points','degrees_north','und') !----------------------------------------------------------------- ! define attributes for time-invariant variables @@ -473,7 +481,6 @@ subroutine ice_write_hist (ns) enddo ! bounds fields with dimensions (nverts,nx,ny) - ! bounds inherits attributes dimid_nverts(1) = nvertexid dimid_nverts(2) = imtid dimid_nverts(3) = jmtid @@ -1210,7 +1217,7 @@ end subroutine ice_write_hist !======================================================================= ! Defines a (time-dependent) history var in the history file -! variables have short_name, long_name and units, coordiantes and cell_measures attributes, +! variables have short_name, long_name and units, coordinates and cell_measures attributes, ! and are compressed and chunked for 'hdf5' subroutine ice_hist_field_def(ncid, hfield, lprecision, dimids, ns) @@ -1284,10 +1291,20 @@ subroutine ice_hist_field_def(ncid, hfield, lprecision, dimids, ns) if (hist_avg(ns) .and. .not. write_ic) then if (TRIM(hfield%vname(1:4))/='sig1' & .and.TRIM(hfield%vname(1:4))/='sig2' & - .and.TRIM(hfield%vname(1:9))/='sistreave' & - .and.TRIM(hfield%vname(1:9))/='sistremax' & + .and.TRIM(hfield%vname(1:5))/='trsig' & + .and.TRIM(hfield%vname(1:4))/='divu' & + .and.TRIM(hfield%vname(1:5))/='shear' & + .and.TRIM(hfield%vname(1:4))/='vort' & + .and.TRIM(hfield%vname(1:9))/='frz_onset' & + .and.TRIM(hfield%vname(1:9))/='mlt_onset' & + .and.TRIM(hfield%vname(1:6))/='aisnap' & + .and.TRIM(hfield%vname(1:6))/='hisnap' & + .and.TRIM(hfield%vname(1:8))/='sidivvel' & + .and.TRIM(hfield%vname(1:10))/='sishearvel' & + .and.TRIM(hfield%vname(1:11))/='sistressave' & + .and.TRIM(hfield%vname(1:11))/='sistressmax' & .and.TRIM(hfield%vname(1:4))/='sigP') then - if (hfield%avg_ice_present) then + if (trim(hfield%avg_ice_present) /= 'none') then status = nf90_put_att(ncid,varid,'cell_methods','area: time: mean where sea ice (mask=siconc)') call ice_check_nc(status, subname// ' ERROR: defining cell methods for '//hfield%vname, & file=__FILE__, line=__LINE__) @@ -1309,8 +1326,10 @@ subroutine ice_hist_field_def(ncid, hfield, lprecision, dimids, ns) .or.TRIM(hfield%vname(1:4))=='sig2' & .or.TRIM(hfield%vname(1:4))=='sigP' & .or.TRIM(hfield%vname(1:5))=='trsig' & - .or.TRIM(hfield%vname(1:9))=='sistreave' & - .or.TRIM(hfield%vname(1:9))=='sistremax' & + .or.TRIM(hfield%vname(1:8))=='sidivvel' & + .or.TRIM(hfield%vname(1:10))=='sishearvel' & + .or.TRIM(hfield%vname(1:11))=='sistressave' & + .or.TRIM(hfield%vname(1:11))=='sistressmax' & .or.TRIM(hfield%vname(1:9))=='mlt_onset' & .or.TRIM(hfield%vname(1:9))=='frz_onset' & .or.TRIM(hfield%vname(1:6))=='hisnap' & diff --git a/cicecore/cicedyn/infrastructure/io/io_pio2/ice_history_write.F90 b/cicecore/cicedyn/infrastructure/io/io_pio2/ice_history_write.F90 index f4c6e51db..5c41f0eda 100644 --- a/cicecore/cicedyn/infrastructure/io/io_pio2/ice_history_write.F90 +++ b/cicecore/cicedyn/infrastructure/io/io_pio2/ice_history_write.F90 @@ -268,14 +268,15 @@ subroutine ice_write_hist (ns) endif ! Define coord time_bounds if hist_avg is true - ! bounds inherit attributes if (hist_avg(ns) .and. .not. write_ic) then - time_coord = coord_attributes('time_bounds', 'undefined', 'undefined', 'undefined') + time_coord = coord_attributes('time_bounds', 'time interval bounds', trim(cal_units), 'undefined') dimid2(1) = boundid dimid2(2) = timid call ice_hist_coord_def(File, time_coord, pio_double, dimid2, varid) + call ice_pio_check(pio_put_att(File,varid,'calendar',cal_att), & + subname//' ERROR: defining att calendar: '//cal_att,file=__FILE__,line=__LINE__) endif endif ! histfreq(ns)/='g' @@ -404,15 +405,14 @@ subroutine ice_write_hist (ns) ! bounds fields are required for CF compliance ! dimensions (nx,ny,nverts) - ! bounds inherit attributes - var_nverts(n_lont_bnds) = coord_attributes('lont_bounds','und','und','und') - var_nverts(n_latt_bnds) = coord_attributes('latt_bounds','und','und','und') - var_nverts(n_lonu_bnds) = coord_attributes('lonu_bounds','und','und','und') - var_nverts(n_latu_bnds) = coord_attributes('latu_bounds','und','und','und') - var_nverts(n_lonn_bnds) = coord_attributes('lonn_bounds','und','und','und') - var_nverts(n_latn_bnds) = coord_attributes('latn_bounds','und','und','und') - var_nverts(n_lone_bnds) = coord_attributes('lone_bounds','und','und','und') - var_nverts(n_late_bnds) = coord_attributes('late_bounds','und','und','und') + var_nverts(n_lont_bnds) = coord_attributes('lont_bounds','longitude bounds (T-cell)','degrees_east','und') + var_nverts(n_latt_bnds) = coord_attributes('latt_bounds','latitude bounds (T-cell)','degrees_north','und') + var_nverts(n_lonu_bnds) = coord_attributes('lonu_bounds','longitude bounds (U-cell)','degrees_east','und') + var_nverts(n_latu_bnds) = coord_attributes('latu_bounds','latitude bounds (U-cell)','degrees_north','und') + var_nverts(n_lonn_bnds) = coord_attributes('lonn_bounds','longitude bounds (N-cell)','degrees_east','und') + var_nverts(n_latn_bnds) = coord_attributes('latn_bounds','latitude bounds (N-cell)','degrees_north','und') + var_nverts(n_lone_bnds) = coord_attributes('lone_bounds','longitude bounds (E-cell)','degrees_east','und') + var_nverts(n_late_bnds) = coord_attributes('late_bounds','latitude bounds (E-cell)','degrees_north','und') !----------------------------------------------------------------- ! define attributes for time-invariant variables @@ -467,7 +467,6 @@ subroutine ice_write_hist (ns) enddo ! bounds fields with dimensions (nverts,nx,ny) - ! bounds inherit attributes dimid_nverts(1) = nvertexid dimid_nverts(2) = imtid dimid_nverts(3) = jmtid @@ -1351,7 +1350,7 @@ end subroutine ice_hist_coord_def !======================================================================= ! Defines a (time-dependent) history var in the history file -! variables have short_name, long_name and units, coordiantes and cell_measures attributes, +! variables have short_name, long_name and units, coordinates and cell_measures attributes, ! and are compressed and chunked for 'hdf5' subroutine ice_hist_field_def(File, hfield,lprecision, dimids, ns) @@ -1425,10 +1424,20 @@ subroutine ice_hist_field_def(File, hfield,lprecision, dimids, ns) if (hist_avg(ns) .and. .not. write_ic) then if (TRIM(hfield%vname(1:4))/='sig1' & .and.TRIM(hfield%vname(1:4))/='sig2' & - .and.TRIM(hfield%vname(1:9))/='sistreave' & - .and.TRIM(hfield%vname(1:9))/='sistremax' & + .and.TRIM(hfield%vname(1:5))/='trsig' & + .and.TRIM(hfield%vname(1:4))/='divu' & + .and.TRIM(hfield%vname(1:5))/='shear' & + .and.TRIM(hfield%vname(1:4))/='vort' & + .and.TRIM(hfield%vname(1:9))/='frz_onset' & + .and.TRIM(hfield%vname(1:9))/='mlt_onset' & + .and.TRIM(hfield%vname(1:6))/='aisnap' & + .and.TRIM(hfield%vname(1:6))/='hisnap' & + .and.TRIM(hfield%vname(1:8))/='sidivvel' & + .and.TRIM(hfield%vname(1:10))/='sishearvel' & + .and.TRIM(hfield%vname(1:11))/='sistressave' & + .and.TRIM(hfield%vname(1:11))/='sistressmax' & .and.TRIM(hfield%vname(1:4))/='sigP') then - if (hfield%avg_ice_present) then + if (trim(hfield%avg_ice_present) /= 'none') then call ice_pio_check(pio_put_att(File,varid,'cell_methods', & 'area: time: mean where sea ice (mask=siconc)'), & subname//' ERROR: defining att cell_methods',file=__FILE__,line=__LINE__) @@ -1449,8 +1458,10 @@ subroutine ice_hist_field_def(File, hfield,lprecision, dimids, ns) .or.TRIM(hfield%vname(1:4))=='sig2' & .or.TRIM(hfield%vname(1:4))=='sigP' & .or.TRIM(hfield%vname(1:5))=='trsig' & - .or.TRIM(hfield%vname(1:9))=='sistreave' & - .or.TRIM(hfield%vname(1:9))=='sistremax' & + .or.TRIM(hfield%vname(1:8))=='sidivvel' & + .or.TRIM(hfield%vname(1:10))=='sishearvel' & + .or.TRIM(hfield%vname(1:11))=='sistressave' & + .or.TRIM(hfield%vname(1:11))=='sistressmax' & .or.TRIM(hfield%vname(1:9))=='mlt_onset' & .or.TRIM(hfield%vname(1:9))=='frz_onset' & .or.TRIM(hfield%vname(1:6))=='hisnap' & diff --git a/cicecore/drivers/direct/hadgem3/CICE_RunMod.F90 b/cicecore/drivers/direct/hadgem3/CICE_RunMod.F90 index ca0099680..874b382ea 100644 --- a/cicecore/drivers/direct/hadgem3/CICE_RunMod.F90 +++ b/cicecore/drivers/direct/hadgem3/CICE_RunMod.F90 @@ -358,7 +358,7 @@ subroutine coupling_prep (iblk) fswthru_ai, fhocn, fswthru, scale_factor, snowfrac, & fswthru_vdr, fswthru_vdf, fswthru_idr, fswthru_idf, & swvdr, swidr, swvdf, swidf, Tf, Tair, Qa, strairxT, strairyt, & - fsens, flat, fswabs, flwout, evap, Tref, Qref, & + fsens, flat, fswabs, fsw, fswup, flwout, evap, Tref, Qref, & fsurfn_f, flatn_f, scale_fluxes, frzmlt_init, frzmlt use ice_flux_bgc, only: faero_ocn, flux_bio, flux_bio_ai use ice_grid, only: tmask @@ -507,6 +507,8 @@ subroutine coupling_prep (iblk) fsalt_ai (i,j,iblk) = fsalt (i,j,iblk) fhocn_ai (i,j,iblk) = fhocn (i,j,iblk) fswthru_ai(i,j,iblk) = fswthru(i,j,iblk) + fswup (i,j,iblk) = aice_init(i,j,iblk) & + * fsw (i,j,iblk) - fswabs(i,j,iblk) if (nbtrcr > 0) then do k = 1, nbtrcr diff --git a/cicecore/drivers/direct/nemo_concepts/CICE_RunMod.F90 b/cicecore/drivers/direct/nemo_concepts/CICE_RunMod.F90 index 23eb990a0..0fa89f984 100644 --- a/cicecore/drivers/direct/nemo_concepts/CICE_RunMod.F90 +++ b/cicecore/drivers/direct/nemo_concepts/CICE_RunMod.F90 @@ -358,7 +358,7 @@ subroutine coupling_prep (iblk) fswthru_ai, fhocn, fswthru, scale_factor, snowfrac, & fswthru_vdr, fswthru_vdf, fswthru_idr, fswthru_idf, & swvdr, swidr, swvdf, swidf, Tf, Tair, Qa, strairxT, strairyt, & - fsens, flat, fswabs, flwout, evap, Tref, Qref, & + fsens, flat, fswabs, fsw, fswup, flwout, evap, Tref, Qref, & fsurfn_f, flatn_f, scale_fluxes, frzmlt_init, frzmlt use ice_flux_bgc, only: faero_ocn, flux_bio, flux_bio_ai use ice_grid, only: tmask @@ -507,6 +507,8 @@ subroutine coupling_prep (iblk) fsalt_ai (i,j,iblk) = fsalt (i,j,iblk) fhocn_ai (i,j,iblk) = fhocn (i,j,iblk) fswthru_ai(i,j,iblk) = fswthru(i,j,iblk) + fswup (i,j,iblk) = aice_init(i,j,iblk) & + * fsw (i,j,iblk) - fswabs(i,j,iblk) if (nbtrcr > 0) then do k = 1, nbtrcr diff --git a/cicecore/drivers/mapl/geos/CICE_RunMod.F90 b/cicecore/drivers/mapl/geos/CICE_RunMod.F90 index ca5cf8739..04c7fcc97 100644 --- a/cicecore/drivers/mapl/geos/CICE_RunMod.F90 +++ b/cicecore/drivers/mapl/geos/CICE_RunMod.F90 @@ -370,7 +370,7 @@ subroutine coupling_prep (iblk) fswthru_vdr, fswthru_vdf, fswthru_idr, fswthru_idf, & fswthru_uvrdr, fswthru_uvrdf, fswthru_pardr, fswthru_pardf, & swvdr, swidr, swvdf, swidf, Tf, Tair, Qa, strairxT, strairyT, & - fsens, flat, fswabs, flwout, evap, Tref, Qref, & + fsens, flat, fswabs, fsw, fswup, flwout, evap, Tref, Qref, & scale_fluxes, frzmlt_init, frzmlt, Uref, wind use ice_flux_bgc, only: faero_ocn, fiso_ocn, Qref_iso, fiso_evap, & flux_bio, flux_bio_ai, & @@ -556,6 +556,8 @@ subroutine coupling_prep (iblk) fsalt_ai (i,j,iblk) = fsalt (i,j,iblk) fhocn_ai (i,j,iblk) = fhocn (i,j,iblk) fswthru_ai(i,j,iblk) = fswthru(i,j,iblk) + fswup (i,j,iblk) = aice_init(i,j,iblk) & + * fsw (i,j,iblk) - fswabs(i,j,iblk) if (nbtrcr > 0) then do k = 1, nbtrcr diff --git a/cicecore/drivers/mct/cesm1/CICE_RunMod.F90 b/cicecore/drivers/mct/cesm1/CICE_RunMod.F90 index d22570ae1..f951e762d 100644 --- a/cicecore/drivers/mct/cesm1/CICE_RunMod.F90 +++ b/cicecore/drivers/mct/cesm1/CICE_RunMod.F90 @@ -429,7 +429,7 @@ subroutine coupling_prep (iblk) fswthru_ai, fhocn, scale_factor, snowfrac, & fswthru, fswthru_vdr, fswthru_vdf, fswthru_idr, fswthru_idf, & swvdr, swidr, swvdf, swidf, Tf, Tair, Qa, strairxT, strairyT, & - fsens, flat, fswabs, flwout, evap, Tref, Qref, & + fsens, flat, fswabs, fsw, fswup, flwout, evap, Tref, Qref, & scale_fluxes, frzmlt_init, frzmlt, Uref, wind use ice_flux_bgc, only: faero_ocn, fiso_ocn, Qref_iso, fiso_evap, & flux_bio, flux_bio_ai, & @@ -585,6 +585,8 @@ subroutine coupling_prep (iblk) fsalt_ai (i,j,iblk) = fsalt (i,j,iblk) fhocn_ai (i,j,iblk) = fhocn (i,j,iblk) fswthru_ai(i,j,iblk) = fswthru(i,j,iblk) + fswup (i,j,iblk) = aice_init(i,j,iblk) & + * fsw (i,j,iblk) - fswabs(i,j,iblk) if (nbtrcr > 0) then do k = 1, nbtrcr diff --git a/cicecore/drivers/nuopc/cmeps/CICE_RunMod.F90 b/cicecore/drivers/nuopc/cmeps/CICE_RunMod.F90 index 876f10512..9d487ea60 100644 --- a/cicecore/drivers/nuopc/cmeps/CICE_RunMod.F90 +++ b/cicecore/drivers/nuopc/cmeps/CICE_RunMod.F90 @@ -420,7 +420,7 @@ subroutine coupling_prep (iblk) fswthru_ai, fhocn, fswthru, scale_factor, snowfrac, & fswthru_vdr, fswthru_vdf, fswthru_idr, fswthru_idf, & swvdr, swidr, swvdf, swidf, Tf, Tair, Qa, strairxT, strairyT, & - fsens, flat, fswabs, flwout, evap, Tref, Qref, & + fsens, flat, fswabs, fsw, fswup, flwout, evap, Tref, Qref, & scale_fluxes, frzmlt_init, frzmlt, Uref, wind use ice_flux_bgc, only: faero_ocn, fiso_ocn, Qref_iso, fiso_evap, & flux_bio, flux_bio_ai, fnit, fsil, famm, fdmsp, fdms, fhum, & @@ -577,6 +577,8 @@ subroutine coupling_prep (iblk) fsalt_ai (i,j,iblk) = fsalt (i,j,iblk) fhocn_ai (i,j,iblk) = fhocn (i,j,iblk) fswthru_ai(i,j,iblk) = fswthru(i,j,iblk) + fswup (i,j,iblk) = aice_init(i,j,iblk) & + * fsw (i,j,iblk) - fswabs(i,j,iblk) if (nbtrcr > 0) then do k = 1, nbtrcr diff --git a/cicecore/drivers/nuopc/cmeps/ice_import_export.F90 b/cicecore/drivers/nuopc/cmeps/ice_import_export.F90 index 412b2cce5..91236c11e 100644 --- a/cicecore/drivers/nuopc/cmeps/ice_import_export.F90 +++ b/cicecore/drivers/nuopc/cmeps/ice_import_export.F90 @@ -1073,6 +1073,7 @@ subroutine ice_export( exportState, rc ) call state_setexport(exportState, 'Si_imask', input=ocn_gridcell_frac, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return else + tempfld(:,:,:) = c0 do iblk = 1, nblocks this_block = get_block(blocks_ice(iblk),iblk) ilo = this_block%ilo @@ -1134,6 +1135,7 @@ subroutine ice_export( exportState, rc ) if (ChkErr(rc,__LINE__,u_FILE_u)) return ! Snow height + tempfld(:,:,:) = c0 do iblk = 1, nblocks this_block = get_block(blocks_ice(iblk),iblk) ilo = this_block%ilo @@ -1191,11 +1193,29 @@ subroutine ice_export( exportState, rc ) areacor=mod2med_areacor, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return + ! Fix outgoing longwave if aice_init = 0, but aice > 0. + tempfld(:,:,:) = flwout(:,:,:) + do iblk = 1, nblocks + this_block = get_block(blocks_ice(iblk),iblk) + ilo = this_block%ilo + ihi = this_block%ihi + jlo = this_block%jlo + jhi = this_block%jhi + do j = jlo, jhi + do i = ilo, ihi + if ( tmask(i,j,iblk) .and. ailohi(i,j,iblk) > c0 .and. flwout(i,j,iblk) > -puny) then + tempfld(i,j,iblk) = (-stefan_boltzmann *(Tf(i,j) + Tffresh)**4) / ailohi(i,j,iblk) + end if + end do + end do + end do ! longwave outgoing (upward), average over ice fraction only - call state_setexport(exportState, 'Faii_lwup' , input=flwout, lmask=tmask, ifrac=ailohi, & + call state_setexport(exportState, 'Faii_lwup' , input=tempfld, lmask=tmask, ifrac=ailohi, & areacor=mod2med_areacor, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return + deallocate(tempfld) + ! Evaporative water flux (kg/m^2/s) call state_setexport(exportState, 'Faii_evap' , input=evap, lmask=tmask, ifrac=ailohi, & areacor=mod2med_areacor, rc=rc) diff --git a/cicecore/drivers/nuopc/dmi/CICE_RunMod.F90 b/cicecore/drivers/nuopc/dmi/CICE_RunMod.F90 index 5f8fb52bc..2de15f3a4 100644 --- a/cicecore/drivers/nuopc/dmi/CICE_RunMod.F90 +++ b/cicecore/drivers/nuopc/dmi/CICE_RunMod.F90 @@ -442,14 +442,13 @@ subroutine coupling_prep (iblk) fswthru_ai, fhocn, scale_factor, snowfrac, & fswthru, fswthru_vdr, fswthru_vdf, fswthru_idr, fswthru_idf, & swvdr, swidr, swvdf, swidf, Tf, Tair, Qa, strairxT, strairyT, & - fsens, flat, fswabs, flwout, evap, Tref, Qref, & + fsens, flat, fswabs, fsw, fswup, flwout, evap, Tref, Qref, & scale_fluxes, frzmlt_init, frzmlt use ice_flux_bgc, only: faero_ocn, fiso_ocn, Qref_iso, fiso_evap, & flux_bio, flux_bio_ai use ice_grid, only: tmask - use ice_state, only: aicen, aice + use ice_state, only: aicen, aice, aice_init #ifdef CICE_IN_NEMO - use ice_state, only: aice_init use ice_flux, only: flatn_f, fsurfn_f #endif use ice_step_mod, only: ocean_mixed_layer @@ -596,6 +595,8 @@ subroutine coupling_prep (iblk) fsalt_ai (i,j,iblk) = fsalt (i,j,iblk) fhocn_ai (i,j,iblk) = fhocn (i,j,iblk) fswthru_ai(i,j,iblk) = fswthru(i,j,iblk) + fswup (i,j,iblk) = aice_init(i,j,iblk) & + * fsw (i,j,iblk) - fswabs(i,j,iblk) if (nbtrcr > 0) then do k = 1, nbtrcr diff --git a/cicecore/drivers/standalone/cice/CICE_RunMod.F90 b/cicecore/drivers/standalone/cice/CICE_RunMod.F90 index 53476776b..335fc1e50 100644 --- a/cicecore/drivers/standalone/cice/CICE_RunMod.F90 +++ b/cicecore/drivers/standalone/cice/CICE_RunMod.F90 @@ -435,14 +435,13 @@ subroutine coupling_prep (iblk) fswthru_ai, fhocn, scale_factor, snowfrac, & fswthru, fswthru_vdr, fswthru_vdf, fswthru_idr, fswthru_idf, & swvdr, swidr, swvdf, swidf, Tf, Tair, Qa, strairxT, strairyT, & - fsens, flat, fswabs, flwout, evap, Tref, Qref, & + fsens, flat, fswabs, fsw, fswup, flwout, evap, Tref, Qref, & scale_fluxes, frzmlt_init, frzmlt use ice_flux_bgc, only: faero_ocn, fiso_ocn, Qref_iso, fiso_evap, & flux_bio, flux_bio_ai use ice_grid, only: tmask - use ice_state, only: aicen, aice + use ice_state, only: aicen, aice, aice_init #ifdef CICE_IN_NEMO - use ice_state, only: aice_init use ice_flux, only: flatn_f, fsurfn_f #endif use ice_step_mod, only: ocean_mixed_layer @@ -585,10 +584,18 @@ subroutine coupling_prep (iblk) alidf_ai (i,j,iblk) = alidf (i,j,iblk) alvdr_ai (i,j,iblk) = alvdr (i,j,iblk) alidr_ai (i,j,iblk) = alidr (i,j,iblk) + + + !---------------------------------------------------------------- + ! Store fluxes before scaling by aice + !---------------------------------------------------------------- + fresh_ai (i,j,iblk) = fresh (i,j,iblk) fsalt_ai (i,j,iblk) = fsalt (i,j,iblk) fhocn_ai (i,j,iblk) = fhocn (i,j,iblk) fswthru_ai(i,j,iblk) = fswthru(i,j,iblk) + fswup (i,j,iblk) = aice_init(i,j,iblk) & + * fsw (i,j,iblk) - fswabs(i,j,iblk) if (nbtrcr > 0) then do k = 1, nbtrcr diff --git a/cicecore/drivers/unittest/opticep/CICE_RunMod.F90 b/cicecore/drivers/unittest/opticep/CICE_RunMod.F90 index 53476776b..4ee0e2bc7 100644 --- a/cicecore/drivers/unittest/opticep/CICE_RunMod.F90 +++ b/cicecore/drivers/unittest/opticep/CICE_RunMod.F90 @@ -435,14 +435,13 @@ subroutine coupling_prep (iblk) fswthru_ai, fhocn, scale_factor, snowfrac, & fswthru, fswthru_vdr, fswthru_vdf, fswthru_idr, fswthru_idf, & swvdr, swidr, swvdf, swidf, Tf, Tair, Qa, strairxT, strairyT, & - fsens, flat, fswabs, flwout, evap, Tref, Qref, & + fsens, flat, fswabs, fsw, fswup, flwout, evap, Tref, Qref, & scale_fluxes, frzmlt_init, frzmlt use ice_flux_bgc, only: faero_ocn, fiso_ocn, Qref_iso, fiso_evap, & flux_bio, flux_bio_ai use ice_grid, only: tmask - use ice_state, only: aicen, aice + use ice_state, only: aicen, aice, aice_init #ifdef CICE_IN_NEMO - use ice_state, only: aice_init use ice_flux, only: flatn_f, fsurfn_f #endif use ice_step_mod, only: ocean_mixed_layer @@ -589,6 +588,8 @@ subroutine coupling_prep (iblk) fsalt_ai (i,j,iblk) = fsalt (i,j,iblk) fhocn_ai (i,j,iblk) = fhocn (i,j,iblk) fswthru_ai(i,j,iblk) = fswthru(i,j,iblk) + fswup (i,j,iblk) = aice_init(i,j,iblk) & + * fsw (i,j,iblk) - fswabs(i,j,iblk) if (nbtrcr > 0) then do k = 1, nbtrcr diff --git a/cicecore/shared/ice_calendar.F90 b/cicecore/shared/ice_calendar.F90 index 829e78218..8f0e793aa 100644 --- a/cicecore/shared/ice_calendar.F90 +++ b/cicecore/shared/ice_calendar.F90 @@ -443,6 +443,11 @@ subroutine calendar() if (mod(elapsed_days,histfreq_n(ns))==0) & write_history(ns) = .true. endif + case ("n", "N") + if (new_day .and. histfreq_n(ns)/=0) then + if (mday == histfreq_n(ns)) & + write_history(ns) = .true. + endif case ("h", "H") if (new_hour .and. histfreq_n(ns)/=0) then if (mod(elapsed_hours,histfreq_n(ns))==0) & diff --git a/configuration/scripts/ice_in b/configuration/scripts/ice_in index 04f7c0d41..5c2bb87ee 100644 --- a/configuration/scripts/ice_in +++ b/configuration/scripts/ice_in @@ -513,12 +513,15 @@ f_VGRDa = .true. f_bounds = .false. f_aice = 'm' + f_aice_init = 'x' f_hi = 'm' f_hs = 'm' f_Tsfc = 'm' f_sice = 'm' f_uvel = 'm' f_vvel = 'm' + f_icedir = 'x' + f_icespd = 'x' f_uatm = 'm' f_vatm = 'm' f_fswdn = 'm' @@ -628,7 +631,78 @@ f_fmelttn_ai = 'x' f_flatn_ai = 'x' f_fsensn_ai = 'x' - f_CMIP = 'x' + f_siage = 'x' + f_siconc = 'x' + f_sifb = 'x' + f_siflcondbot = 'x' + f_siflcondtop = 'x' + f_sifllattop = 'x' + f_sifllwdtop = 'x' + f_sifllwutop = 'x' + f_siflsensbot = 'x' + f_siflsenstop = 'x' + f_siflswdtop = 'x' + f_siflswutop = 'x' + f_sihc = 'x' + f_siitdconc = 'x' + f_siitdsnconc = 'x' + f_siitdsnthick = 'x' + f_siitdthick = 'x' + f_sisali = 'x' + f_sisaltmass = 'x' + f_sisnhc = 'x' + f_sisnthick = 'x' + f_sitempbot = 'x' + f_sitempsnic = 'x' + f_sitemptop = 'x' + f_sithick = 'x' + f_sitimefrac = 'x' + f_siu = 'x' + f_siv = 'x' + f_sicompstren = 'x' + f_sidconcdyn = 'x' + f_sidconcth = 'x' + f_sidivvel = 'x' + f_sidmassdyn = 'x' + f_sidmassevapsubl = 'x' + f_sidmassgrowthbot = 'x' + f_sidmassgrowthsi = 'x' + f_sidmassgrowthwat = 'x' + f_sidmassmeltbot = 'x' + f_sidmassmeltlat = 'x' + f_sidmassmelttop = 'x' + f_sidmassth = 'x' + f_sidmasstranx = 'x' + f_sidmasstrany = 'x' + f_sidragbot = 'x' + f_sidragtop = 'x' + f_siflfwbot = 'x' + f_siflfwdrain = 'x' + f_siflsaltbot = 'x' + f_siforcecoriolx = 'x' + f_siforcecorioly = 'x' + f_siforceintstrx = 'x' + f_siforceintstry = 'x' + f_siforcetiltx = 'x' + f_siforcetilty = 'x' + f_simass = 'x' + f_sipr = 'x' + f_sishearvel = 'x' + f_sisnconc = 'x' + f_sisndmassdyn = 'x' + f_sisndmassmelt = 'x' + f_sisndmasssi = 'x' + f_sisndmasssnf = 'x' + f_sisndmasssubl = 'x' + f_sisnmass = 'x' + f_sispeed = 'x' + f_sistressave = 'x' + f_sistressmax = 'x' + f_sistrxdtop = 'x' + f_sistrydtop = 'x' + f_sistrxubot = 'x' + f_sistryubot = 'x' + f_sivol = 'x' / &icefields_mechred_nml @@ -651,6 +725,8 @@ f_vredistn = 'x' f_araftn = 'x' f_vraftn = 'x' + f_sirdgconc = 'x' + f_sirdgthick = 'x' / &icefields_pond_nml @@ -677,6 +753,10 @@ f_hpond_ai = 'm' f_ipond_ai = 'm' f_apeff_ai = 'm' + f_simpconc = 'x' + f_simpeffconc = 'x' + f_simprefrozen = 'x' + f_simpthick = 'x' / &icefields_snow_nml @@ -692,6 +772,7 @@ f_rsnw = 'm' f_meltsliq = 'm' f_fsloss = 'm' + f_sisndmasswind = 'x' / &icefields_bgc_nml diff --git a/configuration/scripts/options/set_nml.cmip b/configuration/scripts/options/set_nml.cmip new file mode 100644 index 000000000..80d30a755 --- /dev/null +++ b/configuration/scripts/options/set_nml.cmip @@ -0,0 +1,143 @@ + histfreq = 'm','d','n','x','x' + histfreq_n = 1,1,15,1,1 + hist_avg = .true.,.true.,.false.,.false,.false. + f_aice = 'md' + f_aice_init = 'md' + f_aicen = 'md' + f_siage = 'md' + f_siconc = 'md' + f_sifb = 'md' + f_siflcondbot = 'md' + f_siflcondtop = 'md' + f_sifllattop = 'md' + f_sifllwdtop = 'md' + f_sifllwutop = 'md' + f_siflsensbot = 'md' + f_siflsenstop = 'md' + f_siflswdtop = 'md' + f_siflswutop = 'md' + f_sihc = 'md' + f_siitdconc = 'md' + f_siitdsnconc = 'md' + f_siitdsnthick = 'md' + f_siitdthick = 'md' + f_simpconc = 'md' + f_simpeffconc = 'md' + f_simprefrozen = 'md' + f_simpthick = 'md' + f_sirdgconc = 'md' + f_sirdgthick = 'md' + f_sisali = 'md' + f_sisaltmass = 'md' + f_sisnhc = 'md' + f_sisnthick = 'md' + f_sitempbot = 'md' + f_sitempsnic = 'md' + f_sitemptop = 'md' + f_sithick = 'md' + f_sitimefrac = 'md' + f_siu = 'md' + f_siv = 'md' + f_sicompstren = 'm' + f_sidconcdyn = 'm' + f_sidconcth = 'm' + f_sidivvel = 'n' + f_sidmassdyn = 'm' + f_sidmassevapsubl = 'm' + f_sidmassgrowthbot = 'm' + f_sidmassgrowthsi = 'm' + f_sidmassgrowthwat = 'm' + f_sidmassmeltbot = 'm' + f_sidmassmeltlat = 'm' + f_sidmassmelttop = 'm' + f_sidmassth = 'm' + f_sidmasstranx = 'm' + f_sidmasstrany = 'm' + f_sidragbot = 'm' + f_sidragtop = 'm' + f_siflfwbot = 'm' + f_siflfwdrain = 'm' + f_siflsaltbot = 'm' + f_siforcecoriolx = 'm' + f_siforcecorioly = 'm' + f_siforceintstrx = 'm' + f_siforceintstry = 'm' + f_siforcetiltx = 'm' + f_siforcetilty = 'm' + f_simass = 'm' + f_sipr = 'm' + f_sishearvel = 'n' + f_sisnconc = 'm' + f_sisndmassdyn = 'm' + f_sisndmassmelt = 'm' + f_sisndmasssi = 'm' + f_sisndmasssnf = 'm' + f_sisndmasssubl = 'm' + f_sisndmasswind = 'm' + f_sisnmass = 'm' + f_sispeed = 'm' + f_sistressave = 'n' + f_sistressmax = 'n' + f_sistrxdtop = 'm' + f_sistrydtop = 'm' + f_sistrxubot = 'm' + f_sistryubot = 'm' + f_sivol = 'm' + f_icepresent = 'x' + f_hi = 'x' + f_hs = 'x' + f_Tsfc = 'x' + f_iage = 'x' + f_fswdn = 'x' + f_fswup = 'x' + f_fswthru = 'x' + f_flwdn = 'x' + f_flwup = 'x' + f_fsens = 'x' + f_flat = 'x' + f_fhocn = 'x' + f_rain = 'x' + f_snow = 'x' + f_evap = 'x' + f_fsalt = 'x' + f_fresh = 'x' + f_meltl = 'x' + f_melts = 'x' + f_meltt = 'x' + f_meltb = 'x' + f_strairx = 'x' + f_strairy = 'x' + f_strocnx = 'x' + f_strocny = 'x' + f_strtltx = 'x' + f_strtlty = 'x' + f_strintx = 'x' + f_strinty = 'x' + f_strcorx = 'x' + f_strcory = 'x' + f_strength = 'x' + f_daidtt = 'x' + f_daidtd = 'x' + f_dvidtt = 'x' + f_dvidtd = 'x' + f_congel = 'x' + f_frazil = 'x' + f_snoice = 'x' + f_vicen = 'x' + f_vsnon = 'x' + f_divu = 'x' + f_shear = 'x' + f_snowfrac = 'x' + f_snowfracn = 'x' + f_uvel = 'x' + f_vvel = 'x' + f_icespd = 'x' + f_apeff = 'x' + f_apond = 'md' + f_hpond = 'x' + f_ipond = 'x' + f_fsloss = 'x' + f_alvl = 'md' + f_vlvl = 'md' + f_ardg = 'md' + f_vrdg = 'md' diff --git a/configuration/scripts/options/set_nml.histall b/configuration/scripts/options/set_nml.histall index 2b9810bdd..5423e0216 100644 --- a/configuration/scripts/options/set_nml.histall +++ b/configuration/scripts/options/set_nml.histall @@ -21,7 +21,6 @@ f_VGRDb = .true. f_VGRDa = .true. f_bounds = .true. - f_CMIP = 'm' f_aice = 'md1h' f_hi = 'h1dm' f_hs = 'd1m' @@ -29,6 +28,8 @@ f_sice = 'md' f_uvel = 'md' f_vvel = 'dm' + f_icespd = 'md' + f_icedir = 'md' f_uatm = 'dm' f_vatm = 'dm' f_fswdn = 'dm' @@ -237,3 +238,83 @@ f_aice_ww = 'md' f_diam_ww = 'md' f_hice_ww = 'md' + f_aice_init = 'md' + f_siage = 'md' + f_siconc = 'md' + f_sifb = 'md' + f_siflcondbot = 'md' + f_siflcondtop = 'md' + f_sifllattop = 'md' + f_sifllwdtop = 'md' + f_sifllwutop = 'md' + f_siflsensbot = 'md' + f_siflsenstop = 'md' + f_siflswdtop = 'md' + f_siflswutop = 'md' + f_sihc = 'md' + f_siitdconc = 'md' + f_siitdsnconc = 'md' + f_siitdsnthick = 'md' + f_siitdthick = 'md' + f_simpconc = 'md' + f_simpeffconc = 'md' + f_simprefrozen = 'md' + f_simpthick = 'md' + f_sirdgconc = 'md' + f_sirdgthick = 'md' + f_sisali = 'md' + f_sisaltmass = 'md' + f_sisnhc = 'md' + f_sisnthick = 'md' + f_sitempbot = 'md' + f_sitempsnic = 'md' + f_sitemptop = 'md' + f_sithick = 'md' + f_sitimefrac = 'md' + f_siu = 'md' + f_siv = 'md' + f_sicompstren = 'md' + f_sidconcdyn = 'md' + f_sidconcth = 'md' + f_sidivvel = 'md' + f_sidmassdyn = 'md' + f_sidmassevapsubl = 'md' + f_sidmassgrowthbot = 'md' + f_sidmassgrowthsi = 'md' + f_sidmassgrowthwat = 'md' + f_sidmassmeltbot = 'md' + f_sidmassmeltlat = 'md' + f_sidmassmelttop = 'md' + f_sidmassth = 'md' + f_sidmasstranx = 'md' + f_sidmasstrany = 'md' + f_sidragbot = 'md' + f_sidragtop = 'md' + f_siflfwbot = 'md' + f_siflfwdrain = 'md' + f_siflsaltbot = 'md' + f_siforcecoriolx = 'md' + f_siforcecorioly = 'md' + f_siforceintstrx = 'md' + f_siforceintstry = 'md' + f_siforcetiltx = 'md' + f_siforcetilty = 'md' + f_simass = 'md' + f_sipr = 'md' + f_sishearvel = 'md' + f_sisnconc = 'md' + f_sisndmassdyn = 'md' + f_sisndmassmelt = 'md' + f_sisndmasssi = 'md' + f_sisndmasssnf = 'md' + f_sisndmasssubl = 'md' + f_sisndmasswind = 'md' + f_sisnmass = 'md' + f_sispeed = 'md' + f_sistressave = 'md' + f_sistressmax = 'md' + f_sistrxdtop = 'md' + f_sistrydtop = 'md' + f_sistrxubot = 'md' + f_sistryubot = 'md' + f_sivol = 'md' diff --git a/configuration/scripts/options/set_nml.histdbg b/configuration/scripts/options/set_nml.histdbg index a70e734e5..23a7685c7 100644 --- a/configuration/scripts/options/set_nml.histdbg +++ b/configuration/scripts/options/set_nml.histdbg @@ -20,7 +20,6 @@ f_VGRDb = .true. f_VGRDa = .true. f_bounds = .true. - f_CMIP = 'm' f_aice = 'md1h' f_hi = 'h1dm' f_hs = 'd1m' diff --git a/configuration/scripts/tests/io_suite.ts b/configuration/scripts/tests/io_suite.ts index 71bcd00a5..02e9e015e 100644 --- a/configuration/scripts/tests/io_suite.ts +++ b/configuration/scripts/tests/io_suite.ts @@ -68,3 +68,4 @@ restart gx3 8x4 isotope,histall,iopio2,iohdf5,precision8 restart gx3 12x2 fsd12,histall,iopio2,iocdf1,precision8 restart gx3 16x2 debug,histall,iopio2,iocdf2,histinst,precision8 +restart gx3 12x2 cmip,ionetcdf,iocdf2 diff --git a/doc/source/user_guide/ug_case_settings.rst b/doc/source/user_guide/ug_case_settings.rst index 486dfdfc1..2f00fed85 100644 --- a/doc/source/user_guide/ug_case_settings.rst +++ b/doc/source/user_guide/ug_case_settings.rst @@ -189,12 +189,13 @@ setup_nml "", "``zero``", "restart output frequency relative to year-month-day of 0000-01-01", "" "``dumpfreq_n``", "integer array", "write restart frequency with ``dumpfreq``", "1,1,1,1,1" "``dump_last``", "logical", "write restart on last time step of simulation", "``.false.``" - "``histfreq``", "``d``", "write history every ``histfreq_n`` days", "'1','h','d','m','y'" + "``histfreq``", "``d``", "write history every ``histfreq_n`` days", "'1','h','d','m','y','n'" "", "``h``", "write history every ``histfreq_n`` hours", "" "", "``m``", "write history every ``histfreq_n`` months", "" "", "``x``", "unused frequency stream (not written)", "" "", "``y``", "write history every ``histfreq_n`` years", "" "", "``1``", "write history every ``histfreq_n`` time step", "" + "", "``n``", "write history on day ``histfreq_n``", "" "``histfreq_base``", "``init``", "history output frequency relative to year_init, month_init, day_init", "'zero','zero','zero','zero','zero'" "", "``zero``", "history output frequency relative to year-month-day of 0000-01-01", "" "``histfreq_n``", "integer array", "frequency history output is written with ``histfreq``", "1,1,1,1,1" @@ -948,6 +949,7 @@ source code for a full list of supported output fields. "", "``x``", "do not write var to history", "" "", "``y``", "write field var every ``histfreq_n`` years", "" "", "``1``", "write field var every time step", "" + "", "``n``", "write field var on day ``histfreq_n`` instantaneously", "" "", "``md``", "*e.g.,* write both monthly and daily files", "" "``f__ai``", "``d``", "write field cell average var every ``histfreq_n`` days", "" "", "``h``", "write field cell average var every ``histfreq_n`` hours", "" diff --git a/doc/source/user_guide/ug_implementation.rst b/doc/source/user_guide/ug_implementation.rst index 17b1f618e..a79e3bc1e 100644 --- a/doc/source/user_guide/ug_implementation.rst +++ b/doc/source/user_guide/ug_implementation.rst @@ -1296,8 +1296,8 @@ collected in their own history modules (**ice_history_bgc.F90**, **ice_history_drag.F90**, **ice_history_mechred.F90**, **ice_history_pond.F90**). -The history modules allow output at different frequencies. Five output -options (``1``, ``h``, ``d``, ``m``, ``y``) are available simultaneously for ``histfreq`` +The history modules allow output at different frequencies. Six output +options (``1``, ``h``, ``d``, ``m``, ``y``, ``n``) are available simultaneously for ``histfreq`` during a run, and each stream must have a unique value for ``histfreq``. In other words, ``d`` cannot be used by two different streams. Each stream has an associated frequency set by ``histfreq_n``. The frequency is @@ -1396,17 +1396,26 @@ subroutine **define_hist_field**. ``cona`` and ``conb`` are multiplicative and terms respectively that are hardwired into the source code to convert model units to history units. -Beginning with CICE v6, history variables requested by the Sea Ice Model Intercomparison -Project (SIMIP) :cite:`Notz16` have been added as possible history output variables (e.g. -``f_sithick``, ``f_sidmassgrowthbottom``, etc.). The lists of -`monthly `_ and -`daily `_ -requested SIMIP variables provide the names of possible history fields in CICE. -However, each of the additional variables can be output at any temporal frequency -specified in the **icefields_nml** section of **ice_in** as detailed above. -Additionally, a new history output variable, ``f_CMIP``, has been added. When ``f_CMIP`` -is added to the **icefields_nml** section of **ice_in** then all SIMIP variables -will be turned on for output at the frequency specified by ``f_CMIP``. +Beginning with CICE v6, history variables requested by the Sea Ice Model Intercomparison +Project (SIMIP) :cite:`Notz16` are available as history output variables +(e.g. ``f_sithick``, ``f_sidmassgrowthbottom``, etc.). The lists of +`monthly `_ and +`daily `_ +requested SIMIP variables provide their history field names in CICE. +These variables have been updated for the +`CMIP7 data request `_. + +The ``f_CMIP`` flag has been removed. This is now a ``set_nml.cmip`` namelist option +which can be invoked with the ``-s cmip`` option during cice.setup. This optional +namelist setting will turn on the CMIP data request and turn off CICE duplicates of +SIMIP variables. However, these can be changed by the user in their case ``ice_in`` file. +Note that all SIMIP variables have been updated to correspond to the new +`CMIP7 data request `_. + +Note that some SIMIP variables require division by ice or sub-ice areas, which can be extremely +small and cause the output variables to appear unphysically large. Please interpret these +quantities (such as ``sithick``) very carefully. A future release will have an option to mask +these regions. It may also be helpful for debugging to increase the precision of the history file output from 4 bytes to 8 bytes. This is changed through the ``history_precision`` From 29f63e5f9a868795493739c3e2820474b375d6d6 Mon Sep 17 00:00:00 2001 From: Tony Craig Date: Thu, 22 Jan 2026 11:35:24 -0800 Subject: [PATCH 18/21] Add history restart capability (#1069) Add history restart to netcdf and pio IO options. Binary was not included due to the complexity of having to track history fields in binary files. History restart files are written automatically for history streams that are averaged and when a restart is written during the middle of a history accumulation period. There is one history restart file per history stream. File are written in the restart directory using the history name, an appended "_r[histfreq]", and the model date. An ice_read_hist subroutine was added to the ice_history_write.F90 file. For binary, calling this returns with a warning message that history restarts are not implemented. When history restarts are read, the model will only read files and fields that are found and continue with the accumulator initialized to zero for fields that are not found. For production runs, this should work fine. If a user modifies the history streams in the middle or a run, then an assessment should be made of which fields are valid on the first restart run. The history restart files are basically history files, written at double precision, writing the accumulated fields. In addition, some additional fields are written including time_beg, avgct, albcnt, and snwcnt which represent accumulation counters for time average history output. A new histall10d set_nml option was added that turns on 3 averaged history streams and all history fields. When used in a restart test, the scripts will verify bit-for-bit history files and history restart files across the restart. Several tests were added to the io_suite to include formal testing of bit-for-bit history restarts. Two fields, mlt_onset and frz_onset and not turned on with histall10d because they do not restart properly and they are unable to restart bit-for-bit on the history file, see #1068. Several history fields have a bug in them and have been written out incorrectly, and these bugs were fixed. The bug in these cases was that the fields were accumulated during the timestep across categories but were not zeroed out at the start of the timestep. As a result, those fields were accumulating over the entire run incorrectly. The fields that had to be zeroed out were evaps and evaps plus upNO, upNH, bTiz, bphi, iDi, and iki associated with bgc. The bit-for-bit history restart test discovered these errors. Add a new namelist, write_histrest, to turn off history restart writing. The default is that history restarts are on. Update set_nml.cmip to fix an error in f_apond_ai setting. --- cicecore/cicedyn/analysis/ice_history.F90 | 26 +- cicecore/cicedyn/analysis/ice_history_bgc.F90 | 8 +- .../cicedyn/analysis/ice_history_shared.F90 | 50 +- cicecore/cicedyn/general/ice_init.F90 | 7 +- .../io/io_binary/ice_history_write.F90 | 28 +- .../io/io_netcdf/ice_history_write.F90 | 526 ++++++++++++++++- .../io/io_pio2/ice_history_write.F90 | 539 +++++++++++++++++- .../drivers/direct/hadgem3/CICE_InitMod.F90 | 2 + .../direct/nemo_concepts/CICE_InitMod.F90 | 2 + cicecore/drivers/mapl/geos/CICE_InitMod.F90 | 2 + cicecore/drivers/mct/cesm1/CICE_InitMod.F90 | 2 + cicecore/drivers/mct/cesm1/ice_comp_esmf.F90 | 2 + cicecore/drivers/mct/cesm1/ice_comp_mct.F90 | 2 + .../drivers/nuopc/cmeps/ice_comp_nuopc.F90 | 2 + cicecore/drivers/nuopc/dmi/CICE_InitMod.F90 | 2 + .../drivers/standalone/cice/CICE_InitMod.F90 | 2 + .../unittest/gridavgchk/CICE_InitMod.F90 | 2 + .../drivers/unittest/halochk/CICE_InitMod.F90 | 2 + .../drivers/unittest/opticep/CICE_InitMod.F90 | 2 + .../drivers/unittest/sumchk/CICE_InitMod.F90 | 2 + cicecore/shared/ice_calendar.F90 | 1 + configuration/scripts/ice_in | 1 + .../scripts/machines/env.derecho_cray | 1 + .../scripts/machines/env.derecho_gnu | 1 + .../scripts/machines/env.derecho_intel | 1 + .../scripts/machines/env.derecho_intelclassic | 1 + .../scripts/machines/env.derecho_inteloneapi | 1 + .../scripts/machines/env.derecho_nvhpc | 1 + configuration/scripts/options/set_nml.cmip | 1 + configuration/scripts/options/set_nml.histall | 12 + .../scripts/options/set_nml.histall10d | 334 +++++++++++ configuration/scripts/tests/comparebfb.csh | 14 +- configuration/scripts/tests/io_suite.ts | 9 + .../scripts/tests/test_restart.script | 54 +- .../scripts/tests/test_restart2.script | 25 +- doc/source/cice_index.rst | 2 + doc/source/user_guide/ug_case_settings.rst | 1 + doc/source/user_guide/ug_implementation.rst | 33 +- doc/source/user_guide/ug_testing.rst | 2 +- 39 files changed, 1611 insertions(+), 94 deletions(-) create mode 100644 configuration/scripts/options/set_nml.histall10d diff --git a/cicecore/cicedyn/analysis/ice_history.F90 b/cicecore/cicedyn/analysis/ice_history.F90 index 72939f31a..3d5f47312 100644 --- a/cicecore/cicedyn/analysis/ice_history.F90 +++ b/cicecore/cicedyn/analysis/ice_history.F90 @@ -2204,9 +2204,9 @@ subroutine accum_hist (dt) use ice_domain, only: blocks_ice, nblocks use ice_domain_size, only: nfsd use ice_grid, only: tmask, lmask_n, lmask_s, dxU, dyU, grid_ice - use ice_calendar, only: new_year, write_history, & + use ice_calendar, only: new_year, write_history, write_restart, & write_ic, timesecs, histfreq, nstreams, mmonth, & - new_month + new_month, write_histrest use ice_dyn_eap, only: a11, a12, e11, e12, e22, s11, s12, s22, & yieldstress11, yieldstress12, yieldstress22 use ice_dyn_shared, only: kdyn, principal_stress @@ -4037,6 +4037,28 @@ subroutine accum_hist (dt) enddo ! iblk !$OMP END PARALLEL DO + !--------------------------------------------------------------- + ! write history restarts + !--------------------------------------------------------------- + + if (write_histrest .and. write_restart == 1) then + ! turn on histrest features + write_histrest_now = .true. + + ! write history restarts + call ice_timer_start(timer_readwrite) ! reading/writing + do ns = 1, nstrm + ! only write avg history file when something has accumulated + if (hist_avg(ns) .and. avgct(ns)>0) then + call ice_write_hist (ns) + endif + enddo + call ice_timer_stop(timer_readwrite) ! reading/writing + + ! turn off histrest features + write_histrest_now = .false. + endif + end subroutine accum_hist !======================================================================= diff --git a/cicecore/cicedyn/analysis/ice_history_bgc.F90 b/cicecore/cicedyn/analysis/ice_history_bgc.F90 index 7c87c1f70..85b8c4821 100644 --- a/cicecore/cicedyn/analysis/ice_history_bgc.F90 +++ b/cicecore/cicedyn/analysis/ice_history_bgc.F90 @@ -3398,7 +3398,7 @@ subroutine init_history_bgc use ice_arrays_column, only: PP_net, grow_net, hbri, & ice_bio_net, snow_bio_net, fbio_snoice, fbio_atmice, & - zfswin + upNO, upNH, bTiz, bphi, zfswin, iDi, iki use ice_flux_bgc, only: flux_bio, flux_bio_ai, fnit, fsil, & famm, fdmsp, fdms, fhum, fdust, falgalN, fdoc, fdic, & fdon, ffep, ffed @@ -3407,6 +3407,8 @@ subroutine init_history_bgc PP_net (:,:,:) = c0 grow_net (:,:,:) = c0 + upNO (:,:,:) = c0 + upNH (:,:,:) = c0 hbri (:,:,:) = c0 flux_bio (:,:,:,:) = c0 flux_bio_ai (:,:,:,:) = c0 @@ -3414,7 +3416,11 @@ subroutine init_history_bgc snow_bio_net(:,:,:,:) = c0 fbio_snoice (:,:,:,:) = c0 fbio_atmice (:,:,:,:) = c0 + bTiz (:,:,:,:,:) = c0 + bphi (:,:,:,:,:) = c0 zfswin (:,:,:,:,:) = c0 + iDi (:,:,:,:,:) = c0 + iki (:,:,:,:,:) = c0 fnit (:,:,:) = c0 fsil (:,:,:) = c0 famm (:,:,:) = c0 diff --git a/cicecore/cicedyn/analysis/ice_history_shared.F90 b/cicecore/cicedyn/analysis/ice_history_shared.F90 index 2d2c500e8..6b6661b0d 100644 --- a/cicecore/cicedyn/analysis/ice_history_shared.F90 +++ b/cicecore/cicedyn/analysis/ice_history_shared.F90 @@ -39,6 +39,7 @@ module ice_history_shared integer (kind=int_kind), public :: history_precision logical (kind=log_kind), public :: & + write_histrest_now = .false. , & ! true when writing history restarts hist_avg(max_nstrm) ! if true, write averaged data instead of snapshots character (len=char_len_long), public :: & @@ -80,7 +81,7 @@ module ice_history_shared !--------------------------------------------------------------- type, public :: ice_hist_field - character (len=20) :: vname ! variable name + character (len=24) :: vname ! variable name character (len=16) :: vunit ! variable units character (len=25) :: vcoord ! variable coordinates character (len=16) :: vcellmeas ! variable cell measures @@ -776,7 +777,7 @@ module ice_history_shared !======================================================================= - subroutine construct_filename(ncfile,suffix,ns) + subroutine construct_filename(ncfile,suffix,ns,option) use ice_calendar, only: msec, myear, mmonth, daymo, & mday, write_ic, histfreq, histfreq_n, & @@ -787,13 +788,23 @@ subroutine construct_filename(ncfile,suffix,ns) character (len=*), intent(inout) :: ncfile character (len=*), intent(in) :: suffix integer (kind=int_kind), intent(in) :: ns + character (len=*), intent(in), optional :: option integer (kind=int_kind) :: iyear, imonth, iday, isec integer (kind=int_kind) :: n - character (len=char_len) :: cstream + character (len=char_len) :: cstream, loption character (len=char_len_long), save :: ncfile_last(max_nstrm) = 'UnDefineD' character(len=*), parameter :: subname = '(construct_filename)' + loption = 'history' + if (present(option)) then + loption = option + endif + + if (loption /= 'history' .and. loption /= 'histrest') then + call abort_ice(subname//' ERROR: option invalid = '//trim(loption)) + endif + iyear = myear imonth = mmonth iday = mday @@ -807,6 +818,11 @@ subroutine construct_filename(ncfile,suffix,ns) write(ncfile,'(a,a,i4.4,a,i2.2,a,i2.2,a,i5.5,a,a)') & incond_file(1:lenstr(incond_file)),'.',iyear,'-', & imonth,'-',iday,'-',isec,'.',trim(suffix) + + elseif (loption == 'histrest') then + write(ncfile,'(a,i4.4,a,i2.2,a,i2.2,a,i5.5,a,a)') & + history_file(1:lenstr(history_file))//trim(cstream)//'_r'//trim(histfreq(ns))//'.', & + iyear,'-',imonth,'-',iday,'-',msec,'.',trim(suffix) else if (hist_avg(ns)) then @@ -874,19 +890,21 @@ subroutine construct_filename(ncfile,suffix,ns) ! The current filename convention means we just have to check latest filename, ! not all filenames ever generated because of use of current model date/time in filename. - ! write(nu_diag,'(2a,i2,1x,a)') subname, 'debug ncfile= ',ns,trim(ncfile) - do n = 1,max_nstrm - ! write(nu_diag,'(2a,i2,1x,a)') subname, 'debug nfile_last= ',n,trim(ncfile_last(n)) - if (ncfile == ncfile_last(n)) then - write(nu_diag,*) subname,' history stream = ',ns - write(nu_diag,*) subname,' history filename = ',trim(ncfile) - write(nu_diag,*) subname,' filename in use for stream ',n - write(nu_diag,*) subname,' filename for stream ',trim(ncfile_last(n)) - write(nu_diag,*) subname,' Use namelist hist_suffix so history filenames are unique' - call abort_ice(subname//' ERROR: history filename already used for another history stream '//trim(ncfile)) - endif - enddo - ncfile_last(ns) = ncfile + if (loption /= 'histrest') then + ! write(nu_diag,'(2a,i2,1x,a)') subname, 'debug ncfile= ',ns,trim(ncfile) + do n = 1,max_nstrm + ! write(nu_diag,'(2a,i2,1x,a)') subname, 'debug nfile_last= ',n,trim(ncfile_last(n)) + if (ncfile == ncfile_last(n)) then + write(nu_diag,*) subname,' history stream = ',ns + write(nu_diag,*) subname,' history filename = ',trim(ncfile) + write(nu_diag,*) subname,' filename in use for stream ',n + write(nu_diag,*) subname,' filename for stream ',trim(ncfile_last(n)) + write(nu_diag,*) subname,' Use namelist hist_suffix so history filenames are unique' + call abort_ice(subname//' ERROR: history filename already used for another history stream '//trim(ncfile)) + endif + enddo + ncfile_last(ns) = ncfile + endif end subroutine construct_filename diff --git a/cicecore/cicedyn/general/ice_init.F90 b/cicecore/cicedyn/general/ice_init.F90 index 634bb759a..9271a1046 100644 --- a/cicecore/cicedyn/general/ice_init.F90 +++ b/cicecore/cicedyn/general/ice_init.F90 @@ -74,7 +74,7 @@ subroutine input_data istep0, histfreq, histfreq_n, histfreq_base, & dumpfreq, dumpfreq_n, diagfreq, dumpfreq_base, & npt, dt, ndtd, days_per_year, use_leap_years, & - write_ic, dump_last, npt_unit + write_ic, dump_last, npt_unit, write_histrest use ice_arrays_column, only: oceanmixed_ice use ice_restart_column, only: & restart_age, restart_FY, restart_lvl, & @@ -198,7 +198,7 @@ subroutine input_data ice_ic, restart, restart_dir, restart_file, & restart_ext, use_restart_time, restart_format, lcdf64, & restart_root, restart_stride, restart_iotasks, restart_rearranger, & - restart_deflate, restart_chunksize, restart_mod, & + restart_deflate, restart_chunksize, restart_mod, write_histrest,& pointer_file, dumpfreq, dumpfreq_n, dump_last, & diagfreq, diag_type, diag_file, history_format,& history_root, history_stride, history_iotasks, history_rearranger, & @@ -361,6 +361,7 @@ subroutine input_data history_deflate = 0 ! compression level for netcdf4 history_chunksize(:) = 0 ! chunksize for netcdf4 write_ic = .false. ! write out initial condition + write_histrest = .true.! write out history restart files if needed cpl_bgc = .false. ! couple bgc thru driver incond_dir = history_dir ! write to history dir for default incond_file = 'iceh_ic'! file prefix @@ -997,6 +998,7 @@ subroutine input_data call broadcast_scalar(history_deflate, master_task) call broadcast_array(history_chunksize, master_task) call broadcast_scalar(write_ic, master_task) + call broadcast_scalar(write_histrest, master_task) call broadcast_scalar(cpl_bgc, master_task) call broadcast_scalar(incond_dir, master_task) call broadcast_scalar(incond_file, master_task) @@ -2696,6 +2698,7 @@ subroutine input_data write(nu_diag,1031) ' restart_file = ', trim(restart_file) write(nu_diag,1031) ' pointer_file = ', trim(pointer_file) write(nu_diag,1011) ' use_restart_time = ', use_restart_time + write(nu_diag,1011) ' write_histrest = ', write_histrest write(nu_diag,1031) ' ice_ic = ', trim(ice_ic) if (trim(grid_type) /= 'rectangular' .or. & trim(grid_type) /= 'column') then diff --git a/cicecore/cicedyn/infrastructure/io/io_binary/ice_history_write.F90 b/cicecore/cicedyn/infrastructure/io/io_binary/ice_history_write.F90 index 030977ccc..234011f61 100644 --- a/cicecore/cicedyn/infrastructure/io/io_binary/ice_history_write.F90 +++ b/cicecore/cicedyn/infrastructure/io/io_binary/ice_history_write.F90 @@ -18,13 +18,14 @@ module ice_history_write + use ice_communicate, only: my_task, master_task use ice_fileunits, only: nu_history, nu_hdr, nu_diag use ice_exit, only: abort_ice use icepack_intfc, only: icepack_warnings_flush, icepack_warnings_aborted implicit none private - public :: ice_write_hist + public :: ice_write_hist, ice_read_hist !======================================================================= @@ -44,7 +45,6 @@ subroutine ice_write_hist(ns) use ice_kinds_mod use ice_calendar, only: write_ic, dayyr, histfreq, use_leap_years - use ice_communicate, only: my_task, master_task use ice_constants, only: spval use ice_domain_size, only: nx_global, ny_global, max_nstrm use ice_read_write, only: ice_open, ice_write @@ -72,6 +72,14 @@ subroutine ice_write_hist(ns) character(len=*), parameter :: subname = '(ice_write_hist)' + ! not supported in binary IO + if (write_histrest_now) then + if (my_task == master_task) then + write(nu_diag,*) subname,' WARNING: history restarts not supported with binary IO' + endif + return + endif + diag = .false. ! single precision @@ -397,6 +405,22 @@ subroutine ice_write_hist(ns) end subroutine ice_write_hist +!======================================================================= +! +! read history restarts, only called for history restarts +! NOT supported with Binary +! +! author: T. Craig, Nov 2025 + + subroutine ice_read_hist + + character(len=*), parameter :: subname = '(ice_read_hist)' + + if (my_task == master_task) then + write(nu_diag,*) subname,' WARNING: history restarts not supported with binary IO' + endif + + end subroutine ice_read_hist !======================================================================= end module ice_history_write diff --git a/cicecore/cicedyn/infrastructure/io/io_netcdf/ice_history_write.F90 b/cicecore/cicedyn/infrastructure/io/io_netcdf/ice_history_write.F90 index 668badb14..db3eef513 100644 --- a/cicecore/cicedyn/infrastructure/io/io_netcdf/ice_history_write.F90 +++ b/cicecore/cicedyn/infrastructure/io/io_netcdf/ice_history_write.F90 @@ -18,6 +18,7 @@ ! 2009 D Bailey and ECH: Generalized for multiple frequency output ! 2010 Alison McLaren and ECH: Added 3D capability ! 2013 ECH split from ice_history.F90 +! 2025 T Craig: Add history restart capability module ice_history_write @@ -47,7 +48,7 @@ module ice_history_write character (len=20) :: coordinates END TYPE req_attributes - public :: ice_write_hist + public :: ice_write_hist, ice_read_hist integer (kind=int_kind) :: imtid,jmtid @@ -58,6 +59,7 @@ module ice_history_write !======================================================================= ! ! write average ice quantities or snapshots +! supports history output, write_ic, and history restarts ! ! author: Elizabeth C. Hunke, LANL @@ -73,6 +75,7 @@ subroutine ice_write_hist (ns) use ice_communicate, only: my_task, master_task use ice_domain, only: distrb_info use ice_domain_size, only: nx_global, ny_global, max_nstrm, max_blocks + use ice_flux, only: albcnt, snwcnt use ice_gather_scatter, only: gather_global use ice_grid, only: TLON, TLAT, ULON, ULAT, NLON, NLAT, ELON, ELAT, & hm, uvm, npm, epm, bm, tarea, uarea, narea, earea, & @@ -80,6 +83,7 @@ subroutine ice_write_hist (ns) lont_bounds, latt_bounds, lonu_bounds, latu_bounds, & lonn_bounds, latn_bounds, lone_bounds, late_bounds use ice_history_shared + use ice_restart_shared, only: restart_dir #ifdef CESMCOUPLED use ice_restart_shared, only: runid #endif @@ -93,8 +97,8 @@ subroutine ice_write_hist (ns) real (kind=dbl_kind), dimension(nx_block,ny_block,max_blocks) :: work1 integer (kind=int_kind) :: i,k,ic,n,nn, & - ncid,status,kmtidi,kmtids,kmtidb, cmtid,timid,varid, & - nvertexid,ivertex,kmtida,iflag, fmtid + ncid,status,kmtidi,kmtids,kmtidb,cmtid,timid,varid, & + nvertexid,ivertex,kmtida,iflag,fmtid,lhistprec integer (kind=int_kind), dimension(3) :: dimid integer (kind=int_kind), dimension(4) :: dimidz integer (kind=int_kind), dimension(5) :: dimidcz @@ -111,6 +115,7 @@ subroutine ice_write_hist (ns) character (char_len) :: start_time,current_date,current_time character (len=8) :: cdate + character (len=1) :: cns ! time coord TYPE(coord_attributes) :: time_coord @@ -137,16 +142,30 @@ subroutine ice_write_hist (ns) file=__FILE__, line=__LINE__) extvars = '' + write(cns,'(i1.1)') ns + + ! modify history restart output + lhistprec = history_precision + if (write_histrest_now) then + history_precision = 8 + endif + lprecision = nf90_float if (history_precision == 8) lprecision = nf90_double if (my_task == master_task) then - call construct_filename(ncfile,'nc',ns) + if (write_histrest_now) then + call construct_filename(ncfile,'nc',ns, option='histrest') + else + call construct_filename(ncfile,'nc',ns) + endif ! add local directory path name to ncfile if (write_ic) then ncfile = trim(incond_dir)//ncfile + elseif (write_histrest_now) then + ncfile = trim(restart_dir)//ncfile else ncfile = trim(history_dir)//ncfile endif @@ -494,6 +513,13 @@ subroutine ice_write_hist (ns) ! define attributes for time-variant variables !----------------------------------------------------------------- + if (write_histrest_now) then + status = nf90_def_var(ncid, 'time_beg', lprecision, varid=varid) + status = nf90_def_var(ncid, 'avgct', lprecision, varid=varid) + status = nf90_def_var(ncid, 'albcnt'//cns, lprecision, dimid, varid) + status = nf90_def_var(ncid, 'snwcnt'//cns, lprecision, dimid, varid) + endif + do n=1,num_avail_hist_fields_2D if (avail_hist_fields(n)%vhistfreq == histfreq(ns) .or. write_ic) then call ice_hist_field_def(ncid, avail_hist_fields(n),lprecision, dimid,ns) @@ -598,6 +624,7 @@ subroutine ice_write_hist (ns) !----------------------------------------------------------------- ! ... the user should change these to something useful ... !----------------------------------------------------------------- + #ifdef CESMCOUPLED status = nf90_put_att(ncid,nf90_global,'title',runid) call ice_check_nc(status, subname// ' ERROR: in global attribute title', & @@ -973,12 +1000,48 @@ subroutine ice_write_hist (ns) ! write variable data !----------------------------------------------------------------- + if (write_histrest_now) then + if (my_task == master_task) then + status = nf90_inq_varid(ncid,'time_beg',varid) + call ice_check_nc(status, subname// ' ERROR: getting varid for '//'time_beg', & + file=__FILE__, line=__LINE__) + status = nf90_put_var(ncid,varid,time_beg(ns)) + call ice_check_nc(status, subname// ' ERROR: writing variable '//'time_beg', & + file=__FILE__, line=__LINE__) + status = nf90_inq_varid(ncid,'avgct',varid) + call ice_check_nc(status, subname// ' ERROR: getting varid for '//'avgct', & + file=__FILE__, line=__LINE__) + status = nf90_put_var(ncid,varid,avgct(ns)) + call ice_check_nc(status, subname// ' ERROR: writing variable '//'avgct', & + file=__FILE__, line=__LINE__) + endif + call gather_global(work_g1, albcnt(:,:,:,ns), master_task, distrb_info) + if (my_task == master_task) then + status = nf90_inq_varid(ncid,'albcnt'//cns,varid) + call ice_check_nc(status, subname// ' ERROR: getting varid for '//'albcnt'//cns, & + file=__FILE__, line=__LINE__) + status = nf90_put_var(ncid,varid,work_g1, & + count=(/nx_global,ny_global/)) + call ice_check_nc(status, subname// ' ERROR: writing variable '//'albcnt'//cns, & + file=__FILE__, line=__LINE__) + endif + call gather_global(work_g1, snwcnt(:,:,:,ns), master_task, distrb_info) + if (my_task == master_task) then + status = nf90_inq_varid(ncid,'snwcnt'//cns,varid) + call ice_check_nc(status, subname// ' ERROR: getting varid for '//'snwcnt'//cns, & + file=__FILE__, line=__LINE__) + status = nf90_put_var(ncid,varid,work_g1, & + count=(/nx_global,ny_global/)) + call ice_check_nc(status, subname// ' ERROR: writing variable '//'snwcnt'//cns, & + file=__FILE__, line=__LINE__) + endif + endif + work_g1(:,:) = c0 do n=1,num_avail_hist_fields_2D if (avail_hist_fields(n)%vhistfreq == histfreq(ns) .or. write_ic) then - call gather_global(work_g1, a2D(:,:,n,:), & - master_task, distrb_info) + call gather_global(work_g1, a2D(:,:,n,:), master_task, distrb_info) if (my_task == master_task) then status = nf90_inq_varid(ncid,avail_hist_fields(n)%vname,varid) call ice_check_nc(status, subname// ' ERROR: getting varid for '//avail_hist_fields(n)%vname, & @@ -1003,9 +1066,7 @@ subroutine ice_write_hist (ns) file=__FILE__, line=__LINE__) endif do k = 1, ncat_hist - call gather_global(work_g1, a3Dc(:,:,k,nn,:), & - master_task, distrb_info) - + call gather_global(work_g1, a3Dc(:,:,k,nn,:), master_task, distrb_info) if (my_task == master_task) then status = nf90_inq_varid(ncid,avail_hist_fields(n)%vname,varid) call ice_check_nc(status, subname// ' ERROR: getting varid for '//avail_hist_fields(n)%vname, & @@ -1031,9 +1092,7 @@ subroutine ice_write_hist (ns) file=__FILE__, line=__LINE__) endif do k = 1, nzilyr - call gather_global(work_g1, a3Dz(:,:,k,nn,:), & - master_task, distrb_info) - + call gather_global(work_g1, a3Dz(:,:,k,nn,:), master_task, distrb_info) if (my_task == master_task) then status = nf90_put_var(ncid,varid,work_g1, & start=(/ 1, 1,k/), & @@ -1056,9 +1115,7 @@ subroutine ice_write_hist (ns) file=__FILE__, line=__LINE__) endif do k = 1, nzblyr - call gather_global(work_g1, a3Db(:,:,k,nn,:), & - master_task, distrb_info) - + call gather_global(work_g1, a3Db(:,:,k,nn,:), master_task, distrb_info) if (my_task == master_task) then status = nf90_put_var(ncid,varid,work_g1, & start=(/ 1, 1,k/), & @@ -1081,9 +1138,7 @@ subroutine ice_write_hist (ns) file=__FILE__, line=__LINE__) endif do k = 1, nzalyr - call gather_global(work_g1, a3Da(:,:,k,nn,:), & - master_task, distrb_info) - + call gather_global(work_g1, a3Da(:,:,k,nn,:), master_task, distrb_info) if (my_task == master_task) then status = nf90_put_var(ncid,varid,work_g1, & start=(/ 1, 1,k/), & @@ -1106,8 +1161,7 @@ subroutine ice_write_hist (ns) file=__FILE__, line=__LINE__) endif do k = 1, nfsd_hist - call gather_global(work_g1, a3Df(:,:,k,nn,:), & - master_task, distrb_info) + call gather_global(work_g1, a3Df(:,:,k,nn,:), master_task, distrb_info) if (my_task == master_task) then status = nf90_put_var(ncid,varid,work_g1, & start=(/ 1, 1,k/), & @@ -1131,8 +1185,7 @@ subroutine ice_write_hist (ns) endif do ic = 1, ncat_hist do k = 1, nzilyr - call gather_global(work_g1, a4Di(:,:,k,ic,nn,:), & - master_task, distrb_info) + call gather_global(work_g1, a4Di(:,:,k,ic,nn,:), master_task, distrb_info) if (my_task == master_task) then status = nf90_put_var(ncid,varid,work_g1, & start=(/ 1, 1,k,ic/), & @@ -1157,8 +1210,7 @@ subroutine ice_write_hist (ns) endif do ic = 1, ncat_hist do k = 1, nzslyr - call gather_global(work_g1, a4Ds(:,:,k,ic,nn,:), & - master_task, distrb_info) + call gather_global(work_g1, a4Ds(:,:,k,ic,nn,:), master_task, distrb_info) if (my_task == master_task) then status = nf90_put_var(ncid,varid,work_g1, & start=(/ 1, 1,k,ic/), & @@ -1181,8 +1233,7 @@ subroutine ice_write_hist (ns) endif do ic = 1, ncat_hist do k = 1, nfsd_hist - call gather_global(work_g1, a4Df(:,:,k,ic,nn,:), & - master_task, distrb_info) + call gather_global(work_g1, a4Df(:,:,k,ic,nn,:), master_task, distrb_info) if (my_task == master_task) then status = nf90_put_var(ncid,varid,work_g1, & start=(/ 1, 1,k,ic/), & @@ -1205,8 +1256,12 @@ subroutine ice_write_hist (ns) status = nf90_close(ncid) call ice_check_nc(status, subname// ' ERROR: closing netCDF history file', & file=__FILE__, line=__LINE__) - write(nu_diag,*) ' ' - write(nu_diag,*) 'Finished writing ',trim(ncfile) + write(nu_diag,*) subname,' Finished writing ',trim(ncfile) + endif + + ! reset history parameters + if (write_histrest_now) then + history_precision = lhistprec endif #else @@ -1215,6 +1270,421 @@ subroutine ice_write_hist (ns) end subroutine ice_write_hist +!======================================================================= +! +! read history restarts, only called for history restarts +! +! author: T. Craig Nov 2025 + + subroutine ice_read_hist + + use ice_kinds_mod + use ice_blocks, only: nx_block, ny_block + use ice_broadcast, only: broadcast_scalar + use ice_calendar, only: nstreams, histfreq + use ice_communicate, only: my_task, master_task + use ice_constants, only: field_loc_noupdate, field_type_noupdate + use ice_domain, only: distrb_info + use ice_domain_size, only: nx_global, ny_global, max_nstrm, max_blocks + use ice_flux, only: albcnt, snwcnt + use ice_gather_scatter, only: scatter_global + use ice_history_shared + use ice_restart_shared, only: restart_dir + use ice_timers, only: ice_timer_start, ice_timer_stop, timer_readwrite + + ! local variables + + real (kind=dbl_kind), dimension(:,:), allocatable :: work_g1 + + integer (kind=int_kind) :: k,ic,n,nn,ns,ncid,status,varid + character (char_len_long) :: ncfile + character (len=1) :: cns + character (len=32) :: readstr + character (len=*), parameter :: readstrT = ' read ok:' + character (len=*), parameter :: readstrF = ' DID NOT READ:' + + character(len=*), parameter :: subname = '(ice_read_hist)' + + call ice_timer_start(timer_readwrite) ! reading/writing + do ns = 1,nstreams + if (hist_avg(ns)) then + + write(cns,'(i1.1)') ns +#ifdef USE_NETCDF + if (my_task == master_task) then + + call construct_filename(ncfile,'nc',ns, option='histrest') + + ! add local directory path name to ncfile + ncfile = trim(restart_dir)//ncfile + + ! open file + status = nf90_open(ncfile, nf90_nowrite, ncid) + endif ! master_task + + call broadcast_scalar(status,master_task) + if (status /= nf90_noerr) then + if (my_task == master_task) then + write(nu_diag,*) subname,' file not found ',trim(ncfile) + endif + else + if (my_task == master_task) then + write(nu_diag,*) subname,' reading file ',trim(ncfile) + endif + + if (my_task==master_task) then + allocate(work_g1(nx_global,ny_global)) + else + allocate(work_g1(1,1)) + endif + + work_g1(:,:) = c0 + + !----------------------------------------------------------------- + ! read variable data + !----------------------------------------------------------------- + + if (my_task == master_task) then + readstr = readstrF + status = nf90_inq_varid(ncid,'time_beg',varid) + if (status == nf90_noerr) status = nf90_get_var(ncid,varid,time_beg(ns)) + if (status == nf90_noerr) readstr = readstrT + write(nu_diag,*) subname,trim(readstr),' time_beg' + + readstr = readstrF + status = nf90_inq_varid(ncid,'avgct',varid) + if (status == nf90_noerr) status = nf90_get_var(ncid,varid,avgct(ns)) + if (status == nf90_noerr) readstr = readstrT + write(nu_diag,*) subname,trim(readstr),' time_beg' + endif + call broadcast_scalar(time_beg(ns),master_task) + call broadcast_scalar(avgct(ns),master_task) + + if (my_task == master_task) then + readstr = readstrF + status = nf90_inq_varid(ncid,'albcnt'//cns,varid) + if (status == nf90_noerr) then + status = nf90_get_var(ncid,varid,work_g1, & + count=(/nx_global,ny_global/)) + if (status == nf90_noerr) readstr = readstrT + endif + write(nu_diag,*) subname,trim(readstr),' albcnt'//cns + endif + call broadcast_scalar(status,master_task) + if (status == nf90_noerr) then + call scatter_global(albcnt(:,:,:,ns), work_g1, master_task, distrb_info, & + field_loc_noupdate, field_type_noupdate) + endif + + if (my_task == master_task) then + readstr = readstrF + status = nf90_inq_varid(ncid,'snwcnt'//cns,varid) + if (status == nf90_noerr) then + status = nf90_get_var(ncid,varid,work_g1, & + count=(/nx_global,ny_global/)) + if (status == nf90_noerr) readstr = readstrT + endif + write(nu_diag,*) subname,trim(readstr),' snwcnt'//cns + endif + call broadcast_scalar(status,master_task) + if (status == nf90_noerr) then + call scatter_global(snwcnt(:,:,:,ns), work_g1, master_task, distrb_info, & + field_loc_noupdate, field_type_noupdate) + endif + + do n=1,num_avail_hist_fields_2D + if (avail_hist_fields(n)%vhistfreq == histfreq(ns)) then + readstr = readstrF + if (my_task == master_task) then + status = nf90_inq_varid(ncid,avail_hist_fields(n)%vname,varid) + if (status == nf90_noerr) then + status = nf90_get_var(ncid,varid,work_g1, & + count=(/nx_global,ny_global/)) + if (status == nf90_noerr) readstr = readstrT + endif + write(nu_diag,*) subname,trim(readstr),trim(avail_hist_fields(n)%vname) + endif + call broadcast_scalar(status,master_task) + if (status == nf90_noerr) then + call scatter_global(a2D(:,:,n,:), work_g1, master_task, distrb_info, & + field_loc_noupdate, field_type_noupdate) + endif + endif + enddo ! num_avail_hist_fields_2D + + do n = n2D + 1, n3Dccum + nn = n - n2D + if (avail_hist_fields(n)%vhistfreq == histfreq(ns)) then + readstr = readstrF + if (my_task == master_task) then + status = nf90_inq_varid(ncid,avail_hist_fields(n)%vname,varid) + endif + call broadcast_scalar(status,master_task) + if (status == nf90_noerr) then + do k = 1, ncat_hist + if (my_task == master_task) then + status = nf90_get_var(ncid,varid,work_g1, & + start=(/ 1, 1,k/), & + count=(/nx_global,ny_global,1/)) + if (status == nf90_noerr) readstr = readstrT + endif + call broadcast_scalar(status,master_task) + if (status == nf90_noerr) then + call scatter_global(a3Dc(:,:,k,nn,:), work_g1, master_task, distrb_info, & + field_loc_noupdate, field_type_noupdate) + endif + enddo ! k + endif ! varid + if (my_task == master_task) then + write(nu_diag,*) subname,trim(readstr),trim(avail_hist_fields(n)%vname) + endif + endif ! histfreq + enddo ! num_avail_hist_fields_3Dc + + work_g1(:,:) = c0 + + do n = n3Dccum+1, n3Dzcum + nn = n - n3Dccum + if (avail_hist_fields(n)%vhistfreq == histfreq(ns)) then + readstr = readstrF + if (my_task == master_task) then + status = nf90_inq_varid(ncid,avail_hist_fields(n)%vname,varid) + endif + call broadcast_scalar(status,master_task) + if (status == nf90_noerr) then + do k = 1, nzilyr + if (my_task == master_task) then + status = nf90_get_var(ncid,varid,work_g1, & + start=(/ 1, 1,k/), & + count=(/nx_global,ny_global,1/)) + if (status == nf90_noerr) readstr = readstrT + endif + call broadcast_scalar(status,master_task) + if (status == nf90_noerr) then + call scatter_global(a3Dz(:,:,k,nn,:), work_g1, master_task, distrb_info, & + field_loc_noupdate, field_type_noupdate) + endif + enddo ! k + endif ! varid + if (my_task == master_task) then + write(nu_diag,*) subname,trim(readstr),trim(avail_hist_fields(n)%vname) + endif + endif ! histfreq + enddo ! num_avail_hist_fields_3Dz + + work_g1(:,:) = c0 + + do n = n3Dzcum+1, n3Dbcum + nn = n - n3Dzcum + if (avail_hist_fields(n)%vhistfreq == histfreq(ns)) then + readstr = readstrF + if (my_task == master_task) then + status = nf90_inq_varid(ncid,avail_hist_fields(n)%vname,varid) + endif + call broadcast_scalar(status,master_task) + if (status == nf90_noerr) then + do k = 1, nzblyr + if (my_task == master_task) then + status = nf90_get_var(ncid,varid,work_g1, & + start=(/ 1, 1,k/), & + count=(/nx_global,ny_global,1/)) + if (status == nf90_noerr) readstr = readstrT + endif + call broadcast_scalar(status,master_task) + if (status == nf90_noerr) then + call scatter_global(a3Db(:,:,k,nn,:), work_g1, master_task, distrb_info, & + field_loc_noupdate, field_type_noupdate) + endif + enddo ! k + endif ! varid + if (my_task == master_task) then + write(nu_diag,*) subname,trim(readstr),trim(avail_hist_fields(n)%vname) + endif + endif ! histfreq + enddo ! num_avail_hist_fields_3Db + + work_g1(:,:) = c0 + + do n = n3Dbcum+1, n3Dacum + nn = n - n3Dbcum + if (avail_hist_fields(n)%vhistfreq == histfreq(ns)) then + readstr = readstrF + if (my_task == master_task) then + status = nf90_inq_varid(ncid,avail_hist_fields(n)%vname,varid) + endif + call broadcast_scalar(status,master_task) + if (status == nf90_noerr) then + do k = 1, nzalyr + if (my_task == master_task) then + status = nf90_get_var(ncid,varid,work_g1, & + start=(/ 1, 1,k/), & + count=(/nx_global,ny_global,1/)) + endif + call broadcast_scalar(status,master_task) + if (status == nf90_noerr) then + call scatter_global(a3Da(:,:,k,nn,:), work_g1, master_task, distrb_info, & + field_loc_noupdate, field_type_noupdate) + endif + enddo ! k + endif ! varid + if (my_task == master_task) then + write(nu_diag,*) subname,trim(readstr),trim(avail_hist_fields(n)%vname) + endif + endif ! histfreq + enddo ! num_avail_hist_fields_3Da + + work_g1(:,:) = c0 + + do n = n3Dacum+1, n3Dfcum + nn = n - n3Dacum + if (avail_hist_fields(n)%vhistfreq == histfreq(ns)) then + readstr = readstrF + if (my_task == master_task) then + status = nf90_inq_varid(ncid,avail_hist_fields(n)%vname,varid) + endif + call broadcast_scalar(status,master_task) + if (status == nf90_noerr) then + do k = 1, nfsd_hist + if (my_task == master_task) then + status = nf90_get_var(ncid,varid,work_g1, & + start=(/ 1, 1,k/), & + count=(/nx_global,ny_global,1/)) + if (status == nf90_noerr) readstr = readstrT + endif + call broadcast_scalar(status,master_task) + if (status == nf90_noerr) then + call scatter_global(a3Df(:,:,k,nn,:), work_g1, master_task, distrb_info, & + field_loc_noupdate, field_type_noupdate) + endif + enddo ! k + endif ! varid + if (my_task == master_task) then + write(nu_diag,*) subname,trim(readstr),trim(avail_hist_fields(n)%vname) + endif + endif ! histfreq + enddo ! num_avail_hist_fields_3Df + + work_g1(:,:) = c0 + + do n = n3Dfcum+1, n4Dicum + nn = n - n3Dfcum + if (avail_hist_fields(n)%vhistfreq == histfreq(ns)) then + readstr = readstrF + if (my_task == master_task) then + status = nf90_inq_varid(ncid,avail_hist_fields(n)%vname,varid) + endif + call broadcast_scalar(status,master_task) + if (status == nf90_noerr) then + do ic = 1, ncat_hist + do k = 1, nzilyr + if (my_task == master_task) then + status = nf90_get_var(ncid,varid,work_g1, & + start=(/ 1, 1,k,ic/), & + count=(/nx_global,ny_global,1, 1/)) + if (status == nf90_noerr) readstr = readstrT + endif + call broadcast_scalar(status,master_task) + if (status == nf90_noerr) then + call scatter_global(a4Di(:,:,k,ic,nn,:), work_g1, master_task, distrb_info, & + field_loc_noupdate, field_type_noupdate) + endif + enddo ! k + enddo ! ic + endif ! varid + if (my_task == master_task) then + write(nu_diag,*) subname,trim(readstr),trim(avail_hist_fields(n)%vname) + endif + endif ! histfreq + enddo ! num_avail_hist_fields_4Di + + work_g1(:,:) = c0 + + do n = n4Dicum+1, n4Dscum + nn = n - n4Dicum + if (avail_hist_fields(n)%vhistfreq == histfreq(ns)) then + readstr = readstrF + if (my_task == master_task) then + status = nf90_inq_varid(ncid,avail_hist_fields(n)%vname,varid) + endif + call broadcast_scalar(status,master_task) + if (status == nf90_noerr) then + do ic = 1, ncat_hist + do k = 1, nzslyr + if (my_task == master_task) then + status = nf90_get_var(ncid,varid,work_g1, & + start=(/ 1, 1,k,ic/), & + count=(/nx_global,ny_global,1, 1/)) + if (status == nf90_noerr) readstr = readstrT + endif + call broadcast_scalar(status,master_task) + if (status == nf90_noerr) then + call scatter_global(a4Ds(:,:,k,ic,nn,:), work_g1, master_task, distrb_info, & + field_loc_noupdate, field_type_noupdate) + endif + enddo ! k + enddo ! ic + endif ! varid + if (my_task == master_task) then + write(nu_diag,*) subname,trim(readstr),trim(avail_hist_fields(n)%vname) + endif + endif ! histfreq + enddo ! num_avail_hist_fields_4Ds + + do n = n4Dscum+1, n4Dfcum + nn = n - n4Dscum + if (avail_hist_fields(n)%vhistfreq == histfreq(ns)) then + readstr = readstrF + if (my_task == master_task) then + status = nf90_inq_varid(ncid,avail_hist_fields(n)%vname,varid) + endif + call broadcast_scalar(status,master_task) + if (status == nf90_noerr) then + do ic = 1, ncat_hist + do k = 1, nfsd_hist + if (my_task == master_task) then + status = nf90_get_var(ncid,varid,work_g1, & + start=(/ 1, 1,k,ic/), & + count=(/nx_global,ny_global,1, 1/)) + if (status == nf90_noerr) readstr = readstrT + endif + call broadcast_scalar(status,master_task) + if (status == nf90_noerr) then + call scatter_global(a4Df(:,:,k,ic,nn,:), work_g1, master_task, distrb_info, & + field_loc_noupdate, field_type_noupdate) + endif + enddo ! k + enddo ! ic + endif ! varid + if (my_task == master_task) then + write(nu_diag,*) subname,trim(readstr),trim(avail_hist_fields(n)%vname) + endif + endif ! histfreq + enddo ! num_avail_hist_fields_4Df + + deallocate(work_g1) + + !----------------------------------------------------------------- + ! close output dataset + !----------------------------------------------------------------- + + if (my_task == master_task) then + status = nf90_close(ncid) + call ice_check_nc(status, subname// ' ERROR: closing netCDF history file', & + file=__FILE__, line=__LINE__) + write(nu_diag,*) subname,' Finished reading ',trim(ncfile) + endif + + endif ! open file success + endif ! hist_avg + enddo ! nstreams + call ice_timer_stop(timer_readwrite) ! reading/writing + +#else + call abort_ice(subname//' ERROR: USE_NETCDF cpp not defined', file=__FILE__, line=__LINE__) +#endif + + end subroutine ice_read_hist + !======================================================================= ! Defines a (time-dependent) history var in the history file ! variables have short_name, long_name and units, coordinates and cell_measures attributes, diff --git a/cicecore/cicedyn/infrastructure/io/io_pio2/ice_history_write.F90 b/cicecore/cicedyn/infrastructure/io/io_pio2/ice_history_write.F90 index 5c41f0eda..acbd7d8de 100644 --- a/cicecore/cicedyn/infrastructure/io/io_pio2/ice_history_write.F90 +++ b/cicecore/cicedyn/infrastructure/io/io_pio2/ice_history_write.F90 @@ -14,6 +14,7 @@ ! Added option for binary output instead of netCDF ! 2009 D Bailey and ECH: Generalized for multiple frequency output ! 2010 Alison McLaren and ECH: Added 3D capability +! 2025 T Craig: Add history restart capability ! module ice_history_write @@ -41,7 +42,7 @@ module ice_history_write character (len=20) :: coordinates END TYPE req_attributes - public :: ice_write_hist + public :: ice_write_hist, ice_read_hist integer (kind=int_kind) :: imtid,jmtid @@ -52,6 +53,7 @@ module ice_history_write !======================================================================= ! ! write average ice quantities or snapshots +! supports history output, write_ic, and history restarts ! ! author: Elizabeth C. Hunke, LANL @@ -64,7 +66,8 @@ subroutine ice_write_hist (ns) hh_init, mm_init, ss_init use ice_communicate, only: my_task, master_task use ice_domain, only: distrb_info, nblocks - use ice_domain_size, only: nx_global, ny_global, max_blocks, max_nstrm + use ice_domain_size, only: nx_global, ny_global, max_blocks + use ice_flux, only: albcnt, snwcnt use ice_gather_scatter, only: gather_global use ice_grid, only: TLON, TLAT, ULON, ULAT, NLON, NLAT, ELON, ELAT, & hm, bm, uvm, npm, epm, & @@ -74,7 +77,7 @@ subroutine ice_write_hist (ns) lonn_bounds, latn_bounds, lone_bounds, late_bounds use ice_history_shared use ice_arrays_column, only: hin_max, floe_rad_c - use ice_restart_shared, only: runid + use ice_restart_shared, only: runid, restart_dir use pio integer (kind=int_kind), intent(in) :: ns @@ -82,8 +85,8 @@ subroutine ice_write_hist (ns) ! local variables integer (kind=int_kind) :: i,j,k,ic,n,nn, & - ncid,status,kmtidi,kmtids,kmtidb, cmtid,timid, & - length,nvertexid,ivertex,kmtida,fmtid + ncid,status,kmtidi,kmtids,kmtidb,cmtid,timid, & + length,nvertexid,ivertex,kmtida,fmtid,lhistprec integer (kind=int_kind), dimension(2) :: dimid2 integer (kind=int_kind), dimension(3) :: dimid3 integer (kind=int_kind), dimension(4) :: dimidz @@ -92,6 +95,7 @@ subroutine ice_write_hist (ns) integer (kind=int_kind), dimension(6) :: dimidex real (kind= dbl_kind) :: ltime2 character (len=8) :: cdate + character (len=1) :: cns character (len=char_len_long) :: title, cal_units, cal_att character (len=char_len) :: time_period_freq = 'none' character (len=char_len_long) :: ncfile @@ -158,12 +162,27 @@ subroutine ice_write_hist (ns) file=__FILE__, line=__LINE__) extvars = '' + + write(cns,'(i1.1)') ns + + ! modify history restart output + lhistprec = history_precision + if (write_histrest_now) then + history_precision = 8 + endif + if (my_task == master_task) then - call construct_filename(ncfile,'nc',ns) + if (write_histrest_now) then + call construct_filename(ncfile,'nc',ns,option='histrest') + else + call construct_filename(ncfile,'nc',ns) + endif ! add local directory path name to ncfile if (write_ic) then ncfile = trim(incond_dir)//ncfile + elseif (write_histrest_now) then + ncfile = trim(restart_dir)//ncfile else ncfile = trim(history_dir)//ncfile endif @@ -485,6 +504,13 @@ subroutine ice_write_hist (ns) dimid3(2) = jmtid dimid3(3) = timid + if (write_histrest_now) then + status = pio_def_var(File, 'time_beg', lprecision, varid) + status = pio_def_var(File, 'avgct', lprecision, varid) + status = pio_def_var(File, 'albcnt'//cns, lprecision, dimid3, varid) + status = pio_def_var(File, 'snwcnt'//cns, lprecision, dimid3, varid) + endif + do n=1,num_avail_hist_fields_2D if (avail_hist_fields(n)%vhistfreq == histfreq(ns) .or. write_ic) then call ice_hist_field_def(File, avail_hist_fields(n),lprecision, dimid3, ns) @@ -923,6 +949,79 @@ subroutine ice_write_hist (ns) ! write variable data !----------------------------------------------------------------- + if (write_histrest_now) then + call ice_pio_check(pio_inq_varid(File,'time_beg',varid), & + subname// ' ERROR: getting varid for '//'time_beg', & + file=__FILE__, line=__LINE__) + call pio_seterrorhandling(File, PIO_INTERNAL_ERROR) +#ifdef CESM1_PIO + call pio_setframe(varid, int(1,kind=PIO_OFFSET)) +#else + call pio_setframe(File, varid, int(1,kind=PIO_OFFSET_KIND)) +#endif + call pio_seterrorhandling(File, PIO_RETURN_ERROR) + call ice_pio_check(pio_put_var(File,varid,(/1/),time_beg(ns)), & + subname// ' ERROR: writing variable '//'time_beg', & + file=__FILE__, line=__LINE__) + + call ice_pio_check(pio_inq_varid(File,'avgct',varid), & + subname// ' ERROR: getting varid for '//'avgct', & + file=__FILE__, line=__LINE__) + call pio_seterrorhandling(File, PIO_INTERNAL_ERROR) +#ifdef CESM1_PIO + call pio_setframe(varid, int(1,kind=PIO_OFFSET)) +#else + call pio_setframe(File, varid, int(1,kind=PIO_OFFSET_KIND)) +#endif + call pio_seterrorhandling(File, PIO_RETURN_ERROR) + call ice_pio_check(pio_put_var(File,varid,(/1/),avgct(ns)), & + subname// ' ERROR: writing variable '//'avgct', & + file=__FILE__, line=__LINE__) + + call ice_pio_check(pio_inq_varid(File,'albcnt'//cns,varid), & + subname//' ERROR: getting varid for '//'albcnt'//cns,file=__FILE__,line=__LINE__) + workd2(:,:,:) = albcnt(:,:,1:nblocks,ns) + call pio_seterrorhandling(File, PIO_INTERNAL_ERROR) +#ifdef CESM1_PIO + call pio_setframe(varid, int(1,kind=PIO_OFFSET)) +#else + call pio_setframe(File, varid, int(1,kind=PIO_OFFSET_KIND)) +#endif + call pio_seterrorhandling(File, PIO_RETURN_ERROR) + if (history_precision == 8) then + call pio_write_darray(File, varid, iodesc2d,& + workd2, status, fillval=spval_dbl) + else + workr2 = workd2 + call pio_write_darray(File, varid, iodesc2d,& + workr2, status, fillval=spval) + endif + call ice_pio_check(status,subname//' ERROR: writing '//'albcnt'//cns, & + file=__FILE__,line=__LINE__) + + call ice_pio_check(pio_inq_varid(File,'snwcnt'//cns,varid), & + subname//' ERROR: getting varid for '//'snwcnt'//cns,file=__FILE__,line=__LINE__) + workd2(:,:,:) = snwcnt(:,:,1:nblocks,ns) + call pio_seterrorhandling(File, PIO_INTERNAL_ERROR) +#ifdef CESM1_PIO + call pio_setframe(varid, int(1,kind=PIO_OFFSET)) +#else + call pio_setframe(File, varid, int(1,kind=PIO_OFFSET_KIND)) +#endif + call pio_seterrorhandling(File, PIO_RETURN_ERROR) + if (history_precision == 8) then + call pio_write_darray(File, varid, iodesc2d,& + workd2, status, fillval=spval_dbl) + else + workr2 = workd2 + call pio_write_darray(File, varid, iodesc2d,& + workr2, status, fillval=spval) + endif + call ice_pio_check(status,subname//' ERROR: writing '//'snwcnt'//cns, & + file=__FILE__,line=__LINE__) + + endif + ! 2D do n=1,num_avail_hist_fields_2D if (avail_hist_fields(n)%vhistfreq == histfreq(ns) .or. write_ic) then @@ -1135,7 +1234,7 @@ subroutine ice_write_hist (ns) allocate(workd4(nx_block,ny_block,nblocks,nzilyr,ncat_hist)) allocate(workr4(nx_block,ny_block,nblocks,nzilyr,ncat_hist)) - ! 4D (categories, fsd) + ! 4D (categories, vertical ice) do n = n3Dfcum+1, n4Dicum nn = n - n3Dfcum if (avail_hist_fields(n)%vhistfreq == histfreq(ns) .or. write_ic) then @@ -1172,7 +1271,7 @@ subroutine ice_write_hist (ns) allocate(workd4(nx_block,ny_block,nblocks,nzslyr,ncat_hist)) allocate(workr4(nx_block,ny_block,nblocks,nzslyr,ncat_hist)) - ! 4D (categories, vertical ice) + ! 4D (categories, vertical snow) do n = n4Dicum+1, n4Dscum nn = n - n4Dicum if (avail_hist_fields(n)%vhistfreq == histfreq(ns) .or. write_ic) then @@ -1210,7 +1309,7 @@ subroutine ice_write_hist (ns) allocate(workd4(nx_block,ny_block,nblocks,nfsd_hist,ncat_hist)) allocate(workr4(nx_block,ny_block,nblocks,nfsd_hist,ncat_hist)) - ! 4D (categories, vertical ice) + ! 4D (categories, fsd) do n = n4Dscum+1, n4Dfcum nn = n - n4Dscum if (avail_hist_fields(n)%vhistfreq == histfreq(ns) .or. write_ic) then @@ -1269,8 +1368,7 @@ subroutine ice_write_hist (ns) call pio_closefile(File) if (my_task == master_task) then - write(nu_diag,*) ' ' - write(nu_diag,*) 'Finished writing ',trim(ncfile) + write(nu_diag,*) subname,' Finished writing ',trim(ncfile) endif !----------------------------------------------------------------- @@ -1279,11 +1377,430 @@ subroutine ice_write_hist (ns) call ice_pio_finalize() + ! reset history parameters + if (write_histrest_now) then + history_precision = lhistprec + endif + first_call = .false. end subroutine ice_write_hist +!======================================================================= +! +! read history restarts, only called for history restarts +! +! author: T. Craig Nov 2025 + + subroutine ice_read_hist + + use ice_kinds_mod + use ice_blocks, only: nx_block, ny_block + use ice_broadcast, only: broadcast_scalar + use ice_calendar, only: nstreams, histfreq + use ice_communicate, only: my_task, master_task + use ice_domain, only: nblocks + use ice_domain_size, only: max_blocks + use ice_flux, only: albcnt, snwcnt + use ice_history_shared + use ice_restart_shared, only: restart_dir + use ice_timers, only: ice_timer_start, ice_timer_stop, timer_readwrite + use pio + + ! local variables + + real (kind=dbl_kind), dimension(:,:,:), allocatable :: work2 + real (kind=dbl_kind), dimension(:,:,:,:), allocatable :: work3 + real (kind=dbl_kind), dimension(:,:,:,:,:), allocatable :: work4 + + integer (kind=int_kind) :: i,j,k,n,nn,ns,ncid,status + logical (kind=log_kind) :: exists + character (char_len_long) :: ncfile + character (len=1) :: cns + character (len=32) :: readstr + character (len=*), parameter :: readstrT = ' read ok:' + character (len=*), parameter :: readstrF = ' DID NOT READ:' + + integer (kind=int_kind), parameter :: histprec=8 ! hardwired to double + + type(file_desc_t) :: File + type(io_desc_t) :: iodesc2d, & + iodesc3dc, iodesc3di, iodesc3db, iodesc3da, iodesc3df, & + iodesc4di, iodesc4ds, iodesc4df + type(var_desc_t) :: varid + + logical (kind=log_kind), save :: first_call = .true. + + character(len=*), parameter :: subname = '(ice_read_hist)' + + call ice_timer_start(timer_readwrite) ! reading/writing + do ns = 1,nstreams + if (hist_avg(ns)) then + + write(cns,'(i1.1)') ns + + if (my_task == master_task) then + call construct_filename(ncfile,'nc',ns, option='histrest') + ncfile = trim(restart_dir)//ncfile + write(nu_diag,*) subname,' reading file ',trim(ncfile) + endif + call broadcast_scalar(ncfile, master_task) + + ! open file + inquire(file=trim(ncfile),exist=exists) + if (exists) then + File%fh=-1 + call ice_pio_init(mode='read', filename=trim(ncfile), File=File, & + fformat=trim(history_format), rearr=trim(history_rearranger), & + iotasks=history_iotasks, root=history_root, stride=history_stride, debug=first_call) + + call pio_seterrorhandling(File, PIO_RETURN_ERROR) + + call ice_pio_initdecomp(iodesc=iodesc2d, precision=histprec) + call ice_pio_initdecomp(ndim3=ncat_hist, iodesc=iodesc3dc, precision=histprec) + call ice_pio_initdecomp(ndim3=nzilyr, iodesc=iodesc3di, precision=histprec) + call ice_pio_initdecomp(ndim3=nzblyr, iodesc=iodesc3db, precision=histprec) + call ice_pio_initdecomp(ndim3=nzalyr, iodesc=iodesc3da, precision=histprec) + call ice_pio_initdecomp(ndim3=nfsd_hist, iodesc=iodesc3df, precision=histprec) + call ice_pio_initdecomp(ndim3=nzilyr, ndim4=ncat_hist, iodesc=iodesc4di, precision=histprec) + call ice_pio_initdecomp(ndim3=nzslyr, ndim4=ncat_hist, iodesc=iodesc4ds, precision=histprec) + call ice_pio_initdecomp(ndim3=nfsd_hist, ndim4=ncat_hist, iodesc=iodesc4df, precision=histprec) + + !----------------------------------------------------------------- + ! read variable data + !----------------------------------------------------------------- + + readstr = readstrF + status = pio_inq_varid(File, 'time_beg', varid) + if (status == PIO_NOERR) status = pio_get_var(File,varid,(/1/),time_beg(ns)) + if (status == PIO_NOERR) readstr = readstrT + if (my_task == master_task) then + write(nu_diag,*) subname,trim(readstr),' time_beg' + endif + + readstr = readstrF + status = pio_inq_varid(File, 'avgct', varid) + if (status == PIO_NOERR) status = pio_get_var(File,varid,(/1/),avgct(ns)) + if (status == PIO_NOERR) readstr = readstrT + if (my_task == master_task) then + write(nu_diag,*) subname,trim(readstr),' avgct' + endif + + allocate(work2(nx_block,ny_block,max_blocks)) + + work2(:,:,:) = c0 + readstr = readstrF + status = pio_inq_varid(File, 'albcnt'//cns, varid) + if (status == PIO_NOERR) call pio_read_darray(File, varid, iodesc2d, work2, status) + if (status == PIO_NOERR) then + readstr = readstrT + albcnt(:,:,:,ns) = work2(:,:,:) + endif + if (my_task == master_task) then + write(nu_diag,*) subname,trim(readstr),' albcnt'//cns + endif + + work2(:,:,:) = c0 + readstr = readstrF + status = pio_inq_varid(File, 'snwcnt'//cns, varid) + if (status == PIO_NOERR) call pio_read_darray(File, varid, iodesc2d, work2, status) + if (status == PIO_NOERR) then + readstr = readstrT + snwcnt(:,:,:,ns) = work2(:,:,:) + endif + if (my_task == master_task) then + write(nu_diag,*) subname,trim(readstr),' snwcnt'//cns + endif + + do n=1,num_avail_hist_fields_2D + if (avail_hist_fields(n)%vhistfreq == histfreq(ns)) then + readstr = readstrF + status = pio_inq_varid(File,avail_hist_fields(n)%vname,varid) + work2(:,:,:) = c0 + if (status == PIO_NOERR) call pio_read_darray(File, varid, iodesc2d, work2, status) + if (status == PIO_NOERR) then + readstr = readstrT + a2D(:,:,n,:) = work2(:,:,:) + endif + if (my_task == master_task) then + write(nu_diag,*) subname,trim(readstr),trim(avail_hist_fields(n)%vname) + endif + endif + enddo + + deallocate(work2) + allocate(work3(nx_block,ny_block,max_blocks,ncat_hist)) + + ! 2D + do n = n2D + 1, n3Dccum + nn = n - n2D + if (avail_hist_fields(n)%vhistfreq == histfreq(ns)) then + readstr = readstrF + status = pio_inq_varid(File,avail_hist_fields(n)%vname,varid) + work3(:,:,:,:) = c0 + if (status == PIO_NOERR) call pio_read_darray(File, varid, iodesc3dc, work3, status) + if (status == PIO_NOERR) then + readstr = readstrT + do j = 1, nblocks + do i = 1, ncat_hist + a3Dc(:,:,i,nn,j) = work3(:,:,j,i) + enddo + enddo + endif + if (my_task == master_task) then + write(nu_diag,*) subname,trim(readstr),trim(avail_hist_fields(n)%vname) + endif + endif + enddo + + deallocate(work3) + allocate(work3(nx_block,ny_block,max_blocks,ncat_hist)) + + ! 3D (category) + do n = n2D + 1, n3Dccum + nn = n - n2D + if (avail_hist_fields(n)%vhistfreq == histfreq(ns)) then + readstr = readstrF + status = pio_inq_varid(File,avail_hist_fields(n)%vname,varid) + work3(:,:,:,:) = c0 + if (status == PIO_NOERR) call pio_read_darray(File, varid, iodesc3dc, work3, status) + if (status == PIO_NOERR) then + readstr = readstrT + do j = 1, nblocks + do i = 1, ncat_hist + a3Dc(:,:,i,nn,j) = work3(:,:,j,i) + enddo + enddo + endif + if (my_task == master_task) then + write(nu_diag,*) subname,trim(readstr),trim(avail_hist_fields(n)%vname) + endif + endif + enddo + + deallocate(work3) + allocate(work3(nx_block,ny_block,max_blocks,nzilyr)) + + ! 3D (vertical ice) + do n = n3Dccum+1, n3Dzcum + nn = n - n3Dccum + if (avail_hist_fields(n)%vhistfreq == histfreq(ns)) then + readstr = readstrF + status = pio_inq_varid(File,avail_hist_fields(n)%vname,varid) + work3(:,:,:,:) = c0 + if (status == PIO_NOERR) call pio_read_darray(File, varid, iodesc3di, work3, status) + if (status == PIO_NOERR) then + readstr = readstrT + do j = 1, nblocks + do i = 1, nzilyr + a3Dz(:,:,i,nn,j) = work3(:,:,j,i) + enddo + enddo + endif + if (my_task == master_task) then + write(nu_diag,*) subname,trim(readstr),trim(avail_hist_fields(n)%vname) + endif + endif + enddo + + deallocate(work3) + allocate(work3(nx_block,ny_block,max_blocks,nzblyr)) + + ! 3D (vertical ice biology) + do n = n3Dzcum+1, n3Dbcum + nn = n - n3Dzcum + if (avail_hist_fields(n)%vhistfreq == histfreq(ns)) then + readstr = readstrF + status = pio_inq_varid(File,avail_hist_fields(n)%vname,varid) + work3(:,:,:,:) = c0 + if (status == PIO_NOERR) call pio_read_darray(File, varid, iodesc3db, work3, status) + if (status == PIO_NOERR) then + readstr = readstrT + do j = 1, nblocks + do i = 1, nzblyr + a3Db(:,:,i,nn,j) = work3(:,:,j,i) + enddo + enddo + endif + if (my_task == master_task) then + write(nu_diag,*) subname,trim(readstr),trim(avail_hist_fields(n)%vname) + endif + endif + enddo + + deallocate(work3) + allocate(work3(nx_block,ny_block,max_blocks,nzalyr)) + + ! 3D (vertical snow biology) + do n = n3Dbcum+1, n3Dacum + nn = n - n3Dbcum + if (avail_hist_fields(n)%vhistfreq == histfreq(ns)) then + readstr = readstrF + status = pio_inq_varid(File,avail_hist_fields(n)%vname,varid) + work3(:,:,:,:) = c0 + if (status == PIO_NOERR) call pio_read_darray(File, varid, iodesc3da, work3, status) + if (status == PIO_NOERR) then + readstr = readstrT + do j = 1, nblocks + do i = 1, nzalyr + a3Da(:,:,i,nn,j) = work3(:,:,j,i) + enddo + enddo + endif + if (my_task == master_task) then + write(nu_diag,*) subname,trim(readstr),trim(avail_hist_fields(n)%vname) + endif + endif + enddo + + deallocate(work3) + allocate(work3(nx_block,ny_block,max_blocks,nfsd_hist)) + + ! 3D (fsd) + do n = n3Dacum+1, n3Dfcum + nn = n - n3Dacum + if (avail_hist_fields(n)%vhistfreq == histfreq(ns)) then + readstr = readstrF + status = pio_inq_varid(File,avail_hist_fields(n)%vname,varid) + work3(:,:,:,:) = c0 + if (status == PIO_NOERR) call pio_read_darray(File, varid, iodesc3df, work3, status) + if (status == PIO_NOERR) then + readstr = readstrT + do j = 1, nblocks + do i = 1, nfsd_hist + a3Df(:,:,i,nn,j) = work3(:,:,j,i) + enddo + enddo + endif + if (my_task == master_task) then + write(nu_diag,*) subname,trim(readstr),trim(avail_hist_fields(n)%vname) + endif + endif + enddo + + deallocate(work3) + allocate(work4(nx_block,ny_block,max_blocks,nzilyr,ncat_hist)) + + ! 4D (categories, vertical ice) + do n = n3Dfcum+1, n4Dicum + nn = n - n3Dfcum + if (avail_hist_fields(n)%vhistfreq == histfreq(ns)) then + readstr = readstrF + status = pio_inq_varid(File,avail_hist_fields(n)%vname,varid) + work4(:,:,:,:,:) = c0 + if (status == PIO_NOERR) call pio_read_darray(File, varid, iodesc4di, work4, status) + if (status == PIO_NOERR) then + readstr = readstrT + do j = 1, nblocks + do i = 1, ncat_hist + do k = 1, nzilyr + a4Di(:,:,k,i,nn,j) = work4(:,:,j,k,i) + enddo + enddo + enddo + endif + if (my_task == master_task) then + write(nu_diag,*) subname,trim(readstr),trim(avail_hist_fields(n)%vname) + endif + endif + enddo + + deallocate(work4) + allocate(work4(nx_block,ny_block,max_blocks,nzslyr,ncat_hist)) + + ! 4D (categories, vertical snow) + do n = n4Dicum+1, n4Dscum + nn = n - n4Dicum + if (avail_hist_fields(n)%vhistfreq == histfreq(ns)) then + readstr = readstrF + status = pio_inq_varid(File,avail_hist_fields(n)%vname,varid) + work4(:,:,:,:,:) = c0 + if (status == PIO_NOERR) call pio_read_darray(File, varid, iodesc4ds, work4, status) + if (status == PIO_NOERR) then + readstr = readstrT + do j = 1, nblocks + do i = 1, ncat_hist + do k = 1, nzslyr + a4Ds(:,:,k,i,nn,j) = work4(:,:,j,k,i) + enddo + enddo + enddo + endif + if (my_task == master_task) then + write(nu_diag,*) subname,trim(readstr),trim(avail_hist_fields(n)%vname) + endif + endif + enddo + + deallocate(work4) + allocate(work4(nx_block,ny_block,max_blocks,nfsd_hist,ncat_hist)) + + ! 4D (categories, fsd) + do n = n4Dscum+1, n4Dfcum + nn = n - n4Dscum + if (avail_hist_fields(n)%vhistfreq == histfreq(ns)) then + readstr = readstrF + status = pio_inq_varid(File,avail_hist_fields(n)%vname,varid) + work4(:,:,:,:,:) = c0 + if (status == PIO_NOERR) call pio_read_darray(File, varid, iodesc4df, work4, status) + if (status == PIO_NOERR) then + readstr = readstrT + do j = 1, nblocks + do i = 1, ncat_hist + do k = 1, nfsd_hist + a4Df(:,:,k,i,nn,j) = work4(:,:,j,k,i) + enddo + enddo + enddo + endif + if (my_task == master_task) then + write(nu_diag,*) subname,trim(readstr),trim(avail_hist_fields(n)%vname) + endif + endif + enddo + + deallocate(work4) + + !----------------------------------------------------------------- + ! clean-up PIO descriptors + !----------------------------------------------------------------- + call pio_seterrorhandling(File, PIO_INTERNAL_ERROR) + + call pio_freedecomp(File,iodesc2d) + call pio_freedecomp(File,iodesc3dc) + call pio_freedecomp(File,iodesc3di) + call pio_freedecomp(File,iodesc3db) + call pio_freedecomp(File,iodesc3da) + call pio_freedecomp(File,iodesc3df) + call pio_freedecomp(File,iodesc4di) + call pio_freedecomp(File,iodesc4ds) + call pio_freedecomp(File,iodesc4df) + + !----------------------------------------------------------------- + ! close output dataset + !----------------------------------------------------------------- + + call pio_closefile(File) + if (my_task == master_task) then + write(nu_diag,*) subname,' Finished reading ',trim(ncfile) + endif + + !----------------------------------------------------------------- + ! clean up PIO + !----------------------------------------------------------------- + + call ice_pio_finalize() + + first_call = .false. + + endif ! open file success + endif ! hist_avg + enddo ! nstreams + call ice_timer_stop(timer_readwrite) ! reading/writing + + end subroutine ice_read_hist + !======================================================================= ! Defines a coordinate var in the history file ! coordinates have short_name, long_name and units attributes, diff --git a/cicecore/drivers/direct/hadgem3/CICE_InitMod.F90 b/cicecore/drivers/direct/hadgem3/CICE_InitMod.F90 index cc3a4caff..cbafc3868 100644 --- a/cicecore/drivers/direct/hadgem3/CICE_InitMod.F90 +++ b/cicecore/drivers/direct/hadgem3/CICE_InitMod.F90 @@ -82,6 +82,7 @@ subroutine cice_init faero_data, faero_default, alloc_forcing_bgc use ice_grid, only: init_grid1, init_grid2, alloc_grid, dealloc_grid use ice_history, only: init_hist, accum_hist + use ice_history_write, only: ice_read_hist use ice_restart_shared, only: restart, runid, runtype use ice_init, only: input_data, init_state use ice_init_column, only: init_thermo_vertical, init_shortwave, init_zbgc, input_zbgc, count_tracers @@ -214,6 +215,7 @@ subroutine cice_init call dealloc_grid ! deallocate temporary grid arrays if (write_ic) call accum_hist(dt) ! write initial conditions + call ice_read_hist ! read history restarts end subroutine cice_init diff --git a/cicecore/drivers/direct/nemo_concepts/CICE_InitMod.F90 b/cicecore/drivers/direct/nemo_concepts/CICE_InitMod.F90 index 4921482a6..581510154 100644 --- a/cicecore/drivers/direct/nemo_concepts/CICE_InitMod.F90 +++ b/cicecore/drivers/direct/nemo_concepts/CICE_InitMod.F90 @@ -82,6 +82,7 @@ subroutine cice_init faero_data, faero_default, alloc_forcing_bgc use ice_grid, only: init_grid1, init_grid2, alloc_grid, dealloc_grid use ice_history, only: init_hist, accum_hist + use ice_history_write, only: ice_read_hist use ice_restart_shared, only: restart, runid, runtype use ice_init, only: input_data, init_state use ice_init_column, only: init_thermo_vertical, init_shortwave, init_zbgc, input_zbgc, count_tracers @@ -183,6 +184,7 @@ subroutine cice_init call init_shortwave ! initialize radiative transfer if (write_ic) call accum_hist(dt) ! write initial conditions + call ice_read_hist ! read history restarts ! determine the time and date at the end of the first timestep call advance_timestep() diff --git a/cicecore/drivers/mapl/geos/CICE_InitMod.F90 b/cicecore/drivers/mapl/geos/CICE_InitMod.F90 index f187b9eb7..5a4e796ce 100644 --- a/cicecore/drivers/mapl/geos/CICE_InitMod.F90 +++ b/cicecore/drivers/mapl/geos/CICE_InitMod.F90 @@ -145,6 +145,7 @@ subroutine cice_init2!(yr, mo, dy, hr, mn, sc) use ice_forcing_bgc , only: get_forcing_bgc, get_atm_bgc use ice_forcing_bgc , only: faero_default, alloc_forcing_bgc, fiso_default use ice_history , only: init_hist, accum_hist + use ice_history_write, only: ice_read_hist use ice_restart_shared , only: restart, runtype use ice_init , only: input_data, init_state use ice_init_column , only: init_thermo_vertical, init_shortwave, init_zbgc @@ -262,6 +263,7 @@ subroutine cice_init2!(yr, mo, dy, hr, mn, sc) if (write_ic) then call accum_hist(dt) ! write initial conditions end if + call ice_read_hist ! read history restarts call dealloc_grid ! deallocate temporary grid arrays diff --git a/cicecore/drivers/mct/cesm1/CICE_InitMod.F90 b/cicecore/drivers/mct/cesm1/CICE_InitMod.F90 index 8af7704fb..e864372d8 100644 --- a/cicecore/drivers/mct/cesm1/CICE_InitMod.F90 +++ b/cicecore/drivers/mct/cesm1/CICE_InitMod.F90 @@ -84,6 +84,7 @@ subroutine cice_init(mpicom_ice) faero_default, alloc_forcing_bgc, fiso_default use ice_grid, only: init_grid1, init_grid2, alloc_grid, dealloc_grid use ice_history, only: init_hist, accum_hist + use ice_history_write, only: ice_read_hist use ice_restart_shared, only: restart, runtype use ice_init, only: input_data, init_state use ice_init_column, only: init_thermo_vertical, init_shortwave, init_zbgc, input_zbgc, count_tracers @@ -200,6 +201,7 @@ subroutine cice_init(mpicom_ice) call init_shortwave ! initialize radiative transfer if (write_ic) call accum_hist(dt) ! write initial conditions + call ice_read_hist ! read history restarts ! call advance_timestep() diff --git a/cicecore/drivers/mct/cesm1/ice_comp_esmf.F90 b/cicecore/drivers/mct/cesm1/ice_comp_esmf.F90 index 454895410..f0e83612c 100644 --- a/cicecore/drivers/mct/cesm1/ice_comp_esmf.F90 +++ b/cicecore/drivers/mct/cesm1/ice_comp_esmf.F90 @@ -147,6 +147,7 @@ subroutine ice_init_esmf(comp, import_state, export_state, EClock, rc) use CICE_InitMod use ice_restart_shared, only: runid, runtype, restart_dir, restart_format use ice_history, only: accum_hist + use ice_history_write, only: ice_read_hist use ice_history_shared, only: history_dir, history_file use icepack_intfc, only: tr_aero, tr_zaero ! @@ -384,6 +385,7 @@ subroutine ice_init_esmf(comp, import_state, export_state, EClock, rc) call calendar(time) ! update calendar info if (write_ic) call accum_hist(dt) ! write initial conditions + call ice_read_hist ! read history restarts !--------------------------------------------------------------------------- ! Initialize MCT attribute vectors and indices diff --git a/cicecore/drivers/mct/cesm1/ice_comp_mct.F90 b/cicecore/drivers/mct/cesm1/ice_comp_mct.F90 index a1d1a2ad1..f05a47888 100644 --- a/cicecore/drivers/mct/cesm1/ice_comp_mct.F90 +++ b/cicecore/drivers/mct/cesm1/ice_comp_mct.F90 @@ -122,6 +122,7 @@ subroutine ice_init_mct( EClock, cdata_i, x2i_i, i2x_i, NLFilename ) use CICE_InitMod use ice_restart_shared, only: runid, runtype, restart_dir, restart_format use ice_history, only: accum_hist + use ice_history_write, only: ice_read_hist use ice_history_shared, only: history_dir, history_file ! ! !ARGUMENTS: @@ -352,6 +353,7 @@ subroutine ice_init_mct( EClock, cdata_i, x2i_i, i2x_i, NLFilename ) call calendar ! update calendar info if (write_ic) call accum_hist(dt) ! write initial conditions + call ice_read_hist ! read history restarts !--------------------------------------------------------------------------- ! Initialize MCT attribute vectors and indices diff --git a/cicecore/drivers/nuopc/cmeps/ice_comp_nuopc.F90 b/cicecore/drivers/nuopc/cmeps/ice_comp_nuopc.F90 index f2b2e2833..3db0b568b 100644 --- a/cicecore/drivers/nuopc/cmeps/ice_comp_nuopc.F90 +++ b/cicecore/drivers/nuopc/cmeps/ice_comp_nuopc.F90 @@ -33,6 +33,7 @@ module ice_comp_nuopc use ice_restart_shared , only : runid, runtype, restart, use_restart_time, restart_dir, restart_file, & restart_format, restart_chunksize, pointer_date use ice_history , only : accum_hist + use ice_history_write , only : ice_read_hist use ice_history_shared , only : history_format, history_chunksize use ice_exit , only : abort_ice use icepack_intfc , only : icepack_warnings_flush, icepack_warnings_aborted @@ -903,6 +904,7 @@ subroutine InitializeRealize(gcomp, importState, exportState, clock, rc) if (write_ic) then call accum_hist(dt) ! write initial conditions end if + call ice_read_hist ! read history restarts !----------------------------------------------------------------- ! Prescribed ice initialization diff --git a/cicecore/drivers/nuopc/dmi/CICE_InitMod.F90 b/cicecore/drivers/nuopc/dmi/CICE_InitMod.F90 index 4f4449546..7cea84db3 100644 --- a/cicecore/drivers/nuopc/dmi/CICE_InitMod.F90 +++ b/cicecore/drivers/nuopc/dmi/CICE_InitMod.F90 @@ -89,6 +89,7 @@ subroutine cice_init(mpi_comm) faero_default, alloc_forcing_bgc, fiso_default use ice_grid, only: init_grid1, init_grid2, alloc_grid, dealloc_grid use ice_history, only: init_hist, accum_hist + use ice_history_write, only: ice_read_hist use ice_restart_shared, only: restart, runtype use ice_init, only: input_data, init_state use ice_init_column, only: init_thermo_vertical, init_shortwave, init_zbgc, input_zbgc, count_tracers @@ -258,6 +259,7 @@ subroutine cice_init(mpi_comm) call init_flux_ocn ! initialize ocean fluxes sent to coupler if (write_ic) call accum_hist(dt) ! write initial conditions + call ice_read_hist ! read history restarts call dealloc_grid ! deallocate temporary grid arrays if (my_task == master_task) then diff --git a/cicecore/drivers/standalone/cice/CICE_InitMod.F90 b/cicecore/drivers/standalone/cice/CICE_InitMod.F90 index 66a5256e0..74589a064 100644 --- a/cicecore/drivers/standalone/cice/CICE_InitMod.F90 +++ b/cicecore/drivers/standalone/cice/CICE_InitMod.F90 @@ -84,6 +84,7 @@ subroutine cice_init faero_default, alloc_forcing_bgc, fiso_default use ice_grid, only: init_grid1, init_grid2, alloc_grid, dealloc_grid use ice_history, only: init_hist, accum_hist + use ice_history_write, only: ice_read_hist use ice_restart_shared, only: restart, runtype use ice_init, only: input_data, init_state use ice_init_column, only: init_thermo_vertical, init_shortwave, init_zbgc, input_zbgc, count_tracers @@ -197,6 +198,7 @@ subroutine cice_init call init_shortwave ! initialize radiative transfer if (write_ic) call accum_hist(dt) ! write initial conditions + call ice_read_hist ! read history restarts ! tcraig, use advance_timestep here ! istep = istep + 1 ! update time step counters diff --git a/cicecore/drivers/unittest/gridavgchk/CICE_InitMod.F90 b/cicecore/drivers/unittest/gridavgchk/CICE_InitMod.F90 index 66a5256e0..74589a064 100644 --- a/cicecore/drivers/unittest/gridavgchk/CICE_InitMod.F90 +++ b/cicecore/drivers/unittest/gridavgchk/CICE_InitMod.F90 @@ -84,6 +84,7 @@ subroutine cice_init faero_default, alloc_forcing_bgc, fiso_default use ice_grid, only: init_grid1, init_grid2, alloc_grid, dealloc_grid use ice_history, only: init_hist, accum_hist + use ice_history_write, only: ice_read_hist use ice_restart_shared, only: restart, runtype use ice_init, only: input_data, init_state use ice_init_column, only: init_thermo_vertical, init_shortwave, init_zbgc, input_zbgc, count_tracers @@ -197,6 +198,7 @@ subroutine cice_init call init_shortwave ! initialize radiative transfer if (write_ic) call accum_hist(dt) ! write initial conditions + call ice_read_hist ! read history restarts ! tcraig, use advance_timestep here ! istep = istep + 1 ! update time step counters diff --git a/cicecore/drivers/unittest/halochk/CICE_InitMod.F90 b/cicecore/drivers/unittest/halochk/CICE_InitMod.F90 index 66a5256e0..74589a064 100644 --- a/cicecore/drivers/unittest/halochk/CICE_InitMod.F90 +++ b/cicecore/drivers/unittest/halochk/CICE_InitMod.F90 @@ -84,6 +84,7 @@ subroutine cice_init faero_default, alloc_forcing_bgc, fiso_default use ice_grid, only: init_grid1, init_grid2, alloc_grid, dealloc_grid use ice_history, only: init_hist, accum_hist + use ice_history_write, only: ice_read_hist use ice_restart_shared, only: restart, runtype use ice_init, only: input_data, init_state use ice_init_column, only: init_thermo_vertical, init_shortwave, init_zbgc, input_zbgc, count_tracers @@ -197,6 +198,7 @@ subroutine cice_init call init_shortwave ! initialize radiative transfer if (write_ic) call accum_hist(dt) ! write initial conditions + call ice_read_hist ! read history restarts ! tcraig, use advance_timestep here ! istep = istep + 1 ! update time step counters diff --git a/cicecore/drivers/unittest/opticep/CICE_InitMod.F90 b/cicecore/drivers/unittest/opticep/CICE_InitMod.F90 index 66a5256e0..74589a064 100644 --- a/cicecore/drivers/unittest/opticep/CICE_InitMod.F90 +++ b/cicecore/drivers/unittest/opticep/CICE_InitMod.F90 @@ -84,6 +84,7 @@ subroutine cice_init faero_default, alloc_forcing_bgc, fiso_default use ice_grid, only: init_grid1, init_grid2, alloc_grid, dealloc_grid use ice_history, only: init_hist, accum_hist + use ice_history_write, only: ice_read_hist use ice_restart_shared, only: restart, runtype use ice_init, only: input_data, init_state use ice_init_column, only: init_thermo_vertical, init_shortwave, init_zbgc, input_zbgc, count_tracers @@ -197,6 +198,7 @@ subroutine cice_init call init_shortwave ! initialize radiative transfer if (write_ic) call accum_hist(dt) ! write initial conditions + call ice_read_hist ! read history restarts ! tcraig, use advance_timestep here ! istep = istep + 1 ! update time step counters diff --git a/cicecore/drivers/unittest/sumchk/CICE_InitMod.F90 b/cicecore/drivers/unittest/sumchk/CICE_InitMod.F90 index 66a5256e0..74589a064 100644 --- a/cicecore/drivers/unittest/sumchk/CICE_InitMod.F90 +++ b/cicecore/drivers/unittest/sumchk/CICE_InitMod.F90 @@ -84,6 +84,7 @@ subroutine cice_init faero_default, alloc_forcing_bgc, fiso_default use ice_grid, only: init_grid1, init_grid2, alloc_grid, dealloc_grid use ice_history, only: init_hist, accum_hist + use ice_history_write, only: ice_read_hist use ice_restart_shared, only: restart, runtype use ice_init, only: input_data, init_state use ice_init_column, only: init_thermo_vertical, init_shortwave, init_zbgc, input_zbgc, count_tracers @@ -197,6 +198,7 @@ subroutine cice_init call init_shortwave ! initialize radiative transfer if (write_ic) call accum_hist(dt) ! write initial conditions + call ice_read_hist ! read history restarts ! tcraig, use advance_timestep here ! istep = istep + 1 ! update time step counters diff --git a/cicecore/shared/ice_calendar.F90 b/cicecore/shared/ice_calendar.F90 index 8f0e793aa..31ac6501c 100644 --- a/cicecore/shared/ice_calendar.F90 +++ b/cicecore/shared/ice_calendar.F90 @@ -123,6 +123,7 @@ module ice_calendar logical (kind=log_kind), public :: & use_leap_years , & ! use leap year functionality if true write_ic , & ! write initial condition now + write_histrest , & ! write history restarts if needed dump_last , & ! write restart file on last time step force_restart_now, & ! force a restart now write_history(max_nstrm) ! write history now diff --git a/configuration/scripts/ice_in b/configuration/scripts/ice_in index 5c2bb87ee..98ac2dbbb 100644 --- a/configuration/scripts/ice_in +++ b/configuration/scripts/ice_in @@ -68,6 +68,7 @@ history_deflate = 0 history_chunksize = 0, 0 hist_time_axis = 'end' + write_histrest = .true. write_ic = .true. incond_dir = './history/' incond_file = 'iceh_ic' diff --git a/configuration/scripts/machines/env.derecho_cray b/configuration/scripts/machines/env.derecho_cray index 4e886ab71..2eef6aaaa 100644 --- a/configuration/scripts/machines/env.derecho_cray +++ b/configuration/scripts/machines/env.derecho_cray @@ -20,6 +20,7 @@ module load netcdf/4.9.2 #module load netcdf-mpi/4.9.2 module load cray-libsci/23.09.1.1 +module load nco if ($?ICE_IOTYPE) then if ($ICE_IOTYPE =~ pio*) then diff --git a/configuration/scripts/machines/env.derecho_gnu b/configuration/scripts/machines/env.derecho_gnu index 330509636..4ddf4c3a9 100644 --- a/configuration/scripts/machines/env.derecho_gnu +++ b/configuration/scripts/machines/env.derecho_gnu @@ -18,6 +18,7 @@ module load ncarcompilers module load cray-mpich/8.1.29 module load netcdf/4.9.2 module load cray-libsci/24.03.0 +module load nco if ($?ICE_IOTYPE) then if ($ICE_IOTYPE =~ pio*) then diff --git a/configuration/scripts/machines/env.derecho_intel b/configuration/scripts/machines/env.derecho_intel index 05c719838..ada9344bf 100644 --- a/configuration/scripts/machines/env.derecho_intel +++ b/configuration/scripts/machines/env.derecho_intel @@ -20,6 +20,7 @@ module load netcdf/4.9.2 #module load netcdf-mpi/4.9.2 module load cray-libsci/23.09.1.1 +module load nco if ($?ICE_IOTYPE) then if ($ICE_IOTYPE =~ pio*) then diff --git a/configuration/scripts/machines/env.derecho_intelclassic b/configuration/scripts/machines/env.derecho_intelclassic index 8d3639a5e..e1ba716be 100644 --- a/configuration/scripts/machines/env.derecho_intelclassic +++ b/configuration/scripts/machines/env.derecho_intelclassic @@ -20,6 +20,7 @@ module load netcdf/4.9.2 #module load netcdf-mpi/4.9.2 #module load cray-libsci/23.02.1.1 +module load nco if ($?ICE_IOTYPE) then if ($ICE_IOTYPE =~ pio*) then diff --git a/configuration/scripts/machines/env.derecho_inteloneapi b/configuration/scripts/machines/env.derecho_inteloneapi index 79715ba2a..b90958e7d 100644 --- a/configuration/scripts/machines/env.derecho_inteloneapi +++ b/configuration/scripts/machines/env.derecho_inteloneapi @@ -21,6 +21,7 @@ module load netcdf/4.9.2 #module load netcdf-mpi/4.9.2 module load cray-libsci/23.09.1.1 +module load nco if ($?ICE_IOTYPE) then if ($ICE_IOTYPE =~ pio*) then diff --git a/configuration/scripts/machines/env.derecho_nvhpc b/configuration/scripts/machines/env.derecho_nvhpc index 99aa6430a..c482972dc 100644 --- a/configuration/scripts/machines/env.derecho_nvhpc +++ b/configuration/scripts/machines/env.derecho_nvhpc @@ -20,6 +20,7 @@ module load netcdf/4.9.2 #module load netcdf-mpi/4.9.2 module load cray-libsci/23.09.1.1 +module load nco if ($?ICE_IOTYPE) then if ($ICE_IOTYPE =~ pio*) then diff --git a/configuration/scripts/options/set_nml.cmip b/configuration/scripts/options/set_nml.cmip index 80d30a755..f38b8a305 100644 --- a/configuration/scripts/options/set_nml.cmip +++ b/configuration/scripts/options/set_nml.cmip @@ -134,6 +134,7 @@ f_icespd = 'x' f_apeff = 'x' f_apond = 'md' + f_apond_ai = 'md' f_hpond = 'x' f_ipond = 'x' f_fsloss = 'x' diff --git a/configuration/scripts/options/set_nml.histall b/configuration/scripts/options/set_nml.histall index 5423e0216..e05ff729b 100644 --- a/configuration/scripts/options/set_nml.histall +++ b/configuration/scripts/options/set_nml.histall @@ -181,6 +181,18 @@ f_hpond_ai = 'md' f_ipond_ai = 'md' f_apeff_ai = 'md' + f_smassicen = 'md' + f_smassliqn = 'md' + f_rhos_cmpn = 'md' + f_rhos_cntn = 'md' + f_rsnwn = 'md' + f_smassice = 'md' + f_smassliq = 'md' + f_rhos_cmp = 'md' + f_rhos_cnt = 'md' + f_rsnw = 'md' + f_meltsliq = 'md' + f_fsloss = 'md' f_fiso_atm = 'md' f_fiso_ocn = 'md' f_iso = 'md' diff --git a/configuration/scripts/options/set_nml.histall10d b/configuration/scripts/options/set_nml.histall10d new file mode 100644 index 000000000..0ba5b6809 --- /dev/null +++ b/configuration/scripts/options/set_nml.histall10d @@ -0,0 +1,334 @@ + grid_outfile = .true. + histfreq = 'd','h','m','x','x' + histfreq_n = 10,24,1 + histfreq_base = 'zero','init','zero' + hist_avg = .true.,.true.,.true. + write_histrest = .true. + write_ic = .true. + f_tmask = .true. + f_blkmask = .true. + f_tarea = .true. + f_uarea = .true. + f_dxt = .true. + f_dyt = .true. + f_dxu = .true. + f_dyu = .true. + f_HTN = .true. + f_HTE = .true. + f_ANGLE = .true. + f_ANGLET = .true. + f_NCAT = .true. + f_VGRDi = .true. + f_VGRDs = .true. + f_VGRDb = .true. + f_VGRDa = .true. + f_bounds = .true. + f_aice = 'mdh' + f_hi = 'hdm' + f_hs = 'dmh' + f_Tsfc = 'mdh' + f_sice = 'hmd' + f_uvel = 'hmd' + f_vvel = 'hdm' + f_icespd = 'hmd' + f_icedir = 'md' + f_uatm = 'dm' + f_vatm = 'dm' + f_fswdn = 'dm' + f_flwdn = 'md' + f_snowfrac = 'md' + f_snow = 'md' + f_snow_ai = 'md' + f_rain = 'md' + f_rain_ai = 'md' + f_sst = 'md' + f_sss = 'md' + f_uocn = 'md' + f_vocn = 'md' + f_frzmlt = 'md' + f_fswfac = 'md' + f_fswint_ai = 'md' + f_fswabs = 'md' + f_fswabs_ai = 'md' + f_albsni = 'md' + f_alvdr = 'md' + f_alidr = 'md' + f_alvdf = 'md' + f_alidf = 'md' + f_alvdr_ai = 'md' + f_alidr_ai = 'md' + f_alvdf_ai = 'md' + f_alidf_ai = 'md' + f_albice = 'md' + f_albsno = 'md' + f_albpnd = 'md' + f_coszen = 'md' + f_flat = 'md' + f_flat_ai = 'md' + f_fsens = 'md' + f_fsens_ai = 'md' + f_fswup = 'md' + f_flwup = 'md' + f_flwup_ai = 'md' + f_evap = 'md' + f_evap_ai = 'md' + f_Tair = 'md' + f_Tref = 'md' + f_Qref = 'md' + f_congel = 'md' + f_frazil = 'md' + f_snoice = 'md' + f_dsnow = 'md' + f_melts = 'md' + f_meltt = 'md' + f_meltb = 'md' + f_meltl = 'md' + f_fresh = 'md' + f_fresh_ai = 'md' + f_fsalt = 'md' + f_fsalt_ai = 'md' + f_fbot = 'md' + f_fhocn = 'md' + f_fhocn_ai = 'md' + f_fswthru = 'md' + f_fswthru_ai = 'md' + f_fsurf_ai = 'md' + f_fcondtop_ai = 'md' + f_fmeltt_ai = 'md' + f_strairx = 'md' + f_strairy = 'md' + f_strtltx = 'md' + f_strtlty = 'md' + f_strcorx = 'md' + f_strcory = 'md' + f_strocnx = 'md' + f_strocny = 'md' + f_strintx = 'md' + f_strinty = 'md' + f_taubx = 'md' + f_tauby = 'md' + f_strength = 'md' + f_divu = 'md' + f_shear = 'md' + f_vort = 'md' + f_sig1 = 'md' + f_sig2 = 'md' + f_sigP = 'md' + f_dvidtt = 'md' + f_dvidtd = 'md' + f_daidtt = 'md' + f_daidtd = 'md' + f_dagedtt = 'md' + f_dagedtd = 'md' + f_mlt_onset = 'x' + f_frz_onset = 'x' + f_hisnap = 'md' + f_aisnap = 'md' + f_trsig = 'md' + f_icepresent = 'md' + f_iage = 'md' + f_FY = 'md' + f_aicen = 'md' + f_vicen = 'md' + f_vsnon = 'md' + f_snowfracn = 'md' + f_keffn_top = 'md' + f_Tinz = 'md' + f_Sinz = 'md' + f_Tsnz = 'md' + f_fsurfn_ai = 'md' + f_fcondtopn_ai = 'md' + f_fmelttn_ai = 'md' + f_flatn_ai = 'md' + f_fsensn_ai = 'md' + f_alvl = 'md' + f_vlvl = 'md' + f_ardg = 'md' + f_vrdg = 'md' + f_dardg1dt = 'md' + f_dardg2dt = 'md' + f_dvirdgdt = 'md' + f_opening = 'md' + f_ardgn = 'md' + f_vrdgn = 'md' + f_dardg1ndt = 'md' + f_dardg2ndt = 'md' + f_dvirdgndt = 'md' + f_krdgn = 'md' + f_aparticn = 'md' + f_aredistn = 'md' + f_vredistn = 'md' + f_araftn = 'md' + f_vraftn = 'md' + f_apondn = 'md' + f_apeffn = 'md' + f_hpondn = 'md' + f_dpnd_flushn = 'md' + f_dpnd_exponn = 'md' + f_dpnd_freebdn = 'md' + f_dpnd_initialn= 'md' + f_dpnd_dlidn = 'md' + f_apond = 'md' + f_hpond = 'md' + f_ipond = 'md' + f_apeff = 'md' + f_dpnd_flush = 'md' + f_dpnd_expon = 'md' + f_dpnd_freebd = 'md' + f_dpnd_initial = 'md' + f_dpnd_dlid = 'md' + f_dpnd_melt = 'md' + f_dpnd_ridge = 'md' + f_apond_ai = 'md' + f_hpond_ai = 'md' + f_ipond_ai = 'md' + f_apeff_ai = 'md' + f_smassicen = 'md' + f_smassliqn = 'md' + f_rhos_cmpn = 'md' + f_rhos_cntn = 'md' + f_rsnwn = 'md' + f_smassice = 'md' + f_smassliq = 'md' + f_rhos_cmp = 'md' + f_rhos_cnt = 'md' + f_rsnw = 'md' + f_meltsliq = 'md' + f_fsloss = 'md' + f_fiso_atm = 'md' + f_fiso_ocn = 'md' + f_iso = 'md' + f_faero_atm = 'md' + f_faero_ocn = 'md' + f_aero = 'md' + f_fbio = 'md' + f_fbio_ai = 'md' + f_zaero = 'md' + f_bgc_S = 'md' + f_bgc_N = 'md' + f_bgc_C = 'md' + f_bgc_DOC = 'md' + f_bgc_DIC = 'md' + f_bgc_chl = 'md' + f_bgc_Nit = 'md' + f_bgc_Am = 'md' + f_bgc_Sil = 'md' + f_bgc_DMSPp = 'md' + f_bgc_DMSPd = 'md' + f_bgc_DMS = 'md' + f_bgc_DON = 'md' + f_bgc_Fe = 'md' + f_bgc_hum = 'md' + f_bgc_PON = 'md' + f_bgc_ml = 'md' + f_upNO = 'md' + f_upNH = 'md' + f_bTin = 'md' + f_bphi = 'md' + f_iDi = 'md' + f_iki = 'md' + f_fbri = 'md' + f_hbri = 'md' + f_zfswin = 'md' + f_bionet = 'md' + f_biosnow = 'md' + f_grownet = 'md' + f_PPnet = 'md' + f_algalpeak = 'md' + f_zbgc_frac = 'md' + f_drag = 'md' + f_Cdn_atm = 'md' + f_Cdn_ocn = 'md' + f_fsdrad = 'md' + f_fsdperim = 'md' + f_afsd = 'md' + f_afsdn = 'md' + f_dafsd_newi = 'md' + f_dafsd_latg = 'md' + f_dafsd_latm = 'md' + f_dafsd_wave = 'md' + f_dafsd_weld = 'md' + f_wave_sig_ht = 'md' + f_aice_ww = 'md' + f_diam_ww = 'md' + f_hice_ww = 'md' + f_aice_init = 'md' + f_siage = 'md' + f_siconc = 'md' + f_sifb = 'md' + f_siflcondbot = 'md' + f_siflcondtop = 'md' + f_sifllattop = 'md' + f_sifllwdtop = 'md' + f_sifllwutop = 'md' + f_siflsensbot = 'md' + f_siflsenstop = 'md' + f_siflswdtop = 'md' + f_siflswutop = 'md' + f_sihc = 'md' + f_siitdconc = 'md' + f_siitdsnconc = 'md' + f_siitdsnthick = 'md' + f_siitdthick = 'md' + f_simpconc = 'md' + f_simpeffconc = 'md' + f_simprefrozen = 'md' + f_simpthick = 'md' + f_sirdgconc = 'md' + f_sirdgthick = 'md' + f_sisali = 'md' + f_sisaltmass = 'md' + f_sisnhc = 'md' + f_sisnthick = 'md' + f_sitempbot = 'md' + f_sitempsnic = 'md' + f_sitemptop = 'md' + f_sithick = 'md' + f_sitimefrac = 'md' + f_siu = 'md' + f_siv = 'md' + f_sicompstren = 'md' + f_sidconcdyn = 'md' + f_sidconcth = 'md' + f_sidivvel = 'md' + f_sidmassdyn = 'md' + f_sidmassevapsubl = 'md' + f_sidmassgrowthbot = 'md' + f_sidmassgrowthsi = 'md' + f_sidmassgrowthwat = 'md' + f_sidmassmeltbot = 'md' + f_sidmassmeltlat = 'md' + f_sidmassmelttop = 'md' + f_sidmassth = 'md' + f_sidmasstranx = 'md' + f_sidmasstrany = 'md' + f_sidragbot = 'md' + f_sidragtop = 'md' + f_siflfwbot = 'md' + f_siflfwdrain = 'md' + f_siflsaltbot = 'md' + f_siforcecoriolx = 'md' + f_siforcecorioly = 'md' + f_siforceintstrx = 'md' + f_siforceintstry = 'md' + f_siforcetiltx = 'md' + f_siforcetilty = 'md' + f_simass = 'md' + f_sipr = 'md' + f_sishearvel = 'md' + f_sisnconc = 'md' + f_sisndmassdyn = 'md' + f_sisndmassmelt = 'md' + f_sisndmasssi = 'md' + f_sisndmasssnf = 'md' + f_sisndmasssubl = 'md' + f_sisndmasswind = 'md' + f_sisnmass = 'md' + f_sispeed = 'md' + f_sistressave = 'md' + f_sistressmax = 'md' + f_sistrxdtop = 'md' + f_sistrydtop = 'md' + f_sistrxubot = 'md' + f_sistryubot = 'md' + f_sivol = 'md' diff --git a/configuration/scripts/tests/comparebfb.csh b/configuration/scripts/tests/comparebfb.csh index 046f40651..2d2618b21 100755 --- a/configuration/scripts/tests/comparebfb.csh +++ b/configuration/scripts/tests/comparebfb.csh @@ -1,14 +1,14 @@ #!/bin/csh -f -# Compare the binary files +# Compare the CICE files via binary cmp diff #----------------------------------------------------------- # usage: comparebfb.csh base_file test_file -# does binary diff of two files +# does diff of two files # usage: comparebfb.csh base_dir test_dir -# looks for base_iced and iced binary files for comparison +# looks for base_iced and iced files for comparison # usage: comparebfb.csh base_dir -# looks for iced binary files in both directories for comparison +# looks for iced files in both directories for comparison # # Return Codes (depends on quality of error checking) # 0 = pass @@ -38,11 +38,11 @@ else if ( $#argv == 2 ) then else echo "Error in ${0}" echo "Usage: ${0} " - echo " does binary diff of two files" + echo " does diff of two files" echo "Usage: ${0} " - echo " looks for base_iced and iced binary files for comparison" + echo " looks for base_iced and iced files for comparison" echo "Usage: ${0} " - echo " looks for iced binary files in both directories for comparison" + echo " looks for iced files in both directories for comparison" exit 9 endif diff --git a/configuration/scripts/tests/io_suite.ts b/configuration/scripts/tests/io_suite.ts index 02e9e015e..7d7ee2ba3 100644 --- a/configuration/scripts/tests/io_suite.ts +++ b/configuration/scripts/tests/io_suite.ts @@ -7,6 +7,15 @@ smoke gx3 8x2 histall,ionetcdf,iocdf5,run5day #smoke gx3 8x2 histall,iopio2,iocdf5 smoke_gx3_8x2_histall_iocdf5_ionetcdf smoke gx3 8x2 histall,iopio2,iocdf5,run5day +# history restart tests +restart gx3 15x2 gx3ncarbulk,fsd12,isotope,debug,histall10d,iobinary +restart gx3 18x1 debug,fsd12,isotope,bgczm,histall10d,ionetcdf,iocdf5 +restart gx3 20x2 debug,fsd12,isotope,bgczm,histall10d,iopio1,iocdf5 +restart gx3 18x2 debug,fsd12,isotope,bgczm,histall10d,iopio2,iocdf2 +restart gx3 10x2 fsd12,isotope,bgczm,histall10d,ionetcdf,iocdf2 +restart gx3 40x1 fsd12,isotope,bgczm,histall10d,iopio1,iocdf1 +restart gx3 17x2 fsd12,isotope,bgczm,histall10d,iopio2,iocdf5 + # some iobinary configurations fail due to bathymetry netcdf file requirement, remove them # iobinary cannot work with JRA55 because netcdf is turned off restart gx3 8x4 gx3ncarbulk,debug,histall,iobinary,precision8 diff --git a/configuration/scripts/tests/test_restart.script b/configuration/scripts/tests/test_restart.script index 59729b361..e3719f7eb 100644 --- a/configuration/scripts/tests/test_restart.script +++ b/configuration/scripts/tests/test_restart.script @@ -21,20 +21,25 @@ if ( $res != 0 ) then exit 99 endif -# Prepend 'base_' to the final restart file to save for comparison +# Compute date of last file in first run if ( "${ICE_IOTYPE}" == "binary" ) then - set end_date = `ls -t1 ${ICE_RUNDIR}/restart | head -1 | awk -F'.' '{print $NF}'` - foreach file (${ICE_RUNDIR}/restart/*${end_date}) - set surname = `echo $file | awk -F'/' '{print $NF}'` - mv $file ${ICE_RUNDIR}/restart/base_$surname - end + set end_date = `ls -t1 ${ICE_RUNDIR}/restart | head -1 | rev | cut -d "." -f 1 | rev` else - set test_file = `ls -t1 ${ICE_RUNDIR}/restart | head -1` - set test_data = ${ICE_RUNDIR}/restart/${test_file} - set base_data = ${ICE_RUNDIR}/restart/base_${test_file} - mv ${test_data} ${base_data} + set end_date = `ls -t1 ${ICE_RUNDIR}/restart | head -1 | rev | cut -d "." -f 2 | rev` endif +# Prepend 'base_' to final restart and history restart files to save for comparison +foreach file (${ICE_RUNDIR}/restart/*${end_date}*) + set surname = `echo $file | awk -F'/' '{print $NF}'` + mv $file ${ICE_RUNDIR}/restart/base_$surname +end + +# Prepend 'base_' to all history files to save for comparison +foreach file (${ICE_RUNDIR}/history/*) + set surname = `echo $file | awk -F'/' '{print $NF}'` + mv $file ${ICE_RUNDIR}/history/base_$surname +end + #----------------------------------------------------------- # Run the CICE model for the restart simulation @@ -69,13 +74,40 @@ else if (${tcolumn} == "") set tcolumn = -1 echo "PASS ${ICE_TESTNAME} run ${ttimeloop} ${tdynamics} ${tcolumn}" >> ${ICE_CASEDIR}/test_output + set restbfb = "PASS" ${ICE_CASEDIR}/casescripts/comparebfb.csh ${ICE_RUNDIR}/restart set bfbstatus = $status - if (${bfbstatus} == 0) then + if (${bfbstatus} != 0) set restbfb = "FAIL" + + set icehrbfb = "NONE" + if (${ICE_TESTNAME} =~ *histall10d* && ${ICE_IOTYPE} !~ *binary* ) then + echo "${restbfb} ${ICE_TESTNAME} restart " >> ${ICE_CASEDIR}/test_output + foreach file1 (${ICE_RUNDIR}/restart/base_iceh* ${ICE_RUNDIR}/history/base_iceh*) + set file2 = `echo $file1 | sed -e 's|base_iceh|iceh|g'` + if (-e ${file2} && `where ncatted` != "") then + if (${icehrbfb} == "NONE") set icehrbfb = "PASS" + # remove global attributes to do bfb binary compare + set file1m = `echo $file1 | sed -e 's|base_iceh|base_iceh_mod|g'` + set file2m = `echo $file1 | sed -e 's|base_iceh|iceh_mod|g'` + ncatted -h -a ,global,d,, ${file1} ${file1m} + ncatted -h -a ,global,d,, ${file2} ${file2m} + ${ICE_CASEDIR}/casescripts/comparebfb.csh ${file1m} ${file2m} + set bfbstatus = $status + if (${bfbstatus} != 0) set icehrbfb = "FAIL" + rm ${file1m} ${file2m} + endif + end + echo "${icehrbfb} ${ICE_TESTNAME} histrest " >> ${ICE_CASEDIR}/test_output + endif + + if (${restbfb} == PASS && ${icehrbfb} == PASS) then + echo "PASS ${ICE_TESTNAME} test " >> ${ICE_CASEDIR}/test_output + else if (${restbfb} == PASS && ${icehrbfb} == NONE) then echo "PASS ${ICE_TESTNAME} test " >> ${ICE_CASEDIR}/test_output else echo "FAIL ${ICE_TESTNAME} test " >> ${ICE_CASEDIR}/test_output endif + endif #----------------------------------------------------------- diff --git a/configuration/scripts/tests/test_restart2.script b/configuration/scripts/tests/test_restart2.script index 67760bbf4..b62a520bc 100644 --- a/configuration/scripts/tests/test_restart2.script +++ b/configuration/scripts/tests/test_restart2.script @@ -21,20 +21,25 @@ if ( $res != 0 ) then exit 99 endif -# Prepend 'base_' to the final restart file to save for comparison +# Compute date of last file in first run if ( "${ICE_IOTYPE}" == "binary" ) then - set end_date = `ls -t1 ${ICE_RUNDIR}/restart | head -1 | awk -F'.' '{print $NF}'` - foreach file (${ICE_RUNDIR}/restart/*${end_date}) - set surname = `echo $file | awk -F'/' '{print $NF}'` - mv $file ${ICE_RUNDIR}/restart/base_$surname - end + set end_date = `ls -t1 ${ICE_RUNDIR}/restart | head -1 | rev | cut -d "." -f 1 | rev` else - set test_file = `ls -t1 ${ICE_RUNDIR}/restart | head -1` - set test_data = ${ICE_RUNDIR}/restart/${test_file} - set base_data = ${ICE_RUNDIR}/restart/base_${test_file} - mv ${test_data} ${base_data} + set end_date = `ls -t1 ${ICE_RUNDIR}/restart | head -1 | rev | cut -d "." -f 2 | rev` endif +# Prepend 'base_' to final restart and history restart files to save for comparison +foreach file (${ICE_RUNDIR}/restart/*${end_date}*) + set surname = `echo $file | awk -F'/' '{print $NF}'` + mv $file ${ICE_RUNDIR}/restart/base_$surname +end + +# Prepend 'base_' to all history files to save for comparison +foreach file (${ICE_RUNDIR}/history/*) + set surname = `echo $file | awk -F'/' '{print $NF}'` + mv $file ${ICE_RUNDIR}/history/base_$surname +end + #----------------------------------------------------------- # Run the CICE model for the restart simulation diff --git a/doc/source/cice_index.rst b/doc/source/cice_index.rst index 479c0a18c..eef05641a 100644 --- a/doc/source/cice_index.rst +++ b/doc/source/cice_index.rst @@ -784,6 +784,8 @@ section :ref:`tabnamelist`. "wind", "wind speed", "m/s" "windmin", "minimum wind speed to compact snow", "10 m/s" "write_history", "if true, write history now", "" + "write_histrest", "if true, write out history restart files if needed", "" + "write_histrest_now", "write out history restart files now", "" "write_ic", "if true, write initial conditions", "" "write_restart", "if 1, write restart now", "" "**X**", "", "" diff --git a/doc/source/user_guide/ug_case_settings.rst b/doc/source/user_guide/ug_case_settings.rst index 2f00fed85..ea959868d 100644 --- a/doc/source/user_guide/ug_case_settings.rst +++ b/doc/source/user_guide/ug_case_settings.rst @@ -283,6 +283,7 @@ setup_nml "``use_leap_years``", "logical", "include leap days", "``.false.``" "``use_restart_time``", "logical", "set initial date using restart file on initial runtype only", "``.false.``" "``version_name``", "string", "model version", "'unknown_version_name'" + "``write_histrest``", "logical", "write history restarts if needed", "``.true.``" "``write_ic``", "logical", "write initial condition", "``.false.``" "``year_init``", "integer", "the initial year if not using restart", "0" "", "", "", "" diff --git a/doc/source/user_guide/ug_implementation.rst b/doc/source/user_guide/ug_implementation.rst index a79e3bc1e..15c0decd1 100644 --- a/doc/source/user_guide/ug_implementation.rst +++ b/doc/source/user_guide/ug_implementation.rst @@ -1260,7 +1260,7 @@ to the Macros machine file explicity when needed. .. _history: ************* -History files +History Files ************* CICE provides history data output in binary unformatted or netCDF formats via @@ -1424,8 +1424,35 @@ namelist flag. Note that the dpnd pond history fields have not yet been implemented for the topo ponds scheme and are turned off in the code. +************************ +History Restart Files +************************ + +CICE has a history restart capability. History restart files are needed and written when +a restart file is written while history fields are accumulating. The implementation dumps +accumulated history data, one file per history stream, to the restart directory using +a naming convention that uses the history filename, appends '_r' plus the ``histfreq`` character +string and then appends the model time. This occurs only for streams with +``hist_avg = .true.`` and where the accumulator count is greater than zero when the data is +written. Only accumulating data associated with the history stream is written. This feature +can be turned off by setting ``write_histrest = .false.`` in namelist. + +On restart, CICE looks for appropriate history restart files and reads them if they exist. +If the files do not exist or fields cannot be read, the model continues with the history +accumulator set to zero. Output is written to the log file that indicates which history restart +files and fields were read and which were not. In a production run, where the history streams +are set and unchanging, this should result in bit-for-bit history restart capability. If +a user changes the history stream output, CICE will read only files and fields that exist +and any new fields will initialize with zero accumulation and a potentially erroneous accumluation +counter. + +There is a settings option, **histall10d**, that specifies 10-day and monthly time average +history streams for all history variables. For these tests, the test script compares +the history and history restart output generated to verify bit-for-bit history capability +for a restart run. + **************** -Diagnostic files +Diagnostic Files **************** Like ``histfreq``, the parameter ``diagfreq`` can be used to regulate how often @@ -1534,7 +1561,7 @@ The timers use *MPI_WTIME* for parallel runs and the F90 intrinsic .. _restartfiles: ************* -Restart files +Restart Files ************* CICE reads and writes restart data in binary unformatted or netCDF formats via diff --git a/doc/source/user_guide/ug_testing.rst b/doc/source/user_guide/ug_testing.rst index e0cbd2c2a..36ca2f13b 100644 --- a/doc/source/user_guide/ug_testing.rst +++ b/doc/source/user_guide/ug_testing.rst @@ -285,7 +285,7 @@ To run the test:: .. _testsuites: -Test suites +Test Suites ------------ Test suites support running multiple tests specified via From 7c59f237d678ef9fad5f50939c7c1f6829f3b0ff Mon Sep 17 00:00:00 2001 From: Tony Craig Date: Fri, 23 Jan 2026 09:13:17 -0800 Subject: [PATCH 19/21] Update version to 6.6.3 (#1086) Update Copyright to 2026 Remove trailing whitespace Update Icepack to #2f31ee37f3a70, Icepack v1.5.3 --- .zenodo.json | 8 ++++---- COPYRIGHT.pdf | Bin 20755 -> 20693 bytes cicecore/cicedyn/analysis/ice_history.F90 | 8 ++++---- .../cicedyn/analysis/ice_history_mechred.F90 | 4 ++-- cicecore/drivers/direct/hadgem3/CICE.F90 | 2 +- cicecore/drivers/mapl/geos/CICE_copyright.txt | 2 +- cicecore/drivers/mct/cesm1/CICE_copyright.txt | 2 +- .../drivers/nuopc/cmeps/CICE_copyright.txt | 2 +- cicecore/drivers/nuopc/dmi/CICE.F90 | 2 +- cicecore/drivers/standalone/cice/CICE.F90 | 2 +- cicecore/drivers/unittest/opticep/CICE.F90 | 2 +- cicecore/drivers/unittest/opticep/README | 6 +++--- cicecore/version.txt | 2 +- doc/source/conf.py | 6 +++--- icepack | 2 +- 15 files changed, 25 insertions(+), 25 deletions(-) diff --git a/.zenodo.json b/.zenodo.json index d96cfb9bb..fa46def55 100644 --- a/.zenodo.json +++ b/.zenodo.json @@ -1,22 +1,22 @@ { "license": "BSD-3-Clause", - "copyright": "Copyright 1998-2025 Triad National Security, LLC", + "copyright": "Copyright 1998-2026 Triad National Security, LLC", "description": "View detailed release notes at https://github.com/CICE-Consortium/CICE/releases", "language": "eng", - "title": "CICE-Consortium/CICE: CICE Version 6.6.2", + "title": "CICE-Consortium/CICE: CICE Version 6.6.3", "keywords": [ "sea ice model", "CICE", "Icepack" ], - "version": "6.6.2", + "version": "6.6.3", "upload_type": "software", "communities": [ { "identifier": "cice-consortium" } ], - "publication_date": "2025-08-15", + "publication_date": "2026-01-22", "creators": [ { "affiliation": "Los Alamos National Laboratory", diff --git a/COPYRIGHT.pdf b/COPYRIGHT.pdf index 2f37e495f02302a72c6b7943cf05b5ecfe3dfb19..6a8923c9547fe437cd574f543141bf30920e1d3a 100644 GIT binary patch delta 15575 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 UnVG|}GP7}T!BJ3%D@efo53tWJVgLXD diff --git a/cicecore/cicedyn/analysis/ice_history.F90 b/cicecore/cicedyn/analysis/ice_history.F90 index 3d5f47312..83ecd6563 100644 --- a/cicecore/cicedyn/analysis/ice_history.F90 +++ b/cicecore/cicedyn/analysis/ice_history.F90 @@ -1455,10 +1455,10 @@ subroutine init_hist (dt) "weighted by ice area", c1, c0, & ns1, f_FY) - ! CMIP 2D variables (for "intensive" variables per Notz et al 2016 definition, + ! CMIP 2D variables (for "intensive" variables per Notz et al 2016 definition, ! that is a weighted time average when ice is present) - ! Use avg_ice_present = 'init', 'final', 'pond', or 'ridge' to divide by - ! sum(aice), sum(apond), or sum(ardg) over time + ! Use avg_ice_present = 'init', 'final', 'pond', or 'ridge' to divide by + ! sum(aice), sum(apond), or sum(ardg) over time ! aice is at the start of the timestep ('init') or the end of the timestep ('final') ! avg_ice_present = 'none' produces a time average including zeroes when ice is not present @@ -1694,7 +1694,7 @@ subroutine init_hist (dt) ns1, f_sidconcdyn, avg_ice_present='none', mask_ice_free_points=.false.) call define_hist_field(n_sidconcth,"sidconcth","1/s",tstr2D, tcstr, & - "sea-ice area fraction tendency due to thermodynamics", & + "sea-ice area fraction tendency due to thermodynamics", & "total rate of change in sea-ice area fraction through thermodynamic processes", & c1, c0, & ns1, f_sidconcth, avg_ice_present='none', mask_ice_free_points=.false.) diff --git a/cicecore/cicedyn/analysis/ice_history_mechred.F90 b/cicecore/cicedyn/analysis/ice_history_mechred.F90 index f3707f6f6..318132a92 100644 --- a/cicecore/cicedyn/analysis/ice_history_mechred.F90 +++ b/cicecore/cicedyn/analysis/ice_history_mechred.F90 @@ -412,9 +412,9 @@ subroutine accum_hist_mechred (iblk) call accum_hist_field(n_sirdgconc, iblk, & aice(:,:,iblk) * (c1 - trcr(:,:,nt_alvl,iblk)), a2D) - if (f_sirdgthick(1:1)/= 'x') then + if (f_sirdgthick(1:1)/= 'x') then call accum_hist_field(n_sirdgthick, iblk, & - vice(:,:,iblk) * (c1 - trcr(:,:,nt_vlvl,iblk)), a2D) + vice(:,:,iblk) * (c1 - trcr(:,:,nt_vlvl,iblk)), a2D) endif endif ! allocated(a2D) diff --git a/cicecore/drivers/direct/hadgem3/CICE.F90 b/cicecore/drivers/direct/hadgem3/CICE.F90 index ad02ca51b..cacf96c46 100644 --- a/cicecore/drivers/direct/hadgem3/CICE.F90 +++ b/cicecore/drivers/direct/hadgem3/CICE.F90 @@ -1,5 +1,5 @@ !======================================================================= -! Copyright 1998-2025, Triad National Security, LLC +! Copyright 1998-2026, Triad National Security, LLC ! All rights reserved. ! ! This program was produced under U.S. Government contract 89233218CNA000001 diff --git a/cicecore/drivers/mapl/geos/CICE_copyright.txt b/cicecore/drivers/mapl/geos/CICE_copyright.txt index ab684c63e..bc8975d79 100644 --- a/cicecore/drivers/mapl/geos/CICE_copyright.txt +++ b/cicecore/drivers/mapl/geos/CICE_copyright.txt @@ -1,4 +1,4 @@ -! Copyright 1998-2025, Triad National Security, LLC +! Copyright 1998-2026, Triad National Security, LLC ! All rights reserved. ! ! This program was produced under U.S. Government contract 89233218CNA000001 diff --git a/cicecore/drivers/mct/cesm1/CICE_copyright.txt b/cicecore/drivers/mct/cesm1/CICE_copyright.txt index ab684c63e..bc8975d79 100644 --- a/cicecore/drivers/mct/cesm1/CICE_copyright.txt +++ b/cicecore/drivers/mct/cesm1/CICE_copyright.txt @@ -1,4 +1,4 @@ -! Copyright 1998-2025, Triad National Security, LLC +! Copyright 1998-2026, Triad National Security, LLC ! All rights reserved. ! ! This program was produced under U.S. Government contract 89233218CNA000001 diff --git a/cicecore/drivers/nuopc/cmeps/CICE_copyright.txt b/cicecore/drivers/nuopc/cmeps/CICE_copyright.txt index ab684c63e..bc8975d79 100644 --- a/cicecore/drivers/nuopc/cmeps/CICE_copyright.txt +++ b/cicecore/drivers/nuopc/cmeps/CICE_copyright.txt @@ -1,4 +1,4 @@ -! Copyright 1998-2025, Triad National Security, LLC +! Copyright 1998-2026, Triad National Security, LLC ! All rights reserved. ! ! This program was produced under U.S. Government contract 89233218CNA000001 diff --git a/cicecore/drivers/nuopc/dmi/CICE.F90 b/cicecore/drivers/nuopc/dmi/CICE.F90 index 14c7af346..a96ca4ce7 100644 --- a/cicecore/drivers/nuopc/dmi/CICE.F90 +++ b/cicecore/drivers/nuopc/dmi/CICE.F90 @@ -1,5 +1,5 @@ !======================================================================= -! Copyright 1998-2025, Triad National Security, LLC +! Copyright 1998-2026, Triad National Security, LLC ! All rights reserved. ! ! This program was produced under U.S. Government contract 89233218CNA000001 diff --git a/cicecore/drivers/standalone/cice/CICE.F90 b/cicecore/drivers/standalone/cice/CICE.F90 index 14c7af346..a96ca4ce7 100644 --- a/cicecore/drivers/standalone/cice/CICE.F90 +++ b/cicecore/drivers/standalone/cice/CICE.F90 @@ -1,5 +1,5 @@ !======================================================================= -! Copyright 1998-2025, Triad National Security, LLC +! Copyright 1998-2026, Triad National Security, LLC ! All rights reserved. ! ! This program was produced under U.S. Government contract 89233218CNA000001 diff --git a/cicecore/drivers/unittest/opticep/CICE.F90 b/cicecore/drivers/unittest/opticep/CICE.F90 index 14c7af346..a96ca4ce7 100644 --- a/cicecore/drivers/unittest/opticep/CICE.F90 +++ b/cicecore/drivers/unittest/opticep/CICE.F90 @@ -1,5 +1,5 @@ !======================================================================= -! Copyright 1998-2025, Triad National Security, LLC +! Copyright 1998-2026, Triad National Security, LLC ! All rights reserved. ! ! This program was produced under U.S. Government contract 89233218CNA000001 diff --git a/cicecore/drivers/unittest/opticep/README b/cicecore/drivers/unittest/opticep/README index b5f1bdf9c..958e592da 100644 --- a/cicecore/drivers/unittest/opticep/README +++ b/cicecore/drivers/unittest/opticep/README @@ -1,7 +1,7 @@ This unittest tests Icepack optional arguments. The idea is to have source code that is identical to the standard CICE source code except the significant optional arguments passed -into Icepack are removed from the CICE calls. Then to run a standard CICE case with optional +into Icepack are removed from the CICE calls. Then to run a standard CICE case with optional features (fsd, bgc, isotopes, etc) off in namelist. That results should be bit-for-bit identical with an equivalent run from the standard source code. @@ -18,7 +18,7 @@ today, that includes CICE_InitMod.F90 CICE_RunMod.F90 -Add +Add write(nu_diag, *) "OPTICEP TEST COMPLETED SUCCESSFULLY " to CICE_FinalMod.F90 @@ -26,5 +26,5 @@ Do not worry about the parameter/tracer query/init/write methods Interfaces to modify include ice_init_column.F90 (icepack_step_radiation, icepack_init_zbgc) - ice_step_mod.F90 (icepack_step_therm1, icepack_step_therm2, icepack_prep_radiation, + ice_step_mod.F90 (icepack_step_therm1, icepack_step_therm2, icepack_prep_radiation, icepack_step_radiation, icepack_step_ridge) diff --git a/cicecore/version.txt b/cicecore/version.txt index 4efe718e0..cef257940 100644 --- a/cicecore/version.txt +++ b/cicecore/version.txt @@ -1 +1 @@ -CICE 6.6.2 +CICE 6.6.3 diff --git a/doc/source/conf.py b/doc/source/conf.py index 458d72887..fa93c8a1a 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -57,7 +57,7 @@ # General information about the project. project = u'CICE' -copyright = u'1998-2025, Triad National Security, LLC (code) and National Center for Atmospheric Research (documentation)' +copyright = u'1998-2026, Triad National Security, LLC (code) and National Center for Atmospheric Research (documentation)' author = u'CICE-Consortium' # The version info for the project you're documenting, acts as replacement for @@ -65,9 +65,9 @@ # built documents. # # The short X.Y version. -version = u'6.6.2' +version = u'6.6.3' # The full version, including alpha/beta/rc tags. -version = u'6.6.2' +version = u'6.6.3' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/icepack b/icepack index 0bcde2556..2f31ee37f 160000 --- a/icepack +++ b/icepack @@ -1 +1 @@ -Subproject commit 0bcde255637a5947b1b7a4e4fc8dccd77803cb65 +Subproject commit 2f31ee37f3a70a70b5e33cae43476f09dbb33da7 From a214a72597095ab6eed590ddae39b2d28679eade Mon Sep 17 00:00:00 2001 From: "David A. Bailey" Date: Fri, 23 Jan 2026 17:23:09 -0700 Subject: [PATCH 20/21] Fix some bugs with the last CMIP7 PR (#1088) Bug fix for lwout in CESM driver Also some FSD stuff for coupling Fix define for sitimefrac Add the CESM3 namelist changes --- cicecore/cicedyn/analysis/ice_history.F90 | 2 +- .../drivers/nuopc/cmeps/ice_import_export.F90 | 49 ++++++++++++------- configuration/scripts/options/set_nml.cesm3 | 12 +++++ 3 files changed, 44 insertions(+), 19 deletions(-) create mode 100644 configuration/scripts/options/set_nml.cesm3 diff --git a/cicecore/cicedyn/analysis/ice_history.F90 b/cicecore/cicedyn/analysis/ice_history.F90 index 83ecd6563..eb1a66194 100644 --- a/cicecore/cicedyn/analysis/ice_history.F90 +++ b/cicecore/cicedyn/analysis/ice_history.F90 @@ -1823,7 +1823,7 @@ subroutine init_hist (dt) "fraction of time steps with sea ice", & "averaging period during which sea ice is present (siconc > 0) in a grid cell", & c1, c0, & - ns1, f_icepresent, avg_ice_present='none', mask_ice_free_points=.false.) + ns1, f_sitimefrac, avg_ice_present='none', mask_ice_free_points=.false.) call define_hist_field(n_sivol,"sivol","m",tstr2D, tcstr, & "sea-ice volume per area", & diff --git a/cicecore/drivers/nuopc/cmeps/ice_import_export.F90 b/cicecore/drivers/nuopc/cmeps/ice_import_export.F90 index 91236c11e..d2e4cf72e 100644 --- a/cicecore/drivers/nuopc/cmeps/ice_import_export.F90 +++ b/cicecore/drivers/nuopc/cmeps/ice_import_export.F90 @@ -94,6 +94,7 @@ module ice_import_export type (fld_list_type) :: fldsToIce(fldsMax) type (fld_list_type) :: fldsFrIce(fldsMax) + logical :: flds_wave ! wave ice coupling integer , parameter :: io_dbug = 10 ! i/o debug messages character(*), parameter :: u_FILE_u = & __FILE__ @@ -116,7 +117,6 @@ subroutine ice_advertise_fields(gcomp, importState, exportState, flds_scalar_nam character(char_len) :: stdname character(char_len) :: cvalue logical :: flds_wiso ! use case - logical :: flds_wave ! use case logical :: isPresent, isSet character(len=*), parameter :: subname='(ice_import_export:ice_advertise_fields)' !------------------------------------------------------------------------------- @@ -266,10 +266,13 @@ subroutine ice_advertise_fields(gcomp, importState, exportState, flds_scalar_nam ! ice/ocn fluxes computed by ice call fldlist_add(fldsFrIce_num, fldsFrIce, 'Fioi_melth' ) call fldlist_add(fldsFrIce_num, fldsFrIce, 'Fioi_swpen' ) - call fldlist_add(fldsFrIce_num, fldsFrIce, 'Fioi_swpen_vdr' ) - call fldlist_add(fldsFrIce_num, fldsFrIce, 'Fioi_swpen_vdf' ) - call fldlist_add(fldsFrIce_num, fldsFrIce, 'Fioi_swpen_idr' ) - call fldlist_add(fldsFrIce_num, fldsFrIce, 'Fioi_swpen_idf' ) + + if (.not.prescribed_ice) then + call fldlist_add(fldsFrIce_num, fldsFrIce, 'Fioi_swpen_vdr' ) + call fldlist_add(fldsFrIce_num, fldsFrIce, 'Fioi_swpen_vdf' ) + call fldlist_add(fldsFrIce_num, fldsFrIce, 'Fioi_swpen_idr' ) + call fldlist_add(fldsFrIce_num, fldsFrIce, 'Fioi_swpen_idf' ) + endif if (send_i2x_per_cat) then call fldlist_add(fldsFrIce_num, fldsFrIce, 'Fioi_swpen_ifrac_n', & @@ -926,7 +929,7 @@ subroutine ice_export( exportState, rc ) real (kind=dbl_kind) :: floethick(nx_block,ny_block,max_blocks) ! ice thickness logical (kind=log_kind) :: tr_fsd integer (kind=int_kind) :: nt_fsd - real (kind=dbl_kind) :: Tffresh + real (kind=dbl_kind) :: Tffresh, stefan_boltzmann real (kind=dbl_kind), allocatable :: tempfld(:,:,:) real (kind=dbl_kind), pointer :: dataptr_ifrac_n(:,:) real (kind=dbl_kind), pointer :: dataptr_swpen_n(:,:) @@ -938,6 +941,7 @@ subroutine ice_export( exportState, rc ) if (io_dbug > 5) call ESMF_LogWrite(subname//' called', ESMF_LOGMSG_INFO) call icepack_query_parameters(Tffresh_out=Tffresh) + call icepack_query_parameters(stefan_boltzmann_out=stefan_boltzmann) ! call icepack_query_parameters(tfrz_option_out=tfrz_option, & ! modal_aero_out=modal_aero, z_tracers_out=z_tracers, skl_bgc_out=skl_bgc, & ! Tffresh_out=Tffresh) @@ -980,7 +984,7 @@ subroutine ice_export( exportState, rc ) ! surface temperature Tsrf(i,j,iblk) = Tffresh + trcr(i,j,1,iblk) !Kelvin (original ???) - if (tr_fsd) then + if (flds_wave) then ! floe thickness (m) if (aice(i,j,iblk) > puny) then floethick(i,j,iblk) = vice(i,j,iblk) / aice(i,j,iblk) @@ -988,17 +992,22 @@ subroutine ice_export( exportState, rc ) floethick(i,j,iblk) = c0 end if - ! floe diameter (m) - workx = c0 - worky = c0 - do n = 1, ncat - do k = 1, nfsd - workx = workx + floe_rad_c(k) * aicen_init(i,j,n,iblk) * trcrn(i,j,nt_fsd+k-1,n,iblk) - worky = worky + aicen_init(i,j,n,iblk) * trcrn(i,j,nt_fsd+k-1,n,iblk) + if (tr_fsd) then + ! floe diameter (m) + workx = c0 + worky = c0 + do n = 1, ncat + do k = 1, nfsd + workx = workx + floe_rad_c(k) * aicen_init(i,j,n,iblk) * trcrn(i,j,nt_fsd+k-1,n,iblk) + worky = worky + aicen_init(i,j,n,iblk) * trcrn(i,j,nt_fsd+k-1,n,iblk) + end do end do - end do - if (worky > c0) workx = c2*workx / worky - floediam(i,j,iblk) = MAX(c2*floe_rad_c(1),workx) + if (worky > c0) workx = c2*workx / worky + floediam(i,j,iblk) = MAX(c2*floe_rad_c(1),workx) + else ! with FSD off + ! floe diameter (m) + floediam(i,j,iblk) = 50.0_dbl_kind + endif endif ! wind stress (on POP T-grid: convert to lat-lon) @@ -1204,7 +1213,7 @@ subroutine ice_export( exportState, rc ) do j = jlo, jhi do i = ilo, ihi if ( tmask(i,j,iblk) .and. ailohi(i,j,iblk) > c0 .and. flwout(i,j,iblk) > -puny) then - tempfld(i,j,iblk) = (-stefan_boltzmann *(Tf(i,j) + Tffresh)**4) / ailohi(i,j,iblk) + tempfld(i,j,iblk) = (-stefan_boltzmann *(Tf(i,j,iblk) + Tffresh)**4) / ailohi(i,j,iblk) end if end do end do @@ -1235,6 +1244,8 @@ subroutine ice_export( exportState, rc ) areacor=mod2med_areacor, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (.not.prescribed_ice) then + ! flux of vis dir shortwave through ice to ocean call state_setexport(exportState, 'Fioi_swpen_vdr' , input=fswthru_vdr, lmask=tmask, ifrac=ailohi, & areacor=mod2med_areacor, rc=rc) @@ -1255,6 +1266,8 @@ subroutine ice_export( exportState, rc ) areacor=mod2med_areacor, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return + endif + ! flux of heat exchange with ocean call state_setexport(exportState, 'Fioi_melth' , input=fhocn, lmask=tmask, ifrac=ailohi, & areacor=mod2med_areacor, rc=rc) diff --git a/configuration/scripts/options/set_nml.cesm3 b/configuration/scripts/options/set_nml.cesm3 new file mode 100644 index 000000000..35d03f5b6 --- /dev/null +++ b/configuration/scripts/options/set_nml.cesm3 @@ -0,0 +1,12 @@ + +congel_freeze = 'one-step' +hist_time_axis = 'middle' +nfsd = 12 +nfreq = 25 +snwredist = "snwITDrdg" +tr_fsd = .true. +tr_ponds_lvl = .false. +tr_ponds_sealvl = .true. +tr_snow = .true. +tscale_pnd_drain = 0.5d0 +wave_frac_spec = 'alt' From 038a2764fd723d33c4eacf9220784986e284db04 Mon Sep 17 00:00:00 2001 From: anton-seaice Date: Fri, 6 Feb 2026 09:19:01 +1100 Subject: [PATCH 21/21] Making a debug build run --- cicecore/cicedyn/infrastructure/ice_domain.F90 | 6 +++--- cicecore/cicedyn/infrastructure/ice_grid.F90 | 4 ++-- cicecore/drivers/nuopc/cmeps/ice_import_export.F90 | 2 +- configuration/scripts/cmake/CMakeLists.txt | 4 +++- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/cicecore/cicedyn/infrastructure/ice_domain.F90 b/cicecore/cicedyn/infrastructure/ice_domain.F90 index 9a0941e19..f112517a3 100644 --- a/cicecore/cicedyn/infrastructure/ice_domain.F90 +++ b/cicecore/cicedyn/infrastructure/ice_domain.F90 @@ -517,9 +517,9 @@ subroutine init_domain_distribution(KMTG,ULATG,grid_ice) work_per_block = 0 end where if (my_task == master_task) then - write(nu_diag,'(2a,4i9)') subname,' work_unit = ',work_unit, max_work_unit - write(nu_diag,'(2a,4i9)') subname,' nocn = ',minval(nocn),maxval(nocn),sum(nocn) - write(nu_diag,'(2a,4i9)') subname,' work_per_block = ',minval(work_per_block),maxval(work_per_block),sum(work_per_block) + write(nu_diag,'(2a,2i9)') subname,' work_unit = ',work_unit, max_work_unit + write(nu_diag,'(2a,3i16)') subname,' nocn = ',minval(nocn),maxval(nocn),sum(nocn) + write(nu_diag,'(2a,3i9)') subname,' work_per_block = ',minval(work_per_block),maxval(work_per_block),sum(work_per_block) endif deallocate(nocn) diff --git a/cicecore/cicedyn/infrastructure/ice_grid.F90 b/cicecore/cicedyn/infrastructure/ice_grid.F90 index 13a1aa098..8b9cbc7d4 100644 --- a/cicecore/cicedyn/infrastructure/ice_grid.F90 +++ b/cicecore/cicedyn/infrastructure/ice_grid.F90 @@ -1911,8 +1911,8 @@ subroutine mom_corners_global(work_mom, G_U, G_T, G_E, G_N) select case (trim(ns_boundary_type)) case ('tripole') do i = 1, nx_global+1 - G_T(i,ny_global+1) = G_T(nx_global+1-i, ny_global) - G_E(i,ny_global+1) = G_E(nx_global+1-i, ny_global) + G_T(i,ny_global+1) = G_T(nx_global+2-i, ny_global) + G_E(i,ny_global+1) = G_E(nx_global+2-i, ny_global) enddo case ('cyclic') G_T(:,ny_global+1) = G_T(:,1) diff --git a/cicecore/drivers/nuopc/cmeps/ice_import_export.F90 b/cicecore/drivers/nuopc/cmeps/ice_import_export.F90 index d2e4cf72e..c252b05a1 100644 --- a/cicecore/drivers/nuopc/cmeps/ice_import_export.F90 +++ b/cicecore/drivers/nuopc/cmeps/ice_import_export.F90 @@ -1072,7 +1072,7 @@ subroutine ice_export( exportState, rc ) endif ! Create a temporary field - allocate(tempfld(nx_block,ny_block,nblocks)) + allocate(tempfld(nx_block,ny_block,max_blocks)) ! Fractions and mask call state_setexport(exportState, 'Si_ifrac', input=ailohi, rc=rc) diff --git a/configuration/scripts/cmake/CMakeLists.txt b/configuration/scripts/cmake/CMakeLists.txt index aaafbcb4e..d046cbee8 100644 --- a/configuration/scripts/cmake/CMakeLists.txt +++ b/configuration/scripts/cmake/CMakeLists.txt @@ -59,11 +59,13 @@ if(CMAKE_Fortran_COMPILER_ID MATCHES "GNU") set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -fallow-argument-mismatch") endif() set(CMAKE_Fortran_FLAGS_RELEASE "-O") + set(CMAKE_Fortran_FLAGS_RELWITHDEBINFO "-O -g") set(CMAKE_Fortran_FLAGS_DEBUG "-g -Wall -Og -ffpe-trap=zero,overflow -fcheck=bounds") elseif(CMAKE_Fortran_COMPILER_ID MATCHES "Intel") set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -qno-opt-dynamic-align -convert big_endian -assume byterecl -ftz -traceback -assume realloc_lhs -fp-model precise") set(CMAKE_Fortran_FLAGS_RELEASE "-O2 -debug minimal") - set(CMAKE_Fortran_FLAGS_DEBUG "-O0 -g -check uninit -check bounds -check pointers -fpe0 -check noarg_temp_created") + set(CMAKE_Fortran_FLAGS_RELWITHDEBINFO "-O2 -g") + set(CMAKE_Fortran_FLAGS_DEBUG "-O0 -g -check all -fpe0 -check noarg_temp_created") else() message(WARNING "Fortran compiler with ID ${CMAKE_Fortran_COMPILER_ID} will be used with CMake default options") endif()