1 module module_sf_noah_seaice_drv
3 use mpas_atmphys_utilities, only: physics_message,physics_error_fatal
4 #define FATAL_ERROR(M) call physics_error_fatal( M )
5 #define WRITE_MESSAGE(M) call physics_message( M )
8 #define FATAL_ERROR(M) call wrf_error_fatal( M )
9 #define WRITE_MESSAGE(M) call wrf_message( M )
11 use module_sf_noah_seaice
14 subroutine seaice_noah( SEAICE_ALBEDO_OPT, SEAICE_ALBEDO_DEFAULT, SEAICE_THICKNESS_OPT, &
15 & SEAICE_THICKNESS_DEFAULT, SEAICE_SNOWDEPTH_OPT, &
16 & SEAICE_SNOWDEPTH_MAX, SEAICE_SNOWDEPTH_MIN, &
17 & T3D, QV3D, P8W3D, DZ8W, NUM_SOIL_LAYERS, DT, FRPCPN, SR, &
18 & GLW, SWDOWN, RAINBL, SNOALB2D, QGH, XICE, XICE_THRESHOLD, &
19 & ALBSI, ICEDEPTH, SNOWSI, &
20 & TSLB, EMISS, ALBEDO, Z02D, TSK, SNOW, SNOWC, SNOWH2D, &
22 & RIB, ZNT, LH, HFX, QFX, POTEVP, GRDFLX, QSFC, ACSNOW, &
23 & ACSNOM, SNOPCX, SFCRUNOFF, NOAHRES, &
24 & SF_URBAN_PHYSICS, B_T_BEP, B_Q_BEP, RHO, &
25 & IDS, IDE, JDS, JDE, KDS, KDE, &
26 & IMS, IME, JMS, JME, KMS, KME, &
27 & ITS, ITE, JTS, JTE, KTS, KTE )
30 USE module_state_description, ONLY : NOAHUCMSCHEME
31 USE module_state_description, ONLY : BEPSCHEME
32 USE module_state_description, ONLY : BEP_BEMSCHEME
37 INTEGER, INTENT(IN) :: SEAICE_ALBEDO_OPT
38 REAL , INTENT(IN) :: SEAICE_ALBEDO_DEFAULT
39 INTEGER, INTENT(IN) :: SEAICE_THICKNESS_OPT
40 REAL, INTENT(IN) :: SEAICE_THICKNESS_DEFAULT
41 INTEGER, INTENT(IN) :: SEAICE_SNOWDEPTH_OPT
42 REAL, INTENT(IN) :: SEAICE_SNOWDEPTH_MAX
43 REAL, INTENT(IN) :: SEAICE_SNOWDEPTH_MIN
45 INTEGER, INTENT(IN) :: IDS, &
52 INTEGER, INTENT(IN) :: IMS, &
59 INTEGER, INTENT(IN) :: ITS, &
66 REAL, DIMENSION( ims:ime, kms:kme, jms:jme ) , &
67 & INTENT (IN) :: T3D, &
72 REAL, DIMENSION( ims:ime, jms:jme ) , &
73 & INTENT (IN) :: SR, &
82 LOGICAL, INTENT (IN) :: FRPCPN
83 REAL , INTENT (IN) :: DT
84 INTEGER, INTENT (IN) :: NUM_SOIL_LAYERS
85 REAL , INTENT (IN) :: XICE_THRESHOLD
87 REAL, DIMENSION( ims:ime , 1:num_soil_layers, jms:jme ), &
90 REAL, DIMENSION( ims:ime, jms:jme ) , &
91 & INTENT (INOUT) :: EMISS, &
102 REAL, DIMENSION( ims:ime, jms:jme ) , &
103 & INTENT (OUT) :: HFX, &
117 REAL, DIMENSION( ims:ime, jms:jme ) ,&
118 & INTENT(INOUT) :: SNOWSI
120 REAL, DIMENSION( ims:ime, jms:jme ) , &
121 & INTENT (INOUT) :: ICEDEPTH
123 INTEGER, INTENT (IN) :: SF_URBAN_PHYSICS
124 REAL, OPTIONAL, DIMENSION( ims:ime, kms:kme, jms:jme ) , &
125 & INTENT (INOUT) :: B_Q_BEP, &
127 REAL, OPTIONAL, DIMENSION( ims:ime, kms:kme, jms:jme ) , &
153 REAL, DIMENSION(1:NUM_SOIL_LAYERS):: STC
163 REAL :: ETA_KINEMATIC
187 REAL, PARAMETER :: CAPA = R_D / CP
188 REAL, PARAMETER :: A2 = 17.67
189 REAL, PARAMETER :: A3 = 273.15
190 REAL, PARAMETER :: A4 = 29.65
191 REAL, PARAMETER :: A23M4 = A2 * ( A3 - A4 )
192 REAL, PARAMETER :: ROW = 1.E3
193 REAL, PARAMETER :: ELIW = XLF
194 REAL, PARAMETER :: ROWLIW = ROW * ELIW
196 CHARACTER(len=80) :: message
199 FDTW = DT / ( XLV * RHOWATER )
201 NSOIL = NUM_SOIL_LAYERS
203 SEAICE_JLOOP : do J = JTS, JTE
204 SEAICE_ILOOP : do I = ITS, ITE
206 ! Skip the points that are not sea-ice points.
207 IF ( XICE(I,J) < XICE_THRESHOLD ) THEN
208 IF ( SEAICE_THICKNESS_OPT == 1 ) THEN
211 IF ( SEAICE_SNOWDEPTH_OPT == 1 ) THEN
217 SELECT CASE ( SEAICE_THICKNESS_OPT )
219 WRITE(message,'("Namelist value for SEAICE_THICKNESS_OPT not recognized: ",I6)') SEAICE_THICKNESS_OPT
222 ! Use uniform sea-ice thickness.
223 SITHICK = SEAICE_THICKNESS_DEFAULT
225 ! Use the sea-ice as read in from the input files.
226 ! Limit the to between 0.10 and 10.0 m.
227 IF ( ICEDEPTH(I,J) < -1.E6 ) THEN
228 WRITE_MESSAGE("Field ICEDEPTH not found in input files.")
229 WRITE_MESSAGE(".... Namelist SEAICE_THICKNESS_OPT=1 requires ICEDEPTH field.")
230 WRITE_MESSAGE(".... Try namelist option SEAICE_THICKNESS_OPT=0.")
231 FATAL_ERROR("SEAICE_THICKNESS_OPT")
233 SITHICK = MIN ( MAX ( 0.10 , ICEDEPTH(I,J) ) , 10.0 )
234 ICEDEPTH(I,J) = SITHICK
239 IF ( SEAICE_ALBEDO_OPT == 2 ) THEN
240 IF ( ALBSI(I,J) < -1.E6 ) THEN
241 FATAL_ERROR("Field ALBSI not found in input. Field ALBSI is required if SEAICE_ALBEDO_OPT=2")
244 ALBEDO(I,J) = ALBSI(I,J)
247 ALBEDOSI = ALBSI(I,J)
249 SNOALB = SNOALB2D(I,J)
251 ZLVL = 0.5 * DZ8W(I,1,J)
252 EMISSI = EMISS(I,J) ! But EMISSI might change in SFLX_SEAICE
253 LWDN = GLW(I,J) * EMISSI ! But EMISSI might change in SFLX_SEAICE
255 ! convert snow water equivalent from mm to meter
256 SNEQV = SNOW(I,J) * 0.001
258 ! snow depth in meters
262 ! Use mid-day albedo to determine net downward solar (no solar zenith angle correction)
263 SOLNET = SWDOWN(I,J) * (1.-ALBEDO(I,J)) ! But ALBEDO might change after SFLX_SEAICE
265 ! Pressure in middle of lowest layer. Why don't we use the true surface pressure?
266 ! Are there places where we would need to use the true surface pressure?
267 SFCPRS = ( P8W3D(I,KTS+1,j) + P8W3D(I,KTS,J) ) * 0.5
272 ! Convert lowest model level humidity from mixing ratio to specific humidity
273 Q2 = QV3D(I,1,J) / ( 1.0 + QV3D(I,1,J) )
275 ! Calculate TH2 via Exner function
276 APES = ( 1.E5 / PSFC ) ** CAPA
277 APELM = ( 1.E5 / SFCPRS ) ** CAPA
278 TH2 = ( SFCTMP * APELM ) / APES
280 ! Q2SAT is specific humidity
281 Q2SAT = QGH(I,J) / ( 1.0 + QGH(I,J) )
282 DQSDT2 = Q2SAT * A23M4 / ( SFCTMP - A4 ) ** 2
284 SELECT CASE ( SEAICE_SNOWDEPTH_OPT )
287 WRITE(message,'("Namelist value for SEAICE_SNOWDEPTH_OPT not recognized: ",I6)') SEAICE_SNOWDEPTH_OPT
292 ! Minimum and maximum bounds on snow depth are enforced in SFLX_SEAICE
296 ! Snow depth on sea ice comes from a 2D array, SNOWSI, bounded by user-specified
297 ! minimum and maximum values. No matter what anybody else says about snow
298 ! accumulation and melt, we want the snow depth on sea ice to be specified
299 ! as SNOWSI (bounded by SEAICE_SNOWDEPTH_MIN and SEAICE_SNOWDEPTH_MAX).
300 SNOWONSI = MAX ( SEAICE_SNOWDEPTH_MIN , MIN ( SNOWSI(I,J) , SEAICE_SNOWDEPTH_MAX ) )
301 SNEQV = SNOWONSI * 0.3
302 SNOWH2D(I,J) = SNOWONSI
306 IF ( SNOW(I,J) .GT. 0.0 ) THEN
307 ! If snow on surface, use ice saturation properties
308 SFCTSNO = SFCTMP ! Lowest model Air temperature
309 E2SAT = 611.2 * EXP ( 6174. * ( 1./273.15 - 1./SFCTSNO ) )
310 Q2SATI = 0.622 * E2SAT / ( SFCPRS - E2SAT )
311 Q2SATI = Q2SATI / ( 1.0 + Q2SATI ) ! Convert to specific humidity
312 ! T1 is skin temperature
313 IF (T1 .GT. 273.14) THEN
314 ! Warm ground temps, weight the saturation between ice and water according to SNOWC
315 Q2SAT = Q2SAT * (1.-SNOWC(I,J)) + Q2SATI * SNOWC(I,J)
316 DQSDT2 = DQSDT2 * (1.-SNOWC(I,J)) + Q2SATI * 6174. / (SFCTSNO**2) * SNOWC(I,J)
318 ! Cold ground temps, use ice saturation only
320 DQSDT2 = Q2SATI * 6174. / (SFCTSNO**2)
322 IF ( ( T1 .GT. 273. ) .AND. ( SNOWC(I,J) .GT. 0.0 ) ) THEN
323 ! If (SNOW > 0) can we have (SNOWC <= 0) ? Perhaps not, so the check on
324 ! SNOWC here might be superfluous.
325 DQSDT2 = DQSDT2 * ( 1. - SNOWC(I,J) )
329 PRCP = RAINBL(I,J) / DT
331 ! If "SR" is present, set frac of frozen precip ("FFROZP") = snow-ratio ("SR", range:0-1)
332 ! SR from e.g. Ferrier microphysics
333 ! otherwise define from 1st atmos level temperature
338 IF (SFCTMP <= 273.15) THEN
345 ! Sea-ice point has deep-level temperature of about -1.8 C
347 ! TBOT=273.15 ! appropriate value for lake ice.
349 ! INTENT(IN) for SFLX_SEAICE, values unchanged by SFLX_SEAICE
371 STC(NS) = TSLB(I,NS,J)
377 ! INTENT(INOUT) for SFLX_SEAICE, values updated by SFLX_SEAICE
385 ! CH -- but the result isn't used for anything.
386 ! Might as well be intent in to SFLX_SEAICE and changed locally in
388 ! RIBB -- but the result isn't used for anything.
389 ! Might as well be intent in to SFLX_SEAICE and changed locally in
392 ! INTENT(OUT) for SFLX_SEAICE. Input value should not matter.
396 ETA_KINEMATIC = -1.E36
397 FDOWN = -1.E36 ! Returned value unused. Might as well be local to SFLX_SEAICE ?
398 ESNOW = -1.E36 ! Returned value unused. Might as well be local to SFLX_SEAICE ?
399 DEW = -1.E36 ! Returned value unused. Might as well be local to SFLX_SEAICE ?
409 call sflx_seaice(I, J, SEAICE_ALBEDO_OPT, SEAICE_ALBEDO_DEFAULT, & !C
410 & SEAICE_SNOWDEPTH_OPT, SEAICE_SNOWDEPTH_MAX, & !C
411 & SEAICE_SNOWDEPTH_MIN, & !C
412 & FFROZP, DT, ZLVL, NSOIL, & !C
414 & LWDN, SOLNET, SFCPRS, PRCP, SFCTMP, Q2, & !F
415 & TH2, Q2SAT, DQSDT2, & !I
416 & SNOALB, TBOT, Z0BRD, Z0, EMISSI, & !S
417 & T1, STC, SNOWH, SNEQV, ALBEDOK, CH, & !H
418 & ALBEDOSI, SNOWONSI, &
419 & ETA, SHEAT, ETA_KINEMATIC, FDOWN, & !O
420 & ESNOW, DEW, ETP, SSOIL, FLX1, FLX2, FLX3, & !O
421 & SNOMLT, SNCOVR, & !O
424 ! Update our 2d arrays with results from SFLX_SEAICE
425 ALBEDO(I,J) = ALBEDOK
432 ! Convert snow water equivalent from (m) back to (mm)
433 SNOW(I,J) = SNEQV * 1000.
435 ! Update our ice temperature array with results from SFLX_SEAICE
437 TSLB(I,NS,J) = STC(NS)
440 ! Intent (OUT) from SFLX_SEAICE
444 QFX(I,J) = ETA_KINEMATIC
445 POTEVP(I,J) = POTEVP(I,J) + ETP*FDTW
448 ! Exchange Coefficients
449 CHS2(I,J) = CQS2(I,J)
450 IF (Q1 .GT. QSFC(I,J)) THEN
454 ! Convert QSFC term back to Mixing Ratio.
455 QSFC(I,J) = Q1 / ( 1.0 - Q1 )
457 IF ( SEAICE_SNOWDEPTH_OPT == 1 ) THEN
458 SNOWSI(I,J) = SNOWONSI
461 ! Accumulated snow precipitation.
462 IF ( FFROZP .GT. 0.5 ) THEN
463 ACSNOW(I,J) = ACSNOW(I,J) + PRCP * DT
466 ! Accumulated snow melt.
467 ACSNOM(I,J) = ACSNOM(I,J) + SNOMLT * 1000.
469 ! Accumulated snow-melt energy.
470 SNOPCX(I,J) = SNOPCX(I,J) - SNOMLT/FDTLIW
473 SFCRUNOFF(I,J) = SFCRUNOFF(I,J) + RUNOFF1 * DT * 1000.0
476 ! Residual of surface energy balance terms
478 NOAHRES(I,J) = ( SOLNET + LWDN ) &
479 & - SHEAT + SSOIL - ETA &
480 & - ( EMISSI * STBOLT * (T1**4) ) &
481 & - FLX1 - FLX2 - FLX3
482 #if defined(wrfmodel)
484 IF ( ( SF_URBAN_PHYSICS == NOAHUCMSCHEME ) .OR. &
485 (SF_URBAN_PHYSICS == BEPSCHEME ) .OR. &
486 ( SF_URBAN_PHYSICS == BEP_BEMSCHEME ) ) THEN
487 if ( PRESENT (B_T_BEP) ) then
488 B_T_BEP(I,1,J)=hfx(i,j)/dz8w(i,1,j)/rho(i,1,j)/CP
490 if ( PRESENT (B_Q_BEP) ) then
491 B_Q_BEP(I,1,J)=qfx(i,j)/dz8w(i,1,j)/rho(i,1,j)
500 end subroutine seaice_noah
502 end module module_sf_noah_seaice_drv