Besides calculating the trajectory a parcel will take in space and time, TRACMASS can also calculate the characteristic values of its trajectories, which are known as tracers. This allows to see how a trajectory's tracer values, such as temperature and salinity, change along the way. For more detailed information on tracers themselves refer to the documentation here.
In this example, we present the procedure of adding an additional tracer that is calculated from already presented variables. We will have potential temperature (To) and salinity (S) as input data, and we will write a tracer function that converts temperature from degrees Celsius to degrees Kelvin. Even though this example is a primitive unit conversion, the aim of this is to bring attention to the procedure of adding additional custom tracers in the code itself.
Adding extra tracer function
There are two files that would be necessary to modify to add an additional tracer:
- mod_tracerf.F90 - contains the main functions responsible for tracer initiaization, interpolation and management
- mod_tracers.F90 - contains support functions for a specific tracer's calculations, for example, a function for density calculations
First, we will write a function that will convert from degrees Celsius to degrees Kelvin, after which we will add a few extra lines in another function so that our tracer can be callable. Finally, we will add our newly created tracer category in the namelist and test if it is working correctly.
Setting up mod_tracerf.F90
First, we will create a function that carries out the calculations of converting from degrees Celsius to degrees Kelvin. Mathematically, this is a very simple operation, done the following way:
We will call the function celsius2kelvin and we will send one variable over to the function when we call it. The function itself needs to declare any variables we might be using which in this case, we have
- T - input temperature in Celsius, which we want to convert to degrees Kelvin
- celsius2kelvin - output variable holding temperature in degrees Kelvin
- nx, ny, nz - variables to hold the input array's T shape in the x, y, and z directions accordingly
FUNCTION celsius2kelvin(T)
! --------------------------------------------------
!
! Purpose:
! Transform temperature from Celsius to Kelvin units
!
! Method:
! T(K) = T(C) + 273.15
!
! --------------------------------------------------
IMPLICIT NONE
! Input data, Temperature [degC]
REAL, INTENT(IN) :: T(:,:,:)
! Output data, Temperature [degK]
REAL, ALLOCATABLE, DIMENSION (:,:,:) :: celsius2kelvin
! Dimensions of the Temperature array
INTEGER :: nx, ny, nz
! Assigne dimension sizes
nx = SIZE(T,1); ny = SIZE(T,2); nz = SIZE(T,3);
! Create the array with the correct shape
ALLOCATE(celsius2kelvin(nx,ny,nz))
! Carry out calculations
celsius2kelvin(:,:,:) = T(:,:,:) + 273.15
END FUNCTION celsius2kelvin
This function needs to be added in the mod_tracerf.F90 file, at the end of the file, but before the final line of:
END MODULE mod_tracerf
It is good practice to document your code by adding a comment section with a short description of the function's purpose and the method used. Furthermore, it is good to write readable code, or at the very least, add comments to your code when the various functions, loops or if-statements start growing in complexity. The future you will thank you for it later when you review your code.
Setting up mod_tracers.F90
Next step is adding a few lines in the mod_tracers.F90 file. Find the SUBROUTINE called compute_tracers(tracname, var3d). This function is responsible for redirecting the tracer to the correct function for it to be calculated. In our case, we will call our tracer 'c2k', so we add an additional IF-ELSE branch to the IF-ELSE structure, which is the last branch in the code below:
SUBROUTINE compute_tracer(tracname, var3d)
! --------------------------------------------------
!
! Purpose:
! Compute tracer according to different functions
!
! --------------------------------------------------
CHARACTER(len=100) :: tracname
REAL(DP), DIMENSION(:,:,:) :: var3d
! Sigma 0 calculation (using T (degC) and S(g/kg))
IF (TRIM(tracname) == 'sigma0') THEN
var3d = REAL(thermo_dens0(... , ...),8)
var3d = var3d - 1000.d0
! Sigma 0 calculation (using T (K) and S(g/kg))
ELSE IF (TRIM(tracname) == 'sigma0_K') THEN
var3d = REAL(thermo_dens0(..., ...),8)
var3d = var3d - 1000.d0
! Conservative temperatue (CTo) calculation
! (using T (degC) and S(g/kg))
ELSE IF (TRIM(tracname) == 'CTo') THEN
var3d = REAL(thermo_pt2ct(..., ...),8)
! Function we added, from degC to degK
ELSE IF (TRIM(tracname) == 'c2k') THEN
var3d = REAL(celsius2kelvin(REAL(tracers(1)%data(:,:,:,2),4)), 8)
END IF
END SUBROUTINE compute_tracer
Notice that the tracer value will be saved in array var3d. It is necessary, as the var3d variable will be assigned as the new value for the tracer.
Below is a more detailed breakdown of the line that calls the function for tracer calculations.
Format of the output tracer (double precision)
| Function, for tracer calculations
| | Format of input variable (single precision)
| | | Input variable (T, degC)
| | | |
var3d = REAL( celsius2kelvin( REAL( tracers(1)%data(:,:,:,2) ,4) ), 8)
In general, tracer data has 4-dimensions (x, y, z, t) with two possible time steps -
1 is for the past and 2 is for the current time step.
Depending on the tracer, there may be variations in which time step is chosen for other
tracer calculations, but in general, the current data (2) is used to calculate other
derivative tracers.
After the code has been modified, attempt to compile the code and run a test simulation without making changes to the namelist file. If everything has been set up correctly, there should be no error and no changes to the output data.
Setting up the namelist
Finally, now that we have set up the code and tested it, we can make changes to the namelist file. As we mentioned previously, we have titled our tracer as 'c2k', and now we will add it in our namelist. The procedure is the same as setting up any other tracer and the namelist section that needs to be modified is presented in the code below.
It is recommended to keep the potential temperature (To) and salinity (S) tracers in the first and second index position. Some in-built functions rely on them being in these positions, so, to not cause extra problems and ensure that the calculations are correct, do not remove or replace them.
&INIT_TRACERS
! Should we evaluate tracers along the trajectories?
l_tracers = .TRUE.
! Temperature(C), Salinity, Temperature(K)
! Tracer name (description)
tracername = 'To', 'S', 'c2k'
! Tracer unit (description)
tracerunit = 'degC', 'PSU', 'degK'
! Name of the variable in the netcdf (if it's read)
tracervarname = 'thetao', 'so', ' ',
! Action (read or compute)
traceraction = 'read', 'read', 'compute'
! Dimension of the tracer
tracerdimension = 3D, 3D, 3D,
! Minimum and maximum value of the binning
tracermin = -3, 32, 250,
tracermax = 33, 38, 330,
/
With these instructions, the newly added tracer should work correctly. If there are any problems, either try to debug the code or carefully go through these instructions again. Using this as a guide, it is possible to add various other tracers to TRACMASS.
