diff --git a/sette/sette.sh b/sette/sette.sh index 69aee9704262b55e798713cf3b3bfa0ebcccab96..4b816f34dea2998f181975f2c3c70e614a6a3be7 100755 --- a/sette/sette.sh +++ b/sette/sette.sh @@ -221,7 +221,7 @@ if [ ${USING_LOOP_FUSION} == "no" ] ; then export DEL_KEYS="${DEL_KEYS}key_loop if [ ${USING_QCO} == "yes" ] ; then export ADD_KEYS="${ADD_KEYS}key_qco " ; fi if [ ${USING_QCO} == "no" ] ; then export DEL_KEYS="${DEL_KEYS}key_qco key_linssh " ; fi # -if [ ${USING_RK3} == "yes" ] ; then export ADD_KEYS="${ADD_KEYS}key_qco key_RK3 " ; fi +if [ ${USING_RK3} == "yes" ] ; then export ADD_KEYS="${ADD_KEYS}key_RK3 " ; fi if [ ${USING_RK3} == "no" ] ; then export DEL_KEYS="${DEL_KEYS}key_RK3 " ; fi # diff --git a/src/NST/agrif_all_update.F90 b/src/NST/agrif_all_update.F90 index 8fc617eba676216116c165d70709a00c11f1b8e4..753bee7cd3ae087392792fe42a48addd6127ab73 100644 --- a/src/NST/agrif_all_update.F90 +++ b/src/NST/agrif_all_update.F90 @@ -99,9 +99,13 @@ CONTAINS & uu_b(:,:, Kbb_a), 'U',-1._wp, & & vv_b(:,:, Kmm_a), 'V',-1._wp, & & vv_b(:,:, Kbb_a), 'V',-1._wp, & +# if ! defined key_RK3 & ub2_b(:,:), 'U',-1._wp, & - & ub2_i_b(:,:), 'U',-1._wp, & + & un_bf(:,:), 'U',-1._wp, & & vb2_b(:,:), 'V',-1._wp, & + & vn_bf(:,:), 'V',-1._wp, & +# endif + & ub2_i_b(:,:), 'U',-1._wp, & & vb2_i_b(:,:), 'V',-1._wp ) #if defined key_qco diff --git a/src/NST/agrif_oce_interp.F90 b/src/NST/agrif_oce_interp.F90 index 6cd1e9ff2a3c5787c1f617b75c8b20bb3adb5fd7..7d25ea55436f84ebe8c2b190d28aca05d0f0d259 100644 --- a/src/NST/agrif_oce_interp.F90 +++ b/src/NST/agrif_oce_interp.F90 @@ -28,7 +28,6 @@ MODULE agrif_oce_interp USE zdf_oce USE agrif_oce USE phycst -!!! USE dynspg_ts, ONLY: un_adv, vn_adv ! USE in_out_manager USE agrif_oce_sponge @@ -167,18 +166,36 @@ CONTAINS END SUBROUTINE Agrif_istate_ssh - SUBROUTINE Agrif_tra + SUBROUTINE Agrif_tra( kt, kstg ) !!---------------------------------------------------------------------- !! *** ROUTINE Agrif_tra *** !!---------------------------------------------------------------------- + INTEGER, INTENT(in) :: kt + INTEGER, OPTIONAL, INTENT(in) :: kstg + REAL(wp) :: ztindex ! IF( Agrif_Root() ) RETURN ! + ! Set time index depending on stage in case of RK3 time stepping: + IF ( PRESENT( kstg ) ) THEN + ztindex = REAL(Agrif_Nbstepint(), wp) + IF ( kstg == 1 ) THEN + ztindex = ztindex + 1._wp / 3._wp + ELSEIF ( kstg == 2 ) THEN + ztindex = ztindex + 1._wp / 2._wp + ELSEIF ( kstg == 3 ) THEN + ztindex = ztindex + 1._wp + ENDIF + ztindex = ztindex / Agrif_Rhot() + ELSE + ztindex = REAL(Agrif_Nbstepint()+1, wp) / Agrif_Rhot() + ENDIF + ! Agrif_SpecialValue = 0._wp Agrif_UseSpecialValue = l_spc_tra l_vremap = ln_vert_remap ! - CALL Agrif_Bc_variable( ts_interp_id, procname=interptsn ) + CALL Agrif_Bc_variable( ts_interp_id, calledweight=ztindex, procname=interptsn ) ! Agrif_UseSpecialValue = .FALSE. l_vremap = .FALSE. @@ -186,35 +203,52 @@ CONTAINS END SUBROUTINE Agrif_tra - SUBROUTINE Agrif_dyn( kt ) + SUBROUTINE Agrif_dyn( kt, kstg ) !!---------------------------------------------------------------------- !! *** ROUTINE Agrif_DYN *** !!---------------------------------------------------------------------- INTEGER, INTENT(in) :: kt + INTEGER, OPTIONAL, INTENT(in) :: kstg ! INTEGER :: ji, jj, jk ! dummy loop indices INTEGER :: ibdy1, jbdy1, ibdy2, jbdy2 REAL(wp) :: zflag REAL(wp), DIMENSION(jpi,jpj) :: zub, zvb REAL(wp), DIMENSION(jpi,jpj) :: zhub, zhvb + REAL(wp) :: ztindex !!---------------------------------------------------------------------- ! IF( Agrif_Root() ) RETURN ! + ! Set time index depending on stage in case of RK3 time stepping: + IF ( PRESENT( kstg ) ) THEN + ztindex = REAL(Agrif_Nbstepint(), wp) + IF ( kstg == 1 ) THEN + ztindex = ztindex + 1._wp / 3._wp + ELSEIF ( kstg == 2 ) THEN + ztindex = ztindex + 1._wp / 2._wp + ELSEIF ( kstg == 3 ) THEN + ztindex = ztindex + 1._wp + ENDIF + ztindex = ztindex / Agrif_Rhot() + ELSE + ztindex = REAL(Agrif_Nbstepint()+1, wp) / Agrif_Rhot() + ENDIF + ! Agrif_SpecialValue = 0.0_wp Agrif_UseSpecialValue = ln_spc_dyn l_vremap = ln_vert_remap ! use_sign_north = .TRUE. sign_north = -1.0_wp - CALL Agrif_Bc_variable( un_interp_id, procname=interpun ) - CALL Agrif_Bc_variable( vn_interp_id, procname=interpvn ) + CALL Agrif_Bc_variable( un_interp_id, calledweight=ztindex, procname=interpun ) + CALL Agrif_Bc_variable( vn_interp_id, calledweight=ztindex, procname=interpvn ) IF( .NOT.ln_dynspg_ts ) THEN ! Get transports ubdy(:,:) = 0._wp ; vbdy(:,:) = 0._wp utint_stage(:,:) = 0 ; vtint_stage(:,:) = 0 - CALL Agrif_Bc_variable( unb_interp_id, procname=interpunb ) - CALL Agrif_Bc_variable( vnb_interp_id, procname=interpvnb ) + CALL Agrif_Bc_variable( unb_interp_id, calledweight=ztindex, procname=interpunb ) + CALL Agrif_Bc_variable( vnb_interp_id, calledweight=ztindex, procname=interpvnb ) ENDIF use_sign_north = .FALSE. @@ -675,6 +709,13 @@ CONTAINS ! IF( Agrif_Root() ) RETURN ! +#if defined key_RK3 + Agrif_SpecialValue = 0._wp + Agrif_UseSpecialValue = .TRUE. + CALL Agrif_Bc_variable(sshn_id, procname=interpsshn ) + Agrif_UseSpecialValue = .FALSE. +#endif + ! ll_int_cons = ln_bt_fw ! Assume conservative temporal integration in the forward case only ! ! Enforce volume conservation if no time refinement: @@ -1399,10 +1440,11 @@ CONTAINS !!---------------------------------------------------------------------- IF( before ) THEN ! IF ( ln_bt_fw ) THEN +# if defined key_RK3 + ptab(i1:i2,j1:j2) = e2u(i1:i2,j1:j2) * un_adv(i1:i2,j1:j2) +# else ptab(i1:i2,j1:j2) = e2u(i1:i2,j1:j2) * ub2_b(i1:i2,j1:j2) -! ELSE -! ptab(i1:i2,j1:j2) = e2u(i1:i2,j1:j2) * un_adv(i1:i2,j1:j2) -! ENDIF +# endif ELSE zrhot = Agrif_rhot() ! Time indexes bounds for integration @@ -1431,12 +1473,13 @@ CONTAINS REAL(wp) :: zrhoy !!---------------------------------------------------------------------- IF( before ) THEN -! IF ( ln_bt_fw ) THEN +# if defined key_RK3 + ptab(i1:i2,j1:j2) = e2u(i1:i2,j1:j2) * un_adv(i1:i2,j1:j2) & + * umask(i1:i2,j1:j2,1) +# else ptab(i1:i2,j1:j2) = e2u(i1:i2,j1:j2) * ub2_b(i1:i2,j1:j2) & * umask(i1:i2,j1:j2,1) -! ELSE -! ptab(i1:i2,j1:j2) = e2u(i1:i2,j1:j2) * un_adv(i1:i2,j1:j2) -! ENDIF +# endif ELSE zrhoy = Agrif_Rhoy() ! @@ -1466,12 +1509,21 @@ CONTAINS jmin = MAX(j1, 2) ; jmax = MIN(j2, jpj-1) DO ji=imin,imax DO jj=jmin,jmax +# if defined key_RK3 + ptab(ji,jj) = 0.25_wp *(vmask(ji,jj ,1) & + & * ( vn_adv(ji+1,jj )*e1v(ji+1,jj ) & + & -vn_adv(ji-1,jj )*e1v(ji-1,jj ) ) & + & -vmask(ji,jj-1,1) & + & * ( vn_adv(ji+1,jj-1)*e1v(ji+1,jj-1) & + & -vn_adv(ji-1,jj-1)*e1v(ji-1,jj-1) ) ) +# else ptab(ji,jj) = 0.25_wp *(vmask(ji,jj ,1) & & * ( vb2_b(ji+1,jj )*e1v(ji+1,jj ) & & -vb2_b(ji-1,jj )*e1v(ji-1,jj ) ) & & -vmask(ji,jj-1,1) & & * ( vb2_b(ji+1,jj-1)*e1v(ji+1,jj-1) & & -vb2_b(ji-1,jj-1)*e1v(ji-1,jj-1) ) ) +# endif END DO END DO ELSE @@ -1507,11 +1559,11 @@ CONTAINS !!---------------------------------------------------------------------- ! IF( before ) THEN -! IF ( ln_bt_fw ) THEN +# if defined key_RK3 + ptab(i1:i2,j1:j2) = e1v(i1:i2,j1:j2) * vn_adv(i1:i2,j1:j2) +# else ptab(i1:i2,j1:j2) = e1v(i1:i2,j1:j2) * vb2_b(i1:i2,j1:j2) -! ELSE -! ptab(i1:i2,j1:j2) = e1v(i1:i2,j1:j2) * vn_adv(i1:i2,j1:j2) -! ENDIF +# endif ELSE zrhot = Agrif_rhot() ! Time indexes bounds for integration @@ -1541,12 +1593,13 @@ CONTAINS REAL(wp) :: zrhox !!---------------------------------------------------------------------- IF( before ) THEN -! IF ( ln_bt_fw ) THEN +# if defined key_RK3 + ptab(i1:i2,j1:j2) = e1v(i1:i2,j1:j2) * vn_adv(i1:i2,j1:j2) & + * vmask(i1:i2,j1:j2,1) +# else ptab(i1:i2,j1:j2) = e1v(i1:i2,j1:j2) * vb2_b(i1:i2,j1:j2) & * vmask(i1:i2,j1:j2,1) -! ELSE -! ptab(i1:i2,j1:j2) = e1v(i1:i2,j1:j2) * vn_adv(i1:i2,j1:j2) -! ENDIF +# endif ELSE zrhox = Agrif_Rhox() ! @@ -1576,12 +1629,21 @@ CONTAINS jmin = MAX(j1, 2) ; jmax = MIN(j2, jpj-1) DO ji=imin,imax DO jj=jmin,jmax +# if defined key_RK3 + ptab(ji,jj) = 0.25_wp *(umask(ji ,jj,1) & + & * ( un_adv(ji ,jj+1)*e2u(ji ,jj+1) & + & -un_adv(ji ,jj-1)*e2u(ji ,jj-1) ) & + & -umask(ji-1,jj,1) & + & * ( un_adv(ji-1,jj+1)*e2u(ji-1,jj+1) & + & -un_adv(ji-1,jj-1)*e2u(ji-1,jj-1) ) ) +# else ptab(ji,jj) = 0.25_wp *(umask(ji ,jj,1) & & * ( ub2_b(ji ,jj+1)*e2u(ji ,jj+1) & & -ub2_b(ji ,jj-1)*e2u(ji ,jj-1) ) & & -umask(ji-1,jj,1) & & * ( ub2_b(ji-1,jj+1)*e2u(ji-1,jj+1) & & -ub2_b(ji-1,jj-1)*e2u(ji-1,jj-1) ) ) +# endif END DO END DO ELSE diff --git a/src/NST/agrif_oce_sponge.F90 b/src/NST/agrif_oce_sponge.F90 index 5585854cee2220f51c3bd89f5e74ac30967a3db0..d077f7b8846bc7bb5abb81fdf10b3790781c5814 100644 --- a/src/NST/agrif_oce_sponge.F90 +++ b/src/NST/agrif_oce_sponge.F90 @@ -36,7 +36,7 @@ MODULE agrif_oce_sponge # include "do_loop_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/NST 4.0 , NEMO Consortium (2018) - !! $Id: agrif_oce_sponge.F90 15437 2021-10-22 12:21:20Z jchanut $ + !! $Id: agrif_oce_sponge.F90 14800 2021-05-06 15:42:46Z jchanut $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS @@ -50,8 +50,12 @@ CONTAINS !!---------------------------------------------------------------------- ! #if defined SPONGE +#if defined key_RK3 + zcoef = REAL(Agrif_Nbstepint(), wp)/REAL(Agrif_rhot()) +#else !! Assume persistence: zcoef = REAL(Agrif_rhot()-1,wp)/REAL(Agrif_rhot()) +#endif Agrif_SpecialValue = 0._wp Agrif_UseSpecialValue = l_spc_tra @@ -78,7 +82,12 @@ CONTAINS !!---------------------------------------------------------------------- ! #if defined SPONGE + +#if defined key_RK3 + zcoef = REAL(Agrif_Nbstepint(), wp)/REAL(Agrif_rhot()) +#else zcoef = REAL(Agrif_rhot()-1,wp)/REAL(Agrif_rhot()) +#endif Agrif_SpecialValue = 0._wp Agrif_UseSpecialValue = ln_spc_dyn diff --git a/src/NST/agrif_oce_update.F90 b/src/NST/agrif_oce_update.F90 index 0f538408182df07010a6dfc9620eac779c7fd4d9..72fb2eca14f143e5fdcbe8b22978ac1ece46c82a 100644 --- a/src/NST/agrif_oce_update.F90 +++ b/src/NST/agrif_oce_update.F90 @@ -41,7 +41,7 @@ MODULE agrif_oce_update # include "domzgr_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/NST 4.0 , NEMO Consortium (2018) - !! $Id: agrif_oce_update.F90 15317 2021-10-01 16:09:36Z jchanut $ + !! $Id: agrif_oce_update.F90 14800 2021-05-06 15:42:46Z jchanut $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS @@ -98,12 +98,14 @@ CONTAINS ! IF ( ln_dynspg_ts .AND. ln_bt_fw ) THEN ! Update time integrated transports +# if ! defined key_RK3 # if ! defined DECAL_FEEDBACK_2D CALL Agrif_Update_Variable(ub2b_update_id,locupdate1=(/ nn_shift_bar,-2/),locupdate2=(/ nn_shift_bar,-2/),procname = updateub2b) CALL Agrif_Update_Variable(vb2b_update_id,locupdate1=(/ nn_shift_bar,-2/),locupdate2=(/ nn_shift_bar,-2/),procname = updatevb2b) # else CALL Agrif_Update_Variable(ub2b_update_id,locupdate1=(/ nn_shift_bar,-2/),locupdate2=(/1+nn_shift_bar,-2/),procname = updateub2b) CALL Agrif_Update_Variable(vb2b_update_id,locupdate1=(/1+nn_shift_bar,-2/),locupdate2=(/ nn_shift_bar,-2/),procname = updatevb2b) +# endif # endif IF (lk_agrif_fstep) THEN CALL Agrif_Update_Variable(ub2b_update_id,locupdate1=(/ nn_shift_bar+nn_dist_par_bc-1,-2/),locupdate2=(/ nn_shift_bar+nn_dist_par_bc ,-2/),procname = updateumsk) @@ -544,6 +546,7 @@ CONTAINS DO jk=1,jpkm1 DO jj=j1,j2 DO ji=i1,i2 +#if ! defined key_RK3 IF (.NOT.(lk_agrif_fstep.AND.(l_1st_euler))) THEN ! Add asselin part ze3b = e3u(ji,jj,jk,Kbb_a) & ! Recover e3ub before update & - rn_atfp * ( e3u(ji,jj,jk,Kmm_a) - e3u(ji,jj,jk,Krhs_a) ) @@ -553,6 +556,7 @@ CONTAINS uu(ji,jj,jk,Kbb_a) = ( zub + rn_atfp * ( zunu - zuno) ) & & * umask(ji,jj,jk) / e3u(ji,jj,jk,Kbb_a) ENDIF +#endif ! uu(ji,jj,jk,Kmm_a) = tabres_child(ji,jj,jk) * umask(ji,jj,jk) END DO @@ -693,6 +697,7 @@ CONTAINS DO jk=1,jpkm1 DO jj=j1,j2 DO ji=i1,i2 +#if ! defined key_RK3 IF (.NOT.(lk_agrif_fstep.AND.(l_1st_euler))) THEN ! Add asselin part ze3b = e3v(ji,jj,jk,Kbb_a) & ! Recover e3vb before update & - rn_atfp * ( e3v(ji,jj,jk,Kmm_a) - e3v(ji,jj,jk,Krhs_a) ) @@ -702,6 +707,7 @@ CONTAINS vv(ji,jj,jk,Kbb_a) = ( zvb + rn_atfp * ( zvnu - zvno) ) & & * vmask(ji,jj,jk) / e3v(ji,jj,jk,Kbb_a) ENDIF +#endif ! vv(ji,jj,jk,Kmm_a) = tabres_child(ji,jj,jk) * vmask(ji,jj,jk) END DO @@ -768,12 +774,14 @@ CONTAINS DO ji=i1,i2 ! ! Update barotropic velocities: +#if ! defined key_RK3 IF ( .NOT.ln_dynspg_ts .OR. (ln_dynspg_ts.AND.(.NOT.ln_bt_fw)) ) THEN IF (.NOT.(lk_agrif_fstep.AND.(l_1st_euler))) THEN ! Add asselin part zcorr = (tabres(ji,jj) - uu_b(ji,jj,Kmm_a) * hu(ji,jj,Krhs_a)) * r1_hu(ji,jj,Kbb_a) uu_b(ji,jj,Kbb_a) = uu_b(ji,jj,Kbb_a) + rn_atfp * zcorr * umask(ji,jj,1) END IF ENDIF +#endif uu_b(ji,jj,Kmm_a) = tabres(ji,jj) * r1_hu(ji,jj,Kmm_a) * umask(ji,jj,1) ! END DO @@ -838,12 +846,14 @@ CONTAINS DO jj=j1,j2 DO ji=i1,i2 ! Update barotropic velocities: +#if ! defined key_RK3 IF ( .NOT.ln_dynspg_ts .OR. (ln_dynspg_ts.AND.(.NOT.ln_bt_fw)) ) THEN IF (.NOT.(lk_agrif_fstep.AND.(l_1st_euler))) THEN ! Add asselin part zcorr = (tabres(ji,jj) - vv_b(ji,jj,Kmm_a) * hv(ji,jj,Krhs_a)) * r1_hv(ji,jj,Kbb_a) vv_b(ji,jj,Kbb_a) = vv_b(ji,jj,Kbb_a) + rn_atfp * zcorr * vmask(ji,jj,1) END IF ENDIF +#endif vv_b(ji,jj,Kmm_a) = tabres(ji,jj) * r1_hv(ji,jj,Kmm_a) * vmask(ji,jj,1) ! END DO @@ -903,6 +913,7 @@ CONTAINS END DO ELSE ! +#if ! defined key_RK3 IF (.NOT.(lk_agrif_fstep.AND.(l_1st_euler))) THEN DO jj=j1,j2 DO ji=i1,i2 @@ -911,6 +922,7 @@ CONTAINS END DO END DO ENDIF +#endif ! DO jj=j1,j2 DO ji=i1,i2 @@ -977,7 +989,7 @@ CONTAINS ! END SUBROUTINE updatevmsk - +# if ! defined key_RK3 SUBROUTINE updateub2b( tabres, i1, i2, j1, j2, before ) !!---------------------------------------------------------------------- !! *** ROUTINE updateub2b *** @@ -1013,6 +1025,7 @@ CONTAINS ENDIF ! END SUBROUTINE updateub2b +# endif SUBROUTINE reflux_sshu( tabres, i1, i2, j1, j2, before, nb, ndir ) !!--------------------------------------------- @@ -1041,16 +1054,28 @@ CONTAINS ! IF (western_side) THEN DO jj=j1,j2 +# if defined key_RK3 + zcor = rn_Dt * r1_e1e2t(i1 ,jj) * e2u(i1,jj) * (un_adv(i1,jj)-tabres(i1,jj)) +# else zcor = rn_Dt * r1_e1e2t(i1 ,jj) * e2u(i1,jj) * (ub2_b(i1,jj)-tabres(i1,jj)) +# endif ssh(i1 ,jj,Kmm_a) = ssh(i1 ,jj,Kmm_a) + zcor +#if ! defined key_RK3 IF (.NOT.(lk_agrif_fstep.AND.(l_1st_euler))) ssh(i1 ,jj,Kbb_a) = ssh(i1 ,jj,Kbb_a) + rn_atfp * zcor +#endif END DO ENDIF IF (eastern_side) THEN DO jj=j1,j2 +# if defined key_RK3 + zcor = - rn_Dt * r1_e1e2t(i2+1,jj) * e2u(i2,jj) * (un_adv(i2,jj)-tabres(i2,jj)) +# else zcor = - rn_Dt * r1_e1e2t(i2+1,jj) * e2u(i2,jj) * (ub2_b(i2,jj)-tabres(i2,jj)) +# endif ssh(i2+1,jj,Kmm_a) = ssh(i2+1,jj,Kmm_a) + zcor +#if ! defined key_RK3 IF (.NOT.(lk_agrif_fstep.AND.(l_1st_euler))) ssh(i2+1,jj,Kbb_a) = ssh(i2+1,jj,Kbb_a) + rn_atfp * zcor +#endif END DO ENDIF ! @@ -1058,6 +1083,7 @@ CONTAINS ! END SUBROUTINE reflux_sshu +# if ! defined key_RK3 SUBROUTINE updatevb2b( tabres, i1, i2, j1, j2, before ) !!---------------------------------------------------------------------- !! *** ROUTINE updatevb2b *** @@ -1093,6 +1119,7 @@ CONTAINS ENDIF ! END SUBROUTINE updatevb2b +# endif SUBROUTINE reflux_sshv( tabres, i1, i2, j1, j2, before, nb, ndir ) !!--------------------------------------------- @@ -1121,16 +1148,28 @@ CONTAINS ! IF (southern_side) THEN DO ji=i1,i2 +# if defined key_RK3 + zcor = rn_Dt * r1_e1e2t(ji,j1 ) * e1v(ji,j1 ) * (vn_adv(ji,j1)-tabres(ji,j1)) +# else zcor = rn_Dt * r1_e1e2t(ji,j1 ) * e1v(ji,j1 ) * (vb2_b(ji,j1)-tabres(ji,j1)) +# endif ssh(ji,j1 ,Kmm_a) = ssh(ji,j1 ,Kmm_a) + zcor +#if ! defined key_RK3 IF (.NOT.(lk_agrif_fstep.AND.(l_1st_euler))) ssh(ji,j1 ,Kbb_a) = ssh(ji,j1,Kbb_a) + rn_atfp * zcor +#endif END DO ENDIF IF (northern_side) THEN DO ji=i1,i2 +# if defined key_RK3 + zcor = - rn_Dt * r1_e1e2t(ji,j2+1) * e1v(ji,j2 ) * (vn_adv(ji,j2)-tabres(ji,j2)) +# else zcor = - rn_Dt * r1_e1e2t(ji,j2+1) * e1v(ji,j2 ) * (vb2_b(ji,j2)-tabres(ji,j2)) +# endif ssh(ji,j2+1,Kmm_a) = ssh(ji,j2+1,Kmm_a) + zcor +#if ! defined key_RK3 IF (.NOT.(lk_agrif_fstep.AND.(l_1st_euler))) ssh(ji,j2+1,Kbb_a) = ssh(ji,j2+1,Kbb_a) + rn_atfp * zcor +#endif END DO ENDIF ! @@ -1232,6 +1271,7 @@ CONTAINS ! of prognostic variables e3t(i1:i2,j1:j2,1:jpkm1,Krhs_a) = e3t(i1:i2,j1:j2,1:jpkm1,Kmm_a) +#if ! defined key_RK3 IF (.NOT.(lk_agrif_fstep.AND.(l_1st_euler) )) THEN DO jk = 1, jpkm1 DO jj=j1,j2 @@ -1262,6 +1302,7 @@ CONTAINS END DO ! ENDIF +#endif ! ! 2) Updates at NOW time step: ! ---------------------------- diff --git a/src/NST/agrif_top_interp.F90 b/src/NST/agrif_top_interp.F90 index e2314a077cae5495c04fdf8711e2ae8c11c8e449..23ad775defe6e241e9344e484a4142b6120aeddc 100644 --- a/src/NST/agrif_top_interp.F90 +++ b/src/NST/agrif_top_interp.F90 @@ -30,23 +30,42 @@ MODULE agrif_top_interp # include "domzgr_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/NST 4.0 , NEMO Consortium (2018) - !! $Id: agrif_top_interp.F90 14218 2020-12-18 16:44:52Z jchanut $ + !! $Id: agrif_top_interp.F90 14800 2021-05-06 15:42:46Z jchanut $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS - SUBROUTINE Agrif_trc + SUBROUTINE Agrif_trc( kt, kstg ) !!---------------------------------------------------------------------- !! *** ROUTINE Agrif_trc *** !!---------------------------------------------------------------------- + INTEGER, INTENT(in) :: kt + INTEGER, OPTIONAL, INTENT(in) :: kstg + ! + REAL(wp) :: ztindex ! IF( Agrif_Root() ) RETURN ! + ! Set time index depending on stage in case of RK3 time stepping: + IF ( PRESENT( kstg ) ) THEN + ztindex = REAL(Agrif_Nbstepint(), wp) + IF ( kstg == 1 ) THEN + ztindex = ztindex + 1._wp / 3._wp + ELSEIF ( kstg == 2 ) THEN + ztindex = ztindex + 1._wp / 2._wp + ELSEIF ( kstg == 3 ) THEN + ztindex = ztindex + 1._wp + ENDIF + ztindex = ztindex / Agrif_Rhot() + ELSE + ztindex = REAL(Agrif_Nbstepint()+1, wp) / Agrif_Rhot() + ENDIF + ! Agrif_SpecialValue = 0._wp Agrif_UseSpecialValue = l_spc_top l_vremap = ln_vert_remap ! - CALL Agrif_Bc_variable( trn_id, procname=interptrn ) + CALL Agrif_Bc_variable( trn_id,calledweight=ztindex, procname=interptrn ) ! Agrif_UseSpecialValue = .FALSE. l_vremap = .FALSE. diff --git a/src/NST/agrif_top_sponge.F90 b/src/NST/agrif_top_sponge.F90 index e40c7063ca9bdbef336bc0a0c6d641f825e1c1fa..641b9de74e96a4e352885b4c0cadddabd210ab70 100644 --- a/src/NST/agrif_top_sponge.F90 +++ b/src/NST/agrif_top_sponge.F90 @@ -33,7 +33,7 @@ MODULE agrif_top_sponge # include "domzgr_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/NST 4.0 , NEMO Consortium (2018) - !! $Id: agrif_top_sponge.F90 15437 2021-10-22 12:21:20Z jchanut $ + !! $Id: agrif_top_sponge.F90 14800 2021-05-06 15:42:46Z jchanut $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS @@ -46,9 +46,12 @@ CONTAINS !!---------------------------------------------------------------------- ! #if defined SPONGE_TOP +#if defined key_RK3 + zcoef = REAL(Agrif_Nbstepint(), wp)/REAL(Agrif_rhot()) +#else !! Assume persistence: zcoef = REAL(Agrif_rhot()-1,wp)/REAL(Agrif_rhot()) - +#endif Agrif_SpecialValue = 0._wp Agrif_UseSpecialValue = l_spc_top l_vremap = ln_vert_remap diff --git a/src/NST/agrif_top_update.F90 b/src/NST/agrif_top_update.F90 index 9a8f188f92c3c50980e4ee2aa3511d18a9a4c7f3..8cf5231c7dce94ead6126e503632fc343182ceee 100644 --- a/src/NST/agrif_top_update.F90 +++ b/src/NST/agrif_top_update.F90 @@ -29,7 +29,7 @@ MODULE agrif_top_update # include "domzgr_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/NST 4.0 , NEMO Consortium (2018) - !! $Id: agrif_top_update.F90 15265 2021-09-16 11:13:13Z jchanut $ + !! $Id: agrif_top_update.F90 14800 2021-05-06 15:42:46Z jchanut $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS @@ -121,7 +121,7 @@ CONTAINS ENDIF ENDDO ENDDO - +#if ! defined key_RK3 IF (.NOT.(lk_agrif_fstep.AND.(l_1st_euler))) THEN ! Add asselin part DO jn = 1,jptra @@ -142,6 +142,7 @@ CONTAINS END DO END DO ENDIF +#endif DO jn = 1,jptra DO jk = 1, jpkm1 DO jj = j1, j2 @@ -160,6 +161,7 @@ CONTAINS & * tmask(i1:i2,j1:j2,jk) END DO ENDDO +#if ! defined key_RK3 IF (.NOT.(lk_agrif_fstep.AND.(l_1st_euler))) THEN ! Add asselin part DO jn = 1,jptra @@ -180,6 +182,7 @@ CONTAINS END DO END DO ENDIF +#endif DO jn = 1,jptra DO jk=k1,k2 DO jj=j1,j2 diff --git a/src/NST/agrif_user.F90 b/src/NST/agrif_user.F90 index 321c5b91d2ab8ceabf81420df48d8f5151b819fd..2bdc85c5dd683eb011b0ce1e7e0cba9272e7a8a1 100644 --- a/src/NST/agrif_user.F90 +++ b/src/NST/agrif_user.F90 @@ -27,7 +27,11 @@ !!---------------------------------------------------------------------- ! CALL nemo_init !* Initializations of each fine grid +# if defined key_RK3 + Kbb_a = Nbb; Kmm_a = Nbb; Krhs_a = Nrhs +# else Kbb_a = Nbb; Kmm_a = Nnn; Krhs_a = Nrhs ! agrif_oce module copies of time level indices +# endif ! ! !* Agrif initialization CALL Agrif_InitValues_cont @@ -410,29 +414,17 @@ hbdy(:,:) = 0._wp ssh(:,:,Krhs_a) = 0._wp - IF ( ln_dynspg_ts ) THEN - Agrif_UseSpecialValue = ln_spc_dyn - use_sign_north = .TRUE. - sign_north = -1. - CALL Agrif_Bc_variable(ub2b_interp_id,calledweight=1.,procname=interpub2b) ! must be called before unb_id to define ubdy - CALL Agrif_Bc_variable(vb2b_interp_id,calledweight=1.,procname=interpvb2b) ! must be called before vnb_id to define vbdy - CALL Agrif_Bc_variable( unb_interp_id,calledweight=1.,procname=interpunb ) - CALL Agrif_Bc_variable( vnb_interp_id,calledweight=1.,procname=interpvnb ) - use_sign_north = .FALSE. - ubdy(:,:) = 0._wp - vbdy(:,:) = 0._wp - ELSEIF ( ln_dynspg_EXP ) THEN - Agrif_UseSpecialValue = ln_spc_dyn - use_sign_north = .TRUE. - sign_north = -1. - ubdy(:,:) = 0._wp - vbdy(:,:) = 0._wp - CALL Agrif_Bc_variable( unb_interp_id,calledweight=1.,procname=interpunb ) - CALL Agrif_Bc_variable( vnb_interp_id,calledweight=1.,procname=interpvnb ) - use_sign_north = .FALSE. - ubdy(:,:) = 0._wp - vbdy(:,:) = 0._wp - ENDIF + Agrif_UseSpecialValue = ln_spc_dyn + use_sign_north = .TRUE. + sign_north = -1. + ubdy(:,:) = 0._wp + vbdy(:,:) = 0._wp + CALL Agrif_Bc_variable( unb_interp_id,calledweight=1.,procname=interpunb ) + CALL Agrif_Bc_variable( vnb_interp_id,calledweight=1.,procname=interpvnb ) + use_sign_north = .FALSE. + ubdy(:,:) = 0._wp + vbdy(:,:) = 0._wp + Agrif_UseSpecialValue = .FALSE. l_vremap = .FALSE. diff --git a/src/OCE/DIA/diaptr.F90 b/src/OCE/DIA/diaptr.F90 index 501e54f637e7d9ea4b48e51f6cf080dfb3ac659a..8962bd371022c031c3640f49b1d8847d02eada82 100644 --- a/src/OCE/DIA/diaptr.F90 +++ b/src/OCE/DIA/diaptr.F90 @@ -41,6 +41,7 @@ MODULE diaptr END INTERFACE PUBLIC dia_ptr ! call in step module + PUBLIC dia_ptr_init ! call in stprk3 module PUBLIC dia_ptr_hst ! called from tra_ldf/tra_adv routines REAL(wp), ALLOCATABLE, SAVE, DIMENSION(:,:,:) :: hstr_adv, hstr_ldf, hstr_eiv !: Heat/Salt TRansports(adv, diff, Bolus.) @@ -65,7 +66,7 @@ MODULE diaptr # include "domzgr_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/OCE 4.0 , NEMO Consortium (2018) - !! $Id: diaptr.F90 14834 2021-05-11 09:24:44Z hadcv $ + !! $Id: diaptr.F90 15513 2021-11-15 17:31:29Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS @@ -82,7 +83,9 @@ CONTAINS ! IF( ln_timing ) CALL timing_start('dia_ptr') +#if ! defined key_RK3 IF( kt == nit000 .AND. ll_init ) CALL dia_ptr_init ! -> will define l_diaptr and nbasin +#endif ! IF( l_diaptr ) THEN ! Calculate zonal integrals diff --git a/src/OCE/DOM/dom_oce.F90 b/src/OCE/DOM/dom_oce.F90 index 7d73a76d14d0446a62b183b4c1d1beaf83bc553a..71d351a9a8b5d84d08fe69f7fff2fe05dc13c8d1 100644 --- a/src/OCE/DOM/dom_oce.F90 +++ b/src/OCE/DOM/dom_oce.F90 @@ -152,13 +152,12 @@ MODULE dom_oce ! ! reference depths of cells REAL(wp), PUBLIC, ALLOCATABLE, SAVE, DIMENSION(:,:,:) :: gdept_0 !: t- depth [m] REAL(wp), PUBLIC, ALLOCATABLE, SAVE, DIMENSION(:,:,:) :: gdepw_0 !: w- depth [m] - REAL(wp), PUBLIC, ALLOCATABLE, SAVE, DIMENSION(:,:,:) :: gde3w_0 !: w- depth (sum of e3w) [m] ! ! time-dependent depths of cells (domvvl) #if defined key_qco || defined key_linssh #else - REAL(wp), PUBLIC, ALLOCATABLE, SAVE, DIMENSION(:,:,:,:) :: gdept, gdepw - REAL(wp), PUBLIC, ALLOCATABLE, SAVE, DIMENSION(:,:,:) :: gde3w + REAL(wp), PUBLIC, ALLOCATABLE, SAVE, DIMENSION(:,:,:) :: gde3w_0, gde3w !: w- depth (sum of e3w) [m] + REAL(wp), PUBLIC, ALLOCATABLE, SAVE, DIMENSION(:,:,:,:) :: gdept, gdepw #endif ! ! reference heights of ocean water column and its inverse REAL(wp), PUBLIC, ALLOCATABLE, SAVE, DIMENSION(:,:) :: ht_0, r1_ht_0 !: t-depth [m] and [1/m] @@ -286,7 +285,7 @@ CONTAINS & ff_f (jpi,jpj) , ff_t (jpi,jpj) , STAT=ierr(ii) ) ! ii = ii+1 - ALLOCATE( gdept_0 (jpi,jpj,jpk) , gdepw_0 (jpi,jpj,jpk) , gde3w_0(jpi,jpj,jpk) , & + ALLOCATE( gdept_0 (jpi,jpj,jpk) , gdepw_0 (jpi,jpj,jpk) , & & gdept_1d( jpk) , gdepw_1d( jpk) , STAT=ierr(ii) ) ! ii = ii+1 @@ -311,7 +310,8 @@ CONTAINS #else ! vvl : time varation for all vertical coordinate variables ii = ii+1 - ALLOCATE( gdept (jpi,jpj,jpk,jpt) , gdepw (jpi,jpj,jpk,jpt) , gde3w (jpi,jpj,jpk) , STAT=ierr(ii) ) + ALLOCATE( gdept (jpi,jpj,jpk,jpt) , gdepw (jpi,jpj,jpk,jpt) , & + & gde3w_0(jpi,jpj,jpk) , gde3w (jpi,jpj,jpk) , STAT=ierr(ii) ) ! ii = ii+1 ALLOCATE( e3t(jpi,jpj,jpk,jpt) , e3u (jpi,jpj,jpk,jpt) , e3v (jpi,jpj,jpk,jpt) , e3f(jpi,jpj,jpk) , & diff --git a/src/OCE/DOM/domain.F90 b/src/OCE/DOM/domain.F90 index 65865ee690796f3ec3a1e414f6c8e312c847d0ae..0afbb66c9a7154df8f8e37eda2fe122800ab3043 100644 --- a/src/OCE/DOM/domain.F90 +++ b/src/OCE/DOM/domain.F90 @@ -64,7 +64,7 @@ MODULE domain # include "do_loop_substitute.h90" !!------------------------------------------------------------------------- !! NEMO/OCE 4.0 , NEMO Consortium (2018) - !! $Id: domain.F90 15270 2021-09-17 14:27:55Z smasson $ + !! $Id: domain.F90 14547 2021-02-25 17:07:15Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!------------------------------------------------------------------------- CONTAINS @@ -88,7 +88,6 @@ CONTAINS ! INTEGER :: ji, jj, jk, jt ! dummy loop indices INTEGER :: iconf = 0 ! local integers - REAL(wp):: zrdt CHARACTER (len=64) :: cform = "(A12, 3(A13, I7))" INTEGER , DIMENSION(jpi,jpj) :: ik_top , ik_bot ! top and bottom ocean level REAL(wp), DIMENSION(jpi,jpj) :: z1_hu_0, z1_hv_0 @@ -310,8 +309,27 @@ CONTAINS ENDIF ! ! set current model timestep rDt = 2*rn_Dt if MLF or rDt = rn_Dt if RK3 +#if defined key_RK3 + rDt = rn_Dt + r1_Dt = 1._wp / rDt + ! + IF(lwp) THEN + WRITE(numout,*) + WRITE(numout,*) ' ===>>> Runge Kutta 3rd order (RK3) : rDt = ', rDt + WRITE(numout,*) + ENDIF + ! +#else rDt = 2._wp * rn_Dt r1_Dt = 1._wp / rDt + ! + IF(lwp) THEN + WRITE(numout,*) + WRITE(numout,*) ' ===>>> Modified Leap-Frog (MLF) : rDt = ', rDt + WRITE(numout,*) + ENDIF + ! +#endif ! IF( l_SAS .AND. .NOT.ln_linssh ) THEN CALL ctl_warn( 'SAS requires linear ssh : force ln_linssh = T' ) @@ -392,6 +410,8 @@ CONTAINS IF( nn_wxios > 0 ) lwxios = .TRUE. !* set output file type for XIOS based on NEMO namelist nxioso = nn_wxios ENDIF + ! +#if ! defined key_RK3 ! !== Check consistency between ln_rstart and ln_1st_euler ==! (i.e. set l_1st_euler) l_1st_euler = ln_1st_euler ! @@ -427,6 +447,7 @@ CONTAINS IF(lwp) WRITE(numout,*)' an Euler initial time step is used : l_1st_euler is forced to .true. ' l_1st_euler = .TRUE. ENDIF +#endif ! ! !== control of output frequency ==! ! diff --git a/src/OCE/DOM/domqco.F90 b/src/OCE/DOM/domqco.F90 index 82a94386aab4cace92a074e03acedbdb1e1c76e1..5944f59c1057780287cc63828673d090415ce239 100644 --- a/src/OCE/DOM/domqco.F90 +++ b/src/OCE/DOM/domqco.F90 @@ -39,6 +39,7 @@ MODULE domqco PUBLIC dom_qco_init ! called by domain.F90 PUBLIC dom_qco_zgr ! called by isfcpl.F90 PUBLIC dom_qco_r3c ! called by steplf.F90 + PUBLIC dom_qco_r3c_RK3 ! called by stprk3_stg.F90 ! !!* Namelist nam_vvl LOGICAL , PUBLIC :: ln_vvl_zstar = .FALSE. ! zstar vertical coordinate @@ -123,7 +124,9 @@ CONTAINS ! ! Horizontal interpolation of e3t #if defined key_RK3 CALL dom_qco_r3c( ssh(:,:,Kbb), r3t(:,:,Kbb), r3u(:,:,Kbb), r3v(:,:,Kbb), r3f(:,:) ) - CALL dom_qco_r3c( ssh(:,:,Kmm), r3t(:,:,Kmm), r3u(:,:,Kmm), r3v(:,:,Kmm) ) + r3t(:,:,Kmm) = r3t(:,:,Kbb) !!st r3 at Kmm needed to be initialised for Agrid_Grid call in nemo_gcm + r3u(:,:,Kmm) = r3u(:,:,Kbb) !! maybe we only need zeros ??? + r3v(:,:,Kmm) = r3v(:,:,Kbb) #else CALL dom_qco_r3c( ssh(:,:,Kbb), r3t(:,:,Kbb), r3u(:,:,Kbb), r3v(:,:,Kbb) ) CALL dom_qco_r3c( ssh(:,:,Kmm), r3t(:,:,Kmm), r3u(:,:,Kmm), r3v(:,:,Kmm), r3f(:,:) ) @@ -136,6 +139,61 @@ CONTAINS SUBROUTINE dom_qco_r3c( pssh, pr3t, pr3u, pr3v, pr3f ) + !!--------------------------------------------------------------------- + !! *** ROUTINE r3c *** + !! + !! ** Purpose : compute the filtered ratio ssh/h_0 at t-,u-,v-,f-points + !! + !! ** Method : - compute the ssh at u- and v-points (f-point optional) + !! Vector Form : surface weighted averaging + !! Flux Form : simple averaging + !! - compute the ratio ssh/h_0 at t-,u-,v-pts, (f-pt optional) + !!---------------------------------------------------------------------- + REAL(wp), DIMENSION(:,:) , INTENT(in ) :: pssh ! sea surface height [m] + REAL(wp), DIMENSION(:,:) , INTENT( out) :: pr3t, pr3u, pr3v ! ssh/h0 ratio at t-, u-, v-,points [-] + REAL(wp), DIMENSION(:,:), OPTIONAL, INTENT( out) :: pr3f ! ssh/h0 ratio at f-point [-] + ! + INTEGER :: ji, jj ! dummy loop indices + !!---------------------------------------------------------------------- + ! + ! + DO_2D_OVR( nn_hls, nn_hls, nn_hls, nn_hls ) + pr3t(ji,jj) = pssh(ji,jj) * r1_ht_0(ji,jj) !== ratio at t-point ==! + END_2D + ! + ! !== ratio at u-,v-point ==! + ! + DO_2D_OVR( nn_hls, nn_hls-1, nn_hls, nn_hls-1 ) + pr3u(ji,jj) = 0.5_wp * ( e1e2t(ji ,jj) * pssh(ji ,jj) & + & + e1e2t(ji+1,jj) * pssh(ji+1,jj) ) * r1_hu_0(ji,jj) * r1_e1e2u(ji,jj) + pr3v(ji,jj) = 0.5_wp * ( e1e2t(ji,jj ) * pssh(ji,jj ) & + & + e1e2t(ji,jj+1) * pssh(ji,jj+1) ) * r1_hv_0(ji,jj) * r1_e1e2v(ji,jj) + END_2D + ! + IF( .NOT.PRESENT( pr3f ) ) THEN !- lbc on ratio at u-, v-points only + IF (nn_hls==1) CALL lbc_lnk( 'dom_qco_r3c', pr3u, 'U', 1._wp, pr3v, 'V', 1._wp ) + ! + ! + ELSE !== ratio at f-point ==! + ! + DO_2D_OVR( nn_hls, nn_hls-1, nn_hls, nn_hls-1 ) + ! round brackets added to fix the order of floating point operations + ! needed to ensure halo 1 - halo 2 compatibility + pr3f(ji,jj) = 0.25_wp * ( ( e1e2t(ji ,jj ) * pssh(ji ,jj ) & + & + e1e2t(ji+1,jj ) * pssh(ji+1,jj ) ) & ! bracket for halo 1 - halo 2 compatibility + & + ( e1e2t(ji ,jj+1) * pssh(ji ,jj+1) & + & + e1e2t(ji+1,jj+1) * pssh(ji+1,jj+1) ) & ! bracket for halo 1 - halo 2 compatibility + & ) * r1_hf_0(ji,jj) * r1_e1e2f(ji,jj) + END_2D + ! ! lbc on ratio at u-,v-,f-points + IF (nn_hls==1) CALL lbc_lnk( 'dom_qco_r3c', pr3u, 'U', 1._wp, pr3v, 'V', 1._wp, pr3f, 'F', 1._wp ) + ! + ENDIF + ! + END SUBROUTINE dom_qco_r3c + + + SUBROUTINE dom_qco_r3c_RK3( pssh, pr3t, pr3u, pr3v, pr3f ) !!--------------------------------------------------------------------- !! *** ROUTINE r3c *** !! @@ -164,7 +222,7 @@ CONTAINS !!st IF( ln_dynadv_vec ) THEN !- Vector Form (thickness weighted averaging) #if ! defined key_qcoTest_FluxForm ! ! no 'key_qcoTest_FluxForm' : surface weighted ssh average - DO_2D_OVR( nn_hls, nn_hls-1, nn_hls, nn_hls-1 ) + DO_2D( 0, 0, 0, 0 ) pr3u(ji,jj) = 0.5_wp * ( e1e2t(ji ,jj) * pssh(ji ,jj) & & + e1e2t(ji+1,jj) * pssh(ji+1,jj) ) * r1_hu_0(ji,jj) * r1_e1e2u(ji,jj) pr3v(ji,jj) = 0.5_wp * ( e1e2t(ji,jj ) * pssh(ji,jj ) & @@ -172,52 +230,43 @@ CONTAINS END_2D !!st ELSE !- Flux Form (simple averaging) #else - DO_2D_OVR( nn_hls, nn_hls-1, nn_hls, nn_hls-1 ) + DO_2D( 0, 0, 0, 0 ) pr3u(ji,jj) = 0.5_wp * ( pssh(ji,jj) + pssh(ji+1,jj ) ) * r1_hu_0(ji,jj) pr3v(ji,jj) = 0.5_wp * ( pssh(ji,jj) + pssh(ji ,jj+1) ) * r1_hv_0(ji,jj) END_2D !!st ENDIF #endif ! - IF( .NOT.PRESENT( pr3f ) ) THEN !- lbc on ratio at u-, v-points only - IF (nn_hls==1) CALL lbc_lnk( 'dom_qco_r3c', pr3u, 'U', 1._wp, pr3v, 'V', 1._wp ) - ! - ! - ELSE !== ratio at f-point ==! + IF( PRESENT( pr3f ) ) THEN !== ratio at f-point ==! ! !!st IF( ln_dynadv_vec ) THEN !- Vector Form (thickness weighted averaging) #if ! defined key_qcoTest_FluxForm ! ! no 'key_qcoTest_FluxForm' : surface weighted ssh average - DO_2D_OVR( nn_hls, nn_hls-1, nn_hls, nn_hls-1 ) + DO_2D( 0, 0, 0, 0 ) ! round brackets added to fix the order of floating point operations ! needed to ensure halo 1 - halo 2 compatibility - pr3f(ji,jj) = 0.25_wp * ( ( e1e2t(ji ,jj ) * pssh(ji ,jj ) & - & + e1e2t(ji+1,jj ) * pssh(ji+1,jj ) & - & ) & ! bracket for halo 1 - halo 2 compatibility - & + ( e1e2t(ji ,jj+1) * pssh(ji ,jj+1) & - & + e1e2t(ji+1,jj+1) * pssh(ji+1,jj+1) & - & ) & ! bracket for halo 1 - halo 2 compatibility + pr3f(ji,jj) = 0.25_wp * ( ( e1e2t(ji ,jj ) * pssh(ji ,jj ) & + & + e1e2t(ji+1,jj ) * pssh(ji+1,jj ) ) & ! bracket for halo 1 - halo 2 compatibility + & + ( e1e2t(ji ,jj+1) * pssh(ji ,jj+1) & + & + e1e2t(ji+1,jj+1) * pssh(ji+1,jj+1) ) & ! bracket for halo 1 - halo 2 compatibility & ) * r1_hf_0(ji,jj) * r1_e1e2f(ji,jj) END_2D !!st ELSE !- Flux Form (simple averaging) #else - DO_2D_OVR( nn_hls, nn_hls-1, nn_hls, nn_hls-1 ) + DO_2D( 0, 0, 0, 0 ) ! round brackets added to fix the order of floating point operations ! needed to ensure halo 1 - halo 2 compatibility - pr3f(ji,jj) = 0.25_wp * ( ( pssh(ji,jj ) + pssh(ji+1,jj ) ) & - & + ( pssh(ji,jj+1) + pssh(ji+1,jj+1) & - & ) & ! bracket for halo 1 - halo 2 compatibility + pr3f(ji,jj) = 0.25_wp * ( ( pssh(ji,jj ) + pssh(ji+1,jj ) ) & + & + ( pssh(ji,jj+1) + pssh(ji+1,jj+1) ) & ! bracket for halo 1 - halo 2 compatibility & ) * r1_hf_0(ji,jj) END_2D !!st ENDIF #endif - ! ! lbc on ratio at u-,v-,f-points - IF (nn_hls==1) CALL lbc_lnk( 'dom_qco_r3c', pr3u, 'U', 1._wp, pr3v, 'V', 1._wp, pr3f, 'F', 1._wp ) ! ENDIF ! - END SUBROUTINE dom_qco_r3c + END SUBROUTINE dom_qco_r3c_RK3 SUBROUTINE qco_ctl diff --git a/src/OCE/DOM/domzgr.F90 b/src/OCE/DOM/domzgr.F90 index 9a5b6fc364b48758b08b32d0214c084a3d808f6a..85f89ed2c9b67d30da99d6ad550cf09c8d31cfdb 100644 --- a/src/OCE/DOM/domzgr.F90 +++ b/src/OCE/DOM/domzgr.F90 @@ -46,7 +46,7 @@ MODULE domzgr # include "do_loop_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/OCE 4.0 , NEMO Consortium (2018) - !! $Id: domzgr.F90 15556 2021-11-29 15:23:06Z jchanut $ + !! $Id: domzgr.F90 15157 2021-07-29 08:28:32Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS @@ -142,12 +142,17 @@ CONTAINS CALL lbc_lnk( 'usrdef_zgr', zmsk, 'T', 1. ) ! set halos k_top(:,:) = k_top(:,:) * NINT( zmsk(:,:) ) ! -!!gm to be remove when removing the OLD definition of e3 scale factors so that gde3w disappears +#if ! defined key_qco && ! defined key_linssh + ! OLD implementation of coordinate (not with 'key_qco' or 'key_linssh') + ! gde3w_0 has to be defined +!!gm to be remove when removing the OLD definition of e3 scale factors so that gde3w_0=gdept_0 +!!gm therefore gde3w_0 disappears ! Compute gde3w_0 (vertical sum of e3w) gde3w_0(:,:,1) = 0.5_wp * e3w_0(:,:,1) DO jk = 2, jpk gde3w_0(:,:,jk) = gde3w_0(:,:,jk-1) + e3w_0(:,:,jk) END DO +#endif ! ! Any closed seas (defined by closea_mask > 0 in domain_cfg file) to be filled ! in at runtime if ln_closea=.false. @@ -200,14 +205,20 @@ CONTAINS WRITE(numout,*) ' MIN val k_top ', MINVAL( k_top(:,:) ), ' MAX ', MAXVAL( k_top(:,:) ) WRITE(numout,*) ' MIN val k_bot ', MINVAL( k_bot(:,:) ), ' MAX ', MAXVAL( k_bot(:,:) ) WRITE(numout,*) ' MIN val depth t ', MINVAL( gdept_0(:,:,:) ), & - & ' w ', MINVAL( gdepw_0(:,:,:) ), '3w ', MINVAL( gde3w_0(:,:,:) ) +#if ! defined key_qco && ! defined key_linssh + & '3w ', MINVAL( gde3w_0(:,:,:) ), & +#endif + & ' w ', MINVAL( gdepw_0(:,:,:) ) WRITE(numout,*) ' MIN val e3 t ', MINVAL( e3t_0(:,:,:) ), ' f ', MINVAL( e3f_0(:,:,:) ), & & ' u ', MINVAL( e3u_0(:,:,:) ), ' u ', MINVAL( e3v_0(:,:,:) ), & & ' uw', MINVAL( e3uw_0(:,:,:) ), ' vw', MINVAL( e3vw_0(:,:,:)), & & ' w ', MINVAL( e3w_0(:,:,:) ) WRITE(numout,*) ' MAX val depth t ', MAXVAL( gdept_0(:,:,:) ), & - & ' w ', MAXVAL( gdepw_0(:,:,:) ), '3w ', MAXVAL( gde3w_0(:,:,:) ) +#if ! defined key_qco && ! defined key_linssh + & '3w ', MINVAL( gde3w_0(:,:,:) ), & +#endif + & ' w ', MINVAL( gdepw_0(:,:,:) ) WRITE(numout,*) ' MAX val e3 t ', MAXVAL( e3t_0(:,:,:) ), ' f ', MAXVAL( e3f_0(:,:,:) ), & & ' u ', MAXVAL( e3u_0(:,:,:) ), ' u ', MAXVAL( e3v_0(:,:,:) ), & & ' uw', MAXVAL( e3uw_0(:,:,:) ), ' vw', MAXVAL( e3vw_0(:,:,:) ), & diff --git a/src/OCE/DOM/domzgr_substitute.h90 b/src/OCE/DOM/domzgr_substitute.h90 index 35e60fa876232325883d5c7bc5cd2fb49effd4d3..35173ccb8d24651892c617e16bedbf25ad59a67f 100644 --- a/src/OCE/DOM/domzgr_substitute.h90 +++ b/src/OCE/DOM/domzgr_substitute.h90 @@ -51,4 +51,3 @@ # define gde3w(i,j,k) gdept_0(i,j,k) #endif !!---------------------------------------------------------------------- - diff --git a/src/OCE/DOM/istate.F90 b/src/OCE/DOM/istate.F90 index 9d708a3c7e3a421bc04901d8ac9a5c4bcab60b39..a8ea487a05a3e0f8ddae46ca9a39ed1d9c9c270c 100644 --- a/src/OCE/DOM/istate.F90 +++ b/src/OCE/DOM/istate.F90 @@ -50,7 +50,7 @@ MODULE istate # include "domzgr_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/OCE 4.0 , NEMO Consortium (2018) - !! $Id: istate.F90 15052 2021-06-24 14:39:14Z smasson $ + !! $Id: istate.F90 14991 2021-06-14 19:52:31Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS @@ -138,32 +138,47 @@ CONTAINS ts (:,:,:,:,Kmm) = ts (:,:,:,:,Kbb) ! set now values from to before ones uu (:,:,:,Kmm) = uu (:,:,:,Kbb) vv (:,:,:,Kmm) = vv (:,:,:,Kbb) - ENDIF #if defined key_agrif ENDIF #endif ! - ! Initialize "now" and "before" barotropic velocities: - ! Do it whatever the free surface method, these arrays being eventually used +#if defined key_RK3 + IF( .NOT. ln_rstart ) THEN +#endif + ! Initialize "before" barotropic velocities. "now" values are always set but + ! "before" values may have been read from a restart to ensure restartability. + ! In the non-restart or non-RK3 cases they need to be initialised here: + uu_b(:,:,Kbb) = 0._wp ; vv_b(:,:,Kbb) = 0._wp + DO_3D( nn_hls, nn_hls, nn_hls, nn_hls, 1, jpkm1 ) + uu_b(ji,jj,Kbb) = uu_b(ji,jj,Kbb) + e3u(ji,jj,jk,Kbb) * uu(ji,jj,jk,Kbb) * umask(ji,jj,jk) + vv_b(ji,jj,Kbb) = vv_b(ji,jj,Kbb) + e3v(ji,jj,jk,Kbb) * vv(ji,jj,jk,Kbb) * vmask(ji,jj,jk) + END_3D + uu_b(:,:,Kbb) = uu_b(:,:,Kbb) * r1_hu(:,:,Kbb) + vv_b(:,:,Kbb) = vv_b(:,:,Kbb) * r1_hv(:,:,Kbb) + ! +#if defined key_RK3 + ENDIF +#endif ! - uu_b(:,:,Kmm) = 0._wp ; vv_b(:,:,Kmm) = 0._wp - uu_b(:,:,Kbb) = 0._wp ; vv_b(:,:,Kbb) = 0._wp + ! Initialize "now" barotropic velocities: + ! Do it whatever the free surface method, these arrays being used eventually ! -!!gm the use of umsak & vmask is not necessary below as uu(:,:,:,Kmm), vv(:,:,:,Kmm), uu(:,:,:,Kbb), vv(:,:,:,Kbb) are always masked +#if defined key_RK3 + IF( .NOT. ln_rstart ) THEN + uu_b(:,:,Kmm) = uu_b(:,:,Kbb) ! Kmm value set to Kbb for initialisation in Agrif_Regrid in namo_gcm + vv_b(:,:,Kmm) = vv_b(:,:,Kbb) + ENDIF +#else +!!gm the use of umask & vmask is not necessary below as uu(:,:,:,Kmm), vv(:,:,:,Kmm), uu(:,:,:,Kbb), vv(:,:,:,Kbb) are always masked + uu_b(:,:,Kmm) = 0._wp ; vv_b(:,:,Kmm) = 0._wp DO_3D( nn_hls, nn_hls, nn_hls, nn_hls, 1, jpkm1 ) uu_b(ji,jj,Kmm) = uu_b(ji,jj,Kmm) + e3u(ji,jj,jk,Kmm) * uu(ji,jj,jk,Kmm) * umask(ji,jj,jk) vv_b(ji,jj,Kmm) = vv_b(ji,jj,Kmm) + e3v(ji,jj,jk,Kmm) * vv(ji,jj,jk,Kmm) * vmask(ji,jj,jk) - ! - uu_b(ji,jj,Kbb) = uu_b(ji,jj,Kbb) + e3u(ji,jj,jk,Kbb) * uu(ji,jj,jk,Kbb) * umask(ji,jj,jk) - vv_b(ji,jj,Kbb) = vv_b(ji,jj,Kbb) + e3v(ji,jj,jk,Kbb) * vv(ji,jj,jk,Kbb) * vmask(ji,jj,jk) END_3D - ! uu_b(:,:,Kmm) = uu_b(:,:,Kmm) * r1_hu(:,:,Kmm) vv_b(:,:,Kmm) = vv_b(:,:,Kmm) * r1_hv(:,:,Kmm) - ! - uu_b(:,:,Kbb) = uu_b(:,:,Kbb) * r1_hu(:,:,Kbb) - vv_b(:,:,Kbb) = vv_b(:,:,Kbb) * r1_hv(:,:,Kbb) +#endif ! END SUBROUTINE istate_init diff --git a/src/OCE/DYN/divhor.F90 b/src/OCE/DYN/divhor.F90 index 439144b8288a234f46224e2143ea222317fd5775..2cdf53d1848aa5af5c303cbafb3cbfd57777098d 100644 --- a/src/OCE/DYN/divhor.F90 +++ b/src/OCE/DYN/divhor.F90 @@ -12,6 +12,7 @@ MODULE divhor !! 3.7 ! 2014-01 (G. Madec) suppression of velocity curl from in-core memory !! - ! 2014-12 (G. Madec) suppression of cross land advection option !! - ! 2015-10 (G. Madec) add velocity and rnf flag in argument of div_hor + !! 4.5 ! 2015-10 (S. Techene, G. Madec) hdiv replaced by e3divUh !!---------------------------------------------------------------------- !!---------------------------------------------------------------------- @@ -35,19 +36,89 @@ MODULE divhor IMPLICIT NONE PRIVATE - PUBLIC div_hor ! routine called by step.F90 and istate.F90 + ! !! * Interface + INTERFACE div_hor + MODULE PROCEDURE div_hor_RK3, div_hor_old + END INTERFACE + + PUBLIC div_hor ! routine called by ssh_nxt.F90 and istate.F90 !! * Substitutions # include "do_loop_substitute.h90" # include "domzgr_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/OCE 4.0 , NEMO Consortium (2018) - !! $Id: divhor.F90 15150 2021-07-27 10:38:24Z smasson $ + !! $Id: divhor.F90 14808 2021-05-07 12:00:45Z jchanut $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS - SUBROUTINE div_hor( kt, Kbb, Kmm ) + SUBROUTINE div_hor_RK3( kt, Kbb, Kmm, puu, pvv, pe3divUh ) + !!---------------------------------------------------------------------- + !! *** ROUTINE div_hor_RK3 *** + !! + !! ** Purpose : compute the horizontal divergence at now time-step + !! + !! ** Method : the now divergence is computed as : + !! hdiv = 1/(e1e2t*e3t) ( di[e2u*e3u un] + dj[e1v*e3v vn] ) + !! and correct with runoff inflow (div_rnf) and cross land flow (div_cla) + !! + !! ** Action : - thickness weighted horizontal divergence of in input velocity (puu,pvv) + !!---------------------------------------------------------------------- + INTEGER , INTENT(in ) :: kt, Kbb, Kmm ! ocean time-step & time-level indices + REAL(wp), DIMENSION(jpi,jpj,jpk), INTENT(in ) :: puu, pvv ! horizontal velocity + REAL(wp), DIMENSION(jpi,jpj,jpk), INTENT( out) :: pe3divUh ! e3t*div[Uh] + ! + INTEGER :: ji, jj, jk ! dummy loop indices + !!---------------------------------------------------------------------- + ! + IF( ln_timing ) CALL timing_start('div_hor_RK3') + ! + IF( kt == nit000 ) THEN + IF(lwp) WRITE(numout,*) + IF(lwp) WRITE(numout,*) 'div_hor_RK3 : thickness weighted horizontal divergence ' + IF(lwp) WRITE(numout,*) '~~~~~~~~~~~' + hdiv (:,:,:) = 0._wp ! initialize hdiv & pe3divUh for the halos and jpk level at the first time step + ENDIF + ! + pe3divUh(:,:,:) = 0._wp !!gm to be applied to the halos only + ! + DO_3D_OVR( nn_hls-1, nn_hls, nn_hls-1, nn_hls, 1, jpkm1 ) + hdiv(ji,jj,jk) = ( e2u(ji ,jj) * e3u(ji ,jj,jk,Kmm) * puu(ji ,jj,jk) & + & - e2u(ji-1,jj) * e3u(ji-1,jj,jk,Kmm) * puu(ji-1,jj,jk) & + & + e1v(ji,jj ) * e3v(ji,jj ,jk,Kmm) * pvv(ji,jj ,jk) & + & - e1v(ji,jj-1) * e3v(ji,jj-1,jk,Kmm) * pvv(ji,jj-1,jk) ) & + & * r1_e1e2t(ji,jj) / e3t(ji,jj,jk,Kmm) + END_3D + ! + IF( ln_rnf ) CALL sbc_rnf_div( hdiv, Kmm ) !== + runoffs divergence ==! + ! +#if defined key_asminc + IF( ln_sshinc .AND. ln_asmiau ) & !== + SSH assimilation increment ==! + & CALL ssh_asm_div( kt, Kbb, Kmm, hdiv ) +#endif + ! + IF( ln_isf ) CALL isf_hdiv( kt, Kmm, hdiv ) !== + ice-shelf mass exchange ==! + ! + IF( nn_hls==1 ) CALL lbc_lnk( 'divhor', hdiv, 'T', 1._wp ) ! (no sign change) + ! +!!gm Patch before suppression of hdiv from all modules that use it +! DO_3D( 0, 0, 0, 0, 1, jpkm1 ) !== e3t * Horizontal divergence ==! +! pe3divUh(ji,jj,jk) = hdiv(ji,jj,jk) * e3t(ji,jj,jk,Kmm) +! END_3D +!JC: over whole domain, and after lbclnk on hdiv to prevent from reproducibility issues + DO_3D_OVR( nn_hls-1, nn_hls, nn_hls-1, nn_hls, 1, jpkm1 ) + pe3divUh(ji,jj,jk) = hdiv(ji,jj,jk) * e3t(ji,jj,jk,Kmm) + END_3D +!!gm end + ! + ! + IF( ln_timing ) CALL timing_stop('div_hor_RK3') + ! + END SUBROUTINE div_hor_RK3 + + + SUBROUTINE div_hor_old( kt, Kbb, Kmm ) !!---------------------------------------------------------------------- !! *** ROUTINE div_hor *** !! @@ -102,7 +173,7 @@ CONTAINS ! ! needed for ww in sshwzv IF( ln_timing ) CALL timing_stop('div_hor') ! - END SUBROUTINE div_hor + END SUBROUTINE div_hor_old !!====================================================================== END MODULE divhor diff --git a/src/OCE/DYN/dynadv.F90 b/src/OCE/DYN/dynadv.F90 index 1df6b9522caeb9cd86a7523adb125ee7565fd55e..bda2c3a4f806cd4fab1bcc5a6b3bc1ff89f77dd1 100644 --- a/src/OCE/DYN/dynadv.F90 +++ b/src/OCE/DYN/dynadv.F90 @@ -45,12 +45,12 @@ MODULE dynadv !!---------------------------------------------------------------------- !! NEMO/OCE 4.0 , NEMO Consortium (2018) - !! $Id: dynadv.F90 14053 2020-12-03 13:48:38Z techene $ + !! $Id: dynadv.F90 14419 2021-02-09 12:22:16Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS - SUBROUTINE dyn_adv( kt, Kbb, Kmm, puu, pvv, Krhs ) + SUBROUTINE dyn_adv( kt, Kbb, Kmm, puu, pvv, Krhs, pau, pav, paw, no_zad ) !!--------------------------------------------------------------------- !! *** ROUTINE dyn_adv *** !! @@ -63,21 +63,22 @@ CONTAINS !! it is the relative vorticity which is added to coriolis term !! (see dynvor module). !!---------------------------------------------------------------------- - INTEGER , INTENT( in ) :: kt ! ocean time-step index - INTEGER , INTENT( in ) :: Kbb, Kmm, Krhs ! ocean time level indices - REAL(wp), DIMENSION(jpi,jpj,jpk,jpt), INTENT(inout) :: puu, pvv ! ocean velocities and RHS of momentum equation + INTEGER , INTENT(in ) :: kt , Kbb, Kmm, Krhs ! ocean time step and level indices + INTEGER , OPTIONAL , INTENT(in ) :: no_zad ! no vertical advection compotation + REAL(wp), DIMENSION(:,:,:), OPTIONAL, TARGET, INTENT(in ) :: pau, pav, paw ! advective velocity + REAL(wp), DIMENSION(jpi,jpj,jpk,jpt), TARGET, INTENT(inout) :: puu, pvv ! ocean velocities and RHS of momentum Eq. !!---------------------------------------------------------------------- ! IF( ln_timing ) CALL timing_start( 'dyn_adv' ) ! SELECT CASE( n_dynadv ) !== compute advection trend and add it to general trend ==! - CASE( np_VEC_c2 ) - CALL dyn_keg ( kt, nn_dynkeg, Kmm, puu, pvv, Krhs ) ! vector form : horizontal gradient of kinetic energy - CALL dyn_zad ( kt, Kmm, puu, pvv, Krhs ) ! vector form : vertical advection - CASE( np_FLX_c2 ) - CALL dyn_adv_cen2( kt, Kmm, puu, pvv, Krhs ) ! 2nd order centered scheme + CASE( np_VEC_c2 ) != vector form =! + CALL dyn_keg ( kt, nn_dynkeg , Kmm, puu, pvv, Krhs ) ! horizontal gradient of kinetic energy + CALL dyn_zad ( kt , Kmm, puu, pvv, Krhs ) ! vertical advection + CASE( np_FLX_c2 ) != flux form =! + CALL dyn_adv_cen2( kt , Kmm, puu, pvv, Krhs, pau, pav, paw, no_zad ) ! 2nd order centered scheme CASE( np_FLX_ubs ) - CALL dyn_adv_ubs ( kt, Kbb, Kmm, puu, pvv, Krhs ) ! 3rd order UBS scheme (UP3) + CALL dyn_adv_ubs ( kt , Kbb, Kmm, puu, pvv, Krhs, pau, pav, paw, no_zad ) ! 3rd order UBS scheme (UP3) END SELECT ! IF( ln_timing ) CALL timing_stop( 'dyn_adv' ) diff --git a/src/OCE/DYN/dynadv_cen2.F90 b/src/OCE/DYN/dynadv_cen2.F90 index c3cd13226e9bffae79ae0aaad6beb43f8480cb12..7fd7f65f5c19ca959bd2437cb7352cf5bb1fd1b6 100644 --- a/src/OCE/DYN/dynadv_cen2.F90 +++ b/src/OCE/DYN/dynadv_cen2.F90 @@ -30,29 +30,36 @@ MODULE dynadv_cen2 # include "domzgr_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/OCE 4.0 , NEMO Consortium (2018) - !! $Id: dynadv_cen2.F90 14834 2021-05-11 09:24:44Z hadcv $ + !! $Id: dynadv_cen2.F90 14419 2021-02-09 12:22:16Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS - SUBROUTINE dyn_adv_cen2( kt, Kmm, puu, pvv, Krhs ) + SUBROUTINE dyn_adv_cen2( kt, Kmm, puu, pvv, Krhs, pau, pav, paw, no_zad ) !!---------------------------------------------------------------------- !! *** ROUTINE dyn_adv_cen2 *** !! - !! ** Purpose : Compute the now momentum advection trend in flux form + !! ** Purpose : Compute the momentum advection trend in flux form !! and the general trend of the momentum equation. !! - !! ** Method : Trend evaluated using now fields (centered in time) + !! ** Method : Trend evaluated with a 2nd order centered scheme + !! using fields at Kmm time-level. + !! In RK3 time stepping case, the optional arguments (pau,pav,paw) + !! are present. They are used as advective velocity while + !! the advected velocity remains (puu,pvv). !! - !! ** Action : (puu(:,:,:,Krhs),pvv(:,:,:,Krhs)) updated with the now vorticity term trend + !! ** Action : (puu,pvv)(:,:,:,Krhs) updated with the advective trend !!---------------------------------------------------------------------- - INTEGER , INTENT( in ) :: kt ! ocean time-step index - INTEGER , INTENT( in ) :: Kmm, Krhs ! ocean time level indices - REAL(wp), DIMENSION(jpi,jpj,jpk,jpt), INTENT(inout) :: puu, pvv ! ocean velocities and RHS of momentum equation + INTEGER , INTENT(in ) :: kt , Kmm, Krhs ! ocean time-step and level indices + INTEGER , OPTIONAL , INTENT(in ) :: no_zad ! no vertical advection computation + REAL(wp), DIMENSION(jpi,jpj,jpk,jpt), TARGET, INTENT(inout) :: puu, pvv ! ocean velocities and RHS of momentum equation + REAL(wp), DIMENSION(:,:,:), OPTIONAL, TARGET, INTENT(in ) :: pau, pav, paw ! advective velocity ! INTEGER :: ji, jj, jk ! dummy loop indices - REAL(wp), DIMENSION(A2D(nn_hls),jpk) :: zfu_t, zfu_f, zfu_uw, zfu - REAL(wp), DIMENSION(A2D(nn_hls),jpk) :: zfv_t, zfv_f, zfv_vw, zfv, zfw + REAL(wp) :: zzu, zzv ! local scalars + REAL(wp), DIMENSION(A2D(nn_hls),jpk) :: zfu_t, zfu_f, zfu_uw, zfu + REAL(wp), DIMENSION(A2D(nn_hls),jpk) :: zfv_t, zfv_f, zfv_vw, zfv, zfw + REAL(wp), DIMENSION(:,:,:) , POINTER :: zpt_u, zpt_v, zpt_w !!---------------------------------------------------------------------- ! IF( .NOT. l_istiled .OR. ntile == 1 ) THEN ! Do only on the first tile @@ -68,12 +75,22 @@ CONTAINS zfv_vw(:,:,:) = pvv(:,:,:,Krhs) ENDIF ! + IF( PRESENT( pau ) ) THEN ! RK3: advective velocity (pau,pav,paw) /= advected velocity (puu,pvv,ww) + zpt_u => pau(:,:,:) + zpt_v => pav(:,:,:) + zpt_w => paw(:,:,:) + ELSE ! MLF: advective velocity = (puu,pvv,ww) + zpt_u => puu(:,:,:,Kmm) + zpt_v => pvv(:,:,:,Kmm) + zpt_w => ww (:,:,: ) + ENDIF + ! ! !== Horizontal advection ==! ! DO jk = 1, jpkm1 ! horizontal transport DO_2D( 1, 1, 1, 1 ) - zfu(ji,jj,jk) = 0.25_wp * e2u(ji,jj) * e3u(ji,jj,jk,Kmm) * puu(ji,jj,jk,Kmm) - zfv(ji,jj,jk) = 0.25_wp * e1v(ji,jj) * e3v(ji,jj,jk,Kmm) * pvv(ji,jj,jk,Kmm) + zfu(ji,jj,jk) = 0.25_wp * e2u(ji,jj) * e3u(ji,jj,jk,Kmm) * zpt_u(ji,jj,jk) + zfv(ji,jj,jk) = 0.25_wp * e1v(ji,jj) * e3v(ji,jj,jk,Kmm) * zpt_v(ji,jj,jk) END_2D DO_2D( 1, 0, 1, 0 ) ! horizontal momentum fluxes (at T- and F-point) zfu_t(ji+1,jj ,jk) = ( zfu(ji,jj,jk) + zfu(ji+1,jj,jk) ) * ( puu(ji,jj,jk,Kmm) + puu(ji+1,jj ,jk,Kmm) ) @@ -83,11 +100,11 @@ CONTAINS END_2D DO_2D( 0, 0, 0, 0 ) ! divergence of horizontal momentum fluxes puu(ji,jj,jk,Krhs) = puu(ji,jj,jk,Krhs) - ( zfu_t(ji+1,jj,jk) - zfu_t(ji,jj ,jk) & - & + zfv_f(ji ,jj,jk) - zfv_f(ji,jj-1,jk) ) * r1_e1e2u(ji,jj) & - & / e3u(ji,jj,jk,Kmm) + & + zfv_f(ji ,jj,jk) - zfv_f(ji,jj-1,jk) ) * r1_e1e2u(ji,jj) & + & / e3u(ji,jj,jk,Kmm) pvv(ji,jj,jk,Krhs) = pvv(ji,jj,jk,Krhs) - ( zfu_f(ji,jj ,jk) - zfu_f(ji-1,jj,jk) & - & + zfv_t(ji,jj+1,jk) - zfv_t(ji ,jj,jk) ) * r1_e1e2v(ji,jj) & - & / e3v(ji,jj,jk,Kmm) + & + zfv_t(ji,jj+1,jk) - zfv_t(ji ,jj,jk) ) * r1_e1e2v(ji,jj) & + & / e3v(ji,jj,jk,Kmm) END_2D END DO ! @@ -99,42 +116,57 @@ CONTAINS zfv_t(:,:,:) = pvv(:,:,:,Krhs) ENDIF ! - ! !== Vertical advection ==! - ! - DO_2D( 0, 0, 0, 0 ) ! surface/bottom advective fluxes set to zero - zfu_uw(ji,jj,jpk) = 0._wp ; zfv_vw(ji,jj,jpk) = 0._wp - zfu_uw(ji,jj, 1 ) = 0._wp ; zfv_vw(ji,jj, 1 ) = 0._wp - END_2D - IF( ln_linssh ) THEN ! linear free surface: advection through the surface - DO_2D( 0, 0, 0, 0 ) - zfu_uw(ji,jj,1) = 0.5_wp * ( e1e2t(ji,jj) * ww(ji,jj,1) + e1e2t(ji+1,jj) * ww(ji+1,jj,1) ) * puu(ji,jj,1,Kmm) - zfv_vw(ji,jj,1) = 0.5_wp * ( e1e2t(ji,jj) * ww(ji,jj,1) + e1e2t(ji,jj+1) * ww(ji,jj+1,1) ) * pvv(ji,jj,1,Kmm) - END_2D - ENDIF - DO jk = 2, jpkm1 ! interior advective fluxes - DO_2D( 0, 1, 0, 1 ) ! 1/4 * Vertical transport - zfw(ji,jj,jk) = 0.25_wp * e1e2t(ji,jj) * ww(ji,jj,jk) - END_2D - DO_2D( 0, 0, 0, 0 ) - zfu_uw(ji,jj,jk) = ( zfw(ji,jj,jk) + zfw(ji+1,jj ,jk) ) * ( puu(ji,jj,jk,Kmm) + puu(ji,jj,jk-1,Kmm) ) - zfv_vw(ji,jj,jk) = ( zfw(ji,jj,jk) + zfw(ji ,jj+1,jk) ) * ( pvv(ji,jj,jk,Kmm) + pvv(ji,jj,jk-1,Kmm) ) + IF( PRESENT( no_zad ) ) THEN !== No vertical advection ==! (except if linear free surface) + ! == + IF( ln_linssh ) THEN ! linear free surface: advection through the surface z=0 + DO_2D( 0, 0, 0, 0 ) + zzu = 0.5_wp * ( e1e2t(ji,jj) * zpt_w(ji,jj,1) + e1e2t(ji+1,jj) * zpt_w(ji+1,jj,1) ) * puu(ji,jj,1,Kmm) + zzv = 0.5_wp * ( e1e2t(ji,jj) * zpt_w(ji,jj,1) + e1e2t(ji,jj+1) * zpt_w(ji,jj+1,1) ) * pvv(ji,jj,1,Kmm) + puu(ji,jj,1,Krhs) = puu(ji,jj,1,Krhs) - zzu * r1_e1e2u(ji,jj) & + & / e3u(ji,jj,1,Kmm) + pvv(ji,jj,1,Krhs) = pvv(ji,jj,1,Krhs) - zzv * r1_e1e2v(ji,jj) & + & / e3v(ji,jj,1,Kmm) + END_2D + ENDIF + ! + ELSE !== Vertical advection ==! + ! + DO_2D( 0, 0, 0, 0 ) ! surface/bottom advective fluxes set to zero + zfu_uw(ji,jj,jpk) = 0._wp ; zfv_vw(ji,jj,jpk) = 0._wp + zfu_uw(ji,jj, 1 ) = 0._wp ; zfv_vw(ji,jj, 1 ) = 0._wp END_2D - END DO - DO_3D( 0, 0, 0, 0, 1, jpkm1 ) ! divergence of vertical momentum flux divergence - puu(ji,jj,jk,Krhs) = puu(ji,jj,jk,Krhs) - ( zfu_uw(ji,jj,jk) - zfu_uw(ji,jj,jk+1) ) * r1_e1e2u(ji,jj) & - & / e3u(ji,jj,jk,Kmm) - pvv(ji,jj,jk,Krhs) = pvv(ji,jj,jk,Krhs) - ( zfv_vw(ji,jj,jk) - zfv_vw(ji,jj,jk+1) ) * r1_e1e2v(ji,jj) & - & / e3v(ji,jj,jk,Kmm) - END_3D - ! - IF( l_trddyn ) THEN ! trends: send trend to trddyn for diagnostic - zfu_t(:,:,:) = puu(:,:,:,Krhs) - zfu_t(:,:,:) - zfv_t(:,:,:) = pvv(:,:,:,Krhs) - zfv_t(:,:,:) - CALL trd_dyn( zfu_t, zfv_t, jpdyn_zad, kt, Kmm ) + IF( ln_linssh ) THEN ! linear free surface: advection through the surface z=0 + DO_2D( 0, 0, 0, 0 ) + zfu_uw(ji,jj,1) = 0.5_wp * ( e1e2t(ji,jj) * zpt_w(ji,jj,1) + e1e2t(ji+1,jj) * zpt_w(ji+1,jj,1) ) * puu(ji,jj,1,Kmm) + zfv_vw(ji,jj,1) = 0.5_wp * ( e1e2t(ji,jj) * zpt_w(ji,jj,1) + e1e2t(ji,jj+1) * zpt_w(ji,jj+1,1) ) * pvv(ji,jj,1,Kmm) + END_2D + ENDIF + DO jk = 2, jpkm1 ! interior advective fluxes + DO_2D( 0, 1, 0, 1 ) ! 1/4 * Vertical transport + zfw(ji,jj,jk) = 0.25_wp * e1e2t(ji,jj) * zpt_w(ji,jj,jk) + END_2D + DO_2D( 0, 0, 0, 0 ) + zfu_uw(ji,jj,jk) = ( zfw(ji,jj,jk) + zfw(ji+1,jj ,jk) ) * ( puu(ji,jj,jk,Kmm) + puu(ji,jj,jk-1,Kmm) ) + zfv_vw(ji,jj,jk) = ( zfw(ji,jj,jk) + zfw(ji ,jj+1,jk) ) * ( pvv(ji,jj,jk,Kmm) + pvv(ji,jj,jk-1,Kmm) ) + END_2D + END DO + DO_3D( 0, 0, 0, 0, 1, jpkm1 ) ! divergence of vertical momentum flux divergence + puu(ji,jj,jk,Krhs) = puu(ji,jj,jk,Krhs) - ( zfu_uw(ji,jj,jk) - zfu_uw(ji,jj,jk+1) ) * r1_e1e2u(ji,jj) & + & / e3u(ji,jj,jk,Kmm) + pvv(ji,jj,jk,Krhs) = pvv(ji,jj,jk,Krhs) - ( zfv_vw(ji,jj,jk) - zfv_vw(ji,jj,jk+1) ) * r1_e1e2v(ji,jj) & + & / e3v(ji,jj,jk,Kmm) + END_3D + ! + IF( l_trddyn ) THEN ! trends: send trend to trddyn for diagnostic + zfu_t(:,:,:) = puu(:,:,:,Krhs) - zfu_t(:,:,:) + zfv_t(:,:,:) = pvv(:,:,:,Krhs) - zfv_t(:,:,:) + CALL trd_dyn( zfu_t, zfv_t, jpdyn_zad, kt, Kmm ) + ENDIF + ! ! Control print + IF(sn_cfctl%l_prtctl) CALL prt_ctl( tab3d_1=puu(:,:,:,Krhs), clinfo1=' cen2 adv - Ua: ', mask1=umask, & + & tab3d_2=pvv(:,:,:,Krhs), clinfo2= ' Va: ', mask2=vmask, clinfo3='dyn' ) + ! ENDIF - ! ! Control print - IF(sn_cfctl%l_prtctl) CALL prt_ctl( tab3d_1=puu(:,:,:,Krhs), clinfo1=' cen2 adv - Ua: ', mask1=umask, & - & tab3d_2=pvv(:,:,:,Krhs), clinfo2= ' Va: ', mask2=vmask, clinfo3='dyn' ) ! END SUBROUTINE dyn_adv_cen2 diff --git a/src/OCE/DYN/dynadv_ubs.F90 b/src/OCE/DYN/dynadv_ubs.F90 index 50f73f6d4b899a22e15c51d165f205b7f7329b69..645f6fa800606d41375281e38c4bc077f1a848e8 100644 --- a/src/OCE/DYN/dynadv_ubs.F90 +++ b/src/OCE/DYN/dynadv_ubs.F90 @@ -36,12 +36,12 @@ MODULE dynadv_ubs # include "domzgr_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/OCE 4.0 , NEMO Consortium (2018) - !! $Id: dynadv_ubs.F90 14834 2021-05-11 09:24:44Z hadcv $ + !! $Id: dynadv_ubs.F90 14419 2021-02-09 12:22:16Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS - SUBROUTINE dyn_adv_ubs( kt, Kbb, Kmm, puu, pvv, Krhs ) + SUBROUTINE dyn_adv_ubs( kt, Kbb, Kmm, puu, pvv, Krhs, pau, pav, paw, no_zad ) !!---------------------------------------------------------------------- !! *** ROUTINE dyn_adv_ubs *** !! @@ -64,20 +64,26 @@ CONTAINS !! Default value (hard coded in the begining of the module) are !! gamma1=1/3 and gamma2=1/32. !! - !! ** Action : - (puu(:,:,:,Krhs),pvv(:,:,:,Krhs)) updated with the 3D advective momentum trends + !! In RK3 time stepping case, the optional arguments + !! (pau,pav,paw) are present. They are used as advective velocity + !! while the advected velocity remains (puu,pvv). + !! + !! ** Action : (puu,pvv)(:,:,:,Krhs) updated with the advective trend !! !! Reference : Shchepetkin & McWilliams, 2005, Ocean Modelling. !!---------------------------------------------------------------------- - INTEGER , INTENT( in ) :: kt ! ocean time-step index - INTEGER , INTENT( in ) :: Kbb, Kmm, Krhs ! ocean time level indices - REAL(wp), DIMENSION(jpi,jpj,jpk,jpt), INTENT(inout) :: puu, pvv ! ocean velocities and RHS of momentum equation + INTEGER , INTENT(in ) :: kt , Kbb, Kmm, Krhs ! ocean time-step and level indices + INTEGER , OPTIONAL , INTENT(in ) :: no_zad ! no vertical advection compotation + REAL(wp), DIMENSION(jpi,jpj,jpk,jpt), TARGET, INTENT(inout) :: puu, pvv ! ocean velocities and RHS of momentum equation + REAL(wp), DIMENSION(:,:,:), OPTIONAL, TARGET, INTENT(in ) :: pau, pav, paw ! advective velocity ! INTEGER :: ji, jj, jk ! dummy loop indices - REAL(wp) :: zui, zvj, zfuj, zfvi, zl_u, zl_v ! local scalars + REAL(wp) :: zui, zvj, zfuj, zfvi, zl_u, zl_v, zzu, zzv ! local scalars REAL(wp), DIMENSION(A2D(nn_hls),jpk) :: zfu_t, zfu_f, zfu_uw, zfu REAL(wp), DIMENSION(A2D(nn_hls),jpk) :: zfv_t, zfv_f, zfv_vw, zfv, zfw REAL(wp), DIMENSION(A2D(nn_hls),jpk,2) :: zlu_uu, zlu_uv REAL(wp), DIMENSION(A2D(nn_hls),jpk,2) :: zlv_vv, zlv_vu + REAL(wp), DIMENSION(:,:,:), POINTER :: zpt_u, zpt_v, zpt_w !!---------------------------------------------------------------------- ! IF( .NOT. l_istiled .OR. ntile == 1 ) THEN ! Do only on the first tile @@ -102,13 +108,24 @@ CONTAINS zfu_uw(:,:,:) = puu(:,:,:,Krhs) zfv_vw(:,:,:) = pvv(:,:,:,Krhs) ENDIF + ! + IF( PRESENT( pau ) ) THEN ! RK3: advective velocity (pau,pav,paw) /= advected velocity (puu,pvv,ww) + zpt_u => pau(:,:,:) + zpt_v => pav(:,:,:) + zpt_w => paw(:,:,:) + ELSE ! MLF: advective velocity = (puu,pvv,ww) + zpt_u => puu(:,:,:,Kmm) + zpt_v => pvv(:,:,:,Kmm) + zpt_w => ww (:,:,: ) + ENDIF + ! ! ! =========================== ! DO jk = 1, jpkm1 ! Laplacian of the velocity ! ! ! =========================== ! ! ! horizontal volume fluxes DO_2D( nn_hls, nn_hls, nn_hls, nn_hls ) - zfu(ji,jj,jk) = e2u(ji,jj) * e3u(ji,jj,jk,Kmm) * puu(ji,jj,jk,Kmm) - zfv(ji,jj,jk) = e1v(ji,jj) * e3v(ji,jj,jk,Kmm) * pvv(ji,jj,jk,Kmm) + zfu(ji,jj,jk) = e2u(ji,jj) * e3u(ji,jj,jk,Kmm) * zpt_u(ji,jj,jk) + zfv(ji,jj,jk) = e1v(ji,jj) * e3v(ji,jj,jk,Kmm) * zpt_v(ji,jj,jk) END_2D ! DO_2D( nn_hls-1, nn_hls-1, nn_hls-1, nn_hls-1 ) ! laplacian @@ -157,8 +174,8 @@ CONTAINS DO jk = 1, jpkm1 ! ====================== ! ! ! horizontal volume fluxes DO_2D( 1, 1, 1, 1 ) - zfu(ji,jj,jk) = 0.25_wp * e2u(ji,jj) * e3u(ji,jj,jk,Kmm) * puu(ji,jj,jk,Kmm) - zfv(ji,jj,jk) = 0.25_wp * e1v(ji,jj) * e3v(ji,jj,jk,Kmm) * pvv(ji,jj,jk,Kmm) + zfu(ji,jj,jk) = 0.25_wp * e2u(ji,jj) * e3u(ji,jj,jk,Kmm) * zpt_u(ji,jj,jk) + zfv(ji,jj,jk) = 0.25_wp * e1v(ji,jj) * e3v(ji,jj,jk,Kmm) * zpt_v(ji,jj,jk) END_2D ! DO_2D( 1, 0, 1, 0 ) ! horizontal momentum fluxes at T- and F-point @@ -212,42 +229,62 @@ CONTAINS ! ! ==================== ! ! ! Vertical advection ! ! ! ==================== ! - DO_2D( 0, 0, 0, 0 ) ! surface/bottom advective fluxes set to zero - zfu_uw(ji,jj,jpk) = 0._wp - zfv_vw(ji,jj,jpk) = 0._wp - zfu_uw(ji,jj, 1 ) = 0._wp - zfv_vw(ji,jj, 1 ) = 0._wp - END_2D - IF( ln_linssh ) THEN ! constant volume : advection through the surface - DO_2D( 0, 0, 0, 0 ) - zfu_uw(ji,jj,1) = 0.5_wp * ( e1e2t(ji,jj) * ww(ji,jj,1) + e1e2t(ji+1,jj) * ww(ji+1,jj,1) ) * puu(ji,jj,1,Kmm) - zfv_vw(ji,jj,1) = 0.5_wp * ( e1e2t(ji,jj) * ww(ji,jj,1) + e1e2t(ji,jj+1) * ww(ji,jj+1,1) ) * pvv(ji,jj,1,Kmm) - END_2D - ENDIF - DO jk = 2, jpkm1 ! interior fluxes - DO_2D( 0, 1, 0, 1 ) - zfw(ji,jj,jk) = 0.25_wp * e1e2t(ji,jj) * ww(ji,jj,jk) - END_2D - DO_2D( 0, 0, 0, 0 ) - zfu_uw(ji,jj,jk) = ( zfw(ji,jj,jk)+ zfw(ji+1,jj,jk) ) * ( puu(ji,jj,jk,Kmm) + puu(ji,jj,jk-1,Kmm) ) - zfv_vw(ji,jj,jk) = ( zfw(ji,jj,jk)+ zfw(ji,jj+1,jk) ) * ( pvv(ji,jj,jk,Kmm) + pvv(ji,jj,jk-1,Kmm) ) - END_2D - END DO - DO_3D( 0, 0, 0, 0, 1, jpkm1 ) ! divergence of vertical momentum flux divergence - puu(ji,jj,jk,Krhs) = puu(ji,jj,jk,Krhs) - ( zfu_uw(ji,jj,jk) - zfu_uw(ji,jj,jk+1) ) * r1_e1e2u(ji,jj) & - & / e3u(ji,jj,jk,Kmm) - pvv(ji,jj,jk,Krhs) = pvv(ji,jj,jk,Krhs) - ( zfv_vw(ji,jj,jk) - zfv_vw(ji,jj,jk+1) ) * r1_e1e2v(ji,jj) & - & / e3v(ji,jj,jk,Kmm) - END_3D ! - IF( l_trddyn ) THEN ! save the vertical advection trend for diagnostic - zfu_t(:,:,:) = puu(:,:,:,Krhs) - zfu_t(:,:,:) - zfv_t(:,:,:) = pvv(:,:,:,Krhs) - zfv_t(:,:,:) - CALL trd_dyn( zfu_t, zfv_t, jpdyn_zad, kt, Kmm ) + ! ! ======================== ! + IF( PRESENT( no_zad ) ) THEN ! No vertical advection ! (except if linear free surface) + ! ! ======================== ! ------ + ! + IF( ln_linssh ) THEN ! linear free surface: advection through the surface z=0 + DO_2D( 0, 0, 0, 0 ) + zzu = 0.5_wp * ( e1e2t(ji,jj) * zpt_w(ji,jj,1) + e1e2t(ji+1,jj) * zpt_w(ji+1,jj,1) ) * puu(ji,jj,1,Kmm) + zzv = 0.5_wp * ( e1e2t(ji,jj) * zpt_w(ji,jj,1) + e1e2t(ji,jj+1) * zpt_w(ji,jj+1,1) ) * pvv(ji,jj,1,Kmm) + puu(ji,jj,1,Krhs) = puu(ji,jj,1,Krhs) - zzu * r1_e1e2u(ji,jj) & + & / e3u(ji,jj,1,Kmm) + pvv(ji,jj,1,Krhs) = pvv(ji,jj,1,Krhs) - zzv * r1_e1e2v(ji,jj) & + & / e3v(ji,jj,1,Kmm) + END_2D + ENDIF + ! ! =================== ! + ELSE ! Vertical advection ! + ! ! =================== ! + DO_2D( 0, 0, 0, 0 ) ! surface/bottom advective fluxes set to zero + zfu_uw(ji,jj,jpk) = 0._wp + zfv_vw(ji,jj,jpk) = 0._wp + zfu_uw(ji,jj, 1 ) = 0._wp + zfv_vw(ji,jj, 1 ) = 0._wp + END_2D + IF( ln_linssh ) THEN ! constant volume : advection through the surface + DO_2D( 0, 0, 0, 0 ) + zfu_uw(ji,jj,1) = 0.5_wp * ( e1e2t(ji,jj) * zpt_w(ji,jj,1) + e1e2t(ji+1,jj) * zpt_w(ji+1,jj,1) ) * puu(ji,jj,1,Kmm) + zfv_vw(ji,jj,1) = 0.5_wp * ( e1e2t(ji,jj) * zpt_w(ji,jj,1) + e1e2t(ji,jj+1) * zpt_w(ji,jj+1,1) ) * pvv(ji,jj,1,Kmm) + END_2D + ENDIF + DO jk = 2, jpkm1 ! interior fluxes + DO_2D( 0, 1, 0, 1 ) + zfw(ji,jj,jk) = 0.25_wp * e1e2t(ji,jj) * zpt_w(ji,jj,jk) + END_2D + DO_2D( 0, 0, 0, 0 ) + zfu_uw(ji,jj,jk) = ( zfw(ji,jj,jk)+ zfw(ji+1,jj,jk) ) * ( puu(ji,jj,jk,Kmm) + puu(ji,jj,jk-1,Kmm) ) + zfv_vw(ji,jj,jk) = ( zfw(ji,jj,jk)+ zfw(ji,jj+1,jk) ) * ( pvv(ji,jj,jk,Kmm) + pvv(ji,jj,jk-1,Kmm) ) + END_2D + END DO + DO_3D( 0, 0, 0, 0, 1, jpkm1 ) ! divergence of vertical momentum flux divergence + puu(ji,jj,jk,Krhs) = puu(ji,jj,jk,Krhs) - ( zfu_uw(ji,jj,jk) - zfu_uw(ji,jj,jk+1) ) * r1_e1e2u(ji,jj) & + & / e3u(ji,jj,jk,Kmm) + pvv(ji,jj,jk,Krhs) = pvv(ji,jj,jk,Krhs) - ( zfv_vw(ji,jj,jk) - zfv_vw(ji,jj,jk+1) ) * r1_e1e2v(ji,jj) & + & / e3v(ji,jj,jk,Kmm) + END_3D + ! + IF( l_trddyn ) THEN ! save the vertical advection trend for diagnostic + zfu_t(:,:,:) = puu(:,:,:,Krhs) - zfu_t(:,:,:) + zfv_t(:,:,:) = pvv(:,:,:,Krhs) - zfv_t(:,:,:) + CALL trd_dyn( zfu_t, zfv_t, jpdyn_zad, kt, Kmm ) + ENDIF + ! ! Control print + IF(sn_cfctl%l_prtctl) CALL prt_ctl( tab3d_1=puu(:,:,:,Krhs), clinfo1=' ubs2 adv - Ua: ', mask1=umask, & + & tab3d_2=pvv(:,:,:,Krhs), clinfo2= ' Va: ', mask2=vmask, clinfo3='dyn' ) + ! ENDIF - ! ! Control print - IF(sn_cfctl%l_prtctl) CALL prt_ctl( tab3d_1=puu(:,:,:,Krhs), clinfo1=' ubs2 adv - Ua: ', mask1=umask, & - & tab3d_2=pvv(:,:,:,Krhs), clinfo2= ' Va: ', mask2=vmask, clinfo3='dyn' ) ! END SUBROUTINE dyn_adv_ubs diff --git a/src/OCE/DYN/dynhpg.F90 b/src/OCE/DYN/dynhpg.F90 index b64bc83c7903ba68a67d276b6a808b95e1c0323a..145c7f9e17407167fc54774c8fe282f407e31f8b 100644 --- a/src/OCE/DYN/dynhpg.F90 +++ b/src/OCE/DYN/dynhpg.F90 @@ -83,7 +83,7 @@ MODULE dynhpg !!---------------------------------------------------------------------- !! NEMO/OCE 4.0 , NEMO Consortium (2018) - !! $Id: dynhpg.F90 15529 2021-11-23 15:00:19Z techene $ + !! $Id: dynhpg.F90 15157 2021-07-29 08:28:32Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS diff --git a/src/OCE/DYN/dynspg.F90 b/src/OCE/DYN/dynspg.F90 index 24cd9455acb11a63ad9f8a46392e210eb1f9864d..ffd2219a2eff482503a8e24da3f039df87c80e55 100644 --- a/src/OCE/DYN/dynspg.F90 +++ b/src/OCE/DYN/dynspg.F90 @@ -51,12 +51,12 @@ MODULE dynspg # include "do_loop_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/OCE 4.0 , NEMO Consortium (2018) - !! $Id: dynspg.F90 14225 2020-12-19 14:58:39Z smasson $ + !! $Id: dynspg.F90 14547 2021-02-25 17:07:15Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS - SUBROUTINE dyn_spg( kt, Kbb, Kmm, Krhs, puu, pvv, pssh, puu_b, pvv_b, Kaa, k_only_ADV ) + SUBROUTINE dyn_spg( kt, Kbb, Kmm, Krhs, puu, pvv, pssh, puu_b, pvv_b, Kaa ) !!---------------------------------------------------------------------- !! *** ROUTINE dyn_spg *** !! @@ -78,10 +78,9 @@ CONTAINS INTEGER , INTENT( in ) :: Kbb, Kmm, Krhs, Kaa ! ocean time level indices REAL(wp), DIMENSION(jpi,jpj,jpk,jpt), INTENT(inout) :: puu, pvv ! ocean velocities and RHS of momentum equation REAL(wp), DIMENSION(jpi,jpj,jpt) , INTENT(inout) :: pssh, puu_b, pvv_b ! SSH and barotropic velocities at main time levels - INTEGER , OPTIONAL , INTENT( in ) :: k_only_ADV ! only Advection in the RHS ! INTEGER :: ji, jj, jk ! dummy loop indices - REAL(wp) :: z2dt, zg_2, zintp, zgrho0r, zld ! local scalars + REAL(wp) :: zg_2, zintp, zgrho0r, zld ! local scalars REAL(wp) , DIMENSION(jpi,jpj) :: zpgu, zpgv ! 2D workspace REAL(wp), ALLOCATABLE, DIMENSION(:,:) :: zpice REAL(wp), ALLOCATABLE, DIMENSION(:,:,:) :: ztrdu, ztrdv @@ -150,8 +149,8 @@ CONTAINS ! IF( ln_wave .and. ln_bern_srfc ) THEN !== Add J terms: depth-independent Bernoulli head DO_2D( 0, 0, 0, 0 ) - zpgu(ji,jj) = zpgu(ji,jj) + ( bhd_wave(ji+1,jj) - bhd_wave(ji,jj) ) / e1u(ji,jj) !++ bhd_wave from wave model in m2/s2 [BHD parameters in WW3] - zpgv(ji,jj) = zpgv(ji,jj) + ( bhd_wave(ji,jj+1) - bhd_wave(ji,jj) ) / e2v(ji,jj) + zpgu(ji,jj) = zpgu(ji,jj) + ( bhd_wave(ji+1,jj) - bhd_wave(ji,jj) ) * r1_e1u(ji,jj) !++ bhd_wave from wave model in m2/s2 [BHD parameters in WW3] + zpgv(ji,jj) = zpgv(ji,jj) + ( bhd_wave(ji,jj+1) - bhd_wave(ji,jj) ) * r1_e2v(ji,jj) END_2D ENDIF ! @@ -166,7 +165,7 @@ CONTAINS ! SELECT CASE ( nspg ) !== surface pressure gradient computed and add to the general trend ==! CASE ( np_EXP ) ; CALL dyn_spg_exp( kt, Kmm, puu, pvv, Krhs ) ! explicit - CASE ( np_TS ) ; CALL dyn_spg_ts ( kt, Kbb, Kmm, Krhs, puu, pvv, pssh, puu_b, pvv_b, Kaa, k_only_ADV ) ! time-splitting + CASE ( np_TS ) ; CALL dyn_spg_ts ( kt, Kbb, Kmm, Krhs, puu, pvv, pssh, puu_b, pvv_b, Kaa ) ! time-splitting END SELECT ! IF( l_trddyn ) THEN ! save the surface pressure gradient trends for further diagnostics diff --git a/src/OCE/DYN/dynspg_ts.F90 b/src/OCE/DYN/dynspg_ts.F90 index f8856aedf4774b83c2f8cc215cf73454827f0540..83b2d99cac15b0fec655681371eb81ca929b9064 100644 --- a/src/OCE/DYN/dynspg_ts.F90 +++ b/src/OCE/DYN/dynspg_ts.F90 @@ -67,9 +67,8 @@ MODULE dynspg_ts PUBLIC dyn_spg_ts ! called by dyn_spg PUBLIC dyn_spg_ts_init ! - - dyn_spg_init + PUBLIC dyn_drg_init ! called by stp2d - !! Time filtered arrays at baroclinic time step: - REAL(wp), PUBLIC, ALLOCATABLE, SAVE, DIMENSION(:,:) :: un_adv , vn_adv !: Advection vel. at "now" barocl. step ! INTEGER, SAVE :: icycle ! Number of barotropic sub-steps for each internal step nn_e <= 2.5 nn_e REAL(wp),SAVE :: rDt_e ! Barotropic time step @@ -79,6 +78,10 @@ MODULE dynspg_ts REAL(wp), ALLOCATABLE, SAVE, DIMENSION(:,:) :: ftnw, ftne ! triad of coriolis parameter REAL(wp), ALLOCATABLE, SAVE, DIMENSION(:,:) :: ftsw, ftse ! (only used with een vorticity scheme) + REAL(wp), PUBLIC, ALLOCATABLE, SAVE, DIMENSION(:,:) :: sshe_rhs ! RHS of ssh Eq. + REAL(wp), PUBLIC, ALLOCATABLE, SAVE, DIMENSION(:,:) :: Ue_rhs, Ve_rhs ! RHS of barotropic velocity Eq. + REAL(wp), PUBLIC, ALLOCATABLE, SAVE, DIMENSION(:,:) :: CdU_u, CdU_v ! top/bottom stress at u- & v-points + REAL(wp) :: r1_12 = 1._wp / 12._wp ! local ratios REAL(wp) :: r1_8 = 0.125_wp ! REAL(wp) :: r1_4 = 0.25_wp ! @@ -89,7 +92,7 @@ MODULE dynspg_ts # include "domzgr_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/OCE 4.0 , NEMO Consortium (2018) - !! $Id: dynspg_ts.F90 15489 2021-11-10 09:18:39Z jchanut $ + !! $Id: dynspg_ts.F90 14747 2021-04-26 08:47:14Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS @@ -98,7 +101,7 @@ CONTAINS !!---------------------------------------------------------------------- !! *** routine dyn_spg_ts_alloc *** !!---------------------------------------------------------------------- - INTEGER :: ierr(3) + INTEGER :: ierr(2) !!---------------------------------------------------------------------- ierr(:) = 0 ! @@ -106,7 +109,6 @@ CONTAINS IF( ln_dynvor_een .OR. ln_dynvor_eeT ) & & ALLOCATE( ftnw(jpi,jpj) , ftne(jpi,jpj) , ftsw(jpi,jpj) , ftse(jpi,jpj), STAT=ierr(2) ) ! - ALLOCATE( un_adv(jpi,jpj), vn_adv(jpi,jpj) , STAT=ierr(3) ) ! dyn_spg_ts_alloc = MAXVAL( ierr(:) ) ! @@ -116,7 +118,7 @@ CONTAINS END FUNCTION dyn_spg_ts_alloc - SUBROUTINE dyn_spg_ts( kt, Kbb, Kmm, Krhs, puu, pvv, pssh, puu_b, pvv_b, Kaa, k_only_ADV ) + SUBROUTINE dyn_spg_ts( kt, Kbb, Kmm, Krhs, puu, pvv, pssh, puu_b, pvv_b, Kaa ) !!---------------------------------------------------------------------- !! !! ** Purpose : - Compute the now trend due to the explicit time stepping @@ -144,27 +146,24 @@ CONTAINS INTEGER , INTENT( in ) :: kt ! ocean time-step index INTEGER , INTENT( in ) :: Kbb, Kmm, Krhs, Kaa ! ocean time level indices REAL(wp), DIMENSION(jpi,jpj,jpk,jpt), INTENT(inout) :: puu, pvv ! ocean velocities and RHS of momentum equation - REAL(wp), DIMENSION(jpi,jpj,jpt) , INTENT(inout) :: pssh, puu_b, pvv_b ! SSH and barotropic velocities at main time levels - INTEGER , OPTIONAL , INTENT( in ) :: k_only_ADV ! only Advection in the RHS + REAL(wp), DIMENSION(jpi,jpj ,jpt), INTENT(inout) :: pssh, puu_b, pvv_b ! SSH and barotropic velocities at main time levels ! INTEGER :: ji, jj, jk, jn ! dummy loop indices LOGICAL :: ll_fw_start ! =T : forward integration LOGICAL :: ll_init ! =T : special startup of 2d equations INTEGER :: noffset ! local integers : time offset for bdy update - REAL(wp) :: r1_Dt_b, z1_hu, z1_hv ! local scalars - REAL(wp) :: za0, za1, za2, za3 ! - - + REAL(wp) :: z1_hu , z1_hv ! local scalars + REAL(wp) :: zzsshu, zzsshv ! - - + REAL(wp) :: za0, za1, za2, za3 ! - - REAL(wp) :: zztmp, zldg ! - - - REAL(wp) :: zhu_bck, zhv_bck, zhdiv ! - - - REAL(wp) :: zun_save, zvn_save ! - - - REAL(wp), DIMENSION(jpi,jpj) :: zu_trd, zu_frc, zu_spg + REAL(wp) :: zhu_bck, zhv_bck, zhdiv ! - - + REAL(wp) :: zun_save, zvn_save ! - - + REAL(wp), DIMENSION(jpi,jpj) :: zu_trd, zu_frc, zu_spg !!st tests , zssh_frc REAL(wp), DIMENSION(jpi,jpj) :: zv_trd, zv_frc, zv_spg REAL(wp), DIMENSION(jpi,jpj) :: zsshu_a, zhup2_e, zhtp2_e REAL(wp), DIMENSION(jpi,jpj) :: zsshv_a, zhvp2_e, zsshp2_e REAL(wp), DIMENSION(jpi,jpj) :: zCdU_u, zCdU_v ! top/bottom stress at u- & v-points REAL(wp), DIMENSION(jpi,jpj) :: zhU, zhV ! fluxes -!!st#if defined key_qco -!!st REAL(wp), DIMENSION(jpi, jpj, jpk) :: ze3u, ze3v -!!st#endif ! REAL(wp) :: zwdramp ! local scalar - only used if ln_wd_dl = .True. @@ -174,6 +173,7 @@ CONTAINS REAL(wp), ALLOCATABLE, DIMENSION(:,:) :: zcpx, zcpy ! Wetting/Dying gravity filter coef. REAL(wp), ALLOCATABLE, DIMENSION(:,:) :: ztwdmask, zuwdmask, zvwdmask ! ROMS wetting and drying masks at t,u,v points REAL(wp), ALLOCATABLE, DIMENSION(:,:) :: zuwdav2, zvwdav2 ! averages over the sub-steps of zuwdmask and zvwdmask + REAL(wp), ALLOCATABLE, DIMENSION(:,:) :: z2d ! 2D workspace REAL(wp) :: zt0substep ! Time of day at the beginning of the time substep !!---------------------------------------------------------------------- ! @@ -184,7 +184,6 @@ CONTAINS zwdramp = r_rn_wdmin1 ! simplest ramp ! zwdramp = 1._wp / (rn_wdmin2 - rn_wdmin1) ! more general ramp ! ! inverse of baroclinic time step - r1_Dt_b = 1._wp / rDt ! ll_init = ln_bt_av ! if no time averaging, then no specific restart ll_fw_start = .FALSE. @@ -227,17 +226,58 @@ CONTAINS ! ----------------------------------------------------------------------------- ! Phase 1 : Coupling between general trend and barotropic estimates (1st step) ! ----------------------------------------------------------------------------- +#if defined key_RK3 + ! !========================================! + ! !== Phase 1 for RK3 time integration ==! + ! !========================================! + ! + ! ! Currently, RK3 requires the forward mode + IF( kt == nit000 ) THEN + IF( .NOT.ln_bt_fw ) CALL ctl_stop( 'dyn_spg_ts: RK3 requires forward mode (ln_bt_fw=T)' ) + ENDIF + ! + ! ! set values computed in RK3_ssh + ssh_frc(:,:) = sshe_rhs(:,:) + zu_frc(:,:) = Ue_rhs(:,:) + zv_frc(:,:) = Ve_rhs(:,:) + zCdU_u (:,:) = CdU_u (:,:) + zCdU_v (:,:) = CdU_v (:,:) + +!!gm ==>>> !!ts ISSUe her on en discute changer les cas ENS ENE et triad ? + ! + ! != remove 2D Coriolis trend =! + ! ! -------------------------- ! + ! + IF( kt == nit000 .OR. .NOT. ln_linssh ) CALL dyn_cor_2D_init( Kmm ) ! Set zwz, the barotropic Coriolis force coefficient + ! ! recompute zwz = f/depth at every time step for (.NOT.ln_linssh) as the water colomn height changes + ! + zhU(:,:) = puu_b(:,:,Kmm) * hu(:,:,Kmm) * e2u(:,:) ! now fluxes + zhV(:,:) = pvv_b(:,:,Kmm) * hv(:,:,Kmm) * e1v(:,:) ! NB: FULL domain : put a value in last row and column + ! + CALL dyn_cor_2D( ht(:,:), hu(:,:,Kmm), hv(:,:,Kmm), puu_b(:,:,Kmm), pvv_b(:,:,Kmm), zhU, zhV, & ! <<== in + & zu_trd, zv_trd ) ! ==>> out + ! + DO_2D( 0, 0, 0, 0 ) ! Remove coriolis term (and possibly spg) from barotropic trend + zu_frc(ji,jj) = zu_frc(ji,jj) - zu_trd(ji,jj) * ssumask(ji,jj) + zv_frc(ji,jj) = zv_frc(ji,jj) - zv_trd(ji,jj) * ssvmask(ji,jj) + END_2D + +#else + ! !========================================! + ! !== Phase 1 for MLF time integration ==! + ! !========================================! + ! ! ! ! != zu_frc = 1/H e3*d/dt(Ua) =! (Vertical mean of Ua, the 3D trends) ! ! --------------------------- ! -#if defined key_qco +# if defined key_qco zu_frc(:,:) = SUM( e3u_0(:,:,: ) * puu(:,:,:,Krhs) * umask(:,:,:), DIM=3 ) * r1_hu_0(:,:) zv_frc(:,:) = SUM( e3v_0(:,:,: ) * pvv(:,:,:,Krhs) * vmask(:,:,:), DIM=3 ) * r1_hv_0(:,:) -#else +# else zu_frc(:,:) = SUM( e3u(:,:,:,Kmm) * puu(:,:,:,Krhs) * umask(:,:,:), DIM=3 ) * r1_hu(:,:,Kmm) zv_frc(:,:) = SUM( e3v(:,:,:,Kmm) * pvv(:,:,:,Krhs) * vmask(:,:,:), DIM=3 ) * r1_hv(:,:,Kmm) -#endif +# endif ! ! ! != U(Krhs) => baroclinic trend =! (remove its vertical mean) @@ -255,29 +295,21 @@ CONTAINS IF( kt == nit000 .OR. .NOT. ln_linssh ) CALL dyn_cor_2D_init( Kmm ) ! Set zwz, the barotropic Coriolis force coefficient ! ! recompute zwz = f/depth at every time step for (.NOT.ln_linssh) as the water colomn height changes ! - IF( .NOT. PRESENT(k_only_ADV) ) THEN !* remove the 2D Coriolis trend - zhU(:,:) = puu_b(:,:,Kmm) * hu(:,:,Kmm) * e2u(:,:) ! now fluxes - zhV(:,:) = pvv_b(:,:,Kmm) * hv(:,:,Kmm) * e1v(:,:) ! NB: FULL domain : put a value in last row and column - ! - CALL dyn_cor_2d( ht(:,:), hu(:,:,Kmm), hv(:,:,Kmm), puu_b(:,:,Kmm), pvv_b(:,:,Kmm), zhU, zhV, & ! <<== in - & zu_trd, zv_trd ) ! ==>> out - ! - DO_2D( 0, 0, 0, 0 ) ! Remove coriolis term (and possibly spg) from barotropic trend - zu_frc(ji,jj) = zu_frc(ji,jj) - zu_trd(ji,jj) * ssumask(ji,jj) - zv_frc(ji,jj) = zv_frc(ji,jj) - zv_trd(ji,jj) * ssvmask(ji,jj) - END_2D - ENDIF + zhU(:,:) = puu_b(:,:,Kmm) * hu(:,:,Kmm) * e2u(:,:) ! now fluxes + zhV(:,:) = pvv_b(:,:,Kmm) * hv(:,:,Kmm) * e1v(:,:) ! NB: FULL domain : put a value in last row and column + ! + CALL dyn_cor_2D( ht(:,:), hu(:,:,Kmm), hv(:,:,Kmm), puu_b(:,:,Kmm), pvv_b(:,:,Kmm), zhU, zhV, & ! <<== in + & zu_trd, zv_trd ) ! ==>> out + ! + DO_2D( 0, 0, 0, 0 ) ! Remove coriolis term (and possibly spg) from barotropic trend + zu_frc(ji,jj) = zu_frc(ji,jj) - zu_trd(ji,jj) * ssumask(ji,jj) + zv_frc(ji,jj) = zv_frc(ji,jj) - zv_trd(ji,jj) * ssvmask(ji,jj) + END_2D ! ! != Add bottom stress contribution from baroclinic velocities =! ! ! ----------------------------------------------------------- ! - IF( PRESENT(k_only_ADV) ) THEN !* only Advection in the RHS : provide the barotropic bottom drag coefficients - DO_2D( 0, 0, 0, 0 ) - zCdU_u(ji,jj) = r1_2*( rCdU_bot(ji+1,jj)+rCdU_bot(ji,jj) ) - zCdU_v(ji,jj) = r1_2*( rCdU_bot(ji,jj+1)+rCdU_bot(ji,jj) ) - END_2D - ELSE !* remove baroclinic drag AND provide the barotropic drag coefficients - CALL dyn_drg_init( Kbb, Kmm, puu, pvv, puu_b, pvv_b, zu_frc, zv_frc, zCdU_u, zCdU_v ) - ENDIF + CALL dyn_drg_init( Kbb, Kmm, puu , pvv , puu_b , pvv_b , & ! <<= IN + & zu_frc, zv_frc, zCdU_u, zCdU_v ) ! =>> OUT ! ! != Add atmospheric pressure forcing =! ! ! ---------------------------------- ! @@ -313,9 +345,9 @@ CONTAINS END_2D ENDIF ! - ! !----------------! - ! !== sssh_frc ==! Right-Hand-Side of the barotropic ssh equation (over the FULL domain) - ! !----------------! + ! !---------------! + ! !== ssh_frc ==! Right-Hand-Side of the barotropic ssh equation (over the FULL domain) + ! !---------------! ! != Net water flux forcing applied to a water column =! ! ! --------------------------------------------------- ! IF (ln_bt_fw) THEN ! FORWARD integration: use kt+1/2 fluxes (NOW+1/2) @@ -347,13 +379,18 @@ CONTAINS ! END IF ! -#if defined key_asminc +# if defined key_asminc ! != Add the IAU weighted SSH increment =! ! ! ------------------------------------ ! IF( lk_asminc .AND. ln_sshinc .AND. ln_asmiau ) THEN ssh_frc(:,:) = ssh_frc(:,:) - ssh_iau(:,:) ENDIF +# endif + + ! !== END of Phase 1 for MLF time integration ==! #endif + + ! != Fill boundary data arrays for AGRIF ! ! ------------------------------------ #if defined key_agrif @@ -383,7 +420,8 @@ CONTAINS zhtp2_e(:,:) = ht_0(:,:) ENDIF ! - IF( ln_bt_fw ) THEN ! FORWARD integration: start from NOW fields + IF( ln_bt_fw ) THEN ! FORWARD integration: start from NOW fields + ! ! RK3: Kmm = Kbb when calling dynspg_ts sshn_e(:,:) = pssh (:,:,Kmm) un_e (:,:) = puu_b(:,:,Kmm) vn_e (:,:) = pvv_b(:,:,Kmm) @@ -596,7 +634,7 @@ CONTAINS ! zwz array below or triads normally depend on sea level with ln_linssh=F and should be updated ! at each time step. We however keep them constant here for optimization. ! Recall that zhU and zhV hold fluxes at jn+0.5 (extrapolated not backward interpolated) - CALL dyn_cor_2d( zhtp2_e, zhup2_e, zhvp2_e, ua_e, va_e, zhU, zhV, zu_trd, zv_trd ) + CALL dyn_cor_2D( zhtp2_e, zhup2_e, zhvp2_e, ua_e, va_e, zhU, zhV, zu_trd, zv_trd ) ! ! Add tidal astronomical forcing if defined IF ( ln_tide .AND. ln_tide_pot ) THEN @@ -712,34 +750,90 @@ CONTAINS sshbb_e(:,:) = sshb_e(:,:) sshb_e (:,:) = sshn_e(:,:) sshn_e (:,:) = ssha_e(:,:) - - ! !* Sum over whole bt loop + ! + ! !* Sum over whole bt loop (except in weight average) ! ! ---------------------- - za1 = wgtbtp1(jn) - IF( ln_dynadv_vec .OR. ln_linssh ) THEN ! Sum velocities - puu_b (:,:,Kaa) = puu_b (:,:,Kaa) + za1 * ua_e (:,:) - pvv_b (:,:,Kaa) = pvv_b (:,:,Kaa) + za1 * va_e (:,:) - ELSE ! Sum transports - IF ( .NOT.ln_wd_dl ) THEN - puu_b (:,:,Kaa) = puu_b (:,:,Kaa) + za1 * ua_e (:,:) * hu_e (:,:) - pvv_b (:,:,Kaa) = pvv_b (:,:,Kaa) + za1 * va_e (:,:) * hv_e (:,:) - ELSE - puu_b (:,:,Kaa) = puu_b (:,:,Kaa) + za1 * ua_e (:,:) * hu_e (:,:) * zuwdmask(:,:) - pvv_b (:,:,Kaa) = pvv_b (:,:,Kaa) + za1 * va_e (:,:) * hv_e (:,:) * zvwdmask(:,:) - END IF + IF( ln_bt_av ) THEN + za1 = wgtbtp1(jn) + IF( ln_dynadv_vec .OR. ln_linssh ) THEN ! Sum velocities + puu_b (:,:,Kaa) = puu_b (:,:,Kaa) + za1 * ua_e (:,:) + pvv_b (:,:,Kaa) = pvv_b (:,:,Kaa) + za1 * va_e (:,:) + ELSE ! Sum transports + IF ( .NOT.ln_wd_dl ) THEN + puu_b (:,:,Kaa) = puu_b (:,:,Kaa) + za1 * ua_e (:,:) * hu_e (:,:) + pvv_b (:,:,Kaa) = pvv_b (:,:,Kaa) + za1 * va_e (:,:) * hv_e (:,:) + ELSE + puu_b (:,:,Kaa) = puu_b (:,:,Kaa) + za1 * ua_e (:,:) * hu_e (:,:) * zuwdmask(:,:) + pvv_b (:,:,Kaa) = pvv_b (:,:,Kaa) + za1 * va_e (:,:) * hv_e (:,:) * zvwdmask(:,:) + ENDIF + ENDIF + ! ! Sum sea level + pssh(:,:,Kaa) = pssh(:,:,Kaa) + za1 * ssha_e(:,:) ENDIF - ! ! Sum sea level - pssh(:,:,Kaa) = pssh(:,:,Kaa) + za1 * ssha_e(:,:) - + ! ! ! ==================== ! END DO ! end loop ! ! ! ==================== ! + + ! ----------------------------------------------------------------------------- ! Phase 3. update the general trend with the barotropic trend ! ----------------------------------------------------------------------------- ! - ! Set advection velocity correction: - IF (ln_bt_fw) THEN + IF(.NOT.ln_bt_av ) THEN !* Update Kaa barotropic external mode + puu_b(:,:,Kaa) = ua_e (:,:) + pvv_b(:,:,Kaa) = va_e (:,:) + pssh (:,:,Kaa) = ssha_e(:,:) + ENDIF + +#if defined key_RK3 + ! !* RK3 case + ! + IF(.NOT.ln_dynadv_vec .AND. ln_bt_av ) THEN ! at this stage, pssh(:,:,:,Krhs) has been corrected: compute new depths at velocity points + ! +# if defined key_qcoTest_FluxForm + ! ! 'key_qcoTest_FluxForm' : simple ssh average + DO_2D( 0, 0, 0, 0 ) + zzsshu = r1_2 * ( pssh(ji,jj,Kaa) + pssh(ji+1,jj ,Kaa) ) * ssumask(ji,jj) + zzsshv = r1_2 * ( pssh(ji,jj,Kaa) + pssh(ji ,jj+1,Kaa) ) * ssvmask(ji,jj) + ! + ! ! Save barotropic velocities (not transport) + puu_b(ji,jj,Kaa) = puu_b(ji,jj,Kaa) / ( hu_0(ji,jj) + zzsshu + 1._wp - ssumask(ji,jj) ) + pvv_b(ji,jj,Kaa) = pvv_b(ji,jj,Kaa) / ( hv_0(ji,jj) + zzsshv + 1._wp - ssvmask(ji,jj) ) + END_2D +# else + DO_2D( 0, 0, 0, 0 ) + zzsshu = r1_2 * r1_e1e2u(ji,jj) * ( e1e2t(ji ,jj) * pssh(ji ,jj,Kaa) & + & + e1e2t(ji+1,jj) * pssh(ji+1,jj,Kaa) ) * ssumask(ji,jj) + zzsshv = r1_2 * r1_e1e2v(ji,jj) * ( e1e2t(ji,jj ) * pssh(ji,jj ,Kaa) & + & + e1e2t(ji,jj+1) * pssh(ji,jj+1,Kaa) ) * ssvmask(ji,jj) + ! + ! ! Save barotropic velocities (not transport) + puu_b(ji,jj,Kaa) = puu_b(ji,jj,Kaa) / ( hu_0(ji,jj) + zzsshu + 1._wp - ssumask(ji,jj) ) + pvv_b(ji,jj,Kaa) = pvv_b(ji,jj,Kaa) / ( hv_0(ji,jj) + zzsshv + 1._wp - ssvmask(ji,jj) ) + END_2D +# endif + ! + CALL lbc_lnk( 'dynspg_ts', puu_b, 'U', -1._wp, pvv_b, 'V', -1._wp ) ! Boundary conditions + ! + ENDIF + ! + IF( iom_use("ubar") ) THEN ! RK3 single first: hu[N+1/2] = 1/2 ( hu[N] + hu[N+1] ) + ALLOCATE( z2d(jpi,jpj) ) + z2d(:,:) = 2._wp / ( hu_e(:,:) + hu(:,:,Kbb) + 1._wp - ssumask(:,:) ) + CALL iom_put( "ubar", un_adv(:,:)*z2d(:,:) ) ! barotropic i-current + z2d(:,:) = 2._wp / ( hv_e(:,:) + hv(:,:,Kbb) + 1._wp - ssvmask(:,:) ) + CALL iom_put( "vbar", vn_adv(:,:)*z2d(:,:) ) ! barotropic i-current + DEALLOCATE( z2d ) + ENDIF + ! + ! !== END Phase 3 for RK3 (forward mode) ==! + +#else + ! !* MLF case + ! + ! Set advective velocity correction: + IF( ln_bt_fw ) THEN IF( .NOT.( kt == nit000 .AND. l_1st_euler ) ) THEN DO_2D( nn_hls, nn_hls, nn_hls, nn_hls ) zun_save = un_adv(ji,jj) @@ -759,44 +853,53 @@ CONTAINS vn_bf(:,:) = 0._wp ub2_b(:,:) = un_adv(:,:) ! Save integrated transport for next computation vb2_b(:,:) = vn_adv(:,:) - END IF + ENDIF ENDIF - - ! ! Update barotropic trend: IF( ln_dynadv_vec .OR. ln_linssh ) THEN DO jk=1,jpkm1 - puu(:,:,jk,Krhs) = puu(:,:,jk,Krhs) + ( puu_b(:,:,Kaa) - puu_b(:,:,Kbb) ) * r1_Dt_b - pvv(:,:,jk,Krhs) = pvv(:,:,jk,Krhs) + ( pvv_b(:,:,Kaa) - pvv_b(:,:,Kbb) ) * r1_Dt_b + puu(:,:,jk,Krhs) = puu(:,:,jk,Krhs) + ( puu_b(:,:,Kaa) - puu_b(:,:,Kbb) ) * r1_Dt + pvv(:,:,jk,Krhs) = pvv(:,:,jk,Krhs) + ( pvv_b(:,:,Kaa) - pvv_b(:,:,Kbb) ) * r1_Dt END DO ELSE - ! At this stage, pssh(:,:,:,Krhs) has been corrected: compute new depths at velocity points -#if defined key_qcoTest_FluxForm - ! ! 'key_qcoTest_FluxForm' : simple ssh average - DO_2D( 1, 0, 1, 0 ) - zsshu_a(ji,jj) = r1_2 * ( pssh(ji,jj,Kaa) + pssh(ji+1,jj ,Kaa) ) * ssumask(ji,jj) - zsshv_a(ji,jj) = r1_2 * ( pssh(ji,jj,Kaa) + pssh(ji ,jj+1,Kaa) ) * ssvmask(ji,jj) - END_2D -#else - DO_2D( 1, 0, 1, 0 ) - zsshu_a(ji,jj) = r1_2 * r1_e1e2u(ji,jj) * ( e1e2t(ji ,jj) * pssh(ji ,jj,Kaa) & - & + e1e2t(ji+1,jj) * pssh(ji+1,jj,Kaa) ) * ssumask(ji,jj) - zsshv_a(ji,jj) = r1_2 * r1_e1e2v(ji,jj) * ( e1e2t(ji,jj ) * pssh(ji,jj ,Kaa) & - & + e1e2t(ji,jj+1) * pssh(ji,jj+1,Kaa) ) * ssvmask(ji,jj) - END_2D -#endif - CALL lbc_lnk( 'dynspg_ts', zsshu_a, 'U', 1._wp, zsshv_a, 'V', 1._wp ) ! Boundary conditions - ! - DO jk=1,jpkm1 - puu(:,:,jk,Krhs) = puu(:,:,jk,Krhs) + r1_hu(:,:,Kmm) & - & * ( puu_b(:,:,Kaa) - puu_b(:,:,Kbb) * hu(:,:,Kbb) ) * r1_Dt_b - pvv(:,:,jk,Krhs) = pvv(:,:,jk,Krhs) + r1_hv(:,:,Kmm) & - & * ( pvv_b(:,:,Kaa) - pvv_b(:,:,Kbb) * hv(:,:,Kbb) ) * r1_Dt_b - END DO - ! Save barotropic velocities not transport: - puu_b(:,:,Kaa) = puu_b(:,:,Kaa) / ( hu_0(:,:) + zsshu_a(:,:) + 1._wp - ssumask(:,:) ) - pvv_b(:,:,Kaa) = pvv_b(:,:,Kaa) / ( hv_0(:,:) + zsshv_a(:,:) + 1._wp - ssvmask(:,:) ) + IF(.NOT.ln_bt_av ) THEN ! (puu_b,pvv_b)_Kaa is a velocity (hu,hv)_Kaa = (hu_e,hv_e) + ! + DO jk=1,jpkm1 + puu(:,:,jk,Krhs) = puu(:,:,jk,Krhs) + r1_hu(:,:,Kmm) & + & * ( puu_b(:,:,Kaa)*hu_e(:,:) - puu_b(:,:,Kbb) * hu(:,:,Kbb) ) * r1_Dt + pvv(:,:,jk,Krhs) = pvv(:,:,jk,Krhs) + r1_hv(:,:,Kmm) & + & * ( pvv_b(:,:,Kaa)*hv_e(:,:) - pvv_b(:,:,Kbb) * hv(:,:,Kbb) ) * r1_Dt + END DO + ! + ELSE ! at this stage, pssh(:,:,:,Krhs) has been corrected: compute new depths at velocity points + ! +# if defined key_qcoTest_FluxForm + ! ! 'key_qcoTest_FluxForm' : simple ssh average + DO_2D( 1, 0, 1, 0 ) + zsshu_a(ji,jj) = r1_2 * ( pssh(ji,jj,Kaa) + pssh(ji+1,jj ,Kaa) ) * ssumask(ji,jj) + zsshv_a(ji,jj) = r1_2 * ( pssh(ji,jj,Kaa) + pssh(ji ,jj+1,Kaa) ) * ssvmask(ji,jj) + END_2D +# else + DO_2D( 1, 0, 1, 0 ) + zsshu_a(ji,jj) = r1_2 * r1_e1e2u(ji,jj) * ( e1e2t(ji ,jj) * pssh(ji ,jj,Kaa) & + & + e1e2t(ji+1,jj) * pssh(ji+1,jj,Kaa) ) * ssumask(ji,jj) + zsshv_a(ji,jj) = r1_2 * r1_e1e2v(ji,jj) * ( e1e2t(ji,jj ) * pssh(ji,jj ,Kaa) & + & + e1e2t(ji,jj+1) * pssh(ji,jj+1,Kaa) ) * ssvmask(ji,jj) + END_2D +# endif + CALL lbc_lnk( 'dynspg_ts', zsshu_a, 'U', 1._wp, zsshv_a, 'V', 1._wp ) ! Boundary conditions + ! + DO jk=1,jpkm1 + puu(:,:,jk,Krhs) = puu(:,:,jk,Krhs) + r1_hu(:,:,Kmm) & + & * ( puu_b(:,:,Kaa) - puu_b(:,:,Kbb) * hu(:,:,Kbb) ) * r1_Dt + pvv(:,:,jk,Krhs) = pvv(:,:,jk,Krhs) + r1_hv(:,:,Kmm) & + & * ( pvv_b(:,:,Kaa) - pvv_b(:,:,Kbb) * hv(:,:,Kbb) ) * r1_Dt + END DO + ! Save barotropic velocities not transport: + puu_b(:,:,Kaa) = puu_b(:,:,Kaa) / ( hu_0(:,:) + zsshu_a(:,:) + 1._wp - ssumask(:,:) ) + pvv_b(:,:,Kaa) = pvv_b(:,:,Kaa) / ( hv_0(:,:) + zsshv_a(:,:) + 1._wp - ssvmask(:,:) ) + ENDIF ENDIF @@ -806,36 +909,46 @@ CONTAINS pvv(:,:,jk,Kmm) = ( pvv(:,:,jk,Kmm) + vn_adv(:,:)*r1_hv(:,:,Kmm) - pvv_b(:,:,Kmm) ) * vmask(:,:,jk) END DO - IF ( ln_wd_dl .and. ln_wd_dl_bc) THEN + IF( ln_wd_dl .AND. ln_wd_dl_bc) THEN DO jk = 1, jpkm1 puu(:,:,jk,Kmm) = ( un_adv(:,:)*r1_hu(:,:,Kmm) & - & + zuwdav2(:,:)*(puu(:,:,jk,Kmm) - un_adv(:,:)*r1_hu(:,:,Kmm)) ) * umask(:,:,jk) + & + zuwdav2(:,:)*(puu(:,:,jk,Kmm) - un_adv(:,:)*r1_hu(:,:,Kmm)) ) * umask(:,:,jk) pvv(:,:,jk,Kmm) = ( vn_adv(:,:)*r1_hv(:,:,Kmm) & - & + zvwdav2(:,:)*(pvv(:,:,jk,Kmm) - vn_adv(:,:)*r1_hv(:,:,Kmm)) ) * vmask(:,:,jk) + & + zvwdav2(:,:)*(pvv(:,:,jk,Kmm) - vn_adv(:,:)*r1_hv(:,:,Kmm)) ) * vmask(:,:,jk) END DO - END IF - - + ENDIF + CALL iom_put( "ubar", un_adv(:,:)*r1_hu(:,:,Kmm) ) ! barotropic i-current - CALL iom_put( "vbar", vn_adv(:,:)*r1_hv(:,:,Kmm) ) ! barotropic i-current + CALL iom_put( "vbar", vn_adv(:,:)*r1_hv(:,:,Kmm) ) ! barotropic j-current + + ! !== END Phase 3 for MLF time integration ==! +#endif + ! #if defined key_agrif + ! ! Save time integrated fluxes during child grid integration ! (used to update coarse grid transports at next time step) ! - IF( .NOT.Agrif_Root() .AND. ln_bt_fw .AND. ln_agrif_2way ) THEN + IF( .NOT.Agrif_Root() .AND. ln_agrif_2way ) THEN IF( Agrif_NbStepint() == 0 ) THEN ub2_i_b(:,:) = 0._wp vb2_i_b(:,:) = 0._wp END IF ! za1 = 1._wp / REAL(Agrif_rhot(), wp) +# if defined key_RK3 + ub2_i_b(:,:) = ub2_i_b(:,:) + za1 * un_adv(:,:) + vb2_i_b(:,:) = vb2_i_b(:,:) + za1 * vn_adv(:,:) +# else ub2_i_b(:,:) = ub2_i_b(:,:) + za1 * ub2_b(:,:) vb2_i_b(:,:) = vb2_i_b(:,:) + za1 * vb2_b(:,:) + +# endif ENDIF -#endif - ! !* write time-spliting arrays in the restart - IF( lrst_oce .AND.ln_bt_fw ) CALL ts_rst( kt, 'WRITE' ) +#endif + ! !: write time-spliting arrays in the restart + IF( lrst_oce ) CALL ts_rst( kt, 'WRITE' ) ! IF( ln_wd_il ) DEALLOCATE( zcpx, zcpy ) IF( ln_wd_dl ) DEALLOCATE( ztwdmask, zuwdmask, zvwdmask, zuwdav2, zvwdav2 ) @@ -845,80 +958,80 @@ CONTAINS ! END SUBROUTINE dyn_spg_ts - - SUBROUTINE ts_wgt( ll_av, ll_fw, jpit, zwgt1, zwgt2) + + SUBROUTINE ts_wgt( ll_av, ll_fw, Kpit, zwgt1, zwgt2) !!--------------------------------------------------------------------- !! *** ROUTINE ts_wgt *** !! !! ** Purpose : Set time-splitting weights for temporal averaging (or not) !!---------------------------------------------------------------------- - LOGICAL, INTENT(in) :: ll_av ! temporal averaging=.true. - LOGICAL, INTENT(in) :: ll_fw ! forward time splitting =.true. - INTEGER, INTENT(inout) :: jpit ! cycle length - REAL(wp), DIMENSION(3*nn_e), INTENT(inout) :: zwgt1, & ! Primary weights - zwgt2 ! Secondary weights - - INTEGER :: jic, jn, ji ! temporary integers - REAL(wp) :: za1, za2 + LOGICAL, INTENT(in ) :: ll_av ! temporal averaging=.true. + LOGICAL, INTENT(in ) :: ll_fw ! forward time splitting =.true. + INTEGER, INTENT(inout) :: Kpit ! cycle length + !! + INTEGER :: jic, jn, ji ! local integers + REAL(wp) :: za1, za2 ! loca scalars + REAL(wp), DIMENSION(3*nn_e), INTENT(inout) :: zwgt1, zwgt2 ! Primary & Secondary weights !!---------------------------------------------------------------------- - + ! zwgt1(:) = 0._wp zwgt2(:) = 0._wp - - ! Set time index when averaged value is requested - IF (ll_fw) THEN - jic = nn_e - ELSE - jic = 2 * nn_e + ! + ! !== Set time index when averaged value is requested ==! + IF (ll_fw) THEN ; jic = nn_e + ELSE ; jic = 2 * nn_e ENDIF - - ! Set primary weights: - IF (ll_av) THEN - ! Define simple boxcar window for primary weights - ! (width = nn_e, centered around jic) - SELECT CASE ( nn_bt_flt ) - CASE( 0 ) ! No averaging - zwgt1(jic) = 1._wp - jpit = jic - - CASE( 1 ) ! Boxcar, width = nn_e - DO jn = 1, 3*nn_e - za1 = ABS(float(jn-jic))/float(nn_e) - IF (za1 < 0.5_wp) THEN - zwgt1(jn) = 1._wp - jpit = jn - ENDIF - ENDDO - - CASE( 2 ) ! Boxcar, width = 2 * nn_e - DO jn = 1, 3*nn_e - za1 = ABS(float(jn-jic))/float(nn_e) - IF (za1 < 1._wp) THEN - zwgt1(jn) = 1._wp - jpit = jn - ENDIF - ENDDO - CASE DEFAULT ; CALL ctl_stop( 'unrecognised value for nn_bt_flt' ) + ! + ! !== Set primary weights ==! + ! + IF (ll_av) THEN != Define simple boxcar window for primary weights + ! ! (width = nn_e, centered around jic) + SELECT CASE( nn_bt_flt ) + ! + CASE( 0 ) ! No averaging + zwgt1(jic) = 1._wp + Kpit = jic + ! + CASE( 1 ) ! Boxcar, width = nn_e + DO jn = 1, 3*nn_e + za1 = ABS( REAL( jn-jic, wp) ) / REAL( nn_e, wp ) + IF( za1 < 0.5_wp ) THEN + zwgt1(jn) = 1._wp + Kpit = jn + ENDIF + END DO + ! + CASE( 2 ) ! Boxcar, width = 2 * nn_e + DO jn = 1, 3*nn_e + za1 = ABS(REAL( jn-jic, wp) ) / REAL( nn_e, wp ) + IF( za1 < 1._wp ) THEN + zwgt1(jn) = 1._wp + Kpit = jn + ENDIF + END DO + ! + CASE DEFAULT ; CALL ctl_stop( 'unrecognised value for nn_bt_flt' ) + ! END SELECT - ELSE ! No time averaging + ELSE != No time averaging zwgt1(jic) = 1._wp - jpit = jic + Kpit = jic ENDIF - - ! Set secondary weights - DO jn = 1, jpit - DO ji = jn, jpit - zwgt2(jn) = zwgt2(jn) + zwgt1(ji) - END DO + ! + ! !== Set secondary weights ==! + DO jn = 1, Kpit + DO ji = jn, Kpit + zwgt2(jn) = zwgt2(jn) + zwgt1(ji) + END DO END DO - - ! Normalize weigths: - za1 = 1._wp / SUM(zwgt1(1:jpit)) - za2 = 1._wp / SUM(zwgt2(1:jpit)) - DO jn = 1, jpit - zwgt1(jn) = zwgt1(jn) * za1 - zwgt2(jn) = zwgt2(jn) * za2 + ! + ! !== Normalize weigths ==! + za1 = 1._wp / SUM( zwgt1(1:Kpit) ) + za2 = 1._wp / SUM( zwgt2(1:Kpit) ) + DO jn = 1, Kpit + zwgt1(jn) = zwgt1(jn) * za1 + zwgt2(jn) = zwgt2(jn) * za2 END DO ! END SUBROUTINE ts_wgt @@ -936,11 +1049,15 @@ CONTAINS ! IF( TRIM(cdrw) == 'READ' ) THEN ! Read/initialise ! ! --------------- - IF( ln_rstart .AND. ln_bt_fw .AND. .NOT.l_1st_euler ) THEN !* Read the restart file - CALL iom_get( numror, jpdom_auto, 'ub2_b' , ub2_b (:,:), cd_type = 'U', psgn = -1._wp ) - CALL iom_get( numror, jpdom_auto, 'vb2_b' , vb2_b (:,:), cd_type = 'V', psgn = -1._wp ) - CALL iom_get( numror, jpdom_auto, 'un_bf' , un_bf (:,:), cd_type = 'U', psgn = -1._wp ) - CALL iom_get( numror, jpdom_auto, 'vn_bf' , vn_bf (:,:), cd_type = 'V', psgn = -1._wp ) + IF( ln_rstart .AND. .NOT.l_1st_euler ) THEN !* Read the restart file +# if ! defined key_RK3 + IF ( ln_bt_fw ) THEN + CALL iom_get( numror, jpdom_auto, 'ub2_b' , ub2_b (:,:), cd_type = 'U', psgn = -1._wp ) + CALL iom_get( numror, jpdom_auto, 'vb2_b' , vb2_b (:,:), cd_type = 'V', psgn = -1._wp ) + CALL iom_get( numror, jpdom_auto, 'un_bf' , un_bf (:,:), cd_type = 'U', psgn = -1._wp ) + CALL iom_get( numror, jpdom_auto, 'vn_bf' , vn_bf (:,:), cd_type = 'V', psgn = -1._wp ) + ENDIF +# endif IF( .NOT.ln_bt_av ) THEN CALL iom_get( numror, jpdom_auto, 'sshbb_e' , sshbb_e(:,:), cd_type = 'T', psgn = 1._wp ) CALL iom_get( numror, jpdom_auto, 'ubb_e' , ubb_e(:,:), cd_type = 'U', psgn = -1._wp ) @@ -957,13 +1074,21 @@ CONTAINS ELSE ub2_i_b(:,:) = 0._wp ; vb2_i_b(:,:) = 0._wp ! used in the 1st update of agrif ENDIF +# if defined key_RK3 + CALL iom_get( numror, jpdom_auto, 'un_adv' , un_adv(:,:), cd_type = 'U', psgn = -1._wp ) + CALL iom_get( numror, jpdom_auto, 'vn_adv' , vn_adv(:,:), cd_type = 'V', psgn = -1._wp ) +# endif #endif - ELSE !* Start from rest + ELSE + ! !* Start from rest or use RK3 time-step IF(lwp) WRITE(numout,*) IF(lwp) WRITE(numout,*) ' ==>>> start from rest: set barotropic values to 0' +# if ! defined key_RK3 ub2_b (:,:) = 0._wp ; vb2_b (:,:) = 0._wp ! used in the 1st interpol of agrif - un_adv (:,:) = 0._wp ; vn_adv (:,:) = 0._wp ! used in the 1st interpol of agrif un_bf (:,:) = 0._wp ; vn_bf (:,:) = 0._wp ! used in the 1st update of agrif +#else + un_adv (:,:) = 0._wp ; vn_adv (:,:) = 0._wp ! used in the 1st interpol of agrif +#endif #if defined key_agrif ub2_i_b(:,:) = 0._wp ; vb2_i_b(:,:) = 0._wp ! used in the 1st update of agrif #endif @@ -972,10 +1097,14 @@ CONTAINS ELSEIF( TRIM(cdrw) == 'WRITE' ) THEN ! Create restart file ! ! ------------------- IF(lwp) WRITE(numout,*) '---- ts_rst ----' - CALL iom_rstput( kt, nitrst, numrow, 'ub2_b' , ub2_b (:,:) ) - CALL iom_rstput( kt, nitrst, numrow, 'vb2_b' , vb2_b (:,:) ) - CALL iom_rstput( kt, nitrst, numrow, 'un_bf' , un_bf (:,:) ) - CALL iom_rstput( kt, nitrst, numrow, 'vn_bf' , vn_bf (:,:) ) +# if ! defined key_RK3 + IF ( ln_bt_fw ) THEN + CALL iom_rstput( kt, nitrst, numrow, 'ub2_b' , ub2_b (:,:) ) + CALL iom_rstput( kt, nitrst, numrow, 'vb2_b' , vb2_b (:,:) ) + CALL iom_rstput( kt, nitrst, numrow, 'un_bf' , un_bf (:,:) ) + CALL iom_rstput( kt, nitrst, numrow, 'vn_bf' , vn_bf (:,:) ) + ENDIF +# endif ! IF (.NOT.ln_bt_av) THEN CALL iom_rstput( kt, nitrst, numrow, 'sshbb_e' , sshbb_e(:,:) ) @@ -991,6 +1120,10 @@ CONTAINS CALL iom_rstput( kt, nitrst, numrow, 'ub2_i_b' , ub2_i_b(:,:) ) CALL iom_rstput( kt, nitrst, numrow, 'vb2_i_b' , vb2_i_b(:,:) ) ENDIF +# if defined key_RK3 + CALL iom_rstput( kt, nitrst, numrow, 'un_adv' , un_adv(:,:) ) + CALL iom_rstput( kt, nitrst, numrow, 'vn_adv' , vn_adv(:,:) ) +# endif #endif ENDIF ! @@ -1034,19 +1167,23 @@ CONTAINS ELSE IF(lwp) WRITE(numout,*) ' ln_ts_auto=.false.: Use nn_e in namelist nn_e = ', nn_e ENDIF - + ! IF(ln_bt_av) THEN IF(lwp) WRITE(numout,*) ' ln_bt_av =.true. ==> Time averaging over nn_e time steps is on ' ELSE IF(lwp) WRITE(numout,*) ' ln_bt_av =.false. => No time averaging of barotropic variables ' ENDIF ! - ! +# if ! defined key_RK3 IF(ln_bt_fw) THEN IF(lwp) WRITE(numout,*) ' ln_bt_fw=.true. => Forward integration of barotropic variables ' ELSE IF(lwp) WRITE(numout,*) ' ln_bt_fw =.false.=> Centred integration of barotropic variables ' ENDIF +# else + ! Enforce ln_bt_fw = T with RK3 + ln_bt_fw = .true. +# endif ! #if defined key_agrif ! Restrict the use of Agrif to the forward case only @@ -1081,7 +1218,7 @@ CONTAINS ! ! Allocate time-splitting arrays IF( dyn_spg_ts_alloc() /= 0 ) CALL ctl_stop('STOP', 'dyn_spg_init: failed to allocate dynspg_ts arrays' ) ! - ! ! read restart when needed + ! !: restart/initialise CALL ts_rst( nit000, 'READ' ) ! END SUBROUTINE dyn_spg_ts_init @@ -1099,7 +1236,8 @@ CONTAINS !! To remove this approximation, copy lines below inside barotropic loop !! and update depths at T- points (ht) at each barotropic time step !! - !! Compute zwz = f / ( height of the water colomn ) + !! Compute zwz = f/h (potential planetary voricity) + !! Compute ftne, ftnw, ftse, ftsw (triad of potential planetary voricity) !!---------------------------------------------------------------------- INTEGER, INTENT(in) :: Kmm ! Time index INTEGER :: ji ,jj, jk ! dummy loop indices @@ -1149,13 +1287,13 @@ CONTAINS END_2D ! END SELECT - - END SUBROUTINE dyn_cor_2d_init + ! + END SUBROUTINE dyn_cor_2D_init - SUBROUTINE dyn_cor_2d( pht, phu, phv, punb, pvnb, zhU, zhV, zu_trd, zv_trd ) + SUBROUTINE dyn_cor_2D( pht, phu, phv, punb, pvnb, zhU, zhV, zu_trd, zv_trd ) !!--------------------------------------------------------------------- - !! *** ROUTINE dyn_cor_2d *** + !! *** ROUTINE dyn_cor_2D *** !! !! ** Purpose : Compute u and v coriolis trends !!---------------------------------------------------------------------- @@ -1298,11 +1436,13 @@ CONTAINS !! !! ** Purpose : !!---------------------------------------------------------------------- - INTEGER :: ji ,jj ! dummy loop indices - LOGICAL :: ll_tmp1, ll_tmp2 REAL(wp), DIMENSION(jpi,jpj), INTENT(in ) :: pshn REAL(wp), DIMENSION(jpi,jpj), INTENT(inout) :: zcpx, zcpy + ! + INTEGER :: ji ,jj ! dummy loop indices + LOGICAL :: ll_tmp1, ll_tmp2 !!---------------------------------------------------------------------- + ! DO_2D( 0, 0, 0, 0 ) ll_tmp1 = MIN( pshn(ji,jj) , pshn(ji+1,jj) ) > & & MAX( -ht_0(ji,jj) , -ht_0(ji+1,jj) ) .AND. & @@ -1341,7 +1481,7 @@ CONTAINS zcpy(ji,jj) = 0._wp ENDIF END_2D - + ! END SUBROUTINE wad_spg @@ -1385,15 +1525,13 @@ CONTAINS ! !== BOTTOM stress contribution from baroclinic velocities ==! ! IF( ln_bt_fw ) THEN ! FORWARD integration: use NOW bottom baroclinic velocities - DO_2D( 0, 0, 0, 0 ) ikbu = mbku(ji,jj) ikbv = mbkv(ji,jj) zu_i(ji,jj) = puu(ji,jj,ikbu,Kmm) - puu_b(ji,jj,Kmm) zv_i(ji,jj) = pvv(ji,jj,ikbv,Kmm) - pvv_b(ji,jj,Kmm) END_2D - ELSE ! CENTRED integration: use BEFORE bottom baroclinic velocities - + ELSE ! CENTRED integration: use BEFORE bottom baroclinic velocities DO_2D( 0, 0, 0, 0 ) ikbu = mbku(ji,jj) ikbv = mbkv(ji,jj) @@ -1411,7 +1549,6 @@ CONTAINS & r1_hv(ji,jj,Kmm) * r1_2*( rCdU_bot(ji,jj+1)+rCdU_bot(ji,jj) ) , zztmp ) END_2D ELSE ! use "unclipped" drag (even if explicit friction is used in 3D calculation) - DO_2D( 0, 0, 0, 0 ) pu_RHSi(ji,jj) = pu_RHSi(ji,jj) + r1_hu(ji,jj,Kmm) * r1_2*( rCdU_bot(ji+1,jj)+rCdU_bot(ji,jj) ) * zu_i(ji,jj) pv_RHSi(ji,jj) = pv_RHSi(ji,jj) + r1_hv(ji,jj,Kmm) * r1_2*( rCdU_bot(ji,jj+1)+rCdU_bot(ji,jj) ) * zv_i(ji,jj) @@ -1423,15 +1560,13 @@ CONTAINS IF( ln_isfcav.OR.ln_drgice_imp ) THEN ! IF( ln_bt_fw ) THEN ! FORWARD integration: use NOW top baroclinic velocity - DO_2D( 0, 0, 0, 0 ) iktu = miku(ji,jj) iktv = mikv(ji,jj) zu_i(ji,jj) = puu(ji,jj,iktu,Kmm) - puu_b(ji,jj,Kmm) zv_i(ji,jj) = pvv(ji,jj,iktv,Kmm) - pvv_b(ji,jj,Kmm) END_2D - ELSE ! CENTRED integration: use BEFORE top baroclinic velocity - + ELSE ! CENTRED integration: use BEFORE top baroclinic velocity DO_2D( 0, 0, 0, 0 ) iktu = miku(ji,jj) iktv = mikv(ji,jj) @@ -1439,9 +1574,7 @@ CONTAINS zv_i(ji,jj) = pvv(ji,jj,iktv,Kbb) - pvv_b(ji,jj,Kbb) END_2D ENDIF - ! - ! ! use "unclipped" top drag (even if explicit friction is used in 3D calculation) - + ! ! use "unclipped" top drag (even if explicit friction is used in 3D calculation) DO_2D( 0, 0, 0, 0 ) pu_RHSi(ji,jj) = pu_RHSi(ji,jj) + r1_hu(ji,jj,Kmm) * r1_2*( rCdU_top(ji+1,jj)+rCdU_top(ji,jj) ) * zu_i(ji,jj) pv_RHSi(ji,jj) = pv_RHSi(ji,jj) + r1_hv(ji,jj,Kmm) * r1_2*( rCdU_top(ji,jj+1)+rCdU_top(ji,jj) ) * zv_i(ji,jj) @@ -1451,6 +1584,7 @@ CONTAINS ! END SUBROUTINE dyn_drg_init + SUBROUTINE ts_bck_interp( jn, ll_init, & ! <== in & za0, za1, za2, za3 ) ! ==> out !!---------------------------------------------------------------------- @@ -1488,6 +1622,5 @@ CONTAINS ENDIF END SUBROUTINE ts_bck_interp - !!====================================================================== END MODULE dynspg_ts diff --git a/src/OCE/DYN/dynvor.F90 b/src/OCE/DYN/dynvor.F90 index 36f2d4b3fc6b8ed9ea570a7ba598a2234ed9785c..03dda78ceb4f6ce993419062208a9240e3ae7d75 100644 --- a/src/OCE/DYN/dynvor.F90 +++ b/src/OCE/DYN/dynvor.F90 @@ -50,6 +50,10 @@ MODULE dynvor IMPLICIT NONE PRIVATE + + INTERFACE dyn_vor + MODULE PROCEDURE dyn_vor_3D, dyn_vor_RK3 + END INTERFACE PUBLIC dyn_vor ! routine called by step.F90 PUBLIC dyn_vor_init ! routine called by nemogcm.F90 @@ -73,8 +77,9 @@ MODULE dynvor INTEGER, PUBLIC, PARAMETER :: np_EEN = 4 ! EEN scheme INTEGER, PUBLIC, PARAMETER :: np_MIX = 5 ! MIX scheme - INTEGER :: ncor, nrvm, ntot ! choice of calculated vorticity - ! ! associated indices: + ! !: choice of calculated vorticity + INTEGER, PUBLIC :: ncor, nrvm, ntot ! Coriolis, relative vorticity, total vorticity + ! ! associated indices: INTEGER, PUBLIC, PARAMETER :: np_COR = 1 ! Coriolis (planetary) INTEGER, PUBLIC, PARAMETER :: np_RVO = 2 ! relative vorticity INTEGER, PUBLIC, PARAMETER :: np_MET = 3 ! metric term @@ -98,12 +103,12 @@ MODULE dynvor !!---------------------------------------------------------------------- !! NEMO/OCE 4.0 , NEMO Consortium (2018) - !! $Id: dynvor.F90 14834 2021-05-11 09:24:44Z hadcv $ + !! $Id: dynvor.F90 14547 2021-02-25 17:07:15Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS - - SUBROUTINE dyn_vor( kt, Kmm, puu, pvv, Krhs ) + + SUBROUTINE dyn_vor_3D( kt, Kmm, puu, pvv, Krhs ) !!---------------------------------------------------------------------- !! !! ** Purpose : compute the lateral ocean tracer physics. @@ -120,7 +125,7 @@ CONTAINS REAL(wp), ALLOCATABLE, DIMENSION(:,:,:) :: ztrdu, ztrdv !!---------------------------------------------------------------------- ! - IF( ln_timing ) CALL timing_start('dyn_vor') + IF( ln_timing ) CALL timing_start('dyn_vor_3D') ! IF( l_trddyn ) THEN !== trend diagnostics case : split the added trend in two parts ==! ! @@ -208,9 +213,85 @@ CONTAINS IF(sn_cfctl%l_prtctl) CALL prt_ctl( tab3d_1=puu(:,:,:,Krhs), clinfo1=' vor - Ua: ', mask1=umask, & & tab3d_2=pvv(:,:,:,Krhs), clinfo2= ' Va: ', mask2=vmask, clinfo3='dyn' ) ! - IF( ln_timing ) CALL timing_stop('dyn_vor') + IF( ln_timing ) CALL timing_stop('dyn_vor_3D') + ! + END SUBROUTINE dyn_vor_3D + + + SUBROUTINE dyn_vor_RK3( kt, Kmm, puu, pvv, Krhs, knoco ) + !!---------------------------------------------------------------------- + !! + !! ** Purpose : compute the lateral ocean tracer physics. + !! + !! ** Action : - Update (puu(:,:,:,Krhs),pvv(:,:,:,Krhs)) with the now vorticity term trend + !! - save the trends in (ztrdu,ztrdv) in 2 parts (relative + !! and planetary vorticity trends) and send them to trd_dyn + !! for futher diagnostics (l_trddyn=T) + !!---------------------------------------------------------------------- + INTEGER , INTENT(in ) :: kt ! ocean time-step index + INTEGER , INTENT(in ) :: Kmm, Krhs ! ocean time level indices + REAL(wp), DIMENSION(jpi,jpj,jpk,jpt), INTENT(inout) :: puu, pvv ! ocean velocity field and RHS of momentum equation + INTEGER , INTENT(in ) :: knoco ! specified vorticity trend (= np_MET or np_RVO) + !!---------------------------------------------------------------------- + ! + IF( ln_timing ) CALL timing_start('dyn_vor_RK3') + ! + ! !== total vorticity trend added to the general trend ==! + !!st WARNING 22/02 !!!!!!!! stoke drift or not stoke drift ? => bar to do later !!! + !! stoke drift a garder pas vortex force a priori !! + !! ATTENTION déja appelé avec Kbb !! + + ! + SELECT CASE ( nvor_scheme ) !== vorticity trend added to the general trend ==! + CASE( np_ENT ) !* energy conserving scheme (T-pts) + CALL vor_enT( kt, Kmm, knoco, puu(:,:,:,Kmm) , pvv(:,:,:,Kmm) , puu(:,:,:,Krhs), pvv(:,:,:,Krhs) ) ! total vorticity trend + IF( ln_stcor .AND. .NOT. ln_vortex_force ) THEN + CALL vor_enT( kt, Kmm, ncor, usd, vsd, puu(:,:,:,Krhs), pvv(:,:,:,Krhs) ) ! add the Stokes-Coriolis trend + ELSE IF( ln_stcor .AND. ln_vortex_force ) THEN + CALL vor_enT( kt, Kmm, ntot, usd, vsd, puu(:,:,:,Krhs), pvv(:,:,:,Krhs) ) ! add the Stokes-Coriolis trend and vortex force + ENDIF + CASE( np_EET ) !* energy conserving scheme (een scheme using e3t) + CALL vor_eeT( kt, Kmm, knoco, puu(:,:,:,Kmm) , pvv(:,:,:,Kmm) , puu(:,:,:,Krhs), pvv(:,:,:,Krhs) ) ! total vorticity trend + IF( ln_stcor .AND. .NOT. ln_vortex_force ) THEN + CALL vor_eeT( kt, Kmm, ncor, usd, vsd, puu(:,:,:,Krhs), pvv(:,:,:,Krhs) ) ! add the Stokes-Coriolis trend + ELSE IF( ln_stcor .AND. ln_vortex_force ) THEN + CALL vor_eeT( kt, Kmm, ntot, usd, vsd, puu(:,:,:,Krhs), pvv(:,:,:,Krhs) ) ! add the Stokes-Coriolis trend and vortex force + ENDIF + CASE( np_ENE ) !* energy conserving scheme + CALL vor_ene( kt, Kmm, knoco, puu(:,:,:,Kmm) , pvv(:,:,:,Kmm) , puu(:,:,:,Krhs), pvv(:,:,:,Krhs) ) ! total vorticity trend + IF( ln_stcor .AND. .NOT. ln_vortex_force ) THEN + CALL vor_ene( kt, Kmm, ncor, usd, vsd, puu(:,:,:,Krhs), pvv(:,:,:,Krhs) ) ! add the Stokes-Coriolis trend + ELSE IF( ln_stcor .AND. ln_vortex_force ) THEN + CALL vor_ene( kt, Kmm, ntot, usd, vsd, puu(:,:,:,Krhs), pvv(:,:,:,Krhs) ) ! add the Stokes-Coriolis trend and vortex force + ENDIF + CASE( np_ENS ) !* enstrophy conserving scheme + CALL vor_ens( kt, Kmm, knoco, puu(:,:,:,Kmm) , pvv(:,:,:,Kmm) , puu(:,:,:,Krhs), pvv(:,:,:,Krhs) ) ! total vorticity trend + + IF( ln_stcor .AND. .NOT. ln_vortex_force ) THEN + CALL vor_ens( kt, Kmm, ncor, usd, vsd, puu(:,:,:,Krhs), pvv(:,:,:,Krhs) ) ! add the Stokes-Coriolis trend + ELSE IF( ln_stcor .AND. ln_vortex_force ) THEN + CALL vor_ens( kt, Kmm, ntot, usd, vsd, puu(:,:,:,Krhs), pvv(:,:,:,Krhs) ) ! add the Stokes-Coriolis trend and vortex force + ENDIF + CASE( np_MIX ) !* mixed ene-ens scheme + CALL vor_ens( kt, Kmm, nrvm, puu(:,:,:,Kmm) , pvv(:,:,:,Kmm) , puu(:,:,:,Krhs), pvv(:,:,:,Krhs) ) ! relative vorticity or metric trend (ens) + IF( ln_stcor ) CALL vor_ene( kt, Kmm, ncor, usd, vsd, puu(:,:,:,Krhs), pvv(:,:,:,Krhs) ) ! add the Stokes-Coriolis trend + IF( ln_vortex_force ) CALL vor_ens( kt, Kmm, nrvm, usd, vsd, puu(:,:,:,Krhs), pvv(:,:,:,Krhs) ) ! add vortex force + CASE( np_EEN ) !* energy and enstrophy conserving scheme + CALL vor_een( kt, Kmm, knoco, puu(:,:,:,Kmm) , pvv(:,:,:,Kmm) , puu(:,:,:,Krhs), pvv(:,:,:,Krhs) ) ! total vorticity trend + IF( ln_stcor .AND. .NOT. ln_vortex_force ) THEN + CALL vor_een( kt, Kmm, ncor, usd, vsd, puu(:,:,:,Krhs), pvv(:,:,:,Krhs) ) ! add the Stokes-Coriolis trend + ELSE IF( ln_stcor .AND. ln_vortex_force ) THEN + CALL vor_een( kt, Kmm, ntot, usd, vsd, puu(:,:,:,Krhs), pvv(:,:,:,Krhs) ) ! add the Stokes-Coriolis trend and vortex force + ENDIF + END SELECT + ! + ! ! print sum trends (used for debugging) + IF(sn_cfctl%l_prtctl) CALL prt_ctl( tab3d_1=puu(:,:,:,Krhs), clinfo1=' vor - Ua: ', mask1=umask, & + & tab3d_2=pvv(:,:,:,Krhs), clinfo2= ' Va: ', mask2=vmask, clinfo3='dyn' ) + ! + IF( ln_timing ) CALL timing_stop('dyn_vor_RK3') ! - END SUBROUTINE dyn_vor + END SUBROUTINE dyn_vor_RK3 SUBROUTINE vor_enT( kt, Kmm, kvor, pu, pv, pu_rhs, pv_rhs ) diff --git a/src/OCE/DYN/dynzad.F90 b/src/OCE/DYN/dynzad.F90 index 5e6a59ded6271c882b86ff87436de51dc1052ecf..5433b956f84b03e19cc2ffa356f1a23b3938858a 100644 --- a/src/OCE/DYN/dynzad.F90 +++ b/src/OCE/DYN/dynzad.F90 @@ -3,8 +3,9 @@ MODULE dynzad !! *** MODULE dynzad *** !! Ocean dynamics : vertical advection trend !!====================================================================== - !! History : OPA ! 1991-01 (G. Madec) Original code - !! NEMO 0.5 ! 2002-07 (G. Madec) Free form, F90 + !! History : OPA ! 1991-01 (G. Madec) Original code + !! NEMO 0.5 ! 2002-07 (G. Madec) Free form, F90 + !! 4.5 ! 2021-01 (S. Techene, G. Madec) memory optimization !!---------------------------------------------------------------------- !!---------------------------------------------------------------------- @@ -32,7 +33,7 @@ MODULE dynzad # include "domzgr_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/OCE 4.0 , NEMO Consortium (2018) - !! $Id: dynzad.F90 14834 2021-05-11 09:24:44Z hadcv $ + !! $Id: dynzad.F90 14428 2021-02-10 18:12:36Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS @@ -53,15 +54,14 @@ CONTAINS !! ** Action : - Update (puu(:,:,:,Krhs),pvv(:,:,:,Krhs)) with the vert. momentum adv. trends !! - Send the trends to trddyn for diagnostics (l_trddyn=T) !!---------------------------------------------------------------------- - INTEGER , INTENT( in ) :: kt ! ocean time-step inedx - INTEGER , INTENT( in ) :: Kmm, Krhs ! ocean time level indices - REAL(wp), DIMENSION(jpi,jpj,jpk,jpt), INTENT(inout) :: puu, pvv ! ocean velocities and RHS of momentum equation + INTEGER , INTENT(in ) :: kt, Kmm, Krhs ! ocean time-step & time-level indices + REAL(wp), DIMENSION(jpi,jpj,jpk,jpt), INTENT(inout) :: puu, pvv ! ocean velocities and RHS of momentum equation ! INTEGER :: ji, jj, jk ! dummy loop indices - REAL(wp) :: zua, zva ! local scalars - REAL(wp), DIMENSION(A2D(nn_hls)) :: zww - REAL(wp), DIMENSION(A2D(nn_hls),jpk) :: zwuw, zwvw - REAL(wp), DIMENSION(:,:,:), ALLOCATABLE :: ztrdu, ztrdv + REAL(wp) :: zWf, zWfi, zzWfu, zzWdzU ! local scalars + REAL(wp) :: zWfj, zzWfv, zzWdzV ! - - + REAL(wp), DIMENSION(A2D(0)) :: zWdzU, zWdzV ! 2D inner workspace + REAL(wp), DIMENSION(:,:,:), ALLOCATABLE :: ztrdu, ztrdv ! 3D workspace !!---------------------------------------------------------------------- ! IF( ln_timing ) CALL timing_start('dyn_zad') @@ -72,44 +72,53 @@ CONTAINS IF(lwp) WRITE(numout,*) 'dyn_zad : 2nd order vertical advection scheme' ENDIF ENDIF - + ! IF( l_trddyn ) THEN ! Save puu(:,:,:,Krhs) and pvv(:,:,:,Krhs) trends ALLOCATE( ztrdu(jpi,jpj,jpk) , ztrdv(jpi,jpj,jpk) ) ztrdu(:,:,:) = puu(:,:,:,Krhs) ztrdv(:,:,:) = pvv(:,:,:,Krhs) ENDIF - - DO jk = 2, jpkm1 ! Vertical momentum advection at level w and u- and v- vertical - IF( ln_vortex_force ) THEN ! vertical fluxes - DO_2D( 0, 1, 0, 1 ) - zww(ji,jj) = 0.25_wp * e1e2t(ji,jj) * ( ww(ji,jj,jk) + wsd(ji,jj,jk) ) - END_2D - ELSE - DO_2D( 0, 1, 0, 1 ) - zww(ji,jj) = 0.25_wp * e1e2t(ji,jj) * ww(ji,jj,jk) - END_2D + ! + ! !== vertical momentum advection ==! at u- and v-points + ! + zWdzU(A2D(0)) = 0._wp ! set surface (jk=1) vertical advection to zero + zWdzV(A2D(0)) = 0._wp + ! + DO_3D( 0, 0, 0, 0 , 1, jpk-2 ) != surface to jpk-2 vertical advection + ! ! vertical transport at jk+1 uw/vw-level (x2): 2*mi/j[e1e2t*(We)] + IF( ln_vortex_force ) THEN ! We = ww+wsd + zWf = e1e2t(ji ,jj ) * ( ww(ji ,jj ,jk+1) + wsd(ji ,jj ,jk+1) ) + zWfi = e1e2t(ji+1,jj ) * ( ww(ji+1,jj ,jk+1) + wsd(ji+1,jj ,jk+1) ) + zWfj = e1e2t(ji ,jj+1) * ( ww(ji ,jj+1,jk+1) + wsd(ji ,jj+1,jk+1) ) + ELSE ! We = ww + zWf = e1e2t(ji ,jj ) * ww(ji ,jj ,jk+1) + zWfi = e1e2t(ji+1,jj ) * ww(ji+1,jj ,jk+1) + zWfj = e1e2t(ji ,jj+1) * ww(ji ,jj+1,jk+1) ENDIF - DO_2D( 0, 0, 0, 0 ) ! vertical momentum advection at w-point - zwuw(ji,jj,jk) = ( zww(ji+1,jj ) + zww(ji,jj) ) * ( puu(ji,jj,jk-1,Kmm) - puu(ji,jj,jk,Kmm) ) - zwvw(ji,jj,jk) = ( zww(ji ,jj+1) + zww(ji,jj) ) * ( pvv(ji,jj,jk-1,Kmm) - pvv(ji,jj,jk,Kmm) ) - END_2D - END DO + zzWfu = zWfi + zWf ! averaging at uw- and vw-points (x2) + zzWfv = zWfj + zWf + ! ! vertical advection at jk+1 uw-level (x4): zzWfu/v*dk+1[u/v] + zzWdzU = zzWfu * ( puu(ji,jj,jk,Kmm) - puu(ji,jj,jk+1,Kmm) ) + zzWdzV = zzWfv * ( pvv(ji,jj,jk,Kmm) - pvv(ji,jj,jk+1,Kmm) ) + ! + ! ! vertical advection at jk u/v-level + puu(ji,jj,jk,Krhs) = puu(ji,jj,jk,Krhs) - 0.25_wp * r1_e1e2u(ji,jj) / e3u(ji,jj,jk,Kmm) & + & * ( zWdzU(ji,jj) + zzWdzU ) + pvv(ji,jj,jk,Krhs) = pvv(ji,jj,jk,Krhs) - 0.25_wp * r1_e1e2v(ji,jj) / e3v(ji,jj,jk,Kmm) & + & * ( zWdzV(ji,jj) + zzWdzV ) + ! + zWdzU(ji,jj) = zzWdzU ! save for next level computation + zWdzV(ji,jj) = zzWdzV + END_3D ! - ! Surface and bottom advective fluxes set to zero - DO_2D( 0, 0, 0, 0 ) - zwuw(ji,jj, 1 ) = 0._wp - zwvw(ji,jj, 1 ) = 0._wp - zwuw(ji,jj,jpk) = 0._wp - zwvw(ji,jj,jpk) = 0._wp + jk = jpkm1 + DO_2D( 0, 0, 0, 0 ) != bottom vertical advection at jpkm1 + puu(ji,jj,jk,Krhs) = puu(ji,jj,jk,Krhs) - 0.25_wp * r1_e1e2u(ji,jj) / e3u(ji,jj,jk,Kmm) & + & * zWdzU(ji,jj) + pvv(ji,jj,jk,Krhs) = pvv(ji,jj,jk,Krhs) - 0.25_wp * r1_e1e2v(ji,jj) / e3v(ji,jj,jk,Kmm) & + & * zWdzV(ji,jj) END_2D ! - DO_3D( 0, 0, 0, 0, 1, jpkm1 ) ! Vertical momentum advection at u- and v-points - puu(ji,jj,jk,Krhs) = puu(ji,jj,jk,Krhs) - ( zwuw(ji,jj,jk) + zwuw(ji,jj,jk+1) ) * r1_e1e2u(ji,jj) & - & / e3u(ji,jj,jk,Kmm) - pvv(ji,jj,jk,Krhs) = pvv(ji,jj,jk,Krhs) - ( zwvw(ji,jj,jk) + zwvw(ji,jj,jk+1) ) * r1_e1e2v(ji,jj) & - & / e3v(ji,jj,jk,Kmm) - END_3D - IF( l_trddyn ) THEN ! save the vertical advection trends for diagnostic ztrdu(:,:,:) = puu(:,:,:,Krhs) - ztrdu(:,:,:) ztrdv(:,:,:) = pvv(:,:,:,Krhs) - ztrdv(:,:,:) diff --git a/src/OCE/DYN/dynzdf.F90 b/src/OCE/DYN/dynzdf.F90 index d8046188ca9c2c03852b65fde2d32af36ea8f997..1e026021941c8a5891459385a52d899c8c88123e 100644 --- a/src/OCE/DYN/dynzdf.F90 +++ b/src/OCE/DYN/dynzdf.F90 @@ -37,14 +37,12 @@ MODULE dynzdf PUBLIC dyn_zdf ! routine called by step.F90 - REAL(wp) :: r_vvl ! non-linear free surface indicator: =0 if ln_linssh=T, =1 otherwise - !! * Substitutions # include "do_loop_substitute.h90" # include "domzgr_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/OCE 4.0 , NEMO Consortium (2018) - !! $Id: dynzdf.F90 14834 2021-05-11 09:24:44Z hadcv $ + !! $Id: dynzdf.F90 14547 2021-02-25 17:07:15Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS @@ -73,14 +71,14 @@ CONTAINS INTEGER , INTENT( in ) :: Kbb, Kmm, Krhs, Kaa ! ocean time level indices REAL(wp), DIMENSION(jpi,jpj,jpk,jpt), INTENT(inout) :: puu, pvv ! ocean velocities and RHS of momentum equation ! - INTEGER :: ji, jj, jk ! dummy loop indices - INTEGER :: iku, ikv ! local integers - REAL(wp) :: zzwi, ze3ua, zdt ! local scalars - REAL(wp) :: zzws, ze3va ! - - - REAL(wp) :: z1_e3ua, z1_e3va ! - - - REAL(wp) :: zWu , zWv ! - - - REAL(wp) :: zWui, zWvi ! - - - REAL(wp) :: zWus, zWvs ! - - + INTEGER :: ji, jj, jk ! dummy loop indices + INTEGER :: iku, ikv ! local integers + REAL(wp) :: zzwi, ze3ua, zDt_2 ! local scalars + REAL(wp) :: zzws, ze3va ! - - + REAL(wp) :: z1_e3ua, z1_e3va ! - - + REAL(wp) :: zWu , zWv ! - - + REAL(wp) :: zWui, zWvi ! - - + REAL(wp) :: zWus, zWvs ! - - REAL(wp), DIMENSION(A2D(nn_hls),jpk) :: zwi, zwd, zws ! 3D workspace REAL(wp), DIMENSION(:,:,:), ALLOCATABLE :: ztrdu, ztrdv ! - - !!--------------------------------------------------------------------- @@ -92,12 +90,11 @@ CONTAINS IF(lwp) WRITE(numout,*) IF(lwp) WRITE(numout,*) 'dyn_zdf_imp : vertical momentum diffusion implicit operator' IF(lwp) WRITE(numout,*) '~~~~~~~~~~~ ' - ! - If( ln_linssh ) THEN ; r_vvl = 0._wp ! non-linear free surface indicator - ELSE ; r_vvl = 1._wp - ENDIF ENDIF ENDIF + ! + zDt_2 = rDt * 0.5_wp + ! ! !* explicit top/bottom drag case IF( .NOT.ln_drgimp ) CALL zdf_drg_exp( kt, Kmm, puu(:,:,:,Kbb), pvv(:,:,:,Kbb), puu(:,:,:,Krhs), pvv(:,:,:,Krhs) ) ! add top/bottom friction trend to (puu(Kaa),pvv(Kaa)) ! @@ -139,23 +136,19 @@ CONTAINS DO_2D( 0, 0, 0, 0 ) ! Add bottom/top stress due to barotropic component only iku = mbku(ji,jj) ! ocean bottom level at u- and v-points ikv = mbkv(ji,jj) ! (deepest ocean u- and v-points) - ze3ua = ( 1._wp - r_vvl ) * e3u(ji,jj,iku,Kmm) & - & + r_vvl * e3u(ji,jj,iku,Kaa) - ze3va = ( 1._wp - r_vvl ) * e3v(ji,jj,ikv,Kmm) & - & + r_vvl * e3v(ji,jj,ikv,Kaa) - puu(ji,jj,iku,Kaa) = puu(ji,jj,iku,Kaa) + rDt * 0.5*( rCdU_bot(ji+1,jj)+rCdU_bot(ji,jj) ) * uu_b(ji,jj,Kaa) / ze3ua - pvv(ji,jj,ikv,Kaa) = pvv(ji,jj,ikv,Kaa) + rDt * 0.5*( rCdU_bot(ji,jj+1)+rCdU_bot(ji,jj) ) * vv_b(ji,jj,Kaa) / ze3va + puu(ji,jj,iku,Kaa) = puu(ji,jj,iku,Kaa) + zDt_2 *( rCdU_bot(ji+1,jj)+rCdU_bot(ji,jj) ) * uu_b(ji,jj,Kaa) & + & / e3u(ji,jj,iku,Kaa) + pvv(ji,jj,ikv,Kaa) = pvv(ji,jj,ikv,Kaa) + zDt_2 *( rCdU_bot(ji,jj+1)+rCdU_bot(ji,jj) ) * vv_b(ji,jj,Kaa) & + & / e3v(ji,jj,ikv,Kaa) END_2D IF( ln_isfcav.OR.ln_drgice_imp ) THEN ! Ocean cavities (ISF) DO_2D( 0, 0, 0, 0 ) iku = miku(ji,jj) ! top ocean level at u- and v-points ikv = mikv(ji,jj) ! (first wet ocean u- and v-points) - ze3ua = ( 1._wp - r_vvl ) * e3u(ji,jj,iku,Kmm) & - & + r_vvl * e3u(ji,jj,iku,Kaa) - ze3va = ( 1._wp - r_vvl ) * e3v(ji,jj,ikv,Kmm) & - & + r_vvl * e3v(ji,jj,ikv,Kaa) - puu(ji,jj,iku,Kaa) = puu(ji,jj,iku,Kaa) + rDt * 0.5*( rCdU_top(ji+1,jj)+rCdU_top(ji,jj) ) * uu_b(ji,jj,Kaa) / ze3ua - pvv(ji,jj,ikv,Kaa) = pvv(ji,jj,ikv,Kaa) + rDt * 0.5*( rCdU_top(ji,jj+1)+rCdU_top(ji,jj) ) * vv_b(ji,jj,Kaa) / ze3va + puu(ji,jj,iku,Kaa) = puu(ji,jj,iku,Kaa) + zDt_2 *( rCdU_top(ji+1,jj)+rCdU_top(ji,jj) ) * uu_b(ji,jj,Kaa) & + & / e3u(ji,jj,iku,Kaa) + pvv(ji,jj,ikv,Kaa) = pvv(ji,jj,ikv,Kaa) + zDt_2 *( rCdU_top(ji,jj+1)+rCdU_top(ji,jj) ) * vv_b(ji,jj,Kaa) & + & / e3v(ji,jj,ikv,Kaa) END_2D END IF ENDIF @@ -163,70 +156,61 @@ CONTAINS ! !== Vertical diffusion on u ==! ! ! !* Matrix construction - zdt = rDt * 0.5 IF( ln_zad_Aimp ) THEN !! SELECT CASE( nldf_dyn ) CASE( np_lap_i ) ! rotated lateral mixing: add its vertical mixing (akzu) DO_3D( 0, 0, 0, 0, 1, jpkm1 ) - ze3ua = ( 1._wp - r_vvl ) * e3u(ji,jj,jk,Kmm) & - & + r_vvl * e3u(ji,jj,jk,Kaa) ! after scale factor at U-point - zzwi = - zdt * ( avm(ji+1,jj,jk ) + avm(ji,jj,jk ) + akzu(ji,jj,jk ) ) & - & / ( ze3ua * e3uw(ji,jj,jk ,Kmm) ) * wumask(ji,jj,jk ) - zzws = - zdt * ( avm(ji+1,jj,jk+1) + avm(ji,jj,jk+1) + akzu(ji,jj,jk+1) ) & - & / ( ze3ua * e3uw(ji,jj,jk+1,Kmm) ) * wumask(ji,jj,jk+1) - zWui = ( wi(ji,jj,jk ) + wi(ji+1,jj,jk ) ) / ze3ua - zWus = ( wi(ji,jj,jk+1) + wi(ji+1,jj,jk+1) ) / ze3ua - zwi(ji,jj,jk) = zzwi + zdt * MIN( zWui, 0._wp ) - zws(ji,jj,jk) = zzws - zdt * MAX( zWus, 0._wp ) - zwd(ji,jj,jk) = 1._wp - zzwi - zzws + zdt * ( MAX( zWui, 0._wp ) - MIN( zWus, 0._wp ) ) + z1_e3ua = 1._wp / e3u(ji,jj,jk,Kaa) ! after scale factor at U-point + zzwi = - zDt_2 * ( avm(ji+1,jj,jk ) + avm(ji,jj,jk ) + akzu(ji,jj,jk ) ) & + & / e3uw(ji,jj,jk ,Kmm) * z1_e3ua * wumask(ji,jj,jk ) + zzws = - zDt_2 * ( avm(ji+1,jj,jk+1) + avm(ji,jj,jk+1) + akzu(ji,jj,jk+1) ) & + & / e3uw(ji,jj,jk+1,Kmm) * z1_e3ua * wumask(ji,jj,jk+1) + zWui = ( wi(ji,jj,jk ) + wi(ji+1,jj,jk ) ) * z1_e3ua + zWus = ( wi(ji,jj,jk+1) + wi(ji+1,jj,jk+1) ) * z1_e3ua + zwi(ji,jj,jk) = zzwi + zDt_2 * MIN( zWui, 0._wp ) + zws(ji,jj,jk) = zzws - zDt_2 * MAX( zWus, 0._wp ) + zwd(ji,jj,jk) = 1._wp - zzwi - zzws + zDt_2 * ( MAX( zWui, 0._wp ) - MIN( zWus, 0._wp ) ) END_3D CASE DEFAULT ! iso-level lateral mixing DO_3D( 0, 0, 0, 0, 1, jpkm1 ) - ze3ua = ( 1._wp - r_vvl ) * e3u(ji,jj,jk,Kmm) & ! after scale factor at U-point - & + r_vvl * e3u(ji,jj,jk,Kaa) - zzwi = - zdt * ( avm(ji+1,jj,jk ) + avm(ji,jj,jk ) ) & - & / ( ze3ua * e3uw(ji,jj,jk ,Kmm) ) * wumask(ji,jj,jk ) - zzws = - zdt * ( avm(ji+1,jj,jk+1) + avm(ji,jj,jk+1) ) & - & / ( ze3ua * e3uw(ji,jj,jk+1,Kmm) ) * wumask(ji,jj,jk+1) - zWui = ( wi(ji,jj,jk ) + wi(ji+1,jj,jk ) ) / ze3ua - zWus = ( wi(ji,jj,jk+1) + wi(ji+1,jj,jk+1) ) / ze3ua - zwi(ji,jj,jk) = zzwi + zdt * MIN( zWui, 0._wp ) - zws(ji,jj,jk) = zzws - zdt * MAX( zWus, 0._wp ) - zwd(ji,jj,jk) = 1._wp - zzwi - zzws + zdt * ( MAX( zWui, 0._wp ) - MIN( zWus, 0._wp ) ) + z1_e3ua = 1._wp / e3u(ji,jj,jk,Kaa) ! after scale factor at U-point + zzwi = - zDt_2 * ( avm(ji+1,jj,jk ) + avm(ji,jj,jk ) ) & + & / e3uw(ji,jj,jk ,Kmm) * z1_e3ua * wumask(ji,jj,jk ) + zzws = - zDt_2 * ( avm(ji+1,jj,jk+1) + avm(ji,jj,jk+1) ) & + & / e3uw(ji,jj,jk+1,Kmm) * z1_e3ua * wumask(ji,jj,jk+1) + zWui = ( wi(ji,jj,jk ) + wi(ji+1,jj,jk ) ) * z1_e3ua + zWus = ( wi(ji,jj,jk+1) + wi(ji+1,jj,jk+1) ) * z1_e3ua + zwi(ji,jj,jk) = zzwi + zDt_2 * MIN( zWui, 0._wp ) + zws(ji,jj,jk) = zzws - zDt_2 * MAX( zWus, 0._wp ) + zwd(ji,jj,jk) = 1._wp - zzwi - zzws + zDt_2 * ( MAX( zWui, 0._wp ) - MIN( zWus, 0._wp ) ) END_3D END SELECT DO_2D( 0, 0, 0, 0 ) !* Surface boundary conditions zwi(ji,jj,1) = 0._wp - ze3ua = ( 1._wp - r_vvl ) * e3u(ji,jj,1,Kmm) & - & + r_vvl * e3u(ji,jj,1,Kaa) - zzws = - zdt * ( avm(ji+1,jj,2) + avm(ji ,jj,2) ) & - & / ( ze3ua * e3uw(ji,jj,2,Kmm) ) * wumask(ji,jj,2) - zWus = ( wi(ji ,jj,2) + wi(ji+1,jj,2) ) / ze3ua - zws(ji,jj,1 ) = zzws - zdt * MAX( zWus, 0._wp ) - zwd(ji,jj,1 ) = 1._wp - zzws - zdt * ( MIN( zWus, 0._wp ) ) + zzws = - zDt_2 * ( avm(ji+1,jj,2) + avm(ji ,jj,2) ) & + & / ( e3u(ji,jj,1,Kaa) * e3uw(ji,jj,2,Kmm) ) * wumask(ji,jj,2) + zWus = ( wi(ji ,jj,2) + wi(ji+1,jj,2) ) / e3u(ji,jj,1,Kaa) + zws(ji,jj,1 ) = zzws - zDt_2 * MAX( zWus, 0._wp ) + zwd(ji,jj,1 ) = 1._wp - zzws - zDt_2 * ( MIN( zWus, 0._wp ) ) END_2D ELSE SELECT CASE( nldf_dyn ) CASE( np_lap_i ) ! rotated lateral mixing: add its vertical mixing (akzu) DO_3D( 0, 0, 0, 0, 1, jpkm1 ) - ze3ua = ( 1._wp - r_vvl ) * e3u(ji,jj,jk,Kmm) & - & + r_vvl * e3u(ji,jj,jk,Kaa) ! after scale factor at U-point - zzwi = - zdt * ( avm(ji+1,jj,jk ) + avm(ji,jj,jk ) + akzu(ji,jj,jk ) ) & - & / ( ze3ua * e3uw(ji,jj,jk ,Kmm) ) * wumask(ji,jj,jk ) - zzws = - zdt * ( avm(ji+1,jj,jk+1) + avm(ji,jj,jk+1) + akzu(ji,jj,jk+1) ) & - & / ( ze3ua * e3uw(ji,jj,jk+1,Kmm) ) * wumask(ji,jj,jk+1) + zzwi = - zDt_2 * ( avm(ji+1,jj,jk ) + avm(ji,jj,jk ) + akzu(ji,jj,jk ) ) & + & / ( e3u(ji,jj,jk,Kaa) * e3uw(ji,jj,jk ,Kmm) ) * wumask(ji,jj,jk ) + zzws = - zDt_2 * ( avm(ji+1,jj,jk+1) + avm(ji,jj,jk+1) + akzu(ji,jj,jk+1) ) & + & / ( e3u(ji,jj,jk,Kaa) * e3uw(ji,jj,jk+1,Kmm) ) * wumask(ji,jj,jk+1) zwi(ji,jj,jk) = zzwi zws(ji,jj,jk) = zzws zwd(ji,jj,jk) = 1._wp - zzwi - zzws END_3D CASE DEFAULT ! iso-level lateral mixing DO_3D( 0, 0, 0, 0, 1, jpkm1 ) - ze3ua = ( 1._wp - r_vvl ) * e3u(ji,jj,jk,Kmm) & - & + r_vvl * e3u(ji,jj,jk,Kaa) ! after scale factor at U-point - zzwi = - zdt * ( avm(ji+1,jj,jk ) + avm(ji,jj,jk ) ) & - & / ( ze3ua * e3uw(ji,jj,jk ,Kmm) ) * wumask(ji,jj,jk ) - zzws = - zdt * ( avm(ji+1,jj,jk+1) + avm(ji,jj,jk+1) ) & - & / ( ze3ua * e3uw(ji,jj,jk+1,Kmm) ) * wumask(ji,jj,jk+1) + zzwi = - zDt_2 * ( avm(ji+1,jj,jk ) + avm(ji,jj,jk ) ) & + & / ( e3u(ji,jj,jk,Kaa) * e3uw(ji,jj,jk ,Kmm) ) * wumask(ji,jj,jk ) + zzws = - zDt_2 * ( avm(ji+1,jj,jk+1) + avm(ji,jj,jk+1) ) & + & / ( e3u(ji,jj,jk,Kaa) * e3uw(ji,jj,jk+1,Kmm) ) * wumask(ji,jj,jk+1) zwi(ji,jj,jk) = zzwi zws(ji,jj,jk) = zzws zwd(ji,jj,jk) = 1._wp - zzwi - zzws @@ -248,17 +232,15 @@ CONTAINS IF ( ln_drgimp ) THEN ! implicit bottom friction DO_2D( 0, 0, 0, 0 ) iku = mbku(ji,jj) ! ocean bottom level at u- and v-points - ze3ua = ( 1._wp - r_vvl ) * e3u(ji,jj,iku,Kmm) & - & + r_vvl * e3u(ji,jj,iku,Kaa) ! after scale factor at T-point - zwd(ji,jj,iku) = zwd(ji,jj,iku) - rDt * 0.5*( rCdU_bot(ji+1,jj)+rCdU_bot(ji,jj) ) / ze3ua + zwd(ji,jj,iku) = zwd(ji,jj,iku) - zDt_2 *( rCdU_bot(ji+1,jj)+rCdU_bot(ji,jj) ) & + & / e3u(ji,jj,iku,Kaa) END_2D IF ( ln_isfcav.OR.ln_drgice_imp ) THEN ! top friction (always implicit) DO_2D( 0, 0, 0, 0 ) !!gm top Cd is masked (=0 outside cavities) no need of test on mik>=2 ==>> it has been suppressed iku = miku(ji,jj) ! ocean top level at u- and v-points - ze3ua = ( 1._wp - r_vvl ) * e3u(ji,jj,iku,Kmm) & - & + r_vvl * e3u(ji,jj,iku,Kaa) ! after scale factor at T-point - zwd(ji,jj,iku) = zwd(ji,jj,iku) - rDt * 0.5*( rCdU_top(ji+1,jj)+rCdU_top(ji,jj) ) / ze3ua + zwd(ji,jj,iku) = zwd(ji,jj,iku) - zDt_2 *( rCdU_top(ji+1,jj)+rCdU_top(ji,jj) ) & + & / e3u(ji,jj,iku,Kaa) END_2D END IF ENDIF @@ -283,10 +265,14 @@ CONTAINS END_3D ! DO_2D( 0, 0, 0, 0 ) !== second recurrence: SOLk = RHSk - Lk / Dk-1 Lk-1 ==! - ze3ua = ( 1._wp - r_vvl ) * e3u(ji,jj,1,Kmm) & - & + r_vvl * e3u(ji,jj,1,Kaa) - puu(ji,jj,1,Kaa) = puu(ji,jj,1,Kaa) + rDt * 0.5_wp * ( utau_b(ji,jj) + utau(ji,jj) ) & - & / ( ze3ua * rho0 ) * umask(ji,jj,1) +#if defined key_RK3 + ! ! RK3: use only utau (not utau_b) + puu(ji,jj,1,Kaa) = puu(ji,jj,1,Kaa) + rDt * utau(ji,jj) & + & / ( e3u(ji,jj,1,Kaa) * rho0 ) * umask(ji,jj,1) +#else + puu(ji,jj,1,Kaa) = puu(ji,jj,1,Kaa) + zDt_2 * ( utau_b(ji,jj) + utau(ji,jj) ) & + & / ( e3u(ji,jj,1,Kaa) * rho0 ) * umask(ji,jj,1) +#endif END_2D DO_3D( 0, 0, 0, 0, 2, jpkm1 ) puu(ji,jj,jk,Kaa) = puu(ji,jj,jk,Kaa) - zwi(ji,jj,jk) / zwd(ji,jj,jk-1) * puu(ji,jj,jk-1,Kaa) @@ -302,70 +288,61 @@ CONTAINS ! !== Vertical diffusion on v ==! ! ! !* Matrix construction - zdt = rDt * 0.5 IF( ln_zad_Aimp ) THEN !! SELECT CASE( nldf_dyn ) CASE( np_lap_i ) ! rotated lateral mixing: add its vertical mixing (akzv) DO_3D( 0, 0, 0, 0, 1, jpkm1 ) - ze3va = ( 1._wp - r_vvl ) * e3v(ji,jj,jk,Kmm) & - & + r_vvl * e3v(ji,jj,jk,Kaa) ! after scale factor at V-point - zzwi = - zdt * ( avm(ji,jj+1,jk ) + avm(ji,jj,jk ) + akzv(ji,jj,jk ) ) & - & / ( ze3va * e3vw(ji,jj,jk ,Kmm) ) * wvmask(ji,jj,jk ) - zzws = - zdt * ( avm(ji,jj+1,jk+1) + avm(ji,jj,jk+1) + akzv(ji,jj,jk+1) ) & - & / ( ze3va * e3vw(ji,jj,jk+1,Kmm) ) * wvmask(ji,jj,jk+1) - zWvi = ( wi(ji,jj,jk ) + wi(ji,jj+1,jk ) ) / ze3va - zWvs = ( wi(ji,jj,jk+1) + wi(ji,jj+1,jk+1) ) / ze3va - zwi(ji,jj,jk) = zzwi + zdt * MIN( zWvi, 0._wp ) - zws(ji,jj,jk) = zzws - zdt * MAX( zWvs, 0._wp ) - zwd(ji,jj,jk) = 1._wp - zzwi - zzws - zdt * ( - MAX( zWvi, 0._wp ) + MIN( zWvs, 0._wp ) ) + z1_e3va = 1._wp / e3v(ji,jj,jk,Kaa) ! after scale factor at V-point + zzwi = - zDt_2 * ( avm(ji,jj+1,jk ) + avm(ji,jj,jk ) + akzv(ji,jj,jk ) ) & + & / e3vw(ji,jj,jk ,Kmm) * z1_e3va * wvmask(ji,jj,jk ) + zzws = - zDt_2 * ( avm(ji,jj+1,jk+1) + avm(ji,jj,jk+1) + akzv(ji,jj,jk+1) ) & + & / e3vw(ji,jj,jk+1,Kmm) * z1_e3va * wvmask(ji,jj,jk+1) + zWvi = ( wi(ji,jj,jk ) + wi(ji,jj+1,jk ) ) * z1_e3va + zWvs = ( wi(ji,jj,jk+1) + wi(ji,jj+1,jk+1) ) * z1_e3va + zwi(ji,jj,jk) = zzwi + zDt_2 * MIN( zWvi, 0._wp ) + zws(ji,jj,jk) = zzws - zDt_2 * MAX( zWvs, 0._wp ) + zwd(ji,jj,jk) = 1._wp - zzwi - zzws - zDt_2 * ( - MAX( zWvi, 0._wp ) + MIN( zWvs, 0._wp ) ) END_3D CASE DEFAULT ! iso-level lateral mixing DO_3D( 0, 0, 0, 0, 1, jpkm1 ) - ze3va = ( 1._wp - r_vvl ) * e3v(ji,jj,jk,Kmm) & - & + r_vvl * e3v(ji,jj,jk,Kaa) ! after scale factor at V-point - zzwi = - zdt * ( avm(ji,jj+1,jk ) + avm(ji,jj,jk ) ) & - & / ( ze3va * e3vw(ji,jj,jk ,Kmm) ) * wvmask(ji,jj,jk ) - zzws = - zdt * ( avm(ji,jj+1,jk+1) + avm(ji,jj,jk+1) ) & - & / ( ze3va * e3vw(ji,jj,jk+1,Kmm) ) * wvmask(ji,jj,jk+1) - zWvi = ( wi(ji,jj,jk ) + wi(ji,jj+1,jk ) ) / ze3va - zWvs = ( wi(ji,jj,jk+1) + wi(ji,jj+1,jk+1) ) / ze3va - zwi(ji,jj,jk) = zzwi + zdt * MIN( zWvi, 0._wp ) - zws(ji,jj,jk) = zzws - zdt * MAX( zWvs, 0._wp ) - zwd(ji,jj,jk) = 1._wp - zzwi - zzws - zdt * ( - MAX( zWvi, 0._wp ) + MIN( zWvs, 0._wp ) ) + z1_e3va = 1._wp / e3v(ji,jj,jk,Kaa) ! after scale factor at V-point + zzwi = - zDt_2 * ( avm(ji,jj+1,jk ) + avm(ji,jj,jk ) ) & + & / e3vw(ji,jj,jk ,Kmm) * z1_e3va * wvmask(ji,jj,jk ) + zzws = - zDt_2 * ( avm(ji,jj+1,jk+1) + avm(ji,jj,jk+1) ) & + & / e3vw(ji,jj,jk+1,Kmm) * z1_e3va * wvmask(ji,jj,jk+1) + zWvi = ( wi(ji,jj,jk ) + wi(ji,jj+1,jk ) ) * z1_e3va + zWvs = ( wi(ji,jj,jk+1) + wi(ji,jj+1,jk+1) ) * z1_e3va + zwi(ji,jj,jk) = zzwi + zDt_2 * MIN( zWvi, 0._wp ) + zws(ji,jj,jk) = zzws - zDt_2 * MAX( zWvs, 0._wp ) + zwd(ji,jj,jk) = 1._wp - zzwi - zzws - zDt_2 * ( - MAX( zWvi, 0._wp ) + MIN( zWvs, 0._wp ) ) END_3D END SELECT DO_2D( 0, 0, 0, 0 ) !* Surface boundary conditions zwi(ji,jj,1) = 0._wp - ze3va = ( 1._wp - r_vvl ) * e3v(ji,jj,1,Kmm) & - & + r_vvl * e3v(ji,jj,1,Kaa) - zzws = - zdt * ( avm(ji,jj+1,2) + avm(ji,jj,2) ) & - & / ( ze3va * e3vw(ji,jj,2,Kmm) ) * wvmask(ji,jj,2) - zWvs = ( wi(ji,jj ,2) + wi(ji,jj+1,2) ) / ze3va - zws(ji,jj,1 ) = zzws - zdt * MAX( zWvs, 0._wp ) - zwd(ji,jj,1 ) = 1._wp - zzws - zdt * ( MIN( zWvs, 0._wp ) ) + zzws = - zDt_2 * ( avm(ji,jj+1,2) + avm(ji,jj,2) ) & + & / ( e3v(ji,jj,1,Kaa) * e3vw(ji,jj,2,Kmm) ) * wvmask(ji,jj,2) + zWvs = ( wi(ji,jj ,2) + wi(ji,jj+1,2) ) / e3v(ji,jj,1,Kaa) + zws(ji,jj,1 ) = zzws - zDt_2 * MAX( zWvs, 0._wp ) + zwd(ji,jj,1 ) = 1._wp - zzws - zDt_2 * ( MIN( zWvs, 0._wp ) ) END_2D ELSE SELECT CASE( nldf_dyn ) CASE( np_lap_i ) ! rotated lateral mixing: add its vertical mixing (akzu) DO_3D( 0, 0, 0, 0, 1, jpkm1 ) - ze3va = ( 1._wp - r_vvl ) * e3v(ji,jj,jk,Kmm) & - & + r_vvl * e3v(ji,jj,jk,Kaa) ! after scale factor at V-point - zzwi = - zdt * ( avm(ji,jj+1,jk ) + avm(ji,jj,jk ) + akzv(ji,jj,jk ) ) & - & / ( ze3va * e3vw(ji,jj,jk ,Kmm) ) * wvmask(ji,jj,jk ) - zzws = - zdt * ( avm(ji,jj+1,jk+1) + avm(ji,jj,jk+1) + akzv(ji,jj,jk+1) ) & - & / ( ze3va * e3vw(ji,jj,jk+1,Kmm) ) * wvmask(ji,jj,jk+1) + zzwi = - zDt_2 * ( avm(ji,jj+1,jk ) + avm(ji,jj,jk ) + akzv(ji,jj,jk ) ) & + & / ( e3v(ji,jj,jk,Kaa) * e3vw(ji,jj,jk ,Kmm) ) * wvmask(ji,jj,jk ) + zzws = - zDt_2 * ( avm(ji,jj+1,jk+1) + avm(ji,jj,jk+1) + akzv(ji,jj,jk+1) ) & + & / ( e3v(ji,jj,jk,Kaa) * e3vw(ji,jj,jk+1,Kmm) ) * wvmask(ji,jj,jk+1) zwi(ji,jj,jk) = zzwi zws(ji,jj,jk) = zzws zwd(ji,jj,jk) = 1._wp - zzwi - zzws END_3D CASE DEFAULT ! iso-level lateral mixing DO_3D( 0, 0, 0, 0, 1, jpkm1 ) - ze3va = ( 1._wp - r_vvl ) * e3v(ji,jj,jk,Kmm) & - & + r_vvl * e3v(ji,jj,jk,Kaa) ! after scale factor at V-point - zzwi = - zdt * ( avm(ji,jj+1,jk ) + avm(ji,jj,jk ) ) & - & / ( ze3va * e3vw(ji,jj,jk ,Kmm) ) * wvmask(ji,jj,jk ) - zzws = - zdt * ( avm(ji,jj+1,jk+1) + avm(ji,jj,jk+1) ) & - & / ( ze3va * e3vw(ji,jj,jk+1,Kmm) ) * wvmask(ji,jj,jk+1) + zzwi = - zDt_2 * ( avm(ji,jj+1,jk ) + avm(ji,jj,jk ) ) & + & / ( e3v(ji,jj,jk,Kaa) * e3vw(ji,jj,jk ,Kmm) ) * wvmask(ji,jj,jk ) + zzws = - zDt_2 * ( avm(ji,jj+1,jk+1) + avm(ji,jj,jk+1) ) & + & / ( e3v(ji,jj,jk,Kaa) * e3vw(ji,jj,jk+1,Kmm) ) * wvmask(ji,jj,jk+1) zwi(ji,jj,jk) = zzwi zws(ji,jj,jk) = zzws zwd(ji,jj,jk) = 1._wp - zzwi - zzws @@ -386,16 +363,14 @@ CONTAINS IF( ln_drgimp ) THEN DO_2D( 0, 0, 0, 0 ) ikv = mbkv(ji,jj) ! (deepest ocean u- and v-points) - ze3va = ( 1._wp - r_vvl ) * e3v(ji,jj,ikv,Kmm) & - & + r_vvl * e3v(ji,jj,ikv,Kaa) ! after scale factor at T-point - zwd(ji,jj,ikv) = zwd(ji,jj,ikv) - rDt * 0.5*( rCdU_bot(ji,jj+1)+rCdU_bot(ji,jj) ) / ze3va + zwd(ji,jj,ikv) = zwd(ji,jj,ikv) - zDt_2*( rCdU_bot(ji,jj+1)+rCdU_bot(ji,jj) ) & + & / e3v(ji,jj,ikv,Kaa) END_2D IF ( ln_isfcav.OR.ln_drgice_imp ) THEN DO_2D( 0, 0, 0, 0 ) ikv = mikv(ji,jj) ! (first wet ocean u- and v-points) - ze3va = ( 1._wp - r_vvl ) * e3v(ji,jj,ikv,Kmm) & - & + r_vvl * e3v(ji,jj,ikv,Kaa) ! after scale factor at T-point - zwd(ji,jj,ikv) = zwd(ji,jj,ikv) - rDt * 0.5*( rCdU_top(ji,jj+1)+rCdU_top(ji,jj) ) / ze3va + zwd(ji,jj,ikv) = zwd(ji,jj,ikv) - zDt_2*( rCdU_top(ji,jj+1)+rCdU_top(ji,jj) ) & + & / e3v(ji,jj,ikv,Kaa) END_2D ENDIF ENDIF @@ -420,10 +395,14 @@ CONTAINS END_3D ! DO_2D( 0, 0, 0, 0 ) !== second recurrence: SOLk = RHSk - Lk / Dk-1 Lk-1 ==! - ze3va = ( 1._wp - r_vvl ) * e3v(ji,jj,1,Kmm) & - & + r_vvl * e3v(ji,jj,1,Kaa) - pvv(ji,jj,1,Kaa) = pvv(ji,jj,1,Kaa) + rDt * 0.5_wp * ( vtau_b(ji,jj) + vtau(ji,jj) ) & - & / ( ze3va * rho0 ) * vmask(ji,jj,1) +#if defined key_RK3 + ! ! RK3: use only vtau (not vtau_b) + pvv(ji,jj,1,Kaa) = pvv(ji,jj,1,Kaa) + rDt * vtau(ji,jj) & + & / ( e3v(ji,jj,1,Kaa) * rho0 ) * vmask(ji,jj,1) +#else + pvv(ji,jj,1,Kaa) = pvv(ji,jj,1,Kaa) + zDt_2*( vtau_b(ji,jj) + vtau(ji,jj) ) & + & / ( e3v(ji,jj,1,Kaa) * rho0 ) * vmask(ji,jj,1) +#endif END_2D DO_3D( 0, 0, 0, 0, 2, jpkm1 ) pvv(ji,jj,jk,Kaa) = pvv(ji,jj,jk,Kaa) - zwi(ji,jj,jk) / zwd(ji,jj,jk-1) * pvv(ji,jj,jk-1,Kaa) @@ -437,8 +416,8 @@ CONTAINS END_3D ! IF( l_trddyn ) THEN ! save the vertical diffusive trends for further diagnostics - ztrdu(:,:,:) = ( puu(:,:,:,Kaa) - puu(:,:,:,Kbb) ) / rDt - ztrdu(:,:,:) - ztrdv(:,:,:) = ( pvv(:,:,:,Kaa) - pvv(:,:,:,Kbb) ) / rDt - ztrdv(:,:,:) + ztrdu(:,:,:) = ( puu(:,:,:,Kaa) - puu(:,:,:,Kbb) )*r1_Dt - ztrdu(:,:,:) + ztrdv(:,:,:) = ( pvv(:,:,:,Kaa) - pvv(:,:,:,Kbb) )*r1_Dt - ztrdv(:,:,:) CALL trd_dyn( ztrdu, ztrdv, jpdyn_zdf, kt, Kmm ) DEALLOCATE( ztrdu, ztrdv ) ENDIF diff --git a/src/OCE/DYN/sshwzv.F90 b/src/OCE/DYN/sshwzv.F90 index bbe83c8c29241917583873e6c73b783e54c75362..0e2569708b8b4419148cddcaa94827a9fa65c3e7 100644 --- a/src/OCE/DYN/sshwzv.F90 +++ b/src/OCE/DYN/sshwzv.F90 @@ -16,7 +16,9 @@ MODULE sshwzv !!---------------------------------------------------------------------- !! ssh_nxt : after ssh !! ssh_atf : time filter the ssh arrays - !! wzv : compute now vertical velocity + !! wzv : generic interface of vertical velocity calculation + !! wzv_MLF : MLF: compute NOW vertical velocity + !! wzv_RK3 : RK3: Compute a vertical velocity !!---------------------------------------------------------------------- USE oce ! ocean dynamics and tracers variables USE isf_oce ! ice shelf @@ -43,6 +45,10 @@ MODULE sshwzv IMPLICIT NONE PRIVATE + ! !! * Interface + INTERFACE wzv + MODULE PROCEDURE wzv_MLF, wzv_RK3 + END INTERFACE PUBLIC ssh_nxt ! called by step.F90 PUBLIC wzv ! called by step.F90 @@ -54,7 +60,7 @@ MODULE sshwzv # include "domzgr_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/OCE 4.0 , NEMO Consortium (2018) - !! $Id: sshwzv.F90 15150 2021-07-27 10:38:24Z smasson $ + !! $Id: sshwzv.F90 14618 2021-03-19 14:42:32Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS @@ -76,10 +82,11 @@ CONTAINS INTEGER , INTENT(in ) :: kt ! time step INTEGER , INTENT(in ) :: Kbb, Kmm, Kaa ! time level index REAL(wp), DIMENSION(jpi,jpj,jpt), INTENT(inout) :: pssh ! sea-surface height - ! + ! INTEGER :: ji, jj, jk ! dummy loop index REAL(wp) :: zcoef ! local scalar REAL(wp), DIMENSION(jpi,jpj) :: zhdiv ! 2D workspace + REAL(wp), DIMENSION(jpi,jpj,jpk) :: z3d ! 3D workspace !!---------------------------------------------------------------------- ! IF( ln_timing ) CALL timing_start('ssh_nxt') @@ -91,12 +98,11 @@ CONTAINS ENDIF ! zcoef = 0.5_wp * r1_rho0 - ! !------------------------------! ! ! After Sea Surface Height ! ! !------------------------------! IF(ln_wd_il) THEN - CALL wad_lmt(pssh(:,:,Kbb), zcoef * (emp_b(:,:) + emp(:,:)), rDt, Kmm, uu, vv ) + CALL wad_lmt( pssh(:,:,Kbb), zcoef * (emp_b(:,:) + emp(:,:)), rDt, Kmm, uu, vv ) ENDIF CALL div_hor( kt, Kbb, Kmm ) ! Horizontal divergence @@ -110,7 +116,11 @@ CONTAINS ! compute the vertical velocity which can be used to compute the non-linear terms of the momentum equations. ! DO_2D_OVR( 1, nn_hls, 1, nn_hls ) ! Loop bounds limited by hdiv definition in div_hor - pssh(ji,jj,Kaa) = ( pssh(ji,jj,Kbb) - rDt * ( zcoef * ( emp_b(ji,jj) + emp(ji,jj) ) + zhdiv(ji,jj) ) ) * ssmask(ji,jj) +#if defined key_RK3 + pssh(ji,jj,Kaa) = ( pssh(ji,jj,Kbb) - rDt * ( r1_rho0 * emp(ji,jj) + zhdiv(ji,jj) ) ) * ssmask(ji,jj) +#else + pssh(ji,jj,Kaa) = ( pssh(ji,jj,Kbb) - rDt * ( zcoef * ( emp_b(ji,jj) + emp(ji,jj) ) + zhdiv(ji,jj) ) ) * ssmask(ji,jj) +#endif END_2D ! pssh must be defined everywhere (true for dyn_spg_ts, not for dyn_spg_exp) IF ( .NOT. ln_dynspg_ts .AND. nn_hls == 2 ) CALL lbc_lnk( 'sshwzv', pssh(:,:,Kaa), 'T', 1.0_wp ) @@ -123,23 +133,21 @@ CONTAINS IF ( .NOT.ln_dynspg_ts ) THEN IF( ln_bdy ) THEN IF (nn_hls==1) CALL lbc_lnk( 'sshwzv', pssh(:,:,Kaa), 'T', 1.0_wp ) ! Not sure that's necessary - CALL bdy_ssh( pssh(:,:,Kaa) ) ! Duplicate sea level across open boundaries + CALL bdy_ssh( pssh(:,:,Kaa) ) ! Duplicate sea level across open boundaries ENDIF ENDIF - ! !------------------------------! - ! ! outputs ! - ! !------------------------------! ! + ! ! Control print IF(sn_cfctl%l_prtctl) CALL prt_ctl( tab2d_1=pssh(:,:,Kaa), clinfo1=' pssh(:,:,Kaa) - : ', mask1=tmask ) ! IF( ln_timing ) CALL timing_stop('ssh_nxt') ! END SUBROUTINE ssh_nxt - - SUBROUTINE wzv( kt, Kbb, Kmm, Kaa, pww ) + + SUBROUTINE wzv_MLF( kt, Kbb, Kmm, Kaa, pww ) !!---------------------------------------------------------------------- - !! *** ROUTINE wzv *** + !! *** ROUTINE wzv_MLF *** !! !! ** Purpose : compute the now vertical velocity !! @@ -160,12 +168,12 @@ CONTAINS REAL(wp), ALLOCATABLE, DIMENSION(:,:,:) :: zhdiv !!---------------------------------------------------------------------- ! - IF( ln_timing ) CALL timing_start('wzv') + IF( ln_timing ) CALL timing_start('wzv_MLF') ! IF( kt == nit000 ) THEN IF(lwp) WRITE(numout,*) - IF(lwp) WRITE(numout,*) 'wzv : now vertical velocity ' - IF(lwp) WRITE(numout,*) '~~~~~ ' + IF(lwp) WRITE(numout,*) 'wzv_MLF : now vertical velocity ' + IF(lwp) WRITE(numout,*) '~~~~~~~' ! pww(:,:,jpk) = 0._wp ! bottom boundary condition: w=0 (set once for all) ENDIF @@ -198,7 +206,7 @@ CONTAINS & - e3t(ji,jj,jk,Kbb) ) ) * tmask(ji,jj,jk) END_3D ! IF( ln_vvl_layer ) pww(:,:,:) = 0.e0 - DEALLOCATE( zhdiv ) + DEALLOCATE( zhdiv ) ! !=================================! ELSEIF( ln_linssh ) THEN !== linear free surface cases ==! ! !=================================! @@ -209,9 +217,146 @@ CONTAINS ELSE !== Quasi-Eulerian vertical coordinate ==! ('key_qco') ! !==========================================! DO_3DS( nn_hls-1, nn_hls, nn_hls-1, nn_hls, jpkm1, 1, -1 ) ! integrate from the bottom the hor. divergence +#if defined key_qco +!!gm slightly faster + pww(ji,jj,jk) = pww(ji,jj,jk+1) - ( e3t(ji,jj,jk,Kmm) * hdiv(ji,jj,jk) & + & + r1_Dt * e3t_0(ji,jj,jk) * ( r3t(ji,jj,Kaa) - r3t(ji,jj,Kbb) ) ) * tmask(ji,jj,jk) +#else pww(ji,jj,jk) = pww(ji,jj,jk+1) - ( e3t(ji,jj,jk,Kmm) * hdiv(ji,jj,jk) & & + r1_Dt * ( e3t(ji,jj,jk,Kaa) & & - e3t(ji,jj,jk,Kbb) ) ) * tmask(ji,jj,jk) +#endif + END_3D + ENDIF + + IF( ln_bdy ) THEN + DO jk = 1, jpkm1 + DO_2D( nn_hls-1, nn_hls, nn_hls-1, nn_hls ) + pww(ji,jj,jk) = pww(ji,jj,jk) * bdytmask(ji,jj) + END_2D + END DO + ENDIF + ! +#if defined key_agrif + IF( .NOT. AGRIF_Root() ) THEN + ! + ! Mask vertical velocity at first/last columns/row + ! inside computational domain (cosmetic) + DO jk = 1, jpkm1 + IF( lk_west ) THEN ! --- West --- ! + DO ji = mi0(2+nn_hls), mi1(2+nn_hls) + DO jj = 1, jpj + pww(ji,jj,jk) = 0._wp + END DO + END DO + ENDIF + IF( lk_east ) THEN ! --- East --- ! + DO ji = mi0(jpiglo-1-nn_hls), mi1(jpiglo-1-nn_hls) + DO jj = 1, jpj + pww(ji,jj,jk) = 0._wp + END DO + END DO + ENDIF + IF( lk_south ) THEN ! --- South --- ! + DO jj = mj0(2+nn_hls), mj1(2+nn_hls) + DO ji = 1, jpi + pww(ji,jj,jk) = 0._wp + END DO + END DO + ENDIF + IF( lk_north ) THEN ! --- North --- ! + DO jj = mj0(jpjglo-1-nn_hls), mj1(jpjglo-1-nn_hls) + DO ji = 1, jpi + pww(ji,jj,jk) = 0._wp + END DO + END DO + ENDIF + ! + END DO + ! + ENDIF +#endif + ! + IF( ln_timing ) CALL timing_stop('wzv_MLF') + ! + END SUBROUTINE wzv_MLF + + + SUBROUTINE wzv_RK3( kt, Kbb, Kmm, Kaa, puu, pvv, pww ) + !!---------------------------------------------------------------------- + !! *** ROUTINE wzv_RK3 *** + !! + !! ** Purpose : compute the now vertical velocity + !! + !! ** Method : - Using the incompressibility hypothesis, the vertical + !! velocity is computed by integrating the horizontal divergence + !! from the bottom to the surface minus the scale factor evolution. + !! The boundary conditions are w=0 at the bottom (no flux) and. + !! + !! ** action : pww : now vertical velocity + !! + !! Reference : Leclair, M., and G. Madec, 2009, Ocean Modelling. + !!---------------------------------------------------------------------- + INTEGER , INTENT(in ) :: kt ! time step + INTEGER , INTENT(in ) :: Kbb, Kmm, Kaa ! time level indices + REAL(wp), DIMENSION(jpi,jpj,jpk), INTENT(in ) :: puu, pvv ! horizontal velocity at Kmm + REAL(wp), DIMENSION(jpi,jpj,jpk), INTENT(inout) :: pww ! vertical velocity at Kmm + ! + INTEGER :: ji, jj, jk ! dummy loop indices + REAL(wp), ALLOCATABLE, DIMENSION(:,:,:) :: zhdiv + REAL(wp) , DIMENSION(jpi,jpj,jpk) :: ze3div + !!---------------------------------------------------------------------- + ! + IF( ln_timing ) CALL timing_start('wzv_RK3') + ! + IF( kt == nit000 ) THEN + IF(lwp) WRITE(numout,*) + IF(lwp) WRITE(numout,*) 'wzv_RK3 : now vertical velocity ' + IF(lwp) WRITE(numout,*) '~~~~~ ' + ! + pww(:,:,jpk) = 0._wp ! bottom boundary condition: w=0 (set once for all) + ENDIF + ! + CALL div_hor( kt, Kbb, Kmm, puu, pvv, ze3div ) + ! !------------------------------! + ! ! Now Vertical Velocity ! + ! !------------------------------! + ! + ! !===============================! + IF( ln_vvl_ztilde .OR. ln_vvl_layer ) THEN !== z_tilde and layer cases ==! + ! !===============================! + ALLOCATE( zhdiv(jpi,jpj,jpk) ) + ! + DO jk = 1, jpkm1 + ! horizontal divergence of thickness diffusion transport ( velocity multiplied by e3t) + ! - ML - note: computation already done in dom_vvl_sf_nxt. Could be optimized (not critical and clearer this way) + DO_2D( nn_hls-1, nn_hls, nn_hls-1, nn_hls ) + zhdiv(ji,jj,jk) = r1_e1e2t(ji,jj) * ( un_td(ji,jj,jk) - un_td(ji-1,jj,jk) + vn_td(ji,jj,jk) - vn_td(ji,jj-1,jk) ) + END_2D + END DO + IF( nn_hls == 1) CALL lbc_lnk('sshwzv', zhdiv, 'T', 1.0_wp) ! - ML - Perhaps not necessary: not used for horizontal "connexions" + ! ! Is it problematic to have a wrong vertical velocity in boundary cells? + ! ! Same question holds for hdiv. Perhaps just for security + DO_3DS( nn_hls-1, nn_hls, nn_hls-1, nn_hls, jpkm1, 1, -1 ) ! integrate from the bottom the hor. divergence + pww(ji,jj,jk) = pww(ji,jj,jk+1) - ( ze3div(ji,jj,jk) + zhdiv(ji,jj,jk) & + & + r1_Dt * ( e3t(ji,jj,jk,Kaa) & + & - e3t(ji,jj,jk,Kbb) ) ) * tmask(ji,jj,jk) + END_3D + ! + DEALLOCATE( zhdiv ) + ! !=================================! + ELSEIF( ln_linssh ) THEN !== linear free surface cases ==! + ! !=================================! + DO_3DS( nn_hls-1, nn_hls, nn_hls-1, nn_hls, jpkm1, 1, -1 ) ! integrate from the bottom the hor. divergence + pww(ji,jj,jk) = pww(ji,jj,jk+1) - ze3div(ji,jj,jk) + END_3D + ! !==========================================! + ELSE !== Quasi-Eulerian vertical coordinate ==! ('key_qco') + ! !==========================================! + DO_3DS( nn_hls-1, nn_hls, nn_hls-1, nn_hls, jpkm1, 1, -1 ) ! integrate from the bottom the hor. divergence + ! ! NB: [e3t[a] -e3t[b] ]=e3t_0*[r3t[a]-r3t[b]] + pww(ji,jj,jk) = pww(ji,jj,jk+1) - ( ze3div(ji,jj,jk) & + & + r1_Dt * e3t_0(ji,jj,jk) * ( r3t(ji,jj,Kaa) - r3t(ji,jj,Kbb) ) ) * tmask(ji,jj,jk) END_3D ENDIF @@ -263,9 +408,9 @@ CONTAINS ENDIF #endif ! - IF( ln_timing ) CALL timing_stop('wzv') + IF( ln_timing ) CALL timing_stop('wzv_RK3') ! - END SUBROUTINE wzv + END SUBROUTINE wzv_RK3 SUBROUTINE ssh_atf( kt, Kbb, Kmm, Kaa, pssh ) diff --git a/src/OCE/IOM/iom.F90 b/src/OCE/IOM/iom.F90 index f6ac95b9274941401aabc032ec7056627736b1f9..d66b13d1952f6e3973963acd142394caca868e29 100644 --- a/src/OCE/IOM/iom.F90 +++ b/src/OCE/IOM/iom.F90 @@ -55,6 +55,7 @@ MODULE iom #else LOGICAL, PUBLIC, PARAMETER :: lk_iomput = .FALSE. !: iom_put flag #endif + LOGICAL, PUBLIC :: l_iom = .TRUE. !: RK3 iom flag prevent writing at stage 1&2 PUBLIC iom_init, iom_init_closedef, iom_swap, iom_open, iom_close, iom_setkt, iom_varid, iom_get, iom_get_var PUBLIC iom_chkatt, iom_getatt, iom_putatt, iom_getszuld, iom_rstput, iom_delay_rst, iom_put PUBLIC iom_use, iom_context_finalize, iom_update_file_name, iom_miss_val @@ -98,7 +99,7 @@ MODULE iom # include "do_loop_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/OCE 4.0 , NEMO Consortium (2018) - !! $Id: iom.F90 15033 2021-06-21 10:24:45Z smasson $ + !! $Id: iom.F90 15512 2021-11-15 17:22:03Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS diff --git a/src/OCE/IOM/restart.F90 b/src/OCE/IOM/restart.F90 index 783247cc1a063303d335fc67727cd9716be3da43..32e23127996f4c17c31f755174c50a24875e7eb4 100644 --- a/src/OCE/IOM/restart.F90 +++ b/src/OCE/IOM/restart.F90 @@ -52,7 +52,7 @@ MODULE restart # include "domzgr_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/OCE 4.0 , NEMO Consortium (2018) - !! $Id: restart.F90 15141 2021-07-23 14:20:12Z smasson $ + !! $Id: restart.F90 15027 2021-06-19 08:14:22Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS @@ -143,7 +143,7 @@ CONTAINS END SUBROUTINE rst_opn - SUBROUTINE rst_write( kt, Kbb, Kmm ) + SUBROUTINE rst_write( kt, Kbb, Kmm, Kaa ) !!--------------------------------------------------------------------- !! *** ROUTINE rstwrite *** !! @@ -157,6 +157,7 @@ CONTAINS !!---------------------------------------------------------------------- INTEGER, INTENT(in) :: kt ! ocean time-step INTEGER, INTENT(in) :: Kbb, Kmm ! ocean time level indices + INTEGER, OPTIONAL, INTENT(in) :: Kaa ! ocean time level index required for RK3 !!---------------------------------------------------------------------- ! CALL iom_rstput( kt, nitrst, numrow, 'rdt' , rn_Dt ) ! dynamics time step @@ -164,19 +165,27 @@ CONTAINS IF( .NOT.lwxios ) CALL iom_delay_rst( 'WRITE', 'OCE', numrow ) ! save only ocean delayed global communication variables ! IF( .NOT.ln_diurnal_only ) THEN + ! +#if defined key_RK3 + CALL iom_rstput( kt, nitrst, numrow, 'sshn', ssh(:,: ,Kbb) ) ! before fields + CALL iom_rstput( kt, nitrst, numrow, 'un' , uu(:,:,: ,Kbb) ) + CALL iom_rstput( kt, nitrst, numrow, 'vn' , vv(:,:,: ,Kbb) ) + CALL iom_rstput( kt, nitrst, numrow, 'tn' , ts(:,:,:,jp_tem,Kbb) ) + CALL iom_rstput( kt, nitrst, numrow, 'sn' , ts(:,:,:,jp_sal,Kbb) ) + CALL iom_rstput( kt, nitrst, numrow, 'uu_n' , uu_b(:,: ,Kbb) ) + CALL iom_rstput( kt, nitrst, numrow, 'vv_n' , vv_b(:,: ,Kbb) ) +#else CALL iom_rstput( kt, nitrst, numrow, 'sshb', ssh(:,: ,Kbb) ) ! before fields CALL iom_rstput( kt, nitrst, numrow, 'ub' , uu(:,:,: ,Kbb) ) CALL iom_rstput( kt, nitrst, numrow, 'vb' , vv(:,:,: ,Kbb) ) CALL iom_rstput( kt, nitrst, numrow, 'tb' , ts(:,:,:,jp_tem,Kbb) ) CALL iom_rstput( kt, nitrst, numrow, 'sb' , ts(:,:,:,jp_sal,Kbb) ) - ! -#if ! defined key_RK3 - CALL iom_rstput( kt, nitrst, numrow, 'sshn', ssh(:,: ,Kmm) ) ! now fields + + CALL iom_rstput( kt, nitrst, numrow, 'sshn', ssh(:,: ,Kmm) ) ! now fields CALL iom_rstput( kt, nitrst, numrow, 'un' , uu(:,:,: ,Kmm) ) CALL iom_rstput( kt, nitrst, numrow, 'vn' , vv(:,:,: ,Kmm) ) CALL iom_rstput( kt, nitrst, numrow, 'tn' , ts(:,:,:,jp_tem,Kmm) ) CALL iom_rstput( kt, nitrst, numrow, 'sn' , ts(:,:,:,jp_sal,Kmm) ) - IF( .NOT.lk_SWE ) CALL iom_rstput( kt, nitrst, numrow, 'rhop', rhop ) #endif ENDIF @@ -264,6 +273,7 @@ CONTAINS !!---------------------------------------------------------------------- INTEGER , INTENT(in) :: Kbb, Kmm ! ocean time level indices INTEGER :: jk + INTEGER :: id1 REAL(wp), DIMENSION(jpi, jpj, jpk) :: w3d REAL(wp), ALLOCATABLE, DIMENSION(:,:,:) :: zgdept ! 3D workspace for QCO !!---------------------------------------------------------------------- @@ -284,10 +294,30 @@ CONTAINS #if defined key_RK3 ! !* Read Kbb fields (NB: in RK3 Kmm = Kbb = Nbb) IF(lwp) WRITE(numout,*) ' Kbb u, v and T-S fields read in the restart file' - CALL iom_get( numror, jpdom_auto, 'ub', uu(:,:,: ,Kbb), cd_type = 'U', psgn = -1._wp ) - CALL iom_get( numror, jpdom_auto, 'vb', vv(:,:,: ,Kbb), cd_type = 'V', psgn = -1._wp ) - CALL iom_get( numror, jpdom_auto, 'tb', ts(:,:,:,jp_tem,Kbb) ) - CALL iom_get( numror, jpdom_auto, 'sb', ts(:,:,:,jp_sal,Kbb) ) + CALL iom_get( numror, jpdom_auto, 'un' , uu(:,:,: ,Kbb), cd_type = 'U', psgn = -1._wp ) + CALL iom_get( numror, jpdom_auto, 'vn' , vv(:,:,: ,Kbb), cd_type = 'V', psgn = -1._wp ) + CALL iom_get( numror, jpdom_auto, 'tn' , ts(:,:,:,jp_tem,Kbb) ) + CALL iom_get( numror, jpdom_auto, 'sn' , ts(:,:,:,jp_sal,Kbb) ) + id1 = iom_varid( numror, 'uu_n', ldstop = .FALSE. ) !* check presence + IF( id1 > 0 ) THEN + CALL iom_get( numror, jpdom_auto, 'uu_n' , uu_b(:,:,Kbb), cd_type = 'U', psgn = -1._wp ) + CALL iom_get( numror, jpdom_auto, 'vv_n' , vv_b(:,:,Kbb), cd_type = 'V', psgn = -1._wp ) + ELSE + uu_b(:,:,Kbb) = uu(:,:,1,Kbb)*e3u_0(:,:,1)*umask(:,:,1) + vv_b(:,:,Kbb) = vv(:,:,1,Kbb)*e3v_0(:,:,1)*vmask(:,:,1) + DO jk = 2, jpkm1 + uu_b(:,:,Kbb) = uu_b(:,:,Kbb) + uu(:,:,jk,Kbb)*e3u_0(:,:,jk)*umask(:,:,jk) + vv_b(:,:,Kbb) = vv_b(:,:,Kbb) + vv(:,:,jk,Kbb)*e3v_0(:,:,jk)*vmask(:,:,jk) + END DO + uu_b(:,:,Kbb) = uu_b(:,:,Kbb) * r1_hu_0(:,:) + vv_b(:,:,Kbb) = vv_b(:,:,Kbb) * r1_hv_0(:,:) + ENDIF + uu(:,:,: ,Kmm) = uu(:,:,: ,Kbb) ! Kmm values set to Kbb for initialisation (sbc_ssm_init) + vv(:,:,: ,Kmm) = vv(:,:,: ,Kbb) + ts(:,:,:,:,Kmm) = ts(:,:,:,:,Kbb) + ! + uu_b(:,:,Kmm) = uu_b(:,:,Kbb) ! Kmm value set to Kbb for initialisation in Agrif_Regrid + vv_b(:,:,Kmm) = vv_b(:,:,Kbb) #else ! !* Read Kmm fields (MLF only) IF(lwp) WRITE(numout,*) ' Kmm u, v and T-S fields read in the restart file' @@ -311,23 +341,6 @@ CONTAINS ENDIF #endif ! - IF( .NOT.lk_SWE ) THEN - IF( iom_varid( numror, 'rhop', ldstop = .FALSE. ) > 0 ) THEN - CALL iom_get( numror, jpdom_auto, 'rhop' , rhop ) ! now potential density - ELSE -#if defined key_qco - ALLOCATE( zgdept(jpi,jpj,jpk) ) - DO jk = 1, jpk - zgdept(:,:,jk) = gdept(:,:,jk,Kmm) - END DO - CALL eos( ts(:,:,:,:,Kmm), rhd, rhop, zgdept ) - DEALLOCATE( zgdept ) -#else - CALL eos( ts(:,:,:,:,Kmm), rhd, rhop, gdept(:,:,:,Kmm) ) -#endif - ENDIF - ENDIF - ! END SUBROUTINE rst_read @@ -367,10 +380,11 @@ CONTAINS ! !* RK3: Read ssh at Kbb IF(lwp) WRITE(numout,*) IF(lwp) WRITE(numout,*) ' Kbb sea surface height read in the restart file' - CALL iom_get( numror, jpdom_auto, 'sshb' , ssh(:,:,Kbb) ) + CALL iom_get( numror, jpdom_auto, 'sshn' , ssh(:,:,Kbb) ) ! ! !* RK3: Set ssh at Kmm for AGRIF - ssh(:,:,Kmm) = 0._wp + ssh(:,:,Kmm) = ssh(:,:,Kbb) + ! #else ! !* MLF: Read ssh at Kmm IF(lwp) WRITE(numout,*) @@ -420,14 +434,11 @@ CONTAINS ! ENDIF #if defined key_agrif - ! Set ghosts points from parent - IF (.NOT.Agrif_Root()) CALL Agrif_istate_ssh( Kbb, Kmm, Kaa, .true. ) -#endif -#if defined key_RK3 - ssh(:,:,Kmm) = 0._wp !* RK3: set Kmm to 0 for AGRIF -#else - ssh(:,:,Kmm) = ssh(:,:,Kbb) !* MLF: set now values from to before ones + ! Set ghosts points from parent + IF (.NOT.Agrif_Root()) CALL Agrif_istate_ssh( Kbb, Kmm, Kaa, .true. ) #endif + ! + ssh(:,:,Kmm) = ssh(:,:,Kbb) !* set now values from to before ones ENDIF ! ! !==========================! diff --git a/src/OCE/ISF/isfhdiv.F90 b/src/OCE/ISF/isfhdiv.F90 index d8b8264d8327b7437e595b0151c11fd83af1d52b..772ab9a7440cccbb8f1c569ec42de059b4da250c 100644 --- a/src/OCE/ISF/isfhdiv.F90 +++ b/src/OCE/ISF/isfhdiv.F90 @@ -71,6 +71,7 @@ CONTAINS ! END SUBROUTINE isf_hdiv + SUBROUTINE isf_hdiv_mlt(ktop, kbot, phtbl, pfrac, pfwf, pfwf_b, phdiv) !!---------------------------------------------------------------------- !! *** SUBROUTINE sbc_isf_div *** @@ -97,7 +98,11 @@ CONTAINS ! ! compute integrated divergence correction DO_2D( nn_hls-1, nn_hls, nn_hls-1, nn_hls ) +#if defined key_RK3 + zhdiv(ji,jj) = pfwf(ji,jj) * r1_rho0 / phtbl(ji,jj) +#else zhdiv(ji,jj) = 0.5_wp * ( pfwf(ji,jj) + pfwf_b(ji,jj) ) * r1_rho0 / phtbl(ji,jj) +#endif END_2D ! ! update divergence at each level affected by ice shelf top boundary layer diff --git a/src/OCE/LDF/ldftra.F90 b/src/OCE/LDF/ldftra.F90 index 5aaeecd83377adecee77293f3be7b023a3a7c4cb..87e1d746557589acb22e01749b03156bbc5172cb 100644 --- a/src/OCE/LDF/ldftra.F90 +++ b/src/OCE/LDF/ldftra.F90 @@ -67,6 +67,8 @@ MODULE ldftra ! != Use/diagnose eiv =! LOGICAL , PUBLIC :: ln_ldfeiv !: eddy induced velocity flag LOGICAL , PUBLIC :: ln_ldfeiv_dia !: diagnose & output eiv streamfunction and velocity (IOM) + LOGICAL , PUBLIC :: l_ldfeiv_dia !: RK3: modified w.r.t. kstg diagnose & output eiv streamfunction and velocity flag + ! != Coefficients =! INTEGER , PUBLIC :: nn_aei_ijk_t !: choice of time/space variation of the eiv coeff. REAL(wp), PUBLIC :: rn_Ue !: lateral diffusive velocity [m/s] @@ -97,7 +99,7 @@ MODULE ldftra # include "domzgr_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/OCE 4.0 , NEMO Consortium (2018) - !! $Id: ldftra.F90 15475 2021-11-05 14:14:45Z cdllod $ + !! $Id: ldftra.F90 15512 2021-11-15 17:22:03Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS @@ -768,7 +770,11 @@ CONTAINS END_3D ! ! ! diagnose the eddy induced velocity and associated heat transport +#if defined key_RK3 + IF( l_ldfeiv_dia .AND. cdtype == 'TRA' ) CALL ldf_eiv_dia( zpsi_uw, zpsi_vw, Kmm ) +#else IF( ln_ldfeiv_dia .AND. cdtype == 'TRA' ) CALL ldf_eiv_dia( zpsi_uw, zpsi_vw, Kmm ) +#endif ! END SUBROUTINE ldf_eiv_trp @@ -867,7 +873,7 @@ CONTAINS CALL iom_put( "veiv_heattr" , zztmp * zw2d ) ! heat transport in j-direction CALL iom_put( "veiv_heattr3d", zztmp * zw3d ) ! heat transport in j-direction ! - IF( iom_use( 'sophteiv' ) ) CALL dia_ptr_hst( jp_tem, 'eiv', 0.5 * zw3d ) + IF( iom_use( 'sophteiv' ) .AND. l_diaptr ) CALL dia_ptr_hst( jp_tem, 'eiv', 0.5 * zw3d ) ! zztmp = 0.5_wp * 0.5 IF( iom_use('ueiv_salttr') .OR. iom_use('ueiv_salttr3d')) THEN @@ -891,7 +897,7 @@ CONTAINS CALL iom_put( "veiv_salttr" , zztmp * zw2d ) ! salt transport in j-direction CALL iom_put( "veiv_salttr3d", zztmp * zw3d ) ! salt transport in j-direction ! - IF( iom_use( 'sopsteiv' ) ) CALL dia_ptr_hst( jp_sal, 'eiv', 0.5 * zw3d ) + IF( iom_use( 'sopsteiv' ) .AND. l_diaptr ) CALL dia_ptr_hst( jp_sal, 'eiv', 0.5 * zw3d ) ! ! END SUBROUTINE ldf_eiv_dia diff --git a/src/OCE/SBC/sbcmod.F90 b/src/OCE/SBC/sbcmod.F90 index 34764262decdcaa7680b6b9ec654d154a63caaeb..30ee55c7c0dbb66d89024718ff621af8b2c4f73d 100644 --- a/src/OCE/SBC/sbcmod.F90 +++ b/src/OCE/SBC/sbcmod.F90 @@ -537,7 +537,11 @@ CONTAINS ! IF( kt == nit000 ) THEN ! set the forcing field at nit000 - 1 ! ! ! ---------------------------------------- ! - IF( ln_rstart .AND. .NOT.l_1st_euler ) THEN !* Restart: read in restart file +#if defined key_RK3 + IF( ln_rstart .AND. lk_SWE ) THEN !* RK3 + SWE: Restart: read in restart file +#else + IF( ln_rstart .AND. .NOT.l_1st_euler ) THEN !* MLF: Restart: read in restart file +#endif IF(lwp) WRITE(numout,*) ' nit000-1 surface forcing fields read in the restart file' CALL iom_get( numror, jpdom_auto, 'utau_b', utau_b ) ! i-stress CALL iom_get( numror, jpdom_auto, 'vtau_b', vtau_b ) ! j-stress @@ -559,9 +563,17 @@ CONTAINS sfx_b (:,:) = sfx (:,:) ENDIF ENDIF + ! +#if defined key_RK3 + ! ! ---------------------------------------- ! + IF( lrst_oce .AND. lk_SWE ) THEN ! RK3: Write in the ocean restart file ! + ! ! ---------------------------------------- ! +#else ! ! ---------------------------------------- ! - IF( lrst_oce ) THEN ! Write in the ocean restart file ! + IF( lrst_oce ) THEN ! MLF: Write in the ocean restart file ! ! ! ---------------------------------------- ! +#endif + ! IF(lwp) WRITE(numout,*) IF(lwp) WRITE(numout,*) 'sbc : ocean surface forcing fields written in ocean restart file ', & & 'at it= ', kt,' date= ', ndastp diff --git a/src/OCE/SBC/sbcrnf.F90 b/src/OCE/SBC/sbcrnf.F90 index 1a2d0df69f28095d5f12e630d145831bfbf3fe81..758d4f4ba0c3038309ca5c2a251381b8e3ff438a 100644 --- a/src/OCE/SBC/sbcrnf.F90 +++ b/src/OCE/SBC/sbcrnf.F90 @@ -74,7 +74,7 @@ MODULE sbcrnf # include "domzgr_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/OCE 4.0 , NEMO Consortium (2018) - !! $Id: sbcrnf.F90 15190 2021-08-13 12:52:50Z gsamson $ + !! $Id: sbcrnf.F90 14993 2021-06-14 22:35:18Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS @@ -206,13 +206,17 @@ CONTAINS REAL(wp) :: zfact ! local scalar !!---------------------------------------------------------------------- ! - zfact = 0.5_wp + zfact = 0.5_wp * r1_rho0 ! IF( ln_rnf_depth .OR. ln_rnf_depth_ini ) THEN !== runoff distributed over several levels ==! IF( ln_linssh ) THEN !* constant volume case : just apply the runoff input flow DO_2D_OVR( nn_hls-1, nn_hls, nn_hls-1, nn_hls ) DO jk = 1, nk_rnf(ji,jj) - phdivn(ji,jj,jk) = phdivn(ji,jj,jk) - ( rnf(ji,jj) + rnf_b(ji,jj) ) * zfact * r1_rho0 / h_rnf(ji,jj) +#if defined key_RK3 + phdivn(ji,jj,jk) = phdivn(ji,jj,jk) - rnf(ji,jj) * r1_rho0 / h_rnf(ji,jj) ! RK3: rnf forcing at n+1/2 +#else + phdivn(ji,jj,jk) = phdivn(ji,jj,jk) - ( rnf(ji,jj) + rnf_b(ji,jj) ) * zfact / h_rnf(ji,jj) ! MLF: rnf forcing at Kmm (n) +#endif END DO END_2D ELSE !* variable volume case @@ -224,7 +228,11 @@ CONTAINS END_2D DO_2D_OVR( nn_hls-1, nn_hls, nn_hls-1, nn_hls ) ! apply the runoff input flow DO jk = 1, nk_rnf(ji,jj) - phdivn(ji,jj,jk) = phdivn(ji,jj,jk) - ( rnf(ji,jj) + rnf_b(ji,jj) ) * zfact * r1_rho0 / h_rnf(ji,jj) +#if defined key_RK3 + phdivn(ji,jj,jk) = phdivn(ji,jj,jk) - rnf(ji,jj) * r1_rho0 / h_rnf(ji,jj) ! RK3: rnf forcing at n+1/2 +#else + phdivn(ji,jj,jk) = phdivn(ji,jj,jk) - ( rnf(ji,jj) + rnf_b(ji,jj) ) * zfact / h_rnf(ji,jj) ! MLF: rnf forcing at Kmm (n) +#endif END DO END_2D ENDIF @@ -233,7 +241,11 @@ CONTAINS h_rnf (ji,jj) = e3t(ji,jj,1,Kmm) ! update h_rnf to be depth of top box END_2D DO_2D_OVR( nn_hls-1, nn_hls, nn_hls-1, nn_hls ) - phdivn(ji,jj,1) = phdivn(ji,jj,1) - ( rnf(ji,jj) + rnf_b(ji,jj) ) * zfact * r1_rho0 / e3t(ji,jj,1,Kmm) +#if defined key_RK3 + phdivn(ji,jj,1) = phdivn(ji,jj,1) - rnf(ji,jj) * r1_rho0 / e3t(ji,jj,1,Kmm) ! RK3: rnf forcing at n+1/2 +#else + phdivn(ji,jj,1) = phdivn(ji,jj,1) - ( rnf(ji,jj) + rnf_b(ji,jj) ) * zfact / e3t(ji,jj,1,Kmm) ! MLF: rnf forcing at Kmm (n) +#endif END_2D ENDIF ! diff --git a/src/OCE/SBC/sbcssm.F90 b/src/OCE/SBC/sbcssm.F90 index 95e64875363eb85952e4b5b8c5a1dbd72963b9e8..1db7fb00a76649dbac077eb4d7e9f56a6c78a676 100644 --- a/src/OCE/SBC/sbcssm.F90 +++ b/src/OCE/SBC/sbcssm.F90 @@ -64,7 +64,12 @@ CONTAINS zts(:,:,jp_tem) = ts(:,:,1,jp_tem,Kmm) zts(:,:,jp_sal) = ts(:,:,1,jp_sal,Kmm) ! - ! ! ---------------------------------------- ! + ! !===>>> CAUTION: lbc_lnk is required on fraqsr_lev since sea ice computes on the full domain + ! ! otherwise restartability and reproducibility are broken + ! ! computed in traqsr only on the inner domain + CALL lbc_lnk( 'sbc_ssm', fraqsr_1lev(:,:), 'T', 1._wp ) + ! + ! ! ---------------------------------------- ! IF( nn_fsbc == 1 ) THEN ! Instantaneous surface fields ! ! ! ---------------------------------------- ! ssu_m(:,:) = uu(:,:,1,Kbb) @@ -74,7 +79,11 @@ CONTAINS ENDIF sss_m(:,:) = zts(:,:,jp_sal) ! ! removed inverse barometer ssh when Patm forcing is used (for sea-ice dynamics) - IF( ln_apr_dyn ) THEN ; ssh_m(:,:) = ssh(:,:,Kmm) - 0.5 * ( ssh_ib(:,:) + ssh_ibb(:,:) ) +#if defined key_RK3 + IF( ln_apr_dyn ) THEN ; ssh_m(:,:) = ssh(:,:,Kmm) - ssh_ib(:,:) ! RK3: forcing at n+1/2 +#else + IF( ln_apr_dyn ) THEN ; ssh_m(:,:) = ssh(:,:,Kmm) - 0.5 * ( ssh_ib(:,:) + ssh_ibb(:,:) ) ! MLF: forcing at n (Kmm) +#endif ELSE ; ssh_m(:,:) = ssh(:,:,Kmm) ENDIF ! @@ -97,7 +106,11 @@ CONTAINS ENDIF sss_m(:,:) = zcoef * zts(:,:,jp_sal) ! ! removed inverse barometer ssh when Patm forcing is used (for sea-ice dynamics) +#if defined key_RK3 + IF( ln_apr_dyn ) THEN ; ssh_m(:,:) = zcoef * ( ssh(:,:,Kmm) - ssh_ib(:,:) ) +#else IF( ln_apr_dyn ) THEN ; ssh_m(:,:) = zcoef * ( ssh(:,:,Kmm) - 0.5 * ( ssh_ib(:,:) + ssh_ibb(:,:) ) ) +#endif ELSE ; ssh_m(:,:) = zcoef * ssh(:,:,Kmm) ENDIF ! @@ -125,7 +138,11 @@ CONTAINS ENDIF sss_m(:,:) = sss_m(:,:) + zts(:,:,jp_sal) ! ! removed inverse barometer ssh when Patm forcing is used (for sea-ice dynamics) +#if defined key_RK3 + IF( ln_apr_dyn ) THEN ; ssh_m(:,:) = ssh_m(:,:) + ssh(:,:,Kmm) - ssh_ib(:,:) +#else IF( ln_apr_dyn ) THEN ; ssh_m(:,:) = ssh_m(:,:) + ssh(:,:,Kmm) - 0.5 * ( ssh_ib(:,:) + ssh_ibb(:,:) ) +#endif ELSE ; ssh_m(:,:) = ssh_m(:,:) + ssh(:,:,Kmm) ENDIF ! diff --git a/src/OCE/TRA/eosbn2.F90 b/src/OCE/TRA/eosbn2.F90 index 1c461517e7ddc65b16ca2e32bd40f6a18d789361..81fda25e0249bd92da7d324c7e133ee8beb125d1 100644 --- a/src/OCE/TRA/eosbn2.F90 +++ b/src/OCE/TRA/eosbn2.F90 @@ -53,7 +53,7 @@ MODULE eosbn2 ! !! * Interface INTERFACE eos - MODULE PROCEDURE eos_insitu, eos_insitu_pot, eos_insitu_2d, eos_insitu_pot_2d + MODULE PROCEDURE eos_insitu_New, eos_insitu, eos_insitu_pot, eos_insitu_2d, eos_insitu_pot_2d END INTERFACE ! INTERFACE eos_rab @@ -181,11 +181,118 @@ MODULE eosbn2 # include "domzgr_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/OCE 4.0 , NEMO Consortium (2018) - !! $Id: eosbn2.F90 15136 2021-07-23 10:07:28Z smasson $ + !! $Id: eosbn2.F90 14547 2021-02-25 17:07:15Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS + SUBROUTINE eos_insitu_New( pts, Knn, prd ) + !!---------------------------------------------------------------------- + !! *** ROUTINE eos_insitu *** + !! + !! ** Purpose : Compute the in situ density (ratio rho/rho0) from + !! potential temperature and salinity using an equation of state + !! selected in the nameos namelist + !! + !! ** Method : prd(t,s,z) = ( rho(t,s,z) - rho0 ) / rho0 + !! with prd in situ density anomaly no units + !! t TEOS10: CT or EOS80: PT Celsius + !! s TEOS10: SA or EOS80: SP TEOS10: g/kg or EOS80: psu + !! z depth meters + !! rho in situ density kg/m^3 + !! rho0 reference density kg/m^3 + !! + !! ln_teos10 : polynomial TEOS-10 equation of state is used for rho(t,s,z). + !! Check value: rho = 1028.21993233072 kg/m^3 for z=3000 dbar, ct=3 Celsius, sa=35.5 g/kg + !! + !! ln_eos80 : polynomial EOS-80 equation of state is used for rho(t,s,z). + !! Check value: rho = 1028.35011066567 kg/m^3 for z=3000 dbar, pt=3 Celsius, sp=35.5 psu + !! + !! ln_seos : simplified equation of state + !! prd(t,s,z) = ( -a0*(1+lambda/2*(T-T0)+mu*z+nu*(S-S0))*(T-T0) + b0*(S-S0) ) / rho0 + !! linear case function of T only: rn_alpha<>0, other coefficients = 0 + !! linear eos function of T and S: rn_alpha and rn_beta<>0, other coefficients=0 + !! Vallis like equation: use default values of coefficients + !! + !! ** Action : compute prd , the in situ density (no units) + !! + !! References : Roquet et al, Ocean Modelling, in preparation (2014) + !! Vallis, Atmospheric and Oceanic Fluid Dynamics, 2006 + !! TEOS-10 Manual, 2010 + !!---------------------------------------------------------------------- + REAL(wp), DIMENSION(:,:,:,:,:), INTENT(in ) :: pts ! T-S + INTEGER , INTENT(in ) :: Knn ! time-level + REAL(wp), DIMENSION(:,:,: ), INTENT( out) :: prd ! in situ density + ! + INTEGER :: ji, jj, jk ! dummy loop indices + REAL(wp) :: zt , zh , zs , ztm ! local scalars + REAL(wp) :: zn , zn0, zn1, zn2, zn3 ! - - + !!---------------------------------------------------------------------- + ! + IF( ln_timing ) CALL timing_start('eos-insitu') + ! + SELECT CASE( neos ) + ! + CASE( np_teos10, np_eos80 ) !== polynomial TEOS-10 / EOS-80 ==! + ! + DO_3D(nn_hls, nn_hls, nn_hls, nn_hls, 1, jpkm1 ) + ! + zh = gdept(ji,jj,jk,Knn) * r1_Z0 ! depth + zt = pts (ji,jj,jk,jp_tem,Knn) * r1_T0 ! temperature + zs = SQRT( ABS( pts(ji,jj,jk,jp_sal,Knn) + rdeltaS ) * r1_S0 ) ! square root salinity + ztm = tmask(ji,jj,jk) ! tmask + ! + zn3 = EOS013*zt & + & + EOS103*zs+EOS003 + ! + zn2 = (EOS022*zt & + & + EOS112*zs+EOS012)*zt & + & + (EOS202*zs+EOS102)*zs+EOS002 + ! + zn1 = (((EOS041*zt & + & + EOS131*zs+EOS031)*zt & + & + (EOS221*zs+EOS121)*zs+EOS021)*zt & + & + ((EOS311*zs+EOS211)*zs+EOS111)*zs+EOS011)*zt & + & + (((EOS401*zs+EOS301)*zs+EOS201)*zs+EOS101)*zs+EOS001 + ! + zn0 = (((((EOS060*zt & + & + EOS150*zs+EOS050)*zt & + & + (EOS240*zs+EOS140)*zs+EOS040)*zt & + & + ((EOS330*zs+EOS230)*zs+EOS130)*zs+EOS030)*zt & + & + (((EOS420*zs+EOS320)*zs+EOS220)*zs+EOS120)*zs+EOS020)*zt & + & + ((((EOS510*zs+EOS410)*zs+EOS310)*zs+EOS210)*zs+EOS110)*zs+EOS010)*zt & + & + (((((EOS600*zs+EOS500)*zs+EOS400)*zs+EOS300)*zs+EOS200)*zs+EOS100)*zs+EOS000 + ! + zn = ( ( zn3 * zh + zn2 ) * zh + zn1 ) * zh + zn0 + ! + prd(ji,jj,jk) = ( zn * r1_rho0 - 1._wp ) * ztm ! density anomaly (masked) + ! + END_3D + ! + CASE( np_seos ) !== simplified EOS ==! + ! + DO_3D( nn_hls, nn_hls, nn_hls, nn_hls, 1, jpkm1 ) + zt = pts (ji,jj,jk,jp_tem,Knn) - 10._wp + zs = pts (ji,jj,jk,jp_sal,Knn) - 35._wp + zh = gdept(ji,jj,jk,Knn) + ztm = tmask(ji,jj,jk) + ! + zn = - rn_a0 * ( 1._wp + 0.5_wp*rn_lambda1*zt + rn_mu1*zh ) * zt & + & + rn_b0 * ( 1._wp - 0.5_wp*rn_lambda2*zs - rn_mu2*zh ) * zs & + & - rn_nu * zt * zs + ! + prd(ji,jj,jk) = zn * r1_rho0 * ztm ! density anomaly (masked) + END_3D + ! + END SELECT + ! + IF(sn_cfctl%l_prtctl) CALL prt_ctl( tab3d_1=prd, clinfo1=' eos-insitu : ', kdim=jpk ) + ! + IF( ln_timing ) CALL timing_stop('eos-insitu') + ! + END SUBROUTINE eos_insitu_New + + SUBROUTINE eos_insitu( pts, prd, pdep ) !! REAL(wp), DIMENSION(:,:,:,:), INTENT(in ) :: pts ! 1 : potential temperature [Celsius] diff --git a/src/OCE/TRA/traadv.F90 b/src/OCE/TRA/traadv.F90 index aa9d4de26a5624edcc030029f14838f984b2312a..a55ffff58f82cd894ab61636e025e349991b3e1b 100644 --- a/src/OCE/TRA/traadv.F90 +++ b/src/OCE/TRA/traadv.F90 @@ -9,6 +9,7 @@ MODULE traadv !! 3.7 ! 2014-05 (G. Madec) Add 2nd/4th order cases for CEN and FCT schemes !! - ! 2014-12 (G. Madec) suppression of cross land advection option !! 3.6 ! 2015-06 (E. Clementi) Addition of Stokes drift in case of wave coupling + !! 4.5 ! 2021-04 (G. Madec, S. Techene) add advective velocities as optional arguments !!---------------------------------------------------------------------- !!---------------------------------------------------------------------- @@ -43,7 +44,7 @@ MODULE traadv IMPLICIT NONE PRIVATE - PUBLIC tra_adv ! called by step.F90 + PUBLIC tra_adv ! called by step.F90, stpmlf.F90 and stprk3_stg.F90 PUBLIC tra_adv_init ! called by nemogcm.F90 ! !!* Namelist namtra_adv * @@ -58,43 +59,45 @@ MODULE traadv INTEGER :: nn_ubs_v ! =2/4 : vertical choice of the order of UBS scheme LOGICAL :: ln_traadv_qck ! QUICKEST scheme flag - INTEGER, PUBLIC :: nadv ! choice of the type of advection scheme + INTEGER :: nadv ! choice of the type of advection scheme ! ! associated indices: - INTEGER, PARAMETER, PUBLIC :: np_NO_adv = 0 ! no T-S advection - INTEGER, PARAMETER, PUBLIC :: np_CEN = 1 ! 2nd/4th order centered scheme - INTEGER, PARAMETER, PUBLIC :: np_FCT = 2 ! 2nd/4th order Flux Corrected Transport scheme - INTEGER, PARAMETER, PUBLIC :: np_MUS = 3 ! MUSCL scheme - INTEGER, PARAMETER, PUBLIC :: np_UBS = 4 ! 3rd order Upstream Biased Scheme - INTEGER, PARAMETER, PUBLIC :: np_QCK = 5 ! QUICK scheme + INTEGER, PARAMETER :: np_NO_adv = 0 ! no T-S advection + INTEGER, PARAMETER :: np_CEN = 1 ! 2nd/4th order centered scheme + INTEGER, PARAMETER :: np_FCT = 2 ! 2nd/4th order Flux Corrected Transport scheme + INTEGER, PARAMETER :: np_MUS = 3 ! MUSCL scheme + INTEGER, PARAMETER :: np_UBS = 4 ! 3rd order Upstream Biased Scheme + INTEGER, PARAMETER :: np_QCK = 5 ! QUICK scheme !! * Substitutions # include "do_loop_substitute.h90" # include "domzgr_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/OCE 4.0 , NEMO Consortium (2018) - !! $Id: traadv.F90 15073 2021-07-02 14:20:14Z clem $ + !! $Id: traadv.F90 15514 2021-11-16 08:58:22Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS - SUBROUTINE tra_adv( kt, Kbb, Kmm, pts, Krhs ) + SUBROUTINE tra_adv( kt, Kbb, Kmm, pts, Krhs, pau, pav, paw ) !!---------------------------------------------------------------------- !! *** ROUTINE tra_adv *** !! !! ** Purpose : compute the ocean tracer advection trend. !! - !! ** Method : - Update (uu(:,:,:,Krhs),vv(:,:,:,Krhs)) with the advection term following nadv + !! ** Method : - Update ts(Krhs) with the advective trend following nadv !!---------------------------------------------------------------------- - INTEGER , INTENT(in) :: kt ! ocean time-step index - INTEGER , INTENT(in) :: Kbb, Kmm, Krhs ! time level indices - REAL(wp), DIMENSION(jpi,jpj,jpk,jpts,jpt), INTENT(inout) :: pts ! active tracers and RHS of tracer equation + INTEGER , INTENT(in ) :: kt ! ocean time-step index + INTEGER , INTENT(in ) :: Kbb, Kmm, Krhs ! time level indices + REAL(wp), DIMENSION(:,:,:), OPTIONAL, TARGET, INTENT(in ) :: pau, pav, paw ! advective velocity + REAL(wp), DIMENSION(jpi,jpj,jpk,jpts,jpt) , INTENT(inout) :: pts ! active tracers and RHS of tracer equation ! INTEGER :: ji, jj, jk ! dummy loop index + REAL(wp), DIMENSION(:,:,:), POINTER :: zptu, zptv, zptw ! TEMP: [tiling] This change not necessary and can be A2D(nn_hls) after all lbc_lnks removed in the nn_hls = 2 case in tra_adv_fct - REAL(wp), DIMENSION(:,:,:), ALLOCATABLE, SAVE :: zuu, zvv, zww ! 3D workspace - REAL(wp), DIMENSION(:,:,:), ALLOCATABLE :: ztrdt, ztrds + REAL(wp), DIMENSION(:,:,:), ALLOCATABLE, SAVE :: zuu, zvv, zww ! 3D workspace + REAL(wp), DIMENSION(:,:,:), ALLOCATABLE :: ztrdt, ztrds ! TEMP: [tiling] This change not necessary after all lbc_lnks removed in the nn_hls = 2 case in tra_adv_fct - LOGICAL :: lskip + LOGICAL :: lskip !!---------------------------------------------------------------------- ! IF( ln_timing ) CALL timing_start('tra_adv') @@ -114,23 +117,35 @@ CONTAINS lskip = .TRUE. ENDIF ENDIF + ! IF( .NOT. lskip ) THEN - ! !== effective transport ==! + ! !== effective advective transport ==! + ! + IF( PRESENT( pau ) ) THEN ! RK3: advective velocity (pau,pav,paw) /= advected velocity (uu,vv,ww) + zptu => pau(:,:,:) + zptv => pav(:,:,:) + zptw => paw(:,:,:) + ELSE ! MLF: advective velocity = (uu,vv,ww) + zptu => uu(:,:,:,Kmm) + zptv => vv(:,:,:,Kmm) + zptw => ww(:,:,: ) + ENDIF + ! IF( ln_wave .AND. ln_sdw ) THEN DO_3D_OVR( nn_hls, nn_hls-1, nn_hls, nn_hls-1, 1, jpkm1 ) - zuu(ji,jj,jk) = e2u (ji,jj) * e3u(ji,jj,jk,Kmm) * ( uu(ji,jj,jk,Kmm) + usd(ji,jj,jk) ) - zvv(ji,jj,jk) = e1v (ji,jj) * e3v(ji,jj,jk,Kmm) * ( vv(ji,jj,jk,Kmm) + vsd(ji,jj,jk) ) + zuu(ji,jj,jk) = e2u (ji,jj) * e3u(ji,jj,jk,Kmm) * ( zptu(ji,jj,jk) + usd(ji,jj,jk) ) + zvv(ji,jj,jk) = e1v (ji,jj) * e3v(ji,jj,jk,Kmm) * ( zptv(ji,jj,jk) + vsd(ji,jj,jk) ) END_3D DO_3D_OVR( nn_hls-1, nn_hls-1, nn_hls-1, nn_hls-1, 1, jpkm1 ) - zww(ji,jj,jk) = e1e2t(ji,jj) * ( ww(ji,jj,jk) + wsd(ji,jj,jk) ) + zww(ji,jj,jk) = e1e2t(ji,jj) * ( zptw(ji,jj,jk) + wsd(ji,jj,jk) ) END_3D ELSE DO_3D_OVR( nn_hls, nn_hls-1, nn_hls, nn_hls-1, 1, jpkm1 ) - zuu(ji,jj,jk) = e2u (ji,jj) * e3u(ji,jj,jk,Kmm) * uu(ji,jj,jk,Kmm) ! eulerian transport only - zvv(ji,jj,jk) = e1v (ji,jj) * e3v(ji,jj,jk,Kmm) * vv(ji,jj,jk,Kmm) + zuu(ji,jj,jk) = e2u (ji,jj) * e3u(ji,jj,jk,Kmm) * zptu(ji,jj,jk) ! eulerian transport only + zvv(ji,jj,jk) = e1v (ji,jj) * e3v(ji,jj,jk,Kmm) * zptv(ji,jj,jk) END_3D DO_3D_OVR( nn_hls-1, nn_hls-1, nn_hls-1, nn_hls-1, 1, jpkm1 ) - zww(ji,jj,jk) = e1e2t(ji,jj) * ww(ji,jj,jk) + zww(ji,jj,jk) = e1e2t(ji,jj) * zptw(ji,jj,jk) END_3D ENDIF ! @@ -142,7 +157,7 @@ CONTAINS ENDIF ! DO_2D_OVR( nn_hls, nn_hls-1, nn_hls, nn_hls-1 ) - zuu(ji,jj,jpk) = 0._wp ! no transport trough the bottom + zuu(ji,jj,jpk) = 0._wp ! no transport trough the bottom zvv(ji,jj,jpk) = 0._wp zww(ji,jj,jpk) = 0._wp END_2D @@ -153,15 +168,17 @@ CONTAINS IF( ln_mle ) CALL tra_mle_trp( kt, nit000, zuu, zvv, zww, 'TRA', Kmm ) ! add the mle transport (if necessary) ! ! TEMP: [tiling] This change not necessary after all lbc_lnks removed in the nn_hls = 2 case in tra_adv_fct - IF( .NOT. l_istiled .OR. ntile == nijtile ) THEN ! Do only on the last tile - CALL iom_put( "uocetr_eff", zuu ) ! output effective transport - CALL iom_put( "vocetr_eff", zvv ) - CALL iom_put( "wocetr_eff", zww ) + IF( l_iom ) THEN + IF( .NOT. l_istiled .OR. ntile == nijtile ) THEN ! Do only on the last tile + CALL iom_put( "uocetr_eff", zuu ) ! output effective transport + CALL iom_put( "vocetr_eff", zvv ) + CALL iom_put( "wocetr_eff", zww ) + ENDIF ENDIF ! !!gm ??? ! TEMP: [tiling] This copy-in not necessary after all lbc_lnks removed in the nn_hls = 2 case in tra_adv_fct - CALL dia_ptr( kt, Kmm, zvv(A2D(nn_hls),:) ) ! diagnose the effective MSF + IF( l_diaptr ) CALL dia_ptr( kt, Kmm, zvv(A2D(nn_hls),:) ) ! diagnose the effective MSF !!gm ??? ! @@ -245,8 +262,8 @@ CONTAINS WRITE(numout,*) ' Namelist namtra_adv : chose a advection scheme for tracers' WRITE(numout,*) ' No advection on T & S ln_traadv_OFF = ', ln_traadv_OFF WRITE(numout,*) ' centered scheme ln_traadv_cen = ', ln_traadv_cen - WRITE(numout,*) ' horizontal 2nd/4th order nn_cen_h = ', nn_fct_h - WRITE(numout,*) ' vertical 2nd/4th order nn_cen_v = ', nn_fct_v + WRITE(numout,*) ' horizontal 2nd/4th order nn_cen_h = ', nn_cen_h + WRITE(numout,*) ' vertical 2nd/4th order nn_cen_v = ', nn_cen_v WRITE(numout,*) ' Flux Corrected Transport scheme ln_traadv_fct = ', ln_traadv_fct WRITE(numout,*) ' horizontal 2nd/4th order nn_fct_h = ', nn_fct_h WRITE(numout,*) ' vertical 2nd/4th order nn_fct_v = ', nn_fct_v diff --git a/src/OCE/TRA/traadv_fct.F90 b/src/OCE/TRA/traadv_fct.F90 index 500a46d80f8dadc42df2911f9f0e3814acf81b61..e66936ade3de2bb915f4db9b746d07f23b31c5b8 100644 --- a/src/OCE/TRA/traadv_fct.F90 +++ b/src/OCE/TRA/traadv_fct.F90 @@ -48,7 +48,7 @@ MODULE traadv_fct # include "domzgr_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/OCE 4.0 , NEMO Consortium (2018) - !! $Id: traadv_fct.F90 14857 2021-05-12 16:47:25Z hadcv $ + !! $Id: traadv_fct.F90 15512 2021-11-15 17:22:03Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS @@ -106,10 +106,10 @@ CONTAINS l_hst = .FALSE. l_ptr = .FALSE. ll_zAimp = .FALSE. - IF( ( cdtype == 'TRA' .AND. l_trdtra ) .OR. ( cdtype =='TRC' .AND. l_trdtrc ) ) l_trd = .TRUE. - IF( cdtype == 'TRA' .AND. ( iom_use( 'sophtadv' ) .OR. iom_use( 'sophtadv' ) ) ) l_ptr = .TRUE. - IF( cdtype == 'TRA' .AND. ( iom_use("uadv_heattr") .OR. iom_use("vadv_heattr") .OR. & - & iom_use("uadv_salttr") .OR. iom_use("vadv_salttr") ) ) l_hst = .TRUE. + IF( ( cdtype == 'TRA' .AND. l_trdtra ) .OR. ( cdtype =='TRC' .AND. l_trdtrc ) ) l_trd = .TRUE. + IF( l_diaptr .AND. cdtype == 'TRA' .AND. ( iom_use( 'sophtadv' ) .OR. iom_use( 'sophtadv' ) ) ) l_ptr = .TRUE. + IF( l_iom .AND. cdtype == 'TRA' .AND. ( iom_use("uadv_heattr") .OR. iom_use("vadv_heattr") .OR. & + & iom_use("uadv_salttr") .OR. iom_use("vadv_salttr") ) ) l_hst = .TRUE. ! ENDIF diff --git a/src/OCE/TRA/traadv_mus.F90 b/src/OCE/TRA/traadv_mus.F90 index 42db0c909605ab3e3ec5301eda94fdd2bdf606fb..4c4b0437ca01cb250cf6f560527e8b0b5a632803 100644 --- a/src/OCE/TRA/traadv_mus.F90 +++ b/src/OCE/TRA/traadv_mus.F90 @@ -49,7 +49,7 @@ MODULE traadv_mus # include "domzgr_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/OCE 4.0 , NEMO Consortium (2018) - !! $Id: traadv_mus.F90 15139 2021-07-23 12:52:21Z smasson $ + !! $Id: traadv_mus.F90 15512 2021-11-15 17:22:03Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS @@ -121,10 +121,10 @@ CONTAINS l_trd = .FALSE. l_hst = .FALSE. l_ptr = .FALSE. - IF( ( cdtype == 'TRA' .AND. l_trdtra ) .OR. ( cdtype == 'TRC' .AND. l_trdtrc ) ) l_trd = .TRUE. - IF( cdtype == 'TRA' .AND. ( iom_use( 'sophtadv' ) .OR. iom_use( 'sophtadv' ) ) ) l_ptr = .TRUE. - IF( cdtype == 'TRA' .AND. ( iom_use("uadv_heattr") .OR. iom_use("vadv_heattr") .OR. & - & iom_use("uadv_salttr") .OR. iom_use("vadv_salttr") ) ) l_hst = .TRUE. + IF( ( cdtype == 'TRA' .AND. l_trdtra ) .OR. ( cdtype == 'TRC' .AND. l_trdtrc ) ) l_trd = .TRUE. + IF( l_diaptr .AND. cdtype == 'TRA' .AND. ( iom_use( 'sophtadv' ) .OR. iom_use( 'sophtadv' ) ) ) l_ptr = .TRUE. + IF( l_iom .AND. cdtype == 'TRA' .AND. ( iom_use("uadv_heattr") .OR. iom_use("vadv_heattr") .OR. & + & iom_use("uadv_salttr") .OR. iom_use("vadv_salttr") ) ) l_hst = .TRUE. ENDIF ! DO jn = 1, kjpt !== loop over the tracers ==! diff --git a/src/OCE/TRA/traatf.F90 b/src/OCE/TRA/traatf.F90 index 12b280fc30b53bdbc1894691411ee1600aeb2359..57a9ca0a47851146bcfd09c7a769c70ad6a69663 100644 --- a/src/OCE/TRA/traatf.F90 +++ b/src/OCE/TRA/traatf.F90 @@ -60,7 +60,7 @@ MODULE traatf # include "domzgr_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/OCE 4.0 , NEMO Consortium (2018) - !! $Id: traatf.F90 15004 2021-06-16 10:33:18Z mathiot $ + !! $Id: traatf.F90 14800 2021-05-06 15:42:46Z jchanut $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS @@ -106,7 +106,7 @@ CONTAINS ! Update after tracer on domain lateral boundaries ! #if defined key_agrif - CALL Agrif_tra ! AGRIF zoom boundaries + CALL Agrif_tra( kt ) ! AGRIF zoom boundaries #endif ! ! local domain boundaries (T-point, unchanged sign) CALL lbc_lnk( 'traatf', pts(:,:,:,jp_tem,Kaa), 'T', 1.0_wp, pts(:,:,:,jp_sal,Kaa), 'T', 1.0_wp ) @@ -268,6 +268,10 @@ CONTAINS ALLOCATE( ztrd_atf(jpi,jpj,jpk,kjpt) ) ztrd_atf(:,:,:,:) = 0.0_wp ENDIF + ! +!!st variables only computed in the interior by traqsr + IF( ll_traqsr ) CALL lbc_lnk( 'traatf', qsr_hc_b(:,:,:) , 'T', 1.0_wp, qsr_hc(:,:,:) , 'T', 1.0_wp ) + ! zfact = 1._wp / p2dt zfact1 = rn_atfp * p2dt zfact2 = zfact1 * r1_rho0 diff --git a/src/OCE/TRA/traatf_qco.F90 b/src/OCE/TRA/traatf_qco.F90 index 2b6333683a4ccaf96d8c006f72317ea5b8257eef..57034bd06088f54863e35898473f9a6c64f2323a 100644 --- a/src/OCE/TRA/traatf_qco.F90 +++ b/src/OCE/TRA/traatf_qco.F90 @@ -1,7 +1,7 @@ MODULE traatf_qco !!====================================================================== !! *** MODULE traatf_qco *** - !! Ocean active tracers: Asselin time filtering for temperature and salinity + !! Ocean active tracers: MLF, Asselin time filtering for temperature and salinity !!====================================================================== !! History : OPA ! 1991-11 (G. Madec) Original code !! 7.0 ! 1993-03 (M. Guyon) symetrical conditions @@ -16,34 +16,39 @@ MODULE traatf_qco !! 3.1 ! 2009-02 (G. Madec, R. Benshila) re-introduce the vvl option !! 3.3 ! 2010-04 (M. Leclair, G. Madec) semi-implicit hpg with asselin filter + modified LF-RA !! - ! 2010-05 (C. Ethe, G. Madec) merge TRC-TRA - !! 4.1 ! 2019-08 (A. Coward, D. Storkey) rename tranxt.F90 -> traatfLF.F90. Now only does time filtering. + !! 4.1 ! 2019-08 (A. Coward, D. Storkey) rename tranxt.F90 -> traatf.F90. Now only does time filtering. + !! 4.2 ! 2020-06 (S. Techene, G. Madec) qco version of traatf.F90 !!---------------------------------------------------------------------- - +#if defined key_RK3 + !!---------------------------------------------------------------------- + !! 'key_RK3' EMPTY MODULE 3rd order Runge-Kutta + !!---------------------------------------------------------------------- +#else !!---------------------------------------------------------------------- !! tra_atf : time filtering on tracers !! tra_atf_fix : time filtering on tracers : fixed volume case !! tra_atf_vvl : time filtering on tracers : variable volume case !!---------------------------------------------------------------------- - USE oce ! ocean dynamics and tracers variables - USE dom_oce ! ocean space and time domain variables - USE sbc_oce ! surface boundary condition: ocean - USE sbcrnf ! river runoffs - USE isf_oce ! ice shelf melting - USE zdf_oce ! ocean vertical mixing - USE domvvl ! variable volume - USE trd_oce ! trends: ocean variables - USE trdtra ! trends manager: tracers - USE traqsr ! penetrative solar radiation (needed for nksr) - USE phycst ! physical constant - USE ldftra ! lateral physics : tracers - USE ldfslp ! lateral physics : slopes - USE bdy_oce , ONLY : ln_bdy - USE bdytra ! open boundary condition (bdy_tra routine) + USE oce ! ocean dynamics and tracers variables + USE dom_oce ! ocean space and time domain variables + USE sbc_oce ! surface boundary condition: ocean + USE sbcrnf ! river runoffs + USE isf_oce ! ice shelf melting + USE zdf_oce ! ocean vertical mixing + USE domvvl ! variable volume + USE trd_oce ! trends: ocean variables + USE trdtra ! trends manager: tracers + USE traqsr ! penetrative solar radiation (needed for nksr) + USE phycst ! physical constant + USE ldftra ! lateral physics : tracers + USE ldfslp ! lateral physics : slopes + USE bdy_oce , ONLY: ln_bdy + USE bdytra ! open boundary condition (bdy_tra routine) ! - USE in_out_manager ! I/O manager - USE lbclnk ! ocean lateral boundary conditions (or mpp link) - USE prtctl ! Print control - USE timing ! Timing + USE in_out_manager ! I/O manager + USE lbclnk ! ocean lateral boundary conditions (or mpp link) + USE prtctl ! Print control + USE timing ! Timing IMPLICIT NONE PRIVATE @@ -57,7 +62,7 @@ MODULE traatf_qco # include "domzgr_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/OCE 4.0 , NEMO Consortium (2018) - !! $Id: traatf_qco.F90 14433 2021-02-11 08:06:49Z smasson $ + !! $Id: traatf_qco.F90 15028 2021-06-19 08:53:10Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS @@ -197,7 +202,8 @@ CONTAINS ! DO jn = 1, kjpt ! - DO_3D( nn_hls, nn_hls, nn_hls, nn_hls, 1, jpkm1 ) + DO_3D( 0, 0, 0, 0, 1, jpkm1 ) +!!st DO_3D( nn_hls, nn_hls, nn_hls, nn_hls, 1, jpkm1 ) ztn = pt(ji,jj,jk,jn,Kmm) ztd = pt(ji,jj,jk,jn,Kaa) - 2._wp * ztn + pt(ji,jj,jk,jn,Kbb) ! time laplacian on tracers ! @@ -256,13 +262,14 @@ CONTAINS ! IF( ( l_trdtra .AND. cdtype == 'TRA' ) .OR. ( l_trdtrc .AND. cdtype == 'TRC' ) ) THEN ALLOCATE( ztrd_atf(jpi,jpj,jpk,kjpt) ) - ztrd_atf(:,:,:,:) = 0.0_wp + ztrd_atf(:,:,:,:) = 0._wp ENDIF zfact = 1._wp / p2dt zfact1 = rn_atfp * p2dt zfact2 = zfact1 * r1_rho0 DO jn = 1, kjpt - DO_3D( nn_hls, nn_hls, nn_hls, nn_hls, 1, jpkm1 ) + DO_3D( 0, 0, 0, 0, 1, jpkm1 ) +!!st DO_3D( nn_hls, nn_hls, nn_hls, nn_hls, 1, jpkm1 ) ze3t_b = e3t(ji,jj,jk,Kbb) ze3t_n = e3t(ji,jj,jk,Kmm) ze3t_a = e3t(ji,jj,jk,Kaa) @@ -286,7 +293,7 @@ CONTAINS ! solar penetration (temperature only) IF( ll_traqsr .AND. jn == jp_tem .AND. jk <= nksr ) & & ztc_f = ztc_f - zfact1 * ( qsr_hc(ji,jj,jk) - qsr_hc_b(ji,jj,jk) ) - ! + ! ! IF( ll_rnf .AND. jk <= nk_rnf(ji,jj) ) & & ztc_f = ztc_f - zfact1 * ( rnf_tsc(ji,jj,jn) - rnf_tsc_b(ji,jj,jn) ) & @@ -364,6 +371,7 @@ CONTAINS ENDIF ! END SUBROUTINE tra_atf_qco_lf - +#endif + !!====================================================================== END MODULE traatf_qco diff --git a/src/OCE/TRA/traisf.F90 b/src/OCE/TRA/traisf.F90 index 0abba863ee67267e6a598be8ecca360c4a6c4304..7f43285b980dc3d59715f5a76b993fda1a55031f 100644 --- a/src/OCE/TRA/traisf.F90 +++ b/src/OCE/TRA/traisf.F90 @@ -1,13 +1,15 @@ MODULE traisf - !!============================================================================== - !! *** MODULE traisf *** + !!====================================================================== + !! *** MODULE traisf *** !! Ocean active tracers: ice shelf boundary condition - !!============================================================================== - !! History : 4.0 ! 2019-09 (P. Mathiot) original file + !!====================================================================== + !! History : 4.0 ! 2019-09 (P. Mathiot) original file !!---------------------------------------------------------------------- !!---------------------------------------------------------------------- !! tra_isf : update the tracer trend at ocean surface + !! isf_mlt : temperature trend due to the ice shelf melting + !! isf_cpl : T-S trend due to the ice shelf coupling !!---------------------------------------------------------------------- USE isf_oce ! Ice shelf variables USE par_oce , ONLY : nijtile, ntile, ntsi, ntei, ntsj, ntej @@ -31,18 +33,18 @@ MODULE traisf !!---------------------------------------------------------------------- CONTAINS - SUBROUTINE tra_isf ( kt, Kmm, pts, Krhs ) - !!---------------------------------------------------------------------- + SUBROUTINE tra_isf( kt, Kmm, pts, Krhs ) + !!------------------------------------------------------------------- !! *** ROUTINE tra_isf *** !! !! ** Purpose : Compute the temperature trend due to the ice shelf melting (qhoce + qhc) !! !! ** Action : - update pts(:,:,:,:,Krhs) for cav, par and cpl case - !!---------------------------------------------------------------------- + !!------------------------------------------------------------------- INTEGER , INTENT(in ) :: kt ! ocean time step INTEGER , INTENT(in ) :: Kmm, Krhs ! ocean time level indices REAL(wp), DIMENSION(jpi,jpj,jpk,jpts,jpt), INTENT(inout) :: pts ! active tracers and RHS of tracer equation - !!---------------------------------------------------------------------- + !!------------------------------------------------------------------- ! IF( ln_timing ) CALL timing_start('tra_isf') ! @@ -55,10 +57,10 @@ CONTAINS ENDIF ! ! cavity case - IF ( ln_isfcav_mlt ) CALL tra_isf_mlt(misfkt_cav, misfkb_cav, rhisf_tbl_cav, rfrac_tbl_cav, risf_cav_tsc, risf_cav_tsc_b, pts(:,:,:,:,Krhs)) + IF ( ln_isfcav_mlt ) CALL isf_mlt(misfkt_cav, misfkb_cav, rhisf_tbl_cav, rfrac_tbl_cav, risf_cav_tsc, risf_cav_tsc_b, pts(:,:,:,:,Krhs)) ! ! parametrisation case - IF ( ln_isfpar_mlt ) CALL tra_isf_mlt(misfkt_par, misfkb_par, rhisf_tbl_par, rfrac_tbl_par, risf_par_tsc, risf_par_tsc_b, pts(:,:,:,:,Krhs)) + IF ( ln_isfpar_mlt ) CALL isf_mlt(misfkt_par, misfkb_par, rhisf_tbl_par, rfrac_tbl_par, risf_par_tsc, risf_par_tsc_b, pts(:,:,:,:,Krhs)) ! ! ice sheet coupling case IF ( ln_isfcpl ) THEN @@ -69,11 +71,11 @@ CONTAINS ! half of it at nit000+1 (leap frog time step). ! in accordance to this, the heat content flux due to injected water need to be added in the temperature and salt trend ! at time step nit000 and nit000+1 - IF ( kt == nit000 ) CALL tra_isf_cpl(Kmm, risfcpl_tsc , pts(:,:,:,:,Krhs)) - IF ( kt == nit000+1) CALL tra_isf_cpl(Kmm, risfcpl_tsc*0.5_wp, pts(:,:,:,:,Krhs)) + IF ( kt == nit000 ) CALL isf_cpl(Kmm, risfcpl_tsc , pts(:,:,:,:,Krhs)) + IF ( kt == nit000+1) CALL isf_cpl(Kmm, risfcpl_tsc*0.5_wp, pts(:,:,:,:,Krhs)) ! ! ensure 0 trend due to unconservation of the ice shelf coupling - IF ( ln_isfcpl_cons ) CALL tra_isf_cpl(Kmm, risfcpl_cons_tsc, pts(:,:,:,:,Krhs)) + IF ( ln_isfcpl_cons ) CALL isf_cpl(Kmm, risfcpl_cons_tsc, pts(:,:,:,:,Krhs)) ! END IF ! @@ -87,25 +89,25 @@ CONTAINS IF( ln_timing ) CALL timing_stop('tra_isf') ! END SUBROUTINE tra_isf - ! - SUBROUTINE tra_isf_mlt(ktop, kbot, phtbl, pfrac, ptsc, ptsc_b, pts) + + + SUBROUTINE isf_mlt( ktop, kbot, phtbl, pfrac, ptsc, ptsc_b, pts ) !!---------------------------------------------------------------------- - !! *** ROUTINE tra_isf_mlt *** + !! *** ROUTINE isf_mlt *** !! !! *** Purpose : Compute the temperature trend due to the ice shelf melting (qhoce + qhc) for cav or par case !! !! *** Action :: Update pts(:,:,:,:,Krhs) with the surface boundary condition trend !! !!---------------------------------------------------------------------- - REAL(wp), DIMENSION(jpi,jpj,jpk,jpts), INTENT(inout) :: pts - !!---------------------------------------------------------------------- - INTEGER , DIMENSION(jpi,jpj) , INTENT(in ) :: ktop , kbot - REAL(wp), DIMENSION(jpi,jpj) , INTENT(in ) :: phtbl, pfrac - REAL(wp), DIMENSION(jpi,jpj,jpts), INTENT(in ) :: ptsc , ptsc_b - !!---------------------------------------------------------------------- - INTEGER :: ji,jj,jk ! loop index - INTEGER :: ikt, ikb ! top and bottom level of the tbl - REAL(wp), DIMENSION(A2D(nn_hls)) :: ztc ! total ice shelf tracer trend + INTEGER , DIMENSION(jpi,jpj) , INTENT(in ) :: ktop , kbot + REAL(wp), DIMENSION(jpi,jpj) , INTENT(in ) :: phtbl, pfrac + REAL(wp), DIMENSION(jpi,jpj,jpts) , INTENT(in ) :: ptsc , ptsc_b + REAL(wp), DIMENSION(jpi,jpj,jpk,jpts), INTENT(inout) :: pts + !! + INTEGER :: ji,jj,jk ! dummy loop index + INTEGER :: ikt, ikb ! top and bottom level of the tbl + REAL(wp), DIMENSION(A2D(nn_hls)) :: ztc ! total ice shelf tracer trend !!---------------------------------------------------------------------- ! ! compute 2d total trend due to isf @@ -129,21 +131,21 @@ CONTAINS ! END_2D ! - END SUBROUTINE tra_isf_mlt - ! - SUBROUTINE tra_isf_cpl( Kmm, ptsc, ptsa ) + END SUBROUTINE isf_mlt + + + SUBROUTINE isf_cpl( Kmm, ptsc, ptsa ) !!---------------------------------------------------------------------- - !! *** ROUTINE tra_isf_cpl *** + !! *** ROUTINE isf_cpl *** !! !! *** Action :: Update pts(:,:,:,:,Krhs) with the ice shelf coupling trend !! !!---------------------------------------------------------------------- - REAL(wp), DIMENSION(jpi,jpj,jpk,jpts), INTENT(inout) :: ptsa - !!---------------------------------------------------------------------- - INTEGER , INTENT(in ) :: Kmm ! ocean time level index - REAL(wp), DIMENSION(jpi,jpj,jpk,jpts), INTENT(in ) :: ptsc - !!---------------------------------------------------------------------- - INTEGER :: ji, jj, jk + INTEGER , INTENT(in ) :: Kmm ! ocean time-level index + REAL(wp), DIMENSION(jpi,jpj,jpk,jpts), INTENT(in ) :: ptsc + REAL(wp), DIMENSION(jpi,jpj,jpk,jpts), INTENT(inout) :: ptsa + !! + INTEGER :: ji, jj, jk ! dummy loop index !!---------------------------------------------------------------------- ! DO_3D( 0, 0, 0, 0, 1, jpk ) @@ -151,6 +153,7 @@ CONTAINS ptsa(ji,jj,jk,jp_sal) = ptsa(ji,jj,jk,jp_sal) + ptsc(ji,jj,jk,jp_sal) * r1_e1e2t(ji,jj) / e3t(ji,jj,jk,Kmm) END_3D ! - END SUBROUTINE tra_isf_cpl - ! + END SUBROUTINE isf_cpl + + !!====================================================================== END MODULE traisf diff --git a/src/OCE/TRA/traldf_iso.F90 b/src/OCE/TRA/traldf_iso.F90 index d91b67eab805faab7f06fe9c63b44dd843c46945..f93bf2dcda0500c21d02604f78db72b1e7d35209 100644 --- a/src/OCE/TRA/traldf_iso.F90 +++ b/src/OCE/TRA/traldf_iso.F90 @@ -44,7 +44,7 @@ MODULE traldf_iso # include "domzgr_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/OCE 4.0 , NEMO Consortium (2018) - !! $Id: traldf_iso.F90 14834 2021-05-11 09:24:44Z hadcv $ + !! $Id: traldf_iso.F90 15512 2021-11-15 17:22:03Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS @@ -155,9 +155,9 @@ CONTAINS IF( .NOT. l_istiled .OR. ntile == 1 ) THEN ! Do only on the first tile l_hst = .FALSE. l_ptr = .FALSE. - IF( cdtype == 'TRA' .AND. ( iom_use( 'sophtldf' ) .OR. iom_use( 'sopstldf' ) ) ) l_ptr = .TRUE. - IF( cdtype == 'TRA' .AND. ( iom_use("uadv_heattr") .OR. iom_use("vadv_heattr") .OR. & - & iom_use("uadv_salttr") .OR. iom_use("vadv_salttr") ) ) l_hst = .TRUE. + IF( l_diaptr .AND. cdtype == 'TRA' .AND. ( iom_use( 'sophtldf' ) .OR. iom_use( 'sopstldf' ) ) ) l_ptr = .TRUE. + IF( l_iom .AND. cdtype == 'TRA' .AND. ( iom_use("uadv_heattr") .OR. iom_use("vadv_heattr") .OR. & + & iom_use("uadv_salttr") .OR. iom_use("vadv_salttr") ) ) l_hst = .TRUE. ENDIF ! ! Define pt_rhs halo points for multi-point haloes in bilaplacian case diff --git a/src/OCE/TRA/tranpc.F90 b/src/OCE/TRA/tranpc.F90 index d1e9c1c79a8fbac9dcf752eec9452eeb5ab1925a..495ca30b1aafae613264477224694413d330121c 100644 --- a/src/OCE/TRA/tranpc.F90 +++ b/src/OCE/TRA/tranpc.F90 @@ -39,7 +39,7 @@ MODULE tranpc # include "domzgr_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/OCE 4.0 , NEMO Consortium (2018) - !! $Id: tranpc.F90 14834 2021-05-11 09:24:44Z hadcv $ + !! $Id: tranpc.F90 14547 2021-02-25 17:07:15Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS @@ -68,7 +68,7 @@ CONTAINS INTEGER :: jiter, ikbot, ikp, ikup, ikdown, ilayer, ik_low ! local integers LOGICAL :: l_bottom_reached, l_column_treated REAL(wp) :: zta, zalfa, zsum_temp, zsum_alfa, zaw, zdz, zsum_z - REAL(wp) :: zsa, zbeta, zsum_sali, zsum_beta, zbw, zrw, z1_rDt + REAL(wp) :: zsa, zbeta, zsum_sali, zsum_beta, zbw, zrw REAL(wp), PARAMETER :: zn2_zero = 1.e-14_wp ! acceptance criteria for neutrality (N2==0) REAL(wp), DIMENSION( jpk ) :: zvn2 ! vertical profile of N2 at 1 given point... REAL(wp), DIMENSION( jpk,jpts) :: zvts, zvab ! vertical profile of T & S , and alpha & betaat 1 given point @@ -302,9 +302,8 @@ CONTAINS END_2D ! IF( l_trdtra ) THEN ! send the Non penetrative mixing trends for diagnostic - z1_rDt = 1._wp / (2._wp * rn_Dt) - ztrdt(:,:,:) = ( pts(:,:,:,jp_tem,Kaa) - ztrdt(:,:,:) ) * z1_rDt - ztrds(:,:,:) = ( pts(:,:,:,jp_sal,Kaa) - ztrds(:,:,:) ) * z1_rDt + ztrdt(:,:,:) = ( pts(:,:,:,jp_tem,Kaa) - ztrdt(:,:,:) ) * r1_Dt + ztrds(:,:,:) = ( pts(:,:,:,jp_sal,Kaa) - ztrds(:,:,:) ) * r1_Dt CALL trd_tra( kt, Kmm, Krhs, 'TRA', jp_tem, jptra_npc, ztrdt ) CALL trd_tra( kt, Kmm, Krhs, 'TRA', jp_sal, jptra_npc, ztrds ) DEALLOCATE( ztrdt, ztrds ) diff --git a/src/OCE/TRA/traqsr.F90 b/src/OCE/TRA/traqsr.F90 index 5f9c8e94e44f98c29f0cbe76fa1d50aa42332f65..2d5c474ef468f8a555d2e2ea29ff9ee92a71af09 100644 --- a/src/OCE/TRA/traqsr.F90 +++ b/src/OCE/TRA/traqsr.F90 @@ -12,10 +12,16 @@ MODULE traqsr !! 3.6 ! 2012-05 (C. Rousset) store attenuation coef for use in ice model !! 3.6 ! 2015-12 (O. Aumont, J. Jouanno, C. Ethe) use vertical profile of chlorophyll !! 3.7 ! 2015-11 (G. Madec, A. Coward) remove optimisation for fix volume + !! 4.0 ! 2020-11 (A. Coward) optimisation + !! 4.5 ! 2021-03 (G. Madec) further optimisation + adaptation for RK3 !!---------------------------------------------------------------------- !!---------------------------------------------------------------------- !! tra_qsr : temperature trend due to the penetration of solar radiation + !! qsr_RGBc : IR + RGB light penetration with Chlorophyll data case + !! qsr_RGB : IR + RGB light penetration with constant Chlorophyll case + !! qsr_2BD : 2 bands (InfraRed + Visible light) case + !! qsr_ext_lev : level of extinction for each bands !! tra_qsr_init : initialization of the qsr penetration !!---------------------------------------------------------------------- USE oce ! ocean dynamics and active tracers @@ -52,16 +58,25 @@ MODULE traqsr REAL(wp), PUBLIC :: rn_si0 !: very near surface depth of extinction (RGB & 2 bands) REAL(wp), PUBLIC :: rn_si1 !: deepest depth of extinction (water type I) (2 bands) ! - INTEGER , PUBLIC :: nksr !: levels below which the light cannot penetrate (depth larger than 391 m) - INTEGER, PARAMETER :: np_RGB = 1 ! R-G-B light penetration with constant Chlorophyll INTEGER, PARAMETER :: np_RGBc = 2 ! R-G-B light penetration with Chlorophyll data INTEGER, PARAMETER :: np_2BD = 3 ! 2 bands light penetration INTEGER, PARAMETER :: np_BIO = 4 ! bio-model light penetration ! - INTEGER :: nqsr ! user choice of the type of light penetration - REAL(wp) :: xsi0r ! inverse of rn_si0 - REAL(wp) :: xsi1r ! inverse of rn_si1 + INTEGER :: nqsr ! user choice of the type of light penetration + INTEGER :: nc_rgb ! RGB with cst Chlorophyll: index associated with the chosen Chl value + ! + ! ! extinction level + INTEGER :: nk0 !: IR (depth larger ~12 m) + INTEGER :: nkV !: Visible light (depth larger than ~840 m) + INTEGER :: nkR, nkG, nkB !: RGB (depth larger than ~100 m, ~470 m, ~1700 m, resp.) + ! + INTEGER, PUBLIC :: nksr !: =nkV, i.e. maximum level of light extinction (used in traatf(_qco).F90) + ! + ! ! inverse of attenuation length + REAL(wp) :: r1_si0 ! all schemes : infrared = 1/rn_si0 + REAL(wp) :: r1_si1 ! 2 band : mean RGB = 1/rn_si1 + REAL(wp) :: r1_LR, r1_LG, r1_LB ! RGB with constant Chl (np_RGB) ! REAL(wp) , PUBLIC, DIMENSION(3,61) :: rkrgb ! tabulated attenuation coefficients for RGB absorption TYPE(FLD), ALLOCATABLE, DIMENSION(:) :: sf_chl ! structure of input Chl (file informations, fields read) @@ -71,7 +86,7 @@ MODULE traqsr # include "domzgr_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/OCE 4.0 , NEMO Consortium (2018) - !! $Id: traqsr.F90 14834 2021-05-11 09:24:44Z hadcv $ + !! $Id: traqsr.F90 15157 2021-07-29 08:28:32Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS @@ -84,38 +99,20 @@ CONTAINS !! penetration and add it to the general temperature trend. !! !! ** Method : The profile of the solar radiation within the ocean is defined - !! through 2 wavebands (rn_si0,rn_si1) or 3 wavebands (RGB) and a ratio rn_abs - !! Considering the 2 wavebands case: - !! I(k) = Qsr*( rn_abs*EXP(z(k)/rn_si0) + (1.-rn_abs)*EXP(z(k)/rn_si1) ) - !! The temperature trend associated with the solar radiation penetration - !! is given by : zta = 1/e3t dk[ I ] / (rho0*Cp) - !! At the bottom, boudary condition for the radiation is no flux : - !! all heat which has not been absorbed in the above levels is put - !! in the last ocean level. + !! through 2 wavebands (rn_si0,rn_si1) or 3 wavebands (RGB) or computed by + !! the biogeochemical model !! The computation is only done down to the level where - !! I(k) < 1.e-15 W/m2 (i.e. over the top nksr levels) . + !! I(k) < 1.e-15 W/m2 (i.e. over the top nk levels) . !! - !! ** Action : - update ta with the penetrative solar radiation trend + !! ** Action : - update ts(jp_tem) with the penetrative solar radiation trend !! - send trend for further diagnostics (l_trdtra=T) - !! - !! Reference : Jerlov, N. G., 1968 Optical Oceanography, Elsevier, 194pp. - !! Lengaigne et al. 2007, Clim. Dyn., V28, 5, 503-516. - !! Morel, A. et Berthon, JF, 1989, Limnol Oceanogr 34(8), 1545-1562 !!---------------------------------------------------------------------- - INTEGER, INTENT(in ) :: kt ! ocean time-step - INTEGER, INTENT(in ) :: Kmm, Krhs ! time level indices - REAL(wp), DIMENSION(jpi,jpj,jpk,jpts,jpt), INTENT(inout) :: pts ! active tracers and RHS of tracer equation + INTEGER, INTENT(in ) :: kt, Kmm, Krhs ! ocean time-step and time-level indices + REAL(wp), DIMENSION(jpi,jpj,jpk,jpts,jpt), INTENT(inout) :: pts ! active tracers and RHS of tracer equation ! INTEGER :: ji, jj, jk ! dummy loop indices - INTEGER :: irgb ! local integers - REAL(wp) :: zchl, zcoef, z1_2 ! local scalars - REAL(wp) :: zc0 , zc1 , zc2 , zc3 ! - - - REAL(wp) :: zzc0, zzc1, zzc2, zzc3 ! - - - REAL(wp) :: zz0 , zz1 , ze3t, zlui ! - - - REAL(wp) :: zCb, zCmax, zpsi, zpsimax, zrdpsi, zCze - REAL(wp) :: zlogc, zlogze, zlogCtot, zlogCze - REAL(wp), ALLOCATABLE, DIMENSION(:,:) :: ze0, ze1, ze2, ze3 - REAL(wp), ALLOCATABLE, DIMENSION(:,:,:) :: ztrdt, zetot, ztmp3d + REAL(wp) :: z1_2, ze3t ! local scalars + REAL(wp), ALLOCATABLE, DIMENSION(:,:,:) :: ztrdt, zetot !!---------------------------------------------------------------------- ! IF( ln_timing ) CALL timing_start('tra_qsr') @@ -128,10 +125,13 @@ CONTAINS ENDIF ENDIF ! - IF( l_trdtra ) THEN ! trends diagnostic: save the input temperature trend + IF( l_trdtra ) THEN ! trends diagnostic: save the input temperature trend ALLOCATE( ztrdt(jpi,jpj,jpk) ) ztrdt(:,:,:) = pts(:,:,:,jp_tem,Krhs) ENDIF + ! +#if ! defined key_RK3 + ! ! MLF only : heat content trend due to Qsr flux (qsr_hc) ! ! !-----------------------------------! ! ! before qsr induced heat content ! @@ -145,140 +145,62 @@ CONTAINS ENDIF ELSE ! No restart or Euler forward at 1st time step z1_2 = 1._wp - DO_3D_OVR( nn_hls, nn_hls, nn_hls, nn_hls, 1, jpk ) + DO_3D_OVR( 0, 0, 0, 0, 1, jpk ) qsr_hc_b(ji,jj,jk) = 0._wp END_3D ENDIF ELSE !== Swap of qsr heat content ==! z1_2 = 0.5_wp - DO_3D_OVR( nn_hls, nn_hls, nn_hls, nn_hls, 1, jpk ) + DO_3D_OVR( 0, 0, 0, 0, 1, jpk ) qsr_hc_b(ji,jj,jk) = qsr_hc(ji,jj,jk) END_3D ENDIF +#endif + + ! !----------------------------! + SELECT CASE( nqsr ) ! qsr induced heat content ! + ! !----------------------------! ! - ! !--------------------------------! - SELECT CASE( nqsr ) ! now qsr induced heat content ! - ! !--------------------------------! - ! - CASE( np_BIO ) !== bio-model fluxes ==! - ! - DO_3D_OVR( nn_hls, nn_hls, nn_hls, nn_hls, 1, nksr ) - qsr_hc(ji,jj,jk) = r1_rho0_rcp * ( etot3(ji,jj,jk) - etot3(ji,jj,jk+1) ) - END_3D - ! - CASE( np_RGB , np_RGBc ) !== R-G-B fluxes ==! - ! - ALLOCATE( ze0 (A2D(nn_hls)) , ze1 (A2D(nn_hls)) , & - & ze2 (A2D(nn_hls)) , ze3 (A2D(nn_hls)) , & - & ztmp3d(A2D(nn_hls),nksr + 1) ) - ! - IF( nqsr == np_RGBc ) THEN !* Variable Chlorophyll - IF( .NOT. l_istiled .OR. ntile == 1 ) THEN ! Do only for the full domain - IF( ln_tile ) CALL dom_tile_stop( ldhold=.TRUE. ) ! Use full domain - CALL fld_read( kt, 1, sf_chl ) ! Read Chl data and provides it at the current time step - IF( ln_tile ) CALL dom_tile_start( ldhold=.TRUE. ) ! Revert to tile domain - ENDIF - ! - ! Separation in R-G-B depending on the surface Chl - ! perform and store as many of the 2D calculations as possible - ! before the 3D loop (use the temporary 2D arrays to replace the - ! most expensive calculations) - ! - DO_2D_OVR( nn_hls, nn_hls, nn_hls, nn_hls ) - ! zlogc = log(zchl) - zlogc = LOG ( MIN( 10. , MAX( 0.03, sf_chl(1)%fnow(ji,jj,1) ) ) ) - ! zc1 : log(zCze) = log (1.12 * zchl**0.803) - zc1 = 0.113328685307 + 0.803 * zlogc - ! zc2 : log(zCtot) = log(40.6 * zchl**0.459) - zc2 = 3.703768066608 + 0.459 * zlogc - ! zc3 : log(zze) = log(568.2 * zCtot**(-0.746)) - zc3 = 6.34247346942 - 0.746 * zc2 - ! IF( log(zze) > log(102.) ) log(zze) = log(200.0 * zCtot**(-0.293)) - IF( zc3 > 4.62497281328 ) zc3 = 5.298317366548 - 0.293 * zc2 - ! - ze0(ji,jj) = zlogc ! ze0 = log(zchl) - ze1(ji,jj) = EXP( zc1 ) ! ze1 = zCze - ze2(ji,jj) = 1._wp / ( 0.710 + zlogc * ( 0.159 + zlogc * 0.021 ) ) ! ze2 = 1/zdelpsi - ze3(ji,jj) = EXP( - zc3 ) ! ze3 = 1/zze - END_2D - -! - DO_3D_OVR( nn_hls, nn_hls, nn_hls, nn_hls, 1, nksr + 1 ) - ! zchl = ALOG( ze0(ji,jj) ) - zlogc = ze0(ji,jj) - ! - zCb = 0.768 + zlogc * ( 0.087 - zlogc * ( 0.179 + zlogc * 0.025 ) ) - zCmax = 0.299 - zlogc * ( 0.289 - zlogc * 0.579 ) - zpsimax = 0.6 - zlogc * ( 0.640 - zlogc * ( 0.021 + zlogc * 0.115 ) ) - ! zdelpsi = 0.710 + zlogc * ( 0.159 + zlogc * 0.021 ) - ! - zCze = ze1(ji,jj) - zrdpsi = ze2(ji,jj) ! 1/zdelpsi - zpsi = ze3(ji,jj) * gdepw(ji,jj,jk,Kmm) ! gdepw/zze - ! - ! NB. make sure zchl value is such that: zchl = MIN( 10. , MAX( 0.03, zchl ) ) - zchl = MIN( 10. , MAX( 0.03, zCze * ( zCb + zCmax * EXP( -( (zpsi - zpsimax) * zrdpsi )**2 ) ) ) ) - ! Convert chlorophyll value to attenuation coefficient look-up table index - ztmp3d(ji,jj,jk) = 41 + 20.*LOG10(zchl) + 1.e-15 - END_3D - ELSE !* constant chlorophyll - zchl = 0.05 - ! NB. make sure constant value is such that: - zchl = MIN( 10. , MAX( 0.03, zchl ) ) - ! Convert chlorophyll value to attenuation coefficient look-up table index - zlui = 41 + 20.*LOG10(zchl) + 1.e-15 - DO jk = 1, nksr + 1 - ztmp3d(:,:,jk) = zlui - END DO - ENDIF + CASE( np_RGBc ) ; CALL qsr_RGBc( kt, Kmm, pts, Krhs ) !== R-G-B fluxes using chlorophyll data ==! with Morel &Berthon (1989) vertical profile ! - zcoef = ( 1. - rn_abs ) / 3._wp !* surface equi-partition in R-G-B - DO_2D_OVR( nn_hls, nn_hls, nn_hls, nn_hls ) - ze0(ji,jj) = rn_abs * qsr(ji,jj) - ze1(ji,jj) = zcoef * qsr(ji,jj) - ze2(ji,jj) = zcoef * qsr(ji,jj) - ze3(ji,jj) = zcoef * qsr(ji,jj) - ! store the surface SW radiation; re-use the surface ztmp3d array - ! since the surface attenuation coefficient is not used - ztmp3d(ji,jj,1) = qsr(ji,jj) - END_2D + CASE( np_RGB ) ; CALL qsr_RGB ( kt, Kmm, pts, Krhs ) !== R-G-B fluxes with constant chlorophyll ==! ! - ! !* interior equi-partition in R-G-B depending on vertical profile of Chl - DO_3D_OVR( nn_hls, nn_hls, nn_hls, nn_hls, 2, nksr + 1 ) - ze3t = e3t(ji,jj,jk-1,Kmm) - irgb = NINT( ztmp3d(ji,jj,jk) ) - zc0 = ze0(ji,jj) * EXP( - ze3t * xsi0r ) - zc1 = ze1(ji,jj) * EXP( - ze3t * rkrgb(1,irgb) ) - zc2 = ze2(ji,jj) * EXP( - ze3t * rkrgb(2,irgb) ) - zc3 = ze3(ji,jj) * EXP( - ze3t * rkrgb(3,irgb) ) - ze0(ji,jj) = zc0 - ze1(ji,jj) = zc1 - ze2(ji,jj) = zc2 - ze3(ji,jj) = zc3 - ztmp3d(ji,jj,jk) = ( zc0 + zc1 + zc2 + zc3 ) * wmask(ji,jj,jk) - END_3D - ! - DO_3D_OVR( nn_hls, nn_hls, nn_hls, nn_hls, 1, nksr ) !* now qsr induced heat content - qsr_hc(ji,jj,jk) = r1_rho0_rcp * ( ztmp3d(ji,jj,jk) - ztmp3d(ji,jj,jk+1) ) - END_3D + CASE( np_2BD ) ; CALL qsr_2BD ( Kmm, pts, Krhs ) !== 2-bands fluxes ==! ! - DEALLOCATE( ze0 , ze1 , ze2 , ze3 , ztmp3d ) - ! - CASE( np_2BD ) !== 2-bands fluxes ==! - ! - zz0 = rn_abs * r1_rho0_rcp ! surface equi-partition in 2-bands - zz1 = ( 1. - rn_abs ) * r1_rho0_rcp - DO_3D_OVR( nn_hls, nn_hls, nn_hls, nn_hls, 1, nksr ) !* now qsr induced heat content - zc0 = zz0 * EXP( -gdepw(ji,jj,jk ,Kmm)*xsi0r ) + zz1 * EXP( -gdepw(ji,jj,jk ,Kmm)*xsi1r ) - zc1 = zz0 * EXP( -gdepw(ji,jj,jk+1,Kmm)*xsi0r ) + zz1 * EXP( -gdepw(ji,jj,jk+1,Kmm)*xsi1r ) - qsr_hc(ji,jj,jk) = qsr(ji,jj) * ( zc0 * wmask(ji,jj,jk) - zc1 * wmask(ji,jj,jk+1) ) + CASE( np_BIO ) !== bio-model fluxes ==! + DO_3D( 0, 0, 0, 0, 1, nkV ) +#if defined key_RK3 + ! !- RK3 : temperature trend at jk t-level + ze3t = e3t(ji,jj,jk,Kmm) + pts(ji,jj,jk,jp_tem,Krhs) = pts(ji,jj,jk,jp_tem,Krhs) + r1_rho0_rcp * ( etot3(ji,jj,jk) - etot3(ji,jj,jk+1) ) / ze3t +#else + ! !- MLF : heat content trend due to Qsr flux (qsr_hc) + qsr_hc(ji,jj,jk) = r1_rho0_rcp * ( etot3(ji,jj,jk) - etot3(ji,jj,jk+1) ) +#endif END_3D + ! !- sea-ice : store the 1st level attenuation coefficient + WHERE( etot3(A2D(0),1) /= 0._wp ) ; fraqsr_1lev(A2D(0)) = 1._wp - etot3(A2D(0),2) / etot3(A2D(0),1) + ELSEWHERE ; fraqsr_1lev(A2D(0)) = 1._wp + END WHERE ! END SELECT ! - ! !-----------------------------! - ! ! update to the temp. trend ! - ! !-----------------------------! +#if defined key_RK3 + ! ! RK3 : diagnostics/output + IF( l_trdtra .OR. iom_use('qsr3d') ) THEN ! qsr diagnostics + ztrdt(:,:,:) = pts(:,:,:,jp_tem,Krhs) - ztrdt(:,:,:) + ! ! qsr tracers trends saved for diagnostics + IF( l_trdtra ) CALL trd_tra( kt, Kmm, Krhs, 'TRA', jp_tem, jptra_qsr, ztrdt ) + IF( iom_use('qsr3d') ) THEN ! qsr distribution + DO jk = nkV, 1, -1 + ztrdt(:,:,jk) = ztrdt(:,:,jk+1) + qsr_hc(:,:,jk) * rho0_rcp + END DO + CALL iom_put( 'qsr3d', ztrdt ) ! 3D distribution of shortwave Radiation + ENDIF + DEALLOCATE( ztrdt ) + ENDIF +#else + ! ! MLF : add the temperature trend DO_3D( 0, 0, 0, 0, 1, nksr ) pts(ji,jj,jk,jp_tem,Krhs) = pts(ji,jj,jk,jp_tem,Krhs) & & + z1_2 * ( qsr_hc_b(ji,jj,jk) + qsr_hc(ji,jj,jk) ) & @@ -286,7 +208,7 @@ CONTAINS END_3D ! ! sea-ice: store the 1st ocean level attenuation coefficient - DO_2D_OVR( nn_hls, nn_hls, nn_hls, nn_hls ) + DO_2D( 0, 0, 0, 0 ) IF( qsr(ji,jj) /= 0._wp ) THEN ; fraqsr_1lev(ji,jj) = qsr_hc(ji,jj,1) / ( r1_rho0_rcp * qsr(ji,jj) ) ELSE ; fraqsr_1lev(ji,jj) = 1._wp ENDIF @@ -301,6 +223,13 @@ CONTAINS CALL iom_put( 'qsr3d', zetot ) ! 3D distribution of shortwave Radiation DEALLOCATE( zetot ) ENDIF + ! + IF( l_trdtra ) THEN ! qsr tracers trends saved for diagnostics + ztrdt(:,:,:) = pts(:,:,:,jp_tem,Krhs) - ztrdt(:,:,:) + CALL trd_tra( kt, Kmm, Krhs, 'TRA', jp_tem, jptra_qsr, ztrdt ) + DEALLOCATE( ztrdt ) + ENDIF +#endif ! IF( .NOT. l_istiled .OR. ntile == nijtile ) THEN ! Do only on the last tile IF( lrst_oce ) THEN ! write in the ocean restart file @@ -309,11 +238,6 @@ CONTAINS ENDIF ENDIF ! - IF( l_trdtra ) THEN ! qsr tracers trends saved for diagnostics - ztrdt(:,:,:) = pts(:,:,:,jp_tem,Krhs) - ztrdt(:,:,:) - CALL trd_tra( kt, Kmm, Krhs, 'TRA', jp_tem, jptra_qsr, ztrdt ) - DEALLOCATE( ztrdt ) - ENDIF ! ! print mean trends (used for debugging) IF(sn_cfctl%l_prtctl) CALL prt_ctl( tab3d_1=pts(:,:,:,jp_tem,Krhs), clinfo1=' qsr - Ta: ', mask1=tmask, clinfo3='tra-ta' ) ! @@ -322,6 +246,518 @@ CONTAINS END SUBROUTINE tra_qsr + SUBROUTINE qsr_RGBc( kt, Kmm, pts, Krhs ) + !!---------------------------------------------------------------------- + !! *** ROUTINE qsr_RGBc *** + !! + !! ** Purpose : Red-Green-Blue solar radiation using chlorophyll data + !! + !! ** Method : The profile of the solar radiation within the ocean is defined + !! through 2 wavebands (rn_si0,rn_si1) or 3 wavebands (RGB) and a ratio rn_abs + !! Considering the 2 wavebands case: + !! I(k) = Qsr*( rn_abs*EXP(z(k)/rn_si0) + (1.-rn_abs)*EXP(z(k)/rn_si1) ) + !! The temperature trend associated with the solar radiation penetration + !! is given by : zta = 1/e3t dk[ I ] / (rho0*Cp) + !! At the bottom, boudary condition for the radiation is no flux : + !! all heat which has not been absorbed in the above levels is put + !! in the last ocean level. + !! The computation is only done down to the level where + !! I(k) < 1.e-15 W/m2 (i.e. over the top nk levels) . + !! + !! ** Action : - update ta with the penetrative solar radiation trend + !! - send trend for further diagnostics (l_trdtra=T) + !! + !! Reference : Lengaigne et al. 2007, Clim. Dyn., V28, 5, 503-516. + !! Morel, A. et Berthon, JF, 1989, Limnol Oceanogr 34(8), 1545-1562 + !!---------------------------------------------------------------------- + INTEGER, INTENT(in ) :: kt, Kmm, Krhs ! ocean time-step and time-level indices + REAL(wp), DIMENSION(jpi,jpj,jpk,jpts,jpt), INTENT(inout) :: pts ! active tracers and RHS of tracer equation + !! + INTEGER :: ji, jj, jk ! dummy loop indices + INTEGER :: irgb ! local integer + REAL(wp) :: zc1 , zc2 , zc3, zchl ! local scalars + REAL(wp) :: zze0, zzeR, zzeG, zzeB, zzeT ! - - + REAL(wp) :: zz0 , zz1 , ze3t ! - - + REAL(wp) :: zCb, zCmax, zpsi, zpsimax, zrdpsi, zCze ! - - + REAL(wp) :: zlogc, zlogze, zlogCtot, zlogCze ! - - + REAL(wp), DIMENSION(A2D(0) ) :: ze0, zeR, zeG, zeB, zeT + REAL(wp), DIMENSION(A2D(0),0:3) :: zc + !!---------------------------------------------------------------------- + ! + ! + ! !===========================================! + ! !== R-G-B fluxes using chlorophyll data ==! with Morel &Berthon (1989) vertical profile + ! !===================================****====! + ! + ! != Chlorophyll data =! + ! + IF( ntile == 0 .OR. ntile == 1 ) THEN ! Do only for the full domain + IF( ln_tile ) CALL dom_tile( ntsi, ntsj, ntei, ntej, ktile = 0 ) ! Use full domain + CALL fld_read( kt, 1, sf_chl ) ! Read Chl data and provides it at the current time step + IF( ln_tile ) CALL dom_tile( ntsi, ntsj, ntei, ntej, ktile = 1 ) ! Revert to tile domain + ENDIF + ! + DO_2D( 0, 0, 0, 0 ) ! pre-calculated expensive coefficient + zlogc = LOG( MAX( 0.03_wp, MIN( sf_chl(1)%fnow(ji,jj,1) ,10._wp ) ) ) ! zlogc = log(zchl) with 0.03 <= Chl >= 10. + zc1 = 0.113328685307 + 0.803 * zlogc ! zc1 : log(zCze) = log (1.12 * zchl**0.803) + zc2 = 3.703768066608 + 0.459 * zlogc ! zc2 : log(zCtot) = log(40.6 * zchl**0.459) + zc3 = 6.34247346942 - 0.746 * zc2 ! zc3 : log(zze) = log(568.2 * zCtot**(-0.746)) + IF( zc3 > 4.62497281328 ) zc3 = 5.298317366548 - 0.293 * zc2 ! IF(log(zze)>log(102)) log(zze) = log(200*zCtot**(-0.293)) + ! + zc(ji,jj,0) = zlogc ! ze(0) = log(zchl) + zc(ji,jj,1) = EXP( zc1 ) ! ze(1) = zCze + zc(ji,jj,2) = 1._wp / ( 0.710 + zlogc * ( 0.159 + zlogc * 0.021 ) ) ! ze(2) = 1/zdelpsi + zc(ji,jj,3) = EXP( - zc3 ) ! ze(3) = 1/zze + END_2D + ! + ! != surface light =! + ! + zz0 = rn_abs ! Infrared absorption + zz1 = ( 1._wp - rn_abs ) / 3._wp ! R-G-B equi-partition + ! + DO_2D( 0, 0, 0, 0 ) ! surface light + ze0(ji,jj) = zz0 * qsr(ji,jj) ; zeR(ji,jj) = zz1 * qsr(ji,jj) ! IR ; Red + zeG(ji,jj) = zz1 * qsr(ji,jj) ; zeB(ji,jj) = zz1 * qsr(ji,jj) ! Green ; Blue + zeT(ji,jj) = qsr(ji,jj) ! Total + END_2D + ! + ! != interior light =! + ! + DO jk = 1, nk0 !* near surface layers *! (< ~12 meters : IR + RGB ) + DO_2D( 0, 0, 0, 0 ) + ! !- inverse of RGB attenuation lengths + zlogc = zc(ji,jj,0) + zCb = 0.768 + zlogc * ( 0.087 - zlogc * ( 0.179 + zlogc * 0.025 ) ) + zCmax = 0.299 - zlogc * ( 0.289 - zlogc * 0.579 ) + zpsimax = 0.6 - zlogc * ( 0.640 - zlogc * ( 0.021 + zlogc * 0.115 ) ) + ! zdelpsi = 0.710 + zlogc * ( 0.159 + zlogc * 0.021 ) + zCze = zc(ji,jj,1) + zrdpsi = zc(ji,jj,2) ! 1/zdelpsi +!!st05 zpsi = zc(ji,jj,3) * gdepw(ji,jj,jk,Kmm) ! gdepw/zze + zpsi = zc(ji,jj,3) * gdepw(ji,jj,jk+1,Kmm) ! gdepw/zze + ! ! make sure zchl value is such that: 0.03 < zchl < 10. + zchl = MAX( 0.03_wp , MIN( zCze * ( zCb + zCmax * EXP( -( (zpsi - zpsimax) * zrdpsi )**2 ) ) , 10._wp ) ) + ! ! Convert chlorophyll value to attenuation coefficient + irgb = NINT( 41 + 20.*LOG10(zchl) + 1.e-15 ) ! look-up table index + ! Red ! Green ! Blue + r1_LR = rkrgb(3,irgb) ; r1_LG = rkrgb(2,irgb) ; r1_LB = rkrgb(1,irgb) + ! + ! !- fluxes at jk+1 w-level + ze3t = e3t(ji,jj,jk,Kmm) + zze0 = ze0(ji,jj) * EXP( - ze3t*r1_si0 ) ; zzeR = zeR(ji,jj) * EXP( - ze3t*r1_LR ) ! IR ; Red at jk+1 w-level + zzeG = zeG(ji,jj) * EXP( - ze3t*r1_LG ) ; zzeB = zeB(ji,jj) * EXP( - ze3t*r1_LB ) ! Green ; Blue - - + zzeT = ( zze0 + zzeB + zzeG + zzeR ) * wmask(ji,jj,jk+1) ! Total - - +!!st01 zzeT = ( zze0 + zzeR + zzeG + zzeB ) * wmask(ji,jj,jk+1) ! Total - - + ! +#if defined key_RK3 + ! !- RK3 : temperature trend at jk t-level + pts(ji,jj,jk,jp_tem,Krhs) = pts(ji,jj,jk,jp_tem,Krhs) + r1_rho0_rcp * ( zeT(ji,jj) - zzeT ) / ze3t +#else + ! !- MLF : heat content trend due to Qsr flux (qsr_hc) + qsr_hc(ji,jj,jk) = r1_rho0_rcp * ( zeT(ji,jj) - zzeT ) +#endif + ze0(ji,jj) = zze0 ; zeR(ji,jj) = zzeR ! IR ; Red store at jk+1 w-level + zeG(ji,jj) = zzeG ; zeB(ji,jj) = zzeB ! Green ; Blue - - - + zeT(ji,jj) = zzeT ! total - - - + END_2D + ! + END DO + ! + DO jk = nk0+1, nkR !* down to Red extinction *! (< ~71 meters : RGB , IR removed from calculation) + DO_2D( 0, 0, 0, 0 ) + ! !- inverse of RGB attenuation lengths + zlogc = zc(ji,jj,0) + zCb = 0.768 + zlogc * ( 0.087 - zlogc * ( 0.179 + zlogc * 0.025 ) ) + zCmax = 0.299 - zlogc * ( 0.289 - zlogc * 0.579 ) + zpsimax = 0.6 - zlogc * ( 0.640 - zlogc * ( 0.021 + zlogc * 0.115 ) ) + ! zdelpsi = 0.710 + zlogc * ( 0.159 + zlogc * 0.021 ) + zCze = zc(ji,jj,1) + zrdpsi = zc(ji,jj,2) ! 1/zdelpsi + zpsi = zc(ji,jj,3) * gdepw(ji,jj,jk+1,Kmm) ! gdepw/zze +!!st05 zpsi = zc(ji,jj,3) * gdepw(ji,jj,jk,Kmm) ! gdepw/zze + ! ! make sure zchl value is such that: 0.03 < zchl < 10. + zchl = MAX( 0.03_wp , MIN( zCze * ( zCb + zCmax * EXP( -( (zpsi - zpsimax) * zrdpsi )**2 ) ) , 10._wp ) ) + ! ! Convert chlorophyll value to attenuation coefficient + irgb = NINT( 41 + 20.*LOG10(zchl) + 1.e-15 ) ! look-up table index + ! Red ! Green ! Blue + r1_LR = rkrgb(3,irgb) ; r1_LG = rkrgb(2,irgb) ; r1_LB = rkrgb(1,irgb) + ! + ! !- fluxes at jk+1 w-level + ze3t = e3t(ji,jj,jk,Kmm) + zzeR = zeR(ji,jj) * EXP( - ze3t*r1_LR ) ! Red at jk+1 w-level + zzeG = zeG(ji,jj) * EXP( - ze3t*r1_LG ) ; zzeB = zeB(ji,jj) * EXP( - ze3t*r1_LB ) ! Green ; Blue - - + zzeT = ( zzeR + zzeG + zzeB ) * wmask(ji,jj,jk+1) ! Total - - + ! +#if defined key_RK3 + ! !- RK3 : temperature trend at jk t-level + pts(ji,jj,jk,jp_tem,Krhs) = pts(ji,jj,jk,jp_tem,Krhs) + r1_rho0_rcp * ( zeT(ji,jj) - zzeT ) / ze3t +#else + ! !- MLF : heat content trend due to Qsr flux (qsr_hc) + qsr_hc(ji,jj,jk) = r1_rho0_rcp * ( zeT(ji,jj) - zzeT ) +#endif + zeR(ji,jj) = zzeR ! Red store at jk+1 w-level + zeG(ji,jj) = zzeG ; zeB(ji,jj) = zzeB ! Green ; Blue - - - + zeT(ji,jj) = zzeT ! total - - - + END_2D + END DO + ! + DO jk = nkR+1, nkG !* down to Green extinction *! (< ~350 m : GB , IR+R removed from calculation) + DO_2D( 0, 0, 0, 0 ) + ! !- inverse of RGB attenuation lengths + zlogc = zc(ji,jj,0) + zCb = 0.768 + zlogc * ( 0.087 - zlogc * ( 0.179 + zlogc * 0.025 ) ) + zCmax = 0.299 - zlogc * ( 0.289 - zlogc * 0.579 ) + zpsimax = 0.6 - zlogc * ( 0.640 - zlogc * ( 0.021 + zlogc * 0.115 ) ) + ! zdelpsi = 0.710 + zlogc * ( 0.159 + zlogc * 0.021 ) + zCze = zc(ji,jj,1) + zrdpsi = zc(ji,jj,2) ! 1/zdelpsi + zpsi = zc(ji,jj,3) * gdepw(ji,jj,jk+1,Kmm) ! gdepw/zze +!!st05 zpsi = zc(ji,jj,3) * gdepw(ji,jj,jk,Kmm) ! gdepw/zze + ! ! make sure zchl value is such that: 0.03 < zchl < 10. + zchl = MAX( 0.03_wp , MIN( zCze * ( zCb + zCmax * EXP( -( (zpsi - zpsimax) * zrdpsi )**2 ) ) , 10._wp ) ) + ! ! Convert chlorophyll value to attenuation coefficient + irgb = NINT( 41 + 20.*LOG10(zchl) + 1.e-15 ) ! look-up table index + ! Green ! Blue + r1_LG = rkrgb(2,irgb) ; r1_LB = rkrgb(1,irgb) + ! + ! !- fluxes at jk+1 w-level + ze3t = e3t(ji,jj,jk,Kmm) + zzeG = zeG(ji,jj) * EXP( - ze3t * r1_LG ) ; zzeB = zeB(ji,jj) * EXP( - ze3t * r1_LB ) ! Green ; Blue + zzeT = ( zzeG + zzeB ) * wmask(ji,jj,jk+1) ! Total - - +#if defined key_RK3 + ! !- RK3 : temperature trend at jk t-level + pts(ji,jj,jk,jp_tem,Krhs) = pts(ji,jj,jk,jp_tem,Krhs) + r1_rho0_rcp * ( zeT(ji,jj) - zzeT ) / ze3t +#else + ! !- MLF : heat content trend due to Qsr flux (qsr_hc) + qsr_hc(ji,jj,jk) = r1_rho0_rcp * ( zeT(ji,jj) - zzeT ) +#endif + zeG(ji,jj) = zzeG ; zeB(ji,jj) = zzeB ! Green ; Blue store at jk+1 w-level + zeT(ji,jj) = zzeT ! total - - - + END_2D + END DO + ! + DO jk = nkG+1, nkB !* down to Blue extinction *! (< ~1300 m : B , IR+RG removed from calculation) + DO_2D( 0, 0, 0, 0 ) + ! !- inverse of RGB attenuation lengths + zlogc = zc(ji,jj,0) + zCb = 0.768 + zlogc * ( 0.087 - zlogc * ( 0.179 + zlogc * 0.025 ) ) + zCmax = 0.299 - zlogc * ( 0.289 - zlogc * 0.579 ) + zpsimax = 0.6 - zlogc * ( 0.640 - zlogc * ( 0.021 + zlogc * 0.115 ) ) + ! zdelpsi = 0.710 + zlogc * ( 0.159 + zlogc * 0.021 ) + zCze = zc(ji,jj,1) + zrdpsi = zc(ji,jj,2) ! 1/zdelpsi + zpsi = zc(ji,jj,3) * gdepw(ji,jj,jk+1,Kmm) ! gdepw/zze +!!st05 zpsi = zc(ji,jj,3) * gdepw(ji,jj,jk,Kmm) ! gdepw/zze + ! ! make sure zchl value is such that: 0.03 < zchl < 10. + zchl = MAX( 0.03_wp , MIN( zCze * ( zCb + zCmax * EXP( -( (zpsi - zpsimax) * zrdpsi )**2 ) ) , 10._wp ) ) + ! ! Convert chlorophyll value to attenuation coefficient + irgb = NINT( 41 + 20.*LOG10(zchl) + 1.e-15 ) ! look-up table index + r1_LB = rkrgb(1,irgb) ! Blue + ! + ! !- fluxes at jk+1 w-level + ze3t = e3t(ji,jj,jk,Kmm) + zzeB = zeB(ji,jj) * EXP( - ze3t * r1_LB ) ! Blue + zzeT = ( zzeB ) * wmask(ji,jj,jk+1) ! Total - - +#if defined key_RK3 + ! !- RK3 : temperature trend at jk t-level + pts(ji,jj,jk,jp_tem,Krhs) = pts(ji,jj,jk,jp_tem,Krhs) + r1_rho0_rcp * ( zeT(ji,jj) - zzeT ) / ze3t +#else + ! !- MLF : heat content trend due to Qsr flux (qsr_hc) + qsr_hc(ji,jj,jk) = r1_rho0_rcp * ( zeT(ji,jj) - zzeT ) +#endif + zeB(ji,jj) = zzeB ! Blue store at jk+1 w-level + zeT(ji,jj) = zzeT ! total - - - + END_2D + END DO + ! + END SUBROUTINE qsr_RGBc + + + SUBROUTINE qsr_RGB( kt, Kmm, pts, Krhs ) + !!---------------------------------------------------------------------- + !! *** ROUTINE qsr_RGB *** + !! + !! ** Purpose : Red-Green-Blue solar radiation with constant chlorophyll + !! + !! ** Method : The profile of the solar radiation within the ocean is defined + !! through 2 wavebands (rn_si0,rn_si1) or 1 (rn_si0,rn_abs) + 3 wavebands (RGB) + !! At the bottom, boudary condition for the radiation is no flux : + !! all heat which has not been absorbed in the above levels is put + !! in the last ocean level. + !! For each band, the computation is only done down to the level where + !! I(k) < 1.e-15 W/m2 (i.e. over the top nk levels) . + !! + !! ** Action : - update ta with the penetrative solar radiation trend + !! - send trend for further diagnostics (l_trdtra=T) + !! + !! Reference : Lengaigne et al. 2007, Clim. Dyn., V28, 5, 503-516. + !! Morel, A. et Berthon, JF, 1989, Limnol Oceanogr 34(8), 1545-1562 + !!---------------------------------------------------------------------- + INTEGER, INTENT(in ) :: kt, Kmm, Krhs ! ocean time-step and time-level indices + REAL(wp), DIMENSION(jpi,jpj,jpk,jpts,jpt), INTENT(inout) :: pts ! active tracers and RHS of tracer equation + !! + INTEGER :: ji, jj, jk ! dummy loop indices + REAL(wp) :: zze0, zzeR, zzeG, zzeB, zzeT ! - - + REAL(wp) :: zz0 , zz1 , ze3t ! - - + REAL(wp), DIMENSION(A2D(0)) :: ze0, zeR, zeG, zeB, zeT + !!---------------------------------------------------------------------- + ! + ! + ! !==============================================! + ! !== R-G-B fluxes with constant chlorophyll ==! + ! !======================********================! + ! + ! != surface light =! + ! + zz0 = rn_abs ! Infrared absorption + zz1 = ( 1._wp - rn_abs ) / 3._wp ! surface equi-partition in R-G-B + ! + DO_2D( 0, 0, 0, 0 ) ! surface light + ze0(ji,jj) = zz0 * qsr(ji,jj) ; zeR(ji,jj) = zz1 * qsr(ji,jj) ! IR ; Red + zeG(ji,jj) = zz1 * qsr(ji,jj) ; zeB(ji,jj) = zz1 * qsr(ji,jj) ! Green ; Blue + zeT(ji,jj) = qsr(ji,jj) ! Total + END_2D + ! + ! != interior light =! + ! + DO jk = 1, nk0 !* near surface layers *! (< ~12 meters : IR + RGB ) + DO_2D( 0, 0, 0, 0 ) + ze3t = e3t(ji,jj,jk,Kmm) + zze0 = ze0(ji,jj) * EXP( - ze3t * r1_si0 ) ; zzeR = zeR(ji,jj) * EXP( - ze3t * r1_LR ) ! IR ; Red at jk+1 w-level + zzeG = zeG(ji,jj) * EXP( - ze3t * r1_LG ) ; zzeB = zeB(ji,jj) * EXP( - ze3t * r1_LB ) ! Green ; Blue - - + zzeT = ( zze0 + zzeB + zzeG + zzeR ) * wmask(ji,jj,jk+1) ! Total - - +!!st7-9 zzeT = ( zze0 + zzeR + zzeG + zzeB ) * wmask(ji,jj,jk+1) ! Total - - +#if defined key_RK3 + ! ! RK3 : temperature trend at jk t-level + pts(ji,jj,jk,jp_tem,Krhs) = pts(ji,jj,jk,jp_tem,Krhs) + r1_rho0_rcp * ( zeT(ji,jj) - zzeT ) / ze3t +#else + ! ! MLF : heat content trend due to Qsr flux (qsr_hc) + qsr_hc(ji,jj,jk) = r1_rho0_rcp * ( zeT(ji,jj) - zzeT ) +#endif + ze0(ji,jj) = zze0 ; zeR(ji,jj) = zzeR ! IR ; Red store at jk+1 w-level + zeG(ji,jj) = zzeG ; zeB(ji,jj) = zzeB ! Green ; Blue - - - + zeT(ji,jj) = zzeT ! total - - - + END_2D +!!stbug IF( jk == 1 ) THEN !* sea-ice *! store the 1st level attenuation coeff. +!!stbug WHERE( qsr(A2D(0)) /= 0._wp ) ; fraqsr_1lev(A2D(0)) = 1._wp - zeT(A2D(0)) / qsr(A2D(0)) +!!stbug ELSEWHERE ; fraqsr_1lev(A2D(0)) = 1._wp +!!stbug END WHERE +!!stbug ENDIF + END DO + ! + DO jk = nk0+1, nkR !* down to Red extinction *! (< ~71 meters : RGB , IR removed from calculation) + DO_2D( 0, 0, 0, 0 ) + ze3t = e3t(ji,jj,jk,Kmm) + zzeR = zeR(ji,jj) * EXP( - ze3t * r1_LR ) ! Red at jk+1 w-level + zzeG = zeG(ji,jj) * EXP( - ze3t * r1_LG ) ; zzeB = zeB(ji,jj) * EXP( - ze3t * r1_LB ) ! Green ; Blue - - + zzeT = ( zzeB + zzeG + zzeR ) * wmask(ji,jj,jk+1) ! Total - - +!!st7-11 zzeT = ( zzeR + zzeG + zzeB ) * wmask(ji,jj,jk+1) ! Total - - +#if defined key_RK3 + ! ! RK3 : temperature trend at jk t-level + pts(ji,jj,jk,jp_tem,Krhs) = pts(ji,jj,jk,jp_tem,Krhs) + r1_rho0_rcp * ( zeT(ji,jj) - zzeT ) / ze3t +#else + ! ! MLF : heat content trend due to Qsr flux (qsr_hc) + qsr_hc(ji,jj,jk) = r1_rho0_rcp * ( zeT(ji,jj) - zzeT ) +#endif + zeR(ji,jj) = zzeR ! Red store at jk+1 w-level + zeG(ji,jj) = zzeG ; zeB(ji,jj) = zzeB ! Green ; Blue - - - + zeT(ji,jj) = zzeT ! total - - - + END_2D + END DO + ! + DO jk = nkR+1, nkG !* down to Green extinction *! (< ~350 m : GB , IR+R removed from calculation) + DO_2D( 0, 0, 0, 0 ) + ze3t = e3t(ji,jj,jk,Kmm) + zzeG = zeG(ji,jj) * EXP( - ze3t * r1_LG ) ; zzeB = zeB(ji,jj) * EXP( - ze3t * r1_LB ) ! Green ; Blue at jk+1 w-level + zzeT = ( zzeG + zzeB ) * wmask(ji,jj,jk+1) ! Total - - +#if defined key_RK3 + ! ! RK3 : temperature trend at jk t-level + pts(ji,jj,jk,jp_tem,Krhs) = pts(ji,jj,jk,jp_tem,Krhs) + r1_rho0_rcp * ( zeT(ji,jj) - zzeT ) / ze3t +#else + ! ! MLF : heat content trend due to Qsr flux (qsr_hc) + qsr_hc(ji,jj,jk) = r1_rho0_rcp * ( zeT(ji,jj) - zzeT ) +#endif + zeG(ji,jj) = zzeG ; zeB(ji,jj) = zzeB ! Green ; Blue store at jk+1 w-level + zeT(ji,jj) = zzeT ! total - - - + END_2D + END DO + ! + DO jk = nkG+1, nkB !* down to Blue extinction *! (< ~1300 m : B , IR+RG removed from calculation) + DO_2D( 0, 0, 0, 0 ) + ze3t = e3t(ji,jj,jk,Kmm) + zzeB = zeB(ji,jj) * EXP( - ze3t * r1_LB ) ! Blue at jk+1 w-level + zzeT = ( zzeB ) * wmask(ji,jj,jk+1) ! Total - - +#if defined key_RK3 + ! ! RK3 : temperature trend at jk t-level + pts(ji,jj,jk,jp_tem,Krhs) = pts(ji,jj,jk,jp_tem,Krhs) + r1_rho0_rcp * ( zeT(ji,jj) - zzeT ) / ze3t +#else + ! ! MLF : heat content trend due to Qsr flux (qsr_hc) + qsr_hc(ji,jj,jk) = r1_rho0_rcp * ( zeT(ji,jj) - zzeT ) +#endif + zeB(ji,jj) = zzeB ! Blue store at jk+1 w-level + zeT(ji,jj) = zzeT ! total - - - + END_2D + END DO + ! + END SUBROUTINE qsr_RGB + + + SUBROUTINE qsr_2BD( Kmm, pts, Krhs ) + !!---------------------------------------------------------------------- + !! *** ROUTINE qsr_2BD *** + !! + !! ** Purpose : 2 bands (IR+visible) solar radiation with constant chlorophyll + !! + !! ** Method : The profile of the solar radiation within the ocean is defined + !! through 2 wavebands (rn_si0,rn_si1) a ratio rn_abs for IR absorbtion. + !! Considering the 2 wavebands case: + !! I(k) = Qsr*( rn_abs*EXP(z(k)/rn_si0) + (1.-rn_abs)*EXP(z(k)/rn_si1) ) + !! The temperature trend associated with the solar radiation penetration + !! is given by : zta = 1/e3t dk[ I ] / (rho0*Cp) + !! At the bottom, boudary condition for the radiation is no flux : + !! all heat which has not been absorbed in the above levels is put + !! in the last ocean level. + !! The computation is only done down to the level where + !! I(k) < 1.e-15 W/m2 (i.e. over the top nk levels) . + !! + !! ** Action : - update ta with the penetrative solar radiation trend + !! - send trend for further diagnostics (l_trdtra=T) + !! + !! Reference : Jerlov, N. G., 1968 Optical Oceanography, Elsevier, 194pp. + !! Lengaigne et al. 2007, Clim. Dyn., V28, 5, 503-516. + !! Morel, A. et Berthon, JF, 1989, Limnol Oceanogr 34(8), 1545-1562 + !!---------------------------------------------------------------------- + INTEGER, INTENT(in ) :: Kmm, Krhs ! ocean time-step and time-level indices + REAL(wp), DIMENSION(jpi,jpj,jpk,jpts,jpt), INTENT(inout) :: pts ! active tracers and RHS of tracer equation + !! + INTEGER :: ji, jj, jk ! dummy loop indices + REAL(wp) :: zzatt ! - - + REAL(wp) :: zz0 , zz1 , ze3t ! - - + REAL(wp), DIMENSION(A2D(0)) :: zatt + !!---------------------------------------------------------------------- + ! + ! !======================! + ! !== 2-bands fluxes ==! + ! !======================! + ! + zz0 = rn_abs * r1_rho0_rcp ! surface equi-partition in 2-bands + zz1 = ( 1._wp - rn_abs ) * r1_rho0_rcp + ! + zatt(A2D(0)) = r1_rho0_rcp !* surface value *! + ! + DO_2D( 0, 0, 0, 0 ) + zatt(ji,jj) = ( zz0 * EXP( -gdepw(ji,jj,1,Kmm)*r1_si0 ) + zz1 * EXP( -gdepw(ji,jj,1,Kmm)*r1_si1 ) ) + END_2D + ! +!!st IF(lwp) WRITE(numout,*) 'level = ', 1, ' qsr max = ' , MAXVAL(zatt)*rho0_rcp, ' W/m2', ' qsr min = ' , MINVAL(zatt)*rho0_rcp, ' W/m2' + ! + DO jk = 1, nk0 !* near surface layers *! (< ~14 meters : IR + visible light ) + DO_2D( 0, 0, 0, 0 ) + ze3t = e3t(ji,jj,jk,Kmm) ! light attenuation at jk+1 w-level (divided by rho0_rcp) + zzatt = ( zz0 * EXP( -gdepw(ji,jj,jk+1,Kmm)*r1_si0 ) & + & + zz1 * EXP( -gdepw(ji,jj,jk+1,Kmm)*r1_si1 ) ) * wmask(ji,jj,jk+1) +#if defined key_RK3 + ! ! RK3 : temperature trend at jk t-level + pts(ji,jj,jk,jp_tem,Krhs) = pts(ji,jj,jk,jp_tem,Krhs) + qsr(ji,jj) * ( zatt(ji,jj) - zzatt ) / ze3t +#else + ! ! MLF : heat content trend due to Qsr flux (qsr_hc) + qsr_hc(ji,jj,jk) = qsr(ji,jj) * ( zatt(ji,jj) - zzatt ) +#endif + zatt(ji,jj) = zzatt ! save for the next level computation + END_2D +!!stbug ! !* sea-ice *! store the 1st level attenuation coeff. +!!stbug IF( jk == 1 ) fraqsr_1lev(A2D(0)) = 1._wp - zatt(A2D(0)) * rho0_rcp + END DO +!!st IF(lwp) WRITE(numout,*) 'nk0+1= ', nk0+1, ' qsr max = ' , MAXVAL(zatt*qsr)*rho0_rcp, ' W/m2' , MAXVAL(zatt*qsr/e3t(:,:,nk0+1,Kmm)), ' K/s' + ! + DO jk = nk0+1, nkV !* deeper layers *! (visible light only) + DO_2D( 0, 0, 0, 0 ) + ze3t = e3t(ji,jj,jk,Kmm) ! light attenuation at jk+1 w-level (divided by rho0_rcp) + zzatt = ( zz1 * EXP( -gdepw(ji,jj,jk+1,Kmm)*r1_si1 ) ) * wmask(ji,jj,jk+1) +#if defined key_RK3 + ! ! RK3 : temperature trend at jk t-level + pts(ji,jj,jk,jp_tem,Krhs) = pts(ji,jj,jk,jp_tem,Krhs) + qsr(ji,jj) * ( zatt(ji,jj) - zzatt ) / ze3t +#else + ! ! MLF : heat content trend due to Qsr flux (qsr_hc) + qsr_hc(ji,jj,jk) = qsr(ji,jj) * ( zatt(ji,jj) - zzatt ) +#endif + zatt(ji,jj) = zzatt ! save for the next level computation + END_2D + END DO + ! +!!st IF(lwp) WRITE(numout,*) 'nkV+1= ', nkV+1, ' qsr max = ' , MAXVAL(zatt*qsr)*rho0_rcp, ' W/m2' , MAXVAL(zatt*qsr/e3t(:,:,nkV+1,Kmm)), ' K/s' + END SUBROUTINE qsr_2bd + + + FUNCTION qsr_ext_lev( pL, pfr ) RESULT( klev ) + !!---------------------------------------------------------------------- + !! *** ROUTINE trc_oce_ext_lev *** + !! + !! ** Purpose : compute the maximum level of light penetration + !! + !! ** Method : the function provides the level at which irradiance, I, + !! has a negligible effect on temperature. + !! T(n+1)-T(n) = ∆t dk[I] / ( rho0 Cp e3t_k ) + !! I(k) has a negligible effect on temperature at level k if: + !! ∆t I(k) / ( rho0*Cp*e3t_k ) <= 1.e-15 °C + !! with I(z) = Qsr*pfr*EXP(-z/L), therefore : + !! z >= L * LOG( 1.e-15 * rho0*Cp*e3t_k / ( ∆t*Qsr*pfr ) ) + !! with Qsr being the maximum normal surface irradiance at sea + !! level (~1000 W/m2). + !! # pL is the longest depth of extinction: + !! - pL = 23.00 m (2 bands case) + !! - pL = 48.24 m (3 bands case: blue waveband & 0.03 mg/m2 for the chlorophyll) + !! # pfr is the fraction of solar radiation which penetrates, + !! considering Qsr=1000 W/m2 and rn_abs = 0.58: + !! - Qsr*pfr0 = Qsr * rn_abs = 580 W/m2 (top absorbtion) + !! - Qsr*pfr1 = Qsr * (1-rn_abs) = 420 W/m2 (2 bands case) + !! - Qsr*pfr1 = Qsr * (1-rn_abs)/3 = 140 W/m2 (3 bands case & equi-partition) + !! + !!---------------------------------------------------------------------- + INTEGER :: klev ! result: maximum level of light penetration + REAL(wp), INTENT(in) :: pL ! depth of extinction + REAL(wp), INTENT(in) :: pfr ! frac. solar radiation which penetrates + ! + INTEGER :: jk ! dummy loop index + REAL(wp) :: zcoef ! local scalar + REAL(wp) :: zhext ! deepest depth until which light penetrates + REAL(wp) :: ze3t , zdw ! max( e3t_k ) and min( w-depth_k+1 ) + REAL(wp) :: zprec = 10.e-15_wp ! required precision + REAL(wp) :: zQmax= 1000._wp ! maximum normal surface irradiance at sea level (W/m2) + !!---------------------------------------------------------------------- + ! + zQmax = 1000._wp ! maximum normal surface irradiance at sea level (W/m2) + ! + zcoef = zprec * rho0_rcp / ( rDt * zQmax * pfr) + ! + IF( ln_zco .OR. ln_zps ) THEN ! z- or zps coordinate (use 1D ref vertcial coordinate) + klev = jpkm1 ! Level of light extinction zco / zps + DO jk = jpkm1, 1, -1 + zdw = gdepw_1d(jk+1) ! max w-depth at jk+1 level + ze3t = e3t_1d(jk ) ! minimum e3t at jk level + zhext = - pL * LOG( zcoef * ze3t ) ! extinction depth + IF( zdw >= zhext ) klev = jk ! last T-level reached by Qsr + END DO + ELSE ! s- or s-z- coordinate (use 3D vertical coordinate) + klev = jpkm1 ! Level of light extinction + DO jk = jpkm1, 1, -1 ! + IF( SUM( tmask(:,:,jk) ) > 0 ) THEN ! ocean point at that level + zdw = MAXVAL( gdepw_0(:,:,jk+1) * wmask(:,:,jk) ) ! max w-depth at jk+1 level + ze3t = MINVAL( e3t_0(:,:,jk ) , mask=(wmask(:,:,jk+1)==1) ) ! minimum e3t at jk level + zhext = - pL * LOG( zcoef * ze3t ) ! extinction depth + IF( zdw >= zhext ) klev = jk ! last T-level reached by Qsr + ELSE ! only land point at level jk + klev = jk ! local domain sea-bed level + ENDIF + END DO + CALL mpp_max('tra_qsr', klev) ! needed for reproducibility !!st may be modified to avoid this comm. + ! !!st use ssmask to remove the comm ? + ENDIF + ! +!!st IF(lwp) WRITE(numout,*) ' level of e3t light extinction = ', klev, ' ref depth = ', gdepw_1d(klev+1), ' m' + END FUNCTION qsr_ext_lev + + SUBROUTINE tra_qsr_init !!---------------------------------------------------------------------- !! *** ROUTINE tra_qsr_init *** @@ -340,9 +776,9 @@ CONTAINS !! Reference : Jerlov, N. G., 1968 Optical Oceanography, Elsevier, 194pp. !!---------------------------------------------------------------------- INTEGER :: ji, jj, jk ! dummy loop indices - INTEGER :: ios, irgb, ierror, ioptio ! local integer - REAL(wp) :: zz0, zc0 , zc1, zcoef ! local scalars - REAL(wp) :: zz1, zc2 , zc3, zchl ! - - + INTEGER :: ios, ierror, ioptio ! local integer + REAL(wp) :: zLB, zLG, zLR ! local scalar + REAL(wp) :: zVlp, zchl ! - - ! CHARACTER(len=100) :: cn_dir ! Root directory for location of ssr files TYPE(FLD_N) :: sn_chl ! informations about the chlorofyl field to be read @@ -353,12 +789,11 @@ CONTAINS ! READ ( numnam_ref, namtra_qsr, IOSTAT = ios, ERR = 901) 901 IF( ios /= 0 ) CALL ctl_nam ( ios , 'namtra_qsr in reference namelist' ) - ! - READ ( numnam_cfg, namtra_qsr, IOSTAT = ios, ERR = 902 ) + READ ( numnam_cfg, namtra_qsr, IOSTAT = ios, ERR = 902) 902 IF( ios > 0 ) CALL ctl_nam ( ios , 'namtra_qsr in configuration namelist' ) IF(lwm) WRITE ( numond, namtra_qsr ) ! - IF(lwp) THEN ! control print + IF(lwp) THEN !** control print **! WRITE(numout,*) WRITE(numout,*) 'tra_qsr_init : penetration of the surface solar radiation' WRITE(numout,*) '~~~~~~~~~~~~' @@ -368,12 +803,12 @@ CONTAINS WRITE(numout,*) ' bio-model light penetration ln_qsr_bio = ', ln_qsr_bio WRITE(numout,*) ' RGB : Chl data (=1) or cst value (=0) nn_chldta = ', nn_chldta WRITE(numout,*) ' RGB & 2 bands: fraction of light (rn_si1) rn_abs = ', rn_abs - WRITE(numout,*) ' RGB & 2 bands: shortess depth of extinction rn_si0 = ', rn_si0 - WRITE(numout,*) ' 2 bands: longest depth of extinction rn_si1 = ', rn_si1 + WRITE(numout,*) ' RGB & 2 bands: shortess attenuation depth rn_si0 = ', rn_si0 + WRITE(numout,*) ' 2 bands: longest attenuation depth rn_si1 = ', rn_si1 WRITE(numout,*) ENDIF ! - ioptio = 0 ! Parameter control + ioptio = 0 !** Parameter control **! IF( ln_qsr_rgb ) ioptio = ioptio + 1 IF( ln_qsr_2bd ) ioptio = ioptio + 1 IF( ln_qsr_bio ) ioptio = ioptio + 1 @@ -386,21 +821,50 @@ CONTAINS IF( ln_qsr_2bd ) nqsr = np_2BD IF( ln_qsr_bio ) nqsr = np_BIO ! - ! ! Initialisation - xsi0r = 1._wp / rn_si0 - xsi1r = 1._wp / rn_si1 + ! !** Initialisation **! + ! + ! !== Infrared attenuation ==! (all schemes) + ! !============================! + ! + r1_si0 = 1._wp / rn_si0 ! inverse of infrared attenuation length + ! + nk0 = qsr_ext_lev( rn_si0, rn_abs ) ! level of light extinction + ! + IF(lwp) WRITE(numout,*) ' ==>>> Infrared light attenuation' + IF(lwp) WRITE(numout,*) ' level of infrared extinction = ', nk0, ' ref depth = ', gdepw_1d(nk0+1), ' m' + IF(lwp) WRITE(numout,*) ! SELECT CASE( nqsr ) ! - CASE( np_RGB , np_RGBc ) !== Red-Green-Blue light penetration ==! + CASE( np_RGBc, np_RGB ) !== Red-Green-Blue light attenuation ==! (Chl data or constant) + ! !========================================! ! - IF(lwp) WRITE(numout,*) ' ==>>> R-G-B light penetration ' + IF( nqsr == np_RGB ) THEN ; zchl = 0.05 ! constant Chl value + ELSE ; zchl = 0.03 ! minimum Chl value + ENDIF + zchl = MAX( 0.03_wp , MIN( zchl , 10._wp) ) ! NB. make sure that chosen value verifies: 0.03 < zchl < 10 + nc_rgb = NINT( 41 + 20.*LOG10(zchl) + 1.e-15 ) ! Convert Chl value to attenuation coefficient look-up table index ! CALL trc_oce_rgb( rkrgb ) ! tabulated attenuation coef. ! - nksr = trc_oce_ext_lev( r_si2, 33._wp ) ! level of light extinction + zVlp = ( 1._wp - rn_abs ) / 3._wp ! visible light equi-partition + ! + ! 1 / length ! attenuation length ! attenuation level + r1_LR = rkrgb(3,nc_rgb) ; zLR = 1._wp / r1_LR ; nkR = qsr_ext_lev( zLR, zVlp ) ! Red + r1_LG = rkrgb(2,nc_rgb) ; zLG = 1._wp / r1_LG ; nkG = qsr_ext_lev( zLG, zVlp ) ! Green + r1_LB = rkrgb(1,nc_rgb) ; zLB = 1._wp / r1_LB ; nkB = qsr_ext_lev( zLB, zVlp ) ! Blue + ! + nkV = nkB ! maximum level of light penetration ! - IF(lwp) WRITE(numout,*) ' level of light extinction = ', nksr, ' ref depth = ', gdepw_1d(nksr+1), ' m' + IF( nqsr == np_RGB ) THEN + IF(lwp) WRITE(numout,*) ' ==>>> RGB: light attenuation with a constant Chlorophyll = ', zchl + ELSE + IF(lwp) WRITE(numout,*) ' ==>>> RGB: light attenuation using Chlorophyll data with min(Chl) = ', zchl + ENDIF + IF(lwp) WRITE(numout,*) ' level of Red extinction = ', nkR, ' ref depth = ', gdepw_1d(nkR+1), ' m' + IF(lwp) WRITE(numout,*) ' level of Green extinction = ', nkG, ' ref depth = ', gdepw_1d(nkG+1), ' m' + IF(lwp) WRITE(numout,*) ' level of Blue extinction = ', nkB, ' ref depth = ', gdepw_1d(nkB+1), ' m' + IF(lwp) WRITE(numout,*) ! IF( nqsr == np_RGBc ) THEN ! Chl data : set sf_chl structure IF(lwp) WRITE(numout,*) ' ==>>> Chlorophyll read in a file' @@ -408,22 +872,23 @@ CONTAINS IF( ierror > 0 ) THEN CALL ctl_stop( 'tra_qsr_init: unable to allocate sf_chl structure' ) ; RETURN ENDIF - ALLOCATE( sf_chl(1)%fnow(jpi,jpj,1) ) + ALLOCATE( sf_chl(1)%fnow(jpi,jpj,1) ) IF( sn_chl%ln_tint ) ALLOCATE( sf_chl(1)%fdta(jpi,jpj,1,2) ) ! ! fill sf_chl with sn_chl and control print - CALL fld_fill( sf_chl, (/ sn_chl /), cn_dir, 'tra_qsr_init', & + CALL fld_fill( sf_chl, (/ sn_chl /), cn_dir, 'tra_qsr_init', & & 'Solar penetration function of read chlorophyll', 'namtra_qsr' , no_print ) ENDIF - IF( nqsr == np_RGB ) THEN ! constant Chl - IF(lwp) WRITE(numout,*) ' ==>>> Constant Chlorophyll concentration = 0.05' - ENDIF ! - CASE( np_2BD ) !== 2 bands light penetration ==! + CASE( np_2BD ) !== 2 bands light attenuation (IR+ visible light) ==! + ! ! - IF(lwp) WRITE(numout,*) ' ==>>> 2 bands light penetration' + r1_si1 = 1._wp / rn_si1 ! inverse of visible light attenuation + zVlp = ( 1._wp - rn_abs ) ! visible light partition + nkV = qsr_ext_lev( rn_si1, zVlp ) ! level of visible light extinction ! - nksr = trc_oce_ext_lev( rn_si1, 100._wp ) ! level of light extinction - IF(lwp) WRITE(numout,*) ' level of light extinction = ', nksr, ' ref depth = ', gdepw_1d(nksr+1), ' m' + IF(lwp) WRITE(numout,*) ' ==>>> 2 bands attenuation (Infrared + Visible light) ' + IF(lwp) WRITE(numout,*) ' level of visible light extinction = ', nkV, ' ref depth = ', gdepw_1d(nkV+1), ' m' + IF(lwp) WRITE(numout,*) ! CASE( np_BIO ) !== BIO light penetration ==! ! @@ -432,15 +897,19 @@ CONTAINS ! CALL trc_oce_rgb( rkrgb ) ! tabulated attenuation coef. ! - nksr = trc_oce_ext_lev( r_si2, 33._wp ) ! level of light extinction + nkV = trc_oce_ext_lev( r_si2, 33._wp ) ! maximum level of light extinction ! - IF(lwp) WRITE(numout,*) ' level of light extinction = ', nksr, ' ref depth = ', gdepw_1d(nksr+1), ' m' + IF(lwp) WRITE(numout,*) ' level of light extinction = ', nkV, ' ref depth = ', gdepw_1d(nkV+1), ' m' ! END SELECT ! - qsr_hc(:,:,:) = 0._wp ! now qsr heat content set to zero where it will not be computed + nksr = nkV ! name of max level of light extinction used in traatf(_qco).F90 + ! +#if ! defined key_RK3 + qsr_hc(:,:,:) = 0._wp ! MLF : now qsr heat content set to zero where it will not be computed +#endif ! - ! 1st ocean level attenuation coefficient (used in sbcssm) + ! ! Sea-ice : 1st ocean level attenuation coefficient (used in sbcssm) IF( iom_varid( numror, 'fraqsr_1lev', ldstop = .FALSE. ) > 0 ) THEN CALL iom_get( numror, jpdom_auto, 'fraqsr_1lev' , fraqsr_1lev ) ELSE diff --git a/src/OCE/TRA/trasbc.F90 b/src/OCE/TRA/trasbc.F90 index 556be0c26a1818c375fd6a4893abfc5028e28be9..0f8472a324a1753f8c1f128f1bd28e339a297643 100644 --- a/src/OCE/TRA/trasbc.F90 +++ b/src/OCE/TRA/trasbc.F90 @@ -38,14 +38,15 @@ MODULE trasbc IMPLICIT NONE PRIVATE - PUBLIC tra_sbc ! routine called by step.F90 + PUBLIC tra_sbc ! routine called by step.F90 + PUBLIC tra_sbc_RK3 ! routine called by stprk3_stg.F90 !! * Substitutions # include "do_loop_substitute.h90" # include "domzgr_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/OCE 4.0 , NEMO Consortium (2018) - !! $Id: trasbc.F90 14834 2021-05-11 09:24:44Z hadcv $ + !! $Id: trasbc.F90 15379 2021-10-15 09:05:45Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS @@ -221,6 +222,168 @@ CONTAINS IF( ln_timing ) CALL timing_stop('tra_sbc') ! END SUBROUTINE tra_sbc + + + SUBROUTINE tra_sbc_RK3 ( kt, Kmm, pts, Krhs, kstg ) + !!---------------------------------------------------------------------- + !! *** ROUTINE tra_sbc_RK3 *** + !! + !! ** Purpose : Compute the tracer surface boundary condition trend of + !! (flux through the interface, concentration/dilution effect) + !! and add it to the general trend of tracer equations. + !! + !! ** Method : The (air+ice)-sea flux has two components: + !! (1) Fext, external forcing (i.e. flux through the (air+ice)-sea interface); + !! (2) Fwe , tracer carried with the water that is exchanged with air+ice. + !! The input forcing fields (emp, rnf, sfx) contain Fext+Fwe, + !! they are simply added to the tracer trend (ts(Krhs)). + !! In linear free surface case (ln_linssh=T), the volume of the + !! ocean does not change with the water exchanges at the (air+ice)-sea + !! interface. Therefore another term has to be added, to mimic the + !! concentration/dilution effect associated with water exchanges. + !! + !! ** Action : - Update ts(Krhs) with the surface boundary condition trend + !! - send trends to trdtra module for further diagnostics(l_trdtra=T) + !!---------------------------------------------------------------------- + INTEGER , INTENT(in ) :: kt, Kmm, Krhs ! ocean time-step and time-level indices + INTEGER , INTENT(in ) :: kstg ! RK3 stage index + REAL(wp), DIMENSION(jpi,jpj,jpk,jpts,jpt), INTENT(inout) :: pts ! active tracers and RHS of tracer Eq. + ! + INTEGER :: ji, jj, jk, jn ! dummy loop indices + REAL(wp) :: z1_rho0_e3t, zdep, ztim ! local scalar + REAL(wp), ALLOCATABLE, DIMENSION(:,:,:) :: ztrdt, ztrds + !!---------------------------------------------------------------------- + ! + IF( ln_timing ) CALL timing_start('tra_sbc_RK3') + ! + IF( ntile == 0 .OR. ntile == 1 ) THEN ! Do only on the first tile + ! + IF( kt == nit000 ) THEN + IF(lwp) WRITE(numout,*) + IF(lwp) WRITE(numout,*) 'tra_sbc_RK3 : TRAcer Surface Boundary Condition' + IF(lwp) WRITE(numout,*) '~~~~~~~~~~~ ' + ENDIF + ! + IF( l_trdtra ) THEN !* Save ta and sa trends + ALLOCATE( ztrdt(jpi,jpj,jpk), ztrds(jpi,jpj,jpk) ) + ztrdt(:,:,:) = pts(:,:,:,jp_tem,Krhs) + ztrds(:,:,:) = pts(:,:,:,jp_sal,Krhs) + ENDIF + ! + ENDIF + ! + +!!gm This should be moved into sbcmod.F90 module ? (especially now that ln_traqsr is read in namsbc namelist) + IF( .NOT.ln_traqsr .AND. kstg == 1) THEN ! no solar radiation penetration + DO_2D_OVR( nn_hls, nn_hls, nn_hls, nn_hls ) + qns(ji,jj) = qns(ji,jj) + qsr(ji,jj) ! total heat flux in qns + qsr(ji,jj) = 0._wp ! qsr set to zero + END_2D + ENDIF + + !---------------------------------------- + ! EMP, SFX and QNS effects + !---------------------------------------- + ! !== update tracer trend ==! + SELECT CASE( kstg ) + ! + CASE( 1 , 2 ) != stage 1 and 2 =! only in non linear ssh + ! + IF( .NOT.ln_linssh ) THEN !* only heat and salt fluxes associated with mass fluxes + DO_2D( 0, 0, 0, 0 ) + z1_rho0_e3t = r1_rho0 / e3t(ji,jj,1,Kmm) + pts(ji,jj,1,jp_tem,Krhs) = pts(ji,jj,1,jp_tem,Krhs) - emp(ji,jj)*pts(ji,jj,1,jp_tem,Kmm) * z1_rho0_e3t + pts(ji,jj,1,jp_sal,Krhs) = pts(ji,jj,1,jp_sal,Krhs) - emp(ji,jj)*pts(ji,jj,1,jp_sal,Kmm) * z1_rho0_e3t + END_2D + ENDIF + ! + CASE( 3 ) + ! + IF( ln_linssh ) THEN !* linear free surface + DO_2D( 0, 0, 0, 0 ) + z1_rho0_e3t = r1_rho0 / e3t(ji,jj,1,Kmm) + pts(ji,jj,1,jp_tem,Krhs) = pts(ji,jj,1,jp_tem,Krhs) + ( r1_rcp * qns(ji,jj) & ! non solar heat flux + & + emp(ji,jj)*pts(ji,jj,1,jp_tem,Kmm) ) * z1_rho0_e3t ! add concentration/dilution effect due to constant volume cell + pts(ji,jj,1,jp_sal,Krhs) = pts(ji,jj,1,jp_sal,Krhs) + ( sfx(ji,jj) & ! salt flux due to freezing/melting + & + emp(ji,jj)*pts(ji,jj,1,jp_sal,Kmm) ) * z1_rho0_e3t ! add concentration/dilution effect due to constant volume cell + END_2D + IF( ntile == 0 .OR. ntile == nijtile ) THEN ! Do only on the last tile + IF( iom_use('emp_x_sst') ) CALL iom_put( "emp_x_sst", emp (:,:) * pts(:,:,1,jp_tem,Kmm) ) + IF( iom_use('emp_x_sss') ) CALL iom_put( "emp_x_sss", emp (:,:) * pts(:,:,1,jp_sal,Kmm) ) + ENDIF + ELSE + DO_2D( 0, 0, 0, 0 ) + z1_rho0_e3t = r1_rho0 / e3t(ji,jj,1,Kmm) + pts(ji,jj,1,jp_tem,Krhs) = pts(ji,jj,1,jp_tem,Krhs) + r1_rcp * qns(ji,jj) * z1_rho0_e3t + pts(ji,jj,1,jp_sal,Krhs) = pts(ji,jj,1,jp_sal,Krhs) + sfx(ji,jj) * z1_rho0_e3t + END_2D + ENDIF + END SELECT + ! + ! + !---------------------------------------- + ! River Runoff effects + !---------------------------------------- + ! + IF( ln_rnf ) THEN ! input of heat and salt due to river runoff + DO_2D( 0, 0, 0, 0 ) + IF( rnf(ji,jj) /= 0._wp ) THEN + zdep = 1._wp / h_rnf(ji,jj) + DO jk = 1, nk_rnf(ji,jj) + pts(ji,jj,jk,jp_tem,Krhs) = pts(ji,jj,jk,jp_tem,Krhs) + rnf_tsc(ji,jj,jp_tem) * zdep + IF( ln_rnf_sal ) pts(ji,jj,jk,jp_sal,Krhs) = pts(ji,jj,jk,jp_sal,Krhs) + rnf_tsc(ji,jj,jp_sal) * zdep + END DO + ENDIF + END_2D + ENDIF + ! + IF( ntile == 0 .OR. ntile == nijtile ) THEN ! Do only on the last tile + IF( iom_use('rnf_x_sst') ) CALL iom_put( "rnf_x_sst", rnf*pts(:,:,1,jp_tem,Kmm) ) ! runoff term on sst + IF( iom_use('rnf_x_sss') ) CALL iom_put( "rnf_x_sss", rnf*pts(:,:,1,jp_sal,Kmm) ) ! runoff term on sss + ENDIF + +#if defined key_asminc + ! + !---------------------------------------- + ! Assmilation effects + !---------------------------------------- + ! + IF( ln_sshinc .AND. kstg == 3 ) THEN ! input of heat and salt due to assimilation + ! + IF( ln_linssh ) THEN + DO_2D( 0, 0, 0, 0 ) + ztim = ssh_iau(ji,jj) / e3t(ji,jj,1,Kmm) + pts(ji,jj,1,jp_tem,Krhs) = pts(ji,jj,1,jp_tem,Krhs) + pts(ji,jj,1,jp_tem,Kmm) * ztim + pts(ji,jj,1,jp_sal,Krhs) = pts(ji,jj,1,jp_sal,Krhs) + pts(ji,jj,1,jp_sal,Kmm) * ztim + END_2D + ELSE + DO_2D( 0, 0, 0, 0 ) + ztim = ssh_iau(ji,jj) / ( ht(ji,jj) + 1. - ssmask(ji, jj) ) + pts(ji,jj,:,jp_tem,Krhs) = pts(ji,jj,:,jp_tem,Krhs) + pts(ji,jj,:,jp_tem,Kmm) * ztim + pts(ji,jj,:,jp_sal,Krhs) = pts(ji,jj,:,jp_sal,Krhs) + pts(ji,jj,:,jp_sal,Kmm) * ztim + END_2D + ENDIF + ! + ENDIF + ! +#endif + ! + IF( l_trdtra ) THEN ! save the horizontal diffusive trends for further diagnostics + IF( ntile == 0 .OR. ntile == nijtile ) THEN + ztrdt(:,:,:) = pts(:,:,:,jp_tem,Krhs) - ztrdt(:,:,:) + ztrds(:,:,:) = pts(:,:,:,jp_sal,Krhs) - ztrds(:,:,:) + CALL trd_tra( kt, Kmm, Krhs, 'TRA', jp_tem, jptra_nsr, ztrdt ) + CALL trd_tra( kt, Kmm, Krhs, 'TRA', jp_sal, jptra_nsr, ztrds ) + DEALLOCATE( ztrdt , ztrds ) + ENDIF + ENDIF + ! + IF(sn_cfctl%l_prtctl) CALL prt_ctl( tab3d_1=pts(:,:,:,jp_tem,Krhs), clinfo1=' sbc - Ta: ', mask1=tmask, & + & tab3d_2=pts(:,:,:,jp_sal,Krhs), clinfo2= ' Sa: ', mask2=tmask, clinfo3='tra' ) + ! + IF( ln_timing ) CALL timing_stop('tra_sbc_RK3') + ! + END SUBROUTINE tra_sbc_RK3 !!====================================================================== END MODULE trasbc diff --git a/src/OCE/ZDF/zdfphy.F90 b/src/OCE/ZDF/zdfphy.F90 index 66beff367532ff7bd636d5b8a640a8a2918e26f6..5fbf2322015ec8b3097169ea4ac576cab62a9986 100644 --- a/src/OCE/ZDF/zdfphy.F90 +++ b/src/OCE/ZDF/zdfphy.F90 @@ -209,7 +209,7 @@ CONTAINS ioptio = 0 IF( ln_zdfcst ) THEN ; ioptio = ioptio + 1 ; nzdf_phy = np_CST ; ENDIF IF( ln_zdfric ) THEN ; ioptio = ioptio + 1 ; nzdf_phy = np_RIC ; CALL zdf_ric_init ; ENDIF - IF( ln_zdftke ) THEN ; ioptio = ioptio + 1 ; nzdf_phy = np_TKE ; CALL zdf_tke_init( Kmm ) ; ENDIF + IF( ln_zdftke ) THEN ; ioptio = ioptio + 1 ; nzdf_phy = np_TKE ; CALL zdf_tke_init ; ENDIF IF( ln_zdfgls ) THEN ; ioptio = ioptio + 1 ; nzdf_phy = np_GLS ; CALL zdf_gls_init ; ENDIF IF( ln_zdfosm ) THEN ; ioptio = ioptio + 1 ; nzdf_phy = np_OSM ; CALL zdf_osm_init( Kmm ) ; ENDIF ! @@ -350,7 +350,7 @@ CONTAINS IF( ln_zdfiwm ) CALL zdf_iwm( kt, Kmm, avm, avt, avs ) ! internal wave (de Lavergne et al 2017) ! !* Lateral boundary conditions (sign unchanged) - IF(nn_hls==1) THEN + IF(nn_hls==1) THEN ! if nn_hls==2 lbc_lnk done in stp routines IF( l_zdfsh2 ) THEN CALL lbc_lnk( 'zdfphy', avm_k, 'W', 1.0_wp , avt_k, 'W', 1.0_wp, & & avm , 'W', 1.0_wp , avt , 'W', 1.0_wp , avs , 'W', 1.0_wp ) diff --git a/src/OCE/ZDF/zdftke.F90 b/src/OCE/ZDF/zdftke.F90 index 8b6d915587952429fdf3237b4bb8d2718b7fa85a..68dd9f6ed89537ea357a57cb963ec863cfb94e1d 100644 --- a/src/OCE/ZDF/zdftke.F90 +++ b/src/OCE/ZDF/zdftke.F90 @@ -698,7 +698,7 @@ CONTAINS END SUBROUTINE tke_avn - SUBROUTINE zdf_tke_init( Kmm ) + SUBROUTINE zdf_tke_init !!---------------------------------------------------------------------- !! *** ROUTINE zdf_tke_init *** !! @@ -714,7 +714,6 @@ CONTAINS !!---------------------------------------------------------------------- USE zdf_oce , ONLY : ln_zdfiwm ! Internal Wave Mixing flag !! - INTEGER, INTENT(in) :: Kmm ! time level index INTEGER :: ji, jj, jk ! dummy loop indices INTEGER :: ios !! diff --git a/src/OCE/module_example.F90 b/src/OCE/module_example.F90 index 80c10ce05a5e6e3f1cad08c4502abea7878e6f78..2620b2efc856344e2f204d727091a49c55104c44 100644 --- a/src/OCE/module_example.F90 +++ b/src/OCE/module_example.F90 @@ -54,7 +54,7 @@ MODULE exampl # include "exampl_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/OCE 4.0 , NEMO Consortium (2018) - !! $Id: module_example.F90 14842 2021-05-11 13:17:26Z acc $ + !! $Id: module_example.F90 14941 2021-06-03 11:42:27Z acc $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS @@ -144,7 +144,7 @@ CONTAINS !! ** Action : ... !!---------------------------------------------------------------------- INTEGER :: ji, jj, jk, jit ! dummy loop indices - INTEGER :: ios ! Local integer output status for namelist read + INTEGER :: ios ! Local integer output status for namelist read !! NAMELIST/namexa/ exa_v1, exa_v2, nexa_0, sn_ex !!---------------------------------------------------------------------- diff --git a/src/OCE/nemogcm.F90 b/src/OCE/nemogcm.F90 index efd52491e5f9c950a9559740a2751bff29b0569e..9e5ebf364cb019878d34e1d4fd7fc44a94021891 100644 --- a/src/OCE/nemogcm.F90 +++ b/src/OCE/nemogcm.F90 @@ -65,7 +65,11 @@ MODULE nemogcm USE ice_domain_size, only: nx_global, ny_global #endif #if defined key_qco || defined key_linssh +# if defined key_RK3 + USE stprk3 +# else USE stpmlf ! NEMO time-stepping (stp_MLF routine) +# endif #else USE step ! NEMO time-stepping (stp routine) #endif @@ -91,7 +95,7 @@ MODULE nemogcm !!---------------------------------------------------------------------- !! NEMO/OCE 4.0 , NEMO Consortium (2018) - !! $Id: nemogcm.F90 15267 2021-09-17 09:04:34Z smasson $ + !! $Id: nemogcm.F90 15532 2021-11-24 11:47:32Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS @@ -121,7 +125,11 @@ CONTAINS CALL nemo_init !== Initialisations ==! ! !-----------------------! #if defined key_agrif - Kbb_a = Nbb; Kmm_a = Nnn; Krhs_a = Nrhs ! agrif_oce module copies of time level indices +# if defined key_RK3 + Kbb_a = Nbb; Kmm_a = Nbb; Krhs_a = Nrhs ! RK3: agrif_oce module copies of time level indices +# else + Kbb_a = Nbb; Kmm_a = Nnn; Krhs_a = Nrhs ! MLF: agrif_oce module copies of time level indices +# endif CALL Agrif_Declare_Var ! " " " " " DYN/TRA # if defined key_top CALL Agrif_Declare_Var_top ! " " " " " TOP @@ -146,14 +154,22 @@ CONTAINS CALL Agrif_Regrid() ! ! Recursive update from highest nested level to lowest: - Kbb_a = Nbb; Kmm_a = Nnn; Krhs_a = Nrhs ! agrif_oce module copies of time level indices +# if defined key_RK3 + Kbb_a = Nbb; Kmm_a = Nbb; Krhs_a = Nrhs ! RK3: agrif_oce module copies of time level indices +# else + Kbb_a = Nbb; Kmm_a = Nnn; Krhs_a = Nrhs ! MLF: agrif_oce module copies of time level indices +# endif CALL Agrif_step_child_adj(Agrif_Update_All) CALL Agrif_step_child_adj(Agrif_Check_parent_bat) ! DO WHILE( istp <= nitend .AND. nstop == 0 ) ! # if defined key_qco || defined key_linssh +# if defined key_RK3 + CALL stp_RK3 +# else CALL stp_MLF +# endif # else CALL stp # endif @@ -174,7 +190,11 @@ CONTAINS ENDIF ! # if defined key_qco || defined key_linssh +# if defined key_RK3 + CALL stp_RK3( istp ) +# else CALL stp_MLF( istp ) +# endif # else CALL stp ( istp ) # endif @@ -391,7 +411,11 @@ CONTAINS ! Initialise time level indices Nbb = 1 ; Nnn = 2 ; Naa = 3 ; Nrhs = Naa #if defined key_agrif - Kbb_a = Nbb ; Kmm_a = Nnn ; Krhs_a = Nrhs ! agrif_oce module copies of time level indices +# if defined key_RK3 + Kbb_a = Nbb ; Kmm_a = Nbb ; Krhs_a = Nrhs ! RK3: agrif_oce module copies of time level indices +# else + Kbb_a = Nbb ; Kmm_a = Nnn ; Krhs_a = Nrhs ! MLF: agrif_oce module copies of time level indices +# endif #endif ! !-------------------------------! ! ! NEMO general initialization ! @@ -470,7 +494,11 @@ CONTAINS CALL isf_init( Nbb, Nnn, Naa ) #if defined key_top ! ! Passive tracers +# if defined key_RK3 + CALL trc_init( Nbb, Nbb, Naa ) +# else CALL trc_init( Nbb, Nnn, Naa ) +# endif #endif IF( l_ldfslp ) CALL ldf_slp_init ! slope of lateral mixing diff --git a/src/OCE/oce.F90 b/src/OCE/oce.F90 index db45ce295f45f0577c01c50a9f84a48dd6cde58d..c180833bbab0079b9986360001d11f9ddbbd5e98 100644 --- a/src/OCE/oce.F90 +++ b/src/OCE/oce.F90 @@ -20,8 +20,8 @@ MODULE oce !! dynamics and tracer fields !! -------------------------- - REAL(wp), PUBLIC, ALLOCATABLE, SAVE, DIMENSION(:,:,:,:) :: uu , vv !: horizontal velocities [m/s] - REAL(wp), PUBLIC, ALLOCATABLE, SAVE, DIMENSION(:,:,:) :: ww !: vertical velocity [m/s] + REAL(wp), PUBLIC, ALLOCATABLE, SAVE, DIMENSION(:,:,:,:), TARGET :: uu , vv !: horizontal velocities [m/s] + REAL(wp), PUBLIC, ALLOCATABLE, SAVE, DIMENSION(:,:,:) , TARGET :: ww !: vertical velocity [m/s] REAL(wp), PUBLIC, ALLOCATABLE, SAVE, DIMENSION(:,:,:) :: wi !: vertical vel. (adaptive-implicit) [m/s] REAL(wp), PUBLIC, ALLOCATABLE, SAVE, DIMENSION(:,:,:) :: hdiv !: horizontal divergence [s-1] REAL(wp), PUBLIC, ALLOCATABLE, SAVE, DIMENSION(:,:,:,:,:) :: ts !: 4D T-S fields [Celsius,psu] @@ -45,10 +45,13 @@ MODULE oce REAL(wp), PUBLIC, ALLOCATABLE, SAVE, DIMENSION(:,:) :: hv_e !: external v-depth REAL(wp), PUBLIC, ALLOCATABLE, SAVE, DIMENSION(:,:) :: hur_e !: inverse of u-depth REAL(wp), PUBLIC, ALLOCATABLE, SAVE, DIMENSION(:,:) :: hvr_e !: inverse of v-depth + REAL(wp), PUBLIC, ALLOCATABLE, SAVE, DIMENSION(:,:) :: un_adv, vn_adv !: Advective barotropic fluxes +#if ! defined key_RK3 REAL(wp), PUBLIC, ALLOCATABLE, SAVE, DIMENSION(:,:) :: ub2_b , vb2_b !: Half step fluxes (ln_bt_fw=T) REAL(wp), PUBLIC, ALLOCATABLE, SAVE, DIMENSION(:,:) :: un_bf , vn_bf !: Asselin filtered half step fluxes (ln_bt_fw=T) +#endif #if defined key_agrif - REAL(wp), PUBLIC, ALLOCATABLE, SAVE, DIMENSION(:,:) :: ub2_i_b, vb2_i_b !: Half step time integrated fluxes + REAL(wp), PUBLIC, ALLOCATABLE, SAVE, DIMENSION(:,:) :: ub2_i_b, vb2_i_b !: agrif time integrated fluxes #endif !! interpolated gradient (only used in zps case) @@ -76,7 +79,7 @@ MODULE oce !!---------------------------------------------------------------------- !! NEMO/OCE 4.0 , NEMO Consortium (2018) - !! $Id: oce.F90 15556 2021-11-29 15:23:06Z jchanut $ + !! $Id: oce.F90 14381 2021-02-03 12:36:25Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS @@ -85,37 +88,48 @@ CONTAINS !!---------------------------------------------------------------------- !! *** FUNCTION oce_alloc *** !!---------------------------------------------------------------------- - INTEGER :: ierr(6) + INTEGER :: ii + INTEGER, DIMENSION(7) :: ierr !!---------------------------------------------------------------------- ! - ierr(:) = 0 + ii = 0 ; ierr(:) = 0 + ! + ii = ii+1 ALLOCATE( uu (jpi,jpj,jpk,jpt) , vv (jpi,jpj,jpk,jpt) , & & ww (jpi,jpj,jpk) , hdiv(jpi,jpj,jpk) , & & ts (jpi,jpj,jpk,jpts,jpt) , & & rab_b(jpi,jpj,jpk,jpts) , rab_n(jpi,jpj,jpk,jpts) , & & rn2b (jpi,jpj,jpk) , rn2 (jpi,jpj,jpk) , & - & rhd (jpi,jpj,jpk) , rhop (jpi,jpj,jpk) , STAT=ierr(1) ) + & rhd (jpi,jpj,jpk) , rhop (jpi,jpj,jpk) , STAT=ierr(ii) ) ! + ii = ii+1 ALLOCATE( ssh (jpi,jpj,jpt) , uu_b(jpi,jpj,jpt) , vv_b(jpi,jpj,jpt) , & & ssh_frc(jpi,jpj) , & & gtsu(jpi,jpj,jpts) , gtsv(jpi,jpj,jpts) , & & gru (jpi,jpj) , grv (jpi,jpj) , & & gtui(jpi,jpj,jpts) , gtvi(jpi,jpj,jpts) , & & grui(jpi,jpj) , grvi(jpi,jpj) , & - & riceload(jpi,jpj) , STAT=ierr(2) ) + & riceload(jpi,jpj) , STAT=ierr(ii) ) ! - ALLOCATE( fraqsr_1lev(jpi,jpj) , STAT=ierr(3) ) + ii = ii+1 + ALLOCATE( fraqsr_1lev(jpi,jpj) , STAT=ierr(ii) ) ! + ii = ii+1 ALLOCATE( ssha_e(jpi,jpj), sshn_e(jpi,jpj), sshb_e(jpi,jpj), sshbb_e(jpi,jpj), & & ua_e(jpi,jpj), un_e(jpi,jpj), ub_e(jpi,jpj), ubb_e(jpi,jpj), & & va_e(jpi,jpj), vn_e(jpi,jpj), vb_e(jpi,jpj), vbb_e(jpi,jpj), & - & hu_e(jpi,jpj), hur_e(jpi,jpj), hv_e(jpi,jpj), hvr_e(jpi,jpj), STAT=ierr(4) ) + & hu_e(jpi,jpj), hur_e(jpi,jpj), hv_e(jpi,jpj), hvr_e(jpi,jpj), & + & un_adv(jpi,jpj), vn_adv(jpi,jpj) , STAT=ierr(ii) ) ! - ALLOCATE( ub2_b(jpi,jpj), vb2_b(jpi,jpj), un_bf(jpi,jpj), vn_bf(jpi,jpj) , STAT=ierr(5) ) +#if ! defined key_RK3 + ii = ii+1 ! MLF: arrays related to Asselin filter + ??? + ALLOCATE( un_bf(jpi,jpj), vn_bf(jpi,jpj), ub2_b(jpi,jpj), vb2_b(jpi,jpj) , STAT=ierr(ii) ) +#endif #if defined key_agrif - ALLOCATE( ub2_i_b(jpi,jpj), vb2_i_b(jpi,jpj) , STAT=ierr(6) ) + ii = ii+1 ! AGRIF: ??? + ALLOCATE( ub2_i_b(jpi,jpj), vb2_i_b(jpi,jpj) , STAT=ierr(ii) ) #endif - ! + ! oce_alloc = MAXVAL( ierr ) IF( oce_alloc /= 0 ) CALL ctl_stop( 'STOP', 'oce_alloc: failed to allocate arrays' ) ! diff --git a/src/OCE/stp2d.F90 b/src/OCE/stp2d.F90 new file mode 100644 index 0000000000000000000000000000000000000000..96170dc207405395a7248c429d57e8516a227d51 --- /dev/null +++ b/src/OCE/stp2d.F90 @@ -0,0 +1,277 @@ +MODULE stp2d + !!====================================================================== + !! *** MODULE stp2d *** + !! Time-stepping : manager of the ocean, tracer and ice time stepping + !! using a 3rd order Rung Kuta with fixed or quasi-eulerian coordinate + !!====================================================================== + !! History : 4.5 ! 2021-01 (S. Techene, G. Madec, N. Ducousso, F. Lemarie) Original code + !! NEMO + !!---------------------------------------------------------------------- +#if defined key_qco || defined key_linssh + !!---------------------------------------------------------------------- + !! 'key_qco' Quasi-Eulerian vertical coordinate + !! OR + !! 'key_linssh Fixed in time vertical coordinate + !!---------------------------------------------------------------------- + + !!---------------------------------------------------------------------- + !! stp_2D : RK3 case + !!---------------------------------------------------------------------- + USE step_oce ! time stepping used modules + USE domqco ! quasi-eulerian coordinate (dom_qco_r3c routine) + USE dynspg_ts ! 2D mode integration + USE sshwzv ! vertical speed + USE sbc_ice , ONLY : snwice_mass, snwice_mass_b + USE sbcapr ! surface boundary condition: atmospheric pressure + USE sbcwave, ONLY : bhd_wave +#if defined key_agrif + USE agrif_oce_interp + USE agrif_oce_sponge +#endif + + PRIVATE + + PUBLIC stp_2D ! called by nemogcm.F90 + REAL (wp) :: r1_2 = 0.5_wp + + !! * Substitutions +# include "do_loop_substitute.h90" +# include "domzgr_substitute.h90" + !!---------------------------------------------------------------------- + !! NEMO/OCE 4.0 , NEMO Consortium (2018) + !! $Id: step.F90 12377 2020-02-12 14:39:06Z acc $ + !! Software governed by the CeCILL license (see ./LICENSE) + !!---------------------------------------------------------------------- +CONTAINS + + SUBROUTINE stp_2D( kt, Kbb, Kmm, Kaa, Krhs ) + !!---------------------------------------------------------------------- + !! *** ROUTINE stp_2D *** + !! + !! ** Purpose : - Compute sea-surface height and barotropic velocity at Kaa + !! in single 1st RK3. + !! + !! ** Method : -1- Compute the 3D to 2D forcing + !! * Momentum (Ue,Ve)_rhs : + !! 3D to 2D dynamics, i.e. the vertical sum of : + !! - Hor. adv. : KEG + RVO in vector form + !! : ADV_h + MET in flux form + !! - LDF Lateral mixing + !! - HPG Hor. pressure gradient + !! External forcings + !! - baroclinic drag + !! - wind + !! - atmospheric pressure + !! - snow+ice load + !! - surface wave load + !! * ssh (sshe_rhs) : + !! Net column average freshwater flux + !! + !! -2- Solve the external mode Eqs. using sub-time step + !! by a call to dyn_spg_ts (will be renamed dyn_2D or stp_2D) + !! + !! ** action : ssh : N+1 sea surface height (Kaa=N+1) + !! (uu_b,vv_b) : N+1 barotropic velocity + !! (un_adv,vn_adv): barotropic transport from N to N+1 + !!---------------------------------------------------------------------- + INTEGER, INTENT(in) :: kt, Kbb, Kmm, Kaa, Krhs ! ocean time-step and time-level indices + ! + INTEGER :: ji, jj, jk ! dummy loop indices + REAL(wp) :: zg_2, zintp, zgrho0r, zld, zztmp ! local scalars + REAL(wp), ALLOCATABLE, DIMENSION(:,:) :: zpice ! 2D workspace + !! --------------------------------------------------------------------- + ! + IF( ln_timing ) CALL timing_start('stp_2D') + ! + IF( kt == nit000 ) THEN + IF(lwp) WRITE(numout,*) + IF(lwp) WRITE(numout,*) 'stp_2D : barotropic field in single first ' + IF(lwp) WRITE(numout,*) '~~~~~~' + ENDIF + ! + IF( ln_linssh ) THEN !== Compute ww(:,:,1) ==! (needed for momentum advection) +!!gm only in Flux Form, Vector Form dzU_z=0 assumed to be zero +!!gm ww(k=1) = div_h(uu_b) ==> modif dans dynadv <<<=== TO BE DONE + ENDIF + + ALLOCATE( sshe_rhs(jpi,jpj) , Ue_rhs(jpi,jpj) , Ve_rhs(jpi,jpj) , CdU_u(jpi,jpj) , CdU_v(jpi,jpj) ) + + !>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + ! RHS of barotropic momentum Eq. + !<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + + ! !======================================! + ! !== Dynamics 2D RHS from 3D trends ==! (HADV + LDF + HPG) (No Coriolis trend) + ! !======================================! + + uu(:,:,:,Krhs) = 0._wp ! set dynamics trends to zero + vv(:,:,:,Krhs) = 0._wp + ! + ! !* compute advection + coriolis *! + ! + CALL ssh_nxt( kt, Kbb, Kbb, ssh, Kaa ) + ! + IF( .NOT.lk_linssh ) THEN + DO_2D_OVR( 1, nn_hls, 1, nn_hls ) ! loop bounds limited by ssh definition in ssh_nxt + r3t(ji,jj,Kaa) = ssh(ji,jj,Kaa) * r1_ht_0(ji,jj) ! "after" ssh/h_0 ratio guess at t-column at Kaa (n+1) + END_2D + ENDIF + ! + CALL wzv ( kt, Kbb, Kbb, Kaa , uu(:,:,:,Kbb), vv(:,:,:,Kbb), ww ) ! ww guess at Kbb (n) + ! + CALL dyn_adv( kt, Kbb, Kbb , uu, vv, Krhs) !- vector form KEG+ZAD + ! !- flux form ADV + CALL dyn_vor( kt, Kbb, uu, vv, Krhs ) !- vector form COR+RVO + ! !- flux form COR+MET + ! + ! !* lateral viscosity *! + CALL dyn_ldf( kt, Kbb, Kbb, uu, vv, Krhs ) +#if defined key_agrif + IF(.NOT. Agrif_Root() ) THEN !* AGRIF: sponge *! + CALL Agrif_Sponge_dyn + ENDIF +#endif + ! + ! !* hydrostatic pressure gradient *! + CALL eos ( ts , Kbb, rhd ) ! in situ density anomaly at Kbb + CALL dyn_hpg( kt , Kbb , uu, vv, Krhs ) ! horizontal gradient of Hydrostatic pressure + ! + ! !* vertical averaging *! + Ue_rhs(:,:) = SUM( e3u_0(:,:,:) * uu(:,:,:,Krhs) * umask(:,:,:), DIM=3 ) * r1_hu_0(:,:) + Ve_rhs(:,:) = SUM( e3v_0(:,:,:) * vv(:,:,:,Krhs) * vmask(:,:,:), DIM=3 ) * r1_hv_0(:,:) + + ! !===========================! + ! !== external 2D forcing ==! + ! !===========================! + ! + ! !* baroclinic drag forcing *! (also provide the barotropic drag coeff.) + ! + CALL dyn_drg_init( Kbb, Kbb, uu, vv, uu_b, vv_b, Ue_rhs, Ve_rhs, CdU_u, CdU_v ) + ! + ! !* wind forcing *! + IF( ln_bt_fw ) THEN + DO_2D( 0, 0, 0, 0 ) + Ue_rhs(ji,jj) = Ue_rhs(ji,jj) + r1_rho0 * utau(ji,jj) * r1_hu(ji,jj,Kbb) + Ve_rhs(ji,jj) = Ve_rhs(ji,jj) + r1_rho0 * vtau(ji,jj) * r1_hv(ji,jj,Kbb) + END_2D + ELSE + zztmp = r1_rho0 * r1_2 + DO_2D( 0, 0, 0, 0 ) + Ue_rhs(ji,jj) = Ue_rhs(ji,jj) + zztmp * ( utau_b(ji,jj) + utau(ji,jj) ) * r1_hu(ji,jj,Kbb) + Ve_rhs(ji,jj) = Ve_rhs(ji,jj) + zztmp * ( vtau_b(ji,jj) + vtau(ji,jj) ) * r1_hv(ji,jj,Kbb) + END_2D + ENDIF + ! + ! !* atmospheric pressure forcing *! + IF( ln_apr_dyn ) THEN + IF( ln_bt_fw ) THEN ! FORWARD integration: use kt+1/2 pressure (NOW+1/2) + DO_2D( 0, 0, 0, 0 ) + Ue_rhs(ji,jj) = Ue_rhs(ji,jj) + grav * ( ssh_ib (ji+1,jj ) - ssh_ib (ji,jj) ) * r1_e1u(ji,jj) + Ve_rhs(ji,jj) = Ve_rhs(ji,jj) + grav * ( ssh_ib (ji ,jj+1) - ssh_ib (ji,jj) ) * r1_e2v(ji,jj) + END_2D + ELSE ! CENTRED integration: use kt-1/2 + kt+1/2 pressure (NOW) + zztmp = grav * r1_2 + DO_2D( 0, 0, 0, 0 ) + Ue_rhs(ji,jj) = Ue_rhs(ji,jj) + zztmp * ( ssh_ib (ji+1,jj ) - ssh_ib (ji,jj) & + & + ssh_ibb(ji+1,jj ) - ssh_ibb(ji,jj) ) * r1_e1u(ji,jj) + Ve_rhs(ji,jj) = Ve_rhs(ji,jj) + zztmp * ( ssh_ib (ji ,jj+1) - ssh_ib (ji,jj) & + & + ssh_ibb(ji ,jj+1) - ssh_ibb(ji,jj) ) * r1_e2v(ji,jj) + END_2D + ENDIF + ENDIF + ! + ! !* snow+ice load *! (embedded sea ice) + IF( ln_ice_embd ) THEN + ALLOCATE( zpice(jpi,jpj) ) + zintp = REAL( MOD( kt-1, nn_fsbc ) ) / REAL( nn_fsbc ) + zgrho0r = - grav * r1_rho0 + zpice(:,:) = ( zintp * snwice_mass(:,:) + ( 1.- zintp ) * snwice_mass_b(:,:) ) * zgrho0r + DO_2D( 0, 0, 0, 0 ) + Ue_rhs(ji,jj) = Ue_rhs(ji,jj) + ( zpice(ji+1,jj) - zpice(ji,jj) ) * r1_e1u(ji,jj) + Ve_rhs(ji,jj) = Ve_rhs(ji,jj) + ( zpice(ji,jj+1) - zpice(ji,jj) ) * r1_e2v(ji,jj) + END_2D + DEALLOCATE( zpice ) + ENDIF + ! + ! !* surface wave load *! (Bernoulli head) + ! + IF( ln_wave .AND. ln_bern_srfc ) THEN + DO_2D( 0, 0, 0, 0 ) + Ue_rhs(ji,jj) = Ue_rhs(ji,jj) + ( bhd_wave(ji+1,jj) - bhd_wave(ji,jj) ) * r1_e1u(ji,jj) !++ bhd_wave from wave model in m2/s2 [BHD parameters in WW3] + Ve_rhs(ji,jj) = Ve_rhs(ji,jj) + ( bhd_wave(ji,jj+1) - bhd_wave(ji,jj) ) * r1_e1u(ji,jj) + END_2D + ENDIF + + !>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + ! RHS of see surface height Eq. + !<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + ! + ! !== Net water flux forcing ==! (applied to a water column) + ! + IF (ln_bt_fw) THEN ! FORWARD integration: use kt+1/2 fluxes (NOW+1/2) + sshe_rhs(:,:) = r1_rho0 * ( emp(:,:) - rnf(:,:) - fwfisf_cav(:,:) - fwfisf_par(:,:) ) + ELSE ! CENTRED integration: use kt-1/2 + kt+1/2 fluxes (NOW) + zztmp = r1_rho0 * r1_2 + sshe_rhs(:,:) = zztmp * ( emp(:,:) + emp_b(:,:) & + & - rnf(:,:) - rnf_b(:,:) & + & - fwfisf_cav(:,:) - fwfisf_cav_b(:,:) & + & - fwfisf_par(:,:) - fwfisf_par_b(:,:) ) + ENDIF + ! + ! !== Stokes drift divergence ==! (if exist) + ! + IF( ln_sdw ) sshe_rhs(:,:) = sshe_rhs(:,:) + div_sd(:,:) + ! + ! + ! !== ice sheet coupling ==! + ! + IF( ln_isf .AND. ln_isfcpl ) THEN + IF( ln_rstart .AND. kt == nit000 ) sshe_rhs(:,:) = sshe_rhs(:,:) + risfcpl_ssh(:,:) + IF( ln_isfcpl_cons ) sshe_rhs(:,:) = sshe_rhs(:,:) + risfcpl_cons_ssh(:,:) + ENDIF + ! +#if defined key_asminc + ! !== Add the IAU weighted SSH increment ==! + ! + IF( lk_asminc .AND. ln_sshinc .AND. ln_asmiau ) sshe_rhs(:,:) = sshe_rhs(:,:) - ssh_iau(:,:) +#endif + ! +#if defined key_agrif + ! !== AGRIF : fill boundary data arrays (on both ) + IF( .NOT.Agrif_Root() ) CALL agrif_dta_ts( kt ) +#endif + + !>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + ! Compute ssh and (uu_b,vv_b) at N+1 (Kaa) + !<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + + ! using a split-explicit time integration in forward mode + ! ( ABM3-AM4 time-integration Shchepetkin et al. OM2005) with temporal diffusion (Demange et al. JCP2019) ) + + CALL dyn_spg_ts( kt, Kbb, Kbb, Krhs, uu, vv, ssh, uu_b, vv_b, Kaa ) ! time-splitting + + + DEALLOCATE( sshe_rhs , Ue_rhs , Ve_rhs , CdU_u , CdU_v ) + +!!gm this is useless I guess : RK3, done in each stages +! +! IF( ln_dynspg_ts ) THEN ! With split-explicit free surface, since now transports have been updated and ssh(:,:,Krhs) +! ! as well as vertical scale factors and vertical velocity need to be updated +! CALL div_hor ( kstp, Kbb, Kmm ) ! Horizontal divergence (2nd call in time-split case) +! IF(.NOT.lk_linssh) CALL dom_qco_r3c( ssh(:,:,Kaa), r3t(:,:,Kaa), r3u(:,:,Kaa), r3v(:,:,Kaa), r3f(:,:) ) ! update ssh/h_0 ratio at t,u,v,f pts +! ENDIF +!!gm + ! + IF( ln_timing ) CALL timing_stop('stp_2D') + ! + END SUBROUTINE stp_2D + + +#else + !!---------------------------------------------------------------------- + !! default option EMPTY MODULE qco not activated + !!---------------------------------------------------------------------- +#endif + + !!====================================================================== +END MODULE stp2d diff --git a/src/OCE/stpmlf.F90 b/src/OCE/stpmlf.F90 index 81952fc6aa5532f132d891dfba2187d1c7627d8d..bae696704a881cbd31d2ec554ec1d9d6d2fe869c 100644 --- a/src/OCE/stpmlf.F90 +++ b/src/OCE/stpmlf.F90 @@ -34,7 +34,8 @@ MODULE stpmlf !! 4.1 ! 2019-08 (A. Coward, D. Storkey) rewrite in preparation for new timestepping scheme !! 4.x ! 2020-08 (S. Techene, G. Madec) quasi eulerian coordinate time stepping !!---------------------------------------------------------------------- -#if defined key_qco || defined key_linssh +#if ! defined key_RK3 +# if defined key_qco || defined key_linssh !!---------------------------------------------------------------------- !! 'key_qco' Quasi-Eulerian vertical coordinate !! OR @@ -91,8 +92,8 @@ CONTAINS !! -7- Compute the diagnostics variables (rd,N2, hdiv,w) !! -8- Outputs and diagnostics !!---------------------------------------------------------------------- - INTEGER :: ji, jj, jk, jtile ! dummy loop indice - REAL(wp), ALLOCATABLE, DIMENSION(:,:,:) :: zgdept + INTEGER :: ji, jj, jk, jn, jtile ! dummy loop indice + REAL(wp), ALLOCATABLE, DIMENSION(:,:,:) :: zgdept !! --------------------------------------------------------------------- #if defined key_agrif IF( nstop > 0 ) RETURN ! avoid to go further if an error was detected during previous time step (child grid) @@ -281,7 +282,6 @@ CONTAINS IF( ln_zad_Aimp ) CALL wAimp ( kstp, Nnn ) ! Adaptive-implicit vertical advection partitioning ENDIF - !>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ! cool skin !<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @@ -316,11 +316,17 @@ CONTAINS !>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ! Active tracers !<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< - ts(:,:,:,:,Nrhs) = 0._wp ! set tracer trends to zero - IF( ln_tile ) CALL dom_tile_start ! [tiling] TRA tiling loop (1) + IF( ln_tile ) CALL dom_tile_start ! [tiling] TRA tiling loop (1) + DO jtile = 1, nijtile - IF( ln_tile ) CALL dom_tile( ntsi, ntsj, ntei, ntej, ktile = jtile ) + IF( ln_tile ) CALL dom_tile( ntsi, ntsj, ntei, ntej, ktile = jtile ) + + DO jn = 1, jpts + DO_3D( 0, 0, 0, 0, 1, jpkm1 ) + ts(ji,jj,jk,jn,Nrhs) = 0._wp ! set tracer trends to zero + END_3D + END DO IF( lk_asminc .AND. ln_asmiau .AND. & & ln_trainc ) CALL tra_asm_inc( kstp, Nbb, Nnn, ts, Nrhs ) ! apply tracer assimilation increment @@ -473,7 +479,6 @@ CONTAINS !! ** Action : puu(Kmm),pvv(Kmm) updated now horizontal velocity (ln_bt_fw=F) !! puu(Kaa),pvv(Kaa) after horizontal velocity !!---------------------------------------------------------------------- - USE dynspg_ts, ONLY : un_adv, vn_adv ! updated Kmm barotropic transport !! INTEGER , INTENT(in ) :: Kmm, Kaa ! before and after time level indices REAL(wp), DIMENSION(jpi,jpj,jpk,jpt), INTENT(inout) :: puu, pvv ! velocities @@ -542,7 +547,7 @@ CONTAINS ! Update after tracer and velocity on domain lateral boundaries ! # if defined key_agrif - CALL Agrif_tra !* AGRIF zoom boundaries + CALL Agrif_tra( kt ) !* AGRIF zoom boundaries CALL Agrif_dyn( kt ) # endif ! ! local domain boundaries (T-point, unchanged sign) @@ -566,10 +571,11 @@ CONTAINS ! END SUBROUTINE finalize_lbc -#else +# else !!---------------------------------------------------------------------- !! default option EMPTY MODULE qco not activated !!---------------------------------------------------------------------- +# endif #endif !!====================================================================== diff --git a/src/OCE/stprk3.F90 b/src/OCE/stprk3.F90 new file mode 100644 index 0000000000000000000000000000000000000000..337b55f62beb10f4c27aa80a4aa551ced1d860f7 --- /dev/null +++ b/src/OCE/stprk3.F90 @@ -0,0 +1,390 @@ +MODULE stprk3 + !!====================================================================== + !! *** MODULE stpRK3 *** + !! Time-stepping : manager of the ocean, tracer and ice time stepping + !! using a 3rd order Rung Kuta with fixed or quasi-eulerian coordinate + !!====================================================================== + !! History : 4.5 ! 2021-01 (S. Techene, G. Madec, N. Ducousso, F. Lemarie) Original code + !! NEMO + !!---------------------------------------------------------------------- +#if defined key_qco || defined key_linssh + !!---------------------------------------------------------------------- + !! 'key_qco' Quasi-Eulerian vertical coordinate + !! OR + !! 'key_linssh Fixed in time vertical coordinate + !!---------------------------------------------------------------------- + + !!---------------------------------------------------------------------- + !! stp_RK3 : NEMO 3rd order Runge-Kutta time-stepping + !!---------------------------------------------------------------------- + USE step_oce ! time stepping used modules + USE domqco ! quasi-eulerian coordinate (dom_qco_r3c routine) + USE stprk3_stg ! RK3 stages + USE stp2d ! external mode solver + USE trd_oce ! trends: ocean variables + USE diaptr + USE ldftra + + IMPLICIT NONE + PRIVATE + + PUBLIC stp_RK3 ! called by nemogcm.F90 + + ! !** time level indices **! + INTEGER, PUBLIC :: Nbb, Nnn, Naa, Nrhs !: used by nemo_init + + !! * Substitutions +# include "do_loop_substitute.h90" +# include "domzgr_substitute.h90" + !!---------------------------------------------------------------------- + !! NEMO/OCE 4.0 , NEMO Consortium (2018) + !! $Id: step.F90 12377 2020-02-12 14:39:06Z acc $ + !! Software governed by the CeCILL license (see ./LICENSE) + !!---------------------------------------------------------------------- +CONTAINS + +#if defined key_agrif + RECURSIVE SUBROUTINE stp_RK3( ) + INTEGER :: kstp ! ocean time-step index +#else + SUBROUTINE stp_RK3( kstp ) + INTEGER, INTENT(in) :: kstp ! ocean time-step index +#endif + !!---------------------------------------------------------------------- + !! *** ROUTINE stp_RK3 *** + !! + !! ** Purpose : - Time stepping of OCE (momentum and active tracer Eqs.) (RK3) + !! - Time stepping of SI3 (dynamic and thermodynamic Eqs.) (FBS) + !! - Time stepping of TRC (passive tracer Eqs.) + !! + !! ** Method : -1- Update forcings and data + !! -2- Update ocean physics + !! -3- Compute the after (Naa) ssh and velocity + !! -4- diagnostics and output at Now (Nnn) + !! -4- Compute the after (Naa) T-S + !! -5- Update now + !! -6- Update the horizontal velocity + !! -7- Compute the diagnostics variables (rd,N2, hdiv,w) + !! -8- Outputs and diagnostics + !!---------------------------------------------------------------------- + INTEGER :: ji, jj, jk, jtile ! dummy loop indice + REAL(wp), ALLOCATABLE, DIMENSION(:,:,:) :: zgdept + !! --------------------------------------------------------------------- +#if defined key_agrif + IF( nstop > 0 ) RETURN ! avoid to go further if an error was detected during previous time step (child grid) + kstp = nit000 + Agrif_Nb_Step() + Kbb_a = Nbb ; Kmm_a = Nbb ; Krhs_a = Nrhs ! agrif_oce module copies of time level indices + IF( lk_agrif_debug ) THEN + IF( Agrif_Root() .AND. lwp) WRITE(*,*) '---' + IF(lwp) WRITE(*,*) 'Grid Number', Agrif_Fixed(),' time step ', kstp, 'int tstep', Agrif_NbStepint() + ENDIF + IF( kstp == nit000 + 1 ) lk_agrif_fstep = .FALSE. +# if defined key_xios + IF( Agrif_Nbstepint() == 0 ) CALL iom_swap( cxios_context ) +# endif +#endif + ! + IF( ln_timing ) CALL timing_start('stp_RK3') + ! + !>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + ! update I/O and calendar + !<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + ! + IF( kstp == nit000 ) THEN ! initialize IOM context (must be done after nemo_init for AGRIF+XIOS+OASIS) + CALL iom_init( cxios_context, ld_closedef=.FALSE. ) ! for model grid (including possible AGRIF zoom) + IF( lk_diamlr ) CALL dia_mlr_iom_init ! with additional setup for multiple-linear-regression analysis + CALL dia_ptr_init ! called here since it uses iom_use + CALL iom_init_closedef + IF( ln_crs ) CALL iom_init( TRIM(cxios_context)//"_crs" ) ! for coarse grid + ENDIF + IF( kstp == nitrst .AND. lwxios ) THEN + CALL iom_swap( cw_ocerst_cxt ) + CALL iom_init_closedef( cw_ocerst_cxt ) + CALL iom_setkt( kstp - nit000 + 1, cw_ocerst_cxt ) +#if defined key_top + CALL iom_swap( cw_toprst_cxt ) + CALL iom_init_closedef( cw_toprst_cxt ) + CALL iom_setkt( kstp - nit000 + 1, cw_toprst_cxt ) +#endif + ENDIF +#if defined key_si3 + IF( kstp + nn_fsbc - 1 == nitrst .AND. lwxios ) THEN + CALL iom_swap( cw_icerst_cxt ) + CALL iom_init_closedef( cw_icerst_cxt ) + CALL iom_setkt( kstp - nit000 + 1, cw_icerst_cxt ) + ENDIF +#endif + IF( kstp /= nit000 ) CALL day( kstp ) ! Calendar (day was already called at nit000 in day_init) + CALL iom_setkt( kstp - nit000 + 1, cxios_context ) ! tell IOM we are at time step kstp + IF( ln_crs ) CALL iom_setkt( kstp - nit000 + 1, TRIM(cxios_context)//"_crs" ) ! tell IOM we are at time step kstp + + + !>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + ! Update external forcing (tides, open boundaries, ice shelf interaction and surface boundary condition (including sea-ice) + !<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + IF( ln_tide ) CALL tide_update( kstp ) ! update tide potential + IF( ln_apr_dyn ) CALL sbc_apr ( kstp ) ! atmospheric pressure (NB: call before bdy_dta which needs ssh_ib) + IF( ln_bdy ) CALL bdy_dta ( kstp, Nbb ) ! update dynamic & tracer data at open boundaries + IF( ln_isf ) CALL isf_stp ( kstp, Nbb ) ! update iceshelf geometry + CALL sbc ( kstp, Nbb, Nbb ) ! Sea Boundary Condition (including sea-ice) + + !>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + ! Update stochastic parameters and random T/S fluctuations + !>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + IF( ln_sto_eos ) CALL sto_par( kstp ) ! Stochastic parameters + IF( ln_sto_eos ) CALL sto_pts( ts(:,:,:,:,Nnn) ) ! Random T/S fluctuations + +!!gm ocean physic computed at stage 3 ? + + !>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + ! Ocean physics update + !<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + ! THERMODYNAMICS +!!gm only Before is needed for bn2 and rab (except at stage 3 for n2) +!!gm issue with Nnn used in rad(Nbb) + CALL eos_rab( ts(:,:,:,:,Nbb), rab_b, Nbb ) ! before local thermal/haline expension ratio at T-points +!!st CALL eos_rab( ts(:,:,:,:,Nnn), rab_n, Nnn ) ! now local thermal/haline expension ratio at T-points + CALL bn2 ( ts(:,:,:,:,Nbb), rab_b, rn2b, Nbb ) ! before Brunt-Vaisala frequency +!!st CALL bn2 ( ts(:,:,:,:,Nnn), rab_n, rn2, Nnn ) ! now Brunt-Vaisala frequency +!!gm + rab_n = rab_b + rn2 = rn2b +!!gm sh2 computed at the end of the time-step +!!gm or call zdf_phy at the end ! + ! VERTICAL PHYSICS +!!st CALL zdf_phy( kstp, Nbb, Nnn, Nrhs ) ! vertical physics update (top/bot drag, avt, avs, avm + MLD) + CALL zdf_phy( kstp, Nbb, Nbb, Nrhs ) ! vertical physics update (top/bot drag, avt, avs, avm + MLD) +!!gm gdep + ! LATERAL PHYSICS + ! + IF( ln_zps .OR. l_ldfslp ) CALL eos( ts(:,:,:,:,Nbb), rhd, gdept_0(:,:,:) ) ! before in situ density + + IF( ln_zps .AND. .NOT. ln_isfcav) & + & CALL zps_hde ( kstp, jpts, ts(:,:,:,:,Nbb), gtsu, gtsv, & ! Partial steps: before horizontal gradient + & rhd, gru , grv ) ! of t, s, rd at the last ocean level + + IF( ln_zps .AND. ln_isfcav) & + & CALL zps_hde_isf( kstp, jpts, ts(:,:,:,:,Nbb), gtsu, gtsv, gtui, gtvi, & ! Partial steps for top cell (ISF) + & rhd, gru , grv , grui, grvi ) ! of t, s, rd at the first ocean level + + IF( l_ldfslp ) THEN ! slope of lateral mixing + IF( ln_traldf_triad ) THEN + CALL ldf_slp_triad( kstp, Nbb, Nbb ) ! before slope for triad operator + ELSE + CALL ldf_slp ( kstp, rhd, rn2b, Nbb, Nbb ) ! before slope for standard operator + ENDIF + ENDIF + ! ! eddy diffusivity coeff. + IF( l_ldftra_time .OR. l_ldfeiv_time ) CALL ldf_tra( kstp, Nbb, Nbb ) ! and/or eiv coeff. + IF( l_ldfdyn_time ) CALL ldf_dyn( kstp, Nbb ) ! eddy viscosity coeff. + + + !>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + ! RK3 : single first external mode computation + !<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + + CALL stp_2D( kstp, Nbb, Nbb, Naa, Nrhs ) ! out: ssh, (uu_b,vv_b) at Naa and (un_adv,vn_adv) between Nbb and Naa + + + !>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + ! RK3 time integration + !<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + + CALL rk3_dia( kstp, 0 ) ! Diagnostics switched off for stage 1 & 2 + ! + ! Stage 1 : + CALL stp_RK3_stg( 1, kstp, Nbb, Nbb, Nrhs, Naa ) + ! + Nrhs = Nnn ; Nnn = Naa ; Naa = Nrhs ! Swap: Nbb unchanged, Nnn <==> Naa + ! + ! Stage 2 : + CALL stp_RK3_stg( 2, kstp, Nbb, Nnn, Nrhs, Naa ) + ! + Nrhs = Nnn ; Nnn = Naa ; Naa = Nrhs ! Swap: Nbb unchanged, Nnn <==> Naa + ! + ! Stage 3 : + CALL rk3_dia( kstp, 1 ) ! Diagnostics switched on for stage 3 + ! + CALL stp_RK3_stg( 3, kstp, Nbb, Nnn, Nrhs, Naa ) + ! + Nrhs = Nbb ; Nbb = Naa ; Naa = Nrhs ! Swap: Nnn unchanged, Nbb <==> Naa + + ! linear extrapolation of ssh to compute ww at the beginning of the next time-step + ! ssh(n+1) = 2*ssh(n) - ssh(n-1) + ssh(:,:,Naa) = 2*ssh(:,:,Nbb) - ssh(:,:,Naa) + + !>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + ! diagnostics and outputs + !<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + +!==>>> at Nbb no more Nnn + + IF( ln_diacfl ) CALL dia_cfl ( kstp, Nbb ) ! Courant number diagnostics + CALL dia_hth ( kstp, Nbb ) ! Thermocline depth (20 degres isotherm depth) + IF( ln_diadct ) CALL dia_dct ( kstp, Nbb ) ! Transports +!!st CALL dia_ar5 ( kstp, Nbb ) ! ar5 diag + CALL dia_ptr ( kstp, Nbb ) ! Poleward adv/ldf TRansports diagnostics + CALL dia_wri ( kstp, Nbb ) ! ocean model: outputs + IF( ln_crs ) CALL crs_fld ( kstp, Nbb ) ! ocean model: online field coarsening & output + IF( lk_diadetide ) CALL dia_detide( kstp ) ! Weights computation for daily detiding of model diagnostics + IF( lk_diamlr ) CALL dia_mlr ! Update time used in multiple-linear-regression analysis + +!!====>>>> to be modified for RK3 +! IF( ln_floats ) CALL flo_stp ( kstp, Nbb, Nnn ) ! drifting Floats +! IF( ln_diahsb ) CALL dia_hsb ( kstp, Nbb, Nnn ) ! - ML - global conservation diagnostics +!!st + IF( ln_diahsb ) CALL dia_hsb ( kstp, Nbb, Nbb ) ! - ML - global conservation diagnostics +!!st + +!!gm : This does not only concern the dynamics ==>>> add a new title +!!gm2: why ouput restart before AGRIF update? +!! +!!jc: That would be better, but see comment above +!! +!!====>>>> to be modified for RK3 + IF( lrst_oce ) CALL rst_write ( kstp, Nbb, Nnn, Naa ) ! write output ocean restart file + IF( ln_sto_eos ) CALL sto_rst_write( kstp ) ! write restart file for stochastic parameters + +#if defined key_agrif + !>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + ! AGRIF recursive integration + !<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + Kbb_a = Nbb; Kmm_a = Nbb; Krhs_a = Nrhs ! agrif_oce module copies of time level indices + CALL Agrif_Integrate_ChildGrids( stp_RK3 ) ! allows to finish all the Child Grids before updating + +#endif + !>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + ! Control + !<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + CALL stp_ctl ( kstp, Nbb ) +#if defined key_agrif + !>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + ! AGRIF update + !<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + IF( Agrif_NbStepint() == 0 .AND. nstop == 0 ) & + & CALL Agrif_update_all( ) ! Update all components + +#endif + IF( ln_diaobs .AND. nstop == 0 ) & + & CALL dia_obs( kstp, Nnn ) ! obs-minus-model (assimilation) diags (after dynamics update) + + !>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + ! File manipulation at the end of the first time step + !<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + IF( kstp == nit000 ) THEN ! 1st time step only + CALL iom_close( numror ) ! close input ocean restart file + IF( lrxios ) CALL iom_context_finalize( cr_ocerst_cxt ) + IF(lwm) CALL FLUSH ( numond ) ! flush output namelist oce + IF(lwm .AND. numoni /= -1 ) CALL FLUSH ( numoni ) ! flush output namelist ice (if exist) + ENDIF + + !>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + ! Coupled mode + !<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + IF( lk_oasis .AND. nstop == 0 ) CALL sbc_cpl_snd( kstp, Nbb, Nnn ) ! coupled mode : field exchanges + ! +#if defined key_xios + !>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + ! Finalize contextes if end of simulation or error detected + !<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + IF( kstp == nitend .OR. nstop > 0 ) THEN + CALL iom_context_finalize( cxios_context ) ! needed for XIOS+AGRIF + IF( ln_crs ) CALL iom_context_finalize( trim(cxios_context)//"_crs" ) ! + ENDIF +#endif + ! + IF( ln_timing ) CALL timing_stop('stp_RK3') + ! + END SUBROUTINE stp_RK3 + + + SUBROUTINE mlf_baro_corr( Kmm, Kaa, puu, pvv ) + !!---------------------------------------------------------------------- + !! *** ROUTINE mlf_baro_corr *** + !! + !! ** Purpose : Finalize after horizontal velocity. + !! + !! ** Method : * Ensure after velocities transport matches time splitting + !! estimate (ln_dynspg_ts=T) + !! + !! ** Action : puu(Kmm),pvv(Kmm) updated now horizontal velocity (ln_bt_fw=F) + !! puu(Kaa),pvv(Kaa) after horizontal velocity + !!---------------------------------------------------------------------- + !! + INTEGER , INTENT(in ) :: Kmm, Kaa ! before and after time level indices + REAL(wp), DIMENSION(jpi,jpj,jpk,jpt), INTENT(inout) :: puu, pvv ! velocities + ! + INTEGER :: jk ! dummy loop indices + REAL(wp), DIMENSION(jpi,jpj) :: zue, zve + !!---------------------------------------------------------------------- + + ! Ensure below that barotropic velocities match time splitting estimate + ! Compute actual transport and replace it with ts estimate at "after" time step + zue(:,:) = e3u(:,:,1,Kaa) * puu(:,:,1,Kaa) * umask(:,:,1) + zve(:,:) = e3v(:,:,1,Kaa) * pvv(:,:,1,Kaa) * vmask(:,:,1) + DO jk = 2, jpkm1 + zue(:,:) = zue(:,:) + e3u(:,:,jk,Kaa) * puu(:,:,jk,Kaa) * umask(:,:,jk) + zve(:,:) = zve(:,:) + e3v(:,:,jk,Kaa) * pvv(:,:,jk,Kaa) * vmask(:,:,jk) + END DO + DO jk = 1, jpkm1 + puu(:,:,jk,Kaa) = ( puu(:,:,jk,Kaa) - zue(:,:) * r1_hu(:,:,Kaa) + uu_b(:,:,Kaa) ) * umask(:,:,jk) + pvv(:,:,jk,Kaa) = ( pvv(:,:,jk,Kaa) - zve(:,:) * r1_hv(:,:,Kaa) + vv_b(:,:,Kaa) ) * vmask(:,:,jk) + END DO + ! +!!st IF( .NOT.ln_bt_fw ) THEN +!!st ! Remove advective velocity from "now velocities" +!!st ! prior to asselin filtering +!!st ! In the forward case, this is done below after asselin filtering +!!st ! so that asselin contribution is removed at the same time +!!st DO jk = 1, jpkm1 +!!st puu(:,:,jk,Kmm) = ( puu(:,:,jk,Kmm) - un_adv(:,:)*r1_hu(:,:,Kmm) + uu_b(:,:,Kmm) )*umask(:,:,jk) +!!st pvv(:,:,jk,Kmm) = ( pvv(:,:,jk,Kmm) - vn_adv(:,:)*r1_hv(:,:,Kmm) + vv_b(:,:,Kmm) )*vmask(:,:,jk) +!!st END DO +!!st ENDIF + ! + END SUBROUTINE mlf_baro_corr + + + SUBROUTINE rk3_dia( kstp, kswitch ) + !!---------------------------------------------------------------------- + !!---------------------------------------------------------------------- + INTEGER, INTENT(in) :: kstp ! ocean time-step index + INTEGER, INTENT(in) :: kswitch ! on/off = 1/0 + !! + LOGICAL, SAVE :: ll_trddyn, ll_trdtrc, ll_trdtra ! call trd at stage 3 only + LOGICAL, SAVE :: ll_diaptr, ll_ldfeiv_dia + !!---------------------------------------------------------------------- + ! + IF( kstp == nit000 ) THEN ! save diagnotic logical + ll_trdtra = l_trdtra + ll_trdtrc = l_trdtrc + ll_trddyn = l_trddyn + ll_diaptr = l_diaptr + ll_ldfeiv_dia = l_ldfeiv_dia + ENDIF + ! + SELECT CASE( kswitch ) + CASE ( 1 ) ! diagnostic activated (on) + l_trdtra = ll_trdtra + l_trdtrc = ll_trdtrc + l_trddyn = ll_trddyn + l_diaptr = ll_diaptr + l_ldfeiv_dia = ll_ldfeiv_dia + CASE ( 0 ) ! diagnostic desactivated (off) + l_trdtra = .FALSE. + l_trdtrc = .FALSE. + l_trddyn = .FALSE. + l_diaptr = .FALSE. + l_ldfeiv_dia = .FALSE. + END SELECT + ! + END SUBROUTINE rk3_dia + +#else + !!---------------------------------------------------------------------- + !! default option EMPTY MODULE qco not activated + !!---------------------------------------------------------------------- +#endif + + !!====================================================================== +END MODULE stprk3 diff --git a/src/OCE/stprk3_stg.F90 b/src/OCE/stprk3_stg.F90 new file mode 100644 index 0000000000000000000000000000000000000000..b12a1bebbe70608bb1f3c9157138aabd0a364f47 --- /dev/null +++ b/src/OCE/stprk3_stg.F90 @@ -0,0 +1,472 @@ +MODULE stprk3_stg + !!====================================================================== + !! *** MODULE stprk3_stg *** + !! Time-stepping : manager of the ocean, tracer and ice time stepping + !! using a 3rd order Runge-Kutta with fixed or quasi-eulerian coordinate + !!====================================================================== + !! History : 4.5 ! 2021-01 (S. Techene, G. Madec, N. Ducousso, F. Lemarie) Original code + !! NEMO + !!---------------------------------------------------------------------- +#if defined key_qco || defined key_linssh + !!---------------------------------------------------------------------- + !! 'key_qco' Quasi-Eulerian vertical coordinate + !! OR + !! 'key_linssh Fixed in time vertical coordinate + !!---------------------------------------------------------------------- + + !!---------------------------------------------------------------------- + !! stp_RK3_stg : NEMO 3rd order Runge-Kutta stage with qco or linssh + !!---------------------------------------------------------------------- + USE step_oce ! time stepping used modules + USE domqco ! quasi-eulerian coordinate (dom_qco_r3c routine) + USE bdydyn ! ocean open boundary conditions (define bdy_dyn) + USE lbclnk ! ocean lateral boundary conditions (or mpp link) +# if defined key_top + USE trc ! ocean passive tracers variables + USE trcadv ! passive tracers advection (trc_adv routine) + USE trcsms ! passive tracers source and sink + USE trctrp ! passive tracers transport + USE trcsbc ! passive tracers surface boundary condition !!st WARNING USELESS TO BE REMOVED + USE trcbdy ! passive tracers transport open boundary + USE trcstp_rk3 +# endif +# if defined key_agrif + USE agrif_oce_interp +# endif + + ! + USE prtctl ! print control + + IMPLICIT NONE + PRIVATE + + PUBLIC stp_RK3_stg ! called by nemogcm.F90 + + REAL(wp) :: r1_2 = 1._wp / 2._wp + REAL(wp) :: r1_3 = 1._wp / 3._wp + REAL(wp) :: r2_3 = 2._wp / 3._wp + + REAL(wp), ALLOCATABLE, SAVE, DIMENSION(:,:) :: ssha ! sea-surface height at N+1 + REAL(wp), ALLOCATABLE, SAVE, DIMENSION(:,:) :: ua_b, va_b ! barotropic velocity at N+1 + REAL(wp), ALLOCATABLE, SAVE, DIMENSION(:,:) :: r3ta, r3ua, r3va ! ssh/h_0 ratio at t,u,v-column at N+1 + REAL(wp), ALLOCATABLE, SAVE, DIMENSION(:,:) :: r3fb, r3fa ! ssh/h_0 ratio at f-column at N and N+1 + + !! * Substitutions +# include "do_loop_substitute.h90" +# include "domzgr_substitute.h90" + !!---------------------------------------------------------------------- + !! NEMO/OCE 4.0 , NEMO Consortium (2018) + !! $Id: step.F90 12377 2020-02-12 14:39:06Z acc $ + !! Software governed by the CeCILL license (see ./LICENSE) + !!---------------------------------------------------------------------- +CONTAINS + + SUBROUTINE stp_RK3_stg( kstg, kstp, Kbb, Kmm, Krhs, Kaa ) + !!---------------------------------------------------------------------- + !! *** ROUTINE stp_RK3_stg *** + !! + !! ** Purpose : - stage of RK3 time stepping of OCE and TOP + !! + !! ** Method : input: computed in dynspg_ts + !! ssh shea surface height at N+1 (oce.F90) + !! (uu_b,vv_b) barotropic velocity at N, N+1 (oce.F90) + !! (un_adv,vn_adv) barotropic transport from N to N+1 (dynspg_ts.F90) + !! , + !! -1- set ssh(Naa) (Naa=N+1/3, N+1/2, or N) + !! -2- set the advective velocity (zadU,zaV) + !! -4- Compute the after (Naa) T-S + !! -5- Update now + !! -6- Update the horizontal velocity + !!---------------------------------------------------------------------- + INTEGER, INTENT(in) :: kstg ! RK3 stage + INTEGER, INTENT(in) :: kstp, Kbb, Kmm, Krhs, Kaa ! ocean time-step and time-level indices + ! + INTEGER :: ji, jj, jk, jn, jtile ! dummy loop indices + REAL(wp) :: ze3Tb, ze3Sb, z1_e3t ! local scalars + REAL(wp) :: ze3Tr, ze3Sr ! - - + REAL(wp), DIMENSION(jpi,jpj,jpk) :: zaU, zaV ! advective horizontal velocity + REAL(wp), DIMENSION(jpi,jpj) :: zub, zvb ! advective transport + !! --------------------------------------------------------------------- + ! + IF( ln_timing ) CALL timing_start('stp_RK3_stg') + ! + IF( kstp == nit000 ) THEN + IF(lwp) WRITE(numout,*) + IF(lwp) WRITE(numout,*) 'stp_RK3_stg : Runge Kutta 3rd order at stage ', kstg + IF(lwp) WRITE(numout,*) '~~~~~~~~~~~' + ENDIF + ! + !>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + ! ssh, uu_b, vv_b, and ssh/h0 at Kaa + ! 3D advective velocity at Kmm + !<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + ! + SELECT CASE( kstg ) + ! !---------------! + CASE ( 1 ) !== Stage 1 ==! Kbb = Kmm = N ; Kaa = N+1/3 + ! !---------------! + ! + ALLOCATE( ssha(jpi,jpj) , ua_b(jpi,jpj) , va_b(jpi,jpj) ) + ! + rDt = r1_3 * rn_Dt ! set time-step : rn_Dt/3 + r1_Dt = 1._wp / rDt + ! + ssha(:,:) = ssh (:,:,Kaa) ! save ssh, uu_b, vv_b at N+1 (computed in dynspg_ts) + ua_b(:,:) = uu_b(:,:,Kaa) + va_b(:,:) = vv_b(:,:,Kaa) + ! ! interpolated ssh and (uu_b,vv_b) at Kaa (N+1/3) + ssh (:,:,Kaa) = r2_3 * ssh (:,:,Kbb) + r1_3 * ssha(:,:) + uu_b(:,:,Kaa) = r2_3 * uu_b(:,:,Kbb) + r1_3 * ua_b(:,:) + vv_b(:,:,Kaa) = r2_3 * vv_b(:,:,Kbb) + r1_3 * va_b(:,:) + ! + ! + ! !== ssh/h0 ratio at Kaa ==! + ! + IF( .NOT.lk_linssh ) THEN ! "after" ssh/h_0 ratio at t,u,v-column computed at N+1 stored in r3.a + ! + ALLOCATE( r3ta(jpi,jpj) , r3ua(jpi,jpj) , r3va(jpi,jpj) , r3fa(jpi,jpj) , r3fb(jpi,jpj) ) + ! + r3fb(:,:) = r3f(:,:) + CALL dom_qco_r3c_RK3( ssha, r3ta, r3ua, r3va, r3fa ) + ! + CALL lbc_lnk( 'stprk3_stg', r3ua, 'U', 1._wp, r3va, 'V', 1._wp, r3fa, 'F', 1._wp ) + ! ! + r3t(:,:,Kaa) = r2_3 * r3t(:,:,Kbb) + r1_3 * r3ta(:,:) ! at N+1/3 (Kaa) + r3u(:,:,Kaa) = r2_3 * r3u(:,:,Kbb) + r1_3 * r3ua(:,:) + r3v(:,:,Kaa) = r2_3 * r3v(:,:,Kbb) + r1_3 * r3va(:,:) + ! r3f already properly set up ! at N (Kmm) + ENDIF + ! + ! !---------------! + CASE ( 2 ) !== Stage 2 ==! Kbb = N ; Kmm = N+1/3 ; Kaa = N+1/2 + ! !---------------! + ! + rDt = r1_2 * rn_Dt ! set time-step : rn_Dt/2 + r1_Dt = 1._wp / rDt + ! + ! ! set ssh and (uu_b,vv_b) at N+1/2 (Kaa) + ssh (:,:,Kaa) = r1_2 * ( ssh (:,:,Kbb) + ssha(:,:) ) + uu_b(:,:,Kaa) = r1_2 * ( uu_b(:,:,Kbb) + ua_b(:,:) ) + vv_b(:,:,Kaa) = r1_2 * ( vv_b(:,:,Kbb) + va_b(:,:) ) + ! + IF( .NOT.lk_linssh ) THEN + r3t(:,:,Kaa) = r1_2 * ( r3t(:,:,Kbb) + r3ta(:,:) ) ! at N+1/2 (Kaa) + r3u(:,:,Kaa) = r1_2 * ( r3u(:,:,Kbb) + r3ua(:,:) ) + r3v(:,:,Kaa) = r1_2 * ( r3v(:,:,Kbb) + r3va(:,:) ) + r3f(:,:) = r2_3 * r3fb(:,:) + r1_3 * r3fa(:,:) ! at N+1/3 (Kmm) + ENDIF + ! + ! !---------------! + CASE ( 3 ) !== Stage 3 ==! Kbb = N ; Kmm = N+1/2 ; Kaa = N+1 + ! !---------------! + ! + rDt = rn_Dt ! set time-step : rn_Dt + r1_Dt = 1._wp / rDt + ! + ssh (:,:,Kaa) = ssha(:,:) ! recover ssh and (uu_b,vv_b) at N + 1 + uu_b(:,:,Kaa) = ua_b(:,:) + vv_b(:,:,Kaa) = va_b(:,:) + ! + DEALLOCATE( ssha , ua_b , va_b ) + ! + IF( .NOT.lk_linssh ) THEN + r3t(:,:,Kaa) = r3ta(:,:) ! at N+1 (Kaa) + r3u(:,:,Kaa) = r3ua(:,:) + r3v(:,:,Kaa) = r3va(:,:) + r3f(:,: ) = r1_2 * ( r3fb(:,:) + r3fa(:,:) ) ! at N+1/2 (Kmm) + DEALLOCATE( r3ta, r3ua, r3va, r3fb ) ! deallocate all r3. except r3fa which will be + ! ! saved in r3f at the end of the time integration and then deallocated + ! + ENDIF + ! + END SELECT + ! + ! !== advective velocity at Kmm ==! + ! + ! !- horizontal components -! (zaU,zaV) + DO_2D_OVR( nn_hls, nn_hls, nn_hls, nn_hls ) + zub(ji,jj) = un_adv(ji,jj)*r1_hu(ji,jj,Kmm) - uu_b(ji,jj,Kmm) ! barotropic velocity correction + zvb(ji,jj) = vn_adv(ji,jj)*r1_hv(ji,jj,Kmm) - vv_b(ji,jj,Kmm) + END_2D + DO_3D_OVR( nn_hls, nn_hls, nn_hls, nn_hls, 1, jpkm1 ) ! horizontal advective velocity + zaU(ji,jj,jk) = uu(ji,jj,jk,Kmm) + zub(ji,jj)*umask(ji,jj,jk) + zaV(ji,jj,jk) = vv(ji,jj,jk,Kmm) + zvb(ji,jj)*vmask(ji,jj,jk) + END_3D + ! !- vertical components -! ww + ! + IF( ln_dynadv_vec ) THEN ! ww cross-level velocity consistent with uu/vv at Kmm + CALL wzv ( kstp, Kbb, Kmm, Kaa, uu(:,:,:,Kmm), vv(:,:,:,Kmm), ww ) + ELSE ! ww cross-level velocity consistent with zaU/zaV + CALL wzv ( kstp, Kbb, Kmm, Kaa, zaU, zaV, ww ) + ENDIF + +!!st IF( ln_zad_Aimp ) CALL wAimp( kstp, ww, wi ) ! Adaptive-implicit vertical advection partitioning + ! !==>>> implicite for stages 1 & 2 ???? + ! + + !>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + ! RHS of ocean dynamics : ADV + VOR/COR + HPG (+ ASM ) <<<=== Question: Stokes drift ? + !<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + ! + uu(:,:,:,Krhs) = 0._wp ! set dynamics trends to zero + vv(:,:,:,Krhs) = 0._wp + ! +!===>>>>>> Modify dyn_adv_... dyn_keg routines so that Krhs to zero useless + ! ! advection (VF or FF) ==> RHS + IF( ln_dynadv_vec ) THEN ! uu and vv used for momentum advection + CALL dyn_adv( kstp, Kbb, Kmm , uu, vv, Krhs) + ELSE ! advective velocity used for momentum advection + CALL dyn_adv( kstp, Kbb, Kmm , uu, vv, Krhs, zaU, zaV, ww ) + ENDIF + ! ! Coriolis / vorticity ==> RHS + CALL dyn_vor( kstp, Kmm , uu, vv, Krhs ) + ! +!!gm à appeler que pour ln_zad_Aimp=T et en ne faisant que wi par zdf +!! ! ZAD (implicit part) ==> RHS +!! CALL dyn_zdf ( kstp, Kbb, Kmm, Krhs, uu, vv, Kaa ) + +!===>>>>>> Modify dyn_hpg & dyn_hpg_... routines : rhd computed in dyn_hpg and pass in argument to dyn_hpg_... + + CALL eos ( ts, Kmm, rhd ) ! Kmm in situ density anomaly for hpg computation + +!!gm end + CALL dyn_hpg( kstp, Kmm , uu, vv, Krhs ) + ! +!!gm ===>>>>>> Probably useless since uu_b(Kaa) will be imposed at the end of stage 1 and 2 +! but may be necessary in stage 3 due to implicite in dynzdf. +! except if my idea for the matrice construction is OK ! +! ! ! grad_h of ps ==> RHS +! DO_3D( 0, 0, 0, 0, 1, jpkm1 ) +! uu(ji,jj,jk,Krhs) = uu(ji,jj,jk,Krhs) - grav * ( ssh(ji+1,jj ,Kmm) - ssh(ji,jj,Kmm) ) +! vv(ji,jj,jk,Krhs) = vv(ji,jj,jk,Krhs) - grav * ( ssh(ji ,jj+1,Kmm) - ssh(ji,jj,Kmm) ) +! END_3D +!!gm + + !>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + ! RHS of tracers : ADV only using (zaU,zaV,ww) + !<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + ! + ! ! Advective velocity needed for tracers advection - already computed if ln_dynadv_vec=F + IF( ln_dynadv_vec ) CALL wzv ( kstp, Kbb, Kmm, Kaa, zaU, zaV, ww ) + ! +# if defined key_top + ! !== Passive Tracer ==! + ! + SELECT CASE( kstg ) + ! !-------------------! + CASE ( 1 , 2 ) !== Stage 1 & 2 ==! stg1: Kbb = N ; Kaa = N+1/3 + ! !-------------------! stg2: Kbb = N ; Kmm = N+1/3 ; Kaa = N+1/2 + ! + IF( kstg == 1 ) THEN + CALL trc_stp_start( kstp, Kbb, Kmm, Krhs, Kaa ) + ENDIF + ! + IF(.NOT. ln_trcadv_mus ) THEN + ! + DO jn = 1, jptra + tr(:,:,:,jn,Krhs) = 0._wp ! set tracer trends to zero !!st ::: required because of tra_adv new loops + END DO + ! !== advection of passive tracers ==! + rDt_trc = rDt + ! + CALL trc_sbc_RK3( kstp, Kmm, tr, Krhs, kstg ) ! surface boundary condition + ! + CALL trc_adv ( kstp, Kbb, Kmm, tr, Krhs, zaU, zaV, ww ) ! horizontal & vertical advection + ! + ! !== time integration ==! ∆t = rn_Dt/3 (stg1) or rn_Dt/2 (stg2) + DO jn = 1, jptra + DO_3D( 0, 0, 0, 0, 1, jpkm1 ) + ze3Tb = e3t(ji,jj,jk,Kbb) * tr(ji,jj,jk,jn,Kbb ) + ze3Tr = e3t(ji,jj,jk,Kmm) * tr(ji,jj,jk,jn,Krhs) + z1_e3t= 1._wp / e3t(ji,jj,jk, Kaa) + tr(ji,jj,jk,jn,Kaa) = ( ze3Tb + rDt * ze3Tr*tmask(ji,jj,jk) ) * z1_e3t + END_3D + END DO + ! +!!st need a lnc lkn at stage 1 & 2 otherwise tr@Kmm will not be usable in trc_adv + CALL lbc_lnk( 'stprk3_stg', tr(:,:,:,:,Kaa), 'T', 1._wp ) + + ENDIF + ! !---------------! + CASE ( 3 ) !== Stage 3 ==! add all RHS terms but advection (=> Kbb only) + ! !---------------! + ! + DO jn = 1, jptra + tr(:,:,:,jn,Krhs) = 0._wp + END DO + ! !== advection of passive tracers ==! + rDt_trc = rDt + ! + CALL trc_sbc_RK3( kstp, Kmm, tr, Krhs, kstg ) ! surface boundary condition + ! + CALL trc_adv ( kstp, Kbb, Kmm, tr, Krhs, zaU, zaV, ww ) ! horizontal & vertical advection + ! + CALL trc_sms ( kstp, Kbb, Kbb, Krhs ) ! tracers: sinks and sources + CALL trc_trp ( kstp, Kbb, Kmm, Krhs, Kaa ) ! transport of passive tracers (without advection) + ! + ! + CALL trc_stp_end( kstp, Kbb, Kmm, Kaa ) + ! + END SELECT +# endif + + ! !== T-S Tracers ==! + +!===>>>>>> Modify tra_adv_... routines so that Krhs to zero useless + DO jn = 1, jpts + ts(:,:,:,jn,Krhs) = 0._wp ! set tracer trends to zero (:,:,:) needed otherwise it does not work (?) + END DO + + CALL eos( ts(:,:,:,:,Kmm), rhd, rhop, gdept_0 ) ! now in potential density for tra_mle computation +!===>>> CAUTION here may be without GM velocity but stokes drift required ! 0 barotropic divergence for GM != 0 barotropic divergence for SD +!!st consistence 2D / 3D - flux de masse + CALL tra_adv( kstp, Kbb, Kmm, ts, Krhs, zaU, zaV, ww ) ! hor. + vert. advection ==> RHS + +!===>>>>>> stg1&2: Verify the necessity of these trends (we may need it as there are in the RHS of dynspg_ts ?) +!!gm ====>>>> needed for heat and salt fluxes associated with mass/volume flux + CALL tra_sbc_RK3( kstp, Kmm, ts, Krhs, kstg ) ! surface boundary condition + + IF( ln_isf ) CALL tra_isf ( kstp, Kmm, ts, Krhs ) ! ice shelf heat flux + IF( ln_traqsr ) CALL tra_qsr ( kstp, Kmm, ts, Krhs ) ! penetrative solar radiation qsr +!!gm + + ! +!!gm ===>>>>>> Verify the necessity of these trends at stages 1 and 2 +! (we may need it as they are in the RHS of dynspg_ts ?) +! IF( lk_asminc .AND. ln_asmiau ) THEN ! apply assimilation increment +! IF( ln_dyninc ) CALL dyn_asm_inc( kstp, Kbb, Kmm, uu, vv, Krhs ) ! dynamics ==> RHS +! IF( ln_trainc ) CALL tra_asm_inc( kstp, Kbb, Kmm, ts , Krhs ) ! tracers ==> RHS +! ENDIF +!!gm end Verif + + ! + SELECT CASE( kstg ) + ! !-------------------! + CASE ( 1 , 2 ) !== Stage 1 & 2 ==! stg1: Kbb = N ; Kaa = N+1/3 + ! !-------------------! stg2: Kbb = N ; Kmm = N+1/3 ; Kaa = N+1/2 + ! + ! !== time integration ==! ∆t = rn_Dt/3 (stg1) or rn_Dt/2 (stg2) + IF( ln_dynadv_vec .OR. ln_linssh ) THEN ! applied on velocity + DO_3D( 0, 0, 0, 0, 1, jpkm1 ) + uu(ji,jj,jk,Kaa) = ( uu(ji,jj,jk,Kbb) + rDt * uu(ji,jj,jk,Krhs) ) * umask(ji,jj,jk) + vv(ji,jj,jk,Kaa) = ( vv(ji,jj,jk,Kbb) + rDt * vv(ji,jj,jk,Krhs) ) * vmask(ji,jj,jk) + END_3D + ELSE ! applied on thickness weighted velocity + DO_3D( 0, 0, 0, 0, 1, jpkm1 ) + uu(ji,jj,jk,Kaa) = ( e3u(ji,jj,jk,Kbb) * uu(ji,jj,jk,Kbb ) & + & + rDt * e3u(ji,jj,jk,Kmm) * uu(ji,jj,jk,Krhs) ) & + & / e3u(ji,jj,jk,Kaa) * umask(ji,jj,jk) + vv(ji,jj,jk,Kaa) = ( e3v(ji,jj,jk,Kbb) * vv(ji,jj,jk,Kbb ) & + & + rDt * e3v(ji,jj,jk,Kmm) * vv(ji,jj,jk,Krhs) ) & + & / e3v(ji,jj,jk,Kaa) * vmask(ji,jj,jk) + END_3D + ENDIF + ! + DO_3D( 0, 0, 0, 0, 1, jpkm1 ) + ze3Tb = e3t(ji,jj,jk,Kbb) * ts(ji,jj,jk,jp_tem,Kbb ) + ze3Sb = e3t(ji,jj,jk,Kbb) * ts(ji,jj,jk,jp_sal,Kbb ) + ze3Tr = e3t(ji,jj,jk,Kmm) * ts(ji,jj,jk,jp_tem,Krhs) + ze3Sr = e3t(ji,jj,jk,Kmm) * ts(ji,jj,jk,jp_sal,Krhs) + z1_e3t= 1._wp / e3t(ji,jj,jk, Kaa) + ts(ji,jj,jk,jp_tem,Kaa) = ( ze3Tb + rDt * ze3Tr*tmask(ji,jj,jk) ) * z1_e3t + ts(ji,jj,jk,jp_sal,Kaa) = ( ze3Sb + rDt * ze3Sr*tmask(ji,jj,jk) ) * z1_e3t + END_3D + ! + ! + IF(sn_cfctl%l_prtctl) CALL prt_ctl( tab3d_1=uu(:,:,:,Kaa), clinfo1='stp stg - Ua: ', mask1=umask, & + & tab3d_2=vv(:,:,:,Kaa), clinfo2= ' Va: ', mask2=vmask, clinfo3='dyn' ) + ! + IF(sn_cfctl%l_prtctl) CALL prt_ctl( tab3d_1=ts(:,:,:,jp_tem,Kaa), clinfo1='stp stg - Ta: ', mask1=tmask, & + & tab3d_2=ts(:,:,:,jp_sal,Kaa), clinfo2= ' Sa: ', mask2=tmask, clinfo3='tra' ) + ! + ! !---------------! + CASE ( 3 ) !== Stage 3 ==! add all remaining RHS terms + ! !---------------! + ! + ! !== complete the momentum RHS ==! except ZDF (implicit) + ! ! lateral mixing ==> RHS + CALL dyn_ldf( kstp, Kbb, Kmm, uu, vv, Krhs ) + ! ! OSMOSIS non-local velocity fluxes ==> RHS + IF( ln_zdfosm ) CALL dyn_osm( kstp, Kmm, uu, vv, Krhs ) + ! + IF( ln_bdy ) THEN ! bdy damping trends ==> RHS + CALL bdy_dyn3d_dmp ( kstp, Kbb, uu, vv, Krhs ) + CALL bdy_tra_dmp ( kstp, Kbb, ts , Krhs ) + ENDIF + +# if defined key_agrif + IF(.NOT. Agrif_Root() ) THEN ! AGRIF: sponge ==> momentum and tracer RHS + CALL Agrif_Sponge_dyn + CALL Agrif_Sponge_tra + ENDIF +# endif + ! !== complete the tracers RHS ==! except ZDF (implicit) + ! !* T-S Tracer *! + ! + CALL tra_ldf( kstp, Kbb, Kmm, ts, Krhs ) ! lateral mixing + IF( ln_trabbc ) CALL tra_bbc( kstp, Kmm, ts, Krhs ) ! bottom heat flux + IF( ln_trabbl ) CALL tra_bbl( kstp, Kbb, Kmm, ts, Krhs ) ! advective (and/or diffusive) bottom boundary layer scheme + IF( ln_tradmp ) CALL tra_dmp( kstp, Kbb, Kmm, ts, Krhs ) ! internal damping trends + + IF( ln_zdfmfc ) CALL tra_mfc( kstp, Kbb, ts, Krhs ) ! Mass Flux Convection + IF( ln_zdfosm ) THEN + CALL tra_osm( kstp, Kmm, ts, Krhs ) ! OSMOSIS non-local tracer fluxes ==> RHS + IF( lrst_oce ) CALL osm_rst( kstp, Kmm, 'WRITE' ) ! write OSMOSIS outputs + ww (so must do here) to restarts + ENDIF + ! + ! !== DYN & TRA time integration + ZDF ==! ∆t = rDt + ! + CALL dyn_zdf( kstp, Kbb, Kmm, Krhs, uu, vv, Kaa ) ! vertical diffusion and time integration + CALL tra_zdf( kstp, Kbb, Kmm, Krhs, ts , Kaa ) ! vertical mixing and after tracer fields + IF( ln_zdfnpc ) CALL tra_npc( kstp, Kmm, Krhs, ts , Kaa ) ! update after fields by non-penetrative convection + ! + IF( .NOT.lk_linssh ) THEN + r3f(:,:) = r3fa(:,:) ! save r3fa in r3f before deallocation + DEALLOCATE( r3fa ) ! (r3f = r3f(Kbb) of the next time step) + ENDIF + ! + END SELECT + ! !== correction of the barotropic (all stages) ==! at Kaa = N+1/3, N+1/2 or N+1 + ! ! barotropic velocity correction + zub(A2D(0)) = uu_b(A2D(0),Kaa) - SUM( e3u_0(A2D(0),:)*uu(A2D(0),:,Kaa), 3 ) * r1_hu_0(A2D(0)) + zvb(A2D(0)) = vv_b(A2D(0),Kaa) - SUM( e3v_0(A2D(0),:)*vv(A2D(0),:,Kaa), 3 ) * r1_hv_0(A2D(0)) + ! + DO jk = 1, jpkm1 ! corrected horizontal velocity + uu(A2D(0),jk,Kaa) = uu(A2D(0),jk,Kaa) + zub(A2D(0))*umask(A2D(0),jk) + vv(A2D(0),jk,Kaa) = vv(A2D(0),jk,Kaa) + zvb(A2D(0))*vmask(A2D(0),jk) + END DO + + + !>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + ! Set boundary conditions + !<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + ! +# if defined key_agrif + CALL Agrif_tra( kstp, kstg ) !* AGRIF zoom boundaries + CALL Agrif_dyn( kstp, kstg ) +# endif + ! !* local domain boundaries (T-point, unchanged sign) + CALL lbc_lnk( 'stp_RK3_stg', uu(:,:,:, Kaa), 'U', -1., vv(:,:,: ,Kaa), 'V', -1. & + & , ts(:,:,:,jp_tem,Kaa), 'T', 1., ts(:,:,:,jp_sal,Kaa), 'T', 1. ) + ! + IF( nn_hls == 2 .AND. l_zdfsh2 ) CALL lbc_lnk( 'stp_RK3_stg', avm_k, 'W', 1.0_wp ) ! lbc_lnk needed for zdf_sh2 when using nn_hls = 2, moved here to allow tiling in zdf_phy + ! + ! !* BDY open boundaries + IF( ln_bdy ) THEN + CALL bdy_tra( kstp, Kbb, ts, Kaa ) + IF( ln_dynspg_exp ) CALL bdy_dyn( kstp, Kbb, uu, vv, Kaa ) + IF( ln_dynspg_ts ) CALL bdy_dyn( kstp, Kbb, uu, vv, Kaa, dyn3d_only=.true. ) + ENDIF + ! + IF( ln_timing ) CALL timing_stop('stp_RK3_stg') + ! + END SUBROUTINE stp_RK3_stg + +#else + !!---------------------------------------------------------------------- + !! default option EMPTY MODULE qco not activated + !!---------------------------------------------------------------------- +#endif + + !!====================================================================== +END MODULE stprk3_stg diff --git a/src/OFF/dtadyn.F90 b/src/OFF/dtadyn.F90 index 4cffb4a06bf27e6f174067aa8e41bc5c70b73e67..253d699db5d2b13d0e708af11cfb31d1515b4c69 100644 --- a/src/OFF/dtadyn.F90 +++ b/src/OFF/dtadyn.F90 @@ -101,7 +101,7 @@ MODULE dtadyn !!---------------------------------------------------------------------- !! NEMO/OFF 4.0 , NEMO Consortium (2018) - !! $Id: dtadyn.F90 15090 2021-07-06 14:25:18Z cetlod $ + !! $Id: dtadyn.F90 15532 2021-11-24 11:47:32Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS @@ -175,7 +175,7 @@ CONTAINS ENDIF ENDIF ! - CALL eos ( ts(:,:,:,:,Kmm), rhd, rhop, gdept_0(:,:,:) ) ! In any case, we need rhop + CALL eos ( ts(:,:,:,:,Kmm), rhd, gdept_0(:,:,:) ) ! In any case, we need rhd CALL eos_rab( ts(:,:,:,:,Kmm), rab_n, Kmm ) ! now local thermal/haline expension ratio at T-points CALL bn2 ( ts(:,:,:,:,Kmm), rab_n, rn2, Kmm ) ! before Brunt-Vaisala frequency need for zdfmxl @@ -192,7 +192,7 @@ CONTAINS ENDIF ! ! - CALL eos( ts(:,:,:,:,Kmm), rhd, rhop, gdept_0(:,:,:) ) ! In any case, we need rhop + CALL eos( ts(:,:,:,:,Kmm), rhd, gdept_0(:,:,:) ) ! In any case, we need rhd ! IF(sn_cfctl%l_prtctl) THEN ! print control CALL prt_ctl(tab3d_1=ts(:,:,:,jp_tem,Kmm), clinfo1=' tn - : ', mask1=tmask ) @@ -669,7 +669,7 @@ CONTAINS !!--------------------------------------------------------------------- ! IF( l_ldfslp .AND. .NOT.ln_c1d ) THEN ! Computes slopes (here avt is used as workspace) - CALL eos ( pts, rhd, rhop, gdept_0(:,:,:) ) + CALL eos ( pts, rhd, gdept_0(:,:,:) ) CALL eos_rab( pts, rab_n, Kmm ) ! now local thermal/haline expension ratio at T-points CALL bn2 ( pts, rab_n, rn2, Kmm ) ! now Brunt-Vaisala @@ -727,7 +727,7 @@ CONTAINS ts(:,:,:,jp_tem,Kmm) = sf_dyn(jf_tem)%fnow(:,:,:) * tmask(:,:,:) ! temperature ts(:,:,:,jp_sal,Kmm) = sf_dyn(jf_sal)%fnow(:,:,:) * tmask(:,:,:) ! salinity ! - CALL eos ( ts(:,:,:,:,Kmm), rhd, rhop, gdept_0(:,:,:) ) ! In any case, we need rhop + CALL eos ( ts(:,:,:,:,Kmm), rhd, gdept_0(:,:,:) ) ! In any case, we need rhd IF(sn_cfctl%l_prtctl) THEN ! print control CALL prt_ctl(tab3d_1=ts(:,:,:,jp_tem,Kmm), clinfo1=' tn - : ', mask1=tmask ) diff --git a/src/OFF/nemogcm.F90 b/src/OFF/nemogcm.F90 index 73713236f3bcedb4e83056eb89283726e1ed658a..9cffd0190d1a01528c6ce0c37503905e632353d2 100644 --- a/src/OFF/nemogcm.F90 +++ b/src/OFF/nemogcm.F90 @@ -82,7 +82,7 @@ MODULE nemogcm !!---------------------------------------------------------------------- !! NEMO/OFF 4.0 , NEMO Consortium (2018) - !! $Id: nemogcm.F90 15446 2021-10-26 14:34:38Z cetlod $ + !! $Id: nemogcm.F90 14255 2021-01-04 11:35:00Z cetlod $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS @@ -517,7 +517,6 @@ CONTAINS ts (:,:,:,:,Kmm) = 0._wp ! ! ! rhd (:,:,:) = 0.e0 - rhop (:,:,:) = 0.e0 rn2 (:,:,:) = 0.e0 ! END SUBROUTINE istate_init diff --git a/src/TOP/AGE/trcsms_age.F90 b/src/TOP/AGE/trcsms_age.F90 index dec67f35f3115a076f51163c2fe77e798ea4e14c..a8283edf6df534771cbac7aaa40fa40946b6f4e1 100644 --- a/src/TOP/AGE/trcsms_age.F90 +++ b/src/TOP/AGE/trcsms_age.F90 @@ -31,7 +31,7 @@ MODULE trcsms_age !!---------------------------------------------------------------------- !! NEMO/TOP 4.0 , NEMO Consortium (2018) - !! $Id: trcsms_age.F90 14173 2020-12-15 12:44:07Z cetlod $ + !! $Id: trcsms_age.F90 15193 2021-08-13 13:18:24Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS @@ -51,14 +51,17 @@ CONTAINS ! IF( ln_timing ) CALL timing_start('trc_sms_age') ! - IF(lwp) WRITE(numout,*) - IF(lwp) WRITE(numout,*) ' trc_sms_age: AGE model' - IF(lwp) WRITE(numout,*) ' ~~~~~~~~~~~~~~' + IF( kt == nittrc000 ) THEN + IF(lwp) WRITE(numout,*) + IF(lwp) WRITE(numout,*) ' trc_sms_age: AGE model' + IF(lwp) WRITE(numout,*) ' ~~~~~~~~~~~~~~' + ENDIF +#if ! defined key_RK3 IF( l_1st_euler .OR. ln_top_euler ) THEN tr(:,:,:,jp_age,Kbb) = tr(:,:,:,jp_age,Kmm) ENDIF - +#endif DO jk = 1, nla_age tr(:,:,jk,jp_age,Krhs) = rn_age_kill_rate * tr(:,:,jk,jp_age,Kbb) @@ -71,7 +74,7 @@ CONTAINS tr(:,:,jk,jp_age,Krhs) = tmask(:,:,jk) * rryear END DO ! - IF( l_trdtrc ) CALL trd_trc( tr(:,:,:,jp_age,Krhs), jn, jptra_sms, kt, Kmm ) ! save trends + IF( l_trdtrc ) CALL trd_trc( tr(:,:,:,jp_age,Krhs), jn, jptra_sms, kt, Kmm ) ! save trends ! IF( ln_timing ) CALL timing_stop('trc_sms_age') ! diff --git a/src/TOP/PISCES/P4Z/p4zche.F90 b/src/TOP/PISCES/P4Z/p4zche.F90 index 95c07d05db84c985053f7614d5a23c30460b76b4..a71f9350e553ee336f81d980f64d96bb9fcf2935 100644 --- a/src/TOP/PISCES/P4Z/p4zche.F90 +++ b/src/TOP/PISCES/P4Z/p4zche.F90 @@ -11,6 +11,7 @@ MODULE p4zche !! 2.0 ! 2007-12 (C. Ethe, G. Madec) F90 !! ! 2011-02 (J. Simeon, J.Orr ) update O2 solubility constants !! 3.6 ! 2016-03 (O. Aumont) Change chemistry to MOCSY standards + !! 4.2 ! 2020 (J. ORR ) rhop is replaced by "in situ density" rhd !!---------------------------------------------------------------------- !! p4z_che : Sea water chemistry computed following OCMIP protocol !!---------------------------------------------------------------------- @@ -134,7 +135,7 @@ MODULE p4zche # include "domzgr_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/TOP 4.0 , NEMO Consortium (2018) - !! $Id: p4zche.F90 15459 2021-10-29 08:19:18Z cetlod $ + !! $Id: p4zche.F90 15532 2021-11-24 11:47:32Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS @@ -194,9 +195,21 @@ CONTAINS zsal = salinprac(ji,jj,1) + ( 1.- tmask(ji,jj,1) ) * 35. ! ! LN(K0) OF SOLUBILITY OF CO2 (EQ. 12, WEISS, 1980) ! ! AND FOR THE ATMOSPHERE FOR NON IDEAL GAS + ! J. ORR: The previous code has been modified. It computed CO2 solubility in mol/(kg*atm), then converted that to mol/(L*atm). + ! But Weiss (1974) provides sets of coefficients for each of those 2 units. + ! Thus I have changed the code to use the coefficients for mol*L/atm. + ! Hence I've eliminated using the conversion (which used the variable rhop) + ! OLD - Coefficients for CO2 soulbility in mol/(kg*atm) (Weiss,1974, Table 1, column 2) + !zcek1 = 9345.17/ztkel - 60.2409 + 23.3585 * LOG(zt) + zsal*(0.023517 - 0.00023656*ztkel & + !& + 0.0047036e-4*ztkel**2) + ! NEW - Coefficients for CO2 soulbility in mol/(L*atm) (Weiss, 1974, Table 1, column 1) zcek1 = 9050.69/ztkel - 58.0931 + 22.2940 * LOG(zt) + zsal*(0.027766 - 0.00025888*ztkel & - & + 0.0050578e-4*ztkel**2) - chemc(ji,jj,1) = EXP( zcek1 ) * 1E-6 ! mol/(L atm) + & + 0.0050578e-4*ztkel**2) + ! + ! OLD: chemc(ji,jj,1) = EXP( zcek1 ) * 1E-6 * rhop(ji,jj,1) / 1000. ! mol/(L atm) + ! The units indicated in the above line are wrong. They are actually "mol/(L*uatm)" + ! NEW: + chemc(ji,jj,1) = EXP( zcek1 ) * 1E-6 ! mol/(L * uatm) chemc(ji,jj,2) = -1636.75 + 12.0408*ztkel - 0.0327957*ztkel**2 + 0.0000316528*ztkel**3 chemc(ji,jj,3) = 57.7 - 0.118*ztkel END_2D @@ -444,15 +457,16 @@ CONTAINS INTEGER :: ji, jj, jk REAL(wp) :: zca1, zba1 REAL(wp) :: zd, zsqrtd, zhmin - REAL(wp) :: za2, za1, za0 + REAL(wp) :: za2, za1, za0, zrhd REAL(wp) :: p_dictot, p_bortot, p_alkcb !!--------------------------------------------------------------------- IF( ln_timing ) CALL timing_start('ahini_for_at') ! DO_3D( nn_hls, nn_hls, nn_hls, nn_hls, 1, jpk ) - p_alkcb = tr(ji,jj,jk,jptal,Kbb) * 1000. / (rhop(ji,jj,jk) + rtrn) - p_dictot = tr(ji,jj,jk,jpdic,Kbb) * 1000. / (rhop(ji,jj,jk) + rtrn) + zrhd = 1._wp / ( rhd(ji,jj,jk) + 1. ) + p_alkcb = tr(ji,jj,jk,jptal,Kbb) * zrhd + p_dictot = tr(ji,jj,jk,jpdic,Kbb) * zrhd p_bortot = borat(ji,jj,jk) IF (p_alkcb <= 0.) THEN p_hini(ji,jj,jk) = 1.e-3 @@ -501,11 +515,16 @@ CONTAINS REAL(wp), DIMENSION(jpi,jpj,jpk), INTENT(OUT) :: p_alknw_inf REAL(wp), DIMENSION(jpi,jpj,jpk), INTENT(OUT) :: p_alknw_sup INTEGER, INTENT(in) :: Kbb ! time level indices + INTEGER :: ji, jj, jk + REAL(wp) :: zrhd - p_alknw_inf(:,:,:) = -tr(:,:,:,jppo4,Kbb) * 1000. / (rhop(:,:,:) + rtrn) - sulfat(:,:,:) & - & - fluorid(:,:,:) - p_alknw_sup(:,:,:) = (2. * tr(:,:,:,jpdic,Kbb) + 2. * tr(:,:,:,jppo4,Kbb) + tr(:,:,:,jpsil,Kbb) ) & - & * 1000. / (rhop(:,:,:) + rtrn) + borat(:,:,:) + DO_3D( nn_hls, nn_hls, nn_hls, nn_hls, 1, jpk ) + zrhd = 1._wp / ( rhd(ji,jj,jk) + 1. ) + p_alknw_inf(ji,jj,jk) = -tr(ji,jj,jk,jppo4,Kbb) * zrhd - sulfat(ji,jj,jk) & + & - fluorid(ji,jj,jk) + p_alknw_sup(ji,jj,jk) = (2. * tr(ji,jj,jk,jpdic,Kbb) + 2. * tr(ji,jj,jk,jppo4,Kbb) + tr(ji,jj,jk,jpsil,Kbb) ) & + & * zrhd + borat(ji,jj,jk) + END_3D END SUBROUTINE anw_infsup @@ -535,7 +554,7 @@ CONTAINS REAL(wp) :: znumer_so4, zdnumer_so4, zdenom_so4, zalk_so4, zdalk_so4 REAL(wp) :: znumer_flu, zdnumer_flu, zdenom_flu, zalk_flu, zdalk_flu REAL(wp) :: zalk_wat, zdalk_wat - REAL(wp) :: zfact, p_alktot, zdic, zbot, zpt, zst, zft, zsit + REAL(wp) :: zrhd, p_alktot, zdic, zbot, zpt, zst, zft, zsit LOGICAL :: l_exitnow REAL(wp), PARAMETER :: pz_exp_threshold = 1.0 REAL(wp), DIMENSION(jpi,jpj,jpk) :: zalknw_inf, zalknw_sup, rmask, zh_min, zh_max, zeqn_absmin @@ -550,7 +569,8 @@ CONTAINS ! TOTAL H+ scale: conversion factor for Htot = aphscale * Hfree DO_3D( nn_hls, nn_hls, nn_hls, nn_hls, 1, jpk ) IF (rmask(ji,jj,jk) == 1.) THEN - p_alktot = tr(ji,jj,jk,jptal,Kbb) * 1000. / (rhop(ji,jj,jk) + rtrn) + zrhd = 1._wp / ( rhd(ji,jj,jk) + 1. ) + p_alktot = tr(ji,jj,jk,jptal,Kbb) * zrhd aphscale = 1. + sulfat(ji,jj,jk)/aks3(ji,jj,jk) zh_ini = p_hini(ji,jj,jk) @@ -579,12 +599,12 @@ CONTAINS DO jn = 1, jp_maxniter_atgen DO_3D( nn_hls, nn_hls, nn_hls, nn_hls, 1, jpk ) IF (rmask(ji,jj,jk) == 1.) THEN - zfact = rhop(ji,jj,jk) / 1000. + rtrn - p_alktot = tr(ji,jj,jk,jptal,Kbb) / zfact - zdic = tr(ji,jj,jk,jpdic,Kbb) / zfact + zrhd = 1._wp / ( rhd(ji,jj,jk) + 1. ) + p_alktot = tr(ji,jj,jk,jptal,Kbb) * zrhd + zdic = tr(ji,jj,jk,jpdic,Kbb) * zrhd zbot = borat(ji,jj,jk) - zpt = tr(ji,jj,jk,jppo4,Kbb) / zfact * po4r - zsit = tr(ji,jj,jk,jpsil,Kbb) / zfact + zpt = tr(ji,jj,jk,jppo4,Kbb) * zrhd * po4r + zsit = tr(ji,jj,jk,jpsil,Kbb) * zrhd zst = sulfat (ji,jj,jk) zft = fluorid(ji,jj,jk) aphscale = 1. + sulfat(ji,jj,jk)/aks3(ji,jj,jk) diff --git a/src/TOP/PISCES/P4Z/p4zflx.F90 b/src/TOP/PISCES/P4Z/p4zflx.F90 index 36940fd924b94baff0cf7e9c2e77bbad67435cf8..051985ba2037053eb13b4094b8a8aff532c7f2de 100644 --- a/src/TOP/PISCES/P4Z/p4zflx.F90 +++ b/src/TOP/PISCES/P4Z/p4zflx.F90 @@ -9,6 +9,7 @@ MODULE p4zflx !! 1.0 ! 2004 (O. Aumont) modifications !! 2.0 ! 2007-12 (C. Ethe, G. Madec) F90 !! ! 2011-02 (J. Simeon, J. Orr) Include total atm P correction + !! 4.2 ! 2020 (J. ORR ) rhop is replaced by "in situ density" rhd !!---------------------------------------------------------------------- !! p4z_flx : CALCULATES GAS EXCHANGE AND CHEMISTRY AT SEA SURFACE !! p4z_flx_init : Read the namelist @@ -56,7 +57,7 @@ MODULE p4zflx # include "domzgr_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/TOP 4.0 , NEMO Consortium (2018) - !! $Id: p4zflx.F90 15459 2021-10-29 08:19:18Z cetlod $ + !! $Id: p4zflx.F90 15532 2021-11-24 11:47:32Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS @@ -77,7 +78,7 @@ CONTAINS ! INTEGER :: ji, jj, jm, iind, iindm1 REAL(wp) :: ztc, ztc2, ztc3, ztc4, zws, zkgwan - REAL(wp) :: zfld, zflu, zfld16, zflu16, zfact + REAL(wp) :: zfld, zflu, zfld16, zflu16, zrhd REAL(wp) :: zvapsw, zsal, zfco2, zxc2, xCO2approx, ztkel, zfugcoeff REAL(wp) :: zph, zdic, zsch_o2, zsch_co2 REAL(wp) :: zyr_dec, zdco2dt @@ -111,9 +112,9 @@ CONTAINS DO_2D( nn_hls, nn_hls, nn_hls, nn_hls ) ! DUMMY VARIABLES FOR DIC, H+, AND BORATE - zfact = rhop(ji,jj,1) / 1000. + rtrn + zrhd = rhd(ji,jj,1) + 1._wp zdic = tr(ji,jj,1,jpdic,Kbb) - zph = MAX( hi(ji,jj,1), 1.e-10 ) / zfact + zph = MAX( hi(ji,jj,1), 1.e-10 ) / ( zrhd + rtrn ) ! CALCULATE [H2CO3] zh2co3(ji,jj) = zdic/(1. + ak13(ji,jj,1)/zph + ak13(ji,jj,1)*ak23(ji,jj,1)/zph**2) END_2D diff --git a/src/TOP/PISCES/P4Z/p4zlys.F90 b/src/TOP/PISCES/P4Z/p4zlys.F90 index df54a757dcde41e536a4691c70807d27027536e9..007835e179b9aed11fd54f31bedf6e3bc42d167e 100644 --- a/src/TOP/PISCES/P4Z/p4zlys.F90 +++ b/src/TOP/PISCES/P4Z/p4zlys.F90 @@ -11,6 +11,7 @@ MODULE p4zlys !! ! 2011-02 (J. Simeon, J. Orr) Calcon salinity dependence !! 3.4 ! 2011-06 (O. Aumont, C. Ethe) Improvment of calcite dissolution !! 3.6 ! 2015-05 (O. Aumont) PISCES quota + !! 4.2 ! 2020 (J. ORR ) rhop is replaced by "in situ density" rhd !!---------------------------------------------------------------------- !! p4z_lys : Compute the CaCO3 dissolution !! p4z_lys_init : Read the namelist parameters @@ -32,13 +33,17 @@ MODULE p4zlys REAL(wp), PUBLIC :: nca !: order of reaction for calcite dissolution INTEGER :: rmtss ! number of seconds per month - REAL(wp) :: calcon = 1.03E-2 ! mean calcite concentration [Ca2+] in sea water [mole/kg solution] - + + !! * Module variables + REAL(wp) :: calcon = 1.03E-2 !: mean calcite concentration [Ca2+] in sea water [mole/kg solution] + ! J. ORR: Made consistent with mocsy's choice based on literature review from Munhoven +! REAL(wp) :: calcon = 1.0287E-2 !: mean calcite concentration [Ca2+] in sea water [mole/kg solution] + !! * Substitutions # include "do_loop_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/TOP 4.0 , NEMO Consortium (2018) - !! $Id: p4zlys.F90 15287 2021-09-24 11:11:02Z cetlod $ + !! $Id: p4zlys.F90 15532 2021-11-24 11:47:32Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- @@ -58,7 +63,7 @@ CONTAINS INTEGER, INTENT(in) :: Kbb, Krhs ! time level indices ! INTEGER :: ji, jj, jk, jn - REAL(wp) :: zdispot, zfact, zcalcon + REAL(wp) :: zdispot, zrhd, zcalcon REAL(wp) :: zomegaca, zexcess, zexcess0, zkd CHARACTER (len=25) :: charout REAL(wp), DIMENSION(jpi,jpj,jpk) :: zco3, zcaldiss, zhinit, zhi, zco3sat @@ -66,7 +71,8 @@ CONTAINS ! IF( ln_timing ) CALL timing_start('p4z_lys') ! - zhinit (:,:,:) = hi(:,:,:) * 1000. / ( rhop(:,:,:) + rtrn ) + + zhinit (:,:,:) = hi(:,:,:) / ( rhd(:,:,:) + 1._wp ) ! ! ------------------------------------------- ! COMPUTE [CO3--] and [H+] CONCENTRATIONS @@ -76,7 +82,7 @@ CONTAINS DO_3D( nn_hls, nn_hls, nn_hls, nn_hls, 1, jpkm1) zco3(ji,jj,jk) = tr(ji,jj,jk,jpdic,Kbb) * ak13(ji,jj,jk) * ak23(ji,jj,jk) / (zhi(ji,jj,jk)**2 & & + ak13(ji,jj,jk) * zhi(ji,jj,jk) + ak13(ji,jj,jk) * ak23(ji,jj,jk) + rtrn ) - hi (ji,jj,jk) = zhi(ji,jj,jk) * rhop(ji,jj,jk) / 1000. + hi (ji,jj,jk) = zhi(ji,jj,jk) * ( rhd(ji,jj,jk) + 1._wp ) END_3D ! --------------------------------------------------------- @@ -88,11 +94,11 @@ CONTAINS DO_3D( nn_hls, nn_hls, nn_hls, nn_hls, 1, jpkm1) ! DEVIATION OF [CO3--] FROM SATURATION VALUE - ! Salinity dependance in zomegaca and divide by rhop/1000 to have good units + ! Salinity dependance in zomegaca and divide by rhd to have good units zcalcon = calcon * ( salinprac(ji,jj,jk) / 35._wp ) - zfact = rhop(ji,jj,jk) / 1000._wp - zomegaca = ( zcalcon * zco3(ji,jj,jk) ) / ( aksp(ji,jj,jk) * zfact + rtrn ) - zco3sat(ji,jj,jk) = aksp(ji,jj,jk) * zfact / ( zcalcon + rtrn ) + zrhd = rhd(ji,jj,jk) + 1._wp + zomegaca = ( zcalcon * zco3(ji,jj,jk) ) / ( aksp(ji,jj,jk) * zrhd + rtrn ) + zco3sat(ji,jj,jk) = aksp(ji,jj,jk) * zrhd / ( zcalcon + rtrn ) ! SET DEGREE OF UNDER-/SUPERSATURATION excess(ji,jj,jk) = 1._wp - zomegaca diff --git a/src/TOP/TRP/trcadv.F90 b/src/TOP/TRP/trcadv.F90 index c6ceff31d8bcc47266de8e4a3d50888b8328a289..86776d8784ecf5cd192ec8e6917b8d0642f096ad 100644 --- a/src/TOP/TRP/trcadv.F90 +++ b/src/TOP/TRP/trcadv.F90 @@ -7,6 +7,7 @@ MODULE trcadv !! 3.0 ! 2010-06 (C. Ethe) Adapted to passive tracers !! 3.7 ! 2014-05 (G. Madec, C. Ethe) Add 2nd/4th order cases for CEN and FCT schemes !! 4.0 ! 2017-09 (G. Madec) remove vertical time-splitting option + !! 4.5 ! 2021-08 (G. Madec, S. Techene) add advective velocities as optional arguments !!---------------------------------------------------------------------- #if defined key_top !!---------------------------------------------------------------------- @@ -35,7 +36,7 @@ MODULE trcadv IMPLICIT NONE PRIVATE - PUBLIC trc_adv ! called by trctrp.F90 + PUBLIC trc_adv ! called by trctrp.F90 and stprk3_stg.F90 PUBLIC trc_adv_ini ! called by trcini.F90 ! !!* Namelist namtrc_adv * @@ -44,7 +45,7 @@ MODULE trcadv INTEGER :: nn_cen_h, nn_cen_v ! =2/4 : horizontal and vertical choices of the order of CEN scheme LOGICAL :: ln_trcadv_fct ! FCT scheme flag INTEGER :: nn_fct_h, nn_fct_v ! =2/4 : horizontal and vertical choices of the order of FCT scheme - LOGICAL :: ln_trcadv_mus ! MUSCL scheme flag + LOGICAL, PUBLIC :: ln_trcadv_mus ! MUSCL scheme flag LOGICAL :: ln_mus_ups ! use upstream scheme in vivcinity of river mouths LOGICAL :: ln_trcadv_ubs ! UBS scheme flag INTEGER :: nn_ubs_v ! =2/4 : vertical choice of the order of UBS scheme @@ -58,31 +59,35 @@ MODULE trcadv INTEGER, PARAMETER :: np_MUS = 3 ! MUSCL scheme INTEGER, PARAMETER :: np_UBS = 4 ! 3rd order Upstream Biased Scheme INTEGER, PARAMETER :: np_QCK = 5 ! QUICK scheme - + + !! * Substitutions +# include "do_loop_substitute.h90" !! * Substitutions # include "do_loop_substitute.h90" # include "domzgr_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/TOP 4.0 , NEMO Consortium (2018) - !! $Id: trcadv.F90 15073 2021-07-02 14:20:14Z clem $ + !! $Id: trcadv.F90 15510 2021-11-15 15:33:37Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS - SUBROUTINE trc_adv( kt, Kbb, Kmm, ptr, Krhs ) + SUBROUTINE trc_adv( kt, Kbb, Kmm, ptr, Krhs, pau, pav, paw ) !!---------------------------------------------------------------------- !! *** ROUTINE trc_adv *** !! !! ** Purpose : compute the ocean tracer advection trend. !! - !! ** Method : - Update after tracers (tr(Krhs)) with the advection term following nadv + !! ** Method : - Update tr(Krhs) with the advective trend following nadv !!---------------------------------------------------------------------- - INTEGER , INTENT(in) :: kt ! ocean time-step index - INTEGER , INTENT(in) :: Kbb, Kmm, Krhs ! time level indices - REAL(wp), DIMENSION(jpi,jpj,jpk,jptra,jpt), INTENT(inout) :: ptr ! passive tracers and RHS of tracer equation + INTEGER , INTENT(in ) :: kt ! ocean time-step index + INTEGER , INTENT(in ) :: Kbb, Kmm, Krhs ! time level indices + REAL(wp), DIMENSION(:,:,:), OPTIONAL, TARGET, INTENT(in ) :: pau, pav, paw ! advective velocity + REAL(wp), DIMENSION(jpi,jpj,jpk,jptra,jpt) , INTENT(inout) :: ptr ! passive tracers and RHS of tracer equation ! INTEGER :: ji, jj, jk ! dummy loop index CHARACTER (len=22) :: charout + REAL(wp), DIMENSION(:,:,:), POINTER :: zptu, zptv, zptw REAL(wp), DIMENSION(jpi,jpj,jpk) :: zuu, zvv, zww ! effective velocity !!---------------------------------------------------------------------- ! @@ -105,21 +110,32 @@ CONTAINS DO_2D( nn_hls-1, nn_hls-1, nn_hls-1, nn_hls-1 ) zww(ji,jj,jpk) = 0._wp END_2D + ! + IF( PRESENT( pau ) ) THEN ! RK3: advective velocity (pau,pav,paw) /= advected velocity (uu,vv,ww) + zptu => pau(:,:,:) + zptv => pav(:,:,:) + zptw => paw(:,:,:) + ELSE ! MLF: advective velocity = (uu,vv,ww) + zptu => uu(:,:,:,Kmm) + zptv => vv(:,:,:,Kmm) + zptw => ww(:,:,: ) + ENDIF + ! IF( ln_wave .AND. ln_sdw ) THEN DO_3D( nn_hls, nn_hls-1, nn_hls, nn_hls-1, 1, jpkm1 ) ! eulerian transport + Stokes Drift - zuu(ji,jj,jk) = e2u (ji,jj) * e3u(ji,jj,jk,Kmm) * ( uu(ji,jj,jk,Kmm) + usd(ji,jj,jk) ) - zvv(ji,jj,jk) = e1v (ji,jj) * e3v(ji,jj,jk,Kmm) * ( vv(ji,jj,jk,Kmm) + vsd(ji,jj,jk) ) + zuu(ji,jj,jk) = e2u (ji,jj) * e3u(ji,jj,jk,Kmm) * ( zptu(ji,jj,jk) + usd(ji,jj,jk) ) + zvv(ji,jj,jk) = e1v (ji,jj) * e3v(ji,jj,jk,Kmm) * ( zptv(ji,jj,jk) + vsd(ji,jj,jk) ) END_3D DO_3D( nn_hls-1, nn_hls-1, nn_hls-1, nn_hls-1, 1, jpkm1 ) - zww(ji,jj,jk) = e1e2t(ji,jj) * ( ww(ji,jj,jk) + wsd(ji,jj,jk) ) + zww(ji,jj,jk) = e1e2t(ji,jj) * ( zptw(ji,jj,jk) + wsd(ji,jj,jk) ) END_3D ELSE DO_3D( nn_hls, nn_hls-1, nn_hls, nn_hls-1, 1, jpkm1 ) - zuu(ji,jj,jk) = e2u (ji,jj) * e3u(ji,jj,jk,Kmm) * uu(ji,jj,jk,Kmm) ! eulerian transport - zvv(ji,jj,jk) = e1v (ji,jj) * e3v(ji,jj,jk,Kmm) * vv(ji,jj,jk,Kmm) + zuu(ji,jj,jk) = e2u (ji,jj) * e3u(ji,jj,jk,Kmm) * zptu(ji,jj,jk) ! eulerian transport + zvv(ji,jj,jk) = e1v (ji,jj) * e3v(ji,jj,jk,Kmm) * zptv(ji,jj,jk) END_3D DO_3D( nn_hls-1, nn_hls-1, nn_hls-1, nn_hls-1, 1, jpkm1 ) - zww(ji,jj,jk) = e1e2t(ji,jj) * ww(ji,jj,jk) + zww(ji,jj,jk) = e1e2t(ji,jj) * zptw(ji,jj,jk) END_3D ENDIF ! diff --git a/src/TOP/TRP/trcatf.F90 b/src/TOP/TRP/trcatf.F90 index ea202b338aaca155611d66117bcf535274f61b5c..9a2f4e2ed9b169e71e86e0092b57d9ac5e9678db 100644 --- a/src/TOP/TRP/trcatf.F90 +++ b/src/TOP/TRP/trcatf.F90 @@ -20,7 +20,7 @@ MODULE trcatf !! 3.3 ! 2010-06 (C. Ethe, G. Madec) Merge TRA-TRC !! 4.1 ! 2019-08 (A. Coward, D. Storkey) rename trcnxt.F90 -> trcatf.F90. Now only does time filtering. !!---------------------------------------------------------------------- -#if defined key_top +#if defined key_top && ! defined key_RK3 !!---------------------------------------------------------------------- !! 'key_top' TOP models !!---------------------------------------------------------------------- @@ -57,7 +57,7 @@ MODULE trcatf # include "domzgr_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/TOP 4.0 , NEMO Consortium (2018) - !! $Id: trcatf.F90 15090 2021-07-06 14:25:18Z cetlod $ + !! $Id: trcatf.F90 15373 2021-10-14 17:01:57Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS @@ -99,7 +99,7 @@ CONTAINS ENDIF ! #if defined key_agrif - CALL Agrif_trc ! AGRIF zoom boundaries + CALL Agrif_trc( kt ) ! AGRIF zoom boundaries #endif ! Update after tracer on domain lateral boundaries CALL lbc_lnk( 'trcatf', ptr(:,:,:,:,Kaa), 'T', 1._wp ) diff --git a/src/TOP/TRP/trcrad.F90 b/src/TOP/TRP/trcrad.F90 index 92578a8a811bfadc9a6583a1bf504cef315c6311..21766f4bad0e9ec98c45f3cb27802480616189a5 100644 --- a/src/TOP/TRP/trcrad.F90 +++ b/src/TOP/TRP/trcrad.F90 @@ -34,7 +34,7 @@ MODULE trcrad # include "do_loop_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/TOP 4.0 , NEMO Consortium (2018) - !! $Id: trcrad.F90 13324 2020-07-17 19:47:48Z acc $ + !! $Id: trcrad.F90 15561 2021-11-30 13:25:02Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS @@ -148,9 +148,14 @@ CONTAINS IF( l_trdtrc ) ALLOCATE( ztrtrd(jpi,jpj,jpk) ) zs2rdt = 1. / ( 2. * rn_Dt ) ! +#if ! defined key_RK3 DO jt = 1,2 ! Loop over time indices since exactly the same fix is applied to "now" and "after" fields IF( jt == 1 ) itime = Kbb IF( jt == 2 ) itime = Kmm +#else + DO jt = 1,1 ! Loop over time indices since exactly the same fix is applied to "now" and "after" fields + IF( jt == 1 ) itime = Kmm +#endif IF( PRESENT( cpreserv ) ) THEN !== total tracer concentration is preserved ==! ! diff --git a/src/TOP/TRP/trcsbc.F90 b/src/TOP/TRP/trcsbc.F90 index b97f13599ebb62de20048ed0da53a3498dceec27..f817b677b011d92edd8a7515e009f0f22f2a0272 100644 --- a/src/TOP/TRP/trcsbc.F90 +++ b/src/TOP/TRP/trcsbc.F90 @@ -16,9 +16,9 @@ MODULE trcsbc !! trc_sbc : update the tracer trend at ocean surface !!---------------------------------------------------------------------- USE par_trc ! need jptra, number of passive tracers - USE oce_trc ! ocean dynamics and active tracers variables - USE trc ! ocean passive tracers variables - USE prtctl ! Print control for debbuging + USE oce_trc ! ocean dynamics and active tracers variables + USE trc ! ocean passive tracers variables + USE prtctl ! Print control for debbuging USE iom USE trd_oce USE trdtra @@ -26,14 +26,15 @@ MODULE trcsbc IMPLICIT NONE PRIVATE - PUBLIC trc_sbc ! routine called by step.F90 + PUBLIC trc_sbc ! routine called by trctrp.F90 + PUBLIC trc_sbc_RK3 ! routine called by stprk3_stg.F90 !! * Substitutions # include "do_loop_substitute.h90" # include "domzgr_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/TOP 4.0 , NEMO Consortium (2018) - !! $Id: trcsbc.F90 15394 2021-10-18 10:55:29Z cetlod $ + !! $Id: trcsbc.F90 15532 2021-11-24 11:47:32Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS @@ -210,6 +211,185 @@ CONTAINS ! END SUBROUTINE trc_sbc + + SUBROUTINE trc_sbc_RK3 ( kt, Kmm, ptr, Krhs, kstg ) + !!---------------------------------------------------------------------- + !! *** ROUTINE trc_sbc_RK3 *** + !! + !! ** Purpose : Compute the tracer surface boundary condition trend of + !! (concentration/dilution effect) and add it to the general + !! trend of tracer equations. + !! + !! ** Method : + !! * concentration/dilution effect: + !! The surface freshwater flux modify the ocean volume + !! and thus the concentration of a tracer as : + !! tr(Krhs) = tr(Krhs) + emp * tr(Kmm) / e3t_ for k=1 + !! where emp, the surface freshwater budget (evaporation minus + !! precipitation ) given in kg/m2/s is divided + !! by 1035 kg/m3 (density of ocean water) to obtain m/s. + !! + !! ** Action : - Update the 1st level of tr(:,:,:,:,Krhs) with the trend associated + !! with the tracer surface boundary condition + !! + !!---------------------------------------------------------------------- + INTEGER , INTENT(in ) :: kt, Kmm, Krhs ! ocean time-step and time-level indices + INTEGER , INTENT(in ) :: kstg ! RK3 stage index + REAL(wp), DIMENSION(jpi,jpj,jpk,jptra,jpt), INTENT(inout) :: ptr ! passive tracers and RHS of tracer equation + ! + INTEGER :: ji, jj, jn ! dummy loop indices + REAL(wp) :: z1_rho0_e3t ! local scalars + REAL(wp) :: zftra, zdtra, ztfx ! - - + CHARACTER (len=22) :: charout + REAL(wp), ALLOCATABLE, DIMENSION(:,:,:) :: ztrtrd + !!--------------------------------------------------------------------- + ! + IF( ln_timing ) CALL timing_start('trc_sbc_RK3') + ! + IF( kt == nittrc000 ) THEN + IF(lwp) WRITE(numout,*) + IF(lwp) WRITE(numout,*) 'trc_sbc_RK3 : Passive tracers surface boundary condition' + IF(lwp) WRITE(numout,*) '~~~~~~~~~~~ ' + ENDIF + ! +!!st note that trc_sbc can be removed only re-use in atf (not relevant for RK3) + SELECT CASE( kstg ) + ! + CASE( 1 , 2 ) != stage 1 and 2 =! only in non linear ssh + ! + IF( .NOT.ln_linssh ) THEN !* only passive tracer fluxes associated with mass fluxes + ! ! no passive tracer concentration modification due to ssh variation +!!st emp includes fmm see iceupdate.F90 +!!not sure about trc_i case... (1) + DO jn = 1, jptra + DO_2D( 0, 0, 0, 0 ) !!st WHY 1 : exterior here ? + z1_rho0_e3t = r1_rho0 / e3t(ji,jj,1,Kmm) + ptr(ji,jj,1,jn,Krhs) = ptr(ji,jj,1,jn,Krhs) - emp(ji,jj) * ptr(ji,jj,1,jn,Kmm) * z1_rho0_e3t + END_2D + END DO + ! + ENDIF + ! + CASE( 3 ) + ! + ! Allocate temporary workspace + IF( l_trdtrc ) ALLOCATE( ztrtrd(jpi,jpj,jpk) ) + ! + DO jn = 1, jptra + IF( l_trdtrc ) ztrtrd(:,:,:) = ptr(:,:,:,jn,Krhs) ! save trends + END DO + ! + IF( ln_linssh ) THEN !* linear free surface (add concentration/dilution effect artificially since no volume variation) + ! + SELECT CASE ( nn_ice_tr ) + ! + CASE ( -1 ) ! No tracers in sea ice (null concentration in sea ice) + ! + DO jn = 1, jptra + DO_2D( 0, 0, 0, 0 ) + z1_rho0_e3t = r1_rho0 / e3t(ji,jj,1,Kmm) + ptr(ji,jj,1,jn,Krhs) = ptr(ji,jj,1,jn,Krhs) + emp(ji,jj) * r1_rho0 * ptr(ji,jj,1,jn,Kmm) + END_2D + END DO + ! + CASE ( 0 ) ! Same concentration in sea ice and in the ocean fmm contribution to concentration/dilution effect has to be removed + ! + DO jn = 1, jptra + DO_2D( 0, 0, 0, 1 ) + z1_rho0_e3t = r1_rho0 / e3t(ji,jj,1,Kmm) + ptr(ji,jj,1,jn,Krhs) = ptr(ji,jj,1,jn,Krhs) + ( emp(ji,jj) - fmmflx(ji,jj) ) * r1_rho0 * ptr(ji,jj,1,jn,Kmm) + END_2D + END DO + ! + CASE ( 1 ) ! Specific treatment of sea ice fluxes with an imposed concentration in sea ice !!st TODO : check Christian new implementation + ! + DO jn = 1, jptra + DO_2D( 0, 0, 0, 0 ) + z1_rho0_e3t = r1_rho0 / e3t(ji,jj,1,Kmm) + ! tracer flux at the ice/ocean interface (tracer/m2/s) + zftra = - trc_i(ji,jj,jn) * fmmflx(ji,jj) ! uptake of tracer in the sea ice + ! ! only used in the levitating sea ice case + ! tracer flux only : add concentration dilution term in net tracer flux, no F-M in volume flux + ! tracer and mass fluxes : no concentration dilution term in net tracer flux, F-M term in volume flux + ztfx = zftra ! net tracer flux + ! + zdtra = r1_rho0 * ( ztfx + ( emp(ji,jj) - fmmflx(ji,jj) ) * ptr(ji,jj,1,jn,Kmm) ) + IF ( zdtra < 0. ) THEN + zdtra = MAX(zdtra, -ptr(ji,jj,1,jn,Kmm) * e3t(ji,jj,1,Kmm) / rDt_trc ) ! avoid negative concentrations to arise + ENDIF + ptr(ji,jj,1,jn,Krhs) = ptr(ji,jj,1,jn,Krhs) + zdtra + END_2D + END DO + ! + END SELECT + ! + ELSE !* non linear free surface (concentration/dilution effect due to volume variation) + ! + SELECT CASE ( nn_ice_tr ) + ! CASE ( -1 ) natural concentration/dilution effect due to volume variation : nothing to do + ! + CASE ( 0 ) ! Same concentration in sea ice and in the ocean : correct concentration/dilution effect due to "freezing - melting" + ! + DO jn = 1, jptra + DO_2D( 0, 0, 0, 1 ) + z1_rho0_e3t = r1_rho0 / e3t(ji,jj,1,Kmm) + ptr(ji,jj,1,jn,Krhs) = ptr(ji,jj,1,jn,Krhs) - fmmflx(ji,jj) * r1_rho0 * ptr(ji,jj,1,jn,Kmm) + END_2D + END DO + ! + CASE ( 1 ) ! Specific treatment of sea ice fluxes with an imposed concentration in sea ice + ! + DO jn = 1, jptra + DO_2D( 0, 0, 0, 0 ) + ! tracer flux at the ice/ocean interface (tracer/m2/s) + zftra = - trc_i(ji,jj,jn) * fmmflx(ji,jj) ! uptake of tracer in the sea ice + ! ! only used in the levitating sea ice case + ! tracer flux only : add concentration dilution term in net tracer flux, no F-M in volume flux + ! tracer and mass fluxes : no concentration dilution term in net tracer flux, F-M term in volume flux + ztfx = zftra ! net tracer flux + ! + zdtra = r1_rho0 * ( ztfx - fmmflx(ji,jj) * ptr(ji,jj,1,jn,Kmm) ) + IF ( zdtra < 0. ) THEN + zdtra = MAX(zdtra, -ptr(ji,jj,1,jn,Kmm) * e3t(ji,jj,1,Kmm) / rDt_trc ) ! avoid negative concentrations to arise + ENDIF + ptr(ji,jj,1,jn,Krhs) = ptr(ji,jj,1,jn,Krhs) + zdtra + END_2D + END DO + ! + END SELECT + ! + ENDIF + ! + ! +!!st useless trc_sbc only in the interior even in MLF case CALL lbc_lnk( 'trcsbc', sbc_trc(:,:,:), 'T', 1.0_wp ) + ! Concentration dilution effect on tracers due to evaporation & precipitation + DO jn = 1, jptra + ! + IF(lwp) WRITE(numout,*) + IF(lwp) WRITE(numout,*) 'trc_sbc_RK3 : Runge Kutta 3rd order at stage ', kstg, jn + IF(lwp) WRITE(numout,*) + ! + IF( l_trdtrc ) THEN + ztrtrd(:,:,:) = ptr(:,:,:,jn,Krhs) - ztrtrd(:,:,:) + CALL trd_tra( kt, Kmm, Krhs, 'TRC', jn, jptra_nsr, ztrtrd ) + END IF + ! + END DO + ! + IF( l_trdtrc ) DEALLOCATE( ztrtrd ) + ! + END SELECT + ! + IF( sn_cfctl%l_prttrc ) THEN + WRITE(charout, FMT="('sbc ')") ; CALL prt_ctl_info( charout, cdcomp = 'top' ) + CALL prt_ctl( tab4d_1=ptr(:,:,:,:,Krhs), mask1=tmask, clinfo=ctrcnm, clinfo3='trd' ) + ENDIF + ! + IF( ln_timing ) CALL timing_stop('trc_sbc_RK3') + ! + END SUBROUTINE trc_sbc_RK3 + + #else !!---------------------------------------------------------------------- !! Dummy module : NO passive tracer diff --git a/src/TOP/TRP/trctrp.F90 b/src/TOP/TRP/trctrp.F90 index fd5b95dab34a38d16a1a33656e09e12c563e276e..f164444ed42f6aefe1428a0e3ce8413d35aaea49 100644 --- a/src/TOP/TRP/trctrp.F90 +++ b/src/TOP/TRP/trctrp.F90 @@ -5,6 +5,7 @@ MODULE trctrp !!====================================================================== !! History : 1.0 ! 2004-03 (C. Ethe) Original code !! 3.3 ! 2010-07 (C. Ethe) Merge TRA-TRC + !! 4.x ! 2021-08 (S. Techene, G. Madec) Adapt for RK3 time-stepping !!---------------------------------------------------------------------- #if defined key_top !!---------------------------------------------------------------------- @@ -32,16 +33,19 @@ MODULE trctrp #if defined key_agrif USE agrif_top_sponge ! tracers sponges +# if defined key_RK3 + USE agrif_top_interp +# endif #endif IMPLICIT NONE PRIVATE - PUBLIC trc_trp ! called by trc_stp + PUBLIC trc_trp ! called by trc_stp and stprk3_stg !!---------------------------------------------------------------------- !! NEMO/TOP 4.0 , NEMO Consortium (2018) - !! $Id: trctrp.F90 15023 2021-06-18 14:35:25Z gsamson $ + !! $Id: trctrp.F90 15373 2021-10-14 17:01:57Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- @@ -71,7 +75,9 @@ CONTAINS ENDIF ENDIF ! +#if ! defined key_RK3 CALL trc_sbc ( kt, Kmm, tr, Krhs ) ! surface boundary condition +#endif IF( ln_trcbc .AND. lltrcbc .AND. kt /= nit000 ) & CALL trc_bc ( kt, Kmm, tr, Krhs ) ! tracers: surface and lateral Boundary Conditions IF( ln_trcais ) CALL trc_ais ( kt, Kmm, tr, Krhs ) ! tracers from Antarctic Ice Sheet (icb, isf) @@ -81,10 +87,25 @@ CONTAINS #if defined key_agrif IF(.NOT. Agrif_Root()) CALL Agrif_Sponge_trc ! tracers sponge #endif - CALL trc_adv ( kt, Kbb, Kmm, tr, Krhs ) ! horizontal & vertical advection +#if ! defined key_RK3 + ! ! MLF only: add the advection trend to the RHS + CALL trc_adv ( kt, Kbb, Kmm, tr, Krhs ) ! horizontal & vertical advection +#endif CALL trc_ldf ( kt, Kbb, Kmm, tr, Krhs ) ! lateral mixing CALL trc_zdf ( kt, Kbb, Kmm, Krhs, tr, Kaa ) ! vert. mixing & after tracer ==> after - CALL trc_atf ( kt, Kbb, Kmm, Kaa , tr ) ! time filtering of "now" tracer fields +#if defined key_RK3 + ! ! RK3: only manage lateral boundary +# if defined key_agrif + CALL Agrif_trc ( kt ) ! AGRIF zoom boundaries +# endif + ! ! Update after tracer on domain lateral boundaries + CALL lbc_lnk( 'stprk3_stg', tr(:,:,:,:,Kaa), 'T', 1._wp ) + ! + IF( ln_bdy ) CALL trc_bdy ( kt, Kbb, Kmm, Kaa ) +#else + ! ! MLF: apply Asselin time filter and manage lateral boundary + CALL trc_atf ( kt, Kbb, Kmm, Kaa , tr ) ! time filtering of "now" tracer fields +#endif ! ! Subsequent calls use the filtered values: Kmm and Kaa ! These are used explicitly here since time levels will not be swapped until after tra_atf/dyn_atf/ssh_atf in stp diff --git a/src/TOP/oce_trc.F90 b/src/TOP/oce_trc.F90 index 4439665d10faa5038612753a0297747b6db00b78..7745fc71328e0e950e428bd4c4491ec121b266ff 100644 --- a/src/TOP/oce_trc.F90 +++ b/src/TOP/oce_trc.F90 @@ -42,7 +42,6 @@ MODULE oce_trc USE oce , ONLY : vv => vv !: j-horizontal velocity (m s-1) USE oce , ONLY : ww => ww !: vertical velocity (m s-1) USE oce , ONLY : ts => ts !: 4D array contaning ( tn, sn ) - USE oce , ONLY : rhop => rhop !: potential volumic mass (kg m-3) USE oce , ONLY : rhd => rhd !: in situ density anomalie rhd=(rho-rho0)/rho0 (no units) USE oce , ONLY : hdiv => hdiv !: horizontal divergence (1/s) USE oce , ONLY : ssh => ssh !: sea surface height at t-point [m] diff --git a/src/TOP/trcbc.F90 b/src/TOP/trcbc.F90 index 924a6f0764f54003cc16780cb3763477586ec5b1..fc829d8db5b806c8ad2e6edffc680a788ae91800 100644 --- a/src/TOP/trcbc.F90 +++ b/src/TOP/trcbc.F90 @@ -50,7 +50,7 @@ MODULE trcbc # include "domzgr_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/TOP 4.0 , NEMO Consortium (2018) - !! $Id: trcbc.F90 15446 2021-10-26 14:34:38Z cetlod $ + !! $Id: trcbc.F90 15511 2021-11-15 15:46:44Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS @@ -416,7 +416,11 @@ CONTAINS IF( ln_rnf_ctl .AND. .NOT.ln_trc_cbc(jn) ) THEN DO_2D( 0, 0, 0, 1 ) DO jk = 1, nk_rnf(ji,jj) +#if defined key_RK3 + zrnf = rnf(ji,jj) * r1_rho0 / h_rnf(ji,jj) +#else zrnf = (rnf(ji,jj) + rnf_b(ji,jj)) * 0.5_wp * r1_rho0 / h_rnf(ji,jj) +#endif ptr(ji,jj,jk,jn,Krhs) = ptr(ji,jj,jk,jn,Krhs) + (ptr(ji,jj,jk,jn,Kmm) * zrnf) END DO END_2D diff --git a/src/TOP/trcini.F90 b/src/TOP/trcini.F90 index 38ed39425d3ac4aeff275fb1cceb91a0198c25ad..394f1cd16b77cf421edafa76afb8f4bc25316cb7 100644 --- a/src/TOP/trcini.F90 +++ b/src/TOP/trcini.F90 @@ -35,7 +35,7 @@ MODULE trcini # include "domzgr_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/TOP 4.0 , NEMO Consortium (2018) - !! $Id: trcini.F90 15446 2021-10-26 14:34:38Z cetlod $ + !! $Id: trcini.F90 15514 2021-11-16 08:58:22Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS @@ -243,6 +243,8 @@ CONTAINS ! IF( ln_trcdta ) CALL trc_dta_ini( jptra ) ! set initial tracers values ! + tr(:,:,:,:,Kaa) = 0._wp + ! IF( ln_rsttr ) THEN ! restart from a file ! CALL trc_rst_read( Kbb, Kmm ) @@ -263,8 +265,6 @@ CONTAINS ! ENDIF ! - tr(:,:,:,:,Kaa) = 0._wp - ! IF( ln_trcbc .AND. lltrcbc ) THEN CALL trc_bc_ini ( jptra, Kmm ) ! set tracers Boundary Conditions CALL trc_bc ( nit000, Kmm, tr, Kaa ) ! tracers: surface and lateral Boundary Conditions diff --git a/src/TOP/trcrst.F90 b/src/TOP/trcrst.F90 index 40a0d964d15828a5dea7a47807f60b86dd57e348..78ff2bbc411c69ef4c6d0a2876f46de2579ad9fe 100644 --- a/src/TOP/trcrst.F90 +++ b/src/TOP/trcrst.F90 @@ -7,6 +7,7 @@ MODULE trcrst !! 1.0 ! 2005-03 (O. Aumont, A. El Moussaoui) F90 !! - ! 2005-10 (C. Ethe) print control !! 2.0 ! 2005-10 (C. Ethe, G. Madec) revised architecture + !! 4.x ! 2021-08 (S. Techene, G. Madec) RK3 time-stepping only deals with before read/write !!---------------------------------------------------------------------- #if defined key_top !!---------------------------------------------------------------------- @@ -36,7 +37,7 @@ MODULE trcrst # include "domzgr_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/TOP 4.0 , NEMO Consortium (2018) - !! $Id: trcrst.F90 14239 2020-12-23 08:57:16Z smasson $ + !! $Id: trcrst.F90 15321 2021-10-04 10:24:15Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS @@ -129,44 +130,50 @@ CONTAINS IF(lwp) WRITE(numout,*) '~~~~~~~~~~~~' ! READ prognostic variables and computes diagnostic variable - DO jn = 1, jptra +#if ! defined key_RK3 + DO jn = 1, jptra ! MLF only : Now time step CALL iom_get( numrtr, jpdom_auto, 'TRN'//ctrcnm(jn), tr(:,:,:,jn,Kmm) ) END DO - - DO jn = 1, jptra +#endif + DO jn = 1, jptra ! RK3 and MLF : Before time step CALL iom_get( numrtr, jpdom_auto, 'TRB'//ctrcnm(jn), tr(:,:,:,jn,Kbb) ) END DO ! IF(.NOT.lrxios) CALL iom_delay_rst( 'READ', 'TOP', numrtr ) ! read only TOP delayed global communication variables END SUBROUTINE trc_rst_read - SUBROUTINE trc_rst_wri( kt, Kbb, Kmm, Krhs ) + + SUBROUTINE trc_rst_wri( kt, Kbb, Kmm, Kaa ) !!---------------------------------------------------------------------- !! *** trc_rst_wri *** !! !! ** purpose : write passive tracer fields in restart files !!---------------------------------------------------------------------- INTEGER, INTENT( in ) :: kt ! ocean time-step index - INTEGER, INTENT( in ) :: Kbb, Kmm, Krhs ! time level indices + INTEGER, INTENT( in ) :: Kbb, Kmm, Kaa ! time level indices !! INTEGER :: jn !!---------------------------------------------------------------------- ! CALL iom_rstput( kt, nitrst, numrtw, 'rdttrc1', rn_Dt ) ! passive tracer time step (= ocean time step) ! prognostic variables - ! -------------------- - DO jn = 1, jptra - CALL iom_rstput( kt, nitrst, numrtw, 'TRN'//ctrcnm(jn), tr(:,:,:,jn,Kmm) ) + ! -------------------- +#if defined key_RK3 + DO jn = 1, jptra ! RK3 : After time step (before the swap) put in TRB + CALL iom_rstput( kt, nitrst, numrtw, 'TRB'//ctrcnm(jn), tr(:,:,:,jn,Kaa) ) END DO - - DO jn = 1, jptra - CALL iom_rstput( kt, nitrst, numrtw, 'TRB'//ctrcnm(jn), tr(:,:,:,jn,Kbb) ) +#else + DO jn = 1, jptra ! MLF : After time step (before the swap) put in TRN + CALL iom_rstput( kt, nitrst, numrtw, 'TRN'//ctrcnm(jn), tr(:,:,:,jn,Kaa) ) END DO - + DO jn = 1, jptra ! MLF : Now time step (before the swap) put in TRB + CALL iom_rstput( kt, nitrst, numrtw, 'TRB'//ctrcnm(jn), tr(:,:,:,jn,Kmm) ) + END DO +#endif IF( .NOT. lwxios ) CALL iom_delay_rst( 'WRITE', 'TOP', numrtw ) ! save only TOP delayed global communication variables IF( kt == nitrst ) THEN - CALL trc_rst_stat( Kmm, Krhs ) ! statistics + CALL trc_rst_stat( Kaa, Kbb ) ! statistics Kaa et Kbb IF(lwxios) THEN CALL iom_context_finalize( cw_toprst_cxt ) iom_file(numrtw)%nfid = 0 @@ -394,7 +401,7 @@ CONTAINS !!---------------------------------------------------------------------- !! NEMO/TOP 4.0 , NEMO Consortium (2018) - !! $Id: trcrst.F90 14239 2020-12-23 08:57:16Z smasson $ + !! $Id: trcrst.F90 15321 2021-10-04 10:24:15Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!====================================================================== END MODULE trcrst diff --git a/src/TOP/trcsms.F90 b/src/TOP/trcsms.F90 index b31abe68b5ae86d9acf9b443bd12d8a283748b6c..51ad94ba1d88487e8ebdfaae8c2cfc20b93e356b 100644 --- a/src/TOP/trcsms.F90 +++ b/src/TOP/trcsms.F90 @@ -28,7 +28,7 @@ MODULE trcsms !!---------------------------------------------------------------------- !! NEMO/TOP 4.0 , NEMO Consortium (2018) - !! $Id: trcsms.F90 13286 2020-07-09 15:48:29Z smasson $ + !! $Id: trcsms.F90 15373 2021-10-14 17:01:57Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS @@ -58,7 +58,11 @@ CONTAINS IF(sn_cfctl%l_prttrc) THEN ! print mean trends (used for debugging) WRITE(charout, FMT="('sms ')") CALL prt_ctl_info( charout, cdcomp = 'top' ) +#if defined key_RK3 + CALL prt_ctl( tab4d_1=tr(:,:,:,:,Krhs), mask1=tmask, clinfo=ctrcnm ) +#else CALL prt_ctl( tab4d_1=tr(:,:,:,:,Kmm), mask1=tmask, clinfo=ctrcnm ) +#endif ENDIF ! IF( ln_timing ) CALL timing_stop('trc_sms') diff --git a/src/TOP/trcstp.F90 b/src/TOP/trcstp.F90 index 124269c63a1107824dc2ff42089ed503bd7bdb4c..9d7e7574b1874c87bcd76144cbfd7bb97c7e6bff 100644 --- a/src/TOP/trcstp.F90 +++ b/src/TOP/trcstp.F90 @@ -6,7 +6,7 @@ MODULE trcstp !! History : 1.0 ! 2004-03 (C. Ethe) Original !! 4.1 ! 2019-08 (A. Coward, D. Storkey) rewrite in preparation for new timestepping scheme !!---------------------------------------------------------------------- -#if defined key_top +#if defined key_top && ! defined key_RK3 !!---------------------------------------------------------------------- !! trc_stp : passive tracer system time-stepping !!---------------------------------------------------------------------- @@ -29,7 +29,7 @@ MODULE trcstp IMPLICIT NONE PRIVATE - PUBLIC trc_stp ! called by step + PUBLIC trc_stp ! called by step or stpmlf LOGICAL :: llnew ! ??? REAL(wp) :: rdt_sampl ! ??? @@ -40,7 +40,7 @@ MODULE trcstp # include "domzgr_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/TOP 4.0 , NEMO Consortium (2018) - !! $Id: trcstp.F90 15446 2021-10-26 14:34:38Z cetlod $ + !! $Id: trcstp.F90 15191 2021-08-13 13:09:12Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS @@ -115,7 +115,9 @@ CONTAINS IF(lrxios) CALL iom_context_finalize( cr_toprst_cxt ) IF(lwm) CALL FLUSH( numont ) ! flush namelist output ENDIF - IF( lrst_trc ) CALL trc_rst_wri ( kt, Kmm, Kaa, Kbb ) ! write tracer restart file + IF( lrst_trc ) CALL trc_rst_wri ( kt, Kbb, Kmm, Kaa ) ! write tracer restart file +! IF( lrst_trc ) CALL trc_rst_wri ( kt, Kmm, Kaa, Kbb ) ! write tracer restart file + IF( lk_trdmxl_trc ) CALL trd_mxl_trc ( kt, Kaa ) ! trends: Mixed-layer ! IF( ln_top_euler ) THEN diff --git a/src/TOP/trcstp_rk3.F90 b/src/TOP/trcstp_rk3.F90 new file mode 100644 index 0000000000000000000000000000000000000000..450d4b5ed1adbb667939f233d34bf36796931c35 --- /dev/null +++ b/src/TOP/trcstp_rk3.F90 @@ -0,0 +1,291 @@ +MODULE trcstp_rk3 + !!====================================================================== + !! *** MODULE trcstp_rk3 *** + !! Time-stepping : time loop of opa for passive tracer + !!====================================================================== + !! History : 1.0 ! 2004-03 (C. Ethe) Original + !! 4.1 ! 2019-08 (A. Coward, D. Storkey) rewrite in preparation for new timestepping scheme + !! 4.x ! 2021-08 (S. Techene, G. Madec) preparation and finalisation for RK3 time-stepping only + !!---------------------------------------------------------------------- +#if defined key_top + !!---------------------------------------------------------------------- + !! trc_stp_start : prepare passive tracer system time-stepping + !! trc_stp_end : finalise passive tracer system time-stepping + !!---------------------------------------------------------------------- + USE par_trc ! need jptra, number of passive tracers + USE oce_trc ! ocean dynamics and active tracers variables + USE sbc_oce + USE trc + USE trctrp ! passive tracers transport + USE trcsms ! passive tracers sources and sinks + USE trcwri + USE trcrst + USE trdtrc_oce + USE trdmxl_trc + USE sms_pisces, ONLY : ln_check_mass + ! + USE prtctl ! Print control for debbuging + USE iom ! + USE in_out_manager ! + + IMPLICIT NONE + PRIVATE + + PUBLIC trc_stp_start ! called by stprk3_stg + PUBLIC trc_stp_end ! called by stprk3_stg + + LOGICAL :: llnew ! ??? + LOGICAL :: l_trcstat ! flag for tracer statistics + REAL(wp) :: rdt_sampl ! ??? + INTEGER :: nb_rec_per_day, ktdcy ! ??? + REAL(wp) :: rsecfst, rseclast ! ??? + REAL(wp), DIMENSION(:,:,:), SAVE, ALLOCATABLE :: qsr_arr ! save qsr during TOP time-step + +# include "domzgr_substitute.h90" + !!---------------------------------------------------------------------- + !! NEMO/TOP 4.0 , NEMO Consortium (2018) + !! $Id: trcstp.F90 14086 2020-12-04 11:37:14Z cetlod $ + !! Software governed by the CeCILL license (see ./LICENSE) + !!---------------------------------------------------------------------- +CONTAINS + + SUBROUTINE trc_stp_start( kt, Kbb, Kmm, Krhs, Kaa ) + !!------------------------------------------------------------------- + !! *** ROUTINE trc_stp_start *** + !! + !! ** Purpose : Prepare time loop of opa for passive tracer + !! + !! ** Method : Compute the passive tracers trends + !! Update the passive tracers + !! Manage restart file + !!------------------------------------------------------------------- + INTEGER, INTENT( in ) :: kt ! ocean time-step index + INTEGER, INTENT( in ) :: Kbb, Kmm, Krhs, Kaa ! time level indices + ! + INTEGER :: jk, jn ! dummy loop indices + CHARACTER (len=25) :: charout ! + !!------------------------------------------------------------------- + ! + IF( ln_timing ) CALL timing_start('trc_stp_start') + ! + l_trcstat = ( sn_cfctl%l_trcstat ) .AND. & + & ( ( MOD( kt, sn_cfctl%ptimincr ) == 0 ) .OR. ( kt == nitend ) ) + ! + IF( kt == nittrc000 ) CALL trc_stp_ctl ! control + IF( kt == nittrc000 .AND. lk_trdmxl_trc ) CALL trd_mxl_trc_init ! trends: Mixed-layer + ! + IF( .NOT.ln_linssh ) THEN ! update ocean volume due to ssh temporal evolution + DO jk = 1, jpk + cvol(:,:,jk) = e1e2t(:,:) * e3t(:,:,jk,Kmm) * tmask(:,:,jk) + END DO + IF( l_trcstat .OR. kt == nitrst .OR. ( ln_check_mass .AND. kt == nitend ) ) & + & areatot = glob_sum( 'trcstp', cvol(:,:,:) ) + ENDIF + ! + IF( l_trcdm2dc ) CALL trc_mean_qsr( kt ) + ! + IF(sn_cfctl%l_prttrc) THEN + WRITE(charout,FMT="('kt =', I4,' d/m/y =',I2,I2,I4)") kt, nday, nmonth, nyear + CALL prt_ctl_info( charout, cdcomp = 'top' ) + ENDIF + ! + CALL trc_rst_opn ( kt ) ! Open tracer restart file + IF( lrst_trc ) CALL trc_rst_cal ( kt, 'WRITE' ) ! calendar + ! + IF( ln_timing ) CALL timing_stop('trc_stp_start') + ! + END SUBROUTINE trc_stp_start + + + SUBROUTINE trc_stp_end( kt, Kbb, Kmm, Kaa ) + !!------------------------------------------------------------------- + !! *** ROUTINE trc_stp_end *** + !! + !! ** Purpose : Finalise time loop of opa for passive tracer + !! + !! ** Method : Write restart and outputs + !!------------------------------------------------------------------- + INTEGER, INTENT( in ) :: kt ! ocean time-step index + INTEGER, INTENT( in ) :: Kbb, Kmm, Kaa ! time level indices + ! + INTEGER :: jk, jn ! dummy loop indices + REAL(wp):: ztrai ! local scalar + CHARACTER (len=25) :: charout ! + !!------------------------------------------------------------------- + ! + IF( ln_timing ) CALL timing_start('trc_stp_end') + ! + ! + ! Note passive tracers have been time-filtered in trc_trp but the time level + ! indices will not be swapped until after tra_atf/dyn_atf/ssh_atf in stp. Subsequent calls here + ! anticipate this update which will be: Nrhs= Nbb ; Nbb = Nnn ; Nnn = Naa ; Naa = Nrhs + ! and use the filtered levels explicitly. + ! + IF( kt == nittrc000 ) THEN + CALL iom_close( numrtr ) ! close input tracer restart file + IF(lrxios) CALL iom_context_finalize( cr_toprst_cxt ) + IF(lwm) CALL FLUSH( numont ) ! flush namelist output + ENDIF + IF( lrst_trc ) CALL trc_rst_wri ( kt, Kbb, Kmm, Kaa ) ! write tracer restart file + IF( lk_trdmxl_trc ) CALL trd_mxl_trc ( kt, Kaa ) ! trends: Mixed-layer + ! + IF (l_trcstat) THEN + ztrai = 0._wp ! content of all tracers + DO jn = 1, jptra + ztrai = ztrai + glob_sum( 'trcstp_rk3', tr(:,:,:,jn,Kaa) * cvol(:,:,:) ) !!st cvol@Kmm weird !! + END DO + IF( lwm ) WRITE(numstr,9300) kt, ztrai / areatot + ENDIF + ! +9300 FORMAT(i10,D23.16) + ! + CALL trc_wri ( kt, Kaa ) ! output of passive tracers with iom I/O manager before time level swap + ! + IF( ln_timing ) CALL timing_stop('trc_stp_end') + ! + END SUBROUTINE trc_stp_end + + + SUBROUTINE trc_stp_ctl + !!---------------------------------------------------------------------- + !! *** ROUTINE trc_stp_ctl *** + !! ** Purpose : Control + ocean volume + !!---------------------------------------------------------------------- + ! + ! Define logical parameter ton control dirunal cycle in TOP + l_trcdm2dc = ln_dm2dc .OR. ( ln_cpl .AND. ncpl_qsr_freq /= 1 .AND. ncpl_qsr_freq /= 0 ) + l_trcdm2dc = l_trcdm2dc .AND. .NOT. l_offline + ! + IF( l_trcdm2dc .AND. lwp ) CALL ctl_warn( 'Coupling with passive tracers and used of diurnal cycle.', & + & 'Computation of a daily mean shortwave for some biogeochemical models ' ) + ! + END SUBROUTINE trc_stp_ctl + + + SUBROUTINE trc_mean_qsr( kt ) + !!---------------------------------------------------------------------- + !! *** ROUTINE trc_mean_qsr *** + !! + !! ** Purpose : Compute daily mean qsr for biogeochemical model in case + !! of diurnal cycle + !! + !! ** Method : store in TOP the qsr every hour ( or every time-step if the latter + !! is greater than 1 hour ) and then, compute the mean with + !! a moving average over 24 hours. + !! In coupled mode, the sampling is done at every coupling frequency + !!---------------------------------------------------------------------- + INTEGER, INTENT( in ) :: kt ! ocean time-step index + ! + INTEGER :: jn ! dummy loop indices + REAL(wp) :: zkt, zrec ! local scalars + CHARACTER(len=1) :: cl1 ! 1 character + CHARACTER(len=2) :: cl2 ! 2 characters + !!---------------------------------------------------------------------- + ! + IF( ln_timing ) CALL timing_start('trc_mean_qsr') + ! + IF( kt == nittrc000 ) THEN + IF( ln_cpl ) THEN + rdt_sampl = rday / ncpl_qsr_freq + nb_rec_per_day = ncpl_qsr_freq + ELSE + rdt_sampl = MAX( 3600., rn_Dt ) + nb_rec_per_day = INT( rday / rdt_sampl ) + ENDIF + ! + IF(lwp) THEN + WRITE(numout,*) + WRITE(numout,*) ' Sampling frequency dt = ', rdt_sampl, 's',' Number of sampling per day nrec = ', nb_rec_per_day + WRITE(numout,*) + ENDIF + ! + ALLOCATE( qsr_arr(jpi,jpj,nb_rec_per_day ) ) + ! + ! !* Restart: read in restart file + IF( ln_rsttr .AND. nn_rsttr /= 0 .AND. iom_varid( numrtr, 'qsr_mean' , ldstop = .FALSE. ) > 0 & + & .AND. iom_varid( numrtr, 'qsr_arr_1', ldstop = .FALSE. ) > 0 & + & .AND. iom_varid( numrtr, 'ktdcy' , ldstop = .FALSE. ) > 0 & + & .AND. iom_varid( numrtr, 'nrdcy' , ldstop = .FALSE. ) > 0 ) THEN + CALL iom_get( numrtr, 'ktdcy', zkt ) + rsecfst = INT( zkt ) * rn_Dt + IF(lwp) WRITE(numout,*) 'trc_qsr_mean: qsr_mean read in the restart file at time-step rsecfst =', rsecfst, ' s ' + CALL iom_get( numrtr, jpdom_auto, 'qsr_mean', qsr_mean ) ! A mean of qsr + CALL iom_get( numrtr, 'nrdcy', zrec ) ! Number of record per days + IF( INT( zrec ) == nb_rec_per_day ) THEN + DO jn = 1, nb_rec_per_day + IF( jn <= 9 ) THEN + WRITE(cl1,'(i1)') jn + CALL iom_get( numrtr, jpdom_auto, 'qsr_arr_'//cl1, qsr_arr(:,:,jn) ) ! A mean of qsr + ELSE + WRITE(cl2,'(i2.2)') jn + CALL iom_get( numrtr, jpdom_auto, 'qsr_arr_'//cl2, qsr_arr(:,:,jn) ) ! A mean of qsr + ENDIF + END DO + ELSE + DO jn = 1, nb_rec_per_day + qsr_arr(:,:,jn) = qsr_mean(:,:) + END DO + ENDIF + ELSE !* no restart: set from nit000 values + IF(lwp) WRITE(numout,*) 'trc_qsr_mean: qsr_mean set to nit000 values' + rsecfst = kt * rn_Dt + ! + qsr_mean(:,:) = qsr(:,:) + DO jn = 1, nb_rec_per_day + qsr_arr(:,:,jn) = qsr_mean(:,:) + END DO + ENDIF + ! + ENDIF + ! + rseclast = kt * rn_Dt + ! + llnew = ( rseclast - rsecfst ) >= rdt_sampl ! new shortwave to store + IF( llnew ) THEN + ktdcy = kt + IF( lwp .AND. kt < nittrc000 + 100 ) WRITE(numout,*) ' New shortwave to sample for TOP at time kt = ', ktdcy, & + & ' time = ', rseclast/3600.,'hours ' + rsecfst = rseclast + DO jn = 1, nb_rec_per_day - 1 + qsr_arr(:,:,jn) = qsr_arr(:,:,jn+1) + END DO + qsr_arr (:,:,nb_rec_per_day) = qsr(:,:) + qsr_mean(:,: ) = SUM( qsr_arr(:,:,:), 3 ) / nb_rec_per_day + ENDIF + ! + IF( lrst_trc ) THEN !* Write the mean of qsr in restart file + IF(lwp) WRITE(numout,*) + IF(lwp) WRITE(numout,*) 'trc_mean_qsr : write qsr_mean in restart file kt =', kt + IF(lwp) WRITE(numout,*) '~~~~~~~' + zkt = REAL( ktdcy, wp ) + zrec = REAL( nb_rec_per_day, wp ) + CALL iom_rstput( kt, nitrst, numrtw, 'ktdcy', zkt ) + CALL iom_rstput( kt, nitrst, numrtw, 'nrdcy', zrec ) + DO jn = 1, nb_rec_per_day + IF( jn <= 9 ) THEN + WRITE(cl1,'(i1)') jn + CALL iom_rstput( kt, nitrst, numrtw, 'qsr_arr_'//cl1, qsr_arr(:,:,jn) ) + ELSE + WRITE(cl2,'(i2.2)') jn + CALL iom_rstput( kt, nitrst, numrtw, 'qsr_arr_'//cl2, qsr_arr(:,:,jn) ) + ENDIF + END DO + CALL iom_rstput( kt, nitrst, numrtw, 'qsr_mean', qsr_mean(:,:) ) + ENDIF + ! + IF( ln_timing ) CALL timing_stop('trc_mean_qsr') + ! + END SUBROUTINE trc_mean_qsr + +#else + !!---------------------------------------------------------------------- + !! Default key NO passive tracers + !!---------------------------------------------------------------------- +CONTAINS + SUBROUTINE trc_stp( kt ) ! Empty routine + WRITE(*,*) 'trc_stp: You should not have seen this print! error?', kt + END SUBROUTINE trc_stp +#endif + + !!====================================================================== +END MODULE trcstp_rk3 diff --git a/tests/ISOMIP+/EXPREF/namelist_cfg b/tests/ISOMIP+/EXPREF/namelist_cfg index d2b10f0c77c58f15a8647540efaee6dccf588f0c..0b8ae4c942cae45c37a6d6af06a6289e343a890b 100644 --- a/tests/ISOMIP+/EXPREF/namelist_cfg +++ b/tests/ISOMIP+/EXPREF/namelist_cfg @@ -193,7 +193,6 @@ rn_Dt = 720. ! ! vel_stab = velocity and stability dependent transfert coeficient (Holland et al. 1999 for a complete description) rn_gammat0 = 0.0215 ! gammat coefficient used in blk formula rn_gammas0 = 0.614e-3 ! gammas coefficient used in blk formula - rn_vtide = 0.01 ! tidal velocity [m/s] ! rn_htbl = 20. ! thickness of the top boundary layer (Losh et al. 2008) ! ! 0 => thickness of the tbl = thickness of the first wet cell @@ -279,7 +278,7 @@ rn_Dt = 720. &namdrg_top ! TOP friction (ln_drg_OFF =F & ln_isfcav=T) !----------------------------------------------------------------------- rn_Cd0 = 2.5e-3 ! drag coefficient [-] - rn_ke0 = 0.0e-3 ! background kinetic energy [m2/s2] (non-linear cases) + rn_ke0 = 1.0e-4 ! background kinetic energy [m2/s2] (non-linear cases) / !----------------------------------------------------------------------- &namdrg_bot ! BOTTOM friction (ln_drg_OFF =F) diff --git a/tests/ISOMIP+/MY_SRC/eosbn2.F90 b/tests/ISOMIP+/MY_SRC/eosbn2.F90 index ad447ad1486c4692441e74a772bf9c7f8de003e9..d2da8cfd5976e46e78df5a71aad6279ac86fe21b 100644 --- a/tests/ISOMIP+/MY_SRC/eosbn2.F90 +++ b/tests/ISOMIP+/MY_SRC/eosbn2.F90 @@ -55,7 +55,7 @@ MODULE eosbn2 ! !! * Interface INTERFACE eos - MODULE PROCEDURE eos_insitu, eos_insitu_pot, eos_insitu_2d, eos_insitu_pot_2d + MODULE PROCEDURE eos_insitu_New, eos_insitu, eos_insitu_pot, eos_insitu_2d, eos_insitu_pot_2d END INTERFACE ! INTERFACE eos_rab @@ -190,6 +190,130 @@ MODULE eosbn2 !!---------------------------------------------------------------------- CONTAINS + SUBROUTINE eos_insitu_New( pts, Knn, prd ) + !!---------------------------------------------------------------------- + !! *** ROUTINE eos_insitu_New *** + !! + !! ** Purpose : Compute the in situ density (ratio rho/rho0) from + !! potential temperature and salinity using an equation of state + !! selected in the nameos namelist + !! + !! ** Method : prd(t,s,z) = ( rho(t,s,z) - rho0 ) / rho0 + !! with prd in situ density anomaly no units + !! t TEOS10: CT or EOS80: PT Celsius + !! s TEOS10: SA or EOS80: SP TEOS10: g/kg or EOS80: psu + !! z depth meters + !! rho in situ density kg/m^3 + !! rho0 reference density kg/m^3 + !! + !! ln_teos10 : polynomial TEOS-10 equation of state is used for rho(t,s,z). + !! Check value: rho = 1028.21993233072 kg/m^3 for z=3000 dbar, ct=3 Celsius, sa=35.5 g/kg + !! + !! ln_eos80 : polynomial EOS-80 equation of state is used for rho(t,s,z). + !! Check value: rho = 1028.35011066567 kg/m^3 for z=3000 dbar, pt=3 Celsius, sp=35.5 psu + !! + !! ln_seos : simplified equation of state + !! prd(t,s,z) = ( -a0*(1+lambda/2*(T-T0)+mu*z+nu*(S-S0))*(T-T0) + b0*(S-S0) ) / rho0 + !! linear case function of T only: rn_alpha<>0, other coefficients = 0 + !! linear eos function of T and S: rn_alpha and rn_beta<>0, other coefficients=0 + !! Vallis like equation: use default values of coefficients + !! + !! ln_leos : linear ISOMIP equation of state + !! prd(t,s,z) = ( -a0*(T-T0) + b0*(S-S0) ) / rho0 + !! setup for ISOMIP linear eos + !! + !! ** Action : compute prd , the in situ density (no units) + !! + !! References : Roquet et al, Ocean Modelling, in preparation (2014) + !! Vallis, Atmospheric and Oceanic Fluid Dynamics, 2006 + !! TEOS-10 Manual, 2010 + !!---------------------------------------------------------------------- + REAL(wp), DIMENSION(:,:,:,:,:), INTENT(in ) :: pts ! T-S + INTEGER , INTENT(in ) :: Knn ! time-level + REAL(wp), DIMENSION(:,:,: ), INTENT( out) :: prd ! in situ density + ! + INTEGER :: ji, jj, jk ! dummy loop indices + REAL(wp) :: zt , zh , zs , ztm ! local scalars + REAL(wp) :: zn , zn0, zn1, zn2, zn3 ! - - + !!---------------------------------------------------------------------- + ! + IF( ln_timing ) CALL timing_start('eos-insitu') + ! + SELECT CASE( neos ) + ! + CASE( np_teos10, np_eos80 ) !== polynomial TEOS-10 / EOS-80 ==! + ! + DO_3D(nn_hls, nn_hls, nn_hls, nn_hls, 1, jpkm1 ) + ! + zh = gdept(ji,jj,jk,Knn) * r1_Z0 ! depth + zt = pts (ji,jj,jk,jp_tem,Knn) * r1_T0 ! temperature + zs = SQRT( ABS( pts(ji,jj,jk,jp_sal,Knn) + rdeltaS ) * r1_S0 ) ! square root salinity + ztm = tmask(ji,jj,jk) ! tmask + ! + zn3 = EOS013*zt & + & + EOS103*zs+EOS003 + ! + zn2 = (EOS022*zt & + & + EOS112*zs+EOS012)*zt & + & + (EOS202*zs+EOS102)*zs+EOS002 + ! + zn1 = (((EOS041*zt & + & + EOS131*zs+EOS031)*zt & + & + (EOS221*zs+EOS121)*zs+EOS021)*zt & + & + ((EOS311*zs+EOS211)*zs+EOS111)*zs+EOS011)*zt & + & + (((EOS401*zs+EOS301)*zs+EOS201)*zs+EOS101)*zs+EOS001 + ! + zn0 = (((((EOS060*zt & + & + EOS150*zs+EOS050)*zt & + & + (EOS240*zs+EOS140)*zs+EOS040)*zt & + & + ((EOS330*zs+EOS230)*zs+EOS130)*zs+EOS030)*zt & + & + (((EOS420*zs+EOS320)*zs+EOS220)*zs+EOS120)*zs+EOS020)*zt & + & + ((((EOS510*zs+EOS410)*zs+EOS310)*zs+EOS210)*zs+EOS110)*zs+EOS010)*zt & + & + (((((EOS600*zs+EOS500)*zs+EOS400)*zs+EOS300)*zs+EOS200)*zs+EOS100)*zs+EOS000 + ! + zn = ( ( zn3 * zh + zn2 ) * zh + zn1 ) * zh + zn0 + ! + prd(ji,jj,jk) = ( zn * r1_rho0 - 1._wp ) * ztm ! density anomaly (masked) + ! + END_3D + ! + CASE( np_seos ) !== simplified EOS ==! + ! + DO_3D( nn_hls, nn_hls, nn_hls, nn_hls, 1, jpkm1 ) + zt = pts (ji,jj,jk,jp_tem,Knn) - 10._wp + zs = pts (ji,jj,jk,jp_sal,Knn) - 35._wp + zh = gdept(ji,jj,jk,Knn) + ztm = tmask(ji,jj,jk) + ! + zn = - rn_a0 * ( 1._wp + 0.5_wp*rn_lambda1*zt + rn_mu1*zh ) * zt & + & + rn_b0 * ( 1._wp - 0.5_wp*rn_lambda2*zs - rn_mu2*zh ) * zs & + & - rn_nu * zt * zs + ! + prd(ji,jj,jk) = zn * r1_rho0 * ztm ! density anomaly (masked) + END_3D + ! + CASE( np_leos ) !== linear ISOMIP EOS ==! + ! + DO_3D( nn_hls, nn_hls, nn_hls, nn_hls, 1, jpkm1 ) + zt = pts (ji,jj,jk,jp_tem,Knn) - (-1._wp) + zs = pts (ji,jj,jk,jp_sal,Knn) - 34.2_wp + zh = gdept(ji,jj,jk, Knn) + ztm = tmask(ji,jj,jk) + ! + zn = rho0 * ( - rn_a0 * zt + rn_b0 * zs ) + ! + prd(ji,jj,jk) = zn * r1_rho0 * ztm ! density anomaly (masked) + END_3D + ! + END SELECT + ! + IF(sn_cfctl%l_prtctl) CALL prt_ctl( tab3d_1=prd, clinfo1=' eos-insitu : ', kdim=jpk ) + ! + IF( ln_timing ) CALL timing_stop('eos-insitu') + ! + END SUBROUTINE eos_insitu_New + + SUBROUTINE eos_insitu( pts, prd, pdep ) !! REAL(wp), DIMENSION(:,:,:,:), INTENT(in ) :: pts ! 1 : potential temperature [Celsius] diff --git a/tests/ISOMIP+/MY_SRC/isf_oce.F90 b/tests/ISOMIP+/MY_SRC/isf_oce.F90 index 9f5b8ebd7d60b2af6285be5c58c2174a85248614..3bf1b30da0cbf5af17e40e4d0de4d006dd4193d2 100644 --- a/tests/ISOMIP+/MY_SRC/isf_oce.F90 +++ b/tests/ISOMIP+/MY_SRC/isf_oce.F90 @@ -37,7 +37,6 @@ MODULE isf_oce LOGICAL , PUBLIC :: ln_isfcav_mlt !: logical for the use of ice shelf parametrisation REAL(wp) , PUBLIC :: rn_gammat0 !: temperature exchange coeficient [] REAL(wp) , PUBLIC :: rn_gammas0 !: salinity exchange coeficient [] - REAL(wp) , PUBLIC :: rn_vtide !: tidal background velocity (can be different to what is used in the REAL(wp) , PUBLIC :: rn_htbl !: Losch top boundary layer thickness [m] REAL(wp) , PUBLIC :: rn_isfload_T !: REAL(wp) , PUBLIC :: rn_isfload_S !: diff --git a/tests/ISOMIP+/MY_SRC/isfcavgam.F90 b/tests/ISOMIP+/MY_SRC/isfcavgam.F90 index ac0697a87327754464334699f0447209927b30f1..6c0ac2a4d94db9b728d48603e65d1d2f31f548ef 100644 --- a/tests/ISOMIP+/MY_SRC/isfcavgam.F90 +++ b/tests/ISOMIP+/MY_SRC/isfcavgam.F90 @@ -94,9 +94,9 @@ CONTAINS pgt(:,:) = rn_gammat0 pgs(:,:) = rn_gammas0 CASE ( 'vel' ) ! gamma is proportional to u* - CALL gammats_vel ( zutbl, zvtbl, rCd0_top, rn_vtide**2, pgt, pgs ) + CALL gammats_vel ( zutbl, zvtbl, rCd0_top, r_ke0_top, pgt, pgs ) CASE ( 'vel_stab' ) ! gamma depends of stability of boundary layer and u* - CALL gammats_vel_stab (Kmm, pttbl, pstbl, zutbl, zvtbl, rCd0_top, rn_vtide**2, pqoce, pqfwf, pRc, pgt, pgs ) + CALL gammats_vel_stab (Kmm, pttbl, pstbl, zutbl, zvtbl, rCd0_top, r_ke0_top, pqoce, pqfwf, pRc, pgt, pgs ) CASE DEFAULT CALL ctl_stop('STOP','method to compute gamma (cn_gammablk) is unknown (should not see this)') END SELECT diff --git a/tests/ISOMIP+/MY_SRC/isfstp.F90 b/tests/ISOMIP+/MY_SRC/isfstp.F90 index 58b388ac0e645480d19c6f06a1ac3844ac73ebce..2ab920844a3af8cf4afda88d68297208ce312358 100644 --- a/tests/ISOMIP+/MY_SRC/isfstp.F90 +++ b/tests/ISOMIP+/MY_SRC/isfstp.F90 @@ -38,7 +38,7 @@ MODULE isfstp # include "domzgr_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/OCE 4.0 , NEMO Consortium (2018) - !! $Id: isfstp.F90 11876 2019-11-08 11:26:42Z mathiot $ + !! $Id: isfstp.F90 15574 2021-12-03 19:32:50Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS @@ -194,6 +194,11 @@ CONTAINS WRITE(numout,*) ! IF ( ln_isf ) THEN +#if key_qco +# if ! defined key_isf + CALL ctl_stop( 'STOP', 'isf_ctl: ice shelf requires both ln_isf=T AND key_isf activated' ) +# endif +#endif WRITE(numout,*) ' Add debug print in isf module ln_isfdebug = ', ln_isfdebug WRITE(numout,*) WRITE(numout,*) ' melt inside the cavity ln_isfcav_mlt = ', ln_isfcav_mlt @@ -204,7 +209,7 @@ CONTAINS IF ( TRIM(cn_gammablk) .NE. 'spe' ) THEN WRITE(numout,*) ' gammat coefficient rn_gammat0 = ', rn_gammat0 WRITE(numout,*) ' gammas coefficient rn_gammas0 = ', rn_gammas0 - WRITE(numout,*) ' top background ke used (from namdrg_top) rn_vtide**2 = ', rn_vtide**2 + WRITE(numout,*) ' top background ke used (from namdrg_top) rn_ke0 = ', r_ke0_top WRITE(numout,*) ' top drag coef. used (from namdrg_top) rn_Cd0 = ', r_Cdmin_top END IF END IF @@ -299,7 +304,7 @@ CONTAINS & ln_isfcav_mlt , cn_isfcav_mlt , sn_isfcav_fwf , & & ln_isfpar_mlt , cn_isfpar_mlt , sn_isfpar_fwf , & & sn_isfpar_zmin, sn_isfpar_zmax, sn_isfpar_Leff, & - & ln_isfcpl , nn_drown , ln_isfcpl_cons, ln_isfdebug, rn_vtide, & + & ln_isfcpl , nn_drown , ln_isfcpl_cons, ln_isfdebug, & & cn_isfload , rn_isfload_T , rn_isfload_S , cn_isfdir , & & rn_isfpar_bg03_gt0 !!---------------------------------------------------------------------- diff --git a/tests/ISOMIP+/MY_SRC/istate.F90 b/tests/ISOMIP+/MY_SRC/istate.F90 index 35af0fd29e830e5cc573ffabd538e15acd314a41..0f32b25a96257355ffeb7d9dd22781306a3a860a 100644 --- a/tests/ISOMIP+/MY_SRC/istate.F90 +++ b/tests/ISOMIP+/MY_SRC/istate.F90 @@ -32,6 +32,7 @@ MODULE istate USE in_out_manager ! I/O manager USE iom ! I/O library USE lib_mpp ! MPP library + USE lbclnk ! lateal boundary condition / mpp exchanges USE restart ! restart #if defined key_agrif @@ -49,7 +50,7 @@ MODULE istate # include "domzgr_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/OCE 4.0 , NEMO Consortium (2018) - !! $Id: istate.F90 11423 2019-08-08 14:02:49Z mathiot $ + !! $Id: istate.F90 15581 2021-12-07 13:08:22Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS @@ -59,6 +60,8 @@ CONTAINS !! *** ROUTINE istate_init *** !! !! ** Purpose : Initialization of the dynamics and tracer fields. + !! + !! ** Method : !!---------------------------------------------------------------------- INTEGER, INTENT( in ) :: Kbb, Kmm, Kaa ! ocean time level indices ! @@ -86,7 +89,7 @@ CONTAINS #endif #if defined key_agrif - IF ( (.NOT.Agrif_root()).AND.ln_init_chfrpar ) THEN + IF ( .NOT.Agrif_root() .AND. ln_init_chfrpar ) THEN numror = 0 ! define numror = 0 -> no restart file to read ln_1st_euler = .true. ! Set time-step indicator at nit000 (euler forward) CALL day_init @@ -125,37 +128,50 @@ CONTAINS DO jk = 1, jpk zgdept(:,:,jk) = gdept(:,:,jk,Kbb) END DO - CALL usr_def_istate( zgdept, tmask, ts(:,:,:,:,Kbb), uu(:,:,:,Kbb), vv(:,:,:,Kbb) ) + CALL usr_def_istate( zgdept, tmask, ts(:,:,:,:,Kbb), uu(:,:,:,Kbb), vv(:,:,:,Kbb) ) + ! make sure that periodicities are properly applied + CALL lbc_lnk( 'istate', ts(:,:,:,jp_tem,Kbb), 'T', 1._wp, ts(:,:,:,jp_sal,Kbb), 'T', 1._wp, & + & uu(:,:,:, Kbb), 'U', -1._wp, vv(:,:,:, Kbb), 'V', -1._wp ) ENDIF ts (:,:,:,:,Kmm) = ts (:,:,:,:,Kbb) ! set now values from to before ones uu (:,:,:,Kmm) = uu (:,:,:,Kbb) vv (:,:,:,Kmm) = vv (:,:,:,Kbb) - ENDIF #if defined key_agrif ENDIF #endif ! - ! Initialize "now" and "before" barotropic velocities: - ! Do it whatever the free surface method, these arrays being eventually used + ! Initialize "now" barotropic velocities: + ! Do it whatever the free surface method, these arrays being used eventually ! +!!gm the use of umask & vmask is not necessary below as uu(:,:,:,Kmm), vv(:,:,:,Kmm), uu(:,:,:,Kbb), vv(:,:,:,Kbb) are always masked +#if ! defined key_RK3 uu_b(:,:,Kmm) = 0._wp ; vv_b(:,:,Kmm) = 0._wp - uu_b(:,:,Kbb) = 0._wp ; vv_b(:,:,Kbb) = 0._wp - ! -!!gm the use of umsak & vmask is not necessary below as uu(:,:,:,Kmm), vv(:,:,:,Kmm), uu(:,:,:,Kbb), vv(:,:,:,Kbb) are always masked DO_3D( nn_hls, nn_hls, nn_hls, nn_hls, 1, jpkm1 ) uu_b(ji,jj,Kmm) = uu_b(ji,jj,Kmm) + e3u(ji,jj,jk,Kmm) * uu(ji,jj,jk,Kmm) * umask(ji,jj,jk) vv_b(ji,jj,Kmm) = vv_b(ji,jj,Kmm) + e3v(ji,jj,jk,Kmm) * vv(ji,jj,jk,Kmm) * vmask(ji,jj,jk) - ! - uu_b(ji,jj,Kbb) = uu_b(ji,jj,Kbb) + e3u(ji,jj,jk,Kbb) * uu(ji,jj,jk,Kbb) * umask(ji,jj,jk) - vv_b(ji,jj,Kbb) = vv_b(ji,jj,Kbb) + e3v(ji,jj,jk,Kbb) * vv(ji,jj,jk,Kbb) * vmask(ji,jj,jk) END_3D - ! uu_b(:,:,Kmm) = uu_b(:,:,Kmm) * r1_hu(:,:,Kmm) vv_b(:,:,Kmm) = vv_b(:,:,Kmm) * r1_hv(:,:,Kmm) +#endif ! - uu_b(:,:,Kbb) = uu_b(:,:,Kbb) * r1_hu(:,:,Kbb) - vv_b(:,:,Kbb) = vv_b(:,:,Kbb) * r1_hv(:,:,Kbb) +#if defined key_RK3 + IF( .NOT. ln_rstart ) THEN +#endif + ! Initialize "before" barotropic velocities. "now" values are always set but + ! "before" values may have been read from a restart to ensure restartability. + ! In the non-restart or non-RK3 cases they need to be initialised here: + uu_b(:,:,Kbb) = 0._wp ; vv_b(:,:,Kbb) = 0._wp + DO_3D( nn_hls, nn_hls, nn_hls, nn_hls, 1, jpkm1 ) + uu_b(ji,jj,Kbb) = uu_b(ji,jj,Kbb) + e3u(ji,jj,jk,Kbb) * uu(ji,jj,jk,Kbb) * umask(ji,jj,jk) + vv_b(ji,jj,Kbb) = vv_b(ji,jj,Kbb) + e3v(ji,jj,jk,Kbb) * vv(ji,jj,jk,Kbb) * vmask(ji,jj,jk) + END_3D + uu_b(:,:,Kbb) = uu_b(:,:,Kbb) * r1_hu(:,:,Kbb) + vv_b(:,:,Kbb) = vv_b(:,:,Kbb) * r1_hv(:,:,Kbb) + ! +#if defined key_RK3 + ENDIF +#endif ! END SUBROUTINE istate_init diff --git a/tests/ISOMIP+/MY_SRC/sbcfwb.F90 b/tests/ISOMIP+/MY_SRC/sbcfwb.F90 index 5aee8bb6d5921d4127d4f43bebc1406efba312f1..0102aa12740247e044537fa78f63c58149b73414 100644 --- a/tests/ISOMIP+/MY_SRC/sbcfwb.F90 +++ b/tests/ISOMIP+/MY_SRC/sbcfwb.F90 @@ -35,8 +35,9 @@ MODULE sbcfwb PUBLIC sbc_fwb ! routine called by step REAL(wp) :: rn_fwb0 ! initial freshwater adjustment flux [kg/m2/s] (nn_fwb = 2 only) - REAL(wp) :: a_fwb ! annual domain averaged freshwater budget from the - ! previous year + REAL(wp) :: a_fwb ! annual domain averaged freshwater budget from the previous year + REAL(wp) :: a_fwb_b ! annual domain averaged freshwater budget from the year before or at initial state + REAL(wp) :: a_fwb_ini ! initial domain averaged freshwater budget REAL(wp) :: area ! global mean ocean surface (interior domain) !!---------------------------------------------------------------------- @@ -128,68 +129,65 @@ CONTAINS IF( iom_use('vflx_fwb_cea') ) CALL iom_put( 'vflx_fwb_cea', z_fwfprv(1) * tmask(:,:,1) ) ENDIF ! - CASE ( 4 ) !== global mean fwf set to zero (ISOMIP case) ==! - ! - IF( MOD( kt-1, kn_fsbc ) == 0 ) THEN - z_fwf = glob_sum( 'sbcfwb', e1e2t(:,:) * ( emp(:,:) - rnf(:,:) - fwfisf_cav(:,:) - fwfisf_par(:,:) - snwice_fmass(:,:) ) ) - ! - ! correction for ice sheet coupling testing (ie remove the excess through the surface) - ! test impact on the melt as conservation correction made in depth - ! test conservation level as sbcfwb is conserving - ! avoid the model to blow up for large ssh drop (isomip OCEAN3 with melt switch off and uniform T/S) - IF (ln_isfcpl .AND. ln_isfcpl_cons) THEN - z_fwf = z_fwf + glob_sum( 'sbcfwb', e1e2t(:,:) * risfcpl_cons_ssh(:,:) * rho0 ) - END IF - ! - z_fwf = z_fwf / area - zcoef = z_fwf * rcp - emp(:,:) = emp(:,:) - z_fwf * tmask(:,:,1) ! (Eq. 34 AD2015) - qns(:,:) = qns(:,:) + zcoef * sst_m(:,:) * tmask(:,:,1) ! (Eq. 35 AD2015) ! use sst_m to avoid generation of any bouyancy fluxes - sfx(:,:) = sfx(:,:) + z_fwf * sss_m(:,:) * tmask(:,:,1) ! (Eq. 36 AD2015) ! use sss_m to avoid generation of any bouyancy fluxes - ENDIF - ! CASE ( 2 ) !== fw adjustment based on fw budget at the end of the previous year ==! - ! - IF( kt == nit000 ) THEN ! initialisation - ! ! set the fw adjustment (a_fwb) - IF ( ln_rstart .AND. iom_varid( numror, 'a_fwb', ldstop = .FALSE. ) > 0 ) THEN ! as read from restart file - IF(lwp) WRITE(numout,*) 'sbc_fwb : reading FW-budget adjustment from restart file' - CALL iom_get( numror, 'a_fwb', a_fwb ) - ELSE ! as specified in namelist - a_fwb = rn_fwb0 + ! simulation is supposed to start 1st of January + IF( kt == nit000 ) THEN ! initialisation + ! ! set the fw adjustment (a_fwb) + IF ( ln_rstart .AND. iom_varid( numror, 'a_fwb_b', ldstop = .FALSE. ) > 0 & ! as read from restart file + & .AND. iom_varid( numror, 'a_fwb', ldstop = .FALSE. ) > 0 ) THEN + IF(lwp) WRITE(numout,*) 'sbc_fwb : reading freshwater-budget from restart file' + CALL iom_get( numror, 'a_fwb_b', a_fwb_b ) + CALL iom_get( numror, 'a_fwb' , a_fwb ) + ! + a_fwb_ini = a_fwb_b + ELSE ! as specified in namelist + IF(lwp) WRITE(numout,*) 'sbc_fwb : setting freshwater-budget from namelist rn_fwb0' + a_fwb = rn_fwb0 + a_fwb_b = 0._wp ! used only the first year then it is replaced by a_fwb_ini + ! + a_fwb_ini = glob_sum( 'sbcfwb', e1e2t(:,:) * ( ssh(:,:,Kmm) + snwice_mass(:,:) * r1_rho0 ) ) & + & * rho0 / ( area * rday * REAL(nyear_len(1), wp) ) END IF ! - IF(lwp)WRITE(numout,*) - IF(lwp)WRITE(numout,*)'sbc_fwb : initial freshwater-budget adjustment = ', a_fwb, 'kg/m2/s' + IF(lwp) WRITE(numout,*) + IF(lwp) WRITE(numout,*)'sbc_fwb : freshwater-budget at the end of previous year = ', a_fwb , 'kg/m2/s' + IF(lwp) WRITE(numout,*)' freshwater-budget at initial state = ', a_fwb_ini, 'kg/m2/s' + ! + ELSE + ! at the end of year n: + ikty = nyear_len(1) * 86400 / NINT(rn_Dt) + IF( MOD( kt, ikty ) == 0 ) THEN ! Update a_fwb at the last time step of a year + ! It should be the first time step of a year MOD(kt-1,ikty) but then the restart would be wrong + ! Hence, we make a small error here but the code is restartable + a_fwb_b = a_fwb_ini + ! mean sea level taking into account ice+snow + a_fwb = glob_sum( 'sbcfwb', e1e2t(:,:) * ( ssh(:,:,Kmm) + snwice_mass(:,:) * r1_rho0 ) ) + a_fwb = a_fwb * rho0 / ( area * rday * REAL(nyear_len(1), wp) ) ! convert in kg/m2/s + ENDIF ! - ENDIF - ! ! Update a_fwb if new year start - ikty = 365 * 86400 / rn_Dt !!bug use of 365 days leap year or 360d year !!!!!!! - IF( MOD( kt, ikty ) == 0 ) THEN - ! mean sea level taking into account the ice+snow - ! sum over the global domain - a_fwb = glob_sum( 'sbcfwb', e1e2t(:,:) * ( ssh(:,:,Kmm) + snwice_mass(:,:) * r1_rho0 ) ) - a_fwb = a_fwb * 1.e+3 / ( area * rday * 365. ) ! convert in Kg/m3/s = mm/s -!!gm ! !!bug 365d year ENDIF - ! - IF( MOD( kt-1, kn_fsbc ) == 0 ) THEN ! correct the freshwater fluxes - zcoef = a_fwb * rcp - emp(:,:) = emp(:,:) + a_fwb * tmask(:,:,1) - qns(:,:) = qns(:,:) - zcoef * sst_m(:,:) * tmask(:,:,1) ! account for change to the heat budget due to fw correction + ! + IF( MOD( kt-1, kn_fsbc ) == 0 ) THEN ! correct the freshwater fluxes using previous year budget minus initial state + zcoef = ( a_fwb - a_fwb_b ) + emp(:,:) = emp(:,:) + zcoef * tmask(:,:,1) + qns(:,:) = qns(:,:) - zcoef * rcp * sst_m(:,:) * tmask(:,:,1) ! account for change to the heat budget due to fw correction ! outputs - IF( iom_use('hflx_fwb_cea') ) CALL iom_put( 'hflx_fwb_cea', -zcoef * sst_m(:,:) * tmask(:,:,1) ) - IF( iom_use('vflx_fwb_cea') ) CALL iom_put( 'vflx_fwb_cea', -a_fwb * tmask(:,:,1) ) + IF( iom_use('hflx_fwb_cea') ) CALL iom_put( 'hflx_fwb_cea', -zcoef * rcp * sst_m(:,:) * tmask(:,:,1) ) + IF( iom_use('vflx_fwb_cea') ) CALL iom_put( 'vflx_fwb_cea', -zcoef * tmask(:,:,1) ) ENDIF ! Output restart information IF( lrst_oce ) THEN IF(lwp) WRITE(numout,*) IF(lwp) WRITE(numout,*) 'sbc_fwb : writing FW-budget adjustment to ocean restart file at it = ', kt IF(lwp) WRITE(numout,*) '~~~~' - CALL iom_rstput( kt, nitrst, numrow, 'a_fwb', a_fwb ) + CALL iom_rstput( kt, nitrst, numrow, 'a_fwb_b', a_fwb_b ) + CALL iom_rstput( kt, nitrst, numrow, 'a_fwb', a_fwb ) END IF ! - IF( kt == nitend .AND. lwp ) WRITE(numout,*) 'sbc_fwb : final freshwater-budget adjustment = ', a_fwb, 'kg/m2/s' + IF( kt == nitend .AND. lwp ) THEN + WRITE(numout,*) 'sbc_fwb : freshwater-budget at the end of simulation (year now) = ', a_fwb , 'kg/m2/s' + WRITE(numout,*) ' freshwater-budget at initial state = ', a_fwb_b, 'kg/m2/s' + ENDIF ! CASE ( 3 ) !== global fwf set to zero and spread out over erp area ==! ! @@ -248,6 +246,26 @@ CONTAINS ENDIF DEALLOCATE( ztmsk_neg , ztmsk_pos , ztmsk_tospread , z_wgt , zerp_cor ) ! + CASE ( 4 ) !== global mean fwf set to zero (ISOMIP case) ==! + ! + IF( MOD( kt-1, kn_fsbc ) == 0 ) THEN + z_fwf = glob_sum( 'sbcfwb', e1e2t(:,:) * ( emp(:,:) - rnf(:,:) - fwfisf_cav(:,:) - fwfisf_par(:,:) - snwice_fmass(:,:) ) ) + ! + ! correction for ice sheet coupling testing (ie remove the excess through the surface) + ! test impact on the melt as conservation correction made in depth + ! test conservation level as sbcfwb is conserving + ! avoid the model to blow up for large ssh drop (isomip OCEAN3 with melt switch off and uniform T/S) + IF (ln_isfcpl .AND. ln_isfcpl_cons) THEN + z_fwf = z_fwf + glob_sum( 'sbcfwb', e1e2t(:,:) * risfcpl_cons_ssh(:,:) * rho0 ) + END IF + ! + z_fwf = z_fwf / area + zcoef = z_fwf * rcp + emp(:,:) = emp(:,:) - z_fwf * tmask(:,:,1) ! (Eq. 34 AD2015) + qns(:,:) = qns(:,:) + zcoef * sst_m(:,:) * tmask(:,:,1) ! (Eq. 35 AD2015) ! use sst_m to avoid generation of any bouyancy fluxes + sfx(:,:) = sfx(:,:) + z_fwf * sss_m(:,:) * tmask(:,:,1) ! (Eq. 36 AD2015) ! use sss_m to avoid generation of any bouyancy fluxes + ENDIF + ! CASE DEFAULT !== you should never be there ==! CALL ctl_stop( 'sbc_fwb : wrong nn_fwb value for the FreshWater Budget correction, choose either 1, 2 or 3' ) ! diff --git a/tests/ISOMIP+/MY_SRC/tradmp.F90 b/tests/ISOMIP+/MY_SRC/tradmp.F90 index 734d1767061a0c3a8e5224c5fe3c174f8fa5499d..05ed5b09aa1bbdcabb8968ffc18dfd51e11f2acb 100644 --- a/tests/ISOMIP+/MY_SRC/tradmp.F90 +++ b/tests/ISOMIP+/MY_SRC/tradmp.F90 @@ -23,7 +23,6 @@ MODULE tradmp !!---------------------------------------------------------------------- USE oce ! ocean: variables USE dom_oce ! ocean: domain variables - USE c1d ! 1D vertical configuration USE trd_oce ! trends: ocean variables USE trdtra ! trends manager: tracers USE zdf_oce ! ocean: vertical physics @@ -55,7 +54,7 @@ MODULE tradmp # include "domzgr_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/OCE 4.0 , NEMO Consortium (2018) - !! $Id: tradmp.F90 10425 2018-12-19 21:54:16Z smasson $ + !! $Id: tradmp.F90 15574 2021-12-03 19:32:50Z techene $ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS @@ -96,15 +95,19 @@ CONTAINS ! INTEGER :: ji, jj, jk, jn ! dummy loop indices REAL(wp), DIMENSION(A2D(nn_hls),jpk,jpts) :: zts_dta - REAL(wp), DIMENSION(jpi,jpj,jpk) :: ze3t + REAL(wp), DIMENSION(:,:,:) , ALLOCATABLE :: zwrk REAL(wp), DIMENSION(:,:,:,:), ALLOCATABLE :: ztrdts !!---------------------------------------------------------------------- ! IF( ln_timing ) CALL timing_start('tra_dmp') ! IF( l_trdtra .OR. iom_use('hflx_dmp_cea') .OR. iom_use('sflx_dmp_cea') ) THEN !* Save ta and sa trends - ALLOCATE( ztrdts(jpi,jpj,jpk,jpts) ) - ztrdts(:,:,:,:) = pts(:,:,:,:,Krhs) + ALLOCATE( ztrdts(A2D(nn_hls),jpk,jpts) ) + DO jn = 1, jpts + DO_3D( nn_hls, nn_hls, nn_hls, nn_hls, 1, jpk ) + ztrdts(ji,jj,jk,jn) = pts(ji,jj,jk,jn,Krhs) + END_3D + END DO ENDIF ! !== input T-S data at kt ==! CALL dta_tsd( kt, 'dmp', zts_dta ) ! read and interpolates T-S data at kt @@ -142,16 +145,25 @@ CONTAINS END SELECT ! ! outputs (clem trunk) - DO jk = 1, jpk - ze3t(:,:,jk) = e3t(:,:,jk,Kmm) - END DO - ! - IF( iom_use('hflx_dmp_cea') ) & - & CALL iom_put('hflx_dmp_cea', & - & SUM( ( pts(:,:,:,jp_tem,Krhs) - ztrdts(:,:,:,jp_tem) ) * ze3t(:,:,:), dim=3 ) * rcp * rho0 ) ! W/m2 - IF( iom_use('sflx_dmp_cea') ) & - & CALL iom_put('sflx_dmp_cea', & - & SUM( ( pts(:,:,:,jp_sal,Krhs) - ztrdts(:,:,:,jp_sal) ) * ze3t(:,:,:), dim=3 ) * rho0 ) ! g/m2/s + IF( iom_use('hflx_dmp_cea') .OR. iom_use('sflx_dmp_cea') ) THEN + ALLOCATE( zwrk(A2D(nn_hls),jpk) ) ! Needed to handle expressions containing e3t when using key_qco or key_linssh + zwrk(:,:,:) = 0._wp + + IF( iom_use('hflx_dmp_cea') ) THEN + DO_3D( 0, 0, 0, 0, 1, jpk ) + zwrk(ji,jj,jk) = ( pts(ji,jj,jk,jp_tem,Krhs) - ztrdts(ji,jj,jk,jp_tem) ) * e3t(ji,jj,jk,Kmm) + END_3D + CALL iom_put('hflx_dmp_cea', SUM( zwrk(:,:,:), dim=3 ) * rcp * rho0 ) ! W/m2 + ENDIF + IF( iom_use('sflx_dmp_cea') ) THEN + DO_3D( 0, 0, 0, 0, 1, jpk ) + zwrk(ji,jj,jk) = ( pts(ji,jj,jk,jp_sal,Krhs) - ztrdts(ji,jj,jk,jp_sal) ) * e3t(ji,jj,jk,Kmm) + END_3D + CALL iom_put('sflx_dmp_cea', SUM( zwrk(:,:,:), dim=3 ) * rho0 ) ! g/m2/s + ENDIF + + DEALLOCATE( zwrk ) + ENDIF ! IF( l_trdtra ) THEN ! trend diagnostic ztrdts(:,:,:,:) = pts(:,:,:,:,Krhs) - ztrdts(:,:,:,:)