4.7. Other things

4.7.1. Reproducible Sums

The ‘reproducible’ option (DITTO) makes diagnostics bit-for-bit when varying the number of processors. (The simulation results are bit-for-bit regardless, because they do not require global sums or max/mins as do the diagnostics.) This was done mainly by increasing the precision for the global reduction calculations, except for regular double-precision (r8) calculations involving MPI; MPI can not handle MPI_REAL16 on some architectures. Instead, these cases perform sums or max/min calculations across the global block structure, so that the results are bit-for-bit as long as the block distribution is the same (the number of processors can be different).

A more flexible option is available for double-precision MPI calculations, using the namelist variable bfbflag. When true, this flag produces bit-for-bit identical diagnostics with different tasks, threads, blocks and grid decompositions.

4.7.2. Adding Timers

Timing any section of code, or multiple sections, consists of defining the timer and then wrapping the code with start and stop commands for that timer. Printing of the timer output is done simultaneously for all timers. To add a timer, first declare it (timer_[tmr]) at the top of ice_timers.F90 (we recommend doing this in both the mpi/ and serial/ directories), then add a call to get_ice_timer in the subroutine init_ice_timers. In the module containing the code to be timed, call ice_timer_start`(`timer_[tmr]) at the beginning of the section to be timed, and a similar call to ice_timer_stop at the end. A use ice_timers statement may need to be added to the subroutine being modified. Be careful not to have one command outside of a loop and the other command inside. Timers can be run for individual blocks, if desired, by including the block ID in the timer calls.

4.7.3. Adding History fields

To add a variable to be printed in the history output, search for ‘example’ in ice_history_shared.F90:

  1. add a frequency flag for the new field
  2. add the flag to the namelist (here and also in ice_in)
  3. add an index number

and in ice_history.F90:

  1. broadcast the flag
  2. add a call to define_hist_field
  3. add a call to accum_hist_field

The example is for a standard, two-dimensional (horizontal) field; for other array sizes, choose another history variable with a similar shape as an example. Some history variables, especially tracers, are grouped in other files according to their purpose (bgc, melt ponds, etc.).

To add an output frequency for an existing variable, see section History files.

4.7.4. Adding Tracers

A number of optional tracers are available in the code, including ice age, first-year ice area, melt pond area and volume, brine height, aerosols, and level ice area and volume (from which ridged ice quantities are derived). Salinity, enthalpies, age, aerosols, level-ice volume, brine height and most melt pond quantities are volume-weighted tracers, while first-year area, pond area, level-ice area and all of the biogeochemistry tracers in this release are area-weighted tracers. In the absence of sources and sinks, the total mass of a volume-weighted tracer such as aerosol (kg) is conserved under transport in horizontal and thickness space (the mass in a given grid cell will change), whereas the aerosol concentration (kg/m) is unchanged following the motion, and in particular, the concentration is unchanged when there is surface or basal melting. The proper units for a volume-weighted mass tracer in the tracer array are kg/m.

In several places in the code, tracer computations must be performed on the conserved “tracer volume” rather than the tracer itself; for example, the conserved quantity is \(h_{pnd}a_{pnd}a_{lvl}a_{i}\), not \(h_{pnd}\). Conserved quantities are thus computed according to the tracer dependencies, and code must be included to account for new dependencies (e.g., \(a_{lvl}\) and \(a_{pnd}\) in ice_itd.F90 and ice_mechred.F90).

To add a tracer, follow these steps using one of the existing tracers as a pattern.

  • ice_domain_size.F90: increase max_ntrcr via cpps in the build.
  • ice_state.F90: declare nt_[tracer] and tr_[tracer]
  • create initialization, physics, and restart routines. The restart and history routine will be in CICE. The physics will be in Icepack.
  • ice_fileunits.F90: add new dump and restart file units
  • to control the new tracer
    • add new module and tr_[tracer] to list of used modules and variables
    • add logical namelist variable tr_[tracer]
    • initialize namelist variable
    • broadcast namelist variable
    • print namelist variable to diagnostic output file
    • increment number of tracers in use based on namelist input (ntrcr)
    • define tracer types (trcr_depend = 0 for ice area tracers, 1 for ice volume, 2 for snow volume, 2+nt_[tracer] for dependence on other tracers)
  • ice_itd.F90, ice_mechred.F90: Account for new dependencies if needed.
  • CICE_InitMod.F90: initialize tracer (includes reading restart file)
  • CICE_RunMod.F90, ice_step_mod.F90:
    • call routine to write tracer restart data
    • call physics routines as needed (often called from ice_step_mod.F90)
  • ice_restart.F90: define restart variables (for binary,  and PIO)
  • ice_history_[tracer].F90: add history variables (Section Adding History fields)
  • ice_in: add namelist variables to tracer_nml and icefields_nml
  • If strict conservation is necessary, add diagnostics as noted for topo ponds in Section Melt ponds.

See also Icepack documentation.