Skip to content
Snippets Groups Projects
mode_compute_bl89_ml.F90 8.96 KiB
Newer Older
  • Learn to ignore specific revisions
  • MODULE MODE_COMPUTE_BL89_ML
    IMPLICIT NONE
    CONTAINS
    
    !     ######spl
          SUBROUTINE COMPUTE_BL89_ML(KKA,KKB,KKE,KKU,KKL,PDZZ2D, &
                 PTKEM_DEP,PG_O_THVREF,PVPT,KK,OUPORDN,OFLUX,PSHEAR,PLWORK)
    
          USE PARKIND1, ONLY : JPRB
          USE YOMHOOK , ONLY : LHOOK, DR_HOOK
    !     ###################################################################
    !!
    !!     COMPUTE_BL89_ML routine to:
    !!       1/ compute upward or downward mixing length with BL89 formulation
    !!
    !!    AUTHOR
    !!    ------
    !!     J. PERGAUD
    !!
    !!    MODIFICATIONS
    !!    -------------
    !!     Original   19/01/06
    !!     S. Riette Jan 2012: support for both order of vertical levels and cleaning
    !!     R.Honnert Oct 2016 : Update with AROME
    !!     Q.Rodier  01/2019 : support RM17 mixing length as in bl89.f90 
    !  P. Wautelet 10/04/2019: replace ABORT and STOP calls by Print_msg
    !!
    !-------------------------------------------------------------------------------
    !
    !*       0.    DECLARATIONS
    !
    !              ------------
    !
    !!!!!!!!!!!!
    !!!!!!!!!!!!
    !!!!!!!!!!!!!!!!!! WARNING !!
    !!!!!!!!!!!!
    !!!!!!!!!!!!
    !Any modification done to this routine must be copied in bl89.f90.
    !This routine was inlined in bl89 for numerical performance reasons
    !but algorithm must remain the same.
    !!!!!!!!!!!!
    !
    USE MODD_CTURB
    USE MODD_PARAMETERS, ONLY: JPVEXT
    !
    USE MODE_MSG
    !
    
    USE MODI_SHUMAN_MF, ONLY: DZM_MF, MZM_MF
    
    !
    IMPLICIT NONE
    !
    !          0.1 arguments
    !
    INTEGER,                INTENT(IN)   :: KKA          ! near ground array index
    INTEGER,                INTENT(IN)   :: KKB          ! near ground physical index
    INTEGER,                INTENT(IN)   :: KKE          ! uppest atmosphere physical index
    INTEGER,                INTENT(IN)   :: KKU          ! uppest atmosphere array index
    INTEGER,                INTENT(IN)   :: KKL          ! +1 if grid goes from ground to atmosphere top, -1 otherwise
    REAL, DIMENSION(:,:),   INTENT(IN)  :: PDZZ2D        ! height difference between two mass levels
    REAL, DIMENSION(:),     INTENT(IN)  :: PTKEM_DEP     ! TKE to consume
    REAL, DIMENSION(:),     INTENT(IN)  :: PG_O_THVREF   ! g/ThetaVRef at the departure point
    REAL, DIMENSION(:,:),   INTENT(IN)  :: PVPT          ! ThetaV on mass levels
    INTEGER,                INTENT(IN)  :: KK            ! index of departure level
    LOGICAL,                INTENT(IN)  :: OUPORDN       ! switch to compute upward (true) or
                                                         !   downward (false) mixing length
    LOGICAL,                INTENT(IN)  :: OFLUX         ! Computation must be done from flux level
    REAL, DIMENSION(:),     INTENT(OUT) :: PLWORK        ! Resulting mixing length
    REAL, DIMENSION(:,:),   INTENT(IN)  :: PSHEAR        ! vertical wind shear for RM17 mixing length
    
    !          0.2 Local variable
    !
    REAL, DIMENSION(SIZE(PVPT,1)) :: ZLWORK1,ZLWORK2 ! Temporary mixing length
    REAL, DIMENSION(SIZE(PVPT,1)) :: ZINTE,ZPOTE     ! TKE and potential energy
                                                     !   between 2 levels
    REAL, DIMENSION(SIZE(PVPT,1)) :: ZVPT_DEP        ! Thetav on departure point
    !
    REAL, DIMENSION(SIZE(PVPT,1),SIZE(PVPT,2)) :: ZDELTVPT,ZHLVPT                                
                          !Virtual Potential Temp at Half level and DeltaThv between
                          !2 mass levels
    
    INTEGER :: IIJU                 !Internal Domain
    INTEGER :: J1D                  !horizontal loop counter
    INTEGER :: JKK                  !loop counters
    REAL    :: ZTEST,ZTEST0,ZTESTM  !test for vectorization
    !-------------------------------------------------------------------------------------
    !
    !*       1.    INITIALISATION
    !              --------------
    REAL(KIND=JPRB) :: ZHOOK_HANDLE
    IF (LHOOK) CALL DR_HOOK('COMPUTE_BL89_ML',0,ZHOOK_HANDLE)
    IIJU=SIZE(PVPT,1)
    !
    
    ZDELTVPT(:,:)=DZM_MF(PVPT(:,:), KKA, KKU, KKL)
    
    ZDELTVPT(:,KKA)=0.
    WHERE (ABS(ZDELTVPT(:,:))<XLINF)
      ZDELTVPT(:,:)=XLINF
    END WHERE
    !
    
    ZHLVPT(:,:)=MZM_MF(PVPT(:,:), KKA, KKU, KKL)
    
    !
    !We consider that gradient between mass levels KKB and KKB+KKL is the same as
    !the gradient between flux level KKB and mass level KKB
    ZDELTVPT(:,KKB)=PDZZ2D(:,KKB)*ZDELTVPT(:,KKB+KKL)/PDZZ2D(:,KKB+KKL)
    ZHLVPT(:,KKB)=PVPT(:,KKB)-ZDELTVPT(:,KKB)*0.5
    !
    !
    !
    !*       2.    CALCULATION OF THE UPWARD MIXING LENGTH
    !              ---------------------------------------
    !
    
    IF (OUPORDN.EQV..TRUE.) THEN 
     ZINTE(:)=PTKEM_DEP(:)
     PLWORK=0.
     ZTESTM=1.
     IF(OFLUX)THEN
       ZVPT_DEP(:)=ZHLVPT(:,KK) ! departure point is on flux level
       !We must compute what happens between flux level KK and mass level KK
       DO J1D=1,IIJU
         ZTEST0=0.5+SIGN(0.5,ZINTE(J1D)) ! test if there's energy to consume
         ! Energy consumed if parcel cross the entire layer
         ZPOTE(J1D) = ZTEST0*(PG_O_THVREF(J1D)      *      &
             (0.5*(ZHLVPT(J1D,KK)+ PVPT(J1D,KK)) - ZVPT_DEP(J1D)) + &
             XRM17*PSHEAR(J1D,KK)*SQRT(ABS(PTKEM_DEP(J1D))))  * &
             PDZZ2D(J1D,KK)*0.5
         ! Test if it rests some energy to consume
         ZTEST =0.5+SIGN(0.5,ZINTE(J1D)-ZPOTE(J1D))
         ! Length travelled by parcel if it rests energy to consume
         ZLWORK1(J1D)=PDZZ2D(J1D,KK)*0.5
         ! Lenght travelled by parcel to nullify energy
         ZLWORK2(J1D)=        ( - PG_O_THVREF(J1D) *                     &
                (  ZHLVPT(J1D,KK) - ZVPT_DEP(J1D) )                              &
    
                - XRM17*PSHEAR(J1D,KK)*SQRT(ABS(PTKEM_DEP(J1D))) &
    
                (XRM17*PSHEAR(J1D,KK)*SQRT(ABS(PTKEM_DEP(J1D))) +  &
    
                 PG_O_THVREF(J1D) * (ZHLVPT(J1D,KK) - ZVPT_DEP(J1D)) )**2  &
                + 2. * ZINTE(J1D) * PG_O_THVREF(J1D)                        &
                     * ZDELTVPT(J1D,KK) / PDZZ2D(J1D,KK) ))    ) /             &
            ( PG_O_THVREF(J1D) * ZDELTVPT(J1D,KK) / PDZZ2D(J1D,KK) ) 
          ! Effective length travelled by parcel
          PLWORK(J1D)=PLWORK(J1D)+ZTEST0*(ZTEST*ZLWORK1(J1D)+  &
                                        (1-ZTEST)*ZLWORK2(J1D))
          ! Rest of energy to consume
          ZINTE(J1D) = ZINTE(J1D) - ZPOTE(J1D)
       ENDDO
     ELSE
       ZVPT_DEP(:)=PVPT(:,KK) ! departure point is on mass level
     ENDIF
    
     DO JKK=KK+KKL,KKE,KKL
        IF(ZTESTM > 0.) THEN
          ZTESTM=0
          DO J1D=1,IIJU
            ZTEST0=0.5+SIGN(0.5,ZINTE(J1D))
            ZPOTE(J1D) = ZTEST0*(PG_O_THVREF(J1D)      *      &
                (ZHLVPT(J1D,JKK) - ZVPT_DEP(J1D))   &
               + XRM17*PSHEAR(J1D,JKK)*SQRT(ABS(PTKEM_DEP(J1D))))* PDZZ2D(J1D,JKK) 
            ZTEST =0.5+SIGN(0.5,ZINTE(J1D)-ZPOTE(J1D))
            ZTESTM=ZTESTM+ZTEST0
            ZLWORK1(J1D)=PDZZ2D(J1D,JKK)
            !ZLWORK2 jump of the last reached level
            ZLWORK2(J1D)=        ( - PG_O_THVREF(J1D) *                     &
                (  PVPT(J1D,JKK-KKL) - ZVPT_DEP(J1D) )                              &
                - XRM17*PSHEAR(J1D,JKK)*sqrt(abs(PTKEM_DEP(J1D))) &
              + SQRT (ABS(                                                   &
                (XRM17*PSHEAR(J1D,JKK)*sqrt(abs(PTKEM_DEP(J1D))) +  &
                 PG_O_THVREF(J1D) * (PVPT(J1D,JKK-KKL) - ZVPT_DEP(J1D)) )**2  &
                + 2. * ZINTE(J1D) * PG_O_THVREF(J1D)                        &
                     * ZDELTVPT(J1D,JKK) / PDZZ2D(J1D,JKK) ))    ) /             &
            ( PG_O_THVREF(J1D) * ZDELTVPT(J1D,JKK) / PDZZ2D(J1D,JKK) ) 
          !
            PLWORK(J1D)=PLWORK(J1D)+ZTEST0*(ZTEST*ZLWORK1(J1D)+  &
                                        (1-ZTEST)*ZLWORK2(J1D))
            ZINTE(J1D) = ZINTE(J1D) - ZPOTE(J1D)
          END DO 
        ENDIF
      END DO 
    ENDIF
    !!
    !*       2.    CALCULATION OF THE DOWNWARD MIXING LENGTH
    !              ---------------------------------------
    !
    
    IF (OUPORDN.EQV..FALSE.) THEN 
     IF(OFLUX) CALL PRINT_MSG(NVERB_FATAL,'GEN','COMPUTE_BL89_ML','OFLUX option not coded for downward mixing length')
     ZINTE(:)=PTKEM_DEP(:)
     PLWORK=0.
     ZTESTM=1.
     DO JKK=KK,KKB,-KKL
        IF(ZTESTM > 0.) THEN
          ZTESTM=0
          DO J1D=1,IIJU
            ZTEST0=0.5+SIGN(0.5,ZINTE(J1D))
             ZPOTE(J1D) = ZTEST0*(-PG_O_THVREF(J1D)      *      &
                (ZHLVPT(J1D,JKK) - PVPT(J1D,KK)) &
             + XRM17*PSHEAR(J1D,JKK)*SQRT(ABS(PTKEM_DEP(J1D))))* PDZZ2D(J1D,JKK) 
            ZTEST =0.5+SIGN(0.5,ZINTE(J1D)-ZPOTE(J1D))
            ZTESTM=ZTESTM+ZTEST0
            ZLWORK1(J1D)=PDZZ2D(J1D,JKK)
    
            ZLWORK2(J1D)=        ( + PG_O_THVREF(J1D) *                     &
    
                (  PVPT(J1D,JKK) - PVPT(J1D,KK) )                              &
                 -XRM17*PSHEAR(J1D,JKK)*sqrt(abs(PTKEM_DEP(J1D))) &
              + SQRT (ABS(                                                       &
                (XRM17*PSHEAR(J1D,JKK)*sqrt(abs(PTKEM_DEP(J1D))) - &
                 PG_O_THVREF(J1D) * (PVPT(J1D,JKK) - PVPT(J1D,KK)) )**2  &
                + 2. * ZINTE(J1D) * PG_O_THVREF(J1D)                        &
                     * ZDELTVPT(J1D,JKK) / PDZZ2D(J1D,JKK) ))    ) /             &
            ( PG_O_THVREF(J1D) * ZDELTVPT(J1D,JKK) / PDZZ2D(J1D,JKK) ) 
          !
            PLWORK(J1D)=PLWORK(J1D)+ZTEST0*(ZTEST*ZLWORK1(J1D)+  &
                                        (1-ZTEST)*ZLWORK2(J1D)) 
            ZINTE(J1D) = ZINTE(J1D) - ZPOTE(J1D)
          END DO 
        ENDIF
      END DO 
    ENDIF
      
    IF (LHOOK) CALL DR_HOOK('COMPUTE_BL89_ML',1,ZHOOK_HANDLE)
    END SUBROUTINE COMPUTE_BL89_ML
    
    END MODULE MODE_COMPUTE_BL89_ML