-
Notifications
You must be signed in to change notification settings - Fork 148
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
Add TUV-x to CAM #784
base: cam_development
Are you sure you want to change the base?
Add TUV-x to CAM #784
Changes from 81 commits
452b0fc
fdf16a3
9507439
6fa3038
2e3b965
8403076
dd39794
9f6b6d2
5f1378c
46ff4f3
ab18e82
5da13c7
7a59241
ffb0f5e
9cebe0d
3241b31
8e100d5
64f9a3b
49d323b
0a0b3ff
0562e9d
69a5897
e3cc2ab
1e05ffe
80c3479
5d89cb7
422aba7
147e15a
7854fde
f8be1bb
13e030f
996bd91
1011882
ea8a654
439a0ba
9ded52f
facccaf
a3b66a0
ee5f4fc
f4fa3dc
583c4b5
1f433ff
fd715e1
9c3d234
a60e90d
fe1f142
d5c4d84
26375d9
3d8852c
364d905
d29ea42
3c6def8
a7e1030
be7e7f1
37326c4
0608ae3
1b4f238
790a0e1
4b8ca93
a13d6f8
22811e6
770f6cc
620b8d4
d69a00a
1e8d9fa
c47a4c3
60e0f54
eb69196
1a2204e
1a85f0a
f8882cd
07fae13
3e1f445
6d528a2
23c8252
f977c85
1919ddd
889e146
616fcdc
561d226
e0b3ca6
c572a68
0087b93
ab79052
34a48a3
c90dccb
93983f6
8a8c1af
3e4c77b
a3669a5
c12d1e4
15ba87b
ace8449
402be6e
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 |
---|---|---|
|
@@ -7,6 +7,7 @@ create the cam library | |
#pylint: disable=unused-wildcard-import, bad-whitespace, too-many-locals | ||
#pylint: disable=invalid-name | ||
import sys, os, filecmp, shutil, imp | ||
from glob import glob | ||
|
||
_CIMEROOT = os.environ.get("CIMEROOT") | ||
if _CIMEROOT is None: | ||
|
@@ -20,6 +21,7 @@ from CIME.case import Case | |
from CIME.utils import run_cmd, expect | ||
from CIME.buildlib import parse_input | ||
from CIME.build import get_standard_makefile_args | ||
from CIME.XML.env_build import EnvBuild | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
@@ -41,7 +43,7 @@ def _build_fms(caseroot, libroot, bldroot): | |
expect(os.path.exists(fmsbuildlib), "FMS external not found") | ||
stat, _, err = run_cmd("{} {} {} {}".format(fmsbuildlib, case.get_value("EXEROOT"), fmsbuilddir, caseroot), verbose=True) | ||
expect(stat==0, "FMS build Failed {}".format(err)) | ||
|
||
libfms = os.path.join(bldroot,"FMS","libfms.a") | ||
if os.path.exists(libfms): | ||
shutil.copy(libfms, libroot) | ||
|
@@ -108,10 +110,230 @@ def _build_cam(caseroot, libroot, bldroot): | |
logger.info("%s: \n\n output:\n %s \n\n err:\n\n%s\n", cmd, out, err) | ||
expect(rc == 0, "Command %s failed with rc=%s" % (cmd, rc)) | ||
|
||
############################################################################### | ||
def _run_cmd(command, working_dir): | ||
############################################################################### | ||
|
||
rc, out, err = run_cmd(command, from_dir=working_dir, verbose=True) | ||
expect(rc == 0, "Command {} failed with rc={}".format(command, rc)) | ||
|
||
############################################################################### | ||
def _cmake_default_args(caseroot): | ||
############################################################################### | ||
# Returns a dictionary of CMake variables based on the Macros.cmake file for | ||
# the build. | ||
|
||
build = EnvBuild(case_root=caseroot) | ||
with Case(caseroot) as case: | ||
macro_path = os.path.abspath(os.path.join(caseroot, "cmake_macros", "")) | ||
args = "-DCONVERT_TO_MAKE=ON " | ||
args += "-DCASEROOT={} ".format(caseroot) | ||
args += "-DCOMPILER={} ".format(build.get_value("COMPILER")) | ||
args += "-DOS={} ".format(build.get_value("OS")) | ||
args += "-DMACH={} ".format(case.get_value("MACH")) | ||
args += "-DCMAKE_C_COMPILER_WORKS=1 " | ||
args += "-DCMAKE_Fortran_COMPILER_WORKS=1 " | ||
args += "-DCMAKE_CXX_COMPILER_WORKS=1 " | ||
cmd = "cmake {} .".format(args) | ||
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. @mattldawson
|
||
rc, out, err = run_cmd(cmd, combine_output=True, from_dir=macro_path) | ||
expect(rc == 0, "Command {} failed with rc={} out={} err={}".format(cmd, rc, out, err)) | ||
|
||
arg_dict = {} | ||
for line in out.splitlines(): | ||
if ":=" in line: | ||
key, val = line.split(":=") | ||
arg_dict[key.replace('CIME_SET_MAKEFILE_VAR','').strip()] = val.strip() | ||
|
||
return arg_dict | ||
|
||
############################################################################### | ||
def _build_json_fortran(caseroot, libroot, bldroot): | ||
############################################################################### | ||
# Builds the json-fortran library and updates the case variables used to set | ||
# the include paths and linked libraries | ||
|
||
with Case(caseroot) as case: | ||
bldpath = os.path.join(bldroot, "json-fortran") | ||
if not os.path.exists(bldpath): | ||
os.makedirs(bldpath) | ||
srcpath = os.path.abspath(os.path.join(case.get_value("COMP_ROOT_DIR_ATM"), \ | ||
"libraries", "json-fortran", "")) | ||
logger.info("Building json-fortran in {} from source in {}\n".format(bldpath, srcpath)) | ||
|
||
arg_dict = _cmake_default_args(caseroot) | ||
cmake_args = "-DCMAKE_Fortran_COMPILER={} ".format(arg_dict["SFC"]) | ||
cmake_args += "-DCMAKE_C_COMPILER_WORKS=1 " | ||
cmake_args += "-DCMAKE_CXX_COMPILER_WORKS=1 " | ||
cmake_args += "-DCMAKE_BUILD_TYPE=Release " | ||
cmake_args += "-DSKIP_DOC_GEN:BOOL=TRUE " | ||
cmake_args += "-DCMAKE_INSTALL_PREFIX='{}' ".format(libroot) | ||
cmake_args += srcpath | ||
|
||
_run_cmd("cmake {}".format(cmake_args), bldpath) | ||
_run_cmd(case.get_value("GMAKE"), bldpath) | ||
_run_cmd("{} install".format(case.get_value("GMAKE")), bldpath) | ||
|
||
# add json-fortran to include paths | ||
incldir = os.environ.get('USER_INCLDIR') | ||
if incldir is None: | ||
incldir = '' | ||
os.environ['USER_INCLDIR'] = incldir + \ | ||
" -I{} ".format(_json_fortran_include_dir(libroot)) | ||
|
||
# create simlink to library in folder CIME expects libraries to be in | ||
dst = os.path.join(libroot, "libjsonfortran.a") | ||
if os.path.isfile(dst): | ||
os.remove(dst) | ||
os.symlink(_json_fortran_lib_path(libroot), dst) | ||
|
||
############################################################################### | ||
def _json_fortran_include_dir(libroot): | ||
############################################################################### | ||
# Returns the path to the json-fortran include directory | ||
|
||
jsoninc = os.path.join(_json_fortran_install_dir(libroot), "lib", "") | ||
expect(os.path.exists(jsoninc), \ | ||
"JSON-Fortran include directory not found at {}".format(jsoninc)) | ||
return jsoninc | ||
|
||
############################################################################### | ||
def _json_fortran_lib_path(libroot): | ||
############################################################################### | ||
# Returns the path to the json-fortran library | ||
|
||
jsonlib = os.path.join(_json_fortran_install_dir(libroot), "lib", "libjsonfortran.a") | ||
expect(os.path.exists(jsonlib), \ | ||
"JSON-Fortran library not found at {}".format(jsonlib)) | ||
return jsonlib | ||
|
||
############################################################################### | ||
def _json_fortran_install_dir(libroot): | ||
############################################################################### | ||
# Returns the path to the json-fortran install directory | ||
|
||
jsonpaths = glob(os.path.join(libroot, "jsonfortran*")) | ||
expect(len(jsonpaths)>0, \ | ||
"JSON-Fortran not found at {}".format(libroot)) | ||
expect(len(jsonpaths)<2, \ | ||
"Multiple JSON-Fortran versions found at {}".format(libroot)) | ||
expect(os.path.exists(jsonpaths[0]), \ | ||
"JSON-Fortran install directory not found at {}".format(jsonpaths[0])) | ||
return jsonpaths[0] | ||
|
||
############################################################################### | ||
def _build_musica(caseroot, libroot, bldroot): | ||
############################################################################### | ||
# Builds the musica library, including TUV-x, musica, and MICM | ||
# and updates the case variables used to set the include paths | ||
# and linked libraries | ||
|
||
build = EnvBuild(case_root=caseroot) | ||
with Case(caseroot) as case: | ||
bldpath = os.path.join(bldroot, "musica") | ||
if not os.path.exists(bldpath): | ||
os.makedirs(bldpath) | ||
jsoninc = _json_fortran_include_dir(libroot) | ||
jsonlib = _json_fortran_lib_path(libroot) | ||
srcpath = os.path.abspath(os.path.join(case.get_value("COMP_ROOT_DIR_ATM"), \ | ||
"libraries", "musica", "")) | ||
logger.info("Building musica in {} from source in {}\n".format(bldpath, srcpath)) | ||
|
||
arg_dict = _cmake_default_args(caseroot) | ||
if build.get_value("MPILIB") == "mpi-serial": | ||
cmake_args = "-DCMAKE_Fortran_COMPILER={} ".format(arg_dict["SFC"]) | ||
else: | ||
cmake_args = "-DCMAKE_Fortran_COMPILER={} ".format(arg_dict["MPIFC"]) | ||
cmake_args += "-DENABLE_MPI:BOOL=TRUE " | ||
if case.get_value("DEBUG"): | ||
cmake_args += "-DCMAKE_BUILD_TYPE=Debug " | ||
else: | ||
cmake_args += "-DCMAKE_BUILD_TYPE=Release " | ||
cmake_args += "-DENABLE_UTIL_ONLY=ON " | ||
cmake_args += "-DCMAKE_C_COMPILER_WORKS=1 " | ||
cmake_args += "-DCMAKE_CXX_COMPILER_WORKS=1 " | ||
cmake_args += "-DENABLE_MICM=OFF " | ||
cmake_args += "-DENABLE_TUVX=ON " | ||
cmake_args += "-DENABLE_TESTS=OFF " | ||
cmake_args += "-DENABLE_COVERAGE=OFF " | ||
cmake_args += "-DJSON_INCLUDE_DIR={} ".format(jsoninc) | ||
cmake_args += "-DJSON_LIB={} ".format(jsonlib) | ||
cmake_args += "-DCMAKE_Fortran_FLAGS='{}' ".format(arg_dict["FFLAGS"]) | ||
cmake_args += "-DCMAKE_INSTALL_PREFIX='{}' ".format(libroot) | ||
cmake_args += srcpath | ||
|
||
_run_cmd("cmake {}".format(cmake_args), bldpath) | ||
_run_cmd(case.get_value("GMAKE"), bldpath) | ||
_run_cmd("{} install".format(case.get_value("GMAKE")), bldpath) | ||
|
||
# add musica to include paths | ||
incldir = os.environ.get('USER_INCLDIR') | ||
if incldir is None: | ||
incldir = '' | ||
os.environ['USER_INCLDIR'] = incldir + \ | ||
" -I{} ".format(_musica_include_dir(libroot)) | ||
|
||
# create simlink to library in folder CIME expects libraries to be in | ||
dst = os.path.join(libroot, "libmusica.a") | ||
if os.path.isfile(dst): | ||
os.remove(dst) | ||
os.symlink(_musica_lib_path(libroot), dst) | ||
|
||
############################################################################### | ||
def _musica_include_dir(libroot): | ||
############################################################################### | ||
# Returns the path to the musica include directory | ||
|
||
coreinc = os.path.join(_musica_install_dir(libroot), "include", "") | ||
expect(os.path.exists(coreinc), \ | ||
"musica include directory not found at {}".format(coreinc)) | ||
return coreinc | ||
|
||
############################################################################### | ||
def _musica_lib_path(libroot): | ||
############################################################################### | ||
# Returns the path to the musica library | ||
|
||
corelib = os.path.join(_musica_install_dir(libroot), "lib64", "libmusica.a") | ||
if not os.path.exists(corelib): | ||
corelib = os.path.join(_musica_install_dir(libroot), "lib", "libmusica.a") | ||
expect(os.path.exists(corelib), \ | ||
"musica library not found at {}".format(corelib)) | ||
return corelib | ||
|
||
############################################################################### | ||
def _musica_install_dir(libroot): | ||
############################################################################### | ||
# Returns the path to the musica install directory | ||
|
||
corepaths = glob(os.path.join(libroot, "musica*")) | ||
expect(len(corepaths)>0, \ | ||
"musica not found at {}".format(libroot)) | ||
expect(len(corepaths)<2, \ | ||
"Multiple musica versions found at {}".format(libroot)) | ||
expect(os.path.exists(corepaths[0]), \ | ||
"musica install directory not found at {}".format(corepaths[0])) | ||
return corepaths[0] | ||
|
||
############################################################################### | ||
def _musica_package_dir(libroot): | ||
############################################################################### | ||
# Returns the path to the musica CMake package | ||
|
||
paths = glob(os.path.join(libroot, "musica*", "cmake", "musica*" )) | ||
expect(len(paths)>0, \ | ||
"musica package not found at {}".format(libroot)) | ||
expect(len(paths)<2, \ | ||
"Multiple musica versions found at {}".format(libroot)) | ||
expect(os.path.exists(paths[0]), \ | ||
"musica package directory not found at {}".format(paths[0])) | ||
return paths[0] | ||
|
||
############################################################################### | ||
|
||
def _main_func(): | ||
caseroot, libroot, bldroot = parse_input(sys.argv) | ||
_build_json_fortran(caseroot, libroot, bldroot) | ||
_build_musica(caseroot, libroot, bldroot) | ||
_build_fms(caseroot, libroot, bldroot) | ||
_build_cam(caseroot, libroot, bldroot) | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -211,6 +211,17 @@ def buildnml(case, caseroot, compname): | |
if (os.path.isfile(file1)) and (not os.path.isfile(file2)): | ||
shutil.copy(file1,file2) | ||
|
||
# Temporary copy of TUV-x data for development | ||
dest_data = os.path.join(rundir, "data") | ||
if os.path.exists(dest_data): | ||
shutil.rmtree(dest_data) | ||
shutil.copytree(os.path.join(srcroot, "libraries", "musica", "lib", \ | ||
"tuv-x", "data"), dest_data) | ||
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. There are a large number of small data files for cross sections and quantum yields that are currently part of the TUV-x repo (but may eventually move to a database of some kind). These are not CAM-specific files and will be used by other models that link to TUV-x. Is this the correct way to stage them for use in a CAM run? @nusbaume @cacraigucar |
||
shutil.copy2(os.path.join(srcroot, "cime_config", "tuvx_MOZART.json"), \ | ||
os.path.join(rundir, "tuvx_MOZART.json")) | ||
shutil.copy2(os.path.join(srcroot, "cime_config", "tuvx_MOZART_TS1.json"), \ | ||
os.path.join(rundir, "tuvx_MOZART_TS1.json")) | ||
Comment on lines
+220
to
+223
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. There are two CAM-specific configuration files (each for specific MOZART chemical mechanisms) needed to use TUV-x in CAM. Should these be moved to the CAM dataset repository? @nusbaume @cacraigucar 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 handling for config files looks similar to what we originally did for GEOS-Chem. Ultimately we decided to keep the config files in the source code, copy them at case setup time to the case root via cam/cime_config/case.case_setup.py, and then copy from case root to run directory upon submit (via this code in buildnml). This is good if you think your config file template will be tied to source code version and you want users to be able to custom edit it prior to run-time(from case root). |
||
|
||
############################################################################### | ||
def _main_func(): | ||
|
||
|
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 pending CMEPS PR 356