MODULE asminc !!====================================================================== !! *** MODULE asminc *** !! Assimilation increment : Apply an increment generated by data !! assimilation !!====================================================================== !! History : ! 2007-03 (M. Martin) Met Office version !! ! 2007-04 (A. Weaver) calc_date original code !! ! 2007-04 (A. Weaver) Merge with OPAVAR/NEMOVAR !! NEMO 3.3 ! 2010-05 (D. Lea) Update to work with NEMO v3.2 !! - ! 2010-05 (D. Lea) add calc_month_len routine based on day_init !! 3.4 ! 2012-10 (A. Weaver and K. Mogensen) Fix for direct initialization !! ! 2014-09 (D. Lea) Local calc_date removed use routine from OBS !! ! 2015-11 (D. Lea) Handle non-zero initial time of day !!---------------------------------------------------------------------- !!---------------------------------------------------------------------- !! asm_inc_init : Initialize the increment arrays and IAU weights !! tra_asm_inc : Apply the tracer (T and S) increments !! dyn_asm_inc : Apply the dynamic (u and v) increments !! ssh_asm_inc : Apply the SSH increment !! ssh_asm_div : Apply divergence associated with SSH increment !! seaice_asm_inc : Apply the seaice increment !!---------------------------------------------------------------------- USE oce ! Dynamics and active tracers defined in memory USE par_oce ! Ocean space and time domain variables USE dom_oce ! Ocean space and time domain USE domvvl ! domain: variable volume level USE ldfdyn ! lateral diffusion: eddy viscosity coefficients USE eosbn2 ! Equation of state - in situ and potential density USE zpshde ! Partial step : Horizontal Derivative USE asmpar ! Parameters for the assmilation interface USE asmbkg ! USE c1d ! 1D initialization USE sbc_oce ! Surface boundary condition variables. USE diaobs , ONLY : calc_date ! Compute the calendar date on a given step #if defined key_si3 && defined key_asminc USE phycst ! physical constants USE ice1D ! sea-ice: thermodynamics variables USE icetab ! sea-ice: 3D <==> 2D, 2D <==> 1D USE ice #endif ! USE in_out_manager ! I/O manager USE iom ! Library to read input files USE lib_mpp ! MPP library IMPLICIT NONE PRIVATE PUBLIC asm_inc_init !: Initialize the increment arrays and IAU weights PUBLIC tra_asm_inc !: Apply the tracer (T and S) increments PUBLIC dyn_asm_inc !: Apply the dynamic (u and v) increments PUBLIC ssh_asm_inc !: Apply the SSH increment PUBLIC ssh_asm_div !: Apply the SSH divergence PUBLIC seaice_asm_inc !: Apply the seaice increment #if defined key_asminc LOGICAL, PUBLIC, PARAMETER :: lk_asminc = .TRUE. !: Logical switch for assimilation increment interface #else LOGICAL, PUBLIC, PARAMETER :: lk_asminc = .FALSE. !: No assimilation increments #endif LOGICAL, PUBLIC :: ln_bkgwri !: No output of the background state fields LOGICAL, PUBLIC :: ln_asmiau !: No applying forcing with an assimilation increment LOGICAL, PUBLIC :: ln_asmdin !: No direct initialization LOGICAL, PUBLIC :: ln_trainc !: No tracer (T and S) assimilation increments LOGICAL, PUBLIC :: ln_dyninc !: No dynamics (u and v) assimilation increments LOGICAL, PUBLIC :: ln_sshinc !: No sea surface height assimilation increment LOGICAL, PUBLIC :: ln_seaiceinc !: No sea ice concentration increment LOGICAL, PUBLIC :: ln_salfix !: Apply minimum salinity check LOGICAL, PUBLIC :: ln_temnofreeze = .FALSE. !: Don't allow the temperature to drop below freezing INTEGER, PUBLIC :: nn_divdmp !: Apply divergence damping filter nn_divdmp times REAL(wp), PUBLIC, DIMENSION(:,:,:), ALLOCATABLE :: t_bkg , s_bkg !: Background temperature and salinity REAL(wp), PUBLIC, DIMENSION(:,:,:), ALLOCATABLE :: u_bkg , v_bkg !: Background u- & v- velocity components REAL(wp), PUBLIC, DIMENSION(:,:,:), ALLOCATABLE :: t_bkginc, s_bkginc !: Increment to the background T & S REAL(wp), PUBLIC, DIMENSION(:,:,:), ALLOCATABLE :: u_bkginc, v_bkginc !: Increment to the u- & v-components REAL(wp), PUBLIC, DIMENSION(:) , ALLOCATABLE :: wgtiau !: IAU weights for each time step #if defined key_asminc REAL(wp), PUBLIC, DIMENSION(:,:) , ALLOCATABLE :: ssh_iau !: IAU-weighted sea surface height increment #endif ! !!! time steps relative to the cycle interval [0,nitend-nit000-1] INTEGER , PUBLIC :: nitbkg !: Time step of the background state used in the Jb term INTEGER , PUBLIC :: nitdin !: Time step of the background state for direct initialization INTEGER , PUBLIC :: nitiaustr !: Time step of the start of the IAU interval INTEGER , PUBLIC :: nitiaufin !: Time step of the end of the IAU interval ! INTEGER , PUBLIC :: niaufn !: Type of IAU weighing function: = 0 Constant weighting ! !: = 1 Linear hat-like, centred in middle of IAU interval REAL(wp), PUBLIC :: salfixmin !: Ensure that the salinity is larger than this value if (ln_salfix) REAL(wp), DIMENSION(:,:), ALLOCATABLE :: ssh_bkg, ssh_bkginc ! Background sea surface height and its increment REAL(wp), DIMENSION(:,:), ALLOCATABLE :: seaice_bkginc ! Increment to the background sea ice conc REAL(wp) :: zhi_damin ! Ice thickness for new sea ice from DA increment #if defined key_si3 && defined key_asminc REAL(wp), DIMENSION(:,:,:), ALLOCATABLE :: a_i_bkginc ! Increment to the background sea ice conc categories LOGICAL, PUBLIC, DIMENSION(:,:,:), ALLOCATABLE :: incr_newice ! Mask .TRUE.=DA positive ice increment to open water #endif #if defined key_cice && defined key_asminc REAL(wp), DIMENSION(:,:), ALLOCATABLE :: ndaice_da ! ice increment tendency into CICE #endif !! * Substitutions # include "vectopt_loop_substitute.h90" !!---------------------------------------------------------------------- !! NEMO/OCE 4.0 , NEMO Consortium (2018) !! $Id$ !! Software governed by the CeCILL license (see ./LICENSE) !!---------------------------------------------------------------------- CONTAINS SUBROUTINE asm_inc_init !!---------------------------------------------------------------------- !! *** ROUTINE asm_inc_init *** !! !! ** Purpose : Initialize the assimilation increment and IAU weights. !! !! ** Method : Initialize the assimilation increment and IAU weights. !! !! ** Action : !!---------------------------------------------------------------------- INTEGER :: ji, jj, jk, jt, jl ! dummy loop indices INTEGER :: imid, inum ! local integers INTEGER :: ios ! Local integer output status for namelist read INTEGER :: iiauper ! Number of time steps in the IAU period INTEGER :: icycper ! Number of time steps in the cycle REAL(KIND=dp) :: ditend_date ! Date YYYYMMDD.HHMMSS of final time step REAL(KIND=dp) :: ditbkg_date ! Date YYYYMMDD.HHMMSS of background time step for Jb term REAL(KIND=dp) :: ditdin_date ! Date YYYYMMDD.HHMMSS of background time step for DI REAL(KIND=dp) :: ditiaustr_date ! Date YYYYMMDD.HHMMSS of IAU interval start time step REAL(KIND=dp) :: ditiaufin_date ! Date YYYYMMDD.HHMMSS of IAU interval final time step REAL(wp) :: znorm ! Normalization factor for IAU weights REAL(wp) :: ztotwgt ! Value of time-integrated IAU weights (should be equal to one) REAL(wp) :: z_inc_dateb ! Start date of interval on which increment is valid REAL(wp) :: z_inc_datef ! End date of interval on which increment is valid REAL(wp) :: zdate_bkg ! Date in background state file for DI REAL(wp) :: zdate_inc ! Time axis in increments file ! REAL(wp), ALLOCATABLE, DIMENSION(:,:) :: zhdiv ! 2D workspace REAL(wp) :: zremaining_increment !! NAMELIST/nam_asminc/ ln_bkgwri, & & ln_trainc, ln_dyninc, ln_sshinc, & & ln_seaiceinc, ln_asmdin, ln_asmiau, & & nitbkg, nitdin, nitiaustr, nitiaufin, niaufn, & & ln_salfix, salfixmin, nn_divdmp, zhi_damin !!---------------------------------------------------------------------- !----------------------------------------------------------------------- ! Read Namelist nam_asminc : assimilation increment interface !----------------------------------------------------------------------- ln_seaiceinc = .FALSE. ln_temnofreeze = .FALSE. REWIND( numnam_ref ) ! Namelist nam_asminc in reference namelist : Assimilation increment READ ( numnam_ref, nam_asminc, IOSTAT = ios, ERR = 901) 901 IF( ios /= 0 ) CALL ctl_nam ( ios , 'nam_asminc in reference namelist' ) REWIND( numnam_cfg ) ! Namelist nam_asminc in configuration namelist : Assimilation increment READ ( numnam_cfg, nam_asminc, IOSTAT = ios, ERR = 902 ) 902 IF( ios > 0 ) CALL ctl_nam ( ios , 'nam_asminc in configuration namelist' ) IF(lwm) WRITE ( numond, nam_asminc ) ! Control print IF(lwp) THEN WRITE(numout,*) WRITE(numout,*) 'asm_inc_init : Assimilation increment initialization :' WRITE(numout,*) '~~~~~~~~~~~~' WRITE(numout,*) ' Namelist namasm : set assimilation increment parameters' WRITE(numout,*) ' Logical switch for writing out background state ln_bkgwri = ', ln_bkgwri WRITE(numout,*) ' Logical switch for applying tracer increments ln_trainc = ', ln_trainc WRITE(numout,*) ' Logical switch for applying velocity increments ln_dyninc = ', ln_dyninc WRITE(numout,*) ' Logical switch for applying SSH increments ln_sshinc = ', ln_sshinc WRITE(numout,*) ' Logical switch for Direct Initialization (DI) ln_asmdin = ', ln_asmdin WRITE(numout,*) ' Logical switch for applying sea ice increments ln_seaiceinc = ', ln_seaiceinc WRITE(numout,*) ' Logical switch for Incremental Analysis Updating (IAU) ln_asmiau = ', ln_asmiau WRITE(numout,*) ' Timestep of background in [0,nitend-nit000-1] nitbkg = ', nitbkg WRITE(numout,*) ' Timestep of background for DI in [0,nitend-nit000-1] nitdin = ', nitdin WRITE(numout,*) ' Timestep of start of IAU interval in [0,nitend-nit000-1] nitiaustr = ', nitiaustr WRITE(numout,*) ' Timestep of end of IAU interval in [0,nitend-nit000-1] nitiaufin = ', nitiaufin WRITE(numout,*) ' Type of IAU weighting function niaufn = ', niaufn WRITE(numout,*) ' Logical switch for ensuring that the sa > salfixmin ln_salfix = ', ln_salfix WRITE(numout,*) ' Minimum salinity after applying the increments salfixmin = ', salfixmin WRITE(numout,*) ' Minimum ice thickness for new ice from DA zhi_damin = ', zhi_damin ENDIF nitbkg_r = nitbkg + nit000 - 1 ! Background time referenced to nit000 nitdin_r = nitdin + nit000 - 1 ! Background time for DI referenced to nit000 nitiaustr_r = nitiaustr + nit000 - 1 ! Start of IAU interval referenced to nit000 nitiaufin_r = nitiaufin + nit000 - 1 ! End of IAU interval referenced to nit000 iiauper = nitiaufin_r - nitiaustr_r + 1 ! IAU interval length icycper = nitend - nit000 + 1 ! Cycle interval length CALL calc_date( nitend , ditend_date ) ! Date of final time step CALL calc_date( nitbkg_r , ditbkg_date ) ! Background time for Jb referenced to ndate0 CALL calc_date( nitdin_r , ditdin_date ) ! Background time for DI referenced to ndate0 CALL calc_date( nitiaustr_r, ditiaustr_date ) ! IAU start time referenced to ndate0 CALL calc_date( nitiaufin_r, ditiaufin_date ) ! IAU end time referenced to ndate0 IF(lwp) THEN WRITE(numout,*) WRITE(numout,*) ' Time steps referenced to current cycle:' WRITE(numout,*) ' iitrst = ', nit000 - 1 WRITE(numout,*) ' nit000 = ', nit000 WRITE(numout,*) ' nitend = ', nitend WRITE(numout,*) ' nitbkg_r = ', nitbkg_r WRITE(numout,*) ' nitdin_r = ', nitdin_r WRITE(numout,*) ' nitiaustr_r = ', nitiaustr_r WRITE(numout,*) ' nitiaufin_r = ', nitiaufin_r WRITE(numout,*) WRITE(numout,*) ' Dates referenced to current cycle:' WRITE(numout,*) ' ndastp = ', ndastp WRITE(numout,*) ' ndate0 = ', ndate0 WRITE(numout,*) ' nn_time0 = ', nn_time0 WRITE(numout,*) ' ditend_date = ', ditend_date WRITE(numout,*) ' ditbkg_date = ', ditbkg_date WRITE(numout,*) ' ditdin_date = ', ditdin_date WRITE(numout,*) ' ditiaustr_date = ', ditiaustr_date WRITE(numout,*) ' ditiaufin_date = ', ditiaufin_date ENDIF IF ( ( ln_asmdin ).AND.( ln_asmiau ) ) & & CALL ctl_stop( ' ln_asmdin and ln_asmiau :', & & ' Choose Direct Initialization OR Incremental Analysis Updating') IF ( ( ( .NOT. ln_asmdin ).AND.( .NOT. ln_asmiau ) ) & .AND.( ( ln_trainc ).OR.( ln_dyninc ).OR.( ln_sshinc ) .OR. ( ln_seaiceinc) )) & & CALL ctl_stop( ' One or more of ln_trainc, ln_dyninc, ln_sshinc and ln_seaiceinc is set to .true.', & & ' but ln_asmdin and ln_asmiau are both set to .false. :', & & ' Inconsistent options') IF ( ( niaufn /= 0 ).AND.( niaufn /= 1 ) ) & & CALL ctl_stop( ' niaufn /= 0 or niaufn /=1 :', & & ' Type IAU weighting function is invalid') IF ( ( .NOT. ln_trainc ).AND.( .NOT. ln_dyninc ).AND.( .NOT. ln_sshinc ).AND.( .NOT. ln_seaiceinc ) & & ) & & CALL ctl_warn( ' ln_trainc, ln_dyninc, ln_sshinc and ln_seaiceinc are set to .false. :', & & ' The assimilation increments are not applied') IF ( ( ln_asmiau ).AND.( nitiaustr == nitiaufin ) ) & & CALL ctl_stop( ' nitiaustr = nitiaufin :', & & ' IAU interval is of zero length') IF ( ( ln_asmiau ).AND.( ( nitiaustr_r < nit000 ).OR.( nitiaufin_r > nitend ) ) ) & & CALL ctl_stop( ' nitiaustr or nitiaufin :', & & ' IAU starting or final time step is outside the cycle interval', & & ' Valid range nit000 to nitend') IF ( ( nitbkg_r < nit000 - 1 ).OR.( nitbkg_r > nitend ) ) & & CALL ctl_stop( ' nitbkg :', & & ' Background time step is outside the cycle interval') IF ( ( nitdin_r < nit000 - 1 ).OR.( nitdin_r > nitend ) ) & & CALL ctl_stop( ' nitdin :', & & ' Background time step for Direct Initialization is outside', & & ' the cycle interval') IF ( nstop > 0 ) RETURN ! if there are any errors then go no further !-------------------------------------------------------------------- ! Initialize the Incremental Analysis Updating weighting function !-------------------------------------------------------------------- IF( ln_asmiau ) THEN ! ALLOCATE( wgtiau( icycper ) ) ! wgtiau(:) = 0._wp ! ! !--------------------------------------------------------- IF( niaufn == 0 ) THEN ! Constant IAU forcing ! !--------------------------------------------------------- DO jt = 1, iiauper wgtiau(jt+nitiaustr-1) = 1.0 / REAL( iiauper ) END DO ! !--------------------------------------------------------- ELSEIF ( niaufn == 1 ) THEN ! Linear hat-like, centred in middle of IAU interval ! !--------------------------------------------------------- ! Compute the normalization factor znorm = 0._wp IF( MOD( iiauper, 2 ) == 0 ) THEN ! Even number of time steps in IAU interval imid = iiauper / 2 DO jt = 1, imid znorm = znorm + REAL( jt ) END DO znorm = 2.0 * znorm ELSE ! Odd number of time steps in IAU interval imid = ( iiauper + 1 ) / 2 DO jt = 1, imid - 1 znorm = znorm + REAL( jt ) END DO znorm = 2.0 * znorm + REAL( imid ) ENDIF znorm = 1.0 / znorm ! DO jt = 1, imid - 1 wgtiau(jt+nitiaustr-1) = REAL( jt ) * znorm END DO DO jt = imid, iiauper wgtiau(jt+nitiaustr-1) = REAL( iiauper - jt + 1 ) * znorm END DO ! ENDIF ! Test that the integral of the weights over the weighting interval equals 1 IF(lwp) THEN WRITE(numout,*) WRITE(numout,*) 'asm_inc_init : IAU weights' WRITE(numout,*) '~~~~~~~~~~~~' WRITE(numout,*) ' time step IAU weight' WRITE(numout,*) ' ========= =====================' ztotwgt = 0.0 DO jt = 1, icycper ztotwgt = ztotwgt + wgtiau(jt) WRITE(numout,*) ' ', jt, ' ', wgtiau(jt) END DO WRITE(numout,*) ' ===================================' WRITE(numout,*) ' Time-integrated weight = ', ztotwgt WRITE(numout,*) ' ===================================' ENDIF ENDIF !-------------------------------------------------------------------- ! Allocate and initialize the increment arrays !-------------------------------------------------------------------- ALLOCATE( t_bkginc (jpi,jpj,jpk) ) ; t_bkginc (:,:,:) = 0._wp ALLOCATE( s_bkginc (jpi,jpj,jpk) ) ; s_bkginc (:,:,:) = 0._wp ALLOCATE( u_bkginc (jpi,jpj,jpk) ) ; u_bkginc (:,:,:) = 0._wp ALLOCATE( v_bkginc (jpi,jpj,jpk) ) ; v_bkginc (:,:,:) = 0._wp ALLOCATE( ssh_bkginc (jpi,jpj) ) ; ssh_bkginc (:,:) = 0._wp ALLOCATE( seaice_bkginc(jpi,jpj) ) ; seaice_bkginc(:,:) = 0._wp #if defined key_si3 && defined key_asminc ALLOCATE( a_i_bkginc (jpi,jpj,jpl) ) ; a_i_bkginc (:,:,:) = 0._wp ALLOCATE( incr_newice(jpi,jpj,jpl) ) ; incr_newice(:,:,:) = .FALSE. #endif #if defined key_asminc ALLOCATE( ssh_iau (jpi,jpj) ) ; ssh_iau (:,:) = 0._wp #endif #if defined key_cice && defined key_asminc ALLOCATE( ndaice_da (jpi,jpj) ) ; ndaice_da (:,:) = 0._wp #endif ! IF ( ln_trainc .OR. ln_dyninc .OR. & !-------------------------------------- & ln_sshinc .OR. ln_seaiceinc ) THEN ! Read the increments from file ! !-------------------------------------- CALL iom_open( c_asminc, inum ) ! CALL iom_get( inum, 'time' , zdate_inc ) CALL iom_get( inum, 'z_inc_dateb', z_inc_dateb ) CALL iom_get( inum, 'z_inc_datef', z_inc_datef ) z_inc_dateb = zdate_inc z_inc_datef = zdate_inc ! IF(lwp) THEN WRITE(numout,*) WRITE(numout,*) 'asm_inc_init : Assimilation increments valid between dates ', z_inc_dateb,' and ', z_inc_datef WRITE(numout,*) '~~~~~~~~~~~~' ENDIF ! IF ( ( z_inc_dateb < ndastp + nn_time0*0.0001_wp ) .OR. & & ( z_inc_datef > ditend_date ) ) & & CALL ctl_warn( ' Validity time of assimilation increments is ', & & ' outside the assimilation interval' ) IF ( ( ln_asmdin ).AND.( zdate_inc /= ditdin_date ) ) & & CALL ctl_warn( ' Validity time of assimilation increments does ', & & ' not agree with Direct Initialization time' ) IF ( ln_trainc ) THEN CALL iom_get( inum, jpdom_autoglo, 'bckint', t_bkginc, 1 ) CALL iom_get( inum, jpdom_autoglo, 'bckins', s_bkginc, 1 ) ! Apply the masks t_bkginc(:,:,:) = t_bkginc(:,:,:) * tmask(:,:,:) s_bkginc(:,:,:) = s_bkginc(:,:,:) * tmask(:,:,:) ! Set missing increments to 0.0 rather than 1e+20 ! to allow for differences in masks WHERE( ABS( t_bkginc(:,:,:) ) > 1.0e+10 ) t_bkginc(:,:,:) = 0.0 WHERE( ABS( s_bkginc(:,:,:) ) > 1.0e+10 ) s_bkginc(:,:,:) = 0.0 ENDIF IF ( ln_dyninc ) THEN CALL iom_get( inum, jpdom_autoglo, 'bckinu', u_bkginc, 1 ) CALL iom_get( inum, jpdom_autoglo, 'bckinv', v_bkginc, 1 ) ! Apply the masks u_bkginc(:,:,:) = u_bkginc(:,:,:) * umask(:,:,:) v_bkginc(:,:,:) = v_bkginc(:,:,:) * vmask(:,:,:) ! Set missing increments to 0.0 rather than 1e+20 ! to allow for differences in masks WHERE( ABS( u_bkginc(:,:,:) ) > 1.0e+10 ) u_bkginc(:,:,:) = 0.0 WHERE( ABS( v_bkginc(:,:,:) ) > 1.0e+10 ) v_bkginc(:,:,:) = 0.0 ENDIF IF ( ln_sshinc ) THEN CALL iom_get( inum, jpdom_autoglo, 'bckineta', ssh_bkginc, 1 ) ! Apply the masks ssh_bkginc(:,:) = ssh_bkginc(:,:) * tmask(:,:,1) ! Set missing increments to 0.0 rather than 1e+20 ! to allow for differences in masks WHERE( ABS( ssh_bkginc(:,:) ) > 1.0e+10 ) ssh_bkginc(:,:) = 0.0 ENDIF IF ( ln_seaiceinc ) THEN CALL iom_get( inum, jpdom_autoglo, 'bckinseaice', seaice_bkginc, 1 ) ! Apply the masks seaice_bkginc(:,:) = seaice_bkginc(:,:) * tmask(:,:,1) ! Set missing increments to 0.0 rather than 1e+20 ! to allow for differences in masks ! very small increments are also set to zero WHERE( ABS( seaice_bkginc(:,:) ) > 1.0e+10 .OR. & & ABS( seaice_bkginc(:,:) ) < 1.0e-03_wp ) seaice_bkginc(:,:) = 0.0_wp #if defined key_si3 && defined key_asminc IF (lwp) THEN WRITE(numout,*) WRITE(numout,*) 'asm_inc_init : Converting single category increment to multi-category' WRITE(numout,*) '~~~~~~~~~~~~' END IF !single category increment for sea ice conc !convert single category increment to multi category at_i = SUM( a_i(:,:,:), DIM=3 ) ! ensure zhi_damin lies within 1st category IF ( zhi_damin > hi_max(1) ) THEN IF (lwp) THEN WRITE(numout,*) WRITE(numout,*) 'minimum DA thickness > hmax(1): setting minimum DA thickness to hmax(1)' WRITE(numout,*) '~~~~~~~~~~~~' END IF zhi_damin = hi_max(1) - epsi02 END IF DO jj = 1, jpj DO ji = 1, jpi IF ( seaice_bkginc(ji,jj) > 0.0_wp ) THEN !positive ice concentration increments are always !added to the thinnest category of ice a_i_bkginc(ji,jj,1) = seaice_bkginc(ji,jj) ELSE !negative increments are first removed from the thinnest !available category until it reaches zero concentration !and then progressively removed from thicker categories !NOTE: might consider the remote possibility that zremaining_increment !left over is not zero, particulary if SI3 is being run !as a single category zremaining_increment = seaice_bkginc(ji,jj) DO jl = 1, jpl ! assign as much increment as possible to current category a_i_bkginc(ji,jj,jl) = -MIN( a_i(ji,jj,jl), -zremaining_increment ) ! update remaining amount of increment zremaining_increment = zremaining_increment - a_i_bkginc(ji,jj,jl) END DO END IF END DO END DO ! find model points where DA new ice should be added to open water ! in any ice category DO jl = 1,jpl WHERE ( at_i(:,:) < epsi02 .AND. seaice_bkginc(:,:) > 0.0_wp ) incr_newice(:,:,jl) = .TRUE. END WHERE END DO ENDIF #endif ! CALL iom_close( inum ) ! ENDIF ! ! !-------------------------------------- IF ( ln_dyninc .AND. nn_divdmp > 0 ) THEN ! Apply divergence damping filter ! !-------------------------------------- ALLOCATE( zhdiv(jpi,jpj) ) ! DO jt = 1, nn_divdmp ! DO jk = 1, jpkm1 ! zhdiv = e1e1 * div zhdiv(:,:) = 0._wp DO jj = 2, jpjm1 DO ji = fs_2, fs_jpim1 ! vector opt. zhdiv(ji,jj) = ( e2u(ji ,jj) * e3u_n(ji ,jj,jk) * u_bkginc(ji ,jj,jk) & & - e2u(ji-1,jj) * e3u_n(ji-1,jj,jk) * u_bkginc(ji-1,jj,jk) & & + e1v(ji,jj ) * e3v_n(ji,jj ,jk) * v_bkginc(ji,jj ,jk) & & - e1v(ji,jj-1) * e3v_n(ji,jj-1,jk) * v_bkginc(ji,jj-1,jk) ) / e3t_n(ji,jj,jk) END DO END DO CALL lbc_lnk( 'asminc', zhdiv, 'T', 1. ) ! lateral boundary cond. (no sign change) ! DO jj = 2, jpjm1 DO ji = fs_2, fs_jpim1 ! vector opt. u_bkginc(ji,jj,jk) = u_bkginc(ji,jj,jk) & & + 0.2_wp * ( zhdiv(ji+1,jj) - zhdiv(ji ,jj) ) * r1_e1u(ji,jj) * umask(ji,jj,jk) v_bkginc(ji,jj,jk) = v_bkginc(ji,jj,jk) & & + 0.2_wp * ( zhdiv(ji,jj+1) - zhdiv(ji,jj ) ) * r1_e2v(ji,jj) * vmask(ji,jj,jk) END DO END DO END DO ! END DO ! DEALLOCATE( zhdiv ) ! ENDIF ! ! !----------------------------------------------------- IF ( ln_asmdin ) THEN ! Allocate and initialize the background state arrays ! !----------------------------------------------------- ! ALLOCATE( t_bkg (jpi,jpj,jpk) ) ; t_bkg (:,:,:) = 0._wp ALLOCATE( s_bkg (jpi,jpj,jpk) ) ; s_bkg (:,:,:) = 0._wp ALLOCATE( u_bkg (jpi,jpj,jpk) ) ; u_bkg (:,:,:) = 0._wp ALLOCATE( v_bkg (jpi,jpj,jpk) ) ; v_bkg (:,:,:) = 0._wp ALLOCATE( ssh_bkg(jpi,jpj) ) ; ssh_bkg(:,:) = 0._wp ! ! !-------------------------------------------------------------------- ! Read from file the background state at analysis time !-------------------------------------------------------------------- ! CALL iom_open( c_asmdin, inum ) ! CALL iom_get( inum, 'rdastp', zdate_bkg ) ! IF(lwp) THEN WRITE(numout,*) WRITE(numout,*) ' ==>>> Assimilation background state valid at : ', zdate_bkg WRITE(numout,*) ENDIF ! IF ( zdate_bkg /= ditdin_date ) & & CALL ctl_warn( ' Validity time of assimilation background state does', & & ' not agree with Direct Initialization time' ) ! IF ( ln_trainc ) THEN CALL iom_get( inum, jpdom_autoglo, 'tn', t_bkg ) CALL iom_get( inum, jpdom_autoglo, 'sn', s_bkg ) t_bkg(:,:,:) = t_bkg(:,:,:) * tmask(:,:,:) s_bkg(:,:,:) = s_bkg(:,:,:) * tmask(:,:,:) ENDIF ! IF ( ln_dyninc ) THEN CALL iom_get( inum, jpdom_autoglo, 'un', u_bkg ) CALL iom_get( inum, jpdom_autoglo, 'vn', v_bkg ) u_bkg(:,:,:) = u_bkg(:,:,:) * umask(:,:,:) v_bkg(:,:,:) = v_bkg(:,:,:) * vmask(:,:,:) ENDIF ! IF ( ln_sshinc ) THEN CALL iom_get( inum, jpdom_autoglo, 'sshn', ssh_bkg ) ssh_bkg(:,:) = ssh_bkg(:,:) * tmask(:,:,1) ENDIF ! CALL iom_close( inum ) ! ENDIF ! IF(lwp) WRITE(numout,*) ' ==>>> Euler time step switch is ', neuler ! IF( lk_asminc ) THEN !== data assimilation ==! IF( ln_bkgwri ) CALL asm_bkg_wri( nit000 - 1 ) ! Output background fields IF( ln_asmdin ) THEN ! Direct initialization IF( ln_trainc ) CALL tra_asm_inc( nit000 - 1 ) ! Tracers IF( ln_dyninc ) CALL dyn_asm_inc( nit000 - 1 ) ! Dynamics IF( ln_sshinc ) CALL ssh_asm_inc( nit000 - 1 ) ! SSH ENDIF ENDIF ! END SUBROUTINE asm_inc_init SUBROUTINE tra_asm_inc( kt ) !!---------------------------------------------------------------------- !! *** ROUTINE tra_asm_inc *** !! !! ** Purpose : Apply the tracer (T and S) assimilation increments !! !! ** Method : Direct initialization or Incremental Analysis Updating !! !! ** Action : !!---------------------------------------------------------------------- INTEGER, INTENT(IN) :: kt ! Current time step ! INTEGER :: ji, jj, jk INTEGER :: it REAL(wp) :: zincwgt ! IAU weight for current time step REAL (wp), DIMENSION(jpi,jpj,jpk) :: fzptnz ! 3d freezing point values !!---------------------------------------------------------------------- ! ! freezing point calculation taken from oc_fz_pt (but calculated for all depths) ! used to prevent the applied increments taking the temperature below the local freezing point DO jk = 1, jpkm1 CALL eos_fzp( tsn(:,:,jk,jp_sal), fzptnz(:,:,jk), gdept_n(:,:,jk) ) END DO ! ! !-------------------------------------- IF ( ln_asmiau ) THEN ! Incremental Analysis Updating ! !-------------------------------------- ! IF ( ( kt >= nitiaustr_r ).AND.( kt <= nitiaufin_r ) ) THEN ! it = kt - nit000 + 1 zincwgt = wgtiau(it) / rdt ! IAU weight for the current time step ! IF(lwp) THEN WRITE(numout,*) WRITE(numout,*) 'tra_asm_inc : Tracer IAU at time step = ', kt,' with IAU weight = ', wgtiau(it) WRITE(numout,*) '~~~~~~~~~~~~' ENDIF ! ! Update the tracer tendencies DO jk = 1, jpkm1 IF (ln_temnofreeze) THEN ! Do not apply negative increments if the temperature will fall below freezing WHERE(t_bkginc(:,:,jk) > 0.0_wp .OR. & & tsn(:,:,jk,jp_tem) + tsa(:,:,jk,jp_tem) + t_bkginc(:,:,jk) * wgtiau(it) > fzptnz(:,:,jk) ) tsa(:,:,jk,jp_tem) = tsa(:,:,jk,jp_tem) + t_bkginc(:,:,jk) * zincwgt END WHERE ELSE tsa(:,:,jk,jp_tem) = tsa(:,:,jk,jp_tem) + t_bkginc(:,:,jk) * zincwgt ENDIF IF (ln_salfix) THEN ! Do not apply negative increments if the salinity will fall below a specified ! minimum value salfixmin WHERE(s_bkginc(:,:,jk) > 0.0_wp .OR. & & tsn(:,:,jk,jp_sal) + tsa(:,:,jk,jp_sal) + s_bkginc(:,:,jk) * wgtiau(it) > salfixmin ) tsa(:,:,jk,jp_sal) = tsa(:,:,jk,jp_sal) + s_bkginc(:,:,jk) * zincwgt END WHERE ELSE tsa(:,:,jk,jp_sal) = tsa(:,:,jk,jp_sal) + s_bkginc(:,:,jk) * zincwgt ENDIF END DO ! ENDIF ! IF ( kt == nitiaufin_r + 1 ) THEN ! For bias crcn to work DEALLOCATE( t_bkginc ) DEALLOCATE( s_bkginc ) ENDIF ! !-------------------------------------- ELSEIF ( ln_asmdin ) THEN ! Direct Initialization ! !-------------------------------------- ! IF ( kt == nitdin_r ) THEN ! neuler = 0 ! Force Euler forward step ! ! Initialize the now fields with the background + increment IF (ln_temnofreeze) THEN ! Do not apply negative increments if the temperature will fall below freezing WHERE( t_bkginc(:,:,:) > 0.0_wp .OR. tsn(:,:,:,jp_tem) + t_bkginc(:,:,:) > fzptnz(:,:,:) ) tsn(:,:,:,jp_tem) = t_bkg(:,:,:) + t_bkginc(:,:,:) END WHERE ELSE tsn(:,:,:,jp_tem) = t_bkg(:,:,:) + t_bkginc(:,:,:) ENDIF IF (ln_salfix) THEN ! Do not apply negative increments if the salinity will fall below a specified ! minimum value salfixmin WHERE( s_bkginc(:,:,:) > 0.0_wp .OR. tsn(:,:,:,jp_sal) + s_bkginc(:,:,:) > salfixmin ) tsn(:,:,:,jp_sal) = s_bkg(:,:,:) + s_bkginc(:,:,:) END WHERE ELSE tsn(:,:,:,jp_sal) = s_bkg(:,:,:) + s_bkginc(:,:,:) ENDIF tsb(:,:,:,:) = tsn(:,:,:,:) ! Update before fields CALL eos( tsb, rhd, rhop, gdept_0(:,:,:) ) ! Before potential and in situ densities !!gm fabien ! CALL eos( tsb, rhd, rhop ) ! Before potential and in situ densities !!gm IF( ln_zps .AND. .NOT. lk_c1d .AND. .NOT. ln_isfcav) & & CALL zps_hde ( kt, jpts, tsb, gtsu, gtsv, & ! Partial steps: before horizontal gradient & rhd, gru , grv ) ! of t, s, rd at the last ocean level IF( ln_zps .AND. .NOT. lk_c1d .AND. ln_isfcav) & & CALL zps_hde_isf( nit000, jpts, tsb, gtsu, gtsv, gtui, gtvi, & ! Partial steps for top cell (ISF) & rhd, gru , grv , grui, grvi ) ! of t, s, rd at the last ocean level DEALLOCATE( t_bkginc ) DEALLOCATE( s_bkginc ) DEALLOCATE( t_bkg ) DEALLOCATE( s_bkg ) ENDIF ! ENDIF ! Perhaps the following call should be in step IF ( ln_seaiceinc ) CALL seaice_asm_inc ( kt ) ! apply sea ice concentration increment ! END SUBROUTINE tra_asm_inc SUBROUTINE dyn_asm_inc( kt ) !!---------------------------------------------------------------------- !! *** ROUTINE dyn_asm_inc *** !! !! ** Purpose : Apply the dynamics (u and v) assimilation increments. !! !! ** Method : Direct initialization or Incremental Analysis Updating. !! !! ** Action : !!---------------------------------------------------------------------- INTEGER, INTENT(IN) :: kt ! Current time step ! INTEGER :: jk INTEGER :: it REAL(wp) :: zincwgt ! IAU weight for current time step !!---------------------------------------------------------------------- ! ! !-------------------------------------------- IF ( ln_asmiau ) THEN ! Incremental Analysis Updating ! !-------------------------------------------- ! IF ( ( kt >= nitiaustr_r ).AND.( kt <= nitiaufin_r ) ) THEN ! it = kt - nit000 + 1 zincwgt = wgtiau(it) / rdt ! IAU weight for the current time step ! IF(lwp) THEN WRITE(numout,*) WRITE(numout,*) 'dyn_asm_inc : Dynamics IAU at time step = ', kt,' with IAU weight = ', wgtiau(it) WRITE(numout,*) '~~~~~~~~~~~~' ENDIF ! ! Update the dynamic tendencies DO jk = 1, jpkm1 ua(:,:,jk) = ua(:,:,jk) + u_bkginc(:,:,jk) * zincwgt va(:,:,jk) = va(:,:,jk) + v_bkginc(:,:,jk) * zincwgt END DO ! IF ( kt == nitiaufin_r ) THEN DEALLOCATE( u_bkginc ) DEALLOCATE( v_bkginc ) ENDIF ! ENDIF ! !----------------------------------------- ELSEIF ( ln_asmdin ) THEN ! Direct Initialization ! !----------------------------------------- ! IF ( kt == nitdin_r ) THEN ! neuler = 0 ! Force Euler forward step ! ! Initialize the now fields with the background + increment un(:,:,:) = u_bkg(:,:,:) + u_bkginc(:,:,:) vn(:,:,:) = v_bkg(:,:,:) + v_bkginc(:,:,:) ! ub(:,:,:) = un(:,:,:) ! Update before fields vb(:,:,:) = vn(:,:,:) ! DEALLOCATE( u_bkg ) DEALLOCATE( v_bkg ) DEALLOCATE( u_bkginc ) DEALLOCATE( v_bkginc ) ENDIF ! ENDIF ! END SUBROUTINE dyn_asm_inc SUBROUTINE ssh_asm_inc( kt ) !!---------------------------------------------------------------------- !! *** ROUTINE ssh_asm_inc *** !! !! ** Purpose : Apply the sea surface height assimilation increment. !! !! ** Method : Direct initialization or Incremental Analysis Updating. !! !! ** Action : !!---------------------------------------------------------------------- INTEGER, INTENT(IN) :: kt ! Current time step ! INTEGER :: it INTEGER :: jk REAL(wp) :: zincwgt ! IAU weight for current time step !!---------------------------------------------------------------------- ! ! !----------------------------------------- IF ( ln_asmiau ) THEN ! Incremental Analysis Updating ! !----------------------------------------- ! IF ( ( kt >= nitiaustr_r ).AND.( kt <= nitiaufin_r ) ) THEN ! it = kt - nit000 + 1 zincwgt = wgtiau(it) / rdt ! IAU weight for the current time step ! IF(lwp) THEN WRITE(numout,*) WRITE(numout,*) 'ssh_asm_inc : SSH IAU at time step = ', & & kt,' with IAU weight = ', wgtiau(it) WRITE(numout,*) '~~~~~~~~~~~~' ENDIF ! ! Save the tendency associated with the IAU weighted SSH increment ! (applied in dynspg.*) #if defined key_asminc ssh_iau(:,:) = ssh_bkginc(:,:) * zincwgt #endif ! ELSE IF( kt == nitiaufin_r+1 ) THEN ! ! test on ssh_bkginc needed as ssh_asm_inc is called twice by time step IF (ALLOCATED(ssh_bkginc)) DEALLOCATE( ssh_bkginc ) ! #if defined key_asminc ssh_iau(:,:) = 0._wp #endif ! ENDIF ! !----------------------------------------- ELSEIF ( ln_asmdin ) THEN ! Direct Initialization ! !----------------------------------------- ! IF ( kt == nitdin_r ) THEN ! neuler = 0 ! Force Euler forward step ! sshn(:,:) = ssh_bkg(:,:) + ssh_bkginc(:,:) ! Initialize the now fields the background + increment ! sshb(:,:) = sshn(:,:) ! Update before fields e3t_b(:,:,:) = e3t_n(:,:,:) !!gm why not e3u_b, e3v_b, gdept_b ???? ! DEALLOCATE( ssh_bkg ) DEALLOCATE( ssh_bkginc ) ! ENDIF ! ENDIF ! END SUBROUTINE ssh_asm_inc SUBROUTINE ssh_asm_div( kt, phdivn ) !!---------------------------------------------------------------------- !! *** ROUTINE ssh_asm_div *** !! !! ** Purpose : ssh increment with z* is incorporated via a correction of the local divergence !! across all the water column !! !! ** Method : !! CAUTION : sshiau is positive (inflow) decreasing the !! divergence and expressed in m/s !! !! ** Action : phdivn decreased by the ssh increment !!---------------------------------------------------------------------- INTEGER, INTENT(IN) :: kt ! ocean time-step index REAL(wp), DIMENSION(:,:,:), INTENT(inout) :: phdivn ! horizontal divergence !! INTEGER :: jk ! dummy loop index REAL(wp), DIMENSION(:,:) , POINTER :: ztim ! local array !!---------------------------------------------------------------------- ! #if defined key_asminc CALL ssh_asm_inc( kt ) !== (calculate increments) ! IF( ln_linssh ) THEN phdivn(:,:,1) = phdivn(:,:,1) - ssh_iau(:,:) / e3t_n(:,:,1) * tmask(:,:,1) ELSE ALLOCATE( ztim(jpi,jpj) ) ztim(:,:) = ssh_iau(:,:) / ( ht_n(:,:) + 1.0 - ssmask(:,:) ) DO jk = 1, jpkm1 phdivn(:,:,jk) = phdivn(:,:,jk) - ztim(:,:) * tmask(:,:,jk) END DO ! DEALLOCATE(ztim) ENDIF #endif ! END SUBROUTINE ssh_asm_div SUBROUTINE seaice_asm_inc( kt, kindic ) !!---------------------------------------------------------------------- !! *** ROUTINE seaice_asm_inc *** !! !! ** Purpose : Apply the sea ice assimilation increment. !! !! ** Method : Direct initialization or Incremental Analysis Updating. !! !! ** Action : !! !!---------------------------------------------------------------------- INTEGER, INTENT(in) :: kt ! Current time step INTEGER, INTENT(in), OPTIONAL :: kindic ! flag for disabling the deallocation ! INTEGER :: it, jk REAL(wp) :: zincwgt ! IAU weight for current time step #if defined key_si3 && defined key_asminc REAL(wp), DIMENSION(jpi,jpj,jpl) :: da_i ! change in ice concentration REAL(wp), DIMENSION(jpi,jpj,jpl) :: dv_i ! change in ice volume REAL(wp), DIMENSION(jpi,jpj,jpl) :: z1_a_i ! inverse of ice concentration before current IAU step REAL(wp), DIMENSION(jpi,jpj,jpl) :: z1_v_i ! inverse of ice volume before current IAU step REAL(wp), DIMENSION(jpi,jpj) :: zhi_damin_2D ! array with DA thickness for incr_newice #endif !!---------------------------------------------------------------------- ! ! !----------------------------------------- IF ( ln_asmiau ) THEN ! Incremental Analysis Updating ! !----------------------------------------- ! IF ( ( kt >= nitiaustr_r ).AND.( kt <= nitiaufin_r ) ) THEN ! it = kt - nit000 + 1 zincwgt = wgtiau(it) ! IAU weight for the current time step ! note this is not a tendency so should not be divided by rdt (as with the tracer and other increments) ! IF(lwp) THEN WRITE(numout,*) WRITE(numout,*) 'seaice_asm_inc : sea ice conc IAU at time step = ', kt,' with IAU weight = ', wgtiau(it) WRITE(numout,*) '~~~~~~~~~~~~' ENDIF ! ! Sea-ice : SI3 case ! #if defined key_si3 && defined key_asminc ! compute the inverse of key sea ice variables ! to be used later in the code WHERE( a_i(:,:,:) > epsi10 ) z1_a_i(:,:,:) = 1.0_wp / a_i(:,:,:) z1_v_i(:,:,:) = 1.0_wp / v_i(:,:,:) ELSEWHERE z1_a_i(:,:,:) = 0.0_wp z1_v_i(:,:,:) = 0.0_wp END WHERE ! add positive concentration increments to regions where ice ! is already present and bound them to 1 ! ice volume is added based on zhi_damin WHERE ( .NOT. incr_newice .AND. a_i_bkginc(:,:,:) > 0.0_wp ) a_i(:,:,:) = a_i(:,:,:) + MIN( 1.0_wp - a_i(:,:,:), a_i_bkginc(:,:,:) * zincwgt ) v_i(:,:,:) = v_i(:,:,:) + MIN( 1.0_wp - a_i(:,:,:), a_i_bkginc(:,:,:) * zincwgt ) * zhi_damin END WHERE ! add negative concentration increments to regions where ice ! is already present and bound them to 0 ! in this case ice volume is changed based on the current thickness WHERE ( .NOT. incr_newice .AND. a_i_bkginc(:,:,:) < 0.0_wp ) a_i(:,:,:) = MAX( a_i(:,:,:) + a_i_bkginc(:,:,:) * zincwgt, 0.0_wp ) v_i(:,:,:) = a_i(:,:,:) * h_i(:,:,:) END WHERE ! compute changes in ice concentration and volume WHERE ( incr_newice ) da_i(:,:,:) = 1.0_wp dv_i(:,:,:) = 1.0_wp ELSEWHERE da_i(:,:,:) = a_i(:,:,:) * z1_a_i(:,:,:) dv_i(:,:,:) = v_i(:,:,:) * z1_v_i(:,:,:) END WHERE ! initialise thermodynamics of new ice being added to open water ! just do it once since next IAU steps assume that new ice has ! already been added in IF ( kt == nitiaustr_r ) THEN ! assign zhi_damin to ice forming in open water WHERE ( ANY( incr_newice, DIM=3 ) ) zhi_damin_2D(:,:) = zhi_damin ELSEWHERE zhi_damin_2D(:,:) = 0.0_wp END WHERE ! add ice concentration and volume ! ensure the other prognostic variables are set to zero WHERE ( incr_newice ) a_i(:,:,:) = MIN( 1.0_wp, a_i_bkginc(:,:,:) * zincwgt ) v_i(:,:,:) = MIN( 1.0_wp, a_i_bkginc(:,:,:) * zincwgt ) * zhi_damin v_s (:,:,:) = 0.0_wp a_ip(:,:,:) = 0.0_wp v_ip(:,:,:) = 0.0_wp sv_i(:,:,:) = 0.0_wp END WHERE DO jk = 1, nlay_i WHERE ( incr_newice ) e_i(:,:,jk,:) = 0.0_wp END WHERE END DO DO jk = 1, nlay_s WHERE ( incr_newice ) e_s(:,:,jk,:) = 0.0_wp END WHERE END DO ! Initialisation of the salt content and ice enthalpy ! set flag of new ice to false after this CALL init_new_ice_thd( zhi_damin_2D ) incr_newice(:,:,:) = .FALSE. END IF ! maintain equivalent values for key prognostic variables v_s(:,:,:) = v_s(:,:,:) * da_i(:,:,:) DO jk = 1, nlay_s e_s(:,:,jk,:) = e_s(:,:,jk,:) * da_i(:,:,:) END DO a_ip (:,:,:) = a_ip(:,:,:) * da_i(:,:,:) v_ip (:,:,:) = v_ip(:,:,:) * da_i(:,:,:) ! ice volume dependent variables sv_i (:,:,:) = sv_i(:,:,:) * dv_i(:,:,:) DO jk = 1, nlay_i e_i(:,:,jk,:) = e_i(:,:,jk,:) * dv_i(:,:,:) END DO #endif #if defined key_cice && defined key_asminc ! Sea-ice : CICE case. Pass ice increment tendency into CICE ndaice_da(:,:) = seaice_bkginc(:,:) * zincwgt / rdt #endif ! IF ( kt == nitiaufin_r ) THEN DEALLOCATE( seaice_bkginc ) #if defined key_si3 && defined key_asminc DEALLOCATE( incr_newice ) DEALLOCATE( a_i_bkginc ) #endif ENDIF ! ELSE ! #if defined key_cice && defined key_asminc ndaice_da(:,:) = 0._wp ! Sea-ice : CICE case. Zero ice increment tendency into CICE #endif ! ENDIF ! !----------------------------------------- ELSEIF ( ln_asmdin ) THEN ! Direct Initialization ! !----------------------------------------- ! IF ( kt == nitdin_r ) THEN ! neuler = 0 ! Force Euler forward step IF(lwp) THEN WRITE(numout,*) WRITE(numout,*) 'seaice_asm_inc : sea ice direct initialization at time step = ', kt WRITE(numout,*) '~~~~~~~~~~~~' ENDIF ! #if defined key_cice && defined key_asminc ! Sea-ice : CICE case. Pass ice increment tendency into CICE ndaice_da(:,:) = seaice_bkginc(:,:) / rdt #endif IF ( .NOT. PRESENT(kindic) ) THEN DEALLOCATE( seaice_bkginc ) END IF ! ELSE ! #if defined key_cice && defined key_asminc ndaice_da(:,:) = 0._wp ! Sea-ice : CICE case. Zero ice increment tendency into CICE #endif ! ENDIF ! ENDIF ! END SUBROUTINE seaice_asm_inc SUBROUTINE init_new_ice_thd( hi_new ) !!---------------------------------------------------------------------- !! *** ROUTINE init_new_ice_thd *** !! !! ** Purpose : Initialise thermodynamics of new ice !! forming at 1st category with thickness hi_new !! !! ** Method : Apply SI3 equations to initialise !! thermodynamics of new ice !! !! ** Action : update sea ice thermodynamics !!---------------------------------------------------------------------- REAL(wp), DIMENSION(jpi,jpj), INTENT(in) :: hi_new ! total thickness of new ice INTEGER :: jj, ji, jk REAL(wp) :: ztmelts ! melting point REAL(wp), DIMENSION(jpij) :: zh_newice ! 1d version of hi_new REAL(wp), DIMENSION(jpij) :: zs_newice ! salinity of new ice !!---------------------------------------------------------------------- ! Identify grid points where new ice forms npti = 0 ; nptidx(:) = 0 DO jj = 1, jpj DO ji = 1, jpi IF ( hi_new(ji,jj) > 0._wp ) THEN npti = npti + 1 nptidx( npti ) = (jj - 1) * jpi + ji ENDIF END DO END DO ! Move from 2-D to 1-D vectors IF ( npti > 0 ) THEN CALL tab_3d_2d( npti, nptidx(1:npti), sv_i_2d(1:npti,1:jpl), sv_i(:,:,:) ) CALL tab_3d_2d( npti, nptidx(1:npti), v_i_2d (1:npti,1:jpl), v_i (:,:,:) ) CALL tab_2d_1d( npti, nptidx(1:npti), zh_newice (1:npti) , hi_new ) CALL tab_2d_1d( npti, nptidx(1:npti), sss_1d (1:npti) , sss_m ) CALL tab_2d_1d( npti, nptidx(1:npti), t_bo_1d (1:npti) , t_bo ) DO jk = 1, nlay_i CALL tab_2d_1d( npti, nptidx(1:npti), e_i_1d(1:npti,jk), e_i(:,:,jk,1) ) END DO ! --- Salinity of new ice --- ! SELECT CASE ( nn_icesal ) CASE ( 1 ) ! Sice = constant zs_newice(1:npti) = rn_icesal CASE ( 2 ) ! Sice = F(z,t) [Vancoppenolle et al (2005)] DO ji = 1, npti zs_newice(ji) = MIN( 4.606_wp + 0.91_wp / zh_newice(ji) , rn_simax , 0.5_wp * sss_1d(ji) ) END DO CASE ( 3 ) ! Sice = F(z) [multiyear ice] zs_newice(1:npti) = 2.3_wp END SELECT ! --- Update ice salt content --- ! DO ji = 1, npti sv_i_2d(ji,1) = sv_i_2d(ji,1) + zs_newice(ji) * ( v_i_2d(ji,1) ) END DO ! --- Heat content of new ice --- ! ! We assume that new ice is formed at the seawater freezing point DO ji = 1, npti ztmelts = - rTmlt * zs_newice(ji) ! Melting point (C) e_i_1d(ji,:) = rhoi * ( rcpi * ( ztmelts - ( t_bo_1d(ji) - rt0 ) ) & & + rLfus * ( 1.0_wp - ztmelts / MIN( t_bo_1d(ji) - rt0, -epsi10 ) ) & & - rcp * ztmelts ) END DO ! Change units for e_i DO jk = 1, nlay_i e_i_1d(1:npti,jk) = e_i_1d(1:npti,jk) * v_i_2d(1:npti,1) * r1_nlay_i END DO ! Reforming full thermodynamic variables CALL tab_2d_3d( npti, nptidx(1:npti), sv_i_2d(1:npti,1:jpl), sv_i(:,:,:) ) DO jk = 1, nlay_i CALL tab_1d_2d( npti, nptidx(1:npti), e_i_1d(1:npti,jk), e_i(:,:,jk,1) ) END DO END IF END SUBROUTINE init_new_ice_thd !!====================================================================== END MODULE asminc