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

Constituent updates #549

Merged
merged 188 commits into from
Jul 10, 2024
Merged

Constituent updates #549

merged 188 commits into from
Jul 10, 2024

Conversation

peverwhee
Copy link
Collaborator

@peverwhee peverwhee commented Mar 18, 2024

Summary

Brings in optional metadata field to enable dynamic (run-time) constituents; also brings in a couple new methods for the constituent object.

closes #557

Description

Key dynamic constituent mods:

  • ccpp_capgen.py: create dynamic constituent dictionary (key=scheme name) and pass into API()
  • constituents.py: add handling of dynamic constituents to register constituents routine (including conditional call(s) to user-supplied routines); update error handling for register_constituents

Includes additional constituent object methods:

  • set_water_species
  • set_min_val
  • set_molar_mass

Includes fixes to ensure consistent order of generated code (use statements, variables, etc)

Also brings back the .github/workflow/python.yaml workflow that got lost somehow

User interface changes?: Yes, but optional
User can now use "dynamic_constituent_routine" metadata header field to point to a function contained within the module fortran.

Testing:
Modified advection test to include dynamic constituent routines.
Added doctests to ccpp_datafile

Generated code snippet

   subroutine test_host_ccpp_register_constituents(host_constituents, errflg, errmsg)
      ! Create constituent object for suites in 

      use ccpp_constituent_prop_mod, only: ccpp_constituent_properties_t
      ! Suite constituent interfaces
      use ccpp_cld_suite_cap,        only: cld_suite_constituents_num_consts
      use ccpp_cld_suite_cap,        only: cld_suite_constituents_const_name
      use ccpp_cld_suite_cap,        only: cld_suite_constituents_copy_const
      ! Dynamic constituent routines
      use cld_liq, only: cld_liq_dynamic_constituents
      use cld_ice, only: cld_ice_dynamic_constituents

      ! Dummy arguments
      type(ccpp_constituent_properties_t), target, intent(in)  :: host_constituents(:)
      character(len=512), intent(out)   :: errmsg ! ccpp_error_message
      integer,            intent(out)   :: errflg ! ccpp_error_code
      ! Local variables
      integer                                      :: num_suite_consts
      integer                                      :: num_consts
      integer                                      :: num_dyn_consts
      integer                                      :: index, index_start
      integer                                      :: field_ind
      type(ccpp_constituent_properties_t), pointer :: const_prop
      ! dynamic constituent props variable for cld_ice
      type(ccpp_constituent_properties_t), allocatable :: dyn_const_prop_0(:)
      ! dynamic constituent props variable for cld_liq
      type(ccpp_constituent_properties_t), allocatable :: dyn_const_prop_1(:)

      errflg = 0
      num_consts = size(host_constituents, 1)
      num_dyn_consts = 0
      ! Number of suite constants for cld_suite
      num_suite_consts = cld_suite_constituents_num_consts(errflg=errflg, errmsg=errmsg)
      if (errflg /= 0) then
         return
      end if
      num_consts = num_consts + num_suite_consts
      ! Add in dynamic constituents
      call cld_ice_dynamic_constituents(dyn_const_prop_0, errcode=errflg, errmsg=errmsg)
      if (errflg /= 0) then
         return
      end if
      num_dyn_consts = num_dyn_consts + size(dyn_const_prop_0)
      call cld_liq_dynamic_constituents(dyn_const_prop_1, errcode=errflg, errmsg=errmsg)
      if (errflg /= 0) then
         return
      end if
      num_dyn_consts = num_dyn_consts + size(dyn_const_prop_1)
      num_consts = num_consts + num_dyn_consts
      ! Pack dynamic_constituents array
      allocate(dynamic_constituents(num_dyn_consts), stat=errflg)
      if (errflg /= 0) then
         errmsg = 'failed to allocate dynamic_constituents'
         return
      end if
      index_start = 0
      do index = 1, size(dyn_const_prop_0, 1)
         dynamic_constituents(index + index_start) = dyn_const_prop_0(index)
      end do
      index_start = size(dyn_const_prop_0, 1)
      deallocate(dyn_const_prop_0)
      do index = 1, size(dyn_const_prop_1, 1)
         dynamic_constituents(index + index_start) = dyn_const_prop_1(index)
      end do
      index_start = size(dyn_const_prop_1, 1)
      deallocate(dyn_const_prop_1)
      ! Initialize constituent data and field object
      call test_host_constituents_obj%initialize_table(num_consts)
      ! Add host model constituent metadata
      do index = 1, size(host_constituents, 1)
         const_prop => host_constituents(index)
         call test_host_constituents_obj%new_field(const_prop, errcode=errflg, errmsg=errmsg)
         nullify(const_prop)
         if (errflg /= 0) then
            return
         end if
      end do

      ! Add dynamic constituent properties
      do index = 1, size(dynamic_constituents, 1)
         const_prop => dynamic_constituents(index)
         call test_host_constituents_obj%new_field(const_prop, errcode=errflg, errmsg=errmsg)
         nullify(const_prop)
         if (errflg /= 0) then
            return
         end if
      end do
      ! Add cld_suite constituent metadata
      num_suite_consts = cld_suite_constituents_num_consts(errflg=errflg, errmsg=errmsg)
      if (errflg /= 0) then
         return
      end if
      do index = 1, num_suite_consts
         allocate(const_prop, stat=errflg)
         if (errflg /= 0) then
            errmsg = "ERROR allocating const_prop"
            return
         end if
         call cld_suite_constituents_copy_const(index, const_prop, errflg=errflg, errmsg=errmsg)
         if (errflg /= 0) then
            return
         end if
         call test_host_constituents_obj%new_field(const_prop, errcode=errflg, errmsg=errmsg)
         nullify(const_prop)
         if (errflg /= 0) then
            return
         end if
      end do

      call test_host_constituents_obj%lock_table(errcode=errflg, errmsg=errmsg)
      if (errflg /= 0) then
         return
      end if
! Set the index for each active constituent
      do index = 1, SIZE(test_host_model_const_indices)
         call test_host_constituents_obj%const_index(field_ind,                                   &
              test_host_model_const_stdnames(index), errcode=errflg, errmsg=errmsg)
         if (errflg /= 0) then
            return
         end if
         if (field_ind > 0) then
            test_host_model_const_indices(index) = field_ind
         else
            errflg = 1
            errmsg = 'No field index for '//trim(test_host_model_const_stdnames(index))
            return
         end if
      end do

Steve Goldhaber and others added 30 commits July 13, 2022 21:45
Allow schema file to be passed to validate
Add Fortran comment write method
Add metadata table type and name to CCPP datatable variable entries
Improve generated constituent-handling code
Fix issues with output of long comments
Ensure more instance variables are 'private'
Have capgen create database object
Add line fill (target line length) interface to FortranWriter
New Fortran interface, indent_size
New Fortran interface, blank_line
Added insert function for verbatim copy to file
Allow arbitrary break for long lines
Make sure call list variables have an intent
Added link to constituent dictionary
Add metadata to CCPP constituent object DDT
Add Fortran writing unit tests and fix line break bugs
Added constituent props array host interface, improved unit conversion error
Use +ELLIPSIS instead of +IGNORE_EXCEPTION_DETAILS for doctests
Constituent cleanup, no function side effects in interface
Completed and optimized constituent accessor routines
Added minimum allowed value property
Add molecular weight as variable and constituent property
Fix missing property (advected) from database
Rename dir for var_action test to distinguish from ct_build
@peverwhee peverwhee requested a review from climbfuji May 16, 2024 21:17
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. This is a non-expert approval which on its own is not sufficient for merging ;-)

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.

@peverwhee Some minor comments, but overall looks good. Thanks for these changes!
I will start testing in the UFS using this branch and push to get on the commit queue asap.

scripts/ccpp_capgen.py Show resolved Hide resolved
cap.write(f"integer{spc} :: num_consts", 2)
cap.write(f"integer{spc} :: num_dyn_consts", 2)
cap.write(f"integer{spc} :: index, index_start", 2)
cap.write(f"integer{spc} :: field_ind", 2)
cap.write(f"type({CONST_PROP_TYPE}), pointer :: const_prop", 2)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should this be cap.write(f"type({CONST_PROP_TYPE}), pointer :: const_prop => null()", 2)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

updated.

src/ccpp_constituent_prop_mod.F90 Outdated Show resolved Hide resolved
src/ccpp_constituent_prop_mod.F90 Show resolved Hide resolved
cprop => this%find_const(standard_name)
if (associated(cprop)) then
! Standard name already in table, let's see if the existing constituent is the same
cindex = cprop%const_index()
Copy link
Collaborator

Choose a reason for hiding this comment

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

Not used.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

removed!

test/advection_test/test_host.F90 Show resolved Hide resolved
errflg = 0
end if
! Check moist mixing ratio for a dynamic constituent
call const_props(index_dyn2)%is_dry(const_log, errflg, errmsg)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should this be calling "is_moist"?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

added another testing code block to confirm that is_moist returns true (but keeping the test of is_dry() returning false)

test/var_compatibility_test/run_test 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.

@peverwhee Thanks for addressing my comments. Looks good!
(Running the UFS tests now, and will open PRs)

@grantfirl
Copy link
Collaborator

@gold2718 @mwaxmonsky Would you like to re-review before merging this?

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.

Apologies for the delay, looks good to me!

@gold2718
Copy link
Collaborator

gold2718 commented Jun 6, 2024

@gold2718 @mwaxmonsky Would you like to re-review before merging this?

Sorry, can I have today?

@grantfirl
Copy link
Collaborator

@gold2718 @mwaxmonsky Would you like to re-review before merging this?

Sorry, can I have today?

Sure. We're trying to attach this to a set of UFS PRs that are on a queue to be final tested/merged early next week. If we can get final approval this week, it should be fine.

Copy link
Collaborator

@gold2718 gold2718 left a comment

Choose a reason for hiding this comment

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

I have not looked at the test code yet but I have a couple of things that look like they should be changed (looking at 6e165e5).

cap.write("end if", 3)
cap.write("end do", 2)
# 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.

Why not deallocate dyn_const_name here? It does not seem to have any other uses and I do not see any call to {host_model.name}_ccpp_deallocate_dynamic_constituents.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

we can't deallocate {dyn_const_name} here because that's the module-level variable that holds the data for the dynamic constituents; deallocating it would mean you could no longer access those constituent properties

src/ccpp_constituent_prop_mod.F90 Outdated Show resolved Hide resolved
cap.write(f"do index = 1, size(dyn_const_prop_{idx}, 1)", 2)
cap.write(f"{dyn_const_name}(index + index_start) = dyn_const_prop_{idx}(index)", 3)
cap.write("end do", 2)
cap.write(f"index_start = size(dyn_const_prop_{idx}, 1)", 2)
Copy link
Collaborator

Choose a reason for hiding this comment

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

I see how this works if there are two entries in dyn_const_dict but what about 3? Shouldn't this be:

Suggested change
cap.write(f"index_start = size(dyn_const_prop_{idx}, 1)", 2)
cap.write(f"index_start = index_start + size(dyn_const_prop_{idx}, 1)", 2)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

yes good point! fixed

@peverwhee peverwhee requested a review from gold2718 June 7, 2024 17:38
Copy link
Collaborator

@gold2718 gold2718 left a comment

Choose a reason for hiding this comment

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

I'm still not sure I have covered all the corner cases (a simpler implementation would be easy to verify), but I have not found any more definite problems.

@grantfirl grantfirl merged commit 0f82327 into NCAR:main Jul 10, 2024
19 checks passed
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.

VarDictionary doctests broken for python3.12
8 participants