module module_sf_noah_seaice_drv 2 use module_sf_noah_seaice implicit none contains subroutine seaice_noah( SEAICE_ALBEDO_OPT, SEAICE_ALBEDO_DEFAULT, SEAICE_THICKNESS_OPT, & 2,8 & SEAICE_THICKNESS_DEFAULT, SEAICE_SNOWDEPTH_OPT, & & SEAICE_SNOWDEPTH_MAX, SEAICE_SNOWDEPTH_MIN, & & T3D, QV3D, P8W3D, DZ8W, NUM_SOIL_LAYERS, DT, FRPCPN, SR, & & GLW, SWDOWN, RAINBL, SNOALB2D, QGH, XICE, XICE_THRESHOLD, & & ALBSI, ICEDEPTH, SNOWSI, & & TSLB, EMISS, ALBEDO, Z02D, TSK, SNOW, SNOWC, SNOWH2D, & & CHS, CHS2, CQS2, & & RIB, ZNT, LH, HFX, QFX, POTEVP, GRDFLX, QSFC, ACSNOW, & & ACSNOM, SNOPCX, SFCRUNOFF, NOAHRES, & & SF_URBAN_PHYSICS, B_T_BEP, B_Q_BEP, RHO, & & IDS, IDE, JDS, JDE, KDS, KDE, & & IMS, IME, JMS, JME, KMS, KME, & & ITS, ITE, JTS, JTE, KTS, KTE ) #if (NMM_CORE != 1) USE module_state_description, ONLY : NOAHUCMSCHEME USE module_state_description, ONLY : BEPSCHEME USE module_state_description, ONLY : BEP_BEMSCHEME #endif implicit none INTEGER, INTENT(IN) :: SEAICE_ALBEDO_OPT REAL , INTENT(IN) :: SEAICE_ALBEDO_DEFAULT INTEGER, INTENT(IN) :: SEAICE_THICKNESS_OPT REAL, INTENT(IN) :: SEAICE_THICKNESS_DEFAULT INTEGER, INTENT(IN) :: SEAICE_SNOWDEPTH_OPT REAL, INTENT(IN) :: SEAICE_SNOWDEPTH_MAX REAL, INTENT(IN) :: SEAICE_SNOWDEPTH_MIN INTEGER, INTENT(IN) :: IDS, & & IDE, & & JDS, & & JDE, & & KDS, & & KDE INTEGER, INTENT(IN) :: IMS, & & IME, & & JMS, & & JME, & & KMS, & & KME INTEGER, INTENT(IN) :: ITS, & & ITE, & & JTS, & & JTE, & & KTS, & & KTE REAL, DIMENSION( ims:ime, kms:kme, jms:jme ) , & & INTENT (IN) :: T3D, & & QV3D, & & P8W3D, & & DZ8W REAL, DIMENSION( ims:ime, jms:jme ) , & & INTENT (IN) :: SR, & & GLW, & & QGH, & & SWDOWN, & & RAINBL, & & SNOALB2D, & & XICE, & & RIB LOGICAL, INTENT (IN) :: FRPCPN REAL , INTENT (IN) :: DT INTEGER, INTENT (IN) :: NUM_SOIL_LAYERS REAL , INTENT (IN) :: XICE_THRESHOLD REAL, DIMENSION( ims:ime , 1:num_soil_layers, jms:jme ), & INTENT(INOUT) :: TSLB REAL, DIMENSION( ims:ime, jms:jme ) , & & INTENT (INOUT) :: EMISS, & & ALBEDO, & & ALBSI, & & Z02D, & & SNOW, & & TSK, & & SNOWC, & & SNOWH2D, & & CHS, & & CQS2 REAL, DIMENSION( ims:ime, jms:jme ) , & & INTENT (OUT) :: HFX, & & LH, & & QFX, & & ZNT, & & POTEVP, & & GRDFLX, & & QSFC, & & ACSNOW, & & ACSNOM, & & SNOPCX, & & SFCRUNOFF, & & NOAHRES, & & CHS2 REAL, DIMENSION( ims:ime, jms:jme ) ,& & INTENT(INOUT) :: SNOWSI REAL, DIMENSION( ims:ime, jms:jme ) , & & INTENT (INOUT) :: ICEDEPTH INTEGER, INTENT (IN) :: SF_URBAN_PHYSICS REAL, OPTIONAL, DIMENSION( ims:ime, kms:kme, jms:jme ) , & & INTENT (INOUT) :: B_Q_BEP, & & B_T_BEP REAL, DIMENSION( ims:ime, kms:kme, jms:jme ) , & & INTENT (IN) :: RHO INTEGER :: I INTEGER :: J REAL :: FFROZP REAL :: ZLVL INTEGER :: NSOIL REAL :: LWDN REAL :: SOLNET REAL :: SFCPRS REAL :: PRCP REAL :: SFCTMP REAL :: Q2 REAL :: TH2 REAL :: Q2SAT REAL :: DQSDT2 REAL :: SNOALB REAL :: TBOT REAL :: SITHICK REAL :: ALBEDOK REAL :: ALBBRD REAL :: Z0BRD REAL :: EMISSI REAL :: T1 REAL, DIMENSION(1:NUM_SOIL_LAYERS):: STC REAL :: SNOWH REAL :: SNEQV REAL :: CH REAL :: SNCOVR REAL :: RIBB REAL :: Z0 REAL :: ETA REAL :: SHEAT REAL :: ETA_KINEMATIC REAL :: FDOWN REAL :: ESNOW REAL :: DEW REAL :: ETP REAL :: SSOIL REAL :: FLX1 REAL :: FLX2 REAL :: FLX3 REAL :: SNOMLT REAL :: RUNOFF1 REAL :: Q1 REAL :: APES REAL :: APELM REAL :: PSFC REAL :: SFCTSNO REAL :: E2SAT REAL :: Q2SATI INTEGER :: NS REAL :: FDTW REAL :: FDTLIW REAL :: ALBEDOSI REAL :: SNOWONSI REAL, PARAMETER :: CAPA = R_D / CP REAL, PARAMETER :: A2 = 17.67 REAL, PARAMETER :: A3 = 273.15 REAL, PARAMETER :: A4 = 29.65 REAL, PARAMETER :: A23M4 = A2 * ( A3 - A4 ) REAL, PARAMETER :: ROW = 1.E3 REAL, PARAMETER :: ELIW = XLF REAL, PARAMETER :: ROWLIW = ROW * ELIW CHARACTER(len=80) :: message FDTLIW = DT / ROWLIW FDTW = DT / ( XLV * RHOWATER ) NSOIL = NUM_SOIL_LAYERS SEAICE_JLOOP : do J = JTS, JTE SEAICE_ILOOP : do I = ITS, ITE ! Skip the points that are not sea-ice points. IF ( XICE(I,J) < XICE_THRESHOLD ) THEN IF ( SEAICE_THICKNESS_OPT == 1 ) THEN ICEDEPTH(I,J) = 0.0 ENDIF IF ( SEAICE_SNOWDEPTH_OPT == 1 ) THEN SNOWSI(I,J) = 0.0 ENDIF CYCLE SEAICE_ILOOP ENDIF SELECT CASE ( SEAICE_THICKNESS_OPT ) CASE DEFAULT WRITE(message,'("Namelist value for SEAICE_THICKNESS_OPT not recognized: ",I6)') SEAICE_THICKNESS_OPT CALL wrf_error_fatal(message) CASE (0) ! Use uniform sea-ice thickness. SITHICK = SEAICE_THICKNESS_DEFAULT CASE (1) ! Use the sea-ice as read in from the input files. ! Limit the to between 0.10 and 10.0 m. IF ( ICEDEPTH(I,J) < -1.E6 ) THEN call wrf_message("Field ICEDEPTH not found in input files.") call wrf_message(".... Namelist SEAICE_THICKNESS_OPT=1 requires ICEDEPTH field.") call wrf_message(".... Try namelist option SEAICE_THICKNESS_OPT=0.") call wrf_error_fatal("SEAICE_THICKNESS_OPT") ENDIF SITHICK = MIN ( MAX ( 0.10 , ICEDEPTH(I,J) ) , 10.0 ) ICEDEPTH(I,J) = SITHICK END SELECT SFCTMP = T3D(I,1,J) T1 = TSK(I,J) IF ( SEAICE_ALBEDO_OPT == 2 ) THEN IF ( ALBSI(I,J) < -1.E6 ) THEN call wrf_error_fatal("Field ALBSI not found in input. Field ALBSI is required if SEAICE_ALBEDO_OPT=2") ENDIF SNOALB = ALBSI(I,J) ALBEDO(I,J) = ALBSI(I,J) ALBEDOK = ALBSI(I,J) ALBBRD = ALBSI(I,J) ALBEDOSI = ALBSI(I,J) ELSE SNOALB = SNOALB2D(I,J) ENDIF ZLVL = 0.5 * DZ8W(I,1,J) EMISSI = EMISS(I,J) ! But EMISSI might change in SFLX_SEAICE LWDN = GLW(I,J) * EMISSI ! But EMISSI might change in SFLX_SEAICE ! convert snow water equivalent from mm to meter SNEQV = SNOW(I,J) * 0.001 ! snow depth in meters SNOWH = SNOWH2D(I,J) SNCOVR = SNOWC(I,J) ! Use mid-day albedo to determine net downward solar (no solar zenith angle correction) SOLNET = SWDOWN(I,J) * (1.-ALBEDO(I,J)) ! But ALBEDO might change after SFLX_SEAICE ! Pressure in middle of lowest layer. Why don't we use the true surface pressure? ! Are there places where we would need to use the true surface pressure? SFCPRS = ( P8W3D(I,KTS+1,j) + P8W3D(I,KTS,J) ) * 0.5 ! surface pressure PSFC = P8W3D(I,1,J) ! Convert lowest model level humidity from mixing ratio to specific humidity Q2 = QV3D(I,1,J) / ( 1.0 + QV3D(I,1,J) ) ! Calculate TH2 via Exner function APES = ( 1.E5 / PSFC ) ** CAPA APELM = ( 1.E5 / SFCPRS ) ** CAPA TH2 = ( SFCTMP * APELM ) / APES ! Q2SAT is specific humidity Q2SAT = QGH(I,J) / ( 1.0 + QGH(I,J) ) DQSDT2 = Q2SAT * A23M4 / ( SFCTMP - A4 ) ** 2 SELECT CASE ( SEAICE_SNOWDEPTH_OPT ) CASE DEFAULT WRITE(message,'("Namelist value for SEAICE_SNOWDEPTH_OPT not recognized: ",I6)') SEAICE_SNOWDEPTH_OPT CALL wrf_error_fatal(message) CASE ( 0 ) ! Minimum and maximum bounds on snow depth are enforced in SFLX_SEAICE CASE ( 1 ) ! Snow depth on sea ice comes from a 2D array, SNOWSI, bounded by user-specified ! minimum and maximum values. No matter what anybody else says about snow ! accumulation and melt, we want the snow depth on sea ice to be specified ! as SNOWSI (bounded by SEAICE_SNOWDEPTH_MIN and SEAICE_SNOWDEPTH_MAX). SNOWONSI = MAX ( SEAICE_SNOWDEPTH_MIN , MIN ( SNOWSI(I,J) , SEAICE_SNOWDEPTH_MAX ) ) SNEQV = SNOWONSI * 0.3 SNOWH2D(I,J) = SNOWONSI END SELECT IF ( SNOW(I,J) .GT. 0.0 ) THEN ! If snow on surface, use ice saturation properties SFCTSNO = SFCTMP ! Lowest model Air temperature E2SAT = 611.2 * EXP ( 6174. * ( 1./273.15 - 1./SFCTSNO ) ) Q2SATI = 0.622 * E2SAT / ( SFCPRS - E2SAT ) Q2SATI = Q2SATI / ( 1.0 + Q2SATI ) ! Convert to specific humidity ! T1 is skin temperature IF (T1 .GT. 273.14) THEN ! Warm ground temps, weight the saturation between ice and water according to SNOWC Q2SAT = Q2SAT * (1.-SNOWC(I,J)) + Q2SATI * SNOWC(I,J) DQSDT2 = DQSDT2 * (1.-SNOWC(I,J)) + Q2SATI * 6174. / (SFCTSNO**2) * SNOWC(I,J) ELSE ! Cold ground temps, use ice saturation only Q2SAT = Q2SATI DQSDT2 = Q2SATI * 6174. / (SFCTSNO**2) ENDIF IF ( ( T1 .GT. 273. ) .AND. ( SNOWC(I,J) .GT. 0.0 ) ) THEN ! If (SNOW > 0) can we have (SNOWC <= 0) ? Perhaps not, so the check on ! SNOWC here might be superfluous. DQSDT2 = DQSDT2 * ( 1. - SNOWC(I,J) ) ENDIF ENDIF PRCP = RAINBL(I,J) / DT ! If "SR" is present, set frac of frozen precip ("FFROZP") = snow-ratio ("SR", range:0-1) ! SR from e.g. Ferrier microphysics ! otherwise define from 1st atmos level temperature IF (FRPCPN) THEN FFROZP = SR(I,J) ELSE IF (SFCTMP <= 273.15) THEN FFROZP = 1.0 ELSE FFROZP = 0.0 ENDIF ENDIF ! Sea-ice point has deep-level temperature of about -1.8 C TBOT = 271.36 ! TBOT=273.15 ! appropriate value for lake ice. ! INTENT(IN) for SFLX_SEAICE, values unchanged by SFLX_SEAICE ! I -- ! J -- ! FFROZP -- ! DT -- ! ZLVL -- ! NSOIL -- ! LWDN -- ! SOLNET -- ! SFCPRS -- ! PRCP -- ! SFCTMP -- ! Q2 -- ! TH2 -- ! Q2SAT -- ! DQSDT2 -- ! SNOALB -- ! TBOT -- Z0BRD = Z02D(I,J) DO NS = 1, NSOIL STC(NS) = TSLB(I,NS,J) ENDDO CH = CHS(I,J) RIBB = RIB(I,J) ! INTENT(INOUT) for SFLX_SEAICE, values updated by SFLX_SEAICE ! Z0BRD -- ! EMISSI -- ! T1 -- ! STC -- ! SNOWH -- ! SNEQV -- ! SNCOVR -- ! CH -- but the result isn't used for anything. ! Might as well be intent in to SFLX_SEAICE and changed locally in ! that routine? ! RIBB -- but the result isn't used for anything. ! Might as well be intent in to SFLX_SEAICE and changed locally in ! that routine? ! INTENT(OUT) for SFLX_SEAICE. Input value should not matter. Z0 = -1.E36 ETA = -1.E36 SHEAT = -1.E36 ETA_KINEMATIC = -1.E36 FDOWN = -1.E36 ! Returned value unused. Might as well be local to SFLX_SEAICE ? ESNOW = -1.E36 ! Returned value unused. Might as well be local to SFLX_SEAICE ? DEW = -1.E36 ! Returned value unused. Might as well be local to SFLX_SEAICE ? ETP = -1.E36 SSOIL = -1.E36 FLX1 = -1.E36 FLX2 = -1.E36 FLX3 = -1.E36 SNOMLT = -1.E36 RUNOFF1 = -1.E36 Q1 = -1.E36 call sflx_seaice(I, J, SEAICE_ALBEDO_OPT, SEAICE_ALBEDO_DEFAULT, & !C & SEAICE_SNOWDEPTH_OPT, SEAICE_SNOWDEPTH_MAX, & !C & SEAICE_SNOWDEPTH_MIN, & !C & FFROZP, DT, ZLVL, NSOIL, & !C & SITHICK, & & LWDN, SOLNET, SFCPRS, PRCP, SFCTMP, Q2, & !F & TH2, Q2SAT, DQSDT2, & !I & SNOALB, TBOT, Z0BRD, Z0, EMISSI, & !S & T1, STC, SNOWH, SNEQV, ALBEDOK, CH, & !H & ALBEDOSI, SNOWONSI, & & ETA, SHEAT, ETA_KINEMATIC, FDOWN, & !O & ESNOW, DEW, ETP, SSOIL, FLX1, FLX2, FLX3, & !O & SNOMLT, SNCOVR, & !O & RUNOFF1, Q1, RIBB) ! Update our 2d arrays with results from SFLX_SEAICE ALBEDO(I,J) = ALBEDOK EMISS(I,J) = EMISSI TSK(I,J) = T1 Z02D(I,J) = Z0BRD SNOWH2D(I,J) = SNOWH SNOWC(I,J) = SNCOVR ! Convert snow water equivalent from (m) back to (mm) SNOW(I,J) = SNEQV * 1000. ! Update our ice temperature array with results from SFLX_SEAICE DO NS = 1,NSOIL TSLB(I,NS,J) = STC(NS) ENDDO ! Intent (OUT) from SFLX_SEAICE ZNT(I,J) = Z0 LH(I,J) = ETA HFX(I,J) = SHEAT QFX(I,J) = ETA_KINEMATIC POTEVP(I,J) = POTEVP(I,J) + ETP*FDTW GRDFLX(I,J) = SSOIL ! Exchange Coefficients CHS2(I,J) = CQS2(I,J) IF (Q1 .GT. QSFC(I,J)) THEN CQS2(I,J) = CHS(I,J) ENDIF ! Convert QSFC term back to Mixing Ratio. QSFC(I,J) = Q1 / ( 1.0 - Q1 ) IF ( SEAICE_SNOWDEPTH_OPT == 1 ) THEN SNOWSI(I,J) = SNOWONSI ENDIF ! Accumulated snow precipitation. IF ( FFROZP .GT. 0.5 ) THEN ACSNOW(I,J) = ACSNOW(I,J) + PRCP * DT ENDIF ! Accumulated snow melt. ACSNOM(I,J) = ACSNOM(I,J) + SNOMLT * 1000. ! Accumulated snow-melt energy. SNOPCX(I,J) = SNOPCX(I,J) - SNOMLT/FDTLIW ! Surface runoff SFCRUNOFF(I,J) = SFCRUNOFF(I,J) + RUNOFF1 * DT * 1000.0 ! ! Residual of surface energy balance terms ! NOAHRES(I,J) = ( SOLNET + LWDN ) & & - SHEAT + SSOIL - ETA & & - ( EMISSI * STBOLT * (T1**4) ) & & - FLX1 - FLX2 - FLX3 #if (NMM_CORE != 1) IF ( ( SF_URBAN_PHYSICS == NOAHUCMSCHEME ) .OR. & (SF_URBAN_PHYSICS == BEPSCHEME ) .OR. & ( SF_URBAN_PHYSICS == BEP_BEMSCHEME ) ) THEN if ( PRESENT (B_T_BEP) ) then B_T_BEP(I,1,J)=hfx(i,j)/dz8w(i,1,j)/rho(i,1,j)/CP endif if ( PRESENT (B_Q_BEP) ) then B_Q_BEP(I,1,J)=qfx(i,j)/dz8w(i,1,j)/rho(i,1,j) endif ENDIF #endif enddo SEAICE_ILOOP enddo SEAICE_JLOOP end subroutine seaice_noah end module module_sf_noah_seaice_drv