| 1 | module lmdz_blosno_sublimsedim |
|---|
| 2 | |
|---|
| 3 | contains |
|---|
| 4 | |
|---|
| 5 | !============================================================================== |
|---|
| 6 | subroutine blosno_sublimsedim(ngrid,nlay,dtime,ustar,temp,qv,qb,pplay,paprs,dtemp_bs,dqv_bs,dqb_bs,bsfl,precip_bs) |
|---|
| 7 | |
|---|
| 8 | !============================================================================== |
|---|
| 9 | ! Routine that calculates the sublimation, melting and sedimentation |
|---|
| 10 | ! of blowing snow |
|---|
| 11 | ! Reference: Vignon et al 2025, GMD, https://doi.org/10.5194/egusphere-2025-2871 |
|---|
| 12 | ! |
|---|
| 13 | ! Etienne Vignon, October 2022 |
|---|
| 14 | !============================================================================== |
|---|
| 15 | |
|---|
| 16 | use lmdz_blosno_ini, only: iflag_sublim_bs, iflag_sedim_bs, coef_sub_bs, RTT, RD, RG, fallv_bs |
|---|
| 17 | use lmdz_blosno_ini, only: qbmin, RCPD, RLSTT, RLMLT, RLVTT, RVTMP2, RV, RPI |
|---|
| 18 | use lmdz_blosno_ini, only: tbsmelt, taumeltbs0, rhobs, r_bs |
|---|
| 19 | USE lmdz_lscp_tools, only: calc_qsat_ecmwf |
|---|
| 20 | |
|---|
| 21 | implicit none |
|---|
| 22 | |
|---|
| 23 | !++++++++++++++++++++++++++++++++++++++++++++++++++++ |
|---|
| 24 | ! Declarations |
|---|
| 25 | !++++++++++++++++++++++++++++++++++++++++++++++++++++ |
|---|
| 26 | |
|---|
| 27 | !INPUT |
|---|
| 28 | !===== |
|---|
| 29 | integer, intent(in) :: ngrid ! number of horizontal grid points |
|---|
| 30 | integer, intent(in) :: nlay ! number of vertical layers |
|---|
| 31 | real, intent(in) :: dtime ! physics time step [s] |
|---|
| 32 | real, intent(in), dimension(ngrid) :: ustar ! surface friction velocity [m/s] |
|---|
| 33 | real, intent(in), dimension(ngrid, nlay) :: temp ! temperature of the air [K] |
|---|
| 34 | real, intent(in), dimension(ngrid, nlay) :: qv ! specific content of water [kg/kg] |
|---|
| 35 | real, intent(in), dimension(ngrid, nlay) :: qb ! specific content of blowing snow [kg/kg] |
|---|
| 36 | real, intent(in), dimension(ngrid, nlay) :: pplay ! pressure at the middle of layers [Pa] |
|---|
| 37 | real, intent(in), dimension(ngrid, nlay + 1) :: paprs ! pressure at the layer bottom interface [Pa] |
|---|
| 38 | |
|---|
| 39 | ! OUTPUT |
|---|
| 40 | !======== |
|---|
| 41 | real, intent(out), dimension(ngrid, nlay) :: dtemp_bs ! temperature tendency [K/s] |
|---|
| 42 | real, intent(out), dimension(ngrid, nlay) :: dqv_bs ! water vapor tendency [kg/kg/s] |
|---|
| 43 | real, intent(out), dimension(ngrid, nlay) :: dqb_bs ! blowing snow mass tendancy [kg/kg/s] |
|---|
| 44 | real, intent(out), dimension(ngrid, nlay + 1) :: bsfl ! vertical profile of blowing snow vertical flux [kg/m2/s] |
|---|
| 45 | real, intent(out), dimension(ngrid) :: precip_bs ! surface sedimentation flux of blowing snow [kg/s/m2] |
|---|
| 46 | |
|---|
| 47 | ! LOCAL |
|---|
| 48 | !====== |
|---|
| 49 | |
|---|
| 50 | integer :: k, i, n |
|---|
| 51 | real :: cpd, cpw, dqbsub, maxdqbsub, dqbmelt, zmair |
|---|
| 52 | real :: dqsedim, precbs, dqvmelt, zmelt, taumeltbs |
|---|
| 53 | real :: maxdqvmelt, rhoair, dz, dqbsedim |
|---|
| 54 | real :: delta_p, b_p, a_p, c_p, c_sub, qvsub |
|---|
| 55 | real :: p0, T0, Dv, Aprime, Bprime, Ka, radius0, radius |
|---|
| 56 | real, dimension(ngrid) :: ztemp, zqv, zqb, zpres, qsi, dqsi, qsl, dqsl, qzero, sedim |
|---|
| 57 | real, dimension(ngrid) :: zpaprsup, zpaprsdn, ztemp_up, zqb_up, zvelo |
|---|
| 58 | real, dimension(ngrid, nlay) :: temp_seri, qb_seri, qv_seri, zz |
|---|
| 59 | |
|---|
| 60 | !++++++++++++++++++++++++++++++++++++++++++++++++++ |
|---|
| 61 | ! Initialisation |
|---|
| 62 | !++++++++++++++++++++++++++++++++++++++++++++++++++ |
|---|
| 63 | |
|---|
| 64 | qzero(:) = 0. |
|---|
| 65 | dtemp_bs(:, :) = 0. |
|---|
| 66 | dqv_bs(:, :) = 0. |
|---|
| 67 | dqb_bs(:, :) = 0. |
|---|
| 68 | zvelo(:) = 0. |
|---|
| 69 | sedim(:) = 0. |
|---|
| 70 | precip_bs(:) = 0. |
|---|
| 71 | bsfl(:, :) = 0. |
|---|
| 72 | zz(:, :) = 0. |
|---|
| 73 | |
|---|
| 74 | p0 = 101325.0 ! ref pressure |
|---|
| 75 | |
|---|
| 76 | DO k = 1, nlay |
|---|
| 77 | DO i = 1, ngrid |
|---|
| 78 | temp_seri(i, k) = temp(i, k) |
|---|
| 79 | qv_seri(i, k) = qv(i, k) |
|---|
| 80 | qb_seri(i, k) = qb(i, k) |
|---|
| 81 | zz(i, k) = zz(i, k) + (paprs(i, k) - paprs(i, k + 1))/(pplay(i, k)/RD/temp(i, k)*RG) |
|---|
| 82 | END DO |
|---|
| 83 | END DO |
|---|
| 84 | |
|---|
| 85 | ! Sedimentation scheme |
|---|
| 86 | !---------------------- |
|---|
| 87 | |
|---|
| 88 | IF (iflag_sedim_bs .GT. 0) THEN |
|---|
| 89 | ! begin of top-down loop |
|---|
| 90 | DO k = nlay, 1, -1 |
|---|
| 91 | |
|---|
| 92 | DO i = 1, ngrid |
|---|
| 93 | ztemp(i) = temp_seri(i, k) |
|---|
| 94 | zqv(i) = qv_seri(i, k) |
|---|
| 95 | zqb(i) = qb_seri(i, k) |
|---|
| 96 | zpres(i) = pplay(i, k) |
|---|
| 97 | zpaprsup(i) = paprs(i, k + 1) |
|---|
| 98 | zpaprsdn(i) = paprs(i, k) |
|---|
| 99 | END DO |
|---|
| 100 | |
|---|
| 101 | ! thermalization of blowing snow precip coming from above |
|---|
| 102 | IF (k .LE. nlay - 1) THEN |
|---|
| 103 | |
|---|
| 104 | DO i = 1, ngrid |
|---|
| 105 | zmair = (zpaprsdn(i) - zpaprsup(i))/RG |
|---|
| 106 | ! RVTMP2=rcpv/rcpd-1 |
|---|
| 107 | cpd = RCPD*(1.0 + RVTMP2*zqv(i)) |
|---|
| 108 | cpw = RCPD*RVTMP2 |
|---|
| 109 | ! zqb_up: blowing snow mass that has to be thermalized with |
|---|
| 110 | ! layer's air so that precipitation at the ground has the |
|---|
| 111 | ! same temperature as the lowermost layer |
|---|
| 112 | zqb_up(i) = sedim(i)*dtime/zmair |
|---|
| 113 | ztemp_up(i) = temp_seri(i, k + 1) |
|---|
| 114 | |
|---|
| 115 | ! t(i,k+1)+d_t(i,k+1): new temperature of the overlying layer |
|---|
| 116 | ztemp(i) = (ztemp_up(i)*zqb_up(i)*cpw + cpd*ztemp(i)) & |
|---|
| 117 | /(cpd + zqb_up(i)*cpw) |
|---|
| 118 | END DO |
|---|
| 119 | |
|---|
| 120 | END IF |
|---|
| 121 | |
|---|
| 122 | DO i = 1, ngrid |
|---|
| 123 | |
|---|
| 124 | rhoair = zpres(i)/ztemp(i)/RD |
|---|
| 125 | dz = (zpaprsdn(i) - zpaprsup(i))/(rhoair*RG) |
|---|
| 126 | ! BS fall velocity assumed to be constant for now |
|---|
| 127 | zvelo(i) = fallv_bs |
|---|
| 128 | ! dqb/dt_sedim=1/rho(sedim/dz - rho w qb/dz) |
|---|
| 129 | ! implicit resolution |
|---|
| 130 | dqbsedim = (sedim(i)/rhoair/dz*dtime + zqb(i))/(1.+zvelo(i)*dtime/dz) - zqb(i) |
|---|
| 131 | ! flux and dqb update |
|---|
| 132 | zqb(i) = zqb(i) + dqbsedim |
|---|
| 133 | !sedim(i) = sedim(i)-dqbsedim/dtime*rhoair*dz |
|---|
| 134 | sedim(i) = rhoair*zvelo(i)*zqb(i) |
|---|
| 135 | |
|---|
| 136 | ! variables update: |
|---|
| 137 | bsfl(i, k) = sedim(i) |
|---|
| 138 | |
|---|
| 139 | qb_seri(i, k) = zqb(i) |
|---|
| 140 | qv_seri(i, k) = zqv(i) |
|---|
| 141 | temp_seri(i, k) = ztemp(i) |
|---|
| 142 | |
|---|
| 143 | END DO ! Loop on ngrid |
|---|
| 144 | |
|---|
| 145 | END DO ! vertical loop |
|---|
| 146 | |
|---|
| 147 | !surface bs flux |
|---|
| 148 | DO i = 1, ngrid |
|---|
| 149 | precip_bs(i) = sedim(i) |
|---|
| 150 | END DO |
|---|
| 151 | |
|---|
| 152 | END IF |
|---|
| 153 | |
|---|
| 154 | !+++++++++++++++++++++++++++++++++++++++++++++++ |
|---|
| 155 | ! Sublimation and melting |
|---|
| 156 | !++++++++++++++++++++++++++++++++++++++++++++++ |
|---|
| 157 | IF (iflag_sublim_bs .GT. 0) THEN |
|---|
| 158 | |
|---|
| 159 | DO k = 1, nlay |
|---|
| 160 | |
|---|
| 161 | DO i = 1, ngrid |
|---|
| 162 | ztemp(i) = temp_seri(i, k) |
|---|
| 163 | zqv(i) = qv_seri(i, k) |
|---|
| 164 | zqb(i) = qb_seri(i, k) |
|---|
| 165 | zpres(i) = pplay(i, k) |
|---|
| 166 | zpaprsup(i) = paprs(i, k + 1) |
|---|
| 167 | zpaprsdn(i) = paprs(i, k) |
|---|
| 168 | |
|---|
| 169 | ! computation of blowing snow mean radius. Either constant value = r_bs if >0 |
|---|
| 170 | ! or use of the height-dependent formulation from Sauter et al. 2013 and Saigger et al. 2024 |
|---|
| 171 | IF (r_bs .GT. 0.) THEN |
|---|
| 172 | radius = r_bs |
|---|
| 173 | ELSE |
|---|
| 174 | radius0 = 0.5*(ustar(i)*(7.8e-6)/0.036 + 31.e-6) |
|---|
| 175 | radius = radius0*zz(i, k)**(-0.258) |
|---|
| 176 | END IF |
|---|
| 177 | |
|---|
| 178 | END DO |
|---|
| 179 | |
|---|
| 180 | ! calulation saturation specific humidity |
|---|
| 181 | CALL CALC_QSAT_ECMWF(ngrid, ztemp(:), qzero(:), zpres(:), RTT, 2, .false., qsi(:), dqsi(:)) |
|---|
| 182 | |
|---|
| 183 | DO i = 1, ngrid |
|---|
| 184 | |
|---|
| 185 | rhoair = zpres(i)/ztemp(i)/RD |
|---|
| 186 | dz = (zpaprsdn(i) - zpaprsup(i))/(rhoair*RG) |
|---|
| 187 | ! BS fall velocity assumed to be constant for now |
|---|
| 188 | zvelo(i) = fallv_bs |
|---|
| 189 | |
|---|
| 190 | IF (ztemp(i) .GT. RTT) THEN |
|---|
| 191 | |
|---|
| 192 | ! if temperature is positive, we assume that part of the blowing snow |
|---|
| 193 | ! already present melts and evaporates with a typical time |
|---|
| 194 | ! constant taumeltbs |
|---|
| 195 | |
|---|
| 196 | taumeltbs = taumeltbs0*exp(-max(0., (ztemp(i) - RTT)/(tbsmelt - RTT))) |
|---|
| 197 | dqvmelt = min(zqb(i), -1.*zqb(i)*(exp(-dtime/taumeltbs) - 1.)) |
|---|
| 198 | maxdqvmelt = max(RCPD*(1.0 + RVTMP2*(zqv(i) + zqb(i)))*(ztemp(i) - RTT)/(RLMLT + RLVTT), 0.) |
|---|
| 199 | dqvmelt = min(dqvmelt, maxdqvmelt) |
|---|
| 200 | ! qv update, melting + evaporation |
|---|
| 201 | zqv(i) = zqv(i) + dqvmelt |
|---|
| 202 | ! temp update melting + evaporation |
|---|
| 203 | ztemp(i) = ztemp(i) - dqvmelt*(RLMLT + RLVTT)/RCPD/(1.0 + RVTMP2*(zqv(i) + zqb(i))) |
|---|
| 204 | ! qb update melting + evaporation |
|---|
| 205 | zqb(i) = zqb(i) - dqvmelt |
|---|
| 206 | |
|---|
| 207 | ELSE |
|---|
| 208 | ! negative celcius temperature |
|---|
| 209 | ! Sublimation scheme |
|---|
| 210 | |
|---|
| 211 | ! Sublimation formulation for ice crystals from Pruppacher & Klett, Rutledge & Hobbs 1983 |
|---|
| 212 | ! assuming monodispered crystal distrib |
|---|
| 213 | ! dqb/dt_sub=-coef_sub_bs*(1-qv/qsi)*nc*8*radius/(Aprime+Bprime) |
|---|
| 214 | ! assuming Mi=rhobs*4/3*pi*radius**3 |
|---|
| 215 | ! qb=nc*Mi -> nc=qb/Mi |
|---|
| 216 | ! dqb/dt_sub=-coef_sub_bs*(1-qv/qsi)*6*qb/(rhobs*pi*radius**2)/(Aprime+Bprime) |
|---|
| 217 | ! dqb/dt_sub=-c_sub(1-qv/qsi)*qb |
|---|
| 218 | ! c_sub=coef_sub_bs*6/(rhobs*pi*radius**2)/(Aprime+Bprime) |
|---|
| 219 | ! |
|---|
| 220 | ! Note the strong coupling between specific contents of water vapor and blowing snow during sublimation |
|---|
| 221 | ! equations dqv/dt_sub and dqb/dt_sub must be solved jointly to prevent irrealistic increase of water vapor |
|---|
| 222 | ! at typical physics time steps |
|---|
| 223 | ! we thus solve the differential equation using an implicit scheme for both qb and qv |
|---|
| 224 | |
|---|
| 225 | ! we do not consider deposition, only sublimation |
|---|
| 226 | IF (zqv(i) .LT. qsi(i)) THEN |
|---|
| 227 | rhoair = zpres(i)/ztemp(i)/RD |
|---|
| 228 | Dv = 0.0001*0.211*(p0/zpres(i))*((ztemp(i)/RTT)**1.94) ! water vapor diffusivity in air, SI |
|---|
| 229 | Ka = (5.69 + 0.017*(ztemp(i) - RTT))*1.e-5*100.*4.184 ! thermal conductivity of the air, SI |
|---|
| 230 | Aprime = RLSTT/Ka/ztemp(i)*(RLSTT/RV/ztemp(i) - 1.) |
|---|
| 231 | Bprime = 1./(rhoair*Dv*qsi(i)) |
|---|
| 232 | c_sub = coef_sub_bs*3./(rhobs*radius**2)/(Aprime + Bprime) |
|---|
| 233 | c_p = -zqb(i) |
|---|
| 234 | b_p = 1.+c_sub*dtime - c_sub*dtime/qsi(i)*zqb(i) - c_sub*dtime/qsi(i)*zqv(i) |
|---|
| 235 | a_p = c_sub*dtime/qsi(i) |
|---|
| 236 | delta_p = (b_p**2) - 4.*a_p*c_p |
|---|
| 237 | dqbsub = (-b_p + sqrt(delta_p))/(2.*a_p) - zqb(i) |
|---|
| 238 | dqbsub = MIN(0.0, MAX(dqbsub, -zqb(i))) |
|---|
| 239 | ! Sublimation limit: we ensure that the whole mesh does not exceed saturation wrt ice |
|---|
| 240 | maxdqbsub = MAX(0.0, qsi(i) - zqv(i)) |
|---|
| 241 | dqbsub = MAX(dqbsub, -maxdqbsub) |
|---|
| 242 | ELSE |
|---|
| 243 | dqbsub = 0. |
|---|
| 244 | END IF |
|---|
| 245 | |
|---|
| 246 | ! vapor, temperature, precip fluxes update following sublimation |
|---|
| 247 | zqv(i) = zqv(i) - dqbsub |
|---|
| 248 | zqb(i) = zqb(i) + dqbsub |
|---|
| 249 | ztemp(i) = ztemp(i) + dqbsub*RLSTT/RCPD/(1.0 + RVTMP2*(zqv(i) + zqb(i))) |
|---|
| 250 | |
|---|
| 251 | END IF |
|---|
| 252 | |
|---|
| 253 | ! if qb<qbmin, sublimate or melt and evaporate qb |
|---|
| 254 | ! see Gerber et al. 2023, JGR Atmos for the choice of qbmin |
|---|
| 255 | |
|---|
| 256 | IF (zqb(i) .LT. qbmin) THEN |
|---|
| 257 | zqv(i) = zqv(i) + zqb(i) |
|---|
| 258 | IF (ztemp(i) .LT. RTT) THEN |
|---|
| 259 | ztemp(i) = ztemp(i) - zqb(i)*RLSTT/RCPD/(1.0 + RVTMP2*(zqv(i))) |
|---|
| 260 | ELSE |
|---|
| 261 | ztemp(i) = ztemp(i) - zqb(i)*(RLVTT + RLMLT)/RCPD/(1.0 + RVTMP2*(zqv(i))) |
|---|
| 262 | END IF |
|---|
| 263 | zqb(i) = 0. |
|---|
| 264 | END IF |
|---|
| 265 | |
|---|
| 266 | ! variables update |
|---|
| 267 | temp_seri(i, k) = ztemp(i) |
|---|
| 268 | qv_seri(i, k) = zqv(i) |
|---|
| 269 | qb_seri(i, k) = zqb(i) |
|---|
| 270 | END DO |
|---|
| 271 | END DO |
|---|
| 272 | |
|---|
| 273 | END IF |
|---|
| 274 | |
|---|
| 275 | ! OUTPUTS |
|---|
| 276 | !++++++++++ |
|---|
| 277 | |
|---|
| 278 | ! 3D variables |
|---|
| 279 | DO k = 1, nlay |
|---|
| 280 | DO i = 1, ngrid |
|---|
| 281 | dqb_bs(i, k) = qb_seri(i, k) - qb(i, k) |
|---|
| 282 | dqv_bs(i, k) = qv_seri(i, k) - qv(i, k) |
|---|
| 283 | dtemp_bs(i, k) = temp_seri(i, k) - temp(i, k) |
|---|
| 284 | END DO |
|---|
| 285 | END DO |
|---|
| 286 | |
|---|
| 287 | return |
|---|
| 288 | |
|---|
| 289 | end subroutine blosno_sublimsedim |
|---|
| 290 | !============================================================================== |
|---|
| 291 | |
|---|
| 292 | end module lmdz_blosno_sublimsedim |
|---|