-
Notifications
You must be signed in to change notification settings - Fork 21
sima0_16_001: Make constituent names case-insensitive in IC file read path, consistent with the CCPP framework; update framework tag #518
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
Changes from 6 commits
90895b8
4ec5892
5f84e58
8f099a5
f155f64
0d69c6a
4cc3890
1e509e9
43cfa38
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -132,7 +132,7 @@ def write_init_files(cap_database, ic_names, registry_constituents, vars_init_va | |
|
|
||
| # Gather all the host model variables that are required by | ||
| # any of the compiled CCPP physics suites. | ||
| in_vars, out_vars, constituent_set, retmsg = gather_ccpp_req_vars(cap_database, registry_constituents) | ||
| in_vars, out_vars, constituent_set, retmsg = gather_ccpp_req_vars(cap_database) | ||
|
|
||
| # Quit now if there are missing variables | ||
| if retmsg: | ||
|
|
@@ -306,7 +306,7 @@ def _find_and_add_host_variable(stdname, host_dict, var_dict): | |
| return missing_vars | ||
|
|
||
| ############################################################################## | ||
| def gather_ccpp_req_vars(cap_database, registry_constituents): | ||
| def gather_ccpp_req_vars(cap_database): | ||
| """ | ||
| Generate a list of host-model and constituent variables | ||
| required by the CCPP physics suites potentially being used | ||
|
|
@@ -340,10 +340,21 @@ def gather_ccpp_req_vars(cap_database, registry_constituents): | |
| (stdname not in in_vars) and | ||
| (stdname not in _EXCLUDED_STDNAMES)): | ||
| if is_const: | ||
| #Add variable to constituent set: | ||
| constituent_vars.add(stdname) | ||
| #Add variable to required variable list if it's not a registry constituent | ||
| if stdname not in registry_constituents: | ||
| if cvar.get_prop_value('advected'): | ||
| # Advected constituents are allocated/registered by the | ||
| # constituents object and read via the runtime | ||
| # constituent loop (registry ic_file_input_names or | ||
| # the cnst_/pbuf_ fallback). Do NOT add them to the | ||
| # host-variable list: that gives them a | ||
| # phys_var_stdnames row keyed to the scheme's local | ||
| # name, which never matches a CAM snapshot field and | ||
| # would pre-empt the fallback. | ||
| pass | ||
| else: | ||
| # Constituent-related but not advected (e.g. tendency | ||
| # variables): these are read as regular host variables, | ||
| # not through the constituent loop. | ||
| in_vars[stdname] = cvar | ||
| # end if | ||
|
peverwhee marked this conversation as resolved.
Outdated
|
||
| else: | ||
|
|
@@ -974,6 +985,7 @@ def write_phys_read_subroutine(outfile, host_dict, host_vars, host_imports, | |
| "cam_constituents_array", | ||
| "cam_model_const_properties"]], | ||
| ["ccpp_kinds", ["kind_phys"]], | ||
| ["string_utils", ["to_lower", "to_upper"]], | ||
| [phys_check_fname_str, ["phys_var_num", "phys_var_stdnames", | ||
| "input_var_names", "std_name_len", | ||
| "is_initialized"]], | ||
|
|
@@ -1180,26 +1192,31 @@ def write_phys_read_subroutine(outfile, host_dict, host_vars, host_imports, | |
| outfile.write("var_found = .false.", 3) | ||
| outfile.comment("Check if constituent standard name in registered SIMA standard names list:", 3) | ||
| outfile.write("call const_props(constituent_idx)%standard_name(std_name)", 3) | ||
| outfile.write("if(any(phys_var_stdnames == trim(std_name))) then", 3) | ||
| outfile.comment("Find array index to extract correct input names", 3) | ||
| outfile.comment("(case-insensitive: see find_input_name_idx):", 3) | ||
| outfile.write("const_input_idx = -1", 3) | ||
| outfile.write("do n=1, phys_var_num", 3) | ||
| outfile.write("if(to_lower(trim(phys_var_stdnames(n))) == to_lower(trim(std_name))) then", 4) | ||
| outfile.write("const_input_idx = n", 5) | ||
| outfile.write("exit", 5) | ||
| outfile.write("end if", 4) | ||
| outfile.write("end do", 3) | ||
| outfile.write("if(const_input_idx > 0) then", 3) | ||
| outfile.comment("Don't read the variable in if it's already initialized", 4) | ||
| outfile.write("if (is_initialized(std_name)) then", 4) | ||
| outfile.write("cycle", 5) | ||
| outfile.write("end if", 4) | ||
| outfile.comment("Find array index to extract correct input names:", 4) | ||
| outfile.write("do n=1, phys_var_num", 4) | ||
| outfile.write("if(trim(phys_var_stdnames(n)) == trim(std_name)) then", 5) | ||
| outfile.write("const_input_idx = n", 6) | ||
| outfile.write("exit", 6) | ||
| outfile.write("end if", 5) | ||
| outfile.write("end do", 4) | ||
| outfile.write("call read_field(file, std_name, input_var_names(:,const_input_idx), 'lev', timestep, field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found)", 4) | ||
| outfile.write("else", 3) | ||
| outfile.comment("If not in standard names list, then attempt constituent name",4) | ||
| outfile.comment("and cnst_, pbuf_ prefixes used by CAM snapshots (advected, non-advected) as input names:",4) | ||
| # The <std_name>, cnst_<std_name>, pbuf_<std_name> prefix default fallbacks | ||
| # allows us to not enumerate all needed constituents from snapshots in the | ||
| # registry, yet allow reading their values from CAM snapshots. | ||
| outfile.write("call read_field(file, std_name, [character(len=std_name_len+5) :: std_name, 'cnst_'//trim(std_name), 'pbuf_'//trim(std_name)], 'lev', timestep, field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found)", 4) | ||
| outfile.comment("and cnst_, pbuf_ prefixes used by CAM snapshots (advected, non-advected) as input names.",4) | ||
| outfile.comment("Standard names are case-insensitive (capgen lowercases them) but netCDF names are not,",4) | ||
| outfile.comment("so also try the all-upper and all-lower case spellings of the constituent name:",4) | ||
| # The <std_name>, cnst_<std_name>, pbuf_<std_name> prefix default fallbacks -- | ||
| # in the as-registered, all-upper, and all-lower case spellings -- allow us to | ||
| # not enumerate all needed constituents from snapshots in the registry, yet | ||
| # allow reading their values from CAM snapshots regardless of authored name case. | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I might get rid of this comment block, as the text in the generated comments explains it well enough, at least in my opinion.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I also don't like this, so I am happy to remove. Would you think it's self-explanatory that some constituents in CAM are uppercase and some lowercase? I briefly considered changing this to something like
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I personally think it is self-explanatory, simply because having a system that tries the different case combinations is inherently more robust than a system that doesn't cover that space, regardless of what case(s) the constituents actually have. That being said if you don't feel the same then I am happy to include the comment you are proposing (as it is still way shorter than what was originally there). Thanks! |
||
| outfile.write("call read_field(file, std_name, [character(len=std_name_len+5) :: std_name, 'cnst_'//trim(std_name), 'pbuf_'//trim(std_name), to_upper(std_name), 'cnst_'//trim(to_upper(std_name)), 'pbuf_'//trim(to_upper(std_name)), to_lower(std_name), 'cnst_'//trim(to_lower(std_name)), 'pbuf_'//trim(to_lower(std_name))], 'lev', timestep, field_data_ptr(:,:,constituent_idx), mark_as_read=.false., error_on_not_found=.false., var_found=var_found)", 4) | ||
| outfile.write("end if", 3) | ||
| outfile.write("if(.not. var_found) then", 3) | ||
| outfile.write("constituent_has_default = .false.", 4) | ||
|
|
@@ -1306,6 +1323,7 @@ def write_phys_check_subroutine(outfile, host_dict, host_vars, host_imports, | |
| "cam_model_const_properties"]], | ||
| ["cam_constituents", ["const_get_index"]], | ||
| ["ccpp_kinds", ["kind_phys"]], | ||
| ["string_utils", ["to_lower", "to_upper"]], | ||
| ["cam_logfile", ["iulog"]], | ||
| ["spmd_utils", ["masterproc"]], | ||
| ["phys_vars_init_check", ["is_read_from_file"]], | ||
|
|
@@ -1492,25 +1510,30 @@ def write_phys_check_subroutine(outfile, host_dict, host_vars, host_imports, | |
| outfile.write("do constituent_idx = 1, size(const_props)", 2) | ||
| outfile.comment("Check if constituent standard name in registered SIMA standard names list:", 3) | ||
| outfile.write("call const_props(constituent_idx)%standard_name(std_name)", 3) | ||
| outfile.write("if(any(phys_var_stdnames == std_name)) then", 3) | ||
| outfile.comment("Find array index to extract correct input names:", 4) | ||
| outfile.write("do n=1, phys_var_num", 4) | ||
| outfile.write("if(trim(phys_var_stdnames(n)) == trim(std_name)) then", 5) | ||
| outfile.write("const_input_idx = n", 6) | ||
| outfile.write("exit", 6) | ||
| outfile.write("end if", 5) | ||
| outfile.write("end do", 4) | ||
| outfile.comment("Find array index to extract correct input names", 3) | ||
| outfile.comment("(case-insensitive: see find_input_name_idx):", 3) | ||
| outfile.write("const_input_idx = -1", 3) | ||
| outfile.write("do n=1, phys_var_num", 3) | ||
| outfile.write("if(to_lower(trim(phys_var_stdnames(n))) == to_lower(trim(std_name))) then", 4) | ||
| outfile.write("const_input_idx = n", 5) | ||
| outfile.write("exit", 5) | ||
| outfile.write("end if", 4) | ||
| outfile.write("end do", 3) | ||
| outfile.write("if(const_input_idx > 0) then", 3) | ||
| outfile.write("call check_field(file, input_var_names(:,const_input_idx), 'lev', timestep, field_data_ptr(:,:,constituent_idx), std_name, min_difference, min_relative_value, is_first, diff_found)", 4) | ||
| outfile.write("if (diff_found) then", 4) | ||
| outfile.write("overall_diff_found = .true.", 5) | ||
| outfile.write("end if", 4) | ||
| outfile.write("else", 3) | ||
| outfile.comment("If not in standard names list, then attempt constituent name",4) | ||
| outfile.comment("and cnst_, pbuf_ prefixes used by CAM snapshots (advected, non-advected) as input names:",4) | ||
| # The <std_name>, cnst_<std_name>, pbuf_<std_name> prefix default fallbacks | ||
| # allows us to not enumerate all needed constituents from snapshots in the | ||
| # registry, yet allow reading their values from CAM snapshots. | ||
| outfile.write("call check_field(file, [character(len=std_name_len+5) :: std_name, 'cnst_'//trim(std_name), 'pbuf_'//trim(std_name)], 'lev', timestep, field_data_ptr(:,:,constituent_idx), std_name, min_difference, min_relative_value, is_first, diff_found)", 4) | ||
| outfile.comment("and cnst_, pbuf_ prefixes used by CAM snapshots (advected, non-advected) as input names.",4) | ||
| outfile.comment("Standard names are case-insensitive (capgen lowercases them) but netCDF names are not,",4) | ||
| outfile.comment("so also try the all-upper and all-lower case spellings of the constituent name:",4) | ||
| # The <std_name>, cnst_<std_name>, pbuf_<std_name> prefix default fallbacks -- | ||
| # in the as-registered, all-upper, and all-lower case spellings -- allow us to | ||
| # not enumerate all needed constituents from snapshots in the registry, yet | ||
| # allow reading their values from CAM snapshots regardless of authored name case. | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would remove this comment-block as well.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please see question above! |
||
| outfile.write("call check_field(file, [character(len=std_name_len+5) :: std_name, 'cnst_'//trim(std_name), 'pbuf_'//trim(std_name), to_upper(std_name), 'cnst_'//trim(to_upper(std_name)), 'pbuf_'//trim(to_upper(std_name)), to_lower(std_name), 'cnst_'//trim(to_lower(std_name)), 'pbuf_'//trim(to_lower(std_name))], 'lev', timestep, field_data_ptr(:,:,constituent_idx), std_name, min_difference, min_relative_value, is_first, diff_found)", 4) | ||
| outfile.write("if (diff_found) then", 4) | ||
| outfile.write("overall_diff_found = .true.", 5) | ||
| outfile.write("end if", 4) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This feels like a situation where the AI is over-explaining something (i.e. most of time a human wouldn't write a paragraph explaining the no-op path of a conditional). Instead I might just change the conditional to its inverse and remove this
passsection, especially since theelsecomment seems to explain it well enough.Of course if you disagree just let me know, as I could certainly be convinced otherwise!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! I agree this is overly verbose but I think we could document the
if notclause with a reason. Would this be better?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah that comment block for the
if notclause looks good to me, so feel free to add it. Thanks!