Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add CCPP register phase #582

Merged
merged 9 commits into from
Oct 31, 2024
Merged

Add CCPP register phase #582

merged 9 commits into from
Oct 31, 2024

Conversation

peverwhee
Copy link
Collaborator

@peverwhee peverwhee commented Aug 5, 2024

Overview

This PR adds a new phase, register, that can be called by a host model and used by schemes to perform any set up that needs to happen BEFORE the grid is established.

NOTE: this PR also removes the old dynamic_constituent_routine metadata implementation for runtime constituents.

Description

I have implemented it as an "optional" phase, by which I mean that it is not required that a host model call this phase (though I'm happy to be overruled!). As a result, the register phase does not change the CCPP "state" (but will produce an error if it is called after the init phase).

More:

Dynamic/run-time constituent handling:

  • If a scheme has run-time constituents, those shall be allocated, instantiated, and returned from the scheme's register phase. This metadata is required (the framework determines that there are runtime constituents from a scheme if there is a ccpp_constituent_properties_t variable required):
[ <unique dynamic constituent local name> ]
  standard_name = <some unique standard name>
  dimensions = (:)
  type = ccpp_constituent_properties_t
  intent = out
  allocatable = true
  • The standard name doesn't really matter but MUST be different from other runtime constituent standard names in the scheme; it may be easiest to standardize this to something like dynamic_constituents_for_<scheme>
  • The framework will then compile all scheme constituents into module-level variables in the host cap called <suite>_dynamic_constituents, which are then used to pack and initialize the module level constituents object <host>_constituents_obj.
  • If there are no dynamic constituents registered by any schemes within a suite, that suite's dynamic constituents array is allocated to 0.

Generated host cap code examples

  1. Multiple schemes have dynamic constituents:
subroutine test_host_ccpp_physics_register(suite_name, errmsg, errflg)

      use ccpp_cld_suite_cap, only: cld_suite_register

      character(len=*)                         :: suite_name
      character(len=512)                       :: errmsg
      integer                                  :: errflg
      type(ccpp_constituent_properties_t),allocatable          :: dyn_const(:)
      type(ccpp_constituent_properties_t),allocatable          :: dyn_const_ice(:)
      integer                                  :: num_dyn_consts
      integer                                  :: const_index

      errflg = 0
      errmsg = ""
      if (trim(suite_name) == 'cld_suite') then
         call cld_suite_register(errflg=errflg, errmsg=errmsg, dyn_const=dyn_const,               &
              dyn_const_ice=dyn_const_ice)
         allocate(cld_suite_dynamic_constituents(0+size(dyn_const)+size(dyn_const_ice)))
         ! Pack the suite-level dynamic, run-time constituents array
         num_dyn_consts = 0
         do const_index = 1, size(dyn_const)
            cld_suite_dynamic_constituents(num_dyn_consts + const_index) = dyn_const(const_index)
         end do
         num_dyn_consts = num_dyn_consts + size(dyn_const)
         deallocate(dyn_const)
         do const_index = 1, size(cld_suite_dynamic_constituents)
            call cld_suite_dynamic_constituents(const_index)%standard_name(stdname,               &
                 errcode=errflg, errmsg=errmsg)
         end do
         do const_index = 1, size(dyn_const_ice)
            cld_suite_dynamic_constituents(num_dyn_consts + const_index) =                        &
                 dyn_const_ice(const_index)
         end do
         num_dyn_consts = num_dyn_consts + size(dyn_const_ice)
         deallocate(dyn_const_ice)
      else
         write(errmsg, '(3a)')"No suite named ", trim(suite_name), "found"
         errflg = 1
      end if

   end subroutine test_host_ccpp_physics_register
  1. No schemes have dynamic constituents:
subroutine test_host_ccpp_physics_register(suite_name, errmsg, errflg)

      use ccpp_ddt_suite_cap,  only: ddt_suite_register
      use ccpp_temp_suite_cap, only: temp_suite_register

      character(len=*)                         :: suite_name
      character(len=512)                       :: errmsg
      integer                                  :: errflg

      errflg = 0
      errmsg = ""
      if (trim(suite_name) == 'ddt_suite') then
         call ddt_suite_register(errflg=errflg, errmsg=errmsg)
         ! Suite does not return dynamic constituents; allocate to zero
         allocate(ddt_suite_dynamic_constituents(0))
      else if (trim(suite_name) == 'temp_suite') then
         call temp_suite_register(errflg=errflg, errmsg=errmsg, config_var=config_var)
         ! Suite does not return dynamic constituents; allocate to zero
         allocate(temp_suite_dynamic_constituents(0))
      else
         write(errmsg, '(3a)')"No suite named ", trim(suite_name), "found"
         errflg = 1
      end if

   end subroutine test_host_ccpp_physics_register

Misc notes

Since this phase is called before the grid is initialized, variables are not allocated at this time (that still happens in init) and no variables with horizontal and vertical dimensions can be passed in.

UI Changes

User interface changes?: Yes, but they're optional
If a host model wishes to utilize schemes' register phases, they must add a call to <host_model>_ccpp_physics_register(suite_name, errmsg, errflg)

Testing

test removed: removed unit tests for dyn_const_routines (old implementation of runtime constituent handling) - all pass
unit tests: Removed old dynamic constituents testing - all pass
system tests: Updated capgen and advection tests to include register phases (with and without dynamic constituents)

  • Also updated advection test CMakeLists to first run a version with dynamic constituents in the wrong phase and have an expected error
    • This is perhaps not the best way to test this, but it's what I came up with
      manual testing:

Fixes:
closes #572

Copy link
Collaborator

@climbfuji climbfuji left a comment

Choose a reason for hiding this comment

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

This is great work! Unfortunately, I don't have any way to test this, therefore relying on CI.

scripts/ccpp_capgen.py Outdated Show resolved Hide resolved
scripts/host_cap.py Outdated Show resolved Hide resolved
scripts/host_cap.py Outdated Show resolved Hide resolved
scripts/suite_objects.py Outdated Show resolved Hide resolved
Copy link
Collaborator

@climbfuji climbfuji left a comment

Choose a reason for hiding this comment

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

Thanks for addressing my comments! I'll leave the PR unapproved for now, since it is still in draft mode and I don't have any other tests than what is in CI. Once it is ready for review and others have tested it successfully, I'll approve.

@peverwhee peverwhee marked this pull request as ready for review October 7, 2024 17:07
@peverwhee peverwhee changed the title DRAFT TO DISCUSS - add CCPP register phase Add CCPP register phase Oct 7, 2024
Copy link
Collaborator

@climbfuji climbfuji left a comment

Choose a reason for hiding this comment

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

I still don't have a way to test this in NEPTUNE or the UFS, but my comments were addressed, all CI tests pass, and this capability is really important to have. For NEPTUNE, we are primarily interested in getting namelist information from the register phase so that we can setup the output variable registry before going through the ESMF/NUOPC init phase and the subsequent CCPP init phase.

I do have a question, though. The CCPP technical documentation (https://github.com/ncar/ccpp-doc) is for ccpp_prebuild only, and none of the new capabilities developed for capgen are captured in any kind of documentation. Would it make sense to start a feature/capgen branch in ccpp-doc (if we want to keep documenting CCPP in this form), or in some other ways while these new features are being added? It seems daunting to write documentation from scratch after capgen was implemented in the UFS and all other models using prebuild at the moment. Maybe we can discuss this at the next CCPP framework meeting @mkavulich ?

@peverwhee
Copy link
Collaborator Author

I still don't have a way to test this in NEPTUNE or the UFS, but my comments were addressed, all CI tests pass, and this capability is really important to have. For NEPTUNE, we are primarily interested in getting namelist information from the register phase so that we can setup the output variable registry before going through the ESMF/NUOPC init phase and the subsequent CCPP init phase.

I do have a question, though. The CCPP technical documentation (https://github.com/ncar/ccpp-doc) is for ccpp_prebuild only, and none of the new capabilities developed for capgen are captured in any kind of documentation. Would it make sense to start a feature/capgen branch in ccpp-doc (if we want to keep documenting CCPP in this form), or in some other ways while these new features are being added? It seems daunting to write documentation from scratch after capgen was implemented in the UFS and all other models using prebuild at the moment. Maybe we can discuss this at the next CCPP framework meeting @mkavulich ?

@climbfuji yes, I think discussing capgen documentation is a crucial topic to discuss! I've added it to next week's agenda.

Copy link
Collaborator

@mwaxmonsky mwaxmonsky left a comment

Choose a reason for hiding this comment

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

Looks great @peverwhee! Just had a few comments/recommendations but otherwise nothing major.

We talked about the CMake/python test harnesses around capgen so I'll create an issue to template those files and we can address those in another PR if needed.

scripts/host_cap.py Outdated Show resolved Hide resolved
scripts/host_cap.py Outdated Show resolved Hide resolved
scripts/host_cap.py Outdated Show resolved Hide resolved
scripts/suite_objects.py Outdated Show resolved Hide resolved
scripts/suite_objects.py Outdated Show resolved Hide resolved
scripts/host_cap.py Outdated Show resolved Hide resolved
scripts/host_cap.py Outdated Show resolved Hide resolved
Copy link
Collaborator

@dustinswales dustinswales left a comment

Choose a reason for hiding this comment

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

These changes look good to me, just a few tiny things.
And thanks for adding the testing for this new phase!

scripts/ccpp_state_machine.py Show resolved Hide resolved
scripts/suite_objects.py Outdated Show resolved Hide resolved
scripts/suite_objects.py Outdated Show resolved Hide resolved
Copy link
Collaborator

@mwaxmonsky mwaxmonsky left a comment

Choose a reason for hiding this comment

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

Thanks for taking care of those comments @peverwhee, looks good to me!

@climbfuji climbfuji merged commit 5ec3e42 into NCAR:develop Oct 31, 2024
19 checks passed
peverwhee added a commit to ESCOMP/CAM-SIMA that referenced this pull request Nov 6, 2024
Tag name (required for release branches):
Originator(s): peverwhee

Description (include the issue title, and the keyword ['closes',
'fixes', 'resolves'] followed by the issue number):

1. Adds call to new CCPP register phase brought in with framework PR
[#582](NCAR/ccpp-framework#582)
2. Uses the full error message returned from the exception handled when
xmllint is called (updated in framework PR
[#586](NCAR/ccpp-framework#586))
3. Adds `inverse_exner_function_wrt_surface_pressure` as possible input
variable name for exner for backwards compatibility with old converted
snapshots

closes #215 (add optional register phase)
closes #286 (Improve error message returned by XML linter)

Describe any changes made to build system: None

Describe any changes made to the namelist: None

List any changes to the defaults for the input datasets (e.g. boundary
datasets): None

List all files eliminated and why: None

List all files added and what they do: None

List all existing files that have been modified, and describe the
changes:
(Helpful git command: `git diff --name-status
development...<your_branch_name>`)

M  .gitmodules

- brings in new CCPP framework tag

M src/control/cam_comp.F90
M src/physics/utils/phys_comp.F90

- Adds call to new CCPP register phase in the generated cap

M src/data/generate_registry_data.py

- Uses full error message returned from xmllint

M src/data/registry.xml

- add backwards-compatible exner name


If there are new failures (compared to the
`test/existing-test-failures.txt` file),
have them OK'd by the gatekeeper, note them here, and add them to the
file.
If there are baseline differences, include the test and the reason for
the
diff. What is the nature of the change? Roundoff?

derecho/intel/aux_sima: all pass

derecho/gnu/aux_sima: all pass

If this changes climate describe any run(s) done to evaluate the new
climate in enough detail that it(they) could be reproduced: N/A

CAM-SIMA date used for the baseline comparison tests if different than
latest:

---------

Co-authored-by: Courtney Peverley <courtneyp@izumi.cgd.ucar.edu>
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.

4 participants