Constituents#495
Conversation
dustinswales
left a comment
There was a problem hiding this comment.
@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?
|
@peverwhee Can you update this branch with updates from feature/capgen? |
gold2718
left a comment
There was a problem hiding this comment.
Yowza, that is a lot to digest!
I have some question and a few suggested changes but overall, I think this is good.
mkavulich
left a comment
There was a problem hiding this comment.
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): |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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!
| 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"]}'] |
There was a problem hiding this comment.
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
| 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"]}'] |
There was a problem hiding this comment.
Well that is a very interesting feature I had not noticed creeping in. Very Fortran friendly :)
There was a problem hiding this comment.
BTW, I think line 315 has to stay as is. It is a Python string but a Fortran literal.
There was a problem hiding this comment.
changed to new fancy python 3.8 version!
| astat = 1 | ||
| call set_errvars(astat, subname, & | ||
| errcode=errcode, errmsg=errmsg, & | ||
| errmsg2=" ERROR: num_advected_vars index out of bounds") |
There was a problem hiding this comment.
Can this error message also print num_vars and the current index?
| if (check) then | ||
| index_advect = index_advect + 1 | ||
| if (index_advect > this%num_advected_vars) then | ||
| call set_errvars(1, subname, & |
There was a problem hiding this comment.
Same here in these two blocks, print the OOB index and the limit it has exceeded
mwaxmonsky
left a comment
There was a problem hiding this comment.
Great work @peverwhee!! Just wanted to clarify a few things.
| else: | ||
| element_names = None |
There was a problem hiding this comment.
Is this else needed since we don't enter the if block that assigns element_names=[]?
There was a problem hiding this comment.
But if element_names is not given a value, what is returned at the end?
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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):
| else: | ||
| element_names = None |
There was a problem hiding this comment.
But if element_names is not given a value, what is returned at the end?
gold2718
left a comment
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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.
climbfuji
left a comment
There was a problem hiding this comment.
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.
| CCPPFrameworkEnv object.""" | ||
| return self.__kind_dict.keys() | ||
|
|
||
| def debug_on(self): |
There was a problem hiding this comment.
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)
There was a problem hiding this comment.
good call! Changed to a verbose property
| # end if | ||
| lmsg = "Group {}, schemes = {}" | ||
| if run_env.logger and run_env.logger.isEnabledFor(logging.DEBUG): | ||
| if run_env.debug_on(): |
There was a problem hiding this comment.
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.
| # 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(): |
| cap.write("", 0) | ||
| cap.write("! Dummy arguments", 2) | ||
| cap.comment("Update constituent field info from <const_array>", 2) | ||
| cap.blank_line() |
There was a problem hiding this comment.
These (new?) additions blank_line and comment are useful!
| # end if | ||
| if ((not recur) and | ||
| run_env.logger and run_env.logger.isEnabledFor(logging.DEBUG)): | ||
| run_env.debug_on()): |
There was a problem hiding this comment.
| run_env.debug_on()): | |
| run_env.verbose()): |
| 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(): |
There was a problem hiding this comment.
| if run_env.debug_on(): | |
| if run_env.verbose(): |
| end if | ||
|
|
||
| end function ccp_is_initialized | ||
| end function ccp_is_instantiated |
There was a problem hiding this comment.
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)
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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.
I second this. I think the name probably came from the name of the logging level but it is certainly verbose! |
|
@peverwhee We were wondering in our tag up today when/if you were planning to make the |
|
@climbfuji Yes! I will try to finish up addressing the remaining comments tomorrow. |
climbfuji
left a comment
There was a problem hiding this comment.
Thanks for making the debug_on -> verbose change!
Summary
Updates to bring in constituents object and constituent properties object.
Description
User interface changes?: Yes
Can now optionally add constituent via metadata property advected=True
Addresses #282
Testing: