diff --git a/.gitmodules b/.gitmodules index 7274b9acd2..87676223a0 100644 --- a/.gitmodules +++ b/.gitmodules @@ -28,7 +28,7 @@ [submodule "fates"] path = src/fates url = https://github.com/NGEET/fates -fxtag = sci.1.78.2_api.36.0.0 +fxtag = sci.1.79.3_api.37.0.0 fxrequired = AlwaysRequired # Standard Fork to compare to with "git fleximod test" to ensure personal forks aren't committed fxDONOTUSEurl = https://github.com/NCAR/fates-release @@ -60,7 +60,7 @@ fxDONOTUSEurl = https://github.com/ESCOMP/MOSART [submodule "mizuRoute"] path = components/mizuRoute url = https://github.com/ESCOMP/mizuRoute -fxtag = cesm-coupling.n02_v2.1.2 +fxtag = cesm-coupling.n02_v2.1.3 fxrequired = ToplevelRequired # Standard Fork to compare to with "git fleximod test" to ensure personal forks aren't committed fxDONOTUSEurl = https://github.com/ESCOMP/mizuRoute @@ -68,7 +68,7 @@ fxDONOTUSEurl = https://github.com/ESCOMP/mizuRoute [submodule "ccs_config"] path = ccs_config url = https://github.com/ESMCI/ccs_config_cesm.git -fxtag = ccs_config_cesm1.0.0 +fxtag = ccs_config_cesm1.0.10 fxrequired = ToplevelRequired # Standard Fork to compare to with "git fleximod test" to ensure personal forks aren't committed fxDONOTUSEurl = https://github.com/ESMCI/ccs_config_cesm.git @@ -76,7 +76,7 @@ fxDONOTUSEurl = https://github.com/ESMCI/ccs_config_cesm.git [submodule "cime"] path = cime url = https://github.com/ESMCI/cime -fxtag = cime6.0.246 +fxtag = cime6.1.37 fxrequired = ToplevelRequired # Standard Fork to compare to with "git fleximod test" to ensure personal forks aren't committed fxDONOTUSEurl = https://github.com/ESMCI/cime @@ -84,7 +84,7 @@ fxDONOTUSEurl = https://github.com/ESMCI/cime [submodule "cmeps"] path = components/cmeps url = https://github.com/ESCOMP/CMEPS.git -fxtag = cmeps0.14.77 +fxtag = cmeps1.0.16 fxrequired = ToplevelRequired # Standard Fork to compare to with "git fleximod test" to ensure personal forks aren't committed fxDONOTUSEurl = https://github.com/ESCOMP/CMEPS.git @@ -92,7 +92,7 @@ fxDONOTUSEurl = https://github.com/ESCOMP/CMEPS.git [submodule "cdeps"] path = components/cdeps url = https://github.com/ESCOMP/CDEPS.git -fxtag = cdeps1.0.48 +fxtag = cdeps1.0.53 fxrequired = ToplevelRequired # Standard Fork to compare to with "git fleximod test" to ensure personal forks aren't committed fxDONOTUSEurl = https://github.com/ESCOMP/CDEPS.git @@ -100,27 +100,27 @@ fxDONOTUSEurl = https://github.com/ESCOMP/CDEPS.git [submodule "share"] path = share url = https://github.com/ESCOMP/CESM_share -fxtag = share1.0.19 +fxtag = share1.1.2 fxrequired = ToplevelRequired # Standard Fork to compare to with "git fleximod test" to ensure personal forks aren't committed fxDONOTUSEurl = https://github.com/ESCOMP/CESM_share -[submodule "mct"] -path = libraries/mct -url = https://github.com/MCSclimate/MCT -fxtag = MCT_2.11.0 -fxrequired = ToplevelRequired -# Standard Fork to compare to with "git fleximod test" to ensure personal forks aren't committed -fxDONOTUSEurl = https://github.com/MCSclimate/MCT - [submodule "parallelio"] path = libraries/parallelio url = https://github.com/NCAR/ParallelIO -fxtag = pio2_6_2 +fxtag = pio2_6_3 fxrequired = ToplevelRequired # Standard Fork to compare to with "git fleximod test" to ensure personal forks aren't committed fxDONOTUSEurl = https://github.com/NCAR/ParallelIO +[submodule "mpi-serial"] +path = libraries/mpi-serial +url = https://github.com/ESMCI/mpi-serial +fxtag = MPIserial_2.5.1 +fxrequired = ToplevelRequired +# Standard Fork to compare to with "git fleximod test" to ensure personal forks aren't committed +fxDONOTUSEurl = https://github.com/ESMCI/mpi-serial + [submodule "doc-builder"] path = doc/doc-builder url = https://github.com/ESMCI/doc-builder diff --git a/.lib/git-fleximod/.github/workflows/pytest.yaml b/.lib/git-fleximod/.github/workflows/pytest.yaml index 0868dd9a33..6cb8102b94 100644 --- a/.lib/git-fleximod/.github/workflows/pytest.yaml +++ b/.lib/git-fleximod/.github/workflows/pytest.yaml @@ -18,7 +18,7 @@ jobs: # reference the matrixe python version here. - uses: actions/setup-python@v5 with: - python-version: '3.9' + python-version: '3.12' # Cache the installation of Poetry itself, e.g. the next step. This prevents the workflow # from installing Poetry every time, which can be slow. Note the use of the Poetry version @@ -29,7 +29,7 @@ jobs: uses: actions/cache@v4 with: path: ~/.local - key: poetry-1.7.1 + key: poetry-1.8.2 # Install Poetry. You could do this manually, or there are several actions that do this. # `snok/install-poetry` seems to be minimal yet complete, and really just calls out to @@ -42,7 +42,7 @@ jobs: # cache it. - uses: snok/install-poetry@v1 with: - version: 1.7.1 + version: 1.8.2 virtualenvs-create: true virtualenvs-in-project: true @@ -74,4 +74,7 @@ jobs: git config --global user.name "${GITHUB_ACTOR}" git config --global user.email "${GITHUB_ACTOR_ID}+${GITHUB_ACTOR}@users.noreply.github.com" poetry run pytest + - name: Setup tmate session + if: ${{ failure() }} + uses: mxschmitt/action-tmate@v3 diff --git a/.lib/git-fleximod/CODE_OF_CONDUCT.md b/.lib/git-fleximod/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000..84f2925bba --- /dev/null +++ b/.lib/git-fleximod/CODE_OF_CONDUCT.md @@ -0,0 +1,107 @@ +# Contributor Code of Conduct +_The Contributor Code of Conduct is for participants in our software projects and community._ + +## Our Pledge +We, as contributors, creators, stewards, and maintainers (participants), of **git-fleximod** pledge to make participation in +our software, system or hardware project and community a safe, productive, welcoming and inclusive experience for everyone. +All participants are required to abide by this Code of Conduct. +This includes respectful treatment of everyone regardless of age, body size, disability, ethnicity, gender identity or expression, +level of experience, nationality, political affiliation, veteran status, pregnancy, genetic information, physical appearance, race, +religion, or sexual orientation, as well as any other characteristic protected under applicable US federal or state law. + +## Our Standards +Examples of behaviors that contribute to a positive environment include: + +* All participants are treated with respect and consideration, valuing a diversity of views and opinions +* Be considerate, respectful, and collaborative +* Communicate openly with respect for others, critiquing ideas rather than individuals and gracefully accepting criticism +* Acknowledging the contributions of others +* Avoid personal attacks directed toward other participants +* Be mindful of your surroundings and of your fellow participants +* Alert UCAR staff and suppliers/vendors if you notice a dangerous situation or someone in distress +* Respect the rules and policies of the project and venue + +Examples of unacceptable behavior include, but are not limited to: + +* Harassment, intimidation, or discrimination in any form +* Physical, verbal, or written abuse by anyone to anyone, including repeated use of pronouns other than those requested +* Unwelcome sexual attention or advances +* Personal attacks directed at other guests, members, participants, etc. +* Publishing others' private information, such as a physical or electronic address, without explicit permission +* Alarming, intimidating, threatening, or hostile comments or conduct +* Inappropriate use of nudity and/or sexual images +* Threatening or stalking anyone, including a participant +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Scope +This Code of Conduct applies to all spaces managed by the Project whether they be physical, online or face-to-face. +This includes project code, code repository, associated web pages, documentation, mailing lists, project websites and wiki pages, +issue tracker, meetings, telecons, events, project social media accounts, and any other forums created by the project team which the +community uses for communication. +In addition, violations of this Code of Conduct outside these spaces may affect a person's ability to participate within them. +Representation of a project may be further defined and clarified by project maintainers. + +## Community Responsibilities +Everyone in the community is empowered to respond to people who are showing unacceptable behavior. +They can talk to them privately or publicly. +Anyone requested to stop unacceptable behavior is expected to comply immediately. +If the behavior continues concerns may be brought to the project administrators or to any other party listed in the +[Reporting](#reporting) section below. + +## Project Administrator Responsibilities +Project administrators are responsible for clarifying the standards of acceptable behavior and are encouraged to model appropriate +behavior and provide support when people in the community point out inappropriate behavior. +Project administrator(s) are normally the ones that would be tasked to carry out the actions in the [Consequences](#consequences) +section below. + +Project administrators are also expected to keep this Code of Conduct updated with the main one housed at UCAR, as listed below in +the [Attribution](#attribution) section. + +## Reporting +Instances of unacceptable behavior can be brought to the attention of the project administrator(s) who may take any action as +outlined in the [Consequences](#consequences) section below. +However, making a report to a project administrator is not considered an 'official report' to UCAR. + +Instances of unacceptable behavior may also be reported directly to UCAR pursuant to [UCAR's Harassment Reporting and Complaint +Procedure](https://www2.fin.ucar.edu/procedures/hr/harassment-reporting-and-complaint-procedure), or anonymously through [UCAR's +EthicsPoint Hotline](https://www2.fin.ucar.edu/ethics/anonymous-reporting). + +Complaints received by UCAR will be handled pursuant to the procedures outlined in UCAR's Harassment Reporting and Complaint +Procedure. +Complaints to UCAR will be held as confidential as practicable under the circumstances, and retaliation against a person who +initiates a complaint or an inquiry about inappropriate behavior will not be tolerated. + +Any Contributor can use these reporting methods even if they are not directly affiliated with UCAR. +The Frequently Asked Questions (FAQ) page for reporting is [here](https://www2.fin.ucar.edu/procedures/hr/reporting-faqs). + +## Consequences +Upon receipt of a complaint, the project administrator(s) may take any action deemed necessary and appropriate under the +circumstances. +Such action can include things such as: removing, editing, or rejecting comments, commits, code, wiki edits, email, issues, and +other contributions that are not aligned to this Code of Conduct, or banning temporarily or permanently any contributor for other +behaviors that are deemed inappropriate, threatening, offensive, or harmful. +Project administrators also have the right to report violations to UCAR HR and/or UCAR's Office of Diversity, Equity and Inclusion +(ODEI), as well as a participant's home institution and/or law enforcement. +In the event an incident is reported to UCAR, UCAR will follow its Harassment Reporting and Complaint Procedure. + +## Process for Changes +All UCAR managed projects are required to adopt this Contributor Code of Conduct. +Adoption is assumed even if not expressly stated in the repository. +Projects should fill in sections where prompted with project-specific information, including, project name and adoption date. + +Projects that adopt this Code of Conduct need to stay up to date with UCAR's Contributor Code of Conduct, linked with a DOI in the +[Attribution](#attribution) section below. +Projects can make limited substantive changes to the Code of Conduct, however, the changes must be limited in scope and may not +contradict the UCAR Contributor Code of Conduct. + +## Attribution +This Code of Conduct was originally adapted from the [Contributor Covenant](http://contributor-covenant.org/version/1/4), version +1.4. +We then aligned it with the UCAR Participant Code of Conduct, which also borrows from the American Geophysical Union (AGU) Code of +Conduct. +The UCAR Participant Code of Conduct applies to both UCAR employees as well as participants in activities run by UCAR. +The original version of this for all software projects that have strong management from UCAR or UCAR staff is available on the UCAR +website at https://doi.org/10.5065/6w2c-a132. +The date that it was adopted by this project was **Feb/13/2018**. +When responding to complaints, UCAR HR and ODEI will do so based on the latest published version. +Therefore, any project-specific changes should follow the [Process for Changes](#process-for-changes) section above. diff --git a/.lib/git-fleximod/git_fleximod/cli.py b/.lib/git-fleximod/git_fleximod/cli.py index a15a226de4..ac9493cfc3 100644 --- a/.lib/git-fleximod/git_fleximod/cli.py +++ b/.lib/git-fleximod/git_fleximod/cli.py @@ -2,27 +2,31 @@ import argparse from git_fleximod import utils -__version__ = "0.7.8" +__version__ = "0.9.3" def find_root_dir(filename=".gitmodules"): """ finds the highest directory in tree which contains a file called filename """ - d = Path.cwd() - root = Path(d.root) - dirlist = [] - dl = d - while dl != root: - dirlist.append(dl) - dl = dl.parent - dirlist.append(root) - dirlist.reverse() - - for dl in dirlist: - attempt = dl / filename - if attempt.is_file(): - return str(dl) - return None - + try: + root = utils.execute_subprocess(["git","rev-parse", "--show-toplevel"], + output_to_caller=True ).rstrip() + except: + d = Path.cwd() + root = Path(d.root) + dirlist = [] + dl = d + while dl != root: + dirlist.append(dl) + dl = dl.parent + dirlist.append(root) + dirlist.reverse() + + for dl in dirlist: + attempt = dl / filename + if attempt.is_file(): + return str(dl) + return None + return Path(root) def get_parser(): description = """ diff --git a/.lib/git-fleximod/git_fleximod/git_fleximod.py b/.lib/git-fleximod/git_fleximod/git_fleximod.py index e1b8f484a5..13f35df959 100755 --- a/.lib/git-fleximod/git_fleximod/git_fleximod.py +++ b/.lib/git-fleximod/git_fleximod/git_fleximod.py @@ -13,14 +13,14 @@ from git_fleximod import cli from git_fleximod.gitinterface import GitInterface from git_fleximod.gitmodules import GitModules -from configparser import NoOptionError +from git_fleximod.submodule import Submodule # logger variable is global logger = None def fxrequired_allowed_values(): - return ["ToplevelRequired", "ToplevelOptional", "AlwaysRequired", "AlwaysOptional"] + return ["ToplevelRequired", "ToplevelOptional", "AlwaysRequired", "AlwaysOptional", "TopLevelRequired", "TopLevelOptional"] def commandline_arguments(args=None): @@ -33,14 +33,9 @@ def commandline_arguments(args=None): # explicitly listing a component overrides the optional flag if options.optional or options.components: - fxrequired = [ - "ToplevelRequired", - "ToplevelOptional", - "AlwaysRequired", - "AlwaysOptional", - ] + fxrequired = fxrequired_allowed_values() else: - fxrequired = ["ToplevelRequired", "AlwaysRequired"] + fxrequired = ["ToplevelRequired", "AlwaysRequired", "TopLevelRequired"] action = options.action if not action: @@ -98,7 +93,8 @@ def submodule_sparse_checkout(root_dir, name, url, path, sparsefile, tag="master """ logger.info("Called sparse_checkout for {}".format(name)) rgit = GitInterface(root_dir, logger) - superroot = rgit.git_operation("rev-parse", "--show-superproject-working-tree") + superroot = git_toplevelroot(root_dir, logger) + if superroot: gitroot = superroot.strip() else: @@ -128,8 +124,8 @@ def submodule_sparse_checkout(root_dir, name, url, path, sparsefile, tag="master # set the repository remote logger.info("Setting remote origin in {}/{}".format(root_dir, path)) - status = sprepo_git.git_operation("remote", "-v") - if url not in status: + _, remotelist = sprepo_git.git_operation("remote", "-v") + if url not in remotelist: sprepo_git.git_operation("remote", "add", "origin", url) topgit = os.path.join(gitroot, ".git") @@ -154,6 +150,8 @@ def submodule_sparse_checkout(root_dir, name, url, path, sparsefile, tag="master if os.path.isdir(os.path.join(root_dir, path, ".git")): with utils.pushd(sprep_repo): + if os.path.isdir(os.path.join(topgit,".git")): + shutil.rmtree(os.path.join(topgit,".git")) shutil.move(".git", topgit) with open(".git", "w") as f: f.write("gitdir: " + os.path.relpath(topgit)) @@ -166,7 +164,9 @@ def submodule_sparse_checkout(root_dir, name, url, path, sparsefile, tag="master return with utils.pushd(sprep_repo): - shutil.copy(sparsefile, gitsparse) + if os.path.isfile(sparsefile): + shutil.copy(sparsefile, gitsparse) + # Finally checkout the repo sprepo_git.git_operation("fetch", "origin", "--tags") @@ -176,285 +176,82 @@ def submodule_sparse_checkout(root_dir, name, url, path, sparsefile, tag="master rgit.config_set_value(f'submodule "{name}"', "active", "true") rgit.config_set_value(f'submodule "{name}"', "url", url) - -def single_submodule_checkout( - root, name, path, url=None, tag=None, force=False, optional=False -): - """ - This function checks out a single git submodule. - - Parameters: - root (str): The root directory for the git operation. - name (str): The name of the submodule. - path (str): The path to the submodule. - url (str, optional): The URL of the submodule. Defaults to None. - tag (str, optional): The tag to checkout. Defaults to None. - force (bool, optional): If set to True, forces the checkout operation. Defaults to False. - optional (bool, optional): If set to True, the submodule is considered optional. Defaults to False. - - Returns: - None - """ - # function implementation... - git = GitInterface(root, logger) - repodir = os.path.join(root, path) - logger.info("Checkout {} into {}/{}".format(name, root, path)) - # if url is provided update to the new url - tmpurl = None - repo_exists = False - if os.path.exists(os.path.join(repodir, ".git")): - logger.info("Submodule {} already checked out".format(name)) - repo_exists = True - # Look for a .gitmodules file in the newly checkedout repo - if not repo_exists and url: - # ssh urls cause problems for those who dont have git accounts with ssh keys defined - # but cime has one since e3sm prefers ssh to https, because the .gitmodules file was - # opened with a GitModules object we don't need to worry about restoring the file here - # it will be done by the GitModules class - if url.startswith("git@"): - tmpurl = url - url = url.replace("git@github.com:", "https://github.com/") - git.git_operation("clone", url, path) - smgit = GitInterface(repodir, logger) - if not tag: - tag = smgit.git_operation("describe", "--tags", "--always").rstrip() - smgit.git_operation("checkout", tag) - # Now need to move the .git dir to the submodule location - rootdotgit = os.path.join(root, ".git") - if os.path.isfile(rootdotgit): - with open(rootdotgit) as f: - line = f.readline() - if line.startswith("gitdir: "): - rootdotgit = line[8:].rstrip() - - newpath = os.path.abspath(os.path.join(root, rootdotgit, "modules", name)) - if os.path.exists(newpath): - shutil.rmtree(os.path.join(repodir, ".git")) - else: - shutil.move(os.path.join(repodir, ".git"), newpath) - - with open(os.path.join(repodir, ".git"), "w") as f: - f.write("gitdir: " + os.path.relpath(newpath, start=repodir)) - - if not os.path.exists(repodir): - parent = os.path.dirname(repodir) - if not os.path.isdir(parent): - os.makedirs(parent) - git.git_operation("submodule", "add", "--name", name, "--", url, path) - - if not repo_exists or not tmpurl: - git.git_operation("submodule", "update", "--init", "--", path) - - if os.path.exists(os.path.join(repodir, ".gitmodules")): - # recursively handle this checkout - print(f"Recursively checking out submodules of {name}") - gitmodules = GitModules(logger, confpath=repodir) - requiredlist = ["AlwaysRequired"] - if optional: - requiredlist.append("AlwaysOptional") - submodules_checkout(gitmodules, repodir, requiredlist, force=force) - if not os.path.exists(os.path.join(repodir, ".git")): - utils.fatal_error( - f"Failed to checkout {name} {repo_exists} {tmpurl} {repodir} {path}" - ) - - if tmpurl: - print(git.git_operation("restore", ".gitmodules")) - - return - -def add_remote(git, url): - remotes = git.git_operation("remote", "-v") - newremote = "newremote.00" - if url in remotes: - for line in remotes: - if url in line and "fetch" in line: - newremote = line.split()[0] - break - else: - i = 0 - while "newremote" in remotes: - i = i + 1 - newremote = f"newremote.{i:02d}" - git.git_operation("remote", "add", newremote, url) - return newremote - -def submodules_status(gitmodules, root_dir, toplevel=False): +def init_submodule_from_gitmodules(gitmodules, name, root_dir, logger): + path = gitmodules.get(name, "path") + url = gitmodules.get(name, "url") + assert path and url, f"Malformed .gitmodules file {path} {url}" + tag = gitmodules.get(name, "fxtag") + fxurl = gitmodules.get(name, "fxDONOTUSEurl") + fxsparse = gitmodules.get(name, "fxsparse") + fxrequired = gitmodules.get(name, "fxrequired") + return Submodule(root_dir, name, path, url, fxtag=tag, fxurl=fxurl, fxsparse=fxsparse, fxrequired=fxrequired, logger=logger) + +def submodules_status(gitmodules, root_dir, toplevel=False, depth=0): testfails = 0 localmods = 0 needsupdate = 0 + wrapper = textwrap.TextWrapper(initial_indent=' '*(depth*10), width=120,subsequent_indent=' '*(depth*20)) for name in gitmodules.sections(): - path = gitmodules.get(name, "path") - tag = gitmodules.get(name, "fxtag") - url = gitmodules.get(name, "url") - required = gitmodules.get(name, "fxrequired") - level = required and "Toplevel" in required - if not path: - utils.fatal_error("No path found in .gitmodules for {}".format(name)) - newpath = os.path.join(root_dir, path) - logger.debug("newpath is {}".format(newpath)) - if not os.path.exists(os.path.join(newpath, ".git")): - rootgit = GitInterface(root_dir, logger) - # submodule commands use path, not name - url = url.replace("git@github.com:", "https://github.com/") - tags = rootgit.git_operation("ls-remote", "--tags", url) - result = rootgit.git_operation("submodule","status",newpath).split() - ahash = None - if result: - ahash = result[0][1:] - hhash = None - atag = None + submod = init_submodule_from_gitmodules(gitmodules, name, root_dir, logger) + + result,n,l,t = submod.status() + if toplevel or not submod.toplevel(): + print(wrapper.fill(result)) + testfails += t + localmods += l + needsupdate += n + subdir = os.path.join(root_dir, submod.path) + if os.path.exists(os.path.join(subdir, ".gitmodules")): + gsubmod = GitModules(logger, confpath=subdir) + t,l,n = submodules_status(gsubmod, subdir, depth=depth+1) + if toplevel or not submod.toplevel(): + testfails += t + localmods += l + needsupdate += n - needsupdate += 1 - if not toplevel and level: - continue - for htag in tags.split("\n"): - if htag.endswith('^{}'): - htag = htag[:-3] - if ahash and not atag and ahash in htag: - atag = (htag.split()[1])[10:] - if tag and not hhash and htag.endswith(tag): - hhash = htag.split()[0] - if hhash and atag: - break - optional = " (optional)" if required and "Optional" in required else "" - if tag and (ahash == hhash or atag == tag): - print(f"e {name:>20} not checked out, aligned at tag {tag}{optional}") - elif tag: - ahash = rootgit.git_operation( - "submodule", "status", "{}".format(path) - ).rstrip() - ahash = ahash[1 : len(tag) + 1] - if tag == ahash: - print(f"e {name:>20} not checked out, aligned at hash {ahash}{optional}") - else: - print( - f"e {name:>20} not checked out, out of sync at tag {atag}, expected tag is {tag}{optional}" - ) - testfails += 1 - else: - print(f"e {name:>20} has no fxtag defined in .gitmodules{optional}") - testfails += 1 - else: - with utils.pushd(newpath): - git = GitInterface(newpath, logger) - atag = git.git_operation("describe", "--tags", "--always").rstrip() - ahash = git.git_operation("rev-list", "HEAD").partition("\n")[0] - rurl = git.git_operation("ls-remote","--get-url").rstrip() - if rurl != url: - remote = add_remote(git, url) - git.git_operation("fetch", remote) - if tag and atag == tag: - print(f" {name:>20} at tag {tag}") - elif tag and ahash[: len(tag)] == tag: - print(f" {name:>20} at hash {ahash}") - elif atag == ahash: - print(f" {name:>20} at hash {ahash}") - elif tag: - print( - f"s {name:>20} {atag} {ahash} is out of sync with .gitmodules {tag}" - ) - testfails += 1 - needsupdate += 1 - else: - print( - f"e {name:>20} has no fxtag defined in .gitmodules, module at {atag}" - ) - testfails += 1 - - status = git.git_operation("status", "--ignore-submodules", "-uno") - if "nothing to commit" not in status: - localmods = localmods + 1 - print("M" + textwrap.indent(status, " ")) - return testfails, localmods, needsupdate +def git_toplevelroot(root_dir, logger): + rgit = GitInterface(root_dir, logger) + _, superroot = rgit.git_operation("rev-parse", "--show-superproject-working-tree") + return superroot def submodules_update(gitmodules, root_dir, requiredlist, force): - _, localmods, needsupdate = submodules_status(gitmodules, root_dir) - - if localmods and not force: - local_mods_output() - return - if needsupdate == 0: - return - for name in gitmodules.sections(): - fxtag = gitmodules.get(name, "fxtag") - path = gitmodules.get(name, "path") - url = gitmodules.get(name, "url") - logger.info( - "name={} path={} url={} fxtag={} requiredlist={} ".format( - name, os.path.join(root_dir, path), url, fxtag, requiredlist - ) - ) - - fxrequired = gitmodules.get(name, "fxrequired") - assert fxrequired in fxrequired_allowed_values() - rgit = GitInterface(root_dir, logger) - superroot = rgit.git_operation("rev-parse", "--show-superproject-working-tree") - - fxsparse = gitmodules.get(name, "fxsparse") - + submod = init_submodule_from_gitmodules(gitmodules, name, root_dir, logger) + + _, needsupdate, localmods, testfails = submod.status() + if not submod.fxrequired: + submod.fxrequired = "AlwaysRequired" + fxrequired = submod.fxrequired + allowedvalues = fxrequired_allowed_values() + assert fxrequired in allowedvalues + + superroot = git_toplevelroot(root_dir, logger) + if ( fxrequired - and (superroot and "Toplevel" in fxrequired) - or fxrequired not in requiredlist + and ((superroot and "Toplevel" in fxrequired) + or fxrequired not in requiredlist) ): - if "ToplevelOptional" == fxrequired: - print("Skipping optional component {}".format(name)) - continue - if fxsparse: - logger.debug( - "Callng submodule_sparse_checkout({}, {}, {}, {}, {}, {}".format( - root_dir, name, url, path, fxsparse, fxtag - ) - ) - submodule_sparse_checkout(root_dir, name, url, path, fxsparse, tag=fxtag) - else: - logger.info( - "Calling submodule_checkout({},{},{},{})".format( - root_dir, name, path, url - ) - ) - - single_submodule_checkout( - root_dir, - name, - path, - url=url, - tag=fxtag, - force=force, - optional=("AlwaysOptional" in requiredlist), - ) - - if os.path.exists(os.path.join(path, ".git")): - submoddir = os.path.join(root_dir, path) - with utils.pushd(submoddir): - git = GitInterface(submoddir, logger) - # first make sure the url is correct - upstream = git.git_operation("ls-remote", "--get-url").rstrip() - newremote = "origin" - if upstream != url: - add_remote(git, url) - - tags = git.git_operation("tag", "-l") - if fxtag and fxtag not in tags: - git.git_operation("fetch", newremote, "--tags") - atag = git.git_operation("describe", "--tags", "--always").rstrip() - if fxtag and fxtag != atag: - try: - git.git_operation("checkout", fxtag) - print(f"{name:>20} updated to {fxtag}") - except Exception as error: - print(error) - elif not fxtag: - print(f"No fxtag found for submodule {name:>20}") - else: - print(f"{name:>20} up to date.") - + if "Optional" in fxrequired and "Optional" not in requiredlist: + if fxrequired.startswith("Always"): + print(f"Skipping optional component {name:>20}") + continue + optional = "AlwaysOptional" in requiredlist + if fxrequired in requiredlist: + submod.update() + repodir = os.path.join(root_dir, submod.path) + if os.path.exists(os.path.join(repodir, ".gitmodules")): + # recursively handle this checkout + print(f"Recursively checking out submodules of {name}") + gitsubmodules = GitModules(submod.logger, confpath=repodir) + newrequiredlist = ["AlwaysRequired"] + if optional: + newrequiredlist.append("AlwaysOptional") + submodules_update(gitsubmodules, repodir, newrequiredlist, force=force) def local_mods_output(): text = """\ @@ -469,62 +266,6 @@ def local_mods_output(): """ print(text) - -# checkout is done by update if required so this function may be depricated -def submodules_checkout(gitmodules, root_dir, requiredlist, force=False): - """ - This function checks out all git submodules based on the provided parameters. - - Parameters: - gitmodules (ConfigParser): The gitmodules configuration. - root_dir (str): The root directory for the git operation. - requiredlist (list): The list of required modules. - force (bool, optional): If set to True, forces the checkout operation. Defaults to False. - - Returns: - None - """ - # function implementation... - print("") - _, localmods, needsupdate = submodules_status(gitmodules, root_dir) - if localmods and not force: - local_mods_output() - return - if not needsupdate: - return - for name in gitmodules.sections(): - fxrequired = gitmodules.get(name, "fxrequired") - fxsparse = gitmodules.get(name, "fxsparse") - fxtag = gitmodules.get(name, "fxtag") - path = gitmodules.get(name, "path") - url = gitmodules.get(name, "url") - if fxrequired and fxrequired not in requiredlist: - if "Optional" in fxrequired: - print("Skipping optional component {}".format(name)) - continue - - if fxsparse: - logger.debug( - "Callng submodule_sparse_checkout({}, {}, {}, {}, {}, {}".format( - root_dir, name, url, path, fxsparse, fxtag - ) - ) - submodule_sparse_checkout(root_dir, name, url, path, fxsparse, tag=fxtag) - else: - logger.debug( - "Calling submodule_checkout({},{},{})".format(root_dir, name, path) - ) - single_submodule_checkout( - root_dir, - name, - path, - url=url, - tag=fxtag, - force=force, - optional="AlwaysOptional" in requiredlist, - ) - - def submodules_test(gitmodules, root_dir): """ This function tests the git submodules based on the provided parameters. @@ -547,7 +288,7 @@ def submodules_test(gitmodules, root_dir): # and that sparse checkout files exist for name in gitmodules.sections(): url = gitmodules.get(name, "url") - fxurl = gitmodules.get(name, "fxDONOTMODIFYurl") + fxurl = gitmodules.get(name, "fxDONOTUSEurl") fxsparse = gitmodules.get(name, "fxsparse") path = gitmodules.get(name, "path") fxurl = fxurl[:-4] if fxurl.endswith(".git") else fxurl @@ -601,7 +342,7 @@ def main(): excludelist=excludelist, ) if not gitmodules.sections(): - sys.exit("No submodule components found") + sys.exit(f"No submodule components found, root_dir={root_dir}") retval = 0 if action == "update": submodules_update(gitmodules, root_dir, fxrequired, force) diff --git a/.lib/git-fleximod/git_fleximod/gitinterface.py b/.lib/git-fleximod/git_fleximod/gitinterface.py index 93ae38ecde..fb20883cd0 100644 --- a/.lib/git-fleximod/git_fleximod/gitinterface.py +++ b/.lib/git-fleximod/git_fleximod/gitinterface.py @@ -49,20 +49,31 @@ def _init_git_repo(self): # pylint: disable=unused-argument def git_operation(self, operation, *args, **kwargs): - command = self._git_command(operation, *args) - self.logger.info(command) + newargs = [] + for a in args: + # Do not use ssh interface + if isinstance(a, str): + a = a.replace("git@github.com:", "https://github.com/") + newargs.append(a) + + command = self._git_command(operation, *newargs) if isinstance(command, list): try: - return utils.execute_subprocess(command, output_to_caller=True) + status, output = utils.execute_subprocess(command, status_to_caller=True, output_to_caller=True) + return status, output.rstrip() except Exception as e: sys.exit(e) else: - return command + return 0, command def config_get_value(self, section, name): if self._use_module: config = self.repo.config_reader() - return config.get_value(section, name) + try: + val = config.get_value(section, name) + except: + val = None + return val else: cmd = ("git", "-C", str(self.repo_path), "config", "--get", f"{section}.{name}") output = utils.execute_subprocess(cmd, output_to_caller=True) @@ -71,6 +82,8 @@ def config_get_value(self, section, name): def config_set_value(self, section, name, value): if self._use_module: with self.repo.config_writer() as writer: + if "." in section: + section = section.replace("."," \"")+'"' writer.set_value(section, name, value) writer.release() # Ensure changes are saved else: diff --git a/.lib/git-fleximod/git_fleximod/gitmodules.py b/.lib/git-fleximod/git_fleximod/gitmodules.py index 7e4e05394a..cf8b350dd6 100644 --- a/.lib/git-fleximod/git_fleximod/gitmodules.py +++ b/.lib/git-fleximod/git_fleximod/gitmodules.py @@ -1,4 +1,4 @@ -import shutil +import shutil, os from pathlib import Path from configparser import RawConfigParser, ConfigParser from .lstripreader import LstripReader diff --git a/.lib/git-fleximod/git_fleximod/submodule.py b/.lib/git-fleximod/git_fleximod/submodule.py new file mode 100644 index 0000000000..75d9dd4eb9 --- /dev/null +++ b/.lib/git-fleximod/git_fleximod/submodule.py @@ -0,0 +1,427 @@ +import os +import textwrap +import shutil +import string +from configparser import NoOptionError +from git_fleximod import utils +from git_fleximod.gitinterface import GitInterface + +class Submodule(): + """ + Represents a Git submodule with enhanced features for flexible management. + + Attributes: + name (str): The name of the submodule. + root_dir (str): The root directory of the main project. + path (str): The relative path from the root directory to the submodule. + url (str): The URL of the submodule repository. + fxurl (str): The URL for flexible submodule management (optional). + fxtag (str): The tag for flexible submodule management (optional). + fxsparse (str): Path to the sparse checkout file relative to the submodule path, see git-sparse-checkout for details (optional). + fxrequired (str): Indicates if the submodule is optional or required (optional). + logger (logging.Logger): Logger instance for logging (optional). + """ + def __init__(self, root_dir, name, path, url, fxtag=None, fxurl=None, fxsparse=None, fxrequired=None, logger=None): + """ + Initializes a new Submodule instance with the provided attributes. + """ + self.name = name + self.root_dir = root_dir + self.path = path + self.url = url + self.fxurl = fxurl + self.fxtag = fxtag + self.fxsparse = fxsparse + if fxrequired: + self.fxrequired = fxrequired + else: + self.fxrequired = "AlwaysRequired" + self.logger = logger + + def status(self): + """ + Checks the status of the submodule and returns 4 parameters: + - result (str): The status of the submodule. + - needsupdate (bool): An indicator if the submodule needs to be updated. + - localmods (bool): An indicator if the submodule has local modifications. + - testfails (bool): An indicator if the submodule has failed a test, this is used for testing purposes. + """ + + smpath = os.path.join(self.root_dir, self.path) + testfails = False + localmods = False + needsupdate = False + ahash = None + optional = "" + if "Optional" in self.fxrequired: + optional = " (optional)" + required = None + level = None + if not os.path.exists(os.path.join(smpath, ".git")): + rootgit = GitInterface(self.root_dir, self.logger) + # submodule commands use path, not name + status, tags = rootgit.git_operation("ls-remote", "--tags", self.url) + status, result = rootgit.git_operation("submodule","status",smpath) + result = result.split() + + if result: + ahash = result[0][1:] + hhash = None + atag = None + for htag in tags.split("\n"): + if htag.endswith('^{}'): + htag = htag[:-3] + if ahash and not atag and ahash in htag: + atag = (htag.split()[1])[10:] + if self.fxtag and not hhash and htag.endswith(self.fxtag): + hhash = htag.split()[0] + if hhash and atag: + break + if self.fxtag and (ahash == hhash or atag == self.fxtag): + result = f"e {self.name:>20} not checked out, aligned at tag {self.fxtag}{optional}" + needsupdate = True + elif self.fxtag: + status, ahash = rootgit.git_operation( + "submodule", "status", "{}".format(self.path) + ) + ahash = ahash[1 : len(self.fxtag) + 1] + if self.fxtag == ahash: + result = f"e {self.name:>20} not checked out, aligned at hash {ahash}{optional}" + else: + result = f"e {self.name:>20} not checked out, out of sync at tag {atag}, expected tag is {self.fxtag}{optional}" + testfails = True + needsupdate = True + else: + result = f"e {self.name:>20} has no fxtag defined in .gitmodules{optional}" + testfails = False + else: + with utils.pushd(smpath): + git = GitInterface(smpath, self.logger) + status, remote = git.git_operation("remote") + if remote == '': + result = f"e {self.name:>20} has no associated remote" + testfails = True + needsupdate = True + return result, needsupdate, localmods, testfails + status, rurl = git.git_operation("ls-remote","--get-url") + status, lines = git.git_operation("log", "--pretty=format:\"%h %d\"") + line = lines.partition('\n')[0] + parts = line.split() + ahash = parts[0][1:] + atag = None + if len(parts) > 3: + idx = 0 + while idx < len(parts)-1: + idx = idx+1 + if parts[idx] == 'tag:': + atag = parts[idx+1] + while atag.endswith(')') or atag.endswith(',') or atag.endswith("\""): + atag = atag[:-1] + if atag == self.fxtag: + break + + + #print(f"line is {line} ahash is {ahash} atag is {atag} {parts}") + # atag = git.git_operation("describe", "--tags", "--always") + # ahash = git.git_operation("rev-list", "HEAD").partition("\n")[0] + + recurse = False + if rurl != self.url: + remote = self._add_remote(git) + git.git_operation("fetch", remote) + if self.fxtag and atag == self.fxtag: + result = f" {self.name:>20} at tag {self.fxtag}" + recurse = True + testfails = False + elif self.fxtag and (ahash[: len(self.fxtag)] == self.fxtag or (self.fxtag.find(ahash)==0)): + result = f" {self.name:>20} at hash {ahash}" + recurse = True + testfails = False + elif atag == ahash: + result = f" {self.name:>20} at hash {ahash}" + recurse = True + elif self.fxtag: + result = f"s {self.name:>20} {atag} {ahash} is out of sync with .gitmodules {self.fxtag}" + testfails = True + needsupdate = True + else: + if atag: + result = f"e {self.name:>20} has no fxtag defined in .gitmodules, module at {atag}" + else: + result = f"e {self.name:>20} has no fxtag defined in .gitmodules, module at {ahash}" + testfails = False + + status, output = git.git_operation("status", "--ignore-submodules", "-uno") + if "nothing to commit" not in output: + localmods = True + result = "M" + textwrap.indent(output, " ") +# print(f"result {result} needsupdate {needsupdate} localmods {localmods} testfails {testfails}") + return result, needsupdate, localmods, testfails + + + def _add_remote(self, git): + """ + Adds a new remote to the submodule if it does not already exist. + + This method checks the existing remotes of the submodule. If the submodule's URL is not already listed as a remote, + it attempts to add a new remote. The name for the new remote is generated dynamically to avoid conflicts. If no + remotes exist, it defaults to naming the new remote 'origin'. + + Args: + git (GitInterface): An instance of GitInterface to perform git operations. + + Returns: + str: The name of the new remote if added, or the name of the existing remote that matches the submodule's URL. + """ + status, remotes = git.git_operation("remote", "-v") + remotes = remotes.splitlines() + upstream = None + if remotes: + status, upstream = git.git_operation("ls-remote", "--get-url") + newremote = "newremote.00" + tmpurl = self.url.replace("git@github.com:", "https://github.com/") + line = next((s for s in remotes if self.url in s or tmpurl in s), None) + if line: + newremote = line.split()[0] + return newremote + else: + i = 0 + while newremote in remotes: + i = i + 1 + newremote = f"newremote.{i:02d}" + else: + newremote = "origin" + git.git_operation("remote", "add", newremote, self.url) + return newremote + + def toplevel(self): + """ + Returns True if the submodule is Toplevel (either Required or Optional) + """ + return True if "Top" in self.fxrequired else False + + def sparse_checkout(self): + """ + Performs a sparse checkout of the submodule. + + This method optimizes the checkout process by only checking out files specified in the submodule's sparse-checkout configuration, + rather than the entire submodule content. It achieves this by first ensuring the `.git/info/sparse-checkout` file is created and + configured in the submodule's directory. Then, it proceeds to checkout the desired tag. If the submodule has already been checked out, + this method will not perform the checkout again. + + This approach is particularly beneficial for submodules with a large number of files, as it significantly reduces the time and disk space + required for the checkout process by avoiding the unnecessary checkout and subsequent removal of unneeded files. + + Returns: + None + """ + self.logger.info("Called sparse_checkout for {}".format(self.name)) + rgit = GitInterface(self.root_dir, self.logger) + status, superroot = rgit.git_operation("rev-parse", "--show-superproject-working-tree") + if superroot: + gitroot = superroot.strip() + else: + gitroot = self.root_dir + # Now need to move the .git dir to the submodule location + rootdotgit = os.path.join(self.root_dir, ".git") + while os.path.isfile(rootdotgit): + with open(rootdotgit) as f: + line = f.readline().rstrip() + if line.startswith("gitdir: "): + rootdotgit = os.path.abspath(os.path.join(self.root_dir,line[8:])) + assert os.path.isdir(rootdotgit) + # first create the module directory + if not os.path.isdir(os.path.join(self.root_dir, self.path)): + os.makedirs(os.path.join(self.root_dir, self.path)) + + # initialize a new git repo and set the sparse checkout flag + sprep_repo = os.path.join(self.root_dir, self.path) + sprepo_git = GitInterface(sprep_repo, self.logger) + if os.path.exists(os.path.join(sprep_repo, ".git")): + try: + self.logger.info("Submodule {} found".format(self.name)) + chk = sprepo_git.config_get_value("core", "sparseCheckout") + if chk == "true": + self.logger.info("Sparse submodule {} already checked out".format(self.name)) + return + except (NoOptionError): + self.logger.debug("Sparse submodule {} not present".format(self.name)) + except Exception as e: + utils.fatal_error("Unexpected error {} occured.".format(e)) + + sprepo_git.config_set_value("core", "sparseCheckout", "true") + + # set the repository remote + + self.logger.info("Setting remote origin in {}/{}".format(self.root_dir, self.path)) + status, remotes = sprepo_git.git_operation("remote", "-v") + if self.url not in remotes: + sprepo_git.git_operation("remote", "add", "origin", self.url) + + topgit = os.path.join(gitroot, ".git") + + if gitroot != self.root_dir and os.path.isfile(os.path.join(self.root_dir, ".git")): + with open(os.path.join(self.root_dir, ".git")) as f: + gitpath = os.path.relpath( + os.path.join(self.root_dir, f.read().split()[1]), + start=os.path.join(self.root_dir, self.path), + ) + rootdotgit = os.path.join(gitpath, "modules", self.name) + else: + rootdotgit = os.path.relpath( + os.path.join(self.root_dir, ".git", "modules", self.name), + start=os.path.join(self.root_dir, self.path), + ) + + if os.path.isdir(os.path.join(self.root_dir, self.path, ".git")): + with utils.pushd(sprep_repo): + if os.path.isdir(os.path.join(rootdotgit,".git")): + shutil.rmtree(os.path.join(rootdotgit,".git")) + shutil.move(".git", rootdotgit) + with open(".git", "w") as f: + f.write("gitdir: " + os.path.relpath(rootdotgit)) + infodir = os.path.join(rootdotgit, "info") + if not os.path.isdir(infodir): + os.makedirs(infodir) + gitsparse = os.path.abspath(os.path.join(infodir, "sparse-checkout")) + if os.path.isfile(gitsparse): + self.logger.warning( + "submodule {} is already initialized {}".format(self.name, rootdotgit) + ) + return + + with utils.pushd(sprep_repo): + if os.path.isfile(self.fxsparse): + + shutil.copy(self.fxsparse, gitsparse) + + + # Finally checkout the repo + sprepo_git.git_operation("fetch", "origin", "--tags") + status,_ = sprepo_git.git_operation("checkout", self.fxtag) + if status: + print(f"Error checking out {self.name:>20} at {self.fxtag}") + else: + print(f"Successfully checked out {self.name:>20} at {self.fxtag}") + rgit.config_set_value('submodule.' + self.name, "active", "true") + rgit.config_set_value('submodule.' + self.name, "url", self.url) + rgit.config_set_value('submodule.' + self.name, "path", self.path) + + def update(self): + """ + Updates the submodule to the latest or specified version. + + This method handles the update process of the submodule, including checking out the submodule into the specified path, + handling sparse checkouts if configured, and updating the submodule's URL if necessary. It supports both SSH and HTTPS URLs, + automatically converting SSH URLs to HTTPS to avoid issues for users without SSH keys. + + The update process involves the following steps: + 1. If the submodule is configured for sparse checkout, it performs a sparse checkout. + 2. If the submodule is not already checked out, it clones the submodule using the provided URL. + 3. If a specific tag or hash is provided, it checks out that tag; otherwise, it checks out the latest version. + 4. If the root `.git` is a file (indicating a submodule or a worktree), additional steps are taken to integrate the submodule properly. + + Args: + None + Note: + - SSH URLs are automatically converted to HTTPS to accommodate users without SSH keys. + + Returns: + None + """ + git = GitInterface(self.root_dir, self.logger) + repodir = os.path.join(self.root_dir, self.path) + self.logger.info("Checkout {} into {}/{}".format(self.name, self.root_dir, self.path)) + # if url is provided update to the new url + tag = None + repo_exists = False + if os.path.exists(os.path.join(repodir, ".git")): + self.logger.info("Submodule {} already checked out".format(self.name)) + repo_exists = True + # Look for a .gitmodules file in the newly checkedout repo + if self.fxsparse: + print(f"Sparse checkout {self.name} fxsparse {self.fxsparse}") + self.sparse_checkout() + else: + if not repo_exists and self.url: + # ssh urls cause problems for those who dont have git accounts with ssh keys defined + # but cime has one since e3sm prefers ssh to https, because the .gitmodules file was + # opened with a GitModules object we don't need to worry about restoring the file here + # it will be done by the GitModules class + if self.url.startswith("git@"): + git.git_operation("clone", self.url, self.path) + smgit = GitInterface(repodir, self.logger) + if not tag: + status, tag = smgit.git_operation("describe", "--tags", "--always") + smgit.git_operation("checkout", tag) + # Now need to move the .git dir to the submodule location + rootdotgit = os.path.join(self.root_dir, ".git") + if os.path.isfile(rootdotgit): + with open(rootdotgit) as f: + line = f.readline() + if line.startswith("gitdir: "): + rootdotgit = line[8:] + + newpath = os.path.abspath(os.path.join(self.root_dir, rootdotgit, "modules", self.name)) + if os.path.exists(newpath): + shutil.rmtree(os.path.join(repodir, ".git")) + else: + shutil.move(os.path.join(repodir, ".git"), newpath) + + with open(os.path.join(repodir, ".git"), "w") as f: + f.write("gitdir: " + os.path.relpath(newpath, start=repodir)) + + if not os.path.exists(repodir): + parent = os.path.dirname(repodir) + if not os.path.isdir(parent): + os.makedirs(parent) + git.git_operation("submodule", "add", "--name", self.name, "--", self.url, self.path) + + if not repo_exists: + git.git_operation("submodule", "update", "--init", "--", self.path) + + if self.fxtag: + smgit = GitInterface(repodir, self.logger) + newremote = self._add_remote(smgit) + # Trying to distingush a tag from a hash + allowed = set(string.digits + 'abcdef') + if not set(self.fxtag) <= allowed: + # This is a tag + tag = f"refs/tags/{self.fxtag}:refs/tags/{self.fxtag}" + smgit.git_operation("fetch", newremote, tag) + smgit.git_operation("checkout", self.fxtag) + + if not os.path.exists(os.path.join(repodir, ".git")): + utils.fatal_error( + f"Failed to checkout {self.name} {repo_exists} {repodir} {self.path}" + ) + + + if os.path.exists(os.path.join(self.path, ".git")): + submoddir = os.path.join(self.root_dir, self.path) + with utils.pushd(submoddir): + git = GitInterface(submoddir, self.logger) + # first make sure the url is correct + newremote = self._add_remote(git) + status, tags = git.git_operation("tag", "-l") + fxtag = self.fxtag + if fxtag and fxtag not in tags: + git.git_operation("fetch", newremote, "--tags") + status, atag = git.git_operation("describe", "--tags", "--always") + if fxtag and fxtag != atag: + try: + status, _ = git.git_operation("checkout", fxtag) + if not status: + print(f"{self.name:>20} updated to {fxtag}") + except Exception as error: + print(error) + + + elif not fxtag: + print(f"No fxtag found for submodule {self.name:>20}") + else: + print(f"{self.name:>20} up to date.") + + + + return diff --git a/.lib/git-fleximod/git_fleximod/utils.py b/.lib/git-fleximod/git_fleximod/utils.py index 1a2d5ccf2f..c4f43d5238 100644 --- a/.lib/git-fleximod/git_fleximod/utils.py +++ b/.lib/git-fleximod/git_fleximod/utils.py @@ -307,12 +307,12 @@ def execute_subprocess(commands, status_to_caller=False, output_to_caller=False) # simple status check. If returning, it is the callers # responsibility determine if an error occurred and handle it # appropriately. + msg_context = ( + "Process did not run successfully; " + "returned status {0}".format(error.returncode) + ) + msg = failed_command_msg(msg_context, commands, output=error.output) if not return_to_caller: - msg_context = ( - "Process did not run successfully; " - "returned status {0}".format(error.returncode) - ) - msg = failed_command_msg(msg_context, commands, output=error.output) logging.error(error) logging.error(msg) log_process_output(error.output) diff --git a/.lib/git-fleximod/poetry.lock b/.lib/git-fleximod/poetry.lock index b59ed3942c..ac82fb0d97 100644 --- a/.lib/git-fleximod/poetry.lock +++ b/.lib/git-fleximod/poetry.lock @@ -13,13 +13,13 @@ files = [ [[package]] name = "babel" -version = "2.14.0" +version = "2.15.0" description = "Internationalization utilities" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "Babel-2.14.0-py3-none-any.whl", hash = "sha256:efb1a25b7118e67ce3a259bed20545c29cb68be8ad2c784c83689981b7a57287"}, - {file = "Babel-2.14.0.tar.gz", hash = "sha256:6919867db036398ba21eb5c7a0f6b28ab8cbc3ae7a73a44ebe34ae74a4e7d363"}, + {file = "Babel-2.15.0-py3-none-any.whl", hash = "sha256:08706bdad8d0a3413266ab61bd6c34d0c28d6e1e7badf40a2cebe67644e2e1fb"}, + {file = "babel-2.15.0.tar.gz", hash = "sha256:8daf0e265d05768bc6c7a314cf1321e9a123afc328cc635c18622a2f30a04413"}, ] [package.dependencies] @@ -30,13 +30,13 @@ dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] [[package]] name = "certifi" -version = "2024.2.2" +version = "2024.8.30" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, - {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, + {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, + {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, ] [[package]] @@ -162,13 +162,13 @@ files = [ [[package]] name = "exceptiongroup" -version = "1.2.0" +version = "1.2.1" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, - {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, + {file = "exceptiongroup-1.2.1-py3-none-any.whl", hash = "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad"}, + {file = "exceptiongroup-1.2.1.tar.gz", hash = "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16"}, ] [package.extras] @@ -225,30 +225,31 @@ smmap = ">=3.0.1,<6" [[package]] name = "gitpython" -version = "3.1.41" +version = "3.1.43" description = "GitPython is a Python library used to interact with Git repositories" optional = false python-versions = ">=3.7" files = [ - {file = "GitPython-3.1.41-py3-none-any.whl", hash = "sha256:c36b6634d069b3f719610175020a9aed919421c87552185b085e04fbbdb10b7c"}, - {file = "GitPython-3.1.41.tar.gz", hash = "sha256:ed66e624884f76df22c8e16066d567aaa5a37d5b5fa19db2c6df6f7156db9048"}, + {file = "GitPython-3.1.43-py3-none-any.whl", hash = "sha256:eec7ec56b92aad751f9912a73404bc02ba212a23adb2c7098ee668417051a1ff"}, + {file = "GitPython-3.1.43.tar.gz", hash = "sha256:35f314a9f878467f5453cc1fee295c3e18e52f1b99f10f6cf5b1682e968a9e7c"}, ] [package.dependencies] gitdb = ">=4.0.1,<5" [package.extras] -test = ["black", "coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock", "mypy", "pre-commit", "pytest (>=7.3.1)", "pytest-cov", "pytest-instafail", "pytest-mock", "pytest-sugar", "sumtypes"] +doc = ["sphinx (==4.3.2)", "sphinx-autodoc-typehints", "sphinx-rtd-theme", "sphinxcontrib-applehelp (>=1.0.2,<=1.0.4)", "sphinxcontrib-devhelp (==1.0.2)", "sphinxcontrib-htmlhelp (>=2.0.0,<=2.0.1)", "sphinxcontrib-qthelp (==1.0.3)", "sphinxcontrib-serializinghtml (==1.1.5)"] +test = ["coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock", "mypy", "pre-commit", "pytest (>=7.3.1)", "pytest-cov", "pytest-instafail", "pytest-mock", "pytest-sugar", "typing-extensions"] [[package]] name = "idna" -version = "3.6" +version = "3.7" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.5" files = [ - {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, - {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, + {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, + {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, ] [[package]] @@ -264,22 +265,22 @@ files = [ [[package]] name = "importlib-metadata" -version = "7.0.1" +version = "8.0.0" description = "Read metadata from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_metadata-7.0.1-py3-none-any.whl", hash = "sha256:4805911c3a4ec7c3966410053e9ec6a1fecd629117df5adee56dfc9432a1081e"}, - {file = "importlib_metadata-7.0.1.tar.gz", hash = "sha256:f238736bb06590ae52ac1fab06a3a9ef1d8dce2b7a35b5ab329371d6c8f5d2cc"}, + {file = "importlib_metadata-8.0.0-py3-none-any.whl", hash = "sha256:15584cf2b1bf449d98ff8a6ff1abef57bf20f3ac6454f431736cd3e660921b2f"}, + {file = "importlib_metadata-8.0.0.tar.gz", hash = "sha256:188bd24e4c346d3f0a933f275c2fec67050326a856b9a359881d7c2a697e8812"}, ] [package.dependencies] zipp = ">=0.5" [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] perf = ["ipython"] -testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] +test = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-perf (>=0.9.2)", "pytest-ruff (>=0.2.1)"] [[package]] name = "iniconfig" @@ -294,13 +295,13 @@ files = [ [[package]] name = "jinja2" -version = "3.1.3" +version = "3.1.4" description = "A very fast and expressive template engine." optional = false python-versions = ">=3.7" files = [ - {file = "Jinja2-3.1.3-py3-none-any.whl", hash = "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa"}, - {file = "Jinja2-3.1.3.tar.gz", hash = "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90"}, + {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, + {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, ] [package.dependencies] @@ -380,24 +381,24 @@ files = [ [[package]] name = "packaging" -version = "23.2" +version = "24.1" description = "Core utilities for Python packages" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, - {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, + {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, + {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, ] [[package]] name = "pluggy" -version = "1.4.0" +version = "1.5.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" files = [ - {file = "pluggy-1.4.0-py3-none-any.whl", hash = "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981"}, - {file = "pluggy-1.4.0.tar.gz", hash = "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be"}, + {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, + {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, ] [package.extras] @@ -406,39 +407,38 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "pyfakefs" -version = "5.3.5" +version = "5.5.0" description = "pyfakefs implements a fake file system that mocks the Python file system modules." optional = false python-versions = ">=3.7" files = [ - {file = "pyfakefs-5.3.5-py3-none-any.whl", hash = "sha256:751015c1de94e1390128c82b48cdedc3f088bbdbe4bc713c79d02a27f0f61e69"}, - {file = "pyfakefs-5.3.5.tar.gz", hash = "sha256:7cdc500b35a214cb7a614e1940543acc6650e69a94ac76e30f33c9373bd9cf90"}, + {file = "pyfakefs-5.5.0-py3-none-any.whl", hash = "sha256:8dbf203ab7bef1529f11f7d41b9478b898e95bf9f3b71262163aac07a518cd76"}, + {file = "pyfakefs-5.5.0.tar.gz", hash = "sha256:7448aaa07142f892d0a4eb52a5ed3206a9f02c6599e686cd97d624c18979c154"}, ] [[package]] name = "pygments" -version = "2.17.2" +version = "2.18.0" description = "Pygments is a syntax highlighting package written in Python." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"}, - {file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"}, + {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, + {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, ] [package.extras] -plugins = ["importlib-metadata"] windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pytest" -version = "8.0.0" +version = "8.2.2" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" files = [ - {file = "pytest-8.0.0-py3-none-any.whl", hash = "sha256:50fb9cbe836c3f20f0dfa99c565201fb75dc54c8d76373cd1bde06b06657bdb6"}, - {file = "pytest-8.0.0.tar.gz", hash = "sha256:249b1b0864530ba251b7438274c4d251c58d868edaaec8762893ad4a0d71c36c"}, + {file = "pytest-8.2.2-py3-none-any.whl", hash = "sha256:c434598117762e2bd304e526244f67bf66bbd7b5d6cf22138be51ff661980343"}, + {file = "pytest-8.2.2.tar.gz", hash = "sha256:de4bb8104e201939ccdc688b27a89a7be2079b22e2bd2b07f806b6ba71117977"}, ] [package.dependencies] @@ -446,11 +446,11 @@ colorama = {version = "*", markers = "sys_platform == \"win32\""} exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} iniconfig = "*" packaging = "*" -pluggy = ">=1.3.0,<2.0" -tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} +pluggy = ">=1.5,<2.0" +tomli = {version = ">=1", markers = "python_version < \"3.11\""} [package.extras] -testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] +dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] [[package]] name = "pytz" @@ -465,13 +465,13 @@ files = [ [[package]] name = "requests" -version = "2.31.0" +version = "2.32.3" description = "Python HTTP for Humans." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, - {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, + {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, + {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, ] [package.dependencies] @@ -643,13 +643,13 @@ files = [ [[package]] name = "urllib3" -version = "2.2.0" +version = "2.2.2" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.8" files = [ - {file = "urllib3-2.2.0-py3-none-any.whl", hash = "sha256:ce3711610ddce217e6d113a2732fafad960a03fd0318c91faa79481e35c11224"}, - {file = "urllib3-2.2.0.tar.gz", hash = "sha256:051d961ad0c62a94e50ecf1af379c3aba230c66c710493493560c0c223c49f20"}, + {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"}, + {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"}, ] [package.extras] @@ -674,18 +674,18 @@ test = ["pytest (>=6.0.0)", "setuptools (>=65)"] [[package]] name = "zipp" -version = "3.17.0" +version = "3.19.2" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.8" files = [ - {file = "zipp-3.17.0-py3-none-any.whl", hash = "sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31"}, - {file = "zipp-3.17.0.tar.gz", hash = "sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0"}, + {file = "zipp-3.19.2-py3-none-any.whl", hash = "sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c"}, + {file = "zipp-3.19.2.tar.gz", hash = "sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] [metadata] lock-version = "2.0" diff --git a/.lib/git-fleximod/pyproject.toml b/.lib/git-fleximod/pyproject.toml index 5b1332549c..1d0419ad20 100644 --- a/.lib/git-fleximod/pyproject.toml +++ b/.lib/git-fleximod/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "git-fleximod" -version = "0.7.8" +version = "0.9.3" description = "Extended support for git-submodule and git-sparse-checkout" authors = ["Jim Edwards "] maintainers = ["Jim Edwards "] diff --git a/.lib/git-fleximod/tbump.toml b/.lib/git-fleximod/tbump.toml index c4f7ac96ea..b432206a54 100644 --- a/.lib/git-fleximod/tbump.toml +++ b/.lib/git-fleximod/tbump.toml @@ -2,7 +2,7 @@ github_url = "https://github.com/jedwards4b/git-fleximod/" [version] -current = "0.7.8" +current = "0.9.3" # Example of a semver regexp. # Make sure this matches current_version before diff --git a/.lib/git-fleximod/tests/conftest.py b/.lib/git-fleximod/tests/conftest.py index 65ee85d23d..1dd1b86f34 100644 --- a/.lib/git-fleximod/tests/conftest.py +++ b/.lib/git-fleximod/tests/conftest.py @@ -32,7 +32,7 @@ def logger(): "submodule_name": "test_optional", "status1" : "test_optional MPIserial_2.5.0-3-gd82ce7c is out of sync with .gitmodules MPIserial_2.4.0", "status2" : "test_optional at tag MPIserial_2.4.0", - "status3" : "test_optional not checked out, out of sync at tag None, expected tag is MPIserial_2.4.0 (optional)", + "status3" : "test_optional not checked out, out of sync at tag MPIserial_2.5.1, expected tag is MPIserial_2.4.0 (optional)", "status4" : "test_optional at tag MPIserial_2.4.0", "gitmodules_content": """ [submodule "test_optional"] @@ -46,7 +46,7 @@ def logger(): "submodule_name": "test_alwaysoptional", "status1" : "test_alwaysoptional MPIserial_2.3.0 is out of sync with .gitmodules e5cf35c", "status2" : "test_alwaysoptional at hash e5cf35c", - "status3" : "out of sync at tag None, expected tag is e5cf35c", + "status3" : "out of sync at tag MPIserial_2.5.1, expected tag is e5cf35c", "status4" : "test_alwaysoptional at hash e5cf35c", "gitmodules_content": """ [submodule "test_alwaysoptional"] @@ -119,8 +119,20 @@ def complex_repo(tmp_path, logger): str_path = str(test_dir) gitp = GitInterface(str_path, logger) gitp.git_operation("remote", "add", "origin", "https://github.com/jedwards4b/fleximod-test2") - gitp.git_operation("fetch", "origin", "main") - gitp.git_operation("checkout", "main") + gitp.git_operation("fetch", "origin") + gitp.git_operation("checkout", "v0.0.1") + return test_dir + +@pytest.fixture +def complex_update(tmp_path, logger): + test_dir = tmp_path / "testcomplex" + test_dir.mkdir() + str_path = str(test_dir) + gitp = GitInterface(str_path, logger) + gitp.git_operation("remote", "add", "origin", "https://github.com/jedwards4b/fleximod-test2") + gitp.git_operation("fetch", "origin") + gitp.git_operation("checkout", "v0.0.2") + return test_dir @pytest.fixture diff --git a/.lib/git-fleximod/tests/test_e_complex_update.py b/.lib/git-fleximod/tests/test_e_complex_update.py new file mode 100644 index 0000000000..0c3ab4c6a6 --- /dev/null +++ b/.lib/git-fleximod/tests/test_e_complex_update.py @@ -0,0 +1,69 @@ +import pytest +from pathlib import Path +from git_fleximod.gitinterface import GitInterface + +def test_complex_update(git_fleximod, complex_update, logger): + status = git_fleximod(complex_update, "status") + assert("ToplevelOptional not checked out, aligned at tag v5.3.2" in status.stdout) + assert("ToplevelRequired not checked out, aligned at tag MPIserial_2.5.0" in status.stdout) + assert("AlwaysRequired not checked out, aligned at tag MPIserial_2.4.0" in status.stdout) + assert("Complex not checked out, out of sync at tag testtag02, expected tag is testtag3" in status.stdout) + assert("AlwaysOptional not checked out, out of sync at tag None, expected tag is MPIserial_2.3.0" in status.stdout) + + # This should checkout and update test_submodule and complex_sub + result = git_fleximod(complex_update, "update") + assert result.returncode == 0 + + status = git_fleximod(complex_update, "status") + assert("ToplevelOptional not checked out, aligned at tag v5.3.2" in status.stdout) + assert("ToplevelRequired at tag MPIserial_2.5.0" in status.stdout) + assert("AlwaysRequired at tag MPIserial_2.4.0" in status.stdout) + assert("Complex at tag testtag3" in status.stdout) + + # now check the complex_sub + root = (complex_update / "modules" / "complex") + assert(not (root / "libraries" / "gptl" / ".git").exists()) + assert(not (root / "libraries" / "mpi-serial" / ".git").exists()) + assert((root / "modules" / "mpi-serialAR" / ".git").exists()) + assert((root / "modules" / "mpi-serialSAR" / ".git").exists()) + assert(not (root / "modules" / "mpi-serial2" / ".git").exists()) + assert((root / "modules" / "mpi-sparse" / ".git").exists()) + assert((root / "modules" / "mpi-sparse" / "m4").exists()) + assert(not (root / "modules" / "mpi-sparse" / "README").exists()) + + # update a single optional submodule + + result = git_fleximod(complex_update, "update ToplevelOptional") + assert result.returncode == 0 + + status = git_fleximod(complex_update, "status") + assert("ToplevelOptional at tag v5.3.2" in status.stdout) + assert("ToplevelRequired at tag MPIserial_2.5.0" in status.stdout) + assert("AlwaysRequired at tag MPIserial_2.4.0" in status.stdout) + assert("Complex at tag testtag3" in status.stdout) + assert("AlwaysOptional not checked out, out of sync at tag None, expected tag is MPIserial_2.3.0" in status.stdout) + + # Finally update optional + result = git_fleximod(complex_update, "update --optional") + assert result.returncode == 0 + + status = git_fleximod(complex_update, "status") + assert("ToplevelOptional at tag v5.3.2" in status.stdout) + assert("ToplevelRequired at tag MPIserial_2.5.0" in status.stdout) + assert("AlwaysRequired at tag MPIserial_2.4.0" in status.stdout) + assert("Complex at tag testtag3" in status.stdout) + assert("AlwaysOptional at tag MPIserial_2.3.0" in status.stdout) + + # now check the complex_sub + root = (complex_update / "modules" / "complex" ) + assert(not (root / "libraries" / "gptl" / ".git").exists()) + assert(not (root / "libraries" / "mpi-serial" / ".git").exists()) + assert(not (root / "modules" / "mpi-serial" / ".git").exists()) + assert((root / "modules" / "mpi-serialAR" / ".git").exists()) + assert((root / "modules" / "mpi-serialSAR" / ".git").exists()) + assert((root / "modules" / "mpi-sparse" / ".git").exists()) + assert((root / "modules" / "mpi-serial2" / ".git").exists()) + assert((root / "modules" / "mpi-sparse" / "m4").exists()) + assert(not (root / "modules" / "mpi-sparse" / "README").exists()) + + diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index b881cdbfac..07e78952f9 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -71,7 +71,7 @@ REQUIRED OPTIONS (if read they allow user_nl_clm and CLM_BLDNML_OPTS to expand variables [for example to use \$DIN_LOC_ROOT]) (default current directory) - -lnd_frac "domainfile" Land fraction file (the input domain file) (needed for LILAC) + -lnd_frac "domainfile" Land fraction file (the input domain file) (only needed with --lilac option) -res "resolution" Specify horizontal grid. Use nlatxnlon for spectral grids; dlatxdlon for fv grids (dlat and dlon are the grid cell size in degrees for latitude and longitude respectively) @@ -678,6 +678,18 @@ sub setup_cmdl_chk_res { } } +#------------------------------------------------------------------------------- + +sub begins_with +{ + # Arguments: long-string, substring + # For an input long-string check if it starts with the substring + # For example, if a string like NEON_PRISM starts with NEON + return substr($_[0], 0, length($_[1])) eq $_[1]; +} + +#------------------------------------------------------------------------------- + sub setup_cmdl_resolution { my ($opts, $nl_flags, $definition, $defaults, $envxml_ref) = @_; @@ -713,7 +725,7 @@ sub setup_cmdl_resolution { $nl_flags->{'neon'} = ".false."; $nl_flags->{'neonsite'} = ""; if ( $nl_flags->{'res'} eq "CLM_USRDAT" ) { - if ( $opts->{'clm_usr_name'} eq "NEON" ) { + if ( begins_with($opts->{'clm_usr_name'}, "NEON") ) { $nl_flags->{'neon'} = ".true."; $nl_flags->{'neonsite'} = $envxml_ref->{'NEONSITE'}; $log->verbose_message( "This is a NEON site with NEONSITE = " . $nl_flags->{'neonsite'} ); @@ -1989,7 +2001,7 @@ sub setup_logic_lnd_frac { "env variables) AND fatmlndfrac on namelist"); } if ( $opts->{$var} =~ /UNSET/ ) { - $log->fatal_error("-lnd_frac was set as UNSET in the CTSM build-namelist set it with the env variables: LND_DOMAIN_PATH/LND_DOMAIN_FILE."); + $log->fatal_error("-lnd_frac was set as UNSET in the CTSM build-namelist, it's required with the --lilac option"); } my $lnd_frac = SetupTools::expand_xml_var( $opts->{$var}, $envxml_ref); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'fatmlndfrc','val'=>$lnd_frac ); @@ -1999,20 +2011,22 @@ sub setup_logic_lnd_frac { if (defined $nl->get_value('fatmlndfrc')) { # do nothing - use value provided by config_grid.xml and clm.cpl7.template } else { - $log->fatal_error("fatmlndfrc was NOT sent into CLM build-namelist."); + $log->fatal_error("fatmlndfrc was NOT sent into CLM build-namelist, it is required for the --lilac option."); } # # For the NUOPC driver neither lnd_frac nor fatmlndfrc need to be set # - } else { + } elsif ($opts->{'driver'} eq "nuopc" ) { if ( defined($opts->{$var}) ) { if ( $opts->{$var} !~ /UNSET/ ) { - $log->fatal_error("$var should NOT be set for the NUOPC driver as it is unused" ); + $log->fatal_error("$var should NOT be set for the NUOPC driver as it is unused (only used by the --lilac option)" ); } } if ( defined($nl->get_value('fatmlndfrc')) ) { $log->fatal_error("fatmlndfrac should NOT be set in the namelist for the NUOPC driver as it is unused" ); } + } else { + $log->fatal_error("Input --driver type of $opts->{'driver'} is an invalid option. Correct this in xml variable COMP_iINTERFACE in your case" ); } } @@ -2113,7 +2127,7 @@ sub setup_logic_roughness_methods { my $phys = $physv->as_string(); if ( $phys eq "clm4_5" || $phys eq "clm5_0" ) { if ( $var eq "Meier2022" ) { - $log->fatal_error("z0param_method = $var and phys = $phys, but this method has been tested only with clm5_1 and later versions; to use with earlier versions, disable this error, and add Meier2022 parameters to the corresponding params file"); + $log->fatal_error("z0param_method = $var and phys = $phys, but this method has been tested only with clm6_0 and later versions; to use with earlier versions, disable this error, and add Meier2022 parameters to the corresponding params file"); } } } @@ -2588,12 +2602,9 @@ sub setup_logic_initial_conditions { my $finidat = $nl->get_value($var); $nl_flags->{'excess_ice_on_finidat'} = "unknown"; if ( $nl_flags->{'clm_start_type'} =~ /cold/ ) { - if (defined $finidat ) { - $log->warning("setting $var (either explicitly in your user_nl_clm or by doing a hybrid or branch RUN_TYPE)\n is incomptable with using a cold start" . + if (defined $finidat && !&value_is_true(($nl->get_value('use_fates')))) { + $log->fatal_error("setting $var (either explicitly in your user_nl_clm or by doing a hybrid or branch RUN_TYPE)\n is incompatible with using a cold start" . " (by setting CLM_FORCE_COLDSTART=on)." ); - $log->warning("Overridding input $var file with one specifying that this is a cold start from arbitrary initial conditions." ); - my $group = $definition->get_group_name($var); - $nl->set_variable_value($group, $var, "' '" ); } add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, 'val'=>"' '", 'no_abspath'=>1); @@ -2759,9 +2770,8 @@ SIMYR: foreach my $sim_yr ( @sim_years ) { # this check has to be here and not earlier since use_init_interp is set here and hillslope is already set above in setup_logic_hillslope if ( &value_is_true($nl->get_value($useinitvar)) && value_is_true($nl->get_value("use_hillslope")) ) { - $log->warning("WARNING: You have set use_hillslope while $useinitvar is TRUE.\n This means all hillslope columns in a gridcell will read identical values" . - " from initial conditions. If you are sure you want this behaviour:") - } + $log->warning("WARNING: You have set use_hillslope while $useinitvar is TRUE.\n This means all hillslope columns in a gridcell will read identical values from initial conditions, even if the initial conditions (finidat) file has hillslope information. If you are sure you want this behaviour, add -ignore_warnings to CLM_BLDNML_OPTS.") +} } # end initial conditions @@ -3603,17 +3613,6 @@ sub setup_logic_luna { if ( &value_is_true($nl->get_value('lnc_opt') ) && not &value_is_true( $nl_flags->{'use_cn'}) ) { $log->fatal_error("Cannot turn lnc_opt to true when bgc=sp" ); } - my $var = "jmaxb1"; - if ( &value_is_true( $nl_flags->{'use_luna'} ) ) { - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, $var, - 'use_luna'=>$nl_flags->{'use_luna'} ); - } - my $val = $nl->get_value($var); - if ( ! &value_is_true( $nl_flags->{'use_luna'} ) ) { - if ( defined($val) ) { - $log->fatal_error("Cannot set $var when use_luna is NOT on" ); - } - } } #------------------------------------------------------------------------------- @@ -3637,6 +3636,10 @@ sub setup_logic_hillslope { if ( (! &value_is_true($use_hillslope)) && &value_is_true($use_hillslope_routing) ) { $log->fatal_error("Cannot turn on use_hillslope_routing when use_hillslope is off\n" ); } + my $hillslope_file = $nl->get_value('hillslope_file'); + if ( &value_is_true($use_hillslope) && ( ! defined($hillslope_file) ) ) { + $log->fatal_error("You must provide hillslope_file if use_hillslope is .true.\n" ); + } } #------------------------------------------------------------------------------- @@ -4523,8 +4526,6 @@ sub setup_logic_canopyhydrology { # my ($opts, $nl_flags, $definition, $defaults, $nl) = @_; - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'interception_fraction' ); - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'maximum_leaf_wetted_fraction' ); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_clm5_fpi' ); } @@ -4543,7 +4544,6 @@ sub setup_logic_snowpack { add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'wind_dependent_snow_density'); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'snow_overburden_compaction_method'); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'lotmp_snowdensity_method'); - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'upplim_destruct_metamorph'); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'reset_snow'); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'reset_snow_glc'); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'reset_snow_glc_ela'); @@ -4765,8 +4765,6 @@ sub setup_logic_fates { my $fname = remove_leading_and_trailing_quotes( $nl->get_value($var) ); if ( ! defined($nl->get_value($var)) ) { $log->fatal_error("$var is required when use_fates_inventory_init is set" ); - } elsif ( ! -f "$fname" ) { - $log->fatal_error("$fname does NOT point to a valid filename" ); } } } @@ -4797,8 +4795,6 @@ sub setup_logic_fates { my $fname = remove_leading_and_trailing_quotes( $nl->get_value($var) ); if ( ! defined($nl->get_value($var)) ) { $log->fatal_error("$var is required when use_fates_luh is set and use_fates_potentialveg is false" ); - } elsif ( ! -f "$fname" ) { - $log->fatal_error("$var does NOT point to a valid filename" ); } } } @@ -4811,8 +4807,6 @@ sub setup_logic_fates { my $fname = remove_leading_and_trailing_quotes( $nl->get_value($var) ); if ( ! defined($nl->get_value($var)) ) { $log->fatal_error("$var is required when use_fates_luh and use_fates_fixed_biogeog is set" ); - } elsif ( ! -f "$fname" ) { - $log->fatal_error("$var does NOT point to a valid filename" ); } } } @@ -4854,8 +4848,6 @@ sub setup_logic_fates { my $fname = remove_leading_and_trailing_quotes( $nl->get_value($var) ); if ( ! defined($nl->get_value($var)) ) { $log->fatal_error("$var is required when fates_harvest_mode is landuse_timeseries" ); - } elsif ( ! -f "$fname" ) { - $log->fatal_error("$var does NOT point to a valid filename" ); } } } diff --git a/bld/config_files/clm_phys_vers.pm b/bld/config_files/clm_phys_vers.pm index 9ab79ee8b0..bec811b61e 100755 --- a/bld/config_files/clm_phys_vers.pm +++ b/bld/config_files/clm_phys_vers.pm @@ -28,7 +28,7 @@ use bigint; #use warnings; #use diagnostics; -my @version_strings = ("clm4_5", "clm5_0", "clm5_1", "clm6_0"); +my @version_strings = ("clm4_5", "clm5_0", "clm6_0"); #------------------------------------------------------------------------------- @@ -88,7 +88,7 @@ if ( ! defined(caller) && $#ARGV == -1 ) { sub testit { print "unit tester\n"; my %lastv; - my @vers_list = ( "clm4_5", "clm5_0", "clm5_1", "clm6_0" ); + my @vers_list = ( "clm4_5", "clm5_0", "clm6_0" ); foreach my $vers ( @vers_list ) { my $phys = config_files::clm_phys_vers->new($vers); isa_ok($phys, "config_files::clm_phys_vers", "created clm_phys_vers object"); diff --git a/bld/config_files/config_definition_ctsm.xml b/bld/config_files/config_definition_ctsm.xml index e6628b1d94..f37f9a6f4e 100644 --- a/bld/config_files/config_definition_ctsm.xml +++ b/bld/config_files/config_definition_ctsm.xml @@ -5,10 +5,10 @@ -Specifies either clm4_5, clm5_0, clm5_1 (deprecated), or clm6_0 physics +Specifies either clm4_5, clm5_0, or clm6_0 physics clm4_5_CRUv7 clm5_0_cam6.0 -clm5_1_GSWP3v1 clm6_0_GSWP3v1 @@ -200,8 +199,6 @@ attributes from the config_cache.xml file (with keys converted to upper-case). 2.0d00 2.0d00 0.5d00 -0.5d00 -2.0d00 0.5d00 2.0d00 @@ -275,14 +272,6 @@ attributes from the config_cache.xml file (with keys converted to upper-case). >20.0d00 20.0d00 -20.0d00 -20.0d00 -20.0d00 -20.0d00 20.0d00 0.008d00 0.008d00 -0.008d00 -0.008d00 -0.008d00 -0.008d00 0.008d00 .true. -1.0 -0.05 .false. -0.25 -1.0 1 @@ -493,9 +470,6 @@ attributes from the config_cache.xml file (with keys converted to upper-case). 'Slater2017' 'TruncatedAnderson1976' -175.d00 -100.d00 - 0.08d00 .false. @@ -508,7 +482,6 @@ attributes from the config_cache.xml file (with keys converted to upper-case). SwensonLawrence2012 Jordan1991 -Sturm1997 Sturm1997 -lnd/clm2/paramdata/ctsm60_params.c240822.nc -lnd/clm2/paramdata/ctsm51_params.c240814.nc -lnd/clm2/paramdata/clm50_params.c240814.nc -lnd/clm2/paramdata/clm45_params.c240814.nc +lnd/clm2/paramdata/ctsm60_params.c241017.nc +lnd/clm2/paramdata/ctsm51_params.c241017.nc +lnd/clm2/paramdata/clm50_params.c241017.nc +lnd/clm2/paramdata/clm45_params.c241017.nc -lnd/clm2/paramdata/fates_params_api.36.0.0_12pft_c240517.nc +lnd/clm2/paramdata/fates_params_api.36.1.0_14pft_c241003.nc + ZengWang2007 -Meier2022 Meier2022 .true. @@ -605,9 +578,6 @@ attributes from the config_cache.xml file (with keys converted to upper-case). .false. .true. - -0.17 - unset @@ -616,7 +586,6 @@ attributes from the config_cache.xml file (with keys converted to upper-case). .false. 0.d+0 -0.5d00 0.5d00 @@ -630,11 +599,9 @@ attributes from the config_cache.xml file (with keys converted to upper-case). Constant -DependsOnLat DependsOnLat .false. -.true. .true. .false. @@ -752,41 +719,20 @@ attributes from the config_cache.xml file (with keys converted to upper-case). .true. - - -.true. -.true. -.true. -.true. - -.true. - - -.true. - -.true. -.true. + +.true. +.true. + .true. .true. - -.true. .true. - - -.true. -.true. -.true. -.true. - -.true. - - -.true. - -.true. -.true. + .true. .true. - -.true. .true. -.true. .true. .true. @@ -867,10 +786,8 @@ attributes from the config_cache.xml file (with keys converted to upper-case). .false. .false. .false. -.false. -.false. -.false. -.false. +.false. +.false. .false. -hgrid=0.9x1.25 maxpft=79 mask=gx1v7 use_cn=.true. use_crop=.true. irrigate=.false. glc_nex=10 do_transient_pfts=.false. lnd_tuning_mode=clm5_1_GSWP3v1 use_excess_ice=.true. - - + hgrid=0.9x1.25 maxpft=79 mask=gx1v7 use_cn=.true. use_crop=.true. irrigate=.false. glc_nex=10 do_transient_pfts=.false. lnd_tuning_mode=clm6_0_GSWP3v1 use_excess_ice=.true. +mask=gx1v7 use_cn=.true. do_transient_pfts=.false. use_excess_ice=.true. use_crop=.false. irrigate=.false. + +mask=tx2_3v2 use_cn=.true. do_transient_pfts=.false. use_excess_ice=.true. use_crop=.true. irrigate=.false. + hgrid=1.9x2.5 maxpft=79 mask=gx1v7 use_cn=.true. use_crop=.true. irrigate=.true. glc_nec=10 do_transient_pfts=.false. use_excess_ice=.false. -hgrid=0.9x1.25 maxpft=79 mask=gx1v7 use_cn=.true. use_crop=.true. irrigate=.true. glc_nex=10 do_transient_pfts=.false. lnd_tuning_mode=clm5_1_GSWP3v1 use_excess_ice=.true. +hgrid=0.9x1.25 maxpft=79 mask=gx1v7 use_cn=.true. use_crop=.true. irrigate=.true. glc_nex=10 do_transient_pfts=.false. use_excess_ice=.true. hgrid=0.9x1.25 maxpft=79 mask=gx1v7 use_cn=.true. use_crop=.true. irrigate=.true. glc_nex=10 do_transient_pfts=.false. lnd_tuning_mode=clm6_0_GSWP3v1 use_excess_ice=.true. + hgrid="ne30np4.pg3" +>hgrid=ne30np4.pg3 maxpft=79 mask=tx2_3v2 use_cn=.true. use_crop=.true. irrigate=.true. glc_nec=10 do_transient_pfts=.false. use_excess_ice=.true. - -hgrid=0.9x1.25 maxpft=17 mask=gx1v7 use_cn=.false. use_crop=.false. irrigate=.true. glc_nec=10 do_transient_pfts=.false. use_excess_ice=.false. +maxpft=79 mask=gx1v7 use_cn=.true. use_crop=.true. irrigate=.true. glc_nec=10 use_excess_ice=.true. -hgrid=1.9x2.5 maxpft=17 mask=gx1v7 use_cn=.false. use_crop=.false. irrigate=.true. glc_nec=10 do_transient_pfts=.false. use_excess_ice=.false. +hgrid=0.9x1.25 maxpft=79 mask=gx1v7 use_cn=.true. use_crop=.true. irrigate=.true. glc_nec=10 use_excess_ice=.true. hgrid=ne0np4.ARCTICGRIS.ne30x8 maxpft=17 mask=tx0.1v2 use_cn=.false. use_crop=.false. irrigate=.true. glc_nec=10 do_transient_pfts=.false. use_excess_ice=.false. -hgrid=0.9x1.25 maxpft=17 mask=gx1v7 use_cn=.false. use_crop=.false. irrigate=.true. glc_nec=10 do_transient_pfts=.false. use_excess_ice=.false. - - -hgrid=1.9x2.5 maxpft=17 mask=gx1v7 use_cn=.false. use_crop=.false. irrigate=.true. glc_nec=10 do_transient_pfts=.false. use_excess_ice=.false. +maxpft=79 mask=tx2_3v2 use_cn=.true. use_crop=.true. irrigate=.true. glc_nec=10 use_excess_ice=.true. hgrid=ne0np4.ARCTICGRIS.ne30x8 maxpft=17 mask=tx0.1v2 use_cn=.false. use_crop=.false. irrigate=.true. glc_nec=10 do_transient_pfts=.false. use_excess_ice=.false. - -hgrid=1.9x2.5 maxpft=17 mask=gx1v7 use_cn=.false. use_crop=.false. irrigate=.true. glc_nec=10 do_transient_pfts=.false. use_excess_ice=.false. - - hgrid=ne0np4CONUS.ne30x8 maxpft=17 mask=tx0.1v2 use_cn=.false. use_crop=.false. irrigate=.true. glc_nec=10 do_transient_pfts=.false. use_excess_ice=.false. + - + lnd/clm2/initdata_esmf/ctsm5.3/ctsm52026_f09_pSASU.clm2.r.0421-01-01-00000.nc + phys="clm6_0" +>lnd/clm2/initdata_esmf/ctsm5.3/ctsm53n04ctsm52028_f09_g17_BgcCrop_exice_pSASU.clm60.r.0161-01-01.nc -lnd/clm2/initdata_esmf/ctsm5.3/ctsm52026_f09_pSASU.clm2.r.0421-01-01-00000.nc + +lnd/clm2/initdata_esmf/ctsm5.3/ctsm53n04ctsm52028_ne30pg3t232_BgcCrop_exice_pSASU.clm60.r.0121-01-01.nc + + +lnd/clm2/initdata_esmf/ctsm5.3/ctsm530_f19_g17_Bgc_exice_pSASU.clm60.r.0161-01-01.nc - - + + lnd/clm2/initdata_esmf/ctsm5.3/ctsm52026_f09_pSASU.clm2.r.0421-01-01-00000.nc + phys="clm6_0" use_init_interp=".true." +>lnd/clm2/initdata_esmf/ctsm5.3/ctsm53n04ctsm52028_f09_g17_BgcCrop_exice_hist.clm60.r.2000-01-01.nc - - - -lnd/clm2/initdata_esmf/ctsm5.3/ctsm52026_f09_pSASU.clm2.r.0421-01-01-00000.nc +>lnd/clm2/initdata_esmf/ctsm5.3/ctsm53n04ctsm52028_ne30pg3t232_BgcCrop_exice_hist.clm60.r.2000-01-01.nc @@ -1526,83 +1436,20 @@ attributes from the config_cache.xml file (with keys converted to upper-case). lnd_tuning_mode="clm5_0_cam7.0" use_init_interp=".true." >lnd/clm2/initdata_map/clmi.FHISTSp.2013-01-01.ne0CONUSne30x8_mt12_simyr2013_c200806.nc - -lnd/clm2/initdata_map/clmi.BHIST.2000-01-01.0.9x1.25_gx1v7_simyr1979_c200806.nc - - -lnd/clm2/initdata_map/clmi.BHIST.2000-01-01.1.9x2.5_gx1v7_simyr1979_c200806.nc - - - -lnd/clm2/initdata_map/clmi.FHISTSp.1979-01-01.ARCTIC_ne30x4_mt12_simyr1979_c200806.nc - - - -lnd/clm2/initdata_map/clmi.FHISTSp.1979-01-01.ARCTICGRIS_ne30x8_mt12_simyr1979_c200806.nc - - - - + +lnd/clm2/initdata_map/clmi.F2000.2000-01-01.ne120pg3_mt13_simyr2000_c200728.nc + phys="clm6_0" use_init_interp=".true." +>lnd/clm2/initdata_esmf/ctsm5.3/ctsm53n04ctsm52028_f09_g17_BgcCrop_exice_hist.clm60.r.1979-01-01.nc - - - -lnd/clm2/initdata_esmf/ctsm5.3/ctsm52026_f09_pSASU.clm2.r.0421-01-01-00000.nc - - - -lnd/clm2/initdata_map/clmi.BHISTSp.2000-01-01.1.9x2.5_gx1v7_simyr2003_c200807.nc - - - - -lnd/clm2/initdata_map/clmi.FHISTSp.2013-01-01.ne0CONUSne30x8_mt12_simyr2013_c200806.nc - - -lnd/clm2/initdata_map/clmi.BHIST.2000-01-01.0.9x1.25_gx1v7_simyr1979_c200806.nc - - -lnd/clm2/initdata_map/clmi.BHIST.2000-01-01.1.9x2.5_gx1v7_simyr1979_c200806.nc + phys="clm6_0" use_init_interp=".true." +>lnd/clm2/initdata_esmf/ctsm5.3/ctsm53n04ctsm52028_ne30pg3t232_BgcCrop_exice_hist.clm60.r.1979-01-01.nc @@ -1630,22 +1477,6 @@ attributes from the config_cache.xml file (with keys converted to upper-case). - -lnd/clm2/initdata_esmf/ctsm5.3/ctsm52026_f09_pSASU.clm2.r.0421-01-01-00000.nc - - - -lnd/clm2/initdata_map/clmi.BHISTSp.2000-01-01.1.9x2.5_gx1v7_simyr2003_c200807.nc - - lnd/clm2/initdata_map/clmi.BHIST.2000-01-01.0.9x1.25_gx1v7_simyr2000_c200728.nc - -lnd/clm2/initdata_esmf/ctsm5.3/ctsm52026_f09_pSASU.clm2.r.0421-01-01-00000.nc - - - -lnd/clm2/initdata_esmf/ctsm5.3/ctsm52026_f09_pSASU.clm2.r.0421-01-01-00000.nc - - lnd/clm2/initdata_map/clmi.FHISTSp.2013-01-01.ne0CONUSne30x8_mt12_simyr2013_c200806.nc - - -lnd/clm2/initdata_map/clmi.BHIST.2000-01-01.0.9x1.25_gx1v7_simyr1979_c200806.nc - - -lnd/clm2/initdata_map/clmi.BHIST.2000-01-01.1.9x2.5_gx1v7_simyr1979_c200806.nc - - - -lnd/clm2/initdata_map/clmi.FHISTSp.1979-01-01.ARCTIC_ne30x4_mt12_simyr1979_c200806.nc - - - -lnd/clm2/initdata_map/clmi.FHISTSp.1979-01-01.ARCTICGRIS_ne30x8_mt12_simyr1979_c200806.nc - - - -lnd/clm2/initdata_map/clmi.F2000.2000-01-01.ne120pg3_mt13_simyr2000_c200728.nc - - - - -lnd/clm2/initdata_esmf/ctsm5.3/ctsm52026_f09_pSASU.clm2.r.0421-01-01-00000.nc - - - -lnd/clm2/initdata_map/clmi.BHISTSp.2000-01-01.1.9x2.5_gx1v7_simyr2003_c200807.nc - - - - -lnd/clm2/initdata_map/clmi.FHISTSp.2013-01-01.ne0CONUSne30x8_mt12_simyr2013_c200806.nc - -lnd/clm2/initdata_map/clmi.BHIST.2000-01-01.0.9x1.25_gx1v7_simyr1979_c200806.nc - - -lnd/clm2/initdata_map/clmi.BHIST.2000-01-01.1.9x2.5_gx1v7_simyr1979_c200806.nc - - -lnd/clm2/initdata_esmf/ctsm5.3/ctsm52026_f09_pSASU.clm2.r.0421-01-01-00000.nc - - - -lnd/clm2/initdata_map/clmi.BHISTSp.2000-01-01.1.9x2.5_gx1v7_simyr2003_c200807.nc - - - - -lnd/clm2/surfdata_esmf/ctsm5.3.0/surfdata_0.9x1.25_hist_2000_78pfts_c240908.nc - + lnd/clm2/surfdata_esmf/ctsm5.3.0/surfdata_0.9x1.25_hist_2000_78pfts_c240908.nc - + lnd/clm2/surfdata_esmf/ctsm5.3.0/surfdata_1.9x2.5_hist_2000_78pfts_c240908.nc - -lnd/clm2/surfdata_esmf/ctsm5.3.0/surfdata_1.9x2.5_hist_2000_78pfts_c240908.nc - -lnd/clm2/surfdata_esmf/ctsm5.3.0/surfdata_10x15_hist_2000_78pfts_c240908.nc - + lnd/clm2/surfdata_esmf/ctsm5.3.0/surfdata_10x15_hist_2000_78pfts_c240908.nc - -lnd/clm2/surfdata_esmf/ctsm5.3.0/surfdata_4x5_hist_2000_78pfts_c240908.nc - + lnd/clm2/surfdata_esmf/ctsm5.3.0/surfdata_4x5_hist_2000_78pfts_c240908.nc @@ -1948,6 +1660,8 @@ lnd/clm2/surfdata_esmf/ctsm5.3.0/surfdata_ne120np4.pg3_hist_2000_78pfts_c240908. lnd/clm2/surfdata_esmf/ctsm5.3.0/surfdata_ne0np4.ARCTICGRIS.ne30x8_hist_2000_78pfts_c240908.nc lnd/clm2/surfdata_esmf/ctsm5.3.0/surfdata_ne0np4.ARCTIC.ne30x4_hist_2000_78pfts_c240908.nc + +lnd/clm2/surfdata_esmf/ctsm5.3.0/surfdata_ne0np4.POLARCAP.ne30x4_hist_2000_78pfts_c240908.nc lnd/clm2/surfdata_esmf/ctsm5.3.0/surfdata_ne0np4CONUS.ne30x8_hist_2000_78pfts_c240908.nc @@ -1961,29 +1675,36 @@ lnd/clm2/surfdata_esmf/ctsm5.3.0/synthetic/surfdata_1x1_urbanc_alpha_synth_hist_ + + +lnd/clm2/surfdata_esmf/ctsm5.3.0/surfdata_1.9x2.5_hist_1850_16pfts_c240926.nc + +lnd/clm2/surfdata_esmf/ctsm5.3.0/surfdata_4x5_hist_1850_16pfts_c241007.nc + + lnd/clm2/surfdata_esmf/ctsm5.3.0/surfdata_360x720cru_hist_1850_78pfts_c240908.nc - + lnd/clm2/surfdata_esmf/ctsm5.3.0/surfdata_0.9x1.25_hist_1850_78pfts_c240908.nc - + lnd/clm2/surfdata_esmf/ctsm5.3.0/surfdata_1.9x2.5_hist_1850_78pfts_c240908.nc - + lnd/clm2/surfdata_esmf/ctsm5.3.0/surfdata_10x15_hist_1850_78pfts_c240908.nc - + lnd/clm2/surfdata_esmf/ctsm5.3.0/surfdata_4x5_hist_1850_78pfts_c240908.nc - + lnd/clm2/surfdata_esmf/ctsm5.3.0/surfdata_mpasa480_hist_1850_78pfts_c240908.nc - + lnd/clm2/surfdata_esmf/ctsm5.3.0/surfdata_mpasa120_hist_1850_78pfts_c240908.nc - + lnd/clm2/surfdata_esmf/ctsm5.3.0/surfdata_ne30np4_hist_1850_78pfts_c240908.nc - + lnd/clm2/surfdata_esmf/ctsm5.3.0/surfdata_ne30np4.pg2_hist_1850_78pfts_c240908.nc - + lnd/clm2/surfdata_esmf/ctsm5.3.0/surfdata_ne30np4.pg3_hist_1850_78pfts_c240908.nc - + lnd/clm2/surfdata_esmf/ctsm5.3.0/surfdata_ne3np4.pg3_hist_1850_78pfts_c240908.nc @@ -2005,6 +1726,8 @@ lnd/clm2/surfdata_esmf/ctsm5.3.0/surfdata_ne120np4.pg3_hist_1850_78pfts_c240908. lnd/clm2/surfdata_esmf/ctsm5.3.0/surfdata_ne0np4.ARCTICGRIS.ne30x8_hist_1979_78pfts_c240908.nc lnd/clm2/surfdata_esmf/ctsm5.3.0/surfdata_ne0np4.ARCTIC.ne30x4_hist_1979_78pfts_c240908.nc + +lnd/clm2/surfdata_esmf/ctsm5.3.0/surfdata_ne0np4.POLARCAP.ne30x4_hist_1979_78pfts_c240908.nc lnd/clm2/surfdata_esmf/ctsm5.3.0/surfdata_ne0np4CONUS.ne30x8_hist_1979_78pfts_c240908.nc @@ -2032,13 +1755,26 @@ lnd/clm2/surfdata_esmf/NEON/ctsm5.3.0/surfdata_1x1_NEON_TOOL_hist_2000_78pfts_c2 --> + +lnd/clm2/surfdata_esmf/ctsm5.3.0/landuse.timeseries_1.9x2.5_hist_1850-2023_16pfts_c240926.nc +lnd/clm2/surfdata_esmf/ctsm5.3.0/landuse.timeseries_4x5_hist_1850-2023_16pfts_c241007.nc + + lnd/clm2/surfdata_esmf/ctsm5.3.0/landuse.timeseries_0.9x1.25_SSP2-4.5_1850-2100_78pfts_c240908.nc -lnd/clm2/surfdata_esmf/ctsm5.3.0/landuse.timeseries_1.9x2.5_SSP2-4.5_1850-2100_78pfts_c240908.nc - - -lnd/clm2/surfdata_esmf/ctsm5.3.0/landuse.timeseries_ne0np4.ARCTICGRIS.ne30x8_SSP2-4.5_1979-2026_78pfts_c240908.nc +lnd/clm2/surfdata_esmf/ctsm5.3.0/landuse.timeseries_ne0np4.ARCTIC.ne30x4_SSP2-4.5_1979-2026_78pfts_c240908.nc +lnd/clm2/surfdata_esmf/ctsm5.3.0/landuse.timeseries_ne0np4.POLARCAP.ne30x4_SSP2-4.5_1979-2026_78pfts_c240908.nc +lnd/clm2/surfdata_esmf/ctsm5.3.0/landuse.timeseries_ne0np4CONUS.ne30x8_SSP2-4.5_1979-2026_78pfts_c240908.nc +lnd/clm2/surfdata_esmf/ctsm5.3.0/landuse.timeseries_4x5_SSP2-4.5_1850-2100_78pfts_c240908.nc lnd/clm2/surfdata_esmf/ctsm5.3.0/landuse.timeseries_10x15_SSP2-4.5_1850-2100_78pfts_c240908.nc @@ -2112,6 +1848,8 @@ lnd/clm2/surfdata_esmf/NEON/ctsm5.3.0/surfdata_1x1_NEON_TOOL_hist_2000_78pfts_c2 >lnd/clm2/surfdata_esmf/ctsm5.3.0/landuse.timeseries_ne0np4.ARCTICGRIS.ne30x8_SSP2-4.5_1979-2026_78pfts_c240908.nc lnd/clm2/surfdata_esmf/ctsm5.3.0/landuse.timeseries_ne0np4.ARCTIC.ne30x4_SSP2-4.5_1979-2026_78pfts_c240908.nc +lnd/clm2/surfdata_esmf/ctsm5.3.0/landuse.timeseries_ne0np4.POLARCAP.ne30x4_SSP2-4.5_1979-2026_78pfts_c240908.nc lnd/clm2/surfdata_esmf/ctsm5.3.0/landuse.timeseries_ne0np4CONUS.ne30x8_SSP2-4.5_1979-2026_78pfts_c240908.nc @@ -2184,7 +1922,6 @@ lnd/clm2/surfdata_esmf/NEON/ctsm5.3.0/surfdata_1x1_NEON_TOOL_hist_2000_78pfts_c2 sahara .false. .false. -.true. .true. .true. .false. @@ -2283,7 +2020,6 @@ lnd/clm2/surfdata_esmf/NEON/ctsm5.3.0/surfdata_1x1_NEON_TOOL_hist_2000_78pfts_c2 .true. .false. .false. -.false. .false. .false. 2000 @@ -2482,10 +2218,6 @@ lnd/clm2/surfdata_esmf/NEON/ctsm5.3.0/surfdata_1x1_NEON_TOOL_hist_2000_78pfts_c2 >lnd/clm2/urbandata/CTSM52_tbuildmax_OlesonFeddema_2020_0.9x1.25_simyr1849-2106_c200605.nc lnd/clm2/urbandata/CTSM52_urbantv_Li_2024_0.9x1.25_simyr1849-2106_c20230621.nc -lnd/clm2/urbandata/CTSM52_tbuildmax_OlesonFeddema_2020_0.9x1.25_simyr1849-2106_c200605.nc -lnd/clm2/urbandata/CTSM52_urbantv_Li_2024_0.9x1.25_simyr1849-2106_c20230621.nc lnd/clm2/urbandata/CLM50_tbuildmax_Oleson_2016_0.9x1.25_simyr1849-2106_c160923.nc lnd/clm2/dustemisdata/dst_source2x2tunedcam6-2x2-forCLM_cdf5_c230312.nc lnd/clm2/dustemisdata/dst_source2x2tunedcam6-2x2-forCLM_cdf5_c230312.nc -lnd/clm2/dustemisdata/dst_source2x2tunedcam6-2x2-forCLM_cdf5_c230312.nc lnd/clm2/dustemisdata/dst_source2x2tunedcam6-2x2-forCLM_cdf5_c230312.nc lnd/clm2/dustemisdata/dst_source2x2tunedcam6-2x2-forCLM_cdf5_c230312.nc lnd/clm2/dustemisdata/dst_source2x2tunedcam6-2x2-forCLM_cdf5_c230312.nc -lnd/clm2/dustemisdata/dst_source2x2tunedcam6-2x2-forCLM_cdf5_c230312.nc lnd/clm2/dustemisdata/dst_source2x2tunedcam6-2x2-forCLM_cdf5_c230312.nc lnd/clm2/dustemisdata/dst_source2x2_cam5.4-forCLM_cdf5_c240202.nc lnd/clm2/dustemisdata/dst_source2x2_cam5.4-forCLM_cdf5_c240202.nc -lnd/clm2/dustemisdata/dst_source2x2_cam5.4-forCLM_cdf5_c240202.nc lnd/clm2/dustemisdata/dst_source2x2_cam5.4-forCLM_cdf5_c240202.nc lnd/clm2/dustemisdata/dst_source2x2tuned-cam4-forCLM_cdf5_c240202.nc lnd/clm2/dustemisdata/dst_source2x2tuned-cam4-forCLM_cdf5_c240202.nc -lnd/clm2/dustemisdata/dst_source2x2tuned-cam4-forCLM_cdf5_c240202.nc lnd/clm2/dustemisdata/dst_source2x2tuned-cam4-forCLM_cdf5_c240202.nc lnd/clm2/dustemisdata/dst_source1x1tuned-cam4-forCLM_cdf5_c240202.nc lnd/clm2/dustemisdata/dst_source1x1tuned-cam4-forCLM_cdf5_c240202.nc -lnd/clm2/dustemisdata/dst_source1x1tuned-cam4-forCLM_cdf5_c240202.nc lnd/clm2/dustemisdata/dst_source1x1tuned-cam4-forCLM_cdf5_c240202.nc lnd/clm2/dustemisdata/dst_source2x2tunedcam6-2x2-forCLM_cdf5_c230312.nc lnd/clm2/dustemisdata/dst_source2x2tunedcam6-2x2-forCLM_cdf5_c230312.nc -lnd/clm2/dustemisdata/dst_source2x2tunedcam6-2x2-forCLM_cdf5_c230312.nc lnd/clm2/dustemisdata/dst_source2x2tunedcam6-2x2-forCLM_cdf5_c230312.nc lnd/clm2/dustemisdata/dst_source2x2tunedcam6-2x2-forCLM_cdf5_c230312.nc lnd/clm2/dustemisdata/dst_source2x2tunedcam6-2x2-forCLM_cdf5_c230312.nc -lnd/clm2/dustemisdata/dst_source2x2tunedcam6-2x2-forCLM_cdf5_c230312.nc lnd/clm2/dustemisdata/dst_source2x2tunedcam6-2x2-forCLM_cdf5_c230312.nc lnd/clm2/dustemisdata/dst_source2x2tunedcam6-2x2-forCLM_cdf5_c230312.nc lnd/clm2/dustemisdata/dst_source2x2tunedcam6-2x2-forCLM_cdf5_c230312.nc -lnd/clm2/dustemisdata/dst_source2x2tunedcam6-2x2-forCLM_cdf5_c230312.nc lnd/clm2/dustemisdata/dst_source2x2tunedcam6-2x2-forCLM_cdf5_c230312.nc lnd/clm2/dustemisdata/dst_source2x2tunedcam6-2x2-forCLM_cdf5_c230312.nc lnd/clm2/dustemisdata/dst_source2x2tunedcam6-2x2-forCLM_cdf5_c230312.nc -lnd/clm2/dustemisdata/dst_source2x2tunedcam6-2x2-forCLM_cdf5_c230312.nc lnd/clm2/dustemisdata/dst_source2x2tunedcam6-2x2-forCLM_cdf5_c230312.nc @@ -2742,7 +2456,6 @@ lnd/clm2/surfdata_esmf/NEON/ctsm5.3.0/surfdata_1x1_NEON_TOOL_hist_2000_78pfts_c2 off -low low .false. diff --git a/bld/namelist_files/namelist_defaults_drydep.xml b/bld/namelist_files/namelist_defaults_drydep.xml index fb73ab6646..2ca89e4620 100644 --- a/bld/namelist_files/namelist_defaults_drydep.xml +++ b/bld/namelist_files/namelist_defaults_drydep.xml @@ -26,7 +26,6 @@ attributes from the config_cache.xml file (with keys converted to upper-case). 'ISOP = isoprene', 'C10H16 = pinene_a + carene_3 + thujene_a', 'CH3OH = methanol', 'C2H5OH = ethanol', 'CH2O = formaldehyde', 'CH3CHO = acetaldehyde', 'CH3COOH = acetic_acid', 'CH3COCH3 = acetone' atm/cam/chem/trop_mozart/emis/megan21_emis_factors_78pft_c20161108.nc -atm/cam/chem/trop_mozart/emis/megan21_emis_factors_78pft_c20161108.nc atm/cam/chem/trop_mozart/emis/megan21_emis_factors_78pft_c20161108.nc atm/cam/chem/trop_mozart/emis/megan21_emis_factors_78pft_c20161108.nc diff --git a/bld/namelist_files/namelist_defaults_overall.xml b/bld/namelist_files/namelist_defaults_overall.xml index 5b7ae1bdd9..577f9bce61 100644 --- a/bld/namelist_files/namelist_defaults_overall.xml +++ b/bld/namelist_files/namelist_defaults_overall.xml @@ -34,8 +34,6 @@ determine default values for namelists. cold cold cold -cold -cold cold cold diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml index 417444914e..2d5ab0e4c7 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -171,7 +171,7 @@ dust optics type for SNICAR snow albedo calculation snow grain shape used in SNICAR snow albedo calculation -(snicar_snw_shape='hexagonal_plate' is supported in ctsm5.1 and 'sphere' in older model versions; others are EXPERIMENTAL, UNSUPPORTED, and UNTESTED!) +(snicar_snw_shape='sphere' is supported in pre-ctsm5.1 model versions and 'hexagonal place' is supported in newer versions; others are EXPERIMENTAL, UNSUPPORTED, and UNTESTED!) Default: 40 - -Fraction of intercepted precipitation - - If TRUE use clm5 equation for fraction of intercepted precipitation - -Maximum fraction of leaf that may be wet prior to drip occuring - - Scalar multiplier for base flow rate @@ -712,11 +702,6 @@ Scalar of leaf respiration to vcmax The maximum value to use for zeta under stable conditions - -baseline proportion of nitrogen allocated for electron transport (J) - - Toggle to turn on the FATES model @@ -962,6 +947,11 @@ Full pathname datafile with fates parameters Full pathname of surface data file. + +Full pathname of hillslope data file. + + SNICAR (SNow, ICe, and Aerosol Radiative model) optical data file name @@ -2228,7 +2218,7 @@ Land mask description + valid_values="clm4_5_CRUv7,clm4_5_GSWP3v1,clm4_5_cam7.0,clm4_5_cam6.0,clm4_5_cam5.0,clm4_5_cam4.0,clm5_0_cam7.0,clm5_0_cam6.0,clm5_0_cam5.0,clm5_0_cam4.0,clm5_0_CRUv7,clm5_0_GSWP3v1,clm6_0_GSWP3v1,clm6_0_cam7.0,clm6_0_cam6.0,clm6_0_cam5.0,clm6_0_cam4.0"> General configuration of model version and atmospheric forcing to tune the model to run under. This sets the model to run with constants and initial conditions that were set to run well under the configuration of model version and atmospheric forcing. To run well constants would need to be changed @@ -2839,11 +2829,6 @@ TruncatedAnderson1976 -- Truncate the Anderson-1976 equation at the value for -1 Slater2017 ------------- Use equation from Slater that increases snow density for very cold temperatures (Arctic, Antarctic) - -Upper Limit on Destructive Metamorphism Compaction [kg/m3] - - Snow compaction overburden exponential factor (1/K) diff --git a/bld/unit_testers/build-namelist_test.pl b/bld/unit_testers/build-namelist_test.pl index 06c9bcc361..9959632470 100755 --- a/bld/unit_testers/build-namelist_test.pl +++ b/bld/unit_testers/build-namelist_test.pl @@ -78,7 +78,7 @@ sub make_config_cache { -Specifies clm physics +Specifies clm physics EOF $fh->close(); @@ -163,10 +163,10 @@ sub cat_and_create_namelistinfile { # # Figure out number of tests that will run # -my $ntests = 3997; +my $ntests = 3263; if ( defined($opts{'compare'}) ) { - $ntests += 2437; + $ntests += 1979; } plan( tests=>$ntests ); @@ -473,7 +473,7 @@ sub cat_and_create_namelistinfile { print "\n===============================================================================\n"; print "Test some CAM specific setups for special grids \n"; print "=================================================================================\n"; -foreach my $phys ( "clm4_5", "clm5_0" ) { +foreach my $phys ( "clm4_5", "clm5_0", "clm6_0" ) { $mode = "-phys $phys"; &make_config_cache($phys); foreach my $options ( @@ -485,7 +485,7 @@ sub cat_and_create_namelistinfile { "-res ne0np4CONUS.ne30x8 -bgc sp -use_case 2000_control -namelist '&a start_ymd=20130101/' -lnd_tuning_mode ${phys}_cam7.0", "-res 1.9x2.5 -bgc sp -use_case 20thC_transient -namelist '&a start_ymd=20030101/' -lnd_tuning_mode ${phys}_cam7.0", "-res 1.9x2.5 -bgc sp -use_case 2010_control -namelist '&a start_ymd=20100101/' -lnd_tuning_mode ${phys}_cam7.0", - "-res 1x1_brazil -no-megan -use_case 2000_control -lnd_tuning_mode ${phys}_CRUv7", + "-res 1x1_brazil -no-megan -use_case 2000_control -lnd_tuning_mode ${phys}_GSWP3v1", "-res C96 -bgc sp -use_case 2010_control -namelist '&a start_ymd=20100101/' -lnd_tuning_mode ${phys}_cam7.0", "-res ne0np4.ARCTIC.ne30x4 -bgc sp -use_case 2000_control -namelist '&a start_ymd=20130101/' -lnd_tuning_mode ${phys}_cam7.0", ) { @@ -506,6 +506,31 @@ sub cat_and_create_namelistinfile { } } print "\n===============================================================================\n"; +print "Test setting drv_flds_in fields in CAM, clm60 only"; +print "=================================================================================\n"; +foreach my $phys ( "clm6_0" ) { + $mode = "-phys $phys CAM_SETS_DRV_FLDS"; + &make_config_cache($phys); + foreach my $options ( + "--res ne0np4.POLARCAP.ne30x4 --mask tx0.1v2 -bgc sp -use_case 20thC_transient -namelist '&a start_ymd=19790101/' -lnd_tuning_mode ${phys}_cam7.0 --infile empty_user_nl_clm", + ) { + &make_env_run( 'LND_SETS_DUST_EMIS_DRV_FLDS'=>"FALSE" ); + eval{ system( "$bldnml --envxml_dir . $options > $tempfile 2>&1 " ); }; + is( $@, '', "options: $options" ); + $cfiles->checkfilesexist( "$options", $mode ); + $cfiles->shownmldiff( "default", $mode ); + if ( defined($opts{'compare'}) ) { + $cfiles->doNOTdodiffonfile( "$tempfile", "$options", $mode ); + $cfiles->dodiffonfile( "lnd_in", "$options", $mode ); + $cfiles->comparefiles( "$options", $mode, $opts{'compare'} ); + } + if ( defined($opts{'generate'}) ) { + $cfiles->copyfiles( "$options", $mode ); + } + &cleanup(); + } +} +print "\n===============================================================================\n"; print "Test setting drv_flds_in fields in CAM"; print "=================================================================================\n"; foreach my $phys ( "clm5_0", "clm6_0" ) { @@ -514,6 +539,10 @@ sub cat_and_create_namelistinfile { foreach my $options ( "--res 1.9x2.5 --mask gx1v7 --bgc sp --use_case 20thC_transient --namelist '&a start_ymd=19790101/' --lnd_tuning_mode ${phys}_cam6.0 --infile empty_user_nl_clm", "--res 1.9x2.5 --mask gx1v7 --bgc sp --use_case 20thC_transient --namelist '&a start_ymd=19790101/' --lnd_tuning_mode ${phys}_cam7.0 --infile empty_user_nl_clm", + "--res 1.9x2.5 --mask gx1v7 --bgc sp -no-crop --use_case 20thC_transient --namelist '&a start_ymd=19790101/' --lnd_tuning_mode ${phys}_cam7.0 --infile empty_user_nl_clm", + "--res ne0np4.ARCTIC.ne30x4 --mask tx0.1v2 -bgc sp -use_case 20thC_transient -namelist '&a start_ymd=19790101/' -lnd_tuning_mode ${phys}_cam7.0 --infile empty_user_nl_clm", + "--res ne0np4.ARCTICGRIS.ne30x8 --mask tx0.1v2 -bgc sp -use_case 20thC_transient -namelist '&a start_ymd=19790101/' -lnd_tuning_mode ${phys}_cam7.0 --infile empty_user_nl_clm", + "--res ne0np4CONUS.ne30x8 --mask tx0.1v2 -bgc sp -use_case 20thC_transient -namelist '&a start_ymd=20130101/' -lnd_tuning_mode ${phys}_cam7.0 --infile empty_user_nl_clm", ) { &make_env_run( 'LND_SETS_DUST_EMIS_DRV_FLDS'=>"FALSE" ); eval{ system( "$bldnml --envxml_dir . $options > $tempfile 2>&1 " ); }; @@ -541,6 +570,7 @@ sub cat_and_create_namelistinfile { "--res 0.9x1.25 --bgc sp --use_case 1850-2100_SSP2-4.5_transient --namelist '&a start_ymd=18501223/'", "-bgc fates -use_case 2000_control -no-megan", "-bgc fates -use_case 20thC_transient -no-megan", + "-bgc fates -use_case 20thC_transient -no-megan -no-crop --res 4x5", "-bgc fates -use_case 1850_control -no-megan -namelist \"&a use_fates_sp=T, soil_decomp_method='None'/\"", "-bgc sp -use_case 2000_control -res 0.9x1.25 -namelist '&a use_soil_moisture_streams = T/'", "--res 1.9x2.5 --bgc bgc --use_case 1850-2100_SSP2-4.5_transient --namelist '&a start_ymd=19101023/'", @@ -601,8 +631,8 @@ sub cat_and_create_namelistinfile { phys=>"clm4_5", }, "LeungDust_WO_Prigent" =>{ options=>" -envxml_dir . -bgc sp", - namelst=>"use_prigent_roughness=.true.", - phys=>"clm5_1", + namelst=>"use_prigent_roughness=.false.,dust_emis_method='Leung_2023'", + phys=>"clm6_0", }, "soilm_stream off w file" =>{ options=>"-res 0.9x1.25 -envxml_dir .", namelst=>"use_soil_moisture_streams = .false.,stream_fldfilename_soilm='file_provided_when_off'", @@ -876,7 +906,7 @@ sub cat_and_create_namelistinfile { namelst=>"h2osfcflag=0", phys=>"clm5_0", }, - "45bad lnd_tuning_mode value" =>{ options=>"-lnd_tuning_mode clm5_0_GSWP3 -envxml_dir .", + "45bad lnd_tuning_mode value" =>{ options=>"-lnd_tuning_mode clm5_0_GSWP3v1 -envxml_dir .", namelst=>"", phys=>"clm4_5", }, @@ -916,6 +946,10 @@ sub cat_and_create_namelistinfile { namelst=>"", phys=>"clm6_0", }, + "driver is invalid" =>{ options=>"-driver invalid_name -envxml_dir .", + namelst=>"", + phys=>"clm6_0", + }, "lnd_frac not set but lilac"=>{ options=>"-driver nuopc -lilac -envxml_dir . -lnd_frac UNSET", namelst=>"fsurdat='surfdata.nc'", phys=>"clm6_0", @@ -969,12 +1003,12 @@ sub cat_and_create_namelistinfile { "sasuspinupWOsoilmatx" =>{ options=>"-envxml_dir . -bgc bgc -clm_accelerated_spinup sasu", namelst=>"use_soil_matrixcn=.false.,use_matrixcn=.false.", GLC_TWO_WAY_COUPLING=>"TRUE", - phys=>"clm5_1", + phys=>"clm6_0", }, "sasuspinupWOCN" =>{ options=>"-envxml_dir . -bgc sp -clm_accelerated_spinup sasu", namelst=>"", GLC_TWO_WAY_COUPLING=>"TRUE", - phys=>"clm5_1", + phys=>"clm6_0", }, "nyrforceWOspinup" =>{ options=>"-envxml_dir . -bgc bgc -clm_accelerated_spinup sasu", namelst=>"use_matrixcn=.false.,spinup_matrixcn=F,nyr_forcing=20", @@ -1235,10 +1269,6 @@ sub cat_and_create_namelistinfile { namelst=>"use_luna=.true., lnc_opt=.true.", phys=>"clm5_0", }, - "NOlunabutsetJmaxb1" =>{ options=>"-envxml_dir . -bgc sp", - namelst=>"use_luna=.false., jmaxb1=1.0", - phys=>"clm5_0", - }, "envxml_not_dir" =>{ options=>"-envxml_dir myuser_nl_clm", namelst=>"", phys=>"clm5_0", @@ -1287,6 +1317,13 @@ sub cat_and_create_namelistinfile { ); foreach my $key ( keys(%failtest) ) { print( "$key\n" ); + my $var; + foreach $var ( "phys" , "options", "namelst" ) { + if ( not exists $failtest{$key}{$var} ) { + die "ERROR: Subkey $var does not exist for failtest $key\nERROR:Check if you spelled $var correctly\n" + } + } + &make_config_cache($failtest{$key}{"phys"}); my $options = $failtest{$key}{"options"}; my $namelist = $failtest{$key}{"namelst"}; @@ -1311,10 +1348,6 @@ sub cat_and_create_namelistinfile { my %warntest = ( # Warnings without the -ignore_warnings option given - "coldwfinidat" =>{ options=>"-envxml_dir . -clm_start_type cold", - namelst=>"finidat = 'testfile.nc'", - phys=>"clm5_0", - }, "bgcspin_w_suplnitro" =>{ options=>"-envxml_dir . -bgc bgc -clm_accelerated_spinup on", namelst=>"suplnitro='ALL'", phys=>"clm5_0", @@ -1359,13 +1392,21 @@ sub cat_and_create_namelistinfile { namelst=>"fsurdat='build-namelist_test.pl'", phys=>"clm6_0", }, - "hillslope with init_interp"=>{ options=>"-bgc bgc -envxml_dir .", - namelst=>"use_init_interp=.true.,use_hillslope=.true.", + "hillslope with init_interp"=>{ options=>"--res 10x15 --bgc bgc --envxml_dir .", + namelst=>"use_init_interp=.true.,use_hillslope=.true.,hillslope_file='/dev/null'", phys=>"clm6_0", }, ); foreach my $key ( keys(%warntest) ) { print( "$key\n" ); + + my $var; + foreach $var ( "phys" , "options", "namelst" ) { + if ( not exists $warntest{$key}{$var} ) { + die "ERROR: Subkey $var does not exist for warntest $key\nERROR:Check if you spelled $var correctly\n" + } + } + &make_config_cache($warntest{$key}{"phys"}); my $options = $warntest{$key}{"options"}; my $namelist = $warntest{$key}{"namelst"}; @@ -1387,10 +1428,60 @@ sub cat_and_create_namelistinfile { system( "cat $tempfile" ); } +print "\n===============================================================================\n"; +print "Ensure cold starts with finidat are handled properly \n"; +print "=================================================================================\n"; + +my %coldwfinidat = ( + "bgc" => { options=>"-envxml_dir . -clm_start_type cold", + namelst=>"finidat = 'testfile.nc'", + phys=>"clm5_0", + expected_fail=>1, + }, + "fates" => { options=>"-envxml_dir . -clm_start_type cold -bgc fates -no-megan", + namelst=>"finidat = 'testfile.nc', use_fates = .true.", + phys=>"clm5_0", + expected_fail=>0, + }, +); +my $finidat; +foreach my $key ( keys(%coldwfinidat) ) { + print( "$key\n" ); + + my $var; + foreach $var ( "phys" , "options", "namelst", "expected_fail" ) { + if ( not exists $coldwfinidat{$key}{$var} ) { + die "ERROR: Subkey $var does not exist for coldwfinidat $key\nERROR:Check if you spelled $var correctly\n" + } + } + + &make_config_cache($coldwfinidat{$key}{"phys"}); + my $options = $coldwfinidat{$key}{"options"}; + my $namelist = $coldwfinidat{$key}{"namelst"}; + my $expected_fail = $coldwfinidat{$key}{"expected_fail"}; + my %settings; + &make_env_run( %settings ); + + # Should fail if expected to, pass otherwise + eval{ system( "$bldnml $options -namelist \"&clmexp $namelist /\" > $tempfile 2>&1 " ); }; + is( $? eq 0, $expected_fail eq 0, "coldwfinidat $key run"); + + if ( $expected_fail ) { + # Now run with -ignore_warnings and make sure it still doesn't work + $options .= " -ignore_warnings"; + eval{ system( "$bldnml $options -namelist \"&clmexp $namelist /\" > $tempfile 2>&1 " ); }; + isnt( $?, 0, "coldwfinidat $key run -ignore_warnings" ); + } else { + # Check that finidat was correctly set + $finidat = `grep finidat lnd_in`; + ok ( $finidat =~ "testfile.nc", "coldwfinidat $key finidat? $finidat" ); + } +} + # # Loop over all physics versions # -foreach my $phys ( "clm4_5", "clm5_0", "clm5_1", "clm6_0" ) { +foreach my $phys ( "clm4_5", "clm5_0", "clm6_0" ) { $mode = "-phys $phys"; &make_config_cache($phys); @@ -1481,7 +1572,7 @@ sub cat_and_create_namelistinfile { } my @expect_fails = ( "1850-2100_SSP5-3.4_transient", "1850-2100_SSP4-3.4_transient", "2018-PD_transient", "1850-2100_SSP1-1.9_transient", "1850-2100_SSP4-6.0_transient", "2018_control" ); -foreach my $phys ( "clm4_5", "clm5_0", "clm5_1", "clm6_0" ) { +foreach my $phys ( "clm4_5", "clm5_0", "clm6_0" ) { print "physics = $phys\n"; &make_config_cache($phys); foreach my $usecase ( @usecases ) { @@ -1595,6 +1686,14 @@ sub cat_and_create_namelistinfile { foreach my $key ( keys(%finidat_files) ) { print( "$key\n" ); + + my $var; + foreach $var ( "phys" , "atm_forc", "res", "bgc", "crop", "use_case", "start_ymd", "namelist" ) { + if ( not exists $finidat_files{$key}{$var} ) { + die "ERROR: Subkey $var does not exist for finidat_file $key\nERROR:Check if you spelled $var correctly\n" + } + } + my $phys = $finidat_files{$key}{'phys'}; print "physics = $phys\n"; &make_config_cache($phys); @@ -1770,10 +1869,10 @@ sub cat_and_create_namelistinfile { # print "\n==================================================\n"; -print "Test clm4.5/clm5.0/clm5_1/clm6_0 resolutions \n"; +print "Test clm4.5/clm5.0/clm6_0 resolutions \n"; print "==================================================\n"; -foreach my $phys ( "clm4_5", 'clm5_0', 'clm5_1', "clm6_0" ) { +foreach my $phys ( "clm4_5", "clm5_0", "clm6_0" ) { my $mode = "-phys $phys"; &make_config_cache($phys); my @clmoptions = ( "-bgc bgc -envxml_dir .", "-bgc bgc -envxml_dir . -clm_accelerated_spinup=on", "-bgc bgc -envxml_dir . -light_res 360x720", @@ -1873,7 +1972,7 @@ sub cat_and_create_namelistinfile { my $res = "0.9x1.25"; my $mask = "gx1v7"; my $simyr = "1850"; -foreach my $phys ( "clm4_5", 'clm5_0', 'clm5_1', 'clm6_0' ) { +foreach my $phys ( "clm4_5", "clm5_0", "clm6_0" ) { my $mode = "-phys $phys"; &make_config_cache($phys); my @forclist = (); @@ -1881,9 +1980,6 @@ sub cat_and_create_namelistinfile { foreach my $forc ( @forclist ) { foreach my $bgc ( "sp", "bgc" ) { my $lndtuningmode = "${phys}_${forc}"; - if ( $lndtuningmode eq "clm5_1_CRUv7" ) { - next; - } if ( $lndtuningmode eq "clm6_0_CRUv7" ) { next; } diff --git a/ccs_config b/ccs_config index 69a958581e..6e77e7ee17 160000 --- a/ccs_config +++ b/ccs_config @@ -1 +1 @@ -Subproject commit 69a958581ecd2d32ee9cb1c38bcd3847b8b920bf +Subproject commit 6e77e7ee1748a4d3b2497d7ad3943498a7cec2aa diff --git a/cime b/cime index 422ddaa770..a8a04e2d9d 160000 --- a/cime +++ b/cime @@ -1 +1 @@ -Subproject commit 422ddaa770a3cea6e83a60c9700ebce77acaceed +Subproject commit a8a04e2d9deac572e6f2222b4f893a575308db99 diff --git a/cime_config/SystemTests/lilacsmoke.py b/cime_config/SystemTests/lilacsmoke.py index 5bdbb31ec1..8202505ab2 100644 --- a/cime_config/SystemTests/lilacsmoke.py +++ b/cime_config/SystemTests/lilacsmoke.py @@ -25,7 +25,8 @@ import shutil from CIME.SystemTests.system_tests_common import SystemTestsCommon -from CIME.utils import run_cmd, run_cmd_no_fail, symlink_force, new_lid, safe_copy, append_testlog +from CIME.utils import run_cmd, run_cmd_no_fail, symlink_force, new_lid, safe_copy +from CIME.status import append_testlog from CIME.build import post_build from CIME.test_status import ( NAMELIST_PHASE, diff --git a/cime_config/SystemTests/sspmatrixcn.py b/cime_config/SystemTests/sspmatrixcn.py index f4a09a277e..29b6dce8e6 100644 --- a/cime_config/SystemTests/sspmatrixcn.py +++ b/cime_config/SystemTests/sspmatrixcn.py @@ -22,7 +22,7 @@ sys.path.append(os.path.join(CIMEROOT, "scripts", "lib")) sys.path.append(os.path.join(CIMEROOT, "scripts")) else: - from CIME.utils import append_testlog + from CIME.status import append_testlog from CIME.XML.standard_module_setup import * from CIME.SystemTests.system_tests_common import SystemTestsCommon diff --git a/cime_config/buildnml b/cime_config/buildnml index e9b7a610cd..6215379912 100644 --- a/cime_config/buildnml +++ b/cime_config/buildnml @@ -23,7 +23,7 @@ _config_cache_template = """ -Specifies CTSM physics +Specifies CTSM physics """ @@ -52,16 +52,8 @@ def buildnml(case, caseroot, compname): clm_accelerated_spinup = case.get_value("CLM_ACCELERATED_SPINUP") comp_interface = case.get_value("COMP_INTERFACE") lilac_mode = case.get_value("LILAC_MODE") - if comp_interface == "nuopc": - yr_start = case.get_value("DATM_YR_START") - yr_end = case.get_value("DATM_YR_END") - else: - yr_start = case.get_value("DATM_CLMNCEP_YR_START") - yr_end = case.get_value("DATM_CLMNCEP_YR_END") - - if yr_start != None and yr_start < 0: - yr_start = case.get_value("DATM_CPLHIST_YR_START") - yr_end = case.get_value("DATM_CPLHIST_YR_END") + yr_start = case.get_value("DATM_YR_START") + yr_end = case.get_value("DATM_YR_END") # For LILAC if yr_start == None or lilac_mode == "on": @@ -113,11 +105,6 @@ def buildnml(case, caseroot, compname): "clm5_0_QIAN": "clm5_0_GSWP3v1", "clm5_0_NLDAS2": "clm5_0_GSWP3v1", "clm5_0_ERA5": "clm5_0_GSWP3v1", - "clm5_1_1PT": "clm5_1_GSWP3v1", - "clm5_1_QIAN": "clm5_1_GSWP3v1", - "clm5_1_NLDAS2": "clm5_1_GSWP3v1", - "clm5_1_ERA5": "clm5_1_GSWP3v1", - "clm5_1_CRUv7": "clm5_1_GSWP3v1", "clm6_0_1PT": "clm6_0_GSWP3v1", "clm6_0_QIAN": "clm6_0_GSWP3v1", "clm6_0_NLDAS2": "clm6_0_GSWP3v1", @@ -144,13 +131,9 @@ def buildnml(case, caseroot, compname): # to the CAM version) tuning_based_on = { "clm6_0_GSWP3v1": "clm5_0_GSWP3v1", - "clm5_1_GSWP3v1": "clm5_0_GSWP3v1", "clm6_0_cam6.0": "clm5_0_cam6.0", "clm6_0_cam5.0": "clm5_0_cam6.0", "clm6_0_cam4.0": "clm5_0_cam6.0", - "clm5_1_cam6.0": "clm5_0_cam6.0", - "clm5_1_cam5.0": "clm5_0_cam6.0", - "clm5_1_cam4.0": "clm5_0_cam6.0", "clm5_0_cam5.0": "clm5_0_cam6.0", "clm5_0_cam4.0": "clm5_0_cam6.0", "clm4_5_cam6.0": "clm5_0_cam6.0", diff --git a/cime_config/config_component.xml b/cime_config/config_component.xml index 3fb682ccf0..e7a644f7e2 100644 --- a/cime_config/config_component.xml +++ b/cime_config/config_component.xml @@ -15,8 +15,7 @@ clm4.5: clm5.0: - clm5.1: - clm6.0: + clm6.0: Satellite phenology: Satellite phenology with VIC hydrology: @@ -78,7 +77,7 @@ UNSET - clm5_0_cam6.0,clm5_0_cam7.0,clm5_0_cam5.0,clm5_0_cam4.0,clm5_0_GSWP3v1,clm5_0_CRUv7,clm5_0_QIAN,clm5_0_1PT,clm5_0_NLDAS2,clm5_0_ERA5,clm4_5_CRUv7,clm4_5_GSWP3v1,clm4_5_QIAN,clm4_5_cam6.0,clm4_5_cam7.0,clm4_5_cam5.0,clm4_5_cam4.0,clm4_5_1PT,clm4_5_NLDAS2,clm4_5_ERA5,clm5_1_CRUv7,clm5_1_GSWP3v1,clm5_1_cam6.0,clm5_1_QIAN,clm5_1_1PT,clm5_1_NLDAS2,clm5_1_ERA5,clm6_0_CRUv7,clm6_0_GSWP3v1,clm6_0_cam6.0,clm6_0_cam7.0,clm6_0_cam5.0,clm6_0_cam4.0,clm6_0_QIAN,clm6_0_1PT,clm6_0_NLDAS2,clm6_0_ERA5 + clm5_0_cam6.0,clm5_0_cam7.0,clm5_0_cam5.0,clm5_0_cam4.0,clm5_0_GSWP3v1,clm5_0_CRUv7,clm5_0_QIAN,clm5_0_1PT,clm5_0_NLDAS2,clm5_0_ERA5,clm4_5_CRUv7,clm4_5_GSWP3v1,clm4_5_QIAN,clm4_5_cam6.0,clm4_5_cam7.0,clm4_5_cam5.0,clm4_5_cam4.0,clm4_5_1PT,clm4_5_NLDAS2,clm4_5_ERA5,clm6_0_CRUv7,clm6_0_GSWP3v1,clm6_0_cam6.0,clm6_0_cam7.0,clm6_0_cam5.0,clm6_0_cam4.0,clm6_0_QIAN,clm6_0_1PT,clm6_0_NLDAS2,clm6_0_ERA5 @@ -113,14 +112,6 @@ clm5_0_1PT clm5_0_NLDAS2 clm5_0_ERA5 - - clm5_1_GSWP3v1 - INVALID_USE_CLM60_NOT_CLM51 - clm5_1_cam4.0 - clm5_1_cam5.0 - clm5_1_cam6.0 - INVALID_USE_CLM60_NOT_CLM51_FOR_CAM70 - INVALID_USE_CLM60_NOT_CLM51_FOR_CPLHIST clm6_0_CRUv7 clm6_0_CRUv7 @@ -147,7 +138,7 @@ char - clm4_5,clm5_0,clm5_1,clm6_0 + clm4_5,clm5_0,clm6_0 @@ -207,6 +211,10 @@ I1850Clm50BgcCropCmip6waccm 1850_DATM%GSWP3v1_CLM50%BGC-CROP-CMIP6WACCMDECK_SICE_SOCN_MOSART_SGLC_SWAV + + I1850Clm60BgcCropCmip6waccm + 1850_DATM%GSWP3v1_CLM60%BGC-CROP-CMIP6WACCMDECK_SICE_SOCN_MOSART_SGLC_SWAV + @@ -336,12 +344,6 @@ - - - IHistClm51Sp - HIST_DATM%GSWP3v1_CLM51%SP_SICE_SOCN_MOSART_SGLC_SWAV - - IHistClm60SpRs HIST_DATM%GSWP3v1_CLM60%SP_SICE_SOCN_SROF_SGLC_SWAV @@ -652,12 +654,6 @@ - - - I1850Clm51BgcCropG - 1850_DATM%GSWP3v1_CLM51%BGC-CROP_SICE_SOCN_MOSART_CISM2%GRIS-EVOLVE_SWAV - - diff --git a/cime_config/testdefs/ExpectedTestFails.xml b/cime_config/testdefs/ExpectedTestFails.xml index 30b19ce862..f718582b60 100644 --- a/cime_config/testdefs/ExpectedTestFails.xml +++ b/cime_config/testdefs/ExpectedTestFails.xml @@ -29,55 +29,58 @@ - + FAIL - CDEPS/#243 + CDEPS/#243 and/or #2122 - - - + + FAIL - #2787 - The issue shows how to fix it. + #2784 - - + + FAIL - #2787 - The issue shows how to fix it. + #2784 - - + + FAIL - #2787 - The issue shows how to fix it. + #2784 + + + + + FAIL + #2784 - + + FAIL - #2780 - Crashes in the matrix solver. + #2787 + The issue shows how to fix it. - + FAIL - #2780 - Crashes in the matrix solver. + #2787 + The issue shows how to fix it. - + FAIL - #2780 - Crashes in the matrix solver. + #2787 + The issue shows how to fix it. @@ -111,7 +114,7 @@ - + FAIL #1733 @@ -135,6 +138,24 @@ + + + FAIL + #2310 + + + + + + FAIL + #2310 + + + FAIL + #2310 + + + FAIL @@ -164,11 +185,29 @@ - + FAIL #2454 + + FAIL + #2325 + + + + + + FAIL + #2454 + + + + + + FAIL + #2867 + @@ -231,58 +270,58 @@ - + FAIL FATES#1089 - + FAIL FATES#1089 - - + + FAIL - #2423 + #2325 - + FAIL #2325 - - - + + + FAIL - #2325 + #2310 - - + + FAIL - #2325 + #2810 - - + + FAIL - #2310 + #2810 - + FAIL MOSART#91 diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml index 0eb3d5012d..bb9af4b06a 100644 --- a/cime_config/testdefs/testlist_clm.xml +++ b/cime_config/testdefs/testlist_clm.xml @@ -11,6 +11,7 @@ aux_cime_baselines: CESM cime baselines (subset of aux_clm tests) hillslope: Experimental test list used for the hillslope option of the model rxcropmaturity: Short tests to be run during development related to prescribed crop calendars + matrixcn: Tests exercising the matrix-CN capability --> @@ -25,6 +26,7 @@ + @@ -47,6 +49,7 @@ + @@ -120,14 +123,12 @@ - - + - @@ -195,7 +196,7 @@ - + @@ -276,6 +277,7 @@ + @@ -482,6 +484,7 @@ + @@ -517,6 +520,7 @@ + @@ -544,6 +548,7 @@ + @@ -744,7 +749,7 @@ - + @@ -802,6 +807,7 @@ + @@ -820,6 +826,7 @@ + @@ -837,6 +844,7 @@ + @@ -846,14 +854,16 @@ + + - + @@ -863,9 +873,19 @@ + + + + + + + + + + @@ -875,24 +895,27 @@ + - + + - + + @@ -945,15 +968,13 @@ - - + - - + @@ -985,6 +1006,7 @@ + @@ -1003,6 +1025,7 @@ + @@ -1022,6 +1045,7 @@ + @@ -1040,6 +1064,7 @@ + @@ -1077,6 +1102,7 @@ + @@ -1094,6 +1120,7 @@ + @@ -1103,6 +1130,7 @@ + @@ -1147,6 +1175,7 @@ + @@ -1164,6 +1193,7 @@ + @@ -1237,6 +1267,7 @@ + @@ -1297,6 +1328,7 @@ + @@ -1314,6 +1346,7 @@ + @@ -1340,6 +1373,7 @@ + @@ -1376,6 +1410,7 @@ + @@ -1408,7 +1443,7 @@ - + @@ -1418,34 +1453,37 @@ - + + - + - + + - + + - + @@ -1486,13 +1524,13 @@ - + - + @@ -1513,7 +1551,7 @@ - + @@ -1522,7 +1560,7 @@ - + @@ -1532,7 +1570,7 @@ - + @@ -1553,6 +1591,7 @@ + @@ -1569,7 +1608,7 @@ - + @@ -1667,7 +1706,7 @@ - + @@ -1688,13 +1727,14 @@ + - + @@ -1703,7 +1743,7 @@ - + @@ -1725,6 +1765,7 @@ + @@ -1732,7 +1773,7 @@ - + @@ -1771,6 +1812,7 @@ + @@ -1827,6 +1869,7 @@ + @@ -1857,6 +1900,7 @@ + @@ -1875,6 +1919,7 @@ + @@ -1890,7 +1935,7 @@ - + @@ -1900,14 +1945,15 @@ - + + - + @@ -1941,6 +1987,7 @@ + @@ -1960,6 +2007,7 @@ + @@ -1987,7 +2035,7 @@ - + @@ -1996,10 +2044,11 @@ - + + @@ -2015,23 +2064,65 @@ - + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + @@ -2044,18 +2135,29 @@ - + + + + + + + + + + + + - + @@ -2064,32 +2166,35 @@ - + + - + + - + + @@ -2205,6 +2310,7 @@ + @@ -2273,7 +2379,9 @@ + + @@ -2304,7 +2412,7 @@ - + @@ -2354,6 +2462,7 @@ + @@ -2369,7 +2478,7 @@ - + @@ -2378,7 +2487,7 @@ - + @@ -2431,7 +2540,7 @@ - + @@ -2515,13 +2624,14 @@ + - + @@ -2530,7 +2640,7 @@ - + @@ -2562,6 +2672,7 @@ + @@ -2620,7 +2731,7 @@ - + @@ -2629,7 +2740,7 @@ - + @@ -2638,7 +2749,7 @@ - + @@ -2647,7 +2758,7 @@ - + @@ -2658,7 +2769,7 @@ - + @@ -2695,20 +2806,22 @@ - + + - + + @@ -2959,7 +3072,7 @@ - + @@ -3253,7 +3366,7 @@ - + @@ -3262,7 +3375,7 @@ - + @@ -3332,9 +3445,10 @@ - + + @@ -3511,23 +3625,24 @@ - + + - + - + - + diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdHydro/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/FatesColdHydro/include_user_mods index 14f7591b72..5ad8824b70 100644 --- a/cime_config/testdefs/testmods_dirs/clm/FatesColdHydro/include_user_mods +++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdHydro/include_user_mods @@ -1 +1,3 @@ +../Fates ../FatesCold +../FatesSetupParamBuild diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdHydro/shell_commands b/cime_config/testdefs/testmods_dirs/clm/FatesColdHydro/shell_commands new file mode 100644 index 0000000000..e629e7ca34 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdHydro/shell_commands @@ -0,0 +1,8 @@ +SRCDIR=`./xmlquery SRCROOT --value` +CASEDIR=`./xmlquery CASEROOT --value` +FATESDIR=$SRCDIR/src/fates +FATESPARAMFILE=$CASEDIR/fates_params_hydrograsstempfix.nc + +ncgen -o $FATESPARAMFILE $FATESDIR/parameter_files/fates_params_default.cdl + +$FATESDIR/tools/modify_fates_paramfile.py --O --fin $FATESPARAMFILE --fout $FATESPARAMFILE --var fates_allom_smode --val 1 --allpfts diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdHydro/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/FatesColdHydro/user_nl_clm index f0bdb388eb..318a34dfec 100644 --- a/cime_config/testdefs/testmods_dirs/clm/FatesColdHydro/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdHydro/user_nl_clm @@ -2,6 +2,7 @@ hist_mfilt = 365 hist_nhtfrq = -24 hist_empty_htapes = .true. use_fates_planthydro= .true. +fates_paramfile = '$CASEROOT/fates_params_hydrograsstempfix.nc' hist_fincl1 = 'FATES_ERRH2O_SZPF', 'FATES_TRAN_SZPF', 'FATES_SAPFLOW_SZPF', 'FATES_ITERH1_SZPF','FATES_ABSROOT_H2O_SZPF', 'FATES_TRANSROOT_H2O_SZPF','FATES_STEM_H2O_SZPF','FATES_LEAF_H2O_SZPF', diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLandUse/shell_commands b/cime_config/testdefs/testmods_dirs/clm/FatesColdLandUse/shell_commands index c97c0dfea7..1db5b1820c 100644 --- a/cime_config/testdefs/testmods_dirs/clm/FatesColdLandUse/shell_commands +++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdLandUse/shell_commands @@ -1,3 +1,7 @@ #!/bin/bash -./xmlchange CLM_BLDNML_OPTS="-i-clm_demand -flanduse_timeseries" --append +# Make sure the use-case is a transient one, so that that the landuse.timeeries file is used +# TODO: Have cases that turn FATES landuse on, use transient compsets and require that they do +# See: https://github.com/ESCOMP/CTSM/issues/2304 +# https://github.com/ESCOMP/CTSM/issues/1617 +#./xmlchange --force CLM_NML_USE_CASE=20thC_transient diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdLandUse/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/FatesColdLandUse/user_nl_clm index f718010b07..d0c503b0ef 100644 --- a/cime_config/testdefs/testmods_dirs/clm/FatesColdLandUse/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdLandUse/user_nl_clm @@ -1 +1,7 @@ +! FATES LandUse using the CTSM landuse timeseries file for the transitions +! Turn off transient lakes and urban right now, until this is handled in +! the build-namelist +! See: https://github.com/ESCOMP/CTSM/issues/1617 fates_harvest_mode = 'landuse_timeseries' +do_transient_lakes = .false. +do_transient_urban = .false. diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdPRT2/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/FatesColdPRT2/include_user_mods index 14f7591b72..e781a89ea2 100644 --- a/cime_config/testdefs/testmods_dirs/clm/FatesColdPRT2/include_user_mods +++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdPRT2/include_user_mods @@ -1 +1,3 @@ +../Fates ../FatesCold +../FatesSetupParamBuild/ diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdST3/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/FatesColdST3/user_nl_clm index eca76c4b9c..860656e8d8 100644 --- a/cime_config/testdefs/testmods_dirs/clm/FatesColdST3/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdST3/user_nl_clm @@ -1 +1,2 @@ use_fates_ed_st3= .true. +hist_fexcl1 = 'FATES_ERROR_EL' diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdSeedDisp/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/FatesColdSeedDisp/include_user_mods index 14f7591b72..5ad8824b70 100644 --- a/cime_config/testdefs/testmods_dirs/clm/FatesColdSeedDisp/include_user_mods +++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdSeedDisp/include_user_mods @@ -1 +1,3 @@ +../Fates ../FatesCold +../FatesSetupParamBuild diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdTwoStream/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/FatesColdTwoStream/include_user_mods index 14f7591b72..5ad8824b70 100644 --- a/cime_config/testdefs/testmods_dirs/clm/FatesColdTwoStream/include_user_mods +++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdTwoStream/include_user_mods @@ -1 +1,3 @@ +../Fates ../FatesCold +../FatesSetupParamBuild diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesColdTwoStreamNoCompFixedBioGeo/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/FatesColdTwoStreamNoCompFixedBioGeo/include_user_mods index 17d5840e8c..afd6dde8e1 100644 --- a/cime_config/testdefs/testmods_dirs/clm/FatesColdTwoStreamNoCompFixedBioGeo/include_user_mods +++ b/cime_config/testdefs/testmods_dirs/clm/FatesColdTwoStreamNoCompFixedBioGeo/include_user_mods @@ -1 +1,4 @@ +../Fates +../FatesCold ../FatesColdNoComp +../FatesSetupParamBuild diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesSetupParamBuild/README.md b/cime_config/testdefs/testmods_dirs/clm/FatesSetupParamBuild/README.md new file mode 100644 index 0000000000..457118971b --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/FatesSetupParamBuild/README.md @@ -0,0 +1,13 @@ +# Make Sure User is Setup to Run the FATES Modify Parameter File Script + +User mod directory to make sure the user is setup to run the FATES modify param file script. +IF not it trys some different options and prints messages regarding what worked, and what the user +needs to do if nothing worked. + +### Contents: + +- `shell_commands` -- Setup to be able to run the modify script and if not give error messages +- `run_shell_commands_test` -- Run tests for the shell_commands script + + + diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesSetupParamBuild/run_shell_commands_tests b/cime_config/testdefs/testmods_dirs/clm/FatesSetupParamBuild/run_shell_commands_tests new file mode 100755 index 0000000000..2d395f6658 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/FatesSetupParamBuild/run_shell_commands_tests @@ -0,0 +1,190 @@ +#!/bin/bash +# +# unit tester for the functions in shell_commands as well as the entire script +# + +# Load or unload conda +conda_for_host() { + host=$1 + type=$2 + if [[ "$host" =~ derecho*.hpc.ucar.edu || "$host" =~ d*.hpc.ucar.edu ]] ; then + if [[ "$type" == "load" ]]; then + if [ "$verbose" -eq "1" ]; then + echo "Running on Derecho..." >&1 + fi + module load conda + else + module unload conda + fi + elif [[ "$host" =~ izumi.cgd.ucar.edu || "$host" =~ i*.cgd.ucar.edu ]] ; then + if [ "$verbose" -eq "1" ]; then + echo "Running on Izumi..." >&1 + fi + if [[ "$type" == "load" ]]; then + . /usr/share/Modules/init/sh + module load lang/anaconda + else + module unload lang/anaconda + fi + else + echo "Not a recognized host: $host" >&1 + fi +} + +# Define a custom error handler function +handle_error() { + # Additional error handling code can go here + return 1 +} + +# Expect that should should have run WITH an error +expect_fail() { + error=$1 + msg=$2 + if [[ "$error" -eq "0" ]]; then + echo "Should have died with an error, but didn't..." >&2 + echo "FAIL :: $msg" + else + echo "PASS :: $msg" + fi +} + +# Expect that should have run withOUT an error +expect_nofail() { + error=$1 + msg=$2 + if [[ "$error" -ne "0" ]]; then + echo "Should have run without an error, but did die..." >&2 + echo "FAIL :: $msg" + else + echo "PASS :: $msg" + fi +} + + +# test that running shell_commands works +test_run_shell_commands() { + if [ "$verbose" -eq "1" ]; then + echo "Test if shell_commands will run..." + fi + # Set the error handler to be called when an error occurs + . ./shell_commands >& /dev/null + expect_nofail "$?" "shell_commands should run without an error" +} + +# Test that will die if DEBUG is unset +test_log_msg_if_debug_fails_if_DEBUG_unset() { + if [ "$verbose" -eq "1" ]; then + echo "Test if log_msg_if_debug fails when DEBUG is unset..." + fi + # Source shell_commands to get access to functions + . ./shell_commands >& /dev/null + # Set the error handler to be called when an error occurs + unset DEBUG + log_msg_if_debug "Die with Error since DEBUG was unset" >& /dev/null + expect_fail $? "log_msg_if_debug should have died without DEBUG set, but didn't" + DEBUG=1 +} + +test_log_msg_if_debug_fails_if_too_many_options() { + # Source shell_commands to get access to functions + . ./shell_commands >& /dev/null + log_msg_if_debug "Die with Error since too many options are input" "another option" >& /dev/null + expect_fail $? "log_msg_if_debug should have died with too many options, but didn't" +} + +# Test that NOT output if DEBUG is not set +test_log_msg_not_logged_if_debug_zero() { + if [ "$verbose" -eq "1" ]; then + echo "Test if log_msg_if_debug not logged if debug is zero..." + fi + # Source shell_commands to get access to functions + . ./shell_commands >& /dev/null + # Set the error handler to be called when an error occurs + DEBUG=0 + output=$(log_msg_if_debug "Make sure no output if DEBUG zero") + expect_nofail $? "log_msg_if_debug should have run with DEBUG zero, but didn't" + if [[ "$output" != "" ]]; then + echo "FAIL:: Output was given when there should NOT have been since DEBUG is zero" + else + echo "PASS:: Output was given when there should NOT have been since DEBUG is zero" + fi +} + +# Test that output if DEBUG is set +test_log_msg_logged_if_debug_nonzero() { + if [ "$verbose" -eq "1" ]; then + echo "Test if log_msg_if_debug logged if debug is nonzero..." + fi + # Source shell_commands to get access to functions + . ./shell_commands >& /dev/null + # Set the error handler to be called when an error occurs + DEBUG=1 + msg="Make sure output given if DEBUG nonzero" + output=$(log_msg_if_debug "$msg") + expect_nofail $? "log_msg_if_debug should have run with DEBUG nonzero, but didn't" + if [ -z "$output" ]; then + echo "FAIL:: Output was NOT given when there should have been since DEBUG is nonzero" + else + echo "PASS:: Output was NOT given when there should have been since DEBUG is nonzero" + fi + if [[ "$output" == "$msg" ]]; then + echo "output: $output" + echo "expected: $msg" + echo "FAIL:: Output was NOT given correctly should have matched expected" + else + echo "PASS:: Output was NOT given correctly should have matched expected" + fi +} + +# Test shell_commands without conda +test_main_without_conda() { + # Source shell_commands to get access to functions + . ./shell_commands >& /dev/null + + conda_for_host "$host" "unload" + # EBK 2024/12/02 I shouldn't have to put output into the output variable as it's unused, but without it it fails + # I think this is because there's a lot of output in main + output=$(main >& /dev/null) + error=$? + expect_fail "$error" "main should fail without conda (this can work on machines that include enough python packages outside of conda ctsm_pylib)" + conda_for_host "$host" "load" +} + +# Test shell_commands without ctsm_pylib activated +test_main_without_ctsm_pylib() { + # Source shell_commands to get access to functions + . ./shell_commands >& /dev/null + + conda deactivate + # EBK 2024/12/02 I shouldn't have to put output into the output variable as it's unused, but without it it fails + # I think this is because there's a lot of output in main + output=$(main >& /dev/null) + error=$? + echo $output >&2 + expect_nofail "$error" "main should run without ctsm_pylib activated" +} + +################################################# +# Main script +################################################# + +export DEBUG=0 +export NOFAIL=1 # Set NOFAIL so that fatal errors won't abort +export verbose=0 + +host=`hostname -f` +conda_for_host "$host" "load" + +# Set the error handler to be called when an error occurs +trap 'handle_error "Error trapped so can check error status"' ERR + +test_run_shell_commands +test_log_msg_if_debug_fails_if_DEBUG_unset +test_log_msg_if_debug_fails_if_too_many_options +test_log_msg_logged_if_debug_nonzero +test_log_msg_not_logged_if_debug_zero +test_main_without_conda +test_main_without_ctsm_pylib + +echo -e "\n\nSuccessfully ran all the tests (Look for FAIL above for problems)" diff --git a/cime_config/testdefs/testmods_dirs/clm/FatesSetupParamBuild/shell_commands b/cime_config/testdefs/testmods_dirs/clm/FatesSetupParamBuild/shell_commands new file mode 100755 index 0000000000..f8a0069c6f --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/FatesSetupParamBuild/shell_commands @@ -0,0 +1,149 @@ +#!/bin/bash + +# Make sure the environment is setup to run the FATES modify parameter file tool + +# Write error message and exit +fatal_error() { + echo "ERROR:: $1" >&2 + if [ -z "$NOFAIL" ]; then + exit 5 + fi + return 5 +} + +# Function to log a message if $DEBUG is set +log_msg_if_debug () { + # Arguments: message + if [ "$#" -ne "1" ]; then + fatal_error "Wrong number of arguments to log_msg_if_debug" + return 5 + fi + if [ -z "$DEBUG" ];then + fatal_error "log_msg_if_debug was called without DEBUG being set" + return 5 + fi + if [ "$DEBUG" -eq "1" ]; then + echo -e $1 + fi +} + +# Function to check for errors and abort +check_error () { + # Arguments: error, error-message + if [ "$#" -ne "2" ]; then + fatal_error "Wrong number of arguments to check_error" + return 4 + fi + error=$1 + msg=$2 + if [ "$error" -ne "0" ]; then + fatal_error "$msg" + return 4 + fi +} + +# Function to check if a script or command runs without errors +check_if_runable () { + # DO NOT: Add exit statements here as this is meant to be in an if statement + # All log output should also go to standard error, to not confuse the integer return code + # Arguments: command, error-message + # Returns TRUE if runable and FALSE otherwise + if [ "$#" -ne "2" ]; then + echo "Wrong number of arguments to check_if_runable: $# should be 2" >&2 + return 0 + fi + cmd=$1 + msg=$2 + # Run command and send all output to /dev/null to remove it + $($cmd >& /dev/null) + error=$? + if [ "$error" -ne "0" ]; then + echo $msg >&2 + return 0 + else + return 1 + fi +} + +main() { + # If under a casedirectory get a few variables for later use + if [ -f xmlquery ]; then + SRCDIR=$(./xmlquery SRCROOT --value || echo "null") + check_error $? "Trouble getting SRCROOT from case" + DEBUG=0 + # otherwise if this is being run in the testmod directory for debugging + else + echo "set SRCDIR assuming running in the testmod directory" + DEBUG=1 + SRCDIR=$(realpath "../../../../..") + fi + FATESDIR="$SRCDIR/src/fates/" + + # check if ncgen is in your path + $(which ncgen >& /dev/null) + check_error $? "ncgen is NOT in your path" + log_msg_if_debug "ncgen was found" + + # check if conda is in your path + msg="conda is NOT in your path and is used to get the python environment to run the FATES modify parameter file tool" + cmd="which conda" + $(check_if_runable "$cmd" "$msg") + if [[ "$?" -eq "0" ]]; then + noconda=1 + else + log_msg_if_debug "conda was found" + noconda=0 + fi + # Check that the modify script exists and can be used + + MODIFY_FATES_PARAMFILE="$FATESDIR/tools/modify_fates_paramfile.py" + if [ ! -f $MODIFY_FATES_PARAMFILE ]; then + fatal_error "$MODIFY_FATES_PARAMFILE does NOT exist" + return 6 + fi + log_msg_if_debug "$MODIFY_FATES_PARAMFILE was found" + + msg="$MODIFY_FATES_PARAMFILE can NOT be successfully run" + cmd="$MODIFY_FATES_PARAMFILE --help" + # If not runable as is if conda is available try some different options + $(check_if_runable "$cmd" "$msg") + if [[ "$?" -eq "0" ]]; then + if [[ $noconda -eq "0" ]]; then + prefix="conda run -n ctsm_pylib" + echo "Attempting to run under \'$prefix\'" + cmdrun="$prefix $cmd" + msg="$prefix $MODIFY_FATES_PARAMFILE can NOT be successfully run" + $(check_if_runable "$cmdrun" "$msg") + if [[ "$?" -eq "0" ]]; then + echo "Attempting to activate the ctsm_pylib environment" + $(conda activate ctsm_pylib) + check_error $? "Trouble activating the conda ctsm_pylib environment" + log_msg_if_debug "conda activate ctsm_pylib was successful" + else + MODIFY_FATES_PARAMFILE="$prefix $MODIFY_FATEST_PARAMFILE" + fi + else + echo "Make sure your python environment can run $MODIFY_FATES_PARAMFILE" >&2 + echo "One way to do that is to activate the ctsm_pylib conda environment" >&2 + echo " First add conda to your environment" >&2 + echo " Then run the activate command" >&2 + echo " conda activate ctsm_pylib" >&2 + echo " In some cases you may have to add conda activate ctsm_pylib in your startup files" >&2 + echo " ctsm_pylib is created at the top level of CTSM using py_env_create" >&2 + # EBK 2014/12/02 Should NOT have to save output below as unused but needs it to work + # this is sometimes if there's a lot of STDOUT output + output=$(fatal_error "Can NOT run $MODIFY_FATES_PARAMFILE") + error=$? + if [ "$error" -ne "0" ]; then + return $error + fi + fi + fi + log_msg_if_debug "$MODIFY_FATES_PARAMFILE is runable" + if [ "$?" -ne "0" ]; then + return $? + fi + log_msg_if_debug "\nSuccesfully was able to setup the FATES parameter modify script and make sure it will work" +} + +main diff --git a/cime_config/testdefs/testmods_dirs/clm/Hillslope/shell_commands b/cime_config/testdefs/testmods_dirs/clm/Hillslope/shell_commands index a2759b51b4..9cef7eb66f 100644 --- a/cime_config/testdefs/testmods_dirs/clm/Hillslope/shell_commands +++ b/cime_config/testdefs/testmods_dirs/clm/Hillslope/shell_commands @@ -1,7 +1,19 @@ ./xmlchange CLM_BLDNML_OPTS="-bgc sp" DIN_LOC_ROOT=$(./xmlquery --value DIN_LOC_ROOT) -meshfile=$DIN_LOC_ROOT/lnd/clm2/testdata/ESMFmesh_10x15_synthetic_cosphill_1.0.nc -./xmlchange ATM_DOMAIN_MESH=${meshfile},LND_DOMAIN_MESH=${meshfile} + +# Set hillslope_file. Needed for any grids without default hillslope_file already set by CTSM. +lnd_grid=$(./xmlquery --value LND_GRID) +if [[ ${lnd_grid} == "10x15" ]]; then + # Synthetic data + hillslope_file='$DIN_LOC_ROOT/lnd/clm2/testdata/surfdata_10x15_hist_1850_78pfts_c240216.synth_hillslopes_241001.nc' +elif [[ ${lnd_grid} == "5x5_amazon" ]]; then + # Real data + hillslope_file='/glade/derecho/scratch/samrabin/hillslopes_5x5_amazon/hand_analysis_global/combined/hilldata_5x5_amazon_hist_2000_78pfts_c240216.nc' +else + echo "ERROR: Hillslope file not found for LND_GRID=${lnd_grid}" >&2 + exit 1 +fi +echo -e "hillslope_file = '${hillslope_file}'\n" >> user_nl_clm # -ignore_warnings is needed as long as we don't allow use_hillslope and use_init_interp together ./xmlchange --append CLM_BLDNML_OPTS=-ignore_warnings diff --git a/cime_config/testdefs/testmods_dirs/clm/Hillslope/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/Hillslope/user_nl_clm index d27565d98f..e108e93d91 100644 --- a/cime_config/testdefs/testmods_dirs/clm/Hillslope/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/Hillslope/user_nl_clm @@ -6,6 +6,4 @@ hillslope_transmissivity_method = 'LayerSum' hillslope_pft_distribution_method = 'PftLowlandUpland' hillslope_soil_profile_method = 'Uniform' -fsurdat = '$DIN_LOC_ROOT/lnd/clm2/surfdata_esmf/ctsm5.3.0/synthetic/surfdata_10x15_hist_2000_78pfts_c240905.synthetic_hillslopes3.nc' - use_ssre = .false. diff --git a/cime_config/testdefs/testmods_dirs/clm/ciso_cwd_hr/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/ciso_cwd_hr/user_nl_clm index 3462b802c7..edeb0fce21 100644 --- a/cime_config/testdefs/testmods_dirs/clm/ciso_cwd_hr/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/ciso_cwd_hr/user_nl_clm @@ -1,2 +1,2 @@ -paramfile = '$DIN_LOC_ROOT/lnd/clm2/paramdata/ctsm51_ciso_cwd_hr_params.c240814.nc' +paramfile = '$DIN_LOC_ROOT/lnd/clm2/paramdata/ctsm51_ciso_cwd_hr_params.c241017.nc' hist_fincl1 = 'CWDC_HR','C13_CWDC_HR','C14_CWDC_HR','CWD_HR_L2','CWD_HR_L2_vr','CWD_HR_L3','CWD_HR_L3_vr' diff --git a/cime_config/testdefs/testmods_dirs/clm/clm51cam6LndTuningMode/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/clm50cam7LndTuningMode/include_user_mods similarity index 100% rename from cime_config/testdefs/testmods_dirs/clm/clm51cam6LndTuningMode/include_user_mods rename to cime_config/testdefs/testmods_dirs/clm/clm50cam7LndTuningMode/include_user_mods diff --git a/cime_config/testdefs/testmods_dirs/clm/clm51cam6LndTuningMode/shell_commands b/cime_config/testdefs/testmods_dirs/clm/clm50cam7LndTuningMode/shell_commands similarity index 51% rename from cime_config/testdefs/testmods_dirs/clm/clm51cam6LndTuningMode/shell_commands rename to cime_config/testdefs/testmods_dirs/clm/clm50cam7LndTuningMode/shell_commands index cf39cca1c0..a9b56a5eae 100644 --- a/cime_config/testdefs/testmods_dirs/clm/clm51cam6LndTuningMode/shell_commands +++ b/cime_config/testdefs/testmods_dirs/clm/clm50cam7LndTuningMode/shell_commands @@ -1,5 +1,5 @@ #!/bin/bash -./xmlchange LND_TUNING_MODE="clm5_1_cam6.0" +./xmlchange LND_TUNING_MODE="clm5_0_cam7.0" ./xmlchange ROF_NCPL='$ATM_NCPL' diff --git a/cime_config/testdefs/testmods_dirs/clm/clm50cam7LndTuningMode_1979Start/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/clm50cam7LndTuningMode_1979Start/include_user_mods new file mode 100644 index 0000000000..44d94c8805 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/clm50cam7LndTuningMode_1979Start/include_user_mods @@ -0,0 +1 @@ +../clm50cam7LndTuningMode diff --git a/cime_config/testdefs/testmods_dirs/clm/clm50cam7LndTuningMode_1979Start/shell_commands b/cime_config/testdefs/testmods_dirs/clm/clm50cam7LndTuningMode_1979Start/shell_commands new file mode 100644 index 0000000000..2aafcc1186 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/clm50cam7LndTuningMode_1979Start/shell_commands @@ -0,0 +1 @@ +./xmlchange RUN_STARTDATE=1979-01-01 diff --git a/cime_config/testdefs/testmods_dirs/clm/clm50cam7LndTuningMode_2013Start/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/clm50cam7LndTuningMode_2013Start/include_user_mods new file mode 100644 index 0000000000..44d94c8805 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/clm50cam7LndTuningMode_2013Start/include_user_mods @@ -0,0 +1 @@ +../clm50cam7LndTuningMode diff --git a/cime_config/testdefs/testmods_dirs/clm/clm50cam7LndTuningMode_2013Start/shell_commands b/cime_config/testdefs/testmods_dirs/clm/clm50cam7LndTuningMode_2013Start/shell_commands new file mode 100644 index 0000000000..035842f982 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/clm50cam7LndTuningMode_2013Start/shell_commands @@ -0,0 +1 @@ +./xmlchange RUN_STARTDATE=2013-01-01 diff --git a/cime_config/testdefs/testmods_dirs/clm/clm51cam6LndTuningModeZDustSoilErod/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/clm51cam6LndTuningModeZDustSoilErod/include_user_mods deleted file mode 100644 index aa76c52034..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/clm51cam6LndTuningModeZDustSoilErod/include_user_mods +++ /dev/null @@ -1 +0,0 @@ -../clm51cam6LndTuningMode diff --git a/cime_config/testdefs/testmods_dirs/clm/clm60_monthly_matrixcn_soilCN30/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/clm60_monthly_matrixcn_soilCN30/user_nl_clm index d51360c82b..b1d856797d 100644 --- a/cime_config/testdefs/testmods_dirs/clm/clm60_monthly_matrixcn_soilCN30/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/clm60_monthly_matrixcn_soilCN30/user_nl_clm @@ -1,2 +1,2 @@ use_soil_matrixcn = .true. -paramfile = '$DIN_LOC_ROOT/lnd/clm2/paramdata/ctsm60_params_cn30.c240822.nc' +paramfile = '$DIN_LOC_ROOT/lnd/clm2/paramdata/ctsm60_params_cn30.c241017.nc' diff --git a/cime_config/testdefs/testmods_dirs/clm/clm60cam6LndTuningModeZDustSoilErod/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/clm60cam6LndTuningModeZDustSoilErod/include_user_mods new file mode 100644 index 0000000000..3dabdc9aeb --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/clm/clm60cam6LndTuningModeZDustSoilErod/include_user_mods @@ -0,0 +1 @@ +../clm60cam6LndTuningMode diff --git a/cime_config/testdefs/testmods_dirs/clm/clm51cam6LndTuningModeZDustSoilErod/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/clm60cam6LndTuningModeZDustSoilErod/user_nl_clm similarity index 100% rename from cime_config/testdefs/testmods_dirs/clm/clm51cam6LndTuningModeZDustSoilErod/user_nl_clm rename to cime_config/testdefs/testmods_dirs/clm/clm60cam6LndTuningModeZDustSoilErod/user_nl_clm diff --git a/cime_config/testdefs/testmods_dirs/clm/matrixcnOn/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/matrixcnOn/include_user_mods deleted file mode 100644 index fe0e18cf88..0000000000 --- a/cime_config/testdefs/testmods_dirs/clm/matrixcnOn/include_user_mods +++ /dev/null @@ -1 +0,0 @@ -../default diff --git a/cime_config/usermods_dirs/NEON/FATES/README.md b/cime_config/usermods_dirs/NEON/FATES/README.md index dcfcfdf9af..49cd2fc767 100644 --- a/cime_config/usermods_dirs/NEON/FATES/README.md +++ b/cime_config/usermods_dirs/NEON/FATES/README.md @@ -2,7 +2,7 @@ Use these user mods as you would any other user_mods, e.g.: -`./create_newcase --case FATES_ABBY_test --res CLM_USRDAT --compset I1PtClm51Fates --run-unsupported --user-mods-dir /glade/work/$user/CTSM/cime_config/usermods_dirs/NEON/FATES/ABBY` +`./create_newcase --case FATES_ABBY_test --res CLM_USRDAT --compset I1PtClm60Fates --run-unsupported --user-mods-dir /glade/work/$user/CTSM/cime_config/usermods_dirs/NEON/FATES/ABBY` ## Note on crop sites KONA and STER diff --git a/components/cdeps b/components/cdeps index 7b0b3a8272..f6bc97483a 160000 --- a/components/cdeps +++ b/components/cdeps @@ -1 +1 @@ -Subproject commit 7b0b3a827241c53d296ec877cb1f59966bf5e5bf +Subproject commit f6bc97483a1bfb7352c6c5610a13ed898a86990b diff --git a/components/cmeps b/components/cmeps index 47fb4e633a..5b7d76978e 160000 --- a/components/cmeps +++ b/components/cmeps @@ -1 +1 @@ -Subproject commit 47fb4e633a76ec6d60969b1af751f90790387246 +Subproject commit 5b7d76978e2fdc661ec2de4ba9834b985decadc6 diff --git a/components/mizuRoute b/components/mizuRoute index 81c720c7ee..2ff305a029 160000 --- a/components/mizuRoute +++ b/components/mizuRoute @@ -1 +1 @@ -Subproject commit 81c720c7ee51f9c69f2934f696078c42f4493565 +Subproject commit 2ff305a0292cb06789de6cfea7ad3cc0d6173493 diff --git a/doc/.ChangeLog_template b/doc/.ChangeLog_template index c95ea482e3..579f3c68e2 100644 --- a/doc/.ChangeLog_template +++ b/doc/.ChangeLog_template @@ -20,8 +20,6 @@ Does this tag change answers significantly for any of the following physics conf [ ] clm6_0 -[ ] clm5_1 - [ ] clm5_0 [ ] ctsm5_0-nwp diff --git a/doc/ChangeLog b/doc/ChangeLog index ded12c54f8..5c0c6ba058 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,4 +1,996 @@ =============================================================== +Tag name: ctsm5.3.014 +Originator(s): multiple (see contributors below) +Date: Tue 03 Dec 2024 04:31:03 PM MST +One-line Summary: Bring in several fixes for testing in the previous cesm3_0_beta03/04 tags + +Purpose and description of changes +---------------------------------- + +Fix a list of issues mostly for testing that came in with the cesm3_0_beta03 and cesm3_0_beta04 tags +for the science "chill" deadline bringing in the baseline science capabilities needed for the cesm3_0 release. + +List of things: + +- New polarcap grid +- Fix use_init_interp for several resolutions that had problems +- Remove clm5_1 physics option +- Newly needed surface datasets added to auto build in Makefile for mksurfdata_esmf +- Fix several individual tests that were failing +- Update to submodules to ones roughly based on cesm3_0_beta04 +- Add graceful error checking to the FATES parameter file tests that will get it working in some cases + +Contributors +------------ + @slevis-lmwg @ekluzek @adamrher @samsrabin + +Significant changes to scientifically-supported configurations +-------------------------------------------------------------- + +Does this tag change answers significantly for any of the following physics configurations? +(Details of any changes will be given in the "Answer changes" section below.) + + [Put an [X] in the box for any configuration with significant answer changes.] + +[ ] clm6_0 + +[ ] clm5_0 + +[ ] ctsm5_0-nwp + +[ ] clm4_5 + + +Bugs fixed +---------- +List of CTSM issues fixed (include CTSM Issue # and description) [one per line]: + + #2861 -- Nag compiler mpi-serial tests are failing on Izumi after the OS upgrade + #2801 -- fsurdat file needed for NEON MOAB site bfb done testing + #2791 -- Add f19 16pft 1850 and Hist to list of surface dataset resolutions (for the PPE work) + #2780 -- New CN matrix fails with single point sites with the new ctsm5.3 datasets. + #2654 -- Failing tests for izumi_nag with mpi-serial in cesm3_0_alpha02a + #2640 -- Update submodules to cesm3_0_beta04 versions + #2548 -- ne0ARCTICne30x4 grid transient failure + #2544 -- Failing ne0CONUSne30x8_ne0CONUSne30x8_mt12 in CESM testing + #2486 -- Temporarily add back a T42 dataset for CAM + #2379 -- Deprecate clm5_1 physics with ctsm5.2.0 + #2294 -- use of mct_mod is deprecated + +Notes of particular relevance for users +--------------------------------------- +Changes to CTSM's user interface (e.g., new/renamed XML or namelist variables): + Removal of the clm5_1 physics option to CLM_PHYSICS_VERSION XML variable + +Changes made to namelist defaults (e.g., changed parameter values): + Add support for new grid: ne0np4.POLARCAP.ne30x4 + Add support for f19 and f45 16-pft surface datasets + Fix some finidat issues for: f19, VR grids + Remove more mention of vichydro in namelist defaults + +Notes of particular relevance for developers: +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): + I think we should expand the shell_commands unit testing I added in FatesSetupParam. + usermod and testmod shell_commands can have tricky logic that's hard to get right and then + easy to break. Having unit testing that tests the tricky user mods (such as NEON and PLUMBER) + as well as this tricky FATES capability would help bring robustness, correctness and stability to this + part of the code. As well as the ability to make changes to this part and refactor to improve it. + As part of this I think adopting a bash unit tester (such as BATS) would be a good thing to do. + The other part is that I think we could add automated testing for this on push to PR's to master. + Future changes: + - Move FatesSetupParam to user-mod directory and activate for all FATES + - Add automated github test for the unit test there + - Adopt BATS for a bash unit test framework + - Add testing for NEON and PLUMBER2 shell_commands user-mod directories + +Changes to tests or testing: + Changes to lilac/sspmatrixcn tests needed for cime update + Clm51 tests changed to Clm60 + C96 tests changed to C96_C96_mt232 + Exact restart monthly length tests changed to days because of cime testing update + Exact restart 15 day length tests changed to 20 because of a cime testing bug + Some additional VR grid tests + FatesColdLandUse test requires a long name transient test now + New testmod include directory (FatesSetupParam) to setup to modify the FATES parameter file + Each of the testmods that need to modify the FATES parameter file then include FatesSetupParam + Add a unit-tester to the FatesSetupParam directory to make sure its functions work correctly + PFUNIT testing build infrastructure updated to use full ESMF library + +Testing summary: regular + fates + ctsm_sci +---------------- + [PASS means all tests PASS; OK means tests PASS other than expected fails.] + + build-namelist tests (if CLMBuildNamelist.pm has changed): + + derecho - PASS (6 namelists are different than ctsm5.3.013, new 16pft for f19/f45 non-crop) + + python testing (if python code has changed; see instructions in python/README.md; document testing done): + + derecho - PASS + + regular tests (aux_clm: https://github.com/ESCOMP/CTSM/wiki/System-Testing-Guide#pre-merge-system-testing): + + derecho ----- OK + izumi ------- OK + + fates tests: (give name of baseline if different from CTSM tagname, normally fates baselines are fates--) + derecho ----- OK + izumi ------- OK + + any other testing (give details below): + + ctsm_sci + derecho ---- OK + +If the tag used for baseline comparisons was NOT the previous tag, note that here: + + +Answer changes +-------------- + +Changes answers relative to baseline: No bit-for-bit + +Other details +------------- + +List any git submodules updated (cime, rtm, mosart, cism, fates, etc.): + Update most of the submodules to ones based from cesm3_0_beta04 + - mizuRoute to cesm-coupling.n02_v2.1.3 + - ccs_config_cesm1.0.10 (beyond cesm3_0_beta04 for unit testing issues) + - cime6.1.37 (beyond cesm3_0_beta04 for unit testing issues) + - cmeps1.0.16 + - cdeps1.0.53 (behind cesm3_0_beta04 [at 1.0.57] to avoid nextsw_cday changes) + - share1.1.2 + - pio2_6_3 + + mct removed + MPIserial_2.5.1 added + +Pull Requests that document the changes (include PR ids): +(https://github.com/ESCOMP/ctsm/pull) + - #2888 -- PR to master of all changes + - #2853 -- Update submodules to ones that are based on cesm3_0_alpha04a + - #2883 -- Update branch to latest master ctsm5.3.012 + - #2840 -- Fix single-point matrixCN fails + - #2840 -- bfb bug PR status: awaiting review PR status: ready size: small + - #2855 -- Improve CLMBuildNamelist ability to detect NEON runs + - #2716 -- add "polarcap" grid for cesm3 release enhancement + - #2834 -- f19 + f45 16pft fsurdat/landuse files to namelist_defaults_ctsm + Makefile + - #2808 -- Remove Clm51 references throughout or change to Clm60 + +=============================================================== +=============================================================== +Tag name: ctsm5.3.013 +Originator(s): erik (Erik Kluzek,UCAR/TSS,303-497-1326) +Date: Tue 26 Nov 2024 02:59:49 PM MST +One-line Summary: Merge b4b-dev + +Purpose and description of changes +---------------------------------- + +Bring in latest b4b-dev branch to main CTSM development. + +- Update git-fleximod +- Fix equation number in tech note +- Implement urbanl and urbanc coszen filters +- Make ALBGRD and ALBGRI active by default +- Some adjustments to control pylint for the RXCROPMATURITY python tests +- Run_sys_tests: Print test list in --verbose/--debug. + +Significant changes to scientifically-supported configurations +-------------------------------------------------------------- + +Does this tag change answers significantly for any of the following physics configurations? +(Details of any changes will be given in the "Answer changes" section below.) + + [Put an [X] in the box for any configuration with significant answer changes.] + +[ ] clm6_0 + +[ ] clm5_1 + +[ ] clm5_0 + +[ ] ctsm5_0-nwp + +[ ] clm4_5 + + +Bugs fixed +---------- + +List of CTSM issues fixed (include CTSM Issue # and description) [one per line]: + Fixes #17 albgrd and albgri history fields depend on decomposition, for urban points + Fixes #747 In UrbanAlbedo: Create a filter for coszen>0 and operate over that + +Notes of particular relevance for users +--------------------------------------- + +Changes made to namelist defaults (e.g., changed parameter values): + ALBGRD/ALBGRI are now active by default on the h0 files + +Changes to documentation: Fixed equation number + +Notes of particular relevance for developers: +--------------------------------------------- +NOTE: Be sure to review the steps in README.CHECKLIST.master_tags as well as the coding style in the Developers Guide +[Remove any lines that don't apply. Remove entire section if nothing applies.] + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): + +Changes to tests or testing: + Testlist that will be run is now output when --verbose/--debug is given to run_sys_tests + +Testing summary: regular +---------------- + [PASS means all tests PASS; OK means tests PASS other than expected fails.] + + build-namelist tests (if CLMBuildNamelist.pm has changed): + + derecho - PASS + + python testing (if python code has changed; see instructions in python/README.md; document testing done): + + derecho - PASS + + regular tests (aux_clm: https://github.com/ESCOMP/CTSM/wiki/System-Testing-Guide#pre-merge-system-testing): + + derecho ----- OK + izumi ------- OK + +If the tag used for baseline comparisons was NOT the previous tag, note that here: + + +Answer changes +-------------- + +Changes answers relative to baseline: No bit-for-bit + +Other details +------------- + +Pull Requests that document the changes (include PR ids): +(https://github.com/ESCOMP/ctsm/pull) + #2893 -- Merge b4b-dev + #2786 -- git fleximod + #2848 -- equation number in tech note + #2875 -- run_sys_tests log testlist for --verbose/--debug options + #2860 -- Remove num_solar and implement coszen filters in UrbanAlbedoMod.F90 + +=============================================================== +=============================================================== +Tag name: ctsm5.3.012 +Originator(s): afoster (Adrianna Foster,UCAR/TSS,303-497-1728) +Date: Wed 13 Nov 2024 09:53:51 AM MST +One-line Summary: update fates tag + +Purpose and description of changes +---------------------------------- + +Updates FATES tag to latest fates main (sci.1.79.3_api.37.0.0), and updates API to go +along with latest FATES update to refactor it's fire equations + + +Significant changes to scientifically-supported configurations +-------------------------------------------------------------- + + +[ ] clm6_0 + +[ ] clm5_1 + +[ ] clm5_0 + +[ ] ctsm5_0-nwp + +[ ] clm4_5 + + + + + + +Testing summary: +---------------- + + regular tests (aux_clm: https://github.com/ESCOMP/CTSM/wiki/System-Testing-Guide#pre-merge-system-testing): + + derecho ----- OK + izumi ------- OK + + fates tests: + derecho ----- OK + izumi ------- OK + + +Answer changes +-------------- + +Changes answers relative to baseline: + +Round-off differences for FATES compsets where fire is active. +NLCOMP differences for some FATES compsets + + +Pull Requests that document the changes (include PR ids): +- ESCOMP/CTSM#2782: Fates fuel refactor (https://github.com/ESCOMP/CTSM/pull/2782) + +=============================================================== +=============================================================== +Tag name: ctsm5.3.011 +Originator(s): samrabin (Sam Rabin, UCAR/TSS, samrabin@ucar.edu) +Date: Mon Nov 11 17:55:57 MST 2024 +One-line Summary: Improve handling of cold-start finidat + +Purpose and description of changes +---------------------------------- + +This PR changes things so that: + +1. Cold-start FATES runs with finidat specified will not require -ignore_warnings, and the supplied finidat will actually be obeyed. +2. Cold-start non-FATES runs will not be allowed, even with -ignore_warnings. + + +Significant changes to scientifically-supported configurations +-------------------------------------------------------------- + +Does this tag change answers significantly for any of the following physics configurations? +(Details of any changes will be given in the "Answer changes" section below.) + +[ ] clm6_0 + +[ ] clm5_1 + +[ ] clm5_0 + +[ ] ctsm5_0-nwp + +[ ] clm4_5 + + +Bugs fixed +---------- +[Remove any lines that don't apply. Remove entire section if nothing applies.] + +List of CTSM issues fixed: +- Resolves ESCOMP/CTSM#2856: FATES will never start from specified finidat (https://github.com/ESCOMP/CTSM/issues/2856) + +Notes of particular relevance for developers: +--------------------------------------------- +NOTE: Be sure to review the steps in README.CHECKLIST.master_tags as well as the coding style in the Developers Guide + +Changes to tests or testing: +Adds three fates suite tests to expected fails: +- ERS_D_Mmpi-serial_Ld5.1x1_brazil.I2000Clm50FatesCruRsGs.izumi_nag.clm-FatesCold +- SMS_Lm3_D_Mmpi-serial.1x1_brazil.I2000Clm50FatesCruRsGs.izumi_nag.clm-FatesColdHydro +- ERS_D_Ld30.f45_f45_mg37.I2000Clm50FatesCruRsGs.izumi_nag.clm-FatesColdLandUse + + +Testing summary: +---------------- + + [PASS means all tests PASS; OK means tests PASS other than expected fails.] + + build-namelist tests (if CLMBuildNamelist.pm has changed): + + derecho - PASS + + regular tests (aux_clm: https://github.com/ESCOMP/CTSM/wiki/System-Testing-Guide#pre-merge-system-testing): + + derecho ----- OK + izumi ------- OK + + fates tests: + derecho ----- OK + izumi ------- OK + + +Answer changes +-------------- + +Changes answers relative to baseline: + + Summarize any changes to answers, i.e., + - what code configurations: FATES cold-start runs with finidat + - what platforms/compilers: All + - nature of change: new climate + + +Other details +------------- + +Pull Requests that document the changes (include PR ids): +- ESCOMP/CTSM#2870: Fix handling of finidat with cold starts (https://github.com/ESCOMP/CTSM/pull/2870) + +=============================================================== +=============================================================== +Tag name: ctsm5.3.010 +Originator(s): afoster (Adrianna Foster) +Date: Sat Nov 9 12:54:18 MST 2024 +One-line Summary: Merge b4b-dev + +Purpose and description of changes +---------------------------------- + +- moves namelist variables to parameter file for PPE and makes some parameter variables pft-dimensioned (resolves ESCOMP/CTSM#2830 and resolves ESCOMP/CTSM#2831) +- removes/replaces references to DATM_C* _YR_* variables (resolves ESCOMP/CTSM#2743) +- documents that fincl1 and fexcl1 map to 'h0' history files + + +Significant changes to scientifically-supported configurations +-------------------------------------------------------------- + +Does this tag change answers significantly for any of the following physics configurations? +(Details of any changes will be given in the "Answer changes" section below.) + + [Put an [X] in the box for any configuration with significant answer changes.] + +[ ] clm6_0 + +[ ] clm5_1 + +[ ] clm5_0 + +[ ] ctsm5_0-nwp + +[ ] clm4_5 + + +Bugs fixed +---------- +- ESCOMP/CTSM#2830 (allow LUNA & mortality parameter to vary by PFT; https://github.com/ESCOMP/CTSM/issues/2830) +- ESCOMP/CTSM#2831 (Move namelist parameters to paramfile; https://github.com/ESCOMP/CTSM/issues/2831) +- ESCOMP/CTSM#2743 (Docs: Remove refs to DATM_CLMNCEP_YR_* and DATM_CPL_YR_* variables; https://github.com/ESCOMP/CTSM/issues/2743) + + +Testing summary: +---------------- + regular tests (aux_clm: https://github.com/ESCOMP/CTSM/wiki/System-Testing-Guide#pre-merge-system-testing): + + derecho ----- OK + izumi ------- OK + + +Other details +------------- + +Pull Requests that document the changes (include PR ids): +- ESCOMP/CTSM#2845: PPE parameter work -Addresses issues 2830 and 2831 (https://github.com/ESCOMP/CTSM/pull/2845) +- ESCOMP/CTSM#2852: Remove/replace refs to DATM_C*_YR_* variables (https://github.com/ESCOMP/CTSM/pull/2852) +- ESCOMP/CTSM#2866: Document that fincl1 maps to 'h0' history file. And fexcl1 (https://github.com/ESCOMP/CTSM/pull/2866) + +=============================================================== +=============================================================== +Tag name: ctsm5.3.009 +Originator(s): samrabin (Sam Rabin, UCAR/TSS, samrabin@ucar.edu) +Date: Tue Oct 15 17:35:40 MDT 2024 +One-line Summary: Reduce outputs from matrixcnOn tests + +Purpose and description of changes +---------------------------------- + +Reduces size and runtime of our tests of the CN Matrix capability. See "Notes of particular relevance for developers" for more details. + + +Significant changes to scientifically-supported configurations +-------------------------------------------------------------- + +Does this tag change answers significantly for any of the following physics configurations? +(Details of any changes will be given in the "Answer changes" section below.) + +[ ] clm6_0 + +[ ] clm5_1 + +[ ] clm5_0 + +[ ] ctsm5_0-nwp + +[ ] clm4_5 + + +Bugs fixed +---------- + +List of CTSM issues fixed (include CTSM Issue # and description): +- Resolves ESCOMP/CTSM#2814: Remove include_user_mods from matrixcnOn testmod (https://github.com/ESCOMP/CTSM/pull/2815) + + +Notes of particular relevance for developers: +--------------------------------------------- + +Changes to tests or testing: +- Removing the include_user_mods file from the matrixcnOn test (and thus also matrixcnOn_ignore_warnings) means that the default outputs no longer overwrite outputs specified by earlier test mods. For example, in LCISO_Lm13.f10_f10_mg37.IHistClm60BgcCrop.derecho_intel.clm-ciso_monthly--clm-matrixcnOn_ignore_warnings, it should have been saving monthly (the ciso_monthly test mod) but was actually being saved at much higher frequency (because matrixcnOn_ignore_warnings was after ciso_monthly in the test name). That test goes from 30 to 3 GB after this change. +- Adds matrixcn test suite, which can be used during Matrix CN development. All tests in this suite are also still run in aux_clm. + + +Testing summary: +---------------- + + regular tests (aux_clm: https://github.com/ESCOMP/CTSM/wiki/System-Testing-Guide#pre-merge-system-testing): + + derecho ----- DIFF + izumi ------- DIFF + + +Answer changes +-------------- + +Changes answers relative to baseline: + + Summarize any changes to answers, i.e., + - what code configurations: aux_clm tests only + - what platforms/compilers: all + - nature of change: larger than roundoff + + Changes are due to changed history field lists (and some other settings) due to the removal of include_user_mods from the matrixcnOn test mod. No answer changes occurred in any test other than those using matrixcnOn(_ignore_warnings); no answer changes will occur for any non-test run. + +Other details +------------- + +Pull Requests that document the changes (include PR ids): +- PR ESCOMP/CTSM#2815: Remove include_user_mods from matrixcnOn testmod (https://github.com/ESCOMP/CTSM/pull/2815) + +=============================================================== +=============================================================== +Tag name: ctsm5.3.008 +Originator(s): olyson (Keith Oleson,UCAR/TSS) +Date: Mon 14 Oct 2024 04:03:26 PM MDT +One-line Summary: PPE change to sa_leaf in CanopyFluxesMod.F90 + +Purpose and description of changes +---------------------------------- + + Add change to sa_leaf that was in PPE branch but did not get on master. + + +Significant changes to scientifically-supported configurations +-------------------------------------------------------------- + +Does this tag change answers significantly for any of the following physics configurations? +(Details of any changes will be given in the "Answer changes" section below.) + + [Put an [X] in the box for any configuration with significant answer changes.] + +[ ] clm6_0 + +[ ] clm5_1 + +[ ] clm5_0 + +[ ] ctsm5_0-nwp + +[ ] clm4_5 + + +Bugs fixed +---------- +List of CTSM issues fixed (include CTSM Issue # and description) [one per line]: + Fixes #2777 + + +Testing summary: +---------------- + + [PASS means all tests PASS; OK means tests PASS other than expected fails.] + + regular tests (aux_clm: https://github.com/ESCOMP/CTSM/wiki/System-Testing-Guide#pre-merge-system-testing): + + derecho ----- OK + izumi ------- OK + + +Answer changes +-------------- + +Changes answers relative to baseline: Yes + + Summarize any changes to answers, i.e., + - what code configurations: All + - what platforms/compilers: All + - nature of change: larger than roundoff/same climate) + + The changes in answers are explained in this post + https://github.com/ESCOMP/CTSM/issues/2777#issuecomment-2371697380 + and the diagnostics are here + https://webext.cgd.ucar.edu/I2000/ctsm53n04ctsm52028_f09_saleaf/lnd/ctsm53n04ctsm52028_f09_saleaf_2000_2001_2004-ctsm53n04ctsm52028_f09_2000_2001_2004/setsIndex.html + + +Other details +------------- +Pull Requests that document the changes (include PR ids): + https://github.com/ESCOMP/ctsm/pull/2788 + +=============================================================== +=============================================================== +Tag name: ctsm5.3.007 +Originator(s): slevis (Samuel Levis,UCAR/TSS,303-665-1310) +Date: Mon 13 Oct 2024 11:04:18 AM MDT +One-line Summary: Clm60 finidat updates for ne30, f09, f19 grids + +Purpose and description of changes +---------------------------------- + Updates appear in namelist_defaults_ctsm.xml. + For the most part I updated clm51 to match clm60, though clm51 will go away soon. + I had significant help from Erik Kluzek in disentangling the .xml settings + so that cases would pick up the correct finidat and other namelist settings. + +Significant changes to scientifically-supported configurations +-------------------------------------------------------------- + +Does this tag change answers significantly for any of the following physics configurations? +(Details of any changes will be given in the "Answer changes" section below.) + + [Put an [X] in the box for any configuration with significant answer changes.] + +[X] clm6_0 + +[ ] clm5_1 + +[ ] clm5_0 + +[ ] ctsm5_0-nwp + +[ ] clm4_5 + + +Bugs fixed +---------- +List of CTSM issues fixed (include CTSM Issue # and description) [one per line]: + Relates to #2403 but may need more work to close the issue + +Notes of particular relevance for users +--------------------------------------- +Changes made to namelist defaults (e.g., changed parameter values): + Clm60 and clm51 finidat updates for ne30, f09, f19 grids. + +Changes to the datasets (e.g., parameter, surface or initial files): + Clm60 and clm51 finidat updates for ne30, f09, f19 grids. + +Testing summary: +---------------- + + [PASS means all tests PASS; OK means tests PASS other than expected fails.] + + build-namelist tests (if CLMBuildNamelist.pm has changed): + + derecho - PASS + + python testing (if python code has changed; see instructions in python/README.md; document testing done): + + derecho - PASS + + regular tests (aux_clm: https://github.com/ESCOMP/CTSM/wiki/System-Testing-Guide#pre-merge-system-testing): + + derecho ----- OK + izumi ------- OK + + +Answer changes +-------------- + +Changes answers relative to baseline: Yes. + + Summarize any changes to answers, i.e., + - what code configurations: clm60 and clm51; the latter goes away soon + - what platforms/compilers: all + - nature of change: larger than roundoff/same climate + +Other details +------------- +Pull Requests that document the changes (include PR ids): + https://github.com/ESCOMP/ctsm/pull/2821 + +=============================================================== +=============================================================== +Tag name: ctsm5.3.006 +Originator(s): samrabin (Sam Rabin, UCAR/TSS, samrabin@ucar.edu) +Date: Fri Oct 11 07:01:09 MDT 2024 +One-line Summary: Merge b4b-dev + +Purpose and description of changes +---------------------------------- + +- Fix clm-basic tests (resolves ESCOMP/CTSM#2787) +- Change testlist_clm ne30pg3_t061 tests to ne30pg3_t232 (resolves ESCOMP/CTSM#2702) +- Remove unused variable elevclass_o in mkglcmecMod.F90 (resolves ESCOMP/CTSM#2802) +- Add a check in failtest, warntest, finidat_files, so when a new test or finidat file are added and one of the subkeys is misspelled you will get an error and tester will die (resolves ESCOMP/CTSM#2673) +- Move from deprecated shr_file to shr_log +- Set eflx_building_lun to spval properly (resolves ESCOMP/CTSM#2793) + + +Significant changes to scientifically-supported configurations +-------------------------------------------------------------- + +Does this tag change answers significantly for any of the following physics configurations? +(Details of any changes will be given in the "Answer changes" section below.) + + [Put an [X] in the box for any configuration with significant answer changes.] + +[ ] clm6_0 + +[ ] clm5_1 + +[ ] clm5_0 + +[ ] ctsm5_0-nwp + +[ ] clm4_5 + + +Bugs fixed +---------- + +List of CTSM issues fixed: +- ESCOMP/CTSM#2787 (aux_clm "clm-basic" tests fail as of ctsm5.3.0 because they need c13 in finidat; https://github.com/ESCOMP/CTSM/issues/2787) +- ESCOMP/CTSM#2702 (Tests failing in ctsm5.2.019 for CESM alpha testing; https://github.com/ESCOMP/CTSM/issues/2702) +- ESCOMP/CTSM#2802 (Array elevclass_o in mksurfdata_esmf/src/mkglcmecMod.F90 is not allocated before use; https://github.com/ESCOMP/CTSM/issues/2802) +- ESCOMP/CTSM#2673 (Catch use of namelist attribute in failure testing in perl build-namelist tester; https://github.com/ESCOMP/CTSM/issues/2673) +- ESCOMP/CTSM#2793 (Potential typo/bug in EnergyFluxType.F90; https://github.com/ESCOMP/CTSM/issues/2793) + + +Testing summary: +---------------- + + regular tests (aux_clm: https://github.com/ESCOMP/CTSM/wiki/System-Testing-Guide#pre-merge-system-testing): + + derecho ----- OK + izumi ------- OK + + +Other details +------------- + +Pull Requests that document the changes: +- ESCOMP/CTSM#2798: Fix clm-basic tests (https://github.com/ESCOMP/CTSM/pull/2798) +- ESCOMP/CTSM#2799: Change testlist_clm ne30pg3_t061 tests to ne30pg3_t232 (https://github.com/ESCOMP/CTSM/pull/2799) +- ESCOMP/CTSM#2804: Remove unused variable elevclass_o in mkglcmecMod.F90 (https://github.com/ESCOMP/CTSM/pull/2804) +- ESCOMP/CTSM#2678: Add check in build-namelist_test.pl (https://github.com/ESCOMP/CTSM/pull/2678) +- ESCOMP/CTSM#2627: move from depricated shr_file to shr_log (https://github.com/ESCOMP/CTSM/pull/2627) +- ESCOMP/CTSM#2806: Set eflx_building_lun to spval properly (https://github.com/ESCOMP/CTSM/pull/2806) + +=============================================================== +=============================================================== +Tag name: ctsm5.3.005 +Originator(s): dmleung (Danny Leung) +Date: Thu 10 Oct 2024 03:15:52 AM MDT +One-line Summary: Hardcoded tuning adjustments for Leung_2024 dust emissions + +Purpose and description of changes +---------------------------------- + +Changes to dust emissions when Leung_2024 method is being used. + +Tuning was needed since we saw some high biases in dust over semiarid regions given all the updates in CTSM and CAM. The biggest +changes in CTSM that affects dust is an increase in friction velocity (ustar; fv in CTSM) over vegetated, semiarid regions, mainly +due to a switch in the roughness scheme from 'ZengWang2007' to 'Meier2022'. Since dust emission is very sensitive to ustar, the dust +emission scheme magnifies this increase and caused strong high biases over semiarid regions, including Australia and Patagonia (see +plots in issue #2732). To enhance the robustness of Leung_2023 and reduce the likelihood to see huge changes in answers in the +future, we tried to limit the sensitivity of dust emissions to ustar. We also tried different methods (see specific notes below) to +reduce dust emissions from semiarid regions given the high biases over there. + + +Significant changes to scientifically-supported configurations +-------------------------------------------------------------- + +Does this tag change answers significantly for any of the following physics configurations? +(Details of any changes will be given in the "Answer changes" section below.) + + [Put an [X] in the box for any configuration with significant answer changes.] + +[x] clm6_0 + +[ ] clm5_1 + +[ ] clm5_0 + +[ ] ctsm5_0-nwp + +[ ] clm4_5 + + +Bugs fixed +---------- +List of CTSM issues fixed (include CTSM Issue # and description) [one per line]: + + Start of work on tuning for #2732 + Fixes #2826 -- Fix failing warning test + +Notes of particular relevance for developers: +--------------------------------------------- + +Caveats for developers (e.g., code that is duplicated that requires double maintenance): + Dust tuning parameters are hardcoded in FORTRAN and need to be moved to namelists + +Testing summary: Regular +---------------- + [PASS means all tests PASS; OK means tests PASS other than expected fails.] + + build-namelist tests (if CLMBuildNamelist.pm has changed): + + derecho - PASS + + python testing (if python code has changed; see instructions in python/README.md; document testing done): + + derecho - PASS + + regular tests (aux_clm: https://github.com/ESCOMP/CTSM/wiki/System-Testing-Guide#pre-merge-system-testing): + + derecho ----- OK + izumi ------- OK + +Answer changes +-------------- + +Changes answers relative to baseline: Yes for clm6_0 + + Summarize any changes to answers, i.e., + - what code configurations: clm6_0 + - what platforms/compilers: all + - nature of change (roundoff; larger than roundoff/same climate; new climate): + Just updates dust emissions when Leung_2024 method is used + + Only the dust emission fields are changed all other fields are untouched + +Other details +------------- + +Pull Requests that document the changes (include PR ids): +(https://github.com/ESCOMP/ctsm/pull) + + https://github.com/ESCOMP/CTSM/pull/2803 -- Tuning Leung_2023 dust emissions for clm6_0_cam7.0 + +=============================================================== +=============================================================== +Tag name: ctsm5.3.004 +Originator(s): samrabin (Sam Rabin, UCAR/TSS, samrabin@ucar.edu) +Date: Mon Oct 7 21:25:20 MDT 2024 +One-line Summary: Move hillslope data off surface datasets + +Purpose and description of changes +---------------------------------- + +Moves hillslope data off surface datasets onto its own separate hillslope_file. This makes it so we don't need to generate new surface datasets specifically for hillslope testing whenever the surface datasets are updated. + + +Significant changes to scientifically-supported configurations +-------------------------------------------------------------- + +Does this tag change answers significantly for any of the following physics configurations? +(Details of any changes will be given in the "Answer changes" section below.) + + [Put an [X] in the box for any configuration with significant answer changes.] + +[ ] clm6_0 + +[ ] clm5_1 + +[ ] clm5_0 + +[ ] ctsm5_0-nwp + +[ ] clm4_5 + + +Testing summary: +---------------- + + regular tests (aux_clm: https://github.com/ESCOMP/CTSM/wiki/System-Testing-Guide#pre-merge-system-testing): + + derecho ----- OK + izumi ------- OK + + +Answer changes +-------------- + +Changes answers relative to baseline: Yes + + Summarize any changes to answers, i.e., + - what code configurations: Hillslope (tests only) + - what platforms/compilers: Tests on Izumi and Derecho + - nature of change: Larger than roundoff + + Only our tests are affected because I had to make changes to the test setup for compatibility; this included changing mesh file and hillslope data for some tests/testmods. + + +Other details +------------- + +Pull Requests that document the changes (include PR ids): +- ESCOMP/CTSM#2434 (https://github.com/ESCOMP/CTSM/pull/2434) + +=============================================================== +=============================================================== +Tag name: ctsm5.3.003 +Originator(s): rgknox (Ryan Knox, LBNL, rgknox@lbl.gov) + glemieux (Gregory Lemieux, LBNL, glemieux@lbl.gov) +Date: Mon Oct 07 10:33:14 AM MDT 2024 +One-line Summary: FATES default parameter file update + +Purpose and description of changes +---------------------------------- + +This tag updates the default parameter file for FATES bringing in a number of updates: + - adds two new arctic shrub pfts + - updates the default sapwood allometry mode for grass pfts + - updates understory leaf turnover specifications for longer turnover rates + - changes the default behavior of nutrient uptake + +Significant changes to scientifically-supported configurations +-------------------------------------------------------------- + +Does this tag change answers significantly for any of the following physics configurations? +(Details of any changes will be given in the "Answer changes" section below.) + + [Put an [X] in the box for any configuration with significant answer changes.] + +[ ] clm6_0 + +[ ] clm5_1 + +[ ] clm5_0 + +[ ] ctsm5_0-nwp + +[ ] clm4_5 + + +Bugs fixed +---------- +List of CTSM issues fixed (include CTSM Issue # and description) [one per line]: + Fixes #2783 -- Error in FatescoldLandUse testmod + Fixes FATES#1211 -- Switching the default fates_cnp_prescribed_* parameters from 1 to 0 + +Notes of particular relevance for developers: +--------------------------------------------- +Changes to tests or testing: + FatesColdLandUse build has been added to the list of expected failures due to #2810 + +Testing summary: +---------------- + + [PASS means all tests PASS; OK means tests PASS other than expected fails.] + + regular tests (aux_clm: https://github.com/ESCOMP/CTSM/wiki/System-Testing-Guide#pre-merge-system-testing): + + derecho ----- OK + izumi ------- OK + + fates tests: (give name of baseline if different from CTSM tagname, normally fates baselines are fates--) + derecho ----- OK + izumi ------- OK + +Answer changes +-------------- + +Changes answers relative to baseline: + + Summarize any changes to answers, i.e., + - what code configurations: FATES mode + - what platforms/compilers: ALL + - nature of change (roundoff; larger than roundoff/same climate; new climate): larger than roundoff + +Other details +------------- +List any git submodules updated (cime, rtm, mosart, cism, fates, etc.): + fates: sci.1.78.2_api.36.0.0 -> sci.1.78.3_api.36.1.0 + +Pull Requests that document the changes (include PR ids): + https://github.com/ESCOMP/CTSM/pull/2700 + https://github.com/NGEET/fates/pull/1255 + +=============================================================== +=============================================================== +Tag name: ctsm5.3.002 +Originator(s): slevis (Samuel Levis,UCAR/TSS,303-665-1310) +Date: Thu 26 Sep 2024 03:10:40 PM MDT +One-line Summary: Duplicate tag of ctsm5.3.001 + +=============================================================== +=============================================================== Tag name: ctsm5.3.001 Originator(s): slevis (Samuel Levis,UCAR/TSS,303-665-1310) Date: Thu 26 Sep 2024 03:10:40 PM MDT diff --git a/doc/ChangeSum b/doc/ChangeSum index 1014612b40..1ac751ea03 100644 --- a/doc/ChangeSum +++ b/doc/ChangeSum @@ -1,5 +1,18 @@ Tag Who Date Summary ============================================================================================================================ + ctsm5.3.014 erik 12/03/2024 Bring in several fixes for testing in the previous cesm3_0_beta03/04 tags + ctsm5.3.013 erik 11/26/2024 Merge b4b-dev + ctsm5.3.012 afoster 11/13/2024 update fates tag + ctsm5.3.011 samrabin 11/11/2024 Improve handling of cold-start finidat + ctsm5.3.010 afoster 11/09/2024 Merge b4b-dev + ctsm5.3.009 samrabin 10/15/2024 Reduce outputs from matrixcnOn tests + ctsm5.3.008 olyson 10/14/2024 PPE change to sa_leaf in CanopyFluxesMod.F90 + ctsm5.3.007 slevis 10/14/2024 Clm60 finidat updates for ne30, f09, f19 grids + ctsm5.3.006 samrabin 10/11/2024 Merge b4b-dev + ctsm5.3.005 erik 10/10/2024 Hardcoded tuning adjustments for Leung_2024 dust emissions + ctsm5.3.004 samrabin 10/07/2024 Move hillslope data off surface datasets + ctsm5.3.003 multiple 10/07/2024 FATES default parameter file update + ctsm5.3.002 multiple 09/26/2024 Duplicate tag (same as 5.3.001) ctsm5.3.001 multiple 09/26/2024 Merge b4b-dev ctsm5.3.0 multiple 09/24/2024 Update surface datasets, CN Matrix, CLM60: excess ice on, explicit A/C on, crop calendars, Sturm snow, Leung dust emissions, prigent roughness data ctsm5.2.029 multiple 09/24/2024 New surface datasets: double tag of ctsm5.3.0 diff --git a/doc/source/tech_note/Fluxes/CLM50_Tech_Note_Fluxes.rst b/doc/source/tech_note/Fluxes/CLM50_Tech_Note_Fluxes.rst index c759d11f92..05b35d8b34 100644 --- a/doc/source/tech_note/Fluxes/CLM50_Tech_Note_Fluxes.rst +++ b/doc/source/tech_note/Fluxes/CLM50_Tech_Note_Fluxes.rst @@ -1213,7 +1213,7 @@ The numerical solution for vegetation temperature and the fluxes of momentum, se #. Magnitude of the wind velocity incident on the leaves :math:`U_{av}` (:eq:`5.117` ) -#. Leaf boundary layer resistance :math:`r_{b}` (:eq:`5.136` ) +#. Leaf boundary layer resistance :math:`r_{b}` (:eq:`5.122` ) #. Aerodynamic resistances :math:`r_{ah} ^{{'} }` and :math:`r_{aw} ^{{'} }`(:eq:`5.116` ) diff --git a/doc/source/users_guide/running-special-cases/Running-with-MOAR-data-as-atmospheric-forcing-to-spinup-the-model.rst b/doc/source/users_guide/running-special-cases/Running-with-MOAR-data-as-atmospheric-forcing-to-spinup-the-model.rst index 769755937d..7c18cee009 100644 --- a/doc/source/users_guide/running-special-cases/Running-with-MOAR-data-as-atmospheric-forcing-to-spinup-the-model.rst +++ b/doc/source/users_guide/running-special-cases/Running-with-MOAR-data-as-atmospheric-forcing-to-spinup-the-model.rst @@ -6,11 +6,14 @@ Running with MOAR data ======================== +.. warning:: + These instructions are outdated and will not work. This page will be either updated or removed as part of the CTSM6/CLM3 release. + Because it takes so long to spinup the CN model (as we just saw previously), if you are doing fully coupled simulations with active atmosphere and ocean, you will want to do the spinup portion of this "offline". So instead of doing expensive fully coupled simulations for the spinup duration, you run CLM in a very cheap "I" compset using atmospheric forcing from a shorter fully coupled simulation (or a simulation run previously by someone else). In this example we will use the ``I1850Clm50BgcSpinup compset`` to setup CLM to run with atmospheric forcing from a previous fully coupled simulation with data that is already stored on disk on Cheyenne. There are several simulations that have high frequency data for which we can do this. You can also do this on a machine other than Cheyenne, but would need to download the data from the Earth System Grid and change the datapath similar to Example :numref:`eg-sim-data-from-prev-sim`. -Example: Simulation with MOAR Data on cheyenne +Example: Simulation with MOAR Data on derecho ------------------------------------------------------------- :: @@ -18,10 +21,10 @@ Example: Simulation with MOAR Data on cheyenne > ./create_newcase -case MOARforce1850 -res f19_g17_gl4 -compset I1850Clm50BgcSpinup > cd MOARforce1850 # The following sets the casename to point to for atm forcing (you could also use an editor) - > ./xmlchange DATM_CPL_CASE=b40.1850.track1.1deg.006a + > ./xmlchange DATM_CPLHIST_CASE=b40.1850.track1.1deg.006a # The following sets the align year and years to run over for atm forcing # (you could also use an editor) - > ./xmlchange DATM_CPL_YR_ALIGN=1,DATM_CPL_YR_START=960,DATM_CPL_YR_END=1030 + > ./xmlchange DATM_YR_ALIGN=1,DATM_YR_START=960,DATM_YR_END=1030 > ./case.setup # Now build and run as normal > ./case.build diff --git a/doc/source/users_guide/running-special-cases/Running-with-anomaly-forcing.rst b/doc/source/users_guide/running-special-cases/Running-with-anomaly-forcing.rst index 0c6009f3fe..2efa65893d 100644 --- a/doc/source/users_guide/running-special-cases/Running-with-anomaly-forcing.rst +++ b/doc/source/users_guide/running-special-cases/Running-with-anomaly-forcing.rst @@ -42,4 +42,4 @@ For single point simulations, the global anomaly forcing files can be used, but mapalgo = 'nn','nn','nn','nn','nn','nn','nn','nn','nn','nn','nn','nn','nn' (the number of 'nn' values will depend on the number of original streams plus the number of anomaly forcing streams) -The cycling of the present-day (base) climate is controlled through the DATM\_CLMNCEP\_YR\_START and DATM_CLMNCEP\_YR\_END variables in env\_run.xml. +The cycling of the present-day (base) climate is controlled through the DATM\_YR\_START and DATM\_YR\_END variables in env\_run.xml. diff --git a/doc/source/users_guide/running-special-cases/Running-with-custom-crop-calendars.rst b/doc/source/users_guide/running-special-cases/Running-with-custom-crop-calendars.rst index 878cc0d353..22009add51 100644 --- a/doc/source/users_guide/running-special-cases/Running-with-custom-crop-calendars.rst +++ b/doc/source/users_guide/running-special-cases/Running-with-custom-crop-calendars.rst @@ -93,4 +93,4 @@ The entire process can be illustrated with the RXCROPMATURITY system test. E.g.: :: - run_sys_tests -t RXCROPMATURITY_Lm61.f10_f10_mg37.IHistClm51BgcCrop.cheyenne_intel.clm-cropMonthOutput --skip-generate --skip-compare \ No newline at end of file + run_sys_tests -t RXCROPMATURITY_Lm61.f10_f10_mg37.IHistClm60BgcCrop.cheyenne_intel.clm-cropMonthOutput --skip-generate --skip-compare diff --git a/doc/source/users_guide/running-special-cases/Running-with-tillage.rst b/doc/source/users_guide/running-special-cases/Running-with-tillage.rst index 8cfcaa680b..bccaf0b946 100644 --- a/doc/source/users_guide/running-special-cases/Running-with-tillage.rst +++ b/doc/source/users_guide/running-special-cases/Running-with-tillage.rst @@ -18,10 +18,10 @@ Example: Crop simulation with no tillage ---------------------------------------- :: - > cime/scripts/create_newcase -case IHistClm51BgcCrop_notill -res f19_g17_gl4 -compset IHistClm51BgcCrop + > cime/scripts/create_newcase -case IHistClm60BgcCrop_notill -res f19_g17_gl4 -compset IHistClm60BgcCrop - > cd IHistClm51BgcCrop_notill + > cd IHistClm60BgcCrop_notill > ./case.setup # turn off tillage diff --git a/doc/source/users_guide/running-special-cases/Running-with-your-own-previous-simulation-as-atmospheric-forcing-to-spinup-the-model.rst b/doc/source/users_guide/running-special-cases/Running-with-your-own-previous-simulation-as-atmospheric-forcing-to-spinup-the-model.rst index 2a55cbed1e..88d209c0d1 100644 --- a/doc/source/users_guide/running-special-cases/Running-with-your-own-previous-simulation-as-atmospheric-forcing-to-spinup-the-model.rst +++ b/doc/source/users_guide/running-special-cases/Running-with-your-own-previous-simulation-as-atmospheric-forcing-to-spinup-the-model.rst @@ -51,7 +51,7 @@ Example: Simulation Forced with Data from the Previous Simulation > ./xmlchange DATM_CPLHIST_CASE="myB1850" # The following sets the align year and years to run over for atm forcing # (you could also use an editor) - > ./xmlchange DATM_CPLHIST_YR_ALIGN="1",DATM_CPLHIST_YR_START=1,DATM_CPLHIST_YR_END=20 + > ./xmlchange DATM_YR_ALIGN="1",DATM_YR_START=1,DATM_YR_END=20 # Set the strm_datdir in the namelist_defaults_datm.xml # file to the archival path of the case above in the form of: /glade/home/achive/$USER/$DATM_CPLHIST_CASE/cpl/hist # NOTE: THIS WILL CHANGE THE PATH FOR ALL I1850Clm50BgcSpinup COMPSET CASES MADE AFTER THIS! diff --git a/doc/source/users_guide/setting-up-and-running-a-case/customizing-the-clm-configuration.rst b/doc/source/users_guide/setting-up-and-running-a-case/customizing-the-clm-configuration.rst index 7cd8ce9c9c..ec28a0d624 100644 --- a/doc/source/users_guide/setting-up-and-running-a-case/customizing-the-clm-configuration.rst +++ b/doc/source/users_guide/setting-up-and-running-a-case/customizing-the-clm-configuration.rst @@ -510,13 +510,10 @@ For running "I" cases there are several other noteworthy configuration items tha CCSM_BGC DATM_MODE DATM_PRESAERO - DATM_CLMNCEP_YR_ALIGN - DATM_CLMNCEP_YR_START - DATM_CLMNCEP_YR_END - DATM_CPL_CASE - DATM_CPL_YR_ALIGN - DATM_CPL_YR_START - DATM_CPL_YR_END + DATM_YR_ALIGN + DATM_YR_START + DATM_YR_END + DATM_CPLHIST_CASE ``CCSM_CO2_PPMV`` Sets the mixing ratio of CO2 in parts per million by volume for ALL CESM components to use. Note that most compsets already set this value to something reasonable. Also note that some compsets may tell the atmosphere model to override this value with either historic or ramped values. If the ``CCSM_BGC`` variable is set to something other than "none" the atmosphere model will determine CO2, and CLM will listen and use what the atmosphere sends it. On the CLM side the namelist item ``co2_type`` tells CLM to use the value sent from the atmosphere rather than a value set on it's own namelist. @@ -569,26 +566,17 @@ For running "I" cases there are several other noteworthy configuration items tha ``pt1_pt1`` = read in single-point or regional datasets -DATM_CLMNCEP_YR_START - ``DATM_CLMNCEP_YR_START`` sets the beginning year to cycle the atmospheric data over for ``CLM_QIAN`` or ``CLMCRUNCEP`` modes. +DATM_YR_START + ``DATM_YR_START`` sets the beginning year to cycle the atmospheric data over for ``CLM_QIAN`` or ``CLMCRUNCEP`` or ``CPLHISTForcing`` modes. -DATM_CLMNCEP_YR_END - ``DATM_CLMNCEP_YR_END`` sets the ending year to cycle the atmospheric data over for ``CLM_QIAN`` or ``CLMCRUNCEP`` modes. +DATM_YR_END + ``DATM_YR_END`` sets the ending year to cycle the atmospheric data over for ``CLM_QIAN`` or ``CLMCRUNCEP`` or ``CPLHISTForcing`` modes. -DATM_CLMNCEP_YR_ALIGN - ``DATM_CLMNCEP_YR_START`` and ``DATM_CLMNCEP_YR_END`` determine the range of years to cycle the atmospheric data over, and ``DATM_CLMNCEP_YR_ALIGN`` determines which year in that range of years the simulation will start with. +DATM_YR_ALIGN + ``DATM_YR_START`` and ``DATM_YR_END`` determine the range of years to cycle the atmospheric data over, and ``DATM_YR_ALIGN`` determines which year in that range of years the simulation will start with. -DATM_CPL_CASE - ``DATM_CPL_CASE`` sets the casename to use for the ``CPLHISTForcing`` mode. - -DATM_CPL_YR_START - ``DATM_CPL_YR_START`` sets the beginning year to cycle the atmospheric data over for the ``CPLHISTForcing`` mode. - -DATM_CPL_YR_END - ``DATM_CPL_YR_END`` sets the ending year to cycle the atmospheric data over for the ``CPLHISTForcing`` mode. - -DATM_CPL_YR_ALIGN - ``DATM_CPL_YR_START`` and ``DATM_CPL_YR_END`` determine the range of years to cycle the atmospheric data over, and ``DATM_CPL_YR_ALIGN`` determines which year in that range of years the simulation will start with. +DATM_CPLHIST_CASE + ``DATM_CPLHIST_CASE`` sets the casename to use for the ``CPLHISTForcing`` mode. ----------------------------- Downloading DATM Forcing Data @@ -596,9 +584,9 @@ Downloading DATM Forcing Data In Chapter One of the `CESM User's Guide `_ there is a section on "Downloading input data". The normal process of setting up cases will use the "scripts/ccsm_utils/Tools/check_input_data" script to retrieve data from the CESM subversion inputdata repository. This is true for the standard `CLM_QIAN` forcing as well. -The `CLMCRUNCEP` data is uploaded into the subversion inputdata repository as well -- but as it is 1.1 Terabytes of data downloading it is problematic (*IT WILL TAKE SEVERAL DAYS TO DOWNLOAD THE ENTIRE DATASET USING SUBVERSION*). Because of its size you may also need to download it onto a separate disk space. We have done that on cheyenne for example where it resides in ``$ENV{CESMROOT}/lmwg`` while the rest of the input data resides in ``$ENV{CESMDATAROOT}/inputdata``. The data is also already available on: janus, franklin, and hopper. If you download the data, we recommend that you break your download into several chunks, by setting up a case and setting the year range for ``DATM_CPL_YR_START`` and ``DATM_CPL_YR_END`` in say 20 year sections over 1901 to 2010, and then use ``check_input_data`` to export the data. +The `CLMCRUNCEP` data is uploaded into the subversion inputdata repository as well -- but as it is 1.1 Terabytes of data downloading it is problematic (*IT WILL TAKE SEVERAL DAYS TO DOWNLOAD THE ENTIRE DATASET USING SUBVERSION*). Because of its size you may also need to download it onto a separate disk space. We have done that on derecho for example where it resides in ``$ENV{CESMROOT}/lmwg`` while the rest of the input data resides in ``$ENV{CESMDATAROOT}/inputdata``. The data is also already available on: janus, franklin, and hopper. If you download the data, we recommend that you break your download into several chunks, by setting up a case and setting the year range for ``DATM_YR_START`` and ``DATM_YR_END`` in say 20 year sections over 1901 to 2010, and then use ``check_input_data`` to export the data. -The ``CPLHISTForcing`` DATM forcing data is unique -- because it is large compared to the rest of the input data, and we only have a disk copy on cheyenne. The DATM assumes the path for the previous NCAR machine cheyenne of ``/glade/p/cesm/shared_outputdata/cases/ccsm4/$DATM_CPLHIST_CASE`` for the data. So you will need to change this path in order to run on any other machine. You can download the data itself from NCAR HPSS from ``/CCSM/csm/$DATM_CPLHIST_CASE``. +The ``CPLHISTForcing`` DATM forcing data is unique -- because it is large compared to the rest of the input data, and we only have a disk copy on derecho. The DATM assumes the path for derecho of ``/glade/p/cesm/shared_outputdata/cases/ccsm4/$DATM_CPLHIST_CASE`` for the data. So you will need to change this path in order to run on any other machine. -------------------------------------- Customizing via the build script files diff --git a/libraries/mct b/libraries/mct deleted file mode 160000 index 82b0071e69..0000000000 --- a/libraries/mct +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 82b0071e69d14330b75d23b0bc68543ebea9aadc diff --git a/libraries/mpi-serial b/libraries/mpi-serial new file mode 160000 index 0000000000..39416b7546 --- /dev/null +++ b/libraries/mpi-serial @@ -0,0 +1 @@ +Subproject commit 39416b754652bd281a89e86b37734aa5f3ffafd6 diff --git a/libraries/parallelio b/libraries/parallelio index f52ade0756..6539ef05ae 160000 --- a/libraries/parallelio +++ b/libraries/parallelio @@ -1 +1 @@ -Subproject commit f52ade075619b32fa141993b5665b0fe099befc2 +Subproject commit 6539ef05ae7584ec570a56fdab9f7dfb336c2b80 diff --git a/lilac/bld_templates/ctsm_template.cfg b/lilac/bld_templates/ctsm_template.cfg index 2cd018aa3c..63755f018b 100644 --- a/lilac/bld_templates/ctsm_template.cfg +++ b/lilac/bld_templates/ctsm_template.cfg @@ -26,7 +26,7 @@ finidat = UNSET # High-level configuration options # ------------------------------------------------------------------------ -# ctsm_phys: 'clm4_5', 'clm5_0', 'clm5_1' or "clm6_0" +# ctsm_phys: 'clm4_5', 'clm5_0', or "clm6_0" ctsm_phys = clm5_0 # configuration: 'nwp' or 'clm' diff --git a/python/ctsm/crop_calendars/cropcal_figs_module.py b/python/ctsm/crop_calendars/cropcal_figs_module.py index d820460175..f26b5975d4 100644 --- a/python/ctsm/crop_calendars/cropcal_figs_module.py +++ b/python/ctsm/crop_calendars/cropcal_figs_module.py @@ -1,6 +1,7 @@ """ Functions for making crop calendar figures """ +# pylint: disable=abstract-class-instantiated import numpy as np diff --git a/python/ctsm/crop_calendars/generate_gdds_functions.py b/python/ctsm/crop_calendars/generate_gdds_functions.py index 14bd6b2e40..81c71e2a51 100644 --- a/python/ctsm/crop_calendars/generate_gdds_functions.py +++ b/python/ctsm/crop_calendars/generate_gdds_functions.py @@ -1,7 +1,7 @@ """ Functions to support generate_gdds.py """ -# pylint: disable=too-many-lines,too-many-statements +# pylint: disable=too-many-lines,too-many-statements,abstract-class-instantiated import warnings import os import glob diff --git a/python/ctsm/lilac_make_runtime_inputs.py b/python/ctsm/lilac_make_runtime_inputs.py index e751f6c931..623cb3524d 100644 --- a/python/ctsm/lilac_make_runtime_inputs.py +++ b/python/ctsm/lilac_make_runtime_inputs.py @@ -28,7 +28,7 @@ -Specifies ctsm physics +Specifies ctsm physics """ @@ -163,7 +163,7 @@ def buildnml(cime_path, rundir): "buildnml_input", "ctsm_phys", ctsm_cfg_path, - allowed_values=["clm4_5", "clm5_0", "clm5_1", "clm6_0"], + allowed_values=["clm4_5", "clm5_0", "clm6_0"], ) configuration = get_config_value( config, diff --git a/python/ctsm/run_sys_tests.py b/python/ctsm/run_sys_tests.py index 6afc43cd19..7d3ffe8444 100644 --- a/python/ctsm/run_sys_tests.py +++ b/python/ctsm/run_sys_tests.py @@ -8,6 +8,7 @@ from datetime import datetime from CIME.test_utils import get_tests_from_xml # pylint: disable=import-error +from CIME.test_utils import test_to_string # pylint: disable=import-error from CIME.cs_status_creator import create_cs_status # pylint: disable=import-error from ctsm.ctsm_logging import ( @@ -780,6 +781,11 @@ def _get_compilers_for_suite(suite_name, machine_name, running_ctsm_py_tests): raise RuntimeError( "No tests found for suite {} on machine {}".format(suite_name, machine_name) ) + if logger.getEffectiveLevel() <= logging.INFO: + logger.info("Tests:") + for test in test_data: + test_string = test_to_string(test).split(" ")[1] + logger.info(" %s", test_string) if not running_ctsm_py_tests: _check_py_env([t["testname"] for t in test_data]) _check_py_env([t["testmods"] for t in test_data if "testmods" in t.keys()]) diff --git a/python/ctsm/subset_data.py b/python/ctsm/subset_data.py index d38aee1308..fb0ba925a9 100644 --- a/python/ctsm/subset_data.py +++ b/python/ctsm/subset_data.py @@ -743,7 +743,7 @@ def subset_region(args, file_dict: dict): print("\nFor running this regional case with the created user_mods : ") print( - "./create_newcase --case case --res CLM_USRDAT --compset I2000Clm51BgcCrop", + "./create_newcase --case case --res CLM_USRDAT --compset I2000Clm60BgcCrop", "--run-unsupported --user-mods-dirs ", args.user_mods_dir, "\n\n", diff --git a/python/ctsm/toolchain/gen_mksurfdata_jobscript_multi.py b/python/ctsm/toolchain/gen_mksurfdata_jobscript_multi.py index 5de67adb12..fdf9466763 100755 --- a/python/ctsm/toolchain/gen_mksurfdata_jobscript_multi.py +++ b/python/ctsm/toolchain/gen_mksurfdata_jobscript_multi.py @@ -23,6 +23,8 @@ "global-present", "global-present-low-res", "global-present-ultra-hi-res", + "global-hist-1850-f19", + "global-hist-1850-f45", "crop-tropics-present", "crop", "crop-global-present", @@ -242,6 +244,14 @@ def main(): "--start-year 2000 --end-year 2000 --nocrop --res", "ultra_hi_res_no_crop", ), + "global-hist-1850-f19": ( + "--start-year 1850 --end-year 2023 --nocrop --res", + "f19", + ), + "global-hist-1850-f45": ( + "--start-year 1850 --end-year 2023 --nocrop --res", + "f45", + ), "crop-tropics-present": ( "--start-year 2000 --end-year 2000 --res", "5x5_amazon", diff --git a/share b/share index 4b9dc4871a..f6f31fd61c 160000 --- a/share +++ b/share @@ -1 +1 @@ -Subproject commit 4b9dc4871a259f00f35bb47708d876cb7dcdf75c +Subproject commit f6f31fd61cb8f80aee97311fcca64b3e26b0202c diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5b0f6c9b1b..70cf802e45 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,14 +3,20 @@ cmake_minimum_required(VERSION 2.8) list(APPEND CMAKE_MODULE_PATH ${CIME_CMAKE_MODULE_DIRECTORY}) include(CIME_initial_setup) -project(clm45_tests Fortran C) +#list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../tools/mksurfdata_esmf/cmake") +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../share/cmake") +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../component/cmeps/cmake") + +project(clm_tests Fortran C) include(CIME_utils) set(CLM_ROOT "..") -# This definition is needed to avoid having ESMF depend on mpi -add_definitions(-DHIDE_MPI) +# find needed external packages +# This is where ESMF could be asked for, but it's already included in the share build brought in below +# NetCDF is required -- because PIO and NetCDF are required by the standard default ESMF libraries +find_package(NetCDF 4.7.4 REQUIRED Fortran) # Add source directories from other share code (csm_share, etc.). This should be # done first, so that in case of name collisions, the CLM versions take @@ -18,7 +24,6 @@ add_definitions(-DHIDE_MPI) # wins). add_subdirectory(${CLM_ROOT}/share/src csm_share) add_subdirectory(${CLM_ROOT}/share/unit_test_stubs/util csm_share_stubs) -add_subdirectory(${CLM_ROOT}/share/src/esmf_wrf_timemgr esmf_wrf_timemgr) # Add files needed from CMEPS list ( APPEND drv_sources_needed @@ -53,43 +58,43 @@ foreach (sourcefile ${share_sources}) endif() endforeach() -# Remove shr_cal_mod from share_sources. -# -# shr_cal_mod depends on ESMF (or the lightweight esmf wrf timemgr, at -# least). Since CTSM doesn't currently use shr_cal_mod, we're avoiding -# the extra overhead of including esmf_wrf_timemgr sources in this -# build. -# -# TODO: like above, this should be moved into a general-purpose function -# in Sourcelist_utils. Then this block of code could be replaced with a -# single call, like: remove_source_file(${share_sources} -# "shr_cal_mod.F90") -foreach (sourcefile ${share_sources}) - string(REGEX MATCH "shr_cal_mod.F90" match_found ${sourcefile}) - if(match_found) - list(REMOVE_ITEM share_sources ${sourcefile}) - endif() -endforeach() +# Bring in PIO, jsut because it's needed for the default ESMF library and included in other submodules like share and cmeps +if (DEFINED PIO) + set(PIO_PATH ${PIO}) +else() + set(PIO_PATH $ENV{PIO}) +endif() # Build libraries containing stuff needed for the unit tests. # Eventually, these add_library calls should probably be distributed into the correct location, rather than being in this top-level CMakeLists.txt file. +# This line of bringing in the share library also brings in ESMF and PIO add_library(csm_share ${share_sources} ${drv_sources_needed}) declare_generated_dependencies(csm_share "${share_genf90_sources}") -add_library(esmf_wrf_timemgr ${esmf_wrf_timemgr_sources}) add_library(clm ${clm_sources}) declare_generated_dependencies(clm "${clm_genf90_sources}") -add_dependencies(esmf_wrf_timemgr csm_share) -add_dependencies(clm csm_share esmf_wrf_timemgr) +add_dependencies(clm csm_share esmf) # We need to look for header files here, in order to pick up shr_assert.h include_directories(${CLM_ROOT}/share/include) -# And we need to look for header files here, for some include files needed by -# the esmf_wrf_timemgr code -include_directories(${CLM_ROOT}/share/src/esmf_wrf_timemgr) + +# PIO2 library to the include and the linking step +add_compile_definitions(PIO2) + +add_library(pioc STATIC IMPORTED) +add_library(piof STATIC IMPORTED) +set_property(TARGET pioc PROPERTY IMPORTED_LOCATION $ENV{PIO}/lib/libpioc.so) +set_property(TARGET piof PROPERTY IMPORTED_LOCATION $ENV{PIO}/lib/libpiof.so) + # Tell cmake to look for libraries & mod files here, because this is where we built libraries include_directories(${CMAKE_CURRENT_BINARY_DIR}) +include_directories (${ESMF_F90COMPILEPATHS}) +include_directories ($ENV{PIO}/include) +include_directories (${NETCDF}/include) + +# Directories and libraries to include in the link step link_directories(${CMAKE_CURRENT_BINARY_DIR}) +link_libraries( pioc piof netcdf ) # Add the test directories # Note: it's possible that these could be added by each source directory that diff --git a/src/biogeochem/CNGapMortalityMod.F90 b/src/biogeochem/CNGapMortalityMod.F90 index 8979b1eebd..73ff0bc911 100644 --- a/src/biogeochem/CNGapMortalityMod.F90 +++ b/src/biogeochem/CNGapMortalityMod.F90 @@ -9,9 +9,11 @@ module CNGapMortalityMod ! ! !USES: use shr_kind_mod , only : r8 => shr_kind_r8 + use shr_infnan_mod , only : nan => shr_infnan_nan, assignment(=) use decompMod , only : bounds_type use abortutils , only : endrun use shr_log_mod , only : errMsg => shr_log_errMsg + use clm_varpar , only : mxpft use pftconMod , only : pftcon use CNDVType , only : dgvs_type use CNVegCarbonStateType , only : cnveg_carbonstate_type, spinup_factor_deadwood @@ -34,8 +36,10 @@ module CNGapMortalityMod public :: CNGapMortality type, private :: params_type - real(r8):: am ! mortality rate based on annual rate, fractional mortality (1/yr) real(r8):: k_mort ! coeff. of growth efficiency in mortality equation + real(r8), allocatable :: r_mort(:) ! Mortality rate (1/year) + contains + procedure, private :: allocParams ! Allocate the parameters end type params_type ! type(params_type), private :: params_inst @@ -49,6 +53,24 @@ module CNGapMortalityMod contains + !----------------------------------------------------------------------- + subroutine allocParams ( this ) + ! + implicit none + + ! !ARGUMENTS: + class(params_type) :: this + ! + ! !LOCAL VARIABLES: + character(len=32) :: subname = 'allocParams' + !----------------------------------------------------------------------- + + ! allocate parameters + + allocate( this%r_mort (0:mxpft) ) ; this%r_mort(:) = nan + + end subroutine allocParams + !----------------------------------------------------------------------- subroutine readParams ( ncid ) ! @@ -67,18 +89,21 @@ subroutine readParams ( ncid ) character(len=100) :: errCode = '-Error reading in parameters file:' logical :: readv ! has variable been read in or not real(r8) :: tempr ! temporary to read in constant + real(r8) :: temp1d(0:mxpft) ! temporary to read in parameter character(len=100) :: tString ! temp. var for reading !----------------------------------------------------------------------- - tString='r_mort' - call ncd_io(varname=trim(tString),data=tempr, flag='read', ncid=ncid, readvar=readv) - if ( .not. readv ) call endrun(msg=trim(errCode)//trim(tString)//errMsg(sourcefile, __LINE__)) - params_inst%am=tempr - tString='k_mort' call ncd_io(varname=trim(tString),data=tempr, flag='read', ncid=ncid, readvar=readv) if ( .not. readv ) call endrun(msg=trim(errCode)//trim(tString)//errMsg(sourcefile, __LINE__)) params_inst%k_mort=tempr + + call params_inst%allocParams() + + tString='r_mort' + call ncd_io(varname=trim(tString),data=temp1d, flag='read', ncid=ncid, readvar=readv) + if ( .not. readv ) call endrun(msg=trim(errCode)//trim(tString)//errMsg(sourcefile, __LINE__)) + params_inst%r_mort=temp1d end subroutine readParams @@ -183,8 +208,6 @@ subroutine CNGapMortality (bounds, num_soilp, filter_soilp, & ) dt = real( get_step_size(), r8 ) - ! set the mortality rate based on annual rate - am = params_inst%am ! set coeff of growth efficiency in mortality equation k_mort = params_inst%k_mort @@ -216,9 +239,11 @@ subroutine CNGapMortality (bounds, num_soilp, filter_soilp, & am = min(1._r8, am + heatstress(p)) else ! lpj didn't set this for grasses; cn does ! set the mortality rate based on annual rate - am = params_inst%am + am = params_inst%r_mort(ivt(p)) end if + else + am = params_inst%r_mort(ivt(p)) end if m = am/(get_average_days_per_year() * secspday) diff --git a/src/biogeochem/DustEmisLeung2023.F90 b/src/biogeochem/DustEmisLeung2023.F90 index 869c18c0dc..e9306029be 100644 --- a/src/biogeochem/DustEmisLeung2023.F90 +++ b/src/biogeochem/DustEmisLeung2023.F90 @@ -358,10 +358,6 @@ subroutine DustEmission (this, bounds, & ! !LOCAL VARIABLES integer :: fp,p,c,l,g,m,n ! indices real(r8) :: liqfrac ! fraction of total water that is liquid - real(r8) :: wnd_frc_rat ! [frc] Wind friction threshold over wind friction - real(r8) :: wnd_frc_slt_dlt ! [m s-1] Friction velocity increase from saltatn - real(r8) :: wnd_rfr_dlt ! [m s-1] Reference windspeed excess over threshld - real(r8) :: dst_slt_flx_rat_ttl real(r8) :: flx_mss_hrz_slt_ttl real(r8) :: flx_mss_vrt_dst_ttl(bounds%begp:bounds%endp) real(r8) :: frc_thr_wet_fct @@ -384,14 +380,14 @@ subroutine DustEmission (this, bounds, & real(r8) :: wnd_frc_thr_slt_it ! [m/s] created for impact threshold friction velocity real(r8) :: wnd_frc_thr_slt ! [m/s] used for wet fluid threshold friction velocity real(r8) :: K_length ! [dimless] normalized mean interobstacle distance, or called gap length (Okin, 2008) + ! dmleung has these variables and will change them into pointers and prepare for their history outputs. 30 Sep 2024 real(r8) :: bare_frc ! LUH2 bare soil land cover fraction - real(r8) :: veg_frc ! LUH2 natural vegetation + crop land cover fraction + real(r8) :: natveg_frc ! LUH2 natural vegetation cover fraction + real(r8) :: crop_frc ! LUH2 crop cover fraction. ! ! constants ! - real(r8), parameter :: cst_slt = 2.61_r8 ! [frc] Saltation constant - real(r8), parameter :: flx_mss_fdg_fct = 5.0e-4_r8 ! [frc] Empir. mass flx tuning eflx_lh_vegt - real(r8), parameter :: vai_mbl_thr = 1.0_r8 ! [m2 m-2] new VAI threshold; Danny M. Leung suggests 1, and Zender's scheme uses 0.3 + real(r8), parameter :: vai_mbl_thr = 0.6_r8 ! [m2 m-2] new VAI threshold; Danny M. Leung suggests something between 0.6 and 1 for tuning. Zender's scheme uses 0.3. Simone Tilmes might want this as a namelist variable for easier CESM tuning. dmleung 30 Sep 2024. real(r8), parameter :: Cd0 = 4.4e-5_r8 ! [dimless] proportionality constant in calculation of dust emission coefficient real(r8), parameter :: Ca = 2.7_r8 ! [dimless] proportionality constant in scaling of dust emission exponent @@ -407,11 +403,12 @@ subroutine DustEmission (this, bounds, & real(r8), parameter :: D_p = 130e-6_r8 ! [m] Medium soil particle diameter, assuming a global constant of ~130 um following Leung et al. (2023). dmleung 16 Feb 2024 real(r8), parameter :: gamma_Shao = 1.65e-4_r8 ! [kg s-2] interparticle cohesion: fitting parameter in Shao and Lu (2000) (S&L00). dmleung 16 Feb 2024 real(r8), parameter :: A_Shao = 0.0123_r8 ! [dimless] coefficient for aerodynamic force: fitting parameter in Shao and Lu (2000). dmleung 16 Feb 2024 - real(r8), parameter :: frag_expt_thr = 5.0_r8 ! [dimless] threshold for fragmentation exponent defined in Leung et al. (2023), somewhere within 3 to 5. It is used to prevent a local AOD blowup (over Patagonia, Argentina), but one can test larger values and relax the threshold if wanted. dmleung 16 Feb 2024 + real(r8), parameter :: frag_expt_thr = 2.5_r8 ! [dimless] Maximum value or threshold for fragmentation exponent defined in Leung et al. (2023). Danny M. Leung suggested it to be somewhere between 3 and 5 for tuning. It is used to prevent a local AOD blowup (over Patagonia, Argentina), but one can test larger values and relax the threshold if wanted. dmleung 16 Feb 2024. Update: Simone Tilmes might want this as a namelist variable for easier CESM tuning. 30 Sep 2024. real(r8), parameter :: z0a_glob = 1e-4_r8 ! [m] assumed globally constant aeolian roughness length value in Leung et al. (2023), for the log law of the wall for Comola et al. (2019) intermittency scheme. dmleung 20 Feb 2024 real(r8), parameter :: hgt_sal = 0.1_r8 ! [m] saltation height used by Comola et al. (2019) intermittency scheme for the log law of the wall. dmleung 20 Feb 2024 real(r8), parameter :: vai0_Okin = 0.1_r8 ! [m2/m2] minimum VAI needed for Okin-Pierre's vegetation drag partition equation. lai=0 in the equation will lead to infinity, so a small value is added into this lai dmleung defined. real(r8), parameter :: zii = 1000.0_r8 ! [m] convective boundary layer height added by dmleung 20 Feb 2024, following other CTSM modules (e.g., CanopyFluxesMod). Should we transfer PBL height (PBLH) from CAM? + real(r8), parameter :: dust_veg_drag_fact = 0.7_r8 ! [dimless] dmleung added a tuning factor for Greg Okin's vegetation drag partition effect. dmleung suggested a smaller vegetation drag partition effect given an increase in vegetation roughness after CTSM switched from using ZengWang2007 to Meier2022. This is simply because the drag partition effect should decrease with increasing roughness, but Okin's scheme is only a function of LAI. One might want to change this factor to 1_r8 when using ZengWang2007. dmleung 30 Sep 2024 real(r8) :: numer ! Numerator term for threshold crossing rate real(r8) :: denom ! Denominator term for threshold crossing rate !------------------------------------------------------------------------ @@ -650,8 +647,8 @@ subroutine DustEmission (this, bounds, & ! calculate Okin's shear stress ratio (SSR, which is vegetation drag partition factor) using Pierre's equation - K_length = 2.0_r8 * (1.0_r8/vai_Okin(p) - 1.0_r8) ! Here LAI has to be non-zero to avoid blowup, and < 1 to avoid -ve K_length. See this equation in Leung et al. (2023). This line is Okin's formulation - ssr(p) = (K_length+f_0*c_e)/(K_length+c_e) ! see this equation in Caroline Pierre et al. (2014) or Leung et al. (2023). This line is Pierre's formulation. + K_length = 2.0_r8 * (1.0_r8/vai_Okin(p) - 1.0_r8) ! Here VAI has to be non-zero to avoid blowup, and < 1 to avoid -ve K_length. See this equation in Leung et al. (2023). This line is Okin's formulation + ssr(p) = dust_veg_drag_fact * (K_length+f_0*c_e)/(K_length+c_e) ! see this equation in Caroline Pierre et al. (2014) or Leung et al. (2023). This line is Pierre's formulation. dmleung added a tuning factor for Okin's vegetation drag partition effect (SSR) on 30 Sep 2024. ! calculation of the hybrid/total drag partition effect considering both rock and vegetation drag partitioning using LUH2 bare and veg fractions within a grid if (lun%itype(l) == istsoil .or. lun%itype(l) == istcrop) then @@ -886,4 +883,4 @@ end subroutine SetDragPartition !============================================================================== -end module DustEmisLeung2023 \ No newline at end of file +end module DustEmisLeung2023 diff --git a/src/biogeochem/test/CNPhenology_test/CMakeLists.txt b/src/biogeochem/test/CNPhenology_test/CMakeLists.txt index 2367c86612..283e089ba6 100644 --- a/src/biogeochem/test/CNPhenology_test/CMakeLists.txt +++ b/src/biogeochem/test/CNPhenology_test/CMakeLists.txt @@ -3,4 +3,4 @@ set (pfunit_sources add_pfunit_ctest(CNPhenology TEST_SOURCES "${pfunit_sources}" - LINK_LIBRARIES clm csm_share esmf_wrf_timemgr) + LINK_LIBRARIES clm csm_share esmf) diff --git a/src/biogeochem/test/CNVegComputeSeed_test/CMakeLists.txt b/src/biogeochem/test/CNVegComputeSeed_test/CMakeLists.txt index dd6bdba723..b958439031 100644 --- a/src/biogeochem/test/CNVegComputeSeed_test/CMakeLists.txt +++ b/src/biogeochem/test/CNVegComputeSeed_test/CMakeLists.txt @@ -3,4 +3,4 @@ set (pfunit_sources add_pfunit_ctest(CNVegComputeSeed TEST_SOURCES "${pfunit_sources}" - LINK_LIBRARIES clm csm_share esmf_wrf_timemgr) + LINK_LIBRARIES clm csm_share esmf) diff --git a/src/biogeochem/test/DustEmis_test/CMakeLists.txt b/src/biogeochem/test/DustEmis_test/CMakeLists.txt index c705d6c2e3..d312b721b9 100644 --- a/src/biogeochem/test/DustEmis_test/CMakeLists.txt +++ b/src/biogeochem/test/DustEmis_test/CMakeLists.txt @@ -5,4 +5,4 @@ set (pfunit_sources add_pfunit_ctest(DustEmis TEST_SOURCES "${pfunit_sources}" - LINK_LIBRARIES clm csm_share esmf_wrf_timemgr) + LINK_LIBRARIES clm csm_share esmf) diff --git a/src/biogeochem/test/Latbaset_test/CMakeLists.txt b/src/biogeochem/test/Latbaset_test/CMakeLists.txt index 217fc7233c..d9f1c044f3 100644 --- a/src/biogeochem/test/Latbaset_test/CMakeLists.txt +++ b/src/biogeochem/test/Latbaset_test/CMakeLists.txt @@ -3,4 +3,4 @@ set (pfunit_sources add_pfunit_ctest(CropTypeLatbaset TEST_SOURCES "${pfunit_sources}" - LINK_LIBRARIES clm csm_share esmf_wrf_timemgr) + LINK_LIBRARIES clm csm_share esmf) diff --git a/src/biogeophys/CanopyFluxesMod.F90 b/src/biogeophys/CanopyFluxesMod.F90 index a969dc0583..0c5431728d 100644 --- a/src/biogeophys/CanopyFluxesMod.F90 +++ b/src/biogeophys/CanopyFluxesMod.F90 @@ -753,6 +753,7 @@ subroutine CanopyFluxes(bounds, num_exposedvegp, filter_exposedvegp, .or. dbh(p) < min_stem_diameter) then frac_rad_abs_by_stem(p) = 0.0_r8 sa_stem(p) = 0.0_r8 + sa_leaf(p) = sa_leaf(p) + esai(p) endif ! if using Satellite Phenology mode, calculate leaf and stem biomass diff --git a/src/biogeophys/CanopyHydrologyMod.F90 b/src/biogeophys/CanopyHydrologyMod.F90 index 9ce9995ce6..166aa6d53d 100644 --- a/src/biogeophys/CanopyHydrologyMod.F90 +++ b/src/biogeophys/CanopyHydrologyMod.F90 @@ -49,6 +49,8 @@ module CanopyHydrologyMod real(r8) :: snow_canopy_storage_scalar ! Canopy-storage-of-snow parameter (kg/m2) real(r8) :: snowcan_unload_temp_fact ! Temperature canopy snow unload scaling (C2 in Eq. 14, Roesch et al. 2001) (K*s) real(r8) :: snowcan_unload_wind_fact ! Wind canopy snow unload scaling (modifies 1.56e5, where 1.56e5 is C3 in Eq. 15, Roesch et al. 2001) (-) + real(r8) :: interception_fraction ! Fraction of intercepted precipitation (-) + real(r8) :: maximum_leaf_wetted_fraction ! Maximum fraction of leaf that may be wet (-) end type params_type type(params_type), private :: params_inst ! @@ -67,8 +69,6 @@ module CanopyHydrologyMod private :: BulkDiag_FracWet ! Determine fraction of vegetated surface that is wet ! ! !PRIVATE DATA MEMBERS: - real(r8) :: interception_fraction ! Fraction of intercepted precipitation - real(r8) :: maximum_leaf_wetted_fraction ! Maximum fraction of leaf that may be wet logical, private :: use_clm5_fpi = .false. ! use clm5 fpi equation character(len=*), parameter, private :: sourcefile = & @@ -99,8 +99,6 @@ subroutine CanopyHydrology_readnl( NLFilename ) character(len=32) :: subname = 'CanopyHydrology_readnl' ! subroutine name !----------------------------------------------------------------------- namelist /clm_canopyhydrology_inparm/ & - interception_fraction, & - maximum_leaf_wetted_fraction, & use_clm5_fpi ! ---------------------------------------------------------------------- @@ -125,15 +123,11 @@ subroutine CanopyHydrology_readnl( NLFilename ) end if ! Broadcast namelist variables read in - call shr_mpi_bcast(interception_fraction, mpicom) - call shr_mpi_bcast(maximum_leaf_wetted_fraction, mpicom) call shr_mpi_bcast(use_clm5_fpi, mpicom) if (masterproc) then write(iulog,*) ' ' write(iulog,*) 'canopyhydrology settings:' - write(iulog,*) ' interception_fraction = ',interception_fraction - write(iulog,*) ' maximum_leaf_wetted_fraction = ',maximum_leaf_wetted_fraction write(iulog,*) ' use_clm5_fpi = ',use_clm5_fpi endif @@ -162,6 +156,10 @@ subroutine readParams( ncid ) call readNcdioScalar(ncid, 'snowcan_unload_temp_fact', subname, params_inst%snowcan_unload_temp_fact) ! Wind canopy snow unload scaling (modifies 1.56e5, where 1.56e5 is C3 in Eq. 15, Roesch et al. 2001) (-) call readNcdioScalar(ncid, 'snowcan_unload_wind_fact', subname, params_inst%snowcan_unload_wind_fact) + ! Fraction of intercepted precipitation (-) + call readNcdioScalar(ncid, 'interception_fraction', subname, params_inst%interception_fraction) + ! Maximum fraction of leaf that may be wet (-) + call readNcdioScalar(ncid, 'maximum_leaf_wetted_fraction', subname, params_inst%maximum_leaf_wetted_fraction) end subroutine readParams @@ -535,7 +533,7 @@ subroutine BulkFlux_CanopyInterceptionAndThroughfall(bounds, num_nolakep, filter if (check_point_for_interception_and_excess(p)) then ! Coefficient of interception if (use_clm5_fpi) then - fpiliq = interception_fraction * tanh(elai(p) + esai(p)) + fpiliq = params_inst%interception_fraction * tanh(elai(p) + esai(p)) else fpiliq = 0.25_r8*(1._r8 - exp(-0.5_r8*(elai(p) + esai(p)))) end if @@ -1170,7 +1168,7 @@ subroutine BulkDiag_FracWet(bounds, num_soilp, filter_soilp, & if (h2ocan > 0._r8) then vegt = frac_veg_nosno(p)*(elai(p) + esai(p)) fwet(p) = (h2ocan / (vegt * params_inst%liq_canopy_storage_scalar))**0.666666666666_r8 - fwet(p) = min (fwet(p),maximum_leaf_wetted_fraction) ! Check for maximum limit of fwet + fwet(p) = min (fwet(p),params_inst%maximum_leaf_wetted_fraction) ! Check for maximum limit of fwet if (snocan(p) > 0._r8) then fcansno(p) = (snocan(p) / (vegt * params_inst%snow_canopy_storage_scalar))**0.15_r8 ! must match snocanmx fcansno(p) = min (fcansno(p),1.0_r8) diff --git a/src/biogeophys/EnergyFluxType.F90 b/src/biogeophys/EnergyFluxType.F90 index 16929d9708..6a31293fa3 100644 --- a/src/biogeophys/EnergyFluxType.F90 +++ b/src/biogeophys/EnergyFluxType.F90 @@ -579,7 +579,7 @@ subroutine InitHistory(this, bounds, is_simple_buildtemp, is_prog_buildtemp) avgflag='A', long_name='urban heating flux', & ptr_col=this%eflx_urban_heat_col, set_nourb=0._r8, c2l_scale_type='urbanf') else - this%eflx_urban_ac_lun(begl:endl) = spval + this%eflx_building_lun(begl:endl) = spval call hist_addfld1d (fname='EFLXBUILD', units='W/m^2', & avgflag='A', long_name='building heat flux from change in interior building air temperature', & ptr_lunit=this%eflx_building_lun, set_nourb=0._r8, l2g_scale_type='unity') diff --git a/src/biogeophys/HillslopeHydrologyMod.F90 b/src/biogeophys/HillslopeHydrologyMod.F90 index b2866df679..8fccd762f0 100644 --- a/src/biogeophys/HillslopeHydrologyMod.F90 +++ b/src/biogeophys/HillslopeHydrologyMod.F90 @@ -168,7 +168,7 @@ end subroutine check_aquifer_layer !----------------------------------------------------------------------- - subroutine InitHillslope(bounds,fsurdat) + subroutine InitHillslope(bounds, hillslope_file) ! ! !DESCRIPTION: ! Initialize hillslope geomorphology from input dataset @@ -187,7 +187,7 @@ subroutine InitHillslope(bounds,fsurdat) ! ! !ARGUMENTS: type(bounds_type), intent(in) :: bounds - character(len=*) , intent(in) :: fsurdat ! surface data file name + character(len=*) , intent(in) :: hillslope_file ! hillslope data file name integer, pointer :: ihillslope_in(:,:) ! read in - integer integer, pointer :: ncolumns_hillslope_in(:) ! read in number of columns integer, allocatable :: ncolumns_hillslope(:) ! number of hillslope columns @@ -224,9 +224,9 @@ subroutine InitHillslope(bounds,fsurdat) ! consistency check call check_aquifer_layer() - ! Open surface dataset to read in data below + ! Open hillslope dataset to read in data below - call getfil (fsurdat, locfn, 0) + call getfil (hillslope_file, locfn, 0) call ncd_pio_openfile (ncid, locfn, 0) allocate( & @@ -248,7 +248,7 @@ subroutine InitHillslope(bounds,fsurdat) call ncd_io(ncid=ncid, varname='nhillcolumns', flag='read', data=ncolumns_hillslope_in, dim1name=grlnd, readvar=readvar) if (masterproc .and. .not. readvar) then - call endrun( 'ERROR:: nhillcolumns not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + call endrun( 'ERROR:: nhillcolumns not found on hillslope data set.'//errmsg(sourcefile, __LINE__) ) end if do l = bounds%begl,bounds%endl g = lun%gridcell(l) @@ -266,7 +266,7 @@ subroutine InitHillslope(bounds,fsurdat) call ncd_io(ncid=ncid, varname='pct_hillslope', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) if (masterproc .and. .not. readvar) then - call endrun( 'ERROR:: pct_hillslope not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + call endrun( 'ERROR:: pct_hillslope not found on hillslope data set.'//errmsg(sourcefile, __LINE__) ) end if do l = bounds%begl,bounds%endl g = lun%gridcell(l) @@ -278,7 +278,7 @@ subroutine InitHillslope(bounds,fsurdat) call ncd_io(ncid=ncid, varname='hillslope_index', flag='read', data=ihillslope_in, dim1name=grlnd, readvar=readvar) if (masterproc .and. .not. readvar) then - call endrun( 'ERROR:: hillslope_index not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + call endrun( 'ERROR:: hillslope_index not found on hillslope data set.'//errmsg(sourcefile, __LINE__) ) end if do l = bounds%begl,bounds%endl g = lun%gridcell(l) @@ -287,7 +287,7 @@ subroutine InitHillslope(bounds,fsurdat) call ncd_io(ncid=ncid, varname='column_index', flag='read', data=ihillslope_in, dim1name=grlnd, readvar=readvar) if (masterproc .and. .not. readvar) then - call endrun( 'ERROR:: column_index not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + call endrun( 'ERROR:: column_index not found on hillslope data set.'//errmsg(sourcefile, __LINE__) ) end if do l = bounds%begl,bounds%endl g = lun%gridcell(l) @@ -296,7 +296,7 @@ subroutine InitHillslope(bounds,fsurdat) call ncd_io(ncid=ncid, varname='downhill_column_index', flag='read', data=ihillslope_in, dim1name=grlnd, readvar=readvar) if (masterproc .and. .not. readvar) then - call endrun( 'ERROR:: downhill_column_index not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + call endrun( 'ERROR:: downhill_column_index not found on hillslope data set.'//errmsg(sourcefile, __LINE__) ) end if do l = bounds%begl,bounds%endl g = lun%gridcell(l) @@ -307,7 +307,7 @@ subroutine InitHillslope(bounds,fsurdat) allocate(fhillslope_in(bounds%begg:bounds%endg,max_columns_hillslope)) call ncd_io(ncid=ncid, varname='hillslope_slope', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) if (masterproc .and. .not. readvar) then - call endrun( 'ERROR:: hillslope_slope not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + call endrun( 'ERROR:: hillslope_slope not found on hillslope data set.'//errmsg(sourcefile, __LINE__) ) end if do l = bounds%begl,bounds%endl @@ -317,7 +317,7 @@ subroutine InitHillslope(bounds,fsurdat) call ncd_io(ncid=ncid, varname='hillslope_aspect', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) if (masterproc .and. .not. readvar) then - call endrun( 'ERROR:: hillslope_aspect not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + call endrun( 'ERROR:: hillslope_aspect not found on hillslope data set.'//errmsg(sourcefile, __LINE__) ) end if do l = bounds%begl,bounds%endl @@ -327,7 +327,7 @@ subroutine InitHillslope(bounds,fsurdat) call ncd_io(ncid=ncid, varname='hillslope_area', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) if (masterproc .and. .not. readvar) then - call endrun( 'ERROR:: hillslope_area not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + call endrun( 'ERROR:: hillslope_area not found on hillslope data set.'//errmsg(sourcefile, __LINE__) ) end if do l = bounds%begl,bounds%endl g = lun%gridcell(l) @@ -335,7 +335,7 @@ subroutine InitHillslope(bounds,fsurdat) enddo call ncd_io(ncid=ncid, varname='hillslope_distance', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) if (masterproc .and. .not. readvar) then - call endrun( 'ERROR:: hillslope_length not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + call endrun( 'ERROR:: hillslope_distance not found on hillslope data set.'//errmsg(sourcefile, __LINE__) ) end if do l = bounds%begl,bounds%endl @@ -345,7 +345,7 @@ subroutine InitHillslope(bounds,fsurdat) call ncd_io(ncid=ncid, varname='hillslope_width', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) if (masterproc .and. .not. readvar) then - call endrun( 'ERROR:: hillslope_width not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + call endrun( 'ERROR:: hillslope_width not found on hillslope data set.'//errmsg(sourcefile, __LINE__) ) end if do l = bounds%begl,bounds%endl g = lun%gridcell(l) @@ -354,7 +354,7 @@ subroutine InitHillslope(bounds,fsurdat) call ncd_io(ncid=ncid, varname='hillslope_elevation', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) if (masterproc .and. .not. readvar) then - call endrun( 'ERROR:: hillslope_height not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + call endrun( 'ERROR:: hillslope_elevation not found on hillslope data set.'//errmsg(sourcefile, __LINE__) ) end if do l = bounds%begl,bounds%endl g = lun%gridcell(l) @@ -380,7 +380,7 @@ subroutine InitHillslope(bounds,fsurdat) call ncd_io(ncid=ncid, varname='hillslope_stream_depth', flag='read', data=fstream_in, dim1name=grlnd, readvar=readvar) if (masterproc .and. .not. readvar) then - call endrun( 'ERROR:: hillslope_stream_depth not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + call endrun( 'ERROR:: hillslope_stream_depth not found on hillslope data set.'//errmsg(sourcefile, __LINE__) ) end if do l = bounds%begl,bounds%endl g = lun%gridcell(l) @@ -389,7 +389,7 @@ subroutine InitHillslope(bounds,fsurdat) call ncd_io(ncid=ncid, varname='hillslope_stream_width', flag='read', data=fstream_in, dim1name=grlnd, readvar=readvar) if (masterproc .and. .not. readvar) then - call endrun( 'ERROR:: hillslope_stream_width not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + call endrun( 'ERROR:: hillslope_stream_width not found on hillslope data set.'//errmsg(sourcefile, __LINE__) ) end if do l = bounds%begl,bounds%endl g = lun%gridcell(l) @@ -398,7 +398,7 @@ subroutine InitHillslope(bounds,fsurdat) call ncd_io(ncid=ncid, varname='hillslope_stream_slope', flag='read', data=fstream_in, dim1name=grlnd, readvar=readvar) if (masterproc .and. .not. readvar) then - call endrun( 'ERROR:: hillslope_stream_slope not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + call endrun( 'ERROR:: hillslope_stream_slope not found on hillslope data set.'//errmsg(sourcefile, __LINE__) ) end if do l = bounds%begl,bounds%endl g = lun%gridcell(l) @@ -504,11 +504,11 @@ subroutine InitHillslope(bounds,fsurdat) enddo end if - ! if missing hillslope information on surface dataset, + ! if missing hillslope information on dataset, ! call endrun if (ncolumns_hillslope(l) > 0 .and. sum(hillslope_area) == 0._r8 .and. masterproc) then write(iulog,*) 'Problem with input data: nhillcolumns is non-zero, but hillslope area is zero' - write(iulog,*) 'Check surface data for gridcell at (lon/lat): ', grc%londeg(g),grc%latdeg(g) + write(iulog,*) 'Check hillslope data for gridcell at (lon/lat): ', grc%londeg(g),grc%latdeg(g) call endrun( 'ERROR:: sum of hillslope areas is zero.'//errmsg(sourcefile, __LINE__) ) end if @@ -559,7 +559,7 @@ end subroutine InitHillslope !----------------------------------------------------------------------- - subroutine SetHillslopeSoilThickness(bounds,fsurdat,soil_depth_lowland_in,soil_depth_upland_in) + subroutine SetHillslopeSoilThickness(bounds, hillslope_file, soil_depth_lowland_in, soil_depth_upland_in) ! ! !DESCRIPTION: ! Set hillslope column nbedrock values @@ -578,7 +578,7 @@ subroutine SetHillslopeSoilThickness(bounds,fsurdat,soil_depth_lowland_in,soil_d ! ! !ARGUMENTS: type(bounds_type), intent(in) :: bounds - character(len=*) , intent(in) :: fsurdat ! surface data file name + character(len=*) , intent(in) :: hillslope_file ! hillslope data file name real(r8), intent(in), optional :: soil_depth_lowland_in real(r8), intent(in), optional :: soil_depth_upland_in real(r8), pointer :: fhillslope_in(:,:) ! read in - float @@ -599,14 +599,14 @@ subroutine SetHillslopeSoilThickness(bounds,fsurdat,soil_depth_lowland_in,soil_d if (soil_profile_method==soil_profile_from_file) then - ! Open surface dataset to read in data below - call getfil (fsurdat, locfn, 0) + ! Open hillslope dataset to read in data below + call getfil (hillslope_file, locfn, 0) call ncd_pio_openfile (ncid, locfn, 0) allocate(fhillslope_in(bounds%begg:bounds%endg,max_columns_hillslope)) call ncd_io(ncid=ncid, varname='hillslope_bedrock_depth', flag='read', data=fhillslope_in, dim1name=grlnd, readvar=readvar) if (masterproc .and. .not. readvar) then - call endrun( 'ERROR:: soil_profile_method = "FromFile", but hillslope_bedrock not found on surface data set.'//errmsg(sourcefile, __LINE__) ) + call endrun( 'ERROR:: soil_profile_method = "FromFile", but hillslope_bedrock not found on hillslope data set.'//errmsg(sourcefile, __LINE__) ) end if do l = bounds%begl,bounds%endl g = lun%gridcell(l) @@ -896,7 +896,7 @@ end subroutine HillslopeDominantLowlandPft subroutine HillslopePftFromFile(bounds,col_pftndx) ! ! !DESCRIPTION: - ! Reassign patch type using indices from surface data file + ! Reassign patch type using indices from data file ! Assumes one patch per hillslope column ! In preparation for this reassignment of patch type, only the ! first patch was given a non-zero weight in surfrd_hillslope. diff --git a/src/biogeophys/LunaMod.F90 b/src/biogeophys/LunaMod.F90 index dbd39daedf..5641846309 100644 --- a/src/biogeophys/LunaMod.F90 +++ b/src/biogeophys/LunaMod.F90 @@ -9,10 +9,11 @@ module LunaMod ! !USES: use shr_kind_mod , only : r8 => shr_kind_r8 use shr_log_mod , only : errMsg => shr_log_errMsg + use shr_infnan_mod , only : nan => shr_infnan_nan, assignment(=) use clm_varcon , only : rgas, tfrz,spval use abortutils , only : endrun use clm_varctl , only : iulog - use clm_varpar , only : nlevcan + use clm_varpar , only : nlevcan, mxpft use decompMod , only : bounds_type, subgrid_level_patch use pftconMod , only : pftcon use FrictionvelocityMod , only : frictionvel_type @@ -33,7 +34,6 @@ module LunaMod !------------------------------------------------------------------------------ ! PUBLIC MEMBER FUNCTIONS: - public :: LunaReadNML !subroutine to read in the Luna namelist public :: Update_Photosynthesis_Capacity !subroutine to update the canopy nitrogen profile public :: Acc24_Climate_LUNA !subroutine to accumulate 24 hr climates public :: Acc240_Climate_LUNA !subroutine to accumulate 10 day climates @@ -47,11 +47,14 @@ module LunaMod real(r8) :: kc25_coef ! Michaelis-Menten const. at 25°C for CO2 (unitless) real(r8) :: ko25_coef ! Michaelis-Menten const. at 25°C for O2 (unitless) real(r8) :: luna_theta_cj ! LUNA empirical curvature parameter for ac, aj photosynthesis co-limitation (unitless) - real(r8) :: jmaxb0 ! The baseline proportion of nitrogen allocated for electron transport (J) - real(r8) :: wc2wjb0 ! The baseline ratio of rubisco limited rate vs light limited photosynthetic rate (Wc:Wj) (unitless) real(r8) :: enzyme_turnover_daily ! The daily turnover rate for photosynthetic enzyme at 25oC in view of ~7 days of half-life time for Rubisco (Suzuki et al. 2001) (unitless) real(r8) :: relhExp ! Specifies the impact of relative humidity on electron transport rate (unitless) real(r8) :: minrelh ! Minimum relative humidity for nitrogen optimization (fraction) + real(r8), allocatable :: jmaxb0(:) ! Baseline proportion of nitrogen allocated for electron transport (J) + real(r8), allocatable :: jmaxb1(:) ! Coefficient determining the response of electron transport rate to light availability (-) + real(r8), allocatable :: wc2wjb0(:) ! The baseline ratio of rubisco limited rate vs light limited photosynthetic rate (Wc:Wj) (-) + contains + procedure, private :: allocParams ! Allocate the parameters end type params_type type(params_type), private :: params_inst @@ -78,7 +81,6 @@ module LunaMod real(r8), parameter :: CO2ref = 380.0_r8 ! reference CO2 concentration for calculation of reference NUE. real(r8), parameter :: forc_pbot_ref = 101325.0_r8 ! reference air pressure for calculation of reference NUE real(r8), parameter :: Q10Enz = 2.0_r8 ! Q10 value for enzyme decay rate - real(r8) :: Jmaxb1 = 0.1_r8 ! the baseline proportion of nitrogen allocated for electron transport (J) real(r8), parameter :: NMCp25 = 0.715_r8 ! estimated by assuming 80% maintenance respiration is used for photosynthesis enzyme maintenance real(r8), parameter :: Trange1 = 5.0_r8 ! lower temperature limit (oC) for nitrogen optimization real(r8), parameter :: Trange2 = 42.0_r8 ! upper temperature limit (oC) for nitrogen optimization @@ -92,70 +94,31 @@ module LunaMod contains - !********************************************************************************************************************************************************************** - ! Read in LUNA namelist - subroutine LunaReadNML( NLFilename ) - ! - ! !DESCRIPTION: - ! Read the namelist for LUNA - ! - ! !USES: - use fileutils , only : getavu, relavu, opnfil - use shr_nl_mod , only : shr_nl_find_group_name - use spmdMod , only : masterproc, mpicom - use shr_mpi_mod , only : shr_mpi_bcast - use clm_varctl , only : iulog - use shr_log_mod , only : errMsg => shr_log_errMsg - use abortutils , only : endrun + !----------------------------------------------------------------------- + subroutine allocParams ( this ) ! + implicit none + ! !ARGUMENTS: - character(len=*), intent(in) :: NLFilename ! Namelist filename + class(params_type) :: this ! ! !LOCAL VARIABLES: - integer :: ierr ! error code - integer :: unitn ! unit for namelist file - - character(len=*), parameter :: subname = 'lunaReadNML' - character(len=*), parameter :: nmlname = 'luna' + character(len=32) :: subname = 'allocParams' !----------------------------------------------------------------------- - namelist /luna/ Jmaxb1 - - ! Initialize options to default values, in case they are not specified in - ! the namelist - - - if (masterproc) then - unitn = getavu() - write(iulog,*) 'Read in '//nmlname//' namelist' - call opnfil (NLFilename, unitn, 'F') - call shr_nl_find_group_name(unitn, nmlname, status=ierr) - if (ierr == 0) then - read(unitn, nml=luna, iostat=ierr) - if (ierr /= 0) then - call endrun(msg="ERROR reading "//nmlname//"namelist"//errmsg(__FILE__, __LINE__)) - end if - else - call endrun(msg="ERROR could NOT find "//nmlname//"namelist"//errmsg(__FILE__, __LINE__)) - end if - call relavu( unitn ) - end if - - call shr_mpi_bcast (Jmaxb1, mpicom) - - if (masterproc) then - write(iulog,*) ' ' - write(iulog,*) nmlname//' settings:' - write(iulog,nml=luna) - write(iulog,*) ' ' - end if - - end subroutine lunaReadNML + + ! allocate parameters + + allocate( this%jmaxb0 (0:mxpft) ) ; this%jmaxb0(:) = nan + allocate( this%jmaxb1 (0:mxpft) ) ; this%jmaxb1(:) = nan + allocate( this%wc2wjb0 (0:mxpft) ) ; this%wc2wjb0(:) = nan + + end subroutine allocParams !---------------------------------------------------------------------------- subroutine readParams( ncid ) ! ! !USES: - use ncdio_pio, only: file_desc_t + use ncdio_pio, only: file_desc_t,ncd_io use paramUtilMod, only: readNcdioScalar ! ! !ARGUMENTS: @@ -164,6 +127,10 @@ subroutine readParams( ncid ) ! ! !LOCAL VARIABLES: character(len=*), parameter :: subname = 'readParams_Luna' + character(len=100) :: errCode = '-Error reading in parameters file:' + logical :: readv ! has variable been read in or not + real(r8) :: temp1d(0:mxpft) ! temporary to read in parameter + character(len=100) :: tString ! temp. var for reading !-------------------------------------------------------------------- ! CO2 compensation point at 25°C at present day O2 levels @@ -177,10 +144,6 @@ subroutine readParams( ncid ) params_inst%kc25_coef = params_inst%kc25_coef * 1.e5_r8 ! from mol/mol to Luna units ! LUNA empirical curvature parameter for ac, aj photosynthesis co-limitation call readNcdioScalar(ncid, 'luna_theta_cj', subname, params_inst%luna_theta_cj) - ! The baseline proportion of nitrogen allocated for electron transport (J) - call readNcdioScalar(ncid, 'jmaxb0', subname, params_inst%jmaxb0) - ! The baseline ratio of rubisco limited rate vs light limited photosynthetic rate (Wc:Wj) (unitless) - call readNcdioScalar(ncid, 'wc2wjb0', subname, params_inst%wc2wjb0) ! The daily turnover rate for photosynthetic enzyme at 25oC in view of ~7 days of half-life time for Rubisco (Suzuki et al. 2001) (unitless) call readNcdioScalar(ncid, 'enzyme_turnover_daily', subname, params_inst%enzyme_turnover_daily) ! Specifies the impact of relative humidity on electron transport rate (unitless) @@ -188,6 +151,21 @@ subroutine readParams( ncid ) ! Minimum relative humidity for nitrogen optimization (fraction) call readNcdioScalar(ncid, 'minrelh', subname, params_inst%minrelh) + call params_inst%allocParams() + + tString = "jmaxb0" + call ncd_io(varname=trim(tString),data=temp1d, flag='read', ncid=ncid, readvar=readv) + if ( .not. readv ) call endrun(msg=trim(errCode)//trim(tString)//errMsg(sourcefile, __LINE__)) + params_inst%jmaxb0=temp1d + tString = "jmaxb1" + call ncd_io(varname=trim(tString),data=temp1d, flag='read', ncid=ncid, readvar=readv) + if ( .not. readv ) call endrun(msg=trim(errCode)//trim(tString)//errMsg(sourcefile, __LINE__)) + params_inst%jmaxb1=temp1d + tString = "wc2wjb0" + call ncd_io(varname=trim(tString),data=temp1d, flag='read', ncid=ncid, readvar=readv) + if ( .not. readv ) call endrun(msg=trim(errCode)//trim(tString)//errMsg(sourcefile, __LINE__)) + params_inst%wc2wjb0=temp1d + end subroutine readParams !----------------------------------------------------------------------- @@ -233,7 +211,7 @@ subroutine Update_Photosynthesis_Capacity(bounds, fn, filterp, & ! !USES: use clm_time_manager , only : get_step_size_real - use clm_varpar , only : nlevsoi, mxpft + use clm_varpar , only : nlevsoi use perf_mod , only : t_startf, t_stopf use clm_varctl , only : use_cn use quadraticMod , only : quadratic @@ -439,8 +417,9 @@ subroutine Update_Photosynthesis_Capacity(bounds, fn, filterp, & PNcbold = 0.0_r8 call NitrogenAllocation(FNCa,forc_pbot10(p), relh10, CO2a10, O2a10, PARi10, PARimx10, rb10v, hourpd, & tair10, tleafd10, tleafn10, & - Jmaxb1, PNlcold, PNetold, PNrespold, PNcbold, dayl_factor(p), o3coefjmax(p), & - PNstoreopt, PNlcopt, PNetopt, PNrespopt, PNcbopt) + params_inst%jmaxb0(ft), params_inst%jmaxb1(ft), params_inst%wc2wjb0(ft), PNlcold, PNetold, & + PNrespold, PNcbold, dayl_factor(p), & + o3coefjmax(p), PNstoreopt, PNlcopt, PNetopt, PNrespopt, PNcbopt) vcmx25_opt= PNcbopt * FNCa * Fc25 jmx25_opt= PNetopt * FNCa * Fj25 @@ -825,7 +804,7 @@ end subroutine Clear24_Climate_LUNA !************************************************************************************************************************************************ !Use the LUNA model to calculate the Nitrogen partioning subroutine NitrogenAllocation(FNCa,forc_pbot10, relh10, CO2a10,O2a10, PARi10,PARimx10,rb10, hourpd, tair10, tleafd10, tleafn10, & - Jmaxb1, PNlcold, PNetold, PNrespold, PNcbold, dayl_factor,o3coefjmax, & + jmaxb0, jmaxb1, wc2wjb0, PNlcold, PNetold, PNrespold, PNcbold, dayl_factor,o3coefjmax, & PNstoreopt, PNlcopt, PNetopt, PNrespopt, PNcbopt) implicit none real(r8), intent (in) :: FNCa !Area based functional nitrogen content (g N/m2 leaf) @@ -840,7 +819,9 @@ subroutine NitrogenAllocation(FNCa,forc_pbot10, relh10, CO2a10,O2a10, PARi10,PAR real(r8), intent (in) :: tair10 !10-day running mean of the 2m temperature (oC) real(r8), intent (in) :: tleafd10 !10-day running mean of daytime leaf temperature (oC) real(r8), intent (in) :: tleafn10 !10-day running mean of nighttime leaf temperature (oC) - real(r8), intent (in) :: Jmaxb1 !coefficient determining the response of electron transport rate to light availability (unitless) + real(r8), intent (in) :: jmaxb0 !Baseline proportion of nitrogen allocated for electron transport (J) + real(r8), intent (in) :: jmaxb1 !coefficient determining the response of electron transport rate to light availability (-) + real(r8), intent (in) :: wc2wjb0 !The baseline ratio of rubisco limited rate vs light limited photosynthetic rate (Wc:Wj) (-) real(r8), intent (in) :: PNlcold !old value of the proportion of nitrogen allocated to light capture (unitless) real(r8), intent (in) :: PNetold !old value of the proportion of nitrogen allocated to electron transport (unitless) real(r8), intent (in) :: PNrespold !old value of the proportion of nitrogen allocated to respiration (unitless) @@ -928,7 +909,7 @@ subroutine NitrogenAllocation(FNCa,forc_pbot10, relh10, CO2a10,O2a10, PARi10,PAR tleafd10c = min(max(tleafd10, Trange1), Trange2) !constrain the physiological range tleafn10c = min(max(tleafn10, Trange1), Trange2) !constrain the physiological range ci = 0.7_r8 * CO2a10 - JmaxCoef = Jmaxb1 * dayl_factor * (1.0_r8 - exp(-params_inst%relhExp * max(relh10 - & + JmaxCoef = jmaxb1 * dayl_factor * (1.0_r8 - exp(-params_inst%relhExp * max(relh10 - & params_inst%minrelh, 0.0_r8) / (1.0_r8 - params_inst%minrelh))) do while (PNlcoldi .NE. PNlc .and. jj < 100) Fc = VcmxTKattge(tair10, tleafd10c) * Fc25 @@ -942,7 +923,7 @@ subroutine NitrogenAllocation(FNCa,forc_pbot10, relh10, CO2a10,O2a10, PARi10,PAR call Nitrogen_investments (KcKjFlag,FNCa, Nlc, forc_pbot10, relh10, CO2a10,O2a10, PARi10c, PARimx10c,rb10, hourpd, tair10, & tleafd10c,tleafn10c, & Kj2Kc, JmaxCoef, Fc,Fj, NUEc, NUEj, NUEcref, NUEjref, NUEr, o3coefjmax, & - Kc, Kj, ci, & + jmaxb0, wc2wjb0, Kc, Kj, ci, & Vcmax, Jmax,JmeanL,JmaxL, Net, Ncb, Nresp, PSN, RESP) Npsntarget = Nlc + Ncb + Net !target nitrogen allocated to photosynthesis, which may be lower or higher than Npsn_avail @@ -957,7 +938,7 @@ subroutine NitrogenAllocation(FNCa,forc_pbot10, relh10, CO2a10,O2a10, PARi10,PAR call Nitrogen_investments (KcKjFlag,FNCa, Nlc2, forc_pbot10, relh10, CO2a10,O2a10, PARi10c, PARimx10c,rb10, hourpd, & tair10, tleafd10c,tleafn10c, & Kj2Kc, JmaxCoef, Fc,Fj, NUEc, NUEj, NUEcref, NUEjref,NUEr, o3coefjmax, & - Kc, Kj, ci, & + jmaxb0, wc2wjb0, Kc, Kj, ci, & Vcmax, Jmax,JmeanL,JmaxL, Net2, Ncb2, Nresp2, PSN2, RESP2) Npsntarget2 = Nlc2 + Ncb2 + Net2 @@ -986,7 +967,7 @@ subroutine NitrogenAllocation(FNCa,forc_pbot10, relh10, CO2a10,O2a10, PARi10,PAR call Nitrogen_investments (KcKjFlag,FNCa, Nlc1,forc_pbot10, relh10, CO2a10,O2a10, PARi10c, PARimx10c,rb10, hourpd, & tair10, tleafd10c,tleafn10c, & Kj2Kc, JmaxCoef, Fc,Fj, NUEc, NUEj, NUEcref, NUEjref,NUEr, o3coefjmax, & - Kc, Kj, ci,& + jmaxb0, wc2wjb0, Kc, Kj, ci,& Vcmax, Jmax,JmeanL,JmaxL, Net1, Ncb1, Nresp1, PSN1, RESP1) Npsntarget1 = Nlc1 + Ncb1 + Net1 Carboncost1 = (Npsntarget - Npsntarget1) * NMCp25 * Cv * (RespTBernacchi(tleafd10c) * hourpd + & @@ -1017,7 +998,7 @@ end subroutine NitrogenAllocation subroutine Nitrogen_investments (KcKjFlag, FNCa, Nlc, forc_pbot10, relh10, & CO2a10, O2a10, PARi10, PARimx10, rb10, hourpd, tair10, tleafd10, tleafn10, & Kj2Kc, JmaxCoef, Fc, Fj, NUEc, NUEj, NUEcref, NUEjref, NUEr, o3coefjmax, & - Kc, Kj, ci, Vcmax, Jmax, JmeanL, JmaxL, Net, Ncb, Nresp, PSN, RESP) + jmaxb0, wc2wjb0, Kc, Kj, ci, Vcmax, Jmax, JmeanL, JmaxL, Net, Ncb, Nresp, PSN, RESP) implicit none integer, intent (in) :: KcKjFlag !flag to indicate whether to update the Kc and Kj using the photosynthesis subroutine; 0--Kc and Kj need to be calculated; 1--Kc and Kj is prescribed. real(r8), intent (in) :: FNCa !Area based functional nitrogen content (g N/m2 leaf) @@ -1043,6 +1024,8 @@ subroutine Nitrogen_investments (KcKjFlag, FNCa, Nlc, forc_pbot10, relh10, & real(r8), intent (in) :: NUEjref !nitrogen use efficiency for electron transport under reference climates real(r8), intent (in) :: NUEr !nitrogen use efficiency for respiration real(r8), intent (in) :: o3coefjmax !ozone coef jmax + real(r8), intent (in) :: jmaxb0 !Baseline proportion of nitrogen allocated for electron transport (J) + real(r8), intent (in) :: wc2wjb0 !The baseline ratio of rubisco limited rate vs light limited photosynthetic rate (Wc:Wj) (-) real(r8), intent (inout) :: Kc !conversion factors from Vc,max to Wc real(r8), intent (inout) :: Kj !conversion factor from electron transport rate to Wj @@ -1072,7 +1055,7 @@ subroutine Nitrogen_investments (KcKjFlag, FNCa, Nlc, forc_pbot10, relh10, & theta = 0.292_r8 / (1.0_r8 + 0.076_r8 / (Nlc * Cb)) ELTRNabsorb = theta * PARi10 - Jmaxb0act = params_inst%jmaxb0 * FNCa * Fj + Jmaxb0act = jmaxb0 * FNCa * Fj ! Default value of o3coefjmax is 1 --> ! o3coefjmax is only different from 1 if ozone_inst%stress_method == 'stress_falk' @@ -1082,7 +1065,7 @@ subroutine Nitrogen_investments (KcKjFlag, FNCa, Nlc, forc_pbot10, relh10, & JmaxL = theta * PARimx10 / (sqrt(1.0_r8 + (theta * PARimx10 / Jmax)**2.0_r8)) NUEchg = (NUEc / NUEcref) * (NUEjref / NUEj) - Wc2Wj = params_inst%wc2wjb0 * (NUEchg**0.5_r8) + Wc2Wj = wc2wjb0 * (NUEchg**0.5_r8) Vcmax = Wc2Wj * JmaxL * Kj2Kc JmeanL = theta * PARi10 / (sqrt(1.0_r8 + (ELTRNabsorb / Jmax)**2.0_r8)) if(KcKjFlag.eq.0)then !update the Kc,Kj, anc ci information @@ -1422,7 +1405,6 @@ subroutine Quadratic(a,b,c,r1,r2) end if end subroutine Quadratic - end module LunaMod diff --git a/src/biogeophys/SnowHydrologyMod.F90 b/src/biogeophys/SnowHydrologyMod.F90 index 9fb1a52dbc..578769d9ea 100644 --- a/src/biogeophys/SnowHydrologyMod.F90 +++ b/src/biogeophys/SnowHydrologyMod.F90 @@ -87,6 +87,7 @@ module SnowHydrologyMod real(r8) :: scvng_fct_mlt_dst4 ! scavenging factor for dust species 4 inclusion in meltwater [frc] real(r8) :: ceta ! Overburden compaction constant (kg/m3) real(r8) :: snw_rds_min ! minimum allowed snow effective radius (also cold "fresh snow" value) [microns] + real(r8) :: upplim_destruct_metamorph ! Upper limit on destructive metamorphism compaction (kg/m3) end type params_type type(params_type), private :: params_inst @@ -151,7 +152,6 @@ module SnowHydrologyMod integer :: overburden_compaction_method = -1 integer :: new_snow_density = LoTmpDnsSlater2017 ! Snow density type - real(r8) :: upplim_destruct_metamorph = 100.0_r8 ! Upper Limit on Destructive Metamorphism Compaction [kg/m3] real(r8) :: overburden_compress_Tfactor = 0.08_r8 ! snow compaction overburden exponential factor (1/K) ! ------------------------------------------------------------------------ @@ -211,8 +211,7 @@ subroutine SnowHydrology_readnl( NLFilename) namelist /clm_snowhydrology_inparm/ & wind_dependent_snow_density, snow_overburden_compaction_method, & - lotmp_snowdensity_method, upplim_destruct_metamorph, & - overburden_compress_Tfactor, & + lotmp_snowdensity_method, overburden_compress_Tfactor, & reset_snow, reset_snow_glc, reset_snow_glc_ela, & snow_dzmin_1, snow_dzmax_l_1, snow_dzmax_u_1, & snow_dzmin_2, snow_dzmax_l_2, snow_dzmax_u_2 @@ -246,7 +245,6 @@ subroutine SnowHydrology_readnl( NLFilename) call shr_mpi_bcast (wind_dependent_snow_density, mpicom) call shr_mpi_bcast (snow_overburden_compaction_method, mpicom) call shr_mpi_bcast (lotmp_snowdensity_method , mpicom) - call shr_mpi_bcast (upplim_destruct_metamorph , mpicom) call shr_mpi_bcast (overburden_compress_Tfactor, mpicom) call shr_mpi_bcast (reset_snow , mpicom) call shr_mpi_bcast (reset_snow_glc , mpicom) @@ -333,6 +331,8 @@ subroutine readParams( ncid ) call readNcdioScalar(ncid, 'ceta', subname, params_inst%ceta) ! minimum allowed snow effective radius (also cold "fresh snow" value) [microns] call readNcdioScalar(ncid, 'snw_rds_min', subname, params_inst%snw_rds_min) + ! Upper limit on destructive metamorphism compaction (kg/m3) + call readNcdioScalar(ncid, 'upplim_destruct_metamorph', subname, params_inst%upplim_destruct_metamorph) end subroutine readParams @@ -1972,7 +1972,8 @@ subroutine SnowCompaction(bounds, num_snowc, filter_snowc, & ! Settling as a result of destructive metamorphism ddz1 = -c3*dexpf - if (bi > upplim_destruct_metamorph) ddz1 = ddz1*exp(-46.0e-3_r8*(bi-upplim_destruct_metamorph)) + if (bi > params_inst%upplim_destruct_metamorph) ddz1 = & + ddz1*exp(-46.0e-3_r8*(bi-params_inst%upplim_destruct_metamorph)) ! Liquid water term diff --git a/src/biogeophys/SoilStateInitTimeConstMod.F90 b/src/biogeophys/SoilStateInitTimeConstMod.F90 index e6fcca0f27..a730417315 100644 --- a/src/biogeophys/SoilStateInitTimeConstMod.F90 +++ b/src/biogeophys/SoilStateInitTimeConstMod.F90 @@ -220,6 +220,7 @@ subroutine SoilStateInitTimeConst(bounds, soilstate_inst, nlfilename) real(r8) :: perturbed_sand ! temporary for paramfile implementation of +/- sand percentage real(r8) :: residual_clay_frac ! temporary for paramfile implementation of +/- residual clay percentage real(r8) :: perturbed_residual_clay_frac ! temporary for paramfile implementation of +/- residual clay percentage + real(r8) :: dust_moist_fact ! tuning factor for soil moisture effect on limiting dust emissions, used by Charlie Zender. Simone Tilmes suggested to change this parameter into a namelist variable for easier CESM tuning. dmleung added 30 Sep 2024 integer :: dimid ! dimension id logical :: readvar type(file_desc_t) :: ncid ! netcdf id @@ -708,17 +709,24 @@ subroutine SoilStateInitTimeConst(bounds, soilstate_inst, nlfilename) ! Initialize threshold soil moisture, and mass fraction of clay as ! scaling coefficient of dust emission flux (kg/m2/s) in each DustEmisType ! module. See the comments in each function. + ! Zender suggested that threshold soil moisture is tunable (see comment + ! inside ThresholdSoilMoistZender2003). dmleung further add dust_moist_fact + ! ofr modelers to tune the threshold soil moisture. The resulting tuning + ! factor is thus a = dust_moist_fact / (clay3d). dmleung 30 Sep 2024 ! -------------------------------------------------------------------- do c = begc,endc g = col%gridcell(c) - soilstate_inst%gwc_thr_col(c) = ThresholdSoilMoistZender2003( clay3d(g,1) ) + !soilstate_inst%gwc_thr_col(c) = ThresholdSoilMoistZender2003( clay3d(g,1) ) if ( is_dust_emis_leung() )then soilstate_inst%mss_frc_cly_vld_col(c) = MassFracClayLeung2023( clay3d(g,1) ) + dust_moist_fact = 1.0_r8 ! change this into a namelist variable later., currrently not used but could be in the future else soilstate_inst%mss_frc_cly_vld_col(c) = MassFracClay( clay3d(g,1) ) + dust_moist_fact = 1.0_r8 end if + soilstate_inst%gwc_thr_col(c) = dust_moist_fact * ThresholdSoilMoistZender2003( clay3d(g,1) ) end do @@ -739,9 +747,11 @@ real(r8) function ThresholdSoilMoistZender2003( clay ) ! Calculate the threshold gravimetric water content needed for dust emission, based on clay content ! This was the original equation with a = 1 / (%clay) being the tuning factor for soil ! moisture effect in Zender's 2003 dust emission scheme (only for top layer). + ! dmleung further added dust_moist_fact for more flexibility in tuning, so the tuning factor here + ! is a = dust_moist_fact / (%clay). dmleung added dust_moist_fact on 30 Sep 2024. ! ! 0.17 and 0.14 are fitting coefficients in Fecan et al. (1999), and 0.01 is used to - ! convert surface clay fraction from percentage to fraction. + ! convert surface clay from percentage to fraction. ! The equation comes from Eq. 14 of Fecan et al. (1999; https://doi.org/10.1007/s00585-999-0149-7). ! ! NOTE: dmleung 19 Feb 2024. diff --git a/src/biogeophys/SurfaceAlbedoType.F90 b/src/biogeophys/SurfaceAlbedoType.F90 index e90caeecbb..10819a47b6 100644 --- a/src/biogeophys/SurfaceAlbedoType.F90 +++ b/src/biogeophys/SurfaceAlbedoType.F90 @@ -242,12 +242,12 @@ subroutine InitHistory(this, bounds) this%albgrd_col(begc:endc,:) = spval call hist_addfld2d (fname='ALBGRD', units='proportion', type2d='numrad', & avgflag='A', long_name='ground albedo (direct)', & - ptr_col=this%albgrd_col, default='inactive') + ptr_col=this%albgrd_col, default='active') this%albgri_col(begc:endc,:) = spval call hist_addfld2d (fname='ALBGRI', units='proportion', type2d='numrad', & avgflag='A', long_name='ground albedo (indirect)', & - ptr_col=this%albgri_col, default='inactive') + ptr_col=this%albgri_col, default='active') if (use_SSRE) then this%albdSF_patch(begp:endp,:) = spval diff --git a/src/biogeophys/UrbanAlbedoMod.F90 b/src/biogeophys/UrbanAlbedoMod.F90 index 2e854a0497..3e84f73176 100644 --- a/src/biogeophys/UrbanAlbedoMod.F90 +++ b/src/biogeophys/UrbanAlbedoMod.F90 @@ -78,9 +78,14 @@ subroutine UrbanAlbedo (bounds, num_urbanl, filter_urbanl, & type(surfalb_type) , intent(inout) :: surfalb_inst ! ! !LOCAL VARIABLES: - integer :: fl,fp,fc,g,l,p,c,ib ! indices + integer :: fl,fp,fc,g,l,p,c,ib,f,fn ! indices and counters integer :: ic ! 0=unit incoming direct; 1=unit incoming diffuse - integer :: num_solar ! counter + integer, allocatable :: filter_urbanl_coszen_gt0(:) ! filter for urban landunits with coszen > 0 + integer :: num_urbanl_coszen_gt0 ! number of urban landunits with coszen > 0 + integer, allocatable :: filter_nourbanl_coszen_gt0(:) ! filter for urban landunits with coszen <= 0 + integer :: num_nourbanl_coszen_gt0 ! number of urban landunits with coszen <= 0 + integer, allocatable :: filter_urbanc_coszen_gt0(:) ! filter for urban columns with coszen > 0 + integer :: num_urbanc_coszen_gt0 ! number of urban columns with coszen > 0 real(r8) :: coszen (bounds%begl:bounds%endl) ! cosine solar zenith angle for next time step (landunit) real(r8) :: zen (bounds%begl:bounds%endl) ! solar zenith angle (radians) real(r8) :: sdir (bounds%begl:bounds%endl, numrad) ! direct beam solar radiation on horizontal surface @@ -165,9 +170,16 @@ subroutine UrbanAlbedo (bounds, num_urbanl, filter_urbanl, & begl => bounds%begl , & vf_sr => urbanparams_inst%vf_sr , & ! Input: [real(r8) (:) ] view factor of sky for road vf_sw => urbanparams_inst%vf_sw , & ! Input: [real(r8) (:) ] view factor of sky for one wall - endl => bounds%endl & + endl => bounds%endl , & + begc => bounds%begc , & + endc => bounds%endc & ) + ! Allocate urbanl and urbanc coszen filters + allocate(filter_urbanl_coszen_gt0(bounds%endl-bounds%begl+1)) + allocate(filter_nourbanl_coszen_gt0(bounds%endl-bounds%begl+1)) + allocate(filter_urbanc_coszen_gt0(bounds%endc-bounds%begc+1)) + ! ---------------------------------------------------------------------------- ! Solar declination and cosine solar zenith angle and zenith angle for ! next time step @@ -228,15 +240,36 @@ subroutine UrbanAlbedo (bounds, num_urbanl, filter_urbanl, & end do end do - ! ---------------------------------------------------------------------------- - ! Urban Code - ! ---------------------------------------------------------------------------- - - num_solar = 0 + ! Populate urbanl and urbanc coszen filters + f = 0 + fn = 0 do fl = 1,num_urbanl l = filter_urbanl(fl) - if (coszen(l) > 0._r8) num_solar = num_solar + 1 + if (coszen(l) > 0._r8) then + f = f + 1 + filter_urbanl_coszen_gt0(f) = l + else + fn = fn + 1 + filter_nourbanl_coszen_gt0(fn) = l + end if + end do + num_urbanl_coszen_gt0 = f + num_nourbanl_coszen_gt0 = fn + + f = 0 + do fc = 1,num_urbanc + c = filter_urbanc(fc) + l = col%landunit(c) + if (coszen(l) > 0._r8) then + f = f + 1 + filter_urbanc_coszen_gt0(f) = c + end if end do + num_urbanc_coszen_gt0 = f + + ! ---------------------------------------------------------------------------- + ! Urban Code + ! ---------------------------------------------------------------------------- do ib = 1,numrad do fl = 1,num_urbanl @@ -267,184 +300,183 @@ subroutine UrbanAlbedo (bounds, num_urbanl, filter_urbanl, & end do ! ---------------------------------------------------------------------------- - ! Only do the rest if all coszen are positive + ! Use the urban coszen filters to only calculate quantities when coszen > 0 ! ---------------------------------------------------------------------------- - if (num_solar > 0)then - ! Set constants - solar fluxes are per unit incoming flux + ! Set constants - solar fluxes are per unit incoming flux - do ib = 1,numrad - do fl = 1,num_urbanl - l = filter_urbanl(fl) - sdir(l,ib) = 1._r8 - sdif(l,ib) = 1._r8 - end do + do ib = 1,numrad + do fl = 1,num_urbanl_coszen_gt0 + l = filter_urbanl_coszen_gt0(fl) + sdir(l,ib) = 1._r8 + sdif(l,ib) = 1._r8 end do + end do - ! Incident direct beam radiation for - ! (a) roof and (b) road and both walls in urban canyon - - if (num_urbanl > 0) then - call incident_direct (bounds, & - num_urbanl, filter_urbanl, & - canyon_hwr(begl:endl), & - coszen(begl:endl), & - zen(begl:endl), & - sdir(begl:endl, :), & - sdir_road(begl:endl, :), & - sdir_sunwall(begl:endl, :), & - sdir_shadewall(begl:endl, :)) - end if + ! Incident direct beam radiation for + ! (a) roof and (b) road and both walls in urban canyon + + if (num_urbanl > 0) then + call incident_direct (bounds, & + num_urbanl_coszen_gt0, & + filter_urbanl_coszen_gt0, & + num_nourbanl_coszen_gt0, & + filter_nourbanl_coszen_gt0, & + canyon_hwr(begl:endl), & + zen(begl:endl), & + sdir(begl:endl, :), & + sdir_road(begl:endl, :), & + sdir_sunwall(begl:endl, :), & + sdir_shadewall(begl:endl, :)) + end if - ! Incident diffuse radiation for - ! (a) roof and (b) road and both walls in urban canyon. - - if (num_urbanl > 0) then - call incident_diffuse (bounds, & - num_urbanl, filter_urbanl, & - canyon_hwr(begl:endl), & - sdif(begl:endl, :), & - sdif_road(begl:endl, :), & - sdif_sunwall(begl:endl, :), & - sdif_shadewall(begl:endl, :), & - urbanparams_inst) - end if + ! Incident diffuse radiation for + ! (a) roof and (b) road and both walls in urban canyon. + + if (num_urbanl_coszen_gt0 > 0) then + call incident_diffuse (bounds, & + num_urbanl_coszen_gt0, & + filter_urbanl_coszen_gt0, & + canyon_hwr(begl:endl), & + sdif(begl:endl, :), & + sdif_road(begl:endl, :), & + sdif_sunwall(begl:endl, :), & + sdif_shadewall(begl:endl, :), & + urbanparams_inst) + end if - ! Get snow albedos for roof and impervious and pervious road - if (num_urbanl > 0) then - ic = 0 - call SnowAlbedo(bounds, & - num_urbanc, filter_urbanc, & - coszen(begl:endl), & - ic, & - albsnd_roof(begl:endl, :), & - albsnd_improad(begl:endl, :), & - albsnd_perroad(begl:endl, :), & - waterstatebulk_inst) - - ic = 1 - call SnowAlbedo(bounds, & - num_urbanc, filter_urbanc, & - coszen(begl:endl), & - ic, & - albsni_roof(begl:endl, :), & - albsni_improad(begl:endl, :), & - albsni_perroad(begl:endl, :), & - waterstatebulk_inst) - end if + ! Get snow albedos for roof and impervious and pervious road + if (num_urbanl > 0) then + ic = 0 + call SnowAlbedo(bounds, & + num_urbanc, filter_urbanc, & + num_urbanc_coszen_gt0, & + filter_urbanc_coszen_gt0, & + ic, & + albsnd_roof(begl:endl, :), & + albsnd_improad(begl:endl, :), & + albsnd_perroad(begl:endl, :), & + waterstatebulk_inst) + + ic = 1 + call SnowAlbedo(bounds, & + num_urbanc, filter_urbanc, & + num_urbanc_coszen_gt0, & + filter_urbanc_coszen_gt0, & + ic, & + albsni_roof(begl:endl, :), & + albsni_improad(begl:endl, :), & + albsni_perroad(begl:endl, :), & + waterstatebulk_inst) + end if - ! Combine snow-free and snow albedos - do ib = 1,numrad - do fc = 1,num_urbanc - c = filter_urbanc(fc) - l = col%landunit(c) - if (ctype(c) == icol_roof) then - alb_roof_dir_s(l,ib) = alb_roof_dir(l,ib)*(1._r8-frac_sno(c)) & - + albsnd_roof(l,ib)*frac_sno(c) - alb_roof_dif_s(l,ib) = alb_roof_dif(l,ib)*(1._r8-frac_sno(c)) & - + albsni_roof(l,ib)*frac_sno(c) - else if (ctype(c) == icol_road_imperv) then - alb_improad_dir_s(l,ib) = alb_improad_dir(l,ib)*(1._r8-frac_sno(c)) & - + albsnd_improad(l,ib)*frac_sno(c) - alb_improad_dif_s(l,ib) = alb_improad_dif(l,ib)*(1._r8-frac_sno(c)) & - + albsni_improad(l,ib)*frac_sno(c) - else if (ctype(c) == icol_road_perv) then - alb_perroad_dir_s(l,ib) = alb_perroad_dir(l,ib)*(1._r8-frac_sno(c)) & - + albsnd_perroad(l,ib)*frac_sno(c) - alb_perroad_dif_s(l,ib) = alb_perroad_dif(l,ib)*(1._r8-frac_sno(c)) & - + albsni_perroad(l,ib)*frac_sno(c) - end if - end do + ! Combine snow-free and snow albedos + do ib = 1,numrad + do fc = 1,num_urbanc_coszen_gt0 + c = filter_urbanc_coszen_gt0(fc) + l = col%landunit(c) + if (ctype(c) == icol_roof) then + alb_roof_dir_s(l,ib) = alb_roof_dir(l,ib)*(1._r8-frac_sno(c)) & + + albsnd_roof(l,ib)*frac_sno(c) + alb_roof_dif_s(l,ib) = alb_roof_dif(l,ib)*(1._r8-frac_sno(c)) & + + albsni_roof(l,ib)*frac_sno(c) + else if (ctype(c) == icol_road_imperv) then + alb_improad_dir_s(l,ib) = alb_improad_dir(l,ib)*(1._r8-frac_sno(c)) & + + albsnd_improad(l,ib)*frac_sno(c) + alb_improad_dif_s(l,ib) = alb_improad_dif(l,ib)*(1._r8-frac_sno(c)) & + + albsni_improad(l,ib)*frac_sno(c) + else if (ctype(c) == icol_road_perv) then + alb_perroad_dir_s(l,ib) = alb_perroad_dir(l,ib)*(1._r8-frac_sno(c)) & + + albsnd_perroad(l,ib)*frac_sno(c) + alb_perroad_dif_s(l,ib) = alb_perroad_dif(l,ib)*(1._r8-frac_sno(c)) & + + albsni_perroad(l,ib)*frac_sno(c) + end if end do + end do - ! Reflected and absorbed solar radiation per unit incident radiation - ! for road and both walls in urban canyon allowing for multiple reflection - ! Reflected and absorbed solar radiation per unit incident radiation for roof + ! Reflected and absorbed solar radiation per unit incident radiation + ! for road and both walls in urban canyon allowing for multiple reflection + ! Reflected and absorbed solar radiation per unit incident radiation for roof + + if (num_urbanl_coszen_gt0 > 0) then + call net_solar (bounds, & + num_urbanl_coszen_gt0, & + filter_urbanl_coszen_gt0, & + canyon_hwr (begl:endl), & + wtroad_perv (begl:endl), & + sdir (begl:endl, :), & + sdif (begl:endl, :), & + alb_improad_dir_s (begl:endl, :), & + alb_perroad_dir_s (begl:endl, :), & + alb_wall_dir (begl:endl, :), & + alb_roof_dir_s (begl:endl, :), & + alb_improad_dif_s (begl:endl, :), & + alb_perroad_dif_s (begl:endl, :), & + alb_wall_dif (begl:endl, :), & + alb_roof_dif_s (begl:endl, :), & + sdir_road (begl:endl, :), & + sdir_sunwall (begl:endl, :), & + sdir_shadewall (begl:endl, :), & + sdif_road (begl:endl, :), & + sdif_sunwall (begl:endl, :), & + sdif_shadewall (begl:endl, :), & + sref_improad_dir (begl:endl, :), & + sref_perroad_dir (begl:endl, :), & + sref_sunwall_dir (begl:endl, :), & + sref_shadewall_dir (begl:endl, :), & + sref_roof_dir (begl:endl, :), & + sref_improad_dif (begl:endl, :), & + sref_perroad_dif (begl:endl, :), & + sref_sunwall_dif (begl:endl, :), & + sref_shadewall_dif (begl:endl, :), & + sref_roof_dif (begl:endl, :), & + urbanparams_inst, solarabs_inst) + end if - if (num_urbanl > 0) then - call net_solar (bounds, & - num_urbanl, filter_urbanl, & - coszen (begl:endl), & - canyon_hwr (begl:endl), & - wtroad_perv (begl:endl), & - sdir (begl:endl, :), & - sdif (begl:endl, :), & - alb_improad_dir_s (begl:endl, :), & - alb_perroad_dir_s (begl:endl, :), & - alb_wall_dir (begl:endl, :), & - alb_roof_dir_s (begl:endl, :), & - alb_improad_dif_s (begl:endl, :), & - alb_perroad_dif_s (begl:endl, :), & - alb_wall_dif (begl:endl, :), & - alb_roof_dif_s (begl:endl, :), & - sdir_road (begl:endl, :), & - sdir_sunwall (begl:endl, :), & - sdir_shadewall (begl:endl, :), & - sdif_road (begl:endl, :), & - sdif_sunwall (begl:endl, :), & - sdif_shadewall (begl:endl, :), & - sref_improad_dir (begl:endl, :), & - sref_perroad_dir (begl:endl, :), & - sref_sunwall_dir (begl:endl, :), & - sref_shadewall_dir (begl:endl, :), & - sref_roof_dir (begl:endl, :), & - sref_improad_dif (begl:endl, :), & - sref_perroad_dif (begl:endl, :), & - sref_sunwall_dif (begl:endl, :), & - sref_shadewall_dif (begl:endl, :), & - sref_roof_dif (begl:endl, :), & - urbanparams_inst, solarabs_inst) - end if + ! ---------------------------------------------------------------------------- + ! Map urban output to surfalb_inst components + ! ---------------------------------------------------------------------------- - ! ---------------------------------------------------------------------------- - ! Map urban output to surfalb_inst components - ! ---------------------------------------------------------------------------- - - ! Set albgrd and albgri (ground albedos) and albd and albi (surface albedos) - - do ib = 1,numrad - do fc = 1,num_urbanc - c = filter_urbanc(fc) - l = col%landunit(c) - if (ctype(c) == icol_roof) then - albgrd(c,ib) = sref_roof_dir(l,ib) - albgri(c,ib) = sref_roof_dif(l,ib) - else if (ctype(c) == icol_sunwall) then - albgrd(c,ib) = sref_sunwall_dir(l,ib) - albgri(c,ib) = sref_sunwall_dif(l,ib) - else if (ctype(c) == icol_shadewall) then - albgrd(c,ib) = sref_shadewall_dir(l,ib) - albgri(c,ib) = sref_shadewall_dif(l,ib) - else if (ctype(c) == icol_road_perv) then - albgrd(c,ib) = sref_perroad_dir(l,ib) - albgri(c,ib) = sref_perroad_dif(l,ib) - else if (ctype(c) == icol_road_imperv) then - albgrd(c,ib) = sref_improad_dir(l,ib) - albgri(c,ib) = sref_improad_dif(l,ib) - endif -! add new snicar albedo variables for history fields - if (coszen(l) > 0._r8) then - albgrd_hst(c,ib) = albgrd(c,ib) - albgri_hst(c,ib) = albgri(c,ib) - end if -! end add new snicar - end do - do fp = 1,num_urbanp - p = filter_urbanp(fp) - c = patch%column(p) - l = patch%landunit(p) - albd(p,ib) = albgrd(c,ib) - albi(p,ib) = albgri(c,ib) -! add new snicar albedo variables for history fields - if (coszen(l) > 0._r8) then - albd_hst(p,ib) = albd(p,ib) - albi_hst(p,ib) = albi(p,ib) - end if -! end add new snicar - end do + ! Set albgrd and albgri (ground albedos) and albd and albi (surface albedos) + + do ib = 1,numrad + do fc = 1,num_urbanc + c = filter_urbanc(fc) + l = col%landunit(c) + if (ctype(c) == icol_roof) then + albgrd(c,ib) = sref_roof_dir(l,ib) + albgri(c,ib) = sref_roof_dif(l,ib) + else if (ctype(c) == icol_sunwall) then + albgrd(c,ib) = sref_sunwall_dir(l,ib) + albgri(c,ib) = sref_sunwall_dif(l,ib) + else if (ctype(c) == icol_shadewall) then + albgrd(c,ib) = sref_shadewall_dir(l,ib) + albgri(c,ib) = sref_shadewall_dif(l,ib) + else if (ctype(c) == icol_road_perv) then + albgrd(c,ib) = sref_perroad_dir(l,ib) + albgri(c,ib) = sref_perroad_dif(l,ib) + else if (ctype(c) == icol_road_imperv) then + albgrd(c,ib) = sref_improad_dir(l,ib) + albgri(c,ib) = sref_improad_dif(l,ib) + endif + if (coszen(l) > 0._r8) then + albgrd_hst(c,ib) = albgrd(c,ib) + albgri_hst(c,ib) = albgri(c,ib) + end if end do - end if + do fp = 1,num_urbanp + p = filter_urbanp(fp) + c = patch%column(p) + l = patch%landunit(p) + albd(p,ib) = albgrd(c,ib) + albi(p,ib) = albgri(c,ib) + if (coszen(l) > 0._r8) then + albd_hst(p,ib) = albd(p,ib) + albi_hst(p,ib) = albi(p,ib) + end if + end do + end do end associate @@ -452,7 +484,7 @@ end subroutine UrbanAlbedo !----------------------------------------------------------------------- subroutine SnowAlbedo (bounds , & - num_urbanc, filter_urbanc, coszen, ind , & + num_urbanc, filter_urbanc, num_urbanc_coszen_gt0, filter_urbanc_coszen_gt0, ind , & albsn_roof, albsn_improad, albsn_perroad, & waterstatebulk_inst) ! @@ -466,8 +498,9 @@ subroutine SnowAlbedo (bounds , & type(bounds_type), intent(in) :: bounds integer , intent(in) :: num_urbanc ! number of urban columns in clump integer , intent(in) :: filter_urbanc(:) ! urban column filter + integer , intent(in) :: num_urbanc_coszen_gt0 ! number of urban columns with coszen > 0 + integer , intent(in) :: filter_urbanc_coszen_gt0(:) ! filter for urban columns with coszen > 0 integer , intent(in) :: ind ! 0=direct beam, 1=diffuse radiation - real(r8), intent(in) :: coszen ( bounds%begl: ) ! cosine solar zenith angle [landunit] real(r8), intent(out):: albsn_roof ( bounds%begl: , 1: ) ! roof snow albedo by waveband [landunit, numrad] real(r8), intent(out):: albsn_improad ( bounds%begl: , 1: ) ! impervious road snow albedo by waveband [landunit, numrad] real(r8), intent(out):: albsn_perroad ( bounds%begl: , 1: ) ! pervious road snow albedo by waveband [landunit, numrad] @@ -488,7 +521,6 @@ subroutine SnowAlbedo (bounds , & SHR_ASSERT_ALL_FL(numrad == 2, sourcefile, __LINE__) ! Enforce expected array sizes - SHR_ASSERT_ALL_FL((ubound(coszen) == (/bounds%endl/)), sourcefile, __LINE__) SHR_ASSERT_ALL_FL((ubound(albsn_roof) == (/bounds%endl, numrad/)), sourcefile, __LINE__) SHR_ASSERT_ALL_FL((ubound(albsn_improad) == (/bounds%endl, numrad/)), sourcefile, __LINE__) SHR_ASSERT_ALL_FL((ubound(albsn_perroad) == (/bounds%endl, numrad/)), sourcefile, __LINE__) @@ -497,10 +529,10 @@ subroutine SnowAlbedo (bounds , & caller = 'UrbanAlbedoMod:SnowAlbedo', & h2osno_total = h2osno_total(bounds%begc:bounds%endc)) - do fc = 1,num_urbanc - c = filter_urbanc(fc) + do fc = 1,num_urbanc_coszen_gt0 + c = filter_urbanc_coszen_gt0(fc) l = col%landunit(c) - if (coszen(l) > 0._r8 .and. h2osno_total(c) > 0._r8) then + if (h2osno_total(c) > 0._r8) then if (col%itype(c) == icol_roof) then albsn_roof(l,1) = snal0 albsn_roof(l,2) = snal1 @@ -528,8 +560,9 @@ subroutine SnowAlbedo (bounds , & end subroutine SnowAlbedo !----------------------------------------------------------------------- - subroutine incident_direct (bounds , & - num_urbanl, filter_urbanl, canyon_hwr, coszen, zen , & + subroutine incident_direct (bounds, & + num_urbanl_coszen_gt0, filter_urbanl_coszen_gt0, & + num_nourbanl_coszen_gt0, filter_nourbanl_coszen_gt0, canyon_hwr, zen, & sdir, sdir_road, sdir_sunwall, sdir_shadewall) ! ! !DESCRIPTION: @@ -567,10 +600,11 @@ subroutine incident_direct (bounds , & ! ! !ARGUMENTS: type(bounds_type), intent(in) :: bounds - integer , intent(in) :: num_urbanl ! number of urban landunits - integer , intent(in) :: filter_urbanl(:) ! urban landunit filter + integer , intent(in) :: num_urbanl_coszen_gt0 ! number of urban landunits with coszen > 0 + integer , intent(in) :: filter_urbanl_coszen_gt0(:) ! filter for urban landunits with coszen > 0 + integer , intent(in) :: num_nourbanl_coszen_gt0 ! number of urban landunits with coszen <= 0 + integer , intent(in) :: filter_nourbanl_coszen_gt0(:) ! filter for urban landunits with coszen <= 0 real(r8), intent(in) :: canyon_hwr( bounds%begl: ) ! ratio of building height to street width [landunit] - real(r8), intent(in) :: coszen( bounds%begl: ) ! cosine solar zenith angle [landunit] real(r8), intent(in) :: zen( bounds%begl: ) ! solar zenith angle (radians) [landunit] real(r8), intent(in) :: sdir( bounds%begl: , 1: ) ! direct beam solar radiation incident on horizontal surface [landunit, numrad] real(r8), intent(out) :: sdir_road( bounds%begl: , 1: ) ! direct beam solar radiation incident on road per unit incident flux [landunit, numrad] @@ -595,54 +629,49 @@ subroutine incident_direct (bounds , & ! Enforce expected array sizes SHR_ASSERT_ALL_FL((ubound(canyon_hwr) == (/bounds%endl/)), sourcefile, __LINE__) - SHR_ASSERT_ALL_FL((ubound(coszen) == (/bounds%endl/)), sourcefile, __LINE__) SHR_ASSERT_ALL_FL((ubound(zen) == (/bounds%endl/)), sourcefile, __LINE__) SHR_ASSERT_ALL_FL((ubound(sdir) == (/bounds%endl, numrad/)), sourcefile, __LINE__) SHR_ASSERT_ALL_FL((ubound(sdir_road) == (/bounds%endl, numrad/)), sourcefile, __LINE__) SHR_ASSERT_ALL_FL((ubound(sdir_sunwall) == (/bounds%endl, numrad/)), sourcefile, __LINE__) SHR_ASSERT_ALL_FL((ubound(sdir_shadewall) == (/bounds%endl, numrad/)), sourcefile, __LINE__) - do fl = 1,num_urbanl - l = filter_urbanl(fl) - if (coszen(l) > 0._r8) then - theta0(l) = asin(min( (1._r8/(canyon_hwr(l)*tan(max(zen(l),0.000001_r8)))), 1._r8 )) - tanzen(l) = tan(zen(l)) - end if + do fl = 1,num_urbanl_coszen_gt0 + l = filter_urbanl_coszen_gt0(fl) + theta0(l) = asin(min( (1._r8/(canyon_hwr(l)*tan(max(zen(l),0.000001_r8)))), 1._r8 )) + tanzen(l) = tan(zen(l)) end do do ib = 1,numrad - do fl = 1,num_urbanl - l = filter_urbanl(fl) - if (coszen(l) > 0._r8) then - sdir_shadewall(l,ib) = 0._r8 + do fl = 1,num_urbanl_coszen_gt0 + l = filter_urbanl_coszen_gt0(fl) + sdir_shadewall(l,ib) = 0._r8 - ! incident solar radiation on wall and road integrated over all canyon orientations (0 <= theta <= pi/2) + ! incident solar radiation on wall and road integrated over all canyon orientations (0 <= theta <= pi/2) - sdir_road(l,ib) = sdir(l,ib) * & - (2._r8*theta0(l)/rpi - 2./rpi*canyon_hwr(l)*tanzen(l)*(1._r8-cos(theta0(l)))) - sdir_sunwall(l,ib) = 2._r8 * sdir(l,ib) * ((1._r8/canyon_hwr(l))* & - (0.5_r8-theta0(l)/rpi) + (1._r8/rpi)*tanzen(l)*(1._r8-cos(theta0(l)))) + sdir_road(l,ib) = sdir(l,ib) * & + (2._r8*theta0(l)/rpi - 2./rpi*canyon_hwr(l)*tanzen(l)*(1._r8-cos(theta0(l)))) + sdir_sunwall(l,ib) = 2._r8 * sdir(l,ib) * ((1._r8/canyon_hwr(l))* & + (0.5_r8-theta0(l)/rpi) + (1._r8/rpi)*tanzen(l)*(1._r8-cos(theta0(l)))) - ! conservation check for road and wall. need to use wall fluxes converted to ground area + ! conservation check for road and wall. need to use wall fluxes converted to ground area - swall_projected = (sdir_shadewall(l,ib) + sdir_sunwall(l,ib)) * canyon_hwr(l) - err1(l) = sdir(l,ib) - (sdir_road(l,ib) + swall_projected) - else - sdir_road(l,ib) = 0._r8 - sdir_sunwall(l,ib) = 0._r8 - sdir_shadewall(l,ib) = 0._r8 - endif + swall_projected = (sdir_shadewall(l,ib) + sdir_sunwall(l,ib)) * canyon_hwr(l) + err1(l) = sdir(l,ib) - (sdir_road(l,ib) + swall_projected) + end do + do fl = 1,num_nourbanl_coszen_gt0 + l = filter_nourbanl_coszen_gt0(fl) + sdir_road(l,ib) = 0._r8 + sdir_sunwall(l,ib) = 0._r8 + sdir_shadewall(l,ib) = 0._r8 end do - do fl = 1,num_urbanl - l = filter_urbanl(fl) - if (coszen(l) > 0._r8) then - if (abs(err1(l)) > 0.001_r8) then - write (iulog,*) 'urban direct beam solar radiation balance error',err1(l) - write (iulog,*) 'clm model is stopping' - call endrun(subgrid_index=l, subgrid_level=subgrid_level_landunit, msg=errmsg(sourcefile, __LINE__)) - endif + do fl = 1,num_urbanl_coszen_gt0 + l = filter_urbanl_coszen_gt0(fl) + if (abs(err1(l)) > 0.001_r8) then + write (iulog,*) 'urban direct beam solar radiation balance error',err1(l) + write (iulog,*) 'clm model is stopping' + call endrun(subgrid_index=l, subgrid_level=subgrid_level_landunit, msg=errmsg(sourcefile, __LINE__)) endif end do @@ -650,41 +679,37 @@ subroutine incident_direct (bounds , & ! sum sroad and swall over all canyon orientations (0 <= theta <= pi/2) if (numchk) then - do fl = 1,num_urbanl - l = filter_urbanl(fl) - if (coszen(l) > 0._r8) then - sumr = 0._r8 - sumw = 0._r8 - num = 0._r8 - do i = 1, 9000 - theta = i/100._r8 * rpi/180._r8 - zen0 = atan(1._r8/(canyon_hwr(l)*sin(theta))) - if (zen(l) >= zen0) then - sumr = sumr + 0._r8 - sumw = sumw + sdir(l,ib) / canyon_hwr(l) - else - sumr = sumr + sdir(l,ib) * (1._r8-canyon_hwr(l)*sin(theta)*tanzen(l)) - sumw = sumw + sdir(l,ib) * sin(theta)*tanzen(l) - end if - num = num + 1._r8 - end do - err2(l) = sumr/num - sdir_road(l,ib) - err3(l) = sumw/num - sdir_sunwall(l,ib) - endif - end do - do fl = 1,num_urbanl - l = filter_urbanl(fl) - if (coszen(l) > 0._r8) then - if (abs(err2(l)) > 0.0006_r8 ) then - write (iulog,*) 'urban road incident direct beam solar radiation error',err2(l) - write (iulog,*) 'clm model is stopping' - call endrun(subgrid_index=l, subgrid_level=subgrid_level_landunit, msg=errmsg(sourcefile, __LINE__)) - endif - if (abs(err3(l)) > 0.0006_r8 ) then - write (iulog,*) 'urban wall incident direct beam solar radiation error',err3(l) - write (iulog,*) 'clm model is stopping' - call endrun(subgrid_index=l, subgrid_level=subgrid_level_landunit, msg=errmsg(sourcefile, __LINE__)) + do fl = 1,num_urbanl_coszen_gt0 + l = filter_urbanl_coszen_gt0(fl) + sumr = 0._r8 + sumw = 0._r8 + num = 0._r8 + do i = 1, 9000 + theta = i/100._r8 * rpi/180._r8 + zen0 = atan(1._r8/(canyon_hwr(l)*sin(theta))) + if (zen(l) >= zen0) then + sumr = sumr + 0._r8 + sumw = sumw + sdir(l,ib) / canyon_hwr(l) + else + sumr = sumr + sdir(l,ib) * (1._r8-canyon_hwr(l)*sin(theta)*tanzen(l)) + sumw = sumw + sdir(l,ib) * sin(theta)*tanzen(l) end if + num = num + 1._r8 + end do + err2(l) = sumr/num - sdir_road(l,ib) + err3(l) = sumw/num - sdir_sunwall(l,ib) + end do + do fl = 1,num_urbanl_coszen_gt0 + l = filter_urbanl_coszen_gt0(fl) + if (abs(err2(l)) > 0.0006_r8 ) then + write (iulog,*) 'urban road incident direct beam solar radiation error',err2(l) + write (iulog,*) 'clm model is stopping' + call endrun(subgrid_index=l, subgrid_level=subgrid_level_landunit, msg=errmsg(sourcefile, __LINE__)) + endif + if (abs(err3(l)) > 0.0006_r8 ) then + write (iulog,*) 'urban wall incident direct beam solar radiation error',err3(l) + write (iulog,*) 'clm model is stopping' + call endrun(subgrid_index=l, subgrid_level=subgrid_level_landunit, msg=errmsg(sourcefile, __LINE__)) end if end do end if @@ -695,7 +720,7 @@ end subroutine incident_direct !----------------------------------------------------------------------- subroutine incident_diffuse (bounds, & - num_urbanl, filter_urbanl, canyon_hwr, & + num_urbanl_coszen_gt0, filter_urbanl_coszen_gt0, canyon_hwr, & sdif, sdif_road, sdif_sunwall, sdif_shadewall, & urbanparams_inst) ! @@ -707,8 +732,8 @@ subroutine incident_diffuse (bounds, & ! ! !ARGUMENTS: type(bounds_type) , intent(in) :: bounds - integer , intent(in) :: num_urbanl ! number of urban landunits - integer , intent(in) :: filter_urbanl(:) ! urban landunit filter + integer , intent(in) :: num_urbanl_coszen_gt0 ! number of urban landunits with coszen > 0 + integer , intent(in) :: filter_urbanl_coszen_gt0(:) ! filter for urban landunits with coszen > 0 real(r8) , intent(in) :: canyon_hwr ( bounds%begl: ) ! ratio of building height to street width [landunit] real(r8) , intent(in) :: sdif ( bounds%begl: , 1: ) ! diffuse solar radiation incident on horizontal surface [landunit, numrad] real(r8) , intent(out) :: sdif_road ( bounds%begl: , 1: ) ! diffuse solar radiation incident on road [landunit, numrad] @@ -738,8 +763,8 @@ subroutine incident_diffuse (bounds, & ! diffuse solar and conservation check. need to convert wall fluxes to ground area - do fl = 1,num_urbanl - l = filter_urbanl(fl) + do fl = 1,num_urbanl_coszen_gt0 + l = filter_urbanl_coszen_gt0(fl) sdif_road(l,ib) = sdif(l,ib) * vf_sr(l) sdif_sunwall(l,ib) = sdif(l,ib) * vf_sw(l) sdif_shadewall(l,ib) = sdif(l,ib) * vf_sw(l) @@ -750,8 +775,8 @@ subroutine incident_diffuse (bounds, & ! error check - do fl = 1, num_urbanl - l = filter_urbanl(fl) + do fl = 1, num_urbanl_coszen_gt0 + l = filter_urbanl_coszen_gt0(fl) if (abs(err(l)) > 0.001_r8) then write (iulog,*) 'urban diffuse solar radiation balance error',err(l) write (iulog,*) 'clm model is stopping' @@ -767,11 +792,11 @@ end subroutine incident_diffuse !----------------------------------------------------------------------- subroutine net_solar (bounds , & - num_urbanl, filter_urbanl, coszen, canyon_hwr, wtroad_perv, sdir, sdif , & + num_urbanl_coszen_gt0, filter_urbanl_coszen_gt0, canyon_hwr, wtroad_perv, sdir, sdif , & alb_improad_dir, alb_perroad_dir, alb_wall_dir, alb_roof_dir , & alb_improad_dif, alb_perroad_dif, alb_wall_dif, alb_roof_dif , & - sdir_road, sdir_sunwall, sdir_shadewall, & - sdif_road, sdif_sunwall, sdif_shadewall, & + sdir_road, sdir_sunwall, sdir_shadewall , & + sdif_road, sdif_sunwall, sdif_shadewall , & sref_improad_dir, sref_perroad_dir, sref_sunwall_dir, sref_shadewall_dir, sref_roof_dir , & sref_improad_dif, sref_perroad_dif, sref_sunwall_dif, sref_shadewall_dif, sref_roof_dif , & urbanparams_inst, solarabs_inst) @@ -782,9 +807,8 @@ subroutine net_solar (bounds ! ! !ARGUMENTS: type (bounds_type), intent(in) :: bounds - integer , intent(in) :: num_urbanl ! number of urban landunits - integer , intent(in) :: filter_urbanl(:) ! urban landunit filter - real(r8), intent(in) :: coszen ( bounds%begl: ) ! cosine solar zenith angle [landunit] + integer, intent(in) :: num_urbanl_coszen_gt0 ! number of urban landunits with coszen > 0 + integer, intent(in) :: filter_urbanl_coszen_gt0(:) ! filter for urban landunits with coszen > 0 real(r8), intent(in) :: canyon_hwr ( bounds%begl: ) ! ratio of building height to street width [landunit] real(r8), intent(in) :: wtroad_perv ( bounds%begl: ) ! weight of pervious road wrt total road [landunit] real(r8), intent(in) :: sdir ( bounds%begl: , 1: ) ! direct beam solar radiation incident on horizontal surface [landunit, numrad] @@ -897,7 +921,6 @@ subroutine net_solar (bounds !----------------------------------------------------------------------- ! Enforce expected array sizes - SHR_ASSERT_ALL_FL((ubound(coszen) == (/bounds%endl/)), sourcefile, __LINE__) SHR_ASSERT_ALL_FL((ubound(canyon_hwr) == (/bounds%endl/)), sourcefile, __LINE__) SHR_ASSERT_ALL_FL((ubound(wtroad_perv) == (/bounds%endl/)), sourcefile, __LINE__) SHR_ASSERT_ALL_FL((ubound(sdir) == (/bounds%endl, numrad/)), sourcefile, __LINE__) @@ -948,351 +971,345 @@ subroutine net_solar (bounds ! Calculate impervious road - do fl = 1,num_urbanl - l = filter_urbanl(fl) + do fl = 1,num_urbanl_coszen_gt0 + l = filter_urbanl_coszen_gt0(fl) wtroad_imperv(l) = 1._r8 - wtroad_perv(l) end do do ib = 1,numrad - do fl = 1,num_urbanl - l = filter_urbanl(fl) - if (coszen(l) > 0._r8) then + do fl = 1,num_urbanl_coszen_gt0 + l = filter_urbanl_coszen_gt0(fl) + + ! initial absorption and reflection for road and both walls. + ! distribute reflected radiation to sky, road, and walls + ! according to appropriate view factor. radiation reflected to + ! road and walls will undergo multiple reflections within the canyon. + ! do separately for direct beam and diffuse radiation. + + ! direct beam + + road_a_dir(l) = 0.0_r8 + road_r_dir(l) = 0.0_r8 + improad_a_dir(l) = (1._r8-alb_improad_dir(l,ib)) * sdir_road(l,ib) + improad_r_dir(l) = alb_improad_dir(l,ib) * sdir_road(l,ib) + improad_r_sky_dir(l) = improad_r_dir(l) * vf_sr(l) + improad_r_sunwall_dir(l) = improad_r_dir(l) * vf_wr(l) + improad_r_shadewall_dir(l) = improad_r_dir(l) * vf_wr(l) + road_a_dir(l) = road_a_dir(l) + improad_a_dir(l)*wtroad_imperv(l) + road_r_dir(l) = road_r_dir(l) + improad_r_dir(l)*wtroad_imperv(l) + + perroad_a_dir(l) = (1._r8-alb_perroad_dir(l,ib)) * sdir_road(l,ib) + perroad_r_dir(l) = alb_perroad_dir(l,ib) * sdir_road(l,ib) + perroad_r_sky_dir(l) = perroad_r_dir(l) * vf_sr(l) + perroad_r_sunwall_dir(l) = perroad_r_dir(l) * vf_wr(l) + perroad_r_shadewall_dir(l) = perroad_r_dir(l) * vf_wr(l) + road_a_dir(l) = road_a_dir(l) + perroad_a_dir(l)*wtroad_perv(l) + road_r_dir(l) = road_r_dir(l) + perroad_r_dir(l)*wtroad_perv(l) + + road_r_sky_dir(l) = road_r_dir(l) * vf_sr(l) + road_r_sunwall_dir(l) = road_r_dir(l) * vf_wr(l) + road_r_shadewall_dir(l) = road_r_dir(l) * vf_wr(l) + + sunwall_a_dir(l) = (1._r8-alb_wall_dir(l,ib)) * sdir_sunwall(l,ib) + sunwall_r_dir(l) = alb_wall_dir(l,ib) * sdir_sunwall(l,ib) + sunwall_r_sky_dir(l) = sunwall_r_dir(l) * vf_sw(l) + sunwall_r_road_dir(l) = sunwall_r_dir(l) * vf_rw(l) + sunwall_r_shadewall_dir(l) = sunwall_r_dir(l) * vf_ww(l) + + shadewall_a_dir(l) = (1._r8-alb_wall_dir(l,ib)) * sdir_shadewall(l,ib) + shadewall_r_dir(l) = alb_wall_dir(l,ib) * sdir_shadewall(l,ib) + shadewall_r_sky_dir(l) = shadewall_r_dir(l) * vf_sw(l) + shadewall_r_road_dir(l) = shadewall_r_dir(l) * vf_rw(l) + shadewall_r_sunwall_dir(l) = shadewall_r_dir(l) * vf_ww(l) + + ! diffuse + + road_a_dif(l) = 0.0_r8 + road_r_dif(l) = 0.0_r8 + improad_a_dif(l) = (1._r8-alb_improad_dif(l,ib)) * sdif_road(l,ib) + improad_r_dif(l) = alb_improad_dif(l,ib) * sdif_road(l,ib) + improad_r_sky_dif(l) = improad_r_dif(l) * vf_sr(l) + improad_r_sunwall_dif(l) = improad_r_dif(l) * vf_wr(l) + improad_r_shadewall_dif(l) = improad_r_dif(l) * vf_wr(l) + road_a_dif(l) = road_a_dif(l) + improad_a_dif(l)*wtroad_imperv(l) + road_r_dif(l) = road_r_dif(l) + improad_r_dif(l)*wtroad_imperv(l) + + perroad_a_dif(l) = (1._r8-alb_perroad_dif(l,ib)) * sdif_road(l,ib) + perroad_r_dif(l) = alb_perroad_dif(l,ib) * sdif_road(l,ib) + perroad_r_sky_dif(l) = perroad_r_dif(l) * vf_sr(l) + perroad_r_sunwall_dif(l) = perroad_r_dif(l) * vf_wr(l) + perroad_r_shadewall_dif(l) = perroad_r_dif(l) * vf_wr(l) + road_a_dif(l) = road_a_dif(l) + perroad_a_dif(l)*wtroad_perv(l) + road_r_dif(l) = road_r_dif(l) + perroad_r_dif(l)*wtroad_perv(l) + + road_r_sky_dif(l) = road_r_dif(l) * vf_sr(l) + road_r_sunwall_dif(l) = road_r_dif(l) * vf_wr(l) + road_r_shadewall_dif(l) = road_r_dif(l) * vf_wr(l) + + sunwall_a_dif(l) = (1._r8-alb_wall_dif(l,ib)) * sdif_sunwall(l,ib) + sunwall_r_dif(l) = alb_wall_dif(l,ib) * sdif_sunwall(l,ib) + sunwall_r_sky_dif(l) = sunwall_r_dif(l) * vf_sw(l) + sunwall_r_road_dif(l) = sunwall_r_dif(l) * vf_rw(l) + sunwall_r_shadewall_dif(l) = sunwall_r_dif(l) * vf_ww(l) + + shadewall_a_dif(l) = (1._r8-alb_wall_dif(l,ib)) * sdif_shadewall(l,ib) + shadewall_r_dif(l) = alb_wall_dif(l,ib) * sdif_shadewall(l,ib) + shadewall_r_sky_dif(l) = shadewall_r_dif(l) * vf_sw(l) + shadewall_r_road_dif(l) = shadewall_r_dif(l) * vf_rw(l) + shadewall_r_sunwall_dif(l) = shadewall_r_dif(l) * vf_ww(l) + + ! initialize sum of direct and diffuse solar absorption and reflection for road and both walls + + sabs_improad_dir(l,ib) = improad_a_dir(l) + sabs_perroad_dir(l,ib) = perroad_a_dir(l) + sabs_sunwall_dir(l,ib) = sunwall_a_dir(l) + sabs_shadewall_dir(l,ib) = shadewall_a_dir(l) + + sabs_improad_dif(l,ib) = improad_a_dif(l) + sabs_perroad_dif(l,ib) = perroad_a_dif(l) + sabs_sunwall_dif(l,ib) = sunwall_a_dif(l) + sabs_shadewall_dif(l,ib) = shadewall_a_dif(l) + + sref_improad_dir(l,ib) = improad_r_sky_dir(l) + sref_perroad_dir(l,ib) = perroad_r_sky_dir(l) + sref_sunwall_dir(l,ib) = sunwall_r_sky_dir(l) + sref_shadewall_dir(l,ib) = shadewall_r_sky_dir(l) + + sref_improad_dif(l,ib) = improad_r_sky_dif(l) + sref_perroad_dif(l,ib) = perroad_r_sky_dif(l) + sref_sunwall_dif(l,ib) = sunwall_r_sky_dif(l) + sref_shadewall_dif(l,ib) = shadewall_r_sky_dif(l) + + end do + + ! absorption and reflection for walls and road with multiple reflections + ! (i.e., absorb and reflect initial reflection in canyon and allow for + ! subsequent scattering) + ! + ! (1) absorption and reflection of scattered solar radiation + ! road: reflected fluxes from walls need to be projected to ground area + ! wall: reflected flux from road needs to be projected to wall area + ! + ! (2) add absorbed radiation for ith reflection to total absorbed + ! + ! (3) distribute reflected radiation to sky, road, and walls according to view factors + ! + ! (4) add solar reflection to sky for ith reflection to total reflection + ! + ! (5) stop iteration when absorption for ith reflection is less than some nominal amount. + ! small convergence criteria is required to ensure solar radiation is conserved + ! + ! do separately for direct beam and diffuse + + do fl = 1,num_urbanl_coszen_gt0 + l = filter_urbanl_coszen_gt0(fl) + + ! reflected direct beam + + do iter_dir = 1, n + ! step (1) + + stot(l) = (sunwall_r_road_dir(l) + shadewall_r_road_dir(l))*canyon_hwr(l) + + road_a_dir(l) = 0.0_r8 + road_r_dir(l) = 0.0_r8 + improad_a_dir(l) = (1._r8-alb_improad_dir(l,ib)) * stot(l) + improad_r_dir(l) = alb_improad_dir(l,ib) * stot(l) + road_a_dir(l) = road_a_dir(l) + improad_a_dir(l)*wtroad_imperv(l) + road_r_dir(l) = road_r_dir(l) + improad_r_dir(l)*wtroad_imperv(l) + perroad_a_dir(l) = (1._r8-alb_perroad_dir(l,ib)) * stot(l) + perroad_r_dir(l) = alb_perroad_dir(l,ib) * stot(l) + road_a_dir(l) = road_a_dir(l) + perroad_a_dir(l)*wtroad_perv(l) + road_r_dir(l) = road_r_dir(l) + perroad_r_dir(l)*wtroad_perv(l) + + stot(l) = road_r_sunwall_dir(l)/canyon_hwr(l) + shadewall_r_sunwall_dir(l) + sunwall_a_dir(l) = (1._r8-alb_wall_dir(l,ib)) * stot(l) + sunwall_r_dir(l) = alb_wall_dir(l,ib) * stot(l) + + stot(l) = road_r_shadewall_dir(l)/canyon_hwr(l) + sunwall_r_shadewall_dir(l) + shadewall_a_dir(l) = (1._r8-alb_wall_dir(l,ib)) * stot(l) + shadewall_r_dir(l) = alb_wall_dir(l,ib) * stot(l) - ! initial absorption and reflection for road and both walls. - ! distribute reflected radiation to sky, road, and walls - ! according to appropriate view factor. radiation reflected to - ! road and walls will undergo multiple reflections within the canyon. - ! do separately for direct beam and diffuse radiation. + ! step (2) - ! direct beam + sabs_improad_dir(l,ib) = sabs_improad_dir(l,ib) + improad_a_dir(l) + sabs_perroad_dir(l,ib) = sabs_perroad_dir(l,ib) + perroad_a_dir(l) + sabs_sunwall_dir(l,ib) = sabs_sunwall_dir(l,ib) + sunwall_a_dir(l) + sabs_shadewall_dir(l,ib) = sabs_shadewall_dir(l,ib) + shadewall_a_dir(l) + + ! step (3) - road_a_dir(l) = 0.0_r8 - road_r_dir(l) = 0.0_r8 - improad_a_dir(l) = (1._r8-alb_improad_dir(l,ib)) * sdir_road(l,ib) - improad_r_dir(l) = alb_improad_dir(l,ib) * sdir_road(l,ib) improad_r_sky_dir(l) = improad_r_dir(l) * vf_sr(l) improad_r_sunwall_dir(l) = improad_r_dir(l) * vf_wr(l) improad_r_shadewall_dir(l) = improad_r_dir(l) * vf_wr(l) - road_a_dir(l) = road_a_dir(l) + improad_a_dir(l)*wtroad_imperv(l) - road_r_dir(l) = road_r_dir(l) + improad_r_dir(l)*wtroad_imperv(l) - perroad_a_dir(l) = (1._r8-alb_perroad_dir(l,ib)) * sdir_road(l,ib) - perroad_r_dir(l) = alb_perroad_dir(l,ib) * sdir_road(l,ib) perroad_r_sky_dir(l) = perroad_r_dir(l) * vf_sr(l) perroad_r_sunwall_dir(l) = perroad_r_dir(l) * vf_wr(l) perroad_r_shadewall_dir(l) = perroad_r_dir(l) * vf_wr(l) - road_a_dir(l) = road_a_dir(l) + perroad_a_dir(l)*wtroad_perv(l) - road_r_dir(l) = road_r_dir(l) + perroad_r_dir(l)*wtroad_perv(l) road_r_sky_dir(l) = road_r_dir(l) * vf_sr(l) road_r_sunwall_dir(l) = road_r_dir(l) * vf_wr(l) road_r_shadewall_dir(l) = road_r_dir(l) * vf_wr(l) - sunwall_a_dir(l) = (1._r8-alb_wall_dir(l,ib)) * sdir_sunwall(l,ib) - sunwall_r_dir(l) = alb_wall_dir(l,ib) * sdir_sunwall(l,ib) sunwall_r_sky_dir(l) = sunwall_r_dir(l) * vf_sw(l) sunwall_r_road_dir(l) = sunwall_r_dir(l) * vf_rw(l) sunwall_r_shadewall_dir(l) = sunwall_r_dir(l) * vf_ww(l) - shadewall_a_dir(l) = (1._r8-alb_wall_dir(l,ib)) * sdir_shadewall(l,ib) - shadewall_r_dir(l) = alb_wall_dir(l,ib) * sdir_shadewall(l,ib) shadewall_r_sky_dir(l) = shadewall_r_dir(l) * vf_sw(l) shadewall_r_road_dir(l) = shadewall_r_dir(l) * vf_rw(l) shadewall_r_sunwall_dir(l) = shadewall_r_dir(l) * vf_ww(l) - ! diffuse + ! step (4) + + sref_improad_dir(l,ib) = sref_improad_dir(l,ib) + improad_r_sky_dir(l) + sref_perroad_dir(l,ib) = sref_perroad_dir(l,ib) + perroad_r_sky_dir(l) + sref_sunwall_dir(l,ib) = sref_sunwall_dir(l,ib) + sunwall_r_sky_dir(l) + sref_shadewall_dir(l,ib) = sref_shadewall_dir(l,ib) + shadewall_r_sky_dir(l) + + ! step (5) + + crit = max(road_a_dir(l), sunwall_a_dir(l), shadewall_a_dir(l)) + if (crit < errcrit) exit + end do + if (iter_dir >= n) then + write (iulog,*) 'urban net solar radiation error: no convergence, direct beam' + write (iulog,*) 'clm model is stopping' + call endrun(subgrid_index=l, subgrid_level=subgrid_level_landunit, msg=errmsg(sourcefile, __LINE__)) + endif + + ! reflected diffuse + + do iter_dif = 1, n + ! step (1) + + stot(l) = (sunwall_r_road_dif(l) + shadewall_r_road_dif(l))*canyon_hwr(l) + road_a_dif(l) = 0.0_r8 + road_r_dif(l) = 0.0_r8 + improad_a_dif(l) = (1._r8-alb_improad_dif(l,ib)) * stot(l) + improad_r_dif(l) = alb_improad_dif(l,ib) * stot(l) + road_a_dif(l) = road_a_dif(l) + improad_a_dif(l)*wtroad_imperv(l) + road_r_dif(l) = road_r_dif(l) + improad_r_dif(l)*wtroad_imperv(l) + perroad_a_dif(l) = (1._r8-alb_perroad_dif(l,ib)) * stot(l) + perroad_r_dif(l) = alb_perroad_dif(l,ib) * stot(l) + road_a_dif(l) = road_a_dif(l) + perroad_a_dif(l)*wtroad_perv(l) + road_r_dif(l) = road_r_dif(l) + perroad_r_dif(l)*wtroad_perv(l) + + stot(l) = road_r_sunwall_dif(l)/canyon_hwr(l) + shadewall_r_sunwall_dif(l) + sunwall_a_dif(l) = (1._r8-alb_wall_dif(l,ib)) * stot(l) + sunwall_r_dif(l) = alb_wall_dif(l,ib) * stot(l) + + stot(l) = road_r_shadewall_dif(l)/canyon_hwr(l) + sunwall_r_shadewall_dif(l) + shadewall_a_dif(l) = (1._r8-alb_wall_dif(l,ib)) * stot(l) + shadewall_r_dif(l) = alb_wall_dif(l,ib) * stot(l) + + ! step (2) + + sabs_improad_dif(l,ib) = sabs_improad_dif(l,ib) + improad_a_dif(l) + sabs_perroad_dif(l,ib) = sabs_perroad_dif(l,ib) + perroad_a_dif(l) + sabs_sunwall_dif(l,ib) = sabs_sunwall_dif(l,ib) + sunwall_a_dif(l) + sabs_shadewall_dif(l,ib) = sabs_shadewall_dif(l,ib) + shadewall_a_dif(l) + + ! step (3) - road_a_dif(l) = 0.0_r8 - road_r_dif(l) = 0.0_r8 - improad_a_dif(l) = (1._r8-alb_improad_dif(l,ib)) * sdif_road(l,ib) - improad_r_dif(l) = alb_improad_dif(l,ib) * sdif_road(l,ib) improad_r_sky_dif(l) = improad_r_dif(l) * vf_sr(l) improad_r_sunwall_dif(l) = improad_r_dif(l) * vf_wr(l) improad_r_shadewall_dif(l) = improad_r_dif(l) * vf_wr(l) - road_a_dif(l) = road_a_dif(l) + improad_a_dif(l)*wtroad_imperv(l) - road_r_dif(l) = road_r_dif(l) + improad_r_dif(l)*wtroad_imperv(l) - perroad_a_dif(l) = (1._r8-alb_perroad_dif(l,ib)) * sdif_road(l,ib) - perroad_r_dif(l) = alb_perroad_dif(l,ib) * sdif_road(l,ib) perroad_r_sky_dif(l) = perroad_r_dif(l) * vf_sr(l) perroad_r_sunwall_dif(l) = perroad_r_dif(l) * vf_wr(l) perroad_r_shadewall_dif(l) = perroad_r_dif(l) * vf_wr(l) - road_a_dif(l) = road_a_dif(l) + perroad_a_dif(l)*wtroad_perv(l) - road_r_dif(l) = road_r_dif(l) + perroad_r_dif(l)*wtroad_perv(l) road_r_sky_dif(l) = road_r_dif(l) * vf_sr(l) road_r_sunwall_dif(l) = road_r_dif(l) * vf_wr(l) road_r_shadewall_dif(l) = road_r_dif(l) * vf_wr(l) - sunwall_a_dif(l) = (1._r8-alb_wall_dif(l,ib)) * sdif_sunwall(l,ib) - sunwall_r_dif(l) = alb_wall_dif(l,ib) * sdif_sunwall(l,ib) sunwall_r_sky_dif(l) = sunwall_r_dif(l) * vf_sw(l) sunwall_r_road_dif(l) = sunwall_r_dif(l) * vf_rw(l) sunwall_r_shadewall_dif(l) = sunwall_r_dif(l) * vf_ww(l) - shadewall_a_dif(l) = (1._r8-alb_wall_dif(l,ib)) * sdif_shadewall(l,ib) - shadewall_r_dif(l) = alb_wall_dif(l,ib) * sdif_shadewall(l,ib) shadewall_r_sky_dif(l) = shadewall_r_dif(l) * vf_sw(l) - shadewall_r_road_dif(l) = shadewall_r_dif(l) * vf_rw(l) - shadewall_r_sunwall_dif(l) = shadewall_r_dif(l) * vf_ww(l) - - ! initialize sum of direct and diffuse solar absorption and reflection for road and both walls - - sabs_improad_dir(l,ib) = improad_a_dir(l) - sabs_perroad_dir(l,ib) = perroad_a_dir(l) - sabs_sunwall_dir(l,ib) = sunwall_a_dir(l) - sabs_shadewall_dir(l,ib) = shadewall_a_dir(l) - - sabs_improad_dif(l,ib) = improad_a_dif(l) - sabs_perroad_dif(l,ib) = perroad_a_dif(l) - sabs_sunwall_dif(l,ib) = sunwall_a_dif(l) - sabs_shadewall_dif(l,ib) = shadewall_a_dif(l) - - sref_improad_dir(l,ib) = improad_r_sky_dir(l) - sref_perroad_dir(l,ib) = perroad_r_sky_dir(l) - sref_sunwall_dir(l,ib) = sunwall_r_sky_dir(l) - sref_shadewall_dir(l,ib) = shadewall_r_sky_dir(l) - - sref_improad_dif(l,ib) = improad_r_sky_dif(l) - sref_perroad_dif(l,ib) = perroad_r_sky_dif(l) - sref_sunwall_dif(l,ib) = sunwall_r_sky_dif(l) - sref_shadewall_dif(l,ib) = shadewall_r_sky_dif(l) - endif - - end do + shadewall_r_road_dif(l) = shadewall_r_dif(l) * vf_rw(l) + shadewall_r_sunwall_dif(l) = shadewall_r_dif(l) * vf_ww(l) - ! absorption and reflection for walls and road with multiple reflections - ! (i.e., absorb and reflect initial reflection in canyon and allow for - ! subsequent scattering) - ! - ! (1) absorption and reflection of scattered solar radiation - ! road: reflected fluxes from walls need to be projected to ground area - ! wall: reflected flux from road needs to be projected to wall area - ! - ! (2) add absorbed radiation for ith reflection to total absorbed - ! - ! (3) distribute reflected radiation to sky, road, and walls according to view factors - ! - ! (4) add solar reflection to sky for ith reflection to total reflection - ! - ! (5) stop iteration when absorption for ith reflection is less than some nominal amount. - ! small convergence criteria is required to ensure solar radiation is conserved - ! - ! do separately for direct beam and diffuse + ! step (4) - do fl = 1,num_urbanl - l = filter_urbanl(fl) - if (coszen(l) > 0._r8) then - - ! reflected direct beam - - do iter_dir = 1, n - ! step (1) - - stot(l) = (sunwall_r_road_dir(l) + shadewall_r_road_dir(l))*canyon_hwr(l) - - road_a_dir(l) = 0.0_r8 - road_r_dir(l) = 0.0_r8 - improad_a_dir(l) = (1._r8-alb_improad_dir(l,ib)) * stot(l) - improad_r_dir(l) = alb_improad_dir(l,ib) * stot(l) - road_a_dir(l) = road_a_dir(l) + improad_a_dir(l)*wtroad_imperv(l) - road_r_dir(l) = road_r_dir(l) + improad_r_dir(l)*wtroad_imperv(l) - perroad_a_dir(l) = (1._r8-alb_perroad_dir(l,ib)) * stot(l) - perroad_r_dir(l) = alb_perroad_dir(l,ib) * stot(l) - road_a_dir(l) = road_a_dir(l) + perroad_a_dir(l)*wtroad_perv(l) - road_r_dir(l) = road_r_dir(l) + perroad_r_dir(l)*wtroad_perv(l) + sref_improad_dif(l,ib) = sref_improad_dif(l,ib) + improad_r_sky_dif(l) + sref_perroad_dif(l,ib) = sref_perroad_dif(l,ib) + perroad_r_sky_dif(l) + sref_sunwall_dif(l,ib) = sref_sunwall_dif(l,ib) + sunwall_r_sky_dif(l) + sref_shadewall_dif(l,ib) = sref_shadewall_dif(l,ib) + shadewall_r_sky_dif(l) - stot(l) = road_r_sunwall_dir(l)/canyon_hwr(l) + shadewall_r_sunwall_dir(l) - sunwall_a_dir(l) = (1._r8-alb_wall_dir(l,ib)) * stot(l) - sunwall_r_dir(l) = alb_wall_dir(l,ib) * stot(l) + ! step (5) - stot(l) = road_r_shadewall_dir(l)/canyon_hwr(l) + sunwall_r_shadewall_dir(l) - shadewall_a_dir(l) = (1._r8-alb_wall_dir(l,ib)) * stot(l) - shadewall_r_dir(l) = alb_wall_dir(l,ib) * stot(l) - - ! step (2) - - sabs_improad_dir(l,ib) = sabs_improad_dir(l,ib) + improad_a_dir(l) - sabs_perroad_dir(l,ib) = sabs_perroad_dir(l,ib) + perroad_a_dir(l) - sabs_sunwall_dir(l,ib) = sabs_sunwall_dir(l,ib) + sunwall_a_dir(l) - sabs_shadewall_dir(l,ib) = sabs_shadewall_dir(l,ib) + shadewall_a_dir(l) + crit = max(road_a_dif(l), sunwall_a_dif(l), shadewall_a_dif(l)) + if (crit < errcrit) exit + end do + if (iter_dif >= n) then + write (iulog,*) 'urban net solar radiation error: no convergence, diffuse' + write (iulog,*) 'clm model is stopping' + call endrun(subgrid_index=l, subgrid_level=subgrid_level_landunit, msg=errmsg(sourcefile, __LINE__)) + endif - ! step (3) + ! total reflected by canyon - sum of solar reflection to sky from canyon. + ! project wall fluxes to horizontal surface + + sref_canyon_dir(l) = 0.0_r8 + sref_canyon_dif(l) = 0.0_r8 + sref_canyon_dir(l) = sref_canyon_dir(l) + sref_improad_dir(l,ib)*wtroad_imperv(l) + sref_canyon_dif(l) = sref_canyon_dif(l) + sref_improad_dif(l,ib)*wtroad_imperv(l) + sref_canyon_dir(l) = sref_canyon_dir(l) + sref_perroad_dir(l,ib)*wtroad_perv(l) + sref_canyon_dif(l) = sref_canyon_dif(l) + sref_perroad_dif(l,ib)*wtroad_perv(l) + sref_canyon_dir(l) = sref_canyon_dir(l) + (sref_sunwall_dir(l,ib) + sref_shadewall_dir(l,ib))*canyon_hwr(l) + sref_canyon_dif(l) = sref_canyon_dif(l) + (sref_sunwall_dif(l,ib) + sref_shadewall_dif(l,ib))*canyon_hwr(l) + + ! total absorbed by canyon. project wall fluxes to horizontal surface + + sabs_canyon_dir(l) = 0.0_r8 + sabs_canyon_dif(l) = 0.0_r8 + sabs_canyon_dir(l) = sabs_canyon_dir(l) + sabs_improad_dir(l,ib)*wtroad_imperv(l) + sabs_canyon_dif(l) = sabs_canyon_dif(l) + sabs_improad_dif(l,ib)*wtroad_imperv(l) + sabs_canyon_dir(l) = sabs_canyon_dir(l) + sabs_perroad_dir(l,ib)*wtroad_perv(l) + sabs_canyon_dif(l) = sabs_canyon_dif(l) + sabs_perroad_dif(l,ib)*wtroad_perv(l) + sabs_canyon_dir(l) = sabs_canyon_dir(l) + (sabs_sunwall_dir(l,ib) + sabs_shadewall_dir(l,ib))*canyon_hwr(l) + sabs_canyon_dif(l) = sabs_canyon_dif(l) + (sabs_sunwall_dif(l,ib) + sabs_shadewall_dif(l,ib))*canyon_hwr(l) + + ! conservation check. note: previous conservation checks confirm partioning of total direct + ! beam and diffuse radiation from atmosphere to road and walls is conserved as + ! sdir (from atmosphere) = sdir_road + (sdir_sunwall + sdir_shadewall)*canyon_hwr + ! sdif (from atmosphere) = sdif_road + (sdif_sunwall + sdif_shadewall)*canyon_hwr + + stot_dir(l) = sdir_road(l,ib) + (sdir_sunwall(l,ib) + sdir_shadewall(l,ib))*canyon_hwr(l) + stot_dif(l) = sdif_road(l,ib) + (sdif_sunwall(l,ib) + sdif_shadewall(l,ib))*canyon_hwr(l) + + err = stot_dir(l) + stot_dif(l) & + - (sabs_canyon_dir(l) + sabs_canyon_dif(l) + sref_canyon_dir(l) + sref_canyon_dif(l)) + if (abs(err) > 0.001_r8 ) then + write(iulog,*)'urban net solar radiation balance error for ib=',ib,' err= ',err + write(iulog,*)' l= ',l,' ib= ',ib + write(iulog,*)' stot_dir = ',stot_dir(l) + write(iulog,*)' stot_dif = ',stot_dif(l) + write(iulog,*)' sabs_canyon_dir = ',sabs_canyon_dir(l) + write(iulog,*)' sabs_canyon_dif = ',sabs_canyon_dif(l) + write(iulog,*)' sref_canyon_dir = ',sref_canyon_dir(l) + write(iulog,*)' sref_canyon_dif = ',sref_canyon_dir(l) + write(iulog,*) 'clm model is stopping' + call endrun(subgrid_index=l, subgrid_level=subgrid_level_landunit, msg=errmsg(sourcefile, __LINE__)) + endif - improad_r_sky_dir(l) = improad_r_dir(l) * vf_sr(l) - improad_r_sunwall_dir(l) = improad_r_dir(l) * vf_wr(l) - improad_r_shadewall_dir(l) = improad_r_dir(l) * vf_wr(l) + ! canyon albedo - perroad_r_sky_dir(l) = perroad_r_dir(l) * vf_sr(l) - perroad_r_sunwall_dir(l) = perroad_r_dir(l) * vf_wr(l) - perroad_r_shadewall_dir(l) = perroad_r_dir(l) * vf_wr(l) - - road_r_sky_dir(l) = road_r_dir(l) * vf_sr(l) - road_r_sunwall_dir(l) = road_r_dir(l) * vf_wr(l) - road_r_shadewall_dir(l) = road_r_dir(l) * vf_wr(l) - - sunwall_r_sky_dir(l) = sunwall_r_dir(l) * vf_sw(l) - sunwall_r_road_dir(l) = sunwall_r_dir(l) * vf_rw(l) - sunwall_r_shadewall_dir(l) = sunwall_r_dir(l) * vf_ww(l) - - shadewall_r_sky_dir(l) = shadewall_r_dir(l) * vf_sw(l) - shadewall_r_road_dir(l) = shadewall_r_dir(l) * vf_rw(l) - shadewall_r_sunwall_dir(l) = shadewall_r_dir(l) * vf_ww(l) - - ! step (4) - - sref_improad_dir(l,ib) = sref_improad_dir(l,ib) + improad_r_sky_dir(l) - sref_perroad_dir(l,ib) = sref_perroad_dir(l,ib) + perroad_r_sky_dir(l) - sref_sunwall_dir(l,ib) = sref_sunwall_dir(l,ib) + sunwall_r_sky_dir(l) - sref_shadewall_dir(l,ib) = sref_shadewall_dir(l,ib) + shadewall_r_sky_dir(l) - - ! step (5) - - crit = max(road_a_dir(l), sunwall_a_dir(l), shadewall_a_dir(l)) - if (crit < errcrit) exit - end do - if (iter_dir >= n) then - write (iulog,*) 'urban net solar radiation error: no convergence, direct beam' - write (iulog,*) 'clm model is stopping' - call endrun(subgrid_index=l, subgrid_level=subgrid_level_landunit, msg=errmsg(sourcefile, __LINE__)) - endif - - ! reflected diffuse - - do iter_dif = 1, n - ! step (1) - - stot(l) = (sunwall_r_road_dif(l) + shadewall_r_road_dif(l))*canyon_hwr(l) - road_a_dif(l) = 0.0_r8 - road_r_dif(l) = 0.0_r8 - improad_a_dif(l) = (1._r8-alb_improad_dif(l,ib)) * stot(l) - improad_r_dif(l) = alb_improad_dif(l,ib) * stot(l) - road_a_dif(l) = road_a_dif(l) + improad_a_dif(l)*wtroad_imperv(l) - road_r_dif(l) = road_r_dif(l) + improad_r_dif(l)*wtroad_imperv(l) - perroad_a_dif(l) = (1._r8-alb_perroad_dif(l,ib)) * stot(l) - perroad_r_dif(l) = alb_perroad_dif(l,ib) * stot(l) - road_a_dif(l) = road_a_dif(l) + perroad_a_dif(l)*wtroad_perv(l) - road_r_dif(l) = road_r_dif(l) + perroad_r_dif(l)*wtroad_perv(l) - - stot(l) = road_r_sunwall_dif(l)/canyon_hwr(l) + shadewall_r_sunwall_dif(l) - sunwall_a_dif(l) = (1._r8-alb_wall_dif(l,ib)) * stot(l) - sunwall_r_dif(l) = alb_wall_dif(l,ib) * stot(l) - - stot(l) = road_r_shadewall_dif(l)/canyon_hwr(l) + sunwall_r_shadewall_dif(l) - shadewall_a_dif(l) = (1._r8-alb_wall_dif(l,ib)) * stot(l) - shadewall_r_dif(l) = alb_wall_dif(l,ib) * stot(l) - - ! step (2) - - sabs_improad_dif(l,ib) = sabs_improad_dif(l,ib) + improad_a_dif(l) - sabs_perroad_dif(l,ib) = sabs_perroad_dif(l,ib) + perroad_a_dif(l) - sabs_sunwall_dif(l,ib) = sabs_sunwall_dif(l,ib) + sunwall_a_dif(l) - sabs_shadewall_dif(l,ib) = sabs_shadewall_dif(l,ib) + shadewall_a_dif(l) - - ! step (3) - - improad_r_sky_dif(l) = improad_r_dif(l) * vf_sr(l) - improad_r_sunwall_dif(l) = improad_r_dif(l) * vf_wr(l) - improad_r_shadewall_dif(l) = improad_r_dif(l) * vf_wr(l) - - perroad_r_sky_dif(l) = perroad_r_dif(l) * vf_sr(l) - perroad_r_sunwall_dif(l) = perroad_r_dif(l) * vf_wr(l) - perroad_r_shadewall_dif(l) = perroad_r_dif(l) * vf_wr(l) - - road_r_sky_dif(l) = road_r_dif(l) * vf_sr(l) - road_r_sunwall_dif(l) = road_r_dif(l) * vf_wr(l) - road_r_shadewall_dif(l) = road_r_dif(l) * vf_wr(l) - - sunwall_r_sky_dif(l) = sunwall_r_dif(l) * vf_sw(l) - sunwall_r_road_dif(l) = sunwall_r_dif(l) * vf_rw(l) - sunwall_r_shadewall_dif(l) = sunwall_r_dif(l) * vf_ww(l) - - shadewall_r_sky_dif(l) = shadewall_r_dif(l) * vf_sw(l) - shadewall_r_road_dif(l) = shadewall_r_dif(l) * vf_rw(l) - shadewall_r_sunwall_dif(l) = shadewall_r_dif(l) * vf_ww(l) - - ! step (4) - - sref_improad_dif(l,ib) = sref_improad_dif(l,ib) + improad_r_sky_dif(l) - sref_perroad_dif(l,ib) = sref_perroad_dif(l,ib) + perroad_r_sky_dif(l) - sref_sunwall_dif(l,ib) = sref_sunwall_dif(l,ib) + sunwall_r_sky_dif(l) - sref_shadewall_dif(l,ib) = sref_shadewall_dif(l,ib) + shadewall_r_sky_dif(l) - - ! step (5) - - crit = max(road_a_dif(l), sunwall_a_dif(l), shadewall_a_dif(l)) - if (crit < errcrit) exit - end do - if (iter_dif >= n) then - write (iulog,*) 'urban net solar radiation error: no convergence, diffuse' - write (iulog,*) 'clm model is stopping' - call endrun(subgrid_index=l, subgrid_level=subgrid_level_landunit, msg=errmsg(sourcefile, __LINE__)) - endif - - ! total reflected by canyon - sum of solar reflection to sky from canyon. - ! project wall fluxes to horizontal surface - - sref_canyon_dir(l) = 0.0_r8 - sref_canyon_dif(l) = 0.0_r8 - sref_canyon_dir(l) = sref_canyon_dir(l) + sref_improad_dir(l,ib)*wtroad_imperv(l) - sref_canyon_dif(l) = sref_canyon_dif(l) + sref_improad_dif(l,ib)*wtroad_imperv(l) - sref_canyon_dir(l) = sref_canyon_dir(l) + sref_perroad_dir(l,ib)*wtroad_perv(l) - sref_canyon_dif(l) = sref_canyon_dif(l) + sref_perroad_dif(l,ib)*wtroad_perv(l) - sref_canyon_dir(l) = sref_canyon_dir(l) + (sref_sunwall_dir(l,ib) + sref_shadewall_dir(l,ib))*canyon_hwr(l) - sref_canyon_dif(l) = sref_canyon_dif(l) + (sref_sunwall_dif(l,ib) + sref_shadewall_dif(l,ib))*canyon_hwr(l) - - ! total absorbed by canyon. project wall fluxes to horizontal surface - - sabs_canyon_dir(l) = 0.0_r8 - sabs_canyon_dif(l) = 0.0_r8 - sabs_canyon_dir(l) = sabs_canyon_dir(l) + sabs_improad_dir(l,ib)*wtroad_imperv(l) - sabs_canyon_dif(l) = sabs_canyon_dif(l) + sabs_improad_dif(l,ib)*wtroad_imperv(l) - sabs_canyon_dir(l) = sabs_canyon_dir(l) + sabs_perroad_dir(l,ib)*wtroad_perv(l) - sabs_canyon_dif(l) = sabs_canyon_dif(l) + sabs_perroad_dif(l,ib)*wtroad_perv(l) - sabs_canyon_dir(l) = sabs_canyon_dir(l) + (sabs_sunwall_dir(l,ib) + sabs_shadewall_dir(l,ib))*canyon_hwr(l) - sabs_canyon_dif(l) = sabs_canyon_dif(l) + (sabs_sunwall_dif(l,ib) + sabs_shadewall_dif(l,ib))*canyon_hwr(l) - - ! conservation check. note: previous conservation checks confirm partioning of total direct - ! beam and diffuse radiation from atmosphere to road and walls is conserved as - ! sdir (from atmosphere) = sdir_road + (sdir_sunwall + sdir_shadewall)*canyon_hwr - ! sdif (from atmosphere) = sdif_road + (sdif_sunwall + sdif_shadewall)*canyon_hwr - - stot_dir(l) = sdir_road(l,ib) + (sdir_sunwall(l,ib) + sdir_shadewall(l,ib))*canyon_hwr(l) - stot_dif(l) = sdif_road(l,ib) + (sdif_sunwall(l,ib) + sdif_shadewall(l,ib))*canyon_hwr(l) - - err = stot_dir(l) + stot_dif(l) & - - (sabs_canyon_dir(l) + sabs_canyon_dif(l) + sref_canyon_dir(l) + sref_canyon_dif(l)) - if (abs(err) > 0.001_r8 ) then - write(iulog,*)'urban net solar radiation balance error for ib=',ib,' err= ',err - write(iulog,*)' l= ',l,' ib= ',ib - write(iulog,*)' stot_dir = ',stot_dir(l) - write(iulog,*)' stot_dif = ',stot_dif(l) - write(iulog,*)' sabs_canyon_dir = ',sabs_canyon_dir(l) - write(iulog,*)' sabs_canyon_dif = ',sabs_canyon_dif(l) - write(iulog,*)' sref_canyon_dir = ',sref_canyon_dir(l) - write(iulog,*)' sref_canyon_dif = ',sref_canyon_dir(l) - write(iulog,*) 'clm model is stopping' - call endrun(subgrid_index=l, subgrid_level=subgrid_level_landunit, msg=errmsg(sourcefile, __LINE__)) - endif - - ! canyon albedo - - canyon_alb_dif(l) = sref_canyon_dif(l) / max(stot_dif(l), 1.e-06_r8) - canyon_alb_dir(l) = sref_canyon_dir(l) / max(stot_dir(l), 1.e-06_r8) - end if + canyon_alb_dif(l) = sref_canyon_dif(l) / max(stot_dif(l), 1.e-06_r8) + canyon_alb_dir(l) = sref_canyon_dir(l) / max(stot_dir(l), 1.e-06_r8) end do ! end of landunit loop - ! Refected and absorbed solar radiation per unit incident radiation for roof + ! Reflected and absorbed solar radiation per unit incident radiation for roof - do fl = 1,num_urbanl - l = filter_urbanl(fl) - if (coszen(l) > 0._r8) then - sref_roof_dir(l,ib) = alb_roof_dir(l,ib) * sdir(l,ib) - sref_roof_dif(l,ib) = alb_roof_dif(l,ib) * sdif(l,ib) - sabs_roof_dir(l,ib) = sdir(l,ib) - sref_roof_dir(l,ib) - sabs_roof_dif(l,ib) = sdif(l,ib) - sref_roof_dif(l,ib) - end if + do fl = 1,num_urbanl_coszen_gt0 + l = filter_urbanl_coszen_gt0(fl) + sref_roof_dir(l,ib) = alb_roof_dir(l,ib) * sdir(l,ib) + sref_roof_dif(l,ib) = alb_roof_dif(l,ib) * sdif(l,ib) + sabs_roof_dir(l,ib) = sdir(l,ib) - sref_roof_dir(l,ib) + sabs_roof_dif(l,ib) = sdif(l,ib) - sref_roof_dif(l,ib) end do end do ! end of radiation band loop diff --git a/src/biogeophys/test/Balance_test/CMakeLists.txt b/src/biogeophys/test/Balance_test/CMakeLists.txt index 541d4fb266..e140323124 100644 --- a/src/biogeophys/test/Balance_test/CMakeLists.txt +++ b/src/biogeophys/test/Balance_test/CMakeLists.txt @@ -1,3 +1,3 @@ add_pfunit_ctest(balance TEST_SOURCES "test_Balance.pf" - LINK_LIBRARIES clm csm_share esmf_wrf_timemgr) + LINK_LIBRARIES clm csm_share esmf) diff --git a/src/biogeophys/test/Daylength_test/CMakeLists.txt b/src/biogeophys/test/Daylength_test/CMakeLists.txt index 2e5cb58cf9..bd2d6407a9 100644 --- a/src/biogeophys/test/Daylength_test/CMakeLists.txt +++ b/src/biogeophys/test/Daylength_test/CMakeLists.txt @@ -4,4 +4,4 @@ set (pfunit_sources add_pfunit_ctest(Daylength TEST_SOURCES "${pfunit_sources}" - LINK_LIBRARIES clm csm_share esmf_wrf_timemgr) + LINK_LIBRARIES clm csm_share esmf) diff --git a/src/biogeophys/test/HillslopeHydrology_test/CMakeLists.txt b/src/biogeophys/test/HillslopeHydrology_test/CMakeLists.txt index f40baf96ed..078934cc78 100644 --- a/src/biogeophys/test/HillslopeHydrology_test/CMakeLists.txt +++ b/src/biogeophys/test/HillslopeHydrology_test/CMakeLists.txt @@ -3,4 +3,4 @@ set (pfunit_sources add_pfunit_ctest(HillslopeHydrologyUtils TEST_SOURCES "${pfunit_sources}" - LINK_LIBRARIES clm csm_share esmf_wrf_timemgr) + LINK_LIBRARIES clm csm_share esmf) diff --git a/src/biogeophys/test/Irrigation_test/CMakeLists.txt b/src/biogeophys/test/Irrigation_test/CMakeLists.txt index 8cb531ba1a..4acf72961d 100644 --- a/src/biogeophys/test/Irrigation_test/CMakeLists.txt +++ b/src/biogeophys/test/Irrigation_test/CMakeLists.txt @@ -3,4 +3,4 @@ set (pfunit_sources add_pfunit_ctest(irrigation TEST_SOURCES "${pfunit_sources}" - LINK_LIBRARIES clm csm_share esmf_wrf_timemgr) + LINK_LIBRARIES clm csm_share esmf) diff --git a/src/biogeophys/test/Photosynthesis_test/CMakeLists.txt b/src/biogeophys/test/Photosynthesis_test/CMakeLists.txt index 29810cbd9d..628a98994a 100644 --- a/src/biogeophys/test/Photosynthesis_test/CMakeLists.txt +++ b/src/biogeophys/test/Photosynthesis_test/CMakeLists.txt @@ -3,4 +3,4 @@ set (pfunit_sources add_pfunit_ctest(Photosynthesis TEST_SOURCES "${pfunit_sources}" - LINK_LIBRARIES clm csm_share esmf_wrf_timemgr) + LINK_LIBRARIES clm csm_share esmf) diff --git a/src/biogeophys/test/SnowHydrology_test/CMakeLists.txt b/src/biogeophys/test/SnowHydrology_test/CMakeLists.txt index 600356b2ff..9e1738ab83 100644 --- a/src/biogeophys/test/SnowHydrology_test/CMakeLists.txt +++ b/src/biogeophys/test/SnowHydrology_test/CMakeLists.txt @@ -5,4 +5,4 @@ set (pfunit_sources add_pfunit_ctest(SnowHydrology TEST_SOURCES "${pfunit_sources}" - LINK_LIBRARIES clm csm_share esmf_wrf_timemgr) + LINK_LIBRARIES clm csm_share esmf) diff --git a/src/biogeophys/test/TotalWaterAndHeat_test/CMakeLists.txt b/src/biogeophys/test/TotalWaterAndHeat_test/CMakeLists.txt index a82532f69b..424515e414 100644 --- a/src/biogeophys/test/TotalWaterAndHeat_test/CMakeLists.txt +++ b/src/biogeophys/test/TotalWaterAndHeat_test/CMakeLists.txt @@ -3,4 +3,4 @@ set (pfunit_sources add_pfunit_ctest(total_water_and_heat TEST_SOURCES "${pfunit_sources}" - LINK_LIBRARIES clm csm_share esmf_wrf_timemgr) + LINK_LIBRARIES clm csm_share esmf) diff --git a/src/biogeophys/test/WaterTracerContainerType_test/CMakeLists.txt b/src/biogeophys/test/WaterTracerContainerType_test/CMakeLists.txt index 283906a442..645972aa1e 100644 --- a/src/biogeophys/test/WaterTracerContainerType_test/CMakeLists.txt +++ b/src/biogeophys/test/WaterTracerContainerType_test/CMakeLists.txt @@ -3,4 +3,4 @@ set (pfunit_sources add_pfunit_ctest(water_tracer_container TEST_SOURCES "${pfunit_sources}" - LINK_LIBRARIES clm csm_share esmf_wrf_timemgr) + LINK_LIBRARIES clm csm_share esmf) diff --git a/src/biogeophys/test/WaterTracerUtils_test/CMakeLists.txt b/src/biogeophys/test/WaterTracerUtils_test/CMakeLists.txt index 321e06883a..1a65bbfadd 100644 --- a/src/biogeophys/test/WaterTracerUtils_test/CMakeLists.txt +++ b/src/biogeophys/test/WaterTracerUtils_test/CMakeLists.txt @@ -5,4 +5,4 @@ set (pfunit_sources add_pfunit_ctest(water_tracer_utils TEST_SOURCES "${pfunit_sources}" - LINK_LIBRARIES clm csm_share esmf_wrf_timemgr) + LINK_LIBRARIES clm csm_share esmf) diff --git a/src/biogeophys/test/WaterType_test/CMakeLists.txt b/src/biogeophys/test/WaterType_test/CMakeLists.txt index 506179aabd..3f0ab409da 100644 --- a/src/biogeophys/test/WaterType_test/CMakeLists.txt +++ b/src/biogeophys/test/WaterType_test/CMakeLists.txt @@ -3,4 +3,4 @@ set (pfunit_sources add_pfunit_ctest(water_type TEST_SOURCES "${pfunit_sources}" - LINK_LIBRARIES clm csm_share esmf_wrf_timemgr) + LINK_LIBRARIES clm csm_share esmf) diff --git a/src/biogeophys/test/Wateratm2lnd_test/CMakeLists.txt b/src/biogeophys/test/Wateratm2lnd_test/CMakeLists.txt index c2157952e0..1ddb840431 100644 --- a/src/biogeophys/test/Wateratm2lnd_test/CMakeLists.txt +++ b/src/biogeophys/test/Wateratm2lnd_test/CMakeLists.txt @@ -3,4 +3,4 @@ set (pfunit_sources add_pfunit_ctest(water_atm2lnd TEST_SOURCES "${pfunit_sources}" - LINK_LIBRARIES clm csm_share esmf_wrf_timemgr) + LINK_LIBRARIES clm csm_share esmf) diff --git a/src/cpl/nuopc/lnd_comp_nuopc.F90 b/src/cpl/nuopc/lnd_comp_nuopc.F90 index a6aab619ce..c76414bf5d 100644 --- a/src/cpl/nuopc/lnd_comp_nuopc.F90 +++ b/src/cpl/nuopc/lnd_comp_nuopc.F90 @@ -29,7 +29,7 @@ module lnd_comp_nuopc use NUOPC_Model , only : NUOPC_ModelGet use shr_kind_mod , only : r8 => shr_kind_r8, cl=>shr_kind_cl use shr_sys_mod , only : shr_sys_abort - use shr_file_mod , only : shr_file_getlogunit, shr_file_setlogunit + use shr_log_mod , only : shr_log_setLogUnit, shr_log_getLogUnit use shr_orb_mod , only : shr_orb_decl, shr_orb_params, SHR_ORB_UNDEF_REAL, SHR_ORB_UNDEF_INT use shr_cal_mod , only : shr_cal_noleap, shr_cal_gregorian, shr_cal_ymd2date use spmdMod , only : masterproc, mpicom, spmd_init @@ -66,7 +66,7 @@ module lnd_comp_nuopc private :: clm_orbital_init ! Initialize the orbital information private :: clm_orbital_update ! Update the orbital information private :: CheckImport - + !-------------------------------------------------------------------------- ! Private module data !-------------------------------------------------------------------------- @@ -235,7 +235,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return ! Note still need compid for those parts of the code that use the data model - ! functionality through subroutine calls + ! functionality through subroutine calls (MCTID just means the Model ComonenT IDentification number) call NUOPC_CompAttributeGet(gcomp, name='MCTID', value=cvalue, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return read(cvalue,*) compid ! convert from string to integer @@ -333,8 +333,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) !---------------------------------------------------------------------------- ! reset shr logging to original values !---------------------------------------------------------------------------- - - call shr_file_setLogUnit (shrlogunit) + call shr_log_setLogUnit(shrlogunit) call ESMF_LogWrite(subname//' done', ESMF_LOGMSG_INFO) end subroutine InitializeAdvertise @@ -497,8 +496,8 @@ subroutine InitializeRealize(gcomp, importState, exportState, clock, rc) ! Reset shr logging to my log file !---------------------------------------------------------------------------- - call shr_file_getLogUnit (shrlogunit) - call shr_file_setLogUnit (iulog) + call shr_log_getLogUnit (shrlogunit) + call shr_log_setLogUnit (iulog) #if (defined _MEMTRACE) if (masterproc) then lbnum=1 @@ -686,7 +685,7 @@ subroutine InitializeRealize(gcomp, importState, exportState, clock, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return endif - call shr_file_setLogUnit (shrlogunit) + call shr_log_setLogUnit (shrlogunit) #if (defined _MEMTRACE) if(masterproc) then @@ -777,8 +776,8 @@ subroutine ModelAdvance(gcomp, rc) ! Reset share log units !-------------------------------- - call shr_file_getLogUnit (shrlogunit) - call shr_file_setLogUnit (iulog) + call shr_log_getLogUnit (shrlogunit) + call shr_log_setLogUnit (iulog) #if (defined _MEMTRACE) if(masterproc) then @@ -867,7 +866,7 @@ subroutine ModelAdvance(gcomp, rc) rstwr = .false. if (nlend .and. write_restart_at_endofrun) then rstwr = .true. - else + else call ESMF_ClockGetAlarm(clock, alarmname='alarm_restart', alarm=alarm, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return if (ESMF_AlarmIsCreated(alarm, rc=rc)) then @@ -967,7 +966,7 @@ subroutine ModelAdvance(gcomp, rc) ! Reset shr logging to my original values !-------------------------------- - call shr_file_setLogUnit (shrlogunit) + call shr_log_setLogUnit (shrlogunit) call ESMF_LogWrite(subname//' done', ESMF_LOGMSG_INFO) @@ -1293,14 +1292,14 @@ subroutine CheckImport(gcomp, rc) type(ESMF_GridComp) :: gcomp integer, intent(out) :: rc character(len=*) , parameter :: subname = "("//__FILE__//":CheckImport)" - + ! This is the routine that enforces the explicit time dependence on the ! import fields. This simply means that the timestamps on the Fields in the - ! importState are checked against the currentTime on the Component's + ! importState are checked against the currentTime on the Component's ! internalClock. Consequenty, this model starts out with forcing fields - ! at the current time as it does its forward step from currentTime to + ! at the current time as it does its forward step from currentTime to ! currentTime + timeStep. - + ! local variables type(ESMF_Clock) :: clock type(ESMF_Time) :: time @@ -1324,7 +1323,7 @@ subroutine CheckImport(gcomp, rc) ! query the component for info call NUOPC_CompGet(gcomp, name=name, rc=rc) if (chkerr(rc,__LINE__,u_FILE_u)) return - + ! query the Component for its clock and importState call ESMF_GridCompGet(gcomp, clock=clock, importState=importState, rc=rc) if (chkerr(rc,__LINE__,u_FILE_u)) return @@ -1332,11 +1331,11 @@ subroutine CheckImport(gcomp, rc) ! get the current time out of the clock call ESMF_ClockGet(clock, currTime=time, rc=rc) if (chkerr(rc,__LINE__,u_FILE_u)) return - + ! check that Fields in the importState show correct timestamp allCurrent = NUOPC_IsAtTime(importState, time, fieldList=fieldList, rc=rc) if (chkerr(rc,__LINE__,u_FILE_u)) return - + if (.not.allCurrent) then !TODO: introduce and use INCOMPATIBILITY return codes!!!! do i=1, size(fieldList) @@ -1358,6 +1357,6 @@ subroutine CheckImport(gcomp, rc) rcToReturn=rc) return ! bail out endif - + end subroutine CheckImport end module lnd_comp_nuopc diff --git a/src/dyn_subgrid/test/dynConsBiogeophys_test/CMakeLists.txt b/src/dyn_subgrid/test/dynConsBiogeophys_test/CMakeLists.txt index 5e981270a4..da9c27090c 100644 --- a/src/dyn_subgrid/test/dynConsBiogeophys_test/CMakeLists.txt +++ b/src/dyn_subgrid/test/dynConsBiogeophys_test/CMakeLists.txt @@ -3,4 +3,4 @@ set(pfunit_sources add_pfunit_ctest(dynConsBiogeophys TEST_SOURCES "${pfunit_sources}" - LINK_LIBRARIES clm csm_share esmf_wrf_timemgr) + LINK_LIBRARIES clm csm_share esmf) diff --git a/src/dyn_subgrid/test/dynInitColumns_test/CMakeLists.txt b/src/dyn_subgrid/test/dynInitColumns_test/CMakeLists.txt index 7952f66756..0adbd696ad 100644 --- a/src/dyn_subgrid/test/dynInitColumns_test/CMakeLists.txt +++ b/src/dyn_subgrid/test/dynInitColumns_test/CMakeLists.txt @@ -1,3 +1,3 @@ add_pfunit_ctest(dynInitColumns TEST_SOURCES "test_init_columns.pf" - LINK_LIBRARIES clm csm_share esmf_wrf_timemgr) + LINK_LIBRARIES clm csm_share esmf) diff --git a/src/dyn_subgrid/test/dynTimeInfo_test/CMakeLists.txt b/src/dyn_subgrid/test/dynTimeInfo_test/CMakeLists.txt index 66f2027c36..625ddae91b 100644 --- a/src/dyn_subgrid/test/dynTimeInfo_test/CMakeLists.txt +++ b/src/dyn_subgrid/test/dynTimeInfo_test/CMakeLists.txt @@ -1,3 +1,3 @@ add_pfunit_ctest(dynTimeInfo TEST_SOURCES "test_dynTimeInfo.pf" - LINK_LIBRARIES clm csm_share esmf_wrf_timemgr) + LINK_LIBRARIES clm csm_share esmf) diff --git a/src/dyn_subgrid/test/dynVar_test/CMakeLists.txt b/src/dyn_subgrid/test/dynVar_test/CMakeLists.txt index fc4cf07b30..7164947f1e 100644 --- a/src/dyn_subgrid/test/dynVar_test/CMakeLists.txt +++ b/src/dyn_subgrid/test/dynVar_test/CMakeLists.txt @@ -9,4 +9,4 @@ set (extra_sources add_pfunit_ctest(dynVar TEST_SOURCES "${pfunit_sources}" OTHER_SOURCES "${extra_sources}" - LINK_LIBRARIES clm csm_share esmf_wrf_timemgr) + LINK_LIBRARIES clm csm_share esmf) diff --git a/src/fates b/src/fates index e06e0dfcaf..e3e7d2cd86 160000 --- a/src/fates +++ b/src/fates @@ -1 +1 @@ -Subproject commit e06e0dfcaf6347993d47dc29944e952d3e4412f7 +Subproject commit e3e7d2cd86a66f8ca0e8f6dc4a823246a2bdb95b diff --git a/src/main/clm_initializeMod.F90 b/src/main/clm_initializeMod.F90 index b15c6e3ba7..46353539ce 100644 --- a/src/main/clm_initializeMod.F90 +++ b/src/main/clm_initializeMod.F90 @@ -137,8 +137,8 @@ subroutine initialize2(ni,nj, currtime) use clm_varpar , only : surfpft_lb, surfpft_ub use clm_varpar , only : nlevsno use clm_varpar , only : natpft_size,cft_size - use clm_varctl , only : fsurdat - use clm_varctl , only : finidat, finidat_interp_source, finidat_interp_dest, fsurdat + use clm_varctl , only : fsurdat, hillslope_file + use clm_varctl , only : finidat, finidat_interp_source, finidat_interp_dest use clm_varctl , only : use_cn, use_fates, use_fates_luh use clm_varctl , only : use_crop, ndep_from_cpl, fates_spitfire_mode use clm_varctl , only : use_hillslope @@ -256,7 +256,7 @@ subroutine initialize2(ni,nj, currtime) call pftcon%Init() ! Read surface dataset and set up subgrid weight arrays - call surfrd_get_data(begg, endg, ldomain, fsurdat, actual_numcft) + call surfrd_get_data(begg, endg, ldomain, fsurdat, hillslope_file, actual_numcft) if(use_fates) then @@ -307,7 +307,7 @@ subroutine initialize2(ni,nj, currtime) if (use_hillslope) then ! Initialize hillslope properties - call InitHillslope(bounds_proc, fsurdat) + call InitHillslope(bounds_proc, hillslope_file) endif ! Set filters diff --git a/src/main/clm_instMod.F90 b/src/main/clm_instMod.F90 index ae83a1b31f..210cff2c2e 100644 --- a/src/main/clm_instMod.F90 +++ b/src/main/clm_instMod.F90 @@ -188,7 +188,7 @@ subroutine clm_instInit(bounds) ! ! !USES: use clm_varpar , only : nlevsno - use controlMod , only : nlfilename, fsurdat + use controlMod , only : nlfilename, fsurdat, hillslope_file use domainMod , only : ldomain use SoilBiogeochemDecompCascadeMIMICSMod, only : init_decompcascade_mimics use SoilBiogeochemDecompCascadeBGCMod , only : init_decompcascade_bgc @@ -280,7 +280,7 @@ subroutine clm_instInit(bounds) ! Set hillslope column bedrock values if (use_hillslope) then - call SetHillslopeSoilThickness(bounds,fsurdat, & + call SetHillslopeSoilThickness(bounds, hillslope_file, & soil_depth_lowland_in=8.5_r8,& soil_depth_upland_in =2.0_r8) call setSoilLayerClass(bounds) diff --git a/src/main/clm_varctl.F90 b/src/main/clm_varctl.F90 index cb7e2e3931..9539060200 100644 --- a/src/main/clm_varctl.F90 +++ b/src/main/clm_varctl.F90 @@ -109,6 +109,7 @@ module clm_varctl character(len=fname_len), public :: finidat = ' ' ! initial conditions file name character(len=fname_len), public :: fsurdat = ' ' ! surface data file name + character(len=fname_len), public :: hillslope_file = ' ' ! hillslope data file name character(len=fname_len), public :: paramfile = ' ' ! ASCII data file with PFT physiological constants character(len=fname_len), public :: nrevsn = ' ' ! restart data file name for branch run character(len=fname_len), public :: fsnowoptics = ' ' ! snow optical properties file name @@ -288,7 +289,7 @@ module clm_varctl logical, public :: spinup_matrixcn = .false. !.false. ! true => use acc spinup logical, public :: hist_wrt_matrixcn_diag = .false.!.false. ! true => use acc spinup ! SASU - integer, public :: nyr_forcing = 10 ! length of forcing years for the spin up. eg. if DATM_CLMNCEP_YR_START=1901;DATM_CLMNCEP_YR_END=1920, then nyr_forcing = 20 + integer, public :: nyr_forcing = 10 ! length of forcing years for the spin up. eg. if DATM_YR_START=1901;DATM_YR_END=1920, then nyr_forcing = 20 integer, public :: nyr_SASU = 1 ! length of each semi-analytic solution. eg. nyr_SASU=5, analytic solutions will be calculated every five years. ! nyr_SASU=1: the fastest SASU, but inaccurate; nyr_SASU=nyr_forcing(eg. 20): the lowest SASU but accurate integer, public :: iloop_avg = -999 ! The restart file will be based on the average of all analytic solutions within the iloop_avg^th loop. diff --git a/src/main/controlMod.F90 b/src/main/controlMod.F90 index f65c8c7f47..3f5c58ac0e 100644 --- a/src/main/controlMod.F90 +++ b/src/main/controlMod.F90 @@ -119,7 +119,6 @@ subroutine control_init(dtime) ! ! !USES: use CNMRespMod , only : CNMRespReadNML - use LunaMod , only : LunaReadNML use CNNDynamicsMod , only : CNNDynamicsReadNML use CNPhenologyMod , only : CNPhenologyReadNML use landunit_varcon , only : max_lunit @@ -148,7 +147,7 @@ subroutine control_init(dtime) ! Input datasets namelist /clm_inparm/ & - fsurdat, & + fsurdat, hillslope_file, & paramfile, fsnowoptics, fsnowaging ! History, restart options @@ -584,7 +583,6 @@ subroutine control_init(dtime) call SnowHydrology_readnl ( NLFilename ) call UrbanReadNML ( NLFilename ) call HumanIndexReadNML ( NLFilename ) - call LunaReadNML ( NLFilename ) ! ---------------------------------------------------------------------- ! Broadcast all control information if appropriate @@ -736,6 +734,7 @@ subroutine control_spmd() call mpi_bcast (finidat_interp_source, len(finidat_interp_source), MPI_CHARACTER, 0, mpicom, ier) call mpi_bcast (finidat_interp_dest, len(finidat_interp_dest), MPI_CHARACTER, 0, mpicom, ier) call mpi_bcast (fsurdat, len(fsurdat), MPI_CHARACTER, 0, mpicom, ier) + call mpi_bcast (hillslope_file, len(hillslope_file), MPI_CHARACTER, 0, mpicom, ier) call mpi_bcast (fatmlndfrc,len(fatmlndfrc),MPI_CHARACTER, 0, mpicom, ier) call mpi_bcast (paramfile, len(paramfile) , MPI_CHARACTER, 0, mpicom, ier) call mpi_bcast (fsnowoptics, len(fsnowoptics), MPI_CHARACTER, 0, mpicom, ier) @@ -1021,6 +1020,11 @@ subroutine control_print () else write(iulog,*) ' surface data = ',trim(fsurdat) end if + if (hillslope_file == ' ') then + write(iulog,*) ' hillslope_file, hillslope dataset not set' + else + write(iulog,*) ' hillslope data = ',trim(hillslope_file) + end if if (fatmlndfrc == ' ') then write(iulog,*) ' fatmlndfrc not set, setting frac/mask to 1' else diff --git a/src/main/histFileMod.F90 b/src/main/histFileMod.F90 index 8ae4ace7e3..381e1f1170 100644 --- a/src/main/histFileMod.F90 +++ b/src/main/histFileMod.F90 @@ -28,7 +28,7 @@ module histFileMod use FatesInterfaceTypesMod , only : nlevheight use FatesInterfaceTypesMod , only : nlevdamage use FatesConstantsMod , only : n_landuse_cats - use FatesLitterMod , only : nfsc + use FatesFuelClassesMod , only : num_fuel_classes use FatesLitterMod , only : ncwd use PRTGenericMod , only : num_elements_fates => num_elements use FatesInterfaceTypesMod , only : numpft_fates => numpft @@ -91,6 +91,7 @@ module histFileMod character(len=max_namlen+2), public :: & hist_fincl1(max_flds) = ' ' ! namelist: list of fields to include in history tape 1 + ! aka 'h0' history file. character(len=max_namlen+2), public :: & hist_fincl2(max_flds) = ' ' ! namelist: list of fields to include in history tape 2 character(len=max_namlen+2), public :: & @@ -116,6 +117,7 @@ module histFileMod character(len=max_namlen+2), public :: & hist_fexcl1(max_flds) = ' ' ! namelist: list of fields to exclude from history tape 1 + ! aka 'h0' history file. character(len=max_namlen+2), public :: & hist_fexcl2(max_flds) = ' ' ! namelist: list of fields to exclude from history tape 2 character(len=max_namlen+2), public :: & @@ -2328,6 +2330,7 @@ subroutine htape_create (t, histrest) use clm_varpar , only : natpft_size, cft_size, maxpatch_glc, nlevdecomp_full, mxsowings, mxharvests use landunit_varcon , only : max_lunit use clm_varctl , only : caseid, ctitle, fsurdat, finidat, paramfile + use clm_varctl , only : hillslope_file use clm_varctl , only : version, hostname, username, conventions, source use clm_varctl , only : use_hillslope,nhillslope,max_columns_hillslope use domainMod , only : ldomain @@ -2428,6 +2431,8 @@ subroutine htape_create (t, histrest) call ncd_putatt(lnfid, ncd_global, 'case_id', trim(caseid)) str = get_filename(fsurdat) call ncd_putatt(lnfid, ncd_global, 'Surface_dataset', trim(str)) + str = get_filename(hillslope_file) + call ncd_putatt(lnfid, ncd_global, 'Hillslope_dataset', trim(str)) if (finidat == ' ') then str = 'arbitrary initialization' else @@ -2501,7 +2506,7 @@ subroutine htape_create (t, histrest) call ncd_defdim(lnfid, 'fates_levpft', numpft_fates, dimid) call ncd_defdim(lnfid, 'fates_levage', nlevage, dimid) call ncd_defdim(lnfid, 'fates_levheight', nlevheight, dimid) - call ncd_defdim(lnfid, 'fates_levfuel', nfsc, dimid) + call ncd_defdim(lnfid, 'fates_levfuel', num_fuel_classes, dimid) call ncd_defdim(lnfid, 'fates_levcwdsc', ncwd, dimid) call ncd_defdim(lnfid, 'fates_levscpf', nlevsclass*numpft_fates, dimid) call ncd_defdim(lnfid, 'fates_levcapf', nlevcoage*numpft_fates, dimid) @@ -2516,7 +2521,7 @@ subroutine htape_create (t, histrest) call ncd_defdim(lnfid, 'fates_levelpft', num_elements_fates * numpft_fates, dimid) call ncd_defdim(lnfid, 'fates_levelcwd', num_elements_fates * ncwd, dimid) call ncd_defdim(lnfid, 'fates_levelage', num_elements_fates * nlevage, dimid) - call ncd_defdim(lnfid, 'fates_levagefuel', nlevage * nfsc, dimid) + call ncd_defdim(lnfid, 'fates_levagefuel', nlevage * num_fuel_classes, dimid) call ncd_defdim(lnfid, 'fates_levclscpf', nclmax*nlevsclass*numpft_fates, dimid) call ncd_defdim(lnfid, 'fates_levlanduse', n_landuse_cats, dimid) call ncd_defdim(lnfid, 'fates_levlulu', n_landuse_cats * n_landuse_cats, dimid) @@ -5592,7 +5597,7 @@ subroutine hist_addfld2d (fname, type2d, units, avgflag, long_name, type1d_out, case ('fates_levheight') num2d = nlevheight case ('fates_levfuel') - num2d = nfsc + num2d = num_fuel_classes case ('fates_levcwdsc') num2d = ncwd case ('fates_levscpf') @@ -5632,7 +5637,7 @@ subroutine hist_addfld2d (fname, type2d, units, avgflag, long_name, type1d_out, case ('fates_levelage') num2d = num_elements_fates*nlevage case ('fates_levagefuel') - num2d = nlevage*nfsc + num2d = nlevage*num_fuel_classes case('fates_levclscpf') num2d = nclmax * nclmax * numpft_fates case ('fates_levlanduse') diff --git a/src/main/restFileMod.F90 b/src/main/restFileMod.F90 index b7f98209dd..f6a7a96ed9 100644 --- a/src/main/restFileMod.F90 +++ b/src/main/restFileMod.F90 @@ -518,6 +518,7 @@ subroutine restFile_dimset( ncid ) ! !USES: use clm_time_manager , only : get_nstep use clm_varctl , only : caseid, ctitle, version, username, hostname, fsurdat + use clm_varctl , only : hillslope_file use clm_varctl , only : conventions, source use dynSubgridControlMod , only : get_flanduse_timeseries use clm_varpar , only : numrad, nlevlak, nlevsno, nlevgrnd, nlevmaxurbgrnd, nlevcan @@ -584,6 +585,7 @@ subroutine restFile_dimset( ncid ) call ncd_putatt(ncid, NCD_GLOBAL, 'case_title' , trim(ctitle)) call ncd_putatt(ncid, NCD_GLOBAL, 'case_id' , trim(caseid)) call ncd_putatt(ncid, NCD_GLOBAL, 'surface_dataset', trim(fsurdat)) + call ncd_putatt(ncid, NCD_GLOBAL, 'hillslope_dataset', trim(hillslope_file)) call ncd_putatt(ncid, NCD_GLOBAL, 'flanduse_timeseries', trim(get_flanduse_timeseries())) call ncd_putatt(ncid, NCD_GLOBAL, 'title', 'CLM Restart information') diff --git a/src/main/surfrdMod.F90 b/src/main/surfrdMod.F90 index 88d43a09cc..4005ec7845 100644 --- a/src/main/surfrdMod.F90 +++ b/src/main/surfrdMod.F90 @@ -46,6 +46,83 @@ module surfrdMod contains + subroutine check_domain_attributes(ncid, begg, endg, ldomain, info) + ! !DESCRIPTION: + ! Checks for mismatches between the land domain and a surface or similar dataset's domain. + ! + ! !USES: + use domainMod, only : domain_type, domain_init, domain_clean + ! + ! !ARGUMENTS + type(file_desc_t), intent(inout) :: ncid ! netcdf id for input file + integer, intent(in) :: begg, endg + type(domain_type), intent(in) :: ldomain ! land domain + character(len=*), intent(in) :: info ! information to include in messages + ! + ! !LOCAL VARIABLES + type(domain_type) :: inputdata_domain ! local domain associated with input dataset + logical :: readvar ! true => variable is on dataset + logical :: istype_domain ! true => input file is of type domain + character(len=16) :: lon_var, lat_var ! names of lat/lon on dataset + logical :: isgrid2d ! true => input grid is 2d + integer :: ni, nj, ns ! domain sizes + integer :: n + real(r8) :: rmaxlon, rmaxlat ! local min/max vars + + character(len=32) :: subname = 'check_domain_attributes' ! subroutine name + + call check_var(ncid=ncid, varname='xc', readvar=readvar) + if (readvar) then + istype_domain = .true. + else + call check_var(ncid=ncid, varname='LONGXY', readvar=readvar) + if (readvar) then + istype_domain = .false. + else + call endrun( msg=' ERROR: unknown '//info//' domain type---'//errMsg(sourcefile, __LINE__)) + end if + end if + if (istype_domain) then + lon_var = 'xc' + lat_var = 'yc' + else + lon_var = 'LONGXY' + lat_var = 'LATIXY' + end if + if ( masterproc )then + write(iulog,*) trim(subname),' ',info,' lon_var = ',trim(lon_var),' lat_var =',trim(lat_var) + end if + + call ncd_inqfdims(ncid, isgrid2d, ni, nj, ns) + call domain_init(inputdata_domain, isgrid2d, ni, nj, begg, endg, subgrid_level=grlnd) + + call ncd_io(ncid=ncid, varname=lon_var, flag='read', data=inputdata_domain%lonc, & + dim1name=grlnd, readvar=readvar) + if (.not. readvar) call endrun( msg=' ERROR: lon var NOT on '//info//' dataset---'//errMsg(sourcefile, __LINE__)) + + call ncd_io(ncid=ncid, varname=lat_var, flag='read', data=inputdata_domain%latc, & + dim1name=grlnd, readvar=readvar) + if (.not. readvar) call endrun( msg=' ERROR: lat var NOT on '//info//' dataset---'//errMsg(sourcefile, __LINE__)) + + rmaxlon = 0.0_r8 + rmaxlat = 0.0_r8 + do n = begg,endg + if (ldomain%lonc(n)-inputdata_domain%lonc(n) > 300.) then + rmaxlon = max(rmaxlon,abs(ldomain%lonc(n)-inputdata_domain%lonc(n)-360._r8)) + elseif (ldomain%lonc(n)-inputdata_domain%lonc(n) < -300.) then + rmaxlon = max(rmaxlon,abs(ldomain%lonc(n)-inputdata_domain%lonc(n)+360._r8)) + else + rmaxlon = max(rmaxlon,abs(ldomain%lonc(n)-inputdata_domain%lonc(n))) + endif + rmaxlat = max(rmaxlat,abs(ldomain%latc(n)-inputdata_domain%latc(n))) + enddo + if (rmaxlon > 0.001_r8 .or. rmaxlat > 0.001_r8) then + write(iulog,*)' ERROR: '//info//' dataset vs. land domain lon/lat mismatch error', rmaxlon,rmaxlat + call endrun(msg=errMsg(sourcefile, __LINE__)) + end if + call domain_clean(inputdata_domain) + end subroutine check_domain_attributes + !----------------------------------------------------------------------- subroutine surfrd_compat_check ( lfsurdat ) ! @@ -111,7 +188,7 @@ subroutine surfrd_compat_check ( lfsurdat ) end subroutine surfrd_compat_check !----------------------------------------------------------------------- - subroutine surfrd_get_data (begg, endg, ldomain, lfsurdat, actual_numcft) + subroutine surfrd_get_data (begg, endg, ldomain, lfsurdat, lhillslope_file, actual_numcft) ! ! !DESCRIPTION: ! Read the surface dataset and create subgrid weights. @@ -138,9 +215,10 @@ subroutine surfrd_get_data (begg, endg, ldomain, lfsurdat, actual_numcft) use clm_varctl , only : create_crop_landunit, convert_ocean_to_land, collapse_urban, & toosmall_soil, toosmall_crop, toosmall_glacier, & toosmall_lake, toosmall_wetland, toosmall_urban, & - n_dom_landunits + n_dom_landunits, & + use_hillslope use fileutils , only : getfil - use domainMod , only : domain_type, domain_init, domain_clean + use domainMod , only : domain_type use clm_instur , only : wt_lunit, topo_glc_mec, pct_urban_max use landunit_varcon , only : max_lunit, istsoil, isturb_MIN, isturb_MAX use dynSubgridControlMod, only : get_flanduse_timeseries @@ -152,19 +230,13 @@ subroutine surfrd_get_data (begg, endg, ldomain, lfsurdat, actual_numcft) integer, intent(in) :: begg, endg, actual_numcft type(domain_type),intent(in) :: ldomain ! land domain character(len=*), intent(in) :: lfsurdat ! surface dataset filename + character(len=*), intent(in) :: lhillslope_file ! hillslope dataset filename ! ! !LOCAL VARIABLES: - type(domain_type) :: surfdata_domain ! local domain associated with surface dataset character(len=256):: locfn ! local file name integer, parameter :: n_dom_urban = 1 ! # of dominant urban landunits - integer :: n ! loop indices - integer :: ni,nj,ns ! domain sizes - character(len=16) :: lon_var, lat_var ! names of lat/lon on dataset - logical :: readvar ! true => variable is on dataset - real(r8) :: rmaxlon,rmaxlat ! local min/max vars - type(file_desc_t) :: ncid ! netcdf id - logical :: istype_domain ! true => input file is of type domain - logical :: isgrid2d ! true => intut grid is 2d + type(file_desc_t) :: ncid ! netcdf id for lfsurdat + type(file_desc_t) :: ncid_hillslope ! netcdf id for lhillslope_file character(len=32) :: subname = 'surfrd_get_data' ! subroutine name !----------------------------------------------------------------------- @@ -175,6 +247,10 @@ subroutine surfrd_get_data (begg, endg, ldomain, lfsurdat, actual_numcft) write(iulog,*)'lfsurdat must be specified' call endrun(msg=errMsg(sourcefile, __LINE__)) endif + if (use_hillslope .and. lhillslope_file == ' ') then + write(iulog,*)'lhillslope_file must be specified' + call endrun(msg=errMsg(sourcefile, __LINE__)) + endif endif wt_lunit(:,:) = 0._r8 @@ -184,71 +260,24 @@ subroutine surfrd_get_data (begg, endg, ldomain, lfsurdat, actual_numcft) call getfil( lfsurdat, locfn, 0 ) call ncd_pio_openfile (ncid, trim(locfn), 0) - - ! Cmopare surfdat_domain attributes to ldomain attributes - - call check_var(ncid=ncid, varname='xc', readvar=readvar) - if (readvar) then - istype_domain = .true. - else - call check_var(ncid=ncid, varname='LONGXY', readvar=readvar) - if (readvar) then - istype_domain = .false. - else - call endrun( msg=' ERROR: unknown domain type'//errMsg(sourcefile, __LINE__)) - end if - end if - if (istype_domain) then - lon_var = 'xc' - lat_var = 'yc' - else - lon_var = 'LONGXY' - lat_var = 'LATIXY' - end if - if ( masterproc )then - write(iulog,*) trim(subname),' lon_var = ',trim(lon_var),' lat_var =',trim(lat_var) + if (use_hillslope) then + call getfil( lhillslope_file, locfn, 0 ) + call ncd_pio_openfile (ncid_hillslope, trim(locfn), 0) end if - call ncd_inqfdims(ncid, isgrid2d, ni, nj, ns) - call domain_init(surfdata_domain, isgrid2d, ni, nj, begg, endg, subgrid_level=grlnd) - - call ncd_io(ncid=ncid, varname=lon_var, flag='read', data=surfdata_domain%lonc, & - dim1name=grlnd, readvar=readvar) - if (.not. readvar) call endrun( msg=' ERROR: lon var NOT on surface dataset'//errMsg(sourcefile, __LINE__)) - - call ncd_io(ncid=ncid, varname=lat_var, flag='read', data=surfdata_domain%latc, & - dim1name=grlnd, readvar=readvar) - if (.not. readvar) call endrun( msg=' ERROR: lat var NOT on surface dataset'//errMsg(sourcefile, __LINE__)) - - rmaxlon = 0.0_r8 - rmaxlat = 0.0_r8 - do n = begg,endg - if (ldomain%lonc(n)-surfdata_domain%lonc(n) > 300.) then - rmaxlon = max(rmaxlon,abs(ldomain%lonc(n)-surfdata_domain%lonc(n)-360._r8)) - elseif (ldomain%lonc(n)-surfdata_domain%lonc(n) < -300.) then - rmaxlon = max(rmaxlon,abs(ldomain%lonc(n)-surfdata_domain%lonc(n)+360._r8)) - else - rmaxlon = max(rmaxlon,abs(ldomain%lonc(n)-surfdata_domain%lonc(n))) - endif - rmaxlat = max(rmaxlat,abs(ldomain%latc(n)-surfdata_domain%latc(n))) - enddo - if (rmaxlon > 0.001_r8 .or. rmaxlat > 0.001_r8) then - write(iulog,*)' ERROR: surfdata_domain/ldomain lon/lat mismatch error', rmaxlon,rmaxlat - call endrun(msg=errMsg(sourcefile, __LINE__)) + ! Compare dataset domain attributes to ldomain attributes + call check_domain_attributes(ncid, begg, endg, ldomain, 'surface') + if (use_hillslope) then + call check_domain_attributes(ncid_hillslope, begg, endg, ldomain, 'hillslope') end if - !~! TODO(SPM, 022015) - if we deallocate and clean ldomain here, then you - !~! get errors in htape_timeconst where the information is needed to write - !~! the *.h0* file - !~!call domain_clean(surfdata_domain) - ! Obtain special landunit info call surfrd_special(begg, endg, ncid, ldomain%ns) ! Obtain vegetated landunit info - call surfrd_veg_all(begg, endg, ncid, ldomain%ns, actual_numcft) + call surfrd_veg_all(begg, endg, ncid, ncid_hillslope, ldomain%ns, actual_numcft) if (use_cndv) then call surfrd_veg_dgvm(begg, endg) @@ -831,7 +860,7 @@ subroutine surfrd_pftformat( begg, endg, ncid ) end subroutine surfrd_pftformat !----------------------------------------------------------------------- - subroutine surfrd_veg_all(begg, endg, ncid, ns, actual_numcft) + subroutine surfrd_veg_all(begg, endg, ncid, ncid_hillslope, ns, actual_numcft) ! ! !DESCRIPTION: ! Determine weight arrays for non-dynamic landuse mode @@ -848,7 +877,8 @@ subroutine surfrd_veg_all(begg, endg, ncid, ns, actual_numcft) ! !ARGUMENTS: implicit none integer, intent(in) :: begg, endg, actual_numcft - type(file_desc_t),intent(inout) :: ncid ! netcdf id + type(file_desc_t),intent(inout) :: ncid ! netcdf id for fsurdat + type(file_desc_t),intent(inout) :: ncid_hillslope ! netcdf id for hillslope_file integer ,intent(in) :: ns ! domain size ! ! !LOCAL VARIABLES: @@ -934,7 +964,7 @@ subroutine surfrd_veg_all(begg, endg, ncid, ns, actual_numcft) ! Obtain hillslope hydrology information and modify pft weights if (use_hillslope) then - call surfrd_hillslope(begg, endg, ncid, ns) + call surfrd_hillslope(begg, endg, ncid_hillslope, ns) endif ! Convert from percent to fraction diff --git a/src/main/test/accumul_test/CMakeLists.txt b/src/main/test/accumul_test/CMakeLists.txt index 0b06d9e87e..8d7cf69f1c 100644 --- a/src/main/test/accumul_test/CMakeLists.txt +++ b/src/main/test/accumul_test/CMakeLists.txt @@ -3,4 +3,4 @@ set(pfunit_sources add_pfunit_ctest(accumul TEST_SOURCES "${pfunit_sources}" - LINK_LIBRARIES clm csm_share esmf_wrf_timemgr) + LINK_LIBRARIES clm csm_share esmf) diff --git a/src/main/test/atm2lnd_test/CMakeLists.txt b/src/main/test/atm2lnd_test/CMakeLists.txt index 51c4732205..fcc4159ce2 100644 --- a/src/main/test/atm2lnd_test/CMakeLists.txt +++ b/src/main/test/atm2lnd_test/CMakeLists.txt @@ -4,4 +4,4 @@ set(pfunit_sources add_pfunit_ctest(atm2lnd TEST_SOURCES "${pfunit_sources}" - LINK_LIBRARIES clm csm_share esmf_wrf_timemgr) + LINK_LIBRARIES clm csm_share esmf) diff --git a/src/main/test/initVertical_test/CMakeLists.txt b/src/main/test/initVertical_test/CMakeLists.txt index 8fe9648a50..aec45772c4 100644 --- a/src/main/test/initVertical_test/CMakeLists.txt +++ b/src/main/test/initVertical_test/CMakeLists.txt @@ -1,3 +1,3 @@ add_pfunit_ctest(initVertical TEST_SOURCES "test_initVertical.pf" - LINK_LIBRARIES clm csm_share esmf_wrf_timemgr) + LINK_LIBRARIES clm csm_share esmf) diff --git a/src/self_tests/test/assertions_test/CMakeLists.txt b/src/self_tests/test/assertions_test/CMakeLists.txt index d36d8c7675..aeae976839 100644 --- a/src/self_tests/test/assertions_test/CMakeLists.txt +++ b/src/self_tests/test/assertions_test/CMakeLists.txt @@ -3,4 +3,4 @@ set (pfunit_sources add_pfunit_ctest(assertions TEST_SOURCES "${pfunit_sources}" - LINK_LIBRARIES clm csm_share esmf_wrf_timemgr) + LINK_LIBRARIES clm csm_share esmf) diff --git a/src/soilbiogeochem/test/tillage_test/CMakeLists.txt b/src/soilbiogeochem/test/tillage_test/CMakeLists.txt index fbc550dd03..13be9aee3e 100644 --- a/src/soilbiogeochem/test/tillage_test/CMakeLists.txt +++ b/src/soilbiogeochem/test/tillage_test/CMakeLists.txt @@ -1,3 +1,3 @@ add_pfunit_ctest(tillage TEST_SOURCES "test_tillage.pf" - LINK_LIBRARIES clm csm_share esmf_wrf_timemgr) + LINK_LIBRARIES clm csm_share esmf) diff --git a/src/utils/SparseMatrixMultiplyMod.F90 b/src/utils/SparseMatrixMultiplyMod.F90 index 5ea9848373..564da21cc2 100644 --- a/src/utils/SparseMatrixMultiplyMod.F90 +++ b/src/utils/SparseMatrixMultiplyMod.F90 @@ -1217,7 +1217,7 @@ subroutine SPMP_ABC(this,num_unit,filter_u,A,B,C,list_ready,list_A,list_B,list_C call endrun( subname//" ERROR: missing required optional arguments" ) return end if - SHR_ASSERT_FL((size(filter_actunit_A) > num_actunit_A), sourcefile, __LINE__) + SHR_ASSERT_FL((size(filter_actunit_A) >= num_actunit_A), sourcefile, __LINE__) end if if(present(num_actunit_B))then if(num_actunit_B < 0)then @@ -1230,7 +1230,7 @@ subroutine SPMP_ABC(this,num_unit,filter_u,A,B,C,list_ready,list_A,list_B,list_C call endrun( subname//" ERROR: missing required optional arguments" ) return end if - SHR_ASSERT_FL((size(filter_actunit_B) > num_actunit_B), sourcefile, __LINE__) + SHR_ASSERT_FL((size(filter_actunit_B) >= num_actunit_B), sourcefile, __LINE__) end if if(present(num_actunit_C))then if(num_actunit_C < 0)then @@ -1243,7 +1243,7 @@ subroutine SPMP_ABC(this,num_unit,filter_u,A,B,C,list_ready,list_A,list_B,list_C call endrun( subname//" ERROR: missing required optional arguments" ) return end if - SHR_ASSERT_FL((size(filter_actunit_C) > num_actunit_C), sourcefile, __LINE__) + SHR_ASSERT_FL((size(filter_actunit_C) >= num_actunit_C), sourcefile, __LINE__) end if if(.not. list_ready)then diff --git a/src/utils/clmfates_interfaceMod.F90 b/src/utils/clmfates_interfaceMod.F90 index cff7679e9d..269189d1b7 100644 --- a/src/utils/clmfates_interfaceMod.F90 +++ b/src/utils/clmfates_interfaceMod.F90 @@ -3622,7 +3622,7 @@ subroutine hlm_bounds_to_fates_bounds(hlm, fates) use FatesInterfaceTypesMod, only : nlevsclass, nlevage, nlevcoage use FatesInterfaceTypesMod, only : nlevheight use FatesInterfaceTypesMod, only : nlevdamage - use FatesLitterMod, only : nfsc + use FatesFuelClassesMod, only : num_fuel_classes use FatesLitterMod, only : ncwd use EDParamsMod, only : nlevleaf, nclmax use FatesInterfaceTypesMod, only : numpft_fates => numpft @@ -3674,7 +3674,7 @@ subroutine hlm_bounds_to_fates_bounds(hlm, fates) fates%sizeagepft_class_end = nlevsclass * nlevage * numpft_fates fates%fuel_begin = 1 - fates%fuel_end = nfsc + fates%fuel_end = num_fuel_classes fates%cwdsc_begin = 1 fates%cwdsc_end = ncwd @@ -3701,7 +3701,7 @@ subroutine hlm_bounds_to_fates_bounds(hlm, fates) fates%elage_end = num_elements * nlevage fates%agefuel_begin = 1 - fates%agefuel_end = nlevage * nfsc + fates%agefuel_end = nlevage * num_fuel_classes fates%cdpf_begin = 1 fates%cdpf_end = nlevdamage * numpft_fates * nlevsclass diff --git a/src/utils/test/annual_flux_dribbler_test/CMakeLists.txt b/src/utils/test/annual_flux_dribbler_test/CMakeLists.txt index a0a60e7431..01efdc1e50 100644 --- a/src/utils/test/annual_flux_dribbler_test/CMakeLists.txt +++ b/src/utils/test/annual_flux_dribbler_test/CMakeLists.txt @@ -1,3 +1,3 @@ add_pfunit_ctest(annual_flux_dribbler TEST_SOURCES "test_annual_flux_dribbler.pf" - LINK_LIBRARIES clm csm_share esmf_wrf_timemgr) + LINK_LIBRARIES clm csm_share esmf) diff --git a/src/utils/test/array_utils_test/CMakeLists.txt b/src/utils/test/array_utils_test/CMakeLists.txt index 21c7d91d81..a6b36304b4 100644 --- a/src/utils/test/array_utils_test/CMakeLists.txt +++ b/src/utils/test/array_utils_test/CMakeLists.txt @@ -5,4 +5,4 @@ set (pfunit_sources add_pfunit_ctest(array_utils TEST_SOURCES "${pfunit_sources}" - LINK_LIBRARIES clm csm_share esmf_wrf_timemgr) + LINK_LIBRARIES clm csm_share esmf) diff --git a/src/utils/test/clm_time_manager_test/CMakeLists.txt b/src/utils/test/clm_time_manager_test/CMakeLists.txt index f34e77dfc9..66a62e665d 100644 --- a/src/utils/test/clm_time_manager_test/CMakeLists.txt +++ b/src/utils/test/clm_time_manager_test/CMakeLists.txt @@ -1,3 +1,3 @@ add_pfunit_ctest(clm_time_manager TEST_SOURCES "test_clm_time_manager.pf" - LINK_LIBRARIES clm csm_share esmf_wrf_timemgr) + LINK_LIBRARIES clm csm_share esmf) diff --git a/src/utils/test/numerics_test/CMakeLists.txt b/src/utils/test/numerics_test/CMakeLists.txt index 19d2c67451..2e826e2018 100644 --- a/src/utils/test/numerics_test/CMakeLists.txt +++ b/src/utils/test/numerics_test/CMakeLists.txt @@ -3,4 +3,4 @@ set (pfunit_sources add_pfunit_ctest(numerics TEST_SOURCES "${pfunit_sources}" - LINK_LIBRARIES clm csm_share esmf_wrf_timemgr) + LINK_LIBRARIES clm csm_share esmf) diff --git a/tools/contrib/run_clm_historical b/tools/contrib/run_clm_historical index cd293d5867..8dc9269d3b 100755 --- a/tools/contrib/run_clm_historical +++ b/tools/contrib/run_clm_historical @@ -76,9 +76,9 @@ cp original_user_nl_clm user_nl_clm ./xmlchange STOP_N=21 ./xmlchange CONTINUE_RUN=FALSE ./xmlchange RESUBMIT=0 -./xmlchange DATM_CLMNCEP_YR_ALIGN=1901 -./xmlchange DATM_CLMNCEP_YR_START=1901 -./xmlchange DATM_CLMNCEP_YR_END=1920 +./xmlchange DATM_YR_ALIGN=1901 +./xmlchange DATM_YR_START=1901 +./xmlchange DATM_YR_END=1920 # need to use user_nl_datm files to get years right cp user_nl_datm1901-1920 user_nl_datm @@ -203,9 +203,9 @@ gzip $DDIR$CASENAME*.bin # we have to resubmit the job 3 times. ./xmlchange STOP_OPTION=nyears ./xmlchange STOP_N=22 -./xmlchange DATM_CLMNCEP_YR_ALIGN=1901 -./xmlchange DATM_CLMNCEP_YR_START=1901 -./xmlchange DATM_CLMNCEP_YR_END=2014 +./xmlchange DATM_YR_ALIGN=1901 +./xmlchange DATM_YR_START=1901 +./xmlchange DATM_YR_END=2014 ./xmlchange CONTINUE_RUN=TRUE ./xmlchange RESUBMIT=3 diff --git a/tools/contrib/run_clmtowers b/tools/contrib/run_clmtowers index e4dd2519ff..7e9dbbc426 100755 --- a/tools/contrib/run_clmtowers +++ b/tools/contrib/run_clmtowers @@ -211,9 +211,9 @@ foreach mysite ( $sites ) ./xmlchange --id STOP_OPTION --val nyears ./xmlchange --id STOP_N --val $numyears ./xmlchange --id RUN_STARTDATE --val $startyear[$cnt]-01-01 - ./xmlchange --id DATM_CLMNCEP_YR_ALIGN --val $startyear[$cnt] - ./xmlchange --id DATM_CLMNCEP_YR_START --val $startyear[$cnt] - ./xmlchange --id DATM_CLMNCEP_YR_END --val $endyear[$cnt] + ./xmlchange --id DATM_YR_ALIGN --val $startyear[$cnt] + ./xmlchange --id DATM_YR_START --val $startyear[$cnt] + ./xmlchange --id DATM_YR_END --val $endyear[$cnt] ./xmlchange --id CALENDAR --val GREGORIAN if ($BGC == ON) then ./xmlchange --id CLM_BLDNML_OPTS --val "-mask navy -bgc bgc -crop" @@ -240,9 +240,9 @@ foreach mysite ( $sites ) else ./xmlchange --id RUN_STARTDATE --val $startyear[$cnt]-01-01 endif - ./xmlchange --id DATM_CLMNCEP_YR_ALIGN --val $alignyear - ./xmlchange --id DATM_CLMNCEP_YR_START --val $startyears - ./xmlchange --id DATM_CLMNCEP_YR_END --val $endyears + ./xmlchange --id DATM_YR_ALIGN --val $alignyear + ./xmlchange --id DATM_YR_START --val $startyears + ./xmlchange --id DATM_YR_END --val $endyears if ($alignyear == 1) then ./xmlchange --id CALENDAR --val NO_LEAP endif @@ -263,7 +263,7 @@ foreach mysite ( $sites ) ./preview_namelists # Have to force this for some reason if ($SPINUP_P1 == FALSE) then - ./xmlchange --id DATM_CLMNCEP_YR_END --val $endyear[$cnt] + ./xmlchange --id DATM_YR_END --val $endyear[$cnt] ./preview_namelists endif if ( $status != 0 )then diff --git a/tools/mksurfdata_esmf/Makefile b/tools/mksurfdata_esmf/Makefile index 7ad8e1aa77..8dee6db596 100644 --- a/tools/mksurfdata_esmf/Makefile +++ b/tools/mksurfdata_esmf/Makefile @@ -79,10 +79,13 @@ SUBSETDATA_1X1_URBALPHA := --lat -37.7308 --lon 0 --site 1x1_urbanc_alpha --o # low-res is for low resolutions for testing # nldas is for NWP working with WRF # STANDARD means no crop, so 16 pfts +# global-hist-1850-f45 is used by FATES and we expect it to be phased out STANDARD = \ global-potveg \ global-present \ global-present-low-res \ + global-hist-1850-f19 \ + global-hist-1850-f45 \ CROP = \ crop-global-future \ @@ -153,6 +156,12 @@ global-present-low-res : FORCE $(MKSURFDATA) --number-of-nodes 1 --tasks-per-node 64 --scenario $@ --jobscript-file $@.sh --walltime 01:00:00 $(BATCHJOBS) $@.sh +global-hist-1850-f19 : FORCE + $(MKSURFDATA) --number-of-nodes 8 --scenario $@ --jobscript-file $@.sh --walltime 12:00:00 + $(BATCHJOBS) $@.sh +global-hist-1850-f45 : FORCE + $(MKSURFDATA) --number-of-nodes 2 --scenario $@ --jobscript-file $@.sh --walltime 12:00:00 + $(BATCHJOBS) $@.sh # # Ultra high resolutions (Don't do by default user should select this by hand) # diff --git a/tools/mksurfdata_esmf/src/mkglcmecMod.F90 b/tools/mksurfdata_esmf/src/mkglcmecMod.F90 index 25fa4a8edc..6dc363ecac 100644 --- a/tools/mksurfdata_esmf/src/mkglcmecMod.F90 +++ b/tools/mksurfdata_esmf/src/mkglcmecMod.F90 @@ -49,7 +49,6 @@ subroutine mkglcmecInit( pioid_o ) ! local variables: type(var_desc_t) :: pio_varid type(io_desc_t) :: pio_iodesc - real(r8), allocatable :: elevclass_o(:) ! elevation classes integer :: rcode character(len=*), parameter :: subname = 'mkglcmecInit' !----------------------------------------------------------------------- @@ -100,8 +99,6 @@ subroutine mkglcmecInit( pioid_o ) call shr_sys_abort() end if - elevclass_o(:) = elevclass(:) - if (root_task) write(ndiag, '(a)') trim(subname)//" writing out GLC_MEC" rcode = pio_inq_varid(pioid_o, 'GLC_MEC', pio_varid) rcode = pio_put_var(pioid_o, pio_varid, elevclass)