NCAR / ccpp-framework

Common Community Physics Package (CCPP)
http://www.dtcenter.org/community-code/common-community-physics-package-ccpp/
Other
26 stars 64 forks source link

Add CCPP register phase #582

Closed peverwhee closed 3 weeks ago

peverwhee commented 3 months ago

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:

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
  2. 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)

Fixes: closes #572

peverwhee commented 1 month ago

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.