123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368 |
- MODULE traldf
- !!======================================================================
- !! *** MODULE traldf ***
- !! Ocean Active tracers : lateral diffusive trends
- !!=====================================================================
- !! History : 9.0 ! 2005-11 (G. Madec) Original code
- !! NEMO 3.0 ! 2008-01 (C. Ethe, G. Madec) merge TRC-TRA
- !!----------------------------------------------------------------------
- !!----------------------------------------------------------------------
- !! tra_ldf : update the tracer trend with the lateral diffusion
- !! tra_ldf_init : initialization, namelist read, and parameters control
- !! ldf_ano : compute lateral diffusion for constant T-S profiles
- !!----------------------------------------------------------------------
- USE oce ! ocean dynamics and tracers
- USE dom_oce ! ocean space and time domain
- USE phycst ! physical constants
- USE ldftra_oce ! ocean tracer lateral physics
- USE ldfslp ! ???
- USE traldf_bilapg ! lateral mixing (tra_ldf_bilapg routine)
- USE traldf_bilap ! lateral mixing (tra_ldf_bilap routine)
- USE traldf_iso ! lateral mixing (tra_ldf_iso routine)
- USE traldf_iso_grif ! lateral mixing (tra_ldf_iso_grif routine)
- USE traldf_lap ! lateral mixing (tra_ldf_lap routine)
- USE trd_oce ! trends: ocean variables
- USE trdtra ! trends manager: tracers
- !
- USE prtctl ! Print control
- USE in_out_manager ! I/O manager
- USE lib_mpp ! distribued memory computing library
- USE lbclnk ! ocean lateral boundary conditions (or mpp link)
- USE wrk_nemo ! Memory allocation
- USE timing ! Timing
- IMPLICIT NONE
- PRIVATE
- PUBLIC tra_ldf ! called by step.F90
- PUBLIC tra_ldf_init ! called by opa.F90
- !
- INTEGER :: nldf = 0 ! type of lateral diffusion used defined from ln_traldf_... namlist logicals)
- REAL, SAVE, ALLOCATABLE, DIMENSION(:,:,:) :: t0_ldf, s0_ldf !: lateral diffusion trends of T & S for a cst profile
- ! ! (key_traldf_ano only)
- !! * Substitutions
- # include "domzgr_substitute.h90"
- # include "vectopt_loop_substitute.h90"
- !!----------------------------------------------------------------------
- !! NEMO/OPA 3.3 , NEMO Consortium (2010)
- !! $Id: traldf.F90 4990 2014-12-15 16:42:49Z timgraham $
- !! Software governed by the CeCILL licence (NEMOGCM/NEMO_CeCILL.txt)
- !!----------------------------------------------------------------------
- CONTAINS
- SUBROUTINE tra_ldf( kt )
- !!----------------------------------------------------------------------
- !! *** ROUTINE tra_ldf ***
- !!
- !! ** Purpose : compute the lateral ocean tracer physics.
- !!----------------------------------------------------------------------
- INTEGER, INTENT( in ) :: kt ! ocean time-step index
- !!
- REAL(wp), POINTER, DIMENSION(:,:,:) :: ztrdt, ztrds
- !!----------------------------------------------------------------------
- !
- IF( nn_timing == 1 ) CALL timing_start('tra_ldf')
- !
- rldf = 1 ! For active tracers the
- r_fact_lap(:,:,:) = 1.0
- IF( l_trdtra ) THEN !* Save ta and sa trends
- CALL wrk_alloc( jpi, jpj, jpk, ztrdt, ztrds )
- ztrdt(:,:,:) = tsa(:,:,:,jp_tem)
- ztrds(:,:,:) = tsa(:,:,:,jp_sal)
- ENDIF
- SELECT CASE ( nldf ) ! compute lateral mixing trend and add it to the general trend
- CASE ( 0 ) ; CALL tra_ldf_lap ( kt, nit000, 'TRA', gtsu, gtsv, gtui, gtvi, &
- & tsb, tsa, jpts ) ! iso-level laplacian
- CASE ( 1 ) ! rotated laplacian
- IF( ln_traldf_grif ) THEN
- CALL tra_ldf_iso_grif( kt, nit000,'TRA', gtsu, gtsv, tsb, tsa, jpts, ahtb0 ) ! Griffies operator
- ELSE
- CALL tra_ldf_iso ( kt, nit000, 'TRA', gtsu, gtsv, gtui, gtvi, &
- & tsb, tsa, jpts, ahtb0 ) ! Madec operator
- ENDIF
- CASE ( 2 ) ; CALL tra_ldf_bilap ( kt, nit000, 'TRA', gtsu, gtsv, gtui, gtvi, &
- & tsb, tsa, jpts ) ! iso-level bilaplacian
- CASE ( 3 ) ; CALL tra_ldf_bilapg ( kt, nit000, 'TRA', tsb, tsa, jpts ) ! s-coord. geopot. bilap.
- !
- CASE ( -1 ) ! esopa: test all possibility with control print
- CALL tra_ldf_lap ( kt, nit000, 'TRA', gtsu, gtsv, gtui, gtvi, &
- & tsb, tsa, jpts )
- CALL prt_ctl( tab3d_1=tsa(:,:,:,jp_tem), clinfo1=' ldf0 - Ta: ', mask1=tmask, &
- & tab3d_2=tsa(:,:,:,jp_sal), clinfo2= ' Sa: ', mask2=tmask, clinfo3='tra' )
- IF( ln_traldf_grif ) THEN
- CALL tra_ldf_iso_grif( kt, nit000, 'TRA', gtsu, gtsv, tsb, tsa, jpts, ahtb0 )
- ELSE
- CALL tra_ldf_iso ( kt, nit000, 'TRA', gtsu, gtsv, gtui, gtvi, &
- & tsb, tsa, jpts, ahtb0 )
- ENDIF
- CALL prt_ctl( tab3d_1=tsa(:,:,:,jp_tem), clinfo1=' ldf1 - Ta: ', mask1=tmask, &
- & tab3d_2=tsa(:,:,:,jp_sal), clinfo2= ' Sa: ', mask2=tmask, clinfo3='tra' )
- CALL tra_ldf_bilap ( kt, nit000, 'TRA', gtsu, gtsv, gtui, gtvi, &
- & tsb, tsa, jpts )
- CALL prt_ctl( tab3d_1=tsa(:,:,:,jp_tem), clinfo1=' ldf2 - Ta: ', mask1=tmask, &
- & tab3d_2=tsa(:,:,:,jp_sal), clinfo2= ' Sa: ', mask2=tmask, clinfo3='tra' )
- CALL tra_ldf_bilapg( kt, nit000, 'TRA', tsb, tsa, jpts )
- CALL prt_ctl( tab3d_1=tsa(:,:,:,jp_tem), clinfo1=' ldf3 - Ta: ', mask1=tmask, &
- & tab3d_2=tsa(:,:,:,jp_sal), clinfo2= ' Sa: ', mask2=tmask, clinfo3='tra' )
- END SELECT
- #if defined key_traldf_ano
- tsa(:,:,:,jp_tem) = tsa(:,:,:,jp_tem) - t0_ldf(:,:,:) ! anomaly: substract the reference diffusivity
- tsa(:,:,:,jp_sal) = tsa(:,:,:,jp_sal) - s0_ldf(:,:,:)
- #endif
- IF( l_trdtra ) THEN ! save the horizontal diffusive trends for further diagnostics
- ztrdt(:,:,:) = tsa(:,:,:,jp_tem) - ztrdt(:,:,:)
- ztrds(:,:,:) = tsa(:,:,:,jp_sal) - ztrds(:,:,:)
- CALL trd_tra( kt, 'TRA', jp_tem, jptra_ldf, ztrdt )
- CALL trd_tra( kt, 'TRA', jp_sal, jptra_ldf, ztrds )
- CALL wrk_dealloc( jpi, jpj, jpk, ztrdt, ztrds )
- ENDIF
- ! ! print mean trends (used for debugging)
- IF(ln_ctl) CALL prt_ctl( tab3d_1=tsa(:,:,:,jp_tem), clinfo1=' ldf - Ta: ', mask1=tmask, &
- & tab3d_2=tsa(:,:,:,jp_sal), clinfo2= ' Sa: ', mask2=tmask, clinfo3='tra' )
- !
- IF( nn_timing == 1 ) CALL timing_stop('tra_ldf')
- !
- END SUBROUTINE tra_ldf
- SUBROUTINE tra_ldf_init
- !!----------------------------------------------------------------------
- !! *** ROUTINE tra_ldf_init ***
- !!
- !! ** Purpose : Choice of the operator for the lateral tracer diffusion
- !!
- !! ** Method : set nldf from the namtra_ldf logicals
- !! nldf == -1 ESOPA test: ALL operators are used
- !! nldf == 0 laplacian operator
- !! nldf == 1 Rotated laplacian operator
- !! nldf == 2 bilaplacian operator
- !! nldf == 3 Rotated bilaplacian
- !!----------------------------------------------------------------------
- INTEGER :: ioptio, ierr ! temporary integers
- !!----------------------------------------------------------------------
- ! Define the lateral mixing oparator for tracers
- ! ===============================================
-
- IF(lwp) THEN ! Namelist print
- WRITE(numout,*)
- WRITE(numout,*) 'tra_ldf_init : lateral tracer diffusive operator'
- WRITE(numout,*) '~~~~~~~~~~~'
- WRITE(numout,*) ' Namelist namtra_ldf already read in ldftra module'
- WRITE(numout,*) ' see ldf_tra_init report for lateral mixing parameters'
- WRITE(numout,*)
- ENDIF
- ! ! control the input
- ioptio = 0
- IF( ln_traldf_lap ) ioptio = ioptio + 1
- IF( ln_traldf_bilap ) ioptio = ioptio + 1
- IF( ioptio > 1 ) CALL ctl_stop( ' use ONE or NONE of the 2 lap/bilap operator type on tracer' )
- IF( ioptio == 0 ) nldf = -2 ! No lateral diffusion
- ioptio = 0
- IF( ln_traldf_level ) ioptio = ioptio + 1
- IF( ln_traldf_hor ) ioptio = ioptio + 1
- IF( ln_traldf_iso ) ioptio = ioptio + 1
- IF( ioptio > 1 ) CALL ctl_stop( ' use only ONE direction (level/hor/iso)' )
- ! defined the type of lateral diffusion from ln_traldf_... logicals
- ! CAUTION : nldf = 1 is used in trazdf_imp, change it carefully
- ierr = 0
- IF( ln_traldf_lap ) THEN ! laplacian operator
- IF ( ln_zco ) THEN ! z-coordinate
- IF ( ln_traldf_level ) nldf = 0 ! iso-level (no rotation)
- IF ( ln_traldf_hor ) nldf = 0 ! horizontal (no rotation)
- IF ( ln_traldf_iso ) nldf = 1 ! isoneutral ( rotation)
- ENDIF
- IF ( ln_zps ) THEN ! zps-coordinate
- IF ( ln_traldf_level ) ierr = 1 ! iso-level not allowed
- IF ( ln_traldf_hor ) nldf = 0 ! horizontal (no rotation)
- IF ( ln_traldf_iso ) nldf = 1 ! isoneutral ( rotation)
- ENDIF
- IF ( ln_sco ) THEN ! s-coordinate
- IF ( ln_traldf_level ) nldf = 0 ! iso-level (no rotation)
- IF ( ln_traldf_hor ) nldf = 1 ! horizontal ( rotation)
- IF ( ln_traldf_iso ) nldf = 1 ! isoneutral ( rotation)
- ENDIF
- ENDIF
- IF( ln_traldf_bilap ) THEN ! bilaplacian operator
- IF ( ln_zco ) THEN ! z-coordinate
- IF ( ln_traldf_level ) nldf = 2 ! iso-level (no rotation)
- IF ( ln_traldf_hor ) nldf = 2 ! horizontal (no rotation)
- IF ( ln_traldf_iso ) ierr = 2 ! isoneutral ( rotation)
- ENDIF
- IF ( ln_zps ) THEN ! zps-coordinate
- IF ( ln_traldf_level ) ierr = 1 ! iso-level not allowed
- IF ( ln_traldf_hor ) nldf = 2 ! horizontal (no rotation)
- IF ( ln_traldf_iso ) ierr = 2 ! isoneutral ( rotation)
- ENDIF
- IF ( ln_sco ) THEN ! s-coordinate
- IF ( ln_traldf_level ) nldf = 2 ! iso-level (no rotation)
- IF ( ln_traldf_hor ) nldf = 3 ! horizontal ( rotation)
- IF ( ln_traldf_iso ) ierr = 2 ! isoneutral ( rotation)
- ENDIF
- ENDIF
- IF( nldf == 3 ) CALL ctl_warn( 'geopotential bilaplacian tracer diffusion in s-coords not thoroughly tested' )
- IF( ierr == 1 ) CALL ctl_stop( ' iso-level in z-coordinate - partial step, not allowed' )
- IF( ierr == 2 ) CALL ctl_stop( ' isoneutral bilaplacian operator does not exist' )
- IF( ln_traldf_hor .AND. ln_traldf_grif ) &
- & CALL ctl_stop( ' horizontal operator and Griffies triads not available; sitch to isoneutral operator' )
- IF( ln_traldf_grif .AND. ln_isfcav ) &
- CALL ctl_stop( ' ice shelf and traldf_grif not tested')
- IF( lk_traldf_eiv .AND. .NOT.ln_traldf_iso ) &
- CALL ctl_stop( ' eddy induced velocity on tracers', &
- & ' the eddy induced velocity on tracers requires isopycnal laplacian diffusion' )
- IF( nldf == 1 .OR. nldf == 3 ) THEN ! rotation
- IF( .NOT.lk_ldfslp ) CALL ctl_stop( ' the rotation of the diffusive tensor require key_ldfslp' )
- l_traldf_rot = .TRUE. ! needed for trazdf_imp
- ENDIF
- IF( lk_esopa ) THEN
- IF(lwp) WRITE(numout,*) ' esopa control: use all lateral physics options'
- nldf = -1
- ENDIF
- IF(lwp) THEN
- WRITE(numout,*)
- IF( nldf == -2 ) WRITE(numout,*) ' NO lateral diffusion'
- IF( nldf == -1 ) WRITE(numout,*) ' ESOPA test All scheme used'
- IF( nldf == 0 ) WRITE(numout,*) ' laplacian operator'
- IF( nldf == 1 ) WRITE(numout,*) ' Rotated laplacian operator'
- IF( nldf == 2 ) WRITE(numout,*) ' bilaplacian operator'
- IF( nldf == 3 ) WRITE(numout,*) ' Rotated bilaplacian'
- ENDIF
- ! Reference T & S diffusivity (if necessary)
- ! ===========================
- CALL ldf_ano
- !
- END SUBROUTINE tra_ldf_init
- #if defined key_traldf_ano
- !!----------------------------------------------------------------------
- !! 'key_traldf_ano' T & S lateral diffusion on anomalies
- !!----------------------------------------------------------------------
- SUBROUTINE ldf_ano
- !!----------------------------------------------------------------------
- !! *** ROUTINE ldf_ano ***
- !!
- !! ** Purpose : initializations of
- !!----------------------------------------------------------------------
- !
- USE zdf_oce ! vertical mixing
- USE trazdf ! vertical mixing: double diffusion
- USE zdfddm ! vertical mixing: double diffusion
- !
- INTEGER :: jk ! Dummy loop indice
- INTEGER :: ierr ! local integer
- LOGICAL :: llsave ! local logical
- REAL(wp) :: zt0, zs0, z12 ! local scalar
- REAL(wp), POINTER, DIMENSION(:,:,:) :: zt_ref, zs_ref, ztb, zsb, zavt
- !!----------------------------------------------------------------------
- !
- IF( nn_timing == 1 ) CALL timing_start('ldf_ano')
- !
- CALL wrk_alloc( jpi, jpj, jpk, zt_ref, zs_ref, ztb, zsb, zavt )
- !
- IF(lwp) THEN
- WRITE(numout,*)
- WRITE(numout,*) 'tra:ldf_ano : lateral diffusion acting on anomalies'
- WRITE(numout,*) '~~~~~~~~~~~'
- ENDIF
- ! ! allocate trabbl arrays
- ALLOCATE( t0_ldf(jpi,jpj,jpk) , s0_ldf(jpi,jpj,jpk) , STAT=ierr )
- IF( lk_mpp ) CALL mpp_sum( ierr )
- IF( ierr /= 0 ) CALL ctl_stop( 'STOP', 'ldf_ano: unable to allocate arrays' )
- ! defined the T & S reference profiles
- ! ------------------------------------
- zt0 =10.e0 ! homogeneous ocean
- zs0 =35.e0
- zt_ref(:,:,:) = 10.0 * tmask(:,:,:)
- zs_ref(:,:,:) = 35.0 * tmask(:,:,:)
- IF(lwp) WRITE(numout,*) ' homogeneous ocean T = ', zt0, ' S = ',zs0
- ! Initialisation of gtui/gtvi in case of no cavity
- IF ( .NOT. ln_isfcav ) THEN
- gtui(:,:,:) = 0.0_wp
- gtvi(:,:,:) = 0.0_wp
- END IF
- ! ! T & S profile (to be coded +namelist parameter
- ! prepare the ldf computation
- ! ---------------------------
- llsave = l_trdtra
- l_trdtra = .false. ! desactivate trend computation
- t0_ldf(:,:,:) = 0.e0
- s0_ldf(:,:,:) = 0.e0
- ztb (:,:,:) = tsb (:,:,:,jp_tem)
- zsb (:,:,:) = tsb (:,:,:,jp_sal)
- ua (:,:,:) = tsa (:,:,:,jp_tem)
- va (:,:,:) = tsa (:,:,:,jp_sal)
- zavt (:,:,:) = avt(:,:,:)
- IF( lk_zdfddm ) THEN CALL ctl_stop( ' key_traldf_ano with key_zdfddm not implemented' )
- ! set tb, sb to reference values and avr to zero
- tsb (:,:,:,jp_tem) = zt_ref(:,:,:)
- tsb (:,:,:,jp_sal) = zs_ref(:,:,:)
- tsa (:,:,:,jp_tem) = 0.e0
- tsa (:,:,:,jp_sal) = 0.e0
- avt(:,:,:) = 0.e0
- ! Compute the ldf trends
- ! ----------------------
- CALL tra_ldf( nit000 + 1 ) ! horizontal components (+1: no more init)
- CALL tra_zdf( nit000 ) ! vertical component (if necessary nit000 to performed the init)
- ! finalise the computation and recover all arrays
- ! -----------------------------------------------
- l_trdtra = llsave
- z12 = 2.e0
- IF( neuler == 1) z12 = 1.e0
- IF( ln_zdfexp ) THEN ! ta,sa are the trends
- t0_ldf(:,:,:) = tsa(:,:,:,jp_tem)
- s0_ldf(:,:,:) = tsa(:,:,:,jp_sal)
- ELSE
- DO jk = 1, jpkm1
- t0_ldf(:,:,jk) = ( tsa(:,:,jk,jp_tem) - tsb(:,:,jk,jp_tem) ) / ( z12 *rdttra(jk) )
- s0_ldf(:,:,jk) = ( tsa(:,:,jk,jp_sal) - tsb(:,:,jk,jp_sal) ) / ( z12 *rdttra(jk) )
- END DO
- ENDIF
- tsb(:,:,:,jp_tem) = ztb (:,:,:)
- tsb(:,:,:,jp_sal) = zsb (:,:,:)
- tsa(:,:,:,jp_tem) = ua (:,:,:)
- tsa(:,:,:,jp_sal) = va (:,:,:)
- avt(:,:,:) = zavt(:,:,:)
- !
- CALL wrk_dealloc( jpi, jpj, jpk, zt_ref, zs_ref, ztb, zsb, zavt )
- !
- IF( nn_timing == 1 ) CALL timing_stop('ldf_ano')
- !
- END SUBROUTINE ldf_ano
- #else
- !!----------------------------------------------------------------------
- !! default option : Dummy code NO T & S background profiles
- !!----------------------------------------------------------------------
- SUBROUTINE ldf_ano
- IF(lwp) THEN
- WRITE(numout,*)
- WRITE(numout,*) 'tra:ldf_ano : lateral diffusion acting on the full fields'
- WRITE(numout,*) '~~~~~~~~~~~'
- ENDIF
- END SUBROUTINE ldf_ano
- #endif
- !!======================================================================
- END MODULE traldf
|