The following subroutines can be called by programs that are linked against ecTrans. Here we describe in detail their signatures.
Note
ecTrans is a legacy code with an accumulated 30 years of history. Over this time certain features enabled through optional arguments will have fallen out of use. We are currently reviewing all options to identify those that can be safely deleted, but this takes time. In the mean time, we have tagged below all options we deem to be "potentially deprecatable".
ecTrans in principle follows the coding standard and conventions outlined in the IFS Documentation - Part VI: Technical and Computational Procedures section 1.5. Following these standards, all variable names must begin with a one- or two-character prefix denoting their scope (module level, dummy argument, local variables, loop index, or parameter) and type. These are outlined in Table 1.2. Dummy variables have the following prefixes:
K - integerP - real (single or double precision)LD - logicalCD - characterYD - derived typeKIND parametersAs with the IFS, integer and real variables in ecTrans always have an explicit KIND specification.
These are defined in the PARKIND1 module which is part of the Fiat library (a dependency of ecTrans). To understand the
subroutines described here, only two must be considered:
INTEGER, PARAMETER :: JPIM = SELECTED_INT_KIND(9) (i.e. 4-byte integer)INTEGER, PARAMETER :: JPRD = SELECTED_REAL_KIND(13,300) (i.e. 8-byte float)SETUP_TRANS0SUBROUTINE SETUP_TRANS0(KOUT, KERR, KPRINTLEV, KMAX_RESOL, KPROMATR, KPRGPNS, KPRGPEW, KPRTRW, &
& LDMPOFF, LDSYNC_TRANS, KTRANS_SYNC_LEVEL, LDEQ_REGIONS, K_REGIONS_NS, &
& K_REGIONS_EW, K_REGIONS, PRAD, LDALLOPERM, KOPT_MEMORY_TR)
This subroutine initialises all resolution-agnostic aspects of the ecTrans library. It must be called before any other ecTrans subroutines.
OPTIONAL, INTENT(IN) argumentsINTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KOUT6 (i.e. STDOUT)INTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KERR0 (i.e. STDERR)INTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KPRINTLEV0INTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KMAX_RESOL1INTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KPROMATR0INTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KPRGPNS1INTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KPRGPEW1INTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KPRTRW1LOGICAL, OPTIONAL, INTENT(IN) :: LDMPOFF.FALSE.LOGICAL, OPTIONAL, INTENT(IN) :: LDSYNC_TRANS.FALSE.INTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KTRANS_SYNC_LEVEL0LOGICAL, OPTIONAL, INTENT(IN) :: LDEQ_REGIONSEQ_REGIONS partitioning mode..FALSE.LOGICAL, OPTIONAL, INTENT(IN) :: LDALLOPERM.FALSE.REAL(KIND=JPRD), OPTIONAL, INTENT(IN) :: PRAD6371229.0INTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KOPT_MEMORY_TR0OPTIONAL, INTENT(OUT) argumentsINTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: K_REGIONS(:)EQ_REGIONS algorithm.INTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: K_REGIONS_NSEQ_REGIONS algorithm.INTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: K_REGIONS_EWEQ_REGIONS algorithm.SETUP_TRANSSUBROUTINE SETUP_TRANS(KSMAX, KDGL, KDLON, KLOEN, LDSPLIT, PSTRET, KTMAX, KRESOL, PWEIGHT, &
& LDGRIDONLY, LDUSERPNM, LDKEEPRPNM, LDUSEFLT, LDSPSETUPONLY, LDPNMONLY, &
& LDUSEFFTW, LD_ALL_FFTW, LDLL, LDSHIFTLL, CDIO_LEGPOL, CDLEGPOLFNAME, &
& KLEGPOLPTR, KLEGPOLPTR_LEN)
This subroutine establishes the environment for performing a spectral transform. Each call to
this subroutine creates work arrays for a certain resolution. One can do this for NMAX_RESOL
different resolutions (internal parameter corresponding to KMAX_RESOL argument of SETUP_TRANS0).
One must call SETUP_TRANS0 before calling this subroutine for the first time.
INTENT(IN) argumentsINTEGER(KIND=JPIM), INTENT(IN) :: KSMAXINTEGER(KIND=JPIM), INTENT(IN) :: KDGLOPTIONAL, INTENT(IN) argumentsINTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KDLON2 * KDGL, unless LDLL is .TRUE. in which case it will
take the value of 2 * KDGL + 2, unless KLOEN is provided in which case it will take the value
of MAXVAL(KLOEN).INTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KLOEN(:)KDLON points.KDGL)LOGICAL, OPTIONAL, INTENT(IN) :: LDSPLIT.FALSE.REAL(KIND=JPRD), OPTIONAL, INTENT(IN) :: PSTRET1.0INTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KTMAXKSMAXREAL(KIND=JPRD), OPTIONAL, INTENT(IN) :: PWEIGHT(:)LOGICAL, OPTIONAL, INTENT(IN) :: LDGRIDONLY.FALSE.LOGICAL, OPTIONAL, INTENT(IN) :: LDUSEFLT.FALSE.LOGICAL, OPTIONAL, INTENT(IN) :: LD_ALL_FFTW.FALSE.LOGICAL, OPTIONAL, INTENT(IN) :: LDUSERPNM.TRUE.LOGICAL, OPTIONAL, INTENT(IN) :: LDKEEPRPNM.FALSE.LOGICAL, OPTIONAL, INTENT(IN) :: LDSPSETUPONLY.FALSE.LOGICAL, OPTIONAL, INTENT(IN) :: LDPNMONLY.FALSE.LOGICAL, OPTIONAL, INTENT(IN) :: LDLL.FALSE.LOGICAL, OPTIONAL, INTENT(IN) :: LDSHIFTLL.FALSE.CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: CDIO_LEGPOLCDLEGPOLFNAME. If 'writef' is passed, Legendre polynomials will be written to the file given
to CDLEGPOLFNAME. If 'membuf' is passed, Legendre polynomials will be read from shared memory.CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: CDLEGPOLFNAMECDIO_LEGPOL.TYPE(C_PTR), OPTIONAL, INTENT(IN) :: KLEGPOLPTRCDIO_LEGPOL.INTEGER(C_SIZE_T), OPTIONAL, INTENT(IN) :: KLEGPOLPTR_LENCDIO_LEGPOL.LOGICAL, OPTIONAL, INTENT(IN) :: LDUSEFFTWOPTIONAL, INTENT(OUT) argumentsINTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KRESOLTRANS_INQSUBROUTINE TRANS_INQ(KRESOL, KSPEC, KSPEC2, KSPEC2G, KSPEC2MX, KNUMP, KGPTOT, KGPTOTG, KGPTOTMX, &
& KGPTOTL, KMYMS, KASM0, KUMPP, KPOSSP, KPTRMS, KALLMS, KDIM0G, KFRSTLAT, &
& KLSTLAT, KFRSTLOFF, KPTRLAT, KPTRFRSTLAT, KPTRLSTLAT, KPTRFLOFF, KSTA, KONL, &
& KULTPP, KPTRLS, KNMENG, KPRTRW, KMYSETW, KMYSETV, KMY_REGION_NS, &
& KMY_REGION_EW, LDSPLITLAT, KSMAX, PLAPIN, KNVALUE, KDEF_RESOL, LDLAM, PMU, &
& PGW, PRPNM, KLEI3, KSPOLEGL, KPMS, KDGLU)
This subroutine allows one to obtain information on the transform configuration for a given
KRESOL handle (or the default handle if this argument is omitted).
OPTIONAL, INTENT(IN) argumentsINTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KRESOLOPTIONAL, INTENT(OUT) argumentsINTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KSPECINTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KSPEC22 * KSPEC.INTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KSPEC2GINTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KSPEC2MXKSPEC2 over all MPI tasks.INTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KNUMPINTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KGPTOTINTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KGPTOTGINTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KGPTOTMXINTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KGPTOTL(:,:)N_REGIONS_NS:N_REGIONS_EW).INTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KMYMS(:)INTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KASM0(0:)INTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KUMPP(:)INTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KPOSSP(:)INTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KPTRMS(:)INTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KALLMS(:)INTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KDIM0G(0:)INTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KFRSTLAT(:)INTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KLSTLAT(:)INTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KFRSTLOFFINTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KPTRLAT(:)INTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KPTRFRSTLAT(:)INTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KPTRLSTLAT(:)INTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KPTRFLOFFINTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KSTA(:,:)N_REGIONS_NS.INTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KONL(:,:)INTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KULTPP(:)INTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KPTRLS(:)INTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KNMENG(:)INTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KPRTRWINTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KMYSETWINTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KMYSETVINTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KMY_REGION_NSINTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KMY_REGION_EWLOGICAL, OPTIONAL, INTENT(OUT) :: LDSPLITLAT(:)INTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KSMAXREAL(KIND=JPRB), OPTIONAL, INTENT(OUT) :: PLAPIN(-1:)INTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KNVALUE(:)KSPEC2 spectral coeffientINTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KDEF_RESOLLOGICAL, OPTIONAL, INTENT(OUT) :: LDLAMREAL(KIND=JPRD), OPTIONAL, INTENT(OUT) :: PMU(:)REAL(KIND=JPRB), OPTIONAL, INTENT(OUT) :: PGW(:)REAL(KIND=JPRB), OPTIONAL, INTENT(OUT) :: PRPNM(:,:)INTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KLEI3INTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KSPOLEGLINTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KPMS(0:)INTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KDGLU(0:)DIR_TRANSSUBROUTINE DIR_TRANS(PSPVOR, PSPDIV, PSPSCALAR, PSPSC3A, PSPSC3B, PSPSC2, LDLATLON, KPROMA, &
& KVSETUV, KVSETSC, KRESOL, KVSETSC3A, KVSETSC3B, KVSETSC2, PGP, PGPUV, PGP3A, &
& PGP3B, PGP2, LPGP_ON_GPU, LPSP_ON_GPU)
This subroutine performs a direct spectral transform.
DIR_TRANS supports two modes of passing arrays (which we call "call modes" below):
PGP, receive PSPVOR, PSPDIV, PSPSCALAR.PGPUV, PGP3A, PGP3B, PGP2, receive PSPVOR, PSPDIV, PSPSC3A, PSPSC3B, PSPSC2.Although call mode 1 is simpler, it can often entail having to create array copies in order to
prepare the different elements of PGP. Hence, with call mode 2, the input and output arrays are
categorized according to whether they are wind related, 3D scalar, or 2D scalar.
Note that PSPSC3A/PGP3A and PSPSC3B/PGP3B are essentially identical in type and size.
There are cases where it is useful to have the ability to pass two sets of scalar fields to be
transformed independently.
OPTIONAL, INTENT(IN) argumentsINTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KPROMAD%NGPTOTINTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KVSETUV(:)INTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KVSETSC(:)INTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KVSETSC3A(:)INTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KVSETSC3B(:)INTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KVSETSC2(:)INTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KRESOLSETUP_TRANS.LOGICAL, OPTIONAL, INTENT(IN) :: LDLATLONREAL(KIND=JPRB), OPTIONAL, INTENT(IN) :: PGP(:,:,:)REAL(KIND=JPRB), OPTIONAL, INTENT(IN) :: PGPUV(:,:,:,:)DIR_TRANS only operates on U/V winds, not vorticity/divergence. Hence, the third dimension of
PGPUV must be equal to 2 (one for U and one for V).REAL(KIND=JPRB), OPTIONAL, INTENT(IN) :: PGP3A(:,:,:,:)PSPSC3A.REAL(KIND=JPRB), OPTIONAL, INTENT(IN) :: PGP3B(:,:,:,:)PSPSC3B.REAL(KIND=JPRB), OPTIONAL, INTENT(IN) :: PGP2(:,:,:)PSPSC2.LOGICAL, OPTIONAL, INTENT(IN) :: LPGP_ON_GPUPGP, PGPUV, PGP3A, PGP3B and PGP2. If present and
true, the GPU path assumes the corresponding present array is already resident on device and skips
the associated host/device synchronization. Ignored on the CPU path..FALSE.LOGICAL, OPTIONAL, INTENT(IN) :: LPSP_ON_GPUPSPVOR, PSPDIV, PSPSCALAR, PSPSC3A, PSPSC3B, and
PSPSC2. If present and true, the GPU path will not copy these arrays back to host after
performing the transform. Ignored on the CPU path..FALSE.OPTIONAL, INTENT(OUT) argumentsREAL(KIND=JPRB), OPTIONAL, INTENT(OUT) :: PSPVOR(:,:)REAL(KIND=JPRB), OPTIONAL, INTENT(OUT) :: PSPDIV(:,:)REAL(KIND=JPRB), OPTIONAL, INTENT(OUT) :: PSPSCALAR(:,:)REAL(KIND=JPRB), OPTIONAL, INTENT(OUT) :: PSPSC3A(:,:,:)PGP3A.REAL(KIND=JPRB), OPTIONAL, INTENT(OUT) :: PSPSC3B(:,:,:)PGP3B.REAL(KIND=JPRB), OPTIONAL, INTENT(OUT) :: PSPSC2(:,:)PGP2.INV_TRANSSUBROUTINE INV_TRANS(PSPVOR, PSPDIV, PSPSCALAR, PSPSC3A, PSPSC3B, PSPSC2, FSPGL_PROC, LDSCDERS, &
& LDVORGP, LDDIVGP, LDUVDER, LDLATLON, KPROMA, KVSETUV, KVSETSC, KRESOL, &
& KVSETSC3A, KVSETSC3B, KVSETSC2, PGP, PGPUV, PGP3A, PGP3B, PGP2, LPGP_ON_GPU, &
& LPSP_ON_GPU)
This subroutine performs an inverse spectral transform.
INV_TRANS supports two modes of passing arrays (which we call "call modes" below):
PSPVOR, PSPDIV, PSPSCALAR, receive PGP.PSPVOR, PSPDIV, PSPSC3A, PSPSC3B, PSPSC2, receive PGPUV, PGP3A, PGP3B, PGP2Although call mode 1 is simpler, it can often entail having to create array copies in order to
subsequently operate on the different elements of PGP. Hence, with call mode 2, the output
arrays are already categorized according to whether they are wind related, 3D scalar, or 2D
scalar.
Note that PSPSC3A/PGP3A and PSPSC3B/PGP3B are essentially identical in type and size.
There are cases where it is useful to have the ability to pass two sets of scalar fields to be
transformed independently.
OPTIONAL, INTENT(IN) argumentsREAL(KIND=JPRB), OPTIONAL, INTENT(IN) :: PSPVOR(:,:)REAL(KIND=JPRB), OPTIONAL, INTENT(IN) :: PSPDIV(:,:)REAL(KIND=JPRB), OPTIONAL, INTENT(IN) :: PSPSCALAR(:,:)REAL(KIND=JPRB), OPTIONAL, INTENT(IN) :: PSPSC3A(:,:,:)PGP3A.REAL(KIND=JPRB), OPTIONAL, INTENT(IN) :: PSPSC3B(:,:,:)PGP3B.REAL(KIND=JPRB), OPTIONAL, INTENT(IN) :: PSPSC2(:,:)PGP2.LOGICAL, OPTIONAL, INTENT(IN) :: LDSCDERS.FALSE.LOGICAL, OPTIONAL, INTENT(IN) :: LDVORGP.FALSE.LOGICAL, OPTIONAL, INTENT(IN) :: LDDIVGP.FALSE.LOGICAL, OPTIONAL, INTENT(IN) :: LDUVDER.FALSE.LOGICAL, OPTIONAL, INTENT(IN) :: LDLATLON.FALSE.INTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KPROMAD%NGPTOTINTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KVSETUV(:)INTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KVSETSC(:)INTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KVSETSC3A(:)INTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KVSETSC3B(:)INTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KVSETSC2(:)INTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KRESOLSETUP_TRANS.LOGICAL, OPTIONAL, INTENT(IN) :: LPGP_ON_GPUPGP, PGPUV, PGP3A, PGP3B and PGP2. If present and
true, the GPU path leaves the PGP arrays resident on device and skips the associated host/device
synchronization. Ignored on the CPU path..FALSE.LOGICAL, OPTIONAL, INTENT(IN) :: LPSP_ON_GPUPSPVOR, PSPDIV, PSPSCALAR, PSPSC3A, PSPSC3B, and
PSPSC2. If present and true, the GPU path skips the copy of these arrays from host to device,
instead assuming that they are already present. Ignored on the CPU path..FALSE.OPTIONAL, EXTERNAL argumentsOPTIONAL, EXTERNAL :: FSPGL_PROCOPTIONAL, INTENT(OUT) argumentsREAL(KIND=JPRB), OPTIONAL, INTENT(OUT) :: PGP(:,:,:)PSPVOR is present and LDVORGP)PSPDIV is present and LDDIVGP)PSPVOR and PSPDIV are present)PSPVOR and PSPDIV are present)PSPSCALAR is present)PSPSCALAR is present and LDSCDERS)PSPVOR and PSPDIV are present and LDUVDER)PSPVOR and PSPDIV are present and LDUVDER)PSPSCALAR is present and LDSCDERS)REAL(KIND=JPRB), OPTIONAL, INTENT(OUT) :: PGPUV(:,:,:,:)PSPVOR is present and LDVORGP)PSPDIV is present and LDDIVGP)PSPVOR and PSPDIV are present)PSPVOR and PSPDIV are present)PSPVOR and PSPDIV are present and LDUVDER)PSPVOR and PSPDIV are present and LDUVDER)REAL(KIND=JPRB), OPTIONAL, INTENT(OUT) :: PGP3A(:,:,:,:)PSPSC3A.LDSCDERS)LDSCDERS)REAL(KIND=JPRB), OPTIONAL, INTENT(OUT) :: PGP3B(:,:,:,:)PSPSC3B.LDSCDERS)LDSCDERS)REAL(KIND=JPRB), OPTIONAL, INTENT(OUT) :: PGP2(:,:,:)PSPSC2.LDSCDERS)LDSCDERS)SPECNORMSUBROUTINE SPECNORM(PNORM, PSPEC, KVSET, KMASTER, KRESOL, PMET)
This subroutine computes the spectral norms of the fields in the given input array and returns the values to a specific MPI task.
OPTIONAL, INTENT(IN) argumentsREAL(KIND=JPRB), OPTIONAL, INTENT(IN) :: PSPEC(:,:)KVSET.INTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KVSET(:)INTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KMASTERPNORM will contain values.1REAL(KIND=JPRB), OPTIONAL, INTENT(IN) :: PMET(:)R%NSMAX) (R%NSMAX is the same as KSMAX passed to SETUP_TRANS)1.0INTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KRESOLSETUP_TRANS.1 (i.e. first resolution handle)INTENT(OUT) argumentsREAL(KIND=JPRB), INTENT(OUT) :: PNORM(:)KMASTER needs to actually allocate its array
though.GPNORM_TRANSSUBROUTINE GPNORM_TRANS(PGP, KFIELDS, KPROMA, PAVE, PMIN, PMAX, LDAVE_ONLY, KRESOL, LPGP_ON_GPU)
This subroutine calculates the global average (and optionally the global minimum and maximum) of the input fields in grid point space. The results are communicated to task 1 only.
INTENT(IN) argumentsREAL(KIND=JPRB), INTENT(IN) :: PGP(:,:,:)INTEGER(KIND=JPIM), INTENT(IN) :: KFIELDSINTEGER(KIND=JPIM), INTENT(IN) :: KPROMALOGICAL, INTENT(IN) :: LDAVE_ONLYPMIN and PMAX should already contain the minimum and maximum values of each field for each MPI
task's local region, and afterwards they will contain the global maximum and minimum (again, only
on task 1).OPTIONAL, INTENT(IN) argumentsINTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KRESOLSETUP_TRANS.1 (i.e. first resolution handle)LOGICAL, OPTIONAL, INTENT(IN) :: LPGP_ON_GPU.TRUE., this argument indicates that input grid point data is already resident on device
and no host->device update is needed..FALSE.INTENT(OUT) argumentsREAL(KIND=JPRB), INTENT(OUT) :: PAVE(:)KFIELDS)INTENT(INOUT) argumentsREAL(KIND=JPRB), INTENT(INOUT) :: PMIN(:)KFIELDS)REAL(KIND=JPRB), INTENT(INOUT) :: PMAX(:)KFIELDS)GPNORM_TRANSADSUBROUTINE GPNORM_TRANSAD(PGP, KFIELDS, KPROMA, PAVE, KRESOL)
This subroutine is the "adjoint" version of GPNORM_TRANSTL.
INTENT(IN) argumentsINTEGER(KIND=JPIM), INTENT(IN) :: KFIELDSINTEGER(KIND=JPIM), INTENT(IN) :: KPROMAOPTIONAL, INTENT(IN) argumentsINTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KRESOLSETUP_TRANS.1 (i.e. first resolution handle)INTENT(INOUT) argumentsREAL(KIND=JPRB), INTENT(INOUT) :: PAVE(:)KFIELDS)INTENT(OUT) argumentsREAL(KIND=JPRB), INTENT(OUT) :: PGP(:,:,:)GPNORM_TRANSTLSUBROUTINE GPNORM_TRANSTL(PGP, KFIELDS, KPROMA, PAVE, KRESOL)
This subroutine is the "tangent linear" version of GPNORM_TRANS. It is actually identical, but
has a simpler interface as the PMIN and PMAX arguments are not used for tangent-linear
applications.
INTENT(IN) argumentsREAL(KIND=JPRB), INTENT(IN) :: PGP(:,:,:)INTEGER(KIND=JPIM), INTENT(IN) :: KFIELDSINTEGER(KIND=JPIM), INTENT(IN) :: KPROMAOPTIONAL, INTENT(IN) argumentsINTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KRESOLSETUP_TRANS.1 (i.e. first resolution handle)INTENT(OUT) argumentsREAL(KIND=JPRB), INTENT(OUT) :: PAVE(:)KFIELDS)DIST_GRIDSUBROUTINE DIST_GRID(PGPG, KPROMA, KFDISTG, KFROM, KRESOL, PGP, KSORT)
The subroutine distributes one or more global grid point fields resident across one or more MPI
tasks (each field is entirely resident on a single MPI task without decomposition) among all
other tasks, decomposing them along the way. It is the opposite of GATH_GRID.
The figure below illustrates an example in which four fields are distributed equally across four
MPI tasks. Note that at the end, each task receives part of all four input fields. Note also that
the NPROMA-based blocking is introduced at the end of DIST_GRID.

INTENT(IN) argumentsINTEGER(KIND=JPIM), INTENT(IN) :: KFDISTGINTEGER(KIND=JPIM), INTENT(IN) :: KFROM(:)KFDISTG)OPTIONAL, INTENT(IN) argumentsREAL(KIND=JPRB), OPTIONAL, INTENT(IN) :: PGPG(:,:)PGPG).INTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KPROMAD%NGPTOTINTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KRESOLSETUP_TRANS.1 (i.e. first resolution handle)INTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KSORT(:)PGP)INTENT(OUT) argumentsREAL(KIND=JPRB), INTENT(OUT) :: PGP(:,:,:)GATH_GRIDSUBROUTINE GATH_GRID(PGPG, KPROMA, KFGATHG, KTO, KRESOL, PGP)
The subroutine gathers one or more fields distributed across one or more MPI tasks and sends them
to a particular MPI task. It is the opposite of DIST_GRID.
The figure below illustrates an example in which four fields which are distributed equally across four MPI tasks are gathered so that each task possesses one field in its entirety. The NPROMA blocking is removed along the way so that at the end, each field only has a single horizontal dimension

INTENT(IN) argumentsINTEGER(KIND=JPIM), INTENT(IN) :: KFGATHGINTEGER(KIND=JPIM), INTENT(IN) :: KTO(:)KFGATHG)REAL(KIND=JPRB), INTENT(IN) :: PGP(:,:,:)OPTIONAL, INTENT(IN) argumentsINTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KPROMAD%NGPTOTINTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KRESOLSETUP_TRANS.1 (i.e. first resolution handle)OPTIONAL, INTENT(OUT) argumentsREAL(KIND=JPRB), OPTIONAL, INTENT(OUT) :: PGPG(:,:)DIST_SPECSUBROUTINE DIST_SPEC(PSPECG, KFDISTG, KFROM, KVSET, KRESOL, PSPEC, LDIM1_IS_FLD, KSMAX, KSORT)
This subroutine distributes a global spectral array among MPI tasks according to the specified
distribution parameters. Fields are partitioned in the horizontal dimension (i.e. the dimension
of spectral coefficients) and in the "fields" dimension, according to KVSET. This subroutine
is the opposite of GATH_SPEC.
The figure below illustrates an example in which four fields are distributed equally across four
MPI tasks. In this case, NPRTRV = 2 which means that each field is split among two MPI tasks,
as shown. This is in contrast to DIST_GRID, which distributes fields such that each MPI task
receives a slice of every field.

INTENT(IN) argumentsINTEGER(KIND=JPIM), INTENT(IN) :: KFDISTGINTEGER(KIND=JPIM), INTENT(IN) :: KFROM(:)KFDISTG).OPTIONAL, INTENT(IN) argumentsREAL(KIND=JPRB), OPTIONAL, INTENT(IN) :: PSPECG(:,:)LDIM1_IS_FLD is.FALSE.). Note that this is optional, because some tasks may only receive fields (and so they
wouldn't have any fields to offer through PSPECG).INTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KVSET(:)KFDISTG).INTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KRESOLSETUP_TRANS.1 (i.e. first resolution handle)LOGICAL, OPTIONAL, INTENT(IN) :: LDIM1_IS_FLD.TRUE., the first dimension of PSPECG and PSPEC corresponds to fields and the second
dimension corresponds to spectral coefficients. If .FALSE., the first dimension corresponds to
spectral coefficients and the second dimension corresponds to fields..TRUE.INTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KSMAXKRESOL.KRESOLINTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KSORT(:)KFDISTG).OPTIONAL, INTENT(OUT) argumentsREAL(KIND=JPRB), OPTIONAL, INTENT(OUT) :: PSPEC(:,:)GATH_SPECSUBROUTINE GATH_SPEC(PSPECG, KFGATHG, KTO, KVSET, KRESOL, PSPEC, LDIM1_IS_FLD, KSMAX, LDZA0IP)
This subroutine gathers spectral fields decomposed among MPI tasks according to the specified
distribution parameters. This subroutine is the opposite of DIST_SPEC.
The figure below illustrates an example in which four fields distributed across four MPI
tasks are collected so that each task has one global spectral field. In this case, NPRTRV = 2
which means that each field is split among two MPI tasks to begin with, as shown.

INTENT(IN) argumentsINTEGER(KIND=JPIM), INTENT(IN) :: KFGATHGINTEGER(KIND=JPIM), INTENT(IN) :: KTO(:)KFGATHG).OPTIONAL, INTENT(IN) argumentsREAL(KIND=JPRB), OPTIONAL, INTENT(IN) :: PSPEC(:,:)LDIM1_IS_FLD is.FALSE.). Note that this is optional, because some tasks may not actually own any spectral
fields (and so they wouldn't have any fields to offer through PSPEC).INTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KVSET(:)KFGATHG).INTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KRESOLSETUP_TRANS.1 (i.e. first resolution handle)LOGICAL, OPTIONAL, INTENT(IN) :: LDIM1_IS_FLD.TRUE., the first dimension of PSPECG and PSPEC corresponds to fields and the second
dimension corresponds to spectral coefficients. If .FALSE., the first dimension corresponds to
spectral coefficients and the second dimension corresponds to fields..TRUE.INTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KSMAXKRESOL.KRESOLLOGICAL, OPTIONAL, INTENT(IN) :: LDZA0IP.TRUE., the imaginary part of the coefficients corresponding to zonal wavenumber 0 are
zeroed..TRUE.OPTIONAL, INTENT(OUT) argumentsREAL(KIND=JPRB), OPTIONAL, INTENT(OUT) :: PSPECG(:,:)GET_CURRENTSUBROUTINE GET_CURRENT(KRESOL, LDLAM)
This subroutine allows one to retrieve the current resolution handle, NCUR_RESOL, and the LAM
parameter, LDLAM, which indicates if the local area version of ecTrans is being used or not.
Note
LDLAM will always be .FALSE. for the moment. ecTrans currently only supports global spectral
transforms, though local (bifourier) transforms may be supported in future.
OPTIONAL, INTENT(OUT) argumentsINTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KRESOLLOGICAL, OPTIONAL, INTENT(OUT) :: LDLAMINI_SPEC_DISTSUBROUTINE INI_SPEC_DIST(KSMAX, KTMAX, KPRTRW, KMYSETW, KASM0, KSPOLEGL, KPROCM, KUMPP, KSPEC, &
& KSPEC2, KSPEC2MX, KPOSSP, KMYMS, KPTRMS, KALLMS)
This subroutine initializes the arrays controlling spectral wave distribution.
INTENT(IN) argumentsINTEGER(KIND=JPIM), INTENT(IN) :: KSMAXINTEGER(KIND=JPIM), INTENT(IN) :: KTMAXKSMAX.INTEGER(KIND=JPIM), INTENT(IN) :: KPRTRWINTEGER(KIND=JPIM), INTENT(IN) :: KMYSETWOPTIONAL, INTENT(OUT) argumentsINTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KASM0(0:KSMAX)INTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KSPOLEGLINTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KPROCM(0:KSMAX)INTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KUMPP(KPRTRW)INTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KSPECINTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KSPEC2INTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KSPEC2MXKSPEC2 across tasks.INTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KPOSSP(KPRTRW+1)INTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KMYMS(KSMAX+1)INTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KPTRMS(KPRTRW)INTEGER(KIND=JPIM), OPTIONAL, INTENT(OUT) :: KALLMS(KSMAX+1)TRANS_PNMSUBROUTINE TRANS_PNM(KRESOL, KM, PRPNM, LDTRANSPOSE, LDCHEAP)
This subroutine computes the Legendre polynomials for a given wavenumber.
INTENT(IN) argumentsINTEGER(KIND=JPIM), INTENT(IN) :: KMOPTIONAL, INTENT(IN) argumentsINTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KRESOLSETUP_TRANS.1 (i.e. first resolution handle)LOGICAL, OPTIONAL, INTENT(IN) :: LDTRANSPOSEPRPNM below)..FALSE.LOGICAL, OPTIONAL, INTENT(IN) :: LDCHEAP.FALSE.INTENT(OUT) argumentsREAL(KIND=JPRB), INTENT(OUT) :: PRPNM(:,:)LDTRANSPOSE. Note that
this must be already allocated. See
SETUP_DIMS_MOD for
the defininition of R%NLEI3.(R%NTMAX-KM+3, R%NLEI3) if LDTRANSPOSE is .TRUE., else (R%NLEI3, R%NTMAX-KM+3)VORDIV_TO_UVSUBROUTINE VORDIV_TO_UV(PSPVOR, PSPDIV, PSPU, PSPV, KSMAX, KVSETUV)
This subroutine converts spectral space vorticity and divergence to spectral space u and v wind components.
Note that this is a "special" subroutine: it can be called in isolation without initialisation by
SETUP_TRANS0 and SETUP_TRANS. This is why it is necessary to pass in KSMAX explicitly.
INTENT(IN) argumentsREAL(KIND=JPRB), INTENT(IN) :: PSPVOR(:,:)REAL(KIND=JPRB), INTENT(IN) :: PSPDIV(:,:)INTEGER(KIND=JPIM), INTENT(IN) :: KSMAXINTENT(OUT) argumentsREAL(KIND=JPRB), INTENT(OUT) :: PSPU(:,:)REAL(KIND=JPRB), INTENT(OUT) :: PSPV(:,:)OPTIONAL, INTENT(IN) argumentsINTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KVSETUV(:)DIR_TRANSADSUBROUTINE DIR_TRANSAD(PSPVOR, PSPDIV, PSPSCALAR, PSPSC3A, PSPSC3B, PSPSC2, KPROMA, KVSETUV, &
& KVSETSC, KRESOL, KVSETSC3A, KVSETSC3B, KVSETSC2, PGP, PGPUV, PGP3A, PGP3B, &
& PGP2)
This is the adjoint version of the subroutine for performing a direct spectral transform.
Like DIR_TRANS, DIR_TRANSAD supports two modes of passing arrays (which we call "call modes"
below):
PGP, receive PSPVOR, PSPDIV, PSPSCALAR.PGPUV, PGP3A, PGP3B, PGP2, receive PSPVOR, PSPDIV, PSPSC3A, PSPSC3B, PSPSC2.Although call mode 1 is simpler, it can often entail having to create array copies in order to
prepare the different elements of PGP. Hence, with call mode 2, the input and output arrays are
categorized according to whether they are wind related, 3D scalar, or 2D scalar.
Note that PSPSC3A/PGP3A and PSPSC3B/PGP3B are essentially identical in type and size.
There are cases where it is useful to have the ability to pass two sets of scalar fields to be
transformed independently.
OPTIONAL, INTENT(IN) argumentsINTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KPROMAD%NGPTOTINTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KVSETUV(:)INTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KVSETSC(:)INTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KVSETSC3A(:)INTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KVSETSC3B(:)INTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KVSETSC2(:)INTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KRESOLSETUP_TRANS.OPTIONAL, INTENT(OUT) argumentsREAL(KIND=JPRB), OPTIONAL, INTENT(OUT) :: PGP(:,:,:)REAL(KIND=JPRB), OPTIONAL, INTENT(OUT) :: PGPUV(:,:,:,:)DIR_TRANS only operates on U/V winds, not vorticity/divergence. Hence, the third dimension of
PGPUV must be equal to 2 (one for U and one for V).REAL(KIND=JPRB), OPTIONAL, INTENT(OUT) :: PGP3A(:,:,:,:)PSPSC3A.REAL(KIND=JPRB), OPTIONAL, INTENT(OUT) :: PGP3B(:,:,:,:)PSPSC3B.REAL(KIND=JPRB), OPTIONAL, INTENT(OUT) :: PGP2(:,:,:)PSPSC2.OPTIONAL, INTENT(INOUT) argumentsREAL(KIND=JPRB), OPTIONAL, INTENT(INOUT) :: PSPVOR(:,:)REAL(KIND=JPRB), OPTIONAL, INTENT(INOUT) :: PSPDIV(:,:)REAL(KIND=JPRB), OPTIONAL, INTENT(INOUT) :: PSPSCALAR(:,:)REAL(KIND=JPRB), OPTIONAL, INTENT(INOUT) :: PSPSC3A(:,:,:)PGP3A.REAL(KIND=JPRB), OPTIONAL, INTENT(INOUT) :: PSPSC3B(:,:,:)PGP3B.REAL(KIND=JPRB), OPTIONAL, INTENT(INOUT) :: PSPSC2(:,:)PGP2.INV_TRANSADSUBROUTINE INV_TRANSAD(PSPVOR, PSPDIV, PSPSCALAR, PSPSC3A, PSPSC3B, PSPSC2, FSPGL_PROC, LDSCDERS, &
& LDVORGP, LDDIVGP, LDUVDER, KPROMA, KVSETUV, KVSETSC, KRESOL, KVSETSC3A, &
& KVSETSC3B, KVSETSC2, PGP, PGPUV, PGP3A, PGP3B, PGP2)
This is the adjoint version of the subroutine for performing an inverse spectral transform.
Like INV_TRANS, INV_TRANSAD supports two modes of passing arrays (which we call "call modes"
below):
PSPVOR, PSPDIV, PSPSCALAR, receive PGP.PSPVOR, PSPDIV, PSPSC3A, PSPSC3B, PSPSC2, receive PGPUV, PGP3A, PGP3B, PGP2Although call mode 1 is simpler, it can often entail having to create array copies in order to
subsequently operate on the different elements of PGP. Hence, with call mode 2, the output
arrays are already categorized according to whether they are wind related, 3D scalar, or 2D
scalar.
Note that PSPSC3A/PGP3A and PSPSC3B/PGP3B are essentially identical in type and size.
There are cases where it is useful to have the ability to pass two sets of scalar fields to be
transformed independently.
OPTIONAL, INTENT(IN) argumentsLOGICAL, OPTIONAL, INTENT(IN) :: LDSCDERS.FALSE.LOGICAL, OPTIONAL, INTENT(IN) :: LDVORGP.FALSE.LOGICAL, OPTIONAL, INTENT(IN) :: LDDIVGP.FALSE.LOGICAL, OPTIONAL, INTENT(IN) :: LDUVDER.FALSE.INTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KPROMAD%NGPTOTINTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KVSETUV(:)INTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KVSETSC(:)INTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KVSETSC3A(:)INTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KVSETSC3B(:)INTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KVSETSC2(:)INTEGER(KIND=JPIM), OPTIONAL, INTENT(IN) :: KRESOLSETUP_TRANS.REAL(KIND=JPRB), OPTIONAL, INTENT(IN) :: PGP(:,:,:)PSPVOR is present and LDVORGP)PSPDIV is present and LDDIVGP)PSPVOR and PSPDIV are present)PSPVOR and PSPDIV are present)PSPSCALAR is present)PSPSCALAR is present and LDSCDERS)PSPVOR and PSPDIV are present and LDUVDER)PSPVOR and PSPDIV are present and LDUVDER)PSPSCALAR is present and LDSCDERS)REAL(KIND=JPRB), OPTIONAL, INTENT(IN) :: PGPUV(:,:,:,:)PSPVOR is present and LDVORGP)PSPDIV is present and LDDIVGP)PSPVOR and PSPDIV are present)PSPVOR and PSPDIV are present)PSPVOR and PSPDIV are present and LDUVDER)PSPVOR and PSPDIV are present and LDUVDER)REAL(KIND=JPRB), OPTIONAL, INTENT(IN) :: PGP3A(:,:,:,:)PSPSC3A.LDSCDERS)LDSCDERS)REAL(KIND=JPRB), OPTIONAL, INTENT(IN) :: PGP3B(:,:,:,:)PSPSC3B.LDSCDERS)LDSCDERS)REAL(KIND=JPRB), OPTIONAL, INTENT(IN) :: PGP2(:,:,:)PSPSC2.LDSCDERS)LDSCDERS)OPTIONAL, EXTERNAL argumentsOPTIONAL, EXTERNAL :: FSPGL_PROCOPTIONAL, INTENT(OUT) argumentsREAL(KIND=JPRB), OPTIONAL, INTENT(OUT) :: PSPVOR(:,:)REAL(KIND=JPRB), OPTIONAL, INTENT(OUT) :: PSPDIV(:,:)REAL(KIND=JPRB), OPTIONAL, INTENT(OUT) :: PSPSCALAR(:,:)REAL(KIND=JPRB), OPTIONAL, INTENT(OUT) :: PSPSC3A(:,:,:)PGP3A.REAL(KIND=JPRB), OPTIONAL, INTENT(OUT) :: PSPSC3B(:,:,:)PGP3B.REAL(KIND=JPRB), OPTIONAL, INTENT(OUT) :: PSPSC2(:,:)PGP2.TRANS_RELEASESUBROUTINE TRANS_RELEASE(KRESOL)
This subroutine releases (i.e. deallocates and nullifies) all arrays related to the given
resolution tag KRESOL.
INTENT(IN) argumentsINTEGER(KIND=JPIM), INTENT(IN) :: KRESOLTRANS_ENDSUBROUTINE TRANS_END(CDMODE)
This subroutine terminates the transform package by releasing (i.e. deallocating and nullifying) all allocated arrays.
OPTIONAL, INTENT(IN) argumentsCHARACTER*5, OPTIONAL, INTENT(IN) :: CDMODEN_REGIONS and NPRCIDS.'FINAL'