Skip to content

Constituents#495

Merged
peverwhee merged 13 commits intoNCAR:feature/capgenfrom
peverwhee:constituents
Nov 29, 2023
Merged

Constituents#495
peverwhee merged 13 commits intoNCAR:feature/capgenfrom
peverwhee:constituents

Conversation

@peverwhee
Copy link
Copy Markdown
Collaborator

Summary

Updates to bring in constituents object and constituent properties object.

Description

  • Meat of the updates are in src/ccpp_constituent_prop_mod.F90
  • Add interfaces to host cap to access constituent and const props objects
  • Add metadata properties specific to constituents (currently advected=True is the only way to note a constituent
  • Adds ddt object, support, and testing to achieve above

User interface changes?: Yes
Can now optionally add constituent via metadata property advected=True

Addresses #282

Testing:

  • Ran with CAM-SIMA (SE dycore and KESSLER physics)
  • All tests pass except unit conversion test

Copy link
Copy Markdown
Member

@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 @gold2718 Looks fine to me. Thanks for this monster effort. I don't have anything that would hold up this PR from being merged, assuming the new tests all work as expected.

I'm a bit confused about the need for metadata for fields within the DDTs, but maybe this is because some DDTs have column data that may need to be referenced outside of their home DDT?

Comment thread src/ccpp_constituent_prop_mod.meta
Comment thread test/unit_tests/sample_host_files/ddt1.meta
@dustinswales
Copy link
Copy Markdown
Member

@peverwhee Can you update this branch with updates from feature/capgen?

Copy link
Copy Markdown
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.

Yowza, that is a lot to digest!
I have some question and a few suggested changes but overall, I think this is good.

Comment thread scripts/ccpp_capgen.py Outdated
Comment thread scripts/host_model.py
Comment thread scripts/ccpp_suite.py Outdated
Comment thread src/ccpp_constituent_prop_mod.meta
Comment thread test/advection_test/test_host_data.F90
Comment thread test/unit_tests/sample_host_files/ddt1.meta
Comment thread test/unit_tests/sample_host_files/ddt1_plus.meta
Comment thread test/unit_tests/sample_host_files/ddt2.meta
Comment thread test/unit_tests/sample_host_files/ddt_data1_mod.meta
Copy link
Copy Markdown
Collaborator

@mkavulich mkavulich left a comment

Choose a reason for hiding this comment

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

I'll add these as comments since I don't understand enough of the big picture to call this a proper "review".

module=spec_name,
var_dict=var_dict)
mheaders.append(mheader)
if run_env.logger and run_env.logger.isEnabledFor(logging.DEBUG):
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This might be outside the scope of this PR specifically, but It seems like this same debug logic is used a lot in capgen, does it make sense to pull this out into a function so it can be a single line every time?

Copy link
Copy Markdown
Collaborator Author

@peverwhee peverwhee Nov 1, 2023

Choose a reason for hiding this comment

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

Added new function debug_on() routine to CCPPFrameworkEnv

ctx = context_string(pobj, nodir=True)
msg = 'Adding header {}{}'
run_env.logger.debug(msg.format(mheader.table_name, ctx))
# end if
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I understand the need for helper comments like this for very long or convoluted logic blocks, but here (and other if blocks that are only a few lines) it seems superfluous.

I see that this is already present in many places so probably doesn't need to be addressed in this PR, but I thought I would throw it out there.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I would rather have consistent usage and have been saved more than once by these statements showing me where some code block was incorrectly indented.
This particular choice is part of the style guide of some projects I work on. Others use a blank line at the end of every block. I do not know any other project that has different rules for different sized blocks.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

My personal preference would be blank lines, but since this project has started out with # end if (lowercase nowadays, for consistency) it makes sense to continue using it. I shall add those missing statements in my PR #512 later!

Comment thread scripts/constituents.py Outdated
Comment on lines +313 to +317
init_args = [f'std_name="{std_name}"', f'long_name="{long_name}"',
f'units="{units}"', f'vertical_dim="{vertical_dim}"',
f'advected={advect_str}',
f'errcode={errvar_names["ccpp_error_code"]}',
f'errmsg={errvar_names["ccpp_error_message"]}']
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I'm curious what our new minimum python version is? If we require Python 3.8 or newer then this and similar expressions can be greatly simplified

Suggested change
init_args = [f'std_name="{std_name}"', f'long_name="{long_name}"',
f'units="{units}"', f'vertical_dim="{vertical_dim}"',
f'advected={advect_str}',
f'errcode={errvar_names["ccpp_error_code"]}',
f'errmsg={errvar_names["ccpp_error_message"]}']
init_args = [f'{std_name=}', f'{long_name=}',
f'{units=}', f'{vertical_dim=}',
f'{advect_str=}',
f'errcode={errvar_names["ccpp_error_code"]}',
f'errmsg={errvar_names["ccpp_error_message"]}']

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Well that is a very interesting feature I had not noticed creeping in. Very Fortran friendly :)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

BTW, I think line 315 has to stay as is. It is a Python string but a Fortran literal.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

changed to new fancy python 3.8 version!

Comment thread src/ccpp_constituent_prop_mod.F90 Outdated
astat = 1
call set_errvars(astat, subname, &
errcode=errcode, errmsg=errmsg, &
errmsg2=" ERROR: num_advected_vars index out of bounds")
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Can this error message also print num_vars and the current index?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

yep! done

Comment thread src/ccpp_constituent_prop_mod.F90 Outdated
if (check) then
index_advect = index_advect + 1
if (index_advect > this%num_advected_vars) then
call set_errvars(1, subname, &
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Same here in these two blocks, print the OOB index and the limit it has exceeded

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

yep! done

Copy link
Copy Markdown
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.

Great work @peverwhee!! Just wanted to clarify a few things.

Comment thread scripts/constituents.py Outdated
Comment thread scripts/fortran_tools/fortran_write.py Outdated
Comment thread scripts/host_model.py
Comment thread scripts/host_model.py
Comment thread scripts/metavar.py Outdated
Comment on lines +795 to +796
else:
element_names = None
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Is this else needed since we don't enter the if block that assigns element_names=[]?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

agreed. removed.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

But if element_names is not given a value, what is returned at the end?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Good point. At the end of the function if element_names is not defined, python throws an exception.

Would a better suggestion have been to set element_names = None by default before starting the if checks?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't know if it is "better" but it is sufficient. The nice thing about raising exceptions in logic corners that should never be hit is that you can find out if future coding ever takes this routine out of its design range.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

thanks for this discussion, guys. I thoroughly confused myself and will blame the recursion (it definitely isn't a me problem!). Updated to initialize element_names to None at the top of the routine and then also raise an exception if we get to the else of if ddt_lib and (dtitle in ddt_lib):

Comment thread scripts/ccpp_suite.py Outdated
Comment thread scripts/ddt_library.py Outdated
Comment thread scripts/host_cap.py Outdated
Comment thread scripts/host_cap.py Outdated
Comment thread scripts/host_model.py
Comment thread scripts/ddt_library.py Outdated
Comment thread scripts/fortran_tools/parse_fortran_file.py Outdated
Comment thread scripts/metavar.py
Comment thread scripts/metavar.py
Comment thread scripts/metavar.py Outdated
Comment on lines +795 to +796
else:
element_names = None
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

But if element_names is not given a value, what is returned at the end?

Copy link
Copy Markdown
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.

Finished a review of ac18c44 and resolved all the conversations I started. However, I still see a few things I think should be changed.


if (associated(this%prop)) then
call this%prop%vertical_dimension(dimname)
is_2d = len_trim(dimname) == 0
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

For CAM at least, 2-D means there is no vertical dimension so there is no name for it. It might be cleaner and more understandable if a is_2d method was added to the prop obect.

Comment thread src/ccpp_constituent_prop_mod.F90 Outdated
Comment thread src/ccpp_constituent_prop_mod.F90 Outdated
Comment thread src/ccpp_constituent_prop_mod.F90 Outdated
Comment thread src/ccpp_constituent_prop_mod.F90 Outdated
@peverwhee peverwhee requested a review from gold2718 November 8, 2023 22:19
Copy link
Copy Markdown
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 a very high-level review. I was not looking at every single of the 10000-ish lines in the modified/added constituent code, but rather trying to get a bit of an understanding and look at things I know about (and care about more ...).

I am a little concerned about how complicated and extensive this code is, but as long as none of this is mandatory and host models can use capgen without the constituents logic (not saying the should, but at least for transitioning from prebuild to capgen that would be good) then that's all ok.

My only real concern is the newly added debug_on feature, which is inconsistent with how the arguments to capgen and prebuild are called and therefore should be renamed to just verbose. I started suggesting those changes until I got tired, and I certainly overlooked a few.

Comment thread scripts/framework_env.py Outdated
CCPPFrameworkEnv object."""
return self.__kind_dict.keys()

def debug_on(self):
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This should not be debug_on but simply verbose to match the flag that gets passed to capgen, and also to avoid confusion with what the --debug switch for capgen is doing (see PR #512)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

good call! Changed to a verbose property

Comment thread scripts/ccpp_suite.py Outdated
# end if
lmsg = "Group {}, schemes = {}"
if run_env.logger and run_env.logger.isEnabledFor(logging.DEBUG):
if run_env.debug_on():
Copy link
Copy Markdown
Collaborator

@climbfuji climbfuji Nov 9, 2023

Choose a reason for hiding this comment

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

See below, should be just run_env.verbose() or even better a property run_env.verbose. This way it's consistent with #512 where I added run_env.debug.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

changed!

Comment thread scripts/ccpp_suite.py Outdated
# Set name of module and filename of cap
filename = '{module_name}.F90'.format(module_name=self.module)
if run_env.logger and run_env.logger.isEnabledFor(logging.DEBUG):
if run_env.debug_on():
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Ditto

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

changed!

Comment thread scripts/constituents.py
cap.write("", 0)
cap.write("! Dummy arguments", 2)
cap.comment("Update constituent field info from <const_array>", 2)
cap.blank_line()
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

These (new?) additions blank_line and comment are useful!

Comment thread scripts/ddt_library.py Outdated
# end if
if ((not recur) and
run_env.logger and run_env.logger.isEnabledFor(logging.DEBUG)):
run_env.debug_on()):
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
run_env.debug_on()):
run_env.verbose()):

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

changed!

Comment thread scripts/suite_objects.py Outdated
self._local_dim_name = None
super().__init__(index_name, context, parent, run_env)
if run_env.logger and run_env.logger.isEnabledFor(logging.DEBUG):
if run_env.debug_on():
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
if run_env.debug_on():
if run_env.verbose():

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

changed!

end if

end function ccp_is_initialized
end function ccp_is_instantiated
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I have a feeling that I asked this question 2 +/- years ago when the constituents where added originally. What does ccp and ccpt stand for? Should we be concerned about confusion with ccpp that also shows up as acronym in the same part of the code? (This is just for my curiosity or for the future, not really related to this PR)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Sorry, this is just me trying to save space with recursive acronyms (hey, I remember the first infinintely-recursive acronym I ran across, GNU, back when it was still pretty new in 1984).
I figured they are harmless because they are all defined within a type with a well defined name so it should be clear what they are for. However, for the record:
CCP stands for Ccpp_Constituent_Properties_t
and
CCPT stands for Ccpp_Constituent_prop_Ptr_T

These acronyms should not show up outside this module (can they even be called from outside?).


if (associated(this%prop)) then
call this%prop%vertical_dimension(dimname)
is_2d = len_trim(dimname) == 0
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Another point: While many models move to one horizontal dimension and one vertical dimension, we all have a basic understanding that 2d is something on a surface and 3d something in a volume, therefore this makes sense.

Comment thread test/advection_test/test_host.F90
Comment thread test/unit_tests/sample_host_files/data1_mod.meta
@gold2718
Copy link
Copy Markdown
Collaborator

My only real concern is the newly added debug_on feature

I second this. I think the name probably came from the name of the logging level but it is certainly verbose!

Copy link
Copy Markdown
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.

9db9477 looks good, thanks!

@climbfuji
Copy link
Copy Markdown
Collaborator

@peverwhee We were wondering in our tag up today when/if you were planning to make the debug_on() --> verbose() change so that we can approve and merge?

@peverwhee
Copy link
Copy Markdown
Collaborator Author

@climbfuji Yes! I will try to finish up addressing the remaining comments tomorrow.

@peverwhee peverwhee requested a review from climbfuji November 29, 2023 03:51
Copy link
Copy Markdown
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 making the debug_on -> verbose change!

@peverwhee peverwhee merged commit e86d0a7 into NCAR:feature/capgen Nov 29, 2023
@peverwhee peverwhee deleted the constituents branch November 18, 2025 23:42
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.

6 participants