Skip to content
Snippets Groups Projects
sbcblk.F90 83.3 KiB
Newer Older
Guillaume Samson's avatar
Guillaume Samson committed
      !!---------------------------------------------------------------------
      REAL(wp) , INTENT(in   ), DIMENSION(:,:  ) ::   pslp    ! sea-level pressure [Pa]
      REAL(wp) , INTENT(in   ), DIMENSION(:,:  ) ::   pwndi   ! atmospheric wind at T-point [m/s]
      REAL(wp) , INTENT(in   ), DIMENSION(:,:  ) ::   pwndj   ! atmospheric wind at T-point [m/s]
      REAL(wp) , INTENT(in   ), DIMENSION(:,:  ) ::   ptair   ! atmospheric potential temperature at T-point [K]
      REAL(wp) , INTENT(in   ), DIMENSION(:,:  ) ::   pqair   ! atmospheric specific humidity at T-point [kg/kg]
Guillaume Samson's avatar
Guillaume Samson committed
      REAL(wp) , INTENT(in   ), DIMENSION(:,:  ) ::   puice   ! sea-ice velocity on I or C grid [m/s]
      REAL(wp) , INTENT(in   ), DIMENSION(:,:  ) ::   pvice   ! "
      REAL(wp) , INTENT(in   ), DIMENSION(:,:  ) ::   ptsui   ! sea-ice surface temperature [K]
      REAL(wp) , INTENT(  out), DIMENSION(:,:  ), OPTIONAL ::   putaui  ! if ln_blk
      REAL(wp) , INTENT(  out), DIMENSION(:,:  ), OPTIONAL ::   pvtaui  ! if ln_blk
      REAL(wp) , INTENT(  out), DIMENSION(:,:  ), OPTIONAL ::   pseni   ! if ln_abl
      REAL(wp) , INTENT(  out), DIMENSION(:,:  ), OPTIONAL ::   pevpi   ! if ln_abl
      REAL(wp) , INTENT(  out), DIMENSION(:,:  ), OPTIONAL ::   pssqi   ! if ln_abl
      REAL(wp) , INTENT(  out), DIMENSION(:,:  ), OPTIONAL ::   pcd_dui ! if ln_abl
      !
      INTEGER  ::   ji, jj    ! dummy loop indices
      REAL(wp) ::   zootm_su                      ! sea-ice surface mean temperature
      REAL(wp) ::   zztmp1, zztmp2                ! temporary scalars
      REAL(wp), DIMENSION(jpi,jpj) :: ztmp, zsipt ! temporary array
Guillaume Samson's avatar
Guillaume Samson committed
      !!---------------------------------------------------------------------
      !
      ! ------------------------------------------------------------ !
      !    Wind module relative to the moving ice ( U10m - U_ice )   !
      ! ------------------------------------------------------------ !
      ! C-grid ice dynamics :   U & V-points (same as ocean)
      DO_2D( nn_hls, nn_hls, nn_hls, nn_hls )
         wndm_ice(ji,jj) = SQRT( pwndi(ji,jj) * pwndi(ji,jj) + pwndj(ji,jj) * pwndj(ji,jj) )
      END_2D
      !
      ! potential sea-ice surface temperature [K]
      zsipt(:,:) = theta_exner( ptsui(:,:), pslp(:,:) )
Guillaume Samson's avatar
Guillaume Samson committed

      ! sea-ice <-> atmosphere bulk transfer coefficients
Guillaume Samson's avatar
Guillaume Samson committed
      SELECT CASE( nblk_ice )

      CASE( np_ice_cst      )
         ! Constant bulk transfer coefficients over sea-ice:
         Cd_ice(:,:) = rn_Cd_i
         Ch_ice(:,:) = rn_Ch_i
         Ce_ice(:,:) = rn_Ce_i
         ! no height adjustment, keeping zt values:
         theta_zu_i(:,:) = ptair(:,:)
         q_zu_i(:,:)     = pqair(:,:)

      CASE( np_ice_an05 )  ! calculate new drag from Lupkes(2015) equations
         ztmp(:,:) = q_sat( ptsui(:,:), pslp(:,:), l_ice=.TRUE. ) ! temporary array for SSQ
         CALL turb_ice_an05( rn_zqt, rn_zu, zsipt, ptair, ztmp, pqair, wndm_ice,       &
Guillaume Samson's avatar
Guillaume Samson committed
            &                      Cd_ice, Ch_ice, Ce_ice, theta_zu_i, q_zu_i )
         !!
      CASE( np_ice_lu12 )
         ztmp(:,:) = q_sat( ptsui(:,:), pslp(:,:), l_ice=.TRUE. ) ! temporary array for SSQ
         CALL turb_ice_lu12( rn_zqt, rn_zu, zsipt, ptair, ztmp, pqair, wndm_ice, fr_i, &
Guillaume Samson's avatar
Guillaume Samson committed
            &                      Cd_ice, Ch_ice, Ce_ice, theta_zu_i, q_zu_i )
         !!
      CASE( np_ice_lg15 )  ! calculate new drag from Lupkes(2015) equations
         ztmp(:,:) = q_sat( ptsui(:,:), pslp(:,:), l_ice=.TRUE. ) ! temporary array for SSQ
         CALL turb_ice_lg15( rn_zqt, rn_zu, zsipt, ptair, ztmp, pqair, wndm_ice, fr_i, &
Guillaume Samson's avatar
Guillaume Samson committed
            &                      Cd_ice, Ch_ice, Ce_ice, theta_zu_i, q_zu_i )
         !!
      END SELECT

      IF( iom_use('Cd_ice').OR.iom_use('Ce_ice').OR.iom_use('Ch_ice').OR.iom_use('taum_ice').OR.iom_use('utau_ice').OR.iom_use('vtau_ice') ) &
         & ztmp(:,:) = ( 1._wp - MAX(0._wp, SIGN( 1._wp, 1.E-6_wp - fr_i )) )*tmask(:,:,1) ! mask for presence of ice !

      IF( iom_use('Cd_ice') ) CALL iom_put("Cd_ice", Cd_ice*ztmp)
      IF( iom_use('Ce_ice') ) CALL iom_put("Ce_ice", Ce_ice*ztmp)
      IF( iom_use('Ch_ice') ) CALL iom_put("Ch_ice", Ch_ice*ztmp)


      IF( ln_blk ) THEN
         ! ---------------------------------------------------- !
         !    Wind stress relative to nonmoving ice ( U10m )    !
         ! ---------------------------------------------------- !
         ! supress moving ice in wind stress computation as we don't know how to do it properly...
         DO_2D( 0, 1, 0, 1 )    ! at T point
            zztmp1        = rhoa(ji,jj) * Cd_ice(ji,jj) * wndm_ice(ji,jj)
            putaui(ji,jj) = zztmp1 * pwndi(ji,jj)
            pvtaui(ji,jj) = zztmp1 * pwndj(ji,jj)
Guillaume Samson's avatar
Guillaume Samson committed
         END_2D

         !#LB: saving the module, and x-y components, of the ai wind-stress at T-points: NOT weighted by the ice concentration !!!
         IF(iom_use('taum_ice')) CALL iom_put('taum_ice', SQRT( putaui*putaui + pvtaui*pvtaui )*ztmp )
         !#LB: These 2 lines below mostly here for 'STATION_ASF' test-case, otherwize "utau_oi" (U-grid) and vtau_oi" (V-grid) does the job in: [ICE/icedyn_rhg_evp.F90])
         IF(iom_use('utau_ice')) CALL iom_put("utau_ice", putaui*ztmp)  ! utau at T-points!
         IF(iom_use('vtau_ice')) CALL iom_put("vtau_ice", pvtaui*ztmp)  ! vtau at T-points!

         !
         DO_2D( 0, 0, 0, 0 )    ! U & V-points (same as ocean).
            !#LB: QUESTION?? so SI3 expects wind stress vector to be provided at U & V points? Not at T-points ?
            ! take care of the land-sea mask to avoid "pollution" of coastal stress. p[uv]taui used in frazil and  rheology
            zztmp1 = 0.5_wp * ( 2. - umask(ji,jj,1) ) * MAX( tmask(ji,jj,1),tmask(ji+1,jj  ,1) )
            zztmp2 = 0.5_wp * ( 2. - vmask(ji,jj,1) ) * MAX( tmask(ji,jj,1),tmask(ji  ,jj+1,1) )
            putaui(ji,jj) = zztmp1 * ( putaui(ji,jj) + putaui(ji+1,jj  ) )
            pvtaui(ji,jj) = zztmp2 * ( pvtaui(ji,jj) + pvtaui(ji  ,jj+1) )
         END_2D
         CALL lbc_lnk( 'sbcblk', putaui, 'U', -1._wp, pvtaui, 'V', -1._wp )
         !
         IF(sn_cfctl%l_prtctl)  CALL prt_ctl( tab2d_1=putaui  , clinfo1=' blk_ice: putaui : ', mask1=umask   &
            &                               , tab2d_2=pvtaui  , clinfo2='          pvtaui : ', mask2=vmask )
Guillaume Samson's avatar
Guillaume Samson committed
      ELSE ! ln_abl
Guillaume Samson's avatar
Guillaume Samson committed
         DO_2D( nn_hls, nn_hls, nn_hls, nn_hls )
            pcd_dui(ji,jj) = wndm_ice(ji,jj) * Cd_ice(ji,jj)
            pseni  (ji,jj) = wndm_ice(ji,jj) * Ch_ice(ji,jj)
            pevpi  (ji,jj) = wndm_ice(ji,jj) * Ce_ice(ji,jj)
Guillaume Samson's avatar
Guillaume Samson committed
         END_2D
         pssqi(:,:) = q_sat( ptsui(:,:), pslp(:,:), l_ice=.TRUE. ) ; ! more accurate way to obtain ssq !
Guillaume Samson's avatar
Guillaume Samson committed
      !
      IF(sn_cfctl%l_prtctl)  CALL prt_ctl(tab2d_1=wndm_ice  , clinfo1=' blk_ice: wndm_ice : ', mask1=tmask )
Guillaume Samson's avatar
Guillaume Samson committed
      !
   END SUBROUTINE blk_ice_1


   SUBROUTINE blk_ice_2( ptsu, phs, phi, palb, ptair, pqair, pslp, pdqlw, pprec, psnow  )
      !!---------------------------------------------------------------------
      !!                     ***  ROUTINE blk_ice_2  ***
      !!
      !! ** Purpose :   provide the heat and mass fluxes at air-ice interface
      !!
      !! ** Method  :   compute heat and freshwater exchanged
      !!                between atmosphere and sea-ice using bulk formulation
      !!                formulea, ice variables and read atmmospheric fields.
      !!
      !! caution : the net upward water flux has with mm/day unit
      !!---------------------------------------------------------------------
      REAL(wp), DIMENSION(:,:,:), INTENT(in)  ::   ptsu   ! sea ice surface temperature [K]
      REAL(wp), DIMENSION(:,:,:), INTENT(in)  ::   phs    ! snow thickness
      REAL(wp), DIMENSION(:,:,:), INTENT(in)  ::   phi    ! ice thickness
      REAL(wp), DIMENSION(:,:,:), INTENT(in)  ::   palb   ! ice albedo (all skies)
      REAL(wp), DIMENSION(:,:  ), INTENT(in)  ::   ptair  ! potential temperature of air #LB: okay ???
      REAL(wp), DIMENSION(:,:  ), INTENT(in)  ::   pqair  ! specific humidity of air
      REAL(wp), DIMENSION(:,:  ), INTENT(in)  ::   pslp
      REAL(wp), DIMENSION(:,:  ), INTENT(in)  ::   pdqlw
      REAL(wp), DIMENSION(:,:  ), INTENT(in)  ::   pprec
      REAL(wp), DIMENSION(:,:  ), INTENT(in)  ::   psnow
      !!
      INTEGER  ::   ji, jj, jl               ! dummy loop indices
      REAL(wp) ::   zst, zst3, zsq, zsipt    ! local variable
Guillaume Samson's avatar
Guillaume Samson committed
      REAL(wp) ::   zcoef_dqlw, zcoef_dqla   !   -      -
      REAL(wp) ::   zztmp, zzblk, zztmp1, z1_rLsub   !   -      -
      REAL(wp), DIMENSION(:,:,:), ALLOCATABLE ::   zmsk   ! temporary mask for prt_ctl
Guillaume Samson's avatar
Guillaume Samson committed
      REAL(wp), DIMENSION(jpi,jpj,jpl) ::   z_qlw         ! long wave heat flux over ice
      REAL(wp), DIMENSION(jpi,jpj,jpl) ::   z_qsb         ! sensible  heat flux over ice
      REAL(wp), DIMENSION(jpi,jpj,jpl) ::   z_dqlw        ! long wave heat sensitivity over ice
      REAL(wp), DIMENSION(jpi,jpj,jpl) ::   z_dqsb        ! sensible  heat sensitivity over ice
      REAL(wp), DIMENSION(jpi,jpj)     ::   zevap, zsnw   ! evaporation and snw distribution after wind blowing (SI3)
      REAL(wp), DIMENSION(jpi,jpj)     ::   ztmp, ztmp2
Guillaume Samson's avatar
Guillaume Samson committed
      REAL(wp), DIMENSION(jpi,jpj)     ::   ztri
      REAL(wp), DIMENSION(jpi,jpj)     ::   zcptrain, zcptsnw, zcptn ! Heat content per unit mass (J/kg)
      !!---------------------------------------------------------------------
      !
      zcoef_dqlw = 4._wp * emiss_i * stefan             ! local scalars
      zztmp = 1. / ( 1. - albo )
      dqla_ice(:,:,:) = 0._wp

      ! Heat content per unit mass (J/kg)
      zcptrain(:,:) = (      ptair        - rt0 ) * rcp  * tmask(:,:,1)
      zcptsnw (:,:) = ( MIN( ptair, rt0 ) - rt0 ) * rcpi * tmask(:,:,1)
      zcptn   (:,:) =        sst_m                * rcp  * tmask(:,:,1)
      !
      !                                     ! ========================== !
      DO jl = 1, jpl                        !  Loop over ice categories  !
         !                                  ! ========================== !
         DO_2D( nn_hls, nn_hls, nn_hls, nn_hls )

            zst   = ptsu(ji,jj,jl)                                ! surface temperature of sea-ice [K]
            zsq   = q_sat( zst, pslp(ji,jj), l_ice=.TRUE. )       ! surface saturation specific humidity when ice present
            zsipt = theta_exner( zst, pslp(ji,jj) )               ! potential sea-ice surface temperature [K]  

            ! ----------------------------!
            !      I   Radiative FLUXES   !
            ! ----------------------------!
            ! Short Wave (sw)
            qsr_ice(ji,jj,jl) = zztmp * ( 1. - palb(ji,jj,jl) ) * qsr(ji,jj)

            ! Long  Wave (lw)
            zst3 = zst * zst * zst
            z_qlw(ji,jj,jl)   = emiss_i * ( pdqlw(ji,jj) - stefan * zst * zst3 ) * tmask(ji,jj,1)
            ! lw sensitivity
            z_dqlw(ji,jj,jl)  = zcoef_dqlw * zst3

            ! ----------------------------!
            !     II    Turbulent FLUXES  !
            ! ----------------------------!

            ! ... turbulent heat fluxes with Ch_ice recalculated in blk_ice_1

            ! Common term in bulk F. equations...
            zzblk = rhoa(ji,jj) * wndm_ice(ji,jj)

            ! Sensible Heat
            zztmp1 = zzblk * rCp_air * Ch_ice(ji,jj)
            z_qsb (ji,jj,jl) = zztmp1 * (zsipt - theta_zu_i(ji,jj))
            z_dqsb(ji,jj,jl) = zztmp1                        ! ==> Qsens sensitivity (Dqsb_ice/Dtn_ice)

            ! Latent Heat
            zztmp1 = zzblk * rLsub * Ce_ice(ji,jj)
            qla_ice(ji,jj,jl) = MAX( zztmp1 * (zsq - q_zu_i(ji,jj)) , 0._wp )   ! #LB: only sublimation (and not condensation) ???
            IF(qla_ice(ji,jj,jl)>0._wp) dqla_ice(ji,jj,jl) = zztmp1*dq_sat_dt_ice(zst, pslp(ji,jj)) ! ==> Qlat sensitivity  (dQlat/dT)
            !                                                                                       !#LB: dq_sat_dt_ice() in "sbc_phy.F90"
            !#LB: without this unjustified "condensation sensure":
            !qla_ice( ji,jj,jl) = zztmp1 * (zsq - q_zu_i(ji,jj))
            !dqla_ice(ji,jj,jl) = zztmp1 * dq_sat_dt_ice(zst, pslp(ji,jj)) ! ==> Qlat sensitivity  (dQlat/dT)


            ! ----------------------------!
            !     III    Total FLUXES     !
            ! ----------------------------!
            ! Downward Non Solar flux
            qns_ice (ji,jj,jl) =     z_qlw (ji,jj,jl) - z_qsb (ji,jj,jl) - qla_ice (ji,jj,jl)
            ! Total non solar heat flux sensitivity for ice
            dqns_ice(ji,jj,jl) = - ( z_dqlw(ji,jj,jl) + z_dqsb(ji,jj,jl) + dqla_ice(ji,jj,jl) ) !#LB: correct signs ????
Guillaume Samson's avatar
Guillaume Samson committed

         END_2D
         !
      END DO
      !
      tprecip(:,:) = pprec(:,:) * rn_pfac * tmask(:,:,1)  ! total precipitation [kg/m2/s]
      sprecip(:,:) = psnow(:,:) * rn_pfac * tmask(:,:,1)  ! solid precipitation [kg/m2/s]
      CALL iom_put( 'snowpre', sprecip )                  ! Snow precipitation
      CALL iom_put( 'precip' , tprecip )                  ! Total precipitation

      ! --- evaporation --- !
      z1_rLsub = 1._wp / rLsub
      evap_ice (:,:,:) = rn_efac * qla_ice (:,:,:) * z1_rLsub    ! sublimation
      devap_ice(:,:,:) = rn_efac * dqla_ice(:,:,:) * z1_rLsub    ! d(sublimation)/dT
      zevap    (:,:)   = emp(:,:) + tprecip(:,:)   ! evaporation over ocean  !LB: removed rn_efac here, correct???

      ! --- evaporation minus precipitation --- !
      zsnw(:,:) = 0._wp
      CALL ice_var_snwblow( (1.-at_i_b(:,:)), zsnw )  ! snow distribution over ice after wind blowing
      emp_oce(:,:) = ( 1._wp - at_i_b(:,:) ) * zevap(:,:) - ( tprecip(:,:) - sprecip(:,:) ) - sprecip(:,:) * (1._wp - zsnw )
      emp_ice(:,:) = SUM( a_i_b(:,:,:) * evap_ice(:,:,:), dim=3 ) - sprecip(:,:) * zsnw
      emp_tot(:,:) = emp_oce(:,:) + emp_ice(:,:)

      ! --- heat flux associated with emp --- !
      qemp_oce(:,:) = - ( 1._wp - at_i_b(:,:) ) * zevap(:,:) * zcptn(:,:)         & ! evap at sst
         &          + ( tprecip(:,:) - sprecip(:,:) )   *   zcptrain(:,:)         & ! liquid precip at Tair
         &          +   sprecip(:,:) * ( 1._wp - zsnw ) * ( zcptsnw (:,:) - rLfus ) ! solid precip at min(Tair,Tsnow)
      qemp_ice(:,:) =   sprecip(:,:) *           zsnw   * ( zcptsnw (:,:) - rLfus ) ! solid precip (only)

      ! --- total solar and non solar fluxes --- !
      qns_tot(:,:) = ( 1._wp - at_i_b(:,:) ) * qns_oce(:,:) + SUM( a_i_b(:,:,:) * qns_ice(:,:,:), dim=3 )  &
         &           + qemp_ice(:,:) + qemp_oce(:,:)
      qsr_tot(:,:) = ( 1._wp - at_i_b(:,:) ) * qsr_oce(:,:) + SUM( a_i_b(:,:,:) * qsr_ice(:,:,:), dim=3 )

      ! --- heat content of precip over ice in J/m3 (to be used in 1D-thermo) --- !
      qprec_ice(:,:) = rhos * ( zcptsnw(:,:) - rLfus )

      ! --- heat content of evap over ice in W/m2 (to be used in 1D-thermo) ---
      DO jl = 1, jpl
         qevap_ice(:,:,jl) = 0._wp ! should be -evap_ice(:,:,jl)*( ( Tice - rt0 ) * rcpi * tmask(:,:,1) )
         !                         ! But we do not have Tice => consider it at 0degC => evap=0
      END DO

      ! --- shortwave radiation transmitted thru the surface scattering layer (W/m2) --- !
      IF( nn_qtrice == 0 ) THEN
         ! formulation derived from Grenfell and Maykut (1977), where transmission rate
         !    1) depends on cloudiness
         !    2) is 0 when there is any snow
         !    3) tends to 1 for thin ice
         ztri(:,:) = 0.18 * ( 1.0 - cloud_fra(:,:) ) + 0.35 * cloud_fra(:,:)  ! surface transmission when hi>10cm
         DO jl = 1, jpl
            WHERE    ( phs(:,:,jl) <= 0._wp .AND. phi(:,:,jl) <  0.1_wp )     ! linear decrease from hi=0 to 10cm
               qtr_ice_top(:,:,jl) = qsr_ice(:,:,jl) * ( ztri(:,:) + ( 1._wp - ztri(:,:) ) * ( 1._wp - phi(:,:,jl) * 10._wp ) )
            ELSEWHERE( phs(:,:,jl) <= 0._wp .AND. phi(:,:,jl) >= 0.1_wp )     ! constant (ztri) when hi>10cm
               qtr_ice_top(:,:,jl) = qsr_ice(:,:,jl) * ztri(:,:)
            ELSEWHERE                                                         ! zero when hs>0
               qtr_ice_top(:,:,jl) = 0._wp
            END WHERE
         ENDDO
      ELSEIF( nn_qtrice == 1 ) THEN
         ! formulation is derived from the thesis of M. Lebrun (2019).
         !    It represents the best fit using several sets of observations
         !    It comes with snow conductivities adapted to freezing/melting conditions (see icethd_zdf_bl99.F90)
         qtr_ice_top(:,:,:) = 0.3_wp * qsr_ice(:,:,:)
      ENDIF
      !
      IF( iom_use('evap_ao_cea') .OR. iom_use('hflx_evap_cea') ) THEN
         CALL iom_put( 'evap_ao_cea'  , zevap(:,:) * ( 1._wp - at_i_b(:,:) ) * tmask(:,:,1)              )   ! ice-free oce evap (cell average)
         CALL iom_put( 'hflx_evap_cea', zevap(:,:) * ( 1._wp - at_i_b(:,:) ) * tmask(:,:,1) * zcptn(:,:) )   ! heat flux from evap (cell average)
      ENDIF
      IF( iom_use('rain') .OR. iom_use('rain_ao_cea') .OR. iom_use('hflx_rain_cea') ) THEN
         CALL iom_put( 'rain'         ,   tprecip(:,:) - sprecip(:,:)                             )          ! liquid precipitation 
         CALL iom_put( 'rain_ao_cea'  , ( tprecip(:,:) - sprecip(:,:) ) * ( 1._wp - at_i_b(:,:) ) )          ! liquid precipitation over ocean (cell average)
         CALL iom_put( 'hflx_rain_cea', ( tprecip(:,:) - sprecip(:,:) ) * zcptrain(:,:) )                    ! heat flux from rain (cell average)
      ENDIF
      IF(  iom_use('snow_ao_cea')   .OR. iom_use('snow_ai_cea')      .OR. &
         & iom_use('hflx_snow_cea') .OR. iom_use('hflx_snow_ao_cea') .OR. iom_use('hflx_snow_ai_cea')  )  THEN
         CALL iom_put( 'snow_ao_cea'     , sprecip(:,:)                            * ( 1._wp - zsnw(:,:) ) ) ! Snow over ice-free ocean  (cell average)
         CALL iom_put( 'snow_ai_cea'     , sprecip(:,:)                            *           zsnw(:,:)   ) ! Snow over sea-ice         (cell average)
         CALL iom_put( 'hflx_snow_cea'   , sprecip(:,:) * ( zcptsnw(:,:) - rLfus ) )                         ! heat flux from snow (cell average)
         CALL iom_put( 'hflx_snow_ao_cea', sprecip(:,:) * ( zcptsnw(:,:) - rLfus ) * ( 1._wp - zsnw(:,:) ) ) ! heat flux from snow (over ocean)
         CALL iom_put( 'hflx_snow_ai_cea', sprecip(:,:) * ( zcptsnw(:,:) - rLfus ) *           zsnw(:,:)   ) ! heat flux from snow (over ice)
      ENDIF
      IF( iom_use('hflx_prec_cea') ) THEN                                                                    ! heat flux from precip (cell average)
         CALL iom_put('hflx_prec_cea' ,    sprecip(:,:)                  * ( zcptsnw (:,:) - rLfus )  &
            &                          + ( tprecip(:,:) - sprecip(:,:) ) *   zcptrain(:,:) )
      ENDIF
      IF( iom_use('subl_ai_cea') .OR. iom_use('hflx_subl_cea') ) THEN
         CALL iom_put( 'subl_ai_cea'  , SUM( a_i_b(:,:,:) *  evap_ice(:,:,:), dim=3 ) * tmask(:,:,1) ) ! Sublimation over sea-ice (cell average)
         CALL iom_put( 'hflx_subl_cea', SUM( a_i_b(:,:,:) * qevap_ice(:,:,:), dim=3 ) * tmask(:,:,1) ) ! Heat flux from sublimation (cell average)
      ENDIF
      !
      IF(sn_cfctl%l_prtctl) THEN
         ALLOCATE(zmsk(jpi,jpj,jpl))
         DO jl = 1, jpl
            zmsk(:,:,jpl) = tmask(:,:,1)
         END DO
         CALL prt_ctl(tab3d_1=qla_ice , clinfo1=' blk_ice: qla_ice  : ', mask1=zmsk,   &
            &         tab3d_2=z_qsb   , clinfo2=' z_qsb    : '         , mask2=zmsk, kdim=jpl)
         CALL prt_ctl(tab3d_1=z_qlw   , clinfo1=' blk_ice: z_qlw    : ', mask1=zmsk,   &
            &         tab3d_2=dqla_ice, clinfo2=' dqla_ice : '         , mask2=zmsk, kdim=jpl)
         CALL prt_ctl(tab3d_1=z_dqsb  , clinfo1=' blk_ice: z_dqsb   : ', mask1=zmsk,   &
            &         tab3d_2=z_dqlw  , clinfo2=' z_dqlw   : '         , mask2=zmsk, kdim=jpl)
         CALL prt_ctl(tab3d_1=dqns_ice, clinfo1=' blk_ice: dqns_ice : ', mask1=zmsk,   &
            &         tab3d_2=qsr_ice , clinfo2=' qsr_ice  : '         , mask2=zmsk, kdim=jpl)
         CALL prt_ctl(tab3d_1=ptsu    , clinfo1=' blk_ice: ptsu     : ', mask1=zmsk,   &
            &         tab3d_2=qns_ice , clinfo2=' qns_ice  : '         , mask2=zmsk, kdim=jpl)
         CALL prt_ctl(tab2d_1=tprecip , clinfo1=' blk_ice: tprecip  : ', mask1=tmask,   &
            &         tab2d_2=sprecip , clinfo2=' sprecip  : '         , mask2=tmask         )
         DEALLOCATE(zmsk)
Guillaume Samson's avatar
Guillaume Samson committed
      ENDIF

      !#LB:
      ! air-ice heat flux components that are not written from ice_stp()@icestp.F90:
      IF( iom_use('qla_ice') )  CALL iom_put( 'qla_ice', SUM( - qla_ice * a_i_b, dim=3 ) ) !#LB: sign consistent with what's done for ocean
      IF( iom_use('qsb_ice') )  CALL iom_put( 'qsb_ice', SUM( -   z_qsb * a_i_b, dim=3 ) ) !#LB:     ==> negative => loss of heat for sea-ice
      IF( iom_use('qlw_ice') )  CALL iom_put( 'qlw_ice', SUM(     z_qlw * a_i_b, dim=3 ) )
      !#LB.

   END SUBROUTINE blk_ice_2


   SUBROUTINE blk_ice_qcn( ld_virtual_itd, ptsu, ptb, phs, phi )
      !!---------------------------------------------------------------------
      !!                     ***  ROUTINE blk_ice_qcn  ***
      !!
      !! ** Purpose :   Compute surface temperature and snow/ice conduction flux
      !!                to force sea ice / snow thermodynamics
      !!                in the case conduction flux is emulated
      !!
      !! ** Method  :   compute surface energy balance assuming neglecting heat storage
      !!                following the 0-layer Semtner (1976) approach
      !!
      !! ** Outputs : - ptsu    : sea-ice / snow surface temperature (K)
      !!              - qcn_ice : surface inner conduction flux (W/m2)
      !!
      !!---------------------------------------------------------------------
      LOGICAL                   , INTENT(in   ) ::   ld_virtual_itd  ! single-category option
      REAL(wp), DIMENSION(:,:,:), INTENT(inout) ::   ptsu            ! sea ice / snow surface temperature
      REAL(wp), DIMENSION(:,:)  , INTENT(in   ) ::   ptb             ! sea ice base temperature
      REAL(wp), DIMENSION(:,:,:), INTENT(in   ) ::   phs             ! snow thickness
      REAL(wp), DIMENSION(:,:,:), INTENT(in   ) ::   phi             ! sea ice thickness
      !
      INTEGER , PARAMETER ::   nit = 10                  ! number of iterations
      REAL(wp), PARAMETER ::   zepsilon = 0.1_wp         ! characteristic thickness for enhanced conduction
      !
      INTEGER  ::   ji, jj, jl           ! dummy loop indices
      INTEGER  ::   iter                 ! local integer
      REAL(wp) ::   zfac, zfac2, zfac3   ! local scalars
      REAL(wp) ::   zkeff_h, ztsu, ztsu0 !
      REAL(wp) ::   zqc, zqnet           !
      REAL(wp) ::   zhe, zqa0            !
      REAL(wp), DIMENSION(jpi,jpj,jpl) ::   zgfac   ! enhanced conduction factor
      !!---------------------------------------------------------------------

      ! -------------------------------------!
      !      I   Enhanced conduction factor  !
      ! -------------------------------------!
      ! Emulates the enhancement of conduction by unresolved thin ice (ld_virtual_itd = T)
      ! Fichefet and Morales Maqueda, JGR 1997
      !
      zgfac(:,:,:) = 1._wp

      IF( ld_virtual_itd ) THEN
         !
         zfac  = 1._wp /  ( rn_cnd_s + rcnd_i )
         zfac2 = EXP(1._wp) * 0.5_wp * zepsilon
         zfac3 = 2._wp / zepsilon
         !
         DO jl = 1, jpl
            DO_2D( nn_hls, nn_hls, nn_hls, nn_hls )
               zhe = ( rn_cnd_s * phi(ji,jj,jl) + rcnd_i * phs(ji,jj,jl) ) * zfac                            ! Effective thickness
               IF( zhe >=  zfac2 )   zgfac(ji,jj,jl) = MIN( 2._wp, 0.5_wp * ( 1._wp + LOG( zhe * zfac3 ) ) ) ! Enhanced conduction factor
            END_2D
         END DO
         !
      ENDIF

      ! -------------------------------------------------------------!
      !      II   Surface temperature and conduction flux            !
      ! -------------------------------------------------------------!
      !
      zfac = rcnd_i * rn_cnd_s
      !
      DO jl = 1, jpl
         DO_2D( nn_hls, nn_hls, nn_hls, nn_hls )
            !
            zkeff_h = zfac * zgfac(ji,jj,jl) / &                                    ! Effective conductivity of the snow-ice system divided by thickness
               &      ( rcnd_i * phs(ji,jj,jl) + rn_cnd_s * MAX( 0.01, phi(ji,jj,jl) ) )
            ztsu    = ptsu(ji,jj,jl)                                                ! Store current iteration temperature
            ztsu0   = ptsu(ji,jj,jl)                                                ! Store initial surface temperature
            zqa0    = qsr_ice(ji,jj,jl) - qtr_ice_top(ji,jj,jl) + qns_ice(ji,jj,jl) ! Net initial atmospheric heat flux
            !
            DO iter = 1, nit     ! --- Iterative loop
               zqc   = zkeff_h * ( ztsu - ptb(ji,jj) )                              ! Conduction heat flux through snow-ice system (>0 downwards)
               zqnet = zqa0 + dqns_ice(ji,jj,jl) * ( ztsu - ptsu(ji,jj,jl) ) - zqc  ! Surface energy budget
               ztsu  = ztsu - zqnet / ( dqns_ice(ji,jj,jl) - zkeff_h )              ! Temperature update
            END DO
            !
            ptsu   (ji,jj,jl) = MIN( rt0, ztsu )
            qcn_ice(ji,jj,jl) = zkeff_h * ( ptsu(ji,jj,jl) - ptb(ji,jj) )
            qns_ice(ji,jj,jl) = qns_ice(ji,jj,jl) + dqns_ice(ji,jj,jl) * ( ptsu(ji,jj,jl) - ztsu0 )
            qml_ice(ji,jj,jl) = ( qsr_ice(ji,jj,jl) - qtr_ice_top(ji,jj,jl) + qns_ice(ji,jj,jl) - qcn_ice(ji,jj,jl) )  &
               &   * MAX( 0._wp , SIGN( 1._wp, ptsu(ji,jj,jl) - rt0 ) )

            ! --- Diagnose the heat loss due to changing non-solar flux (as in icethd_zdf_bl99) --- !
            hfx_err_dif(ji,jj) = hfx_err_dif(ji,jj) - ( dqns_ice(ji,jj,jl) * ( ptsu(ji,jj,jl) - ztsu0 ) ) * a_i_b(ji,jj,jl)

         END_2D
         !
      END DO
      !
   END SUBROUTINE blk_ice_qcn

#endif

   !!======================================================================
END MODULE sbcblk