src/layered/gotm.h
General Ocean Turbulence Model interface for multilayer
This module interfaces the multilayer solver with GOTM.
Vertical diffusion of momentum, temperature and salinity is handled by GOTM.
The temperature and salinity fields are undefined by default. If the calling solver defines them, the corresponding GOTM vertical diffusion routines will be called.
scalar T = {-1}, S = {-1};
The surface fluxes of momentum, heat and short-wave radiation are provided as surface fields by the calling solver. They are zero by default.
// surface wind stress (eg. in Pa or N/m^2)
(const) vector airsea_tau[] = {0.};
// surface heat flux (eg. in W/m^2)
(const) scalar airsea_heat_flux[] = 0.;
// surface short-wave radiation flux (eg. in W/m^2)
(const) scalar airsea_swr_flux[] = 0.;
Implementation
It uses the relevant headers from the C interface to GOTM.
#include "gotm/common.h"
#include <gotm/gotm/gotm.h>
// #include <gotm/gotm/diagnostics.h>
// #include <gotm/util/time.h>
#include <gotm/meanflow/meanflow.h>
// #include <gotm/meanflow/updategrid.h>
// #include <gotm/meanflow/wequation.h>
#include <gotm/meanflow/coriolis.h>
#include <gotm/meanflow/uequation.h>
#include <gotm/meanflow/vequation.h>
// #include <gotm/meanflow/extpressure.h>
// #include <gotm/meanflow/intpressure.h>
#include <gotm/meanflow/friction.h>
#include <gotm/meanflow/shear.h>
#include <gotm/meanflow/stratification.h>
#include <gotm/meanflow/salinity.h>
#include <gotm/meanflow/temperature.h>
#include <gotm/meanflow/convectiveadjustment.h>
#include <gotm/util/convert_fluxes.h>
#include <gotm/util/tridiagonal.h>
#include <gotm/util/eqstate.h>
#include <gotm/turbulence/turbulence.h>
#include <gotm/turbulence/kpp.h>
// #include <gotm/observations/observations.h>
#include <gotm/airsea/airsea.h>
The corresponding GOTM libraries need to be linked. Note that the
GOTM
environment variable need to point to the proper
installation directory.
#pragma autolink \
-L$GOTM/build/ -lgotm -lairsea -lmeanflow -lobservations -lturbulence \
-linput -lutil -loutput_manager `nf-config --flibs` \
-lgfortran
The timestepping routine is based on its Fortran counterpart.
static void gotm_step (long n)
{
// prepare time and output
// time_update_time (&n);
// all observations/data
#if 0
(&time_julianday, &time_secondsofday,
input_do_input &nl, &meanflow_z);
(&time_julianday, &time_secondsofday,
observations_get_all_obs &nl, &meanflow_z);
#endif
// external forcing
#if 0
if (airsea_calc_fluxes) {
// fixme: check indices
(&meanflow_t.a[nl-1]); // check this
airsea_set_sst (&meanflow_u.a[nl-1],
airsea_set_ssuv &meanflow_v.a[nl-1]);
}
#endif
// airsea_do_airsea (&time_julianday, &time_secondsofday);
// reset some quantities
/= meanflow_rho_0;
airsea_tx /= meanflow_rho_0;
airsea_ty
// sum fluxes as a diagnostic
// airsea_integrated_fluxes (&dt);
// meanflow integration starts
#if 0
realtype zeta = observations_get_zeta();
(&nl, &dt, &zeta);
meanflow_updategrid (&nl, &dt);
meanflow_wequation #endif
#if 0
double omega = 2.*pi/86164.;
double latitude = 50.; // 50.;
= 2.*omega*sin(2.*pi*latitude/360.);
meanflow_cori (&nl, &dt);
meanflow_coriolis #endif
// update velocity
integer ext_press_mode = 99; // no external pressure gradient
(&nl, &dt, &gotm_cnpar, &airsea_tx,
meanflow_uequation .a, turbulence_gamu.a,
turbulence_num&ext_press_mode);
(&nl, &dt, &gotm_cnpar, &airsea_ty,
meanflow_vequation .a, turbulence_gamv.a,
turbulence_num&ext_press_mode);
#if 0
(&observations_ext_press_mode, &nl);
meanflow_extpressure (&nl);
meanflow_intpressure #endif
(&turbulence_kappa, &meanflow_avmolu,
meanflow_friction &airsea_tx, &airsea_ty);
// update temperature and salinity
if (S.i >= 0)
(&nl, &dt, &gotm_cnpar,
meanflow_salinity .a, turbulence_gams.a);
turbulence_nus
if (T.i >= 0)
(&nl, &dt, &gotm_cnpar, &airsea_i_0, &airsea_heat,
meanflow_temperature .a, turbulence_gamh.a, meanflow_rad.a);
turbulence_nuh
// update shear and stratification
(&nl, &gotm_cnpar);
meanflow_shear (&nl, &gotm_buoy_method,
meanflow_stratification &dt, &gotm_cnpar,
.a, turbulence_gamh.a);
turbulence_nuh
// compute turbulent mixing
switch (turbulence_turb_method) {
case 0:
// do convective adjustment
(&nl, turbulence_num.a, turbulence_nuh.a,
meanflow_convectiveadjustment &turbulence_const_num, &turbulence_const_nuh,
&gotm_buoy_method, &meanflow_gravity,
&meanflow_rho_0);
break;
case 99: {
// update KPP model
realtype precip = airsea_precip + airsea_evap;
realtype tFlux, btFlux, sFlux, bsFlux;
realtype tRad[nl+1], bRad[nl+1]; // fixme: check this
(&nl, &meanflow_gravity, &meanflow_cp,
util_convert_fluxes &meanflow_rho_0,
&airsea_heat, &precip,
.a, meanflow_t.a, meanflow_s.a,
meanflow_rad&tFlux, &sFlux, &btFlux, &bsFlux,
, bRad);
tRad
(&nl, &meanflow_depth,
kpp_do_kpp .a, meanflow_rho.a, meanflow_u.a,
meanflow_h.a, meanflow_nn.a, meanflow_nnt.a, meanflow_nns.a,
meanflow_v.a,
meanflow_ss&meanflow_u_taus, &meanflow_u_taub,
&tFlux, &btFlux, &sFlux, &bsFlux,
, bRad, &meanflow_cori);
tRadbreak;
}
default:
// update one-point models
(&nl, &dt, &meanflow_depth,
turbulence_do_turbulence &meanflow_u_taus,
&meanflow_u_taub, &meanflow_z0s, &meanflow_z0b,
.a, meanflow_nn.a, meanflow_ss.a,
meanflow_h#ifdef SEAGRASS
.a
xP#else
NULL#endif
);
}
}
The initialisation tries to call the relevant initialisation functions from GOTM, as they appear in the original gotm.F90 source code.
event defaults (i = 0)
{
// cnpar [float, minimum = 0, maximum = 1]
// Constant for the theta scheme used for time integration of
// diffusion-reaction components. \theta=0.5 for Cranck-Nicholson
// (second-order accurate), \theta=0 for Forward Euler (first-
// order accurate), \theta=1 for Backward Euler (first-order
// accurate). Note that only \theta=1 guarantees positive
// solutions for positive definite systems.
= 1.;
gotm_cnpar
// buoy_method [integer]
// method to compute mean buoyancy
// 1: from equation of state (i.e. from potential temperature
// and salinity)
// 2: from prognostic equation
= 1;
gotm_buoy_method
= G;
meanflow_gravity
(&nl);
mtridiagonal_init_tridiagonal realtype latitude = 0.;
(&nl, &latitude);
meanflow_post_init_meanflow if (turbulence_turb_method == 99) {
integer namlst = -1;
(&namlst, "", &nl, &meanflow_depth, meanflow_h.a,
kpp_init_kpp &G, &meanflow_rho_0);
}
else(&nl);
turbulence_post_init_turbulence }
Vertical diffusion is part of the “viscous terms” of the multilayer event loop. We just copy the relevant fields into the corresponding GOTM fields, call GOTM and retrieve the updated fields.
event viscous_term (i++)
{
struct { realtype * x, * y; } gotm_u = { meanflow_u.a, meanflow_v.a };
struct { realtype * x, * y; } gotm_t = { &airsea_tx, &airsea_ty };
foreach() {
foreach_dimension()
*gotm_t.x = airsea_tau.x[];
double z = zb[];
() {
foreach_layer.a[point.l + 1] = h[];
meanflow_hforeach_dimension()
.x[point.l + 1] = u.x[];
gotm_uif (T.i >= 0)
.a[point.l + 1] = T[];
meanflow_tif (S.i >= 0)
.a[point.l + 1] = S[];
meanflow_s.a[point.l + 1] = z + h[]/2.;
meanflow_z+= h[];
z }
= airsea_heat_flux[];
airsea_heat = airsea_swr_flux[];
airsea_i_0 gotm_step (i);
() {
foreach_layerforeach_dimension()
.x[] = gotm_u.x[point.l + 1];
uif (T.i >= 0)
[] = meanflow_t.a[point.l + 1];
Tif (S.i >= 0)
[] = meanflow_s.a[point.l + 1];
S}
}
}
The GOTM cleanup function deallocates Fortran fields etc.
event cleanup (t = end)
{
();
gotm_clean_up}
Utility functions
This function uses GOTM to initialize a vertical temperature profile
corresponding to a squared buoyancy frequency NN
for a
given constant salinity and top temperature.
void constant_NNT (double T_top, double S_const, double NN,
scalar T)
{
foreach() {
double z = zb[];
()
foreach_layer+= h[];
z [0,0,nl-1] = T_top;
Tfor (int l = nl - 2; l >= 0; l--) {
double pFace = G*(z - h[0,0,l]/2.);
double alpha = eqstate_eos_alpha (&S_const, &T[0,0,l+1], &pFace, &G,
&meanflow_rho_0);
[0,0,l] = T[0,0,l+1] - 1./(G*alpha)*NN*h[0,0,l];
T-= h[0,0,l];
z }
}
}