Skip to content

Add capability to create aerosol AOD analysis products in GRIB2 format via UPP#3889

Closed
ypwang19 wants to merge 57 commits into
NOAA-EMC:developfrom
ypwang19:feature/aero_postprocess
Closed

Add capability to create aerosol AOD analysis products in GRIB2 format via UPP#3889
ypwang19 wants to merge 57 commits into
NOAA-EMC:developfrom
ypwang19:feature/aero_postprocess

Conversation

@ypwang19
Copy link
Copy Markdown
Contributor

@ypwang19 ypwang19 commented Jul 21, 2025

Description

This PR resolves issue #3888
This PR adds the capability to process analysis tracer fields into aerosol AOD product in GRIB2 format using the upp tool within the GCAFS workflow. Aerosol variables in atmospheric analysis file (analysis.atm.a006.nc) are all missing data and not updated, such that the analysis fields on the Gaussian grid are generated by adding aerosol increments (aeroinc_gaussian) and atmospheric increments (increment.atm.i006.nc) to the atm.f006 background file.
This feature is integrated into the aeroanlfinal job.

A new GCAFS control file has been updated in UPP. The UPP hash has been updated in ufs model and fv3atm.

This PR requires updates in GDASApp NOAA-EMC/GDASApp#1964

Type of change

  • New feature (adds functionality)

Change characteristics

How has this been tested?

  • C96_gcafs_cycled CI test on Hera

Checklist

  • Any dependent changes have been merged and published
  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have documented my code, including function, input, and output descriptions
  • My changes generate no new warnings
  • New and existing tests pass with my changes
  • This change is covered by an existing CI test or a new one has been added
  • Any new scripts have been added to the .github/CODEOWNERS file with owners
  • I have made corresponding changes to the system documentation if necessary

@DavidNew-NOAA DavidNew-NOAA linked an issue Jul 22, 2025 that may be closed by this pull request
@CoryMartin-NOAA
Copy link
Copy Markdown
Contributor

I believe @bbakernoaa said the UPP hash has been updated in the UFS-Weather-Model now. I also see several open PRs in the global-workflow that are UPP related, could these be combined?

@ypwang19
Copy link
Copy Markdown
Contributor Author

I believe @bbakernoaa said the UPP hash has been updated in the UFS-Weather-Model now. I also see several open PRs in the global-workflow that are UPP related, could these be combined?

Thanks for reminding me about the UPP hash, I just updated that.
@zhanglikate's PR is related to this PR, but this PR needs more modification, including updating yamls in GDASApp.

@ypwang19 ypwang19 marked this pull request as ready for review October 30, 2025 19:36
Comment thread ush/python/pygfs/task/aero_analysis.py Outdated
Copy link
Copy Markdown
Contributor

@DavidNew-NOAA DavidNew-NOAA left a comment

Choose a reason for hiding this comment

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

A few comments. Making UPP_CONFIG_YAML a key inside of TASK_CONFIG_YAML would require changes inside of NOAA-EMC/GDASApp#1964, but wait for @aerorahul's feedback about invoking the upp object in exglobal_aero_analysis_execute.py before making those changes, since in that case, UPP_CONFIG_YAML should indeed be a separate yaml.

AeroAnl = AerosolAnalysis(config)

# Process aerosal products through UPP
AeroAnl.upp_anlproc()
Copy link
Copy Markdown
Contributor

@DavidNew-NOAA DavidNew-NOAA Nov 3, 2025

Choose a reason for hiding this comment

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

Finalize jobs generally involve moving files to COM or archiving/compressing files. This method involves computing analyses and processing those analyses. I think this should be moved to the execute job (exglobal_aero_analysis_execute.py)

upp_yaml = upp.task_config.upp_yaml
upp.initialize(upp_yaml)

upp_dict = AttrDict()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

There probably isn't a reason to create a separate dict for UPP as long as there are no conflicts. You can just pass task_config to it, making sure task_config has everything the upp object needs.


# ---- add atmo increments to atmf000 files
logger.info('Adding atmo increments to RESTART files')
inc_file = os.path.join(upp_dict.DATA, f"{self.task_config.APREFIX}increment.atm.i006.nc")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Best to put filenames like this in task_config in the constructor

# ---- add aero increments to atm analysis files
logger.info('Adding aero increments to RESTART files')
bkg_file = os.path.join(upp_dict.DATA, f"{self.task_config.GPREFIX }atm.f006.nc")
inc_filename = f"aeroinc_gauss.{self.task_config.current_cycle.strftime('%Y-%m-%dT%H:%M:%S')}Z.gaussian.modelLevels.nc"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Use to_isotime from wxflow here

with Dataset(file, mode='a') as rstfile:
time = rstfile.variables['time']
time[:] = 0.0
time.setncattr("units", f"hours since {self.task_config.current_cycle.strftime('%Y-%m-%d %H:%M:%S')}")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If it's ok for the format to be slightly different for this attribute (no space in the middle and a "Z" at the end), you can just use to_isotime from wxflow

increment = incfile.variables[incname][:]
# handel latitude inversion: atminc: lat=-90 to +90, atmbkg: lat=+90 to -90
lat_axis_index = 1
increment_lat_inversion = np.flip(increment, axis=lat_axis_index)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Double check that you still need to do this since @RussTreadon-NOAA fixed the inverted axes in https://github.com/JCSDA-internal/fv3-jedi/pull/1428

export TASK_CONFIG_YAML="${PARMgfs}/gdas/aero/aero_det_config.yaml.j2"
export OBS_LIST_YAML="${PARMgfs}/gdas/aero/aero_obs_list.yaml.j2"
export BIAS_FILES_YAML="${PARMgfs}/gdas/aero/aero_bias_files.yaml.j2"
export UPP_CONFIG_YAML="${PARMgfs}/gdas/aero/aero_upp_config.yaml.j2"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If this is all part of the same task, then this whole yaml should just me a key in TASK_CONFIG_YAML (aero_det_config.yaml.j2). That's the reason for #4080, to have a single configuration yaml for each task

- Execute upp.x
"""

upp = UPP(self.task_config)
Copy link
Copy Markdown
Contributor

@DavidNew-NOAA DavidNew-NOAA Nov 3, 2025

Choose a reason for hiding this comment

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

I'm torn about invoking a Task object (upp) inside of another Task object (AerosolAnalysis inherits from Analysis which inherits from Task). I'm wondering if this should be invoked inside the exglobal_aero_analysis_execute.py after running AerosolAnalysis.execute(). That might be awkward though, because it would require quite a bit of code to live in exglobal_aero_analysis_execute.py in order to initialize the upp object. I would like to know what @aerorahul thinks

AeroAnl = AerosolAnalysis(config)

# Process aerosal products through UPP
AeroAnl.upp_anlproc()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The UPP should be a different job and task in the workflow and not part of the aerosol analysis job. The aerosol analysis task is the dependency of the aerosol UPP

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yes, good point. I don't know how long UPP takes to run, but if it does take a while, then putting it in the aerosol analysis task will delay the forecast job from running

@ypwang19 ypwang19 marked this pull request as draft November 6, 2025 21:10
@ypwang19 ypwang19 closed this Nov 7, 2025
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.

Generate aerosol AOD analysis products with UPP

5 participants