-
Notifications
You must be signed in to change notification settings - Fork 24
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
Support cesm workflow #131
Changes from all commits
ac076aa
2b36874
97fd4d4
a40ef5d
1842649
910e4c9
1466ad4
a52a042
bb3f37d
0888657
dba6bea
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 |
---|---|---|
@@ -0,0 +1,113 @@ | ||
#!/usr/bin/env python3 | ||
from __future__ import annotations | ||
|
||
import argparse | ||
import os | ||
import sys | ||
|
||
import yaml | ||
|
||
|
||
def _parse_args(): | ||
"""Parse command line arguments""" | ||
|
||
parser = argparse.ArgumentParser( | ||
description="Generate config.yml based on an existing CUPID example", | ||
formatter_class=argparse.ArgumentDefaultsHelpFormatter, | ||
) | ||
|
||
# Command line argument for location of CESM source code (required) | ||
parser.add_argument( | ||
"--cesm-root", | ||
action="store", | ||
dest="cesm_root", | ||
required=True, | ||
help="Location of CESM source code", | ||
) | ||
|
||
# Command line argument for CUPiD example from which to get config.yml | ||
parser.add_argument( | ||
"--cupid-example", | ||
action="store", | ||
dest="cupid_example", | ||
default="key_metrics", | ||
help="CUPiD example to use as template for config.yml", | ||
) | ||
|
||
# Command line argument location of CESM case directory | ||
parser.add_argument( | ||
"--case-root", | ||
action="store", | ||
dest="case_root", | ||
default=os.getcwd(), | ||
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. It may also be worth logging information on what arguments were used? 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. dba6bea adds information about the arguments to the comment section at the head of the new 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. This seems like a good place-- especially since the config.yml file also says it's generated by the script, so all that information is in one area. |
||
help="CESM case directory", | ||
) | ||
|
||
return parser.parse_args() | ||
|
||
|
||
def generate_cupid_config(case_root, cesm_root, cupid_example): | ||
sys.path.append(os.path.join(cesm_root, "cime")) | ||
from CIME.case import Case | ||
|
||
# Is cupid_example a valid value? | ||
cupid_root = os.path.join(cesm_root, "tools", "CUPiD") | ||
cupid_examples = os.path.join(cupid_root, "examples") | ||
valid_examples = [ | ||
example | ||
for example in next(os.walk(cupid_examples))[1] | ||
if example not in ["ilamb", "nblibrary"] | ||
] | ||
if cupid_example not in valid_examples: | ||
error_msg = f"argument --cupid-example: invalid choice '{cupid_example}'" | ||
raise KeyError( | ||
f"{error_msg} (choose from subdirectories of {cupid_examples}: {valid_examples})", | ||
) | ||
|
||
with Case(case_root, read_only=False, record=True) as cesm_case: | ||
case = cesm_case.get_value("CASE") | ||
dout_s_root = cesm_case.get_value("DOUT_S_ROOT") | ||
|
||
# Additional options we need to get from env_cupid.xml | ||
nyears = 1 | ||
start_date = "0001-01-01" | ||
end_date = f"{nyears+1:04d}-01-01" | ||
climo_nyears = 1 | ||
base_case_output_dir = "/glade/campaign/cesm/development/cross-wg/diagnostic_framework/CESM_output_for_testing" | ||
base_nyears = 100 | ||
base_end_date = f"{base_nyears+1:04d}-01-01" | ||
base_climo_nyears = 40 | ||
|
||
with open(os.path.join(cupid_root, "examples", cupid_example, "config.yml")) as f: | ||
my_dict = yaml.safe_load(f) | ||
|
||
my_dict["global_params"]["case_name"] = case | ||
my_dict["global_params"]["start_date"] = start_date | ||
my_dict["global_params"]["end_date"] = end_date | ||
my_dict["global_params"]["climo_nyears"] = climo_nyears | ||
my_dict["global_params"]["base_case_output_dir"] = base_case_output_dir | ||
my_dict["global_params"]["base_end_date"] = base_end_date | ||
my_dict["global_params"]["base_climo_nyears"] = base_climo_nyears | ||
my_dict["timeseries"]["case_name"] = case | ||
my_dict["timeseries"]["atm"]["end_years"] = [nyears, base_nyears] | ||
|
||
# replace with environment variable | ||
my_dict["global_params"]["CESM_output_dir"] = dout_s_root | ||
|
||
# create new file, make it writeable | ||
with open("config.yml", "w") as f: | ||
# Header of file is a comment logging provenance | ||
f.write(f"# This file has been auto-generated for use with {case}\n") | ||
f.write(f"# It is based off of examples/{cupid_example}/config.yml\n") | ||
f.write("# Arguments used:\n") | ||
f.write(f"# cesm_root = {cesm_root}\n") | ||
f.write(f"# case_root = {case_root}\n") | ||
f.write(f"# cupid_example= {cupid_example}\n") | ||
|
||
# enter in each element of the dictionary into the new file | ||
yaml.dump(my_dict, f, sort_keys=False) | ||
|
||
|
||
if __name__ == "__main__": | ||
args = vars(_parse_args()) | ||
TeaganKing marked this conversation as resolved.
Show resolved
Hide resolved
|
||
generate_cupid_config(**args) |
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.
The default as key_metrics is great. Is it worthwhile to mention that the example choices are coupled_model and key_metrics? I'm not sure how many different examples we'll end up having?
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 is a tough one -- I'd love to use the
choices
argument ofadd_argument()
along with theos.walk()
function to list the subdirectories ofCUPiD/examples/
, but we don't know where theexamples/
directory is until we resolve--cesm-root
. The best option is probably to enforce this immediately after enteringgenerate_cupid_config()
by ensuring thatos.path.join(cupid_root, "examples", cupid_example)
is a directory and printing out a useful error message if it isn't?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.
That makes sense that adding the
choices
would entail using information we don't have yet. The suggestion you shared sounds great!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.
The code in bb3f37d has the check and gives the following:
Note that both
ilamb
andnblibrary
are left off the list ofvalid_examples
; eventually we'll probably reinstateilamb
, but for now it doesn't have aconfig.yml
file. I'd really like to movenblibrary/
out ofexamples/
but that seems like a big thing to tackle in this PR :)I should probably add text about
'foo' is not a valid option for --cupid-examples
; I'll get to that in the morningThere 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.
Sounds good!
Yes, let's move nblibrary out of examples after this PR is merged in.
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.
0888657 has the improved check:
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.
Fantastic!