Skip to content

Update for Explicit Subcanopy Effects on Chemical Tracers in the PBL-SATMEDMF Scheme#350

Open
drnimbusrain wants to merge 32 commits intoufs-community:ufs/devfrom
noaa-oar-arl:feature/aqm_canopy_vdf
Open

Update for Explicit Subcanopy Effects on Chemical Tracers in the PBL-SATMEDMF Scheme#350
drnimbusrain wants to merge 32 commits intoufs-community:ufs/devfrom
noaa-oar-arl:feature/aqm_canopy_vdf

Conversation

@drnimbusrain
Copy link

@drnimbusrain drnimbusrain commented Jan 20, 2026

Description of Changes:

This PR updates the current integrated subcanopy effect (previously merged PR #253 ) to use a more robust, explicit, 3-layer subcanopy effect on chemical tracers (ONLY) in the PBL-SATMEDMF scheme. The vegetative canopy modulates vertical diffusion. We split the diffusion on 3 sub-canopy layers with variable height located at 1, 0.5 and 0.2 canopy height (based on Makar et al. 2017), while ensuring mass conservation before returning to the original model layers (for advection, deposition, other physical processes). This leads to a more pronounced effect on the transport of chemical tracers, particularly those as precursors to near-surface ozone formation in the UFS-AQM configuration.

Here we add four new routines to the PBL-SATMEDMF scheme directory, described briefly as follows:

  1. canopy_mask.F90: Controls the contiguous forest canopy mask (based on input, satellite-based forest canopy datasets) that determines the canopy and non-canopy columns in the model domain.
  2. canopy_levs.F90: Initiates and combines the additional canopy levels and all required fields needed in the newly combined model + 3-layer canopy structure.
  3. canopy_transfer.F90: Transfers the resulting combined model layer structure (i.e., 3-layer canopy + resolved model layers), ensuring mass conservation, back to original model layers (for advection, deposition, and other physical processes).
  4. canopy_driver.F90: Main driver for additional canopy routines 1-3, with associated canopy_driver.meta file for necessary canopy variables.

Note: A copy of the satmedmfvdifq routine (satmedmfvdifq_can) is necessary to pass diffusion coefficients on the canopy layers (e.g., dkt_can & dku_can) this version of the PBL SATMEDMF scheme for the additional 3-canopy layers.

Also note that currently we are not yet including the explicit 3-layer subcanopy effects on diffusivities for heat, moisture, and momentum until more testing and evaluations can be completed here on the detailed met effects. We expect these to be re-included in a future PR.

All canopy codes are controlled and initiated by the 'do_canopy' flag.

Tests Conducted:

Tests conducted on Gaea-C6 with the SRW-App AQM configuration/compilers.

Impacts shows larger effects on the SRW-App AQM predictions of near-surface ozone, with significantly improved model performance (e.g., reducing NMB by about half) in regions of contiguous canopies (compared against U.S. EPA AirNow observations):
image

OR Add any links to tests conducted. For example, "See ufs-community/ufs-weather-model#<pr_number>"

Dependencies:

Contributors (optional):

@iri01

Copy link
Collaborator

@JongilHan66 JongilHan66 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this subcanopy effect parameterization are physically sound, it would also show a positive impact on meteorological variables (e.g., surface fluxes, 2m temperature and 10m winds) as well as on air quality variables. In the future update, the subcanopy effect should be tested and included for improving weather forecasts.

@drnimbusrain
Copy link
Author

If this subcanopy effect parameterization are physically sound, it would also show a positive impact on meteorological variables (e.g., surface fluxes, 2m temperature and 10m winds) as well as on air quality variables. In the future update, the subcanopy effect should be tested and included for improving weather forecasts.

Thank you @JongilHan66 for approving! Yes, the subcanopy effect on meteorology is also physically sound, and we plan to re-include them in the near-future as we showed promising results on improved weather forecasts (e.g., 2-m temp, 2-m mixing ratio, and 10-m wind speeds) using an integrated approach (as you have seen). Our target right now is to make upcoming UFS-AQMv8 developments and implementation for chemical tracers, but once we have more testing of this more robust, explicit 3-layer subcanopy effect on the diffusivities for heat/momentum in your PBL scheme (and evaluation of enhanced met effects) we will update in new PR. We also are planning a paper on all of this, and would appreciate it if you would join us as a co-author.

@drnimbusrain
Copy link
Author

drnimbusrain commented Jan 22, 2026

If this subcanopy effect parameterization are physically sound, it would also show a positive impact on meteorological variables (e.g., surface fluxes, 2m temperature and 10m winds) as well as on air quality variables. In the future update, the subcanopy effect should be tested and included for improving weather forecasts.

Thank you @JongilHan66 for approving! Yes, the subcanopy effect on meteorology is also physically sound, and we plan to re-include them in the near-future as we showed promising results on improved weather forecasts (e.g., 2-m temp, 2-m mixing ratio, and 10-m wind speeds) using an integrated approach (as you have seen). Our target right now is to make upcoming UFS-AQMv8 developments and implementation for chemical tracers, but once we have more testing of this more robust, explicit 3-layer subcanopy effect on the diffusivities for heat/momentum in your PBL scheme (and evaluation of enhanced met effects) we will update in new PR. We also are planning a paper on all of this, and would appreciate it if you would join us as a co-author.

@JongilHan66 et al.: To clarify further about met effects, we do include the explicit 3-layer subcanopy impacts on moisture/relative humidity diffusivities as the mass transfer for this acts like other chemical mass tracers. So we do still include the impact on relative humidity, which shows model improvements with these explicit 3-layer subcanopy updates :
image
Increasing humidity due to the 3-layer canopy effect will help TD2 underpredictions in GFS compared to surface observations.

Later (likely a future PR) we will update for heat/momentum diffusivities (for impacts on temp and winds), since the relationships are somewhat different for non-mass diffusivities.

@JongilHan66
Copy link
Collaborator

If this subcanopy effect parameterization are physically sound, it would also show a positive impact on meteorological variables (e.g., surface fluxes, 2m temperature and 10m winds) as well as on air quality variables. In the future update, the subcanopy effect should be tested and included for improving weather forecasts.

Thank you @JongilHan66 for approving! Yes, the subcanopy effect on meteorology is also physically sound, and we plan to re-include them in the near-future as we showed promising results on improved weather forecasts (e.g., 2-m temp, 2-m mixing ratio, and 10-m wind speeds) using an integrated approach (as you have seen). Our target right now is to make upcoming UFS-AQMv8 developments and implementation for chemical tracers, but once we have more testing of this more robust, explicit 3-layer subcanopy effect on the diffusivities for heat/momentum in your PBL scheme (and evaluation of enhanced met effects) we will update in new PR. We also are planning a paper on all of this, and would appreciate it if you would join us as a co-author.

@JongilHan66 et al.: To clarify further about met effects, we do include the explicit 3-layer subcanopy impacts on moisture/relative humidity diffusivities as the mass transfer for this acts like other chemical mass tracers. So we do still include the impact on relative humidity, which shows model improvements with these explicit 3-layer subcanopy updates : image Increasing humidity due to the 3-layer canopy effect will help TD2 underpredictions in GFS compared to surface observations.

Later (likely a future PR) we will update for heat/momentum diffusivities (for impacts on temp and winds), since the relationships are somewhat different for non-mass diffusivities.

@drnimbusrain Thank for further information!! I look forward to updating non-mass diffusivities with canopy effect.

@yangfanglin
Copy link
Collaborator

Great work ! We should test this in GFS once we start to develop the next version (v18)

@gspetro-NOAA
Copy link

Could we get another approval on this PR so that we can schedule WM parent PR 3060?

…vities correction.

For consistency, turn OFF the 3-layer-canopy PBL humidity effect and turn on the integrated-canopy PBL met effects (temerature, humidity, winds, TKE).
@gspetro-NOAA
Copy link

@grantfirl I know you had mentioned this PR would take a while to review. Are you expecting any other reviewers, or can we go ahead with the WM parent PR now that Rhaesung and others have approved?

@grantfirl
Copy link
Collaborator

@grantfirl I know you had mentioned this PR would take a while to review. Are you expecting any other reviewers, or can we go ahead with the WM parent PR now that Rhaesung and others have approved?

@gspetro-NOAA I'd like to review it as well. I haven't had time yet. Is this high priority?

@gspetro-NOAA
Copy link

@grantfirl I know you had mentioned this PR would take a while to review. Are you expecting any other reviewers, or can we go ahead with the WM parent PR now that Rhaesung and others have approved?

@gspetro-NOAA I'd like to review it as well. I haven't had time yet. Is this high priority?

It is listed as normal priority, but @drnimbusrain may be able to say whether there is a particular timeline for this PR.

@drnimbusrain
Copy link
Author

@grantfirl @gspetro-NOAA Thank you for raising this. If we could bump it to say a medium priority, we would appreciate it. We don't have an exact timeline, but would like to update to a later UWM with these updates soon for our ongoing AQMv8 development/tested targeted for operations. We are also limited in available resources and developments under this particular canopy project that is ending relatively soon. Thanks again!

@grantfirl
Copy link
Collaborator

TBH, I find the code organization a little confusing. I see that canopy_driver is the new CCPP-compliant scheme and has metadata. It calls the mostly-replicated satmedmfvdifq_can subroutine, which is itself CCPP-compliant except for the lack of metadata. In addition, in NOAA-EMC/ufsatm#1056, the new canopy_driver scheme is added after satmedmfvdifq. How is this not double-counting PBL schemes/vertical diffusion? Does the satmedmfvdifq_can scheme just modify what is coming out of satmedmfvdifq already?

parameter(cs0=0.4,csmf=0.5)
parameter(rchck=1.5,ndt=20)
real(kind=kind_phys), parameter :: epsilon = 1.e-10

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this scheme is added to 2 SDFs in NOAA-EMC/ufsatm#1056, the description claims that the new code is controlled by the do_canopy flag, but wouldn't at least some of the code in this routine get executed even if do_canopy is false? Should you place a check before anything is executed and return if do_canopy is false?

COUNTCAN = COUNTCAN + 1
ZCANX (COUNTCAN) = ZCAN
EDDYVESTX (COUNTCAN) = (SIGMACAN*SIGMACAN)*TLCAN
!
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this extraneous line.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this is a style disagreement, but I don't understand the point of these blank commented-out lines. If you feel that a blank line is needed for code readability, that is OK, but why not just add a blank line. I don't see the point in adding a !.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of course, not needed.

COUNTCAN = COUNTCAN + 1
ZCANX (COUNTCAN) = ZCAN
EDDYVESTX (COUNTCAN) = (SIGMACAN*SIGMACAN)*TLCAN
! IVAI
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove these debugging output lines.

! & EDDYVESTX (COUNTCAN)
!
END IF
!
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this line

END IF
!
ZCAN = ZCAN-0.5 !step down in-canopy resolution of 0.5m
!
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this line.

ZZ_INT= IntegrateTrapezoid(
& ZCANX(COUNTCAN:1:-1), ZOOOX(COUNTCAN:1:-1))
END IF
!
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove these debugging output lines.

& k, i, COUNTCAN ,
& ZFL, FCH, ZZ_INT ,
& ZCANX(COUNTCAN)
!
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this line.

& ),EDDYVESTX(COUNTCAN:1:-1)) /
& ZZ_INT ! ZFL (Jan9) !IVAI
END IF
!
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this line

& ZFL, FCH, EDDYVEST_INT ,
& EDDYVESTX(COUNTCAN),
& ZCANX(COUNTCAN)
!
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this line

!PCC_CANOPY_utilities
use canopy_utils_mod
use satmedmfvdifq_can_mod
use canopy_mask_mod
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider using the only functionality to explicitly describe what you're using from these module. This makes the code easier to follow and you wouldn't need extra comments like below.

! contains: canopy_mask_init, canopy_mask_run
! =====================

use canopy_levs_mod
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto.

! ZMOM_CAN3 (:,:,NLAYT+1)
! =====================

use canopy_transfer_mod
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DItto


contains

!> \defgroup module_canopy_driver GFS TKE-EDMF PBL Module
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is copied from satmedmfvdifq, right? It isn't really valid for this module right? Please remove if so.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All that the CCPP needs is the following bit:
!> \section arg_table_canopy_driver_init Argument Table
!! \htmlinclude canopy_driver_init.html
!!

!! \htmlinclude canopy_driver_run.html
!!
!!\section gen_canopy_driver GFS canopy_driver General Algorithm
!! canopy_driver_run() computes subgrid vertical turbulence mixing
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this copied too? Shouldn't it be updated to reflect what it is actually doing?

& ntqv,dtend,dtidx,index_of_temperature,index_of_x_wind, ! inout: dtend (.ldiag3d.)
& index_of_y_wind,index_of_process_pbl,gen_tend,ldiag3d,
& errmsg,errflg)
! IVAI: aux diag arrays
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove these commented lines.

!! -# A mass-flux approach is also used to represent the stratocumulus-top-induced turbulence
!! (mfscuq.f).
!! \section detail_canopy GFS canopy_driver Detailed Algorithm
subroutine canopy_driver_run(im,km,ntrac,ntcw,ntrw,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, this is like a wrapper on top of satmedmfvdifq_can, which is mostly replicated from satmedmfvdifq_run, correct?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct. This routine calculates/initialized all the inputs to the satmedmfvdifq_can routine on the combined (canopy plus resolved) layers.

!
!----------------------------------------------------------------------
!***
!*** local variables
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A lot of these local variables are not used within this scheme. Please clean this up and remove unused variables.

Copy link

@iri01 iri01 Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed these can go.

!!! BEFORE SAT CANOPY CALL!!

! Output canopy pbl tendency of QV
if(ldiag3d) then
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing actually happens within this if section. Please remove.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed this can go. This is for sanity checks when debugging.


do i = 1,im
! Non-Canopy columns set to resolved
IF (FRT_MASK(i) <= 0.) THEN
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If nothing happens in this branch, why keep it?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, this can go.

! Update Met & TKE & MP (microphysics) cloud fields
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! Update all model layers
do k = 1,km
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing is happening within this loop. Why keep it?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, this is where we apply the explicit canopy met effects. For this PR, we comment them out (turn them OFF), and keep the "integrated" canopy met effect in satmedmfvdifq routine (if do_canopy). We do plan to include the explicit canopy met effect in a future PR.

But if you think, this is confusing things, I can remove it altogether, and add it when we are ready.

@iri01
Copy link

iri01 commented Feb 11, 2026

Thank you @grantfirl for the comments!
Of course, I'll clean up the unused lines of code.
Here is the rational for the canopy "replicate" of the sat routine. Comments welcome how to make the code less confusing, or remove the replicate all together if possible.

You are correct, the explicit (3-layer) canopy does a 2nd call to the sat routine, with inputs on the combined (canopy plus resolved) layers and output on these same layers. The call to canopy_driver is after satmedmfvdifq because the 2nd call also uses as inputs, the output from the 1st call -- specifically filling in values on the non-canopy columns/grid cells, where the canopy effect is not applied.
The in-canopy outputs (basically the tendencies of heat tdt, momentum du dv and tracers rtg) overwrite the tendencies from the 1st call only in the canopy columns. So correct, satmedmfvdifq_can scheme just modifies/overwrites the tendencies coming out of satmedmfvdifq already. So are not applying the diffusion tendencies twice.

I'm not sure how to avoid the replica and call the sat scheme twice with different inputs and outputs. Ideally, we want to run the sat scheme in the canopy columns only (defined by the canopy mask), but that would require restructuring of the scheme (not just a replica) and I didn't think this would pass.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants