diff --git a/.circleci/config.yml b/.circleci/config.yml index 7c7d0d6a..31a4f50c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,11 +1,11 @@ version: 2.1 # Anchors in case we need to override the defaults from the orb -#baselibs_version: &baselibs_version v7.27.0 -#bcs_version: &bcs_version v11.6.0 +#baselibs_version: &baselibs_version v8.24.0 +#bcs_version: &bcs_version v12.0.0 orbs: - ci: geos-esm/circleci-tools@4 + ci: geos-esm/circleci-tools@5 workflows: build-test: @@ -21,7 +21,10 @@ workflows: #baselibs_version: *baselibs_version repo: GEOSgcm checkout_fixture: true - mepodevelop: true + # V12 code uses a special branch for now. + fixture_branch: feature/sdrabenh/gcm_v12 + # We comment out this as it will "undo" the fixture_branch + #mepodevelop: true persist_workspace: true # Needs to be true to run fv3/gcm experiment, costs extra # Run AMIP GCM (1 hour, no ExtData) @@ -45,7 +48,7 @@ workflows: - docker-hub-creds matrix: parameters: - compiler: [gfortran, ifort] + compiler: [ifort] requires: - build-GEOSgcm-on-<< matrix.compiler >> repo: GEOSgcm diff --git a/.github/workflows/enforce-labels.yml b/.github/workflows/enforce-labels.yml index ad7937eb..86f4bb4e 100644 --- a/.github/workflows/enforce-labels.yml +++ b/.github/workflows/enforce-labels.yml @@ -14,7 +14,7 @@ jobs: with: mode: minimum count: 1 - labels: "0 diff,0 diff trivial,Non 0-diff,0 diff structural,0-diff trivial,Not 0-diff,0-diff,automatic,0-diff uncoupled" + labels: "0 diff,0 diff trivial,Non 0-diff,0 diff structural,0-diff trivial,Not 0-diff,0-diff,automatic,0-diff uncoupled,github_actions" add_comment: true message: "This PR is being prevented from merging because you have not added one of our required labels: {{ provided }}. Please add one so that the PR can be merged." diff --git a/.github/workflows/validate_yaml_files.yml b/.github/workflows/validate_yaml_files.yml index 449db6e6..e55ad93c 100644 --- a/.github/workflows/validate_yaml_files.yml +++ b/.github/workflows/validate_yaml_files.yml @@ -15,7 +15,11 @@ jobs: validate-YAML: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - name: Checkout repo + uses: actions/checkout@v6 + with: + fetch-depth: 0 + filter: blob:none - id: yaml-lint name: yaml-lint uses: ibiqlik/action-yamllint@v3 @@ -24,7 +28,7 @@ jobs: format: colored config_file: .yamllint.yml - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v6 if: always() with: name: yamllint-logfile diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml new file mode 100644 index 00000000..e474c770 --- /dev/null +++ b/.github/workflows/workflow.yml @@ -0,0 +1,40 @@ +name: Build Tests + +on: + pull_request: + types: [opened, synchronize, reopened] + # Do not run if the only files changed cannot affect the build + paths-ignore: + - "**.md" + - "**.pro" + - "**.sh" + - "**.perl" + - ".github/CODEOWNERS" + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} + +jobs: + build_gcm: + strategy: + matrix: + compiler: [ifort, gfortran-14, gfortran-15] + build-type: [Debug] + fail-fast: false + uses: GEOS-ESM/CI-workflows/.github/workflows/geosgcm_build_tests.yml@project/geosgcm + with: + compiler: ${{ matrix.compiler }} + cmake-build-type: ${{ matrix.build-type }} + fixture-repo: GEOS-ESM/GEOSgcm + fixture-ref: feature/sdrabenh/gcm_v12 + + spack_build: + uses: GEOS-ESM/CI-workflows/.github/workflows/spack_gcc_build.yml@project/geosgcm + secrets: + BUILDCACHE_USERNAME: ${{ secrets.BUILDCACHE_USERNAME }} + BUILDCACHE_TOKEN: ${{ secrets.BUILDCACHE_TOKEN }} + with: + fixture-repo: GEOS-ESM/GEOSgcm + fixture-ref: feature/sdrabenh/gcm_v12 + diff --git a/CHANGELOG.md b/CHANGELOG.md index 760f0687..bee63cb2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed ### Deprecated +## [1.16.1] - 2025-12-16 + +### Added + +- Added the capability to compute LFC in Lightning module, needed for CTM + +### Changed + +- Slight refactoring of LOPEZ lightning scheme, minor numerical difference +- Renamed lightning option 'usePreconCape' to 'useImportedCape' in order to cover both GCM and CTM +- Moved from `f2py2` to `f2py3` to enable removal of Python 2 support +- Updated CI + +### Fixed + +- ChemEnv now updates the precip exports (total, conv, non-conv) as part of Run1 (not just Run2). + ## [1.16.0 - 2025-02-18] diff --git a/ChemEnv.rc b/ChemEnv.rc index fe747e8f..798f58ab 100644 --- a/ChemEnv.rc +++ b/ChemEnv.rc @@ -37,4 +37,10 @@ lightNOampFactor: 1.07 numberNOperFlash: 1.50e+26 minDeepCloudTop: 7.0 -usePreconCape: TRUE +# originally called usePreconCape +# IF TRUE: CHEM should use the IMPORT state for CAPE, INHB, BYNCY, LFC +# for GMI, imports come from MOIST and reflect the state prior to convective transport +# for CTM, imports come from ExtData or CTMenv (currently these fields are not supported) +# IF FALSE: compute CAPE, INHB, BYNCY, LFC in the CHEM module + use the FALSE setting for CTM +useImportedCape: TRUE diff --git a/GEOS_ChemEnvGridComp.F90 b/GEOS_ChemEnvGridComp.F90 index a97f48ba..a7e974ab 100644 --- a/GEOS_ChemEnvGridComp.F90 +++ b/GEOS_ChemEnvGridComp.F90 @@ -49,7 +49,7 @@ module GEOS_ChemEnvGridCompMod real :: FIT_flashFactor real :: HEMCO_flashFactor real :: LOPEZ_flashFactor - logical :: usePreconCape ! use CAPE, INHB and BYNCY from MOIST + logical :: useImportedCape ! use CAPE, INHB and BYNCY from Import State ! May change during the course of the run: integer :: year_for_ratio = 0 @@ -777,7 +777,7 @@ subroutine Initialize_ ( GC, impChem, expChem, clock, RC ) numberNOperFlash, & MOIST_flashFactor, FIT_flashFactor, & HEMCO_flashFactor, LOPEZ_flashFactor, & - usePreconCape, & + useImportedCape, & __RC__ ) IF(MAPL_AM_I_ROOT()) THEN @@ -786,7 +786,7 @@ subroutine Initialize_ ( GC, impChem, expChem, clock, RC ) if ( flash_source_enum == FLASH_SOURCE_HEMCO ) PRINT*,'HEMCO_flashFactor is ', HEMCO_flashFactor if ( flash_source_enum == FLASH_SOURCE_LOPEZ ) PRINT*,'LOPEZ_flashFactor is ', LOPEZ_flashFactor - PRINT*,'usePreconCape = ', usePreconCape + PRINT*,'useImportedCape = ', useImportedCape ENDIF RETURN_(ESMF_SUCCESS) @@ -849,16 +849,18 @@ subroutine Run1 ( GC, IMPORT, EXPORT, CLOCK, RC ) real, pointer, dimension(:,:) :: TS => null() real, pointer, dimension(:,:) :: FROCEAN => null() real, pointer, dimension(:,:) :: FRLAND => null() - real, pointer, dimension(:,:) :: CN_PRCP => null() real, pointer, dimension(:,:) :: PHIS => null() real, pointer, dimension(:,:,:) :: CNV_MFC => null() real, pointer, dimension(:,:,:) :: CNV_MFD => null() real, pointer, dimension(:,:,:) :: PFI_CN => null() real, pointer, dimension(:,:,:) :: CNV_QC => null() - real, pointer, dimension(:,:) :: CAPE_PRECON => null() - real, pointer, dimension(:,:) :: INHB_PRECON => null() - real, pointer, dimension(:,:,:) :: BYNCY_PRECON => null() + real, pointer, dimension(:,:) :: CAPE_IMPORT => null() + real, pointer, dimension(:,:) :: INHB_IMPORT => null() + real, pointer, dimension(:,:,:) :: BYNCY_IMPORT => null() + + real, pointer, dimension(:,:) :: pr_total => null() + real, pointer, dimension(:,:) :: pr_conv => null() ! Exports real, pointer, dimension(:,:,:) :: delp => null() @@ -867,6 +869,10 @@ subroutine Run1 ( GC, IMPORT, EXPORT, CLOCK, RC ) real, pointer, dimension(:,:) :: CAPE => null() real*4, pointer, dimension(:,:,:) :: LIGHT_NO_PROD => null() + real, pointer, dimension(:,:) :: tprec => null() + real, pointer, dimension(:,:) :: cn_prcp => null() + real, pointer, dimension(:,:) :: ncn_prcp => null() + !============================================================================= integer :: k, k0 @@ -941,6 +947,21 @@ subroutine Run1 ( GC, IMPORT, EXPORT, CLOCK, RC ) end do end if +! Import total precip from SURFACE (either model or observed precip) +! When running CTM, use fields such that (total - convective) >= 0.0 +! Export total, convective and non-convective precipitation. +! -------------------------------------------------------------------- + call MAPL_GetPointer ( EXPORT, tprec, 'TPREC', __RC__ ) + call MAPL_GetPointer ( EXPORT, cn_prcp, 'CN_PRCP', __RC__ ) + call MAPL_GetPointer ( EXPORT, ncn_prcp, 'NCN_PRCP', __RC__ ) + + call MAPL_GetPointer ( IMPORT, pr_total, 'PRECTOT', __RC__ ) + call MAPL_GetPointer ( IMPORT, pr_conv, 'CN_PRCP', __RC__ ) + + if (associated( tprec)) tprec = pr_total + if (associated( cn_prcp)) cn_prcp = pr_conv + if (associated(ncn_prcp)) ncn_prcp = (pr_total - pr_conv) + !------------------------------------------------ ! Flash Rate (LFR) for Lighting Parameterization @@ -959,7 +980,6 @@ subroutine Run1 ( GC, IMPORT, EXPORT, CLOCK, RC ) call MAPL_GetPointer ( IMPORT, CNV_MFC, 'CNV_MFC', __RC__ ) call MAPL_GetPointer ( IMPORT, CNV_MFD, 'CNV_MFD', __RC__ ) - call MAPL_GetPointer ( IMPORT, CN_PRCP, 'CN_PRCP', __RC__ ) call MAPL_GetPointer ( IMPORT, PHIS, 'PHIS', __RC__ ) call MAPL_GetPointer ( IMPORT, PFI_CN, 'PFI_CN', __RC__ ) @@ -975,9 +995,9 @@ subroutine Run1 ( GC, IMPORT, EXPORT, CLOCK, RC ) call MAPL_GetPointer ( IMPORT, CNV_QC, 'CNV_QC', __RC__ ) call MAPL_GetPointer ( IMPORT, cellArea, 'AREA', __RC__ ) - call MAPL_GetPointer ( IMPORT, CAPE_PRECON, 'CAPE', __RC__ ) - call MAPL_GetPointer ( IMPORT, INHB_PRECON, 'INHB', __RC__ ) - call MAPL_GetPointer ( IMPORT, BYNCY_PRECON, 'BYNCY', __RC__ ) + call MAPL_GetPointer ( IMPORT, CAPE_IMPORT, 'CAPE', __RC__ ) + call MAPL_GetPointer ( IMPORT, INHB_IMPORT, 'INHB', __RC__ ) + call MAPL_GetPointer ( IMPORT, BYNCY_IMPORT, 'BYNCY', __RC__ ) call MAPL_GetPointer ( IMPORT, ZLFC, 'ZLFC', __RC__ ) call MAPL_GetPointer ( IMPORT, ZLCL, 'ZLCL', __RC__ ) @@ -991,7 +1011,7 @@ subroutine Run1 ( GC, IMPORT, EXPORT, CLOCK, RC ) LIGHT_NO_PROD(:,:,:) = REAL(0) end if -! print*,'ENV MOIST CN_PRCP ', MINVAL(CN_PRCP), MAXVAL(CN_PRCP) +! print*,'ENV MOIST CN_PRCP ', MINVAL(pr_conv), MAXVAL(pr_conv) ! print*,'ENV MOIST FROCEAN ', MINVAL(FROCEAN), MAXVAL(FROCEAN) ! print*,'ENV MOIST TS ', MINVAL(TS ), MAXVAL(TS ) ! print*,'ENV MOIST CNV_MFC ', MINVAL(CNV_MFC), MAXVAL(CNV_MFC) @@ -1005,12 +1025,12 @@ subroutine Run1 ( GC, IMPORT, EXPORT, CLOCK, RC ) call getLightning ( GC, ggState, CLOCK, & flash_source_enum, ratioGlobalLight, DT, & - LONSLOCAL, LATSLOCAL, CN_PRCP, FRLAND, FROCEAN, LWI, & + LONSLOCAL, LATSLOCAL, pr_conv, FRLAND, FROCEAN, LWI, & PBLH, mcor, cellArea, MIDLAT_ADJ, RATIO_LOCAL, & TS, CNV_MFC, CNV_QC, T, TH, PFI_CN, PLE, Q, ZLE, & minDeepCloudTop, lightNOampFactor, numberNOperFlash, & MOIST_flashFactor, FIT_flashFactor, HEMCO_flashFactor, LOPEZ_flashFactor, & - CNV_MFD, usePreconCape, CAPE_PRECON, INHB_PRECON, BYNCY_PRECON, & + CNV_MFD, useImportedCape, CAPE_IMPORT, INHB_IMPORT, BYNCY_IMPORT, & CAPE, BYNCY, ZLFC, ZLCL, LFR, LIGHT_NO_PROD, PHIS, & __RC__) @@ -1133,18 +1153,17 @@ subroutine Run2 ( GC, IMPORT, EXPORT, CLOCK, RC ) end do end if -! Import total precip from SURFACE (either model or observed precip) -! Export total, convective and non-convective precipitation. -!-------------------------------------------------------------- +! Import total precip from SURFACE (either model or observed precip) +! When running CTM, use fields such that (total - convective) >= 0.0 +! Export total, convective and non-convective precipitation. +! -------------------------------------------------------------------- call MAPL_GetPointer ( EXPORT, tprec, 'TPREC', __RC__ ) call MAPL_GetPointer ( EXPORT, cn_prcp, 'CN_PRCP', __RC__ ) call MAPL_GetPointer ( EXPORT, ncn_prcp, 'NCN_PRCP', __RC__ ) - - call MAPL_GetPointer ( IMPORT, pr_total, 'PRECTOT', __RC__ ) - call MAPL_GetPointer ( IMPORT, pr_conv, 'CN_PRCP', __RC__ ) + call MAPL_GetPointer ( IMPORT, pr_total, 'PRECTOT', __RC__ ) + call MAPL_GetPointer ( IMPORT, pr_conv, 'CN_PRCP', __RC__ ) - if (associated( tprec)) tprec = pr_total if (associated( cn_prcp)) cn_prcp = pr_conv if (associated(ncn_prcp)) ncn_prcp = (pr_total - pr_conv) diff --git a/Shared/Chem_Shared/Lightning_mod.F90 b/Shared/Chem_Shared/Lightning_mod.F90 index 3afa56c9..97af7bd5 100644 --- a/Shared/Chem_Shared/Lightning_mod.F90 +++ b/Shared/Chem_Shared/Lightning_mod.F90 @@ -132,7 +132,7 @@ subroutine getLightning (GC, ggState, CLOCK, & PFICU, PLE, Q, ZLE, & minDeepCloudTop, lightNOampFactor, numberNOperFlash, & MOIST_flashFactor, FIT_flashFactor, HEMCO_flashFactor, LOPEZ_flashFactor, & - CNV_MFD, usePreconCape, CAPE_PRECON, INHB_PRECON, BYNCY_PRECON, & + CNV_MFD, useImportedCape, CAPE_IMPORT, INHB_IMPORT, BYNCY_IMPORT, & CAPE, BYNCY, ZLFC, ZLCL, flashRate, light_NO_prod, PHIS, & RC) @@ -176,7 +176,7 @@ subroutine getLightning (GC, ggState, CLOCK, & ! edge vars (vertical indices: 1 to LM+1) real, dimension(:,:,:), intent(in) :: CNV_MFC ! cumulative mass flux (kg m-2 s-1) [top-down] real, dimension(:,:,:), intent(in) :: PLE ! edge pressures (Pa) - real, dimension(:,:,:), intent(in) :: ZLE ! geopotential height (m) [top-down] + real, dimension(:,:,:), intent(in) :: ZLE ! edge heights (m) above sea-level [top-down] real, dimension(:,:,:), intent(in) :: PFICU ! flux of ice in convective updrafts (kg m-2 s-1) real, dimension(:,:,:), intent(in) :: T ! air temperature (K) [top-down] @@ -188,10 +188,10 @@ subroutine getLightning (GC, ggState, CLOCK, & real, intent(in) :: numberNOperFlash ! NO molecules generated by each flash real, dimension(:,:,:), intent(in) :: CNV_MFD ! detraining_mass_flux (kg m-2 s-1) [top-down] - logical, intent(in) :: usePreconCape ! Whether to use CAPE, INHB and BYNCY from MOIST - real, dimension(:,:), intent(in) :: CAPE_PRECON - real, dimension(:,:), intent(in) :: INHB_PRECON - real, dimension(:,:,:), intent(in) :: BYNCY_PRECON + logical, intent(in) :: useImportedCape ! Whether to use CAPE, INHB and BYNCY from Import State, or compute them locally + real, dimension(:,:), intent(in) :: CAPE_IMPORT + real, dimension(:,:), intent(in) :: INHB_IMPORT + real, dimension(:,:,:), intent(in) :: BYNCY_IMPORT REAL, dimension(:,:), INTENT(IN) :: ZLFC ! Level of Free Convection height [m] REAL, dimension(:,:), INTENT(IN) :: ZLCL ! Lifted Condensation Level height [m] @@ -208,18 +208,16 @@ subroutine getLightning (GC, ggState, CLOCK, & ! type (ESMF_Grid) :: esmfGrid ! Lopez calculation; TODO these variables can be contained within a contains block - real, allocatable :: PLO(:,:,:) ! pressure at middle of gridbox [hPa] - real, allocatable :: PKE(:,:,:) - real, allocatable :: PK(:,:,:) + real, allocatable :: PLmb(:,:,:) ! pressure at middle of gridbox [hPa] real, allocatable :: QSS(:,:,:) ! saturation specific humidity real, allocatable :: DQS(:,:,:) ! derivative of satuation specific humidity wrt temperature - real, allocatable :: DZ(:,:,:) + real, allocatable :: DZET(:,:,:) real, allocatable :: DM(:,:,:) - real, allocatable :: THV(:,:,:) - real, allocatable :: ZLO(:,:,:) - real, allocatable :: ZLE2(:,:,:) + real, allocatable :: ZLE_ZERO(:,:,:) ! Edge heights (m) above surface (equals zero at ground level) + real, allocatable :: ZL_ZERO(:,:,:) ! Mid-point heights (m) above surface real, allocatable :: CAPE_MERRA2(:,:) real, allocatable :: INHB(:,:) + real, allocatable :: LFC(:,:) ! Level of Free Convection (m) - compute using the BYNCY of choice integer, allocatable :: LWI_INT(:,:) real*8, allocatable :: LFR_R8(:,:) @@ -256,6 +254,10 @@ subroutine getLightning (GC, ggState, CLOCK, & character(len=80) :: cNym character(len=3) :: binName + integer :: KLFC ! index of Level of Free Convection + integer :: KLNB ! index of Level of Neutral Buoyancy, computed but not used + logical :: aboveLFC + character(len=*), parameter :: Iam = "getLightning" ! can be moduleName // getLightning TODO if (PRESENT(RC)) RC = ESMF_SUCCESS @@ -288,59 +290,33 @@ subroutine getLightning (GC, ggState, CLOCK, & IF ( need_cape ) THEN ALLOCATE( INHB(IM, JM), __STAT__ ) + ALLOCATE( LFC(IM, JM), __STAT__ ) ! on gridbox centers: - ALLOCATE( PLO(IM, JM, 1:LM), __STAT__ ) - ALLOCATE( PK(IM, JM, 1:LM), __STAT__ ) + ALLOCATE( PLmb(IM, JM, 1:LM), __STAT__ ) ALLOCATE( DQS(IM, JM, 1:LM), __STAT__ ) ALLOCATE( QSS(IM, JM, 1:LM), __STAT__ ) - ALLOCATE( DZ(IM, JM, 1:LM), __STAT__ ) - ALLOCATE( THV(IM, JM, 1:LM), __STAT__ ) - ALLOCATE( ZLO(IM, JM, 1:LM), __STAT__ ) + ALLOCATE( DZET(IM, JM, 1:LM), __STAT__ ) + ALLOCATE( ZL_ZERO(IM, JM, 1:LM), __STAT__ ) ! on gridbox edges: - ALLOCATE( PKE(IM, JM, 0:LM), __STAT__ ) - ALLOCATE( ZLE2(IM, JM, 0:LM), __STAT__ ) - - - PLO = 0.5*(PLE(:,:,K0:KM-1) + PLE(:,:,K0+1:KM ) )*0.01 - PKE(:,:,0:LM) = (PLE(:,:,K0:KM)*(1.0/MAPL_P00))**(MAPL_RGAS/MAPL_CP) + ALLOCATE( ZLE_ZERO(IM, JM, 0:LM), __STAT__ ) - PK = (PLO*(100.0/MAPL_P00))**(MAPL_RGAS/MAPL_CP) + PLmb = 0.5*(PLE(:,:,K0:KM-1) + PLE(:,:,K0+1:KM ) )*0.01 - DQS = GEOS_DQSAT (TH*PK, PLO, qsat=QSS) + DQS = GEOS_DQSAT (T, PLmb, qsat=QSS) - THV(:,:,:) = TH(:,:,:) * (1.+MAPL_VIREPS*Q(:,:,:)) +!! In order to compute Buoyancy as done in MOIST, we want mid-level heights above surface, not above sea-level +!! Compute as done in MOIST (KROK) +!! Note: ZLE is height above sea level, z-index 1..73 +!! ZLE_ZERO is height above surface, z-index 0..72 + DO L=0,LM + ZLE_ZERO(:,:,L)= ZLE(:,:,L+1) - ZLE(:,:,LM+1) ! Edge Height (m) above the surface + END DO + ZL_ZERO = 0.5*(ZLE_ZERO(:,:,0:LM-1) + ZLE_ZERO(:,:,1:LM) ) ! Layer Height (m) above the surface + DZET = (ZLE_ZERO(:,:,0:LM-1) - ZLE_ZERO(:,:,1:LM) ) ! Layer thickness (m) - ZLE2(:,:,LM) = 0. ! ORIGINAL FORMULATION - does Saulo need this? - ZLE2(:,:,LM) = PHIS/MAPL_GRAV ! Better match for archived ZLE - do L=LM,1,-1 - ZLO(:,:,L ) = ZLE2(:,:,L) + (MAPL_CP/MAPL_GRAV)*( PKE(:,:,L)-PK (:,:,L ) ) * THV(:,:,L) - DZ (:,:,L ) = (MAPL_CP/MAPL_GRAV)*( PKE(:,:,L)-PKE(:,:,L-1) ) * THV(:,:,L) - ZLE2(:,:,L-1) = ZLE2(:,:,L) + DZ(:,:,L) -! ZLE2(:,:,L-1) = ZLE2(:,:,L) + (MAPL_CP/MAPL_GRAV)*( PKE(:,:,L)-PKE(:,:,L-1) ) * THV(:,:,L) - end do - -! TODO - decide if we can remove ZLE or ZLE2 since they are nearly duplicates -! although the indices are mismatched (ZLE starts at 1, ZLE2 starts at 0) -! IF(MAPL_AM_I_ROOT()) THEN -! DO i=K0,KM -! PRINT *,'ZLE, ZLE2:', i, ZLE(1,1,i), ZLE2(1,1,i-1), ZLE(1,1,i)-ZLE2(1,1,i-1) -! ENDDO -! ENDIF - -! IF(MAPL_AM_I_ROOT()) THEN -! PRINT*,' ZLE vert: ', LBOUND(ZLE, 3), UBOUND(ZLE, 3) -! PRINT*,'ZLE2 vert: ', LBOUND(ZLE2,3), UBOUND(ZLE2,3) -! PRINT*,' PLE vert: ', LBOUND(PLE, 3), UBOUND(PLE, 3) -! -! ! ZLE vert: 1 73 -! ! ZLE2 vert: 0 72 -! ! PLE vert: 1 73 -! -! ENDIF - - ! ALL SET to call BUOYANCY (T, Q, QSS, DQS, DZ, ZLO, BYNCY, CAPE, INHB) + ! ALL SET to call BUOYANCY (T, Q, QSS, DQS, DZET, ZL_ZERO, BYNCY, CAPE, INHB) ! DEALLOCATE vars at the end @@ -353,22 +329,65 @@ subroutine getLightning (GC, ggState, CLOCK, & !----------------------------------------------------------------------- if (flash_source_enum == FLASH_SOURCE_LOPEZ) then - ! callLopezCalcuations() put above end subroutine getLightning - - if (usePreconCape) then - CAPE = CAPE_PRECON - INHB = INHB_PRECON - BYNCY = BYNCY_PRECON + ! useImportedCape - in GCM this means to use the values from MOIST + ! useImportedCape - in CTM this means to use the values from ExtData or CtmEnv (not presently available) + if (useImportedCape) then + CAPE = CAPE_IMPORT + INHB = INHB_IMPORT + BYNCY = BYNCY_IMPORT + LFC = ZLFC ! MOIST returns LFC from the 'surface based' computation of CAPE else - call BUOYANCY (T, Q, QSS, DQS, DZ, ZLO, BYNCY, CAPE, INHB) + call BUOYANCY (T, Q, QSS, DQS, DZET, ZL_ZERO, BYNCY, CAPE, INHB) + + !!! Derive LFC for two reasons: + !!! 1) In GCM it is computed using a different Buoyancy field (8% avg difference) + !!! 2) In CTM it is not available + !!! Adapted from RETURN_CAPE_CIN in the MOIST GridComp (4.15.25) + + DO i=1,IM + DO j=1,JM + + ! if surface parcel immediately buoyant, scan upward to find first elevated + ! B>0 level above a B<0 level, label it LFC. If no such level, set LFC at surface. + KLFC = LM + KLNB = LM + aboveLFC = .false. + if (BYNCY(i,j,LM-1).gt.0.) then + do L = LM-2,1,-1 ! scan up to find elevated LFC + if (BYNCY(i,j,L).gt.0. .and. BYNCY(i,j,L+1).le.0.) then + KLFC = L + aboveLFC = .true. + end if + if (aboveLFC .and. BYNCY(i,j,L).lt.0. ) then + KLNB = L + exit + end if + end do + else ! if surface parcel not immediately buoyant, LFC is first B>0 level + do L = LM-1,1,-1 + if (BYNCY(i,j,L).gt.0. .and. .not.aboveLFC) then + KLFC = L + aboveLFC = .true. + end if + if (aboveLFC .and. BYNCY(i,j,L).lt.0.) then + KLNB = L + exit + end if + end do + end if + LFC(i,j) = ZL_ZERO(i,j,KLFC) ! level of free convection +! LNB(i,j) = ZL_ZERO(i,j,KLNB) ! level of neutral buoyancy + + END DO + END DO end if + ALLOCATE( flashRateLopez(IM, JM), STAT=STATUS); VERIFY_(STATUS) flashRateLopez = real(0) -! flashRateLopez(:,:) = 0.01 - call LOPEZ_FlashRate(ggState, IM, JM, LM, FROCEAN, PBLH, CAPE, ZLE2, PFICU, & - CNV_QC, T, PLO, ZLFC, ZLCL, LOPEZ_flashFactor, flashRateLopez, __RC__ ) + call LOPEZ_FlashRate(ggState, IM, JM, LM, FROCEAN, PBLH, CAPE, DZET, PFICU, & + CNV_QC, T, PLmb, LFC, ZLCL, LOPEZ_flashFactor, flashRateLopez, __RC__ ) !print*, "min/max LFR LOPEZ: ", minval(flashRateLopez), maxval(flashRateLopez) @@ -389,16 +408,6 @@ subroutine getLightning (GC, ggState, CLOCK, & !----------------------------------------------------------------------- else if (flash_source_enum == FLASH_SOURCE_HEMCO) then -! The HEMCO flash routine may use BYNCY in the future -! if (usePreconCape) then -! CAPE = CAPE_PRECON -! INHB = INHB_PRECON -! BYNCY = BYNCY_PRECON -! else -! call BUOYANCY (T, Q, QSS, DQS, DZ, ZLO, BYNCY, CAPE, INHB) -! end if - - call HEMCO_FlashRate (cellArea, LWI, LONSLOCAL, LATSLOCAL, T, PLE, & ZLE, CNV_MFC, HEMCO_flashFactor, flashRate, __RC__ ) @@ -417,11 +426,11 @@ subroutine getLightning (GC, ggState, CLOCK, & DM(:,:,1:LM) = ( PLE(:,:,K0+1:KM)-PLE(:,:,K0:KM-1) ) * (1./MAPL_GRAV) ! DELP / g - if (usePreconCape) then + if (useImportedCape) then - CAPE = CAPE_PRECON - INHB = INHB_PRECON - BYNCY = BYNCY_PRECON + CAPE = CAPE_IMPORT + INHB = INHB_IMPORT + BYNCY = BYNCY_IMPORT CAPE_MERRA2(:,:) = 0. @@ -436,7 +445,7 @@ subroutine getLightning (GC, ggState, CLOCK, & end where else - call BUOYANCY (T, Q, QSS, DQS, DZ, ZLO, BYNCY, CAPE, INHB, & + call BUOYANCY (T, Q, QSS, DQS, DZET, ZL_ZERO, BYNCY, CAPE, INHB, & DM=DM, CAPE_MERRA2=CAPE_MERRA2) end if @@ -528,7 +537,7 @@ subroutine getLightning (GC, ggState, CLOCK, & endif IF ( need_cape ) THEN - DEALLOCATE( INHB, PLO, PK, DQS, QSS, DZ, THV, ZLO, PKE, ZLE2, __STAT__ ) + DEALLOCATE( INHB, LFC, PLmb, DQS, QSS, ZLE_ZERO, ZL_ZERO, DZET, __STAT__ ) END IF !print*, "min/max Final LFR: ", minval(flashRate), maxval(flashRate) @@ -642,7 +651,7 @@ subroutine read_lightning_config ( im, jm, rcfilen, flash_source_enum, & lightNOampFactor, numberNOperFlash, & MOIST_flashFactor, FIT_flashFactor, & HEMCO_flashFactor, LOPEZ_flashFactor, & - usePreconCape, & + useImportedCape, & RC ) ! IN: @@ -660,7 +669,7 @@ subroutine read_lightning_config ( im, jm, rcfilen, flash_source_enum, & real, intent(out) :: FIT_flashFactor real, intent(out) :: HEMCO_flashFactor real, intent(out) :: LOPEZ_flashFactor - logical, intent(out) :: usePreconCape + logical, intent(out) :: useImportedCape integer, optional, intent(out) :: RC ! Local vars: @@ -745,8 +754,8 @@ subroutine read_lightning_config ( im, jm, rcfilen, flash_source_enum, & Label = "numberNOperFlash:", & Default = 1.50E+26, __RC__ ) - call ESMF_ConfigGetAttribute(esmfConfig, usePreconCape, & - Label = "usePreconCape:", & + call ESMF_ConfigGetAttribute(esmfConfig, useImportedCape, & + Label = "useImportedCape:", & Default = .TRUE., __RC__ ) call ESMF_ConfigDestroy(esmfConfig, __RC__) @@ -774,7 +783,7 @@ end subroutine read_lightning_config ! 1 Nov 2019 Damon Bringing routine to GEOS_Shared !EOP !----------------------------------------------------------------------- - subroutine BUOYANCY( T, Q, QS, DQS, DZ, ZLO, BUOY, CAPE, INHB, DM, CAPE_MERRA2) + subroutine BUOYANCY( T, Q, QS, DQS, DZ, ZL_ZERO, BUOY, CAPE, INHB, DM, CAPE_MERRA2) ! !DESCRIPTION: Computes the buoyancy $ g \frac{T_c-T_e}{T_e} $ at each level @@ -785,8 +794,8 @@ subroutine BUOYANCY( T, Q, QS, DQS, DZ, ZLO, BUOY, CAPE, INHB, DM, CAPE_MERRA2) real, dimension(:,:,:), intent(in) :: Q ! specific humidity (kg kg-1) [top-down] real, dimension(:,:,:), intent(in) :: QS ! saturation specific humidity real, dimension(:,:,:), intent(in) :: DQS ! derivative of satuation specific humidity wrt temperature - real, dimension(:,:,:), intent(in) :: DZ ! gridbox height - real, dimension(:,:,:), intent(in) :: ZLO ! geopotential height at center of gridbox + real, dimension(:,:,:), intent(in) :: DZ ! gridbox height (delta-Z) + real, dimension(:,:,:), intent(in) :: ZL_ZERO ! height above surface (center of gridbox) real, dimension(:,:,:), intent(out) :: BUOY ! [m/s/s] real, dimension(:,:), intent(out) :: CAPE ! [J/kg] @@ -799,10 +808,10 @@ subroutine BUOYANCY( T, Q, QS, DQS, DZ, ZLO, BUOY, CAPE, INHB, DM, CAPE_MERRA2) LM = size(T,3) - BUOY(:,:,LM) = T(:,:,LM) + (MAPL_GRAV/MAPL_CP)*ZLO(:,:,LM) + (MAPL_ALHL/MAPL_CP)*Q(:,:,LM) + BUOY(:,:,LM) = T(:,:,LM) + (MAPL_GRAV/MAPL_CP)*ZL_ZERO(:,:,LM) + (MAPL_ALHL/MAPL_CP)*Q(:,:,LM) do L=LM-1,1,-1 - BUOY(:,:,L) = BUOY(:,:,LM) - (T(:,:,L) + (MAPL_GRAV/MAPL_CP)*ZLO(:,:,L) + (MAPL_ALHL/MAPL_CP)*QS(:,:,L)) + BUOY(:,:,L) = BUOY(:,:,LM) - (T(:,:,L) + (MAPL_GRAV/MAPL_CP)*ZL_ZERO(:,:,L) + (MAPL_ALHL/MAPL_CP)*QS(:,:,L)) BUOY(:,:,L) = MAPL_GRAV*BUOY(:,:,L) / ( (1.+ (MAPL_ALHL/MAPL_CP)*DQS(:,:,L))*T(:,:,L) ) enddo @@ -1529,16 +1538,16 @@ end subroutine HEMCO_FlashRate subroutine LOPEZ_FlashRate(STATE, IM, JM, LM, FROCEAN, ZKBCON, CAPE, & - ZLE, PFI_CN_GF, CNV_QC, TE, PLO, ZLFC, ZLCL, LOPEZ_flashFactor, & + DELZ, PFI_CN_GF, CNV_QC, TE, PLmb, ZLFC, ZLCL, LOPEZ_flashFactor, & LFR_Lopez, RC) implicit none TYPE(MAPL_MetaComp), POINTER :: STATE ! Internal MAPL_Generic state integer ,intent(in) :: im,jm,lm - real, intent(in), dimension(im,jm,0:lm) :: ZLE ! layer depths [m] real, intent(in), dimension(im,jm,0:lm) :: PFI_CN_GF ! 3d_ice_precipitation_flux_GF_CONVECTIVE [kg/m2/s] in updrafts + real, intent(in), dimension(im,jm,lm) :: DELZ ! layer depths [m] real, intent(in), dimension(im,jm,lm) :: TE ! air temp [K] - real, intent(in), dimension(im,jm,lm) :: PLO ! press (hPa) + real, intent(in), dimension(im,jm,lm) :: PLmb ! press (hPa) real, intent(in), dimension(im,jm,lm) :: CNV_QC ! grid_mean_convective_condensate [kg/kg] @@ -1586,7 +1595,7 @@ subroutine LOPEZ_FlashRate(STATE, IM, JM, LM, FROCEAN, ZKBCON, CAPE, & integer :: i,j,k, k_initial, k_final real :: tdif, td2 - real :: Q_R, z_base,beta,prec_flx_fr,dz + real :: Q_R, z_base,beta,prec_flx_fr real, dimension(1:lm) :: q_graup,q_snow,rho ! REAL :: f_oc_thresh @@ -1607,10 +1616,10 @@ subroutine LOPEZ_FlashRate(STATE, IM, JM, LM, FROCEAN, ZKBCON, CAPE, & ! print*, "im, jm, lm: ", im, jm, lm ! print*, "FRLAND: ", minval(FRLAND), maxval(FRLAND) ! print*, "CAPE: ", minval(CAPE), maxval(CAPE) -! print*, "ZLE: ", minval(ZLE), maxval(ZLE) +! print*, "DELZ: ", minval(DELZ), maxval(DELZ) ! print*, "PFI_CN_GF ", minval(PFI_CN_GF), maxval(PFI_CN_GF) ! print*, "TE: ", minval(TE), maxval(TE) -! print*, "PLO: ", minval(PLO), maxval(PLO) +! print*, "PLmb: ", minval(PLmb), maxval(PLmb) ! print*, "CNV_QC: ", minval(CNV_QC), maxval(CNV_QC) ! print*, "zkbcon: ", minval(zkbcon), maxval(zkbcon) !!! @@ -1657,7 +1666,7 @@ subroutine LOPEZ_FlashRate(STATE, IM, JM, LM, FROCEAN, ZKBCON, CAPE, & q_snow (:) = 0. do k=1,lm - rho(k) = 100.*PLO(i,j,k) / (MAPL_RGAS*TE(i,j,k) ) + rho(k) = 100.*PLmb(i,j,k) / (MAPL_RGAS*TE(i,j,k) ) prec_flx_fr = (( PFI_CN_GF(i,j,k ) + & PFI_CN_GF(i,j,k-1) ) * 0.5 ) / rho(k) @@ -1696,10 +1705,7 @@ subroutine LOPEZ_FlashRate(STATE, IM, JM, LM, FROCEAN, ZKBCON, CAPE, & Q_R = 0.0 do k = k_final, k_initial - - dz = zle(i,j,k-1)-zle(i,j,k) - - Q_R = Q_R + dz*rho(k)*(q_graup(k)*(CNV_QC(i,j,k)+q_snow(k))) + Q_R = Q_R + DELZ(i,j,k)*rho(k)*(q_graup(k)*(CNV_QC(i,j,k)+q_snow(k))) enddo