diff --git a/.gitmodules b/.gitmodules index 0176e8431c..752c3bf4f7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -9,7 +9,7 @@ path = src/physics/carma/base url = https://github.com/ESCOMP/CARMA_base.git fxrequired = AlwaysRequired - fxtag = carma4_01 + fxtag = carma4_09 fxDONOTUSEurl = https://github.com/ESCOMP/CARMA_base.git [submodule "pumas"] @@ -36,7 +36,7 @@ [submodule "atmos_phys"] path = src/atmos_phys url = https://github.com/ESCOMP/atmospheric_physics - fxtag = atmos_phys0_06_000 + fxtag = atmos_phys0_07_001 fxrequired = AlwaysRequired fxDONOTUSEurl = https://github.com/ESCOMP/atmospheric_physics @@ -151,7 +151,7 @@ fxDONOTUSEurl = https://github.com/ESMCI/ccs_config_cesm.git [submodule "cime"] path = cime url = https://github.com/ESMCI/cime -fxtag = cime6.1.49 +fxtag = cime6.1.56 fxrequired = ToplevelRequired fxDONOTUSEurl = https://github.com/ESMCI/cime @@ -186,7 +186,7 @@ fxDONOTUSEurl = https://github.com/NCAR/ParallelIO [submodule "cice"] path = components/cice url = https://github.com/ESCOMP/CESM_CICE -fxtag = cesm_cice6_5_0_12 +fxtag = cesm3_cice6_6_0_6 fxrequired = ToplevelRequired fxDONOTUSEurl = https://github.com/ESCOMP/CESM_CICE diff --git a/.lib/git-fleximod/git_fleximod/cli.py b/.lib/git-fleximod/git_fleximod/cli.py index b6f728f881..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.8.4" +__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 50e0ef83df..13f35df959 100755 --- a/.lib/git-fleximod/git_fleximod/git_fleximod.py +++ b/.lib/git-fleximod/git_fleximod/git_fleximod.py @@ -124,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") @@ -213,7 +213,7 @@ def submodules_status(gitmodules, root_dir, toplevel=False, depth=0): def git_toplevelroot(root_dir, logger): rgit = GitInterface(root_dir, logger) - superroot = rgit.git_operation("rev-parse", "--show-superproject-working-tree") + _, superroot = rgit.git_operation("rev-parse", "--show-superproject-working-tree") return superroot def submodules_update(gitmodules, root_dir, requiredlist, force): @@ -342,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 5831201446..fb20883cd0 100644 --- a/.lib/git-fleximod/git_fleximod/gitinterface.py +++ b/.lib/git-fleximod/git_fleximod/gitinterface.py @@ -59,11 +59,12 @@ def git_operation(self, operation, *args, **kwargs): 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: @@ -81,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/submodule.py b/.lib/git-fleximod/git_fleximod/submodule.py index 70a3018a42..75d9dd4eb9 100644 --- a/.lib/git-fleximod/git_fleximod/submodule.py +++ b/.lib/git-fleximod/git_fleximod/submodule.py @@ -60,8 +60,9 @@ def status(self): if not os.path.exists(os.path.join(smpath, ".git")): rootgit = GitInterface(self.root_dir, self.logger) # submodule commands use path, not name - tags = rootgit.git_operation("ls-remote", "--tags", self.url) - result = rootgit.git_operation("submodule","status",smpath).split() + 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:] @@ -80,9 +81,9 @@ def status(self): result = f"e {self.name:>20} not checked out, aligned at tag {self.fxtag}{optional}" needsupdate = True elif self.fxtag: - ahash = rootgit.git_operation( + status, ahash = rootgit.git_operation( "submodule", "status", "{}".format(self.path) - ).rstrip() + ) 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}" @@ -96,14 +97,15 @@ def status(self): else: with utils.pushd(smpath): git = GitInterface(smpath, self.logger) - remote = git.git_operation("remote").rstrip() + 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 - rurl = git.git_operation("ls-remote","--get-url").rstrip() - line = git.git_operation("log", "--pretty=format:\"%h %d\"").partition('\n')[0] + 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 @@ -120,7 +122,7 @@ def status(self): #print(f"line is {line} ahash is {ahash} atag is {atag} {parts}") - # atag = git.git_operation("describe", "--tags", "--always").rstrip() + # atag = git.git_operation("describe", "--tags", "--always") # ahash = git.git_operation("rev-list", "HEAD").partition("\n")[0] recurse = False @@ -149,10 +151,10 @@ def status(self): result = f"e {self.name:>20} has no fxtag defined in .gitmodules, module at {ahash}" testfails = False - status = git.git_operation("status", "--ignore-submodules", "-uno") - if "nothing to commit" not in status: + status, output = git.git_operation("status", "--ignore-submodules", "-uno") + if "nothing to commit" not in output: localmods = True - result = "M" + textwrap.indent(status, " ") + result = "M" + textwrap.indent(output, " ") # print(f"result {result} needsupdate {needsupdate} localmods {localmods} testfails {testfails}") return result, needsupdate, localmods, testfails @@ -171,10 +173,11 @@ def _add_remote(self, git): Returns: str: The name of the new remote if added, or the name of the existing remote that matches the submodule's URL. """ - remotes = git.git_operation("remote", "-v").splitlines() + status, remotes = git.git_operation("remote", "-v") + remotes = remotes.splitlines() upstream = None if remotes: - upstream = git.git_operation("ls-remote", "--get-url").rstrip() + 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) @@ -183,7 +186,7 @@ def _add_remote(self, git): return newremote else: i = 0 - while "newremote" in remotes: + while newremote in remotes: i = i + 1 newremote = f"newremote.{i:02d}" else: @@ -214,12 +217,19 @@ def sparse_checkout(self): """ self.logger.info("Called sparse_checkout for {}".format(self.name)) rgit = GitInterface(self.root_dir, self.logger) - superroot = rgit.git_operation("rev-parse", "--show-superproject-working-tree") + status, superroot = rgit.git_operation("rev-parse", "--show-superproject-working-tree") if superroot: gitroot = superroot.strip() else: - gitroot = self.root_dir.strip() - assert os.path.isdir(os.path.join(gitroot, ".git")) + 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)) @@ -244,8 +254,8 @@ def sparse_checkout(self): # set the repository remote self.logger.info("Setting remote origin in {}/{}".format(self.root_dir, self.path)) - status = sprepo_git.git_operation("remote", "-v") - if self.url not in status: + 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") @@ -256,46 +266,46 @@ def sparse_checkout(self): os.path.join(self.root_dir, f.read().split()[1]), start=os.path.join(self.root_dir, self.path), ) - topgit = os.path.join(gitpath, "modules") + rootdotgit = os.path.join(gitpath, "modules", self.name) else: - topgit = os.path.relpath( - os.path.join(self.root_dir, ".git", "modules"), + rootdotgit = os.path.relpath( + os.path.join(self.root_dir, ".git", "modules", self.name), start=os.path.join(self.root_dir, self.path), ) - with utils.pushd(sprep_repo): - if not os.path.isdir(topgit): - os.makedirs(topgit) - topgit += os.sep + self.name - 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(topgit,".git")): - shutil.rmtree(os.path.join(topgit,".git")) - shutil.move(".git", topgit) + 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(topgit)) - # assert(os.path.isdir(os.path.relpath(topgit, start=sprep_repo))) - gitsparse = os.path.abspath(os.path.join(topgit, "info", "sparse-checkout")) + 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, topgit) + "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") - sprepo_git.git_operation("checkout", self.fxtag) - - print(f"Successfully checked out {self.name:>20} at {self.fxtag}") - rgit.config_set_value(f'submodule "{self.name}"', "active", "true") - rgit.config_set_value(f'submodule "{self.name}"', "url", self.url) - rgit.config_set_value(f'submodule "{self.name}"', "path", self.path) + 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): """ @@ -342,7 +352,7 @@ def update(self): git.git_operation("clone", self.url, self.path) smgit = GitInterface(repodir, self.logger) if not tag: - tag = smgit.git_operation("describe", "--tags", "--always").rstrip() + 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") @@ -350,7 +360,7 @@ def update(self): with open(rootdotgit) as f: line = f.readline() if line.startswith("gitdir: "): - rootdotgit = line[8:].rstrip() + rootdotgit = line[8:] newpath = os.path.abspath(os.path.join(self.root_dir, rootdotgit, "modules", self.name)) if os.path.exists(newpath): @@ -393,15 +403,16 @@ def update(self): git = GitInterface(submoddir, self.logger) # first make sure the url is correct newremote = self._add_remote(git) - tags = git.git_operation("tag", "-l") + status, tags = git.git_operation("tag", "-l") fxtag = self.fxtag if fxtag and fxtag not in tags: git.git_operation("fetch", newremote, "--tags") - atag = git.git_operation("describe", "--tags", "--always").rstrip() + status, atag = git.git_operation("describe", "--tags", "--always") if fxtag and fxtag != atag: try: - git.git_operation("checkout", fxtag) - print(f"{self.name:>20} updated to {fxtag}") + status, _ = git.git_operation("checkout", fxtag) + if not status: + print(f"{self.name:>20} updated to {fxtag}") except Exception as error: print(error) 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 3a74effcd1..ac82fb0d97 100644 --- a/.lib/git-fleximod/poetry.lock +++ b/.lib/git-fleximod/poetry.lock @@ -30,13 +30,13 @@ dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] [[package]] name = "certifi" -version = "2024.6.2" +version = "2024.8.30" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2024.6.2-py3-none-any.whl", hash = "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56"}, - {file = "certifi-2024.6.2.tar.gz", hash = "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516"}, + {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, + {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, ] [[package]] diff --git a/.lib/git-fleximod/pyproject.toml b/.lib/git-fleximod/pyproject.toml index 850e57d59d..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.8.4" +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 bd82c557ad..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.8.4" +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 81edbe713e..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"] diff --git a/bld/build-namelist b/bld/build-namelist index 429555ff44..9a38f49926 100755 --- a/bld/build-namelist +++ b/bld/build-namelist @@ -1268,6 +1268,7 @@ if ($carma ne 'none') { add_default($nl, 'carma_model', 'val'=>$carma); add_default($nl, 'carma_flag', 'val'=>'.true.'); add_default($nl, 'history_carma', 'val'=>'.true.'); + add_default($nl, 'carma_sulfnuc_method','val'=>'ZhaoTurco'); } if ($carma eq 'bc_strat') { add_default($nl, 'carma_do_drydep', 'val'=>'.true.'); @@ -1587,7 +1588,7 @@ if (defined $nl->get_value('prescribed_strataero_3modes')) { # determine if prescribed stratospheric aerosol data is needed if ( ($het_chem) || ($nl->get_value('prescribed_strataero_feedback') =~ /$TRUE/io ) ){ - if ( ($carma ne 'sulfate') && !($nl->get_value('modal_strat_sulfate') =~ /$TRUE/io) ) { # if no prognostic stratospheric aerosols + if ( !($nl->get_value('modal_strat_sulfate') =~ /$TRUE/io) ) { # if no prognostic stratospheric aerosols unless (defined $nl->get_value('prescribed_strataero_type')) { add_default($nl, 'prescribed_strataero_type','val'=>'CYCLICAL'); diff --git a/bld/configure b/bld/configure index 9bee5d2077..8f9f435c8c 100755 --- a/bld/configure +++ b/bld/configure @@ -2341,6 +2341,7 @@ sub write_filepath print $fh "$camsrcdir/src/atmos_phys/schemes/tropopause_find\n"; print $fh "$camsrcdir/src/atmos_phys/schemes/zhang_mcfarlane\n"; print $fh "$camsrcdir/src/atmos_phys/schemes/dry_adiabatic_adjust\n"; + print $fh "$camsrcdir/src/atmos_phys/schemes/check_energy\n"; print $fh "$camsrcdir/src/atmos_phys/schemes/utilities\n"; # Dynamics package and test utilities diff --git a/bld/namelist_files/namelist_defaults_cam.xml b/bld/namelist_files/namelist_defaults_cam.xml index 5b2abb453a..8edaedf5f4 100644 --- a/bld/namelist_files/namelist_defaults_cam.xml +++ b/bld/namelist_files/namelist_defaults_cam.xml @@ -264,8 +264,6 @@ atm/cam/inic/se/ape_cam5_ne120np4_L30_c170419.nc atm/cam/inic/se/cam6_QPC6_aqua_ne3pg3_mg37_L32_01-01-31_c221214.nc -atm/cam/inic/se/cam6_QPC6_aqua_ne3pg3_mg37_L58_01-01-31_c221214.nc -atm/cam/inic/se/cam6_QPC6_aqua_ne3pg3_mg37_L93_01_02_01_c240518.nc atm/cam/inic/se/ape_cam6_ne5np4_L32_c170517.nc atm/cam/inic/se/ape_cam6_ne16np4_L32_c170509.nc atm/cam/inic/se/ape_cam6_ne30np4_L32_c170509.nc diff --git a/bld/namelist_files/namelist_definition.xml b/bld/namelist_files/namelist_definition.xml index 9fc56c40f7..24851424cc 100644 --- a/bld/namelist_files/namelist_definition.xml +++ b/bld/namelist_files/namelist_definition.xml @@ -4488,6 +4488,23 @@ is not active. Default: none + + Nucleation methods: + ZhaoTurco + Zhao, J. and Turco, R., + Nucleation simulations in the wake of a jet aircraft in stratospheric flight, + J. Aerosol Sci., 26, 779-795, 1995, + https://doi.org/10.1016/0021-8502(95)00010-A + Vehkamaki + Vehkamaki, H., M. Kulmala, I. Napari, K.E.J. Lehtinen, + C. Timmreck, M. Noppel and A. Laaksonen, 2002, + An improved parameterization for sulfuric acid-water nucleation + rates for tropospheric and stratospheric conditions, + J. Geophys. Res., 107, 4622, doi:10.1029/2002jd002184 +Default: none + + A fraction that scales how tight the convergence criteria are to diff --git a/bld/namelist_files/use_cases/aquaplanet_cam7.xml b/bld/namelist_files/use_cases/aquaplanet_cam7.xml new file mode 100644 index 0000000000..8e1c9fba5a --- /dev/null +++ b/bld/namelist_files/use_cases/aquaplanet_cam7.xml @@ -0,0 +1,63 @@ + + + + + +atm/cam/inic/se/QPLT_L58_ne3pg3_c241127.nc +atm/cam/inic/se/QPLT_L58_ne30pg3_c241127.nc +atm/cam/inic/se/QPMT_L93_ne3pg3_c241223.nc +atm/cam/inic/se/QPMT_L93_ne30pg3_c241223.nc + + +0. +0. +0. +fixed_parameters + + + false + + +1.650e-6 +0.306e-6 +348.0e-6 +0.0 +0.0 + + +atm/cam/solar/ape_solar_ave_tsi_1365.nc + + +apeozone_cam3_5_54.nc +aquaplanet_ozone_hightop_c20180412.nc +atm/cam/ozone +OZONE +CYCLICAL +1990 + + +86164.10063718943 +6.37100e6 +9.79764 +28.96623324623746 +18.01618112892741 +1.846e3 + +.false. + +.true. +.true. + "" + "" + "" + "" + "" + + 0.0 + + + 'A:Q:H2O', 'N:O2:O2', 'N:CO2:CO2', 'N:ozone:O3', + 'N:N2O:N2O', 'N:CH4:CH4', 'N:CFC11:CFC11', 'N:CFC12:CFC12' + + diff --git a/bld/namelist_files/use_cases/sd_waccm_sulfur.xml b/bld/namelist_files/use_cases/sd_waccm_sulfur.xml index 7a02c11544..d035ea8b79 100644 --- a/bld/namelist_files/use_cases/sd_waccm_sulfur.xml +++ b/bld/namelist_files/use_cases/sd_waccm_sulfur.xml @@ -133,7 +133,7 @@ atm/cam/met/GEOS5 atm/cam/met/GEOS5_filenames_list_c120516.txt - + atm/cam/met/USGS-gtopo30_1.9x2.5_phys_geos5_c100929.nc diff --git a/cime b/cime index b2f271b174..ac8e583108 160000 --- a/cime +++ b/cime @@ -1 +1 @@ -Subproject commit b2f271b1742533715a05701b1bdd80a24bb2ad77 +Subproject commit ac8e583108b1ce1f592a6f6436c71d6dc087f447 diff --git a/cime_config/config_component.xml b/cime_config/config_component.xml index 2ab0a50558..45b2506bbf 100644 --- a/cime_config/config_component.xml +++ b/cime_config/config_component.xml @@ -204,6 +204,7 @@ -aquaplanet -aquaplanet + -chem none -offline_drv rad @@ -255,6 +256,7 @@ aquaplanet_cam6 aquaplanet_cam6 aquaplanet_rce_cam6 + aquaplanet_cam7 aquaplanet_waccm_2000 2010_cam6 diff --git a/cime_config/config_compsets.xml b/cime_config/config_compsets.xml index c04f925dda..31eba44982 100644 --- a/cime_config/config_compsets.xml +++ b/cime_config/config_compsets.xml @@ -291,6 +291,16 @@ + + QPLT + 2000_CAM70%LT_SLND_SICE_DOCN%AQP3_SROF_SGLC_SWAV + + + + QPMT + 2000_CAM70%MT_SLND_SICE_DOCN%AQP3_SROF_SGLC_SWAV + + QPC2000climo 2000_CAM60%CT1S_SLND_SICE_DOCN%AQP3_SROF_SGLC_SWAV diff --git a/cime_config/testdefs/testlist_cam.xml b/cime_config/testdefs/testlist_cam.xml index c95f004d25..d0789ac1f3 100644 --- a/cime_config/testdefs/testlist_cam.xml +++ b/cime_config/testdefs/testlist_cam.xml @@ -49,7 +49,7 @@ - + @@ -59,7 +59,7 @@ - + @@ -161,7 +161,6 @@ - @@ -191,13 +190,42 @@ - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -582,6 +610,15 @@ + + + + + + + + + @@ -602,7 +639,16 @@ + + + + + + + + + @@ -614,7 +660,15 @@ - + + + + + + + + + @@ -625,6 +679,15 @@ + + + + + + + + + @@ -636,6 +699,15 @@ + + + + + + + + + @@ -647,6 +719,14 @@ + + + + + + + + @@ -655,9 +735,17 @@ - + + + + + + + + + @@ -669,6 +757,14 @@ + + + + + + + + @@ -680,6 +776,14 @@ + + + + + + + + @@ -691,6 +795,15 @@ + + + + + + + + + @@ -738,6 +851,14 @@ + + + + + + + + @@ -749,6 +870,14 @@ + + + + + + + + @@ -757,28 +886,28 @@ - + - - + - + - + + @@ -799,6 +928,7 @@ + @@ -809,6 +939,7 @@ + @@ -829,6 +960,7 @@ + @@ -839,6 +971,7 @@ + @@ -859,6 +992,7 @@ + @@ -2021,15 +2155,7 @@ - - - - - - - - - + diff --git a/cime_config/testdefs/testmods_dirs/cam/carma_dust/user_nl_cam b/cime_config/testdefs/testmods_dirs/cam/carma_dust/user_nl_cam index cfac3a4818..9893ae9a9e 100644 --- a/cime_config/testdefs/testmods_dirs/cam/carma_dust/user_nl_cam +++ b/cime_config/testdefs/testmods_dirs/cam/carma_dust/user_nl_cam @@ -6,4 +6,3 @@ pbuf_global_allocate=.false. history_carma=.true. fincl2 = 'CRSLERFC' carma_do_fixedinit=.false. -carma_reftfile="camrun.cam.r.carma_reft.nc" diff --git a/cime_config/testdefs/testmods_dirs/cam/carma_meteor_impact/user_nl_cam b/cime_config/testdefs/testmods_dirs/cam/carma_meteor_impact/user_nl_cam index 36487d1f35..ca4ea707ef 100644 --- a/cime_config/testdefs/testmods_dirs/cam/carma_meteor_impact/user_nl_cam +++ b/cime_config/testdefs/testmods_dirs/cam/carma_meteor_impact/user_nl_cam @@ -5,7 +5,6 @@ inithist='ENDOFRUN' pbuf_global_allocate=.false. history_carma=.true. carma_do_fixedinit=.false. -carma_reftfile="camrun.cam.r.carma_reft.nc" solar_data_type='FIXED' solar_data_ymd=20000101 carma_emis_maxlat = 40. diff --git a/cime_config/testdefs/testmods_dirs/cam/carma_meteor_smoke/user_nl_cam b/cime_config/testdefs/testmods_dirs/cam/carma_meteor_smoke/user_nl_cam index f69245ce24..2a81a976e2 100644 --- a/cime_config/testdefs/testmods_dirs/cam/carma_meteor_smoke/user_nl_cam +++ b/cime_config/testdefs/testmods_dirs/cam/carma_meteor_smoke/user_nl_cam @@ -5,7 +5,6 @@ inithist='ENDOFRUN' pbuf_global_allocate=.false. history_carma=.true. carma_do_fixedinit=.false. -carma_reftfile="camrun.cam.r.carma_reft.nc" solar_data_type='FIXED' solar_data_ymd=20000101 diff --git a/cime_config/testdefs/testmods_dirs/cam/carma_mixed_sulfate/user_nl_cam b/cime_config/testdefs/testmods_dirs/cam/carma_mixed_sulfate/user_nl_cam index 52b192f861..d292329b4c 100644 --- a/cime_config/testdefs/testmods_dirs/cam/carma_mixed_sulfate/user_nl_cam +++ b/cime_config/testdefs/testmods_dirs/cam/carma_mixed_sulfate/user_nl_cam @@ -5,7 +5,6 @@ inithist='ENDOFRUN' pbuf_global_allocate=.false. history_carma=.true. carma_do_fixedinit=.false. -carma_reftfile="camrun.cam.r.carma_reft.nc" flbc_list = 'CCL4', 'CF2CLBR', 'CF3BR', 'CFC11', 'CFC113', 'CFC12', 'CH3BR', 'CH3CCL3', 'CH3CL', 'CH4', 'CO2', 'H2', 'HCFC22', 'N2O', 'OCS' solar_data_type='FIXED' diff --git a/cime_config/testdefs/testmods_dirs/cam/carma_pmc/user_nl_cam b/cime_config/testdefs/testmods_dirs/cam/carma_pmc/user_nl_cam index b40ad17f97..3ec29d7308 100644 --- a/cime_config/testdefs/testmods_dirs/cam/carma_pmc/user_nl_cam +++ b/cime_config/testdefs/testmods_dirs/cam/carma_pmc/user_nl_cam @@ -6,4 +6,3 @@ pbuf_global_allocate=.false. history_carma=.true. carma_do_fixedinit=.false. carma_do_partialinit=.false. -carma_reftfile="camrun.cam.r.carma_reft.nc" diff --git a/cime_config/testdefs/testmods_dirs/cam/carma_sea_salt/user_nl_cam b/cime_config/testdefs/testmods_dirs/cam/carma_sea_salt/user_nl_cam index 377cbb2295..bb1512a995 100644 --- a/cime_config/testdefs/testmods_dirs/cam/carma_sea_salt/user_nl_cam +++ b/cime_config/testdefs/testmods_dirs/cam/carma_sea_salt/user_nl_cam @@ -5,4 +5,3 @@ inithist='ENDOFRUN' pbuf_global_allocate=.false. history_carma=.true. carma_do_fixedinit=.false. -carma_reftfile="camrun.cam.r.carma_reft.nc" diff --git a/cime_config/testdefs/testmods_dirs/cam/carma_sulfate/user_nl_cam b/cime_config/testdefs/testmods_dirs/cam/carma_sulfate/user_nl_cam index cfc4580f54..e3a93951a0 100644 --- a/cime_config/testdefs/testmods_dirs/cam/carma_sulfate/user_nl_cam +++ b/cime_config/testdefs/testmods_dirs/cam/carma_sulfate/user_nl_cam @@ -5,7 +5,6 @@ inithist='ENDOFRUN' pbuf_global_allocate=.false. history_carma=.true. carma_do_fixedinit=.false. -carma_reftfile="camrun.cam.r.carma_reft.nc" flbc_list = 'CCL4', 'CF2CLBR', 'CF3BR', 'CFC11', 'CFC113', 'CFC12', 'CH3BR', 'CH3CCL3', 'CH3CL', 'CH4', 'CO2', 'H2', 'HCFC22', 'N2O', 'OCS' solar_data_type='FIXED' diff --git a/cime_config/testdefs/testmods_dirs/cam/carma_test_growth/user_nl_cam b/cime_config/testdefs/testmods_dirs/cam/carma_test_growth/user_nl_cam index 377cbb2295..bb1512a995 100644 --- a/cime_config/testdefs/testmods_dirs/cam/carma_test_growth/user_nl_cam +++ b/cime_config/testdefs/testmods_dirs/cam/carma_test_growth/user_nl_cam @@ -5,4 +5,3 @@ inithist='ENDOFRUN' pbuf_global_allocate=.false. history_carma=.true. carma_do_fixedinit=.false. -carma_reftfile="camrun.cam.r.carma_reft.nc" diff --git a/cime_config/testdefs/testmods_dirs/cam/carma_test_passive/user_nl_cam b/cime_config/testdefs/testmods_dirs/cam/carma_test_passive/user_nl_cam index 377cbb2295..bb1512a995 100644 --- a/cime_config/testdefs/testmods_dirs/cam/carma_test_passive/user_nl_cam +++ b/cime_config/testdefs/testmods_dirs/cam/carma_test_passive/user_nl_cam @@ -5,4 +5,3 @@ inithist='ENDOFRUN' pbuf_global_allocate=.false. history_carma=.true. carma_do_fixedinit=.false. -carma_reftfile="camrun.cam.r.carma_reft.nc" diff --git a/cime_config/testdefs/testmods_dirs/cam/carma_test_radiative/user_nl_cam b/cime_config/testdefs/testmods_dirs/cam/carma_test_radiative/user_nl_cam index 377cbb2295..bb1512a995 100644 --- a/cime_config/testdefs/testmods_dirs/cam/carma_test_radiative/user_nl_cam +++ b/cime_config/testdefs/testmods_dirs/cam/carma_test_radiative/user_nl_cam @@ -5,4 +5,3 @@ inithist='ENDOFRUN' pbuf_global_allocate=.false. history_carma=.true. carma_do_fixedinit=.false. -carma_reftfile="camrun.cam.r.carma_reft.nc" diff --git a/cime_config/testdefs/testmods_dirs/cam/carma_test_swelling/user_nl_cam b/cime_config/testdefs/testmods_dirs/cam/carma_test_swelling/user_nl_cam index 377cbb2295..bb1512a995 100644 --- a/cime_config/testdefs/testmods_dirs/cam/carma_test_swelling/user_nl_cam +++ b/cime_config/testdefs/testmods_dirs/cam/carma_test_swelling/user_nl_cam @@ -5,4 +5,3 @@ inithist='ENDOFRUN' pbuf_global_allocate=.false. history_carma=.true. carma_do_fixedinit=.false. -carma_reftfile="camrun.cam.r.carma_reft.nc" diff --git a/cime_config/testdefs/testmods_dirs/cam/carma_test_tracers/user_nl_cam b/cime_config/testdefs/testmods_dirs/cam/carma_test_tracers/user_nl_cam index 377cbb2295..bb1512a995 100644 --- a/cime_config/testdefs/testmods_dirs/cam/carma_test_tracers/user_nl_cam +++ b/cime_config/testdefs/testmods_dirs/cam/carma_test_tracers/user_nl_cam @@ -5,4 +5,3 @@ inithist='ENDOFRUN' pbuf_global_allocate=.false. history_carma=.true. carma_do_fixedinit=.false. -carma_reftfile="camrun.cam.r.carma_reft.nc" diff --git a/cime_config/testdefs/testmods_dirs/cam/carma_test_tracers2/user_nl_cam b/cime_config/testdefs/testmods_dirs/cam/carma_test_tracers2/user_nl_cam index 377cbb2295..bb1512a995 100644 --- a/cime_config/testdefs/testmods_dirs/cam/carma_test_tracers2/user_nl_cam +++ b/cime_config/testdefs/testmods_dirs/cam/carma_test_tracers2/user_nl_cam @@ -5,4 +5,3 @@ inithist='ENDOFRUN' pbuf_global_allocate=.false. history_carma=.true. carma_do_fixedinit=.false. -carma_reftfile="camrun.cam.r.carma_reft.nc" diff --git a/cime_config/testdefs/testmods_dirs/cam/dae/shell_commands b/cime_config/testdefs/testmods_dirs/cam/dae/shell_commands deleted file mode 100644 index f091402c1d..0000000000 --- a/cime_config/testdefs/testmods_dirs/cam/dae/shell_commands +++ /dev/null @@ -1,6 +0,0 @@ -# Test CAM post-Data Assimilation handling -SRCROOT="`./xmlquery --value COMP_ROOT_DIR_ATM`" -DAFILE="${SRCROOT}/test/system/da_cam_no_data_mod.sh" -./xmlchange DATA_ASSIMILATION_SCRIPT=${DAFILE} -# Turn off any use case -./xmlchange CAM_NML_USE_CASE="UNSET" diff --git a/cime_config/testdefs/testmods_dirs/cam/dae/user_nl_cam b/cime_config/testdefs/testmods_dirs/cam/dae/user_nl_cam deleted file mode 100644 index f837808297..0000000000 --- a/cime_config/testdefs/testmods_dirs/cam/dae/user_nl_cam +++ /dev/null @@ -1,4 +0,0 @@ -! CAM history files have different names when DA is active so turn them off -nhtfrq = 0,-10000,-10000,-10000,-10000,-10000 -fexcl1 = 'OMEGA','OMEGAT','PHIS','PS','PSL','QRS','T','U','UU','V','VT','VU','VV','Z3' -fexcl2 = 'T','U','V' diff --git a/cime_config/testdefs/testmods_dirs/cam/dae/user_nl_cpl b/cime_config/testdefs/testmods_dirs/cam/dae/user_nl_cpl deleted file mode 100644 index 398535cf65..0000000000 --- a/cime_config/testdefs/testmods_dirs/cam/dae/user_nl_cpl +++ /dev/null @@ -1,2 +0,0 @@ -reprosum_diffmax=1.0e-14 -reprosum_recompute=.true. diff --git a/cime_config/testdefs/testmods_dirs/cam/outfrq3s_cosp/shell_commands b/cime_config/testdefs/testmods_dirs/cam/outfrq3s_cosp/shell_commands index 09a1939ddb..11a171a04e 100644 --- a/cime_config/testdefs/testmods_dirs/cam/outfrq3s_cosp/shell_commands +++ b/cime_config/testdefs/testmods_dirs/cam/outfrq3s_cosp/shell_commands @@ -1,8 +1,7 @@ CAM_CONFIG_OPTS=`./xmlquery CAM_CONFIG_OPTS --value` if [[ $CAM_CONFIG_OPTS != *"-cosp"* ]]; then - ./xmlchange -append CAM_CONFIG_OPTS="-cosp" + ./xmlchange --append CAM_CONFIG_OPTS="-cosp" fi ./xmlchange ROF_NCPL=\$ATM_NCPL ./xmlchange GLC_NCPL=\$ATM_NCPL -./xmlchange CAM_NML_USE_CASE=UNSET ./xmlchange RUN_STARTDATE="19950101" diff --git a/cime_config/testdefs/testmods_dirs/cam/outfrq3s_cosp/user_nl_cam b/cime_config/testdefs/testmods_dirs/cam/outfrq3s_cosp/user_nl_cam index ddff96685c..a2a8169e6f 100644 --- a/cime_config/testdefs/testmods_dirs/cam/outfrq3s_cosp/user_nl_cam +++ b/cime_config/testdefs/testmods_dirs/cam/outfrq3s_cosp/user_nl_cam @@ -2,4 +2,5 @@ mfilt=1,1,1,1,1,1 ndens=1,1,1,1,1,1 nhtfrq=3,3,3,3,3,3 inithist='ENDOFRUN' -fexcl1='CFAD_DBZE94_CS','CLDTOT_CALCS','CLD_CAL_NOTCS','CS_MIXCERT','CS_MIXPOSS','CS_NOPRECIP','CS_PIA','CS_RAINPOSS','CS_RAINPROB' +fexcl1='CFAD_DBZE94_CS','CLDTOT_CALCS','CLD_CAL_NOTCS','CS_MIXCERT','CS_MIXPOSS','CS_NOPRECIP','CS_PIA', + 'CS_RAINPOSS','CS_RAINPROB','CS_SNOWCERT','CS_SNOWPOSS' diff --git a/components/cice b/components/cice index f14ec8339b..e51ab1d3f1 160000 --- a/components/cice +++ b/components/cice @@ -1 +1 @@ -Subproject commit f14ec8339bc5bc4a7a0664da5e247b5cfda531a1 +Subproject commit e51ab1d3f12ae2959b7df978f77dc5a1ee0181d3 diff --git a/doc/ChangeLog b/doc/ChangeLog index cf2aa2517d..625bc0dbbb 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,5 +1,883 @@ =============================================================== +Tag name: cam6_4_055 +Originator(s): eaton +Date: 13 January 2025 +One-line Summary: Add QPLT and QPMT compsets, plus misc. +Github PR URL: https://github.com/ESCOMP/CAM/pull/1203 + +Purpose of changes (include the issue number and title text for each relevant GitHub issue): + +Issue #814 - Introduce QPC7 and possibly QPS7 aquaplanet compsets + - Analogous to FLT and FMT compset names, create QPLT and QPMT compsets. + - Open new issue to address QPS7. + - The new aquaplanet configurations use '-chem none' to eliminate the + aerosols. This is much faster and requires much less memory than a + configuration that leaves the default chemistry in place and removes + aerosols by zeroing the initial concentrations and emission sources. + +Issue #1159 - Prealpha tests exceeding wallclock + - increased time limit to 20 minutes for these prealpha tests: + ERP_Ln9.f09_f09_mg17.FHIST_BGC.derecho_intel.cam-outfrq9s + ERP_Ln9.f09_f09_mg17.FHIST.derecho_intel.cam-outfrq9s + +Issue #670 - DAE test broken + - ChangeLog indicates that this test has never worked since it was added + in cam6_2_046 (2020-09-01). Test removed. + +Issue #807 - add UT and UQ to cam_diagnostics + - Add UT and UQ. Note that other possible fields mentioned in the issue, + i.e., OMEGA2, OMEGAQ, OMEGAU, and OMEGAV, are already implemented. + OMEGA2 is called OMGAOMGA. + +Describe any changes made to build system: none + +Describe any changes made to the namelist: none + +List any changes to the defaults for the boundary datasets: +. add spun up initial files for QPLT compset on ne3pg3 and ne30pg3 grids. + atm/cam/inic/se/QPLT_L58_ne3pg3_c241127.nc + atm/cam/inic/se/QPLT_L58_ne30pg3_c241127.nc + +. add spun up initial files for QPMT compset on ne3pg3 and ne30pg3 grids. + atm/cam/inic/se/QPMT_L93_ne3pg3_c241223.nc + atm/cam/inic/se/QPMT_L93_ne30pg3_c241223.nc + +. add ozone dataset for high top aquaplanet runs + atm/cam/ozone/aquaplanet_ozone_hightop_c20180412.nc + +Describe any substantial timing or memory changes: n/a + +Code reviewed by: cacraig + +List all files eliminated: + +cime_config/testdefs/testmods_dirs/cam/dae/shell_commands +cime_config/testdefs/testmods_dirs/cam/dae/user_nl_cam +cime_config/testdefs/testmods_dirs/cam/dae/user_nl_cpl +test/system/da_cam_no_data_mod.sh +. DAE test removed + +List all files added and what they do: none + +List all existing files that have been modified, and describe the changes: + +bld/namelist_files/namelist_defaults_cam.xml +. Remove ncdata files for nlev=58 and nlev=93 aquaplanet. Those files are + specified in the aquaplanet_cam7.xml use case file. + +bld/namelist_files/use_cases/aquaplanet_cam7.xml +. use case file for QPLT and QPMT. Same as for QPC6 except: + - set f11vmr=f12vmr=0 to override the non-zero default values from + namelist_defaults_cam.xml. + - set prescribed_aero_file="" and prescribed_aero_specifier="" to + override the default bulk aerosol settings from build-namelist. + - set rad_climate to just make the GHGs radiatively active to override + the default build-namelist setting which includes bulk aerosols. + - Add spun-up IC files. This allows us to remove the ic_ymd attribute + which should not be needed for aquaplanet runs. Removing ic_ymd + enables testing with arbitrary start dates. + - Add ozone dataset for high top aquaplanet configuration + +cime_config/config_component.xml +. CAM_CONFIG_OPTS + - add match for _CAM70.*_SLND_SICE_DOCN%AQP to set '-chem none' +. CAM_NML_USE_CASE + - add match for 2000_CAM70.*_SLND_SICE_DOCN%AQP to use aquaplanet_cam7. + This match will work for both %LT and %MT configs. + +cime_config/config_compsets.xml +. add QPLT = 2000_CAM70%LT_SLND_SICE_DOCN%AQP3_SROF_SGLC_SWAV +. add QPMT = 2000_CAM70%MT_SLND_SICE_DOCN%AQP3_SROF_SGLC_SWAV + +cime_config/testdefs/testlist_cam.xml +. increase time limit to 20 minutes for these prealpha tests: + ERP_Ln9.f09_f09_mg17.FHIST_BGC.derecho_intel.cam-outfrq9s + ERP_Ln9.f09_f09_mg17.FHIST.derecho_intel.cam-outfrq9s +. remove non-working DAE test +. replace ERP_D_Ln9.f19_f19_mg17.QPC6.derecho_intel.cam-outfrq9s + by ERP_D_Ln9.ne30pg3_ne30pg3_mg17.QPLT.derecho_intel.cam-outfrq3s_cosp +. Add ERP_D_Ln9.ne30pg3_ne30pg3_mg17.QPMT.derecho_intel.cam-outfrq9s +. replace ERP_D_Ln9.ne3pg3_ne3pg3_mg37.QPC6.izumi_gnu.cam-outfrq9s_rrtmgp + by ERP_D_Ln9.ne3pg3_ne3pg3_mg37.QPLT.izumi_gnu.cam-outfrq9s +. Add ERP_D_Ln9.ne3pg3_ne3pg3_mg37.QPMT.izumi_gnu.cam-outfrq9s + +cime_config/testdefs/testmods_dirs/cam/outfrq3s_cosp/shell_commands +. remove "./xmlchange CAM_NML_USE_CASE=UNSET" + +cime_config/testdefs/testmods_dirs/cam/outfrq3s_cosp/user_nl_cam +. add CS_SNOWCERT and CS_SNOWPOSS to fexcl1 + +src/chemistry/mozart/mo_drydep.F90 +. get_landuse_and_soilw_from_file + - restrict the INFO messages to only print from masterproc + +src/physics/cam/cam_diagnostics.F90 +. diag_init_dry + - add addfld call for UT, and corresponding add_default for UT inside the + history_eddy conditional. +. diag_phys_writeout_dry + - add calculation and outfld call for UT +. diag_init_moist + - add addfld call for UQ, and corresponding add_default for UQ inside the + history_eddy conditional. +. diag_phys_writeout_moist + - add calculation and outfld call for UQ + +src/physics/cam/microp_aero.F90 +. microp_aero_run + - add condition that number of bulk aerosols must be > 0 before calling + ndrop_bam_run. + +src/physics/cam/nucleate_ice_cam.F90 +. nucleate_ice_cam_calc + - add conditionals so naer2 array not referenced when there are no + aerosols. + +src/physics/cam/vertical_diffusion.F90 +. vertical_diffusion_init + - fix conditional around add_default call for UFLX and VFLX so those + fields aren't added if they're not computed. + +src/physics/cam7/physpkg.F90 +. tphysbc + - add conditionals so modal aerosol calculations only called when modal + aerosols are present. + +If there were any failures reported from running test_driver.sh on any test +platform, and checkin with these failures has been OK'd by the gatekeeper, +then copy the lines from the td.*.status files for the failed tests to the +appropriate machine below. All failed tests must be justified. + +derecho/intel/aux_cam: + +ERC_D_Ln9.f19_f19_mg17.QPC6.derecho_intel.cam-outfrq3s_cosp (Overall: DIFF) +- diffs due to changing the test definition (in outfrq3s_cosp) so that the use case file, + aquaplanet_cam6.xml, is no longer ignored. This changes answers. + +ERP_D_Ln9.ne30pg3_ne30pg3_mg17.QPLT.derecho_intel.cam-outfrq3s_cosp (Overall: DIFF) +ERP_D_Ln9.ne30pg3_ne30pg3_mg17.QPMT.derecho_intel.cam-outfrq9s (Overall: DIFF) +- There are no baselines for these new tests. + +ERP_Ln9.f09_f09_mg17.FCSD_HCO.derecho_intel.cam-outfrq9s (Overall: FAIL) +- pre-existing failure due to HEMCO not having reproducible results issues #1018 and #856 + +SMS_D_Ln9.f19_f19_mg17.FXHIST.derecho_intel.cam-outfrq9s_amie (Overall: FAIL) +SMS_D_Ln9_P1280x1.ne0CONUSne30x8_ne0CONUSne30x8_mt12.FCHIST.derecho_intel.cam-outfrq9s (Overall: FAIL) +- pre-existing failures due to build-namelist error requiring CLM/CTSM external update. + +derecho/nvhpc/aux_cam: + +ERS_Ln9.ne30pg3_ne30pg3_mg17.F2000dev.derecho_nvhpc.cam-outfrq9s_gpu_default (Overall: FAIL) +- pre-existing failure -- issue #1220 + +izumi/nag/aux_cam: + +ERC_D_Ln9.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s_cosp (Overall: DIFF) details: +- diffs due to changing the test definition (in outfrq3s_cosp) so that the use case file, + aquaplanet_cam5.xml, is no longer ignored. This changes answers. + +izumi/gnu/aux_cam: + +ERC_D_Ln9.f10_f10_mg37.QPC4.izumi_gnu.cam-outfrq3s_diags (Overall: DIFF) +- Diff is due to the new diagnostic fields UT and UQ being included in the + test. Otherwise the run is identical with the baseline. + +ERP_D_Ln9.ne3pg3_ne3pg3_mg37.QPLT.izumi_gnu.cam-outfrq9s (Overall: DIFF) +ERP_D_Ln9.ne3pg3_ne3pg3_mg37.QPMT.izumi_gnu.cam-outfrq9s (Overall: DIFF) +- There are no baselines for these new tests. + +CAM tag used for the baseline comparison tests if different than previous +tag: + +Summarize any changes to answers: BFB. Note however that a change in the + test definition for outfrq3s_cosp causes answer changes for tests + using that testmod. + +=============================================================== +=============================================================== + +Tag name: cam6_4_054 +Originator(s): nusbaume +Date: 9 Jan 2025 +One-line Summary: Revert t_sfc limiter in RRTMGP +Github PR URL: https://github.com/ESCOMP/CAM/pull/1211 + +Purpose of changes (include the issue number and title text for each relevant GitHub issue): + +#1188 - Revert t_sfc limiter + - Also updates the CICE tag to fix the original bad temperatures problem. + +Describe any changes made to build system: N/A + +Describe any changes made to the namelist: N/A + +List any changes to the defaults for the boundary datasets: N/A + +Describe any substantial timing or memory changes: N/A + +Code reviewed by: cacraig, peverwhee + +List all files eliminated: N/A + +List all files added and what they do: N/A + +List all existing files that have been modified, and describe the changes: + +M .gitmodules +M components/cice + - Update CICE tag to cesm3_cice6_6_0_6 (Github issue #1185) + +M src/physics/rrtmgp/rrtmgp_inputs.F90 + - Revert t_sfc limiter in RRTMGP (Github PR #1184) + +If there were any failures reported from running test_driver.sh on any test +platform, and checkin with these failures has been OK'd by the gatekeeper, +then copy the lines from the td.*.status files for the failed tests to the +appropriate machine below. All failed tests must be justified. + +ALL F-compset answers changed (DIFF) due to the new CICE tag. + +Also any tests with RRTMGP will also have answer changes due +to the removal of the surface temperature limiter. + +derecho/intel/aux_cam: + + All F-compset tests + -NLCOMP and baseline DIFF failures due to the new CICE tag and t_sfc changes + + ERP_Ln9.f09_f09_mg17.FCSD_HCO.derecho_intel.cam-outfrq9s (Overall: FAIL) + - pre-existing failure -- issue #856 + + SMS_D_Ln9.f19_f19_mg17.FXHIST.derecho_intel.cam-outfrq9s_amie (Overall: FAIL) + SMS_D_Ln9_P1280x1.ne0CONUSne30x8_ne0CONUSne30x8_mt12.FCHIST.derecho_intel.cam-outfrq9s (Overall: FAIL) + - pre-existing failures due to build-namelist error requiring CLM/CTSM external update. + +derecho/nvhpc/aux_cam: + + ERS_Ln9.ne30pg3_ne30pg3_mg17.F2000dev.derecho_nvhpc.cam-outfrq9s_gpu_default (Overall: FAIL) + - pre-existing failure -- issue #1220 + - also had NLCOMP and baseline DIFF failures due to the new CICE tag and t_sfc changes. + +izumi/nag/aux_cam: + + DAE.f45_f45_mg37.FHS94.izumi_nag.cam-dae (Overall: FAIL) + - pre-existing failure -- issue #670 + +izumi/gnu/aux_cam: + + ERP_D_Ln9.ne3pg3_ne3pg3_mg37.FLTHIST.izumi_gnu.cam-outfrq9s (Overall: DIFF) + ERS_Ln9_P24x1.mpasa480_mpasa480.F2000climo.izumi_gnu.cam-outfrq9s_mpasa480 (Overall: DIFF) + SMS_P48x1_D_Ln9.f19_f19_mg17.FW4madSD.izumi_gnu.cam-outfrq9s (Overall: DIFF) + - NLCOMP and baseline DIFF failures due to the new CICE tag and t_sfc changes. + +CAM tag used for the baseline comparison tests if different than previous +tag: + +Summarize any changes to answers: + +=============================================================== +=============================================================== + +Tag name: cam6_4_053 +Originator(s): fvitt +Date: 7 Jan 2025 +One-line Summary: Update CARMA base external tag +Github PR URL: https://github.com/ESCOMP/CAM/pull/1201 + +Purpose of changes (include the issue number and title text for each relevant GitHub issue): + + Update CARMA sectional aerosol model base external to tag carma4_09 and update existing CARMA models accordingly + (Update CARMA base external #1181) + +Describe any changes made to build system: N/A + +Describe any changes made to the namelist: + - new carma_sulfnuc_method option + +List any changes to the defaults for the boundary datasets: N/A + +Describe any substantial timing or memory changes: N/A + +Code reviewed by: cacraigucar + +List all files eliminated: N/A + +List all files added and what they do: N/A + +List all existing files that have been modified, and describe the changes: +M .gitmodules + - update carma base tag + +M bld/build-namelist +M bld/namelist_files/namelist_definition.xml + - new carma_sulfnuc_method namelist option + +M cime_config/testdefs/testlist_cam.xml + - adjustments to carma tests + +M cime_config/testdefs/testmods_dirs/cam/carma_dust/user_nl_cam +M cime_config/testdefs/testmods_dirs/cam/carma_meteor_impact/user_nl_cam +M cime_config/testdefs/testmods_dirs/cam/carma_meteor_smoke/user_nl_cam +M cime_config/testdefs/testmods_dirs/cam/carma_mixed_sulfate/user_nl_cam +M cime_config/testdefs/testmods_dirs/cam/carma_pmc/user_nl_cam +M cime_config/testdefs/testmods_dirs/cam/carma_sea_salt/user_nl_cam +M cime_config/testdefs/testmods_dirs/cam/carma_sulfate/user_nl_cam +M cime_config/testdefs/testmods_dirs/cam/carma_test_growth/user_nl_cam +M cime_config/testdefs/testmods_dirs/cam/carma_test_passive/user_nl_cam +M cime_config/testdefs/testmods_dirs/cam/carma_test_radiative/user_nl_cam +M cime_config/testdefs/testmods_dirs/cam/carma_test_swelling/user_nl_cam +M cime_config/testdefs/testmods_dirs/cam/carma_test_tracers/user_nl_cam +M cime_config/testdefs/testmods_dirs/cam/carma_test_tracers2/user_nl_cam + - remove carma_reftfile namelist setting + +M src/physics/cam/carma_flags_mod.F90 + - updates to carma runtime options + +M src/physics/cam/carma_intr.F90 +M src/physics/cam/physpkg.F90 +M src/physics/cam7/physpkg.F90 + - interface changes for including pbuf + +M src/physics/carma/cam/carma_constants_mod.F90 + - add MAXCLDAERDIAG + +M src/physics/carma/cam/carma_intr.F90 + - add "only" to use statements + - add restart routines + - new diags flags + - many other updates needed for the development of trop_strat carma models + +M src/physics/carma/cam/carma_precision_mod.F90 +M src/physics/carma/models/bc_strat/carma_model_mod.F90 +M src/physics/carma/models/cirrus/carma_model_mod.F90 +M src/physics/carma/models/cirrus/growevapl.F90 +M src/physics/carma/models/cirrus_dust/carma_mod.F90 +M src/physics/carma/models/cirrus_dust/carma_model_mod.F90 +M src/physics/carma/models/cirrus_dust/growevapl.F90 +M src/physics/carma/models/meteor_impact/carma_model_flags_mod.F90 + - fix end module statements + - include missing real kind specifiers + +M src/physics/carma/models/dust/carma_model_mod.F90 +M src/physics/carma/models/meteor_impact/carma_model_mod.F90 +M src/physics/carma/models/meteor_smoke/carma_model_mod.F90 +M src/physics/carma/models/mixed_sulfate/carma_model_mod.F90 +M src/physics/carma/models/pmc/carma_model_mod.F90 +M src/physics/carma/models/pmc_sulfate/carma_model_mod.F90 +M src/physics/carma/models/sea_salt/carma_model_mod.F90 +M src/physics/carma/models/sulfate/carma_model_mod.F90 +M src/physics/carma/models/test_detrain/carma_model_mod.F90 +M src/physics/carma/models/test_growth/carma_model_mod.F90 +M src/physics/carma/models/test_passive/carma_model_mod.F90 +M src/physics/carma/models/test_radiative/carma_model_mod.F90 +M src/physics/carma/models/test_swelling/carma_model_mod.F90 +M src/physics/carma/models/test_tracers/carma_model_mod.F90 +M src/physics/carma/models/test_tracers2/carma_model_mod.F90 +M src/physics/carma/models/tholin/carma_model_mod.F90 + - update interfaces including optics calculations + - include missing real kind specifiers + +M test/system/TR8.sh + - include physics/carma and subdirectories in the r8 checks + +If there were any failures reported from running test_driver.sh on any test +platform, and checkin with these failures has been OK'd by the gatekeeper, +then copy the lines from the td.*.status files for the failed tests to the +appropriate machine below. All failed tests must be justified. + +derecho/intel/aux_cam: + FAIL ERP_Ln9.f09_f09_mg17.FCSD_HCO.derecho_intel.cam-outfrq9s COMPARE_base_rest + - pre-existing failure -- issue #856 + + FAIL SMS_D_Ln9.f19_f19_mg17.FXHIST.derecho_intel.cam-outfrq9s_amie SETUP + FAIL SMS_D_Ln9_P1280x1.ne0CONUSne30x8_ne0CONUSne30x8_mt12.FCHIST.derecho_intel.cam-outfrq9s SETUP + - pre-existing failures due to build-namelist error requiring CLM/CTSM external update. + +derecho/nvhpc/aux_cam: + FAIL ERS_Ln9.ne30pg3_ne30pg3_mg17.F2000dev.derecho_nvhpc.cam-outfrq9s_gpu_default COMPARE_base_rest + - pre-existing failure -- issue #1220 + +izumi/nag/aux_cam: + FAIL DAE.f45_f45_mg37.FHS94.izumi_nag.cam-dae + - pre-existing failure -- issue #670 + + DIFF ERC_D_Ln9.f10_f10_mg37.QPC5.izumi_nag.cam-carma_sea_salt + - expected differences due to updates to carma base code + +izumi/gnu/aux_cam: All PASS + +Summarize any changes to answers: + CARAM configurations change answers, otherwise bit-for-bit unchanged + +=============================================================== +=============================================================== + +Tag name: cam6_4_052 +Originator(s): huebleruwm, nusbaume +Date: 6 Jan 2025 +One-line Summary: clubb_intr GPUization +Github PR URL: https://github.com/ESCOMP/CAM/pull/1175 + +Purpose of changes (include the issue number and title text for each relevant GitHub issue): + +Adds OpenACC directives to clubb_intr.F90 to enable GPU offloading of CLUBB. +BFB on CPUs, answer changing (but passes ECT) on GPUs. + +Describe any changes made to build system: N/A + +Describe any changes made to the namelist: N/A + +List any changes to the defaults for the boundary datasets: N/A + +Describe any substantial timing or memory changes: N/A + +Code reviewed by: nusbaume, katetc, cacraigucar + +List all files eliminated: N/A + +List all files added and what they do: N/A + +List all existing files that have been modified, and describe the changes: +M src/physics/cam/clubb_intr.F90 + - add OpenACC directives for GPU offloading + - add timer calls to evaulate performance + +If there were any failures reported from running test_driver.sh on any test +platform, and checkin with these failures has been OK'd by the gatekeeper, +then copy the lines from the td.*.status files for the failed tests to the +appropriate machine below. All failed tests must be justified. + +derecho/intel/aux_cam: + + DIFF SMS_Lh12.f09_f09_mg17.FCSD_HCO.derecho_intel.cam-outfrq3h + FAIL ERP_Ln9.f09_f09_mg17.FCSD_HCO.derecho_intel.cam-outfrq9s + - pre-existing failure due to HEMCO not having reproducible results issues #1018 and #856 + + PEND SMS_D_Ln9.f19_f19_mg17.FXHIST.derecho_intel.cam-outfrq9s_amie + FAIL SMS_D_Ln9_P1280x1.ne0CONUSne30x8_ne0CONUSne30x8_mt12.FCHIST.derecho_intel.cam-outfrq9s + - pre-existing failures due to build-namelist error requiring CLM/CTSM external update. + +derecho/nvhpc/aux_cam: + +ERS_Ln9.ne30pg3_ne30pg3_mg17.F2000dev.derecho_nvhpc.cam-outfrq9s_gpu_default (Overall: FAIL) + - Expected baseline failures due to non-BFB answer changes with new CLUBB GPU-offloading. + +izumi/nag/aux_cam: + FAIL DAE.f45_f45_mg37.FHS94.izumi_nag.cam-dae + - pre-existing failure -- issue #670 + +izumi/gnu/aux_cam: ALL PASS + +=============================================================== +=============================================================== + +Tag name: cam6_4_051 +Originator(s): fvitt +Date: 2 Jan 2025 +One-line Summary: Updates to age of air tracers history output +Github PR URL: https://github.com/ESCOMP/CAM/pull/1198 + +Purpose of changes (include the issue number and title text for each relevant GitHub issue): + + Changes to age of air output #1197 + . Output age of air tracers mix ratios to history as soon as the tendencies are update, + before the tracers are transported in the time loop + . Rename history field 'AOAMF' as 'AOA1' + +Describe any changes made to build system: N/A + +Describe any changes made to the namelist: N/A + +List any changes to the defaults for the boundary datasets: N/A + +Describe any substantial timing or memory changes: N/A + +Code reviewed by: cacraigucar + +List all files eliminated: N/A + +List all files added and what they do: N/A + +List all existing files that have been modified, and describe the changes: +M src/physics/cam/aoa_tracers.F90 + - add outfld calls for AOA tracers + - rename 'AOAMF' as 'AOA1' + +If there were any failures reported from running test_driver.sh on any test +platform, and checkin with these failures has been OK'd by the gatekeeper, +then copy the lines from the td.*.status files for the failed tests to the +appropriate machine below. All failed tests must be justified. + +derecho/intel/aux_cam: + + PEND SMS_D_Ln9.f19_f19_mg17.FXHIST.derecho_intel.cam-outfrq9s_amie + FAIL SMS_D_Ln9_P1280x1.ne0CONUSne30x8_ne0CONUSne30x8_mt12.FCHIST.derecho_intel.cam-outfrq9s + - pre-existing failures due to build-namelist error requiring CLM/CTSM external update. + + DIFF SMS_Lh12.f09_f09_mg17.FCSD_HCO.derecho_intel.cam-outfrq3h + FAIL ERP_Ln9.f09_f09_mg17.FCSD_HCO.derecho_intel.cam-outfrq9s + - pre-existing failure due to HEMCO not having reproducible results issues #1018 and #856 + + DIFF ERC_D_Ln9.f19_f19_mg17.QPX2000.derecho_intel.cam-outfrq3s + DIFF ERP_Ld3.f09_f09_mg17.FWHIST.derecho_intel.cam-reduced_hist1d + DIFF ERP_Ld3.ne30pg3_ne30pg3_mg17.FHISTC_MTt4s.derecho_intel.cam-outfrq1d_aoa + DIFF ERP_Lh12.f19_f19_mg17.FW4madSD.derecho_intel.cam-outfrq3h + DIFF ERP_Ln9.f19_f19_mg17.FWsc1850.derecho_intel.cam-outfrq9s + DIFF ERP_Ln9.ne30pg3_ne30pg3_mg17.FCnudged.derecho_intel.cam-outfrq9s + DIFF ERP_Ln9.ne30pg3_ne30pg3_mg17.FW2000climo.derecho_intel.cam-outfrq9s + DIFF ERS_Ln9.f09_f09_mg17.FX2000.derecho_intel.cam-outfrq9s + DIFF ERS_Ln9.f19_f19_mg17.FXSD.derecho_intel.cam-outfrq9s + DIFF SMS_D_Ln9.f09_f09_mg17.FCts2nudged.derecho_intel.cam-outfrq9s_leapday + DIFF SMS_D_Ln9.f09_f09_mg17.FCvbsxHIST.derecho_intel.cam-outfrq9s + DIFF SMS_D_Ln9.f19_f19_mg17.FWma2000climo.derecho_intel.cam-outfrq9s + DIFF SMS_D_Ln9.f19_f19_mg17.FWma2000climo.derecho_intel.cam-outfrq9s_waccm_ma_mam4 + DIFF SMS_D_Ln9.f19_f19_mg17.QPC2000climo.derecho_intel.cam-outfrq3s_usecase + DIFF SMS_D_Ln9.ne16_ne16_mg17.QPX2000.derecho_intel.cam-outfrq9s + DIFF SMS_D_Ln9.ne16pg3_ne16pg3_mg17.FX2000.derecho_intel.cam-outfrq9s + DIFF SMS_Ld1.f09_f09_mg17.FW2000climo.derecho_intel.cam-outfrq1d + DIFF SMS_Ld1.ne30pg3_ne30pg3_mg17.FC2010climo.derecho_intel.cam-outfrq1d + DIFF SMS_Ln9.f09_f09_mg17.FW1850.derecho_intel.cam-reduced_hist3s + DIFF SMS_Ln9.ne30pg3_ne30pg3_mg17.FW2000climo.derecho_intel.cam-outfrq9s_rrtmgp + - expected differences in AOA history fields, otherwise bit-for-bit unchanged + +derecho/nvhpc/aux_cam: All PASS + +izumi/nag/aux_cam: + FAIL DAE.f45_f45_mg37.FHS94.izumi_nag.cam-dae + - pre-existing failure -- issue #670 + + DIFF ERC_D_Ln9.f10_f10_mg37.QPWmaC6.izumi_nag.cam-outfrq3s + DIFF SMS_D_Ln3.ne5pg3_ne5pg3_mg37.QPX2000.izumi_nag.cam-outfrq3s + DIFF SMS_D_Ln6.ne5_ne5_mg37.QPWmaC4.izumi_nag.cam-outfrq3s_physgrid_tem + - expected differences in AOA history fields, otherwise bit-for-bit unchanged + +izumi/gnu/aux_cam: + DIFF ERP_Ln9_P24x2.f45_f45_mg37.QPWmaC6.izumi_gnu.cam-outfrq9s_mee_fluxes + DIFF SMS_D_Ln9.f10_f10_mg37.QPWmaC4.izumi_gnu.cam-outfrq9s_apmee + DIFF SMS_P48x1_D_Ln9.f19_f19_mg17.FW4madSD.izumi_gnu.cam-outfrq9s + - expected differences in AOA history fields, otherwise bit-for-bit unchanged + +Summarize any changes to answers: + Differences in AOA history fields, otherwise bit-for-bit unchanged + +=============================================================== +=============================================================== + +Tag name: cam6_4_050 +Originator(s): jimmielin +Date: 31 Dec 2024 +One-line Summary: Implement CCPPized check_energy_chng and check_energy_fix +Github PR URL: https://github.com/ESCOMP/CAM/pull/1180 + +Purpose of changes (include the issue number and title text for each relevant GitHub issue): +- CCPPize check_energy_chng and check_energy_fix (https://github.com/ESCOMP/CAM/issues/1138) + CAM interfaces have been kept in check_energy.F90 instead of a new module because check_tracers is not yet CCPPized, there are other non-CCPPized routines in module, and for compatibility with FV3 external calls +- Save air_composition cp_or_cv_dycore into state snapshot +- Separate out "energy_formula_physics"/"energy_formula_dycore" definitions used in get_hydrostatic_energy from dyn_tests_utils "vcoord" for an eventual change in SIMA. + +Describe any changes made to build system: N/A + +Describe any changes made to the namelist: N/A + +List any changes to the defaults for the boundary datasets: N/A + +Describe any substantial timing or memory changes: N/A + +Code reviewed by: nusbaume, cacraigucar + +List all files eliminated: N/A + +List all files added and what they do: +- separate out energy formula definitions used in get_hydrostatic_energy from dyn_tests_utils "vcoord" +A src/utils/cam_thermo_formula.F90 + +List all existing files that have been modified, and describe the changes: + +Update atmos_phys external with CCPPized check_energy +M .gitmodules +M bld/configure +M src/atmos_phys + +Save cp_or_cv_dycore in state snapshot +M src/control/cam_snapshot_common.F90 + +New CAM interfaces to CCPPized routines, when available +M src/physics/cam/check_energy.F90 + +Update calls to CCPPized routines, when available +M src/physics/cam/physpkg.F90 +M src/physics/cam/zm_conv_intr.F90 +M src/physics/cam7/physpkg.F90 +M src/physics/simple/physpkg.F90 +M src/physics/spcam/crm_physics.F90 +M src/physics/spcam/spcam_drivers.F90 + +If there were any failures reported from running test_driver.sh on any test +platform, and checkin with these failures has been OK'd by the gatekeeper, +then copy the lines from the td.*.status files for the failed tests to the +appropriate machine below. All failed tests must be justified. + +derecho/intel/aux_cam: + +SMS_D_Ln9.f19_f19_mg17.FXHIST.derecho_intel.cam-outfrq9s_amie (Overall: FAIL) +SMS_D_Ln9_P1280x1.ne0CONUSne30x8_ne0CONUSne30x8_mt12.FCHIST.derecho_intel.cam-outfrq9s (Overall: FAIL) + - pre-existing failures due to build-namelist error requiring CLM/CTSM external update. + +ERP_Ln9.f09_f09_mg17.FCSD_HCO.derecho_intel.cam-outfrq9s (Overall: FAIL) +SMS_Ld1.f09_f09_mg17.FCHIST_GC.derecho_intel.cam-outfrq1d (Overall: PASS) + - pre-existing failure due to HEMCO not having reproducible results issues #1018 and #856 + +derecho/nvhpc/aux_cam: All PASS + +izumi/nag/aux_cam: + +DAE.f45_f45_mg37.FHS94.izumi_nag.cam-dae (Overall: FAIL) + - pre-existing failure -- issue #670 + +izumi/gnu/aux_cam: All PASS + +Summarize any changes to answers: B4B + +=============================================================== + +Tag name: cam6_4_049 +Originator(s): peverwhee +Date: 30 December 2024 +One-line Summary: History bugfixes +Github PR URL: https://github.com/ESCOMP/CAM/pull/1163 + +Purpose of changes (include the issue number and title text for each relevant GitHub issue): +- Issue #1149: cam history always chooses first averaging flag when using duplicate fields +- Issue #1150: CAM history erroneously overrides averaging flags for nhtfrq=1 +- Issue #1166: time_bounds array should not be present in history files containing instantaneous output +- Issue #1167: Time shown in history file names is incorrect for instantaneous data +- Issue #1183: Suggested improvement for openfile +- Update git-fleximod to v0.9.3 +- Update archive_baseline.sh modify read permissions on izumi +- Update CIME tag to cime6.1.56 to fix restart issue in CAM + +Describe any changes made to build system: +M bld/namelist_files/use_cases/sd_waccm_sulfur.xml + - Remove bad XML comment line + +Describe any changes made to the namelist: none + +List any changes to the defaults for the boundary datasets: none + +Describe any substantial timing or memory changes: none + +Code reviewed by: brian-eaton + +List all files eliminated: none + +List all files added and what they do: none + +List all existing files that have been modified, and describe the changes: + +M .gitmodules + - update CIME tag to cime6.1.56 + +M .lib/git-fleximod/* + - updates to move git-fleximod to v0.9.3 + +M src/control/cam_history.F90 + - remove nhtfrq=1 accumulation flag override if sampled_on_subcyle=.true. + - modify list_index routine to optionally check for duplicates/compatibility + - endrun with message including all duplicates found (if flags differ) + - remove time_bounds from instantaneous history files + - override instantaneous file name for monthly files to include full timestep + - also report correct timestamp on inst. files (don't use prev timestamp as + in accumulated files) + +M src/control/cam_history_support.F90 + - add sampled_on_subcycle to field_info object + +M src/physics/cam/cam_diagnostics.F90 +M src/physics/cam/clubb_intr.F90 +M src/physics/cam/hetfrz_classnuc_cam.F90 +M src/physics/cam/macrop_driver.F90 +M src/physics/cam/micro_pumas_cam.F90 +M src/physics/cam/microp_aero.F90 +M src/physics/cam/ndrop.F90 +M src/physics/cam/ndrop_bam.F90 +M src/physics/cam/nucleate_ice_cam.F90 +M src/physics/cam/subcol_SILHS.F90 +M src/physics/cam7/micro_pumas_cam.F90 +M src/physics/cam7/stochastic_emulated_cam.F90 +M src/physics/cam7/stochastic_tau_cam.F90 + - add sampled_on_subcycle=.true. argument to addflds calls for history fields + that are outfld-ed in the macmic loop + +M src/utils/cam_pio_utils.F90 + - move filename logging to before pio call + +M test/system/archive_baseline.sh + - make all baseline files globally readable on izumi + +If there were any failures reported from running test_driver.sh on any test +platform, and checkin with these failures has been OK'd by the gatekeeper, +then copy the lines from the td.*.status files for the failed tests to the +appropriate machine below. All failed tests must be justified. + +derecho/intel/aux_cam: + +ERC_D_Ln9.f19_f19_mg17.QPC6.derecho_intel.cam-outfrq3s_cosp (Overall: DIFF) +ERC_D_Ln9.f19_f19_mg17.QPMOZ.derecho_intel.cam-outfrq3s (Overall: DIFF) +ERC_D_Ln9.f19_f19_mg17.QPX2000.derecho_intel.cam-outfrq3s (Overall: DIFF) +ERC_D_Ln9.ne16_ne16_mg17.FADIAB.derecho_intel.cam-terminator (Overall: DIFF) +ERC_D_Ln9.ne16_ne16_mg17.QPC5HIST.derecho_intel.cam-outfrq3s_usecase (Overall: DIFF) +ERC_D_Ln9_P144x1.ne16pg3_ne16pg3_mg17.QPC6HIST.derecho_intel.cam-outfrq3s_ttrac_usecase (Overall: DIFF) +ERC_D_Ln9.T42_T42_mg17.FDABIP04.derecho_intel.cam-outfrq3s_usecase (Overall: DIFF) +ERC_D_Ln9.T42_T42_mg17.FHS94.derecho_intel.cam-outfrq3s_usecase (Overall: DIFF) +ERI_D_Ln18.f45_f45_mg37.QPC41850.derecho_intel.cam-co2rmp_usecase (Overall: DIFF) +ERP_D_Ln9.f19_f19_mg17.QPC6.derecho_intel.cam-outfrq9s (Overall: DIFF) +ERP_D_Ln9.ne30pg3_ne30pg3_mg17.FLTHIST.derecho_intel.cam-outfrq9s (Overall: DIFF) +ERP_D_Ln9_P64x2.f09_f09_mg17.QSC6.derecho_intel.cam-outfrq9s (Overall: DIFF) +ERP_Ld3.f09_f09_mg17.FWHIST.derecho_intel.cam-reduced_hist1d (Overall: DIFF) +ERP_Ld3.ne30pg3_ne30pg3_mg17.FHISTC_MTt4s.derecho_intel.cam-outfrq1d_aoa (Overall: DIFF) +ERP_Lh12.f19_f19_mg17.FW4madSD.derecho_intel.cam-outfrq3h (Overall: DIFF) +ERP_Ln9.C96_C96_mg17.F2000climo.derecho_intel.cam-outfrq9s_mg3 (Overall: DIFF) +ERP_Ln9.f09_f09_mg17.F1850.derecho_intel.cam-outfrq9s (Overall: DIFF) +ERP_Ln9.f09_f09_mg17.F2000climo.derecho_intel.cam-outfrq9s (Overall: DIFF) +ERP_Ln9.f09_f09_mg17.F2010climo.derecho_intel.cam-outfrq9s (Overall: DIFF) +ERP_Ln9.f09_f09_mg17.FHIST_BDRD.derecho_intel.cam-outfrq9s (Overall: DIFF) +ERP_Ln9.f19_f19_mg17.FWsc1850.derecho_intel.cam-outfrq9s (Overall: DIFF) +ERP_Ln9.ne30pg3_ne30pg3_mg17.FCnudged.derecho_intel.cam-outfrq9s (Overall: DIFF) +ERP_Ln9.ne30pg3_ne30pg3_mg17.FW2000climo.derecho_intel.cam-outfrq9s (Overall: DIFF) +ERS_Ln9.f09_f09_mg17.FX2000.derecho_intel.cam-outfrq9s (Overall: DIFF) +ERS_Ln9.f19_f19_mg17.FSPCAMS.derecho_intel.cam-outfrq9s (Overall: DIFF) +ERS_Ln9.f19_f19_mg17.FXSD.derecho_intel.cam-outfrq9s (Overall: DIFF) +ERS_Ln9.ne0TESTONLYne5x4_ne0TESTONLYne5x4_mg37.FADIAB.derecho_intel.cam-outfrq3s_refined (Overall: DIFF) +ERS_Ln9_P288x1.mpasa120_mpasa120.F2000climo.derecho_intel.cam-outfrq9s_mpasa120 (Overall: DIFF) +SCT_D_Ln7.ne3_ne3_mg37.QPC5.derecho_intel.cam-scm_prep (Overall: DIFF) +SCT_D_Ln7.T42_T42_mg17.QPC5.derecho_intel.cam-scm_prep (Overall: DIFF) +SMS_D_Ld2.f19_f19_mg17.QPC5HIST.derecho_intel.cam-volc_usecase (Overall: DIFF) +SMS_D_Ld5.f19_f19_mg17.PC4.derecho_intel.cam-cam4_port5d (Overall: DIFF) +SMS_D_Ln9.f09_f09_mg17.FCts2nudged.derecho_intel.cam-outfrq9s_leapday (Overall: DIFF) +SMS_D_Ln9.f09_f09_mg17.FCvbsxHIST.derecho_intel.cam-outfrq9s (Overall: DIFF) +SMS_D_Ln9.f09_f09_mg17.FSD.derecho_intel.cam-outfrq9s (Overall: DIFF) +SMS_D_Ln9.f19_f19_mg17.FWma2000climo.derecho_intel.cam-outfrq9s (Overall: DIFF) +SMS_D_Ln9.f19_f19_mg17.FWma2000climo.derecho_intel.cam-outfrq9s_waccm_ma_mam4 (Overall: DIFF) +SMS_D_Ln9.f19_f19_mg17.QPC2000climo.derecho_intel.cam-outfrq3s_usecase (Overall: DIFF) +SMS_D_Ln9.f19_f19_mg17.QPC5M7.derecho_intel.cam-outfrq9s (Overall: DIFF) +SMS_D_Ln9.ne16_ne16_mg17.QPX2000.derecho_intel.cam-outfrq9s (Overall: DIFF) +SMS_D_Ln9.ne16pg3_ne16pg3_mg17.FX2000.derecho_intel.cam-outfrq9s (Overall: DIFF) +SMS_D_Ln9.ne30pg3_ne30pg3_mg17.FMTHIST.derecho_intel.cam-outfrq9s (Overall: DIFF) +SMS_D_Ln9_P1280x1.ne0ARCTICne30x4_ne0ARCTICne30x4_mt12.FHIST.derecho_intel.cam-outfrq9s (Overall: DIFF) +SMS_D_Ln9_P1280x1.ne30pg3_ne30pg3_mg17.FHISTC_MTt1s.derecho_intel.cam-outfrq9s_Leung_dust (Overall: DIFF) +SMS_D_Ln9.T42_T42.FSCAMARM97.derecho_intel.cam-outfrq9s (Overall: DIFF) +SMS_Ld1.f09_f09_mg17.FCHIST_GC.derecho_intel.cam-outfrq1d (Overall: DIFF) +SMS_Ld1.f09_f09_mg17.FW2000climo.derecho_intel.cam-outfrq1d (Overall: DIFF) +SMS_Ld1.ne30pg3_ne30pg3_mg17.FC2010climo.derecho_intel.cam-outfrq1d (Overall: DIFF) +SMS_Ld5.f09_f09_mg17.PC6.derecho_intel.cam-cam6_port_f09 (Overall: DIFF) +SMS_Lh12.f09_f09_mg17.FCSD_HCO.derecho_intel.cam-outfrq3h (Overall: DIFF) +SMS_Ln9.f09_f09_mg17.F2010climo.derecho_intel.cam-nudging (Overall: DIFF) +SMS_Ln9.f09_f09_mg17.FW1850.derecho_intel.cam-reduced_hist3s (Overall: DIFF) +SMS_Ln9.f19_f19.F2000climo.derecho_intel.cam-silhs (Overall: DIFF) details: +SMS_Ln9.f19_f19_mg17.FHIST.derecho_intel.cam-outfrq9s_nochem (Overall: DIFF) +SMS_Ln9.ne30pg3_ne30pg3_mg17.FW2000climo.derecho_intel.cam-outfrq9s_rrtmgp (Overall: DIFF) + - fieldlist differences due to removal of time_bounds field from instantaneous file + +SMS_D_Ln9.f19_f19_mg17.FXHIST.derecho_intel.cam-outfrq9s_amie (Overall: FAIL) +SMS_D_Ln9_P1280x1.ne0CONUSne30x8_ne0CONUSne30x8_mt12.FCHIST.derecho_intel.cam-outfrq9s (Overall: FAIL) + - pre-existing failures due to build-namelist error requiring CLM/CTSM external update. + +ERP_Ln9.f09_f09_mg17.FCSD_HCO.derecho_intel.cam-outfrq9s (Overall: FAIL) +SMS_Ld1.f09_f09_mg17.FCHIST_GC.derecho_intel.cam-outfrq1d (Overall: DIFF) + - pre-existing failure due to HEMCO not having reproducible results issues #1018 and #856 + +derecho/nvhpc/aux_cam: + +ERS_Ln9.ne30pg3_ne30pg3_mg17.F2000dev.derecho_nvhpc.cam-outfrq9s_gpu_default (Overall: DIFF) + - fieldlist differences due to removal of time_bounds field from instantaneous file + +izumi/nag/aux_cam: + +ERC_D_Ln9.f10_f10_mg37.QPC5.izumi_nag.cam-carma_sea_salt (Overall: DIFF) details: +ERC_D_Ln9.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s_cosp (Overall: DIFF) details: +ERC_D_Ln9.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s_subcol (Overall: DIFF) details: +ERC_D_Ln9.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s_am (Overall: DIFF) details: +ERC_D_Ln9.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s_cospsathist (Overall: DIFF) details: +ERC_D_Ln9.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s (Overall: DIFF) details: +ERC_D_Ln9.f10_f10_mg37.QPWmaC6.izumi_nag.cam-outfrq3s (Overall: DIFF) details: +ERC_D_Ln9.f10_f10_mg37.QSPCAMS.izumi_nag.cam-outfrq3s (Overall: DIFF) details: +ERC_D_Ln9.mpasa480z32_mpasa480.FHS94.izumi_nag.cam-outfrq3s_usecase (Overall: DIFF) details: +ERC_D_Ln9.ne16_ne16_mg17.QPC4.izumi_nag.cam-outfrq3s_usecase (Overall: DIFF) details: +ERC_D_Ln9.ne16pg3_ne16pg3_mg17.QPC4.izumi_nag.cam-outfrq3s_usecase (Overall: DIFF) details: +ERC_D_Ln9.ne5_ne5_mg37.QPC5.izumi_nag.cam-outfrq3s_ttrac (Overall: DIFF) details: +ERC_D_Ln9.T5_T5_mg37.QPC4.izumi_nag.cam-outfrq3s_usecase (Overall: DIFF) details: +ERI_D_Ln18.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s_eoyttrac (Overall: DIFF) details: +ERI_D_Ln18.f19_f19_mg17.QPC6.izumi_nag.cam-ghgrmp_e8 (Overall: DIFF) details: +ERI_D_Ln18.ne5_ne5_mg37.FADIAB.izumi_nag.cam-outfrq3s_bwic (Overall: DIFF) details: +ERI_D_Ln18.ne5pg3_ne5pg3_mg37.FADIAB.izumi_nag.cam-outfrq3s_bwic (Overall: DIFF) details: +ERP_Ln9.ne5pg3_ne5pg3_mg37.QPC6.izumi_nag.cam-outfrq9s_clubbmf (Overall: DIFF) details: +ERS_Ln27.ne5pg3_ne5pg3_mg37.FKESSLER.izumi_nag.cam-outfrq9s (Overall: DIFF) details: +ERS_Ln9.ne5_ne5_mg37.FADIAB.izumi_nag.cam-outfrq9s (Overall: DIFF) details: +PEM_D_Ln9.ne5_ne5_mg37.FADIAB.izumi_nag.cam-outfrq3s (Overall: DIFF) details: +PLB_D_Ln9.f10_f10_mg37.QPC5.izumi_nag.cam-ttrac_loadbal0 (Overall: DIFF) details: +PLB_D_Ln9.f10_f10_mg37.QPC5.izumi_nag.cam-ttrac_loadbal1 (Overall: DIFF) details: +PLB_D_Ln9.f10_f10_mg37.QPC5.izumi_nag.cam-ttrac_loadbal3 (Overall: DIFF) details: +PLB_D_Ln9.ne5_ne5_mg37.QPC5.izumi_nag.cam-ttrac_loadbal0 (Overall: DIFF) details: +PLB_D_Ln9.ne5_ne5_mg37.QPC5.izumi_nag.cam-ttrac_loadbal1 (Overall: DIFF) details: +PLB_D_Ln9.ne5_ne5_mg37.QPC5.izumi_nag.cam-ttrac_loadbal3 (Overall: DIFF) details: +SMS_D_Ld2.f45_f45_mg37.PC5.izumi_nag.cam-outfrq24h_port (Overall: DIFF) details: +SMS_D_Ln3.ne5pg3_ne5pg3_mg37.QPX2000.izumi_nag.cam-outfrq3s (Overall: DIFF) details: +SMS_D_Ln6.ne5_ne5_mg37.QPWmaC4.izumi_nag.cam-outfrq3s_physgrid_tem (Overall: DIFF) details: +SMS_D_Ln7.T42_T42_mg17.QPSCAMC5.izumi_nag.cam-scmarm (Overall: DIFF) details: +SMS_D_Ln9.f10_f10_mg37.QPC5.izumi_nag.cam-rad_diag_mam (Overall: DIFF) details: +SMS_D_Ln9.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s_ba (Overall: DIFF) details: +SMS_D_Ln9_P1x1.ne5_ne5_mg37.FADIAB.izumi_nag.cam-outfrq3s (Overall: DIFF) details: +SMS_P48x1_D_Ln3.f09_f09_mg17.QPC6HIST.izumi_nag.cam-outfrq3s_co2cycle_usecase (Overall: DIFF) details: +SUB_D_Ln9.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s (Overall: DIFF) details: +TMC_D.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s_eoyttrac (Overall: DIFF) details: +TMC_D.T5_T5_mg37.QPC5.izumi_nag.cam-ghgrmp_e8 (Overall: DIFF) details: + - fieldlist differences due to removal of time_bounds field from instantaneous file + +DAE.f45_f45_mg37.FHS94.izumi_nag.cam-dae (Overall: FAIL) + - pre-existing failure -- issue #670 + +izumi/gnu/aux_cam: + +ERC_D_Ln9.f10_f10_mg37.FADIAB.izumi_gnu.cam-terminator (Overall: DIFF) details: +ERC_D_Ln9.f10_f10_mg37.QPC4.izumi_gnu.cam-outfrq3s_diags (Overall: DIFF) details: +ERC_D_Ln9.f10_f10_mg37.QPC5.izumi_gnu.cam-outfrq3s_unicon (Overall: DIFF) details: +ERC_D_Ln9.f10_f10_mg37.QPC5.izumi_gnu.cam-rad_diag (Overall: DIFF) details: +ERC_D_Ln9.f10_f10_mg37.QPSPCAMM.izumi_gnu.cam-outfrq3s (Overall: DIFF) details: +ERC_D_Ln9.ne5_ne5_mg37.QPC4.izumi_gnu.cam-outfrq3s_nudging_ne5_L26 (Overall: DIFF) details: +ERC_D_Ln9.ne5_ne5_mg37.QPC5.izumi_gnu.cam-outfrq3s_ba (Overall: DIFF) details: +ERC_D_Ln9.ne5pg2_ne5pg2_mg37.FADIAB.izumi_gnu.cam-outfrq3s (Overall: DIFF) details: +ERC_D_Ln9.ne5pg3_ne5pg3_mg37.FADIAB.izumi_gnu.cam-outfrq3s (Overall: DIFF) details: +ERI_D_Ln18.T5_T5_mg37.QPC4.izumi_gnu.cam-co2rmp (Overall: DIFF) details: +ERP_D_Ln9.C48_C48_mg17.QPC6.izumi_gnu.cam-outfrq9s (Overall: DIFF) details: +ERP_D_Ln9.ne3pg3_ne3pg3_mg37.FLTHIST.izumi_gnu.cam-outfrq9s (Overall: DIFF) details: +ERP_D_Ln9.ne3pg3_ne3pg3_mg37.QPC6.izumi_gnu.cam-outfrq9s_rrtmgp (Overall: DIFF) details: +ERP_Ln9.ne5_ne5_mg37.FHS94.izumi_gnu.cam-outfrq9s (Overall: DIFF) details: +ERP_Ln9.ne5_ne5_mg37.QPC5.izumi_gnu.cam-outfrq9s (Overall: DIFF) details: +ERP_Ln9_P24x2.f45_f45_mg37.QPWmaC6.izumi_gnu.cam-outfrq9s_mee_fluxes (Overall: DIFF) details: +ERS_Ln9_P24x1.mpasa480_mpasa480.F2000climo.izumi_gnu.cam-outfrq9s_mpasa480 (Overall: DIFF) details: +PEM_D_Ln9.ne5pg3_ne5pg3_mg37.FADIAB.izumi_gnu.cam-outfrq3s (Overall: DIFF) details: +PLB_D_Ln9.ne5pg3_ne5pg3_mg37.QPC5.izumi_gnu.cam-ttrac_loadbal0 (Overall: DIFF) details: +PLB_D_Ln9.ne5pg3_ne5pg3_mg37.QPC5.izumi_gnu.cam-ttrac_loadbal1 (Overall: DIFF) details: +PLB_D_Ln9.ne5pg3_ne5pg3_mg37.QPC5.izumi_gnu.cam-ttrac_loadbal3 (Overall: DIFF) details: +SCT_D_Ln7.ne3_ne3_mg37.QPC6.izumi_gnu.cam-scm_prep_c6 (Overall: DIFF) details: +SCT_D_Ln7.T42_T42_mg17.QPC4.izumi_gnu.cam-scm_prep (Overall: DIFF) details: +SCT_D_Ln7.T42_T42_mg17.QPC6.izumi_gnu.cam-scm_prep_c6 (Overall: DIFF) details: +SMS_D_Ln3.f10_f10_mg37.QPMOZ.izumi_gnu.cam-outfrq3s_chemproc (Overall: DIFF) details: +SMS_D_Ln9.f10_f10_mg37.QPWmaC4.izumi_gnu.cam-outfrq9s_apmee (Overall: DIFF) details: +SMS_D_Ln9.ne5pg3_ne5pg3_mg37.QPC5.izumi_gnu.cam-outfrq3s_ttrac (Overall: DIFF) details: +SMS_Ld5.f09_f09_mg17.PC6.izumi_gnu.cam-cam6_port_f09_rrtmgp (Overall: DIFF) details: +SMS_P48x1_D_Ln9.f19_f19_mg17.FW4madSD.izumi_gnu.cam-outfrq9s (Overall: DIFF) details: + - fieldlist differences due to removal of time_bounds field from instantaneous file + +CAM tag used for the baseline comparison tests if different than previous +tag: + +Summarize any changes to answers: none + +=============================================================== + +>>>>>>> upstream/cam_development Tag name: cam6_4_048 Originator(s): jedwards4b, peverwhee Date: 20 December 2024 @@ -120,13 +998,85 @@ derecho/nvhpc/aux_cam: ERS_Ln9.ne30pg3_ne30pg3_mg17.F2000dev.derecho_nvhpc.cam-outfrq9s_gpu_default (Overall: DIFF) details: - Diffs due to updated CTSM external -izumi/nag/aux_cam: !!due to izumi being down and the desire to make a CESM alpha -tag, the izumi tests were not run!! this changelog entry will be updated once -the tests are run +izumi/nag/aux_cam: izumi tests run 12/21/2024 + +ERC_D_Ln9.f10_f10_mg37.QPC5.izumi_nag.cam-carma_sea_salt (Overall: NLFAIL) details: +ERC_D_Ln9.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s_cosp (Overall: NLFAIL) details: +ERC_D_Ln9.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s_subcol (Overall: NLFAIL) details: +ERC_D_Ln9.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s_am (Overall: NLFAIL) details: +ERC_D_Ln9.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s_cospsathist (Overall: NLFAIL) details: +ERC_D_Ln9.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s (Overall: NLFAIL) details: +ERC_D_Ln9.f10_f10_mg37.QPWmaC6.izumi_nag.cam-outfrq3s (Overall: NLFAIL) details: +ERC_D_Ln9.f10_f10_mg37.QSPCAMS.izumi_nag.cam-outfrq3s (Overall: NLFAIL) details: +ERC_D_Ln9.mpasa480z32_mpasa480.FHS94.izumi_nag.cam-outfrq3s_usecase (Overall: NLFAIL) details: +ERC_D_Ln9.ne16_ne16_mg17.QPC4.izumi_nag.cam-outfrq3s_usecase (Overall: NLFAIL) details: +ERC_D_Ln9.ne16pg3_ne16pg3_mg17.QPC4.izumi_nag.cam-outfrq3s_usecase (Overall: NLFAIL) details: +ERC_D_Ln9.ne5_ne5_mg37.QPC5.izumi_nag.cam-outfrq3s_ttrac (Overall: NLFAIL) details: +ERC_D_Ln9.T5_T5_mg37.QPC4.izumi_nag.cam-outfrq3s_usecase (Overall: NLFAIL) details: +ERI_D_Ln18.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s_eoyttrac (Overall: NLFAIL) details: +ERI_D_Ln18.f19_f19_mg17.QPC6.izumi_nag.cam-ghgrmp_e8 (Overall: NLFAIL) details: +ERI_D_Ln18.ne5_ne5_mg37.FADIAB.izumi_nag.cam-outfrq3s_bwic (Overall: NLFAIL) details: +ERI_D_Ln18.ne5pg3_ne5pg3_mg37.FADIAB.izumi_nag.cam-outfrq3s_bwic (Overall: NLFAIL) details: +ERP_Ln9.ne5pg3_ne5pg3_mg37.QPC6.izumi_nag.cam-outfrq9s_clubbmf (Overall: NLFAIL) details: +ERS_Ln27.ne5pg3_ne5pg3_mg37.FKESSLER.izumi_nag.cam-outfrq9s (Overall: NLFAIL) details: +ERS_Ln9.ne5_ne5_mg37.FADIAB.izumi_nag.cam-outfrq9s (Overall: NLFAIL) details: +PEM_D_Ln9.ne5_ne5_mg37.FADIAB.izumi_nag.cam-outfrq3s (Overall: NLFAIL) details: +PLB_D_Ln9.f10_f10_mg37.QPC5.izumi_nag.cam-ttrac_loadbal0 (Overall: NLFAIL) details: +PLB_D_Ln9.f10_f10_mg37.QPC5.izumi_nag.cam-ttrac_loadbal1 (Overall: NLFAIL) details: +PLB_D_Ln9.f10_f10_mg37.QPC5.izumi_nag.cam-ttrac_loadbal3 (Overall: NLFAIL) details: +PLB_D_Ln9.ne5_ne5_mg37.QPC5.izumi_nag.cam-ttrac_loadbal0 (Overall: NLFAIL) details: +PLB_D_Ln9.ne5_ne5_mg37.QPC5.izumi_nag.cam-ttrac_loadbal1 (Overall: NLFAIL) details: +PLB_D_Ln9.ne5_ne5_mg37.QPC5.izumi_nag.cam-ttrac_loadbal3 (Overall: NLFAIL) details: +SMS_D_Ld2.f45_f45_mg37.PC5.izumi_nag.cam-outfrq24h_port (Overall: NLFAIL) details: +SMS_D_Ln3.ne5pg3_ne5pg3_mg37.QPX2000.izumi_nag.cam-outfrq3s (Overall: NLFAIL) details: +SMS_D_Ln6.ne5_ne5_mg37.QPWmaC4.izumi_nag.cam-outfrq3s_physgrid_tem (Overall: NLFAIL) details: +SMS_D_Ln7.T42_T42_mg17.QPSCAMC5.izumi_nag.cam-scmarm (Overall: NLFAIL) details: +SMS_D_Ln9.f10_f10_mg37.QPC5.izumi_nag.cam-rad_diag_mam (Overall: NLFAIL) details: +SMS_D_Ln9.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s_ba (Overall: NLFAIL) details: +MS_D_Ln9_P1x1.ne5_ne5_mg37.FADIAB.izumi_nag.cam-outfrq3s (Overall: NLFAIL) details: +SMS_P48x1_D_Ln3.f09_f09_mg17.QPC6HIST.izumi_nag.cam-outfrq3s_co2cycle_usecase (Overall: NLFAIL) details: +SUB_D_Ln9.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s (Overall: NLFAIL) details: +TMC_D.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s_eoyttrac (Overall: NLFAIL) details: +TMC_D.T5_T5_mg37.QPC5.izumi_nag.cam-ghgrmp_e8 (Overall: NLFAIL) details: + - NL diffs due to CMEPS & CTSM external updates + +DAE.f45_f45_mg37.FHS94.izumi_nag.cam-dae (Overall: FAIL) + - pre-existing failure -- issue #670 + +izumi/gnu/aux_cam: izumi tests run 12/21/2024 + +ERC_D_Ln9.f10_f10_mg37.FADIAB.izumi_gnu.cam-terminator (Overall: NLFAIL) details: +ERC_D_Ln9.f10_f10_mg37.QPC4.izumi_gnu.cam-outfrq3s_diags (Overall: NLFAIL) details: +ERC_D_Ln9.f10_f10_mg37.QPC5.izumi_gnu.cam-outfrq3s_unicon (Overall: NLFAIL) details: +ERC_D_Ln9.f10_f10_mg37.QPC5.izumi_gnu.cam-rad_diag (Overall: NLFAIL) details: +ERC_D_Ln9.f10_f10_mg37.QPSPCAMM.izumi_gnu.cam-outfrq3s (Overall: NLFAIL) details: +ERC_D_Ln9.ne5_ne5_mg37.QPC4.izumi_gnu.cam-outfrq3s_nudging_ne5_L26 (Overall: NLFAIL) details: +ERC_D_Ln9.ne5_ne5_mg37.QPC5.izumi_gnu.cam-outfrq3s_ba (Overall: NLFAIL) details: +ERC_D_Ln9.ne5pg2_ne5pg2_mg37.FADIAB.izumi_gnu.cam-outfrq3s (Overall: NLFAIL) details: +ERC_D_Ln9.ne5pg3_ne5pg3_mg37.FADIAB.izumi_gnu.cam-outfrq3s (Overall: NLFAIL) details: +ERI_D_Ln18.T5_T5_mg37.QPC4.izumi_gnu.cam-co2rmp (Overall: NLFAIL) details: +ERP_D_Ln9.C48_C48_mg17.QPC6.izumi_gnu.cam-outfrq9s (Overall: NLFAIL) details: +ERP_D_Ln9.ne3pg3_ne3pg3_mg37.QPC6.izumi_gnu.cam-outfrq9s_rrtmgp (Overall: NLFAIL) details: +ERP_Ln9.ne5_ne5_mg37.FHS94.izumi_gnu.cam-outfrq9s (Overall: NLFAIL) details: +ERP_Ln9.ne5_ne5_mg37.QPC5.izumi_gnu.cam-outfrq9s (Overall: NLFAIL) details: +ERP_Ln9_P24x2.f45_f45_mg37.QPWmaC6.izumi_gnu.cam-outfrq9s_mee_fluxes (Overall: NLFAIL) details: +PEM_D_Ln9.ne5pg3_ne5pg3_mg37.FADIAB.izumi_gnu.cam-outfrq3s (Overall: NLFAIL) details: +PLB_D_Ln9.ne5pg3_ne5pg3_mg37.QPC5.izumi_gnu.cam-ttrac_loadbal0 (Overall: NLFAIL) details: +PLB_D_Ln9.ne5pg3_ne5pg3_mg37.QPC5.izumi_gnu.cam-ttrac_loadbal1 (Overall: NLFAIL) details: +PLB_D_Ln9.ne5pg3_ne5pg3_mg37.QPC5.izumi_gnu.cam-ttrac_loadbal3 (Overall: NLFAIL) details: +SCT_D_Ln7.ne3_ne3_mg37.QPC6.izumi_gnu.cam-scm_prep_c6 (Overall: NLFAIL) details: +SCT_D_Ln7.T42_T42_mg17.QPC4.izumi_gnu.cam-scm_prep (Overall: NLFAIL) details: +SCT_D_Ln7.T42_T42_mg17.QPC6.izumi_gnu.cam-scm_prep_c6 (Overall: NLFAIL) details: +SMS_D_Ln3.f10_f10_mg37.QPMOZ.izumi_gnu.cam-outfrq3s_chemproc (Overall: NLFAIL) details: +SMS_D_Ln9.f10_f10_mg37.QPWmaC4.izumi_gnu.cam-outfrq9s_apmee (Overall: NLFAIL) details: +SMS_D_Ln9.ne5pg3_ne5pg3_mg37.QPC5.izumi_gnu.cam-outfrq3s_ttrac (Overall: NLFAIL) details: +SMS_Ld5.f09_f09_mg17.PC6.izumi_gnu.cam-cam6_port_f09_rrtmgp (Overall: NLFAIL) details: + - NL diffs due to CMEPS & CTSM external updates -izumi/gnu/aux_cam: !!due to izumi being down and the desire to make a CESM alpha -tag, the izumi tests were not run!! this changelog entry will be updated once -the tests are run +ERP_D_Ln9.ne3pg3_ne3pg3_mg37.FLTHIST.izumi_gnu.cam-outfrq9s (Overall: DIFF) details: +ERS_Ln9_P24x1.mpasa480_mpasa480.F2000climo.izumi_gnu.cam-outfrq9s_mpasa480 (Overall: DIFF) details: +SMS_P48x1_D_Ln9.f19_f19_mg17.FW4madSD.izumi_gnu.cam-outfrq9s (Overall: DIFF) details: + - Diffs due to updated CTSM external CAM tag used for the baseline comparison tests if different than previous tag: diff --git a/src/atmos_phys b/src/atmos_phys index 67927f1511..c3de8468f7 160000 --- a/src/atmos_phys +++ b/src/atmos_phys @@ -1 +1 @@ -Subproject commit 67927f15113eb9c5d4a57f2276d67b8ad88c5149 +Subproject commit c3de8468f7b245a939448f4ca6d3ef386584e92d diff --git a/src/chemistry/mozart/mo_drydep.F90 b/src/chemistry/mozart/mo_drydep.F90 index 06b87797c4..12e1d3e0a9 100644 --- a/src/chemistry/mozart/mo_drydep.F90 +++ b/src/chemistry/mozart/mo_drydep.F90 @@ -520,11 +520,13 @@ subroutine get_landuse_and_soilw_from_file() logical :: lexist if (len_trim(drydep_srf_file) == 0) then - write(iulog,*)'**************************************' - write(iulog,*)' get_landuse_and_soilw_from_file: INFO:' - write(iulog,*)' drydep_srf_file not set:' - write(iulog,*)' setting fraction_landuse to zero' - write(iulog,*)'**************************************' + if (masterproc) then + write(iulog,*)'**************************************' + write(iulog,*)' get_landuse_and_soilw_from_file: INFO:' + write(iulog,*)' drydep_srf_file not set:' + write(iulog,*)' setting fraction_landuse to zero' + write(iulog,*)'**************************************' + end if fraction_landuse = 0._r8 return end if @@ -536,12 +538,14 @@ subroutine get_landuse_and_soilw_from_file() call infld('fraction_landuse', piofile, 'ncol','class',1,pcols,1,n_land_type, begchunk,endchunk, & fraction_landuse, readvar, gridname='physgrid') if (.not. readvar) then - write(iulog,*)'**************************************' - write(iulog,*)'get_landuse_and_soilw_from_file: INFO:' - write(iulog,*)' fraction_landuse not read from file: ' - write(iulog,*)' ', trim(locfn) - write(iulog,*)' setting all values to zero' - write(iulog,*)'**************************************' + if (masterproc) then + write(iulog,*)'**************************************' + write(iulog,*)'get_landuse_and_soilw_from_file: INFO:' + write(iulog,*)' fraction_landuse not read from file: ' + write(iulog,*)' ', trim(locfn) + write(iulog,*)' setting all values to zero' + write(iulog,*)'**************************************' + end if fraction_landuse = 0._r8 end if diff --git a/src/control/cam_history.F90 b/src/control/cam_history.F90 index 39222fc536..81659ec12a 100644 --- a/src/control/cam_history.F90 +++ b/src/control/cam_history.F90 @@ -309,6 +309,7 @@ module cam_history ! character(len=max_string_len) :: rhfilename_spec = '%c.cam.rh%t.%y-%m-%d-%s.nc' ! history restart character(len=max_string_len) :: hfilename_spec(ptapes) = (/ (' ', idx=1, ptapes) /) ! filename specifyer + logical :: default_monthly_filename(ptapes) = .false. ! Flag for if there are accumulated fields specified for a given tape logical :: hfile_accum(ptapes) = .false. @@ -486,10 +487,12 @@ subroutine intht (model_doi_url_in) ! do t=1,ptapes do fld=1,nflds(t) - if (nhtfrq(t) == 1) then - ! Override any non-I flags if nhtfrq equals 1 + if ((.not. tape(t)%hlist(fld)%field%sampled_on_subcycle) .and. nhtfrq(t) == 1) then + ! Override accumulate flag to "I" if nhtfrq equals 1 and subcycle + ! averaging is not enabled tape(t)%hlist(fld)%avgflag = 'I' end if + if (tape(t)%hlist(fld)%avgflag .ne. 'I') then hfile_accum(t) = .true. end if @@ -810,6 +813,7 @@ subroutine history_readnl(nlfile) if ( nhtfrq(t) == 0 )then ! Monthly files hfilename_spec(t) = '%c.cam' // trim(inst_suffix) // '.h%t%f.%y-%m.nc' + default_monthly_filename(t) = .true. else hfilename_spec(t) = '%c.cam' // trim(inst_suffix) // '.h%t%f.%y-%m-%d-%s.nc' end if @@ -878,6 +882,7 @@ subroutine history_readnl(nlfile) call mpi_bcast(write_nstep0,1, mpi_logical, masterprocid, mpicom, ierr) call mpi_bcast(avgflag_pertape, ptapes, mpi_character, masterprocid, mpicom, ierr) call mpi_bcast(hfilename_spec, len(hfilename_spec(1))*ptapes, mpi_character, masterprocid, mpicom, ierr) + call mpi_bcast(default_monthly_filename, ptapes, mpi_logical, masterprocid, mpicom, ierr) call mpi_bcast(fincl, len(fincl (1,1))*pflds*ptapes, mpi_character, masterprocid, mpicom, ierr) call mpi_bcast(fexcl, len(fexcl (1,1))*pflds*ptapes, mpi_character, masterprocid, mpicom, ierr) @@ -2556,6 +2561,7 @@ subroutine fldlst () use cam_grid_support, only: cam_grid_num_grids use spmd_utils, only: mpicom use dycore, only: dycore_is + use shr_kind_mod, only: cm => shr_kind_cm !----------------------------------------------------------------------- ! @@ -2571,6 +2577,8 @@ subroutine fldlst () integer t, fld ! tape, field indices integer ffld ! index into include, exclude and fprec list integer :: i + character(len=cm) :: duplicate_error ! string to be populated if an incompatible duplicate is found + character(len=cm) :: tempmsg ! string to be populated if an incompatible duplicate is found character(len=fieldname_len) :: name ! field name portion of fincl (i.e. no avgflag separator) character(len=max_fieldname_len) :: mastername ! name from masterlist field character(len=max_chars) :: errormsg ! error output field @@ -2733,6 +2741,7 @@ subroutine fldlst () allocate(gridsontape(cam_grid_num_grids() + 1, ptapes)) gridsontape = -1 + errormsg = '' do t=1,ptapes ! ! Add the field to the tape if specified via namelist (FINCL[1-ptapes]), or if @@ -2744,7 +2753,15 @@ subroutine fldlst () listentry => masterlinkedlist do while(associated(listentry)) mastername = listentry%field%name - call list_index (fincl(1,t), mastername, ffld) + call list_index (fincl(1,t), mastername, ffld, duplicate_error=duplicate_error) + if (len(trim(duplicate_error)) > 0) then + if (len_trim(errormsg) == 0) then + write(errormsg,*) & + 'FLDLST: Found duplicate field(s) with different averaging flags. Place in separate fincl lists: ' + end if + write(tempmsg, '(2a, i0, a)') trim(duplicate_error), ' (fincl', t, '). ' + errormsg = trim(errormsg) // trim(tempmsg) + end if fieldontape = .false. if (ffld > 0) then @@ -2756,7 +2773,7 @@ subroutine fldlst () end if end if if (fieldontape) then - ! The field is active so increment the number fo fields and add + ! The field is active so increment the number of fields and add ! its decomp type to the list of decomp types on this tape nflds(t) = nflds(t) + 1 do ffld = 1, size(gridsontape, 1) @@ -2771,6 +2788,9 @@ subroutine fldlst () listentry=>listentry%next_entry end do end do + if (len_trim(errormsg) > 0) then + call endrun(trim(errormsg)) + end if ! ! Determine total number of active history tapes ! @@ -2882,7 +2902,6 @@ subroutine fldlst () tape(t)%hlist(ffld+1) = tmp else if (tape(t)%hlist(ffld)%field%name == tape(t)%hlist(ffld+1)%field%name) then - write(errormsg,'(2a,2(a,i3))') 'FLDLST: Duplicate field: ', & trim(tape(t)%hlist(ffld)%field%name),', tape = ', t, ', ffld = ', ffld call endrun(errormsg) @@ -3502,12 +3521,13 @@ end function getflag !####################################################################### - subroutine list_index (list, name, index) + subroutine list_index (list, name, index, duplicate_error) ! ! Input arguments ! - character(len=*), intent(in) :: list(pflds) ! input list of names, possibly ":" delimited - character(len=max_fieldname_len), intent(in) :: name ! name to be searched for + character(len=*), intent(in) :: list(pflds) ! input list of names, possibly ":" delimited + character(len=*), intent(in) :: name ! name to be searched for + character(len=*), optional, intent(out) :: duplicate_error ! if present, check the flags and return an error if incompatible ! ! Output arguments ! @@ -3516,9 +3536,15 @@ subroutine list_index (list, name, index) ! Local workspace ! character(len=fieldname_len) :: listname ! input name with ":" stripped off. - integer f ! field index + character(len=fieldname_len) :: flag ! accumulate flag for field + character(len=fieldname_len) :: flag_comp ! accumulate flag to compare with previous entry + integer :: f ! field index index = 0 + if (present(duplicate_error)) then + duplicate_error = '' + end if + do f=1,pflds ! ! Only list items @@ -3526,8 +3552,21 @@ subroutine list_index (list, name, index) listname = getname (list(f)) if (listname == ' ') exit if (listname == name) then - index = f - exit + if (index /= 0 .and. present(duplicate_error)) then + ! This already exists in the field list - check the flag + flag_comp = getflag(list(f)) + if (trim(flag_comp) /= trim(flag)) then + write(duplicate_error,*) & + '"', trim(list(f)), '", "', trim(name), & + ':', trim(flag), '"' + return + ! No else - if the flags are identical, we're ok to return the first + ! instance + end if + else + index = f + flag = getflag(list(f)) + end if end if end do @@ -3992,7 +4031,9 @@ subroutine h_inquire (t) ierr=pio_inq_varid (tape(t)%Files(f),'nscur ', tape(t)%nscurid) ierr=pio_inq_varid (tape(t)%Files(f),'nsteph ', tape(t)%nstephid) end if - ierr=pio_inq_varid (tape(t)%Files(f),'time_bounds', tape(t)%tbndid) + if (f == accumulated_file_index) then + ierr=pio_inq_varid (tape(t)%Files(f),'time_bounds', tape(t)%tbndid) + end if ierr=pio_inq_varid (tape(t)%Files(f),'date_written', tape(t)%date_writtenid) ierr=pio_inq_varid (tape(t)%Files(f),'time_written', tape(t)%time_writtenid) #if ( defined BFB_CAM_SCAM_IOP ) @@ -4470,13 +4511,6 @@ subroutine h_define (t, restart) if(.not. is_satfile(t)) then - ierr=pio_put_att (tape(t)%Files(f), tape(t)%timeid, 'bounds', 'time_bounds') - - ierr=pio_def_var (tape(t)%Files(f),'time_bounds',pio_double,(/bnddim,timdim/),tape(t)%tbndid) - ierr=pio_put_att (tape(t)%Files(f), tape(t)%tbndid, 'long_name', 'time interval endpoints') - str = 'days since ' // date2yyyymmdd(nbdate) // ' ' // sec2hms(nbsec) - ierr=pio_put_att (tape(t)%Files(f), tape(t)%tbndid, 'units', trim(str)) - ierr=pio_put_att (tape(t)%Files(f), tape(t)%tbndid, 'calendar', trim(calendar)) ! ! Character ! @@ -4525,7 +4559,6 @@ subroutine h_define (t, restart) ierr=pio_put_att (tape(t)%Files(f), tape(t)%nscurid, 'long_name', trim(str)) end if - if (.not. is_initfile(file_index=t) .and. f == instantaneous_file_index) then ! Don't write the GHG/Solar forcing data to the IC file. ! Only write the GHG/Solar forcing data to the instantaneous file @@ -4628,6 +4661,13 @@ subroutine h_define (t, restart) ierr=pio_def_var (tape(t)%Files(f),'nsteph ',pio_int,(/timdim/),tape(t)%nstephid) str = 'current timestep' ierr=pio_put_att (tape(t)%Files(f), tape(t)%nstephid, 'long_name', trim(str)) + else if (f == accumulated_file_index) then + ierr=pio_def_var (tape(t)%Files(f),'time_bounds',pio_double,(/bnddim,timdim/),tape(t)%tbndid) + ierr=pio_put_att (tape(t)%Files(f), tape(t)%timeid, 'bounds', 'time_bounds') + ierr=pio_put_att (tape(t)%Files(f), tape(t)%tbndid, 'long_name', 'time interval endpoints') + str = 'days since ' // date2yyyymmdd(nbdate) // ' ' // sec2hms(nbsec) + ierr=pio_put_att (tape(t)%Files(f), tape(t)%tbndid, 'units', trim(str)) + ierr=pio_put_att (tape(t)%Files(f), tape(t)%tbndid, 'calendar', trim(calendar)) end if end if ! .not. is_satfile @@ -4991,6 +5031,7 @@ subroutine h_define (t, restart) deallocate(header_info) end if + ! Write the mdim variable data do f = 1, maxsplitfiles if (pio_file_is_open(tape(t)%Files(f))) then @@ -5575,6 +5616,7 @@ subroutine wshist (rgnht_in) character(len=max_string_len) :: fname ! Filename character(len=max_string_len) :: fname_inst ! Filename for instantaneous tape character(len=max_string_len) :: fname_acc ! Filename for accumulated tape + character(len=max_string_len) :: inst_filename_spec ! Filename specifier override for monthly inst. files logical :: prev ! Label file with previous date rather than current logical :: duplicate ! Flag for duplicate file name integer :: ierr @@ -5688,8 +5730,15 @@ subroutine wshist (rgnht_in) else fname_acc = interpret_filename_spec( hfilename_spec(t), number=(t-1), & prev=prev, flag_spec='a' ) - fname_inst = interpret_filename_spec( hfilename_spec(t), number=(t-1), & - prev=prev, flag_spec='i' ) + ! If this is a monthly instantaneous file, override to default timestamp + ! unless the user input a filename specifier + if (default_monthly_filename(t)) then + inst_filename_spec = '%c.cam' // trim(inst_suffix) // '.h%t%f.%y-%m-%d-%s.nc' + else + inst_filename_spec = hfilename_spec(t) + end if + fname_inst = interpret_filename_spec( inst_filename_spec, number=(t-1), & + flag_spec='i' ) end if ! ! Check that this new filename isn't the same as a previous or current filename @@ -5813,14 +5862,19 @@ subroutine wshist (rgnht_in) cycle end if ! We have two files - one for accumulated and one for instantaneous fields - if (f == accumulated_file_index .and. .not. restart .and. .not. is_initfile(t)) then - ! accumulated tape - time is midpoint of time_bounds - ierr=pio_put_var (tape(t)%Files(f), tape(t)%timeid, (/start/),(/count1/),(/(tdata(1) + tdata(2)) / 2._r8/)) + if (f == accumulated_file_index) then + if (.not. restart .and. .not. is_initfile(t)) then + ! accumulated tape - time is midpoint of time_bounds + ierr=pio_put_var (tape(t)%Files(f), tape(t)%timeid, (/start/),(/count1/),(/(tdata(1) + tdata(2)) / 2._r8/)) + else + ! restart or initfile - time is current time + ierr=pio_put_var (tape(t)%Files(f), tape(t)%timeid, (/start/),(/count1/),(/time/)) + end if + ierr=pio_put_var (tape(t)%Files(f), tape(t)%tbndid, startc, countc, tdata) else ! not an accumulated history tape - time is current time ierr=pio_put_var (tape(t)%Files(f), tape(t)%timeid, (/start/),(/count1/),(/time/)) end if - ierr=pio_put_var (tape(t)%Files(f), tape(t)%tbndid, startc, countc, tdata) end do if(.not.restart) beg_time(t) = time ! update beginning time of next interval startc(1) = 1 @@ -5908,7 +5962,7 @@ end subroutine wshist subroutine addfld_1d(fname, vdim_name, avgflag, units, long_name, & gridname, flag_xyfill, sampling_seq, standard_name, fill_value, & - optype, op_f1name, op_f2name) + optype, op_f1name, op_f2name, sampled_on_subcycle) ! !----------------------------------------------------------------------- @@ -5940,6 +5994,7 @@ subroutine addfld_1d(fname, vdim_name, avgflag, units, long_name, & character(len=*), intent(in), optional :: optype ! currently 'dif' or 'sum' is supported character(len=*), intent(in), optional :: op_f1name ! first field to be operated on character(len=*), intent(in), optional :: op_f2name ! second field which is subtracted from or added to first field + logical, intent(in), optional :: sampled_on_subcycle ! If .true., subcycle averaging is enabled ! ! Local workspace ! @@ -5958,13 +6013,13 @@ subroutine addfld_1d(fname, vdim_name, avgflag, units, long_name, & end if call addfld(fname, dimnames, avgflag, units, long_name, gridname, & flag_xyfill, sampling_seq, standard_name, fill_value, optype, op_f1name, & - op_f2name) + op_f2name, sampled_on_subcycle) end subroutine addfld_1d subroutine addfld_nd(fname, dimnames, avgflag, units, long_name, & gridname, flag_xyfill, sampling_seq, standard_name, fill_value, optype, & - op_f1name, op_f2name) + op_f1name, op_f2name, sampled_on_subcycle) ! !----------------------------------------------------------------------- @@ -6000,6 +6055,7 @@ subroutine addfld_nd(fname, dimnames, avgflag, units, long_name, & character(len=*), intent(in), optional :: optype ! currently 'dif' or 'sum' supported character(len=*), intent(in), optional :: op_f1name ! first field to be operated on character(len=*), intent(in), optional :: op_f2name ! second field which is subtracted from or added to first field + logical, intent(in), optional :: sampled_on_subcycle ! If .true., subcycle averaging is enabled ! ! Local workspace @@ -6124,6 +6180,15 @@ subroutine addfld_nd(fname, dimnames, avgflag, units, long_name, & listentry%field%fillvalue = fillvalue endif + ! + ! Whether to allow subcycle averages; default is false + ! + if (present(sampled_on_subcycle)) then + listentry%field%sampled_on_subcycle = sampled_on_subcycle + else + listentry%field%sampled_on_subcycle = .false. + end if + ! ! Process shape ! diff --git a/src/control/cam_history_support.F90 b/src/control/cam_history_support.F90 index 940dc8c177..5e5983e784 100644 --- a/src/control/cam_history_support.F90 +++ b/src/control/cam_history_support.F90 @@ -118,6 +118,9 @@ module cam_history_support integer :: meridional_complement ! meridional field id or -1 integer :: zonal_complement ! zonal field id or -1 + ! Logical to determine if subcycle averages are allowed + logical :: sampled_on_subcycle = .false. + character(len=field_op_len) :: field_op = '' ! 'sum' or 'dif' integer :: op_field1_id ! first field id or -1 integer :: op_field2_id ! second field id or -1 diff --git a/src/control/cam_snapshot_common.F90 b/src/control/cam_snapshot_common.F90 index ffae561370..0f49d27a02 100644 --- a/src/control/cam_snapshot_common.F90 +++ b/src/control/cam_snapshot_common.F90 @@ -81,7 +81,7 @@ module cam_snapshot_common integer :: cam_snapshot_before_num, cam_snapshot_after_num ! Note the maximum number of variables for each type -type (snapshot_type) :: state_snapshot(29) +type (snapshot_type) :: state_snapshot(30) type (snapshot_type) :: cnst_snapshot(pcnst) type (snapshot_type) :: tend_snapshot(6) type (snapshot_type) :: cam_in_snapshot(30) @@ -283,6 +283,9 @@ subroutine cam_state_snapshot_init(cam_snapshot_before_num_in, cam_snapshot_afte call snapshot_addfld( nstate_var, state_snapshot, cam_snapshot_before_num, cam_snapshot_after_num, & 'state%te_cur_dyn', 'state_te_cur_dyn', 'unset', horiz_only) + call snapshot_addfld( nstate_var, state_snapshot, cam_snapshot_before_num, cam_snapshot_after_num, & + 'air_composition_cp_or_cv_dycore', 'cp_or_cv_dycore', 'J kg-1 K-1', 'lev') + end subroutine cam_state_snapshot_init subroutine cam_cnst_snapshot_init(cam_snapshot_before_num, cam_snapshot_after_num) @@ -741,6 +744,7 @@ end subroutine snapshot_addfld subroutine state_snapshot_all_outfld(lchnk, file_num, state) use physics_types, only: phys_te_idx, dyn_te_idx + use air_composition, only: cp_or_cv_dycore integer, intent(in) :: lchnk integer, intent(in) :: file_num @@ -843,6 +847,11 @@ subroutine state_snapshot_all_outfld(lchnk, file_num, state) case ('state%te_cur_dyn') call outfld(state_snapshot(i)%standard_name, state%te_cur(:, dyn_te_idx), pcols, lchnk) + case ('air_composition_cp_or_cv_dycore') + ! this field is not part of physics state (it is in air_composition) + ! but describes the atmospheric thermodynamic state and thus saved within the snapshot + call outfld(state_snapshot(i)%standard_name, cp_or_cv_dycore(:,:,lchnk), pcols, lchnk) + case default call endrun('ERROR in state_snapshot_all_outfld: no match found for '//trim(state_snapshot(i)%ddt_string)) diff --git a/src/physics/cam/aoa_tracers.F90 b/src/physics/cam/aoa_tracers.F90 index f0c272b69d..2d42853756 100644 --- a/src/physics/cam/aoa_tracers.F90 +++ b/src/physics/cam/aoa_tracers.F90 @@ -31,13 +31,13 @@ module aoa_tracers integer, parameter :: ncnst=3 ! number of constituents implemented by this module ! constituent names - character(len=6), parameter :: c_names(ncnst) = (/'AOAMF ', 'HORZ ', 'VERT '/) + character(len=4), parameter :: c_names(ncnst) = (/'AOA1', 'HORZ', 'VERT'/) ! constituent source/sink names - character(len=8), parameter :: src_names(ncnst) = (/'AOAMFSRC', 'HORZSRC ', 'VERTSRC '/) + character(len=7), parameter :: src_names(ncnst) = (/'AOA1SRC', 'HORZSRC', 'VERTSRC'/) integer :: ifirst = -1 ! global index of first constituent - integer :: ixaoa = -1 ! global index for AOAMFSRC tracer + integer :: ixaoa = -1 ! global index for AOA1SRC tracer integer :: ixht = -1 ! global index for HORZ tracer integer :: ixvt = -1 ! global index for VERT tracer @@ -132,12 +132,12 @@ subroutine aoa_tracers_register if (.not. aoa_tracers_flag) return call cnst_add(c_names(1), mwdry, cpair, 0._r8, ixaoa, readiv=aoa_read_from_ic_file, & - longname='mixing ratio LB tracer') + longname='mixing ratio LB tracer', cam_outfld=.false.) call cnst_add(c_names(2), mwdry, cpair, 1._r8, ixht, readiv=aoa_read_from_ic_file, & - longname='horizontal tracer') + longname='horizontal tracer', cam_outfld=.false.) call cnst_add(c_names(3), mwdry, cpair, 0._r8, ixvt, readiv=aoa_read_from_ic_file, & - longname='vertical tracer') + longname='vertical tracer', cam_outfld=.false.) ifirst = ixaoa @@ -324,6 +324,8 @@ subroutine aoa_tracers_timestep_tend(state, ptend, dt) real(r8), parameter :: mmr0 = 1.0e-6_r8 ! initial lower boundary mmr real(r8), parameter :: per_yr = 0.02_r8 ! fractional increase per year + real(r8) :: mmr_out(pcols,pver,ncnst) + !------------------------------------------------------------------ teul = .5_r8*dt/(86400._r8 * treldays) ! 1/2 for the semi-implicit scheme if dt=time step @@ -345,7 +347,7 @@ subroutine aoa_tracers_timestep_tend(state, ptend, dt) lchnk = state%lchnk ncol = state%ncol - ! AOAMF + ! AOA1 xmmr = mmr0*(1._r8 + per_yr*years) ptend%q(1:ncol,pver,ixaoa) = (xmmr - state%q(1:ncol,pver,ixaoa)) / dt @@ -371,6 +373,15 @@ subroutine aoa_tracers_timestep_tend(state, ptend, dt) call outfld (src_names(2), ptend%q(:,:,ixht), pcols, lchnk) call outfld (src_names(3), ptend%q(:,:,ixvt), pcols, lchnk) + ! output mixing ratios to history + mmr_out(:ncol,:,1) = state%q(:ncol,:,ixaoa) + dt*ptend%q(1:ncol,:,ixaoa) + mmr_out(:ncol,:,2) = state%q(:ncol,:,ixht) + dt*ptend%q(1:ncol,:,ixht) + mmr_out(:ncol,:,3) = state%q(:ncol,:,ixvt) + dt*ptend%q(1:ncol,:,ixvt) + + call outfld (c_names(1), mmr_out(:,:,1), pcols, lchnk) + call outfld (c_names(2), mmr_out(:,:,2), pcols, lchnk) + call outfld (c_names(3), mmr_out(:,:,3), pcols, lchnk) + end subroutine aoa_tracers_timestep_tend !=========================================================================== @@ -392,7 +403,7 @@ subroutine init_cnst_3d(m, latvals, lonvals, mask, q) if (m == ixaoa) then - ! AOAMF + ! AOA1 q(:,:) = 0.0_r8 else if (m == ixht) then diff --git a/src/physics/cam/cam_diagnostics.F90 b/src/physics/cam/cam_diagnostics.F90 index 97dad2ba01..d7539fd9af 100644 --- a/src/physics/cam/cam_diagnostics.F90 +++ b/src/physics/cam/cam_diagnostics.F90 @@ -232,9 +232,9 @@ subroutine diag_init_dry(pbuf2d) call register_vector_field('UTEND_TOT','VTEND_TOT') ! Debugging negative water output fields - call addfld ('INEGCLPTEND ', (/ 'lev' /), 'A', 'kg/kg/s', 'Cloud ice tendency due to clipping neg values after microp') - call addfld ('LNEGCLPTEND ', (/ 'lev' /), 'A', 'kg/kg/s', 'Cloud liq tendency due to clipping neg values after microp') - call addfld ('VNEGCLPTEND ', (/ 'lev' /), 'A', 'kg/kg/s', 'Vapor tendency due to clipping neg values after microp') + call addfld ('INEGCLPTEND ', (/ 'lev' /), 'A', 'kg/kg/s', 'Cloud ice tendency due to clipping neg values after microp', sampled_on_subcycle=.true.) + call addfld ('LNEGCLPTEND ', (/ 'lev' /), 'A', 'kg/kg/s', 'Cloud liq tendency due to clipping neg values after microp', sampled_on_subcycle=.true.) + call addfld ('VNEGCLPTEND ', (/ 'lev' /), 'A', 'kg/kg/s', 'Vapor tendency due to clipping neg values after microp', sampled_on_subcycle=.true.) call addfld ('Z3', (/ 'lev' /), 'A', 'm', 'Geopotential Height (above sea level)') call addfld ('Z1000', horiz_only, 'A', 'm', 'Geopotential Z at 1000 mbar pressure surface') @@ -253,6 +253,7 @@ subroutine diag_init_dry(pbuf2d) call addfld ('OMEGAV', (/ 'lev' /), 'A', 'm Pa/s2 ', 'Vertical flux of meridional momentum' ) call addfld ('OMGAOMGA', (/ 'lev' /), 'A', 'Pa2/s2', 'Vertical flux of vertical momentum' ) + call addfld ('UT', (/ 'lev' /), 'A', 'K m/s ', 'Zonal heat transport') call addfld ('UU', (/ 'lev' /), 'A', 'm2/s2', 'Zonal velocity squared' ) call addfld ('WSPEED', (/ 'lev' /), 'X', 'm/s', 'Horizontal total wind speed maximum' ) call addfld ('WSPDSRFMX', horiz_only, 'X', 'm/s', 'Horizontal total wind speed maximum at surface layer midpoint' ) @@ -339,6 +340,7 @@ subroutine diag_init_dry(pbuf2d) call add_default ('VT ', 1, ' ') call add_default ('VU ', 1, ' ') call add_default ('VV ', 1, ' ') + call add_default ('UT ', 1, ' ') call add_default ('UU ', 1, ' ') call add_default ('OMEGAT ', 1, ' ') call add_default ('OMEGAU ', 1, ' ') @@ -438,6 +440,7 @@ subroutine diag_init_moist(pbuf2d) ! outfld calls in diag_phys_writeout call addfld ('OMEGAQ', (/ 'lev' /), 'A', 'kgPa/kgs', 'Vertical water transport' ) + call addfld ('UQ', (/ 'lev' /), 'A', 'm/skg/kg', 'Zonal water transport') call addfld ('VQ', (/ 'lev' /), 'A', 'm/skg/kg', 'Meridional water transport') call addfld ('QQ', (/ 'lev' /), 'A', 'kg2/kg2', 'Eddy moisture variance') @@ -611,6 +614,7 @@ subroutine diag_init_moist(pbuf2d) end if if (history_eddy) then + call add_default ('UQ ', 1, ' ') call add_default ('VQ ', 1, ' ') endif @@ -1017,6 +1021,9 @@ subroutine diag_phys_writeout_dry(state, pbuf, p_surf_t) ! ! zonal advection ! + ftem(:ncol,:) = state%u(:ncol,:)*state%t(:ncol,:) + call outfld ('UT ',ftem ,pcols ,lchnk ) + ftem(:ncol,:) = state%u(:ncol,:)**2 call outfld ('UU ',ftem ,pcols ,lchnk ) @@ -1281,9 +1288,10 @@ subroutine diag_phys_writeout_moist(state, pbuf, p_surf_t) call outfld('PDELDRY', state%pdeldry, pcols, lchnk) call outfld('PDEL', state%pdel, pcols, lchnk) - ! - ! Meridional advection fields - ! + + ftem(:ncol,:) = state%u(:ncol,:)*state%q(:ncol,:,ixq) + call outfld ('UQ ',ftem ,pcols ,lchnk ) + ftem(:ncol,:) = state%v(:ncol,:)*state%q(:ncol,:,ixq) call outfld ('VQ ',ftem ,pcols ,lchnk ) diff --git a/src/physics/cam/carma_flags_mod.F90 b/src/physics/cam/carma_flags_mod.F90 index 59fee48bf3..2ed1fcc531 100644 --- a/src/physics/cam/carma_flags_mod.F90 +++ b/src/physics/cam/carma_flags_mod.F90 @@ -11,8 +11,13 @@ module carma_flags_mod use spmd_utils, only: masterproc ! Flags for integration with CAM Microphysics - public carma_readnl ! read the carma namelist - + + implicit none + public + + integer, parameter :: carma_maxdiags = 100 + integer, protected :: carma_ndiagpkgs ! Number of diags_packages listed + integer, protected :: carma_ndebugpkgs ! Number of diags_packages listed ! Namelist flags ! @@ -20,45 +25,53 @@ module carma_flags_mod ! calculations, but it will still initialize itself. This allows the same build and ! namelist to be used, but the CARMA processing diabled. Use the configure option ! -carma none to totally disable CARMA and prevent even the register from happening. - logical, public :: carma_flag = .false. ! If .true. then turn on CARMA microphysics in CAM - logical, public :: carma_do_aerosol = .true. ! If .true. then CARMA is processed after surface coupling - logical, public :: carma_do_cldice = .false. ! If .true. then do cloud ice - logical, public :: carma_do_cldliq = .false. ! If .true. then do cloud liquid - logical, public :: carma_do_clearsky = .false. ! If .true. then do clear sky particle calculations - logical, public :: carma_do_coag = .false. ! If .true. then do coagulation - logical, public :: carma_do_detrain = .false. ! If .true. then do detrain - logical, public :: carma_do_drydep = .false. ! If .true. then do dry deposition - logical, public :: carma_do_emission = .false. ! If .true. then do emission - logical, public :: carma_do_fixedinit= .false. ! If .true. then do fixed initialization to a reference state - logical, public :: carma_hetchem_feedback= .false.! If .true. then CARMA sulfate surface area density used in heterogeneous chemistry - logical, public :: carma_rad_feedback= .false. ! If .true. then CARMA sulfate mass mixing ratio & effective radius used in radiation - logical, public :: carma_do_explised = .false. ! If .true. then do sedimentation with substepping - logical, public :: carma_do_incloud = .false. ! If .true. then do incloud particle calculations - logical, public :: carma_do_grow = .false. ! If .true. then do growth - logical, public :: carma_do_optics = .false. ! If .true. then do optical properties file - logical, public :: carma_do_partialinit= .false. ! If .true. then do initialization of coagulation to a reference state (requires fixedinit) - logical, public :: carma_do_pheat = .false. ! If .true. then do particle heating - logical, public :: carma_do_pheatatm = .false. ! If .true. then do particle heating of atmosphere - logical, public :: carma_do_substep = .false. ! If .true. then do substeping - logical, public :: carma_do_thermo = .false. ! If .true. then do solve thermodynamics equation - logical, public :: carma_do_wetdep = .false. ! If .true. then do wet deposition - logical, public :: carma_do_vdiff = .false. ! If .true. then do vertical brownian diffusion - logical, public :: carma_do_vtran = .false. ! If .true. then do vertical transport - integer, public :: carma_maxsubsteps = 1 ! Maximum number of time substeps allowed - integer, public :: carma_minsubsteps = 1 ! Minimum number of time substeps allowed - integer, public :: carma_maxretries = 8 ! Maximum number of time substeps allowed - real(r8), public :: carma_conmax = 0.1_r8 ! Minumum relative concentration to consider in substep - real(r8), public :: carma_dgc_threshold = 0.0_r8 ! When non-zero, the largest percentage change in gas concentration allowed per substep. - real(r8), public :: carma_ds_threshold = 0.0_r8 ! When non-zero, the largest percentage change in gas saturation allowed per substep. - real(r8), public :: carma_dt_threshold = 0.0_r8 ! When non-zero, the largest change in temperature (K) allowed per substep. - real(r8), public :: carma_tstick = 1.0_r8 ! Thermal accommodation coefficient - real(r8), public :: carma_gsticki = 0.93_r8 ! Growth accommodation coefficient for ice - real(r8), public :: carma_gstickl = 1.0_r8 ! Growth accommodation coefficient for liquid - real(r8), public :: carma_cstick = 1.0_r8 ! Coagulation accommodation coefficient - real(r8), public :: carma_rhcrit = 1.0_r8 ! Critical relative humidity for liquid clouds - real(r8), public :: carma_vf_const = 0.0_r8 ! If specified and non-zero, constant fall velocity for all particles [cm/s] - character(len=256), public :: carma_reftfile = 'carma_reft.nc' ! path to the file containing the reference temperature profile - character(len=32), public :: carma_model = "none" ! String (no spaces) that identifies the model + logical, protected :: carma_flag = .false. ! If .true. then turn on CARMA microphysics in CAM + logical, protected :: carma_do_aerosol = .true. ! If .true. then CARMA is processed after surface coupling + logical, protected :: carma_do_coremasscheck = .false. ! If .true. then do coremasscheck and abort model after certain subroutines + logical, protected :: carma_do_cldice = .false. ! If .true. then do cloud ice + logical, protected :: carma_do_cldliq = .false. ! If .true. then do cloud liquid + logical, protected :: carma_do_clearsky = .false. ! If .true. then do clear sky particle calculations + logical, protected :: carma_do_cloudborne = .false. ! If .true. then do then the carma groups can be cloudborne + logical, protected :: carma_do_coag = .false. ! If .true. then do coagulation + logical, protected :: carma_do_detrain = .false. ! If .true. then do detrain + logical, protected :: carma_do_drydep = .false. ! If .true. then do dry deposition + logical, protected :: carma_do_emission = .false. ! If .true. then do emission + logical, protected :: carma_do_fixedinit= .false. ! If .true. then do fixed initialization to a reference state + logical, protected :: carma_hetchem_feedback=.false.! If .true. then CARMA sulfate surface area density used in heterogeneous chemistry + logical, protected :: carma_rad_feedback= .false. ! If .true. then CARMA sulfate mass mixing ratio & effective radius used in radiation + logical, protected :: carma_do_explised = .false. ! If .true. then do sedimentation with substepping + logical, protected :: carma_do_incloud = .false. ! If .true. then do incloud particle calculations + logical, protected :: carma_do_budget_diags = .false. ! If .true. then do budget diagnostics + logical, protected :: carma_do_package_diags = .false. ! If .true. then do package diagnostics + logical, protected :: carma_do_grow = .false. ! If .true. then do growth + logical, protected :: carma_do_optics = .false. ! If .true. then do optical properties file + logical, protected :: carma_do_partialinit= .false. ! If .true. then do initialization of coagulation to a reference state (requires fixedinit) + logical, protected :: carma_do_pheat = .false. ! If .true. then do particle heating + logical, protected :: carma_do_pheatatm = .false. ! If .true. then do particle heating of atmosphere + logical, protected :: carma_do_substep = .false. ! If .true. then do substeping + logical, protected :: carma_do_thermo = .false. ! If .true. then do solve thermodynamics equation + logical, protected :: carma_do_wetdep = .false. ! If .true. then do wet deposition + logical, protected :: carma_do_vdiff = .false. ! If .true. then do vertical brownian diffusion + logical, protected :: carma_do_vtran = .false. ! If .true. then do vertical transport + integer, protected :: carma_diags_file = 0 ! Default file for diagnostic output + integer, protected :: carma_maxsubsteps = 1 ! Maximum number of time substeps allowed + integer, protected :: carma_minsubsteps = 1 ! Minimum number of time substeps allowed + integer, protected :: carma_maxretries = 8 ! Maximum number of time substeps allowed + real(r8), protected :: carma_conmax = 0.1_r8 ! Minumum relative concentration to consider in substep + real(r8), protected :: carma_dgc_threshold = 0.0_r8 ! When non-zero, the largest percentage change in gas concentration allowed per substep. + real(r8), protected :: carma_ds_threshold = 0.0_r8 ! When non-zero, the largest percentage change in gas saturation allowed per substep. + real(r8), protected :: carma_dt_threshold = 0.0_r8 ! When non-zero, the largest change in temperature (K) allowed per substep. + real(r8), protected :: carma_tstick = 1.0_r8 ! Thermal accommodation coefficient + real(r8), protected :: carma_gsticki = 0.93_r8 ! Growth accommodation coefficient for ice + real(r8), protected :: carma_gstickl = 1.0_r8 ! Growth accommodation coefficient for liquid + real(r8), protected :: carma_cstick = 1.0_r8 ! Coagulation accommodation coefficient + real(r8), protected :: carma_rhcrit = 1.0_r8 ! Critical relative humidity for liquid clouds + real(r8), protected :: carma_vf_const = 0.0_r8 ! If specified and non-zero, constant fall velocity for all particles [cm/s] + character(len=32), protected :: carma_model = "none" ! String (no spaces) that identifies the model + character(len=10), protected :: carma_sulfnuc_method = "none" ! Sulfate Nucleation method + character(len=32), protected :: carma_diags_packages(carma_maxdiags) = " " ! Names of physics packages for which diagnostic output is desired + character(len=12), protected :: carma_debug_packages(carma_maxdiags) = " " ! Names of physics packages for which debug output is desired + contains @@ -68,30 +81,32 @@ module carma_flags_mod !! @author Chuck Bardeen !! @version Aug-2010 subroutine carma_readnl(nlfile) - + ! Read carma namelist group. - + use cam_abortutils, only: endrun use namelist_utils, only: find_group_name - use units, only: getunit, freeunit - use mpishorthand + use spmd_utils, only: mpicom, masterprocid, mpi_real8, mpi_integer, mpi_logical, mpi_character, mpi_success use carma_model_flags_mod, only: carma_model_readnl - + ! args - + character(len=*), intent(in) :: nlfile ! filepath for file containing namelist input - + ! local vars - - integer :: unitn, ierr - + + integer :: unitn, ierr, i + character(len=*), parameter :: prefix = 'carma_readnl: ' + ! read namelist for CARMA namelist /carma_nl/ & carma_flag, & carma_do_aerosol, & + carma_do_coremasscheck, & carma_do_cldliq, & carma_do_cldice, & carma_do_clearsky, & + carma_do_cloudborne, & carma_do_coag, & carma_do_detrain, & carma_do_drydep, & @@ -115,7 +130,6 @@ subroutine carma_readnl(nlfile) carma_minsubsteps, & carma_maxretries, & carma_model, & - carma_reftfile, & carma_conmax, & carma_dgc_threshold, & carma_ds_threshold, & @@ -125,67 +139,136 @@ subroutine carma_readnl(nlfile) carma_gstickl, & carma_cstick, & carma_rhcrit, & - carma_vf_const - + carma_vf_const, & + carma_sulfnuc_method, & + carma_do_budget_diags, & + carma_do_package_diags, & + carma_diags_packages, & + carma_debug_packages, & + carma_diags_file + if (masterproc) then - unitn = getunit() - open( unitn, file=trim(nlfile), status='old' ) + open( newunit=unitn, file=trim(nlfile), status='old' ) call find_group_name(unitn, 'carma_nl', status=ierr) if (ierr == 0) then read(unitn, carma_nl, iostat=ierr) if (ierr /= 0) then - call endrun('carma_readnl: ERROR reading namelist') + call endrun(prefix//'ERROR reading namelist') end if end if close(unitn) - call freeunit(unitn) end if - -#ifdef SPMD - call mpibcast (carma_flag, 1 ,mpilog, 0,mpicom) - call mpibcast (carma_do_aerosol, 1 ,mpilog, 0,mpicom) - call mpibcast (carma_do_cldliq, 1 ,mpilog, 0,mpicom) - call mpibcast (carma_do_cldice, 1 ,mpilog, 0,mpicom) - call mpibcast (carma_do_clearsky, 1 ,mpilog, 0,mpicom) - call mpibcast (carma_do_coag, 1 ,mpilog, 0,mpicom) - call mpibcast (carma_do_detrain, 1 ,mpilog, 0,mpicom) - call mpibcast (carma_do_drydep, 1 ,mpilog, 0,mpicom) - call mpibcast (carma_do_emission, 1 ,mpilog, 0,mpicom) - call mpibcast (carma_do_fixedinit, 1 ,mpilog, 0,mpicom) - call mpibcast (carma_hetchem_feedback,1 ,mpilog, 0,mpicom) - call mpibcast (carma_rad_feedback, 1 ,mpilog, 0,mpicom) - call mpibcast (carma_do_explised, 1 ,mpilog, 0,mpicom) - call mpibcast (carma_do_incloud, 1 ,mpilog, 0,mpicom) - call mpibcast (carma_do_grow, 1 ,mpilog, 0,mpicom) - call mpibcast (carma_do_optics, 1 ,mpilog, 0,mpicom) - call mpibcast (carma_do_partialinit, 1 ,mpilog, 0,mpicom) - call mpibcast (carma_do_pheat, 1 ,mpilog, 0,mpicom) - call mpibcast (carma_do_pheatatm, 1 ,mpilog, 0,mpicom) - call mpibcast (carma_do_substep, 1 ,mpilog, 0,mpicom) - call mpibcast (carma_do_thermo, 1 ,mpilog, 0,mpicom) - call mpibcast (carma_do_wetdep, 1 ,mpilog, 0,mpicom) - call mpibcast (carma_do_vdiff, 1 ,mpilog, 0,mpicom) - call mpibcast (carma_do_vtran, 1 ,mpilog, 0,mpicom) - call mpibcast (carma_maxsubsteps, 1 ,mpiint, 0,mpicom) - call mpibcast (carma_minsubsteps, 1 ,mpiint, 0,mpicom) - call mpibcast (carma_maxretries, 1 ,mpiint, 0,mpicom) - call mpibcast (carma_conmax, 1 ,mpir8, 0,mpicom) - call mpibcast (carma_dgc_threshold, 1 ,mpir8, 0,mpicom) - call mpibcast (carma_ds_threshold, 1 ,mpir8, 0,mpicom) - call mpibcast (carma_dt_threshold, 1 ,mpir8, 0,mpicom) - call mpibcast (carma_tstick, 1 ,mpir8, 0,mpicom) - call mpibcast (carma_gsticki, 1 ,mpir8, 0,mpicom) - call mpibcast (carma_gstickl, 1 ,mpir8, 0,mpicom) - call mpibcast (carma_cstick, 1 ,mpir8, 0,mpicom) - call mpibcast (carma_rhcrit, 1 ,mpir8, 0,mpicom) - call mpibcast (carma_vf_const, 1 ,mpir8, 0,mpicom) - call mpibcast (carma_model, len(carma_model), mpichar, 0, mpicom) - call mpibcast (carma_reftfile, len(carma_reftfile), mpichar, 0, mpicom) -#endif + + call mpi_bcast (carma_flag, 1 ,mpi_logical, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_flag') + call mpi_bcast (carma_do_aerosol, 1 ,mpi_logical, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_do_aerosol') + call mpi_bcast (carma_do_coremasscheck,1 ,mpi_logical, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_do_coremasscheck') + call mpi_bcast (carma_do_cldliq, 1 ,mpi_logical, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_do_cldliq') + call mpi_bcast (carma_do_cldice, 1 ,mpi_logical, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_do_cldice') + call mpi_bcast (carma_do_clearsky, 1 ,mpi_logical, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_do_clearsky') + call mpi_bcast (carma_do_cloudborne, 1 ,mpi_logical, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_do_cloudborne') + call mpi_bcast (carma_do_coag, 1 ,mpi_logical, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_do_coag') + call mpi_bcast (carma_do_detrain, 1 ,mpi_logical, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_do_detrain') + call mpi_bcast (carma_do_drydep, 1 ,mpi_logical, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_do_drydep') + call mpi_bcast (carma_do_emission, 1 ,mpi_logical, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_do_emission') + call mpi_bcast (carma_do_fixedinit, 1 ,mpi_logical, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_do_fixedinit') + call mpi_bcast (carma_hetchem_feedback,1 ,mpi_logical, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_hetchem_feedback') + call mpi_bcast (carma_rad_feedback, 1 ,mpi_logical, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_rad_feedback') + call mpi_bcast (carma_do_explised, 1 ,mpi_logical, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_do_explised') + call mpi_bcast (carma_do_budget_diags, 1 ,mpi_logical, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_do_budget_diags') + call mpi_bcast (carma_do_package_diags,1 ,mpi_logical, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_do_package_diags') + call mpi_bcast (carma_do_incloud, 1 ,mpi_logical, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_do_incloud') + call mpi_bcast (carma_do_grow, 1 ,mpi_logical, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_do_grow') + call mpi_bcast (carma_do_optics, 1 ,mpi_logical, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_do_optics') + call mpi_bcast (carma_do_partialinit, 1 ,mpi_logical, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_do_partialinit') + call mpi_bcast (carma_do_pheat, 1 ,mpi_logical, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_do_pheat') + call mpi_bcast (carma_do_pheatatm, 1 ,mpi_logical, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_do_pheatatm') + call mpi_bcast (carma_do_substep, 1 ,mpi_logical, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_do_substep') + call mpi_bcast (carma_do_thermo, 1 ,mpi_logical, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_do_thermo') + call mpi_bcast (carma_do_wetdep, 1 ,mpi_logical, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_do_wetdep') + call mpi_bcast (carma_do_vdiff, 1 ,mpi_logical, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_do_vdiff') + call mpi_bcast (carma_do_vtran, 1 ,mpi_logical, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_do_vtran') + call mpi_bcast (carma_diags_file, 1 ,mpi_integer, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_diags_file') + call mpi_bcast (carma_maxsubsteps, 1 ,mpi_integer, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_maxsubsteps') + call mpi_bcast (carma_minsubsteps, 1 ,mpi_integer, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_minsubsteps') + call mpi_bcast (carma_maxretries, 1 ,mpi_integer, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_maxretries') + call mpi_bcast (carma_conmax, 1 ,mpi_real8, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_conmax') + call mpi_bcast (carma_dgc_threshold, 1 ,mpi_real8, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_dgc_threshold') + call mpi_bcast (carma_ds_threshold, 1 ,mpi_real8, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_ds_threshold') + call mpi_bcast (carma_dt_threshold, 1 ,mpi_real8, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_dt_threshold') + call mpi_bcast (carma_tstick, 1 ,mpi_real8, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_tstick') + call mpi_bcast (carma_gsticki, 1 ,mpi_real8, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_gsticki') + call mpi_bcast (carma_gstickl, 1 ,mpi_real8, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_gstickl') + call mpi_bcast (carma_cstick, 1 ,mpi_real8, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_cstick') + call mpi_bcast (carma_rhcrit, 1 ,mpi_real8, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_rhcrit') + call mpi_bcast (carma_vf_const, 1 ,mpi_real8, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_vf_const') + call mpi_bcast (carma_model, len(carma_model), mpi_character, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_model') + call mpi_bcast (carma_sulfnuc_method, len(carma_sulfnuc_method), mpi_character, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_sulfnuc_method') + call mpibcast (carma_diags_packages, len(carma_diags_packages(1))*carma_maxdiags, mpi_character, 0, mpicom) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_diags_packages') + call mpibcast (carma_debug_packages, len(carma_debug_packages(1))*carma_maxdiags, mpi_character, 0, mpicom) + if (ierr/=mpi_success) call endrun(prefix//'mpi_bcast error : carma_debug_packages') + + carma_ndiagpkgs = 0 + do i = 1, carma_maxdiags + if (len_trim(carma_diags_packages(i)) > 0) then + carma_ndiagpkgs = carma_ndiagpkgs + 1 + endif + enddo + + carma_ndebugpkgs = 0 + do i = 1, carma_maxdiags + if (len_trim(carma_debug_packages(i)) > 0) then + carma_ndebugpkgs = carma_ndebugpkgs + 1 + endif + enddo ! Also cause the CARMA model flags to be read in. call carma_model_readnl(nlfile) - + end subroutine carma_readnl end module carma_flags_mod diff --git a/src/physics/cam/carma_intr.F90 b/src/physics/cam/carma_intr.F90 index fc09de5246..b555aaf68a 100644 --- a/src/physics/cam/carma_intr.F90 +++ b/src/physics/cam/carma_intr.F90 @@ -22,12 +22,12 @@ module carma_intr implicit none - + private save ! Public interfaces - + ! CAM Physics Interface public carma_register ! register consituents public carma_is_active ! retrns true if this package is active (microphysics = .true.) @@ -38,11 +38,11 @@ module carma_intr public carma_timestep_init ! initialize timestep dependent variables public carma_timestep_tend ! interface to tendency computation public carma_accumulate_stats ! collect stats from all MPI tasks - + ! Other Microphysics public carma_emission_tend ! calculate tendency from emission source function public carma_wetdep_tend ! calculate tendency from wet deposition - + contains @@ -55,40 +55,41 @@ end subroutine carma_register function carma_is_active() implicit none - + logical :: carma_is_active - + carma_is_active = .false. - + return end function carma_is_active function carma_implements_cnst(name) implicit none - + character(len=*), intent(in) :: name !! constituent name logical :: carma_implements_cnst ! return value carma_implements_cnst = .false. - + return end function carma_implements_cnst - - subroutine carma_init + + subroutine carma_init(pbuf2d) implicit none - + type(physics_buffer_desc), pointer :: pbuf2d(:,:) + return end subroutine carma_init subroutine carma_final implicit none - + return end subroutine carma_final - + subroutine carma_timestep_init implicit none @@ -103,7 +104,7 @@ subroutine carma_timestep_tend(state, cam_in, cam_out, ptend, dt, pbuf, dlf, rli use time_manager, only: get_nstep, get_step_size, is_first_step use camsrfexch, only: cam_in_t, cam_out_t use scamMod, only: single_column - + implicit none type(physics_state), intent(inout) :: state !! physics state variables @@ -114,13 +115,13 @@ subroutine carma_timestep_tend(state, cam_in, cam_out, ptend, dt, pbuf, dlf, rli type(physics_buffer_desc), pointer :: pbuf(:) !! physics buffer real(r8), intent(in), optional :: dlf(pcols,pver) !! Detraining cld H20 from convection (kg/kg/s) real(r8), intent(inout), optional :: rliq(pcols) !! vertical integral of liquid not yet in q(ixcldliq) - real(r8), intent(out), optional :: prec_str(pcols) !! [Total] sfc flux of precip from stratiform (m/s) + real(r8), intent(out), optional :: prec_str(pcols) !! [Total] sfc flux of precip from stratiform (m/s) real(r8), intent(out), optional :: snow_str(pcols) !! [Total] sfc flux of snow from stratiform (m/s) real(r8), intent(out), optional :: prec_sed(pcols) !! total precip from cloud sedimentation (m/s) real(r8), intent(out), optional :: snow_sed(pcols) !! snow from cloud ice sedimentation (m/s) real(r8), intent(in), optional :: ustar(pcols) !! friction velocity (m/s) real(r8), intent(in), optional :: obklen(pcols) !! Obukhov length [ m ] - + call physics_ptend_init(ptend,state%psetcols,'none') !Initialize an empty ptend for use with physics_update if (present(prec_str)) prec_str(:) = 0._r8 @@ -140,27 +141,28 @@ subroutine carma_init_cnst(name, latvals, lonvals, mask, q) real(r8), intent(in) :: lonvals(:) !! lon in degrees (ncol) logical, intent(in) :: mask(:) !! Only initialize where .true. real(r8), intent(out) :: q(:,:) !! mass mixing ratio - + if (name == "carma") then q = 0._r8 - end if - + end if + return end subroutine carma_init_cnst - subroutine carma_emission_tend(state, ptend, cam_in, dt) + subroutine carma_emission_tend(state, ptend, cam_in, dt, pbuf) use camsrfexch, only: cam_in_t implicit none - + type(physics_state), intent(in ) :: state !! physics state type(physics_ptend), intent(inout) :: ptend !! physics state tendencies type(cam_in_t), intent(inout) :: cam_in !! surface inputs real(r8), intent(in) :: dt !! time step (s) + type(physics_buffer_desc), pointer :: pbuf(:) !! physics buffer return - end subroutine carma_emission_tend + end subroutine carma_emission_tend subroutine carma_wetdep_tend(state, ptend, dt, pbuf, dlf, cam_out) diff --git a/src/physics/cam/check_energy.F90 b/src/physics/cam/check_energy.F90 index 9c569387e0..d1d59e173f 100644 --- a/src/physics/cam/check_energy.F90 +++ b/src/physics/cam/check_energy.F90 @@ -21,57 +21,57 @@ module check_energy !--------------------------------------------------------------------------------- use shr_kind_mod, only: r8 => shr_kind_r8 - use ppgrid, only: pcols, pver, begchunk, endchunk + use ppgrid, only: pcols, pver use spmd_utils, only: masterproc - use gmean_mod, only: gmean - use physconst, only: gravit, rga, latvap, latice, cpair, rair - use air_composition, only: cpairv, rairv, cp_or_cv_dycore - use physics_types, only: physics_state, physics_tend, physics_ptend, physics_ptend_init + use physconst, only: rga + use air_composition, only: cpairv, cp_or_cv_dycore + use physics_types, only: physics_state use constituents, only: cnst_get_ind, pcnst, cnst_name, cnst_get_type_byind - use time_manager, only: is_first_step use cam_logfile, only: iulog - use scamMod, only: single_column, use_camiop, heat_glob_scm - use cam_history, only: outfld, write_camiop implicit none private -! Public types: + ! Public types: public check_tracers_data -! Public methods - public :: check_energy_readnl ! read namelist values - public :: check_energy_register ! register fields in physics buffer - public :: check_energy_get_integrals ! get energy integrals computed in check_energy_gmean - public :: check_energy_init ! initialization of module - public :: check_energy_timestep_init ! timestep initialization of energy integrals and cumulative boundary fluxes - public :: check_energy_chng ! check changes in integrals against cumulative boundary fluxes - public :: check_energy_gmean ! global means of physics input and output total energy - public :: check_energy_fix ! add global mean energy difference as a heating - public :: check_tracers_init ! initialize tracer integrals and cumulative boundary fluxes - public :: check_tracers_chng ! check changes in integrals against cumulative boundary fluxes + ! Public methods - not CCPP-ized + public :: check_tracers_init ! initialize tracer integrals and cumulative boundary fluxes + public :: check_tracers_chng ! check changes in integrals against cumulative boundary fluxes + public :: tot_energy_phys ! calculate and output total energy and axial angular momentum diagnostics - public :: tot_energy_phys ! calculate and output total energy and axial angular momentum diagnostics + ! These subroutines cannot be CCPP-ized + public :: check_energy_readnl ! read namelist values + public :: check_energy_register ! register fields in physics buffer + public :: check_energy_init ! initialization of module + public :: check_energy_gmean ! global means of physics input and output total energy + public :: check_energy_get_integrals ! get energy integrals computed in check_energy_gmean -! Private module data + ! Public methods - CAM interfaces to CCPP version: + public :: check_energy_cam_chng ! check changes in integrals against cumulative boundary fluxes + public :: check_energy_timestep_init ! timestep initialization of energy integrals and cumulative boundary fluxes + ! name is retained for FV3 compatibility - logical :: print_energy_errors = .false. - - real(r8) :: teout_glob ! global mean energy of output state - real(r8) :: teinp_glob ! global mean energy of input state - real(r8) :: tedif_glob ! global mean energy difference - real(r8) :: psurf_glob ! global mean surface pressure - real(r8) :: ptopb_glob ! global mean top boundary pressure - real(r8) :: heat_glob ! global mean heating rate + public :: check_energy_cam_fix ! add heating rate required for global mean total energy conservation -! Physics buffer indices + ! Private module data + logical :: print_energy_errors = .false. - integer :: teout_idx = 0 ! teout index in physics buffer - integer :: dtcore_idx = 0 ! dtcore index in physics buffer - integer :: dqcore_idx = 0 ! dqcore index in physics buffer - integer :: ducore_idx = 0 ! ducore index in physics buffer - integer :: dvcore_idx = 0 ! dvcore index in physics buffer + ! used for check_energy_gmean + real(r8) :: teout_glob ! global mean energy of output state + real(r8) :: teinp_glob ! global mean energy of input state + real(r8) :: tedif_glob ! global mean energy difference + real(r8) :: psurf_glob ! global mean surface pressure + real(r8) :: ptopb_glob ! global mean top boundary pressure + real(r8) :: heat_glob ! global mean heating rate + + ! Physics buffer indices + integer, public :: teout_idx = 0 ! teout index in physics buffer + integer, public :: dtcore_idx = 0 ! dtcore index in physics buffer + integer, public :: dqcore_idx = 0 ! dqcore index in physics buffer + integer, public :: ducore_idx = 0 ! ducore index in physics buffer + integer, public :: dvcore_idx = 0 ! dvcore index in physics buffer type check_tracers_data real(r8) :: tracer(pcols,pcnst) ! initial vertically integrated total (kinetic + static) energy @@ -91,6 +91,9 @@ subroutine check_energy_readnl(nlfile) use spmd_utils, only: mpicom, mstrid=>masterprocid, mpi_logical use cam_abortutils, only: endrun + ! update the CCPP-ized namelist option + use check_energy_chng, only: check_energy_chng_init + character(len=*), intent(in) :: nlfile ! filepath for file containing namelist input ! Local variables @@ -123,6 +126,9 @@ subroutine check_energy_readnl(nlfile) write(iulog,*) ' print_energy_errors =', print_energy_errors end if + ! update the CCPP-ized namelist option + call check_energy_chng_init(print_energy_errors_in=print_energy_errors) + end subroutine check_energy_readnl !=============================================================================== @@ -157,28 +163,6 @@ subroutine check_energy_register() end subroutine check_energy_register -!=============================================================================== - -subroutine check_energy_get_integrals( tedif_glob_out, heat_glob_out ) - -!----------------------------------------------------------------------- -! Purpose: Return energy integrals -!----------------------------------------------------------------------- - - real(r8), intent(out), optional :: tedif_glob_out - real(r8), intent(out), optional :: heat_glob_out - -!----------------------------------------------------------------------- - - if ( present(tedif_glob_out) ) then - tedif_glob_out = tedif_glob - endif - if ( present(heat_glob_out) ) then - heat_glob_out = heat_glob - endif - -end subroutine check_energy_get_integrals - !================================================================================================ subroutine check_energy_init() @@ -217,415 +201,6 @@ subroutine check_energy_init() end subroutine check_energy_init -!=============================================================================== - - subroutine check_energy_timestep_init(state, tend, pbuf, col_type) - use cam_thermo, only: get_hydrostatic_energy - use physics_buffer, only: physics_buffer_desc, pbuf_set_field - use cam_abortutils, only: endrun - use dyn_tests_utils, only: vc_physics, vc_dycore, vc_height, vc_dry_pressure - use physics_types, only: phys_te_idx, dyn_te_idx -!----------------------------------------------------------------------- -! Compute initial values of energy and water integrals, -! zero cumulative tendencies -!----------------------------------------------------------------------- -!------------------------------Arguments-------------------------------- - - type(physics_state), intent(inout) :: state - type(physics_tend ), intent(inout) :: tend - type(physics_buffer_desc), pointer :: pbuf(:) - integer, optional :: col_type ! Flag inidicating whether using grid or subcolumns -!---------------------------Local storage------------------------------- - real(r8) :: cp_or_cv(state%psetcols,pver) - integer lchnk ! chunk identifier - integer ncol ! number of atmospheric columns -!----------------------------------------------------------------------- - - lchnk = state%lchnk - ncol = state%ncol - - ! cp_or_cv needs to be allocated to a size which matches state and ptend - ! If psetcols == pcols, cpairv is the correct size and just copy into cp_or_cv - ! If psetcols > pcols and all cpairv match cpair, then assign the constant cpair - - if (state%psetcols == pcols) then - cp_or_cv(:,:) = cpairv(:,:,lchnk) - else if (state%psetcols > pcols .and. all(cpairv(:,:,lchnk) == cpair)) then - cp_or_cv(1:ncol,:) = cpair - else - call endrun('check_energy_timestep_init: cpairv is not allowed to vary when subcolumns are turned on') - end if - ! - ! CAM physics total energy - ! - call get_hydrostatic_energy(state%q(1:ncol,1:pver,1:pcnst),.true., & - state%pdel(1:ncol,1:pver), cp_or_cv(1:ncol,1:pver), & - state%u(1:ncol,1:pver), state%v(1:ncol,1:pver), state%T(1:ncol,1:pver), & - vc_physics, ptop=state%pintdry(1:ncol,1), phis = state%phis(1:ncol),& - te = state%te_ini(1:ncol,phys_te_idx), H2O = state%tw_ini(1:ncol)) - ! - ! Dynamical core total energy - ! - state%temp_ini(:ncol,:) = state%T(:ncol,:) - state%z_ini(:ncol,:) = state%zm(:ncol,:) - if (vc_dycore == vc_height) then - ! - ! MPAS specific hydrostatic energy computation (internal energy) - ! - if (state%psetcols == pcols) then - cp_or_cv(:ncol,:) = cp_or_cv_dycore(:ncol,:,lchnk) - else - cp_or_cv(:ncol,:) = cpair-rair - endif - - call get_hydrostatic_energy(state%q(1:ncol,1:pver,1:pcnst),.true., & - state%pdel(1:ncol,1:pver), cp_or_cv(1:ncol,1:pver), & - state%u(1:ncol,1:pver), state%v(1:ncol,1:pver), state%T(1:ncol,1:pver), & - vc_dycore, ptop=state%pintdry(1:ncol,1), phis = state%phis(1:ncol), & - z_mid = state%z_ini(1:ncol,:), & - te = state%te_ini(1:ncol,dyn_te_idx), H2O = state%tw_ini(1:ncol)) - else if (vc_dycore == vc_dry_pressure) then - ! - ! SE specific hydrostatic energy (enthalpy) - ! - if (state%psetcols == pcols) then - cp_or_cv(:ncol,:) = cp_or_cv_dycore(:ncol,:,lchnk) - else - cp_or_cv(:ncol,:) = cpair - endif - call get_hydrostatic_energy(state%q(1:ncol,1:pver,1:pcnst),.true., & - state%pdel(1:ncol,1:pver), cp_or_cv(1:ncol,1:pver), & - state%u(1:ncol,1:pver), state%v(1:ncol,1:pver), state%T(1:ncol,1:pver), & - vc_dry_pressure, ptop=state%pintdry(1:ncol,1), phis = state%phis(1:ncol), & - te = state%te_ini(1:ncol,dyn_te_idx), H2O = state%tw_ini(1:ncol)) - else - ! - ! dycore energy is the same as physics - ! - state%te_ini(1:ncol,dyn_te_idx) = state%te_ini(1:ncol,phys_te_idx) - end if - state%te_cur(:ncol,:) = state%te_ini(:ncol,:) - state%tw_cur(:ncol) = state%tw_ini(:ncol) - -! zero cummulative boundary fluxes - tend%te_tnd(:ncol) = 0._r8 - tend%tw_tnd(:ncol) = 0._r8 - - state%count = 0 - -! initialize physics buffer - if (is_first_step()) then - call pbuf_set_field(pbuf, teout_idx, state%te_ini(:,dyn_te_idx), col_type=col_type) - end if - - end subroutine check_energy_timestep_init - -!=============================================================================== - - subroutine check_energy_chng(state, tend, name, nstep, ztodt, & - flx_vap, flx_cnd, flx_ice, flx_sen) - use cam_thermo, only: get_hydrostatic_energy - use dyn_tests_utils, only: vc_physics, vc_dycore, vc_height, vc_dry_pressure - use cam_abortutils, only: endrun - use physics_types, only: phys_te_idx, dyn_te_idx -!----------------------------------------------------------------------- -! Check that the energy and water change matches the boundary fluxes -!----------------------------------------------------------------------- -!------------------------------Arguments-------------------------------- - - type(physics_state) , intent(inout) :: state - type(physics_tend ) , intent(inout) :: tend - character*(*),intent(in) :: name ! parameterization name for fluxes - integer , intent(in ) :: nstep ! current timestep number - real(r8), intent(in ) :: ztodt ! 2 delta t (model time increment) - real(r8), intent(in ) :: flx_vap(:) ! (pcols) - boundary flux of vapor (kg/m2/s) - real(r8), intent(in ) :: flx_cnd(:) ! (pcols) -boundary flux of liquid+ice (m/s) (precip?) - real(r8), intent(in ) :: flx_ice(:) ! (pcols) -boundary flux of ice (m/s) (snow?) - real(r8), intent(in ) :: flx_sen(:) ! (pcols) -boundary flux of sensible heat (w/m2) - -!******************** BAB ****************************************************** -!******* Note that the precip and ice fluxes are in precip units (m/s). ******** -!******* I would prefer to have kg/m2/s. ******** -!******* I would also prefer liquid (not total) and ice fluxes ******** -!******************************************************************************* - -!---------------------------Local storage------------------------------- - - real(r8) :: te_xpd(state%ncol) ! expected value (f0 + dt*boundary_flux) - real(r8) :: te_dif(state%ncol) ! energy of input state - original energy - real(r8) :: te_tnd(state%ncol) ! tendency from last process - real(r8) :: te_rer(state%ncol) ! relative error in energy column - - real(r8) :: tw_xpd(state%ncol) ! expected value (w0 + dt*boundary_flux) - real(r8) :: tw_dif(state%ncol) ! tw_inp - original water - real(r8) :: tw_tnd(state%ncol) ! tendency from last process - real(r8) :: tw_rer(state%ncol) ! relative error in water column - - real(r8) :: te(state%ncol) ! vertical integral of total energy - real(r8) :: tw(state%ncol) ! vertical integral of total water - real(r8) :: cp_or_cv(state%psetcols,pver) ! cp or cv depending on vcoord - real(r8) :: scaling(state%psetcols,pver) ! scaling for conversion of temperature increment - real(r8) :: temp(state%ncol,pver) ! temperature - - real(r8) :: se(state%ncol) ! enthalpy or internal energy (J/m2) - real(r8) :: po(state%ncol) ! surface potential or potential energy (J/m2) - real(r8) :: ke(state%ncol) ! kinetic energy (J/m2) - real(r8) :: wv(state%ncol) ! column integrated vapor (kg/m2) - real(r8) :: liq(state%ncol) ! column integrated liquid (kg/m2) - real(r8) :: ice(state%ncol) ! column integrated ice (kg/m2) - - integer lchnk ! chunk identifier - integer ncol ! number of atmospheric columns - integer i ! column index -!----------------------------------------------------------------------- - - lchnk = state%lchnk - ncol = state%ncol - - ! If psetcols == pcols, cpairv is the correct size and just copy into cp_or_cv - ! If psetcols > pcols and all cpairv match cpair, then assign the constant cpair - - if (state%psetcols == pcols) then - cp_or_cv(:,:) = cpairv(:,:,lchnk) - else if (state%psetcols > pcols .and. all(cpairv(:,:,:) == cpair)) then - cp_or_cv(:,:) = cpair - else - call endrun('check_energy_chng: cpairv is not allowed to vary when subcolumns are turned on') - end if - - call get_hydrostatic_energy(state%q(1:ncol,1:pver,1:pcnst),.true., & - state%pdel(1:ncol,1:pver), cp_or_cv(1:ncol,1:pver), & - state%u(1:ncol,1:pver), state%v(1:ncol,1:pver), state%T(1:ncol,1:pver), & - vc_physics, ptop=state%pintdry(1:ncol,1), phis = state%phis(1:ncol), & - te = te(1:ncol), H2O = tw(1:ncol), se=se(1:ncol),po=po(1:ncol), & - ke=ke(1:ncol),wv=wv(1:ncol),liq=liq(1:ncol),ice=ice(1:ncol)) - ! compute expected values and tendencies - do i = 1, ncol - ! change in static energy and total water - te_dif(i) = te(i) - state%te_cur(i,phys_te_idx) - tw_dif(i) = tw(i) - state%tw_cur(i) - - ! expected tendencies from boundary fluxes for last process - te_tnd(i) = flx_vap(i)*(latvap+latice) - (flx_cnd(i) - flx_ice(i))*1000._r8*latice + flx_sen(i) - tw_tnd(i) = flx_vap(i) - flx_cnd(i) *1000._r8 - - ! cummulative tendencies from boundary fluxes - tend%te_tnd(i) = tend%te_tnd(i) + te_tnd(i) - tend%tw_tnd(i) = tend%tw_tnd(i) + tw_tnd(i) - - ! expected new values from previous state plus boundary fluxes - te_xpd(i) = state%te_cur(i,phys_te_idx) + te_tnd(i)*ztodt - tw_xpd(i) = state%tw_cur(i) + tw_tnd(i)*ztodt - - ! relative error, expected value - input state / previous state - te_rer(i) = (te_xpd(i) - te(i)) / state%te_cur(i,phys_te_idx) - end do - - ! relative error for total water (allow for dry atmosphere) - tw_rer = 0._r8 - where (state%tw_cur(:ncol) > 0._r8) - tw_rer(:ncol) = (tw_xpd(:ncol) - tw(:ncol)) / state%tw_cur(:ncol) - end where - - ! error checking - if (print_energy_errors) then - if (any(abs(te_rer(1:ncol)) > 1.E-14_r8 .or. abs(tw_rer(1:ncol)) > 1.E-10_r8)) then - do i = 1, ncol - ! the relative error threshold for the water budget has been reduced to 1.e-10 - ! to avoid messages generated by QNEG3 calls - ! PJR- change to identify if error in energy or water - if (abs(te_rer(i)) > 1.E-14_r8 ) then - state%count = state%count + 1 - write(iulog,*) "significant energy conservation error after ", name, & - " count", state%count, " nstep", nstep, "chunk", lchnk, "col", i - write(iulog,*) te(i),te_xpd(i),te_dif(i),tend%te_tnd(i)*ztodt, & - te_tnd(i)*ztodt,te_rer(i) - endif - if ( abs(tw_rer(i)) > 1.E-10_r8) then - state%count = state%count + 1 - write(iulog,*) "significant water conservation error after ", name, & - " count", state%count, " nstep", nstep, "chunk", lchnk, "col", i - write(iulog,*) tw(i),tw_xpd(i),tw_dif(i),tend%tw_tnd(i)*ztodt, & - tw_tnd(i)*ztodt,tw_rer(i) - end if - end do - end if - end if - - ! copy new value to state - - do i = 1, ncol - state%te_cur(i,phys_te_idx) = te(i) - state%tw_cur(i) = tw(i) - end do - - ! - ! Dynamical core total energy - ! - if (vc_dycore == vc_height) then - ! - ! compute cv if vertical coordinate is height: cv = cp - R - ! - ! Note: cp_or_cv set above for pressure coordinate - if (state%psetcols == pcols) then - cp_or_cv(:ncol,:) = cp_or_cv_dycore(:ncol,:,lchnk) - else - cp_or_cv(:ncol,:) = cpair-rair - endif - scaling(:,:) = cpairv(:,:,lchnk)/cp_or_cv(:,:) !cp/cv scaling - temp(1:ncol,:) = state%temp_ini(1:ncol,:)+scaling(1:ncol,:)*(state%T(1:ncol,:)-state%temp_ini(1:ncol,:)) - call get_hydrostatic_energy(state%q(1:ncol,1:pver,1:pcnst),.true., & - state%pdel(1:ncol,1:pver), cp_or_cv(1:ncol,1:pver), & - state%u(1:ncol,1:pver), state%v(1:ncol,1:pver), temp(1:ncol,1:pver), & - vc_dycore, ptop=state%pintdry(1:ncol,1), phis = state%phis(1:ncol), & - z_mid = state%z_ini(1:ncol,:), & - te = state%te_cur(1:ncol,dyn_te_idx), H2O = state%tw_cur(1:ncol)) - else if (vc_dycore == vc_dry_pressure) then - ! - ! SE specific hydrostatic energy - ! - if (state%psetcols == pcols) then - cp_or_cv(:ncol,:) = cp_or_cv_dycore(:ncol,:,lchnk) - scaling(:ncol,:) = cpairv(:ncol,:,lchnk)/cp_or_cv_dycore(:ncol,:,lchnk) - else - cp_or_cv(:ncol,:) = cpair - scaling(:ncol,:) = 1.0_r8 - endif - ! - ! enthalpy scaling for energy consistency - ! - temp(1:ncol,:) = state%temp_ini(1:ncol,:)+scaling(1:ncol,:)*(state%T(1:ncol,:)-state%temp_ini(1:ncol,:)) - call get_hydrostatic_energy(state%q(1:ncol,1:pver,1:pcnst),.true., & - state%pdel(1:ncol,1:pver), cp_or_cv(1:ncol,1:pver), & - state%u(1:ncol,1:pver), state%v(1:ncol,1:pver), temp(1:ncol,1:pver), & - vc_dry_pressure, ptop=state%pintdry(1:ncol,1), phis = state%phis(1:ncol), & - te = state%te_cur(1:ncol,dyn_te_idx), H2O = state%tw_cur(1:ncol)) - else - state%te_cur(1:ncol,dyn_te_idx) = te(1:ncol) - end if - end subroutine check_energy_chng - - - subroutine check_energy_gmean(state, pbuf2d, dtime, nstep) - - use physics_buffer, only : physics_buffer_desc, pbuf_get_field, pbuf_get_chunk - use physics_types, only: dyn_te_idx - use cam_history, only: write_camiop -!----------------------------------------------------------------------- -! Compute global mean total energy of physics input and output states -! computed consistently with dynamical core vertical coordinate -! (under hydrostatic assumption) -!----------------------------------------------------------------------- -!------------------------------Arguments-------------------------------- - - type(physics_state), intent(in ), dimension(begchunk:endchunk) :: state - type(physics_buffer_desc), pointer :: pbuf2d(:,:) - - real(r8), intent(in) :: dtime ! physics time step - integer , intent(in) :: nstep ! current timestep number - -!---------------------------Local storage------------------------------- - integer :: ncol ! number of active columns - integer :: lchnk ! chunk index - - real(r8) :: te(pcols,begchunk:endchunk,4) - ! total energy of input/output states (copy) - real(r8) :: te_glob(4) ! global means of total energy - real(r8), pointer :: teout(:) -!----------------------------------------------------------------------- - - ! Copy total energy out of input and output states - do lchnk = begchunk, endchunk - ncol = state(lchnk)%ncol - ! input energy using dynamical core energy formula - te(:ncol,lchnk,1) = state(lchnk)%te_ini(:ncol,dyn_te_idx) - ! output energy - call pbuf_get_field(pbuf_get_chunk(pbuf2d,lchnk),teout_idx, teout) - - te(:ncol,lchnk,2) = teout(1:ncol) - ! surface pressure for heating rate - te(:ncol,lchnk,3) = state(lchnk)%pint(:ncol,pver+1) - ! model top pressure for heating rate (not constant for z-based vertical coordinate!) - te(:ncol,lchnk,4) = state(lchnk)%pint(:ncol,1) - end do - - ! Compute global means of input and output energies and of - ! surface pressure for heating rate (assume uniform ptop) - call gmean(te, te_glob, 4) - - if (begchunk .le. endchunk) then - teinp_glob = te_glob(1) - teout_glob = te_glob(2) - psurf_glob = te_glob(3) - ptopb_glob = te_glob(4) - - ! Global mean total energy difference - tedif_glob = teinp_glob - teout_glob - heat_glob = -tedif_glob/dtime * gravit / (psurf_glob - ptopb_glob) - if (masterproc) then - write(iulog,'(1x,a9,1x,i8,5(1x,e25.17))') "nstep, te", nstep, teinp_glob, teout_glob, & - heat_glob, psurf_glob, ptopb_glob - end if - else - heat_glob = 0._r8 - end if ! (begchunk .le. endchunk) - - end subroutine check_energy_gmean - -!=============================================================================== - subroutine check_energy_fix(state, ptend, nstep, eshflx) - -!----------------------------------------------------------------------- -! Add heating rate required for global mean total energy conservation -!----------------------------------------------------------------------- -!------------------------------Arguments-------------------------------- - - type(physics_state), intent(in ) :: state - type(physics_ptend), intent(out) :: ptend - - integer , intent(in ) :: nstep ! time step number - real(r8), intent(out ) :: eshflx(pcols) ! effective sensible heat flux - -!---------------------------Local storage------------------------------- - integer :: i ! column - integer :: ncol ! number of atmospheric columns in chunk - integer :: lchnk ! chunk number - real(r8) :: heat_out(pcols) -!----------------------------------------------------------------------- - lchnk = state%lchnk - ncol = state%ncol - - call physics_ptend_init(ptend, state%psetcols, 'chkenergyfix', ls=.true.) - -#if ( defined OFFLINE_DYN ) - ! disable the energy fix for offline driver - heat_glob = 0._r8 -#endif - - ! Special handling of energy fix for SCAM - supplied via CAMIOP - zero's for normal IOPs - if (single_column) then - if ( use_camiop) then - heat_glob = heat_glob_scm(1) - else - heat_glob = 0._r8 - endif - endif - ptend%s(:ncol,:pver) = heat_glob - - if (nstep > 0 .and. write_camiop) then - heat_out(:ncol) = heat_glob - call outfld('heat_glob', heat_out(:ncol), pcols, lchnk) - endif - -! compute effective sensible heat flux - do i = 1, ncol - eshflx(i) = heat_glob * (state%pint(i,pver+1) - state%pint(i,1)) * rga - end do - - return - end subroutine check_energy_fix - - !=============================================================================== subroutine check_tracers_init(state, tracerint) @@ -840,7 +415,8 @@ subroutine tot_energy_phys(state, outfld_name_suffix,vc) use cam_thermo, only: get_hydrostatic_energy,thermo_budget_num_vars,thermo_budget_vars, & wvidx,wlidx,wiidx,seidx,poidx,keidx,moidx,mridx,ttidx,teidx use cam_history, only: outfld - use dyn_tests_utils, only: vc_physics, vc_height, vc_dry_pressure + use dyn_tests_utils, only: vc_physics + use cam_thermo_formula, only: ENERGY_FORMULA_DYCORE_SE, ENERGY_FORMULA_DYCORE_MPAS use cam_abortutils, only: endrun use cam_history_support, only: max_fieldname_len @@ -849,7 +425,7 @@ subroutine tot_energy_phys(state, outfld_name_suffix,vc) type(physics_state), intent(inout) :: state character(len=*), intent(in) :: outfld_name_suffix ! suffix for "outfld" - integer, optional, intent(in) :: vc ! vertical coordinate + integer, optional, intent(in) :: vc ! vertical coordinate (controls energy formula to use) !---------------------------Local storage------------------------------- real(r8) :: se(pcols) ! Dry Static energy (J/m2) @@ -885,6 +461,9 @@ subroutine tot_energy_phys(state, outfld_name_suffix,vc) lchnk = state%lchnk ncol = state%ncol + ! The "vertical coordinate" parameter is equivalent to the dynamical core + ! energy formula parameter, which controls the dycore energy formula used + ! by get_hydrostatic_energy. if (present(vc)) then vc_loc = vc else @@ -892,7 +471,7 @@ subroutine tot_energy_phys(state, outfld_name_suffix,vc) end if if (state%psetcols == pcols) then - if (vc_loc == vc_height .or. vc_loc == vc_dry_pressure) then + if (vc_loc == ENERGY_FORMULA_DYCORE_MPAS .or. vc_loc == ENERGY_FORMULA_DYCORE_SE) then cp_or_cv(:ncol,:) = cp_or_cv_dycore(:ncol,:,lchnk) else cp_or_cv(:ncol,:) = cpairv(:ncol,:,lchnk) @@ -901,7 +480,7 @@ subroutine tot_energy_phys(state, outfld_name_suffix,vc) call endrun('tot_energy_phys: energy diagnostics not implemented/tested for subcolumns') end if - if (vc_loc == vc_height .or. vc_loc == vc_dry_pressure) then + if (vc_loc == ENERGY_FORMULA_DYCORE_MPAS .or. vc_loc == ENERGY_FORMULA_DYCORE_SE) then scaling(:ncol,:) = cpairv(:ncol,:,lchnk)/cp_or_cv(:ncol,:)!scaling for energy consistency else scaling(:ncol,:) = 1.0_r8 !internal energy / enthalpy same as CAM physics @@ -982,5 +561,363 @@ subroutine tot_energy_phys(state, outfld_name_suffix,vc) end subroutine tot_energy_phys + ! Compute global mean total energy of physics input and output states + ! computed consistently with dynamical core vertical coordinate + ! (under hydrostatic assumption) + ! + ! This subroutine cannot use the CCPP-ized equivalent because + ! it is dependent on chunks. + subroutine check_energy_gmean(state, pbuf2d, dtime, nstep) + use physics_buffer, only: physics_buffer_desc, pbuf_get_field, pbuf_get_chunk + use physics_types, only: dyn_te_idx + use ppgrid, only: begchunk, endchunk + use spmd_utils, only: masterproc + use cam_logfile, only: iulog + use gmean_mod, only: gmean + use physconst, only: gravit + + type(physics_state), intent(in), dimension(begchunk:endchunk) :: state + type(physics_buffer_desc), pointer :: pbuf2d(:,:) + + real(r8), intent(in) :: dtime ! physics time step + integer , intent(in) :: nstep ! current timestep number + + integer :: ncol ! number of active columns + integer :: lchnk ! chunk index + + real(r8) :: te(pcols,begchunk:endchunk,4) + ! total energy of input/output states (copy) + real(r8) :: te_glob(4) ! global means of total energy + real(r8), pointer :: teout(:) + + ! Copy total energy out of input and output states + do lchnk = begchunk, endchunk + ncol = state(lchnk)%ncol + ! input energy using dynamical core energy formula + te(:ncol,lchnk,1) = state(lchnk)%te_ini(:ncol,dyn_te_idx) + ! output energy + call pbuf_get_field(pbuf_get_chunk(pbuf2d,lchnk),teout_idx, teout) + + te(:ncol,lchnk,2) = teout(1:ncol) + ! surface pressure for heating rate + te(:ncol,lchnk,3) = state(lchnk)%pint(:ncol,pver+1) + ! model top pressure for heating rate (not constant for z-based vertical coordinate!) + te(:ncol,lchnk,4) = state(lchnk)%pint(:ncol,1) + end do + + ! Compute global means of input and output energies and of + ! surface pressure for heating rate (assume uniform ptop) + call gmean(te, te_glob, 4) + + if (begchunk .le. endchunk) then + teinp_glob = te_glob(1) + teout_glob = te_glob(2) + psurf_glob = te_glob(3) + ptopb_glob = te_glob(4) + + ! Global mean total energy difference + tedif_glob = teinp_glob - teout_glob + heat_glob = -tedif_glob/dtime * gravit / (psurf_glob - ptopb_glob) + if (masterproc) then + write(iulog,'(1x,a9,1x,i8,5(1x,e25.17))') "nstep, te", nstep, teinp_glob, teout_glob, & + heat_glob, psurf_glob, ptopb_glob + end if + else + heat_glob = 0._r8 + end if ! (begchunk .le. endchunk) + + end subroutine check_energy_gmean + + ! Return energy integrals (module variables) + subroutine check_energy_get_integrals(tedif_glob_out, heat_glob_out) + real(r8), intent(out), optional :: tedif_glob_out + real(r8), intent(out), optional :: heat_glob_out + + if ( present(tedif_glob_out) ) then + tedif_glob_out = tedif_glob + endif + + if ( present(heat_glob_out) ) then + heat_glob_out = heat_glob + endif + end subroutine check_energy_get_integrals + + ! Compute initial values of energy and water integrals, + ! zero cumulative tendencies + subroutine check_energy_timestep_init(state, tend, pbuf, col_type) + use physics_buffer, only: physics_buffer_desc, pbuf_set_field + use cam_abortutils, only: endrun + use dyn_tests_utils, only: vc_physics, vc_dycore + use cam_thermo_formula, only: ENERGY_FORMULA_DYCORE_SE, ENERGY_FORMULA_DYCORE_MPAS + use physics_types, only: physics_tend + use physics_types, only: phys_te_idx, dyn_te_idx + use time_manager, only: is_first_step + use physconst, only: cpair, rair + use air_composition, only: cpairv, cp_or_cv_dycore + + ! CCPP-ized subroutine + use check_energy_chng, only: check_energy_chng_timestep_init + + type(physics_state), intent(inout) :: state + type(physics_tend ), intent(inout) :: tend + type(physics_buffer_desc), pointer :: pbuf(:) + integer, optional :: col_type ! Flag indicating whether using grid or subcolumns + + real(r8) :: local_cp_phys(state%psetcols,pver) + real(r8) :: local_cp_or_cv_dycore(state%psetcols,pver) + real(r8) :: teout(state%ncol) ! dummy teout argument + integer :: lchnk ! chunk identifier + integer :: ncol ! number of atmospheric columns + character(len=512) :: errmsg + integer :: errflg + + lchnk = state%lchnk + ncol = state%ncol + + ! The code below is split into not-subcolumns and subcolumns code, as there is different handling of the + ! cp passed into the hydrostatic energy call. CAM-SIMA does not support subcolumns, so we keep this special + ! handling inside this CAM interface. (hplin, 9/9/24) + if(state%psetcols == pcols) then + ! No subcolumns + local_cp_phys(:ncol,:) = cpairv(:ncol,:,lchnk) + local_cp_or_cv_dycore(:ncol,:) = cp_or_cv_dycore(:ncol,:,lchnk) + else if (state%psetcols > pcols) then + ! Subcolumns code + ! Subcolumns specific error handling + if(.not. all(cpairv(:,:,lchnk) == cpair)) then + call endrun('check_energy_timestep_init: cpairv is not allowed to vary when subcolumns are turned on') + endif + + local_cp_phys(1:ncol,:) = cpair + + if (vc_dycore == ENERGY_FORMULA_DYCORE_MPAS) then + ! MPAS specific hydrostatic energy computation (internal energy) + local_cp_or_cv_dycore(:ncol,:) = cpair-rair + else if(vc_dycore == ENERGY_FORMULA_DYCORE_SE) then + ! SE specific hydrostatic energy (enthalpy) + local_cp_or_cv_dycore(:ncol,:) = cpair + else + ! cp_or_cv is not used in the underlying subroutine, zero it out to be sure + local_cp_or_cv_dycore(:ncol,:) = 0.0_r8 + endif + end if + + ! Call CCPP-ized underlying subroutine. + call check_energy_chng_timestep_init( & + ncol = ncol, & + pver = pver, & + pcnst = pcnst, & + is_first_timestep = is_first_step(), & + q = state%q(1:ncol,1:pver,1:pcnst), & + pdel = state%pdel(1:ncol,1:pver), & + u = state%u(1:ncol,1:pver), & + v = state%v(1:ncol,1:pver), & + T = state%T(1:ncol,1:pver), & + pintdry = state%pintdry(1:ncol,1:pver), & + phis = state%phis(1:ncol), & + zm = state%zm(1:ncol,:), & + cp_phys = local_cp_phys(1:ncol,:), & + cp_or_cv_dycore = local_cp_or_cv_dycore(1:ncol,:), & + te_ini_phys = state%te_ini(1:ncol,phys_te_idx), & + te_ini_dyn = state%te_ini(1:ncol,dyn_te_idx), & + tw_ini = state%tw_ini(1:ncol), & + te_cur_phys = state%te_cur(1:ncol,phys_te_idx), & + te_cur_dyn = state%te_cur(1:ncol,dyn_te_idx), & + tw_cur = state%tw_cur(1:ncol), & + tend_te_tnd = tend%te_tnd(1:ncol), & + tend_tw_tnd = tend%tw_tnd(1:ncol), & + temp_ini = state%temp_ini(:ncol,:), & + z_ini = state%z_ini(:ncol,:), & + count = state%count, & + teout = teout(1:ncol), & ! dummy argument - actual teout written to pbuf directly below + energy_formula_physics = vc_physics, & + energy_formula_dycore = vc_dycore, & + errmsg = errmsg, & + errflg = errflg & + ) + + ! initialize physics buffer + if (is_first_step()) then + call pbuf_set_field(pbuf, teout_idx, state%te_ini(:,dyn_te_idx), col_type=col_type) + end if + + end subroutine check_energy_timestep_init + + ! Check that the energy and water change matches the boundary fluxes + subroutine check_energy_cam_chng(state, tend, name, nstep, ztodt, & + flx_vap, flx_cnd, flx_ice, flx_sen) + use dyn_tests_utils, only: vc_physics, vc_dycore + use cam_thermo_formula, only: ENERGY_FORMULA_DYCORE_SE, ENERGY_FORMULA_DYCORE_MPAS + use cam_abortutils, only: endrun + use physics_types, only: phys_te_idx, dyn_te_idx + use physics_types, only: physics_tend + use physconst, only: cpair, rair, latice, latvap + use air_composition, only: cpairv, cp_or_cv_dycore + + ! CCPP-ized subroutine + use check_energy_chng, only: check_energy_chng_run + + type(physics_state), intent(inout) :: state + type(physics_tend ), intent(inout) :: tend + character*(*),intent(in) :: name ! parameterization name for fluxes + integer , intent(in) :: nstep ! current timestep number + real(r8), intent(in) :: ztodt ! physics timestep (s) + real(r8), intent(in) :: flx_vap(:) ! (pcols) - boundary flux of vapor (kg/m2/s) + real(r8), intent(in) :: flx_cnd(:) ! (pcols) - boundary flux of lwe liquid+ice (m/s) + real(r8), intent(in) :: flx_ice(:) ! (pcols) - boundary flux of lwe ice (m/s) + real(r8), intent(in) :: flx_sen(:) ! (pcols) - boundary flux of sensible heat (W/m2) + + integer :: lchnk ! chunk identifier + integer :: ncol ! number of atmospheric columns + real(r8) :: local_cp_phys(state%psetcols,pver) + real(r8) :: local_cp_or_cv_dycore(state%psetcols,pver) + real(r8) :: scaling_dycore(state%ncol,pver) + character(len=512) :: errmsg + integer :: errflg + + lchnk = state%lchnk + ncol = state%ncol + + if(state%psetcols == pcols) then + ! No subcolumns + local_cp_phys(:ncol,:) = cpairv(:ncol,:,lchnk) + + ! Only if using MPAS or SE energy formula cp_or_cv_dycore is nonzero. + if(vc_dycore == ENERGY_FORMULA_DYCORE_MPAS .or. vc_dycore == ENERGY_FORMULA_DYCORE_SE) then + local_cp_or_cv_dycore(:ncol,:) = cp_or_cv_dycore(:ncol,:,lchnk) + + scaling_dycore(:ncol,:) = cpairv(:ncol,:,lchnk)/local_cp_or_cv_dycore(:ncol,:) ! cp/cv scaling + endif + else if(state%psetcols > pcols) then + ! Subcolumns + if(.not. all(cpairv(:,:,:) == cpair)) then + call endrun('check_energy_chng: cpairv is not allowed to vary when subcolumns are turned on') + endif + + local_cp_phys(:,:) = cpair + + ! Note: cp_or_cv set above for pressure coordinate + if (vc_dycore == ENERGY_FORMULA_DYCORE_MPAS) then + ! compute cv if vertical coordinate is height: cv = cp - R + local_cp_or_cv_dycore(:ncol,:) = cpair-rair + scaling_dycore(:ncol,:) = cpairv(:ncol,:,lchnk)/local_cp_or_cv_dycore(:ncol,:) ! cp/cv scaling + else if (vc_dycore == ENERGY_FORMULA_DYCORE_SE) then + ! SE specific hydrostatic energy + local_cp_or_cv_dycore(:ncol,:) = cpair + scaling_dycore(:ncol,:) = 1.0_r8 + else + ! Moist pressure... use phys formula, cp_or_cv_dycore is unused. Reset for safety + local_cp_or_cv_dycore(:ncol,:) = 0.0_r8 + scaling_dycore(:ncol,:) = 0.0_r8 + end if + endif + + ! Call CCPP-ized underlying subroutine. + call check_energy_chng_run( & + ncol = ncol, & + pver = pver, & + pcnst = pcnst, & + iulog = iulog, & + q = state%q(1:ncol,1:pver,1:pcnst), & + pdel = state%pdel(1:ncol,1:pver), & + u = state%u(1:ncol,1:pver), & + v = state%v(1:ncol,1:pver), & + T = state%T(1:ncol,1:pver), & + pintdry = state%pintdry(1:ncol,1:pver), & + phis = state%phis(1:ncol), & + zm = state%zm(1:ncol,:), & + cp_phys = local_cp_phys(1:ncol,:), & + cp_or_cv_dycore = local_cp_or_cv_dycore(1:ncol,:), & + scaling_dycore = scaling_dycore(1:ncol,:), & + te_cur_phys = state%te_cur(1:ncol,phys_te_idx), & + te_cur_dyn = state%te_cur(1:ncol,dyn_te_idx), & + tw_cur = state%tw_cur(1:ncol), & + tend_te_tnd = tend%te_tnd(1:ncol), & + tend_tw_tnd = tend%tw_tnd(1:ncol), & + temp_ini = state%temp_ini(:ncol,:), & + z_ini = state%z_ini(:ncol,:), & + count = state%count, & + ztodt = ztodt, & + latice = latice, & + latvap = latvap, & + energy_formula_physics = vc_physics, & + energy_formula_dycore = vc_dycore, & + name = name, & + flx_vap = flx_vap, & + flx_cnd = flx_cnd, & + flx_ice = flx_ice, & + flx_sen = flx_sen, & + errmsg = errmsg, & + errflg = errflg & + ) + + end subroutine check_energy_cam_chng + + ! Add heating rate required for global mean total energy conservation + subroutine check_energy_cam_fix(state, ptend, nstep, eshflx) + use physics_types, only: physics_ptend, physics_ptend_init + use physconst, only: gravit + + ! SCAM support + use scamMod, only: single_column, use_camiop, heat_glob_scm + use cam_history, only: write_camiop + use cam_history, only: outfld + + ! CCPP-ized subroutine + use check_energy_fix, only: check_energy_fix_run + + type(physics_state), intent(in) :: state + type(physics_ptend), intent(out) :: ptend + + integer , intent(in) :: nstep ! time step number + real(r8), intent(out) :: eshflx(pcols) ! effective sensible heat flux + + integer :: ncol ! number of atmospheric columns in chunk + integer :: lchnk ! chunk number + real(r8) :: heat_out(pcols) + character(len=64) :: dummy_scheme_name ! dummy scheme name for CCPP-ized scheme + + integer :: errflg + character(len=512) :: errmsg + + lchnk = state%lchnk + ncol = state%ncol + + call physics_ptend_init(ptend, state%psetcols, 'chkenergyfix', ls=.true.) + +#if ( defined OFFLINE_DYN ) + ! disable the energy fix for offline driver + heat_glob = 0._r8 +#endif + + ! Special handling of energy fix for SCAM - supplied via CAMIOP - zero's for normal IOPs + if (single_column) then + if (use_camiop) then + heat_glob = heat_glob_scm(1) + else + heat_glob = 0._r8 + endif + endif + + if (nstep > 0 .and. write_camiop) then + heat_out(:ncol) = heat_glob + call outfld('heat_glob', heat_out(:ncol), pcols, lchnk) + endif + ! Call the CCPP-ized subroutine (for non-SCAM) + ! to compute the effective sensible heat flux and save to ptend%s + call check_energy_fix_run( & + ncol = ncol, & + pver = pver, & + pint = state%pint(:ncol,:), & + gravit = gravit, & + heat_glob = heat_glob, & + ptend_s = ptend%s(:ncol,:), & + eshflx = eshflx(:ncol), & + scheme_name = dummy_scheme_name, & + errmsg = errmsg, & + errflg = errflg & + ) + + end subroutine check_energy_cam_fix end module check_energy diff --git a/src/physics/cam/clubb_intr.F90 b/src/physics/cam/clubb_intr.F90 index 9bbf211fba..a9f25f0256 100644 --- a/src/physics/cam/clubb_intr.F90 +++ b/src/physics/cam/clubb_intr.F90 @@ -31,7 +31,7 @@ module clubb_intr #ifdef CLUBB_SGS use clubb_api_module, only: pdf_parameter, implicit_coefs_terms - use clubb_api_module, only: clubb_config_flags_type, grid, stats, & + use clubb_api_module, only: clubb_config_flags_type, grid, stats, & nu_vertical_res_dep, stats_metadata_type, & hm_metadata_type, sclr_idx_type @@ -52,12 +52,16 @@ module clubb_intr stats_sfc(pcols) ! stats_sfc type (hm_metadata_type) :: & hm_metadata - + type (stats_metadata_type) :: & stats_metadata type (sclr_idx_type) :: & sclr_idx + + integer :: & + nzm_clubb, & !Number of vertical levels used by CLUBB momentum variables + nzt_clubb !Number of vertical levels used by CLUBB thermodynamic variables #endif private @@ -95,7 +99,7 @@ module clubb_intr ! These are zero by default, but will be set by SILHS before they are used by subcolumns integer :: & - hydromet_dim = 0, & + hydromet_dim = 0, & pdf_dim = 0 @@ -117,7 +121,7 @@ module clubb_intr hm_metadata #endif #endif - + ! ------------ ! ! Private data ! ! ------------ ! @@ -340,7 +344,7 @@ module clubb_intr clubb_l_mono_flux_lim_um, & ! Flag to turn on monotonic flux limiter for um clubb_l_mono_flux_lim_vm, & ! Flag to turn on monotonic flux limiter for vm clubb_l_mono_flux_lim_spikefix, & ! Flag to implement monotonic flux limiter code that - ! eliminates spurious drying tendencies at model top + ! eliminates spurious drying tendencies at model top clubb_l_host_applies_sfc_fluxes ! Whether the host model applies the surface fluxes logical :: & @@ -349,7 +353,7 @@ module clubb_intr ! Constant parameters logical, parameter, private :: & l_implemented = .true. ! Implemented in a host model (always true) - + logical, parameter, private :: & apply_to_heat = .false. ! Apply WACCM energy fixer to heat or not (.true. = yes (duh)) @@ -1477,7 +1481,7 @@ subroutine clubb_ini_cam(pbuf2d) logical, parameter :: l_input_fields = .false. ! Always false for CAM-CLUBB. logical, parameter :: l_update_pressure = .false. ! Always false for CAM-CLUBB. - integer :: nlev, ierr=0 + integer :: ierr=0 real(r8) :: & C1, C1b, C1c, C2rt, C2thl, C2rtthl, & @@ -1505,12 +1509,15 @@ subroutine clubb_ini_cam(pbuf2d) !----- Begin Code ----- - nlev = pver + 1 - top_lev - if (core_rknd /= r8) then call endrun('clubb_ini_cam: CLUBB library core_rknd must match CAM r8 and it does not') end if + ! Determine number of vertical levels used in clubb, thermo variables are nzt_clubb + ! and momentum variables are nzm_clubb + nzt_clubb = pver + 1 - top_lev + nzm_clubb = pverp + 1 - top_lev + ! Allocate PDF parameters across columns and chunks allocate( & pdf_params_chnk(begchunk:endchunk), & @@ -1733,7 +1740,7 @@ subroutine clubb_ini_cam(pbuf2d) clubb_params_single_col(iwpxp_Ri_exp) = clubb_wpxp_Ri_exp clubb_params_single_col(iz_displace) = clubb_z_displace - ! Override clubb default + ! Override clubb default if ( trim(subcol_scheme) == 'SILHS' ) then clubb_config_flags%saturation_formula = saturation_flatau else @@ -1742,17 +1749,17 @@ subroutine clubb_ini_cam(pbuf2d) ! Define model constant parameters call setup_parameters_model_api( theta0, ts_nudge, clubb_params_single_col(iSkw_max_mag) ) - + ! Set up CLUBB core. Note that some of these inputs are overwritten ! when clubb_tend_cam is called. The reason is that heights can change ! at each time step, which is why dummy arrays are read in here for heights ! as they are immediately overwrote. !$OMP PARALLEL - call check_clubb_settings_api( nlev+1, clubb_params_single_col, & ! Intent(in) - l_implemented, & ! Intent(in) - l_input_fields, & ! Intent(in) - clubb_config_flags, & ! intent(in) - err_code ) ! Intent(out) + call check_clubb_settings_api( nzm_clubb, clubb_params_single_col, & ! Intent(in) + l_implemented, & ! Intent(in) + l_input_fields, & ! Intent(in) + clubb_config_flags, & ! intent(in) + err_code ) ! Intent(out) if ( err_code == clubb_fatal_error ) then call endrun('clubb_ini_cam: FATAL ERROR CALLING SETUP_CLUBB_CORE') @@ -1777,96 +1784,96 @@ subroutine clubb_ini_cam(pbuf2d) ! ----------------------------------------------------------------- ! ! These are default CLUBB output. Not the higher order history budgets - call addfld ('RHO_CLUBB', (/ 'lev' /), 'A', 'kg/m3', 'Air Density') - call addfld ('UP2_CLUBB', (/ 'ilev' /), 'A', 'm2/s2', 'Zonal Velocity Variance') - call addfld ('VP2_CLUBB', (/ 'ilev' /), 'A', 'm2/s2', 'Meridional Velocity Variance') - call addfld ('WP2_CLUBB', (/ 'ilev' /), 'A', 'm2/s2', 'Vertical Velocity Variance') - call addfld ('WP2_ZT_CLUBB', (/ 'lev' /), 'A', 'm2/s2', 'Vert Vel Variance on zt grid') - call addfld ('UPWP_CLUBB', (/ 'ilev' /), 'A', 'm2/s2', 'Zonal Momentum Flux') - call addfld ('VPWP_CLUBB', (/ 'ilev' /), 'A', 'm2/s2', 'Meridional Momentum Flux') - call addfld ('WP3_CLUBB', (/ 'lev' /), 'A', 'm3/s3', 'Third Moment Vertical Velocity') - call addfld ('WPTHLP_CLUBB', (/ 'ilev' /), 'A', 'W/m2', 'Heat Flux') - call addfld ('WPRTP_CLUBB', (/ 'ilev' /), 'A', 'W/m2', 'Moisture Flux') - call addfld ('RTP2_CLUBB', (/ 'ilev' /), 'A', 'kg^2/kg^2', 'Moisture Variance') - call addfld ('RTP2_ZT_CLUBB', (/ 'lev' /), 'A', 'kg^2/kg^2','Moisture Variance on zt grid') - call addfld ('PDFP_RTP2_CLUBB', (/ 'ilev' /), 'A', 'kg^2/kg^2','PDF Rtot Variance') - call addfld ('THLP2_CLUBB', (/ 'ilev' /), 'A', 'K^2', 'Temperature Variance') - call addfld ('THLP2_ZT_CLUBB', (/ 'lev' /), 'A', 'K^2', 'Temperature Variance on zt grid') - call addfld ('RTPTHLP_CLUBB', (/ 'ilev' /), 'A', 'K kg/kg', 'Temp. Moist. Covariance') - call addfld ('RCM_CLUBB', (/ 'lev' /), 'A', 'kg/kg', 'Cloud Water Mixing Ratio') - call addfld ('RTM_CLUBB', (/ 'lev' /), 'A', 'kg/kg', 'Total Water Mixing Ratio') - call addfld ('THLM_CLUBB', (/ 'lev' /), 'A', 'K', 'Liquid Water Potential Temperature') - call addfld ('WPRCP_CLUBB', (/ 'ilev' /), 'A', 'W/m2', 'Liquid Water Flux') - call addfld ('CLOUDFRAC_CLUBB', (/ 'lev' /), 'A', 'fraction', 'Cloud Fraction') - call addfld ('RCMINLAYER_CLUBB', (/ 'lev' /), 'A', 'kg/kg', 'Cloud Water in Layer') - call addfld ('CLOUDCOVER_CLUBB', (/ 'lev' /), 'A', 'fraction', 'Cloud Cover') - call addfld ('WPTHVP_CLUBB', (/ 'ilev' /), 'A', 'W/m2', 'Buoyancy Flux') - call addfld ('RVMTEND_CLUBB', (/ 'lev' /), 'A', 'kg/kg /s', 'Water vapor tendency') - call addfld ('STEND_CLUBB', (/ 'lev' /), 'A', 'J/(kg s)', 'Static energy tendency') - call addfld ('RCMTEND_CLUBB', (/ 'lev' /), 'A', 'kg/kg /s', 'Cloud Liquid Water Tendency') - call addfld ('RIMTEND_CLUBB', (/ 'lev' /), 'A', 'kg/kg /s', 'Cloud Ice Tendency') - call addfld ('UTEND_CLUBB', (/ 'lev' /), 'A', 'm/s /s', 'U-wind Tendency') - call addfld ('VTEND_CLUBB', (/ 'lev' /), 'A', 'm/s /s', 'V-wind Tendency') - call addfld ('ZT_CLUBB', (/ 'lev' /), 'A', 'm', 'Thermodynamic Heights') - call addfld ('ZM_CLUBB', (/ 'ilev' /), 'A', 'm', 'Momentum Heights') - call addfld ('UM_CLUBB', (/ 'lev' /), 'A', 'm/s', 'Zonal Wind') - call addfld ('VM_CLUBB', (/ 'lev' /), 'A', 'm/s', 'Meridional Wind') - call addfld ('WM_ZT_CLUBB', (/ 'lev' /), 'A', 'm/s', 'Vertical Velocity') - call addfld ('PBLH', horiz_only, 'A', 'm', 'PBL height') - call addfld ('CLDST', (/ 'lev' /), 'A', 'fraction', 'Stratus cloud fraction') - call addfld ('ZMDLF', (/ 'lev' /), 'A', 'kg/kg/s', 'Detrained liquid water from ZM convection') - call addfld ('TTENDICE', (/ 'lev' /), 'A', 'K/s', 'T tendency from Ice Saturation Adjustment') - call addfld ('QVTENDICE', (/ 'lev' /), 'A', 'kg/kg/s', 'Q tendency from Ice Saturation Adjustment') - call addfld ('QITENDICE', (/ 'lev' /), 'A', 'kg/kg/s', 'CLDICE tendency from Ice Saturation Adjustment') - call addfld ('NITENDICE', (/ 'lev' /), 'A', 'kg/kg/s', 'NUMICE tendency from Ice Saturation Adjustment') - - - call addfld ('QCTENDICE', (/ 'lev' /), 'A', 'kg/kg/s', 'CLDICE tendency from Ice Saturation Adjustment') - call addfld ('NCTENDICE', (/ 'lev' /), 'A', 'kg/kg/s', 'NUMICE tendency from Ice Saturation Adjustment') - call addfld ('FQTENDICE', (/ 'lev' /), 'A', 'fraction', 'Frequency of Ice Saturation Adjustment') - - call addfld ('DPDLFLIQ', (/ 'lev' /), 'A', 'kg/kg/s', 'Detrained liquid water from deep convection') - call addfld ('DPDLFICE', (/ 'lev' /), 'A', 'kg/kg/s', 'Detrained ice from deep convection') - call addfld ('DPDLFT', (/ 'lev' /), 'A', 'K/s', 'T-tendency due to deep convective detrainment') - call addfld ('RELVAR', (/ 'lev' /), 'A', '-', 'Relative cloud water variance') - call addfld ('CLUBB_GRID_SIZE', horiz_only, 'A', 'm', 'Horizontal grid box size seen by CLUBB') - - - call addfld ('ZMDLFI', (/ 'lev' /), 'A', 'kg/kg/s', 'Detrained ice water from ZM convection') - call addfld ('CONCLD', (/ 'lev' /), 'A', 'fraction', 'Convective cloud cover') - call addfld ('CMELIQ', (/ 'lev' /), 'A', 'kg/kg/s', 'Rate of cond-evap of liq within the cloud') - call addfld ('DETNLIQTND', (/ 'lev' /), 'A', '1/kg/s', 'CLDNUM tendency in detrained water') - - call addfld ('QSATFAC', (/ 'lev' /), 'A', '-', 'Subgrid cloud water saturation scaling factor') - call addfld ('KVH_CLUBB', (/ 'ilev' /), 'A', 'm2/s', 'CLUBB vertical diffusivity of heat/moisture on interface levels') - call addfld ('ELEAK_CLUBB', horiz_only, 'A', 'W/m2', 'CLUBB energy leak') - call addfld ('TFIX_CLUBB', horiz_only, 'A', 'K', 'Temperature increment to conserve energy') + call addfld ('RHO_CLUBB', (/ 'lev' /), 'A', 'kg/m3', 'Air Density', sampled_on_subcycle=.true.) + call addfld ('UP2_CLUBB', (/ 'ilev' /), 'A', 'm2/s2', 'Zonal Velocity Variance', sampled_on_subcycle=.true.) + call addfld ('VP2_CLUBB', (/ 'ilev' /), 'A', 'm2/s2', 'Meridional Velocity Variance', sampled_on_subcycle=.true.) + call addfld ('WP2_CLUBB', (/ 'ilev' /), 'A', 'm2/s2', 'Vertical Velocity Variance', sampled_on_subcycle=.true.) + call addfld ('WP2_ZT_CLUBB', (/ 'lev' /), 'A', 'm2/s2', 'Vert Vel Variance on zt grid', sampled_on_subcycle=.true.) + call addfld ('UPWP_CLUBB', (/ 'ilev' /), 'A', 'm2/s2', 'Zonal Momentum Flux', sampled_on_subcycle=.true.) + call addfld ('VPWP_CLUBB', (/ 'ilev' /), 'A', 'm2/s2', 'Meridional Momentum Flux', sampled_on_subcycle=.true.) + call addfld ('WP3_CLUBB', (/ 'lev' /), 'A', 'm3/s3', 'Third Moment Vertical Velocity', sampled_on_subcycle=.true.) + call addfld ('WPTHLP_CLUBB', (/ 'ilev' /), 'A', 'W/m2', 'Heat Flux', sampled_on_subcycle=.true.) + call addfld ('WPRTP_CLUBB', (/ 'ilev' /), 'A', 'W/m2', 'Moisture Flux', sampled_on_subcycle=.true.) + call addfld ('RTP2_CLUBB', (/ 'ilev' /), 'A', 'kg^2/kg^2', 'Moisture Variance', sampled_on_subcycle=.true.) + call addfld ('RTP2_ZT_CLUBB', (/ 'lev' /), 'A', 'kg^2/kg^2','Moisture Variance on zt grid', sampled_on_subcycle=.true.) + call addfld ('PDFP_RTP2_CLUBB', (/ 'ilev' /), 'A', 'kg^2/kg^2','PDF Rtot Variance', sampled_on_subcycle=.true.) + call addfld ('THLP2_CLUBB', (/ 'ilev' /), 'A', 'K^2', 'Temperature Variance', sampled_on_subcycle=.true.) + call addfld ('THLP2_ZT_CLUBB', (/ 'lev' /), 'A', 'K^2', 'Temperature Variance on zt grid', sampled_on_subcycle=.true.) + call addfld ('RTPTHLP_CLUBB', (/ 'ilev' /), 'A', 'K kg/kg', 'Temp. Moist. Covariance', sampled_on_subcycle=.true.) + call addfld ('RCM_CLUBB', (/ 'lev' /), 'A', 'kg/kg', 'Cloud Water Mixing Ratio', sampled_on_subcycle=.true.) + call addfld ('RTM_CLUBB', (/ 'lev' /), 'A', 'kg/kg', 'Total Water Mixing Ratio', sampled_on_subcycle=.true.) + call addfld ('THLM_CLUBB', (/ 'lev' /), 'A', 'K', 'Liquid Water Potential Temperature', sampled_on_subcycle=.true.) + call addfld ('WPRCP_CLUBB', (/ 'ilev' /), 'A', 'W/m2', 'Liquid Water Flux', sampled_on_subcycle=.true.) + call addfld ('CLOUDFRAC_CLUBB', (/ 'lev' /), 'A', 'fraction', 'Cloud Fraction', sampled_on_subcycle=.true.) + call addfld ('RCMINLAYER_CLUBB', (/ 'lev' /), 'A', 'kg/kg', 'Cloud Water in Layer', sampled_on_subcycle=.true.) + call addfld ('CLOUDCOVER_CLUBB', (/ 'lev' /), 'A', 'fraction', 'Cloud Cover', sampled_on_subcycle=.true.) + call addfld ('WPTHVP_CLUBB', (/ 'ilev' /), 'A', 'W/m2', 'Buoyancy Flux', sampled_on_subcycle=.true.) + call addfld ('RVMTEND_CLUBB', (/ 'lev' /), 'A', 'kg/kg /s', 'Water vapor tendency', sampled_on_subcycle=.true.) + call addfld ('STEND_CLUBB', (/ 'lev' /), 'A', 'J/(kg s)', 'Static energy tendency', sampled_on_subcycle=.true.) + call addfld ('RCMTEND_CLUBB', (/ 'lev' /), 'A', 'kg/kg /s', 'Cloud Liquid Water Tendency', sampled_on_subcycle=.true.) + call addfld ('RIMTEND_CLUBB', (/ 'lev' /), 'A', 'kg/kg /s', 'Cloud Ice Tendency', sampled_on_subcycle=.true.) + call addfld ('UTEND_CLUBB', (/ 'lev' /), 'A', 'm/s /s', 'U-wind Tendency', sampled_on_subcycle=.true.) + call addfld ('VTEND_CLUBB', (/ 'lev' /), 'A', 'm/s /s', 'V-wind Tendency', sampled_on_subcycle=.true.) + call addfld ('ZT_CLUBB', (/ 'lev' /), 'A', 'm', 'Thermodynamic Heights', sampled_on_subcycle=.true.) + call addfld ('ZM_CLUBB', (/ 'ilev' /), 'A', 'm', 'Momentum Heights', sampled_on_subcycle=.true.) + call addfld ('UM_CLUBB', (/ 'lev' /), 'A', 'm/s', 'Zonal Wind', sampled_on_subcycle=.true.) + call addfld ('VM_CLUBB', (/ 'lev' /), 'A', 'm/s', 'Meridional Wind', sampled_on_subcycle=.true.) + call addfld ('WM_ZT_CLUBB', (/ 'lev' /), 'A', 'm/s', 'Vertical Velocity', sampled_on_subcycle=.true.) + call addfld ('PBLH', horiz_only, 'A', 'm', 'PBL height', sampled_on_subcycle=.true.) + call addfld ('CLDST', (/ 'lev' /), 'A', 'fraction', 'Stratus cloud fraction', sampled_on_subcycle=.true.) + call addfld ('ZMDLF', (/ 'lev' /), 'A', 'kg/kg/s', 'Detrained liquid water from ZM convection', sampled_on_subcycle=.true.) + call addfld ('TTENDICE', (/ 'lev' /), 'A', 'K/s', 'T tendency from Ice Saturation Adjustment', sampled_on_subcycle=.true.) + call addfld ('QVTENDICE', (/ 'lev' /), 'A', 'kg/kg/s', 'Q tendency from Ice Saturation Adjustment', sampled_on_subcycle=.true.) + call addfld ('QITENDICE', (/ 'lev' /), 'A', 'kg/kg/s', 'CLDICE tendency from Ice Saturation Adjustment', sampled_on_subcycle=.true.) + call addfld ('NITENDICE', (/ 'lev' /), 'A', 'kg/kg/s', 'NUMICE tendency from Ice Saturation Adjustment', sampled_on_subcycle=.true.) + + + call addfld ('QCTENDICE', (/ 'lev' /), 'A', 'kg/kg/s', 'CLDICE tendency from Ice Saturation Adjustment', sampled_on_subcycle=.true.) + call addfld ('NCTENDICE', (/ 'lev' /), 'A', 'kg/kg/s', 'NUMICE tendency from Ice Saturation Adjustment', sampled_on_subcycle=.true.) + call addfld ('FQTENDICE', (/ 'lev' /), 'A', 'fraction', 'Frequency of Ice Saturation Adjustment', sampled_on_subcycle=.true.) + + call addfld ('DPDLFLIQ', (/ 'lev' /), 'A', 'kg/kg/s', 'Detrained liquid water from deep convection', sampled_on_subcycle=.true.) + call addfld ('DPDLFICE', (/ 'lev' /), 'A', 'kg/kg/s', 'Detrained ice from deep convection', sampled_on_subcycle=.true.) + call addfld ('DPDLFT', (/ 'lev' /), 'A', 'K/s', 'T-tendency due to deep convective detrainment', sampled_on_subcycle=.true.) + call addfld ('RELVAR', (/ 'lev' /), 'A', '-', 'Relative cloud water variance', sampled_on_subcycle=.true.) + call addfld ('CLUBB_GRID_SIZE', horiz_only, 'A', 'm', 'Horizontal grid box size seen by CLUBB', sampled_on_subcycle=.true.) + + + call addfld ('ZMDLFI', (/ 'lev' /), 'A', 'kg/kg/s', 'Detrained ice water from ZM convection', sampled_on_subcycle=.true.) + call addfld ('CONCLD', (/ 'lev' /), 'A', 'fraction', 'Convective cloud cover', sampled_on_subcycle=.true.) + call addfld ('CMELIQ', (/ 'lev' /), 'A', 'kg/kg/s', 'Rate of cond-evap of liq within the cloud', sampled_on_subcycle=.true.) + call addfld ('DETNLIQTND', (/ 'lev' /), 'A', '1/kg/s', 'CLDNUM tendency in detrained water', sampled_on_subcycle=.true.) + + call addfld ('QSATFAC', (/ 'lev' /), 'A', '-', 'Subgrid cloud water saturation scaling factor', sampled_on_subcycle=.true.) + call addfld ('KVH_CLUBB', (/ 'ilev' /), 'A', 'm2/s', 'CLUBB vertical diffusivity of heat/moisture on interface levels', sampled_on_subcycle=.true.) + call addfld ('ELEAK_CLUBB', horiz_only, 'A', 'W/m2', 'CLUBB energy leak', sampled_on_subcycle=.true.) + call addfld ('TFIX_CLUBB', horiz_only, 'A', 'K', 'Temperature increment to conserve energy', sampled_on_subcycle=.true.) ! ---------------------------------------------------------------------------- ! ! Below are for detailed analysis of EDMF Scheme ! ! ---------------------------------------------------------------------------- ! if (do_clubb_mf) then - call addfld ( 'edmf_DRY_A' , (/ 'ilev' /), 'A', 'fraction', 'Dry updraft area fraction (EDMF)' ) - call addfld ( 'edmf_MOIST_A' , (/ 'ilev' /), 'A', 'fraction', 'Moist updraft area fraction (EDMF)' ) - call addfld ( 'edmf_DRY_W' , (/ 'ilev' /), 'A', 'm/s' , 'Dry updraft vertical velocity (EDMF)' ) - call addfld ( 'edmf_MOIST_W' , (/ 'ilev' /), 'A', 'm/s' , 'Moist updraft vertical velocity (EDMF)' ) - call addfld ( 'edmf_DRY_QT' , (/ 'ilev' /), 'A', 'kg/kg' , 'Dry updraft total water mixing ratio (EDMF)' ) - call addfld ( 'edmf_MOIST_QT' , (/ 'ilev' /), 'A', 'kg/kg' , 'Moist updraft total water mixing ratio (EDMF)' ) - call addfld ( 'edmf_DRY_THL' , (/ 'ilev' /), 'A', 'K' , 'Dry updraft liquid-ice potential temperature (EDMF)' ) - call addfld ( 'edmf_MOIST_THL', (/ 'ilev' /), 'A', 'K' , 'Moist updraft liquid-ice potential temperature (EDMF)' ) - call addfld ( 'edmf_DRY_U' , (/ 'ilev' /), 'A', 'm/s' , 'Dry updraft zonal velocity (EDMF)' ) - call addfld ( 'edmf_MOIST_U' , (/ 'ilev' /), 'A', 'm/s' , 'Moist updraft zonal velocity (EDMF)' ) - call addfld ( 'edmf_DRY_V' , (/ 'ilev' /), 'A', 'm/s' , 'Dry updraft meridional velocity (EDMF)' ) - call addfld ( 'edmf_MOIST_V' , (/ 'ilev' /), 'A', 'm/s' , 'Moist updraft meridional velocity (EDMF)' ) - call addfld ( 'edmf_MOIST_QC' , (/ 'ilev' /), 'A', 'kg/kg' , 'Moist updraft condensate mixing ratio (EDMF)' ) - call addfld ( 'edmf_S_AE' , (/ 'ilev' /), 'A', 'fraction', '1 minus sum of a_i*w_i (EDMF)' ) - call addfld ( 'edmf_S_AW' , (/ 'ilev' /), 'A', 'm/s' , 'Sum of a_i*w_i (EDMF)' ) - call addfld ( 'edmf_S_AWTHL' , (/ 'ilev' /), 'A', 'K m/s' , 'Sum of a_i*w_i*thl_i (EDMF)' ) - call addfld ( 'edmf_S_AWQT' , (/ 'ilev' /), 'A', 'kgm/kgs' , 'Sum of a_i*w_i*q_ti (EDMF)' ) - call addfld ( 'edmf_S_AWU' , (/ 'ilev' /), 'A', 'm2/s2' , 'Sum of a_i*w_i*u_i (EDMF)' ) - call addfld ( 'edmf_S_AWV' , (/ 'ilev' /), 'A', 'm2/s2' , 'Sum of a_i*w_i*v_i (EDMF)' ) - call addfld ( 'edmf_thlflx' , (/ 'ilev' /), 'A', 'W/m2' , 'thl flux (EDMF)' ) - call addfld ( 'edmf_qtflx' , (/ 'ilev' /), 'A', 'W/m2' , 'qt flux (EDMF)' ) + call addfld ( 'edmf_DRY_A' , (/ 'ilev' /), 'A', 'fraction', 'Dry updraft area fraction (EDMF)', sampled_on_subcycle=.true.) + call addfld ( 'edmf_MOIST_A' , (/ 'ilev' /), 'A', 'fraction', 'Moist updraft area fraction (EDMF)', sampled_on_subcycle=.true.) + call addfld ( 'edmf_DRY_W' , (/ 'ilev' /), 'A', 'm/s' , 'Dry updraft vertical velocity (EDMF)', sampled_on_subcycle=.true.) + call addfld ( 'edmf_MOIST_W' , (/ 'ilev' /), 'A', 'm/s' , 'Moist updraft vertical velocity (EDMF)', sampled_on_subcycle=.true.) + call addfld ( 'edmf_DRY_QT' , (/ 'ilev' /), 'A', 'kg/kg' , 'Dry updraft total water mixing ratio (EDMF)', sampled_on_subcycle=.true.) + call addfld ( 'edmf_MOIST_QT' , (/ 'ilev' /), 'A', 'kg/kg' , 'Moist updraft total water mixing ratio (EDMF)', sampled_on_subcycle=.true.) + call addfld ( 'edmf_DRY_THL' , (/ 'ilev' /), 'A', 'K' , 'Dry updraft liquid-ice potential temperature (EDMF)', sampled_on_subcycle=.true.) + call addfld ( 'edmf_MOIST_THL', (/ 'ilev' /), 'A', 'K' , 'Moist updraft liquid-ice potential temperature (EDMF)', sampled_on_subcycle=.true.) + call addfld ( 'edmf_DRY_U' , (/ 'ilev' /), 'A', 'm/s' , 'Dry updraft zonal velocity (EDMF)', sampled_on_subcycle=.true.) + call addfld ( 'edmf_MOIST_U' , (/ 'ilev' /), 'A', 'm/s' , 'Moist updraft zonal velocity (EDMF)', sampled_on_subcycle=.true.) + call addfld ( 'edmf_DRY_V' , (/ 'ilev' /), 'A', 'm/s' , 'Dry updraft meridional velocity (EDMF)', sampled_on_subcycle=.true.) + call addfld ( 'edmf_MOIST_V' , (/ 'ilev' /), 'A', 'm/s' , 'Moist updraft meridional velocity (EDMF)', sampled_on_subcycle=.true.) + call addfld ( 'edmf_MOIST_QC' , (/ 'ilev' /), 'A', 'kg/kg' , 'Moist updraft condensate mixing ratio (EDMF)', sampled_on_subcycle=.true.) + call addfld ( 'edmf_S_AE' , (/ 'ilev' /), 'A', 'fraction', '1 minus sum of a_i*w_i (EDMF)', sampled_on_subcycle=.true.) + call addfld ( 'edmf_S_AW' , (/ 'ilev' /), 'A', 'm/s' , 'Sum of a_i*w_i (EDMF)', sampled_on_subcycle=.true.) + call addfld ( 'edmf_S_AWTHL' , (/ 'ilev' /), 'A', 'K m/s' , 'Sum of a_i*w_i*thl_i (EDMF)', sampled_on_subcycle=.true.) + call addfld ( 'edmf_S_AWQT' , (/ 'ilev' /), 'A', 'kgm/kgs' , 'Sum of a_i*w_i*q_ti (EDMF)', sampled_on_subcycle=.true.) + call addfld ( 'edmf_S_AWU' , (/ 'ilev' /), 'A', 'm2/s2' , 'Sum of a_i*w_i*u_i (EDMF)', sampled_on_subcycle=.true.) + call addfld ( 'edmf_S_AWV' , (/ 'ilev' /), 'A', 'm2/s2' , 'Sum of a_i*w_i*v_i (EDMF)', sampled_on_subcycle=.true.) + call addfld ( 'edmf_thlflx' , (/ 'ilev' /), 'A', 'W/m2' , 'thl flux (EDMF)', sampled_on_subcycle=.true.) + call addfld ( 'edmf_qtflx' , (/ 'ilev' /), 'A', 'W/m2' , 'qt flux (EDMF)', sampled_on_subcycle=.true.) end if if ( trim(subcol_scheme) /= 'SILHS' ) then @@ -1885,9 +1892,9 @@ subroutine clubb_ini_cam(pbuf2d) dum3 = 300._r8 if (stats_metadata%l_stats) then - + call stats_init_clubb( .true., dum1, dum2, & - nlev+1, nlev+1, nlev+1, dum3, & + nzm_clubb, nzm_clubb, nzm_clubb, dum3, & stats_zt(:), stats_zm(:), stats_sfc(:), & stats_rad_zt(:), stats_rad_zm(:)) @@ -2111,6 +2118,7 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & use cam_logfile, only: iulog use tropopause, only: tropopause_findChemTrop use time_manager, only: get_nstep, is_first_restart_step + use perf_mod, only: t_startf, t_stopf #ifdef CLUBB_SGS use hb_diff, only: pblintd @@ -2146,8 +2154,6 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & use macrop_driver, only: liquid_macro_tend use clubb_mf, only: integrate_mf - use perf_mod - #endif implicit none @@ -2185,12 +2191,14 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & ! Local Variables ! ! ---------------------------------------------------- ! + integer :: i !Must be delcared outside "CLUBB_SGS" ifdef for det_s and det_ice zero-ing loops + #ifdef CLUBB_SGS type(physics_state) :: state1 ! Local copy of state variable type(physics_ptend) :: ptend_loc ! Local tendency from processes, added up to return as ptend_all - integer :: i, j, k, t, ixind, nadv + integer :: j, k, t, ixind, nadv integer :: ixcldice, ixcldliq, ixnumliq, ixnumice, ixq integer :: itim_old integer :: ncol, lchnk ! # of columns, and chunk identifier @@ -2239,7 +2247,7 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & ! Local CLUBB variables dimensioned as NCOL (only useful columns) to be sent into the clubb run api ! NOTE: THESE VARIABLS SHOULD NOT BE USED IN PBUF OR OUTFLD (HISTORY) SUBROUTINES - real(r8), dimension(state%ncol,pverp+1-top_lev) :: & + real(r8), dimension(state%ncol,nzm_clubb) :: & thlm_forcing, & ! theta_l forcing (thermodynamic levels) [K/s] rtm_forcing, & ! r_t forcing (thermodynamic levels) [(kg/kg)/s] um_forcing, & ! u wind forcing (thermodynamic levels) [m/s/s] @@ -2339,25 +2347,23 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & ! Local CLUBB variables dimensioned as NCOL (only useful columns) to be sent into the clubb run api ! NOTE: THESE VARIABLS SHOULD NOT BE USED IN PBUF OR OUTFLD (HISTORY) SUBROUTINES - real(r8), dimension(state%ncol,pverp+1-top_lev,sclr_dim) :: & + real(r8), dimension(state%ncol,nzm_clubb,sclr_dim) :: & sclrm_forcing, & ! Passive scalar forcing [{units vary}/s] sclrm, & ! Passive scalar mean (thermo. levels) [units vary] sclrp2, & ! sclr'^2 (momentum levels) [{units vary}^2] sclrp3, & ! sclr'^3 (thermo. levels) [{units vary}^3] sclrprtp, & ! sclr'rt' (momentum levels) [{units vary} (kg/kg)] sclrpthlp, & ! sclr'thlp' (momentum levels) [{units vary} (K)] - wpsclrp ! w'sclr' (momentum levels) [{units vary} m/s] - - real(r8), dimension(state%ncol,pverp,sclr_dim) :: & - sclrpthvp_inout ! sclr'th_v' (momentum levels) [{units vary} (K)] + wpsclrp, & ! w'sclr' (momentum levels) [{units vary} m/s] + sclrpthvp_inout ! sclr'th_v' (momentum levels) [{units vary} (K)] - real(r8), dimension(state%ncol,pverp+1-top_lev,edsclr_dim) :: & + real(r8), dimension(state%ncol,nzm_clubb,edsclr_dim) :: & edsclrm_forcing, & ! Eddy passive scalar forcing [{units vary}/s] edsclr_in ! Scalars to be diffused through CLUBB [units vary] ! Local CLUBB variables dimensioned as NCOL (only useful columns) to be sent into the clubb run api ! NOTE: THESE VARIABLS SHOULD NOT BE USED IN PBUF OR OUTFLD (HISTORY) SUBROUTINES - real(r8), dimension(state%ncol,pverp+1-top_lev,hydromet_dim) :: & + real(r8), dimension(state%ncol,nzm_clubb,hydromet_dim) :: & hydromet, & wphydrometp, & wp2hmp, & @@ -2366,10 +2372,9 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & ! Variables below are needed to compute energy integrals for conservation ! NOTE: Arrays of size PCOLS (all possible columns) can be used to access State, PBuf and History Subroutines - real(r8) :: ke_a(pcols), ke_b(pcols), te_a(pcols), te_b(pcols) - real(r8) :: wv_a(pcols), wv_b(pcols), wl_b(pcols), wl_a(pcols) - real(r8) :: se_dis(pcols), se_a(pcols), se_b(pcols), clubb_s(pcols,pver) - real(r8) :: eleak(pcols) + real(r8) :: te_a, se_a, ke_a, wv_a, wl_a + real(r8) :: te_b, se_b, ke_b, wv_b, wl_b + real(r8) :: se_dis(pcols), clubb_s(pcols,pver), eleak(pcols) real(r8) :: inv_exner_clubb(pcols,pverp) ! Inverse exner function consistent with CLUBB [-] real(r8) :: inv_exner_clubb_surf(pcols) ! Inverse exner function at the surface @@ -2409,7 +2414,7 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & real(r8) :: rrho(pcols) ! Inverse of air density [1/kg/m^3] real(r8) :: kinwat(pcols) ! Kinematic water vapor flux [m/s] real(r8) :: latsub - real(r8) :: thlp2_rad_out(pcols,pverp+1-top_lev) + real(r8) :: thlp2_rad_out(pcols,nzm_clubb) real(r8) :: apply_const, rtm_test real(r8) :: dl_rad, di_rad, dt_low @@ -2576,7 +2581,21 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & real(r8) :: temp2d(pcols,pver), temp2dp(pcols,pverp) ! temporary array for holding scaled outputs - integer :: nlev + real(r8), dimension(pcols,pver) :: & + rvmtend_clubb, & + rcmtend_clubb, & + rimtend_clubb, & + stend_clubb, & + utend_clubb, & + vtend_clubb, & + dpdlfliq, & + dpdlfice, & + dpdlft, & + detnliquid + + real(r8), dimension(pcols,pverp) :: & + wprcp_clubb, & + wpthvp_clubb intrinsic :: max @@ -2591,43 +2610,39 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & real(r8), dimension(state%ncol,nparams) :: & clubb_params ! Adjustable CLUBB parameters (C1, C2 ...) - -#endif - det_s(:) = 0.0_r8 - det_ice(:) = 0.0_r8 - -#ifdef CLUBB_SGS - !-----------------------------------------------------------------------------------! - ! MAIN COMPUTATION BEGINS HERE ! - !-----------------------------------------------------------------------------------! + integer :: & + sclr, & + edsclr, & + n - call t_startf("clubb_tend_cam") +#endif - nlev = pver + 1 - top_lev + call t_startf('clubb_tend_cam') - rtp2_zt_out = 0._r8 - thl2_zt_out = 0._r8 - wp2_zt_out = 0._r8 - pdfp_rtp2 = 0._r8 - wm_zt_out = 0._r8 + do i = 1, pcols + det_s(i) = 0.0_r8 + det_ice(i) = 0.0_r8 + end do - temp2d = 0._r8 - temp2dp = 0._r8 +#ifdef CLUBB_SGS - dl_rad = clubb_detliq_rad - di_rad = clubb_detice_rad - dt_low = clubb_detphase_lowtemp +#ifdef _OPENACC + ! These options have not been GPUized + if ( do_clubb_mf ) call endrun(subr//': do_clubb_mf=.true. not available when compiling with OpenACC') + if ( do_rainturb ) call endrun(subr//': do_rainturb=.true. not available when compiling with OpenACC') + if ( do_cldcool ) call endrun(subr//': do_cldcool=.true. not available when compiling with OpenACC') + if ( clubb_do_icesuper ) call endrun(subr//': clubb_do_icesuper=.true. not available when compiling with OpenACC') + if ( single_column .and. .not. scm_cambfb_mode ) then + call endrun(subr//': (single_column && !scm_cambfb_mode)=.true. not available when compiling with OpenACC') + end if +#endif - frac_limit = 0.01_r8 - ic_limit = 1.e-12_r8 - inv_rh2o = 1._r8/rh2o + !-----------------------------------------------------------------------------------! + ! MAIN COMPUTATION BEGINS HERE ! + !-----------------------------------------------------------------------------------! - if (clubb_do_adv) then - apply_const = 1._r8 ! Initialize to one, only if CLUBB's moments are advected - else - apply_const = 0._r8 ! Never want this if CLUBB's moments are not advected - endif + call t_startf('clubb_tend_cam:NAR') ! Get indicees for cloud and ice mass and cloud and ice number call cnst_get_ind('Q',ixq) @@ -2636,28 +2651,6 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & call cnst_get_ind('NUMLIQ',ixnumliq) call cnst_get_ind('NUMICE',ixnumice) - if (clubb_do_icesuper) then - call pbuf_get_field(pbuf, naai_idx, naai) - end if - - ! Initialize physics tendency arrays, copy the state to state1 array to use in this routine - call physics_ptend_init(ptend_all, state%psetcols, 'clubb') - - ! Copy the state to state1 array to use in this routine - call physics_state_copy(state, state1) - - ! Constituents are all treated as dry mmr by clubb. Convert the water species to - ! a dry basis. - call set_wet_to_dry(state1, convert_cnst_type='wet') - - if (clubb_do_liqsupersat) then - call pbuf_get_field(pbuf, npccn_idx, npccn) - endif - - ! Determine number of columns and which chunk computation is to be performed on - ncol = state%ncol - lchnk = state%lchnk - ! Determine time step of physics buffer itim_old = pbuf_old_tim_idx() @@ -2754,80 +2747,53 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & call pbuf_get_field(pbuf, vpwp_clubb_gw_mc_idx, vpwp_clubb_gw_mc ) call pbuf_get_field(pbuf, wpthlp_clubb_gw_mc_idx, wpthlp_clubb_gw_mc ) - - ! Allocate pdf_params only if they aren't allocated already. - if ( .not. allocated(pdf_params_chnk(lchnk)%mixt_frac) ) then - call init_pdf_params_api( pverp+1-top_lev, ncol, pdf_params_chnk(lchnk) ) - call init_pdf_params_api( pverp+1-top_lev, ncol, pdf_params_zm_chnk(lchnk) ) + if (clubb_do_icesuper) then + call pbuf_get_field(pbuf, naai_idx, naai) end if - if ( .not. allocated(pdf_implicit_coefs_terms_chnk(lchnk)%coef_wp4_implicit) ) then - call init_pdf_implicit_coefs_terms_api( pverp+1-top_lev, ncol, sclr_dim, & - pdf_implicit_coefs_terms_chnk(lchnk) ) - end if + ! Initialize physics tendency arrays + call physics_ptend_init(ptend_all, state%psetcols, 'clubb') - ! Initialize the apply_const variable (note special logic is due to eularian backstepping) - if (clubb_do_adv .and. (is_first_step() .or. all(wpthlp(1:ncol,1:pver) == 0._r8))) then - apply_const = 0._r8 ! On first time through do not remove constant - ! from moments since it has not been added yet - endif + ! Copy the state to state1 array to use in this routine + call physics_state_copy(state, state1) - ! Set the ztodt timestep in pbuf for SILHS - ztodtptr(:) = 1.0_r8*hdtime + ! Constituents are all treated as dry mmr by clubb. Convert the water species to + ! a dry basis. + call set_wet_to_dry(state1, convert_cnst_type='wet') + + if (clubb_do_liqsupersat) then + call pbuf_get_field(pbuf, npccn_idx, npccn) + endif ! Define the grid box size. CLUBB needs this information to determine what ! the maximum length scale should be. This depends on the column for ! variable mesh grids and lat-lon grids - call grid_size(state1, grid_dx, grid_dy) - if (clubb_do_icesuper) then - - ! -------------------------------------- ! - ! Ice Saturation Adjustment Computation ! - ! -------------------------------------- ! - - lq2(:) = .FALSE. - lq2(1) = .TRUE. - lq2(ixcldice) = .TRUE. - lq2(ixnumice) = .TRUE. - - latsub = latvap + latice - - call physics_ptend_init(ptend_loc, state%psetcols, 'iceadj', ls=.true., lq=lq2 ) - - stend(:ncol,:)=0._r8 - qvtend(:ncol,:)=0._r8 - qitend(:ncol,:)=0._r8 - initend(:ncol,:)=0._r8 - - call ice_macro_tend(naai(1:ncol,top_lev:pver), state1%t(1:ncol,top_lev:pver), & - state1%pmid(1:ncol,top_lev:pver), state1%q(1:ncol,top_lev:pver,1), & - state1%q(1:ncol,top_lev:pver,ixcldice), state1%q(1:ncol,top_lev:pver,ixnumice), & - latsub, hdtime, stend(1:ncol,top_lev:pver), qvtend(1:ncol,top_lev:pver), & - qitend(1:ncol,top_lev:pver), initend(1:ncol,top_lev:pver), ncol*(pver-top_lev+1)) - - ! update local copy of state with the tendencies - ptend_loc%q(:ncol,top_lev:pver,1)=qvtend(:ncol,top_lev:pver) - ptend_loc%q(:ncol,top_lev:pver,ixcldice)=qitend(:ncol,top_lev:pver) - ptend_loc%q(:ncol,top_lev:pver,ixnumice)=initend(:ncol,top_lev:pver) - ptend_loc%s(:ncol,top_lev:pver)=stend(:ncol,top_lev:pver) + ! Determine number of columns and which chunk computation is to be performed on + ncol = state%ncol + lchnk = state%lchnk - ! Add the ice tendency to the output tendency - call physics_ptend_sum(ptend_loc, ptend_all, ncol) + ! Allocate pdf_params only if they aren't allocated already. + if ( .not. allocated(pdf_params_chnk(lchnk)%mixt_frac) ) then + call init_pdf_params_api( nzm_clubb, ncol, pdf_params_chnk(lchnk) ) + call init_pdf_params_api( nzm_clubb, ncol, pdf_params_zm_chnk(lchnk) ) + end if - ! ptend_loc is reset to zero by this call - call physics_update(state1, ptend_loc, hdtime) + if ( .not. allocated(pdf_implicit_coefs_terms_chnk(lchnk)%coef_wp4_implicit) ) then + call init_pdf_implicit_coefs_terms_api( nzm_clubb, ncol, sclr_dim, & + pdf_implicit_coefs_terms_chnk(lchnk) ) + end if - !Write output for tendencies: - temp2d(:ncol,:pver) = stend(:ncol,:pver)/cpairv(:ncol,:pver,lchnk) - call outfld( 'TTENDICE', temp2d, pcols, lchnk ) - call outfld( 'QVTENDICE', qvtend, pcols, lchnk ) - call outfld( 'QITENDICE', qitend, pcols, lchnk ) - call outfld( 'NITENDICE', initend, pcols, lchnk ) + !--------------------- Scalar Setting -------------------- - endif + dl_rad = clubb_detliq_rad + di_rad = clubb_detice_rad + dt_low = clubb_detphase_lowtemp + frac_limit = 0.01_r8 + ic_limit = 1.e-12_r8 + inv_rh2o = 1._r8/rh2o ! Determine CLUBB time step and make it sub-step friendly ! For now we want CLUBB time step to be 5 min since that is @@ -2867,214 +2833,520 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & ! host time step divided by CLUBB time step nadv = max(hdtime/dtime,1._r8) - ! Initialize forcings for transported scalars to zero - sclrm_forcing(:,:,:) = 0._r8 - edsclrm_forcing(:,:,:) = 0._r8 - sclrm(:,:,:) = 0._r8 - ! Compute inverse exner function consistent with CLUBB's definition, which uses a constant - ! surface pressure. CAM's exner (in state) does not. Therefore, for consistent - ! treatment with CLUBB code, anytime exner is needed to treat CLUBB variables - ! (such as thlm), use "inv_exner_clubb" otherwise use the exner in state - do k=1,pver - do i=1,ncol - inv_exner_clubb(i,k) = 1._r8/((state1%pmid(i,k)/p0_clubb)**(rairv(i,k,lchnk)/cpairv(i,k,lchnk))) - enddo - enddo - - ! Compute exner at the surface for converting the sensible heat fluxes - ! to a flux of potential temperature for use as clubb's boundary conditions - do i=1,ncol - inv_exner_clubb_surf(i) = 1._r8/((state1%pmid(i,pver)/p0_clubb)**(rairv(i,pver,lchnk)/cpairv(i,pver,lchnk))) - enddo - - ! At each CLUBB call, initialize mean momentum and thermo CLUBB state - ! from the CAM state - do k=1,pver ! loop over levels - do i=1,ncol ! loop over columns - - rtm(i,k) = state1%q(i,k,ixq)+state1%q(i,k,ixcldliq) - rvm(i,k) = state1%q(i,k,ixq) - um(i,k) = state1%u(i,k) - vm(i,k) = state1%v(i,k) - thlm(i,k) = ( state1%t(i,k) & - - (latvap/cpairv(i,k,lchnk))*state1%q(i,k,ixcldliq) ) & - * inv_exner_clubb(i,k) - - if (clubb_do_adv) then - if (macmic_it == 1) then + ! Set stats output and increment equal to CLUBB and host dt + stats_metadata%stats_tsamp = dtime + stats_metadata%stats_tout = hdtime - ! Note that some of the moments below can be positive or negative. - ! Remove a constant that was added to prevent dynamics from clipping - ! them to prevent dynamics from making them positive. - thlp2(i,k) = state1%q(i,k,ixthlp2) - rtp2(i,k) = state1%q(i,k,ixrtp2) - rtpthlp(i,k) = state1%q(i,k,ixrtpthlp) - (rtpthlp_const*apply_const) - wpthlp(i,k) = state1%q(i,k,ixwpthlp) - (wpthlp_const*apply_const) - wprtp(i,k) = state1%q(i,k,ixwprtp) - (wprtp_const*apply_const) - wp2(i,k) = state1%q(i,k,ixwp2) - wp3(i,k) = state1%q(i,k,ixwp3) - (wp3_const*apply_const) - up2(i,k) = state1%q(i,k,ixup2) - vp2(i,k) = state1%q(i,k,ixvp2) - endif - endif + stats_nsamp = nint(stats_metadata%stats_tsamp/dtime) + stats_nout = nint(stats_metadata%stats_tout/dtime) - enddo - enddo if (clubb_do_adv) then - ! If not last step of macmic loop then set apply_const back to - ! zero to prevent output from being corrupted. - if (macmic_it == cld_macmic_num_steps) then - apply_const = 1._r8 - else - apply_const = 0._r8 - endif + apply_const = 1._r8 ! Initialize to one, only if CLUBB's moments are advected + else + apply_const = 0._r8 ! Never want this if CLUBB's moments are not advected endif - rtm(1:ncol,pverp) = rtm(1:ncol,pver) - um(1:ncol,pverp) = state1%u(1:ncol,pver) - vm(1:ncol,pverp) = state1%v(1:ncol,pver) - thlm(1:ncol,pverp) = thlm(1:ncol,pver) - - if (clubb_do_adv) then - thlp2(1:ncol,pverp) = thlp2(1:ncol,pver) - rtp2(1:ncol,pverp) = rtp2(1:ncol,pver) - rtpthlp(1:ncol,pverp) = rtpthlp(1:ncol,pver) - wpthlp(1:ncol,pverp) = wpthlp(1:ncol,pver) - wprtp(1:ncol,pverp) = wprtp(1:ncol,pver) - wp2(1:ncol,pverp) = wp2(1:ncol,pver) - wp3(1:ncol,pverp) = wp3(1:ncol,pver) - up2(1:ncol,pverp) = up2(1:ncol,pver) - vp2(1:ncol,pverp) = vp2(1:ncol,pver) + ! Initialize the apply_const variable (note special logic is due to eulerian backstepping) + if (clubb_do_adv .and. (is_first_step() .or. all(wpthlp(1:ncol,1:pver) == 0._r8))) then + apply_const = 0._r8 ! On first time through do not remove constant + ! from moments since it has not been added yet endif - ! Compute virtual potential temperature, which is needed for CLUBB - do k=1,pver - do i=1,ncol - thv(i,k) = state1%t(i,k)*inv_exner_clubb(i,k)*(1._r8+zvir*state1%q(i,k,ixq)& - -state1%q(i,k,ixcldliq)) - enddo - enddo - - call physics_ptend_init(ptend_loc,state%psetcols, 'clubb', ls=.true., lu=.true., lv=.true., lq=lq) - - !REMOVECAM - no longer need this when CAM is retired and pcols no longer exists - troplev(:) = 0 - !REMOVECAM_END - call tropopause_findChemTrop(state, troplev) - - ! Initialize EDMF outputs - if (do_clubb_mf) then - mf_dry_a_output(:,:) = 0._r8 - mf_moist_a_output(:,:) = 0._r8 - mf_dry_w_output(:,:) = 0._r8 - mf_moist_w_output(:,:) = 0._r8 - mf_dry_qt_output(:,:) = 0._r8 - mf_moist_qt_output(:,:) = 0._r8 - mf_dry_thl_output(:,:) = 0._r8 - mf_moist_thl_output(:,:) = 0._r8 - mf_dry_u_output(:,:) = 0._r8 - mf_moist_u_output(:,:) = 0._r8 - mf_dry_v_output(:,:) = 0._r8 - mf_moist_v_output(:,:) = 0._r8 - mf_moist_qc_output(:,:) = 0._r8 - s_ae_output(:,:) = 0._r8 - s_aw_output(:,:) = 0._r8 - s_awthl_output(:,:) = 0._r8 - s_awqt_output(:,:) = 0._r8 - s_awql_output(:,:) = 0._r8 - s_awqi_output(:,:) = 0._r8 - s_awu_output(:,:) = 0._r8 - s_awv_output(:,:) = 0._r8 - mf_thlflx_output(:,:) = 0._r8 - mf_qtflx_output(:,:) = 0._r8 - end if - - call t_startf("clubb_tend_cam_i_loop") + !--------------------- Initializations -------------------- - ! Determine Coriolis force at given latitude. This is never used - ! when CLUBB is implemented in a host model, therefore just set - ! to zero. - fcor(:) = 0._r8 + ! Set the ztodt timestep in pbuf for SILHS + ztodtptr(:) = 1.0_r8*hdtime - ! Define the CLUBB momentum grid (in height, units of m) - do k=1, nlev+1 - do i=1, ncol - zi_g(i,k) = state1%zi(i,pverp-k+1)-state1%zi(i,pver+1) + call t_stopf('clubb_tend_cam:NAR') + call t_startf('clubb_tend_cam:acc_copyin') + !$acc data copyin( sclr_idx, clubb_params_single_col, grid_dx, grid_dy, rairv, cpairv, radf_clubb, qrl, & + !$acc pdf_params_chnk(lchnk), pdf_params_zm_chnk(lchnk), & + !$acc state1, state1%q, state1%u, state1%v, state1%t, state1%pmid, state1%s, state1%pint, & + !$acc state1%zm, state1%zi, state1%pdeldry, state1%pdel, state1%omega, state1%phis, & + !$acc cam_in, cam_in%shf, cam_in%wsx, cam_in%wsy, cam_in%cflx, & + !$acc rrho, prer_evap, rtp2_mc_zt, thlp2_mc_zt, wprtp_mc_zt, wpthlp_mc_zt, rtpthlp_mc_zt ) & + !$acc copy( um, vm, upwp, vpwp, wpthvp, wp2thvp, rtpthvp, thlpthvp, up2, vp2, up3, vp3, & + !$acc wp2, wp3, rtp2, thlp2, rtp3, thlp3, thlm, rtm, rvm, wprtp, wpthlp, rtpthlp, & + !$acc cloud_frac, wp2rtp, wp2thlp, uprcp, vprcp, rc_coef, wp4, wpup2, wpvp2, & + !$acc ttend_clubb_mc, upwp_clubb_gw_mc, vpwp_clubb_gw_mc, thlp2_clubb_gw_mc, wpthlp_clubb_gw_mc, & + !$acc ttend_clubb, upwp_clubb_gw, vpwp_clubb_gw, thlp2_clubb_gw, wpthlp_clubb_gw, & + !$acc wp2up2, wp2vp2, ice_supersat_frac ) & + !$acc copyout( temp2d, temp2dp, rtp2_zt_out, thl2_zt_out, wp2_zt_out, pdfp_rtp2, wm_zt_out, inv_exner_clubb, & + !$acc rcm, wprcp, rcm_in_layer, cloud_cover, zt_out, zi_out, khzm, qclvar, thv, dz_g, & + !$acc clubbtop, se_dis, eleak, clubb_s, wpthvp_clubb, wprcp_clubb ) & + !$acc create( upwp_sfc_pert, vpwp_sfc_pert, khzt_out, khzm_out, & + !$acc fcor, um_in, vm_in, upwp_in, vpwp_in, wpthvp_in, wp2thvp_in, rtpthvp_in, thlpthvp_in, & + !$acc up2_in, vp2_in, up3_in, vp3_in, wp2_in, wp3_in, rtp2_in, thlp2_in, rtp3_in, & + !$acc thlp3_in, thlm_in, rtm_in, rvm_in, wprtp_in, wpthlp_in, rtpthlp_in, cloud_frac_inout, & + !$acc rcm_inout, wp2rtp_inout, wp2thlp_inout, uprcp_inout, vprcp_inout, & + !$acc rc_coef_inout, wp4_inout, wpup2_inout, wpvp2_inout, wp2up2_inout, wp2vp2_inout, & + !$acc ice_supersat_frac_inout, pre_in, kappa_zt, qc_zt, invrs_exner_zt, kappa_zm, p_in_Pa_zm, & + !$acc invrs_exner_zm, cloud_cover_out, rcm_in_layer_out, wprcp_out, & + !$acc qclvar_out, rtp2_zt, thl2_zt, wp2_zt, w_up_in_cloud_out, cloudy_downdraft_frac_out, & + !$acc w_down_in_cloud_out, invrs_tau_zm_out, vm_pert_inout, upwp_pert_inout, vpwp_pert_inout, & + !$acc thlm_forcing, rtm_forcing, um_forcing, vm_forcing, & + !$acc wprtp_forcing, wpthlp_forcing, rtp2_forcing, thlp2_forcing, & + !$acc rtpthlp_forcing, wm_zm, wm_zt, rho_zm, rho_zt, rho_ds_zm, rho_ds_zt, & + !$acc invrs_rho_ds_zm, invrs_rho_ds_zt, thv_ds_zm, thv_ds_zt, rfrzm, & + !$acc radf, wpthlp_sfc, clubb_params, sfc_elevation, wprtp_sfc, upwp_sfc, vpwp_sfc, & + !$acc rtm_ref, thlm_ref, um_ref, vm_ref, ug, vg, p_in_Pa, exner, um_pert_inout, & + !$acc inv_exner_clubb_surf, thlprcp_out, zi_g, zt_g, qrl_clubb, & + !$acc pdf_zm_w_1, pdf_zm_w_2, pdf_zm_varnce_w_1, pdf_zm_varnce_w_2, pdf_zm_mixt_frac, & + !$acc pdf_params_chnk(lchnk)%w_1, pdf_params_chnk(lchnk)%w_2, & + !$acc pdf_params_chnk(lchnk)%varnce_w_1, pdf_params_chnk(lchnk)%varnce_w_2, & + !$acc pdf_params_chnk(lchnk)%rt_1, pdf_params_chnk(lchnk)%rt_2, & + !$acc pdf_params_chnk(lchnk)%varnce_rt_1, pdf_params_chnk(lchnk)%varnce_rt_2, & + !$acc pdf_params_chnk(lchnk)%thl_1, pdf_params_chnk(lchnk)%thl_2, & + !$acc pdf_params_chnk(lchnk)%varnce_thl_1, pdf_params_chnk(lchnk)%varnce_thl_2, & + !$acc pdf_params_chnk(lchnk)%corr_w_rt_1, pdf_params_chnk(lchnk)%corr_w_rt_2, & + !$acc pdf_params_chnk(lchnk)%corr_w_thl_1, pdf_params_chnk(lchnk)%corr_w_thl_2, & + !$acc pdf_params_chnk(lchnk)%corr_rt_thl_1, pdf_params_chnk(lchnk)%corr_rt_thl_2,& + !$acc pdf_params_chnk(lchnk)%alpha_thl, pdf_params_chnk(lchnk)%alpha_rt, & + !$acc pdf_params_chnk(lchnk)%crt_1, pdf_params_chnk(lchnk)%crt_2, pdf_params_chnk(lchnk)%cthl_1, & + !$acc pdf_params_chnk(lchnk)%cthl_2, pdf_params_chnk(lchnk)%chi_1, & + !$acc pdf_params_chnk(lchnk)%chi_2, pdf_params_chnk(lchnk)%stdev_chi_1, & + !$acc pdf_params_chnk(lchnk)%stdev_chi_2, pdf_params_chnk(lchnk)%stdev_eta_1, & + !$acc pdf_params_chnk(lchnk)%stdev_eta_2, pdf_params_chnk(lchnk)%covar_chi_eta_1, & + !$acc pdf_params_chnk(lchnk)%covar_chi_eta_2, pdf_params_chnk(lchnk)%corr_w_chi_1, & + !$acc pdf_params_chnk(lchnk)%corr_w_chi_2, pdf_params_chnk(lchnk)%corr_w_eta_1, & + !$acc pdf_params_chnk(lchnk)%corr_w_eta_2, pdf_params_chnk(lchnk)%corr_chi_eta_1, & + !$acc pdf_params_chnk(lchnk)%corr_chi_eta_2, pdf_params_chnk(lchnk)%rsatl_1, & + !$acc pdf_params_chnk(lchnk)%rsatl_2, pdf_params_chnk(lchnk)%rc_1, pdf_params_chnk(lchnk)%rc_2, & + !$acc pdf_params_chnk(lchnk)%cloud_frac_1, pdf_params_chnk(lchnk)%cloud_frac_2, & + !$acc pdf_params_chnk(lchnk)%mixt_frac, pdf_params_chnk(lchnk)%ice_supersat_frac_1, & + !$acc pdf_params_chnk(lchnk)%ice_supersat_frac_2, & + !$acc pdf_params_zm_chnk(lchnk)%w_1, pdf_params_zm_chnk(lchnk)%w_2, & + !$acc pdf_params_zm_chnk(lchnk)%varnce_w_1, pdf_params_zm_chnk(lchnk)%varnce_w_2, & + !$acc pdf_params_zm_chnk(lchnk)%rt_1, pdf_params_zm_chnk(lchnk)%rt_2, & + !$acc pdf_params_zm_chnk(lchnk)%varnce_rt_1, pdf_params_zm_chnk(lchnk)%varnce_rt_2, & + !$acc pdf_params_zm_chnk(lchnk)%thl_1, pdf_params_zm_chnk(lchnk)%thl_2, & + !$acc pdf_params_zm_chnk(lchnk)%varnce_thl_1, pdf_params_zm_chnk(lchnk)%varnce_thl_2, & + !$acc pdf_params_zm_chnk(lchnk)%corr_w_rt_1, pdf_params_zm_chnk(lchnk)%corr_w_rt_2, & + !$acc pdf_params_zm_chnk(lchnk)%corr_w_thl_1, pdf_params_zm_chnk(lchnk)%corr_w_thl_2, & + !$acc pdf_params_zm_chnk(lchnk)%corr_rt_thl_1, pdf_params_zm_chnk(lchnk)%corr_rt_thl_2,& + !$acc pdf_params_zm_chnk(lchnk)%alpha_thl, pdf_params_zm_chnk(lchnk)%alpha_rt, & + !$acc pdf_params_zm_chnk(lchnk)%crt_1, pdf_params_zm_chnk(lchnk)%crt_2, pdf_params_zm_chnk(lchnk)%cthl_1, & + !$acc pdf_params_zm_chnk(lchnk)%cthl_2, pdf_params_zm_chnk(lchnk)%chi_1, & + !$acc pdf_params_zm_chnk(lchnk)%chi_2, pdf_params_zm_chnk(lchnk)%stdev_chi_1, & + !$acc pdf_params_zm_chnk(lchnk)%stdev_chi_2, pdf_params_zm_chnk(lchnk)%stdev_eta_1, & + !$acc pdf_params_zm_chnk(lchnk)%stdev_eta_2, pdf_params_zm_chnk(lchnk)%covar_chi_eta_1, & + !$acc pdf_params_zm_chnk(lchnk)%covar_chi_eta_2, pdf_params_zm_chnk(lchnk)%corr_w_chi_1, & + !$acc pdf_params_zm_chnk(lchnk)%corr_w_chi_2, pdf_params_zm_chnk(lchnk)%corr_w_eta_1, & + !$acc pdf_params_zm_chnk(lchnk)%corr_w_eta_2, pdf_params_zm_chnk(lchnk)%corr_chi_eta_1, & + !$acc pdf_params_zm_chnk(lchnk)%corr_chi_eta_2, pdf_params_zm_chnk(lchnk)%rsatl_1, & + !$acc pdf_params_zm_chnk(lchnk)%rsatl_2, pdf_params_zm_chnk(lchnk)%rc_1, pdf_params_zm_chnk(lchnk)%rc_2, & + !$acc pdf_params_zm_chnk(lchnk)%cloud_frac_1, pdf_params_zm_chnk(lchnk)%cloud_frac_2, & + !$acc pdf_params_zm_chnk(lchnk)%mixt_frac, pdf_params_zm_chnk(lchnk)%ice_supersat_frac_1, & + !$acc pdf_params_zm_chnk(lchnk)%ice_supersat_frac_2 ) + + !$acc data if( sclr_dim > 0 ) & + !$acc create( wpsclrp_sfc, sclrm_forcing, sclrm, wpsclrp, sclrp2, sclrp3, sclrprtp, sclrpthlp, sclrpthvp_inout) & + !$acc copyin( sclr_tol ) + + !$acc data if( edsclr_dim > 0 ) & + !$acc create( wpedsclrp_sfc, edsclrm_forcing, edsclr_in ) & + !$acc copyout( edsclr_out ) + + !$acc data if( hydromet_dim > 0 ) & + !$acc create( hydromet, wphydrometp, wp2hmp, rtphmp_zt, thlphmp_zt ) & + !$acc copyin( hm_metadata, hm_metadata%l_mix_rat_hm ) + call t_stopf('clubb_tend_cam:acc_copyin') + call t_startf('clubb_tend_cam:ACCR') + + !$acc parallel loop gang vector collapse(2) default(present) + do k = 1, pverp + do i = 1, pcols + rtp2_zt_out(i,k) = 0._r8 + thl2_zt_out(i,k) = 0._r8 + wp2_zt_out(i,k) = 0._r8 + pdfp_rtp2(i,k) = 0._r8 + wm_zt_out(i,k) = 0._r8 + temp2dp(i,k) = 0._r8 end do end do - ! Define the CLUBB thermodynamic grid (in units of m) - do k=1, nlev - do i=1, ncol - zt_g(i,k+1) = state1%zm(i,pver-k+1)-state1%zi(i,pver+1) + !$acc parallel loop gang vector collapse(2) default(present) + do k = 1, pver + do i = 1, pcols + temp2d(i,k) = 0._r8 end do end do - do k=1, pver - do i=1, ncol - dz_g(i,k) = state1%zi(i,k)-state1%zi(i,k+1) ! compute thickness + !$acc parallel loop gang vector collapse(2) default(present) + do k = 1, nzm_clubb + do i = 1, ncol + + ! Define forcings from CAM to CLUBB as zero for momentum and thermo, + ! forcings already applied through CAM + thlm_forcing(i,k) = 0._r8 + rtm_forcing(i,k) = 0._r8 + um_forcing(i,k) = 0._r8 + vm_forcing(i,k) = 0._r8 + + rtm_ref(i,k) = 0.0_r8 + thlm_ref(i,k) = 0.0_r8 + um_ref(i,k) = 0.0_r8 + vm_ref(i,k) = 0.0_r8 + ug(i,k) = 0.0_r8 + vg(i,k) = 0.0_r8 end do end do - ! Thermodynamic ghost point is below surface - do i=1, ncol - zt_g(i,1) = -1._r8*zt_g(i,2) + !$acc parallel loop gang vector collapse(2) default(present) + do k = 1, nzm_clubb + do i = 1, ncol + ! Perturbed winds are not used in CAM + um_pert_inout(i,k) = 0.0_r8 + vm_pert_inout(i,k) = 0.0_r8 + upwp_pert_inout(i,k) = 0.0_r8 + vpwp_pert_inout(i,k) = 0.0_r8 + + ! Initialize these to prevent crashing behavior + wprcp_out(i,k) = 0._r8 + rcm_in_layer_out(i,k) = 0._r8 + cloud_cover_out(i,k) = 0._r8 + khzm_out(i,k) = 0._r8 + khzt_out(i,k) = 0._r8 + end do end do - do i=1, ncol - ! Set the elevation of the surface - sfc_elevation(i) = state1%zi(i,pver+1) + !$acc parallel loop gang vector default(present) + do i = 1, ncol + ! Perturbed winds are not used in CAM + upwp_sfc_pert(i) = 0.0_r8 + vpwp_sfc_pert(i) = 0.0_r8 + + ! Determine Coriolis force at given latitude. This is never used + ! when CLUBB is implemented in a host model, therefore just set + ! to zero. + fcor(i) = 0._r8 end do - ! Compute thermodynamic stuff needed for CLUBB on thermo levels. - ! Inputs for the momentum levels are set below setup_clubb core - do k=1,nlev - do i=1, ncol - ! base state (dry) variables - rho_ds_zt(i,k+1) = rga*(state1%pdeldry(i,pver-k+1)/dz_g(i,pver-k+1)) - invrs_rho_ds_zt(i,k+1) = 1._r8/(rho_ds_zt(i,k+1)) + if ( sclr_dim > 0 ) then + ! higher order scalar stuff, put to zero + !$acc parallel loop gang vector collapse(3) default(present) + do sclr = 1, sclr_dim + do k = 1, nzm_clubb + do i=1, ncol + sclrm(i,k,sclr) = 0._r8 + wpsclrp(i,k,sclr) = 0._r8 + sclrp2(i,k,sclr) = 0._r8 + sclrp3(i,k,sclr) = 0._r8 + sclrprtp(i,k,sclr) = 0._r8 + sclrpthlp(i,k,sclr) = 0._r8 + sclrpthvp_inout(i,k,sclr) = 0._r8 + sclrm_forcing(i,k,sclr) = 0._r8 + end do + end do + end do - ! full state (moist) variables - p_in_Pa(i,k+1) = state1%pmid(i,pver-k+1) - exner(i,k+1) = 1._r8/inv_exner_clubb(i,pver-k+1) - thv(i,k+1) = state1%t(i,pver-k+1)*inv_exner_clubb(i,pver-k+1)*(1._r8+zvir*state1%q(i,pver-k+1,ixq) & - -state1%q(i,pver-k+1,ixcldliq)) - rho_zt(i,k+1) = rga*state1%pdel(i,pver-k+1)/dz_g(i,pver-k+1) + !$acc parallel loop gang vector collapse(2) default(present) + do sclr = 1, sclr_dim + do i=1, ncol + wpsclrp_sfc(i,sclr) = 0._r8 + end do + end do + end if - ! exception - setting this to moist thv - thv_ds_zt(i,k+1) = thv(i,k+1) + if ( hydromet_dim > 0 ) then + !$acc parallel loop gang vector collapse(3) default(present) + do ixind=1, hydromet_dim + do k=1, nzm_clubb + do i=1, ncol + hydromet(i,k,ixind) = 0._r8 + wphydrometp(i,k,ixind) = 0._r8 + wp2hmp(i,k,ixind) = 0._r8 + rtphmp_zt(i,k,ixind) = 0._r8 + thlphmp_zt(i,k,ixind) = 0._r8 + end do + end do + end do + end if - rfrzm(i,k+1) = state1%q(i,pver-k+1,ixcldice) - radf(i,k+1) = radf_clubb(i,pver-k+1) - qrl_clubb(i,k+1) = qrl(i,pver-k+1)/(cpairv(i,k,lchnk)*state1%pdeldry(i,pver-k+1)) + if ( edsclr_dim > 0 ) then + !$acc parallel loop gang vector collapse(3) default(present) + do edsclr = 1, edsclr_dim + do i = 1, ncol + do k = 1, nzm_clubb + edsclrm_forcing(i,k,edsclr) = 0._r8 + edsclr_in(i,k,edsclr) = 0._r8 + end do + end do end do - end do - ! Compute mean w wind on thermo grid, convert from omega to w - do k=1,nlev - do i=1,ncol - wm_zt(i,k+1) = -1._r8*(state1%omega(i,pver-k+1)-state1%omega(i,pver))/(rho_zt(i,k+1)*gravit) + ! Define surface sources for transported variables for diffusion, will + ! be zero as these tendencies are done in vertical_diffusion + !$acc parallel loop gang vector collapse(2) default(present) + do edsclr = 1, edsclr_dim + do i = 1, ncol + wpedsclrp_sfc(i,edsclr) = 0._r8 + end do end do - end do + end if - ! Below computes the same stuff for the ghost point. May or may - ! not be needed, just to be safe to avoid NaN's - do i=1, ncol - thv_ds_zt(i,1) = thv_ds_zt(i,2) - rho_ds_zt(i,1) = rho_ds_zt(i,2) - invrs_rho_ds_zt(i,1) = invrs_rho_ds_zt(i,2) - p_in_Pa(i,1) = p_in_Pa(i,2) - exner(i,1) = exner(i,2) - thv(i,1) = thv(i,2) - rho_zt(i,1) = rho_zt(i,2) - rfrzm(i,1) = rfrzm(i,2) - radf(i,1) = radf(i,2) - qrl_clubb(i,1) = qrl_clubb(i,2) - wm_zt(i,1) = wm_zt(i,2) - end do + ! need to initialize macmic coupling to zero + if ( macmic_it == 1 ) then + !$acc parallel loop gang vector collapse(2) default(present) + do i = 1, ncol + do k = 1, pverp + ttend_clubb_mc(i,k) = 0._r8 + upwp_clubb_gw_mc(i,k) = 0._r8 + vpwp_clubb_gw_mc(i,k) = 0._r8 + thlp2_clubb_gw_mc(i,k) = 0._r8 + wpthlp_clubb_gw_mc(i,k) = 0._r8 + end do + end do + end if + ! Initialize EDMF outputs + if (do_clubb_mf) then + do k = 1, pverp + do i = 1, pcols + mf_dry_a_output(i,k) = 0._r8 + mf_moist_a_output(i,k) = 0._r8 + mf_dry_w_output(i,k) = 0._r8 + mf_moist_w_output(i,k) = 0._r8 + mf_dry_qt_output(i,k) = 0._r8 + mf_moist_qt_output(i,k) = 0._r8 + mf_dry_thl_output(i,k) = 0._r8 + mf_moist_thl_output(i,k) = 0._r8 + mf_dry_u_output(i,k) = 0._r8 + mf_moist_u_output(i,k) = 0._r8 + mf_dry_v_output(i,k) = 0._r8 + mf_moist_v_output(i,k) = 0._r8 + mf_moist_qc_output(i,k) = 0._r8 + s_ae_output(i,k) = 0._r8 + s_aw_output(i,k) = 0._r8 + s_awthl_output(i,k) = 0._r8 + s_awqt_output(i,k) = 0._r8 + s_awql_output(i,k) = 0._r8 + s_awqi_output(i,k) = 0._r8 + s_awu_output(i,k) = 0._r8 + s_awv_output(i,k) = 0._r8 + mf_thlflx_output(i,k) = 0._r8 + mf_qtflx_output(i,k) = 0._r8 + end do + end do + end if + + if (clubb_do_icesuper) then + + ! -------------------------------------- ! + ! Ice Saturation Adjustment Computation ! + ! -------------------------------------- ! + + lq2(:) = .FALSE. + lq2(1) = .TRUE. + lq2(ixcldice) = .TRUE. + lq2(ixnumice) = .TRUE. + + latsub = latvap + latice + + call physics_ptend_init(ptend_loc, state%psetcols, 'iceadj', ls=.true., lq=lq2 ) + + do i = 1, ncol + do k = 1, pver + stend(i,k) = 0._r8 + qvtend(i,k) = 0._r8 + qitend(i,k) = 0._r8 + initend(i,k) = 0._r8 + end do + end do + + call t_startf('clubb_tend_cam:ice_macro_tend') + call ice_macro_tend(naai(1:ncol,top_lev:pver), state1%t(1:ncol,top_lev:pver), & + state1%pmid(1:ncol,top_lev:pver), state1%q(1:ncol,top_lev:pver,1), & + state1%q(1:ncol,top_lev:pver,ixcldice), state1%q(1:ncol,top_lev:pver,ixnumice), & + latsub, hdtime, stend(1:ncol,top_lev:pver), qvtend(1:ncol,top_lev:pver), & + qitend(1:ncol,top_lev:pver), initend(1:ncol,top_lev:pver), ncol*(pver-top_lev+1)) + call t_stopf('clubb_tend_cam:ice_macro_tend') + + ! update local copy of state with the tendencies + do i = 1, ncol + do k = top_lev, pver + ptend_loc%q(i,k,1) = qvtend(i,k) + ptend_loc%q(i,k,ixcldice) = qitend(i,k) + ptend_loc%q(i,k,ixnumice) = initend(i,k) + ptend_loc%s(i,k) = stend(i,k) + end do + end do + + ! Add the ice tendency to the output tendency + call physics_ptend_sum(ptend_loc, ptend_all, ncol) + + ! ptend_loc is reset to zero by this call + call physics_update(state1, ptend_loc, hdtime) + + ! Write output for tendencies: + do i = 1, ncol + do k = 1, pver + temp2d(i,k) = stend(i,k) / cpairv(i,k,lchnk) + end do + end do + + call outfld( 'TTENDICE', temp2d, pcols, lchnk ) + call outfld( 'QVTENDICE', qvtend, pcols, lchnk ) + call outfld( 'QITENDICE', qitend, pcols, lchnk ) + call outfld( 'NITENDICE', initend, pcols, lchnk ) + + endif + + if (clubb_do_adv) then + + if (macmic_it == 1) then + + ! Note that some of the moments below can be positive or negative. + ! Remove a constant that was added to prevent dynamics from clipping + ! them to prevent dynamics from making them positive. + do k = 1, pver + do i = 1, ncol + thlp2(i,k) = state1%q(i,k,ixthlp2) + rtp2(i,k) = state1%q(i,k,ixrtp2) + rtpthlp(i,k) = state1%q(i,k,ixrtpthlp) - ( rtpthlp_const * apply_const ) + wpthlp(i,k) = state1%q(i,k,ixwpthlp) - ( wpthlp_const * apply_const ) + wprtp(i,k) = state1%q(i,k,ixwprtp) - ( wprtp_const * apply_const ) + wp2(i,k) = state1%q(i,k,ixwp2) + wp3(i,k) = state1%q(i,k,ixwp3) - ( wp3_const * apply_const ) + up2(i,k) = state1%q(i,k,ixup2) + vp2(i,k) = state1%q(i,k,ixvp2) + enddo + enddo + + endif + + ! If not last step of macmic loop then set apply_const back to + ! zero to prevent output from being corrupted. + if (macmic_it == cld_macmic_num_steps) then + apply_const = 1._r8 + else + apply_const = 0._r8 + endif + + do i = 1, ncol + thlp2(i,pverp) = thlp2(i,pver) + rtp2(i,pverp) = rtp2(i,pver) + rtpthlp(i,pverp) = rtpthlp(i,pver) + wpthlp(i,pverp) = wpthlp(i,pver) + wprtp(i,pverp) = wprtp(i,pver) + wp2(i,pverp) = wp2(i,pver) + wp3(i,pverp) = wp3(i,pver) + up2(i,pverp) = up2(i,pver) + vp2(i,pverp) = vp2(i,pver) + end do + + endif + + ! Define the CLUBB momentum grid (in height, units of m) + !$acc parallel loop gang vector collapse(2) default(present) + do k=1, nzm_clubb + do i=1, ncol + zi_g(i,k) = state1%zi(i,pverp-k+1) - state1%zi(i,pver+1) + end do + end do + + !$acc parallel loop gang vector collapse(2) default(present) + do k=1, pver + do i=1, ncol + + ! Compute inverse exner function consistent with CLUBB's definition, which uses a constant + ! surface pressure. CAM's exner (in state) does not. Therefore, for consistent + ! treatment with CLUBB code, anytime exner is needed to treat CLUBB variables + ! (such as thlm), use "inv_exner_clubb" otherwise use the exner in state + inv_exner_clubb(i,k) = 1._r8 / ( ( state1%pmid(i,k) / p0_clubb )**( rairv(i,k,lchnk) / cpairv(i,k,lchnk) ) ) + + ! Compute virtual potential temperature, which is needed for CLUBB + thv(i,k) = state1%t(i,k) * inv_exner_clubb(i,k) & + * ( 1._r8 + zvir * state1%q(i,k,ixq) - state1%q(i,k,ixcldliq) ) + + dz_g(i,k) = state1%zi(i,k) - state1%zi(i,k+1) ! compute thickness + + ! At each CLUBB call, initialize mean momentum and thermo CLUBB state + ! from the CAM state + rtm(i,k) = state1%q(i,k,ixq) + state1%q(i,k,ixcldliq) + rvm(i,k) = state1%q(i,k,ixq) + um(i,k) = state1%u(i,k) + vm(i,k) = state1%v(i,k) + thlm(i,k) = ( state1%t(i,k) - ( latvap / cpairv(i,k,lchnk) ) * state1%q(i,k,ixcldliq) ) & + * inv_exner_clubb(i,k) + + enddo + enddo + + !$acc parallel loop gang vector default(present) + do i = 1, ncol + rtm(i,pverp) = rtm(i,pver) + um(i,pverp) = state1%u(i,pver) + vm(i,pverp) = state1%v(i,pver) + thlm(i,pverp) = thlm(i,pver) + + ! Compute exner at the surface for converting the sensible heat fluxes + ! to a flux of potential temperature for use as clubb's boundary conditions + inv_exner_clubb_surf(i) = inv_exner_clubb(i,pver) + end do + + ! Compute thermodynamic stuff needed for CLUBB on thermo levels. + ! Inputs for the momentum levels are set below setup_clubb core + !$acc parallel loop gang vector collapse(2) default(present) + do k = 1, nzt_clubb + do i = 1, ncol + + ! Define the CLUBB thermodynamic grid (in units of m) + zt_g(i,k+1) = state1%zm(i,pver-k+1) - state1%zi(i,pver+1) + + ! base state (dry) variables + rho_ds_zt(i,k+1) = rga * ( state1%pdeldry(i,pver-k+1) / dz_g(i,pver-k+1) ) + invrs_rho_ds_zt(i,k+1) = 1._r8 / rho_ds_zt(i,k+1) + + ! full state (moist) variables + p_in_Pa(i,k+1) = state1%pmid(i,pver-k+1) + exner(i,k+1) = 1._r8 / inv_exner_clubb(i,pver-k+1) + thv(i,k+1) = state1%t(i,pver-k+1) * inv_exner_clubb(i,pver-k+1) & + * ( 1._r8 + zvir * state1%q(i,pver-k+1,ixq) - state1%q(i,pver-k+1,ixcldliq) ) + rho_zt(i,k+1) = rga * state1%pdel(i,pver-k+1) / dz_g(i,pver-k+1) + + ! exception - setting this to moist thv + thv_ds_zt(i,k+1) = thv(i,k+1) + + rfrzm(i,k+1) = state1%q(i,pver-k+1,ixcldice) + radf(i,k+1) = radf_clubb(i,pver-k+1) + qrl_clubb(i,k+1) = qrl(i,pver-k+1) / ( cpairv(i,k,lchnk) * state1%pdeldry(i,pver-k+1) ) + + ! Compute mean w wind on thermo grid, convert from omega to w + wm_zt(i,k+1) = -1._r8 * ( state1%omega(i,pver-k+1) - state1%omega(i,pver) ) & + / ( rho_zt(i,k+1) * gravit ) + end do + end do + + ! Below computes the same stuff for the ghost point. May or may + ! not be needed, just to be safe to avoid NaN's + !$acc parallel loop gang vector default(present) + do i = 1, ncol + zt_g(i,1) = -1._r8 * zt_g(i,2) + rho_ds_zt(i,1) = rho_ds_zt(i,2) + invrs_rho_ds_zt(i,1) = invrs_rho_ds_zt(i,2) + p_in_Pa(i,1) = p_in_Pa(i,2) + exner(i,1) = exner(i,2) + thv(i,1) = thv(i,2) + rho_zt(i,1) = rho_zt(i,2) + thv_ds_zt(i,1) = thv_ds_zt(i,2) + rfrzm(i,1) = rfrzm(i,2) + radf(i,1) = radf(i,2) + qrl_clubb(i,1) = qrl_clubb(i,2) + wm_zt(i,1) = wm_zt(i,2) + + ! Set the elevation of the surface + sfc_elevation(i) = state1%zi(i,pverp) + end do + + + !$acc parallel loop gang vector collapse(2) default(present) + do i = 1, ncol + do n = 1, nparams + clubb_params(i,n) = clubb_params_single_col(n) + end do + end do ! ------------------------------------------------- ! ! Begin case specific code for SCAM cases. ! @@ -3126,20 +3398,6 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & end if - ! Define surface sources for transported variables for diffusion, will - ! be zero as these tendencies are done in vertical_diffusion - do ixind=1,edsclr_dim - do i=1,ncol - wpedsclrp_sfc(i,ixind) = 0._r8 - end do - end do - - ! Set stats output and increment equal to CLUBB and host dt - stats_metadata%stats_tsamp = dtime - stats_metadata%stats_tout = hdtime - - stats_nsamp = nint(stats_metadata%stats_tsamp/dtime) - stats_nout = nint(stats_metadata%stats_tout/dtime) ! Heights need to be set at each timestep. Therefore, recall ! setup_grid and setup_parameters for this. @@ -3148,62 +3406,74 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & ! Important note: do not make any calls that use CLUBB grid-height ! operators (such as zt2zm_api, etc.) until AFTER the ! call to setup_grid_heights_api. - call setup_grid_api( nlev+1, ncol, sfc_elevation, l_implemented, & ! intent(in) - grid_type, zi_g(:,2), zi_g(:,1), zi_g(:,nlev+1), & ! intent(in) + + call t_stopf('clubb_tend_cam:ACCR') + call t_startf('clubb_tend_cam:NAR') + !$acc update host( zi_g, zt_g, clubb_params, sfc_elevation ) + + call setup_grid_api( nzm_clubb, ncol, sfc_elevation, l_implemented, & ! intent(in) + grid_type, zi_g(:,2), zi_g(:,1), zi_g(:,nzm_clubb), & ! intent(in) zi_g, zt_g, & ! intent(in) gr ) ! intent(out) - do i = 1, ncol - clubb_params(i,:) = clubb_params_single_col(:) - end do call setup_parameters_api( zi_g(:,2), clubb_params, gr, ncol, grid_type, & ! intent(in) clubb_config_flags%l_prescribed_avg_deltaz, & ! intent(in) lmin, nu_vert_res_dep, err_code ) ! intent(out) + if ( err_code == clubb_fatal_error ) then - call endrun(subr//': Fatal error in CLUBB setup_parameters') + call endrun(subr//': Fatal error in CLUBB setup_parameters') end if - - ! Define forcings from CAM to CLUBB as zero for momentum and thermo, - ! forcings already applied through CAM - thlm_forcing(:,:) = 0._r8 - rtm_forcing(:,:) = 0._r8 - um_forcing(:,:) = 0._r8 - vm_forcing(:,:) = 0._r8 - - - rtm_ref(:,:) = 0.0_r8 - thlm_ref(:,:) = 0.0_r8 - um_ref(:,:) = 0.0_r8 - vm_ref(:,:) = 0.0_r8 - ug(:,:) = 0.0_r8 - vg(:,:) = 0.0_r8 + call t_stopf('clubb_tend_cam:NAR') + call t_startf('clubb_tend_cam:acc_copyin') + !$acc data copyin( gr, gr%zm, gr%zt, gr%dzm, gr%dzt, gr%invrs_dzt, gr%invrs_dzm, & + !$acc gr%weights_zt2zm, gr%weights_zm2zt, & + !$acc nu_vert_res_dep, nu_vert_res_dep%nu2, nu_vert_res_dep%nu9, & + !$acc nu_vert_res_dep%nu1, nu_vert_res_dep%nu8, nu_vert_res_dep%nu10, & + !$acc nu_vert_res_dep%nu6) + call t_stopf('clubb_tend_cam:acc_copyin') + call t_startf('clubb_tend_cam:ACCR') + + !$acc parallel loop gang vector collapse(2) default(present) + do k = 1, nzm_clubb + do i = 1, ncol + rtp2_forcing(i,k) = rtp2_mc_zt(i,k) + thlp2_forcing(i,k) = thlp2_mc_zt(i,k) + wprtp_forcing(i,k) = wprtp_mc_zt(i,k) + wpthlp_forcing(i,k) = wpthlp_mc_zt(i,k) + rtpthlp_forcing(i,k) = rtpthlp_mc_zt(i,k) + end do + end do ! Add forcings for SILHS covariance contributions - rtp2_forcing = zt2zm_api( pverp+1-top_lev, ncol, gr, rtp2_mc_zt(1:ncol,:) ) - thlp2_forcing = zt2zm_api( pverp+1-top_lev, ncol, gr, thlp2_mc_zt(1:ncol,:) ) - wprtp_forcing = zt2zm_api( pverp+1-top_lev, ncol, gr, wprtp_mc_zt(1:ncol,:) ) - wpthlp_forcing = zt2zm_api( pverp+1-top_lev, ncol, gr, wpthlp_mc_zt(1:ncol,:) ) - rtpthlp_forcing = zt2zm_api( pverp+1-top_lev, ncol, gr, rtpthlp_mc_zt(1:ncol,:) ) + rtp2_forcing = zt2zm_api( nzm_clubb, ncol, gr, rtp2_forcing ) + thlp2_forcing = zt2zm_api( nzm_clubb, ncol, gr, thlp2_forcing ) + wprtp_forcing = zt2zm_api( nzm_clubb, ncol, gr, wprtp_forcing ) + wpthlp_forcing = zt2zm_api( nzm_clubb, ncol, gr, wpthlp_forcing ) + rtpthlp_forcing = zt2zm_api( nzm_clubb, ncol, gr, rtpthlp_forcing ) ! Zero out SILHS covariance contribution terms - rtp2_mc_zt(:,:) = 0.0_r8 - thlp2_mc_zt(:,:) = 0.0_r8 - wprtp_mc_zt(:,:) = 0.0_r8 - wpthlp_mc_zt(:,:) = 0.0_r8 - rtpthlp_mc_zt(:,:) = 0.0_r8 - - - ! Compute some inputs from the thermodynamic grid - ! to the momentum grid - rho_ds_zm = zt2zm_api( pverp+1-top_lev, ncol, gr, rho_ds_zt ) - rho_zm = zt2zm_api( pverp+1-top_lev, ncol, gr, rho_zt ) - invrs_rho_ds_zm = zt2zm_api( pverp+1-top_lev, ncol, gr, invrs_rho_ds_zt ) - thv_ds_zm = zt2zm_api( pverp+1-top_lev, ncol, gr, thv_ds_zt ) - wm_zm = zt2zm_api( pverp+1-top_lev, ncol, gr, wm_zt ) - - ! Surface fluxes provided by host model + !$acc parallel loop gang vector collapse(2) default(present) + do k = 1, pverp + do i = 1, pcols + rtp2_mc_zt(i,k) = 0.0_r8 + thlp2_mc_zt(i,k) = 0.0_r8 + wprtp_mc_zt(i,k) = 0.0_r8 + wpthlp_mc_zt(i,k) = 0.0_r8 + rtpthlp_mc_zt(i,k) = 0.0_r8 + end do + end do + + ! Compute some inputs from the thermodynamic grid to the momentum grid + rho_ds_zm = zt2zm_api( nzm_clubb, ncol, gr, rho_ds_zt ) + rho_zm = zt2zm_api( nzm_clubb, ncol, gr, rho_zt ) + invrs_rho_ds_zm = zt2zm_api( nzm_clubb, ncol, gr, invrs_rho_ds_zt ) + thv_ds_zm = zt2zm_api( nzm_clubb, ncol, gr, thv_ds_zt ) + wm_zm = zt2zm_api( nzm_clubb, ncol, gr, wm_zt ) + + ! Surface fluxes provided by host model + !$acc parallel loop gang vector default(present) do i=1,ncol wpthlp_sfc(i) = cam_in%shf(i)/(cpairv(i,pver,lchnk)*rho_ds_zm(i,1)) ! Sensible heat flux wpthlp_sfc(i) = wpthlp_sfc(i)*inv_exner_clubb_surf(i) ! Potential temperature flux @@ -3213,31 +3483,44 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & ! Implementation after Thomas Toniazzo (NorESM) and Colin Zarzycki (PSU) ! Other Surface fluxes provided by host model if( (cld_macmic_num_steps > 1) .and. clubb_l_intr_sfc_flux_smooth ) then - ! Adjust surface stresses using winds from the prior macmic iteration - do i=1,ncol - ubar = sqrt(state1%u(i,pver)**2+state1%v(i,pver)**2) - if (ubar < 0.25_r8) ubar = 0.25_r8 - call calc_ustar( state1%t(i,pver), state1%pmid(i,pver), cam_in%wsx(i), cam_in%wsy(i), & - rrho(i), ustar ) + call t_stopf('clubb_tend_cam:ACCR') + call t_startf('clubb_tend_cam:NAR') + !$acc update host( state1%u, state1%v, state1%t, state1%pmid, cam_in%wsx, cam_in%wsy, rrho ) + + ! Adjust surface stresses using winds from the prior macmic iteration + do i=1,ncol + ubar = sqrt(state1%u(i,pver)**2+state1%v(i,pver)**2) + if (ubar < 0.25_r8) ubar = 0.25_r8 + + call calc_ustar( state1%t(i,pver), state1%pmid(i,pver), cam_in%wsx(i), cam_in%wsy(i), & + rrho(i), ustar ) + + upwp_sfc(i) = -state1%u(i,pver)*ustar**2/ubar + vpwp_sfc(i) = -state1%v(i,pver)*ustar**2/ubar + end do + + !$acc update device( upwp_sfc, vpwp_sfc ) + call t_stopf('clubb_tend_cam:NAR') + call t_startf('clubb_tend_cam:ACCR') - upwp_sfc(i) = -state1%u(i,pver)*ustar**2/ubar - vpwp_sfc(i) = -state1%v(i,pver)*ustar**2/ubar - end do else - do i=1,ncol - upwp_sfc(i) = cam_in%wsx(i)/rho_ds_zm(i,1) ! Surface meridional momentum flux - vpwp_sfc(i) = cam_in%wsy(i)/rho_ds_zm(i,1) ! Surface zonal momentum flux - end do + + !$acc parallel loop gang vector default(present) + do i=1,ncol + upwp_sfc(i) = cam_in%wsx(i)/rho_ds_zm(i,1) ! Surface meridional momentum flux + vpwp_sfc(i) = cam_in%wsy(i)/rho_ds_zm(i,1) ! Surface zonal momentum flux + end do + endif - ! Perturbed winds are not used in CAM - upwp_sfc_pert = 0.0_r8 - vpwp_sfc_pert = 0.0_r8 + call t_startf('clubb_tend_cam:flip-index') ! Need to flip arrays around for CLUBB core - do k=1,nlev+1 - do i=1,ncol + !$acc parallel loop gang vector collapse(2) default(present) + do k = 1, nzm_clubb + do i = 1, ncol + um_in(i,k) = um(i,pverp-k+1) vm_in(i,k) = vm(i,pverp-k+1) upwp_in(i,k) = upwp(i,pverp-k+1) @@ -3267,18 +3550,6 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & rcm_inout(i,k) = state1%q(i,pverp-k+1,ixcldliq) end if - ! We only need to copy pdf_params from pbuf if this is a restart and - ! we're calling pdf_closure at the end of advance_clubb_core - if ( is_first_restart_step() & - .and. clubb_config_flags%ipdf_call_placement .eq. ipdf_post_advance_fields ) then - pdf_params_zm_chnk(lchnk)%w_1(i,k) = pdf_zm_w_1(i,pverp-k+1) - pdf_params_zm_chnk(lchnk)%w_2(i,k) = pdf_zm_w_2(i,pverp-k+1) - pdf_params_zm_chnk(lchnk)%varnce_w_1(i,k) = pdf_zm_varnce_w_1(i,pverp-k+1) - pdf_params_zm_chnk(lchnk)%varnce_w_2(i,k) = pdf_zm_varnce_w_2(i,pverp-k+1) - pdf_params_zm_chnk(lchnk)%mixt_frac(i,k) = pdf_zm_mixt_frac(i,pverp-k+1) - end if - - sclrpthvp_inout(i,k,:) = 0._r8 wp2rtp_inout(i,k) = wp2rtp(i,pverp-k+1) wp2thlp_inout(i,k) = wp2thlp(i,pverp-k+1) uprcp_inout(i,k) = uprcp(i,pverp-k+1) @@ -3293,63 +3564,33 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & end do end do - ! Perturbed winds are not used in CAM - um_pert_inout = 0.0_r8 - vm_pert_inout = 0.0_r8 - upwp_pert_inout = 0.0_r8 - vpwp_pert_inout = 0.0_r8 + ! We only need to copy pdf_params from pbuf if this is a restart and + ! we're calling pdf_closure at the end of advance_clubb_core + if ( is_first_restart_step() & + .and. clubb_config_flags%ipdf_call_placement .eq. ipdf_post_advance_fields ) then + !$acc parallel loop gang vector collapse(2) default(present) + do k = 1, nzm_clubb + do i = 1, ncol + pdf_params_zm_chnk(lchnk)%w_1(i,k) = pdf_zm_w_1(i,pverp-k+1) + pdf_params_zm_chnk(lchnk)%w_2(i,k) = pdf_zm_w_2(i,pverp-k+1) + pdf_params_zm_chnk(lchnk)%varnce_w_1(i,k) = pdf_zm_varnce_w_1(i,pverp-k+1) + pdf_params_zm_chnk(lchnk)%varnce_w_2(i,k) = pdf_zm_varnce_w_2(i,pverp-k+1) + pdf_params_zm_chnk(lchnk)%mixt_frac(i,k) = pdf_zm_mixt_frac(i,pverp-k+1) + end do + end do + end if - do k=2,nlev+1 + !$acc parallel loop gang vector collapse(2) default(present) + do k=2, nzm_clubb do i=1,ncol pre_in(i,k) = prer_evap(i,pverp-k+1) end do end do + !$acc parallel loop gang vector default(present) do i=1,ncol - pre_in(i,1) = pre_in(i,2) - end do - - do i=1,ncol - rcm_inout(i,1) = rcm_inout(i,2) - end do - - ! Initialize these to prevent crashing behavior - do k=1,nlev+1 - do i=1,ncol - wprcp_out(i,k) = 0._r8 - rcm_in_layer_out(i,k) = 0._r8 - cloud_cover_out(i,k) = 0._r8 - edsclr_in(i,k,:) = 0._r8 - khzm_out(i,k) = 0._r8 - khzt_out(i,k) = 0._r8 - end do - end do - - ! higher order scalar stuff, put to zero - do ixind=1, sclr_dim - do k=1, nlev+1 - do i=1, ncol - sclrm(i,k,ixind) = 0._r8 - wpsclrp(i,k,ixind) = 0._r8 - sclrp2(i,k,ixind) = 0._r8 - sclrp3(i,k,ixind) = 0._r8 - sclrprtp(i,k,ixind) = 0._r8 - sclrpthlp(i,k,ixind) = 0._r8 - wpsclrp_sfc(i,ixind) = 0._r8 - end do - end do - end do - - do ixind=1, hydromet_dim - do k=1, nlev+1 - do i=1, ncol - hydromet(i,k,ixind) = 0._r8 - wphydrometp(i,k,ixind) = 0._r8 - wp2hmp(i,k,ixind) = 0._r8 - rtphmp_zt(i,k,ixind) = 0._r8 - thlphmp_zt(i,k,ixind) = 0._r8 - end do - end do + pre_in(i,1) = pre_in(i,2) + rcm_inout(i,1) = rcm_inout(i,2) end do ! pressure,exner on momentum grid needed for mass flux calc. @@ -3369,7 +3610,7 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & invrs_exner_zt(i,1) = invrs_exner_zt(i,2) end do - kappa_zm(1:ncol,:) = zt2zm_api(pverp+1-top_lev, ncol, gr, kappa_zt(1:ncol,:)) + kappa_zm(1:ncol,:) = zt2zm_api(nzm_clubb, ncol, gr, kappa_zt(1:ncol,:)) do k=1,pverp do i=1,ncol @@ -3380,21 +3621,20 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & end if - if (clubb_do_adv) then if (macmic_it == 1) then - wp2_in = zt2zm_api(pverp+1-top_lev, ncol, gr, wp2_in ) - wpthlp_in = zt2zm_api(pverp+1-top_lev, ncol, gr, wpthlp_in ) - wprtp_in = zt2zm_api(pverp+1-top_lev, ncol, gr, wprtp_in ) - up2_in = zt2zm_api(pverp+1-top_lev, ncol, gr, up2_in ) - vp2_in = zt2zm_api(pverp+1-top_lev, ncol, gr, vp2_in ) - thlp2_in = zt2zm_api(pverp+1-top_lev, ncol, gr, thlp2_in ) - rtp2_in = zt2zm_api(pverp+1-top_lev, ncol, gr, rtp2_in ) - rtpthlp_in = zt2zm_api(pverp+1-top_lev, ncol, gr, rtpthlp_in ) + wp2_in = zt2zm_api(nzm_clubb, ncol, gr, wp2_in ) + wpthlp_in = zt2zm_api(nzm_clubb, ncol, gr, wpthlp_in ) + wprtp_in = zt2zm_api(nzm_clubb, ncol, gr, wprtp_in ) + up2_in = zt2zm_api(nzm_clubb, ncol, gr, up2_in ) + vp2_in = zt2zm_api(nzm_clubb, ncol, gr, vp2_in ) + thlp2_in = zt2zm_api(nzm_clubb, ncol, gr, thlp2_in ) + rtp2_in = zt2zm_api(nzm_clubb, ncol, gr, rtp2_in ) + rtpthlp_in = zt2zm_api(nzm_clubb, ncol, gr, rtpthlp_in ) - do k=1,nlev+1 - do i=1,ncol + do k = 1, nzm_clubb + do i = 1, ncol thlp2_in(i,k) = max(thl_tol**2,thlp2_in(i,k)) rtp2_in(i,k) = max(rt_tol**2,rtp2_in(i,k)) wp2_in(i,k) = max(w_tol_sqd,wp2_in(i,k)) @@ -3413,12 +3653,14 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & icnt = icnt+1 - do k=1,nlev + !$acc parallel loop gang vector collapse(2) default(present) + do k=1,nzt_clubb do i=1,ncol edsclr_in(i,k+1,icnt) = state1%q(i,pver-k+1,ixind) end do end do + !$acc parallel loop gang vector default(present) do i=1,ncol edsclr_in(i,1,icnt) = edsclr_in(i,2,icnt) end do @@ -3426,15 +3668,17 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & end if end do - if (clubb_l_do_expldiff_rtm_thlm) then - do k=1,nlev + + !$acc parallel loop gang vector collapse(2) default(present) + do k=1,nzt_clubb do i=1, ncol edsclr_in(i,k+1,icnt+1) = thlm(i,pver-k+1) edsclr_in(i,k+1,icnt+2) = rtm(i,pver-k+1) end do end do + !$acc parallel loop gang vector default(present) do i=1, ncol edsclr_in(i,1,icnt+1) = edsclr_in(i,2,icnt+1) edsclr_in(i,1,icnt+2) = edsclr_in(i,2,icnt+2) @@ -3442,12 +3686,7 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & endif - ! need to initialize macmic coupling to zero - if (macmic_it==1) ttend_clubb_mc(:ncol,:) = 0._r8 - if (macmic_it==1) upwp_clubb_gw_mc(:ncol,:) = 0._r8 - if (macmic_it==1) vpwp_clubb_gw_mc(:ncol,:) = 0._r8 - if (macmic_it==1) thlp2_clubb_gw_mc(:ncol,:) = 0._r8 - if (macmic_it==1) wpthlp_clubb_gw_mc(:ncol,:) = 0._r8 + call t_stopf('clubb_tend_cam:flip-index') do t=1,nadv ! do needed number of "sub" timesteps for each CAM step @@ -3461,6 +3700,7 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & !###################### CALL MF DIAGNOSTIC PLUMES ###################### !####################################################################### if (do_clubb_mf) then + call t_startf('clubb_tend_cam:do_clubb_mf') do k=2,pverp do i=1, ncol @@ -3473,8 +3713,8 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & invrs_dzt(i,:) = 1._r8/dzt(i,:) end do - rtm_zm_in(1:ncol,:) = zt2zm_api( pverp+1-top_lev, ncol, gr, rtm_in(1:ncol,:) ) - thlm_zm_in(1:ncol,:) = zt2zm_api( pverp+1-top_lev, ncol, gr, thlm_in(1:ncol,:) ) + rtm_zm_in(1:ncol,:) = zt2zm_api( nzm_clubb, ncol, gr, rtm_in(1:ncol,:) ) + thlm_zm_in(1:ncol,:) = zt2zm_api( nzm_clubb, ncol, gr, thlm_in(1:ncol,:) ) do i=1, ncol call integrate_mf( pverp, dzt(i,:), zi_g(i,:), p_in_Pa_zm(i,:), invrs_exner_zm(i,:), & ! input @@ -3511,11 +3751,13 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & ((rho_ds_zm(i,k) * mf_thlflx(i,k)) - (rho_ds_zm(i,k-1) * mf_thlflx(i,k-1))) end do end do + call t_stopf('clubb_tend_cam:do_clubb_mf') end if ! Advance CLUBB CORE one timestep in the future - call advance_clubb_core_api( gr, pverp+1-top_lev, ncol, & + call t_startf('clubb_tend_cam:advance_clubb_core_api') + call advance_clubb_core_api( gr, nzm_clubb, ncol, & l_implemented, dtime, fcor, sfc_elevation, & hydromet_dim, & sclr_dim, sclr_tol, edsclr_dim, sclr_idx, & @@ -3559,6 +3801,7 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & wprcp_out, w_up_in_cloud_out, w_down_in_cloud_out, & cloudy_updraft_frac_out, cloudy_downdraft_frac_out, & rcm_in_layer_out, cloud_cover_out, invrs_tau_zm_out ) + call t_stopf('clubb_tend_cam:advance_clubb_core_api') ! Note that CLUBB does not produce an error code specific to any column, and ! one value only for the entire chunk @@ -3574,22 +3817,23 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & call endrun(subr//': Fatal error in CLUBB library') end if - if (do_rainturb) then + if ( do_rainturb ) then + call t_startf('clubb_tend_cam:do_rainturb') - do k=1,nlev+1 + do k=1,nzm_clubb do i=1,ncol rvm_in(i,k) = rtm_in(i,k) - rcm_inout(i,k) end do end do - call update_xp2_mc_api( gr, nlev+1, ncol, dtime, cloud_frac_inout, & + call update_xp2_mc_api( gr, nzm_clubb, ncol, dtime, cloud_frac_inout, & rcm_inout, rvm_in, thlm_in, wm_zt, & exner, pre_in, pdf_params_chnk(lchnk), & rtp2_mc_out, thlp2_mc_out, & wprtp_mc_out, wpthlp_mc_out, & rtpthlp_mc_out) - do k=1,nlev+1 + do k=1,nzm_clubb do i=1,ncol dum1 = (1._r8 - cam_in%landfrac(i)) @@ -3601,17 +3845,18 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & end do end do + call t_stopf('clubb_tend_cam:do_rainturb') end if - if (do_cldcool) then + call t_startf('clubb_tend_cam:do_cldcool') - rcm_out_zm = zt2zm_api(pverp+1-top_lev, ncol, gr, rcm_inout ) - qrl_zm = zt2zm_api(pverp+1-top_lev, ncol, gr, qrl_clubb ) + rcm_out_zm = zt2zm_api(nzm_clubb, ncol, gr, rcm_inout ) + qrl_zm = zt2zm_api(nzm_clubb, ncol, gr, qrl_clubb ) thlp2_rad_out(:,:) = 0._r8 do i=1, ncol - call calculate_thlp2_rad_api(nlev+1, rcm_out_zm(i,:), thlprcp_out(i,:), qrl_zm(i,:), clubb_params(i,:), & + call calculate_thlp2_rad_api(nzm_clubb, rcm_out_zm(i,:), thlprcp_out(i,:), qrl_zm(i,:), clubb_params(i,:), & thlp2_rad_out(i,:)) end do @@ -3619,16 +3864,19 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & thlp2_in(i,:) = thlp2_in(i,:) + thlp2_rad_out(i,:) * dtime thlp2_in(i,:) = max(thl_tol**2,thlp2_in(i,:)) end do + call t_stopf('clubb_tend_cam:do_cldcool') end if ! Check to see if stats should be output, here stats are read into ! output arrays to make them conformable to CAM output if (stats_metadata%l_stats) then + call t_startf('clubb_tend_cam:stats_end_timestep_clubb') do i=1, ncol call stats_end_timestep_clubb(i, stats_zt(i), stats_zm(i), stats_rad_zt(i), stats_rad_zm(i), stats_sfc(i), & out_zt, out_zm, out_radzt, out_radzm, out_sfc) end do + call t_stopf('clubb_tend_cam:stats_end_timestep_clubb') end if enddo ! end time loop @@ -3636,16 +3884,16 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & if (clubb_do_adv) then if (macmic_it == cld_macmic_num_steps) then - wp2_in = zm2zt_api( pverp+1-top_lev, ncol, gr, wp2_in ) - wpthlp_in = zm2zt_api( pverp+1-top_lev, ncol, gr, wpthlp_in ) - wprtp_in = zm2zt_api( pverp+1-top_lev, ncol, gr, wprtp_in ) - up2_in = zm2zt_api( pverp+1-top_lev, ncol, gr, up2_in ) - vp2_in = zm2zt_api( pverp+1-top_lev, ncol, gr, vp2_in ) - thlp2_in = zm2zt_api( pverp+1-top_lev, ncol, gr, thlp2_in ) - rtp2_in = zm2zt_api( pverp+1-top_lev, ncol, gr, rtp2_in ) - rtpthlp_in = zm2zt_api( pverp+1-top_lev, ncol, gr, rtpthlp_in ) + wp2_in = zm2zt_api( nzm_clubb, ncol, gr, wp2_in ) + wpthlp_in = zm2zt_api( nzm_clubb, ncol, gr, wpthlp_in ) + wprtp_in = zm2zt_api( nzm_clubb, ncol, gr, wprtp_in ) + up2_in = zm2zt_api( nzm_clubb, ncol, gr, up2_in ) + vp2_in = zm2zt_api( nzm_clubb, ncol, gr, vp2_in ) + thlp2_in = zm2zt_api( nzm_clubb, ncol, gr, thlp2_in ) + rtp2_in = zm2zt_api( nzm_clubb, ncol, gr, rtp2_in ) + rtpthlp_in = zm2zt_api( nzm_clubb, ncol, gr, rtpthlp_in ) - do k=1,nlev+1 + do k=1,nzm_clubb do i=1, ncol thlp2_in(i,k) = max(thl_tol**2, thlp2_in(i,k)) rtp2_in(i,k) = max(rt_tol**2, rtp2_in(i,k)) @@ -3659,12 +3907,15 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & end if ! Convert RTP2 and THLP2 to thermo grid for output - rtp2_zt = zm2zt_api( pverp+1-top_lev, ncol, gr, rtp2_in ) - thl2_zt = zm2zt_api( pverp+1-top_lev, ncol, gr, thlp2_in ) - wp2_zt = zm2zt_api( pverp+1-top_lev, ncol, gr, wp2_in ) + rtp2_zt = zm2zt_api( nzm_clubb, ncol, gr, rtp2_in ) + thl2_zt = zm2zt_api( nzm_clubb, ncol, gr, thlp2_in ) + wp2_zt = zm2zt_api( nzm_clubb, ncol, gr, wp2_in ) + + call t_startf('clubb_tend_cam:flip-index') ! Arrays need to be "flipped" to CAM grid - do k=1, nlev+1 + !$acc parallel loop gang vector collapse(2) default(present) + do k=1, nzm_clubb do i=1, ncol um(i,pverp-k+1) = um_in(i,k) vm(i,pverp-k+1) = vm_in(i,k) @@ -3723,47 +3974,19 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & end do end do - ! Accumulate vars through macmic subcycle - upwp_clubb_gw_mc(:ncol,:) = upwp_clubb_gw_mc(:ncol,:) + upwp(:ncol,:) - vpwp_clubb_gw_mc(:ncol,:) = vpwp_clubb_gw_mc(:ncol,:) + vpwp(:ncol,:) - thlp2_clubb_gw_mc(:ncol,:) = thlp2_clubb_gw_mc(:ncol,:) + thlp2(:ncol,:) - wpthlp_clubb_gw_mc(:ncol,:) = wpthlp_clubb_gw_mc(:ncol,:) + wpthlp(:ncol,:) - - ! And average at last macmic step - if (macmic_it == cld_macmic_num_steps) then - upwp_clubb_gw(:ncol,:) = upwp_clubb_gw_mc(:ncol,:)/REAL(cld_macmic_num_steps,r8) - vpwp_clubb_gw(:ncol,:) = vpwp_clubb_gw_mc(:ncol,:)/REAL(cld_macmic_num_steps,r8) - thlp2_clubb_gw(:ncol,:) = thlp2_clubb_gw_mc(:ncol,:)/REAL(cld_macmic_num_steps,r8) - wpthlp_clubb_gw(:ncol,:) = wpthlp_clubb_gw_mc(:ncol,:)/REAL(cld_macmic_num_steps,r8) - end if - - do k=1, nlev+1 - do i=1, ncol - - mean_rt = pdf_params_chnk(lchnk)%mixt_frac(i,k) & - * pdf_params_chnk(lchnk)%rt_1(i,k) & - + ( 1.0_r8 - pdf_params_chnk(lchnk)%mixt_frac(i,k) ) & - * pdf_params_chnk(lchnk)%rt_2(i,k) - - pdfp_rtp2(i,pverp-k+1) = pdf_params_chnk(lchnk)%mixt_frac(i,k) & - * ( ( pdf_params_chnk(lchnk)%rt_1(i,k) - mean_rt )**2 & - + pdf_params_chnk(lchnk)%varnce_rt_1(i,k) ) & - + ( 1.0_r8 - pdf_params_chnk(lchnk)%mixt_frac(i,k) ) & - * ( ( pdf_params_chnk(lchnk)%rt_2(i,k) - mean_rt )**2 & - + pdf_params_chnk(lchnk)%varnce_rt_2(i,k) ) - end do - end do - - do ixind=1,edsclr_dim - do k=1, nlev+1 - do i=1, ncol - edsclr_out(i,pverp-k+1,ixind) = edsclr_in(i,k,ixind) + if ( edsclr_dim > 0 ) then + !$acc parallel loop gang vector collapse(3) default(present) + do ixind=1,edsclr_dim + do k=1, nzm_clubb + do i=1, ncol + edsclr_out(i,pverp-k+1,ixind) = edsclr_in(i,k,ixind) + end do end do end do - end do + end if if (do_clubb_mf) then - do k=1, nlev+1 + do k=1, nzm_clubb do i=1, ncol mf_dry_a_output(i,pverp-k+1) = mf_dry_a(i,k) mf_moist_a_output(i,pverp-k+1) = mf_moist_a(i,k) @@ -3794,9 +4017,51 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & end do end if - ! Values to use above top_lev, for variables that have not already been - ! set up there. These are mostly fill values that should not actually be - ! used in the run, but may end up in diagnostic output. + !$acc parallel loop gang vector collapse(2) default(present) + do k=1, nzm_clubb + do i=1, ncol + + mean_rt = pdf_params_chnk(lchnk)%mixt_frac(i,k) & + * pdf_params_chnk(lchnk)%rt_1(i,k) & + + ( 1.0_r8 - pdf_params_chnk(lchnk)%mixt_frac(i,k) ) & + * pdf_params_chnk(lchnk)%rt_2(i,k) + + pdfp_rtp2(i,pverp-k+1) = pdf_params_chnk(lchnk)%mixt_frac(i,k) & + * ( ( pdf_params_chnk(lchnk)%rt_1(i,k) - mean_rt )**2 & + + pdf_params_chnk(lchnk)%varnce_rt_1(i,k) ) & + + ( 1.0_r8 - pdf_params_chnk(lchnk)%mixt_frac(i,k) ) & + * ( ( pdf_params_chnk(lchnk)%rt_2(i,k) - mean_rt )**2 & + + pdf_params_chnk(lchnk)%varnce_rt_2(i,k) ) + end do + end do + + call t_stopf('clubb_tend_cam:flip-index') + + !$acc parallel loop gang vector collapse(2) default(present) + do k=1, pverp + do i=1, ncol + + ! Accumulate vars through macmic subcycle + upwp_clubb_gw_mc(i,k) = upwp_clubb_gw_mc(i,k) + upwp(i,k) + vpwp_clubb_gw_mc(i,k) = vpwp_clubb_gw_mc(i,k) + vpwp(i,k) + thlp2_clubb_gw_mc(i,k) = thlp2_clubb_gw_mc(i,k) + thlp2(i,k) + wpthlp_clubb_gw_mc(i,k) = wpthlp_clubb_gw_mc(i,k) + wpthlp(i,k) + + ! And average at last macmic step + if (macmic_it == cld_macmic_num_steps) then + upwp_clubb_gw(i,k) = upwp_clubb_gw_mc(i,k)/REAL(cld_macmic_num_steps,r8) + vpwp_clubb_gw(i,k) = vpwp_clubb_gw_mc(i,k)/REAL(cld_macmic_num_steps,r8) + thlp2_clubb_gw(i,k) = thlp2_clubb_gw_mc(i,k)/REAL(cld_macmic_num_steps,r8) + wpthlp_clubb_gw(i,k) = wpthlp_clubb_gw_mc(i,k)/REAL(cld_macmic_num_steps,r8) + end if + + end do + end do + + ! Values to use above top_lev, for variables that have not already been + ! set up there. These are mostly fill values that should not actually be + ! used in the run, but may end up in diagnostic output. + !$acc parallel loop gang vector collapse(2) default(present) do k=1, top_lev-1 do i=1, ncol upwp(i,k) = 0._r8 @@ -3812,24 +4077,31 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & end do end do + ! Fill up arrays needed for McICA. Note we do not want the ghost point, + ! thus why the second loop is needed. + !$acc parallel loop gang vector default(present) + do i=1, pcols + zi_out(i,1) = 0._r8 + end do + ! enforce zero tracer tendencies above the top_lev level -- no change icnt=0 do ixind=1,pcnst if (lq(ixind)) then icnt=icnt+1 - do i=1, ncol - edsclr_out(i,:top_lev-1,icnt) = state1%q(i,:top_lev-1,ixind) + !$acc parallel loop gang vector collapse(2) default(present) + do k=1, top_lev-1 + do i=1, ncol + edsclr_out(i,k,icnt) = state1%q(i,k,ixind) + end do end do end if end do - ! Fill up arrays needed for McICA. Note we do not want the ghost point, - ! thus why the second loop is needed. - zi_out(:,1) = 0._r8 - ! Compute static energy using CLUBB's variables + !$acc parallel loop gang vector collapse(2) default(present) do k=1,pver do i=1, ncol clubb_s(i,k) = cpairv(i,k,lchnk) * thlm(i,k) / inv_exner_clubb(i,k) & @@ -3843,63 +4115,59 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & ! Initialize clubbtop to top_lev, for finding the highlest level CLUBB is ! active for informing where to apply the energy fixer. + !$acc parallel loop gang vector default(present) do i=1, ncol clubbtop(i) = top_lev do while ((rtp2(i,clubbtop(i)) <= 1.e-15_r8 .and. rcm(i,clubbtop(i)) == 0._r8) .and. clubbtop(i) < pver) clubbtop(i) = clubbtop(i) + 1 end do end do - ! - ! set pbuf field so that HB scheme is only applied above CLUBB top - ! - if (do_hb_above_clubb) then - call pbuf_set_field(pbuf, clubbtop_idx, clubbtop) - endif + !$acc parallel loop gang vector default(present) + do i=1, ncol - ! Compute integrals for static energy, kinetic energy, water vapor, and liquid water - ! after CLUBB is called. This is for energy conservation purposes. - se_a(:) = 0._r8 - ke_a(:) = 0._r8 - wv_a(:) = 0._r8 - wl_a(:) = 0._r8 + se_a = 0._r8 + ke_a = 0._r8 + wv_a = 0._r8 + wl_a = 0._r8 - do k=1,pver - do i=1, ncol - se_a(i) = se_a(i) + clubb_s(i,k)*state1%pdel(i,k)*rga - ke_a(i) = ke_a(i) + 0.5_r8*(um(i,k)**2+vm(i,k)**2)*state1%pdel(i,k)*rga - wv_a(i) = wv_a(i) + (rtm(i,k)-rcm(i,k))*state1%pdeldry(i,k)*rga - wl_a(i) = wl_a(i) + (rcm(i,k))*state1%pdeldry(i,k)*rga + se_b = 0._r8 + ke_b = 0._r8 + wv_b = 0._r8 + wl_b = 0._r8 + + do k=1,pver + ! Compute integrals for static energy, kinetic energy, water vapor, and liquid water + ! after CLUBB is called. This is for energy conservation purposes. + se_a = se_a + clubb_s(i,k)*state1%pdel(i,k)*rga + ke_a = ke_a + 0.5_r8*(um(i,k)**2+vm(i,k)**2)*state1%pdel(i,k)*rga + wv_a = wv_a + (rtm(i,k)-rcm(i,k))*state1%pdeldry(i,k)*rga + wl_a = wl_a + (rcm(i,k))*state1%pdeldry(i,k)*rga end do - end do - ! Do the same as above, but for before CLUBB was called. - se_b(:) = 0._r8 - ke_b(:) = 0._r8 - wv_b(:) = 0._r8 - wl_b(:) = 0._r8 + ! Based on these integrals, compute the total energy after CLUBB call + te_a = se_a + ke_a + (latvap+latice) * wv_a + latice * wl_a - do k=1, pver - do i=1, ncol - se_b(i) = se_b(i) + state1%s(i,k)*state1%pdel(i,k)*rga - ke_b(i) = ke_b(i) + 0.5_r8*(state1%u(i,k)**2+state1%v(i,k)**2)*state1%pdel(i,k)*rga - wv_b(i) = wv_b(i) + state1%q(i,k,ixq)*state1%pdeldry(i,k)*rga - wl_b(i) = wl_b(i) + state1%q(i,k,ixcldliq)*state1%pdeldry(i,k)*rga + do k=1, pver + ! Do the same as above, but for before CLUBB was called. + se_b = se_b + state1%s(i,k)*state1%pdel(i,k)*rga + ke_b = ke_b + 0.5_r8*(state1%u(i,k)**2+state1%v(i,k)**2)*state1%pdel(i,k)*rga + wv_b = wv_b + state1%q(i,k,ixq)*state1%pdeldry(i,k)*rga + wl_b = wl_b + state1%q(i,k,ixcldliq)*state1%pdeldry(i,k)*rga end do - end do - - do i=1, ncol - ! Based on these integrals, compute the total energy before and after CLUBB call - te_a(i) = se_a(i) + ke_a(i) + (latvap+latice) * wv_a(i) + latice * wl_a(i) - te_b(i) = se_b(i) + ke_b(i) + (latvap+latice) * wv_b(i) + latice * wl_b(i) + ! Based on these integrals, compute the total energy before CLUBB call + te_b = se_b + ke_b + (latvap+latice) * wv_b + latice * wl_b ! Take into account the surface fluxes of heat and moisture ! Use correct qflux from cam_in, not lhf/latvap as was done previously - te_b(i) = te_b(i) + (cam_in%shf(i)+cam_in%cflx(i,1)*(latvap+latice)) * hdtime + te_b = te_b + (cam_in%shf(i)+cam_in%cflx(i,1)*(latvap+latice)) * hdtime ! Compute the disbalance of total energy, over depth where CLUBB is active - se_dis(i) = (te_a(i) - te_b(i))/(state1%pint(i,pverp)-state1%pint(i,clubbtop(i))) + se_dis(i) = ( te_a - te_b ) / ( state1%pint(i,pverp) - state1%pint(i,clubbtop(i)) ) + + eleak(i) = ( te_a - te_b ) / hdtime + end do ! Fix the total energy coming out of CLUBB so it achieves energy conservation. @@ -3910,46 +4178,80 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & ! when using specified dynamics, so allow this to be turned off via a namelist ! variable. if (clubb_do_energyfix) then + + !$acc parallel loop gang vector default(present) do i=1, ncol + do k=clubbtop(i),pver clubb_s(i,k) = clubb_s(i,k) - se_dis(i)*gravit end do ! convert to units of +ve [K] se_dis(i) = -1._r8*se_dis(i)*gravit/cpairv(i,pver,lchnk) + end do + endif + !$acc parallel loop gang vector collapse(2) default(present) + do k=1, pverp + do i=1, ncol + wpthvp_clubb(i,k) = wpthvp(i,k) * cpair + wprcp_clubb(i,k) = wprcp(i,k) * latvap + end do + end do + + call t_stopf('clubb_tend_cam:ACCR') + + call t_startf('clubb_tend_cam:acc_copyout') + !$acc end data + !$acc end data + !$acc end data + !$acc end data + !$acc end data + call t_stopf('clubb_tend_cam:acc_copyout') + + call t_startf('clubb_tend_cam:NAR') + + + call physics_ptend_init( ptend_loc, state%psetcols, 'clubb', ls=.true., lu=.true., lv=.true., lq=lq ) ! Now compute the tendencies of CLUBB to CAM, note that pverp is the ghost point ! for all variables and therefore is never called in this loop - rtm_integral_vtend(:) = 0._r8 - rtm_integral_ltend(:) = 0._r8 + do i=1, ncol - do k=1, pver - do i=1, ncol + rtm_integral_vtend(i) = 0._r8 + rtm_integral_ltend(i) = 0._r8 - ptend_loc%u(i,k) = (um(i,k) - state1%u(i,k)) / hdtime ! east-west wind - ptend_loc%v(i,k) = (vm(i,k) - state1%v(i,k)) / hdtime ! north-south wind - ptend_loc%q(i,k,ixq) = (rtm(i,k) - rcm(i,k)-state1%q(i,k,ixq)) / hdtime ! water vapor - ptend_loc%q(i,k,ixcldliq) = (rcm(i,k) - state1%q(i,k,ixcldliq)) / hdtime ! Tendency of liquid water - ptend_loc%s(i,k) = (clubb_s(i,k) - state1%s(i,k)) / hdtime ! Tendency of static energy + do k=1, pver - rtm_integral_ltend(i) = rtm_integral_ltend(i) + ptend_loc%q(i,k,ixcldliq)*state1%pdel(i,k) - rtm_integral_vtend(i) = rtm_integral_vtend(i) + ptend_loc%q(i,k,ixq)*state1%pdel(i,k) + ptend_loc%u(i,k) = (um(i,k) - state1%u(i,k)) / hdtime ! east-west wind + ptend_loc%v(i,k) = (vm(i,k) - state1%v(i,k)) / hdtime ! north-south wind + ptend_loc%q(i,k,ixq) = (rtm(i,k) - rcm(i,k)-state1%q(i,k,ixq)) / hdtime ! water vapor + ptend_loc%q(i,k,ixcldliq) = (rcm(i,k) - state1%q(i,k,ixcldliq)) / hdtime ! Tendency of liquid water + ptend_loc%s(i,k) = (clubb_s(i,k) - state1%s(i,k)) / hdtime ! Tendency of static energy - end do - end do + rtm_integral_ltend(i) = rtm_integral_ltend(i) + ptend_loc%q(i,k,ixcldliq)*state1%pdel(i,k) + rtm_integral_vtend(i) = rtm_integral_vtend(i) + ptend_loc%q(i,k,ixq)*state1%pdel(i,k) + + end do - rtm_integral_ltend(:) = rtm_integral_ltend(:)/gravit - rtm_integral_vtend(:) = rtm_integral_vtend(:)/gravit + rtm_integral_ltend(i) = rtm_integral_ltend(i)/gravit + rtm_integral_vtend(i) = rtm_integral_vtend(i)/gravit + + end do ! Accumulate Air Temperature Tendency (TTEND) for Gravity Wave parameterization - ttend_clubb_mc(:ncol,:pver) = ttend_clubb_mc(:ncol,:pver) + ptend_loc%s(:ncol,:pver)/cpair + do k=1, pver + do i=1, ncol + ttend_clubb_mc(i,k) = ttend_clubb_mc(i,k) + ptend_loc%s(i,k)/cpair - ! Average at last macmic step - if (macmic_it == cld_macmic_num_steps) then - ttend_clubb(:ncol,:) = ttend_clubb_mc(:ncol,:pver)/REAL(cld_macmic_num_steps,r8) - end if + ! Average at last macmic step + if (macmic_it == cld_macmic_num_steps) then + ttend_clubb(i,k) = ttend_clubb_mc(i,k) / REAL(cld_macmic_num_steps,r8) + end if + + end do + end do if (clubb_do_adv) then if (macmic_it == cld_macmic_num_steps) then @@ -3978,6 +4280,12 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & end do end do + ! Add constant to ghost point so that output is not corrupted + wp3(:,pverp) = wp3(:,pverp) + wp3_const + rtpthlp(:,pverp) = rtpthlp(:,pverp) + rtpthlp_const + wpthlp(:,pverp) = wpthlp(:,pverp) + wpthlp_const + wprtp(:,pverp) = wprtp(:,pverp) + wprtp_const + else do k=1, pver @@ -4021,46 +4329,26 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & end if end do - call t_stopf("clubb_tend_cam_i_loop") - - call outfld('KVH_CLUBB', khzm, pcols, lchnk) - - eleak(:ncol) = (te_a(:ncol) - te_b(:ncol))/hdtime - call outfld('ELEAK_CLUBB', eleak, pcols, lchnk) - call outfld('TFIX_CLUBB', se_dis, pcols, lchnk) + rvmtend_clubb(:ncol,:pver) = ptend_loc%q(:ncol,:pver,ixq)*state1%pdeldry(:ncol,:pver)/state1%pdel(:ncol,:pver) + rcmtend_clubb(:ncol,:pver) = ptend_loc%q(:ncol,:pver,ixcldliq)*state1%pdeldry(:ncol,:pver)/state1%pdel(:ncol,:pver) + rimtend_clubb(:ncol,:pver) = ptend_loc%q(:ncol,:pver,ixcldice)*state1%pdeldry(:ncol,:pver)/state1%pdel(:ncol,:pver) + stend_clubb(:ncol,:pver) = ptend_loc%s(:ncol,:pver) + utend_clubb(:ncol,:pver) = ptend_loc%u(:ncol,:pver) + vtend_clubb(:ncol,:pver) = ptend_loc%v(:ncol,:pver) + cmeliq(:ncol,:pver) = ptend_loc%q(:ncol,:pver,ixcldliq)*state1%pdeldry(:ncol,:pver)/state1%pdel(:ncol,:pver) - ! Add constant to ghost point so that output is not corrupted - if (clubb_do_adv) then - if (macmic_it == cld_macmic_num_steps) then - wp3(:,pverp) = wp3(:,pverp) + wp3_const - rtpthlp(:,pverp) = rtpthlp(:,pverp) + rtpthlp_const - wpthlp(:,pverp) = wpthlp(:,pverp) + wpthlp_const - wprtp(:,pverp) = wprtp(:,pverp) + wprtp_const - end if - end if + ! + ! set pbuf field so that HB scheme is only applied above CLUBB top + ! + if (do_hb_above_clubb) then + call pbuf_set_field(pbuf, clubbtop_idx, clubbtop) + endif ! ------------------------------------------------- ! ! End column computation of CLUBB, begin to apply ! ! and compute output, etc ! ! ------------------------------------------------- ! - ! Output CLUBB tendencies (convert dry basis to wet for consistency with history variable definition) - temp2d(:ncol,:pver) = ptend_loc%q(:ncol,:pver,ixq)*state1%pdeldry(:ncol,:pver)/state1%pdel(:ncol,:pver) - call outfld( 'RVMTEND_CLUBB', temp2d, pcols, lchnk) - - temp2d(:ncol,:pver) = ptend_loc%q(:ncol,:pver,ixcldliq)*state1%pdeldry(:ncol,:pver)/state1%pdel(:ncol,:pver) - call outfld( 'RCMTEND_CLUBB', temp2d, pcols, lchnk) - - temp2d(:ncol,:pver) = ptend_loc%q(:ncol,:pver,ixcldice)*state1%pdeldry(:ncol,:pver)/state1%pdel(:ncol,:pver) - call outfld( 'RIMTEND_CLUBB', temp2d, pcols, lchnk) - - call outfld( 'STEND_CLUBB', ptend_loc%s,pcols, lchnk) - call outfld( 'UTEND_CLUBB', ptend_loc%u,pcols, lchnk) - call outfld( 'VTEND_CLUBB', ptend_loc%v,pcols, lchnk) - - cmeliq(:ncol,:pver) = ptend_loc%q(:ncol,:pver,ixcldliq)*state1%pdeldry(:ncol,:pver)/state1%pdel(:ncol,:pver) - call outfld( 'CMELIQ', cmeliq, pcols, lchnk) - call physics_ptend_sum(ptend_loc,ptend_all,ncol) call physics_update(state1,ptend_loc,hdtime) @@ -4071,6 +4359,7 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & if (clubb_do_liqsupersat) then + call t_startf('clubb_cam_tend:do_liqsupersat') ! -------------------------------------- ! ! Ice Saturation Adjustment Computation ! ! -------------------------------------- ! @@ -4122,6 +4411,7 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & end where call outfld( 'FQTENDICE', fqtend, pcols, lchnk ) + call t_stopf('clubb_cam_tend:do_liqsupersat') end if ! ------------------------------------------------------------ ! @@ -4149,6 +4439,7 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & do k=1,pver do i=1,ncol + if( state1%t(i,k) > meltpt_temp ) then dum1 = 0.0_r8 elseif ( state1%t(i,k) < dt_low ) then @@ -4185,19 +4476,10 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & enddo det_ice(:ncol) = det_ice(:ncol)/1000._r8 ! divide by density of water - - ! output moist basis to be consistent with history variable definition - temp2d(:ncol,:pver) = ptend_loc%q(:ncol,:pver,ixcldliq)*state1%pdeldry(:ncol,:pver)/state1%pdel(:ncol,:pver) - call outfld( 'DPDLFLIQ', temp2d, pcols, lchnk) - - ! output moist basis to be consistent with history variable definition - temp2d(:ncol,:pver) = ptend_loc%q(:ncol,:pver,ixcldice)*state1%pdeldry(:ncol,:pver)/state1%pdel(:ncol,:pver) - call outfld( 'DPDLFICE', temp2d, pcols, lchnk) - - temp2d(:ncol,:pver) = ptend_loc%s(:ncol,:pver)/cpairv(:ncol,:pver, lchnk) - call outfld( 'DPDLFT', temp2d, pcols, lchnk) - - call outfld( 'DETNLIQTND', ptend_loc%q(:,:,ixnumliq),pcols, lchnk ) + dpdlfliq(:ncol,:pver) = ptend_loc%q(:ncol,:pver,ixcldliq)*state1%pdeldry(:ncol,:pver)/state1%pdel(:ncol,:pver) + dpdlfice(:ncol,:pver) = ptend_loc%q(:ncol,:pver,ixcldice)*state1%pdeldry(:ncol,:pver)/state1%pdel(:ncol,:pver) + dpdlft(:ncol,:pver) = ptend_loc%s(:ncol,:pver)/cpairv(:ncol,:pver, lchnk) + detnliquid(:ncol,:pver) = ptend_loc%q(:ncol,:pver,ixnumliq) call physics_ptend_sum(ptend_loc,ptend_all,ncol) call physics_update(state1,ptend_loc,hdtime) @@ -4224,11 +4506,20 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & relvarmax = 10.0_r8 endif - relvar(:,:) = relvarmax ! default + do i = 1, ncol + do k = 1, pver + relvar(i,k) = relvarmax ! default + end do + end do if (deep_scheme .ne. 'CLUBB_SGS') then - where (rcm(:ncol,:pver) /= 0 .and. qclvar(:ncol,:pver) /= 0) & - relvar(:ncol,:pver) = min(relvarmax,max(0.001_r8,rcm(:ncol,:pver)**2/qclvar(:ncol,:pver))) + do i = 1, ncol + do k = 1, pver + if ( rcm(i,k) /= 0 .and. qclvar(i,k) /= 0 ) then + relvar(i,k) = min( relvarmax, max(0.001_r8, rcm(i,k)**2 / qclvar(i,k) ) ) + end if + end do + end do endif ! ------------------------------------------------- ! @@ -4341,6 +4632,11 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & ! use the aist_vector function to compute the ice cloud fraction ! ! --------------------------------------------------------------------------------- ! + !REMOVECAM - no longer need this when CAM is retired and pcols no longer exists + troplev(:) = 0 + !REMOVECAM_END + call tropopause_findChemTrop( state, troplev ) + aist(:,:top_lev-1) = 0._r8 qsatfac(:, :) = 0._r8 ! Zero out entire profile in case qsatfac is left undefined in aist_vector below @@ -4430,8 +4726,6 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & ustar2, obklen, kbfs, pblh, dummy2, & state1%zi, cloud_frac(:,1:pver), 1._r8-cam_in%landfrac, dummy3) - ! Output the PBL depth - call outfld('PBLH', pblh, pcols, lchnk) ! Assign the first pver levels of cloud_frac back to cld cld(:,1:pver) = cloud_frac(:,1:pver) @@ -4440,6 +4734,30 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & ! END CLOUD FRACTION DIAGNOSIS, begin to store variables back into buffer ! ! --------------------------------------------------------------------------------- ! + call outfld( 'DETNLIQTND', detnliquid,pcols, lchnk ) + + ! Output CLUBB tendencies (convert dry basis to wet for consistency with history variable definition) + call outfld( 'RVMTEND_CLUBB', rvmtend_clubb, pcols, lchnk) + call outfld( 'RCMTEND_CLUBB', rcmtend_clubb, pcols, lchnk) + call outfld( 'RIMTEND_CLUBB', rimtend_clubb, pcols, lchnk) + call outfld( 'STEND_CLUBB', stend_clubb, pcols, lchnk) + call outfld( 'UTEND_CLUBB', utend_clubb, pcols, lchnk) + call outfld( 'VTEND_CLUBB', vtend_clubb, pcols, lchnk) + + call outfld( 'CMELIQ', cmeliq, pcols, lchnk) + + ! output moist basis to be consistent with history variable definition + call outfld( 'DPDLFLIQ', dpdlfliq, pcols, lchnk) + call outfld( 'DPDLFICE', dpdlfice, pcols, lchnk) + call outfld( 'DPDLFT', dpdlft, pcols, lchnk) + + ! Output the PBL depth + call outfld('PBLH', pblh, pcols, lchnk) + + call outfld('KVH_CLUBB', khzm, pcols, lchnk) + call outfld('ELEAK_CLUBB', eleak, pcols, lchnk) + call outfld('TFIX_CLUBB', se_dis, pcols, lchnk) + ! Output calls of variables goes here call outfld( 'RELVAR', relvar, pcols, lchnk ) call outfld( 'RHO_CLUBB', rho(:,1:pver), pcols, lchnk ) @@ -4456,13 +4774,8 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & call outfld( 'RCM_CLUBB', rcm(:,1:pver), pcols, lchnk ) call outfld( 'RTM_CLUBB', rtm(:,1:pver), pcols, lchnk ) call outfld( 'THLM_CLUBB', thlm(:,1:pver), pcols, lchnk ) - - temp2dp(:ncol,:) = wprcp(:ncol,:) * latvap - call outfld( 'WPRCP_CLUBB', temp2dp, pcols, lchnk ) - - temp2dp(:ncol,:) = wpthvp(:ncol,:) * cpair - call outfld( 'WPTHVP_CLUBB', temp2dp, pcols, lchnk ) - + call outfld( 'WPRCP_CLUBB', wprcp_clubb, pcols, lchnk ) + call outfld( 'WPTHVP_CLUBB', wpthvp_clubb, pcols, lchnk ) call outfld( 'RTP2_ZT_CLUBB', rtp2_zt_out(:,1:pver), pcols, lchnk ) call outfld( 'THLP2_ZT_CLUBB', thl2_zt_out(:,1:pver), pcols, lchnk ) call outfld( 'WP2_ZT_CLUBB', wp2_zt_out(:,1:pver), pcols, lchnk ) @@ -4547,11 +4860,13 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & enddo endif + call t_stopf('clubb_tend_cam:NAR') +#endif - call t_stopf("clubb_tend_cam") + call t_stopf('clubb_tend_cam') return -#endif + end subroutine clubb_tend_cam subroutine clubb_emissions_cam (state, cam_in, ptend) @@ -4833,7 +5148,7 @@ subroutine stats_init_clubb( l_stats_in, stats_tsamp_in, stats_tout_in, & ! Set stats_variables variables with inputs from calling subroutine stats_metadata%l_stats = l_stats_in - + stats_metadata%stats_tsamp = stats_tsamp_in stats_metadata%stats_tout = stats_tout_in @@ -5115,7 +5430,8 @@ subroutine stats_init_clubb( l_stats_in, stats_tsamp_in, stats_tout_in, & call addfld( trim(sub), (/ 'ilev' /), 'A', & trim(stats_zt(1)%file%grid_avg_var(i)%units), & - trim(stats_zt(1)%file%grid_avg_var(i)%description) ) + trim(stats_zt(1)%file%grid_avg_var(i)%description), & + sampled_on_subcycle=.true. ) enddo do i = 1, stats_zm(1)%num_output_fields @@ -5126,7 +5442,8 @@ subroutine stats_init_clubb( l_stats_in, stats_tsamp_in, stats_tout_in, & call addfld( trim(sub), (/ 'ilev' /), 'A', & trim(stats_zm(1)%file%grid_avg_var(i)%units), & - trim(stats_zm(1)%file%grid_avg_var(i)%description) ) + trim(stats_zm(1)%file%grid_avg_var(i)%description), & + sampled_on_subcycle=.true. ) enddo if (stats_metadata%l_output_rad_files) then @@ -5137,7 +5454,8 @@ subroutine stats_init_clubb( l_stats_in, stats_tsamp_in, stats_tout_in, & if (len(temp1) > max_fieldname_len) sub = temp1(1:max_fieldname_len) call addfld( trim(sub), (/ 'ilev' /), 'A', & trim(stats_rad_zt(1)%file%grid_avg_var(i)%units), & - trim(stats_rad_zt(1)%file%grid_avg_var(i)%description) ) + trim(stats_rad_zt(1)%file%grid_avg_var(i)%description), & + sampled_on_subcycle=.true. ) enddo do i = 1, stats_rad_zm(1)%num_output_fields @@ -5146,7 +5464,8 @@ subroutine stats_init_clubb( l_stats_in, stats_tsamp_in, stats_tout_in, & if (len(temp1) > max_fieldname_len) sub = temp1(1:max_fieldname_len) call addfld( trim(sub), (/ 'ilev' /), 'A', & trim(stats_rad_zm(1)%file%grid_avg_var(i)%units), & - trim(stats_rad_zm(1)%file%grid_avg_var(i)%description) ) + trim(stats_rad_zm(1)%file%grid_avg_var(i)%description), & + sampled_on_subcycle=.true. ) enddo endif @@ -5156,7 +5475,8 @@ subroutine stats_init_clubb( l_stats_in, stats_tsamp_in, stats_tout_in, & if (len(temp1) > max_fieldname_len) sub = temp1(1:max_fieldname_len) call addfld( trim(sub), horiz_only, 'A', & trim(stats_sfc(1)%file%grid_avg_var(i)%units), & - trim(stats_sfc(1)%file%grid_avg_var(i)%description) ) + trim(stats_sfc(1)%file%grid_avg_var(i)%description), & + sampled_on_subcycle=.true. ) enddo diff --git a/src/physics/cam/hetfrz_classnuc_cam.F90 b/src/physics/cam/hetfrz_classnuc_cam.F90 index 2f6d11787b..175ba8cfbb 100644 --- a/src/physics/cam/hetfrz_classnuc_cam.F90 +++ b/src/physics/cam/hetfrz_classnuc_cam.F90 @@ -228,23 +228,23 @@ subroutine hetfrz_classnuc_cam_init(mincld_in, aero_props) wactfac_hnames(cnt) = trim(tmpstr)//'_wactfac' call addfld(tot_dens_hnames(cnt),(/ 'lev' /), 'A', '#/cm3', & - 'total '//trim(tmpstr)//' number density' ) + 'total '//trim(tmpstr)//' number density', sampled_on_subcycle=.true.) call addfld(cld_dens_hnames(cnt),(/ 'lev' /), 'A', '#/cm3', & - 'cloud borne '//trim(tmpstr)//' number density' ) + 'cloud borne '//trim(tmpstr)//' number density', sampled_on_subcycle=.true.) call addfld(cldfn_dens_hnames(cnt),(/ 'lev' /), 'A', '#/cm3', & - 'cloud borne '//trim(tmpstr)//' number density derived from fn' ) + 'cloud borne '//trim(tmpstr)//' number density derived from fn', sampled_on_subcycle=.true.) call addfld(amb_dens_hnames(cnt),(/ 'lev' /), 'A', '#/cm3', & - 'ambient '//trim(tmpstr)//' number density' ) + 'ambient '//trim(tmpstr)//' number density', sampled_on_subcycle=.true.) call addfld(coated_dens_hnames(cnt),(/ 'lev' /), 'A', '#/cm3', & - 'coated '//trim(tmpstr)//' number density' ) + 'coated '//trim(tmpstr)//' number density', sampled_on_subcycle=.true.) call addfld(uncoated_dens_hnames(cnt),(/ 'lev' /), 'A', '#/cm3', & - 'uncoated '//trim(tmpstr)//' number density' ) + 'uncoated '//trim(tmpstr)//' number density', sampled_on_subcycle=.true.) call addfld(coated_frac_hnames(cnt),(/ 'lev' /), 'A', '#/cm3', & - 'coated '//trim(tmpstr)//' fraction' ) + 'coated '//trim(tmpstr)//' fraction', sampled_on_subcycle=.true.) call addfld(radius_hnames(cnt),(/ 'lev' /), 'A', 'm', & - 'ambient '//trim(tmpstr)//' radius' ) + 'ambient '//trim(tmpstr)//' radius', sampled_on_subcycle=.true.) call addfld(wactfac_hnames(cnt),(/ 'lev' /), 'A', ' ', & - trim(tmpstr)//' water activity mass factor' ) + trim(tmpstr)//' water activity mass factor', sampled_on_subcycle=.true.) end if end do @@ -261,49 +261,49 @@ subroutine hetfrz_classnuc_cam_init(mincld_in, aero_props) ! pbuf fields used by hetfrz_classnuc ast_idx = pbuf_get_index('AST') - call addfld('FRZIMM', (/ 'lev' /), 'A', ' ', 'immersion freezing') - call addfld('FRZCNT', (/ 'lev' /), 'A', ' ', 'contact freezing') - call addfld('FRZDEP', (/ 'lev' /), 'A', ' ', 'deposition freezing') - call addfld('FREQIMM', (/ 'lev' /), 'A', 'fraction', 'Fractional occurance of immersion freezing') - call addfld('FREQCNT', (/ 'lev' /), 'A', 'fraction', 'Fractional occurance of contact freezing') - call addfld('FREQDEP', (/ 'lev' /), 'A', 'fraction', 'Fractional occurance of deposition freezing') - call addfld('FREQMIX', (/ 'lev' /), 'A', 'fraction', 'Fractional occurance of mixed-phase clouds' ) + call addfld('FRZIMM', (/ 'lev' /), 'A', ' ', 'immersion freezing', sampled_on_subcycle=.true.) + call addfld('FRZCNT', (/ 'lev' /), 'A', ' ', 'contact freezing', sampled_on_subcycle=.true.) + call addfld('FRZDEP', (/ 'lev' /), 'A', ' ', 'deposition freezing', sampled_on_subcycle=.true.) + call addfld('FREQIMM', (/ 'lev' /), 'A', 'fraction', 'Fractional occurance of immersion freezing', sampled_on_subcycle=.true.) + call addfld('FREQCNT', (/ 'lev' /), 'A', 'fraction', 'Fractional occurance of contact freezing', sampled_on_subcycle=.true.) + call addfld('FREQDEP', (/ 'lev' /), 'A', 'fraction', 'Fractional occurance of deposition freezing', sampled_on_subcycle=.true.) + call addfld('FREQMIX', (/ 'lev' /), 'A', 'fraction', 'Fractional occurance of mixed-phase clouds' , sampled_on_subcycle=.true.) - call addfld('DSTFREZIMM', (/ 'lev' /), 'A', 'm-3s-1', 'dust immersion freezing rate') - call addfld('DSTFREZCNT', (/ 'lev' /), 'A', 'm-3s-1', 'dust contact freezing rate') - call addfld('DSTFREZDEP', (/ 'lev' /), 'A', 'm-3s-1', 'dust deposition freezing rate') + call addfld('DSTFREZIMM', (/ 'lev' /), 'A', 'm-3s-1', 'dust immersion freezing rate', sampled_on_subcycle=.true.) + call addfld('DSTFREZCNT', (/ 'lev' /), 'A', 'm-3s-1', 'dust contact freezing rate', sampled_on_subcycle=.true.) + call addfld('DSTFREZDEP', (/ 'lev' /), 'A', 'm-3s-1', 'dust deposition freezing rate', sampled_on_subcycle=.true.) - call addfld('BCFREZIMM', (/ 'lev' /), 'A', 'm-3s-1', 'bc immersion freezing rate') - call addfld('BCFREZCNT', (/ 'lev' /), 'A', 'm-3s-1', 'bc contact freezing rate') - call addfld('BCFREZDEP', (/ 'lev' /), 'A', 'm-3s-1', 'bc deposition freezing rate') + call addfld('BCFREZIMM', (/ 'lev' /), 'A', 'm-3s-1', 'bc immersion freezing rate', sampled_on_subcycle=.true.) + call addfld('BCFREZCNT', (/ 'lev' /), 'A', 'm-3s-1', 'bc contact freezing rate', sampled_on_subcycle=.true.) + call addfld('BCFREZDEP', (/ 'lev' /), 'A', 'm-3s-1', 'bc deposition freezing rate', sampled_on_subcycle=.true.) call addfld('NIMIX_IMM', (/ 'lev' /), 'A', '#/m3', & - 'Activated Ice Number Concentration due to het immersion freezing in Mixed Clouds') + 'Activated Ice Number Concentration due to het immersion freezing in Mixed Clouds', sampled_on_subcycle=.true.) call addfld('NIMIX_CNT', (/ 'lev' /), 'A', '#/m3', & - 'Activated Ice Number Concentration due to het contact freezing in Mixed Clouds') + 'Activated Ice Number Concentration due to het contact freezing in Mixed Clouds', sampled_on_subcycle=.true.) call addfld('NIMIX_DEP', (/ 'lev' /), 'A', '#/m3', & - 'Activated Ice Number Concentration due to het deposition freezing in Mixed Clouds') + 'Activated Ice Number Concentration due to het deposition freezing in Mixed Clouds', sampled_on_subcycle=.true.) call addfld('DSTNIDEP', (/ 'lev' /), 'A', '#/m3', & - 'Activated Ice Number Concentration due to dst dep freezing in Mixed Clouds') + 'Activated Ice Number Concentration due to dst dep freezing in Mixed Clouds', sampled_on_subcycle=.true.) call addfld('DSTNICNT', (/ 'lev' /), 'A', '#/m3', & - 'Activated Ice Number Concentration due to dst cnt freezing in Mixed Clouds') + 'Activated Ice Number Concentration due to dst cnt freezing in Mixed Clouds', sampled_on_subcycle=.true.) call addfld('DSTNIIMM', (/ 'lev' /), 'A', '#/m3', & - 'Activated Ice Number Concentration due to dst imm freezing in Mixed Clouds') + 'Activated Ice Number Concentration due to dst imm freezing in Mixed Clouds', sampled_on_subcycle=.true.) call addfld('BCNIDEP', (/ 'lev' /), 'A', '#/m3', & - 'Activated Ice Number Concentration due to bc dep freezing in Mixed Clouds') + 'Activated Ice Number Concentration due to bc dep freezing in Mixed Clouds', sampled_on_subcycle=.true.) call addfld('BCNICNT', (/ 'lev' /), 'A', '#/m3', & - 'Activated Ice Number Concentration due to bc cnt freezing in Mixed Clouds') + 'Activated Ice Number Concentration due to bc cnt freezing in Mixed Clouds', sampled_on_subcycle=.true.) call addfld('BCNIIMM', (/ 'lev' /), 'A', '#/m3', & - 'Activated Ice Number Concentration due to bc imm freezing in Mixed Clouds') + 'Activated Ice Number Concentration due to bc imm freezing in Mixed Clouds', sampled_on_subcycle=.true.) call addfld('NUMICE10s', (/ 'lev' /), 'A', '#/m3', & - 'Ice Number Concentration due to het freezing in Mixed Clouds during 10-s period') + 'Ice Number Concentration due to het freezing in Mixed Clouds during 10-s period', sampled_on_subcycle=.true.) call addfld('NUMIMM10sDST', (/ 'lev' /), 'A', '#/m3', & - 'Ice Number Concentration due to imm freezing by dst in Mixed Clouds during 10-s period') + 'Ice Number Concentration due to imm freezing by dst in Mixed Clouds during 10-s period', sampled_on_subcycle=.true.) call addfld('NUMIMM10sBC', (/ 'lev' /), 'A', '#/m3', & - 'Ice Number Concentration due to imm freezing by bc in Mixed Clouds during 10-s period') + 'Ice Number Concentration due to imm freezing by bc in Mixed Clouds during 10-s period', sampled_on_subcycle=.true.) if (hist_hetfrz_classnuc) then diff --git a/src/physics/cam/macrop_driver.F90 b/src/physics/cam/macrop_driver.F90 index 92d52fff8c..d381387bfc 100644 --- a/src/physics/cam/macrop_driver.F90 +++ b/src/physics/cam/macrop_driver.F90 @@ -237,53 +237,53 @@ subroutine macrop_driver_init(pbuf2d) use_shfrc = .false. endif - call addfld ('DPDLFLIQ', (/ 'lev' /), 'A', 'kg/kg/s', 'Detrained liquid water from deep convection' ) - call addfld ('DPDLFICE', (/ 'lev' /), 'A', 'kg/kg/s', 'Detrained ice from deep convection' ) - call addfld ('SHDLFLIQ', (/ 'lev' /), 'A', 'kg/kg/s', 'Detrained liquid water from shallow convection' ) - call addfld ('SHDLFICE', (/ 'lev' /), 'A', 'kg/kg/s', 'Detrained ice from shallow convection' ) - call addfld ('DPDLFT', (/ 'lev' /), 'A', 'K/s', 'T-tendency due to deep convective detrainment' ) - call addfld ('SHDLFT', (/ 'lev' /), 'A', 'K/s', 'T-tendency due to shallow convective detrainment' ) + call addfld ('DPDLFLIQ', (/ 'lev' /), 'A', 'kg/kg/s', 'Detrained liquid water from deep convection', sampled_on_subcycle=.true.) + call addfld ('DPDLFICE', (/ 'lev' /), 'A', 'kg/kg/s', 'Detrained ice from deep convection', sampled_on_subcycle=.true.) + call addfld ('SHDLFLIQ', (/ 'lev' /), 'A', 'kg/kg/s', 'Detrained liquid water from shallow convection', sampled_on_subcycle=.true.) + call addfld ('SHDLFICE', (/ 'lev' /), 'A', 'kg/kg/s', 'Detrained ice from shallow convection', sampled_on_subcycle=.true.) + call addfld ('DPDLFT', (/ 'lev' /), 'A', 'K/s', 'T-tendency due to deep convective detrainment', sampled_on_subcycle=.true.) + call addfld ('SHDLFT', (/ 'lev' /), 'A', 'K/s', 'T-tendency due to shallow convective detrainment', sampled_on_subcycle=.true.) - call addfld ('ZMDLF', (/ 'lev' /), 'A', 'kg/kg/s', 'Detrained liquid water from ZM convection' ) + call addfld ('ZMDLF', (/ 'lev' /), 'A', 'kg/kg/s', 'Detrained liquid water from ZM convection', sampled_on_subcycle=.true.) - call addfld ('MACPDT', (/ 'lev' /), 'A', 'W/kg', 'Heating tendency - Revised macrophysics' ) - call addfld ('MACPDQ', (/ 'lev' /), 'A', 'kg/kg/s', 'Q tendency - Revised macrophysics' ) - call addfld ('MACPDLIQ', (/ 'lev' /), 'A', 'kg/kg/s', 'CLDLIQ tendency - Revised macrophysics' ) - call addfld ('MACPDICE', (/ 'lev' /), 'A', 'kg/kg/s', 'CLDICE tendency - Revised macrophysics' ) + call addfld ('MACPDT', (/ 'lev' /), 'A', 'W/kg', 'Heating tendency - Revised macrophysics', sampled_on_subcycle=.true.) + call addfld ('MACPDQ', (/ 'lev' /), 'A', 'kg/kg/s', 'Q tendency - Revised macrophysics', sampled_on_subcycle=.true.) + call addfld ('MACPDLIQ', (/ 'lev' /), 'A', 'kg/kg/s', 'CLDLIQ tendency - Revised macrophysics', sampled_on_subcycle=.true.) + call addfld ('MACPDICE', (/ 'lev' /), 'A', 'kg/kg/s', 'CLDICE tendency - Revised macrophysics', sampled_on_subcycle=.true.) call addfld ('CLDVAPADJ', (/ 'lev' /), 'A', 'kg/kg/s', & - 'Q tendency associated with liq/ice adjustment - Revised macrophysics' ) - call addfld ('CLDLIQADJ', (/ 'lev' /), 'A', 'kg/kg/s', 'CLDLIQ adjustment tendency - Revised macrophysics' ) - call addfld ('CLDICEADJ', (/ 'lev' /), 'A', 'kg/kg/s', 'CLDICE adjustment tendency - Revised macrophysics' ) + 'Q tendency associated with liq/ice adjustment - Revised macrophysics', sampled_on_subcycle=.true.) + call addfld ('CLDLIQADJ', (/ 'lev' /), 'A', 'kg/kg/s', 'CLDLIQ adjustment tendency - Revised macrophysics', sampled_on_subcycle=.true.) + call addfld ('CLDICEADJ', (/ 'lev' /), 'A', 'kg/kg/s', 'CLDICE adjustment tendency - Revised macrophysics', sampled_on_subcycle=.true.) call addfld ('CLDLIQDET', (/ 'lev' /), 'A', 'kg/kg/s', & - 'Detrainment of conv cld liq into envrionment - Revised macrophysics' ) + 'Detrainment of conv cld liq into envrionment - Revised macrophysics', sampled_on_subcycle=.true.) call addfld ('CLDICEDET', (/ 'lev' /), 'A', 'kg/kg/s', & - 'Detrainment of conv cld ice into envrionment - Revised macrophysics' ) - call addfld ('CLDLIQLIM', (/ 'lev' /), 'A', 'kg/kg/s', 'CLDLIQ limiting tendency - Revised macrophysics' ) - call addfld ('CLDICELIM', (/ 'lev' /), 'A', 'kg/kg/s', 'CLDICE limiting tendency - Revised macrophysics' ) + 'Detrainment of conv cld ice into envrionment - Revised macrophysics', sampled_on_subcycle=.true.) + call addfld ('CLDLIQLIM', (/ 'lev' /), 'A', 'kg/kg/s', 'CLDLIQ limiting tendency - Revised macrophysics', sampled_on_subcycle=.true.) + call addfld ('CLDICELIM', (/ 'lev' /), 'A', 'kg/kg/s', 'CLDICE limiting tendency - Revised macrophysics', sampled_on_subcycle=.true.) - call addfld ('AST', (/ 'lev' /), 'A', '1', 'Stratus cloud fraction' ) - call addfld ('LIQCLDF', (/ 'lev' /), 'A', '1', 'Stratus Liquid cloud fraction' ) - call addfld ('ICECLDF', (/ 'lev' /), 'A', '1', 'Stratus ICE cloud fraction' ) + call addfld ('AST', (/ 'lev' /), 'A', '1', 'Stratus cloud fraction', sampled_on_subcycle=.true.) + call addfld ('LIQCLDF', (/ 'lev' /), 'A', '1', 'Stratus Liquid cloud fraction', sampled_on_subcycle=.true.) + call addfld ('ICECLDF', (/ 'lev' /), 'A', '1', 'Stratus ICE cloud fraction', sampled_on_subcycle=.true.) - call addfld ('CLDST', (/ 'lev' /), 'A', 'fraction', 'Stratus cloud fraction' ) - call addfld ('CONCLD', (/ 'lev' /), 'A', 'fraction', 'Convective cloud cover' ) + call addfld ('CLDST', (/ 'lev' /), 'A', 'fraction', 'Stratus cloud fraction', sampled_on_subcycle=.true.) + call addfld ('CONCLD', (/ 'lev' /), 'A', 'fraction', 'Convective cloud cover', sampled_on_subcycle=.true.) - call addfld ('CLR_LIQ', (/ 'lev' /), 'A', 'fraction', 'Clear sky fraction for liquid stratus' ) - call addfld ('CLR_ICE', (/ 'lev' /), 'A', 'fraction', 'Clear sky fraction for ice stratus' ) + call addfld ('CLR_LIQ', (/ 'lev' /), 'A', 'fraction', 'Clear sky fraction for liquid stratus', sampled_on_subcycle=.true.) + call addfld ('CLR_ICE', (/ 'lev' /), 'A', 'fraction', 'Clear sky fraction for ice stratus', sampled_on_subcycle=.true.) - call addfld ('CLDLIQSTR', (/ 'lev' /), 'A', 'kg/kg', 'Stratiform CLDLIQ' ) - call addfld ('CLDICESTR', (/ 'lev' /), 'A', 'kg/kg', 'Stratiform CLDICE' ) - call addfld ('CLDLIQCON', (/ 'lev' /), 'A', 'kg/kg', 'Convective CLDLIQ' ) - call addfld ('CLDICECON', (/ 'lev' /), 'A', 'kg/kg', 'Convective CLDICE' ) + call addfld ('CLDLIQSTR', (/ 'lev' /), 'A', 'kg/kg', 'Stratiform CLDLIQ', sampled_on_subcycle=.true.) + call addfld ('CLDICESTR', (/ 'lev' /), 'A', 'kg/kg', 'Stratiform CLDICE', sampled_on_subcycle=.true.) + call addfld ('CLDLIQCON', (/ 'lev' /), 'A', 'kg/kg', 'Convective CLDLIQ', sampled_on_subcycle=.true.) + call addfld ('CLDICECON', (/ 'lev' /), 'A', 'kg/kg', 'Convective CLDICE', sampled_on_subcycle=.true.) - call addfld ('CLDSICE', (/ 'lev' /), 'A', 'kg/kg', 'CloudSat equivalent ice mass mixing ratio' ) - call addfld ('CMELIQ', (/ 'lev' /), 'A', 'kg/kg/s', 'Rate of cond-evap of liq within the cloud' ) + call addfld ('CLDSICE', (/ 'lev' /), 'A', 'kg/kg', 'CloudSat equivalent ice mass mixing ratio', sampled_on_subcycle=.true.) + call addfld ('CMELIQ', (/ 'lev' /), 'A', 'kg/kg/s', 'Rate of cond-evap of liq within the cloud', sampled_on_subcycle=.true.) - call addfld ('TTENDICE', (/ 'lev' /), 'A', 'K/s', 'T tendency from Ice Saturation Adjustment' ) - call addfld ('QVTENDICE', (/ 'lev' /), 'A', 'kg/kg/s', 'Q tendency from Ice Saturation Adjustment' ) - call addfld ('QITENDICE', (/ 'lev' /), 'A', 'kg/kg/s', 'CLDICE tendency from Ice Saturation Adjustment' ) - call addfld ('NITENDICE', (/ 'lev' /), 'A', 'kg/kg/s', 'NUMICE tendency from Ice Saturation Adjustment' ) + call addfld ('TTENDICE', (/ 'lev' /), 'A', 'K/s', 'T tendency from Ice Saturation Adjustment', sampled_on_subcycle=.true.) + call addfld ('QVTENDICE', (/ 'lev' /), 'A', 'kg/kg/s', 'Q tendency from Ice Saturation Adjustment', sampled_on_subcycle=.true.) + call addfld ('QITENDICE', (/ 'lev' /), 'A', 'kg/kg/s', 'CLDICE tendency from Ice Saturation Adjustment', sampled_on_subcycle=.true.) + call addfld ('NITENDICE', (/ 'lev' /), 'A', 'kg/kg/s', 'NUMICE tendency from Ice Saturation Adjustment', sampled_on_subcycle=.true.) if ( history_budget ) then call add_default ('DPDLFLIQ ', history_budget_histfile_num, ' ') diff --git a/src/physics/cam/micro_pumas_cam.F90 b/src/physics/cam/micro_pumas_cam.F90 index a0c66eb7f1..d5f98c9813 100644 --- a/src/physics/cam/micro_pumas_cam.F90 +++ b/src/physics/cam/micro_pumas_cam.F90 @@ -925,251 +925,251 @@ subroutine micro_pumas_cam_init(pbuf2d) call cnst_get_ind(cnst_names(m), mm) if ( any(mm == (/ ixcldliq, ixcldice, ixrain, ixsnow, ixgraupel /)) ) then ! mass mixing ratios - call addfld(cnst_name(mm), (/ 'lev' /), 'A', 'kg/kg', cnst_longname(mm) ) - call addfld(sflxnam(mm), horiz_only, 'A', 'kg/m2/s', trim(cnst_name(mm))//' surface flux') + call addfld(cnst_name(mm), (/ 'lev' /), 'A', 'kg/kg', cnst_longname(mm), sampled_on_subcycle=.true.) + call addfld(sflxnam(mm), horiz_only, 'A', 'kg/m2/s', trim(cnst_name(mm))//' surface flux', sampled_on_subcycle=.true.) else if ( any(mm == (/ ixnumliq, ixnumice, ixnumrain, ixnumsnow, ixnumgraupel /)) ) then ! number concentrations - call addfld(cnst_name(mm), (/ 'lev' /), 'A', '1/kg', cnst_longname(mm) ) - call addfld(sflxnam(mm), horiz_only, 'A', '1/m2/s', trim(cnst_name(mm))//' surface flux') + call addfld(cnst_name(mm), (/ 'lev' /), 'A', '1/kg', cnst_longname(mm), sampled_on_subcycle=.true.) + call addfld(sflxnam(mm), horiz_only, 'A', '1/m2/s', trim(cnst_name(mm))//' surface flux', sampled_on_subcycle=.true.) else call endrun( "micro_pumas_cam_init: & &Could not call addfld for constituent with unknown units.") endif end do - call addfld(apcnst(ixcldliq), (/ 'lev' /), 'A', 'kg/kg', trim(cnst_name(ixcldliq))//' after physics' ) - call addfld(apcnst(ixcldice), (/ 'lev' /), 'A', 'kg/kg', trim(cnst_name(ixcldice))//' after physics' ) - call addfld(bpcnst(ixcldliq), (/ 'lev' /), 'A', 'kg/kg', trim(cnst_name(ixcldliq))//' before physics' ) - call addfld(bpcnst(ixcldice), (/ 'lev' /), 'A', 'kg/kg', trim(cnst_name(ixcldice))//' before physics' ) + call addfld(apcnst(ixcldliq), (/ 'lev' /), 'A', 'kg/kg', trim(cnst_name(ixcldliq))//' after physics', sampled_on_subcycle=.true.) + call addfld(apcnst(ixcldice), (/ 'lev' /), 'A', 'kg/kg', trim(cnst_name(ixcldice))//' after physics', sampled_on_subcycle=.true.) + call addfld(bpcnst(ixcldliq), (/ 'lev' /), 'A', 'kg/kg', trim(cnst_name(ixcldliq))//' before physics', sampled_on_subcycle=.true.) + call addfld(bpcnst(ixcldice), (/ 'lev' /), 'A', 'kg/kg', trim(cnst_name(ixcldice))//' before physics', sampled_on_subcycle=.true.) if (micro_mg_version > 1) then - call addfld(apcnst(ixrain), (/ 'lev' /), 'A', 'kg/kg', trim(cnst_name(ixrain))//' after physics' ) - call addfld(apcnst(ixsnow), (/ 'lev' /), 'A', 'kg/kg', trim(cnst_name(ixsnow))//' after physics' ) - call addfld(bpcnst(ixrain), (/ 'lev' /), 'A', 'kg/kg', trim(cnst_name(ixrain))//' before physics' ) - call addfld(bpcnst(ixsnow), (/ 'lev' /), 'A', 'kg/kg', trim(cnst_name(ixsnow))//' before physics' ) + call addfld(apcnst(ixrain), (/ 'lev' /), 'A', 'kg/kg', trim(cnst_name(ixrain))//' after physics', sampled_on_subcycle=.true.) + call addfld(apcnst(ixsnow), (/ 'lev' /), 'A', 'kg/kg', trim(cnst_name(ixsnow))//' after physics', sampled_on_subcycle=.true.) + call addfld(bpcnst(ixrain), (/ 'lev' /), 'A', 'kg/kg', trim(cnst_name(ixrain))//' before physics', sampled_on_subcycle=.true.) + call addfld(bpcnst(ixsnow), (/ 'lev' /), 'A', 'kg/kg', trim(cnst_name(ixsnow))//' before physics', sampled_on_subcycle=.true.) end if if (micro_mg_version > 2) then - call addfld(apcnst(ixgraupel), (/ 'lev' /), 'A', 'kg/kg', trim(cnst_name(ixgraupel))//' after physics' ) - call addfld(bpcnst(ixgraupel), (/ 'lev' /), 'A', 'kg/kg', trim(cnst_name(ixgraupel))//' before physics' ) + call addfld(apcnst(ixgraupel), (/ 'lev' /), 'A', 'kg/kg', trim(cnst_name(ixgraupel))//' after physics', sampled_on_subcycle=.true.) + call addfld(bpcnst(ixgraupel), (/ 'lev' /), 'A', 'kg/kg', trim(cnst_name(ixgraupel))//' before physics', sampled_on_subcycle=.true.) end if - call addfld ('CME', (/ 'lev' /), 'A', 'kg/kg/s', 'Rate of cond-evap within the cloud' ) - call addfld ('PRODPREC', (/ 'lev' /), 'A', 'kg/kg/s', 'Rate of conversion of condensate to precip' ) - call addfld ('EVAPPREC', (/ 'lev' /), 'A', 'kg/kg/s', 'Rate of evaporation of falling precip' ) - call addfld ('EVAPSNOW', (/ 'lev' /), 'A', 'kg/kg/s', 'Rate of evaporation of falling snow' ) - call addfld ('HPROGCLD', (/ 'lev' /), 'A', 'W/kg' , 'Heating from prognostic clouds' ) - call addfld ('FICE', (/ 'lev' /), 'A', 'fraction', 'Fractional ice content within cloud' ) - call addfld ('CLDFSNOW', (/ 'lev' /), 'A', '1', 'Cloud fraction adjusted for snow' ) - call addfld ('ICWMRST', (/ 'lev' /), 'A', 'kg/kg', 'Prognostic in-stratus water mixing ratio' ) - call addfld ('ICIMRST', (/ 'lev' /), 'A', 'kg/kg', 'Prognostic in-stratus ice mixing ratio' ) + call addfld ('CME', (/ 'lev' /), 'A', 'kg/kg/s', 'Rate of cond-evap within the cloud', sampled_on_subcycle=.true.) + call addfld ('PRODPREC', (/ 'lev' /), 'A', 'kg/kg/s', 'Rate of conversion of condensate to precip', sampled_on_subcycle=.true.) + call addfld ('EVAPPREC', (/ 'lev' /), 'A', 'kg/kg/s', 'Rate of evaporation of falling precip', sampled_on_subcycle=.true.) + call addfld ('EVAPSNOW', (/ 'lev' /), 'A', 'kg/kg/s', 'Rate of evaporation of falling snow', sampled_on_subcycle=.true.) + call addfld ('HPROGCLD', (/ 'lev' /), 'A', 'W/kg' , 'Heating from prognostic clouds', sampled_on_subcycle=.true.) + call addfld ('FICE', (/ 'lev' /), 'A', 'fraction', 'Fractional ice content within cloud', sampled_on_subcycle=.true.) + call addfld ('CLDFSNOW', (/ 'lev' /), 'A', '1', 'Cloud fraction adjusted for snow', sampled_on_subcycle=.true.) + call addfld ('ICWMRST', (/ 'lev' /), 'A', 'kg/kg', 'Prognostic in-stratus water mixing ratio', sampled_on_subcycle=.true.) + call addfld ('ICIMRST', (/ 'lev' /), 'A', 'kg/kg', 'Prognostic in-stratus ice mixing ratio', sampled_on_subcycle=.true.) ! MG microphysics diagnostics - call addfld ('QCSEVAP', (/ 'lev' /), 'A', 'kg/kg/s', 'Rate of evaporation of falling cloud water' ) - call addfld ('QISEVAP', (/ 'lev' /), 'A', 'kg/kg/s', 'Rate of sublimation of falling cloud ice' ) - call addfld ('QVRES', (/ 'lev' /), 'A', 'kg/kg/s', 'Rate of residual condensation term' ) - call addfld ('CMEIOUT', (/ 'lev' /), 'A', 'kg/kg/s', 'Rate of deposition/sublimation of cloud ice' ) - call addfld ('VTRMC', (/ 'lev' /), 'A', 'm/s', 'Mass-weighted cloud water fallspeed' ) - call addfld ('VTRMI', (/ 'lev' /), 'A', 'm/s', 'Mass-weighted cloud ice fallspeed' ) - call addfld ('QCSEDTEN', (/ 'lev' /), 'A', 'kg/kg/s', 'Cloud water mixing ratio tendency from sedimentation' ) - call addfld ('QISEDTEN', (/ 'lev' /), 'A', 'kg/kg/s', 'Cloud ice mixing ratio tendency from sedimentation' ) - call addfld ('PRAO', (/ 'lev' /), 'A', 'kg/kg/s', 'Accretion of cloud water by rain' ) - call addfld ('PRCO', (/ 'lev' /), 'A', 'kg/kg/s', 'Autoconversion of cloud water' ) - call addfld ('MNUCCCO', (/ 'lev' /), 'A', 'kg/kg/s', 'Immersion freezing of cloud water' ) - call addfld ('MNUCCTO', (/ 'lev' /), 'A', 'kg/kg/s', 'Contact freezing of cloud water' ) - call addfld ('MNUCCDO', (/ 'lev' /), 'A', 'kg/kg/s', 'Homogeneous and heterogeneous nucleation from vapor' ) - call addfld ('MNUCCDOhet', (/ 'lev' /), 'A', 'kg/kg/s', 'Heterogeneous nucleation from vapor' ) - call addfld ('MSACWIO', (/ 'lev' /), 'A', 'kg/kg/s', 'Conversion of cloud water from rime-splintering' ) - call addfld ('PSACWSO', (/ 'lev' /), 'A', 'kg/kg/s', 'Accretion of cloud water by snow' ) - call addfld ('BERGSO', (/ 'lev' /), 'A', 'kg/kg/s', 'Conversion of cloud water to snow from bergeron' ) - call addfld ('BERGO', (/ 'lev' /), 'A', 'kg/kg/s', 'Conversion of cloud water to cloud ice from bergeron' ) - call addfld ('MELTO', (/ 'lev' /), 'A', 'kg/kg/s', 'Melting of cloud ice' ) - call addfld ('MELTSTOT', (/ 'lev' /), 'A', 'kg/kg/s', 'Melting of snow' ) - call addfld ('MNUDEPO', (/ 'lev' /), 'A', 'kg/kg/s', 'Deposition Nucleation' ) - call addfld ('HOMOO', (/ 'lev' /), 'A', 'kg/kg/s', 'Homogeneous freezing of cloud water' ) - call addfld ('QCRESO', (/ 'lev' /), 'A', 'kg/kg/s', 'Residual condensation term for cloud water' ) - call addfld ('PRCIO', (/ 'lev' /), 'A', 'kg/kg/s', 'Autoconversion of cloud ice to snow' ) - call addfld ('PRAIO', (/ 'lev' /), 'A', 'kg/kg/s', 'Accretion of cloud ice to snow' ) - call addfld ('QIRESO', (/ 'lev' /), 'A', 'kg/kg/s', 'Residual deposition term for cloud ice' ) - call addfld ('MNUCCRO', (/ 'lev' /), 'A', 'kg/kg/s', 'Heterogeneous freezing of rain to snow' ) - call addfld ('MNUCCRIO', (/ 'lev' /), 'A', 'kg/kg/s', 'Heterogeneous freezing of rain to ice' ) - call addfld ('PRACSO', (/ 'lev' /), 'A', 'kg/kg/s', 'Accretion of rain by snow' ) - call addfld ('MELTSDT', (/ 'lev' /), 'A', 'W/kg', 'Latent heating rate due to melting of snow' ) - call addfld ('FRZRDT', (/ 'lev' /), 'A', 'W/kg', 'Latent heating rate due to homogeneous freezing of rain' ) + call addfld ('QCSEVAP', (/ 'lev' /), 'A', 'kg/kg/s', 'Rate of evaporation of falling cloud water', sampled_on_subcycle=.true.) + call addfld ('QISEVAP', (/ 'lev' /), 'A', 'kg/kg/s', 'Rate of sublimation of falling cloud ice', sampled_on_subcycle=.true.) + call addfld ('QVRES', (/ 'lev' /), 'A', 'kg/kg/s', 'Rate of residual condensation term', sampled_on_subcycle=.true.) + call addfld ('CMEIOUT', (/ 'lev' /), 'A', 'kg/kg/s', 'Rate of deposition/sublimation of cloud ice',sampled_on_subcycle=.true.) + call addfld ('VTRMC', (/ 'lev' /), 'A', 'm/s', 'Mass-weighted cloud water fallspeed', sampled_on_subcycle=.true.) + call addfld ('VTRMI', (/ 'lev' /), 'A', 'm/s', 'Mass-weighted cloud ice fallspeed', sampled_on_subcycle=.true.) + call addfld ('QCSEDTEN', (/ 'lev' /), 'A', 'kg/kg/s', 'Cloud water mixing ratio tendency from sedimentation', sampled_on_subcycle=.true.) + call addfld ('QISEDTEN', (/ 'lev' /), 'A', 'kg/kg/s', 'Cloud ice mixing ratio tendency from sedimentation', sampled_on_subcycle=.true.) + call addfld ('PRAO', (/ 'lev' /), 'A', 'kg/kg/s', 'Accretion of cloud water by rain', sampled_on_subcycle=.true.) + call addfld ('PRCO', (/ 'lev' /), 'A', 'kg/kg/s', 'Autoconversion of cloud water', sampled_on_subcycle=.true.) + call addfld ('MNUCCCO', (/ 'lev' /), 'A', 'kg/kg/s', 'Immersion freezing of cloud water', sampled_on_subcycle=.true.) + call addfld ('MNUCCTO', (/ 'lev' /), 'A', 'kg/kg/s', 'Contact freezing of cloud water', sampled_on_subcycle=.true.) + call addfld ('MNUCCDO', (/ 'lev' /), 'A', 'kg/kg/s', 'Homogeneous and heterogeneous nucleation from vapor', sampled_on_subcycle=.true.) + call addfld ('MNUCCDOhet', (/ 'lev' /), 'A', 'kg/kg/s', 'Heterogeneous nucleation from vapor', sampled_on_subcycle=.true.) + call addfld ('MSACWIO', (/ 'lev' /), 'A', 'kg/kg/s', 'Conversion of cloud water from rime-splintering', sampled_on_subcycle=.true.) + call addfld ('PSACWSO', (/ 'lev' /), 'A', 'kg/kg/s', 'Accretion of cloud water by snow', sampled_on_subcycle=.true.) + call addfld ('BERGSO', (/ 'lev' /), 'A', 'kg/kg/s', 'Conversion of cloud water to snow from bergeron', sampled_on_subcycle=.true.) + call addfld ('BERGO', (/ 'lev' /), 'A', 'kg/kg/s', 'Conversion of cloud water to cloud ice from bergeron', sampled_on_subcycle=.true.) + call addfld ('MELTO', (/ 'lev' /), 'A', 'kg/kg/s', 'Melting of cloud ice', sampled_on_subcycle=.true.) + call addfld ('MELTSTOT', (/ 'lev' /), 'A', 'kg/kg/s', 'Melting of snow', sampled_on_subcycle=.true.) + call addfld ('MNUDEPO', (/ 'lev' /), 'A', 'kg/kg/s', 'Deposition Nucleation', sampled_on_subcycle=.true.) + call addfld ('HOMOO', (/ 'lev' /), 'A', 'kg/kg/s', 'Homogeneous freezing of cloud water', sampled_on_subcycle=.true.) + call addfld ('QCRESO', (/ 'lev' /), 'A', 'kg/kg/s', 'Residual condensation term for cloud water', sampled_on_subcycle=.true.) + call addfld ('PRCIO', (/ 'lev' /), 'A', 'kg/kg/s', 'Autoconversion of cloud ice to snow', sampled_on_subcycle=.true.) + call addfld ('PRAIO', (/ 'lev' /), 'A', 'kg/kg/s', 'Accretion of cloud ice to snow', sampled_on_subcycle=.true.) + call addfld ('QIRESO', (/ 'lev' /), 'A', 'kg/kg/s', 'Residual deposition term for cloud ice', sampled_on_subcycle=.true.) + call addfld ('MNUCCRO', (/ 'lev' /), 'A', 'kg/kg/s', 'Heterogeneous freezing of rain to snow', sampled_on_subcycle=.true.) + call addfld ('MNUCCRIO', (/ 'lev' /), 'A', 'kg/kg/s', 'Heterogeneous freezing of rain to ice', sampled_on_subcycle=.true.) + call addfld ('PRACSO', (/ 'lev' /), 'A', 'kg/kg/s', 'Accretion of rain by snow', sampled_on_subcycle=.true.) + call addfld ('MELTSDT', (/ 'lev' /), 'A', 'W/kg', 'Latent heating rate due to melting of snow', sampled_on_subcycle=.true.) + call addfld ('FRZRDT', (/ 'lev' /), 'A', 'W/kg', 'Latent heating rate due to homogeneous freezing of rain', sampled_on_subcycle=.true.) if (micro_mg_version > 1) then - call addfld ('QRSEDTEN', (/ 'lev' /), 'A', 'kg/kg/s', 'Rain mixing ratio tendency from sedimentation' ) - call addfld ('QSSEDTEN', (/ 'lev' /), 'A', 'kg/kg/s', 'Snow mixing ratio tendency from sedimentation' ) + call addfld ('QRSEDTEN', (/ 'lev' /), 'A', 'kg/kg/s', 'Rain mixing ratio tendency from sedimentation', sampled_on_subcycle=.true.) + call addfld ('QSSEDTEN', (/ 'lev' /), 'A', 'kg/kg/s', 'Snow mixing ratio tendency from sedimentation', sampled_on_subcycle=.true.) end if if (micro_mg_version > 2) then - call addfld ('PSACRO', (/ 'lev' /), 'A', 'kg/kg/s', 'Collisions between rain & snow (Graupel collecting snow)') - call addfld ('PRACGO', (/ 'lev' /), 'A', 'kg/kg/s', 'Change in q collection rain by graupel' ) - call addfld ('PSACWGO', (/ 'lev' /), 'A', 'kg/kg/s', 'Change in q collection droplets by graupel' ) - call addfld ('PGSACWO', (/ 'lev' /), 'A', 'kg/kg/s', 'Q conversion to graupel due to collection droplets by snow') - call addfld ('PGRACSO', (/ 'lev' /), 'A', 'kg/kg/s', 'Q conversion to graupel due to collection rain by snow') - call addfld ('PRDGO', (/ 'lev' /), 'A', 'kg/kg/s', 'Deposition of graupel') - call addfld ('QMULTGO', (/ 'lev' /), 'A', 'kg/kg/s', 'Q change due to ice mult droplets/graupel') - call addfld ('QMULTRGO', (/ 'lev' /), 'A', 'kg/kg/s', 'Q change due to ice mult rain/graupel') - call addfld ('QGSEDTEN', (/ 'lev' /), 'A', 'kg/kg/s', 'Graupel/Hail mixing ratio tendency from sedimentation') - call addfld ('NPRACGO', (/ 'lev' /), 'A', 'kg/kg/s', 'Change N collection rain by graupel') - call addfld ('NSCNGO', (/'lev'/),'A','kg/kg/s','Change N conversion to graupel due to collection droplets by snow') - call addfld ('NGRACSO',(/'lev'/),'A','kg/kg/s','Change N conversion to graupel due to collection rain by snow') - call addfld ('NMULTGO', (/ 'lev' /), 'A', 'kg/kg/s', 'Ice mult due to acc droplets by graupel ') - call addfld ('NMULTRGO', (/ 'lev' /), 'A', 'kg/kg/s', 'Ice mult due to acc rain by graupel') - call addfld ('NPSACWGO', (/ 'lev' /), 'A', 'kg/kg/s', 'Change N collection droplets by graupel') - call addfld ('CLDFGRAU', (/ 'lev' /), 'A', '1', 'Cloud fraction adjusted for graupel' ) - call addfld ('MELTGTOT', (/ 'lev' /), 'A', 'kg/kg/s', 'Melting of graupel' ) + call addfld ('PSACRO', (/ 'lev' /), 'A', 'kg/kg/s', 'Collisions between rain & snow (Graupel collecting snow)', sampled_on_subcycle=.true.) + call addfld ('PRACGO', (/ 'lev' /), 'A', 'kg/kg/s', 'Change in q collection rain by graupel', sampled_on_subcycle=.true.) + call addfld ('PSACWGO', (/ 'lev' /), 'A', 'kg/kg/s', 'Change in q collection droplets by graupel', sampled_on_subcycle=.true.) + call addfld ('PGSACWO', (/ 'lev' /), 'A', 'kg/kg/s', 'Q conversion to graupel due to collection droplets by snow', sampled_on_subcycle=.true.) + call addfld ('PGRACSO', (/ 'lev' /), 'A', 'kg/kg/s', 'Q conversion to graupel due to collection rain by snow', sampled_on_subcycle=.true.) + call addfld ('PRDGO', (/ 'lev' /), 'A', 'kg/kg/s', 'Deposition of graupel', sampled_on_subcycle=.true.) + call addfld ('QMULTGO', (/ 'lev' /), 'A', 'kg/kg/s', 'Q change due to ice mult droplets/graupel', sampled_on_subcycle=.true.) + call addfld ('QMULTRGO', (/ 'lev' /), 'A', 'kg/kg/s', 'Q change due to ice mult rain/graupel', sampled_on_subcycle=.true.) + call addfld ('QGSEDTEN', (/ 'lev' /), 'A', 'kg/kg/s', 'Graupel/Hail mixing ratio tendency from sedimentation', sampled_on_subcycle=.true.) + call addfld ('NPRACGO', (/ 'lev' /), 'A', 'kg/kg/s', 'Change N collection rain by graupel', sampled_on_subcycle=.true.) + call addfld ('NSCNGO', (/'lev'/),'A','kg/kg/s','Change N conversion to graupel due to collection droplets by snow', sampled_on_subcycle=.true.) + call addfld ('NGRACSO',(/'lev'/),'A','kg/kg/s','Change N conversion to graupel due to collection rain by snow', sampled_on_subcycle=.true.) + call addfld ('NMULTGO', (/ 'lev' /), 'A', 'kg/kg/s', 'Ice mult due to acc droplets by graupel', sampled_on_subcycle=.true.) + call addfld ('NMULTRGO', (/ 'lev' /), 'A', 'kg/kg/s', 'Ice mult due to acc rain by graupel', sampled_on_subcycle=.true.) + call addfld ('NPSACWGO', (/ 'lev' /), 'A', 'kg/kg/s', 'Change N collection droplets by graupel', sampled_on_subcycle=.true.) + call addfld ('CLDFGRAU', (/ 'lev' /), 'A', '1', 'Cloud fraction adjusted for graupel', sampled_on_subcycle=.true.) + call addfld ('MELTGTOT', (/ 'lev' /), 'A', 'kg/kg/s', 'Melting of graupel', sampled_on_subcycle=.true.) end if - call addfld ('RBFRAC', horiz_only, 'A', 'Fraction', 'Fraction of sky covered by a potential rainbow' ) - call addfld ('RBFREQ', horiz_only, 'A', 'Frequency', 'Potential rainbow frequency' ) - call addfld( 'rbSZA', horiz_only, 'I', 'degrees', 'solar zenith angle' ) + call addfld ('RBFRAC', horiz_only, 'A', 'Fraction', 'Fraction of sky covered by a potential rainbow', sampled_on_subcycle=.true.) + call addfld ('RBFREQ', horiz_only, 'A', 'Frequency', 'Potential rainbow frequency', sampled_on_subcycle=.true.) + call addfld( 'rbSZA', horiz_only, 'I', 'degrees', 'solar zenith angle', sampled_on_subcycle=.true.) ! History variables for CAM5 microphysics - call addfld ('MPDT', (/ 'lev' /), 'A', 'W/kg', 'Heating tendency - Morrison microphysics' ) - call addfld ('MPDQ', (/ 'lev' /), 'A', 'kg/kg/s', 'Q tendency - Morrison microphysics' ) - call addfld ('MPDLIQ', (/ 'lev' /), 'A', 'kg/kg/s', 'CLDLIQ tendency - Morrison microphysics' ) - call addfld ('MPDICE', (/ 'lev' /), 'A', 'kg/kg/s', 'CLDICE tendency - Morrison microphysics' ) - call addfld ('MPDNLIQ', (/ 'lev' /), 'A', '1/kg/s', 'NUMLIQ tendency - Morrison microphysics' ) - call addfld ('MPDNICE', (/ 'lev' /), 'A', '1/kg/s', 'NUMICE tendency - Morrison microphysics' ) - call addfld ('MPDW2V', (/ 'lev' /), 'A', 'kg/kg/s', 'Water <--> Vapor tendency - Morrison microphysics' ) - call addfld ('MPDW2I', (/ 'lev' /), 'A', 'kg/kg/s', 'Water <--> Ice tendency - Morrison microphysics' ) - call addfld ('MPDW2P', (/ 'lev' /), 'A', 'kg/kg/s', 'Water <--> Precip tendency - Morrison microphysics' ) - call addfld ('MPDI2V', (/ 'lev' /), 'A', 'kg/kg/s', 'Ice <--> Vapor tendency - Morrison microphysics' ) - call addfld ('MPDI2W', (/ 'lev' /), 'A', 'kg/kg/s', 'Ice <--> Water tendency - Morrison microphysics' ) - call addfld ('MPDI2P', (/ 'lev' /), 'A', 'kg/kg/s', 'Ice <--> Precip tendency - Morrison microphysics' ) - call addfld ('ICWNC', (/ 'lev' /), 'A', 'm-3', 'Prognostic in-cloud water number conc' ) - call addfld ('ICINC', (/ 'lev' /), 'A', 'm-3', 'Prognostic in-cloud ice number conc' ) - call addfld ('EFFLIQ_IND', (/ 'lev' /), 'A','Micron', 'Prognostic droplet effective radius (indirect effect)' ) - call addfld ('CDNUMC', horiz_only, 'A', '1/m2', 'Vertically-integrated droplet concentration' ) + call addfld ('MPDT', (/ 'lev' /), 'A', 'W/kg', 'Heating tendency - Morrison microphysics', sampled_on_subcycle=.true.) + call addfld ('MPDQ', (/ 'lev' /), 'A', 'kg/kg/s', 'Q tendency - Morrison microphysics', sampled_on_subcycle=.true.) + call addfld ('MPDLIQ', (/ 'lev' /), 'A', 'kg/kg/s', 'CLDLIQ tendency - Morrison microphysics', sampled_on_subcycle=.true.) + call addfld ('MPDICE', (/ 'lev' /), 'A', 'kg/kg/s', 'CLDICE tendency - Morrison microphysics', sampled_on_subcycle=.true.) + call addfld ('MPDNLIQ', (/ 'lev' /), 'A', '1/kg/s', 'NUMLIQ tendency - Morrison microphysics', sampled_on_subcycle=.true.) + call addfld ('MPDNICE', (/ 'lev' /), 'A', '1/kg/s', 'NUMICE tendency - Morrison microphysics', sampled_on_subcycle=.true.) + call addfld ('MPDW2V', (/ 'lev' /), 'A', 'kg/kg/s', 'Water <--> Vapor tendency - Morrison microphysics', sampled_on_subcycle=.true.) + call addfld ('MPDW2I', (/ 'lev' /), 'A', 'kg/kg/s', 'Water <--> Ice tendency - Morrison microphysics', sampled_on_subcycle=.true.) + call addfld ('MPDW2P', (/ 'lev' /), 'A', 'kg/kg/s', 'Water <--> Precip tendency - Morrison microphysics', sampled_on_subcycle=.true.) + call addfld ('MPDI2V', (/ 'lev' /), 'A', 'kg/kg/s', 'Ice <--> Vapor tendency - Morrison microphysics', sampled_on_subcycle=.true.) + call addfld ('MPDI2W', (/ 'lev' /), 'A', 'kg/kg/s', 'Ice <--> Water tendency - Morrison microphysics', sampled_on_subcycle=.true.) + call addfld ('MPDI2P', (/ 'lev' /), 'A', 'kg/kg/s', 'Ice <--> Precip tendency - Morrison microphysics', sampled_on_subcycle=.true.) + call addfld ('ICWNC', (/ 'lev' /), 'A', 'm-3', 'Prognostic in-cloud water number conc', sampled_on_subcycle=.true.) + call addfld ('ICINC', (/ 'lev' /), 'A', 'm-3', 'Prognostic in-cloud ice number conc', sampled_on_subcycle=.true.) + call addfld ('EFFLIQ_IND', (/ 'lev' /), 'A','Micron', 'Prognostic droplet effective radius (indirect effect)', sampled_on_subcycle=.true.) + call addfld ('CDNUMC', horiz_only, 'A', '1/m2', 'Vertically-integrated droplet concentration', sampled_on_subcycle=.true.) call addfld ('MPICLWPI', horiz_only, 'A', 'kg/m2', 'Vertically-integrated & - &in-cloud Initial Liquid WP (Before Micro)' ) + &in-cloud Initial Liquid WP (Before Micro)', sampled_on_subcycle=.true.) call addfld ('MPICIWPI', horiz_only, 'A', 'kg/m2', 'Vertically-integrated & - &in-cloud Initial Ice WP (Before Micro)' ) + &in-cloud Initial Ice WP (Before Micro)', sampled_on_subcycle=.true.) ! This is provided as an example on how to write out subcolumn output ! NOTE -- only 'I' should be used for sub-column fields as subc-columns could shift from time-step to time-step if (use_subcol_microp) then call addfld('FICE_SCOL', (/'psubcols','lev '/), 'I', 'fraction', & - 'Sub-column fractional ice content within cloud', flag_xyfill=.true., fill_value=1.e30_r8) + 'Sub-column fractional ice content within cloud', flag_xyfill=.true., fill_value=1.e30_r8, sampled_on_subcycle=.true.) call addfld('MPDICE_SCOL', (/'psubcols','lev '/), 'I', 'kg/kg/s', & - 'Sub-column CLDICE tendency - Morrison microphysics', flag_xyfill=.true., fill_value=1.e30_r8) + 'Sub-column CLDICE tendency - Morrison microphysics', flag_xyfill=.true., fill_value=1.e30_r8, sampled_on_subcycle=.true.) call addfld('MPDLIQ_SCOL', (/'psubcols','lev '/), 'I', 'kg/kg/s', & - 'Sub-column CLDLIQ tendency - Morrison microphysics', flag_xyfill=.true., fill_value=1.e30_r8) + 'Sub-column CLDLIQ tendency - Morrison microphysics', flag_xyfill=.true., fill_value=1.e30_r8, sampled_on_subcycle=.true.) end if ! This is only if the coldpoint temperatures are being adjusted. ! NOTE: Some fields related to these and output later are added in tropopause.F90. if (micro_mg_adjust_cpt) then - call addfld ('TROPF_TADJ', (/ 'lev' /), 'A', 'K', 'Temperatures after cold point adjustment' ) - call addfld ('TROPF_RHADJ', (/ 'lev' /), 'A', 'K', 'Relative Hunidity after cold point adjustment' ) - call addfld ('TROPF_CDT', horiz_only, 'A', 'K', 'Cold point temperature adjustment' ) - call addfld ('TROPF_CDZ', horiz_only, 'A', 'm', 'Distance of coldpoint from coldest model level' ) + call addfld ('TROPF_TADJ', (/ 'lev' /), 'A', 'K', 'Temperatures after cold point adjustment', sampled_on_subcycle=.true.) + call addfld ('TROPF_RHADJ', (/ 'lev' /), 'A', 'K', 'Relative Hunidity after cold point adjustment', sampled_on_subcycle=.true.) + call addfld ('TROPF_CDT', horiz_only, 'A', 'K', 'Cold point temperature adjustment', sampled_on_subcycle=.true.) + call addfld ('TROPF_CDZ', horiz_only, 'A', 'm', 'Distance of coldpoint from coldest model level', sampled_on_subcycle=.true.) end if ! Averaging for cloud particle number and size - call addfld ('AWNC', (/ 'lev' /), 'A', 'm-3', 'Average cloud water number conc' ) - call addfld ('AWNI', (/ 'lev' /), 'A', 'm-3', 'Average cloud ice number conc' ) - call addfld ('AREL', (/ 'lev' /), 'A', 'Micron', 'Average droplet effective radius' ) - call addfld ('AREI', (/ 'lev' /), 'A', 'Micron', 'Average ice effective radius' ) + call addfld ('AWNC', (/ 'lev' /), 'A', 'm-3', 'Average cloud water number conc', sampled_on_subcycle=.true.) + call addfld ('AWNI', (/ 'lev' /), 'A', 'm-3', 'Average cloud ice number conc', sampled_on_subcycle=.true.) + call addfld ('AREL', (/ 'lev' /), 'A', 'Micron', 'Average droplet effective radius', sampled_on_subcycle=.true.) + call addfld ('AREI', (/ 'lev' /), 'A', 'Micron', 'Average ice effective radius', sampled_on_subcycle=.true.) ! Frequency arrays for above - call addfld ('FREQL', (/ 'lev' /), 'A', 'fraction', 'Fractional occurrence of liquid' ) - call addfld ('FREQI', (/ 'lev' /), 'A', 'fraction', 'Fractional occurrence of ice' ) + call addfld ('FREQL', (/ 'lev' /), 'A', 'fraction', 'Fractional occurrence of liquid', sampled_on_subcycle=.true.) + call addfld ('FREQI', (/ 'lev' /), 'A', 'fraction', 'Fractional occurrence of ice', sampled_on_subcycle=.true.) ! Average cloud top particle size and number (liq, ice) and frequency - call addfld ('ACTREL', horiz_only, 'A', 'Micron', 'Average Cloud Top droplet effective radius' ) - call addfld ('ACTREI', horiz_only, 'A', 'Micron', 'Average Cloud Top ice effective radius' ) - call addfld ('ACTNL', horiz_only, 'A', 'm-3', 'Average Cloud Top droplet number' ) - call addfld ('ACTNI', horiz_only, 'A', 'm-3', 'Average Cloud Top ice number' ) + call addfld ('ACTREL', horiz_only, 'A', 'Micron', 'Average Cloud Top droplet effective radius', sampled_on_subcycle=.true.) + call addfld ('ACTREI', horiz_only, 'A', 'Micron', 'Average Cloud Top ice effective radius', sampled_on_subcycle=.true.) + call addfld ('ACTNL', horiz_only, 'A', 'm-3', 'Average Cloud Top droplet number', sampled_on_subcycle=.true.) + call addfld ('ACTNI', horiz_only, 'A', 'm-3', 'Average Cloud Top ice number', sampled_on_subcycle=.true.) - call addfld ('FCTL', horiz_only, 'A', 'fraction', 'Fractional occurrence of cloud top liquid' ) - call addfld ('FCTI', horiz_only, 'A', 'fraction', 'Fractional occurrence of cloud top ice' ) + call addfld ('FCTL', horiz_only, 'A', 'fraction', 'Fractional occurrence of cloud top liquid', sampled_on_subcycle=.true.) + call addfld ('FCTI', horiz_only, 'A', 'fraction', 'Fractional occurrence of cloud top ice', sampled_on_subcycle=.true.) ! New frequency arrays for mixed phase and supercooled liquid (only and mixed) for (a) Cloud Top and (b) everywhere.. - call addfld ('FREQM', (/ 'lev' /), 'A', 'fraction', 'Fractional occurrence of mixed phase' ) - call addfld ('FREQSL', (/ 'lev' /), 'A', 'fraction', 'Fractional occurrence of only supercooled liquid' ) - call addfld ('FREQSLM', (/ 'lev' /), 'A', 'fraction', 'Fractional occurrence of super cooled liquid with ice' ) - call addfld ('FCTM', horiz_only, 'A', 'fraction', 'Fractional occurrence of cloud top mixed phase' ) - call addfld ('FCTSL', horiz_only, 'A', 'fraction', 'Fractional occurrence of cloud top only supercooled liquid' ) - call addfld ('FCTSLM', horiz_only, 'A', 'fraction', 'Fractional occurrence of cloud top super cooled liquid with ice' ) - - call addfld ('LS_FLXPRC', (/ 'ilev' /), 'A', 'kg/m2/s', 'ls stratiform gbm interface rain+snow flux' ) - call addfld ('LS_FLXSNW', (/ 'ilev' /), 'A', 'kg/m2/s', 'ls stratiform gbm interface snow flux' ) - - call addfld ('REL', (/ 'lev' /), 'A', 'micron', 'MG REL stratiform cloud effective radius liquid' ) - call addfld ('REI', (/ 'lev' /), 'A', 'micron', 'MG REI stratiform cloud effective radius ice' ) - call addfld ('LS_REFFRAIN', (/ 'lev' /), 'A', 'micron', 'ls stratiform rain effective radius' ) - call addfld ('LS_REFFSNOW', (/ 'lev' /), 'A', 'micron', 'ls stratiform snow effective radius' ) - call addfld ('CV_REFFLIQ', (/ 'lev' /), 'A', 'micron', 'convective cloud liq effective radius' ) - call addfld ('CV_REFFICE', (/ 'lev' /), 'A', 'micron', 'convective cloud ice effective radius' ) - call addfld ('MG_SADICE', (/ 'lev' /), 'A', 'cm2/cm3', 'MG surface area density ice' ) - call addfld ('MG_SADSNOW', (/ 'lev' /), 'A', 'cm2/cm3', 'MG surface area density snow' ) + call addfld ('FREQM', (/ 'lev' /), 'A', 'fraction', 'Fractional occurrence of mixed phase', sampled_on_subcycle=.true.) + call addfld ('FREQSL', (/ 'lev' /), 'A', 'fraction', 'Fractional occurrence of only supercooled liquid', sampled_on_subcycle=.true.) + call addfld ('FREQSLM', (/ 'lev' /), 'A', 'fraction', 'Fractional occurrence of super cooled liquid with ice', sampled_on_subcycle=.true.) + call addfld ('FCTM', horiz_only, 'A', 'fraction', 'Fractional occurrence of cloud top mixed phase', sampled_on_subcycle=.true.) + call addfld ('FCTSL', horiz_only, 'A', 'fraction', 'Fractional occurrence of cloud top only supercooled liquid', sampled_on_subcycle=.true.) + call addfld ('FCTSLM', horiz_only, 'A', 'fraction', 'Fractional occurrence of cloud top super cooled liquid with ice', sampled_on_subcycle=.true.) + + call addfld ('LS_FLXPRC', (/ 'ilev' /), 'A', 'kg/m2/s', 'ls stratiform gbm interface rain+snow flux', sampled_on_subcycle=.true.) + call addfld ('LS_FLXSNW', (/ 'ilev' /), 'A', 'kg/m2/s', 'ls stratiform gbm interface snow flux', sampled_on_subcycle=.true.) + + call addfld ('REL', (/ 'lev' /), 'A', 'micron', 'MG REL stratiform cloud effective radius liquid', sampled_on_subcycle=.true.) + call addfld ('REI', (/ 'lev' /), 'A', 'micron', 'MG REI stratiform cloud effective radius ice', sampled_on_subcycle=.true.) + call addfld ('LS_REFFRAIN', (/ 'lev' /), 'A', 'micron', 'ls stratiform rain effective radius', sampled_on_subcycle=.true.) + call addfld ('LS_REFFSNOW', (/ 'lev' /), 'A', 'micron', 'ls stratiform snow effective radius', sampled_on_subcycle=.true.) + call addfld ('CV_REFFLIQ', (/ 'lev' /), 'A', 'micron', 'convective cloud liq effective radius', sampled_on_subcycle=.true.) + call addfld ('CV_REFFICE', (/ 'lev' /), 'A', 'micron', 'convective cloud ice effective radius', sampled_on_subcycle=.true.) + call addfld ('MG_SADICE', (/ 'lev' /), 'A', 'cm2/cm3', 'MG surface area density ice', sampled_on_subcycle=.true.) + call addfld ('MG_SADSNOW', (/ 'lev' /), 'A', 'cm2/cm3', 'MG surface area density snow', sampled_on_subcycle=.true.) ! diagnostic precip - call addfld ('QRAIN', (/ 'lev' /), 'A', 'kg/kg', 'Diagnostic grid-mean rain mixing ratio' ) - call addfld ('QSNOW', (/ 'lev' /), 'A', 'kg/kg', 'Diagnostic grid-mean snow mixing ratio' ) - call addfld ('NRAIN', (/ 'lev' /), 'A', 'm-3', 'Diagnostic grid-mean rain number conc' ) - call addfld ('NSNOW', (/ 'lev' /), 'A', 'm-3', 'Diagnostic grid-mean snow number conc' ) + call addfld ('QRAIN', (/ 'lev' /), 'A', 'kg/kg', 'Diagnostic grid-mean rain mixing ratio', sampled_on_subcycle=.true.) + call addfld ('QSNOW', (/ 'lev' /), 'A', 'kg/kg', 'Diagnostic grid-mean snow mixing ratio', sampled_on_subcycle=.true.) + call addfld ('NRAIN', (/ 'lev' /), 'A', 'm-3', 'Diagnostic grid-mean rain number conc', sampled_on_subcycle=.true.) + call addfld ('NSNOW', (/ 'lev' /), 'A', 'm-3', 'Diagnostic grid-mean snow number conc', sampled_on_subcycle=.true.) ! size of precip - call addfld ('RERCLD', (/ 'lev' /), 'A', 'm', 'Diagnostic effective radius of Liquid Cloud and Rain' ) - call addfld ('DSNOW', (/ 'lev' /), 'A', 'm', 'Diagnostic grid-mean snow diameter' ) + call addfld ('RERCLD', (/ 'lev' /), 'A', 'm', 'Diagnostic effective radius of Liquid Cloud and Rain', sampled_on_subcycle=.true.) + call addfld ('DSNOW', (/ 'lev' /), 'A', 'm', 'Diagnostic grid-mean snow diameter', sampled_on_subcycle=.true.) ! diagnostic radar reflectivity, cloud-averaged - call addfld ('REFL', (/ 'lev' /), 'A', 'DBz', '94 GHz radar reflectivity' ) - call addfld ('AREFL', (/ 'lev' /), 'A', 'DBz', 'Average 94 GHz radar reflectivity' ) - call addfld ('FREFL', (/ 'lev' /), 'A', 'fraction', 'Fractional occurrence of radar reflectivity' ) + call addfld ('REFL', (/ 'lev' /), 'A', 'DBz', '94 GHz radar reflectivity', sampled_on_subcycle=.true.) + call addfld ('AREFL', (/ 'lev' /), 'A', 'DBz', 'Average 94 GHz radar reflectivity', sampled_on_subcycle=.true.) + call addfld ('FREFL', (/ 'lev' /), 'A', 'fraction', 'Fractional occurrence of radar reflectivity', sampled_on_subcycle=.true.) - call addfld ('CSRFL', (/ 'lev' /), 'A', 'DBz', '94 GHz radar reflectivity (CloudSat thresholds)' ) - call addfld ('ACSRFL', (/ 'lev' /), 'A', 'DBz', 'Average 94 GHz radar reflectivity (CloudSat thresholds)' ) - call addfld ('FCSRFL', (/ 'lev' /), 'A', 'fraction', 'Fractional occurrence of radar reflectivity (CloudSat thresholds)' ) + call addfld ('CSRFL', (/ 'lev' /), 'A', 'DBz', '94 GHz radar reflectivity (CloudSat thresholds)', sampled_on_subcycle=.true.) + call addfld ('ACSRFL', (/ 'lev' /), 'A', 'DBz', 'Average 94 GHz radar reflectivity (CloudSat thresholds)', sampled_on_subcycle=.true.) + call addfld ('FCSRFL', (/ 'lev' /), 'A', 'fraction', 'Fractional occurrence of radar reflectivity (CloudSat thresholds)', sampled_on_subcycle=.true.) - call addfld ('AREFLZ', (/ 'lev' /), 'A', 'mm^6/m^3', 'Average 94 GHz radar reflectivity' ) + call addfld ('AREFLZ', (/ 'lev' /), 'A', 'mm^6/m^3', 'Average 94 GHz radar reflectivity', sampled_on_subcycle=.true.) ! Aerosol information - call addfld ('NCAL', (/ 'lev' /), 'A', '1/m3', 'Number Concentation Activated for Liquid' ) - call addfld ('NCAI', (/ 'lev' /), 'A', '1/m3', 'Number Concentation Activated for Ice' ) + call addfld ('NCAL', (/ 'lev' /), 'A', '1/m3', 'Number Concentation Activated for Liquid', sampled_on_subcycle=.true.) + call addfld ('NCAI', (/ 'lev' /), 'A', '1/m3', 'Number Concentation Activated for Ice', sampled_on_subcycle=.true.) ! Average rain and snow mixing ratio (Q), number (N) and diameter (D), with frequency - call addfld ('AQRAIN', (/ 'lev' /), 'A', 'kg/kg', 'Average rain mixing ratio' ) - call addfld ('AQSNOW', (/ 'lev' /), 'A', 'kg/kg', 'Average snow mixing ratio' ) - call addfld ('ANRAIN', (/ 'lev' /), 'A', 'm-3', 'Average rain number conc' ) - call addfld ('ANSNOW', (/ 'lev' /), 'A', 'm-3', 'Average snow number conc' ) - call addfld ('ADRAIN', (/ 'lev' /), 'A', 'm', 'Average rain effective Diameter' ) - call addfld ('ADSNOW', (/ 'lev' /), 'A', 'm', 'Average snow effective Diameter' ) - call addfld ('FREQR', (/ 'lev' /), 'A', 'fraction', 'Fractional occurrence of rain' ) - call addfld ('FREQS', (/ 'lev' /), 'A', 'fraction', 'Fractional occurrence of snow' ) + call addfld ('AQRAIN', (/ 'lev' /), 'A', 'kg/kg', 'Average rain mixing ratio', sampled_on_subcycle=.true.) + call addfld ('AQSNOW', (/ 'lev' /), 'A', 'kg/kg', 'Average snow mixing ratio', sampled_on_subcycle=.true.) + call addfld ('ANRAIN', (/ 'lev' /), 'A', 'm-3', 'Average rain number conc', sampled_on_subcycle=.true.) + call addfld ('ANSNOW', (/ 'lev' /), 'A', 'm-3', 'Average snow number conc', sampled_on_subcycle=.true.) + call addfld ('ADRAIN', (/ 'lev' /), 'A', 'm', 'Average rain effective Diameter', sampled_on_subcycle=.true.) + call addfld ('ADSNOW', (/ 'lev' /), 'A', 'm', 'Average snow effective Diameter', sampled_on_subcycle=.true.) + call addfld ('FREQR', (/ 'lev' /), 'A', 'fraction', 'Fractional occurrence of rain', sampled_on_subcycle=.true.) + call addfld ('FREQS', (/ 'lev' /), 'A', 'fraction', 'Fractional occurrence of snow', sampled_on_subcycle=.true.) ! precipitation efficiency & other diagnostic fields - call addfld('PE' , horiz_only, 'A', '1', 'Stratiform Precipitation Efficiency (precip/cmeliq)' ) - call addfld('APRL' , horiz_only, 'A', 'm/s', 'Average Stratiform Precip Rate over efficiency calculation' ) - call addfld('PEFRAC', horiz_only, 'A', '1', 'Fraction of timesteps precip efficiency reported' ) - call addfld('VPRCO' , horiz_only, 'A', 'kg/kg/s', 'Vertical average of autoconversion rate' ) - call addfld('VPRAO' , horiz_only, 'A', 'kg/kg/s', 'Vertical average of accretion rate' ) - call addfld('RACAU' , horiz_only, 'A', 'kg/kg/s', 'Accretion/autoconversion ratio from vertical average' ) + call addfld('PE' , horiz_only, 'A', '1', 'Stratiform Precipitation Efficiency (precip/cmeliq)', sampled_on_subcycle=.true.) + call addfld('APRL' , horiz_only, 'A', 'm/s', 'Average Stratiform Precip Rate over efficiency calculation', sampled_on_subcycle=.true.) + call addfld('PEFRAC', horiz_only, 'A', '1', 'Fraction of timesteps precip efficiency reported', sampled_on_subcycle=.true.) + call addfld('VPRCO' , horiz_only, 'A', 'kg/kg/s', 'Vertical average of autoconversion rate', sampled_on_subcycle=.true.) + call addfld('VPRAO' , horiz_only, 'A', 'kg/kg/s', 'Vertical average of accretion rate', sampled_on_subcycle=.true.) + call addfld('RACAU' , horiz_only, 'A', 'kg/kg/s', 'Accretion/autoconversion ratio from vertical average', sampled_on_subcycle=.true.) if (micro_mg_version > 1) then - call addfld('UMR', (/ 'lev' /), 'A', 'm/s', 'Mass-weighted rain fallspeed' ) - call addfld('UMS', (/ 'lev' /), 'A', 'm/s', 'Mass-weighted snow fallspeed' ) + call addfld('UMR', (/ 'lev' /), 'A', 'm/s', 'Mass-weighted rain fallspeed', sampled_on_subcycle=.true.) + call addfld('UMS', (/ 'lev' /), 'A', 'm/s', 'Mass-weighted snow fallspeed', sampled_on_subcycle=.true.) end if if (micro_mg_version > 2) then - call addfld('UMG', (/ 'lev' /), 'A', 'm/s', 'Mass-weighted graupel/hail fallspeed' ) - call addfld ('FREQG', (/ 'lev' /), 'A', 'fraction', 'Fractional occurrence of Graupel' ) - call addfld ('LS_REFFGRAU', (/ 'lev' /), 'A', 'micron', 'ls stratiform graupel/hail effective radius' ) - call addfld ('AQGRAU', (/ 'lev' /), 'A', 'kg/kg', 'Average graupel/hail mixing ratio' ) - call addfld ('ANGRAU', (/ 'lev' /), 'A', 'm-3', 'Average graupel/hail number conc' ) + call addfld('UMG', (/ 'lev' /), 'A', 'm/s', 'Mass-weighted graupel/hail fallspeed', sampled_on_subcycle=.true.) + call addfld ('FREQG', (/ 'lev' /), 'A', 'fraction', 'Fractional occurrence of Graupel', sampled_on_subcycle=.true.) + call addfld ('LS_REFFGRAU', (/ 'lev' /), 'A', 'micron', 'ls stratiform graupel/hail effective radius', sampled_on_subcycle=.true.) + call addfld ('AQGRAU', (/ 'lev' /), 'A', 'kg/kg', 'Average graupel/hail mixing ratio', sampled_on_subcycle=.true.) + call addfld ('ANGRAU', (/ 'lev' /), 'A', 'm-3', 'Average graupel/hail number conc', sampled_on_subcycle=.true.) end if ! qc limiter (only output in versions 1.5 and later) if (.not. (micro_mg_version == 1 .and. micro_mg_sub_version == 0)) then - call addfld('QCRAT', (/ 'lev' /), 'A', 'fraction', 'Qc Limiter: Fraction of qc tendency applied') + call addfld('QCRAT', (/ 'lev' /), 'A', 'fraction', 'Qc Limiter: Fraction of qc tendency applied', sampled_on_subcycle=.true.) end if ! determine the add_default fields diff --git a/src/physics/cam/microp_aero.F90 b/src/physics/cam/microp_aero.F90 index 4961a139a8..38079466af 100644 --- a/src/physics/cam/microp_aero.F90 +++ b/src/physics/cam/microp_aero.F90 @@ -334,10 +334,10 @@ subroutine microp_aero_init(phys_state,pbuf2d) end if - call addfld('LCLOUD', (/ 'lev' /), 'A', ' ', 'Liquid cloud fraction used in stratus activation') + call addfld('LCLOUD', (/ 'lev' /), 'A', ' ', 'Liquid cloud fraction used in stratus activation', sampled_on_subcycle=.true.) - call addfld('WSUB', (/ 'lev' /), 'A', 'm/s', 'Diagnostic sub-grid vertical velocity' ) - call addfld('WSUBI', (/ 'lev' /), 'A', 'm/s', 'Diagnostic sub-grid vertical velocity for ice' ) + call addfld('WSUB', (/ 'lev' /), 'A', 'm/s', 'Diagnostic sub-grid vertical velocity', sampled_on_subcycle=.true.) + call addfld('WSUBI', (/ 'lev' /), 'A', 'm/s', 'Diagnostic sub-grid vertical velocity for ice', sampled_on_subcycle=.true.) if (history_amwg) then call add_default ('WSUB ', 1, ' ') @@ -756,7 +756,7 @@ subroutine microp_aero_run ( & do k = top_lev, pver do i = 1, ncol - if (state1%q(i,k,cldliq_idx) >= qsmall) then + if (naer_all > 0 .and. state1%q(i,k,cldliq_idx) >= qsmall) then ! get droplet activation rate diff --git a/src/physics/cam/ndrop.F90 b/src/physics/cam/ndrop.F90 index 9eea87d218..ea3d7522da 100644 --- a/src/physics/cam/ndrop.F90 +++ b/src/physics/cam/ndrop.F90 @@ -135,10 +135,10 @@ subroutine ndrop_init(aero_props) ! Add tendency fields to the history only when prognostic MAM is enabled. long_name = trim(tmpname) // ' dropmixnuc mixnuc column tendency' - call addfld(fieldname(mm), horiz_only, 'A', unit, long_name) + call addfld(fieldname(mm), horiz_only, 'A', unit, long_name, sampled_on_subcycle=.true.) long_name = trim(tmpname_cw) // ' dropmixnuc mixnuc column tendency' - call addfld(fieldname_cw(mm), horiz_only, 'A', unit, long_name) + call addfld(fieldname_cw(mm), horiz_only, 'A', unit, long_name, sampled_on_subcycle=.true.) if (history_aerosol) then call add_default(fieldname(mm), 1, ' ') @@ -148,19 +148,19 @@ subroutine ndrop_init(aero_props) end do end do - call addfld('CCN1',(/ 'lev' /), 'A','#/cm3','CCN concentration at S=0.02%') - call addfld('CCN2',(/ 'lev' /), 'A','#/cm3','CCN concentration at S=0.05%') - call addfld('CCN3',(/ 'lev' /), 'A','#/cm3','CCN concentration at S=0.1%') - call addfld('CCN4',(/ 'lev' /), 'A','#/cm3','CCN concentration at S=0.2%') - call addfld('CCN5',(/ 'lev' /), 'A','#/cm3','CCN concentration at S=0.5%') - call addfld('CCN6',(/ 'lev' /), 'A','#/cm3','CCN concentration at S=1.0%') + call addfld('CCN1',(/ 'lev' /), 'A','#/cm3','CCN concentration at S=0.02%', sampled_on_subcycle=.true.) + call addfld('CCN2',(/ 'lev' /), 'A','#/cm3','CCN concentration at S=0.05%', sampled_on_subcycle=.true.) + call addfld('CCN3',(/ 'lev' /), 'A','#/cm3','CCN concentration at S=0.1%', sampled_on_subcycle=.true.) + call addfld('CCN4',(/ 'lev' /), 'A','#/cm3','CCN concentration at S=0.2%', sampled_on_subcycle=.true.) + call addfld('CCN5',(/ 'lev' /), 'A','#/cm3','CCN concentration at S=0.5%', sampled_on_subcycle=.true.) + call addfld('CCN6',(/ 'lev' /), 'A','#/cm3','CCN concentration at S=1.0%', sampled_on_subcycle=.true.) - call addfld('WTKE', (/ 'lev' /), 'A', 'm/s', 'Standard deviation of updraft velocity') - call addfld('NDROPMIX', (/ 'lev' /), 'A', '#/kg/s', 'Droplet number mixing') - call addfld('NDROPSRC', (/ 'lev' /), 'A', '#/kg/s', 'Droplet number source') - call addfld('NDROPSNK', (/ 'lev' /), 'A', '#/kg/s', 'Droplet number loss by microphysics') - call addfld('NDROPCOL', horiz_only, 'A', '#/m2', 'Column droplet number') + call addfld('WTKE', (/ 'lev' /), 'A', 'm/s', 'Standard deviation of updraft velocity', sampled_on_subcycle=.true.) + call addfld('NDROPMIX', (/ 'lev' /), 'A', '#/kg/s', 'Droplet number mixing', sampled_on_subcycle=.true.) + call addfld('NDROPSRC', (/ 'lev' /), 'A', '#/kg/s', 'Droplet number source', sampled_on_subcycle=.true.) + call addfld('NDROPSNK', (/ 'lev' /), 'A', '#/kg/s', 'Droplet number loss by microphysics', sampled_on_subcycle=.true.) + call addfld('NDROPCOL', horiz_only, 'A', '#/m2', 'Column droplet number', sampled_on_subcycle=.true.) ! set the add_default fields if (history_amwg) then diff --git a/src/physics/cam/ndrop_bam.F90 b/src/physics/cam/ndrop_bam.F90 index 6cd8231356..01ab3b5856 100644 --- a/src/physics/cam/ndrop_bam.F90 +++ b/src/physics/cam/ndrop_bam.F90 @@ -112,7 +112,7 @@ subroutine ndrop_bam_init if (trim(aername(iaer)) == 'SULFATE') idxsul = iaer ! aerosol number concentration - call addfld(trim(aername(iaer))//'_m3', (/ 'lev' /), 'A', 'm-3', 'aerosol number concentration') + call addfld(trim(aername(iaer))//'_m3', (/ 'lev' /), 'A', 'm-3', 'aerosol number concentration', sampled_on_subcycle=.true.) end do @@ -129,12 +129,12 @@ subroutine ndrop_bam_init end if end if - call addfld ('CCN1',(/ 'lev' /), 'A','#/cm3','CCN concentration at S=0.02%') - call addfld ('CCN2',(/ 'lev' /), 'A','#/cm3','CCN concentration at S=0.05%') - call addfld ('CCN3',(/ 'lev' /), 'A','#/cm3','CCN concentration at S=0.1%') - call addfld ('CCN4',(/ 'lev' /), 'A','#/cm3','CCN concentration at S=0.2%') - call addfld ('CCN5',(/ 'lev' /), 'A','#/cm3','CCN concentration at S=0.5%') - call addfld ('CCN6',(/ 'lev' /), 'A','#/cm3','CCN concentration at S=1.0%') + call addfld ('CCN1',(/ 'lev' /), 'A','#/cm3','CCN concentration at S=0.02%', sampled_on_subcycle=.true.) + call addfld ('CCN2',(/ 'lev' /), 'A','#/cm3','CCN concentration at S=0.05%', sampled_on_subcycle=.true.) + call addfld ('CCN3',(/ 'lev' /), 'A','#/cm3','CCN concentration at S=0.1%', sampled_on_subcycle=.true.) + call addfld ('CCN4',(/ 'lev' /), 'A','#/cm3','CCN concentration at S=0.2%', sampled_on_subcycle=.true.) + call addfld ('CCN5',(/ 'lev' /), 'A','#/cm3','CCN concentration at S=0.5%', sampled_on_subcycle=.true.) + call addfld ('CCN6',(/ 'lev' /), 'A','#/cm3','CCN concentration at S=1.0%', sampled_on_subcycle=.true.) if (history_amwg) then call add_default('CCN3', 1, ' ') diff --git a/src/physics/cam/nucleate_ice_cam.F90 b/src/physics/cam/nucleate_ice_cam.F90 index 7dff84f529..bd0a8b6636 100644 --- a/src/physics/cam/nucleate_ice_cam.F90 +++ b/src/physics/cam/nucleate_ice_cam.F90 @@ -263,52 +263,52 @@ subroutine nucleate_ice_cam_init(mincld_in, bulk_scale_in, pbuf2d, aero_props) if (cam_physpkg_is("cam7")) then ! Updates for PUMAS v1.21+ - call addfld('NIHFTEN', (/ 'lev' /), 'A', '1/m3/s', 'Activated Ice Number Concentration tendency due to homogenous freezing') - call addfld('NIDEPTEN', (/ 'lev' /), 'A', '1/m3/s', 'Activated Ice Number Concentration tendency due to deposition nucleation') - call addfld('NIIMMTEN', (/ 'lev' /), 'A', '1/m3/s', 'Activated Ice Number Concentration tendency due to immersion freezing') - call addfld('NIMEYTEN', (/ 'lev' /), 'A', '1/m3/s', 'Activated Ice Number Concentration tendency due to meyers deposition') + call addfld('NIHFTEN', (/ 'lev' /), 'A', '1/m3/s', 'Activated Ice Number Concentration tendency due to homogenous freezing', sampled_on_subcycle=.true.) + call addfld('NIDEPTEN', (/ 'lev' /), 'A', '1/m3/s', 'Activated Ice Number Concentration tendency due to deposition nucleation', sampled_on_subcycle=.true.) + call addfld('NIIMMTEN', (/ 'lev' /), 'A', '1/m3/s', 'Activated Ice Number Concentration tendency due to immersion freezing', sampled_on_subcycle=.true.) + call addfld('NIMEYTEN', (/ 'lev' /), 'A', '1/m3/s', 'Activated Ice Number Concentration tendency due to meyers deposition', sampled_on_subcycle=.true.) else - call addfld('NIHF', (/ 'lev' /), 'A', '1/m3', 'Activated Ice Number Concentration due to homogenous freezing') - call addfld('NIDEP', (/ 'lev' /), 'A', '1/m3', 'Activated Ice Number Concentration due to deposition nucleation') - call addfld('NIIMM', (/ 'lev' /), 'A', '1/m3', 'Activated Ice Number Concentration due to immersion freezing') - call addfld('NIMEY', (/ 'lev' /), 'A', '1/m3', 'Activated Ice Number Concentration due to meyers deposition') + call addfld('NIHF', (/ 'lev' /), 'A', '1/m3', 'Activated Ice Number Concentration due to homogenous freezing', sampled_on_subcycle=.true.) + call addfld('NIDEP', (/ 'lev' /), 'A', '1/m3', 'Activated Ice Number Concentration due to deposition nucleation', sampled_on_subcycle=.true.) + call addfld('NIIMM', (/ 'lev' /), 'A', '1/m3', 'Activated Ice Number Concentration due to immersion freezing', sampled_on_subcycle=.true.) + call addfld('NIMEY', (/ 'lev' /), 'A', '1/m3', 'Activated Ice Number Concentration due to meyers deposition', sampled_on_subcycle=.true.) endif - call addfld('NIREGM',(/ 'lev' /), 'A', 'C', 'Ice Nucleation Temperature Threshold for Regime') - call addfld('NISUBGRID',(/ 'lev' /), 'A', '', 'Ice Nucleation subgrid saturation factor') - call addfld('NITROP_PD',(/ 'lev' /), 'A', '', 'Chemical Tropopause probability') + call addfld('NIREGM',(/ 'lev' /), 'A', 'C', 'Ice Nucleation Temperature Threshold for Regime', sampled_on_subcycle=.true.) + call addfld('NISUBGRID',(/ 'lev' /), 'A', '', 'Ice Nucleation subgrid saturation factor', sampled_on_subcycle=.true.) + call addfld('NITROP_PD',(/ 'lev' /), 'A', '', 'Chemical Tropopause probability', sampled_on_subcycle=.true.) if ( history_cesm_forcing ) then call add_default('NITROP_PD',8,' ') endif if (use_preexisting_ice) then - call addfld('fhom', (/ 'lev' /), 'A','fraction', 'Fraction of cirrus where homogeneous freezing occur' ) - call addfld ('WICE', (/ 'lev' /), 'A','m/s','Vertical velocity Reduction caused by preexisting ice' ) - call addfld ('WEFF', (/ 'lev' /), 'A','m/s','Effective Vertical velocity for ice nucleation' ) + call addfld('fhom', (/ 'lev' /), 'A','fraction', 'Fraction of cirrus where homogeneous freezing occur', sampled_on_subcycle=.true.) + call addfld ('WICE', (/ 'lev' /), 'A','m/s','Vertical velocity Reduction caused by preexisting ice', sampled_on_subcycle=.true.) + call addfld ('WEFF', (/ 'lev' /), 'A','m/s','Effective Vertical velocity for ice nucleation', sampled_on_subcycle=.true.) if (cam_physpkg_is("cam7")) then ! Updates for PUMAS v1.21+ - call addfld ('INnso4TEN', (/ 'lev' /), 'A','1/m3/s','Number Concentration tendency so4 (in) to ice_nucleation') - call addfld ('INnbcTEN', (/ 'lev' /), 'A','1/m3/s','Number Concentration tendency bc (in) to ice_nucleation') - call addfld ('INndustTEN', (/ 'lev' /), 'A','1/m3/s','Number Concentration tendency dust (in) ice_nucleation') - call addfld ('INondustTEN', (/ 'lev' /), 'A','1/m3/s','Number Concentration tendency dust (out) from ice_nucleation') + call addfld ('INnso4TEN', (/ 'lev' /), 'A','1/m3/s','Number Concentration tendency so4 (in) to ice_nucleation', sampled_on_subcycle=.true.) + call addfld ('INnbcTEN', (/ 'lev' /), 'A','1/m3/s','Number Concentration tendency bc (in) to ice_nucleation', sampled_on_subcycle=.true.) + call addfld ('INndustTEN', (/ 'lev' /), 'A','1/m3/s','Number Concentration tendency dust (in) ice_nucleation', sampled_on_subcycle=.true.) + call addfld ('INondustTEN', (/ 'lev' /), 'A','1/m3/s','Number Concentration tendency dust (out) from ice_nucleation', sampled_on_subcycle=.true.) call addfld ('INhetTEN', (/ 'lev' /), 'A','1/m3/s', & - 'Tendency for contribution for in-cloud ice number density increase by het nucleation in ice cloud') + 'Tendency for contribution for in-cloud ice number density increase by het nucleation in ice cloud', sampled_on_subcycle=.true.) call addfld ('INhomTEN', (/ 'lev' /), 'A','1/m3/s', & - 'Tendency for contribution for in-cloud ice number density increase by hom nucleation in ice cloud') + 'Tendency for contribution for in-cloud ice number density increase by hom nucleation in ice cloud', sampled_on_subcycle=.true.) else - call addfld ('INnso4', (/ 'lev' /), 'A','1/m3','Number Concentration so4 (in) to ice_nucleation') - call addfld ('INnbc', (/ 'lev' /), 'A','1/m3','Number Concentration bc (in) to ice_nucleation') - call addfld ('INndust', (/ 'lev' /), 'A','1/m3','Number Concentration dust (in) ice_nucleation') - call addfld ('INondust', (/ 'lev' /), 'A','1/m3','Number Concentration dust (out) from ice_nucleation') + call addfld ('INnso4', (/ 'lev' /), 'A','1/m3','Number Concentration so4 (in) to ice_nucleation', sampled_on_subcycle=.true.) + call addfld ('INnbc', (/ 'lev' /), 'A','1/m3','Number Concentration bc (in) to ice_nucleation', sampled_on_subcycle=.true.) + call addfld ('INndust', (/ 'lev' /), 'A','1/m3','Number Concentration dust (in) ice_nucleation', sampled_on_subcycle=.true.) + call addfld ('INondust', (/ 'lev' /), 'A','1/m3','Number Concentration dust (out) from ice_nucleation', sampled_on_subcycle=.true.) call addfld ('INhet', (/ 'lev' /), 'A','1/m3', & - 'contribution for in-cloud ice number density increase by het nucleation in ice cloud') + 'contribution for in-cloud ice number density increase by het nucleation in ice cloud', sampled_on_subcycle=.true.) call addfld ('INhom', (/ 'lev' /), 'A','1/m3', & - 'contribution for in-cloud ice number density increase by hom nucleation in ice cloud') + 'contribution for in-cloud ice number density increase by hom nucleation in ice cloud', sampled_on_subcycle=.true.) endif - call addfld ('INFrehom', (/ 'lev' /), 'A','frequency','hom IN frequency ice cloud') - call addfld ('INFreIN', (/ 'lev' /), 'A','frequency','frequency of ice nucleation occur') + call addfld ('INFrehom', (/ 'lev' /), 'A','frequency','hom IN frequency ice cloud', sampled_on_subcycle=.true.) + call addfld ('INFreIN', (/ 'lev' /), 'A','frequency','frequency of ice nucleation occur', sampled_on_subcycle=.true.) if (hist_preexisting_ice) then call add_default ('WSUBI ', 1, ' ') ! addfld/outfld calls are in microp_aero @@ -607,12 +607,18 @@ subroutine nucleate_ice_cam_calc( & else ! for bulk model - dust_num_col(:ncol,:) = naer2(:ncol,:,idxdst1)/25._r8 * per_cm3 & ! #/cm3 - + naer2(:ncol,:,idxdst2)/25._r8 * per_cm3 & - + naer2(:ncol,:,idxdst3)/25._r8 * per_cm3 & - + naer2(:ncol,:,idxdst4)/25._r8 * per_cm3 - sulf_num_col(:ncol,:) = naer2(:ncol,:,idxsul)/25._r8 * per_cm3 - soot_num_col(:ncol,:) = naer2(:ncol,:,idxbcphi)/25._r8 * per_cm3 + if (idxdst1 > 0 .and. idxdst2 > 0 .and. idxdst3 > 0 .and. idxdst4 > 0) then + dust_num_col(:ncol,:) = naer2(:ncol,:,idxdst1)/25._r8 * per_cm3 & ! #/cm3 + + naer2(:ncol,:,idxdst2)/25._r8 * per_cm3 & + + naer2(:ncol,:,idxdst3)/25._r8 * per_cm3 & + + naer2(:ncol,:,idxdst4)/25._r8 * per_cm3 + end if + if (idxsul > 0) then + sulf_num_col(:ncol,:) = naer2(:ncol,:,idxsul)/25._r8 * per_cm3 + end if + if (idxbcphi > 0) then + soot_num_col(:ncol,:) = naer2(:ncol,:,idxbcphi)/25._r8 * per_cm3 + end if endif kloop: do k = top_lev, pver diff --git a/src/physics/cam/physpkg.F90 b/src/physics/cam/physpkg.F90 index ba36670ce8..609006e75a 100644 --- a/src/physics/cam/physpkg.F90 +++ b/src/physics/cam/physpkg.F90 @@ -855,7 +855,7 @@ subroutine phys_init( phys_state, phys_tend, pbuf2d, cam_in, cam_out ) call aer_rad_props_init() ! initialize carma - call carma_init() + call carma_init(pbuf2d) ! Prognostic chemistry. call chem_init(phys_state,pbuf2d) @@ -1390,8 +1390,9 @@ subroutine tphysac (ztodt, cam_in, & use aero_model, only: aero_model_drydep use carma_intr, only: carma_emission_tend, carma_timestep_tend use carma_flags_mod, only: carma_do_aerosol, carma_do_emission - use check_energy, only: check_energy_chng, tot_energy_phys + use check_energy, only: tot_energy_phys use check_energy, only: check_tracers_data, check_tracers_init, check_tracers_chng + use check_energy, only: check_energy_cam_chng use time_manager, only: get_nstep use cam_abortutils, only: endrun use dycore, only: dycore_is @@ -1530,7 +1531,7 @@ subroutine tphysac (ztodt, cam_in, & if (carma_do_emission) then ! carma emissions - call carma_emission_tend (state, ptend, cam_in, ztodt) + call carma_emission_tend (state, ptend, cam_in, ztodt, pbuf) call physics_update(state, ptend, ztodt, tend) end if @@ -1615,7 +1616,7 @@ subroutine tphysac (ztodt, cam_in, & call cam_snapshot_all_outfld_tphysac(cam_snapshot_after_num, state, tend, cam_in, cam_out, pbuf,& fh2o, surfric, obklen, flx_heat) end if - call check_energy_chng(state, tend, "chem", nstep, ztodt, fh2o, zero, zero, zero) + call check_energy_cam_chng(state, tend, "chem", nstep, ztodt, fh2o, zero, zero, zero) call check_tracers_chng(state, tracerint, "chem_timestep_tend", nstep, ztodt, & cam_in%cflx) end if @@ -1677,9 +1678,9 @@ subroutine tphysac (ztodt, cam_in, & call t_stopf('rayleigh_friction') if (do_clubb_sgs) then - call check_energy_chng(state, tend, "vdiff", nstep, ztodt, zero, zero, zero, zero) + call check_energy_cam_chng(state, tend, "vdiff", nstep, ztodt, zero, zero, zero, zero) else - call check_energy_chng(state, tend, "vdiff", nstep, ztodt, cam_in%cflx(:,1), zero, & + call check_energy_cam_chng(state, tend, "vdiff", nstep, ztodt, cam_in%cflx(:,1), zero, & zero, cam_in%shf) endif @@ -1719,7 +1720,7 @@ subroutine tphysac (ztodt, cam_in, & call carma_timestep_tend(state, cam_in, cam_out, ptend, ztodt, pbuf, obklen=obklen, ustar=surfric) call physics_update(state, ptend, ztodt, tend) - call check_energy_chng(state, tend, "carma_tend", nstep, ztodt, zero, zero, zero, zero) + call check_energy_cam_chng(state, tend, "carma_tend", nstep, ztodt, zero, zero, zero, zero) call t_stopf('carma_timestep_tend') end if @@ -1759,7 +1760,7 @@ subroutine tphysac (ztodt, cam_in, & end if ! Check energy integrals - call check_energy_chng(state, tend, "gwdrag", nstep, ztodt, zero, & + call check_energy_cam_chng(state, tend, "gwdrag", nstep, ztodt, zero, & zero, zero, flx_heat) call t_stopf('gw_tend') @@ -1789,7 +1790,7 @@ subroutine tphysac (ztodt, cam_in, & end if ! Check energy integrals - call check_energy_chng(state, tend, "qborelax", nstep, ztodt, zero, zero, zero, zero) + call check_energy_cam_chng(state, tend, "qborelax", nstep, ztodt, zero, zero, zero, zero) ! Lunar tides call lunar_tides_tend( state, ptend ) @@ -1801,7 +1802,7 @@ subroutine tphysac (ztodt, cam_in, & end if call physics_update(state, ptend, ztodt, tend) ! Check energy integrals - call check_energy_chng(state, tend, "lunar_tides", nstep, ztodt, zero, zero, zero, zero) + call check_energy_cam_chng(state, tend, "lunar_tides", nstep, ztodt, zero, zero, zero, zero) ! Ion drag calculation call t_startf ( 'iondrag' ) @@ -1851,7 +1852,7 @@ subroutine tphysac (ztodt, cam_in, & endif ! Check energy integrals - call check_energy_chng(state, tend, "iondrag", nstep, ztodt, zero, zero, zero, zero) + call check_energy_cam_chng(state, tend, "iondrag", nstep, ztodt, zero, zero, zero, zero) call t_stopf ( 'iondrag' ) @@ -1866,7 +1867,7 @@ subroutine tphysac (ztodt, cam_in, & call outfld( 'VTEND_NDG', ptend%v, pcols, lchnk) end if call physics_update(state,ptend,ztodt,tend) - call check_energy_chng(state, tend, "nudging", nstep, ztodt, zero, zero, zero, zero) + call check_energy_cam_chng(state, tend, "nudging", nstep, ztodt, zero, zero, zero, zero) endif !-------------- Energy budget checks vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv @@ -2044,7 +2045,8 @@ subroutine tphysbc (ztodt, state, & use convect_deep, only: convect_deep_tend, convect_deep_tend_2, deep_scheme_does_scav_trans use time_manager, only: is_first_step, get_nstep use convect_shallow, only: convect_shallow_tend - use check_energy, only: check_energy_chng, check_energy_fix, check_energy_timestep_init + use check_energy, only: check_energy_timestep_init, check_energy_cam_chng + use check_energy, only: check_energy_cam_fix use check_energy, only: check_tracers_data, check_tracers_init, check_tracers_chng use check_energy, only: tot_energy_phys use dycore, only: dycore_is @@ -2254,9 +2256,11 @@ subroutine tphysbc (ztodt, state, & call tot_energy_phys(state, 'phBF') call tot_energy_phys(state, 'dyBF',vc=vc_dycore) if (.not.dycore_is('EUL')) then - call check_energy_fix(state, ptend, nstep, flx_heat) + call check_energy_cam_fix(state, ptend, nstep, flx_heat) + call physics_update(state, ptend, ztodt, tend) - call check_energy_chng(state, tend, "chkengyfix", nstep, ztodt, zero, zero, zero, flx_heat) + + call check_energy_cam_chng(state, tend, "chkengyfix", nstep, ztodt, zero, zero, zero, flx_heat) call outfld( 'EFIX', flx_heat , pcols, lchnk ) end if call tot_energy_phys(state, 'phBP') @@ -2384,7 +2388,7 @@ subroutine tphysbc (ztodt, state, & ! Check energy integrals, including "reserved liquid" flx_cnd(:ncol) = prec_dp(:ncol) + rliq(:ncol) snow_dp(:ncol) = snow_dp(:ncol) + rice(:ncol) - call check_energy_chng(state, tend, "convect_deep", nstep, ztodt, zero, flx_cnd, snow_dp, zero) + call check_energy_cam_chng(state, tend, "convect_deep", nstep, ztodt, zero, flx_cnd, snow_dp, zero) snow_dp(:ncol) = snow_dp(:ncol) - rice(:ncol) ! @@ -2427,7 +2431,7 @@ subroutine tphysbc (ztodt, state, & end if flx_cnd(:ncol) = prec_sh(:ncol) + rliq2(:ncol) - call check_energy_chng(state, tend, "convect_shallow", nstep, ztodt, zero, flx_cnd, snow_sh, zero) + call check_energy_cam_chng(state, tend, "convect_shallow", nstep, ztodt, zero, flx_cnd, snow_sh, zero) call check_tracers_chng(state, tracerint, "convect_shallow", nstep, ztodt, zero_tracers) @@ -2459,9 +2463,9 @@ subroutine tphysbc (ztodt, state, & ! Before the detrainment, the reserved condensate is all liquid, but if CARMA is doing ! detrainment, then the reserved condensate is snow. if (carma_do_detrain) then - call check_energy_chng(state, tend, "carma_tend", nstep, ztodt, zero, prec_str+rliq, snow_str+rliq, zero) + call check_energy_cam_chng(state, tend, "carma_tend", nstep, ztodt, zero, prec_str+rliq, snow_str+rliq, zero) else - call check_energy_chng(state, tend, "carma_tend", nstep, ztodt, zero, prec_str, snow_str, zero) + call check_energy_cam_chng(state, tend, "carma_tend", nstep, ztodt, zero, prec_str, snow_str, zero) end if end if @@ -2483,7 +2487,7 @@ subroutine tphysbc (ztodt, state, & cam_in%ts, cam_in%sst, zdu) call physics_update(state, ptend, ztodt, tend) - call check_energy_chng(state, tend, "cldwat_tend", nstep, ztodt, zero, prec_str, snow_str, zero) + call check_energy_cam_chng(state, tend, "cldwat_tend", nstep, ztodt, zero, prec_str, snow_str, zero) call t_stopf('rk_stratiform_tend') @@ -2555,7 +2559,7 @@ subroutine tphysbc (ztodt, state, & flx_heat, cmfmc, cmfcme, zdu, rliq, rice, dlf, dlf2, rliq2, det_s, det_ice, net_flx) end if - call check_energy_chng(state, tend, "macrop_tend", nstep, ztodt, & + call check_energy_cam_chng(state, tend, "macrop_tend", nstep, ztodt, & zero, flx_cnd(:ncol)/cld_macmic_num_steps, & det_ice(:ncol)/cld_macmic_num_steps, & flx_heat(:ncol)/cld_macmic_num_steps) @@ -2602,7 +2606,7 @@ subroutine tphysbc (ztodt, state, & end if ! Use actual qflux (not lhf/latvap) for consistency with surface fluxes and revised code - call check_energy_chng(state, tend, "clubb_tend", nstep, ztodt, & + call check_energy_cam_chng(state, tend, "clubb_tend", nstep, ztodt, & cam_in%cflx(:ncol,1)/cld_macmic_num_steps, & flx_cnd(:ncol)/cld_macmic_num_steps, & det_ice(:ncol)/cld_macmic_num_steps, & @@ -2703,7 +2707,7 @@ subroutine tphysbc (ztodt, state, & flx_heat, cmfmc, cmfcme, zdu, rliq, rice, dlf, dlf2, rliq2, det_s, det_ice, net_flx) end if - call check_energy_chng(state_sc, tend_sc, "microp_tend_subcol", & + call check_energy_cam_chng(state_sc, tend_sc, "microp_tend_subcol", & nstep, ztodt, zero_sc, & prec_str_sc(:state_sc%ncol)/cld_macmic_num_steps, & snow_str_sc(:state_sc%ncol)/cld_macmic_num_steps, zero_sc) @@ -2735,7 +2739,7 @@ subroutine tphysbc (ztodt, state, & flx_heat, cmfmc, cmfcme, zdu, rliq, rice, dlf, dlf2, rliq2, det_s, det_ice, net_flx) end if - call check_energy_chng(state, tend, "microp_tend", nstep, ztodt, & + call check_energy_cam_chng(state, tend, "microp_tend", nstep, ztodt, & zero, prec_str(:ncol)/cld_macmic_num_steps, & snow_str(:ncol)/cld_macmic_num_steps, zero) @@ -2888,7 +2892,7 @@ subroutine tphysbc (ztodt, state, & flx_heat, cmfmc, cmfcme, zdu, rliq, rice, dlf, dlf2, rliq2, det_s, det_ice, net_flx) end if - call check_energy_chng(state, tend, "radheat", nstep, ztodt, zero, zero, zero, net_flx) + call check_energy_cam_chng(state, tend, "radheat", nstep, ztodt, zero, zero, zero, net_flx) call t_stopf('radiation') diff --git a/src/physics/cam/subcol_SILHS.F90 b/src/physics/cam/subcol_SILHS.F90 index c373ed6b3e..05653b9f03 100644 --- a/src/physics/cam/subcol_SILHS.F90 +++ b/src/physics/cam/subcol_SILHS.F90 @@ -489,80 +489,80 @@ subroutine subcol_init_SILHS(pbuf2d) ! Register output fields from SILHS !------------------------------- call addfld('SILHS_NCLD_SCOL', (/'psubcols', 'ilev '/), 'I', 'm^-3', & - 'Subcolumn Cloud Number Concentration', flag_xyfill=.true., fill_value=1.e30_r8) + 'Subcolumn Cloud Number Concentration', flag_xyfill=.true., fill_value=1.e30_r8, sampled_on_subcycle=.true.) call addfld('SILHS_NRAIN_SCOL', (/'psubcols', 'ilev '/), 'I', 'm^-3', & - 'Subcolumn Number Concentration of Rain from SILHS', flag_xyfill=.true., fill_value=1.e30_r8) + 'Subcolumn Number Concentration of Rain from SILHS', flag_xyfill=.true., fill_value=1.e30_r8, sampled_on_subcycle=.true.) call addfld('SILHS_OMEGA_SCOL', (/'psubcols', 'ilev '/), 'I', 'Pa/s', & - 'Subcolumn vertical pressure velocity', flag_xyfill=.true., fill_value=1.e30_r8) + 'Subcolumn vertical pressure velocity', flag_xyfill=.true., fill_value=1.e30_r8, sampled_on_subcycle=.true.) call addfld('SILHS_RCM_SCOL', (/'psubcols', 'ilev '/), 'I', 'kg/kg', & - 'Subcolumn Cloud Liquid Water from SILHS', flag_xyfill=.true., fill_value=1.e30_r8) + 'Subcolumn Cloud Liquid Water from SILHS', flag_xyfill=.true., fill_value=1.e30_r8, sampled_on_subcycle=.true.) call addfld('SILHS_RICLD_SCOL', (/'psubcols', 'ilev '/), 'I', 'kg/kg', & - 'Subcolumn Cloud Ice Water from SILHS', flag_xyfill=.true., fill_value=1.e30_r8) + 'Subcolumn Cloud Ice Water from SILHS', flag_xyfill=.true., fill_value=1.e30_r8, sampled_on_subcycle=.true.) call addfld('SILHS_NICLD_SCOL', (/'psubcols', 'ilev '/), 'I', 'kg/kg', & - 'Subcolumn Cloud Ice Number Conc from SILHS', flag_xyfill=.true., fill_value=1.e30_r8) + 'Subcolumn Cloud Ice Number Conc from SILHS', flag_xyfill=.true., fill_value=1.e30_r8, sampled_on_subcycle=.true.) call addfld('SILHS_RRAIN_SCOL', (/'psubcols', 'ilev '/), 'I', 'kg/kg', & - 'Subcolumn Precipitating Liquid Water from SILHS', flag_xyfill=.true., fill_value=1.e30_r8) + 'Subcolumn Precipitating Liquid Water from SILHS', flag_xyfill=.true., fill_value=1.e30_r8, sampled_on_subcycle=.true.) call addfld('SILHS_RT_SCOL', (/'psubcols', 'ilev '/), 'I', 'kg/kg ', & - 'Subcolumn Total Water from SILHS', flag_xyfill=.true., fill_value=1.e30_r8) + 'Subcolumn Total Water from SILHS', flag_xyfill=.true., fill_value=1.e30_r8, sampled_on_subcycle=.true.) call addfld('SILHS_THLM_SCOL', (/'psubcols', 'ilev '/), 'I', 'K', & - 'Subcolumn liquid water pot temperature', flag_xyfill=.true., fill_value=1.e30_r8) + 'Subcolumn liquid water pot temperature', flag_xyfill=.true., fill_value=1.e30_r8, sampled_on_subcycle=.true.) call addfld('SILHS_WEIGHT_SCOL', (/'psubcols'/), 'I', 'frac', & - 'Weights for each subcolumn', flag_xyfill=.true., fill_value=1.e30_r8) + 'Weights for each subcolumn', flag_xyfill=.true., fill_value=1.e30_r8, sampled_on_subcycle=.true.) call addfld('SILHS_WM_SCOL', (/'psubcols', 'ilev '/), 'I', 'm/s', & - 'Subcolumn vertical velocity from SILHS', flag_xyfill=.true., fill_value=1.e30_r8) + 'Subcolumn vertical velocity from SILHS', flag_xyfill=.true., fill_value=1.e30_r8, sampled_on_subcycle=.true.) call addfld('NR_IN_LH', (/ 'lev' /), 'I', 'm^-3', & - 'Num Rain Conc as input to SILHS') + 'Num Rain Conc as input to SILHS', sampled_on_subcycle=.true.) call addfld('SILHS_RTM', (/ 'ilev' /), 'I', 'kg/kg', & - 'Input total water mixing ratio') + 'Input total water mixing ratio', sampled_on_subcycle=.true.) call addfld('SILHS_THLM', (/ 'ilev' /), 'I', 'K', & - 'Input liquid water potential temperature') + 'Input liquid water potential temperature', sampled_on_subcycle=.true.) call addfld('SILHS_QC_IN', (/ 'lev' /), 'I', 'kg/kg', & - 'Input cloud water mixing ratio') + 'Input cloud water mixing ratio', sampled_on_subcycle=.true.) call addfld('SILHS_QI_IN', (/ 'lev' /), 'I', 'kg/kg', & - 'Input cloud ice mixing ratio') + 'Input cloud ice mixing ratio', sampled_on_subcycle=.true.) call addfld('SILHS_NC_IN', (/ 'lev' /), 'I', '#/kg', & - 'Input cloud water number concentration') + 'Input cloud water number concentration', sampled_on_subcycle=.true.) call addfld('SILHS_NI_IN', (/ 'lev' /), 'I', '#/kg', & - 'Input cloud ice number concentration') + 'Input cloud ice number concentration', sampled_on_subcycle=.true.) call addfld('AKM_CLUBB', (/ 'ilev' /), 'I', '(kg/kg)/s', & - 'Exact Kessler autoconversion') + 'Exact Kessler autoconversion', sampled_on_subcycle=.true.) call addfld('AKM_LH_CLUBB', (/ 'ilev' /), 'I', '(kg/kg)/s', & - 'Monte Carlo estimate of Kessler autoconversion') + 'Monte Carlo estimate of Kessler autoconversion', sampled_on_subcycle=.true.) call addfld('INVS_EXNER', (/ 'lev' /), 'I', 'none', & - 'inverse EXNER function from state in subcol_SILHS') + 'inverse EXNER function from state in subcol_SILHS', sampled_on_subcycle=.true.) call addfld('SILHS_ZTODT', horiz_only, 'I', 's', & - 'Length of Physics timestep (for debugging)') + 'Length of Physics timestep (for debugging)', sampled_on_subcycle=.true.) if ( subcol_SILHS_constrainmn ) then call addfld('SILHS_MSC_CLDICE', (/ 'lev' /), 'A', 'kg/kg', & - 'Mean Cloud Ice across subcolumns') + 'Mean Cloud Ice across subcolumns', sampled_on_subcycle=.true.) call addfld('SILHS_STDSC_CLDICE', (/ 'lev' /), 'A', 'kg/kg', & - 'Standard deviation of Ice across subcolumns') + 'Standard deviation of Ice across subcolumns', sampled_on_subcycle=.true.) if ( ixsnow > 0 ) then call addfld('SILHS_MSC_CLDLIQ', (/ 'lev' /), 'A', 'kg/kg', & - 'Mean Cloud Liquid across subcolumns') + 'Mean Cloud Liquid across subcolumns', sampled_on_subcycle=.true.) call addfld('SILHS_STDSC_CLDLIQ', (/ 'lev' /), 'A', 'kg/kg', & - 'Standard deviation of Liquid across subcolumns') + 'Standard deviation of Liquid across subcolumns', sampled_on_subcycle=.true.) call addfld('SILHS_MSC_Q', (/ 'lev' /), 'A', 'kg/kg', & - 'Mean water vapor across subcolumns') + 'Mean water vapor across subcolumns', sampled_on_subcycle=.true.) call addfld('SILHS_STDSC_Q', (/ 'lev' /), 'A', 'kg/kg', & - 'Standard deviation of water vapor across subcolumns') + 'Standard deviation of water vapor across subcolumns', sampled_on_subcycle=.true.) endif ! ixsnow > 0 endif ! subcol_SILHS_constrainmn call addfld('SILHS_EFF_CLDFRAC', (/ 'lev' /), 'A', 'frac', & - 'Calculated cloud fraction from subcolumn liq or ice') + 'Calculated cloud fraction from subcolumn liq or ice', sampled_on_subcycle=.true.) call addfld('SILHS_CLUBB_PRECIP_FRAC', (/ 'lev' /), 'A', 'frac', & - 'Precipitation fraction from CLUBB (set_up_pdf_params_incl_hydromet)') + 'Precipitation fraction from CLUBB (set_up_pdf_params_incl_hydromet)', sampled_on_subcycle=.true.) call addfld('SILHS_CLUBB_ICE_SS_FRAC', (/ 'lev' /), 'A', 'frac', & - 'Ice supersaturation fraction from CLUBB') - - call addfld ('QVHFTEN', (/ 'lev' /), 'A', 'kg/kg/s', 'Water vapor mixing ratio tendency from hole filling') - call addfld ('QCHFTEN', (/ 'lev' /), 'A', 'kg/kg/s', 'Cloud water mixing ratio tendency from hole filling') - call addfld ('QRHFTEN', (/ 'lev' /), 'A', 'kg/kg/s', 'Rain water mixing ratio tendency from hole filling') - call addfld ('QIHFTEN', (/ 'lev' /), 'A', 'kg/kg/s', 'Cloud ice mixing ratio tendency from hole filling') - call addfld ('QSHFTEN', (/ 'lev' /), 'A', 'kg/kg/s', 'Snow mixing ratio tendency from hole filling') - call addfld ('THFTEN', (/ 'lev' /), 'A', 'K/s', 'Temperature tendency from hole filling') + 'Ice supersaturation fraction from CLUBB', sampled_on_subcycle=.true.) + + call addfld ('QVHFTEN', (/ 'lev' /), 'A', 'kg/kg/s', 'Water vapor mixing ratio tendency from hole filling', sampled_on_subcycle=.true.) + call addfld ('QCHFTEN', (/ 'lev' /), 'A', 'kg/kg/s', 'Cloud water mixing ratio tendency from hole filling', sampled_on_subcycle=.true.) + call addfld ('QRHFTEN', (/ 'lev' /), 'A', 'kg/kg/s', 'Rain water mixing ratio tendency from hole filling', sampled_on_subcycle=.true.) + call addfld ('QIHFTEN', (/ 'lev' /), 'A', 'kg/kg/s', 'Cloud ice mixing ratio tendency from hole filling', sampled_on_subcycle=.true.) + call addfld ('QSHFTEN', (/ 'lev' /), 'A', 'kg/kg/s', 'Snow mixing ratio tendency from hole filling', sampled_on_subcycle=.true.) + call addfld ('THFTEN', (/ 'lev' /), 'A', 'K/s', 'Temperature tendency from hole filling', sampled_on_subcycle=.true.) #endif #endif diff --git a/src/physics/cam/vertical_diffusion.F90 b/src/physics/cam/vertical_diffusion.F90 index 472b2a5501..e2d571a4de 100644 --- a/src/physics/cam/vertical_diffusion.F90 +++ b/src/physics/cam/vertical_diffusion.F90 @@ -619,8 +619,10 @@ subroutine vertical_diffusion_init(pbuf2d) endif if (history_eddy) then - call add_default( 'UFLX ', 1, ' ' ) - call add_default( 'VFLX ', 1, ' ' ) + if (.not. do_pbl_diags) then + call add_default( 'UFLX ', 1, ' ' ) + call add_default( 'VFLX ', 1, ' ' ) + end if endif if( history_budget ) then diff --git a/src/physics/cam/zm_conv_intr.F90 b/src/physics/cam/zm_conv_intr.F90 index 4113c33a4b..5db6d1bc03 100644 --- a/src/physics/cam/zm_conv_intr.F90 +++ b/src/physics/cam/zm_conv_intr.F90 @@ -393,7 +393,6 @@ subroutine zm_conv_tend(pblh ,mcon ,cme , & use time_manager, only: get_nstep, is_first_step use physics_buffer, only : pbuf_get_field, physics_buffer_desc, pbuf_old_tim_idx use constituents, only: pcnst, cnst_get_ind, cnst_is_convtran1 - use check_energy, only: check_energy_chng use physconst, only: gravit, latice, latvap, tmelt, cpwv, cpliq, rh2o use phys_control, only: cam_physpkg_is diff --git a/src/physics/cam7/micro_pumas_cam.F90 b/src/physics/cam7/micro_pumas_cam.F90 index 0d9f448e2f..5d76f36be5 100644 --- a/src/physics/cam7/micro_pumas_cam.F90 +++ b/src/physics/cam7/micro_pumas_cam.F90 @@ -958,286 +958,286 @@ subroutine micro_pumas_cam_init(pbuf2d) call cnst_get_ind(cnst_names(m), mm) if ( any(mm == (/ ixcldliq, ixcldice, ixrain, ixsnow, ixgraupel /)) ) then ! mass mixing ratios - call addfld(cnst_name(mm), (/ 'lev' /), 'A', 'kg/kg', cnst_longname(mm) ) - call addfld(sflxnam(mm), horiz_only, 'A', 'kg/m2/s', trim(cnst_name(mm))//' surface flux') + call addfld(cnst_name(mm), (/ 'lev' /), 'A', 'kg/kg', cnst_longname(mm), sampled_on_subcycle=.true.) + call addfld(sflxnam(mm), horiz_only, 'A', 'kg/m2/s', trim(cnst_name(mm))//' surface flux', sampled_on_subcycle=.true.) else if ( any(mm == (/ ixnumliq, ixnumice, ixnumrain, ixnumsnow, ixnumgraupel /)) ) then ! number concentrations - call addfld(cnst_name(mm), (/ 'lev' /), 'A', '1/kg', cnst_longname(mm) ) - call addfld(sflxnam(mm), horiz_only, 'A', '1/m2/s', trim(cnst_name(mm))//' surface flux') + call addfld(cnst_name(mm), (/ 'lev' /), 'A', '1/kg', cnst_longname(mm), sampled_on_subcycle=.true.) + call addfld(sflxnam(mm), horiz_only, 'A', '1/m2/s', trim(cnst_name(mm))//' surface flux', sampled_on_subcycle=.true.) else call endrun( "micro_pumas_cam_init: & &Could not call addfld for constituent with unknown units.") endif end do - call addfld(apcnst(ixcldliq), (/ 'lev' /), 'A', 'kg/kg', trim(cnst_name(ixcldliq))//' after physics' ) - call addfld(apcnst(ixcldice), (/ 'lev' /), 'A', 'kg/kg', trim(cnst_name(ixcldice))//' after physics' ) - call addfld(bpcnst(ixcldliq), (/ 'lev' /), 'A', 'kg/kg', trim(cnst_name(ixcldliq))//' before physics' ) - call addfld(bpcnst(ixcldice), (/ 'lev' /), 'A', 'kg/kg', trim(cnst_name(ixcldice))//' before physics' ) + call addfld(apcnst(ixcldliq), (/ 'lev' /), 'A', 'kg/kg', trim(cnst_name(ixcldliq))//' after physics', sampled_on_subcycle=.true.) + call addfld(apcnst(ixcldice), (/ 'lev' /), 'A', 'kg/kg', trim(cnst_name(ixcldice))//' after physics', sampled_on_subcycle=.true.) + call addfld(bpcnst(ixcldliq), (/ 'lev' /), 'A', 'kg/kg', trim(cnst_name(ixcldliq))//' before physics', sampled_on_subcycle=.true.) + call addfld(bpcnst(ixcldice), (/ 'lev' /), 'A', 'kg/kg', trim(cnst_name(ixcldice))//' before physics', sampled_on_subcycle=.true.) - call addfld(apcnst(ixrain), (/ 'lev' /), 'A', 'kg/kg', trim(cnst_name(ixrain))//' after physics' ) - call addfld(apcnst(ixsnow), (/ 'lev' /), 'A', 'kg/kg', trim(cnst_name(ixsnow))//' after physics' ) - call addfld(bpcnst(ixrain), (/ 'lev' /), 'A', 'kg/kg', trim(cnst_name(ixrain))//' before physics' ) - call addfld(bpcnst(ixsnow), (/ 'lev' /), 'A', 'kg/kg', trim(cnst_name(ixsnow))//' before physics' ) + call addfld(apcnst(ixrain), (/ 'lev' /), 'A', 'kg/kg', trim(cnst_name(ixrain))//' after physics', sampled_on_subcycle=.true.) + call addfld(apcnst(ixsnow), (/ 'lev' /), 'A', 'kg/kg', trim(cnst_name(ixsnow))//' after physics', sampled_on_subcycle=.true.) + call addfld(bpcnst(ixrain), (/ 'lev' /), 'A', 'kg/kg', trim(cnst_name(ixrain))//' before physics', sampled_on_subcycle=.true.) + call addfld(bpcnst(ixsnow), (/ 'lev' /), 'A', 'kg/kg', trim(cnst_name(ixsnow))//' before physics', sampled_on_subcycle=.true.) if (micro_mg_version > 2) then - call addfld(apcnst(ixgraupel), (/ 'lev' /), 'A', 'kg/kg', trim(cnst_name(ixgraupel))//' after physics' ) - call addfld(bpcnst(ixgraupel), (/ 'lev' /), 'A', 'kg/kg', trim(cnst_name(ixgraupel))//' before physics' ) + call addfld(apcnst(ixgraupel), (/ 'lev' /), 'A', 'kg/kg', trim(cnst_name(ixgraupel))//' after physics', sampled_on_subcycle=.true.) + call addfld(bpcnst(ixgraupel), (/ 'lev' /), 'A', 'kg/kg', trim(cnst_name(ixgraupel))//' before physics', sampled_on_subcycle=.true.) end if - call addfld ('CME', (/ 'lev' /), 'A', 'kg/kg/s', 'Rate of cond-evap within the cloud' ) - call addfld ('PRODPREC', (/ 'lev' /), 'A', 'kg/kg/s', 'Rate of conversion of condensate to precip' ) - call addfld ('EVAPPREC', (/ 'lev' /), 'A', 'kg/kg/s', 'Rate of evaporation of falling precip' ) - call addfld ('EVAPSNOW', (/ 'trop_cld_lev' /), 'A', 'kg/kg/s', 'Rate of evaporation of falling snow' ) - call addfld ('HPROGCLD', (/ 'lev' /), 'A', 'W/kg' , 'Heating from prognostic clouds' ) - call addfld ('FICE', (/ 'lev' /), 'A', 'fraction', 'Fractional ice content within cloud' ) - call addfld ('CLDFSNOW', (/ 'lev' /), 'A', '1', 'Cloud fraction adjusted for snow' ) - call addfld ('ICWMRST', (/ 'lev' /), 'A', 'kg/kg', 'Prognostic in-stratus water mixing ratio' ) - call addfld ('ICIMRST', (/ 'lev' /), 'A', 'kg/kg', 'Prognostic in-stratus ice mixing ratio' ) + call addfld ('CME', (/ 'lev' /), 'A', 'kg/kg/s', 'Rate of cond-evap within the cloud', sampled_on_subcycle=.true.) + call addfld ('PRODPREC', (/ 'lev' /), 'A', 'kg/kg/s', 'Rate of conversion of condensate to precip', sampled_on_subcycle=.true.) + call addfld ('EVAPPREC', (/ 'lev' /), 'A', 'kg/kg/s', 'Rate of evaporation of falling precip', sampled_on_subcycle=.true.) + call addfld ('EVAPSNOW', (/ 'trop_cld_lev' /), 'A', 'kg/kg/s', 'Rate of evaporation of falling snow', sampled_on_subcycle=.true.) + call addfld ('HPROGCLD', (/ 'lev' /), 'A', 'W/kg' , 'Heating from prognostic clouds', sampled_on_subcycle=.true.) + call addfld ('FICE', (/ 'lev' /), 'A', 'fraction', 'Fractional ice content within cloud', sampled_on_subcycle=.true.) + call addfld ('CLDFSNOW', (/ 'lev' /), 'A', '1', 'Cloud fraction adjusted for snow', sampled_on_subcycle=.true.) + call addfld ('ICWMRST', (/ 'lev' /), 'A', 'kg/kg', 'Prognostic in-stratus water mixing ratio', sampled_on_subcycle=.true.) + call addfld ('ICIMRST', (/ 'lev' /), 'A', 'kg/kg', 'Prognostic in-stratus ice mixing ratio', sampled_on_subcycle=.true.) ! MG microphysics diagnostics - call addfld ('QCSEVAP', (/ 'trop_cld_lev' /), 'A', 'kg/kg/s', 'Rate of evaporation of falling cloud water' ) - call addfld ('QISEVAP', (/ 'trop_cld_lev' /), 'A', 'kg/kg/s', 'Rate of sublimation of falling cloud ice' ) - call addfld ('QVRES', (/ 'trop_cld_lev' /), 'A', 'kg/kg/s', 'Rate of residual condensation term' ) - call addfld ('CMEIOUT', (/ 'trop_cld_lev' /), 'A', 'kg/kg/s', 'Rate of deposition/sublimation of cloud ice' ) - call addfld ('VTRMC', (/ 'trop_cld_lev' /), 'A', 'm/s', 'Mass-weighted cloud water fallspeed' ) - call addfld ('VTRMI', (/ 'trop_cld_lev' /), 'A', 'm/s', 'Mass-weighted cloud ice fallspeed' ) - call addfld ('QCSEDTEN', (/ 'trop_cld_lev' /), 'A', 'kg/kg/s', 'Cloud water mixing ratio tendency from sedimentation' ) - call addfld ('QISEDTEN', (/ 'trop_cld_lev' /), 'A', 'kg/kg/s', 'Cloud ice mixing ratio tendency from sedimentation' ) - call addfld ('PRAO', (/ 'lev' /), 'A', 'kg/kg/s', 'Accretion of cloud water by rain' ) - call addfld ('PRCO', (/ 'lev' /), 'A', 'kg/kg/s', 'Autoconversion of cloud water' ) - call addfld ('MNUCCCO', (/ 'lev' /), 'A', 'kg/kg/s', 'Immersion freezing of cloud water' ) - call addfld ('MNUCCTO', (/ 'lev' /), 'A', 'kg/kg/s', 'Contact freezing of cloud water' ) - call addfld ('MNUCCDO', (/ 'trop_cld_lev' /), 'A', 'kg/kg/s', 'Homogeneous and heterogeneous nucleation from vapor' ) - call addfld ('MNUCCDOhet', (/ 'lev' /), 'A', 'kg/kg/s', 'Heterogeneous nucleation from vapor' ) - call addfld ('MSACWIO', (/ 'lev' /), 'A', 'kg/kg/s', 'Conversion of cloud water from rime-splintering' ) - call addfld ('PSACWSO', (/ 'lev' /), 'A', 'kg/kg/s', 'Accretion of cloud water by snow' ) - call addfld ('BERGSO', (/ 'lev' /), 'A', 'kg/kg/s', 'Conversion of cloud water to snow from bergeron' ) - call addfld ('BERGO', (/ 'lev' /), 'A', 'kg/kg/s', 'Conversion of cloud water to cloud ice from bergeron' ) - call addfld ('MELTO', (/ 'lev' /), 'A', 'kg/kg/s', 'Melting of cloud ice' ) - call addfld ('MELTSTOT', (/ 'trop_cld_lev' /), 'A', 'kg/kg/s', 'Melting of snow' ) - call addfld ('MNUDEPO', (/ 'trop_cld_lev' /), 'A', 'kg/kg/s', 'Deposition Nucleation' ) - call addfld ('HOMOO', (/ 'lev' /), 'A', 'kg/kg/s', 'Homogeneous freezing of cloud water' ) - call addfld ('QCRESO', (/ 'lev' /), 'A', 'kg/kg/s', 'Residual condensation term for cloud water' ) - call addfld ('PRCIO', (/ 'lev' /), 'A', 'kg/kg/s', 'Autoconversion of cloud ice to snow' ) - call addfld ('PRAIO', (/ 'lev' /), 'A', 'kg/kg/s', 'Accretion of cloud ice to snow' ) - call addfld ('QIRESO', (/ 'lev' /), 'A', 'kg/kg/s', 'Residual deposition term for cloud ice' ) - call addfld ('MNUCCRO', (/ 'trop_cld_lev' /), 'A', 'kg/kg/s', 'Heterogeneous freezing of rain to snow' ) - call addfld ('MNUCCRIO', (/ 'trop_cld_lev' /), 'A', 'kg/kg/s', 'Heterogeneous freezing of rain to ice' ) - call addfld ('PRACSO', (/ 'trop_cld_lev' /), 'A', 'kg/kg/s', 'Accretion of rain by snow' ) - call addfld ('VAPDEPSO', (/ 'trop_cld_lev' /), 'A', 'kg/kg/s', 'Vapor deposition onto snow' ) - call addfld ('MELTSDT', (/ 'trop_cld_lev' /), 'A', 'W/kg', 'Latent heating rate due to melting of snow' ) - call addfld ('FRZRDT', (/ 'trop_cld_lev' /), 'A', 'W/kg', 'Latent heating rate due to homogeneous freezing of rain' ) - call addfld ('QRSEDTEN', (/ 'trop_cld_lev' /), 'A', 'kg/kg/s', 'Rain mixing ratio tendency from sedimentation' ) - call addfld ('QSSEDTEN', (/ 'trop_cld_lev' /), 'A', 'kg/kg/s', 'Snow mixing ratio tendency from sedimentation' ) - call addfld ('NNUCCCO', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'Number Tendency due to Immersion freezing of cloud water') - call addfld ('NNUCCTO', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'Number Tendency due to Contact freezing of cloud water') - call addfld ('NNUCCDO', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'Number Tendency due to Ice nucleation') - call addfld ('NNUDEPO', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'Number Tendency due to Deposition Nucleation') - call addfld ('NHOMO', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'Number Tendency due to Homogeneous freezing of cloud water') - call addfld ('NNUCCRO', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'Number Tendency due to heterogeneous freezing of rain to snow') - call addfld ('NNUCCRIO', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'Number Tendency due to Heterogeneous freezing of rain to ice') - call addfld ('NSACWIO', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'Number Tendency due to Ice Multiplication- Rime-splintering') - call addfld ('NPRAO', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'Number Tendency due to Accretion of cloud water by rain') - call addfld ('NPSACWSO', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'Number Tendency due to Accretion of cloud water by snow') - call addfld ('NPRAIO', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'Number Tendency due to Accretion of cloud ice to snow') - call addfld ('NPRACSO', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'Number Tendency due to Accretion of rain by snow') - call addfld ('NPRCO', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'Number Tendency due to Autoconversion of cloud water [to rain]') - call addfld ('NPRCIO', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'Number Tendency due to Autoconversion of cloud ice to snow') - call addfld ('NCSEDTEN', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'Number Tendency due to cloud liquid sedimentation') - call addfld ('NISEDTEN', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'Number Tendency due to cloud ice sedimentation') - call addfld ('NRSEDTEN', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'Number Tendency due to rain sedimentation') - call addfld ('NSSEDTEN', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'Number Tendency due to snow sedimentation') - call addfld ('NMELTO', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'Number Tendency due to Melting of cloud ice ') - call addfld ('NMELTS', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'Number Tendency due to Melting of snow') + call addfld ('QCSEVAP', (/ 'trop_cld_lev' /), 'A', 'kg/kg/s', 'Rate of evaporation of falling cloud water', sampled_on_subcycle=.true.) + call addfld ('QISEVAP', (/ 'trop_cld_lev' /), 'A', 'kg/kg/s', 'Rate of sublimation of falling cloud ice', sampled_on_subcycle=.true.) + call addfld ('QVRES', (/ 'trop_cld_lev' /), 'A', 'kg/kg/s', 'Rate of residual condensation term', sampled_on_subcycle=.true.) + call addfld ('CMEIOUT', (/ 'trop_cld_lev' /), 'A', 'kg/kg/s', 'Rate of deposition/sublimation of cloud ice',sampled_on_subcycle=.true.) + call addfld ('VTRMC', (/ 'trop_cld_lev' /), 'A', 'm/s', 'Mass-weighted cloud water fallspeed', sampled_on_subcycle=.true.) + call addfld ('VTRMI', (/ 'trop_cld_lev' /), 'A', 'm/s', 'Mass-weighted cloud ice fallspeed', sampled_on_subcycle=.true.) + call addfld ('QCSEDTEN', (/ 'trop_cld_lev' /), 'A', 'kg/kg/s', 'Cloud water mixing ratio tendency from sedimentation', sampled_on_subcycle=.true.) + call addfld ('QISEDTEN', (/ 'trop_cld_lev' /), 'A', 'kg/kg/s', 'Cloud ice mixing ratio tendency from sedimentation', sampled_on_subcycle=.true.) + call addfld ('PRAO', (/ 'lev' /), 'A', 'kg/kg/s', 'Accretion of cloud water by rain', sampled_on_subcycle=.true.) + call addfld ('PRCO', (/ 'lev' /), 'A', 'kg/kg/s', 'Autoconversion of cloud water', sampled_on_subcycle=.true.) + call addfld ('MNUCCCO', (/ 'lev' /), 'A', 'kg/kg/s', 'Immersion freezing of cloud water', sampled_on_subcycle=.true.) + call addfld ('MNUCCTO', (/ 'lev' /), 'A', 'kg/kg/s', 'Contact freezing of cloud water', sampled_on_subcycle=.true.) + call addfld ('MNUCCDO', (/ 'trop_cld_lev' /), 'A', 'kg/kg/s', 'Homogeneous and heterogeneous nucleation from vapor', sampled_on_subcycle=.true.) + call addfld ('MNUCCDOhet', (/ 'lev' /), 'A', 'kg/kg/s', 'Heterogeneous nucleation from vapor', sampled_on_subcycle=.true.) + call addfld ('MSACWIO', (/ 'lev' /), 'A', 'kg/kg/s', 'Conversion of cloud water from rime-splintering', sampled_on_subcycle=.true.) + call addfld ('PSACWSO', (/ 'lev' /), 'A', 'kg/kg/s', 'Accretion of cloud water by snow', sampled_on_subcycle=.true.) + call addfld ('BERGSO', (/ 'lev' /), 'A', 'kg/kg/s', 'Conversion of cloud water to snow from bergeron', sampled_on_subcycle=.true.) + call addfld ('BERGO', (/ 'lev' /), 'A', 'kg/kg/s', 'Conversion of cloud water to cloud ice from bergeron',sampled_on_subcycle=.true.) + call addfld ('MELTO', (/ 'lev' /), 'A', 'kg/kg/s', 'Melting of cloud ice', sampled_on_subcycle=.true.) + call addfld ('MELTSTOT', (/ 'trop_cld_lev' /), 'A', 'kg/kg/s', 'Melting of snow', sampled_on_subcycle=.true.) + call addfld ('MNUDEPO', (/ 'trop_cld_lev' /), 'A', 'kg/kg/s', 'Deposition Nucleation', sampled_on_subcycle=.true.) + call addfld ('HOMOO', (/ 'lev' /), 'A', 'kg/kg/s', 'Homogeneous freezing of cloud water', sampled_on_subcycle=.true.) + call addfld ('QCRESO', (/ 'lev' /), 'A', 'kg/kg/s', 'Residual condensation term for cloud water', sampled_on_subcycle=.true.) + call addfld ('PRCIO', (/ 'lev' /), 'A', 'kg/kg/s', 'Autoconversion of cloud ice to snow', sampled_on_subcycle=.true.) + call addfld ('PRAIO', (/ 'lev' /), 'A', 'kg/kg/s', 'Accretion of cloud ice to snow', sampled_on_subcycle=.true.) + call addfld ('QIRESO', (/ 'lev' /), 'A', 'kg/kg/s', 'Residual deposition term for cloud ice', sampled_on_subcycle=.true.) + call addfld ('MNUCCRO', (/ 'trop_cld_lev' /), 'A', 'kg/kg/s', 'Heterogeneous freezing of rain to snow', sampled_on_subcycle=.true.) + call addfld ('MNUCCRIO', (/ 'trop_cld_lev' /), 'A', 'kg/kg/s', 'Heterogeneous freezing of rain to ice', sampled_on_subcycle=.true.) + call addfld ('PRACSO', (/ 'trop_cld_lev' /), 'A', 'kg/kg/s', 'Accretion of rain by snow', sampled_on_subcycle=.true.) + call addfld ('VAPDEPSO', (/ 'trop_cld_lev' /), 'A', 'kg/kg/s', 'Vapor deposition onto snow', sampled_on_subcycle=.true.) + call addfld ('MELTSDT', (/ 'trop_cld_lev' /), 'A', 'W/kg', 'Latent heating rate due to melting of snow', sampled_on_subcycle=.true.) + call addfld ('FRZRDT', (/ 'trop_cld_lev' /), 'A', 'W/kg', 'Latent heating rate due to homogeneous freezing of rain', sampled_on_subcycle=.true.) + call addfld ('QRSEDTEN', (/ 'trop_cld_lev' /), 'A', 'kg/kg/s', 'Rain mixing ratio tendency from sedimentation', sampled_on_subcycle=.true.) + call addfld ('QSSEDTEN', (/ 'trop_cld_lev' /), 'A', 'kg/kg/s', 'Snow mixing ratio tendency from sedimentation', sampled_on_subcycle=.true.) + call addfld ('NNUCCCO', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'Number Tendency due to Immersion freezing of cloud water', sampled_on_subcycle=.true.) + call addfld ('NNUCCTO', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'Number Tendency due to Contact freezing of cloud water', sampled_on_subcycle=.true.) + call addfld ('NNUCCDO', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'Number Tendency due to Ice nucleation', sampled_on_subcycle=.true.) + call addfld ('NNUDEPO', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'Number Tendency due to Deposition Nucleation', sampled_on_subcycle=.true.) + call addfld ('NHOMO', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'Number Tendency due to Homogeneous freezing of cloud water', sampled_on_subcycle=.true.) + call addfld ('NNUCCRO', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'Number Tendency due to heterogeneous freezing of rain to snow', sampled_on_subcycle=.true.) + call addfld ('NNUCCRIO', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'Number Tendency due to Heterogeneous freezing of rain to ice', sampled_on_subcycle=.true.) + call addfld ('NSACWIO', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'Number Tendency due to Ice Multiplication- Rime-splintering', sampled_on_subcycle=.true.) + call addfld ('NPRAO', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'Number Tendency due to Accretion of cloud water by rain', sampled_on_subcycle=.true.) + call addfld ('NPSACWSO', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'Number Tendency due to Accretion of cloud water by snow', sampled_on_subcycle=.true.) + call addfld ('NPRAIO', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'Number Tendency due to Accretion of cloud ice to snow', sampled_on_subcycle=.true.) + call addfld ('NPRACSO', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'Number Tendency due to Accretion of rain by snow', sampled_on_subcycle=.true.) + call addfld ('NPRCO', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'Number Tendency due to Autoconversion of cloud water [to rain]', sampled_on_subcycle=.true.) + call addfld ('NPRCIO', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'Number Tendency due to Autoconversion of cloud ice to snow', sampled_on_subcycle=.true.) + call addfld ('NCSEDTEN', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'Number Tendency due to cloud liquid sedimentation', sampled_on_subcycle=.true.) + call addfld ('NISEDTEN', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'Number Tendency due to cloud ice sedimentation', sampled_on_subcycle=.true.) + call addfld ('NRSEDTEN', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'Number Tendency due to rain sedimentation', sampled_on_subcycle=.true.) + call addfld ('NSSEDTEN', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'Number Tendency due to snow sedimentation', sampled_on_subcycle=.true.) + call addfld ('NMELTO', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'Number Tendency due to Melting of cloud ice', sampled_on_subcycle=.true.) + call addfld ('NMELTS', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'Number Tendency due to Melting of snow', sampled_on_subcycle=.true.) if (trim(micro_mg_warm_rain) == 'kk2000') then - call addfld ('qctend_KK2000', (/ 'trop_cld_lev' /), 'A', 'kg/kg/s', 'cloud liquid mass tendency due to autoconversion & accretion from KK2000') - call addfld ('nctend_KK2000', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'cloud number mass tendency due to autoconversion & accretion from KK2000') - call addfld ('qrtend_KK2000', (/ 'trop_cld_lev' /), 'A', 'kg/kg/s', 'rain mass tendency due to autoconversion & accretion from KK2000') - call addfld ('nrtend_KK2000', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'rain number tendency due to autoconversion & accretion from KK2000') + call addfld ('qctend_KK2000', (/ 'trop_cld_lev' /), 'A', 'kg/kg/s', 'cloud liquid mass tendency due to autoconversion & accretion from KK2000', sampled_on_subcycle=.true.) + call addfld ('nctend_KK2000', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'cloud number mass tendency due to autoconversion & accretion from KK2000', sampled_on_subcycle=.true.) + call addfld ('qrtend_KK2000', (/ 'trop_cld_lev' /), 'A', 'kg/kg/s', 'rain mass tendency due to autoconversion & accretion from KK2000', sampled_on_subcycle=.true.) + call addfld ('nrtend_KK2000', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'rain number tendency due to autoconversion & accretion from KK2000', sampled_on_subcycle=.true.) end if if (trim(micro_mg_warm_rain) == 'sb2001') then - call addfld ('qctend_SB2001', (/ 'trop_cld_lev' /), 'A', 'kg/kg/s', 'cloud liquid mass tendency due to autoconversion & accretion from SB2001') - call addfld ('nctend_SB2001', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'cloud liquid number tendency due to autoconversion & accretion from SB2001') - call addfld ('qrtend_SB2001', (/ 'trop_cld_lev' /), 'A', 'kg/kg/s', 'rain mass tendency due to autoconversion & accretion from SB2001') - call addfld ('nrtend_SB2001', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'rain number tendency due to autoconversion & accretion from SB2001') + call addfld ('qctend_SB2001', (/ 'trop_cld_lev' /), 'A', 'kg/kg/s', 'cloud liquid mass tendency due to autoconversion & accretion from SB2001', sampled_on_subcycle=.true.) + call addfld ('nctend_SB2001', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'cloud liquid number tendency due to autoconversion & accretion from SB2001',sampled_on_subcycle=.true.) + call addfld ('qrtend_SB2001', (/ 'trop_cld_lev' /), 'A', 'kg/kg/s', 'rain mass tendency due to autoconversion & accretion from SB2001', sampled_on_subcycle=.true.) + call addfld ('nrtend_SB2001', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'rain number tendency due to autoconversion & accretion from SB2001', sampled_on_subcycle=.true.) end if - call addfld ('LAMC', (/ 'trop_cld_lev' /), 'A', 'unitless', 'Size distribution parameter lambda for liquid' ) - call addfld ('LAMR', (/ 'trop_cld_lev' /), 'A', 'unitless', 'Size distribution parameter lambda for rain' ) - call addfld ('PGAM', (/ 'trop_cld_lev' /), 'A', 'unitless', 'Size distribution parameter mu (pgam) for liquid' ) - call addfld ('N0R', (/ 'trop_cld_lev' /), 'A', 'unitless', 'Size distribution parameter n0 for rain' ) + call addfld ('LAMC', (/ 'trop_cld_lev' /), 'A', 'unitless', 'Size distribution parameter lambda for liquid', sampled_on_subcycle=.true. ) + call addfld ('LAMR', (/ 'trop_cld_lev' /), 'A', 'unitless', 'Size distribution parameter lambda for rain', sampled_on_subcycle=.true.) + call addfld ('PGAM', (/ 'trop_cld_lev' /), 'A', 'unitless', 'Size distribution parameter mu (pgam) for liquid', sampled_on_subcycle=.true.) + call addfld ('N0R', (/ 'trop_cld_lev' /), 'A', 'unitless', 'Size distribution parameter n0 for rain', sampled_on_subcycle=.true.) if (micro_mg_version > 2) then - call addfld ('NMELTG', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'Number Tendency due to Melting of graupel') - call addfld ('NGSEDTEN', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'Number Tendency due to graupel sedimentation') - call addfld ('PSACRO', (/ 'lev' /), 'A', 'kg/kg/s', 'Collisions between rain & snow (Graupel collecting snow)') - call addfld ('PRACGO', (/ 'lev' /), 'A', 'kg/kg/s', 'Change in q collection rain by graupel' ) - call addfld ('PSACWGO', (/ 'lev' /), 'A', 'kg/kg/s', 'Change in q collection droplets by graupel' ) - call addfld ('PGSACWO', (/ 'lev' /), 'A', 'kg/kg/s', 'Q conversion to graupel due to collection droplets by snow') - call addfld ('PGRACSO', (/ 'lev' /), 'A', 'kg/kg/s', 'Q conversion to graupel due to collection rain by snow') - call addfld ('PRDGO', (/ 'lev' /), 'A', 'kg/kg/s', 'Deposition of graupel') - call addfld ('QMULTGO', (/ 'lev' /), 'A', 'kg/kg/s', 'Q change due to ice mult droplets/graupel') - call addfld ('QMULTRGO', (/ 'lev' /), 'A', 'kg/kg/s', 'Q change due to ice mult rain/graupel') - call addfld ('QGSEDTEN', (/ 'trop_cld_lev' /), 'A', 'kg/kg/s', 'Graupel/Hail mixing ratio tendency from sedimentation') - call addfld ('NPRACGO', (/ 'lev' /), 'A', '#/kg/s', 'Change N collection rain by graupel') - call addfld ('NSCNGO', (/ 'lev' /), 'A', '#/kg/s', 'Change N conversion to graupel due to collection droplets by snow') - call addfld ('NGRACSO', (/ 'lev' /), 'A', '#/kg/s', 'Change N conversion to graupel due to collection rain by snow') - call addfld ('NMULTGO', (/ 'lev' /), 'A', '#/kg/s', 'Ice mult due to acc droplets by graupel ') - call addfld ('NMULTRGO', (/ 'lev' /), 'A', '#/kg/s', 'Ice mult due to acc rain by graupel') - call addfld ('NPSACWGO', (/ 'lev' /), 'A', '#/kg/s', 'Change N collection droplets by graupel') - call addfld ('CLDFGRAU', (/ 'lev' /), 'A', '1', 'Cloud fraction adjusted for graupel' ) - call addfld ('MELTGTOT', (/ 'trop_cld_lev' /), 'A', 'kg/kg/s', 'Melting of graupel' ) + call addfld ('NMELTG', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'Number Tendency due to Melting of graupel', sampled_on_subcycle=.true.) + call addfld ('NGSEDTEN', (/ 'trop_cld_lev' /), 'A', '#/kg/s', 'Number Tendency due to graupel sedimentation', sampled_on_subcycle=.true.) + call addfld ('PSACRO', (/ 'lev' /), 'A', 'kg/kg/s', 'Collisions between rain & snow (Graupel collecting snow)',sampled_on_subcycle=.true.) + call addfld ('PRACGO', (/ 'lev' /), 'A', 'kg/kg/s', 'Change in q collection rain by graupel', sampled_on_subcycle=.true.) + call addfld ('PSACWGO', (/ 'lev' /), 'A', 'kg/kg/s', 'Change in q collection droplets by graupel', sampled_on_subcycle=.true.) + call addfld ('PGSACWO', (/ 'lev' /), 'A', 'kg/kg/s', 'Q conversion to graupel due to collection droplets by snow', sampled_on_subcycle=.true.) + call addfld ('PGRACSO', (/ 'lev' /), 'A', 'kg/kg/s', 'Q conversion to graupel due to collection rain by snow', sampled_on_subcycle=.true.) + call addfld ('PRDGO', (/ 'lev' /), 'A', 'kg/kg/s', 'Deposition of graupel', sampled_on_subcycle=.true.) + call addfld ('QMULTGO', (/ 'lev' /), 'A', 'kg/kg/s', 'Q change due to ice mult droplets/graupel', sampled_on_subcycle=.true.) + call addfld ('QMULTRGO', (/ 'lev' /), 'A', 'kg/kg/s', 'Q change due to ice mult rain/graupel', sampled_on_subcycle=.true.) + call addfld ('QGSEDTEN', (/ 'trop_cld_lev' /), 'A', 'kg/kg/s', 'Graupel/Hail mixing ratio tendency from sedimentation', sampled_on_subcycle=.true.) + call addfld ('NPRACGO', (/ 'lev' /), 'A', '#/kg/s', 'Change N collection rain by graupel', sampled_on_subcycle=.true.) + call addfld ('NSCNGO', (/ 'lev' /), 'A', '#/kg/s', 'Change N conversion to graupel due to collection droplets by snow', sampled_on_subcycle=.true.) + call addfld ('NGRACSO', (/ 'lev' /), 'A', '#/kg/s', 'Change N conversion to graupel due to collection rain by snow', sampled_on_subcycle=.true.) + call addfld ('NMULTGO', (/ 'lev' /), 'A', '#/kg/s', 'Ice mult due to acc droplets by graupel', sampled_on_subcycle=.true.) + call addfld ('NMULTRGO', (/ 'lev' /), 'A', '#/kg/s', 'Ice mult due to acc rain by graupel', sampled_on_subcycle=.true.) + call addfld ('NPSACWGO', (/ 'lev' /), 'A', '#/kg/s', 'Change N collection droplets by graupel', sampled_on_subcycle=.true.) + call addfld ('CLDFGRAU', (/ 'lev' /), 'A', '1', 'Cloud fraction adjusted for graupel', sampled_on_subcycle=.true.) + call addfld ('MELTGTOT', (/ 'trop_cld_lev' /), 'A', 'kg/kg/s', 'Melting of graupel', sampled_on_subcycle=.true.) end if - call addfld ('RBFRAC', horiz_only, 'A', 'Fraction', 'Fraction of sky covered by a potential rainbow' ) - call addfld ('RBFREQ', horiz_only, 'A', 'Frequency', 'Potential rainbow frequency' ) - call addfld( 'rbSZA', horiz_only, 'I', 'degrees', 'solar zenith angle' ) + call addfld ('RBFRAC', horiz_only, 'A', 'Fraction', 'Fraction of sky covered by a potential rainbow', sampled_on_subcycle=.true.) + call addfld ('RBFREQ', horiz_only, 'A', 'Frequency', 'Potential rainbow frequency', sampled_on_subcycle=.true.) + call addfld( 'rbSZA', horiz_only, 'I', 'degrees', 'solar zenith angle', sampled_on_subcycle=.true.) ! History variables for CAM5 microphysics - call addfld ('MPDT', (/ 'lev' /), 'A', 'W/kg', 'Heating tendency - Morrison microphysics' ) - call addfld ('MPDQ', (/ 'lev' /), 'A', 'kg/kg/s', 'Q tendency - Morrison microphysics' ) - call addfld ('MPDLIQ', (/ 'lev' /), 'A', 'kg/kg/s', 'CLDLIQ tendency - Morrison microphysics' ) - call addfld ('MPDICE', (/ 'lev' /), 'A', 'kg/kg/s', 'CLDICE tendency - Morrison microphysics' ) - call addfld ('MPDNLIQ', (/ 'lev' /), 'A', '1/kg/s', 'NUMLIQ tendency - Morrison microphysics' ) - call addfld ('MPDNICE', (/ 'lev' /), 'A', '1/kg/s', 'NUMICE tendency - Morrison microphysics' ) - call addfld ('MPDW2V', (/ 'lev' /), 'A', 'kg/kg/s', 'Water <--> Vapor tendency - Morrison microphysics' ) - call addfld ('MPDW2I', (/ 'lev' /), 'A', 'kg/kg/s', 'Water <--> Ice tendency - Morrison microphysics' ) - call addfld ('MPDW2P', (/ 'lev' /), 'A', 'kg/kg/s', 'Water <--> Precip tendency - Morrison microphysics' ) - call addfld ('MPDI2V', (/ 'lev' /), 'A', 'kg/kg/s', 'Ice <--> Vapor tendency - Morrison microphysics' ) - call addfld ('MPDI2W', (/ 'lev' /), 'A', 'kg/kg/s', 'Ice <--> Water tendency - Morrison microphysics' ) - call addfld ('MPDI2P', (/ 'lev' /), 'A', 'kg/kg/s', 'Ice <--> Precip tendency - Morrison microphysics' ) - call addfld ('ICWNC', (/ 'lev' /), 'A', 'm-3', 'Prognostic in-cloud water number conc' ) - call addfld ('ICINC', (/ 'lev' /), 'A', 'm-3', 'Prognostic in-cloud ice number conc' ) - call addfld ('EFFLIQ_IND', (/ 'lev' /), 'A','Micron', 'Prognostic droplet effective radius (indirect effect)' ) - call addfld ('CDNUMC', horiz_only, 'A', '1/m2', 'Vertically-integrated droplet concentration' ) + call addfld ('MPDT', (/ 'lev' /), 'A', 'W/kg', 'Heating tendency - Morrison microphysics', sampled_on_subcycle=.true.) + call addfld ('MPDQ', (/ 'lev' /), 'A', 'kg/kg/s', 'Q tendency - Morrison microphysics', sampled_on_subcycle=.true.) + call addfld ('MPDLIQ', (/ 'lev' /), 'A', 'kg/kg/s', 'CLDLIQ tendency - Morrison microphysics', sampled_on_subcycle=.true.) + call addfld ('MPDICE', (/ 'lev' /), 'A', 'kg/kg/s', 'CLDICE tendency - Morrison microphysics', sampled_on_subcycle=.true.) + call addfld ('MPDNLIQ', (/ 'lev' /), 'A', '1/kg/s', 'NUMLIQ tendency - Morrison microphysics', sampled_on_subcycle=.true.) + call addfld ('MPDNICE', (/ 'lev' /), 'A', '1/kg/s', 'NUMICE tendency - Morrison microphysics', sampled_on_subcycle=.true.) + call addfld ('MPDW2V', (/ 'lev' /), 'A', 'kg/kg/s', 'Water <--> Vapor tendency - Morrison microphysics', sampled_on_subcycle=.true.) + call addfld ('MPDW2I', (/ 'lev' /), 'A', 'kg/kg/s', 'Water <--> Ice tendency - Morrison microphysics', sampled_on_subcycle=.true.) + call addfld ('MPDW2P', (/ 'lev' /), 'A', 'kg/kg/s', 'Water <--> Precip tendency - Morrison microphysics',sampled_on_subcycle=.true.) + call addfld ('MPDI2V', (/ 'lev' /), 'A', 'kg/kg/s', 'Ice <--> Vapor tendency - Morrison microphysics', sampled_on_subcycle=.true.) + call addfld ('MPDI2W', (/ 'lev' /), 'A', 'kg/kg/s', 'Ice <--> Water tendency - Morrison microphysics', sampled_on_subcycle=.true.) + call addfld ('MPDI2P', (/ 'lev' /), 'A', 'kg/kg/s', 'Ice <--> Precip tendency - Morrison microphysics', sampled_on_subcycle=.true.) + call addfld ('ICWNC', (/ 'lev' /), 'A', 'm-3', 'Prognostic in-cloud water number conc', sampled_on_subcycle=.true.) + call addfld ('ICINC', (/ 'lev' /), 'A', 'm-3', 'Prognostic in-cloud ice number conc', sampled_on_subcycle=.true.) + call addfld ('EFFLIQ_IND', (/ 'lev' /), 'A','Micron', 'Prognostic droplet effective radius (indirect effect)', sampled_on_subcycle=.true.) + call addfld ('CDNUMC', horiz_only, 'A', '1/m2', 'Vertically-integrated droplet concentration', sampled_on_subcycle=.true.) call addfld ('MPICLWPI', horiz_only, 'A', 'kg/m2', 'Vertically-integrated & - &in-cloud Initial Liquid WP (Before Micro)' ) + &in-cloud Initial Liquid WP (Before Micro)', sampled_on_subcycle=.true.) call addfld ('MPICIWPI', horiz_only, 'A', 'kg/m2', 'Vertically-integrated & - &in-cloud Initial Ice WP (Before Micro)' ) + &in-cloud Initial Ice WP (Before Micro)', sampled_on_subcycle=.true.) ! This is provided as an example on how to write out subcolumn output ! NOTE -- only 'I' should be used for sub-column fields as subc-columns could shift from time-step to time-step if (use_subcol_microp) then call addfld('FICE_SCOL', (/'psubcols','lev '/), 'I', 'fraction', & - 'Sub-column fractional ice content within cloud', flag_xyfill=.true., fill_value=1.e30_r8) + 'Sub-column fractional ice content within cloud', flag_xyfill=.true., fill_value=1.e30_r8, sampled_on_subcycle=.true.) call addfld('MPDICE_SCOL', (/'psubcols','lev '/), 'I', 'kg/kg/s', & - 'Sub-column CLDICE tendency - Morrison microphysics', flag_xyfill=.true., fill_value=1.e30_r8) + 'Sub-column CLDICE tendency - Morrison microphysics', flag_xyfill=.true., fill_value=1.e30_r8, sampled_on_subcycle=.true.) call addfld('MPDLIQ_SCOL', (/'psubcols','lev '/), 'I', 'kg/kg/s', & - 'Sub-column CLDLIQ tendency - Morrison microphysics', flag_xyfill=.true., fill_value=1.e30_r8) + 'Sub-column CLDLIQ tendency - Morrison microphysics', flag_xyfill=.true., fill_value=1.e30_r8, sampled_on_subcycle=.true.) end if ! This is only if the coldpoint temperatures are being adjusted. ! NOTE: Some fields related to these and output later are added in tropopause.F90. if (micro_mg_adjust_cpt) then - call addfld ('TROPF_TADJ', (/ 'lev' /), 'A', 'K', 'Temperatures after cold point adjustment' ) - call addfld ('TROPF_RHADJ', (/ 'lev' /), 'A', 'K', 'Relative Hunidity after cold point adjustment' ) - call addfld ('TROPF_CDT', horiz_only, 'A', 'K', 'Cold point temperature adjustment' ) - call addfld ('TROPF_CDZ', horiz_only, 'A', 'm', 'Distance of coldpoint from coldest model level' ) + call addfld ('TROPF_TADJ', (/ 'lev' /), 'A', 'K', 'Temperatures after cold point adjustment', sampled_on_subcycle=.true.) + call addfld ('TROPF_RHADJ', (/ 'lev' /), 'A', 'K', 'Relative Hunidity after cold point adjustment', sampled_on_subcycle=.true.) + call addfld ('TROPF_CDT', horiz_only, 'A', 'K', 'Cold point temperature adjustment', sampled_on_subcycle=.true.) + call addfld ('TROPF_CDZ', horiz_only, 'A', 'm', 'Distance of coldpoint from coldest model level',sampled_on_subcycle=.true.) end if ! Averaging for cloud particle number and size - call addfld ('AWNC', (/ 'lev' /), 'A', 'm-3', 'Average cloud water number conc' ) - call addfld ('AWNI', (/ 'lev' /), 'A', 'm-3', 'Average cloud ice number conc' ) - call addfld ('AREL', (/ 'lev' /), 'A', 'Micron', 'Average droplet effective radius' ) - call addfld ('AREI', (/ 'lev' /), 'A', 'Micron', 'Average ice effective radius' ) + call addfld ('AWNC', (/ 'lev' /), 'A', 'm-3', 'Average cloud water number conc', sampled_on_subcycle=.true.) + call addfld ('AWNI', (/ 'lev' /), 'A', 'm-3', 'Average cloud ice number conc', sampled_on_subcycle=.true.) + call addfld ('AREL', (/ 'lev' /), 'A', 'Micron', 'Average droplet effective radius', sampled_on_subcycle=.true.) + call addfld ('AREI', (/ 'lev' /), 'A', 'Micron', 'Average ice effective radius', sampled_on_subcycle=.true.) ! Frequency arrays for above - call addfld ('FREQL', (/ 'lev' /), 'A', 'fraction', 'Fractional occurrence of liquid' ) - call addfld ('FREQI', (/ 'lev' /), 'A', 'fraction', 'Fractional occurrence of ice' ) + call addfld ('FREQL', (/ 'lev' /), 'A', 'fraction', 'Fractional occurrence of liquid', sampled_on_subcycle=.true.) + call addfld ('FREQI', (/ 'lev' /), 'A', 'fraction', 'Fractional occurrence of ice', sampled_on_subcycle=.true.) ! Average cloud top particle size and number (liq, ice) and frequency - call addfld ('ACTREL', horiz_only, 'A', 'Micron', 'Average Cloud Top droplet effective radius' ) - call addfld ('ACTREI', horiz_only, 'A', 'Micron', 'Average Cloud Top ice effective radius' ) - call addfld ('ACTNL', horiz_only, 'A', 'm-3', 'Average Cloud Top droplet number' ) - call addfld ('ACTNI', horiz_only, 'A', 'm-3', 'Average Cloud Top ice number' ) + call addfld ('ACTREL', horiz_only, 'A', 'Micron', 'Average Cloud Top droplet effective radius', sampled_on_subcycle=.true.) + call addfld ('ACTREI', horiz_only, 'A', 'Micron', 'Average Cloud Top ice effective radius', sampled_on_subcycle=.true.) + call addfld ('ACTNL', horiz_only, 'A', 'm-3', 'Average Cloud Top droplet number', sampled_on_subcycle=.true.) + call addfld ('ACTNI', horiz_only, 'A', 'm-3', 'Average Cloud Top ice number', sampled_on_subcycle=.true.) - call addfld ('FCTL', horiz_only, 'A', 'fraction', 'Fractional occurrence of cloud top liquid' ) - call addfld ('FCTI', horiz_only, 'A', 'fraction', 'Fractional occurrence of cloud top ice' ) + call addfld ('FCTL', horiz_only, 'A', 'fraction', 'Fractional occurrence of cloud top liquid', sampled_on_subcycle=.true.) + call addfld ('FCTI', horiz_only, 'A', 'fraction', 'Fractional occurrence of cloud top ice', sampled_on_subcycle=.true.) ! New frequency arrays for mixed phase and supercooled liquid (only and mixed) for (a) Cloud Top and (b) everywhere.. - call addfld ('FREQM', (/ 'lev' /), 'A', 'fraction', 'Fractional occurrence of mixed phase' ) - call addfld ('FREQSL', (/ 'lev' /), 'A', 'fraction', 'Fractional occurrence of only supercooled liquid' ) - call addfld ('FREQSLM', (/ 'lev' /), 'A', 'fraction', 'Fractional occurrence of super cooled liquid with ice' ) - call addfld ('FCTM', horiz_only, 'A', 'fraction', 'Fractional occurrence of cloud top mixed phase' ) - call addfld ('FCTSL', horiz_only, 'A', 'fraction', 'Fractional occurrence of cloud top only supercooled liquid' ) - call addfld ('FCTSLM', horiz_only, 'A', 'fraction', 'Fractional occurrence of cloud top super cooled liquid with ice' ) - - call addfld ('LS_FLXPRC', (/ 'ilev' /), 'A', 'kg/m2/s', 'ls stratiform gbm interface rain+snow flux' ) - call addfld ('LS_FLXSNW', (/ 'ilev' /), 'A', 'kg/m2/s', 'ls stratiform gbm interface snow flux' ) - - call addfld ('REL', (/ 'lev' /), 'A', 'micron', 'MG REL stratiform cloud effective radius liquid' ) - call addfld ('REI', (/ 'lev' /), 'A', 'micron', 'MG REI stratiform cloud effective radius ice' ) - call addfld ('LS_REFFRAIN', (/ 'lev' /), 'A', 'micron', 'ls stratiform rain effective radius' ) - call addfld ('LS_REFFSNOW', (/ 'lev' /), 'A', 'micron', 'ls stratiform snow effective radius' ) - call addfld ('CV_REFFLIQ', (/ 'lev' /), 'A', 'micron', 'convective cloud liq effective radius' ) - call addfld ('CV_REFFICE', (/ 'lev' /), 'A', 'micron', 'convective cloud ice effective radius' ) - call addfld ('MG_SADICE', (/ 'lev' /), 'A', 'cm2/cm3', 'MG surface area density ice' ) - call addfld ('MG_SADSNOW', (/ 'lev' /), 'A', 'cm2/cm3', 'MG surface area density snow' ) + call addfld ('FREQM', (/ 'lev' /), 'A', 'fraction', 'Fractional occurrence of mixed phase', sampled_on_subcycle=.true.) + call addfld ('FREQSL', (/ 'lev' /), 'A', 'fraction', 'Fractional occurrence of only supercooled liquid', sampled_on_subcycle=.true.) + call addfld ('FREQSLM', (/ 'lev' /), 'A', 'fraction', 'Fractional occurrence of super cooled liquid with ice', sampled_on_subcycle=.true.) + call addfld ('FCTM', horiz_only, 'A', 'fraction', 'Fractional occurrence of cloud top mixed phase', sampled_on_subcycle=.true.) + call addfld ('FCTSL', horiz_only, 'A', 'fraction', 'Fractional occurrence of cloud top only supercooled liquid', sampled_on_subcycle=.true.) + call addfld ('FCTSLM', horiz_only, 'A', 'fraction', 'Fractional occurrence of cloud top super cooled liquid with ice', sampled_on_subcycle=.true.) + + call addfld ('LS_FLXPRC', (/ 'ilev' /), 'A', 'kg/m2/s', 'ls stratiform gbm interface rain+snow flux', sampled_on_subcycle=.true.) + call addfld ('LS_FLXSNW', (/ 'ilev' /), 'A', 'kg/m2/s', 'ls stratiform gbm interface snow flux', sampled_on_subcycle=.true.) + + call addfld ('REL', (/ 'lev' /), 'A', 'micron', 'MG REL stratiform cloud effective radius liquid', sampled_on_subcycle=.true.) + call addfld ('REI', (/ 'lev' /), 'A', 'micron', 'MG REI stratiform cloud effective radius ice', sampled_on_subcycle=.true.) + call addfld ('LS_REFFRAIN', (/ 'lev' /), 'A', 'micron', 'ls stratiform rain effective radius', sampled_on_subcycle=.true.) + call addfld ('LS_REFFSNOW', (/ 'lev' /), 'A', 'micron', 'ls stratiform snow effective radius', sampled_on_subcycle=.true.) + call addfld ('CV_REFFLIQ', (/ 'lev' /), 'A', 'micron', 'convective cloud liq effective radius', sampled_on_subcycle=.true.) + call addfld ('CV_REFFICE', (/ 'lev' /), 'A', 'micron', 'convective cloud ice effective radius', sampled_on_subcycle=.true.) + call addfld ('MG_SADICE', (/ 'lev' /), 'A', 'cm2/cm3', 'MG surface area density ice', sampled_on_subcycle=.true.) + call addfld ('MG_SADSNOW', (/ 'lev' /), 'A', 'cm2/cm3', 'MG surface area density snow', sampled_on_subcycle=.true.) ! diagnostic precip - call addfld ('QRAIN', (/ 'lev' /), 'A', 'kg/kg', 'Diagnostic grid-mean rain mixing ratio' ) - call addfld ('QSNOW', (/ 'lev' /), 'A', 'kg/kg', 'Diagnostic grid-mean snow mixing ratio' ) - call addfld ('NRAIN', (/ 'lev' /), 'A', 'm-3', 'Diagnostic grid-mean rain number conc' ) - call addfld ('NSNOW', (/ 'lev' /), 'A', 'm-3', 'Diagnostic grid-mean snow number conc' ) + call addfld ('QRAIN', (/ 'lev' /), 'A', 'kg/kg', 'Diagnostic grid-mean rain mixing ratio', sampled_on_subcycle=.true.) + call addfld ('QSNOW', (/ 'lev' /), 'A', 'kg/kg', 'Diagnostic grid-mean snow mixing ratio', sampled_on_subcycle=.true.) + call addfld ('NRAIN', (/ 'lev' /), 'A', 'm-3', 'Diagnostic grid-mean rain number conc', sampled_on_subcycle=.true.) + call addfld ('NSNOW', (/ 'lev' /), 'A', 'm-3', 'Diagnostic grid-mean snow number conc', sampled_on_subcycle=.true.) ! size of precip - call addfld ('RERCLD', (/ 'lev' /), 'A', 'm', 'Diagnostic effective radius of Liquid Cloud and Rain' ) - call addfld ('DSNOW', (/ 'lev' /), 'A', 'm', 'Diagnostic grid-mean snow diameter' ) + call addfld ('RERCLD', (/ 'lev' /), 'A', 'm', 'Diagnostic effective radius of Liquid Cloud and Rain', sampled_on_subcycle=.true.) + call addfld ('DSNOW', (/ 'lev' /), 'A', 'm', 'Diagnostic grid-mean snow diameter', sampled_on_subcycle=.true.) ! diagnostic radar reflectivity, cloud-averaged - call addfld ('REFL', (/ 'lev' /), 'A', 'DBz', '94 GHz radar reflectivity' ) - call addfld ('AREFL', (/ 'lev' /), 'A', 'DBz', 'Average 94 GHz radar reflectivity' ) - call addfld ('FREFL', (/ 'lev' /), 'A', 'fraction', 'Fractional occurrence of radar reflectivity' ) + call addfld ('REFL', (/ 'lev' /), 'A', 'DBz', '94 GHz radar reflectivity', sampled_on_subcycle=.true.) + call addfld ('AREFL', (/ 'lev' /), 'A', 'DBz', 'Average 94 GHz radar reflectivity', sampled_on_subcycle=.true.) + call addfld ('FREFL', (/ 'lev' /), 'A', 'fraction', 'Fractional occurrence of radar reflectivity', sampled_on_subcycle=.true.) - call addfld ('CSRFL', (/ 'lev' /), 'A', 'DBz', '94 GHz radar reflectivity (CloudSat thresholds)' ) - call addfld ('ACSRFL', (/ 'lev' /), 'A', 'DBz', 'Average 94 GHz radar reflectivity (CloudSat thresholds)' ) - call addfld ('FCSRFL', (/ 'lev' /), 'A', 'fraction', 'Fractional occurrence of radar reflectivity (CloudSat thresholds)' ) + call addfld ('CSRFL', (/ 'lev' /), 'A', 'DBz', '94 GHz radar reflectivity (CloudSat thresholds)', sampled_on_subcycle=.true.) + call addfld ('ACSRFL', (/ 'lev' /), 'A', 'DBz', 'Average 94 GHz radar reflectivity (CloudSat thresholds)', sampled_on_subcycle=.true.) + call addfld ('FCSRFL', (/ 'lev' /), 'A', 'fraction', 'Fractional occurrence of radar reflectivity (CloudSat thresholds)', sampled_on_subcycle=.true.) - call addfld ('AREFLZ', (/ 'lev' /), 'A', 'mm^6/m^3', 'Average 94 GHz radar reflectivity' ) + call addfld ('AREFLZ', (/ 'lev' /), 'A', 'mm^6/m^3', 'Average 94 GHz radar reflectivity', sampled_on_subcycle=.true.) ! 10cm (rain) radar reflectivity - call addfld ('REFL10CM', (/ 'lev' /), 'A', 'DBz', '10cm (Rain) radar reflectivity (Dbz)' ) - call addfld ('REFLZ10CM', (/ 'lev' /), 'A', 'mm^6/m^3', '10cm (Rain) radar reflectivity (Z units)' ) + call addfld ('REFL10CM', (/ 'lev' /), 'A', 'DBz', '10cm (Rain) radar reflectivity (Dbz)', sampled_on_subcycle=.true.) + call addfld ('REFLZ10CM', (/ 'lev' /), 'A', 'mm^6/m^3', '10cm (Rain) radar reflectivity (Z units)', sampled_on_subcycle=.true.) ! Aerosol information - call addfld ('NCAL', (/ 'lev' /), 'A', '1/m3', 'Number Concentation Activated for Liquid' ) - call addfld ('NCAI', (/ 'lev' /), 'A', '1/m3', 'Number Concentation Activated for Ice' ) + call addfld ('NCAL', (/ 'lev' /), 'A', '1/m3', 'Number Concentation Activated for Liquid', sampled_on_subcycle=.true.) + call addfld ('NCAI', (/ 'lev' /), 'A', '1/m3', 'Number Concentation Activated for Ice', sampled_on_subcycle=.true.) ! Average rain and snow mixing ratio (Q), number (N) and diameter (D), with frequency - call addfld ('AQRAIN', (/ 'lev' /), 'A', 'kg/kg', 'Average rain mixing ratio' ) - call addfld ('AQSNOW', (/ 'lev' /), 'A', 'kg/kg', 'Average snow mixing ratio' ) - call addfld ('ANRAIN', (/ 'lev' /), 'A', 'm-3', 'Average rain number conc' ) - call addfld ('ANSNOW', (/ 'lev' /), 'A', 'm-3', 'Average snow number conc' ) - call addfld ('ADRAIN', (/ 'lev' /), 'A', 'm', 'Average rain effective Diameter' ) - call addfld ('ADSNOW', (/ 'lev' /), 'A', 'm', 'Average snow effective Diameter' ) - call addfld ('FREQR', (/ 'lev' /), 'A', 'fraction', 'Fractional occurrence of rain' ) - call addfld ('FREQS', (/ 'lev' /), 'A', 'fraction', 'Fractional occurrence of snow' ) + call addfld ('AQRAIN', (/ 'lev' /), 'A', 'kg/kg', 'Average rain mixing ratio', sampled_on_subcycle=.true.) + call addfld ('AQSNOW', (/ 'lev' /), 'A', 'kg/kg', 'Average snow mixing ratio', sampled_on_subcycle=.true.) + call addfld ('ANRAIN', (/ 'lev' /), 'A', 'm-3', 'Average rain number conc', sampled_on_subcycle=.true.) + call addfld ('ANSNOW', (/ 'lev' /), 'A', 'm-3', 'Average snow number conc', sampled_on_subcycle=.true.) + call addfld ('ADRAIN', (/ 'lev' /), 'A', 'm', 'Average rain effective Diameter', sampled_on_subcycle=.true.) + call addfld ('ADSNOW', (/ 'lev' /), 'A', 'm', 'Average snow effective Diameter', sampled_on_subcycle=.true.) + call addfld ('FREQR', (/ 'lev' /), 'A', 'fraction', 'Fractional occurrence of rain', sampled_on_subcycle=.true.) + call addfld ('FREQS', (/ 'lev' /), 'A', 'fraction', 'Fractional occurrence of snow', sampled_on_subcycle=.true.) ! precipitation efficiency & other diagnostic fields - call addfld('PE' , horiz_only, 'A', '1', 'Stratiform Precipitation Efficiency (precip/cmeliq)' ) - call addfld('APRL' , horiz_only, 'A', 'm/s', 'Average Stratiform Precip Rate over efficiency calculation' ) - call addfld('PEFRAC', horiz_only, 'A', '1', 'Fraction of timesteps precip efficiency reported' ) - call addfld('VPRCO' , horiz_only, 'A', 'kg/kg/s', 'Vertical average of autoconversion rate' ) - call addfld('VPRAO' , horiz_only, 'A', 'kg/kg/s', 'Vertical average of accretion rate' ) - call addfld('RACAU' , horiz_only, 'A', 'kg/kg/s', 'Accretion/autoconversion ratio from vertical average' ) + call addfld('PE' , horiz_only, 'A', '1', 'Stratiform Precipitation Efficiency (precip/cmeliq)', sampled_on_subcycle=.true.) + call addfld('APRL' , horiz_only, 'A', 'm/s', 'Average Stratiform Precip Rate over efficiency calculation', sampled_on_subcycle=.true.) + call addfld('PEFRAC', horiz_only, 'A', '1', 'Fraction of timesteps precip efficiency reported', sampled_on_subcycle=.true.) + call addfld('VPRCO' , horiz_only, 'A', 'kg/kg/s', 'Vertical average of autoconversion rate', sampled_on_subcycle=.true.) + call addfld('VPRAO' , horiz_only, 'A', 'kg/kg/s', 'Vertical average of accretion rate', sampled_on_subcycle=.true.) + call addfld('RACAU' , horiz_only, 'A', 'kg/kg/s', 'Accretion/autoconversion ratio from vertical average', sampled_on_subcycle=.true.) - call addfld('UMR', (/ 'trop_cld_lev' /), 'A', 'm/s', 'Mass-weighted rain fallspeed' ) - call addfld('UMS', (/ 'trop_cld_lev' /), 'A', 'm/s', 'Mass-weighted snow fallspeed' ) + call addfld('UMR', (/ 'trop_cld_lev' /), 'A', 'm/s', 'Mass-weighted rain fallspeed', sampled_on_subcycle=.true.) + call addfld('UMS', (/ 'trop_cld_lev' /), 'A', 'm/s', 'Mass-weighted snow fallspeed', sampled_on_subcycle=.true.) if (micro_mg_version > 2) then - call addfld('UMG', (/ 'trop_cld_lev' /), 'A', 'm/s', 'Mass-weighted graupel/hail fallspeed' ) - call addfld ('FREQG', (/ 'lev' /), 'A', 'fraction', 'Fractional occurrence of Graupel' ) - call addfld ('LS_REFFGRAU', (/ 'lev' /), 'A', 'micron', 'ls stratiform graupel/hail effective radius' ) - call addfld ('AQGRAU', (/ 'lev' /), 'A', 'kg/kg', 'Average graupel/hail mixing ratio' ) - call addfld ('ANGRAU', (/ 'lev' /), 'A', 'm-3', 'Average graupel/hail number conc' ) + call addfld('UMG', (/ 'trop_cld_lev' /), 'A', 'm/s', 'Mass-weighted graupel/hail fallspeed', sampled_on_subcycle=.true.) + call addfld ('FREQG', (/ 'lev' /), 'A', 'fraction', 'Fractional occurrence of Graupel', sampled_on_subcycle=.true.) + call addfld ('LS_REFFGRAU', (/ 'lev' /), 'A', 'micron', 'ls stratiform graupel/hail effective radius', sampled_on_subcycle=.true.) + call addfld ('AQGRAU', (/ 'lev' /), 'A', 'kg/kg', 'Average graupel/hail mixing ratio', sampled_on_subcycle=.true.) + call addfld ('ANGRAU', (/ 'lev' /), 'A', 'm-3', 'Average graupel/hail number conc', sampled_on_subcycle=.true.) end if ! qc limiter (only output in versions 1.5 and later) - call addfld('QCRAT', (/ 'lev' /), 'A', 'fraction', 'Qc Limiter: Fraction of qc tendency applied') + call addfld('QCRAT', (/ 'lev' /), 'A', 'fraction', 'Qc Limiter: Fraction of qc tendency applied', sampled_on_subcycle=.true.) ! determine the add_default fields call phys_getopts(history_amwg_out = history_amwg , & diff --git a/src/physics/cam7/physpkg.F90 b/src/physics/cam7/physpkg.F90 index 83d03c46d1..e58f6399b8 100644 --- a/src/physics/cam7/physpkg.F90 +++ b/src/physics/cam7/physpkg.F90 @@ -853,7 +853,7 @@ subroutine phys_init( phys_state, phys_tend, pbuf2d, cam_in, cam_out ) call aer_rad_props_init() ! initialize carma - call carma_init() + call carma_init(pbuf2d) ! Prognostic chemistry. call chem_init(phys_state,pbuf2d) @@ -1366,7 +1366,8 @@ subroutine tphysac (ztodt, cam_in, & use aoa_tracers, only: aoa_tracers_timestep_tend use physconst, only: rhoh2o use aero_model, only: aero_model_drydep - use check_energy, only: check_energy_chng, tot_energy_phys + use check_energy, only: check_energy_timestep_init, check_energy_cam_chng + use check_energy, only: tot_energy_phys use check_energy, only: check_tracers_data, check_tracers_init, check_tracers_chng use time_manager, only: get_nstep use cam_abortutils, only: endrun @@ -1405,7 +1406,6 @@ subroutine tphysac (ztodt, cam_in, & use aero_model, only: aero_model_wetdep use aero_wetdep_cam, only: wetdep_lq use physics_buffer, only: col_type_subcol - use check_energy, only: check_energy_timestep_init use carma_intr, only: carma_wetdep_tend, carma_timestep_tend, carma_emission_tend use carma_flags_mod, only: carma_do_aerosol, carma_do_emission, carma_do_detrain use carma_flags_mod, only: carma_do_cldice, carma_do_cldliq, carma_do_wetdep @@ -1615,7 +1615,7 @@ subroutine tphysac (ztodt, cam_in, & if (carma_do_emission) then ! carma emissions - call carma_emission_tend (state, ptend, cam_in, ztodt) + call carma_emission_tend (state, ptend, cam_in, ztodt, pbuf) call physics_update(state, ptend, ztodt, tend) end if @@ -1644,7 +1644,7 @@ subroutine tphysac (ztodt, cam_in, & call physics_update(state, ptend, ztodt, tend) - call check_energy_chng(state, tend, "clubb_emissions_tend", nstep, ztodt, zero, zero, zero, zero) + call check_energy_cam_chng(state, tend, "clubb_emissions_tend", nstep, ztodt, zero, zero, zero, zero) call t_stopf('clubb_emissions_tend') @@ -1672,9 +1672,9 @@ subroutine tphysac (ztodt, cam_in, & ! CARMA is doing ! detrainment, then the reserved condensate is snow. if (carma_do_detrain) then - call check_energy_chng(state, tend, "carma_tend", nstep, ztodt, zero, prec_str+rliq, snow_str+rliq, zero) + call check_energy_cam_chng(state, tend, "carma_tend", nstep, ztodt, zero, prec_str+rliq, snow_str+rliq, zero) else - call check_energy_chng(state, tend, "carma_tend", nstep, ztodt, zero, prec_str, snow_str, zero) + call check_energy_cam_chng(state, tend, "carma_tend", nstep, ztodt, zero, prec_str, snow_str, zero) end if end if @@ -1749,7 +1749,7 @@ subroutine tphysac (ztodt, cam_in, & end if ! Use actual qflux (not lhf/latvap) for consistency with surface fluxes and revised code - call check_energy_chng(state, tend, "clubb_tend", nstep, ztodt, & + call check_energy_cam_chng(state, tend, "clubb_tend", nstep, ztodt, & cam_in%cflx(:ncol,1)/cld_macmic_num_steps, & flx_cnd(:ncol)/cld_macmic_num_steps, & det_ice(:ncol)/cld_macmic_num_steps, & @@ -1848,7 +1848,7 @@ subroutine tphysac (ztodt, cam_in, & fh2o, surfric, obklen, flx_heat, cmfmc, dlf, det_s, det_ice, net_flx) end if - call check_energy_chng(state_sc, tend_sc, "microp_tend_subcol", & + call check_energy_cam_chng(state_sc, tend_sc, "microp_tend_subcol", & nstep, ztodt, zero_sc, & prec_str_sc(:state_sc%ncol)/cld_macmic_num_steps, & snow_str_sc(:state_sc%ncol)/cld_macmic_num_steps, zero_sc) @@ -1880,7 +1880,7 @@ subroutine tphysac (ztodt, cam_in, & fh2o, surfric, obklen, flx_heat, cmfmc, dlf, det_s, det_ice, net_flx) end if - call check_energy_chng(state, tend, "microp_tend", nstep, ztodt, & + call check_energy_cam_chng(state, tend, "microp_tend", nstep, ztodt, & zero, prec_str(:ncol)/cld_macmic_num_steps, & snow_str(:ncol)/cld_macmic_num_steps, zero) @@ -2036,7 +2036,7 @@ subroutine tphysac (ztodt, cam_in, & fh2o, surfric, obklen, flx_heat, cmfmc, dlf, det_s, det_ice, net_flx) end if - call check_energy_chng(state, tend, "radheat", nstep, ztodt, zero, zero, zero, net_flx) + call check_energy_cam_chng(state, tend, "radheat", nstep, ztodt, zero, zero, zero, net_flx) call t_stopf('radiation') @@ -2113,7 +2113,7 @@ subroutine tphysac (ztodt, cam_in, & call cam_snapshot_all_outfld_tphysac(cam_snapshot_after_num, state, tend, cam_in, cam_out, pbuf,& fh2o, surfric, obklen, flx_heat, cmfmc, dlf, det_s, det_ice, net_flx) end if - call check_energy_chng(state, tend, "chem", nstep, ztodt, fh2o, zero, zero, zero) + call check_energy_cam_chng(state, tend, "chem", nstep, ztodt, fh2o, zero, zero, zero) call check_tracers_chng(state, tracerint, "chem_timestep_tend", nstep, ztodt, & cam_in%cflx) end if @@ -2175,9 +2175,9 @@ subroutine tphysac (ztodt, cam_in, & call t_stopf('rayleigh_friction') if (do_clubb_sgs) then - call check_energy_chng(state, tend, "vdiff", nstep, ztodt, zero, zero, zero, zero) + call check_energy_cam_chng(state, tend, "vdiff", nstep, ztodt, zero, zero, zero, zero) else - call check_energy_chng(state, tend, "vdiff", nstep, ztodt, cam_in%cflx(:,1), zero, & + call check_energy_cam_chng(state, tend, "vdiff", nstep, ztodt, cam_in%cflx(:,1), zero, & zero, cam_in%shf) endif @@ -2221,7 +2221,7 @@ subroutine tphysac (ztodt, cam_in, & call carma_timestep_tend(state, cam_in, cam_out, ptend, ztodt, pbuf, obklen=obklen, ustar=surfric) call physics_update(state, ptend, ztodt, tend) - call check_energy_chng(state, tend, "carma_tend", nstep, ztodt, zero, zero, zero, zero) + call check_energy_cam_chng(state, tend, "carma_tend", nstep, ztodt, zero, zero, zero, zero) call t_stopf('carma_timestep_tend') end if @@ -2260,7 +2260,7 @@ subroutine tphysac (ztodt, cam_in, & end if ! Check energy integrals - call check_energy_chng(state, tend, "gwdrag", nstep, ztodt, zero, & + call check_energy_cam_chng(state, tend, "gwdrag", nstep, ztodt, zero, & zero, zero, flx_heat) call t_stopf('gw_tend') @@ -2290,7 +2290,7 @@ subroutine tphysac (ztodt, cam_in, & end if ! Check energy integrals - call check_energy_chng(state, tend, "qborelax", nstep, ztodt, zero, zero, zero, zero) + call check_energy_cam_chng(state, tend, "qborelax", nstep, ztodt, zero, zero, zero, zero) ! Lunar tides call lunar_tides_tend( state, ptend ) @@ -2302,7 +2302,7 @@ subroutine tphysac (ztodt, cam_in, & end if call physics_update(state, ptend, ztodt, tend) ! Check energy integrals - call check_energy_chng(state, tend, "lunar_tides", nstep, ztodt, zero, zero, zero, zero) + call check_energy_cam_chng(state, tend, "lunar_tides", nstep, ztodt, zero, zero, zero, zero) ! Ion drag calculation call t_startf ( 'iondrag' ) @@ -2351,7 +2351,7 @@ subroutine tphysac (ztodt, cam_in, & endif ! Check energy integrals - call check_energy_chng(state, tend, "iondrag", nstep, ztodt, zero, zero, zero, zero) + call check_energy_cam_chng(state, tend, "iondrag", nstep, ztodt, zero, zero, zero, zero) call t_stopf ( 'iondrag' ) @@ -2366,7 +2366,7 @@ subroutine tphysac (ztodt, cam_in, & call outfld( 'VTEND_NDG', ptend%v, pcols, lchnk) end if call physics_update(state,ptend,ztodt,tend) - call check_energy_chng(state, tend, "nudging", nstep, ztodt, zero, zero, zero, zero) + call check_energy_cam_chng(state, tend, "nudging", nstep, ztodt, zero, zero, zero, zero) endif !-------------- Energy budget checks vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv @@ -2517,7 +2517,7 @@ subroutine tphysbc (ztodt, state, & use convect_deep, only: convect_deep_tend use time_manager, only: is_first_step, get_nstep use convect_diagnostics,only: convect_diagnostics_calc - use check_energy, only: check_energy_chng, check_energy_fix + use check_energy, only: check_energy_cam_chng, check_energy_cam_fix use check_energy, only: check_tracers_data, check_tracers_init use check_energy, only: tot_energy_phys use dycore, only: dycore_is @@ -2699,9 +2699,9 @@ subroutine tphysbc (ztodt, state, & call tot_energy_phys(state, 'dyBF',vc=vc_dycore) if (.not.dycore_is('EUL')) then - call check_energy_fix(state, ptend, nstep, flx_heat) + call check_energy_cam_fix(state, ptend, nstep, flx_heat) call physics_update(state, ptend, ztodt, tend) - call check_energy_chng(state, tend, "chkengyfix", nstep, ztodt, zero, zero, zero, flx_heat) + call check_energy_cam_chng(state, tend, "chkengyfix", nstep, ztodt, zero, zero, zero, flx_heat) call outfld( 'EFIX', flx_heat , pcols, lchnk ) end if @@ -2831,7 +2831,7 @@ subroutine tphysbc (ztodt, state, & ! Check energy integrals, including "reserved liquid" flx_cnd(:ncol) = prec_dp(:ncol) + rliq(:ncol) snow_dp(:ncol) = snow_dp(:ncol) + rice(:ncol) - call check_energy_chng(state, tend, "convect_deep", nstep, ztodt, zero, flx_cnd, snow_dp, zero) + call check_energy_cam_chng(state, tend, "convect_deep", nstep, ztodt, zero, flx_cnd, snow_dp, zero) snow_dp(:ncol) = snow_dp(:ncol) - rice(:ncol) !=================================================== @@ -2882,8 +2882,10 @@ subroutine tphysbc (ztodt, state, & ! Run wet deposition routines to intialize aerosols !=================================================== - call modal_aero_calcsize_diag(state, pbuf) - call modal_aero_wateruptake_dr(state, pbuf) + if (clim_modal_aero) then + call modal_aero_calcsize_diag(state, pbuf) + call modal_aero_wateruptake_dr(state, pbuf) + end if !=================================================== ! Radiation computations diff --git a/src/physics/cam7/stochastic_emulated_cam.F90 b/src/physics/cam7/stochastic_emulated_cam.F90 index 8fbc9e44a1..1433c940e3 100644 --- a/src/physics/cam7/stochastic_emulated_cam.F90 +++ b/src/physics/cam7/stochastic_emulated_cam.F90 @@ -85,44 +85,44 @@ subroutine stochastic_emulated_init_cam(stochastic_emulated_filename_quantile_ou call add_hist_coord('bins_ncd', ncd, 'bins for TAU microphysics') - call addfld('amk_c',(/'trop_cld_lev','bins_ncd '/),'A','kg','cloud liquid mass from bins') - call addfld('ank_c',(/'trop_cld_lev','bins_ncd '/),'A','1/kg','cloud liquid number concentration from bins') - call addfld('amk_r',(/'trop_cld_lev','bins_ncd '/),'A','kg','rain mass from bins') - call addfld('ank_r',(/'trop_cld_lev','bins_ncd '/),'A','1/kg','rain number concentration from bins') - call addfld('amk',(/'trop_cld_lev','bins_ncd '/),'A','kg','all liquid mass from bins') - call addfld('ank',(/'trop_cld_lev','bins_ncd '/),'A','1/kg','all liquid number concentration from bins') - call addfld('amk_out',(/'trop_cld_lev','bins_ncd '/),'A','kg','all liquid mass from bins') - call addfld('ank_out',(/'trop_cld_lev','bins_ncd '/),'A','1/kg','all liquid number concentration from bins') - - call addfld('scale_nc',(/'trop_cld_lev'/),'A','1','scaling factor for nc') - call addfld('scale_nr',(/'trop_cld_lev'/),'A','1','scaling factor for nr') - call addfld('scale_qc',(/'trop_cld_lev'/),'A','1','scaling factor for qc') - call addfld('scale_qr',(/'trop_cld_lev'/),'A','1','scaling factor for qr') + call addfld('amk_c',(/'trop_cld_lev','bins_ncd '/),'A','kg','cloud liquid mass from bins', sampled_on_subcycle=.true.) + call addfld('ank_c',(/'trop_cld_lev','bins_ncd '/),'A','1/kg','cloud liquid number concentration from bins',sampled_on_subcycle=.true.) + call addfld('amk_r',(/'trop_cld_lev','bins_ncd '/),'A','kg','rain mass from bins', sampled_on_subcycle=.true.) + call addfld('ank_r',(/'trop_cld_lev','bins_ncd '/),'A','1/kg','rain number concentration from bins', sampled_on_subcycle=.true.) + call addfld('amk',(/'trop_cld_lev','bins_ncd '/),'A','kg','all liquid mass from bins', sampled_on_subcycle=.true.) + call addfld('ank',(/'trop_cld_lev','bins_ncd '/),'A','1/kg','all liquid number concentration from bins', sampled_on_subcycle=.true.) + call addfld('amk_out',(/'trop_cld_lev','bins_ncd '/),'A','kg','all liquid mass from bins', sampled_on_subcycle=.true.) + call addfld('ank_out',(/'trop_cld_lev','bins_ncd '/),'A','1/kg','all liquid number concentration from bins',sampled_on_subcycle=.true.) + + call addfld('scale_nc',(/'trop_cld_lev'/),'A','1','scaling factor for nc', sampled_on_subcycle=.true.) + call addfld('scale_nr',(/'trop_cld_lev'/),'A','1','scaling factor for nr', sampled_on_subcycle=.true.) + call addfld('scale_qc',(/'trop_cld_lev'/),'A','1','scaling factor for qc', sampled_on_subcycle=.true.) + call addfld('scale_qr',(/'trop_cld_lev'/),'A','1','scaling factor for qr', sampled_on_subcycle=.true.) - call addfld('QC_TAU_in',(/'trop_cld_lev'/),'A','kg/kg','qc in TAU') - call addfld('NC_TAU_in',(/'trop_cld_lev'/),'A','1/kg','nc in TAU') - call addfld('QR_TAU_in',(/'trop_cld_lev'/),'A','kg/kg','qr in TAU') - call addfld('NR_TAU_in',(/'trop_cld_lev'/),'A','1/kg','nr in TAU') - call addfld('QC_TAU_out',(/'trop_cld_lev'/),'A','kg/kg','qc out TAU') - call addfld('NC_TAU_out',(/'trop_cld_lev'/),'A','1/kg','nc out TAU') - call addfld('QR_TAU_out',(/'trop_cld_lev'/),'A','kg/kg','qr out TAU') - call addfld('NR_TAU_out',(/'trop_cld_lev'/),'A','1/kg','nr out TAU') + call addfld('QC_TAU_in',(/'trop_cld_lev'/),'A','kg/kg','qc in TAU', sampled_on_subcycle=.true.) + call addfld('NC_TAU_in',(/'trop_cld_lev'/),'A','1/kg','nc in TAU', sampled_on_subcycle=.true.) + call addfld('QR_TAU_in',(/'trop_cld_lev'/),'A','kg/kg','qr in TAU', sampled_on_subcycle=.true.) + call addfld('NR_TAU_in',(/'trop_cld_lev'/),'A','1/kg','nr in TAU', sampled_on_subcycle=.true.) + call addfld('QC_TAU_out',(/'trop_cld_lev'/),'A','kg/kg','qc out TAU', sampled_on_subcycle=.true.) + call addfld('NC_TAU_out',(/'trop_cld_lev'/),'A','1/kg','nc out TAU', sampled_on_subcycle=.true.) + call addfld('QR_TAU_out',(/'trop_cld_lev'/),'A','kg/kg','qr out TAU', sampled_on_subcycle=.true.) + call addfld('NR_TAU_out',(/'trop_cld_lev'/),'A','1/kg','nr out TAU', sampled_on_subcycle=.true.) - call addfld('qctend_TAU',(/'trop_cld_lev'/),'A','kg/kg/s','qc tendency due to TAU bin code') - call addfld('nctend_TAU',(/'trop_cld_lev'/),'A','1/kg/s','nc tendency due to TAU bin code') - call addfld('qrtend_TAU',(/'trop_cld_lev'/),'A','kg/kg/s','qr tendency due to TAU bin code') - call addfld('nrtend_TAU',(/'trop_cld_lev'/),'A','1/kg/s','nr tendency due to TAU bin code') - call addfld('qctend_TAU_diag',(/'trop_cld_lev'/),'A','kg/kg/s','qc tendency due to TAU bin code') - call addfld('nctend_TAU_diag',(/'trop_cld_lev'/),'A','1/kg/s','nc tendency due to TAU bin code') - call addfld('qrtend_TAU_diag',(/'trop_cld_lev'/),'A','kg/kg/s','qr tendency due to TAU bin code') - call addfld('nrtend_TAU_diag',(/'trop_cld_lev'/),'A','1/kg/s','nr tendency due to TAU bin code') - - call addfld('gmnnn_lmnnn_TAU',(/'trop_cld_lev'/),'A','1','sum of mass gain and loss from bin code') - call addfld('ML_fixer',(/'trop_cld_lev'/),'A','1','frequency that ML fixer is activated') - call addfld('qc_fixer',(/'trop_cld_lev'/),'A','kg/kg','delta qc due to ML fixer') - call addfld('nc_fixer',(/'trop_cld_lev'/),'A','kg/kg','delta nc due to ML fixer') - call addfld('qr_fixer',(/'trop_cld_lev'/),'A','kg/kg','delta qr due to ML fixer') - call addfld('nr_fixer',(/'trop_cld_lev'/),'A','kg/kg','delta nr due to ML fixer') + call addfld('qctend_TAU',(/'trop_cld_lev'/),'A','kg/kg/s','qc tendency due to TAU bin code', sampled_on_subcycle=.true.) + call addfld('nctend_TAU',(/'trop_cld_lev'/),'A','1/kg/s','nc tendency due to TAU bin code', sampled_on_subcycle=.true.) + call addfld('qrtend_TAU',(/'trop_cld_lev'/),'A','kg/kg/s','qr tendency due to TAU bin code', sampled_on_subcycle=.true.) + call addfld('nrtend_TAU',(/'trop_cld_lev'/),'A','1/kg/s','nr tendency due to TAU bin code', sampled_on_subcycle=.true.) + call addfld('qctend_TAU_diag',(/'trop_cld_lev'/),'A','kg/kg/s','qc tendency due to TAU bin code', sampled_on_subcycle=.true.) + call addfld('nctend_TAU_diag',(/'trop_cld_lev'/),'A','1/kg/s','nc tendency due to TAU bin code', sampled_on_subcycle=.true.) + call addfld('qrtend_TAU_diag',(/'trop_cld_lev'/),'A','kg/kg/s','qr tendency due to TAU bin code', sampled_on_subcycle=.true.) + call addfld('nrtend_TAU_diag',(/'trop_cld_lev'/),'A','1/kg/s','nr tendency due to TAU bin code', sampled_on_subcycle=.true.) + + call addfld('gmnnn_lmnnn_TAU',(/'trop_cld_lev'/),'A','1','sum of mass gain and loss from bin code', sampled_on_subcycle=.true.) + call addfld('ML_fixer',(/'trop_cld_lev'/),'A','1','frequency that ML fixer is activated', sampled_on_subcycle=.true.) + call addfld('qc_fixer',(/'trop_cld_lev'/),'A','kg/kg','delta qc due to ML fixer', sampled_on_subcycle=.true.) + call addfld('nc_fixer',(/'trop_cld_lev'/),'A','kg/kg','delta nc due to ML fixer', sampled_on_subcycle=.true.) + call addfld('qr_fixer',(/'trop_cld_lev'/),'A','kg/kg','delta qr due to ML fixer', sampled_on_subcycle=.true.) + call addfld('nr_fixer',(/'trop_cld_lev'/),'A','kg/kg','delta nr due to ML fixer', sampled_on_subcycle=.true.) stochastic_emulated_filename_quantile_out = stochastic_emulated_filename_quantile stochastic_emulated_filename_input_scale_out = stochastic_emulated_filename_input_scale diff --git a/src/physics/cam7/stochastic_tau_cam.F90 b/src/physics/cam7/stochastic_tau_cam.F90 index b305201e7c..0cea0201a0 100644 --- a/src/physics/cam7/stochastic_tau_cam.F90 +++ b/src/physics/cam7/stochastic_tau_cam.F90 @@ -72,44 +72,44 @@ subroutine stochastic_tau_init_cam call add_hist_coord('bins_ncd', ncd, 'bins for TAU microphysics') !Note: lev needs to be trop_cld_lev for proc_rates.... - call addfld('amk_c',(/'trop_cld_lev','bins_ncd '/),'A','kg','cloud liquid mass from bins') - call addfld('ank_c',(/'trop_cld_lev','bins_ncd '/),'A','1/kg','cloud liquid number concentration from bins') - call addfld('amk_r',(/'trop_cld_lev','bins_ncd '/),'A','kg','rain mass from bins') - call addfld('ank_r',(/'trop_cld_lev','bins_ncd '/),'A','1/kg','rain number concentration from bins') - call addfld('amk',(/'trop_cld_lev','bins_ncd '/),'A','kg','all liquid mass from bins') - call addfld('ank',(/'trop_cld_lev','bins_ncd '/),'A','1/kg','all liquid number concentration from bins') - call addfld('amk_out',(/'trop_cld_lev','bins_ncd '/),'A','kg','all liquid mass from bins') - call addfld('ank_out',(/'trop_cld_lev','bins_ncd '/),'A','1/kg','all liquid number concentration from bins') - - call addfld('scale_nc',(/'trop_cld_lev'/),'A','1','scaling factor for nc') - call addfld('scale_nr',(/'trop_cld_lev'/),'A','1','scaling factor for nr') - call addfld('scale_qc',(/'trop_cld_lev'/),'A','1','scaling factor for qc') - call addfld('scale_qr',(/'trop_cld_lev'/),'A','1','scaling factor for qr') + call addfld('amk_c',(/'trop_cld_lev','bins_ncd '/),'A','kg','cloud liquid mass from bins', sampled_on_subcycle=.true.) + call addfld('ank_c',(/'trop_cld_lev','bins_ncd '/),'A','1/kg','cloud liquid number concentration from bins', sampled_on_subcycle=.true.) + call addfld('amk_r',(/'trop_cld_lev','bins_ncd '/),'A','kg','rain mass from bins', sampled_on_subcycle=.true.) + call addfld('ank_r',(/'trop_cld_lev','bins_ncd '/),'A','1/kg','rain number concentration from bins', sampled_on_subcycle=.true.) + call addfld('amk',(/'trop_cld_lev','bins_ncd '/),'A','kg','all liquid mass from bins', sampled_on_subcycle=.true.) + call addfld('ank',(/'trop_cld_lev','bins_ncd '/),'A','1/kg','all liquid number concentration from bins', sampled_on_subcycle=.true.) + call addfld('amk_out',(/'trop_cld_lev','bins_ncd '/),'A','kg','all liquid mass from bins', sampled_on_subcycle=.true.) + call addfld('ank_out',(/'trop_cld_lev','bins_ncd '/),'A','1/kg','all liquid number concentration from bins', sampled_on_subcycle=.true.) + + call addfld('scale_nc',(/'trop_cld_lev'/),'A','1','scaling factor for nc', sampled_on_subcycle=.true.) + call addfld('scale_nr',(/'trop_cld_lev'/),'A','1','scaling factor for nr', sampled_on_subcycle=.true.) + call addfld('scale_qc',(/'trop_cld_lev'/),'A','1','scaling factor for qc', sampled_on_subcycle=.true.) + call addfld('scale_qr',(/'trop_cld_lev'/),'A','1','scaling factor for qr', sampled_on_subcycle=.true.) - call addfld('QC_TAU_in',(/'trop_cld_lev'/),'A','kg/kg','qc in TAU') - call addfld('NC_TAU_in',(/'trop_cld_lev'/),'A','1/kg','nc in TAU') - call addfld('QR_TAU_in',(/'trop_cld_lev'/),'A','kg/kg','qr in TAU') - call addfld('NR_TAU_in',(/'trop_cld_lev'/),'A','1/kg','nr in TAU') - call addfld('QC_TAU_out',(/'trop_cld_lev'/),'A','kg/kg','qc out TAU') - call addfld('NC_TAU_out',(/'trop_cld_lev'/),'A','1/kg','nc out TAU') - call addfld('QR_TAU_out',(/'trop_cld_lev'/),'A','kg/kg','qr out TAU') - call addfld('NR_TAU_out',(/'trop_cld_lev'/),'A','1/kg','nr out TAU') + call addfld('QC_TAU_in',(/'trop_cld_lev'/),'A','kg/kg','qc in TAU', sampled_on_subcycle=.true.) + call addfld('NC_TAU_in',(/'trop_cld_lev'/),'A','1/kg','nc in TAU', sampled_on_subcycle=.true.) + call addfld('QR_TAU_in',(/'trop_cld_lev'/),'A','kg/kg','qr in TAU', sampled_on_subcycle=.true.) + call addfld('NR_TAU_in',(/'trop_cld_lev'/),'A','1/kg','nr in TAU', sampled_on_subcycle=.true.) + call addfld('QC_TAU_out',(/'trop_cld_lev'/),'A','kg/kg','qc out TAU', sampled_on_subcycle=.true.) + call addfld('NC_TAU_out',(/'trop_cld_lev'/),'A','1/kg','nc out TAU', sampled_on_subcycle=.true.) + call addfld('QR_TAU_out',(/'trop_cld_lev'/),'A','kg/kg','qr out TAU', sampled_on_subcycle=.true.) + call addfld('NR_TAU_out',(/'trop_cld_lev'/),'A','1/kg','nr out TAU', sampled_on_subcycle=.true.) - call addfld('qctend_TAU',(/'trop_cld_lev'/),'A','kg/kg/s','qc tendency due to TAU bin code') - call addfld('nctend_TAU',(/'trop_cld_lev'/),'A','1/kg/s','nc tendency due to TAU bin code') - call addfld('qrtend_TAU',(/'trop_cld_lev'/),'A','kg/kg/s','qr tendency due to TAU bin code') - call addfld('nrtend_TAU',(/'trop_cld_lev'/),'A','1/kg/s','nr tendency due to TAU bin code') - call addfld('qctend_TAU_diag',(/'trop_cld_lev'/),'A','kg/kg/s','qc tendency due to TAU bin code') - call addfld('nctend_TAU_diag',(/'trop_cld_lev'/),'A','1/kg/s','nc tendency due to TAU bin code') - call addfld('qrtend_TAU_diag',(/'trop_cld_lev'/),'A','kg/kg/s','qr tendency due to TAU bin code') - call addfld('nrtend_TAU_diag',(/'trop_cld_lev'/),'A','1/kg/s','nr tendency due to TAU bin code') - - call addfld('gmnnn_lmnnn_TAU',(/'trop_cld_lev'/),'A','1','sum of mass gain and loss from bin code') - call addfld('ML_fixer',(/'trop_cld_lev'/),'A','1','frequency that ML fixer is activated') - call addfld('qc_fixer',(/'trop_cld_lev'/),'A','kg/kg','delta qc due to ML fixer') - call addfld('nc_fixer',(/'trop_cld_lev'/),'A','kg/kg','delta nc due to ML fixer') - call addfld('qr_fixer',(/'trop_cld_lev'/),'A','kg/kg','delta qr due to ML fixer') - call addfld('nr_fixer',(/'trop_cld_lev'/),'A','kg/kg','delta nr due to ML fixer') + call addfld('qctend_TAU',(/'trop_cld_lev'/),'A','kg/kg/s','qc tendency due to TAU bin code', sampled_on_subcycle=.true.) + call addfld('nctend_TAU',(/'trop_cld_lev'/),'A','1/kg/s','nc tendency due to TAU bin code', sampled_on_subcycle=.true.) + call addfld('qrtend_TAU',(/'trop_cld_lev'/),'A','kg/kg/s','qr tendency due to TAU bin code', sampled_on_subcycle=.true.) + call addfld('nrtend_TAU',(/'trop_cld_lev'/),'A','1/kg/s','nr tendency due to TAU bin code', sampled_on_subcycle=.true.) + call addfld('qctend_TAU_diag',(/'trop_cld_lev'/),'A','kg/kg/s','qc tendency due to TAU bin code', sampled_on_subcycle=.true.) + call addfld('nctend_TAU_diag',(/'trop_cld_lev'/),'A','1/kg/s','nc tendency due to TAU bin code', sampled_on_subcycle=.true.) + call addfld('qrtend_TAU_diag',(/'trop_cld_lev'/),'A','kg/kg/s','qr tendency due to TAU bin code', sampled_on_subcycle=.true.) + call addfld('nrtend_TAU_diag',(/'trop_cld_lev'/),'A','1/kg/s','nr tendency due to TAU bin code', sampled_on_subcycle=.true.) + + call addfld('gmnnn_lmnnn_TAU',(/'trop_cld_lev'/),'A','1','sum of mass gain and loss from bin code', sampled_on_subcycle=.true.) + call addfld('ML_fixer',(/'trop_cld_lev'/),'A','1','frequency that ML fixer is activated', sampled_on_subcycle=.true.) + call addfld('qc_fixer',(/'trop_cld_lev'/),'A','kg/kg','delta qc due to ML fixer', sampled_on_subcycle=.true.) + call addfld('nc_fixer',(/'trop_cld_lev'/),'A','kg/kg','delta nc due to ML fixer', sampled_on_subcycle=.true.) + call addfld('qr_fixer',(/'trop_cld_lev'/),'A','kg/kg','delta qr due to ML fixer', sampled_on_subcycle=.true.) + call addfld('nr_fixer',(/'trop_cld_lev'/),'A','kg/kg','delta nr due to ML fixer', sampled_on_subcycle=.true.) end subroutine stochastic_tau_init_cam end module stochastic_tau_cam diff --git a/src/physics/carma/base b/src/physics/carma/base index bf165cd84e..67418505b4 160000 --- a/src/physics/carma/base +++ b/src/physics/carma/base @@ -1 +1 @@ -Subproject commit bf165cd84ef94087d9a5669a5ad47838ab24c0ef +Subproject commit 67418505b48787bd305a50ffb581f98f0b466cba diff --git a/src/physics/carma/cam/carma_constants_mod.F90 b/src/physics/carma/cam/carma_constants_mod.F90 index e7392cc6a5..c29820d382 100644 --- a/src/physics/carma/cam/carma_constants_mod.F90 +++ b/src/physics/carma/cam/carma_constants_mod.F90 @@ -119,9 +119,9 @@ module carma_constants_mod !! NWAVE should be the total number of bands CAM supports. integer, public, parameter :: NWAVE = nlwbands+nswbands ! Number of wavelength bands - - - + !! The maximum number of diagnostic values that can be returned by + !! CARMA_CalculateCloudborneDiagnostics + integer, public, parameter :: MAXCLDAERDIAG = 16 !! These are constants per CARMA's definition, but are set dynamically in CAM and thus !! can not be set as constants. They must be initialized as variables in carma_init. @@ -147,5 +147,4 @@ module carma_constants_mod !! Define ratio of gas constant for dry air and specific heat real(kind=f) :: RKAPPA - -end module +end module carma_constants_mod diff --git a/src/physics/carma/cam/carma_intr.F90 b/src/physics/carma/cam/carma_intr.F90 index e726c296c9..89f7f415d6 100644 --- a/src/physics/carma/cam/carma_intr.F90 +++ b/src/physics/carma/cam/carma_intr.F90 @@ -9,39 +9,45 @@ !! @version July 2009 module carma_intr - use carma_precision_mod - use carma_enums_mod - use carma_constants_mod - use carma_types_mod - use carma_flags_mod - use carma_model_mod - use carmaelement_mod - use carmagas_mod - use carmagroup_mod - use carmasolute_mod - use carmastate_mod - use carma_mod + use carma_precision_mod, only: f + use carma_enums_mod, only: I_OPTICS_FIXED, I_OPTICS_MIXED_CORESHELL, I_OPTICS_MIXED_VOLUME, & + I_OPTICS_MIXED_MAXWELL, I_OPTICS_SULFATE, I_CNSTTYPE_PROGNOSTIC, I_HYBRID + use carma_constants_mod, only : GRAV, REARTH, WTMOL_AIR, WTMOL_H2O, R_AIR, CP, RKAPPA, NWAVE, & + CARMA_NAME_LEN, CARMA_SHORT_NAME_LEN, PI, CAM_FILL, RGAS, RM2CGS, RAD2DEG, CLDFRC_INCLOUD + use carma_types_mod, only : carma_type, carmastate_type + use carma_flags_mod, only : carma_flag, carma_do_fixedinit, carma_model, carma_do_wetdep, carma_do_emission, & + carma_do_pheat, carma_do_substep, carma_do_thermo, carma_do_cldice, carma_diags_file, & + carma_do_grow, carma_ndebugpkgs, carma_conmax, carma_cstick, carma_tstick, carma_vf_const, carma_sulfnuc_method, & + carma_rhcrit, carma_rad_feedback, carma_minsubsteps, carma_maxsubsteps, carma_gstickl, carma_gsticki, & + carma_maxretries, carma_dt_threshold, carma_ds_threshold, carma_do_vtran, carma_do_vdiff, carma_do_pheatatm, & + carma_do_partialinit, carma_do_optics, carma_do_incloud, carma_do_explised, carma_do_drydep, carma_do_detrain, & + carma_do_coremasscheck, carma_do_coag, carma_do_clearsky, carma_do_cldliq, carma_do_aerosol, carma_dgc_threshold + + use carma_model_mod, only : NGAS, NBIN, NELEM, NGROUP, NMIE_WTP, NREFIDX, MIE_RH, NMIE_RH, NSOLUTE + use carma_model_mod, only : mie_rh, mie_wtp, is_convtran1, CARMAMODEL_DiagnoseBulk, CARMAMODEL_DiagnoseBins, & + CARMAMODEL_Detrain, CARMAMODEL_OutputDiagnostics, CARMAMODEL_CreateOpticsFile, CARMAMODEL_WetDeposition, & + CARMAMODEL_EmitParticle, CARMAMODEL_InitializeParticle, CARMAMODEL_DefineModel, CARMAMODEL_InitializeModel + use carmaelement_mod, only : CARMAELEMENT_Get + use carmagas_mod, only : CARMAGAS_Get + use carmagroup_mod, only : CARMAGROUP_Get + use carmastate_mod, only : CARMASTATE_CreateFromReference, CARMASTATE_SetGas, CARMASTATE_Step, CARMASTATE_GetBin, & + CARMASTATE_GetGas, CARMASTATE_GetState, CARMASTATE_Get, CARMASTATE_Create, CARMASTATE_SetBin, CARMASTATE_Destroy + use carma_mod, only : CARMA_Get, CARMA_Create, CARMA_Initialize, CARMA_Destroy use shr_kind_mod, only: r8 => shr_kind_r8 - use spmd_utils, only: masterproc - use pmgrid, only: plat, plev, plevp, plon + use spmd_utils, only: masterproc, mpicom use ppgrid, only: pcols, pver, pverp use ref_pres, only: pref_mid, pref_edge, pref_mid_norm, psurf_ref use physics_types, only: physics_state, physics_ptend, physics_ptend_init, & set_dry_to_wet, physics_state_copy - use phys_grid, only: get_lat_all_p - use physconst, only: avogad, cpair + use physconst, only: cpair use constituents, only: pcnst, cnst_add, cnst_get_ind, & - cnst_name, cnst_longname, cnst_type - use chem_surfvals, only: chem_surfvals_get + cnst_name, cnst_longname use cam_abortutils, only: endrun use physics_buffer, only: physics_buffer_desc, pbuf_add_field, pbuf_old_tim_idx, & - pbuf_get_index, pbuf_get_field, dtype_r8 - - -#if ( defined SPMD ) - use mpishorthand -#endif + pbuf_get_index, pbuf_get_field, dtype_r8, pbuf_set_field + use pio, only: var_desc_t + use radconstants, only: nlwbands, nswbands implicit none @@ -61,17 +67,20 @@ module carma_intr public carma_timestep_tend ! interface to tendency computation public carma_accumulate_stats ! collect stats from all MPI tasks + ! Other Microphysics public carma_emission_tend ! calculate tendency from emission source function public carma_wetdep_tend ! calculate tendency from wet deposition - + public :: carma_restart_init + public :: carma_restart_write + public :: carma_restart_read ! Private data ! Particle Group Statistics ! Gridbox average - integer, parameter :: NGPDIAGS = 12 ! Number of particle diagnostics ... + integer, parameter :: NGPDIAGS = 13 ! Number of particle diagnostics ... integer, parameter :: GPDIAGS_ND = 1 ! Number density integer, parameter :: GPDIAGS_AD = 2 ! Surface area density integer, parameter :: GPDIAGS_MD = 3 ! Mass density @@ -84,10 +93,15 @@ module carma_intr integer, parameter :: GPDIAGS_VM = 10 ! Mass Weighted Fall Velocity integer, parameter :: GPDIAGS_PA = 11 ! Projected Area integer, parameter :: GPDIAGS_AR = 12 ! Area Ratio + integer, parameter :: GPDIAGS_VR = 13 ! Volatile Mixing Ratio ! Particle Bin (Element) Statistics - integer, parameter :: NBNDIAGS = 1 ! Number of bin surface diagnostics ... + integer, parameter :: NBNDIAGS = 5 ! Number of bin surface diagnostics ... integer, parameter :: BNDIAGS_TP = 1 ! Delta Particle Temperature [K] + integer, parameter :: BNDIAGS_WETR = 2 ! wet radius + integer, parameter :: BNDIAGS_ND = 3 ! Number density + integer, parameter :: BNDIAGS_RO = 4 ! particle density + integer, parameter :: BNDIAGS_VR = 5 ! Volatile Mixing Ratio ! Surface integer, parameter :: NSBDIAGS = 2 ! Number of bin surface diagnostics ... @@ -134,16 +148,19 @@ module carma_intr ! Physics Buffer Indicies - integer :: ipbuf4gas(NGAS) ! physics buffer index for a carma gas - integer :: ipbuf4t ! physics buffer index for a carma temperature - integer :: ipbuf4sati(NGAS) ! physics buffer index for a carma saturation over ice - integer :: ipbuf4satl(NGAS) ! physics buffer index for a carma saturation over liquid + integer :: ipbuf4gas(NGAS)=-1 ! physics buffer index for a carma gas + integer :: ipbuf4t=-1 ! physics buffer index for a carma temperature + integer :: ipbuf4sati(NGAS)=-1 ! physics buffer index for a carma saturation over ice + integer :: ipbuf4satl(NGAS)=-1 ! physics buffer index for a carma saturation over liquid ! Globals used for a reference atmosphere. - real(kind=f) :: carma_t_ref(pver) ! midpoint temperature (Pa) - real(kind=f) :: carma_h2o_ref(pver) ! h2o mmmr (kg/kg) - real(kind=f) :: carma_h2so4_ref(pver) ! h2so4 mmr (kg/kg) + real(kind=f) :: carma_t_ref(pver) = -huge(1._f) ! midpoint temperature (Pa) + real(kind=f) :: carma_h2o_ref(pver) = -huge(1._f) ! h2o mmmr (kg/kg) + real(kind=f) :: carma_h2so4_ref(pver) = -huge(1._f) ! h2so4 mmr (kg/kg) + type(var_desc_t) :: t_ref_desc + type(var_desc_t) :: h2o_ref_desc + type(var_desc_t) :: h2so4_ref_desc ! Globals used for total statistics real(kind=f) :: glob_max_nsubstep = 0._f @@ -158,7 +175,6 @@ module carma_intr real(kind=f) :: step_nsubstep = 0._f real(kind=f) :: step_nretry = 0._f - contains @@ -177,8 +193,7 @@ module carma_intr !! @author Chuck Bardeen !! @version May-2009 subroutine carma_register - use radconstants, only : nswbands, nlwbands, & - get_sw_spectral_boundaries, get_lw_spectral_boundaries + use radconstants, only : get_sw_spectral_boundaries, get_lw_spectral_boundaries use cam_logfile, only : iulog use cam_control_mod, only : initial_run use physconst, only: gravit, p_rearth=>rearth, mwdry, mwh2o @@ -251,19 +266,19 @@ subroutine carma_register ! Create the CARMA object that will contain all the information about the ! how CARMA is configured. - call CARMA_Create(carma, NBIN, NELEM, NGROUP, NSOLUTE, NGAS, NWAVE, rc, & - LUNOPRT=LUNOPRT, wave=wave, dwave=dwave, do_wave_emit=do_wave_emit) + LUNOPRT=LUNOPRT, wave=wave, dwave=dwave, do_wave_emit=do_wave_emit, NREFIDX=NREFIDX) if (rc < 0) call endrun('carma_register::CARMA_Create failed.') ! Define the microphysical model. - call CARMA_DefineModel(carma, rc) + call CARMAMODEL_DefineModel(carma, rc) if (rc < 0) call endrun('carma_register::CARMA_DefineModel failed.') if (masterproc) then write(LUNOPRT,*) '' write(LUNOPRT,*) 'CARMA general settings for ', trim(carma_model), ' model : ' write(LUNOPRT,*) ' carma_do_aerosol = ', carma_do_aerosol + write(LUNOPRT,*) ' carma_do_coremasscheck = ',carma_do_coremasscheck write(LUNOPRT,*) ' carma_do_cldice = ', carma_do_cldice write(LUNOPRT,*) ' carma_do_cldliq = ', carma_do_cldliq write(LUNOPRT,*) ' carma_do_clearsky = ', carma_do_clearsky @@ -297,8 +312,8 @@ subroutine carma_register write(LUNOPRT,*) ' carma_maxretries = ', carma_maxretries write(LUNOPRT,*) ' carma_vf_const = ', carma_vf_const write(LUNOPRT,*) ' cldfrc_incloud = ', CLDFRC_INCLOUD - write(LUNOPRT,*) ' carma_reftfile = ', trim(carma_reftfile) write(LUNOPRT,*) ' carma_rad_feedback = ', carma_rad_feedback + write(LUNOPRT,*) ' carma_sulfnuc_method = ', carma_sulfnuc_method write(LUNOPRT,*) '' endif @@ -309,6 +324,8 @@ subroutine carma_register ! assumptions made in the CAM energy checking and microphysics code. call CARMA_Initialize(carma, & rc, & + sulfnucl_method = carma_sulfnuc_method, & + do_coremasscheck = carma_do_coremasscheck, & do_clearsky = carma_do_clearsky, & do_cnst_rlh = .true., & do_coag = carma_do_coag, & @@ -338,7 +355,6 @@ subroutine carma_register tstick = carma_tstick) if (rc < 0) call endrun('carma_register::CARMA_Initialize failed.') - ! The elements and gases from CARMA need to be added as constituents in ! CAM (if they don't already exist). For the elements, each radius bin ! needs to be its own constiuent in CAM. @@ -362,16 +378,14 @@ subroutine carma_register ! For prognostic groups, all of the bins need to be represented as actual CAM ! constituents. Diagnostic groups are determined from state information that ! is already present in CAM, and thus their bins only exist in CARMA. - if (cnsttype == I_CNSTTYPE_PROGNOSTIC) then - - do ibin = 1, NBIN + do ibin = 1, NBIN + write(btndname(igroup, ibin), '(A, I2.2)') trim(grp_short), ibin + if (cnsttype == I_CNSTTYPE_PROGNOSTIC) then ! Bins past maxbin are treated as diagnostic even if the group ! is prognostic and thus are not advected in the paerent model. if (ibin <= maxbin) then - write(btndname(igroup, ibin), '(A, I2.2)') trim(grp_short), ibin - write(c_name, '(A, I2.2)') trim(shortname), ibin write(c_longname, '(A, e11.4, A)') trim(name) // ', ', r(ibin)*1.e4_r8, ' um' @@ -381,8 +395,8 @@ subroutine carma_register call cnst_add(c_name, WTMOL_AIR, cpair, 0._r8, icnst4elem(ielem, ibin), & longname=c_longname, mixtype=carma_mixtype, is_convtran1=is_convtran1(igroup)) end if - end do - end if + end if + end do end do ! Find the constituent for the gas or add it if not found. @@ -508,16 +522,14 @@ end function carma_implements_cnst !! !! @author Chuck Bardeen !! @version May 2009 - subroutine carma_init + subroutine carma_init(pbuf2d) use cam_history, only: addfld, add_default, horiz_only - use ioFileMod, only : getfil use wrap_nf use time_manager, only: is_first_step use phys_control, only: phys_getopts - implicit none + type(physics_buffer_desc), pointer :: pbuf2d(:,:) - integer :: iz ! vertical index integer :: ielem ! element index integer :: ibin ! bin index integer :: igas ! gas index @@ -529,15 +541,10 @@ subroutine carma_init integer :: maxbin ! last prognostic bin logical :: is_cloud ! is the group a cloud? logical :: do_drydep ! is dry deposition enabled? + integer :: ncore ! number of core elements in the group - integer :: ier - integer :: ncid, dimid_lev, vid_T - logical :: lexist - character(len=256) :: locfn - integer :: nlev - integer :: LUNOPRT ! logical unit number for output - logical :: do_print ! do print output? logical :: history_carma + logical :: history_carma_srf_flx 1 format(a6,4x,a11,4x,a11,4x,a11) 2 format(i6,4x,3(1pe11.3,4x)) @@ -546,6 +553,7 @@ subroutine carma_init rc = 0 call phys_getopts(history_carma_out=history_carma) + history_carma_srf_flx = .false. ! Set names of constituent sources and declare them as history variables; howver, ! only prognostic variables have. @@ -589,9 +597,18 @@ subroutine carma_init call addfld(trim(etndname(ielem, ibin))//'SW', horiz_only, 'A', 'kg/m2/s', & trim(cnst_name(icnst)) // ' wet deposition flux at surface') + if (history_carma_srf_flx) then + call add_default(trim(etndname(ielem, ibin))//'EM', 1, ' ') + call add_default(trim(etndname(ielem, ibin))//'SF', 1, ' ') + call add_default(trim(etndname(ielem, ibin))//'SW', 1, ' ') + end if + if (do_drydep) then - call addfld(trim(etndname(ielem, ibin))//'DD', horiz_only, 'A', 'kg/m2/s ', & - trim(cnst_name(icnst)) // ' dry deposition') + call addfld(trim(etndname(ielem, ibin))//'DD', horiz_only, 'A', 'kg/m2/s ', & + trim(cnst_name(icnst)) // ' dry deposition') + if (history_carma_srf_flx) then + call add_default(trim(etndname(ielem, ibin))//'DD', 1, ' ') + end if end if if (carma_do_pheat) then @@ -604,7 +621,7 @@ subroutine carma_init end do do igroup = 1, NGROUP - call CARMAGROUP_Get(carma, igroup, rc, shortname=sname, is_cloud=is_cloud, do_drydep=do_drydep) + call CARMAGROUP_Get(carma, igroup, rc, shortname=sname, is_cloud=is_cloud, do_drydep=do_drydep, ncore=ncore) if (rc < 0) call endrun('carma_init::CARMAGROUP_GetGroup failed.') ! Gridbox average @@ -623,6 +640,7 @@ subroutine carma_init call addfld(trim(sname)//'PA', (/ 'lev' /), 'A', 'cm2', trim(sname) // ' projected area') call addfld(trim(sname)//'AR', (/ 'lev' /), 'A', ' ', trim(sname) // ' area ratio') call addfld(trim(sname)//'VM', (/ 'lev' /), 'A', 'm/s', trim(sname) // ' fall velocity') + call addfld(trim(sname)//'VR', (/ 'lev' /), 'A', 'kg/kg', trim(sname) // ' volatile mass mixing ratio') if (history_carma) then call add_default(trim(sname)//'ND', 1, ' ') @@ -636,6 +654,7 @@ subroutine carma_init call add_default(trim(sname)//'PA', 1, ' ') call add_default(trim(sname)//'AR', 1, ' ') call add_default(trim(sname)//'VM', 1, ' ') + call add_default(trim(sname)//'VR', 1, ' ') if (carma_do_grow) then call add_default(trim(sname)//'JN', 1, ' ') @@ -644,12 +663,39 @@ subroutine carma_init ! Per bin stats .. if (do_drydep) then - do ibin = 1, NBIN - call addfld(trim(btndname(igroup, ibin))//'VD', horiz_only, 'A', 'm/s', & - trim(btndname(igroup, ibin))//' dry deposition velocity') - end do + do ibin = 1, NBIN + call addfld(trim(btndname(igroup, ibin))//'VD', horiz_only, 'A', 'm/s', & + trim(btndname(igroup, ibin)) // ' dry deposition velocity') + end do end if + do ibin = 1, NBIN + call addfld(trim(btndname(igroup, ibin))//'ND', (/ 'lev' /), 'A', '#/cm3', & + trim(btndname(igroup, ibin)) // ' number density') + call addfld(trim(btndname(igroup, ibin))//'WR', (/ 'lev' /), 'A', 'um', & + trim(btndname(igroup, ibin)) // ' wet radius') + call addfld(trim(btndname(igroup, ibin))//'RO', (/ 'lev' /), 'A', 'g/cm3', & + trim(btndname(igroup, ibin)) // ' wet particle density') + call addfld(trim(btndname(igroup, ibin))//'VR', (/ 'lev' /), 'A', 'um', & + trim(btndname(igroup, ibin)) // ' volatile mixing ratio') + + + if ((carma_ndebugpkgs > 0) .and. (ncore > 0)) then + call addfld(trim(btndname(igroup, ibin))//'LCFM', horiz_only, 'A', 'kg/m2', trim(btndname(igroup, ibin)) // ' CARMA local mass fixer fail mass ') + call addfld(trim(btndname(igroup, ibin))//'LCFP', horiz_only, 'A', 'probability', trim(btndname(igroup, ibin)) // ' CARMA mass local fail PDF') + call addfld(trim(btndname(igroup, ibin))//'LCR', (/ 'lev' /), 'A', 'kg/kg', trim(btndname(igroup, ibin)) // ' CARMA local mass fix MMR') + call addfld(trim(btndname(igroup, ibin))//'LCP', (/ 'lev' /), 'A', 'probability', trim(btndname(igroup, ibin)) // ' CARMA local fix PDF') + + if (carma_diags_file > 0) then + call add_default(trim(btndname(igroup, ibin))//'LCFM', carma_diags_file, ' ') + call add_default(trim(btndname(igroup, ibin))//'LCFP', carma_diags_file, ' ') + call add_default(trim(btndname(igroup, ibin))//'LCR', carma_diags_file, ' ') + call add_default(trim(btndname(igroup, ibin))//'LCP', carma_diags_file, ' ') + end if + end if + + end do + end do do igas = 1, NGAS @@ -708,105 +754,20 @@ subroutine carma_init if (carma%f_igash2o /= 0) call carma_getH2O(carma_h2o_ref) if (carma%f_igash2So4 /= 0) call carma_getH2SO4(carma_h2so4_ref) end if - - if (masterproc) then - call CARMA_Get(carma, rc, do_print=do_print, LUNOPRT=LUNOPRT) - if (rc < 0) call endrun('carma_init::CARMA_Get failed.') - - if (do_print) write(LUNOPRT,*) "" - if (do_print) write(LUNOPRT,*) "CARMA initializing to fixed reference state." - if (do_print) write(LUNOPRT,*) "" - - ! For temperature, get the average temperature from reference temperature file - ! if it exists or from the initial condition file if the reference temperature file - ! doesn't exist. - ! - ! NOTE: The reference temperature file will only be created for an inital run. It - ! must already exist for a restart run. - - ! Does reference temperature file already exist? - call getfil(carma_reftfile, locfn, iflag=1) - - inquire(file=locfn, exist=lexist) - - ! Read the reference temperature from the file. - if (lexist) then - - ! Open the netcdf file. - call wrap_open(trim(locfn), NF90_NOWRITE, ncid) - - ! Inquire about dimensions - call wrap_inq_dimid(ncid, 'lev', dimid_lev) - call wrap_inq_dimlen(ncid, dimid_lev, nlev) - - ! Does the number of levels match? - if (nlev /= pver) then - call endrun("carma_init::ERROR - Incompatible number of levels & - &in the CARMA reference temperature file ... " // trim(locfn)) - end if - - ! Get variable ID for reference temperature - call wrap_inq_varid(ncid, 'T', vid_T) - - ! Read in the temperature data. - call wrap_get_var_realx(ncid, vid_T, carma_T_ref) - - if (carma%f_igash2o /= 0) then - ! Get variable ID for reference temperature - call wrap_inq_varid(ncid, 'Q', vid_T) - - ! Read in the temperature data. - call wrap_get_var_realx(ncid, vid_T, carma_h2o_ref) - end if - - if (carma%f_igash2so4 /= 0) then - ! Get variable ID for reference temperature - call wrap_inq_varid(ncid, 'H2SO4', vid_T) - - ! Read in the temperature data. - call wrap_get_var_realx(ncid, vid_T, carma_h2so4_ref) - end if - - ! Close the file - call wrap_close(ncid) - - ! Is this an initial or restart run? - else if (is_first_step()) then - - if (do_print) write(LUNOPRT,*) "" - if (do_print) write(LUNOPRT,*) 'Creating CARMA reference temperature file ... ', trim(locfn) - - ! Save the average into a file to be used for restarts. - call CARMA_CreateRefTFile(carma, locfn, pref_mid(:) / 100._r8, & - carma_t_ref(:), rc, refh2o=carma_h2o_ref(:), refh2so4=carma_h2so4_ref(:)) - else - - ! The file must already exist for a restart run. - call endrun("carma_init::ERROR - Can't find the CARMA reference temperature file ... " // trim(carma_reftfile)) - - end if - - ! Write out the values that are being used. - if (do_print) write(LUNOPRT,*) "" - if (do_print) write(LUNOPRT,1) "Level","Int P (Pa)","Mid P (Pa)","Mid T (K)" - - do iz = 1, pver - if (do_print) write(LUNOPRT,2) iz, pref_edge(iz), pref_mid(iz), carma_t_ref(iz) - end do - if (do_print) write(LUNOPRT,2) iz, pref_edge(iz), 0.0_r8, 0.0_r8 - if (do_print) write(LUNOPRT,*) "" - end if - -#ifdef SPMD - - ! Communicate the settings to the other MPI tasks. - call mpi_bcast(carma_t_ref, pver, MPI_REAL8, 0, mpicom, ier) -#endif end if + if (is_first_step()) then + ! initialize physics buffer fields + do igas = 1, NGAS + call pbuf_set_field(pbuf2d, ipbuf4gas(igas), 0.0_r8) + call pbuf_set_field(pbuf2d, ipbuf4sati(igas), 0.0_r8) + call pbuf_set_field(pbuf2d, ipbuf4satl(igas), 0.0_r8) + end do + call pbuf_set_field(pbuf2d, ipbuf4t, 0.0_r8) + endif ! Do a model specific initialization. - call CARMA_InitializeModel(carma, lq_carma, rc) + call CARMAMODEL_InitializeModel(carma, lq_carma, pbuf2d, rc) if (rc < 0) call endrun('carma_init::CARMA_InitializeModel failed.') return @@ -846,9 +807,9 @@ subroutine carma_final glob_nretry / glob_nstep else if (do_print) write(LUNOPRT,2) glob_max_nsubstep, & - 0., & + 0._r8, & glob_max_nretry, & - 0. + 0._r8 end if end if end if @@ -902,7 +863,7 @@ end subroutine carma_timestep_init !! @version May-2009 subroutine carma_timestep_tend(state, cam_in, cam_out, ptend, dt, pbuf, dlf, rliq, prec_str, snow_str, & prec_sed, snow_sed, ustar, obklen) - use time_manager, only: get_nstep, get_step_size, is_first_step + use time_manager, only: get_nstep, is_first_step use camsrfexch, only: cam_in_t, cam_out_t use planck, only: planckIntensity @@ -968,9 +929,12 @@ subroutine carma_timestep_tend(state, cam_in, cam_out, ptend, dt, pbuf, dlf, rli real(r8) :: ar(pver) ! Area Ratio real(r8) :: vm(pver) ! Massweighted fall velocity (cm2) real(r8) :: jn(pver) ! nucleation (cm-3) + real(r8) :: totalmmr(pver) ! total particle mmr (kg/kg) real(r8) :: numberDensity(pver) ! number density (cm-3) real(r8) :: nucleationRate(pver) ! nucleation rate (cm-3 s-1) real(r8) :: extinctionCoefficient(pver) ! extinction coefficient (cm2) + real(r8) :: r_wet(pver) ! wet radius (um) + real(r8) :: rhop_wet(pver) ! wet particle density (g/cm3) real(r8) :: dd ! dry deposition (kg/m2) real(r8) :: vd ! dry deposition velocity (cm/s) real(r8) :: vf(pverp) ! fall velocity (cm/s) @@ -986,7 +950,6 @@ subroutine carma_timestep_tend(state, cam_in, cam_out, ptend, dt, pbuf, dlf, rli real(r8), pointer, dimension(:,:) :: tnd_qsnow ! external tendency on snow mass (kg/kg/s) real(r8), pointer, dimension(:,:) :: tnd_nsnow ! external tendency on snow number(#/kg/s) real(r8), pointer, dimension(:,:) :: re_ice ! ice effective radius (m) - integer :: lchnk ! chunk identifier integer :: iz real(r8) :: cldfrc(pver) ! cloud fraction [fraction] real(r8) :: rhcrit(pver) ! relative humidity for onset of liquid clouds [fraction] @@ -1010,7 +973,6 @@ subroutine carma_timestep_tend(state, cam_in, cam_out, ptend, dt, pbuf, dlf, rli logical :: is_ice ! is the group ice? logical :: grp_do_drydep ! is dry depostion enabled for group? logical :: do_drydep ! is dry depostion enabled? - logical :: do_fixedinit ! do initialization from reference atm? logical :: do_detrain ! do convective detrainment? integer :: iwvl real(r8), parameter :: zzocen = 0.0001_r8 ! Ocean aerodynamic roughness length [m] @@ -1048,8 +1010,6 @@ subroutine carma_timestep_tend(state, cam_in, cam_out, ptend, dt, pbuf, dlf, rli call cnst_get_ind('Q', icnst_q) ! Get pointers into pbuf ... - lchnk = state_loc%lchnk - call pbuf_get_field(pbuf, ipbuf4t, t_ptr) ! If doing particle heating, then get pointers to the spectral flux data provided @@ -1080,11 +1040,10 @@ subroutine carma_timestep_tend(state, cam_in, cam_out, ptend, dt, pbuf, dlf, rli ! If initializing CARMASTATE from a reference state, do it before entering the main ! loop. ! - call CARMA_Get(carma, rc, do_fixedinit=do_fixedinit, do_drydep=do_drydep) + call CARMA_Get(carma, rc, do_drydep=do_drydep) if (rc < 0) call endrun('carma_timestep_tend::CARMA_Get failed.') - if (do_fixedinit) then - + if (carma_do_fixedinit) then call CARMASTATE_CreateFromReference(cstate, & carma_ptr, & time, & @@ -1101,7 +1060,7 @@ subroutine carma_timestep_tend(state, cam_in, cam_out, ptend, dt, pbuf, dlf, rli rc, & qh2o=carma_h2o_ref, & qh2so4=carma_h2so4_ref) - if (rc < 0) call endrun('carma_timestep_tend::CARMASTATE_CreateFromReference failed.') + if (rc < 0) call endrun('carma_timestep_tend::CARMASTATE_CreateFromReference failed.') end if @@ -1227,7 +1186,7 @@ subroutine carma_timestep_tend(state, cam_in, cam_out, ptend, dt, pbuf, dlf, rli end do - call CARMA_DiagnoseBins(carma, cstate, state_loc, pbuf, icol, dt, rc, rliq=rliq, prec_str=prec_str, snow_str=snow_str) + call CARMAMODEL_DiagnoseBins(carma, cstate, state_loc, pbuf, icol, dt, rc, rliq=rliq, prec_str=prec_str, snow_str=snow_str) if (rc < 0) call endrun('carma_timestep_tend::CARMA_DiagnoseBins failed.') @@ -1237,7 +1196,7 @@ subroutine carma_timestep_tend(state, cam_in, cam_out, ptend, dt, pbuf, dlf, rli if (rc < 0) call endrun('CARMA_Detrain::CARMA_Get failed.') if (do_detrain) then - call CARMA_Detrain(carma, cstate, cam_in, dlf, state_loc, icol, dt, rc, rliq=rliq, prec_str=prec_str, & + call CARMAMODEL_Detrain(carma, cstate, cam_in, dlf, state_loc, icol, dt, rc, rliq=rliq, prec_str=prec_str, & snow_str=snow_str, tnd_qsnow=tnd_qsnow, tnd_nsnow=tnd_nsnow) if (rc < 0) call endrun('carma_timestep_tend::CARMA_Detrain failed.') end if @@ -1312,11 +1271,11 @@ subroutine carma_timestep_tend(state, cam_in, cam_out, ptend, dt, pbuf, dlf, rli ! NOTE: To work around an XL Fortran compiler bug, the optional arguments can only ! be passed when defined. if (present(rliq)) then - call CARMA_DiagnoseBulk(carma, cstate, cam_out, state_loc, pbuf, ptend, icol, dt, rc, & + call CARMAMODEL_DiagnoseBulk(carma, cstate, cam_out, state_loc, pbuf, ptend, icol, dt, rc, & rliq=rliq, prec_str=prec_str, snow_str=snow_str, prec_sed=prec_sed, & snow_sed=snow_sed, tnd_qsnow=tnd_qsnow, tnd_nsnow=tnd_nsnow, re_ice=re_ice) else - call CARMA_DiagnoseBulk(carma, cstate, cam_out, state_loc, pbuf, ptend, icol, dt, rc) + call CARMAMODEL_DiagnoseBulk(carma, cstate, cam_out, state_loc, pbuf, ptend, icol, dt, rc) end if if (rc < 0) call endrun('carma_timestep_tend::CARMASTATE_DiagnoseBulk failed.') @@ -1351,7 +1310,8 @@ subroutine carma_timestep_tend(state, cam_in, cam_out, ptend, dt, pbuf, dlf, rli do ibin = 1, NBIN call CARMASTATE_GetBin(cstate, ielem, ibin, newstate(:), rc, & - numberDensity=numberDensity, nucleationRate=nucleationRate, surface=dd, vd=vd, vf=vf, dtpart=dtpart) + numberDensity=numberDensity, nucleationRate=nucleationRate, r_wet=r_wet, & + rhop_wet=rhop_wet, sedimentationflux=dd, vd=vd, vf=vf, dtpart=dtpart, totalmmr=totalmmr) if (rc < 0) call endrun('carma_timestep_tend::CARMASTATE_GetBin failed.') ! For prognostic groups, set the tendency from the corresponding constituents. @@ -1367,7 +1327,7 @@ subroutine carma_timestep_tend(state, cam_in, cam_out, ptend, dt, pbuf, dlf, rli ptend%q(icol, :, icnst) = (newstate(:) - state_loc%q(icol, :, icnst)) / dt if (grp_do_drydep) then - sbdiags(icol, ibin, ielem, SBDIAGS_DD) = dd / dt + sbdiags(icol, ibin, ielem, SBDIAGS_DD) = dd sbdiags(icol, ibin, ielem, SBDIAGS_VD) = - vd / 100._r8 end if end if @@ -1382,7 +1342,7 @@ subroutine carma_timestep_tend(state, cam_in, cam_out, ptend, dt, pbuf, dlf, rli re3(:) = re3(:) + numberDensity(:) * ((r(ibin)*rrat(ibin))**3) ad(:) = ad(:) + numberDensity(:) * 4.0_r8 * PI * (r(ibin)**2) * 1.0e8_r8 md(:) = md(:) + numberDensity(:) * rmass(ibin) - mr(:) = mr(:) + newstate(:) + mr(:) = mr(:) + totalmmr(:) pa(:) = pa(:) + numberDensity(:) * PI * ((r(ibin) * rrat(ibin))**2) * arat(ibin) vm(:) = vm(:) + numberDensity(:) * rmass(ibin) * vf(2:) / 100._f @@ -1397,6 +1357,9 @@ subroutine carma_timestep_tend(state, cam_in, cam_out, ptend, dt, pbuf, dlf, rli od(:) = od(:) + numberDensity(:) * extinctionCoefficient(:) * dz(:) * 100._r8 end if + bndiags(icol,:,ibin,ielem,BNDIAGS_VR) = bndiags(icol,:,ibin,ielem,BNDIAGS_VR) + totalmmr(:) + gpdiags(icol, :, igroup, GPDIAGS_VR) = gpdiags(icol, :, igroup, GPDIAGS_VR) + totalmmr(:) + ! Particle temperatures from particle heating. if (carma_do_pheat) then bndiags(icol, :, ibin, ielem, BNDIAGS_TP) = dtpart(:) @@ -1405,6 +1368,12 @@ subroutine carma_timestep_tend(state, cam_in, cam_out, ptend, dt, pbuf, dlf, rli if (nucleationRate(1) /= CAM_FILL) then jn(:) = jn(:) + nucleationRate(:) end if + + ! Output nd and wet radius for each bin. + r_wet = r_wet * 1e4_r8 ! cm to um + bndiags(icol,:,ibin,ielem,BNDIAGS_WETR) = r_wet(:) + bndiags(icol,:,ibin,ielem,BNDIAGS_ND) = numberDensity(:) + bndiags(icol,:,ibin,ielem,BNDIAGS_RO) = rhop_wet(:) end do ! If this is the number element for the group, then write out the @@ -1454,7 +1423,7 @@ subroutine carma_timestep_tend(state, cam_in, cam_out, ptend, dt, pbuf, dlf, rli call pbuf_get_field(pbuf, ipbuf4satl(igas), satl_ptr) call CARMASTATE_GetGas(cstate, igas, newstate(:), rc, satice=satice, satliq=satliq, & - eqice=eqice, eqliq=eqliq, wtpct=wtpct) + eqice=eqice, eqliq=eqliq, wtpct=wtpct) if (rc < 0) call endrun('carma_timestep_tend::CARMASTATE_GetGas failed.') icnst = icnst4gas(igas) @@ -1492,7 +1461,9 @@ subroutine carma_timestep_tend(state, cam_in, cam_out, ptend, dt, pbuf, dlf, rli if (rc < 0) call endrun('carma_timestep_tend::CARMASTATE_Get failed.') spdiags(icol, :, SPDIAGS_NSTEP) = zsubsteps(:) - spdiags(icol, :, SPDIAGS_LNSTEP) = log(zsubsteps(:)) + where (zsubsteps/=0.0_r8) + spdiags(icol, :, SPDIAGS_LNSTEP) = log(zsubsteps(:)) + end where end if end do @@ -1517,14 +1488,35 @@ subroutine carma_timestep_tend(state, cam_in, cam_out, ptend, dt, pbuf, dlf, rli call CARMASTATE_Destroy(cstate, rc) if (rc < 0) call endrun('carma_timestep_tend::CARMASTATE_Destroy failed.') - ! Output diagnostic fields. - call carma_output_diagnostics(state_loc, ptend, gpdiags, sbdiags, gsdiags, spdiags, bndiags) + call carma_output_diagnostics(state_loc, ptend, pbuf, cam_in, gpdiags, sbdiags, gsdiags, spdiags, bndiags) end subroutine carma_timestep_tend + !! Get the index for the constituents array for the specified bin + !! of the specified element. + !! + !! @author Yunqian Zhu, Francis Vitt + !! @version September-2022 + subroutine carma_getcnstforbin(ielem, ibin, icnst) + implicit none + + integer, intent(in) :: ielem, ibin + integer, intent(out) :: icnst + + icnst = icnst4elem(ielem,ibin) + return + end subroutine carma_getcnstforbin + + !! Collect CARMA substep statistics from all MPI tasks. + !! + !! @author Chuck Bardeen + !! @version May-2009 subroutine carma_accumulate_stats() +#if ( defined SPMD ) + use mpishorthand +#endif implicit none integer :: istat @@ -1600,9 +1592,9 @@ subroutine carma_accumulate_stats() step_nretry / step_nstep else if (do_print) write(LUNOPRT,1) step_max_nsubstep, & - 0., & + 0._r8, & step_max_nretry, & - 0. + 0._r8 end if end if end if @@ -1665,7 +1657,7 @@ subroutine carma_init_cnst(name, latvals, lonvals, mask, q) end where end do - call CARMA_InitializeParticle(carma, ielem, ibin, latvals, lonvals, mask, q, rc) + call CARMAMODEL_InitializeParticle(carma, ielem, ibin, latvals, lonvals, mask, q, rc) if (rc < 0) call endrun('carma_init_cnst::CARMA_InitializeParticle failed.') end if end if @@ -1679,19 +1671,21 @@ subroutine carma_init_cnst(name, latvals, lonvals, mask, q) return end subroutine carma_init_cnst - !! Outputs tracer tendencies and diagnositc fields to the history files. !! All the columns in the chunk should be output at the same time. !! !! @author Chuck Bardeen !! @version May-2009 - subroutine carma_output_diagnostics(state, ptend, gpdiags, sbdiags, gsdiags, spdiags, bndiags) + subroutine carma_output_diagnostics(state, ptend, pbuf, cam_in, gpdiags, sbdiags, gsdiags, spdiags, bndiags) use cam_history, only: outfld + use camsrfexch, only: cam_in_t implicit none type(physics_state), intent(in) :: state !! Physics state variables - before CARMA type(physics_ptend), intent(in) :: ptend !! indivdual parameterization tendencies + type(physics_buffer_desc), pointer :: pbuf(:) !! physics buffer + type(cam_in_t), intent(in) :: cam_in !! surface inputs real(r8), intent(in), dimension(pcols, pver, NGROUP, NGPDIAGS) :: gpdiags !! CARMA group diagnostic output real(r8), intent(in), dimension(pcols, NBIN, NELEM, NSBDIAGS) :: sbdiags !! CARMA surface bin diagnostic output real(r8), intent(in), dimension(pcols, pver, NGAS, NGSDIAGS) :: gsdiags !! CARMA gas diagnostic output @@ -1706,7 +1700,6 @@ subroutine carma_output_diagnostics(state, ptend, gpdiags, sbdiags, gsdiags, spd integer :: ienconc ! element index for group's concentration element integer :: icnst ! constituent index integer :: lchnk ! chunk identifier - integer :: ncol ! number of columns integer :: rc ! CARMA return code character(len=8) :: sname ! short (CAM) name integer :: cnsttype ! constituent type @@ -1714,12 +1707,13 @@ subroutine carma_output_diagnostics(state, ptend, gpdiags, sbdiags, gsdiags, spd logical :: is_cloud ! is the group a cloud? logical :: do_drydep ! is dry deposition enabled? + character(len=*), parameter :: subname = 'carma_output_diagnostics' + ! Initialize the return code. rc = 0 ! Check each column int the chunk. lchnk = state%lchnk - ncol = state%ncol ! Output step diagnostics. if (carma_do_substep) then @@ -1732,10 +1726,10 @@ subroutine carma_output_diagnostics(state, ptend, gpdiags, sbdiags, gsdiags, spd do ibin = 1, NBIN call CARMAELEMENT_Get(carma, ielem, rc, igroup=igroup) - if (rc < 0) call endrun('carma_timestep_tend::CARMAELEMENT_Get failed.') + if (rc < 0) call endrun(subname//'::CARMAELEMENT_Get failed.') call CARMAGROUP_Get(carma, igroup, rc, cnsttype=cnsttype, maxbin=maxbin, do_drydep=do_drydep) - if (rc < 0) call endrun('carma_timestep_tend::CARMAGROUP_Get failed.') + if (rc < 0) call endrun(subname//'::CARMAGROUP_Get failed.') if (cnsttype == I_CNSTTYPE_PROGNOSTIC) then @@ -1766,7 +1760,7 @@ subroutine carma_output_diagnostics(state, ptend, gpdiags, sbdiags, gsdiags, spd ! Output the particle diagnostics. do igroup = 1, NGROUP call CARMAGROUP_Get(carma, igroup, rc, shortname=sname, is_cloud=is_cloud, do_drydep=do_drydep, ienconc=ienconc) - if (rc < 0) call endrun('carma_output_diagnostics::CARMAGROUP_Get failed.') + if (rc < 0) call endrun(subname//'::CARMAGROUP_Get failed.') ! Gridbox average call outfld(trim(sname)//'ND', gpdiags(:, :, igroup, GPDIAGS_ND), pcols, lchnk) @@ -1781,12 +1775,20 @@ subroutine carma_output_diagnostics(state, ptend, gpdiags, sbdiags, gsdiags, spd call outfld(trim(sname)//'PA', gpdiags(:, :, igroup, GPDIAGS_PA), pcols, lchnk) call outfld(trim(sname)//'AR', gpdiags(:, :, igroup, GPDIAGS_AR), pcols, lchnk) call outfld(trim(sname)//'VM', gpdiags(:, :, igroup, GPDIAGS_VM), pcols, lchnk) + call outfld(trim(sname)//'VR', gpdiags(:, :, igroup, GPDIAGS_VR), pcols, lchnk) if (do_drydep) then do ibin = 1, NBIN call outfld(trim(btndname(igroup, ibin))//'VD', sbdiags(:, ibin, ienconc, SBDIAGS_VD), pcols, lchnk) end do end if + + do ibin = 1,NBIN + call outfld(trim(btndname(igroup, ibin))//'ND',bndiags(:, :, ibin, ienconc, BNDIAGS_ND), pcols, lchnk) + call outfld(trim(btndname(igroup, ibin))//'WR',bndiags(:, :, ibin, ienconc, BNDIAGS_WETR), pcols, lchnk) + call outfld(trim(btndname(igroup, ibin))//'RO',bndiags(:, :, ibin, ienconc, BNDIAGS_RO), pcols, lchnk) + call outfld(trim(btndname(igroup, ibin))//'VR',bndiags(:, :, ibin, ienconc, BNDIAGS_VR), pcols, lchnk) + end do end do ! Output the gas tendencies. @@ -1808,19 +1810,21 @@ subroutine carma_output_diagnostics(state, ptend, gpdiags, sbdiags, gsdiags, spd call outfld('CRTT', ptend%s(:, :) / cpair, pcols, lchnk) end if + ! Allow models to output their own diagnostics + call CARMAMODEL_OutputDiagnostics(carma, icnst4elem, state, ptend, pbuf, cam_in, rc) + return end subroutine carma_output_diagnostics - !! Calculate the emissions for CARMA aerosols. This is taken from !! the routine aerosol_emis_intr in aerosol_intr.F90 and dust_emis_intr in !! dust_intr.F90 by Phil Rasch. !! !! @author Chuck Bardeen !! @version May-2009 - subroutine carma_emission_tend (state, ptend, cam_in, dt) - use cam_history, only: outfld - use camsrfexch, only: cam_in_t + subroutine carma_emission_tend (state, ptend, cam_in, dt, pbuf) + use cam_history, only: outfld + use camsrfexch, only: cam_in_t implicit none @@ -1828,6 +1832,7 @@ subroutine carma_emission_tend (state, ptend, cam_in, dt) type(physics_ptend), intent(inout) :: ptend !! physics state tendencies type(cam_in_t), intent(inout) :: cam_in !! surface inputs real(r8), intent(in) :: dt !! time step (s) + type(physics_buffer_desc), pointer :: pbuf(:) !! physics buffer integer :: lchnk ! chunk identifier integer :: ncol ! number of columns in chunk @@ -1873,7 +1878,7 @@ subroutine carma_emission_tend (state, ptend, cam_in, dt) icnst = icnst4elem(ielem, ibin) - call CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tendency, surfaceFlux, rc) + call CARMAMODEL_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tendency, surfaceFlux, pbuf, rc) if (rc < 0) call endrun('carma_emission_tend::CARMA_EmitParticle failed.') ! Add any surface flux here. @@ -1908,7 +1913,6 @@ end subroutine carma_emission_tend subroutine carma_wetdep_tend(state, ptend, dt, pbuf, dlf, cam_out) use cam_history, only: outfld use phys_control, only: cam_physpkg_is - use phys_grid, only: get_lat_all_p, get_lon_all_p, get_rlat_all_p use wetdep, only: clddiag, wetdepa_v1, wetdepa_v2 use camsrfexch, only: cam_out_t use physconst, only: gravit @@ -1942,7 +1946,7 @@ subroutine carma_wetdep_tend(state, ptend, dt, pbuf, dlf, cam_out) integer :: ixcldice real(r8) :: totcond(pcols, pver) ! total condensate real(r8) :: solfac(pcols, pver) ! solubility factor - real(r8) :: solfactor + real(r8) :: solfac_in ! solubility factor real(r8) :: scavcoef ! scavenging Coefficient logical :: do_wetdep integer :: ncol ! number of columns @@ -2030,11 +2034,11 @@ subroutine carma_wetdep_tend(state, ptend, dt, pbuf, dlf, cam_out) if (rc < 0) call endrun('carma_wetdep_tend::CARMAELEMENT_Get failed.') call CARMAGROUP_Get(carma, igroup, rc, cnsttype=cnsttype, do_wetdep=do_wetdep, & - solfac=solfactor, scavcoef=scavcoef, maxbin=maxbin) - solfac(:ncol,:) = solfactor - + solfac=solfac_in, scavcoef=scavcoef, maxbin=maxbin) if (rc < 0) call endrun('carma_wetdep_tend::CARMAGROUP_Get failed.') + solfac(:,:) = solfac_in + if ((do_wetdep) .and. (cnsttype == I_CNSTTYPE_PROGNOSTIC)) then do ibin = 1, NBIN @@ -2099,7 +2103,7 @@ subroutine carma_wetdep_tend(state, ptend, dt, pbuf, dlf, cam_out) iscavt, & cldv, & fracis(:, :, icnst), & - solfactor, & + solfac_in, & ncol, & z_scavcoef) else @@ -2122,7 +2126,7 @@ subroutine carma_wetdep_tend(state, ptend, dt, pbuf, dlf, cam_out) call outfld(trim(cnst_name(icnst))//'SW', sflx, pcols, lchnk) ! Add this to the surface amount of the constituent - call CARMA_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) + call CARMAMODEL_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) end if end do @@ -2138,10 +2142,114 @@ end subroutine carma_wetdep_tend !! code to include the impact of CARMA particles in the radiative transfer !! calculation. !! + !! The opticsType that is specified for the group determines how the optical + !! properties will be generated for that group. Each group can use a different + !! optics method if needed. Refractive indices need for these calculation are + !! are specified in the group's elements rather than at the group level. This + !! allows various mixing approaches to be used to determine the refractive index + !! for the particle as a whole. + !! + !! The I_OPTICS_MIXED_YU2105 and I_OPTICS_SULFATE_YU2015 optics methods are + !! designed to trop_strat models as define in the Yu et al. (2015) paper. The + !! other optics types can be applied more generically to a number of different + !! aerosol/cloud models. + !! !! NOTE: The format of this file is determined by the needs of the radiative tranfer !! code, so ideally a routine would exist in that module that could create a file !! with the proper format. Since that doesn't exist, we do it all here. subroutine CARMA_CreateOpticsFile(carma, rc) + + implicit none + + type(carma_type), intent(inout) :: carma !! the carma object + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Local variables + integer :: igroup + logical :: do_mie + integer :: cnsttype ! constituent type + integer :: opticsType + + ! Assume success. + rc = 0 + + ! Process each group that is defined in the model. + do igroup = 1, NGROUP + + ! Get the necessary group properties. + call CARMAGROUP_Get(carma, igroup, rc, do_mie=do_mie, cnsttype=cnsttype, iopticstype=opticsType) + if (rc < 0) call endrun('carma_CreateOpticsFile::CARMAGROUP_Get failed.') + + ! Are we supposed to do the mie calculation for this group? + if ((do_mie) .and. (cnsttype == I_CNSTTYPE_PROGNOSTIC)) then + + ! What type of calculation is needed for this group? + ! + ! NOTE: Some of these calculations generate optical properties as single mass + ! coefficients, while others are lookup tables designed around multiple + ! dimensions. + select case (opticsType) + + ! This is for fixed composition, but the particle may swell in response + ! to changes in RH. Only one refractive index specified at the group level. + ! + ! NOTE: This is what was used by the first CARMA models that were radiatively + ! active. + case (I_OPTICS_FIXED) + call CARMA_CreateOpticsFile_Fixed(carma, igroup, rc) + if (rc < 0) call endrun('carma_CreateOpticsFile::CreateOpticsFile_Fixed failed.') + + ! This is similar to Yu (2015) in that handles mixed particles treated as + ! core shell particles; however the dimensions of the lookup table are the + ! the radii and the refractive indicies, so it can be used with various + ! aerosol configurations (not just as in the Yu(2015)). + case(I_OPTICS_MIXED_CORESHELL) + call endrun('carma_CreateOpticsFile mixed_coreshell has not been implemented.') + + ! This is similar to MAM4, in that a volume mixing approach is used to + ! mixed both the core and the shell together and thus only one radius and + ! one refractive index are needed in the lookup table. + case(I_OPTICS_MIXED_VOLUME) + call endrun('carma_CreateOpticsFile mixed_volume has not been implemented.') + + ! This is similar to "mixed_volume", except that Maxwell-Garnett mixing + ! is used instead of volume mixing. + case(I_OPTICS_MIXED_MAXWELL) + call endrun('carma_CreateOpticsFile mixed_maxwell has not been implemented.') + + ! This is for a pure sulfate group where the table is based upon weight + ! percent; however, unlike sulfate_Yu, the refractive index of the sulfate + ! changes with the weight percent of H2SO4. + case(I_OPTICS_SULFATE) + call CARMA_CreateOpticsFile_Sulfate(carma, igroup, rc) + if (rc < 0) call endrun('carma_CreateOpticsFile::CreateOpticsFile_Sulfate failed.') + + ! Other types are not generically useful are are particular to the + ! specific model, so thos are handled by model specific code. These + ! include: + ! I_OPTICS_MIXED_YU2015 + ! I_OPTICS_MIXED_YU_H2O + ! I_OPTICS_SULFATE_YU2015 + case default + call CARMAMODEL_CreateOpticsFile(carma, igroup, opticsType, rc) + + end select + end if + end do + + return + end subroutine CARMA_CreateOpticsFile + + + !! This routine creates files containing optical properties for each radiatively + !! active particle type. These optical properties are used by the RRTMG radiation + !! code to include the impact of CARMA particles in the radiative transfer + !! calculation. + !! + !! NOTE: The format of this file is determined by the needs of the radiative tranfer + !! code, so ideally a routine would exist in that module that could create a file + !! with the proper format. Since that doesn't exist, we do it all here. + subroutine CARMA_CreateOpticsFile_Fixed(carma, igroup, rc) use radconstants, only : nswbands, nlwbands use wrap_nf use wetr, only : getwetr @@ -2149,16 +2257,17 @@ subroutine CARMA_CreateOpticsFile(carma, rc) implicit none type(carma_type), intent(inout) :: carma !! the carma object + integer, intent(in) :: igroup !! group index integer, intent(out) :: rc !! return code, negative indicates failure ! Local variables - integer :: igroup, ibin, iwave, irh + integer :: ibin, iwave, irh integer :: irhswell integer :: ienconc real(kind=f) :: rho(NBIN), rhopwet real(kind=f) :: r(NBIN), rmass(NBIN), rlow(NBIN), rup(NBIN) real(kind=f) :: wave(NWAVE) - complex(kind=f) :: refidx(NWAVE) + complex(kind=f) :: refidx(NWAVE, NREFIDX) character(len=CARMA_NAME_LEN) :: name character(len=CARMA_SHORT_NAME_LEN) :: shortname logical :: do_mie @@ -2199,381 +2308,661 @@ subroutine CARMA_CreateOpticsFile(carma, rc) call CARMA_GET(carma, rc, wave=wave, do_print=do_print, LUNOPRT=LUNOPRT) if (rc < 0) call endrun('carma_CreateOpticsFile::CARMA_Get failed.') - ! Process each group that is defined in the model. - do igroup = 1, NGROUP + ! Get the necessary group properties. + call CARMAGROUP_Get(carma, igroup, rc, do_mie=do_mie, name=name, shortname=shortname, r=r, & + rlow=rlow, rup=rup, rmass=rmass, irhswell=irhswell, & + ienconc=ienconc, cnsttype=cnsttype, maxbin=maxbin) + if (rc < 0) call endrun('carma_CreateOpticsFile::CARMAGROUP_Get failed.') - ! Get the necessary group properties. - call CARMAGROUP_Get(carma, igroup, rc, do_mie=do_mie, name=name, shortname=shortname, r=r, & - rlow=rlow, rup=rup, rmass=rmass, refidx=refidx, irhswell=irhswell, & - ienconc=ienconc, cnsttype=cnsttype, maxbin=maxbin) - if (rc < 0) call endrun('carma_CreateOpticsFile::CARMAGROUP_Get failed.') + call CARMAELEMENT_Get(carma, ienconc, rc, rho=rho, refidx=refidx) + if (rc < 0) call endrun('carma_CreateOpticsFile::CARMAELEMENT_Get failed.') - ! Are we supposed to do the mie calculation for this group? - if ((do_mie) .and. (cnsttype == I_CNSTTYPE_PROGNOSTIC)) then + ! A file needs to be created for each bin. + do ibin = 1, NBIN - call CARMAELEMENT_Get(carma, ienconc, rc, rho=rho) - if (rc < 0) call endrun('carma_CreateOpticsFile::CARMAELEMENT_Get failed.') + ! Bins past maxbin are treated as diagnostic even if the group + ! is prognostic and thus are not advected in the paerent model. + if (ibin <= maxbin) then - ! A file needs to be created for each bin. - do ibin = 1, NBIN + write(c_name, '(A, I2.2)') trim(shortname), ibin - ! Bins past maxbin are treated as diagnostic even if the group - ! is prognostic and thus are not advected in the paerent model. - if (ibin <= maxbin) then + ! Construct the path to the file. Each model will have its own subdirectory + ! where the optical property files are stored. + filepath = trim(carma_model) // '_' // trim(c_name) // '_rrtmg.nc' - write(c_name, '(A, I2.2)') trim(shortname), ibin + if (do_print) write(LUNOPRT,*) 'Creating CARMA optics file ... ', trim(filepath) - ! Construct the path to the file. Each model will have its own subdirectory - ! where the optical property files are stored. - filepath = trim(carma_model) // '_' // trim(c_name) // '_rrtmg.nc' + ! Create the file. + call wrap_create(filepath, NF90_CLOBBER, fid) - if (do_print) write(LUNOPRT,*) 'Creating CARMA optics file ... ', trim(filepath) + ! For non-hygroscopic, only use 1 RH value. + if (irhswell /= 0) then + nrh = NMIE_RH + else + nrh = min(NMIE_RH, 1) + end if - ! Create the file. - call wrap_create(filepath, NF90_CLOBBER, fid) + ! Define the dimensions: rh, lwbands, swbands + call wrap_def_dim(fid, 'rh_idx', nrh, rhdim) + call wrap_def_dim(fid, 'lw_band', nlwbands, lwdim) + call wrap_def_dim(fid, 'sw_band', nswbands, swdim) - ! For non-hygroscopic, only use 1 RH value. - if (irhswell /= 0) then - nrh = NMIE_RH - else - nrh = min(NMIE_RH, 1) - end if + write(LUNOPRT,*) "Defined rh_idx, lw_band, and sw_band dims." - ! Define the dimensions: rh, lwbands, swbands - call wrap_def_dim(fid, 'rh_idx', nrh, rhdim) - call wrap_def_dim(fid, 'lw_band', nlwbands, lwdim) - call wrap_def_dim(fid, 'sw_band', nswbands, swdim) + dimids(1) = rhdim + call wrap_def_var(fid, 'rh', NF90_DOUBLE, 1, dimids(1:1), rhvar) - write(LUNOPRT,*) "Defined rh_idx, lw_band, and sw_band dims." + dimids(1) = lwdim + call wrap_def_var(fid, 'lw_band', NF90_DOUBLE, 1, dimids(1:1), lwvar) - dimids(1) = rhdim - call wrap_def_var(fid, 'rh', NF90_DOUBLE, 1, dimids(1:1), rhvar) + dimids(1) = swdim + call wrap_def_var(fid, 'sw_band', NF90_DOUBLE, 1, dimids(1:1), swvar) - dimids(1) = lwdim - call wrap_def_var(fid, 'lw_band', NF90_DOUBLE, 1, dimids(1:1), lwvar) + write(LUNOPRT,*) "Defined rh_idx, lw_band, and sw_band vars." - dimids(1) = swdim - call wrap_def_var(fid, 'sw_band', NF90_DOUBLE, 1, dimids(1:1), swvar) + call wrap_put_att_text(fid, rhvar, 'units', 'fraction') + call wrap_put_att_text(fid, lwvar, 'units', 'm') + call wrap_put_att_text(fid, swvar, 'units', 'm') - write(LUNOPRT,*) "Defined rh_idx, lw_band, and sw_band vars." + call wrap_put_att_text(fid, rhvar, 'long_name', 'relative humidity') + call wrap_put_att_text(fid, lwvar, 'long_name', 'longwave bands') + call wrap_put_att_text(fid, swvar, 'long_name', 'shortwave bands') - call wrap_put_att_text(fid, rhvar, 'units', 'fraction') - call wrap_put_att_text(fid, lwvar, 'units', 'm') - call wrap_put_att_text(fid, swvar, 'units', 'm') + ! Define the variables: abs_lw, ext_sw, ssa_sw, asm_sw + dimids(1) = rhdim + dimids(2) = lwdim + call wrap_def_var(fid, 'abs_lw', NF90_DOUBLE, 2, dimids, abs_lw_var) - call wrap_put_att_text(fid, rhvar, 'long_name', 'relative humidity') - call wrap_put_att_text(fid, lwvar, 'long_name', 'longwave bands') - call wrap_put_att_text(fid, swvar, 'long_name', 'shortwave bands') + write(LUNOPRT,*) "Defined abs_lw." - ! Define the variables: abs_lw, ext_sw, ssa_sw, asm_sw - dimids(1) = rhdim - dimids(2) = lwdim - call wrap_def_var(fid, 'abs_lw', NF90_DOUBLE, 2, dimids, abs_lw_var) + call wrap_put_att_text(fid, abs_lw_var, 'units', 'meter^2 kilogram^-1') - write(LUNOPRT,*) "Defined abs_lw." + dimids(1) = rhdim + dimids(2) = swdim + call wrap_def_var(fid, 'ext_sw', NF90_DOUBLE, 2, dimids, ext_sw_var) + call wrap_def_var(fid, 'ssa_sw', NF90_DOUBLE, 2, dimids, ssa_sw_var) + call wrap_def_var(fid, 'asm_sw', NF90_DOUBLE, 2, dimids, asm_sw_var) - call wrap_put_att_text(fid, abs_lw_var, 'units', 'meter^2 kilogram^-1') + write(LUNOPRT,*) "Defined ext_sw, ssa_sw, and asm_sw." - dimids(1) = rhdim - dimids(2) = swdim - call wrap_def_var(fid, 'ext_sw', NF90_DOUBLE, 2, dimids, ext_sw_var) - call wrap_def_var(fid, 'ssa_sw', NF90_DOUBLE, 2, dimids, ssa_sw_var) - call wrap_def_var(fid, 'asm_sw', NF90_DOUBLE, 2, dimids, asm_sw_var) + call wrap_put_att_text(fid, ssa_sw_var, 'units', 'fraction') + call wrap_put_att_text(fid, ext_sw_var, 'units', 'meter^2 kilogram^-1') + call wrap_put_att_text(fid, asm_sw_var, 'units', '-') - write(LUNOPRT,*) "Defined ext_sw, ssa_sw, and asm_sw." + ! Define the variables for the refractive indicies. + dimids(1) = swdim + call wrap_def_var(fid, 'refindex_real_aer_sw', NF90_DOUBLE, 1, dimids(1:1), sw_r_refidx_var) + call wrap_def_var(fid, 'refindex_im_aer_sw', NF90_DOUBLE, 1, dimids(1:1), sw_i_refidx_var) - call wrap_put_att_text(fid, ssa_sw_var, 'units', 'fraction') - call wrap_put_att_text(fid, ext_sw_var, 'units', 'meter^2 kilogram^-1') - call wrap_put_att_text(fid, asm_sw_var, 'units', '-') + write(LUNOPRT,*) "Defined lw refindex." - ! Define the variables for the refractive indicies. - dimids(1) = swdim - call wrap_def_var(fid, 'refindex_real_aer_sw', NF90_DOUBLE, 1, dimids(1:1), sw_r_refidx_var) - call wrap_def_var(fid, 'refindex_im_aer_sw', NF90_DOUBLE, 1, dimids(1:1), sw_i_refidx_var) + dimids(1) = lwdim + call wrap_def_var(fid, 'refindex_real_aer_lw', NF90_DOUBLE, 1, dimids(1:1), lw_r_refidx_var) + call wrap_def_var(fid, 'refindex_im_aer_lw', NF90_DOUBLE, 1, dimids(1:1), lw_i_refidx_var) - write(LUNOPRT,*) "Defined lw refindex." + write(LUNOPRT,*) "Defined sw refindex." - dimids(1) = lwdim - call wrap_def_var(fid, 'refindex_real_aer_lw', NF90_DOUBLE, 1, dimids(1:1), lw_r_refidx_var) - call wrap_def_var(fid, 'refindex_im_aer_lw', NF90_DOUBLE, 1, dimids(1:1), lw_i_refidx_var) + call wrap_put_att_text(fid, sw_r_refidx_var, 'units', '-') + call wrap_put_att_text(fid, sw_i_refidx_var, 'units', '-') + call wrap_put_att_text(fid, lw_r_refidx_var, 'units', '-') + call wrap_put_att_text(fid, lw_i_refidx_var, 'units', '-') - write(LUNOPRT,*) "Defined sw refindex." + call wrap_put_att_text(fid, sw_r_refidx_var, 'long_name', 'real refractive index of aerosol - shortwave') + call wrap_put_att_text(fid, sw_i_refidx_var, 'long_name', 'imaginary refractive index of aerosol - shortwave') + call wrap_put_att_text(fid, lw_r_refidx_var, 'long_name', 'real refractive index of aerosol - longwave') + call wrap_put_att_text(fid, lw_i_refidx_var, 'long_name', 'imaginary refractive index of aerosol - longwave') - call wrap_put_att_text(fid, sw_r_refidx_var, 'units', '-') - call wrap_put_att_text(fid, sw_i_refidx_var, 'units', '-') - call wrap_put_att_text(fid, lw_r_refidx_var, 'units', '-') - call wrap_put_att_text(fid, lw_i_refidx_var, 'units', '-') - call wrap_put_att_text(fid, sw_r_refidx_var, 'long_name', 'real refractive index of aerosol - shortwave') - call wrap_put_att_text(fid, sw_i_refidx_var, 'long_name', 'imaginary refractive index of aerosol - shortwave') - call wrap_put_att_text(fid, lw_r_refidx_var, 'long_name', 'real refractive index of aerosol - longwave') - call wrap_put_att_text(fid, lw_i_refidx_var, 'long_name', 'imaginary refractive index of aerosol - longwave') + ! Define fields that define the aerosol properties. + call wrap_def_dim(fid, 'opticsmethod_len', 32, omdim) + dimids(1) = omdim + call wrap_def_var(fid, 'opticsmethod', NF90_CHAR, 1, dimids(1:1), omvar) + write(LUNOPRT,*) "Defined omdim." - ! Define fields that define the aerosol properties. - call wrap_def_dim(fid, 'opticsmethod_len', 32, omdim) - dimids(1) = omdim - call wrap_def_var(fid, 'opticsmethod', NF90_CHAR, 1, dimids(1:1), omvar) + call wrap_def_dim(fid, 'namelength', 20, andim) + dimids(1) = andim + call wrap_def_var(fid, 'aername', NF90_CHAR, 1, dimids(1:1), anvar) - write(LUNOPRT,*) "Defined omdim." + write(LUNOPRT,*) "Defined aername." - call wrap_def_dim(fid, 'namelength', 20, andim) - dimids(1) = andim - call wrap_def_var(fid, 'aername', NF90_CHAR, 1, dimids(1:1), anvar) + call wrap_def_dim(fid, 'name_len', 32, namedim) + dimids(1) = namedim + call wrap_def_var(fid, 'name', NF90_CHAR, 1, dimids(1:1), namevar) - write(LUNOPRT,*) "Defined aername." + write(LUNOPRT,*) "Defined name." - call wrap_def_dim(fid, 'name_len', 32, namedim) - dimids(1) = namedim - call wrap_def_var(fid, 'name', NF90_CHAR, 1, dimids(1:1), namevar) + call wrap_def_var(fid, 'density', NF90_DOUBLE, 0, dimids(1:0), denvar) + call wrap_def_var(fid, 'sigma_logr', NF90_DOUBLE, 0, dimids(1:0), slogvar) + call wrap_def_var(fid, 'dryrad', NF90_DOUBLE, 0, dimids(1:0), dryrvar) + call wrap_def_var(fid, 'radmin_aer', NF90_DOUBLE, 0, dimids(1:0), rminvar) + call wrap_def_var(fid, 'radmax_aer', NF90_DOUBLE, 0, dimids(1:0), rmaxvar) + call wrap_def_var(fid, 'hygroscopicity', NF90_DOUBLE, 0, dimids(1:0), hygrovar) + call wrap_def_var(fid, 'num_to_mass_ratio', NF90_DOUBLE, 0, dimids(1:0), ntmvar) - write(LUNOPRT,*) "Defined name." + call wrap_put_att_text(fid, denvar, 'units', 'kg m^-3') + call wrap_put_att_text(fid, slogvar, 'units', '-') + call wrap_put_att_text(fid, dryrvar, 'units', 'm') + call wrap_put_att_text(fid, rminvar, 'units', 'm') + call wrap_put_att_text(fid, rmaxvar, 'units', 'm') + call wrap_put_att_text(fid, hygrovar, 'units', '-') + call wrap_put_att_text(fid, ntmvar, 'units', 'kg^-1') - call wrap_def_var(fid, 'density', NF90_DOUBLE, 0, dimids(1:0), denvar) - call wrap_def_var(fid, 'sigma_logr', NF90_DOUBLE, 0, dimids(1:0), slogvar) - call wrap_def_var(fid, 'dryrad', NF90_DOUBLE, 0, dimids(1:0), dryrvar) - call wrap_def_var(fid, 'radmin_aer', NF90_DOUBLE, 0, dimids(1:0), rminvar) - call wrap_def_var(fid, 'radmax_aer', NF90_DOUBLE, 0, dimids(1:0), rmaxvar) - call wrap_def_var(fid, 'hygroscopicity', NF90_DOUBLE, 0, dimids(1:0), hygrovar) - call wrap_def_var(fid, 'num_to_mass_ratio', NF90_DOUBLE, 0, dimids(1:0), ntmvar) + call wrap_put_att_text(fid, denvar, 'long_name', 'aerosol material density') + call wrap_put_att_text(fid, slogvar, 'long_name', 'geometric standard deviation of aerosol') + call wrap_put_att_text(fid, dryrvar, 'long_name', 'dry number mode radius of aerosol') + call wrap_put_att_text(fid, rminvar, 'long_name', 'minimum dry radius of aerosol for bin') + call wrap_put_att_text(fid, rmaxvar, 'long_name', 'maximum dry radius of aerosol for bin') + call wrap_put_att_text(fid, hygrovar, 'long_name', 'hygroscopicity of aerosol') + call wrap_put_att_text(fid, ntmvar, 'long_name', 'ratio of number to mass of aerosol') - call wrap_put_att_text(fid, denvar, 'units', 'kg m^-3') - call wrap_put_att_text(fid, slogvar, 'units', '-') - call wrap_put_att_text(fid, dryrvar, 'units', 'm') - call wrap_put_att_text(fid, rminvar, 'units', 'm') - call wrap_put_att_text(fid, rmaxvar, 'units', 'm') - call wrap_put_att_text(fid, hygrovar, 'units', '-') - call wrap_put_att_text(fid, ntmvar, 'units', 'kg^-1') - call wrap_put_att_text(fid, denvar, 'long_name', 'aerosol material density') - call wrap_put_att_text(fid, slogvar, 'long_name', 'geometric standard deviation of aerosol') - call wrap_put_att_text(fid, dryrvar, 'long_name', 'dry number mode radius of aerosol') - call wrap_put_att_text(fid, rminvar, 'long_name', 'minimum dry radius of aerosol for bin') - call wrap_put_att_text(fid, rmaxvar, 'long_name', 'maximum dry radius of aerosol for bin') - call wrap_put_att_text(fid, hygrovar, 'long_name', 'hygroscopicity of aerosol') - call wrap_put_att_text(fid, ntmvar, 'long_name', 'ratio of number to mass of aerosol') + write(LUNOPRT,*) "Defined all variables." + ! End the defintion phase of the netcdf file. + call wrap_enddef(fid) - write(LUNOPRT,*) "Defined all variables." + ! Write out the dimensions. + call wrap_put_var_realx(fid, rhvar, mie_rh(:nrh)) + call wrap_put_var_realx(fid, lwvar, wave(:nlwbands) * 1e-2_f) + call wrap_put_var_realx(fid, swvar, wave(nlwbands+1:) * 1e-2_f) - ! End the defintion phase of the netcdf file. - call wrap_enddef(fid) + ! Write out the refractive indicies. + call wrap_put_var_realx(fid, sw_r_refidx_var, real(refidx(nlwbands+1:, 1))) + call wrap_put_var_realx(fid, sw_i_refidx_var, aimag(refidx(nlwbands+1:, 1))) + call wrap_put_var_realx(fid, lw_r_refidx_var, real(refidx(:nlwbands, 1))) + call wrap_put_var_realx(fid, lw_i_refidx_var, aimag(refidx(:nlwbands, 1))) - ! Write out the dimensions. - call wrap_put_var_realx(fid, rhvar, mie_rh(:nrh)) - call wrap_put_var_realx(fid, lwvar, wave(:nlwbands) * 1e-2_f) - call wrap_put_var_realx(fid, swvar, wave(nlwbands+1:) * 1e-2_f) + ! Pad the names out with spaces. + aer_name = ' ' + aer_name(1:len(trim(c_name))) = c_name + + start_text(1) = 1 + count_text(1) = 32 + call wrap_put_vara_text(fid, namevar, start_text, count_text, (/ aer_name /)) + count_text(1) = 20 + call wrap_put_vara_text(fid, anvar, start_text, count_text, (/ aer_name /)) - ! Write out the refractive indicies. - call wrap_put_var_realx(fid, sw_r_refidx_var, real(refidx(nlwbands+1:))) - call wrap_put_var_realx(fid, sw_i_refidx_var, aimag(refidx(nlwbands+1:))) - call wrap_put_var_realx(fid, lw_r_refidx_var, real(refidx(:nlwbands))) - call wrap_put_var_realx(fid, lw_i_refidx_var, aimag(refidx(:nlwbands))) + ! These fields control whether the particle is treated as a CCN. For now, + ! set these so that CARMA particles are not considered as CCN by the + ! CAM microphysics. + if (irhswell /= 0) then + count_text(1) = len('hygroscopic ') + call wrap_put_vara_text(fid, omvar, start_text, count_text, (/ 'hygroscopic ' /)) + else + count_text(1) = len('insoluble ') + call wrap_put_vara_text(fid, omvar, start_text, count_text, (/ 'insoluble ' /)) + end if + call wrap_put_var_realx(fid, denvar, (/ rho(ibin) * 1e-3_f / 1e-6_f /)) + call wrap_put_var_realx(fid, slogvar, (/ 0._f /)) + call wrap_put_var_realx(fid, dryrvar, (/ r(ibin) * 1e-2_f /)) + call wrap_put_var_realx(fid, rminvar, (/ rlow(ibin) * 1e-2_f /)) + call wrap_put_var_realx(fid, rmaxvar, (/ rup(ibin) * 1e-2_f /)) + call wrap_put_var_realx(fid, hygrovar, (/ 0._f /)) + call wrap_put_var_realx(fid, ntmvar, (/ 1._f / rmass(ibin) / 1e-3_f /)) - ! Pad the names out with spaces. - aer_name = ' ' - aer_name(1:len(trim(c_name))) = c_name + ! Iterate over a range of relative humidities, since the particle may swell + ! with relative humidity which will change its optical properties. + do irh = 1, nrh - start_text(1) = 1 - count_text(1) = 32 - call wrap_put_vara_text(fid, namevar, start_text, count_text, (/ aer_name /)) - count_text(1) = 20 - call wrap_put_vara_text(fid, anvar, start_text, count_text, (/ aer_name /)) + ! Determine the wet radius. + call getwetr(carma, igroup, mie_rh(irh), r(ibin), rwet, rho(ibin), rhopwet, rc) + if (rc < 0) call endrun('carma_CreateOpticsFile::wetr failed.') - ! These fields control whether the particle is treated as a CCN. For now, - ! set these so that CARMA particles are not considered as CCN by the - ! CAM microphysics. - if (irhswell /= 0) then - count_text(1) = len('hygroscopic ') - call wrap_put_vara_text(fid, omvar, start_text, count_text, (/ 'hygroscopic ' /)) - else - count_text(1) = len('insoluble ') - call wrap_put_vara_text(fid, omvar, start_text, count_text, (/ 'insoluble ' /)) - end if + ! Calculate at each wavelength. + do iwave = 1, NWAVE - call wrap_put_var_realx(fid, denvar, (/ rho(ibin) * 1e-3_f / 1e-6_f /)) - call wrap_put_var_realx(fid, slogvar, (/ 0._f /)) - call wrap_put_var_realx(fid, dryrvar, (/ r(ibin) * 1e-2_f /)) - call wrap_put_var_realx(fid, rminvar, (/ rlow(ibin) * 1e-2_f /)) - call wrap_put_var_realx(fid, rmaxvar, (/ rup(ibin) * 1e-2_f /)) - call wrap_put_var_realx(fid, hygrovar, (/ 0._f /)) - call wrap_put_var_realx(fid, ntmvar, (/ 1._f / rmass(ibin) / 1e-3_f /)) - - ! Iterate over a range of relative humidities, since the particle may swell - ! with relative humidity which will change its optical properties. - do irh = 1, nrh - - ! Determine the wet radius. - call getwetr(carma, igroup, mie_rh(irh), r(ibin), rwet, rho(ibin), rhopwet, rc) - if (rc < 0) call endrun('carma_CreateOpticsFile::wetr failed.') - - ! Calculate at each wavelength. - do iwave = 1, NWAVE -write(carma%f_LUNOPRT,*) "CARMA mie calc: start ", igroup, ibin, iwave, carma%f_wave(iwave), carma%f_group(igroup)%f_nmon(ibin) - - - ! Using Mie code, calculate the optical properties: extinction coefficient, - ! single scattering albedo and asymmetry factor. - ! Assume the particle is homogeneous (no core). - ! - ! NOTE: nmon, df, rmon and falpha are only used for fractal particles. - call mie(carma, & - carma%f_group(igroup)%f_imiertn, & - rwet, & - carma%f_wave(iwave), & - carma%f_group(igroup)%f_nmon(ibin), & - carma%f_group(igroup)%f_df(ibin), & - carma%f_group(igroup)%f_rmon, & - carma%f_group(igroup)%f_falpha, & - carma%f_group(igroup)%f_refidx(iwave), & - Qext, & - Qsca, & - asym, & - rc) - if (rc < 0) call endrun('carma_CreateOpticsFile::mie failed.') -write(carma%f_LUNOPRT,*) "CARMA mie calc: done ", Qext, Qsca, asym - - - ! Calculate the shortwave and longwave properties? - ! - ! NOTE: miess is in cgs units, but the optics file needs to be in mks - ! units, so perform the necessary conversions. - if (iwave <= nlwbands) then - - ! Longwave just needs absorption: abs_lw. - abs_lw(irh, iwave) = (Qext - Qsca) * PI * (rwet * 1e-2_f)**2 / (rmass(ibin) * 1e-3_f) - else - - ! Shortwave needs extinction, single scattering albedo and asymmetry factor: - ! ext_sw, ssa_sw and asm_sw. - ext_sw(irh, iwave - nlwbands) = Qext * PI * (rwet * 1e-2_f)**2 / (rmass(ibin) * 1e-3_f) - ssa_sw(irh, iwave - nlwbands) = Qsca / Qext - asm_sw(irh, iwave - nlwbands) = asym - end if - end do - end do + ! Using Mie code, calculate the optical properties: extinction coefficient, + ! single scattering albedo and asymmetry factor. + ! Assume the particle is homogeneous (no core). + ! + ! NOTE: nmon, df, rmon and falpha are only used for fractal particles. + call mie(carma, & + carma%f_group(igroup)%f_imiertn, & + rwet, & + carma%f_wave(iwave), & + real(carma%f_group(igroup)%f_nmon(ibin),kind=f), & + carma%f_group(igroup)%f_df(ibin), & + carma%f_group(igroup)%f_rmon, & + carma%f_group(igroup)%f_falpha, & + refidx(iwave, 1), & + 0.0_f, & + refidx(iwave, 1), & + Qext, & + Qsca, & + asym, & + rc) + if (rc < 0) call endrun('carma_CreateOpticsFile::mie failed.') + + ! Calculate the shortwave and longwave properties? + ! + ! NOTE: miess is in cgs units, but the optics file needs to be in mks + ! units, so perform the necessary conversions. + if (iwave <= nlwbands) then - ! Write out the longwave fields. - ret = nf90_put_var (fid, abs_lw_var, abs_lw(:nrh, :)) - if (ret/=NF90_NOERR) then - write(iulog,*)'CARMA_CreateOpticsFile: error writing varid =', abs_lw_var - call handle_error (ret) - end if + ! Longwave just needs absorption: abs_lw. + abs_lw(irh, iwave) = (Qext - Qsca) * PI * (rwet * 1e-2_f)**2 / (rmass(ibin) * 1e-3_f) + else - ! Write out the shortwave fields. - ret = nf90_put_var (fid, ext_sw_var, ext_sw(:nrh, :)) - if (ret/=NF90_NOERR) then - write(iulog,*)'CARMA_CreateOpticsFile: error writing varid =', ext_sw_var - call handle_error (ret) - end if - ret = nf90_put_var (fid, ssa_sw_var, ssa_sw(:nrh, :)) - if (ret/=NF90_NOERR) then - write(iulog,*)'CARMA_CreateOpticsFile: error writing varid =', ssa_sw_var - call handle_error (ret) + ! Shortwave needs extinction, single scattering albedo and asymmetry factor: + ! ext_sw, ssa_sw and asm_sw. + ext_sw(irh, iwave - nlwbands) = Qext * PI * (rwet * 1e-2_f)**2 / (rmass(ibin) * 1e-3_f) + ssa_sw(irh, iwave - nlwbands) = Qsca / Qext + asm_sw(irh, iwave - nlwbands) = asym end if - ret = nf90_put_var (fid, asm_sw_var, asm_sw(:nrh, :)) - if (ret/=NF90_NOERR) then - write(iulog,*)'CARMA_CreateOpticsFile: error writing varid =', asm_sw_var - call handle_error (ret) - end if - - ! Close the file. - call wrap_close(fid) - end if + end do end do + + ! Write out the longwave fields. + ret = nf90_put_var (fid, abs_lw_var, abs_lw(:nrh, :)) + if (ret/=NF90_NOERR) then + write(iulog,*)'CARMA_CreateOpticsFile: error writing varid =', abs_lw_var + call handle_error (ret) + end if + + ! Write out the shortwave fields. + ret = nf90_put_var (fid, ext_sw_var, ext_sw(:nrh, :)) + if (ret/=NF90_NOERR) then + write(iulog,*)'CARMA_CreateOpticsFile: error writing varid =', ext_sw_var + call handle_error (ret) + end if + ret = nf90_put_var (fid, ssa_sw_var, ssa_sw(:nrh, :)) + if (ret/=NF90_NOERR) then + write(iulog,*)'CARMA_CreateOpticsFile: error writing varid =', ssa_sw_var + call handle_error (ret) + end if + ret = nf90_put_var (fid, asm_sw_var, asm_sw(:nrh, :)) + if (ret/=NF90_NOERR) then + write(iulog,*)'CARMA_CreateOpticsFile: error writing varid =', asm_sw_var + call handle_error (ret) + end if + + ! Close the file. + call wrap_close(fid) end if end do return - end subroutine CARMA_CreateOpticsFile + end subroutine CARMA_CreateOpticsFile_Fixed - !! This routine creates a file containing a reference temperature profile - !! for use with fixed initialization. - subroutine CARMA_CreateRefTFile(carma, filepath, lev, reft, rc, refh2o, refh2so4) + + !! This routine creates files containing optical properties for the pure sulfate group + !! following Yu et al. (2015). These optical properties are used by the RRTMG radiation + !! code to include the impact of CARMA particles in the radiative transfer + !! calculation. + subroutine CARMA_CreateOpticsFile_Sulfate(carma, igroup, rc) + use radconstants, only : nswbands, nlwbands use wrap_nf + use wetr, only : getwetr implicit none - type(carma_type), intent(inout) :: carma !! the carma object - character(len=*), intent(in) :: filepath !! the file path - real(kind=f), intent(in) :: lev(pver) !! pressure levels - real(kind=f), intent(in) :: reft(pver) !! reference temperature - integer, intent(out) :: rc !! return code, negative indicates failure - real(kind=f), optional, intent(in) :: refh2o(pver) !! reference water vapor - real(kind=f), optional, intent(in) :: refh2so4(pver) !! reference sulfuric acid + type(carma_type), intent(inout) :: carma !! the carma object + integer, intent(in) :: igroup !! group index + integer, intent(out) :: rc !! return code, negative indicates failure ! Local variables + integer :: ibin, iwave, iwtp + integer :: irhswell + integer :: imiertn + integer :: ienconc + real(kind=f) :: rho(NBIN), rhopwet + real(kind=f) :: r(NBIN), rmass(NBIN), rlow(NBIN), rup(NBIN) + real(kind=f) :: wave(NWAVE) + complex(kind=f) :: refidx(NWAVE) + complex(kind=f) :: refidxS(NWAVE, NREFIDX) + complex(kind=f) :: refidxW(NWAVE) + character(len=CARMA_NAME_LEN) :: name + character(len=CARMA_SHORT_NAME_LEN) :: shortname integer :: fid - integer :: levdim - integer :: levvar, tvar, h2ovar, h2so4var + integer :: rhdim, lwdim, swdim, wtpdim + integer :: rhvar, lwvar, swvar, wtp_var + integer :: rwetvar + integer :: abs_lw_wtp_var, qabs_lw_wtp_var + integer :: ext_sw_wtp_var, ssa_sw_wtp_var, asm_sw_wtp_var, qext_sw_wtp_var + integer :: omdim, andim, namedim + integer :: omvar, anvar, namevar integer :: dimids(2) + integer :: denvar, slogvar, dryrvar, rminvar, rmaxvar, hygrovar, ntmvar + real(kind=f) :: abs_lw_wtp(NMIE_WTP, nlwbands) + real(kind=f) :: qabs_lw_wtp(NMIE_WTP, nlwbands) + real(kind=f) :: ext_sw_wtp(NMIE_WTP, nswbands) + real(kind=f) :: qext_sw_wtp(NMIE_WTP, nswbands) + real(kind=f) :: ssa_sw_wtp(NMIE_WTP, nswbands) + real(kind=f) :: asm_sw_wtp(NMIE_WTP, nswbands) + character(len=8) :: c_name ! constituent name + character(len=32) :: aer_name ! long enough for both aername and name + character(len=255) :: filepath + real(kind=f) :: rwet + real(kind=f) :: Qext + real(kind=f) :: Qsca + real(kind=f) :: asym + integer :: start_text(2), count_text(2) + integer :: sw_r_refidx_var, sw_i_refidx_var, lw_r_refidx_var, lw_i_refidx_var + integer :: cnsttype ! constituent type + integer :: maxbin ! last prognostic bin + integer :: LUNOPRT ! logical unit number for output + logical :: do_print ! do print output? + integer :: ret + real(kind=f) :: volwater + real(kind=f) :: volsulfate + real(kind=f) :: volshell + integer :: igash2o ! Assume success. rc = 0 - ! Create the file. - call wrap_create(filepath, NF90_CLOBBER, fid) + ! Get the wavelength structure. + call CARMA_GET(carma, rc, wave=wave, do_print=do_print, LUNOPRT=LUNOPRT, igash2o=igash2o) + if (rc < 0) call endrun('carma_CreateOpticsFile::CARMA_Get failed.') + ! Get the necessary group properties. + call CARMAGROUP_Get(carma, igroup, rc, name=name, shortname=shortname, r=r, & + rlow=rlow, rup=rup, rmass=rmass, irhswell=irhswell, & + ienconc=ienconc, cnsttype=cnsttype, maxbin=maxbin, imiertn=imiertn) + if (rc < 0) call endrun('carma_CreateOpticsFile::CARMAGROUP_Get failed.') - ! Define the dimensions: lev - call wrap_def_dim(fid, 'lev', pver, levdim) + ! Get the necessary element properties. + call CARMAELEMENT_Get(carma, ienconc, rc, rho=rho, refidx=refidxS) + if (rc < 0) call endrun('carma_CreateOpticsFile::CARMAELEMENT_Get failed.') - dimids(1) = levdim - call wrap_def_var(fid, 'lev', NF90_DOUBLE, 1, dimids(1:1), levvar) + ! Get the refractive index for water. + call CARMAGAS_Get(carma, igash2o, rc, refidx=refidxW) + if (rc < 0) call endrun('carma_CreateOpticsFile::CARMAGAS_Get failed.') - call wrap_put_att_text(fid, levvar, 'units', 'level') - call wrap_put_att_text(fid, levvar, 'long_name', 'hybrid level at midpoints (1000*(A+B))') - call wrap_put_att_text(fid, levvar, 'positive', 'down') - call wrap_put_att_text(fid, levvar, 'standard_name', 'atmosphere_hybrid_sigma_pressure_coordinate') - call wrap_put_att_text(fid, levvar, 'formula_terms', 'a: hyam b: hybm p0: P0 ps: PS') + ! A file needs to be created for each bin. + do ibin = 1, NBIN - ! Define the variables: T - call wrap_def_var(fid, 'T', NF90_DOUBLE, 1, dimids(1:1), tvar) + ! Bins past maxbin are treated as diagnostic even if the group + ! is prognostic and thus are not advected in the paerent model. + if (ibin <= maxbin) then - call wrap_put_att_text(fid, tvar, 'units', 'K') - call wrap_put_att_text(fid, tvar, 'long_name', 'Temperature') + write(c_name, '(A, I2.2)') trim(shortname), ibin - if ((carma%f_igash2o /= 0) .and. present(refh2o)) then - call wrap_def_var(fid, 'Q', NF90_DOUBLE, 1, dimids(1:1), h2ovar) + ! Construct the path to the file. Each model will have its own subdirectory + ! where the optical property files are stored. + filepath = trim(carma_model) // '_' // trim(c_name) // '_rrtmg.nc' + + if (do_print) write(LUNOPRT,*) 'Creating CARMA optics file ... ', trim(filepath) - call wrap_put_att_text(fid, h2ovar, 'units', 'kg/kg') - call wrap_put_att_text(fid, h2ovar, 'long_name', 'Specific Humidity') - end if + ! Create the file. + call wrap_create(filepath, NF90_CLOBBER, fid) + + ! Define the dimensions: rh, lwbands, swbands + call wrap_def_dim(fid, 'rh_idx', NMIE_RH, rhdim) + call wrap_def_dim(fid, 'lw_band', nlwbands, lwdim) + call wrap_def_dim(fid, 'sw_band', nswbands, swdim) + + call wrap_def_dim(fid, 'wgtpct', NMIE_WTP, wtpdim) + + dimids(1) = rhdim + call wrap_def_var(fid, 'rh', NF90_DOUBLE, 1, dimids(1), rhvar) + call wrap_def_var(fid, 'rwet',NF90_DOUBLE, 1, dimids(1), rwetvar) + + dimids(1) = lwdim + call wrap_def_var(fid, 'lw_band', NF90_DOUBLE, 1, dimids(1), lwvar) + + dimids(1) = swdim + call wrap_def_var(fid, 'sw_band', NF90_DOUBLE, 1, dimids(1), swvar) + + dimids(1) = wtpdim + call wrap_def_var(fid, 'wgtpct', NF90_DOUBLE, 1, dimids(1), wtp_var) + + call wrap_put_att_text(fid, rhvar, 'units', 'fraction') + call wrap_put_att_text(fid, rwetvar, 'units', 'cm') + call wrap_put_att_text(fid, lwvar, 'units', 'm') + call wrap_put_att_text(fid, swvar, 'units', 'm') + + call wrap_put_att_text(fid, wtp_var,'units', 'unitless') + call wrap_put_att_text(fid, wtp_var,'long_name', 'weight percent') + + call wrap_put_att_text(fid, rhvar, 'long_name', 'relative humidity') + call wrap_put_att_text(fid, rwetvar, 'long_name', 'wet radius') + call wrap_put_att_text(fid, lwvar, 'long_name', 'longwave bands') + call wrap_put_att_text(fid, swvar, 'long_name', 'shortwave bands') + + ! Define the variables: abs_lw, ext_sw, ssa_sw, asm_sw + ! Define 2-dimension (:nrh,:nswbands) LW optics properties: abs_lw, qabs_lw + dimids(1) = wtpdim + dimids(2) = lwdim + call wrap_def_var(fid, 'abs_lw_wtp', NF90_DOUBLE, 2, dimids(1:2), abs_lw_wtp_var) + call wrap_def_var(fid, 'qabs_lw_wtp',NF90_DOUBLE, 2, dimids(1:2), qabs_lw_wtp_var) + + call wrap_put_att_text(fid, abs_lw_wtp_var, 'units', 'meter^2 kilogram^-1') + call wrap_put_att_text(fid, qabs_lw_wtp_var,'units', '-') + + ! Define 2-dimension (:nrh,:nswbands) optics properties: ext_sw, qext_sw, ssa_sw, asm_sw + dimids(1) = wtpdim + dimids(2) = swdim + call wrap_def_var(fid, 'ext_sw_wtp', NF90_DOUBLE, 2, dimids(1:2), ext_sw_wtp_var) + call wrap_def_var(fid, 'qext_sw_wtp',NF90_DOUBLE, 2, dimids(1:2), qext_sw_wtp_var) + call wrap_def_var(fid, 'ssa_sw_wtp', NF90_DOUBLE, 2, dimids(1:2), ssa_sw_wtp_var) + call wrap_def_var(fid, 'asm_sw_wtp', NF90_DOUBLE, 2, dimids(1:2), asm_sw_wtp_var) + + call wrap_put_att_text(fid, ssa_sw_wtp_var, 'units', 'fraction') + call wrap_put_att_text(fid, qext_sw_wtp_var,'units', '-') + call wrap_put_att_text(fid, ext_sw_wtp_var, 'units', 'meter^2 kilogram^-1') + call wrap_put_att_text(fid, asm_sw_wtp_var, 'units', '-') + + ! Define the variables for the refractive indicies. + dimids(1) = swdim + call wrap_def_var(fid, 'refindex_real_aer_sw', NF90_DOUBLE, 1, dimids(1), sw_r_refidx_var) + call wrap_def_var(fid, 'refindex_im_aer_sw', NF90_DOUBLE, 1, dimids(1), sw_i_refidx_var) + + dimids(1) = lwdim + call wrap_def_var(fid, 'refindex_real_aer_lw', NF90_DOUBLE, 1, dimids(1), lw_r_refidx_var) + call wrap_def_var(fid, 'refindex_im_aer_lw', NF90_DOUBLE, 1, dimids(1), lw_i_refidx_var) + + call wrap_put_att_text(fid, sw_r_refidx_var, 'units', '-') + call wrap_put_att_text(fid, sw_i_refidx_var, 'units', '-') + call wrap_put_att_text(fid, lw_r_refidx_var, 'units', '-') + call wrap_put_att_text(fid, lw_i_refidx_var, 'units', '-') + + call wrap_put_att_text(fid, sw_r_refidx_var, 'long_name', 'real refractive index of aerosol - shortwave') + call wrap_put_att_text(fid, sw_i_refidx_var, 'long_name', 'imaginary refractive index of aerosol - shortwave') + call wrap_put_att_text(fid, lw_r_refidx_var, 'long_name', 'real refractive index of aerosol - longwave') + call wrap_put_att_text(fid, lw_i_refidx_var, 'long_name', 'imaginary refractive index of aerosol - longwave') + + + ! Define fields that define the aerosol properties. + call wrap_def_dim(fid, 'opticsmethod_len', 32, omdim) + dimids(1) = omdim + call wrap_def_var(fid, 'opticsmethod', NF90_CHAR, 1, dimids(1), omvar) + + call wrap_def_dim(fid, 'namelength', 20, andim) + dimids(1) = andim + call wrap_def_var(fid, 'aername', NF90_CHAR, 1, dimids(1), anvar) + + call wrap_def_dim(fid, 'name_len', 32, namedim) + dimids(1) = namedim + call wrap_def_var(fid, 'name', NF90_CHAR, 1, dimids, namevar) + + call wrap_def_var(fid, 'density', NF90_DOUBLE, 0, dimids(1), denvar) + call wrap_def_var(fid, 'sigma_logr', NF90_DOUBLE, 0, dimids(1), slogvar) + call wrap_def_var(fid, 'dryrad', NF90_DOUBLE, 0, dimids(1), dryrvar) + call wrap_def_var(fid, 'radmin_aer', NF90_DOUBLE, 0, dimids(1), rminvar) + call wrap_def_var(fid, 'radmax_aer', NF90_DOUBLE, 0, dimids(1), rmaxvar) + call wrap_def_var(fid, 'hygroscopicity', NF90_DOUBLE, 0, dimids(1), hygrovar) + call wrap_def_var(fid, 'num_to_mass_ratio', NF90_DOUBLE, 0, dimids(1), ntmvar) + + call wrap_put_att_text(fid, denvar, 'units', 'kg m^-3') + call wrap_put_att_text(fid, slogvar, 'units', '-') + call wrap_put_att_text(fid, dryrvar, 'units', 'm') + call wrap_put_att_text(fid, rminvar, 'units', 'm') + call wrap_put_att_text(fid, rmaxvar, 'units', 'm') + call wrap_put_att_text(fid, hygrovar, 'units', '-') + call wrap_put_att_text(fid, ntmvar, 'units', 'kg^-1') + + call wrap_put_att_text(fid, denvar, 'long_name', 'aerosol material density') + call wrap_put_att_text(fid, slogvar, 'long_name', 'geometric standard deviation of aerosol') + call wrap_put_att_text(fid, dryrvar, 'long_name', 'dry number mode radius of aerosol') + call wrap_put_att_text(fid, rminvar, 'long_name', 'minimum dry radius of aerosol for bin') + call wrap_put_att_text(fid, rmaxvar, 'long_name', 'maximum dry radius of aerosol for bin') + call wrap_put_att_text(fid, hygrovar, 'long_name', 'hygroscopicity of aerosol') + call wrap_put_att_text(fid, ntmvar, 'long_name', 'ratio of number to mass of aerosol') + + ! End the defintion phase of the netcdf file. + call wrap_enddef(fid) + + ! Write out the dimensions. + call wrap_put_var_realx(fid, rhvar, mie_rh(:)) + call wrap_put_var_realx(fid, lwvar, wave(:nlwbands) * 1e-2_f) + call wrap_put_var_realx(fid, swvar, wave(nlwbands+1:) * 1e-2_f) + + call wrap_put_var_realx(fid, wtp_var, mie_wtp(:)*100._f) + + ! Write out the refractive indicies. + call wrap_put_var_realx(fid, sw_r_refidx_var, real(refidxS(nlwbands+1:, 1))) + call wrap_put_var_realx(fid, sw_i_refidx_var, aimag(refidxS(nlwbands+1:, 1))) + call wrap_put_var_realx(fid, lw_r_refidx_var, real(refidxS(:nlwbands, 1))) + call wrap_put_var_realx(fid, lw_i_refidx_var, aimag(refidxS(:nlwbands, 1))) + + ! Pad the names out with spaces. + aer_name = ' ' + aer_name(1:len(trim(c_name))) = c_name + + start_text(1) = 1 + count_text(1) = 32 + call wrap_put_vara_text(fid, namevar, start_text, count_text, (/ aer_name /)) + count_text(1) = 20 + call wrap_put_vara_text(fid, anvar, start_text, count_text, (/ aer_name /)) + + count_text(1) = len('hygroscopic_wtp ') + call wrap_put_vara_text(fid, omvar, start_text, count_text, (/ 'hygroscopic_wtp ' /)) + + call wrap_put_var_realx(fid, denvar, (/ rho(ibin) * 1e-3_f / 1e-6_f /)) + call wrap_put_var_realx(fid, slogvar, (/ 0._f /)) + call wrap_put_var_realx(fid, dryrvar, (/ r(ibin) * 1e-2_f /)) + call wrap_put_var_realx(fid, rminvar, (/ rlow(ibin) * 1e-2_f /)) + call wrap_put_var_realx(fid, rmaxvar, (/ rup(ibin) * 1e-2_f /)) + call wrap_put_var_realx(fid, hygrovar, (/ 0.6_f /)) + call wrap_put_var_realx(fid, ntmvar, (/ 1._f / rmass(ibin) / 1e-3_f /)) + + ! For now, ext_sw(:nrh, :nswbands) and ext_sw_coreshell(:nrh, :nswbands, :ncoreshellratio) both are calculated + ! Since other aerosols in CAM may use ext_sw rather than ext_sw_coreshell + ! Modified by Pengfei Yu + ! April.1, 2012 + + ! calculate qext and ext for pure sulfate dependent on weight percent + ! ideally qext is based on (wgt,temp,wave), however Beyer et al. (1996) Figure 5 + ! shows sulfate density is roughly 0.006 g/cm3/k, I negelet temp dimension, assuming temp = 270 K + ! In code, sulfate density is precisely calculated to determine wet raidus + do iwtp = 1, NMIE_WTP + + ! NOTE: Weight percent is normal a result of the getwetr calculation. To build the + ! table based upon weight percent, we need to pass in the desired value and a + ! reference temperature. In that case, the RH is ignored. + call getwetr(carma, igroup, mie_rh(1), r(ibin), rwet, rho(ibin), rhopwet, rc, wgtpct=mie_wtp(iwtp)*100._f, temp=270._f) + if (rc < 0) call endrun('carma_CreateOpticsFile::wetr failed.') + + ! This is not in Yu (2015), but rather than using the refractive + ! index of H2SO4 for the shell, do a volume mix of water and H2SO4 + ! for the refractive index of the shell. + volwater = rwet**3._f - r(ibin)**3._f + volsulfate = r(ibin)**3._f + volshell = volwater + volsulfate + if (volshell > 0._f) then + refidx(:) = (volwater / volshell) * refidxW(:) + (volsulfate / volshell) * refidxS(:, 1) + else + refidx(:) = refidxS(:, 1) + end if - if ((carma%f_igash2so4 /= 0) .and. present(refh2so4)) then - call wrap_def_var(fid, 'H2SO4', NF90_DOUBLE, 1, dimids(1:1), h2so4var) + ! Calculate at each wavelength. + do iwave = 1, NWAVE - call wrap_put_att_text(fid, h2so4var, 'units', 'kg/kg') - call wrap_put_att_text(fid, h2so4var, 'long_name', 'H2SO4') - end if + ! Using Mie code, calculate the optical properties: extinction coefficient, + ! single scattering albedo and asymmetry factor. + ! Assume the particle is homogeneous (no core). + ! + ! NOTE: The refractive index for sulfate changes with RH/weight percent, which + ! is not reflected in this code. + call mie(carma, & + imiertn, & + rwet, & + wave(iwave), & + 0._f, & + 3.0_f, & + 0.0_f, & + 1.0_f, & + refidx(iwave), & + 0.0_f, & + refidx(iwave), & + Qext, & + Qsca, & + asym, & + rc) + if (rc < 0) call endrun('carma_CreateOpticsFile::mie failed.') + + ! Calculate the shortwave and longwave properties? + ! + ! NOTE: miess is in cgs units, but the optics file needs to be in mks + ! units, so perform the necessary conversions. + if (iwave <= nlwbands) then - ! End the defintion phase of the netcdf file. - call wrap_enddef(fid) + ! Longwave just needs absorption: abs_lw. + qabs_lw_wtp(iwtp, iwave) = (Qext - Qsca) ! absorption per particle + abs_lw_wtp (iwtp, iwave) = (Qext - Qsca) * PI * (rwet * 1e-2_f)**2 / (rmass(ibin) * 1e-3_f) + else + ! Shortwave needs extinction, single scattering albedo and asymmetry factor: + ! ext_sw, ssa_sw and asm_sw. + qext_sw_wtp(iwtp, iwave - nlwbands) = Qext ! extinction per particle + ext_sw_wtp (iwtp, iwave - nlwbands) = Qext * PI * (rwet * 1e-2_f)**2 / (rmass(ibin) * 1e-3_f) + ssa_sw_wtp (iwtp, iwave - nlwbands) = Qsca / Qext + asm_sw_wtp (iwtp, iwave - nlwbands) = asym + end if + end do ! iwave + end do ! iwtp + + ! Write out the longwave fields. + ret = nf90_put_var(fid, abs_lw_wtp_var, abs_lw_wtp (:, :)) + if (ret /= NF90_NOERR) then + write(iulog,*)'CARMA_CreateOpticsFile_SulfateYu: error writing varid =', fid, abs_lw_wtp_var + call handle_error(ret) + end if - ! Write out the dimensions. - call wrap_put_var_realx(fid, levvar, lev) + ret = nf90_put_var(fid, qabs_lw_wtp_var, qabs_lw_wtp(:, :)) + if (ret /= NF90_NOERR) then + write(iulog,*)'CARMA_CreateOpticsFile_SulfateYu: error writing varid =', qabs_lw_wtp_var + call handle_error(ret) + end if - ! Write out the variables. - call wrap_put_var_realx(fid, tvar, reft) + ! Write out the shortwave fields. + ret = nf90_put_var(fid, ext_sw_wtp_var, ext_sw_wtp (:, :)) + if (ret /= NF90_NOERR) then + write(iulog,*)'CARMA_CreateOpticsFile_SulfateYu: error writing varid =', ext_sw_wtp_var + call handle_error(ret) + end if - if ((carma%f_igash2o /= 0) .and. present(refh2o)) then - call wrap_put_var_realx(fid, h2ovar, refh2o(:)) - end if + ret = nf90_put_var(fid, qext_sw_wtp_var,qext_sw_wtp(:, :)) + if (ret /= NF90_NOERR) then + write(iulog,*)'CARMA_CreateOpticsFile_SulfateYu: error writing varid =', qext_sw_wtp_var + call handle_error(ret) + end if - if ((carma%f_igash2so4 /= 0) .and. present(refh2so4)) then - call wrap_put_var_realx(fid, h2so4var, refh2so4(:)) - end if + ret = nf90_put_var(fid, ssa_sw_wtp_var, ssa_sw_wtp (:, :)) + if (ret /= NF90_NOERR) then + write(iulog,*)'CARMA_CreateOpticsFile_SulfateYu: error writing varid =', ssa_sw_wtp_var + call handle_error(ret) + end if + + ret = nf90_put_var(fid, asm_sw_wtp_var, asm_sw_wtp (:, :)) + if (ret /= NF90_NOERR) then + write(iulog,*)'CARMA_CreateOpticsFile_SulfateYu: error writing varid =', asm_sw_wtp_var + call handle_error(ret) + end if - ! Close the file. - call wrap_close(fid) + ! Close the file. + call wrap_close(fid) + end if + end do return - end subroutine CARMA_CreateRefTFile + end subroutine CARMA_CreateOpticsFile_Sulfate !! Calculate the aerodynamic resistance for dry deposition. @@ -2645,4 +3034,87 @@ subroutine CARMA_calcram(ustar, z0, pdel, pmid, tmid, obklen, ram) return end subroutine CARMA_calcram + + !--------------------------------------------------------------------------- + ! define fields for reference profiles in cam restart file + !--------------------------------------------------------------------------- + subroutine CARMA_restart_init( File ) + use cam_pio_utils, only: cam_pio_def_dim + use pio, only: file_desc_t, pio_def_var, pio_double + + ! arguments + type(file_desc_t),intent(inout) :: File ! pio File pointer + + ! local variables + integer :: levid, ierr + + if (carma_do_fixedinit) then + call cam_pio_def_dim(File, 'lev', pver, levid, existOK=.true.) + ierr = pio_def_var(File, 'CARMA_REF_T', pio_double, (/ levid /), t_ref_desc) + ierr = pio_def_var(File, 'CARMA_REF_H2O', pio_double, (/ levid /), h2o_ref_desc) + ierr = pio_def_var(File, 'CARMA_REF_H2SO4', pio_double, (/ levid /), h2so4_ref_desc) + endif + + end subroutine CARMA_restart_init + + !--------------------------------------------------------------------------- + ! write reference profiles to restart file + !--------------------------------------------------------------------------- + subroutine CARMA_restart_write(File) + use pio, only: file_desc_t, pio_put_var + + ! arguments + type(file_desc_t), intent(inout) :: File + + ! local variables + integer ::ierr + + if (carma_do_fixedinit) then + ierr = pio_put_var(File, t_ref_desc, carma_t_ref) + if (carma%f_igash2o /= 0) then + ierr = pio_put_var(File, h2o_ref_desc, carma_h2o_ref) + endif + if (carma%f_igash2So4 /= 0) then + ierr = pio_put_var(File, h2so4_ref_desc, carma_h2so4_ref) + endif + endif + + end subroutine CARMA_restart_write + + !--------------------------------------------------------------------------- + ! read reference profiles from restart file + !--------------------------------------------------------------------------- + subroutine CARMA_restart_read(File) + use pio, only: file_desc_t, pio_inq_varid, pio_get_var + + ! arguments + type(file_desc_t),intent(inout) :: File ! pio File pointer + + ! local variables + integer :: ierr, varid + character(len=*), parameter :: subname = 'CARMA_restart_read: ' + + if (carma_do_fixedinit) then + ierr = pio_inq_varid(File, 'CARMA_REF_T', varid) + if (varid>0) then + ierr = pio_get_var(File, varid, carma_t_ref) + else + call endrun(subname//'restart file must include CARMA_REF_T') + endif + ierr = pio_inq_varid(File, 'CARMA_REF_H2O', varid) + if (varid>0) then + ierr = pio_get_var(File, varid, carma_h2o_ref) + else if (carma%f_igash2o /= 0) then + call endrun(subname//'restart file must include CARMA_REF_H2O') + endif + ierr = pio_inq_varid(File, 'CARMA_REF_H2SO4', varid) + if (varid>0) then + ierr = pio_get_var(File, varid, carma_h2so4_ref) + else if (carma%f_igash2So4 /= 0) then + call endrun(subname//'restart file must include CARMA_REF_H2SO4') + endif + endif + + end subroutine CARMA_restart_read + end module carma_intr diff --git a/src/physics/carma/cam/carma_precision_mod.F90 b/src/physics/carma/cam/carma_precision_mod.F90 index db76f798c6..ae22471312 100644 --- a/src/physics/carma/cam/carma_precision_mod.F90 +++ b/src/physics/carma/cam/carma_precision_mod.F90 @@ -35,4 +35,4 @@ module carma_precision_mod !! Define smallest possible number such that ONE + ALMOST_ZERO > ONE real(kind=f), parameter :: ALMOST_ZERO = epsilon( ONE ) real(kind=f), parameter :: ALMOST_ONE = ONE - ALMOST_ZERO -end module +end module carma_precision_mod diff --git a/src/physics/carma/models/bc_strat/carma_model_mod.F90 b/src/physics/carma/models/bc_strat/carma_model_mod.F90 index 42dc276a01..e4a933dd67 100644 --- a/src/physics/carma/models/bc_strat/carma_model_mod.F90 +++ b/src/physics/carma/models/bc_strat/carma_model_mod.F90 @@ -417,4 +417,4 @@ subroutine CARMA_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) return end subroutine CARMA_WetDeposition -end module +end module carma_model_mod diff --git a/src/physics/carma/models/cirrus/carma_model_mod.F90 b/src/physics/carma/models/cirrus/carma_model_mod.F90 index 446a17cdd8..b751221964 100644 --- a/src/physics/carma/models/cirrus/carma_model_mod.F90 +++ b/src/physics/carma/models/cirrus/carma_model_mod.F90 @@ -315,7 +315,7 @@ subroutine CARMA_DefineModel(carma, rc) ! Read in the tables. call wrap_inq_varid(fid, 'wavelength', wave_vid) call wrap_get_var_realx(fid, wave_vid, warren_wave) - warren_wave = warren_wave * 1e-4 ! um -> cm + warren_wave = warren_wave * 1e-4_r8 ! um -> cm call wrap_inq_varid(fid, 'm_real', real_vid) call wrap_get_var_realx(fid, real_vid, warren_real) @@ -1344,7 +1344,7 @@ subroutine CARMA_InitializeModel(carma, lq_carma, rc) ! Now integrate the snow distribution. We know the snow amount, but need an effective radius ! to determine the snow number. sub_d = 2._f * (r(NBIN) + (dr(NBIN) / 2._f)) * shapeFactor - sub_dd = (snow_max_d * 1e-4 - sub_d) / NINTS_SNOW + sub_dd = (snow_max_d * 1e-4_r8 - sub_d) / NINTS_SNOW sub_d = sub_d + sub_dd / 2._f remainder = 0._f @@ -1361,7 +1361,7 @@ subroutine CARMA_InitializeModel(carma, lq_carma, rc) ! m = aD^2.1 ! ! NOTE: This needs to match the density assumption made in the detrained ice bins. - remainder = remainder + nsnow / lambda * 4.22e-3_f * (sub_d**2.1) + remainder = remainder + nsnow / lambda * 4.22e-3_f * (sub_d**2.1_r8) sub_d = sub_d + sub_dd end do @@ -1374,7 +1374,7 @@ subroutine CARMA_InitializeModel(carma, lq_carma, rc) ! Now integrate the snow distribution. We know the snow amount, but need an effective radius ! to determine the snow number. snow_d = 2._f * ((r(NBIN) + dr(NBIN) / 2._f)) - sub_dd = (snow_max_d * 1e-4 - snow_d) / NINTS_SNOW + sub_dd = (snow_max_d * 1e-4_r8 - snow_d) / NINTS_SNOW sub_d = snow_d + (sub_dd / 2._f) snow_r3 = 0._f @@ -2064,4 +2064,4 @@ subroutine CARMA_CheckMassAndEnergy(carma, cstate, madeSnow, name, state, & return end subroutine CARMA_CheckMassAndEnergy -end module +end module carma_model_mod diff --git a/src/physics/carma/models/cirrus/growevapl.F90 b/src/physics/carma/models/cirrus/growevapl.F90 index e1020eb802..c6659bdbb4 100644 --- a/src/physics/carma/models/cirrus/growevapl.F90 +++ b/src/physics/carma/models/cirrus/growevapl.F90 @@ -216,7 +216,7 @@ subroutine growevapl(carma, cstate, iz, rc) if( x .lt. 1._f )then growlg(ibin,igroup) = dmdt(ibin)/pc(iz,ibin,iepart) & - * ( ar(ibin) - 0.5*dela(ibin)*x + & + * ( ar(ibin) - 0.5_r8*dela(ibin)*x + & (x/2._f - x**2/3._f)*a6(ibin) ) else growlg(ibin,igroup) = dmdt(ibin) / dm(ibin,igroup) diff --git a/src/physics/carma/models/cirrus_dust/carma_mod.F90 b/src/physics/carma/models/cirrus_dust/carma_mod.F90 index ab89065690..f6ac6945ae 100644 --- a/src/physics/carma/models/cirrus_dust/carma_mod.F90 +++ b/src/physics/carma/models/cirrus_dust/carma_mod.F90 @@ -1475,4 +1475,4 @@ subroutine CARMA_Get(carma, rc, LUNOPRT, NBIN, NELEM, NGAS, NGROUP, NSOLUTE, NWA return end subroutine CARMA_Get -end module +end module carma_mod diff --git a/src/physics/carma/models/cirrus_dust/carma_model_mod.F90 b/src/physics/carma/models/cirrus_dust/carma_model_mod.F90 index 036e1ea977..0ff512539e 100644 --- a/src/physics/carma/models/cirrus_dust/carma_model_mod.F90 +++ b/src/physics/carma/models/cirrus_dust/carma_model_mod.F90 @@ -335,7 +335,7 @@ subroutine CARMA_DefineModel(carma, rc) ! Read in the tables. call wrap_inq_varid(fid, 'wavelength', wave_vid) call wrap_get_var_realx(fid, wave_vid, warren_wave) - warren_wave = warren_wave * 1e-4 ! um -> cm + warren_wave = warren_wave * 1e-4_r8 ! um -> cm call wrap_inq_varid(fid, 'm_real', real_vid) call wrap_get_var_realx(fid, real_vid, warren_real) @@ -1386,7 +1386,7 @@ subroutine CARMA_InitializeModel(carma, lq_carma, rc) ! Now integrate the snow distribution. We know the snow amount, but need an effective radius ! to determine the snow number. sub_d = 2._f * (r(NBIN) + (dr(NBIN) / 2._f)) * shapeFactor - sub_dd = (snow_max_d * 1e-4 - sub_d) / NINTS_SNOW + sub_dd = (snow_max_d * 1e-4_r8 - sub_d) / NINTS_SNOW sub_d = sub_d + sub_dd / 2._f remainder = 0._f @@ -1403,7 +1403,7 @@ subroutine CARMA_InitializeModel(carma, lq_carma, rc) ! m = aD^2.1 ! ! NOTE: This needs to match the density assumption made in the detrained ice bins. - remainder = remainder + nsnow / lambda * 4.22e-3_f * (sub_d**2.1) + remainder = remainder + nsnow / lambda * 4.22e-3_f * (sub_d**2.1_r8) sub_d = sub_d + sub_dd end do @@ -1416,7 +1416,7 @@ subroutine CARMA_InitializeModel(carma, lq_carma, rc) ! Now integrate the snow distribution. We know the snow amount, but need an effective radius ! to determine the snow number. snow_d = 2._f * ((r(NBIN) + dr(NBIN) / 2._f)) - sub_dd = (snow_max_d * 1e-4 - snow_d) / NINTS_SNOW + sub_dd = (snow_max_d * 1e-4_r8 - snow_d) / NINTS_SNOW sub_d = snow_d + (sub_dd / 2._f) snow_r3 = 0._f @@ -2570,7 +2570,7 @@ subroutine CARMA_SurfaceWind(carma, state, icol, ilat, ilon, ielem, igroup, ibin * sqrt(1._r8 + .006_r8/rhop(ibin)/GRAV/(r(ibin)*2._r8)**2.5_r8) & / sqrt(1.928_r8*(1331._r8*(r(ibin)*2._r8)**1.56_r8 + .38_r8)**.092_r8 - 1._r8) else - uth = uthfact*1.e-2_r8* 0.13_r8 * sqrt(rhop(ibin)*GRAV*(.75e-4_r8)*2./rhoa) & + uth = uthfact*1.e-2_r8* 0.13_r8 * sqrt(rhop(ibin)*GRAV*(.75e-4_r8)*2._r8/rhoa) & * sqrt(1._r8 + .006_r8/rhop(ibin)/GRAV/((.75e-4_r8)*2._r8)**2.5_r8) & / sqrt(1.928_r8*(1331._r8*((.75e-4_r8)*2._r8)**1.56_r8 + .38_r8)**.092_r8 - 1._r8) endif @@ -2703,7 +2703,7 @@ subroutine WeibullWind(u, uth, n, uwb, wbk) if (present(wbk)) then k = wbk else - k = 0.94*u**0.5_r8 ! follow Grini and Zender, 2004JGR + k = 0.94_r8*u**0.5_r8 ! follow Grini and Zender, 2004JGR ! k = 2.5_r8 ! Lansing's estimate end if @@ -2718,4 +2718,4 @@ subroutine WeibullWind(u, uth, n, uwb, wbk) end subroutine WeibullWind -end module +end module carma_model_mod diff --git a/src/physics/carma/models/cirrus_dust/growevapl.F90 b/src/physics/carma/models/cirrus_dust/growevapl.F90 index e1020eb802..c6659bdbb4 100644 --- a/src/physics/carma/models/cirrus_dust/growevapl.F90 +++ b/src/physics/carma/models/cirrus_dust/growevapl.F90 @@ -216,7 +216,7 @@ subroutine growevapl(carma, cstate, iz, rc) if( x .lt. 1._f )then growlg(ibin,igroup) = dmdt(ibin)/pc(iz,ibin,iepart) & - * ( ar(ibin) - 0.5*dela(ibin)*x + & + * ( ar(ibin) - 0.5_r8*dela(ibin)*x + & (x/2._f - x**2/3._f)*a6(ibin) ) else growlg(ibin,igroup) = dmdt(ibin) / dm(ibin,igroup) diff --git a/src/physics/carma/models/dust/carma_model_mod.F90 b/src/physics/carma/models/dust/carma_model_mod.F90 index 22ba9b69d2..09c96b2bf0 100644 --- a/src/physics/carma/models/dust/carma_model_mod.F90 +++ b/src/physics/carma/models/dust/carma_model_mod.F90 @@ -46,14 +46,19 @@ module carma_model_mod private ! Declare the public methods. - public CARMA_DefineModel - public CARMA_Detrain - public CARMA_DiagnoseBins - public CARMA_DiagnoseBulk - public CARMA_EmitParticle - public CARMA_InitializeModel - public CARMA_InitializeParticle - public CARMA_WetDeposition + public CARMAMODEL_CalculateCloudborneDiagnostics + public CARMAMODEL_CreateOpticsFile + public CARMAMODEL_DefineModel + public CARMAMODEL_Detrain + public CARMAMODEL_DiagnoseBins + public CARMAMODEL_DiagnoseBulk + public CARMAMODEL_EmitParticle + public CARMAMODEL_InitializeModel + public CARMAMODEL_InitializeParticle + public CARMAMODEL_OutputBudgetDiagnostics + public CARMAMODEL_OutputCloudborneDiagnostics + public CARMAMODEL_OutputDiagnostics + public CARMAMODEL_WetDeposition ! Declare public constants integer, public, parameter :: NGROUP = 1 !! Number of particle groups @@ -66,6 +71,10 @@ module carma_model_mod integer, public, parameter :: NMIE_RH = 8 !! Number of relative humidities for mie calculations real(kind=f), public :: mie_rh(NMIE_RH) + integer, public, parameter :: NMIE_WTP = 0 !! Number of weight percents for mie calculations + real(kind=f), public :: mie_wtp(NMIE_WTP) + integer, public, parameter :: NREFIDX = 1 !! Number of refractive indices per element + ! Defines whether the groups should undergo deep convection in phase 1 or phase 2. ! Water vapor and cloud particles are convected in phase 1, while all other constituents ! are done in phase 2. @@ -90,7 +99,7 @@ module carma_model_mod !! !! @version May-2009 !! @author Chuck Bardeen - subroutine CARMA_DefineModel(carma, rc) + subroutine CARMAMODEL_DefineModel(carma, rc) type(carma_type), intent(inout) :: carma !! the carma object integer, intent(out) :: rc !! return code, negative indicates failure @@ -107,7 +116,7 @@ subroutine CARMA_DefineModel(carma, rc) ! Report model specific namelist configuration parameters. if (masterproc) then call CARMA_Get(carma, rc, do_print=do_print, LUNOPRT=LUNOPRT) - if (rc < 0) call endrun("CARMA_DefineModel: CARMA_Get failed.") + if (rc < 0) call endrun("CARMAMODEL_DefineModel: CARMA_Get failed.") if (do_print) write(LUNOPRT,*) '' if (do_print) write(LUNOPRT,*) 'CARMA ', trim(carma_model), ' specific settings :' @@ -122,7 +131,7 @@ subroutine CARMA_DefineModel(carma, rc) call CARMAGROUP_Create(carma, 1, "dust", rmin, vmrat, I_SPHERE, 1._f, .false., & rc, do_wetdep=.true., do_drydep=.true., solfac=0.3_f, & scavcoef=0.1_f, shortname="CRDUST") - if (rc < 0) call endrun('CARMA_DefineModel::CARMA_AddGroup failed.') + if (rc < 0) call endrun('CARMAMODEL_DefineModel::CARMA_AddGroup failed.') ! Define the Elements @@ -130,7 +139,7 @@ subroutine CARMA_DefineModel(carma, rc) ! NOTE: For CAM, the optional shortname needs to be provided for the group. These names ! should be 6 characters or less and without spaces. call CARMAELEMENT_Create(carma, 1, 1, "dust", RHO_DUST, I_INVOLATILE, I_DUST, rc, shortname="CRDUST") - if (rc < 0) call endrun('CARMA_DefineModel::CARMA_AddElement failed.') + if (rc < 0) call endrun('CARMAMODEL_DefineModel::CARMA_AddElement failed.') ! Define the Solutes @@ -143,7 +152,7 @@ subroutine CARMA_DefineModel(carma, rc) return - end subroutine CARMA_DefineModel + end subroutine CARMAMODEL_DefineModel !! Defines all the CARMA components (groups, elements, solutes and gases) and process @@ -153,7 +162,7 @@ end subroutine CARMA_DefineModel !! @author Chuck Bardeen !! !! @see CARMASTATE_SetDetrain - subroutine CARMA_Detrain(carma, cstate, cam_in, dlf, state, icol, dt, rc, rliq, prec_str, snow_str, & + subroutine CARMAMODEL_Detrain(carma, cstate, cam_in, dlf, state, icol, dt, rc, rliq, prec_str, snow_str, & tnd_qsnow, tnd_nsnow) use camsrfexch, only: cam_in_t use physconst, only: latice, latvap, cpair @@ -178,14 +187,14 @@ subroutine CARMA_Detrain(carma, cstate, cam_in, dlf, state, icol, dt, rc, rliq, rc = RC_OK return - end subroutine CARMA_Detrain + end subroutine CARMAMODEL_Detrain !! For diagnostic groups, sets up up the CARMA bins based upon the CAM state. !! !! @version July-2009 !! @author Chuck Bardeen - subroutine CARMA_DiagnoseBins(carma, cstate, state, pbuf, icol, dt, rc, rliq, prec_str, snow_str) + subroutine CARMAMODEL_DiagnoseBins(carma, cstate, state, pbuf, icol, dt, rc, rliq, prec_str, snow_str) use time_manager, only: is_first_step implicit none @@ -211,14 +220,14 @@ subroutine CARMA_DiagnoseBins(carma, cstate, state, pbuf, icol, dt, rc, rliq, pr ! code to determine the mass in each bin from the CAM state. return - end subroutine CARMA_DiagnoseBins + end subroutine CARMAMODEL_DiagnoseBins !! For diagnostic groups, determines the tendencies on the CAM state from the CARMA bins. !! !! @version July-2009 !! @author Chuck Bardeen - subroutine CARMA_DiagnoseBulk(carma, cstate, cam_out, state, pbuf, ptend, icol, dt, rc, rliq, prec_str, snow_str, & + subroutine CARMAMODEL_DiagnoseBulk(carma, cstate, cam_out, state, pbuf, ptend, icol, dt, rc, rliq, prec_str, snow_str, & prec_sed, snow_sed, tnd_qsnow, tnd_nsnow, re_ice) use camsrfexch, only: cam_out_t @@ -249,7 +258,7 @@ subroutine CARMA_DiagnoseBulk(carma, cstate, cam_out, state, pbuf, ptend, icol, ! code to determine the bulk mass from the CARMA state. return - end subroutine CARMA_DiagnoseBulk + end subroutine CARMAMODEL_DiagnoseBulk !! Calculates the emissions for CARMA aerosol particles. By default, there is no @@ -258,7 +267,7 @@ end subroutine CARMA_DiagnoseBulk !! !! @author Lin Su, Pengfei Yu, Chuck Bardeen !! @version Dec-2010 - subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tendency, surfaceFlux, rc) + subroutine CARMAMODEL_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tendency, surfaceFlux, pbuf, rc) use shr_kind_mod, only: r8 => shr_kind_r8 use ppgrid, only: pcols, pver use physics_types, only: physics_state @@ -276,10 +285,9 @@ subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tend type(cam_in_t), intent(in) :: cam_in !! surface inputs real(r8), intent(out) :: tendency(pcols, pver) !! constituent tendency (kg/kg/s) real(r8), intent(out) :: surfaceFlux(pcols) !! constituent surface flux (kg/m^2/s) + type(physics_buffer_desc), pointer :: pbuf(:) !! physics buffer integer, intent(out) :: rc !! return code, negative indicates failure - integer :: ilat(pcols) ! latitude index - integer :: ilon(pcols) ! longitude index integer :: lchnk ! chunk identifier integer :: ncol ! number of columns in chunk integer :: icol ! column index @@ -341,7 +349,7 @@ subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tend ! Process each column. do icol = 1,ncol - call CARMA_SurfaceWind(carma, state, icol, ielem, igroup, idustbin, cam_in, uv10, wwd, uth, rc) + call CARMAMODEL_SurfaceWind(carma, state, icol, ielem, igroup, idustbin, cam_in, uv10, wwd, uth, rc) ! Is the wind above the threshold for dust production? if (uv10 > uth) then @@ -351,16 +359,15 @@ subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tend ! Scale the clay bins based upon the smallest silt bin. surfaceFlux(icol) = clay_mf(ibin) * surfaceFlux(icol) - end do ! For debug purposes, output the soil erosion factor. call outfld('CRSLERFC', soil_factor(:ncol, lchnk), ncol, lchnk) - end if + end if return - end subroutine CARMA_EmitParticle + end subroutine CARMAMODEL_EmitParticle !! Allows the model to perform its own initialization in addition to what is done @@ -368,16 +375,17 @@ end subroutine CARMA_EmitParticle !! !! @author Chuck Bardeen !! @version May-2009 - subroutine CARMA_InitializeModel(carma, lq_carma, rc) + subroutine CARMAMODEL_InitializeModel(carma, lq_carma, pbuf2d, rc) use cam_history, only: addfld, add_default, horiz_only use constituents, only: pcnst implicit none - type(carma_type), intent(in) :: carma !! the carma object - logical, intent(inout) :: lq_carma(pcnst) !! flags to indicate whether the constituent + type(carma_type), intent(in) :: carma !! the carma object + logical, intent(inout) :: lq_carma(pcnst) !! flags to indicate whether the constituent !! could have a CARMA tendency - integer, intent(out) :: rc !! return code, negative indicates failure + type(physics_buffer_desc), pointer :: pbuf2d(:,:) + integer, intent(out) :: rc !! return code, negative indicates failure ! -------- local variables ---------- integer :: ibin ! CARMA bin index @@ -421,7 +429,7 @@ subroutine CARMA_InitializeModel(carma, lq_carma, rc) end do ! Read in the soil factors. - call CARMA_ReadSoilErosionFactor(carma, rc) + call CARMAMODEL_ReadSoilErosionFactor(carma, rc) if (RC < RC_ERROR) return ! To determine Clay Mass Fraction @@ -431,7 +439,7 @@ subroutine CARMA_InitializeModel(carma, lq_carma, rc) if (RC < RC_ERROR) return if (shortname .eq. "CRDUST") then - call CARMA_ClayMassFraction(carma, igroup, rc) + call CARMAMODEL_ClayMassFraction(carma, igroup, rc) end if end do @@ -452,7 +460,7 @@ subroutine CARMA_InitializeModel(carma, lq_carma, rc) call addfld('CRSLERFC', horiz_only, 'A', 'fraction', 'CARMA soil erosion factor') return - end subroutine CARMA_InitializeModel + end subroutine CARMAMODEL_InitializeModel !! Sets the initial condition for CARMA aerosol particles. By default, there are no @@ -464,7 +472,7 @@ end subroutine CARMA_InitializeModel !! !! @author Chuck Bardeen !! @version May-2009 - subroutine CARMA_InitializeParticle(carma, ielem, ibin, latvals, lonvals, mask, q, rc) + subroutine CARMAMODEL_InitializeParticle(carma, ielem, ibin, latvals, lonvals, mask, q, rc) use shr_kind_mod, only: r8 => shr_kind_r8 use pmgrid, only: plev @@ -487,15 +495,55 @@ subroutine CARMA_InitializeParticle(carma, ielem, ibin, latvals, lonvals, mask, ! NOTE: Initialized to 0. by the caller, so nothing needs to be done. return - end subroutine CARMA_InitializeParticle + end subroutine CARMAMODEL_InitializeParticle + + !! This routine is an extension of CARMA_CreateOpticsFile() that allows for + !! model specific tables to be created in addition to the model independent + !! methods that are in carma_intr.F90. + !! + !! The opticsType that is specified for the group determines how the optical + !! properties will be generated for that group. Each group can use a different + !! optics method if needed. Refractive indices need for these calculation are + !! are specified in the group's elements rather than at the group level. This + !! allows various mixing approaches to be used to determine the refractive index + !! for the particle as a whole. If the refractive index for water is needed, + !! it is specific the the CARMAGAS object for H2O. + subroutine CARMAMODEL_CreateOpticsFile(carma, igroup, opticsType, rc) + + implicit none + + type(carma_type), intent(inout) :: carma !! the carma object + integer, intent(in) :: igroup !! group identifier + integer, intent(in) :: opticsType !! optics type (see I_OPTICS_... in carma_enums.F90) + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Local variables + logical :: do_mie + integer :: cnsttype ! constituent type + + ! Assume success. + rc = 0 + ! What type of calculation is needed for this group? + ! + ! NOTE: Some of these calculations generate optical properties as single mass + ! coefficients, while others are lookup tables designed around multiple + ! dimensions. + select case (opticsType) + + case default + call endrun('carma_CreateOpticsFile:: Unknown optics type.') + end select + + return + end subroutine CARMAMODEL_CreateOpticsFile !! Called after wet deposition has been performed. Allows the specific model to add !! wet deposition of CARMA aerosols to the aerosols being communicated to the surface. !! !! @version July-2011 !! @author Chuck Bardeen - subroutine CARMA_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) + subroutine CARMAMODEL_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) use camsrfexch, only: cam_out_t implicit none @@ -514,7 +562,7 @@ subroutine CARMA_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) rc = RC_OK return - end subroutine CARMA_WetDeposition + end subroutine CARMAMODEL_WetDeposition !! Determines the mass fraction for the clay (submicron) bins based upon @@ -529,7 +577,7 @@ end subroutine CARMA_WetDeposition !! !! @version July-2012 !! @author Lin Su, Pengfei Yu, Chuck Bardeen - subroutine CARMA_ClayMassFraction(carma, igroup, rc) + subroutine CARMAMODEL_ClayMassFraction(carma, igroup, rc) implicit none type(carma_type), intent(in) :: carma !! the carma object @@ -610,7 +658,7 @@ subroutine CARMA_ClayMassFraction(carma, igroup, rc) clay_mf(ind_low(IABOVE):) = 1._r8 return - end subroutine CARMA_ClayMassFraction + end subroutine CARMAMODEL_ClayMassFraction !! Calculate the sea surface wind with a Weibull distribution. @@ -621,7 +669,7 @@ end subroutine CARMA_ClayMassFraction !! !! @author Lin Su, Pengfei Yu, Chuck Bardeen !! @version July-2012 - subroutine CARMA_SurfaceWind(carma, state, icol, ielem, igroup, ibin, cam_in, uv10, wwd, uth, rc) + subroutine CARMAMODEL_SurfaceWind(carma, state, icol, ielem, igroup, ibin, cam_in, uv10, wwd, uth, rc) use ppgrid, only: pcols, pver use physics_types, only: physics_state use camsrfexch, only: cam_in_t @@ -669,7 +717,7 @@ subroutine CARMA_SurfaceWind(carma, state, icol, ielem, igroup, ibin, cam_in, uv * sqrt(1._r8 + .006_r8/rhop(ibin)/GRAV/(r(ibin)*2._r8)**2.5_r8) & / sqrt(1.928_r8*(1331._r8*(r(ibin)*2._r8)**1.56_r8 + .38_r8)**.092_r8 - 1._r8) else - uth = uthfact*1.e-2_r8* 0.13_r8 * sqrt(rhop(ibin)*GRAV*(.75e-4_r8)*2./rhoa) & + uth = uthfact*1.e-2_r8* 0.13_r8 * sqrt(rhop(ibin)*GRAV*(.75e-4_r8)*2._r8/rhoa) & * sqrt(1._r8 + .006_r8/rhop(ibin)/GRAV/((.75e-4_r8)*2._r8)**2.5_r8) & / sqrt(1.928_r8*(1331._r8*((.75e-4_r8)*2._r8)**1.56_r8 + .38_r8)**.092_r8 - 1._r8) endif @@ -681,7 +729,7 @@ subroutine CARMA_SurfaceWind(carma, state, icol, ielem, igroup, ibin, cam_in, uv call WeibullWind(uv10, uth, 2._r8, wwd) return - end subroutine CARMA_SurfaceWind + end subroutine CARMAMODEL_SurfaceWind !! Read in the dust source (soil) erodibility factor from a NETCDF file. In this @@ -693,7 +741,7 @@ end subroutine CARMA_SurfaceWind !! !! @author Pengfei Yu !! @version July-2012 - subroutine CARMA_ReadSoilErosionFactor(carma, rc) + subroutine CARMAMODEL_ReadSoilErosionFactor(carma, rc) use ppgrid, only: begchunk, endchunk, pcols use ioFileMod, only: getfil use wrap_nf @@ -742,7 +790,7 @@ subroutine CARMA_ReadSoilErosionFactor(carma, rc) call wrap_inq_varid(fid, 'new_source', idvar) i = nf90_get_var (fid, idvar, ero_factor) if (i/=NF90_NOERR) then - write(iulog,*)'CARMA_ReadSoilErosionFactor: error reading varid =', idvar + write(iulog,*)'CARMAMODEL_ReadSoilErosionFactor: error reading varid =', idvar call handle_error (i) end if call wrap_inq_varid(fid, 'plat', idlat) @@ -775,7 +823,8 @@ subroutine CARMA_ReadSoilErosionFactor(carma, rc) deallocate(ero_lon) deallocate(ero_factor) - end subroutine CARMA_ReadSoilErosionFactor + return + end subroutine CARMAMODEL_ReadSoilErosionFactor !! Calculate the nth mean of u using Weibull wind distribution @@ -804,7 +853,7 @@ subroutine WeibullWind(u, uth, n, uwb, wbk) if (present(wbk)) then k = wbk else - k = 0.94*u**0.5_r8 ! follow Grini and Zender, 2004JGR + k = 0.94_r8*u**0.5_r8 ! follow Grini and Zender, 2004JGR ! k = 2.5_r8 ! Lansing's estimate end if @@ -819,4 +868,92 @@ subroutine WeibullWind(u, uth, n, uwb, wbk) end subroutine WeibullWind -end module + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_CalculateCloudborneDiagnostics(carma, state, pbuf, aerclddiag, rc) + + type(carma_type), intent(in) :: carma !! the carma object + type(physics_state), intent(in) :: state !! Physics state variables - before pname + type(physics_buffer_desc), pointer, intent(in) :: pbuf(:) !! physics buffer + real(r8), intent(out) :: aerclddiag(pcols,MAXCLDAERDIAG) !! the total cloudborne aerosols, supports up to MAXCLDAERDIAG different values + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_CalculateCloudborneDiagnostics + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_OutputBudgetDiagnostics(carma, icnst4elem, icnst4gas, state, ptend, old_cflux, cflux, dt, pname, rc) + use cam_history, only: outfld + use constituents, only: pcnst, cnst_get_ind + + type(carma_type), intent(in) :: carma !! the carma object + integer, intent(in) :: icnst4elem(NELEM, NBIN) !! constituent index for a carma element + integer, intent(in) :: icnst4gas(NGAS) !! constituent index for a carma gas + type(physics_state), intent(in) :: state !! Physics state variables - before pname + type(physics_ptend), intent(in) :: ptend !! indivdual parameterization tendencies + real(r8) :: old_cflux(pcols,pcnst) !! cam_in%clfux from before the timestep_tend + real(r8) :: cflux(pcols,pcnst) !! cam_in%clfux from after the timestep_tend + real(r8), intent(in) :: dt !! timestep (s) + character(*), intent(in) :: pname !! short name of the physics package + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_OutputBudgetDiagnostics + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_OutputCloudborneDiagnostics(carma, state, pbuf, dt, pname, oldaerclddiag, rc) + use cam_history, only: outfld + + type(carma_type), intent(in) :: carma !! the carma object + type(physics_state), intent(in) :: state !! Physics state variables - before CARMA + type(physics_buffer_desc), pointer, intent(in) :: pbuf(:) !! physics buffer + real(r8), intent(in) :: dt !! timestep (s) + character(*), intent(in) :: pname !! short name of the physics package + real(r8), intent(in ) :: oldaerclddiag(pcols,MAXCLDAERDIAG) !! the before timestep cloudborne aerosol diags + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_OutputCloudborneDiagnostics + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_OutputDiagnostics(carma, icnst4elem, state, ptend, pbuf, cam_in, rc) + use cam_history, only: outfld + use constituents, only: cnst_get_ind + use camsrfexch, only: cam_in_t + + type(carma_type), intent(in) :: carma !! the carma object + integer, intent(in) :: icnst4elem(NELEM, NBIN) !! constituent index for a carma element + type(physics_state), intent(in) :: state !! Physics state variables - before CARMA + type(physics_ptend), intent(in) :: ptend !! indivdual parameterization tendencies + type(physics_buffer_desc), pointer, intent(in) :: pbuf(:) !! physics buffer + type(cam_in_t), intent(in) :: cam_in !! surface inputs + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_OutputDiagnostics + +end module carma_model_mod diff --git a/src/physics/carma/models/meteor_impact/carma_model_flags_mod.F90 b/src/physics/carma/models/meteor_impact/carma_model_flags_mod.F90 index 360ddb9499..efe43af66d 100644 --- a/src/physics/carma/models/meteor_impact/carma_model_flags_mod.F90 +++ b/src/physics/carma/models/meteor_impact/carma_model_flags_mod.F90 @@ -24,16 +24,16 @@ module carma_model_flags_mod ! ! Create a public definition of any new namelist variables that you wish to have, ! and default them to an inital value. - real(r8), public :: carma_emis_dust = 0._r8 !! Total dust emission for the event (kg) - real(r8), public :: carma_emis_soot = 0._r8 !! Total soot emission for the event (kg) - integer, public :: carma_emis_startdate = 1 !! start year and day of year (yyyyddd) - integer, public :: carma_emis_stopdate = 1 !! stop year and day of year (yyyyddd) - integer, public :: carma_emis_starttime = 0 !! start time of day (s) - integer, public :: carma_emis_stoptime = 0 !! stop time of day (s) - real(r8), public :: carma_emis_minlat = -90. !! minimum latitude - real(r8), public :: carma_emis_maxlat = 90. !! maximum latitude - real(r8), public :: carma_emis_minlon = 0. !! minimum longitude - real(r8), public :: carma_emis_maxlon = 360. !! maximum longitude + real(r8), public :: carma_emis_dust = 0._r8 !! Total dust emission for the event (kg) + real(r8), public :: carma_emis_soot = 0._r8 !! Total soot emission for the event (kg) + integer, public :: carma_emis_startdate = 1 !! start year and day of year (yyyyddd) + integer, public :: carma_emis_stopdate = 1 !! stop year and day of year (yyyyddd) + integer, public :: carma_emis_starttime = 0 !! start time of day (s) + integer, public :: carma_emis_stoptime = 0 !! stop time of day (s) + real(r8), public :: carma_emis_minlat = -90._r8 !! minimum latitude + real(r8), public :: carma_emis_maxlat = 90._r8 !! maximum latitude + real(r8), public :: carma_emis_minlon = 0._r8 !! minimum longitude + real(r8), public :: carma_emis_maxlon = 360._r8 !! maximum longitude logical, public :: carma_fractal_soot = .false. !! fractal Soot contains diff --git a/src/physics/carma/models/meteor_impact/carma_model_mod.F90 b/src/physics/carma/models/meteor_impact/carma_model_mod.F90 index f8ebec713d..ecc131f0cf 100755 --- a/src/physics/carma/models/meteor_impact/carma_model_mod.F90 +++ b/src/physics/carma/models/meteor_impact/carma_model_mod.F90 @@ -42,14 +42,19 @@ module carma_model_mod private ! Declare the public methods. - public CARMA_DefineModel - public CARMA_Detrain - public CARMA_DiagnoseBins - public CARMA_DiagnoseBulk - public CARMA_EmitParticle - public CARMA_InitializeModel - public CARMA_InitializeParticle - public CARMA_WetDeposition + public CARMAMODEL_CalculateCloudborneDiagnostics + public CARMAMODEL_CreateOpticsFile + public CARMAMODEL_DefineModel + public CARMAMODEL_Detrain + public CARMAMODEL_DiagnoseBins + public CARMAMODEL_DiagnoseBulk + public CARMAMODEL_EmitParticle + public CARMAMODEL_InitializeModel + public CARMAMODEL_InitializeParticle + public CARMAMODEL_OutputBudgetDiagnostics + public CARMAMODEL_OutputCloudborneDiagnostics + public CARMAMODEL_OutputDiagnostics + public CARMAMODEL_WetDeposition ! Declare public constants integer, public, parameter :: NGROUP = 2 !! Number of particle groups @@ -65,6 +70,10 @@ module carma_model_mod integer, public, parameter :: NMIE_RH = 8 !! Number of relative humidities for mie calculations real(kind=f), public :: mie_rh(NMIE_RH) = (/ 0._f, 0.5_f, 0.7_f, 0.8_f, 0.9_f, 0.95_f, 0.98_f, 0.99_f /) + integer, public, parameter :: NMIE_WTP = 0 !! Number of weight percents for mie calculations + real(kind=f), public :: mie_wtp(NMIE_WTP) + integer, public, parameter :: NREFIDX = 1 !! Number of refractive indices per element + ! Defines whether the groups should undergo deep convection in phase 1 or phase 2. ! Water vapor and cloud particles are convected in phase 1, while all other constituents ! are done in phase 2. @@ -96,7 +105,7 @@ module carma_model_mod !! !! @version May-2009 !! @author Chuck Bardeen - subroutine CARMA_DefineModel(carma, rc) + subroutine CARMAMODEL_DefineModel(carma, rc) type(carma_type), intent(inout) :: carma !! the carma object integer, intent(out) :: rc !! return code, negative indicates failure @@ -107,7 +116,7 @@ subroutine CARMA_DefineModel(carma, rc) real(kind=f), parameter :: dust_vmrat = 2.49_f ! dust volume ratio real(kind=f), parameter :: soot_rmin = 20.e-7_f ! dust minimum radius (cm) real(kind=f), parameter :: soot_vmrat = 2.49_f ! dust volume ratio - complex(kind=f) :: refidx(NWAVE) ! refractice indices + complex(kind=f) :: refidx(NWAVE,NREFIDX) ! refractice indices integer :: LUNOPRT ! logical unit number for output logical :: do_print ! do print output? @@ -123,13 +132,13 @@ subroutine CARMA_DefineModel(carma, rc) if (carma_emis_maxlon < 0._f) carma_emis_maxlon = 360._f + carma_emis_maxlon if (carma_emis_minlat > carma_emis_maxlat) then - if (do_print) write(LUNOPRT,*) 'CARMA_DefineModel::ERROR - carma_emis_minlat greater than carma_emis_maxlat' + if (do_print) write(LUNOPRT,*) 'CARMAMODEL_DefineModel::ERROR - carma_emis_minlat greater than carma_emis_maxlat' end if ! Report model specific namelist configuration parameters. if (masterproc) then call CARMA_Get(carma, rc, do_print=do_print, LUNOPRT=LUNOPRT) - if (rc < 0) call endrun("CARMA_InitializeModel: CARMA_Get failed.") + if (rc < 0) call endrun("CARMAMODEL_DefineModel: CARMA_Get failed.") if (do_print) write(LUNOPRT,*) '' if (do_print) write(LUNOPRT,*) 'CARMA ', trim(carma_model), ' specific settings :' @@ -154,19 +163,10 @@ subroutine CARMA_DefineModel(carma, rc) ! defined. If wetdep is defined, then the optional solubility factor ! should also be defined. - ! Use the same refractive index at all wavelengths. This value is typical of soot and - ! is recommended by Toon et al. 2012. TBD Wagner et al. 2011 shows variability in the - ! real part (0.003 (IR) to 0.05 (UV)). - refidx(:) = (1.53_f, 0.008_f) - call CARMAGROUP_Create(carma, I_GRP_DUST, "Dust", dust_rmin, dust_vmrat, I_SPHERE, 1._f, .false., & rc, do_wetdep=.true., do_drydep=.true., solfac=0.3_f, & - scavcoef=0.1_f, shortname="CRDUST", refidx=refidx, do_mie=.true.) - if (rc < 0) call endrun('CARMA_DefineModel::CARMA_AddGroup failed.') - - ! Use the same refractive index at all wavelengths. This value is typical of soot and - ! is recommended by Toon et al. 2012. - refidx(:) = (1.8_f, 0.67_f) + scavcoef=0.1_f, shortname="CRDUST", do_mie=.true.) + if (rc < 0) call endrun('CARMAMODEL_DefineModel::CARMA_AddGroup failed.') if (carma_fractal_soot) then RHO_SOOT = 1.8_f @@ -178,27 +178,37 @@ subroutine CARMA_DefineModel(carma, rc) call CARMAGROUP_Create(carma, I_GRP_SOOT, "Soot", soot_rmin, soot_vmrat, I_SPHERE, 1._f, .false., & rc, do_wetdep=.true., do_drydep=.true., solfac=0.1_f, & - scavcoef=0.1_f, shortname="CRSOOT", refidx=refidx, do_mie=.true., & + scavcoef=0.1_f, shortname="CRSOOT", do_mie=.true., & is_fractal=.true., rmon=soot_rmon, df=soot_df, falpha=soot_falpha, & imiertn=I_MIERTN_BOTET1997) else RHO_SOOT = 1.0_f call CARMAGROUP_Create(carma, I_GRP_SOOT, "Soot", soot_rmin, soot_vmrat, I_SPHERE, 1._f, .false., & rc, do_wetdep=.true., do_drydep=.true., solfac=0.1_f, & - scavcoef=0.1_f, shortname="CRSOOT", refidx=refidx, do_mie=.true.) + scavcoef=0.1_f, shortname="CRSOOT", do_mie=.true.) end if - if (rc < 0) call endrun('CARMA_DefineModel::CARMA_AddGroup failed.') + if (rc < 0) call endrun('CARMAMODEL_DefineModel::CARMA_AddGroup failed.') ! Define the Elements ! ! NOTE: For CAM, the optional shortname needs to be provided for the group. These names ! should be 6 characters or less and without spaces. - call CARMAELEMENT_Create(carma, I_ELEM_DUST, I_GRP_DUST, "Dust", RHO_DUST, I_INVOLATILE, I_DUST, rc, shortname="CRDUST") - if (rc < 0) call endrun('CARMA_DefineModel::CARMA_AddElement failed.') - call CARMAELEMENT_Create(carma, I_ELEM_SOOT, I_GRP_SOOT, "Soot", RHO_SOOT, I_INVOLATILE, I_SOOT, rc, shortname="CRSOOT") - if (rc < 0) call endrun('CARMA_DefineModel::CARMA_AddElement failed.') + ! Use the same refractive index at all wavelengths. This value is typical of dust and + ! is recommended by Toon et al. 2012. TBD Wagner et al. 2011 shows variability in the + ! real part (0.003 (IR) to 0.05 (UV)). + refidx(:,1) = CMPLX(1.53_f, 0.008_f, kind=f) + + call CARMAELEMENT_Create(carma, I_ELEM_DUST, I_GRP_DUST, "Dust", RHO_DUST, I_INVOLATILE, I_DUST, rc, shortname="CRDUST", refidx=refidx) + if (rc < 0) call endrun('CARMAMODEL_DefineModel::CARMA_AddElement failed.') + + ! Use the same refractive index at all wavelengths. This value is typical of soot and + ! is recommended by Toon et al. 2012. + refidx(:,1) = CMPLX(1.8_f, 0.67_f, kind=f) + + call CARMAELEMENT_Create(carma, I_ELEM_SOOT, I_GRP_SOOT, "Soot", RHO_SOOT, I_INVOLATILE, I_SOOT, rc, shortname="CRSOOT", refidx=refidx) + if (rc < 0) call endrun('CARMAMODEL_DefineModel::CARMA_AddElement failed.') ! Define the Solutes @@ -209,13 +219,13 @@ subroutine CARMA_DefineModel(carma, rc) ! Define the Processes call CARMA_AddCoagulation(carma, I_GRP_DUST, I_GRP_DUST, I_GRP_DUST, I_COLLEC_DATA, rc) - if (rc < 0) call endrun('CARMA_DefineModel::CARMA_AddCoagulation failed.') + if (rc < 0) call endrun('CARMAMODEL_DefineModel::CARMA_AddCoagulation failed.') call CARMA_AddCoagulation(carma, I_GRP_SOOT, I_GRP_SOOT, I_GRP_SOOT, I_COLLEC_DATA, rc) - if (rc < 0) call endrun('CARMA_DefineModel::CARMA_AddCoagulation failed.') + if (rc < 0) call endrun('CARMAMODEL_DefineModel::CARMA_AddCoagulation failed.') return - end subroutine CARMA_DefineModel + end subroutine CARMAMODEL_DefineModel !! Defines all the CARMA components (groups, elements, solutes and gases) and process @@ -225,7 +235,7 @@ end subroutine CARMA_DefineModel !! @author Chuck Bardeen !! !! @see CARMASTATE_SetDetrain - subroutine CARMA_Detrain(carma, cstate, cam_in, dlf, state, icol, dt, rc, rliq, prec_str, snow_str, & + subroutine CARMAMODEL_Detrain(carma, cstate, cam_in, dlf, state, icol, dt, rc, rliq, prec_str, snow_str, & tnd_qsnow, tnd_nsnow) use camsrfexch, only: cam_in_t use physconst, only: latice, latvap, cpair @@ -250,14 +260,14 @@ subroutine CARMA_Detrain(carma, cstate, cam_in, dlf, state, icol, dt, rc, rliq, rc = RC_OK return - end subroutine CARMA_Detrain + end subroutine CARMAMODEL_Detrain !! For diagnostic groups, sets up up the CARMA bins based upon the CAM state. !! !! @version July-2009 !! @author Chuck Bardeen - subroutine CARMA_DiagnoseBins(carma, cstate, state, pbuf, icol, dt, rc, rliq, prec_str, snow_str) + subroutine CARMAMODEL_DiagnoseBins(carma, cstate, state, pbuf, icol, dt, rc, rliq, prec_str, snow_str) use time_manager, only: is_first_step implicit none @@ -283,14 +293,14 @@ subroutine CARMA_DiagnoseBins(carma, cstate, state, pbuf, icol, dt, rc, rliq, pr ! code to determine the mass in each bin from the CAM state. return - end subroutine CARMA_DiagnoseBins + end subroutine CARMAMODEL_DiagnoseBins !! For diagnostic groups, determines the tendencies on the CAM state from the CARMA bins. !! !! @version July-2009 !! @author Chuck Bardeen - subroutine CARMA_DiagnoseBulk(carma, cstate, cam_out, state, pbuf, ptend, icol, dt, rc, rliq, prec_str, snow_str, & + subroutine CARMAMODEL_DiagnoseBulk(carma, cstate, cam_out, state, pbuf, ptend, icol, dt, rc, rliq, prec_str, snow_str, & prec_sed, snow_sed, tnd_qsnow, tnd_nsnow, re_ice) use camsrfexch, only: cam_out_t @@ -329,7 +339,7 @@ subroutine CARMA_DiagnoseBulk(carma, cstate, cam_out, state, pbuf, ptend, icol, do ibin = 1, NBIN call CARMASTATE_GetBin(cstate, ielem, ibin, mmr, rc, sedimentationFlux=sflx) - if (rc < 0) call endrun('CARMA_DiagnoseBulk::CARMA_GetBin failed.') + if (rc < 0) call endrun('CARMAMODEL_DiagnoseBulk::CARMA_GetBin failed.') cam_out%bcphidry(icol) = cam_out%bcphidry(icol) + max(sflx, 0._r8) end do @@ -338,7 +348,7 @@ subroutine CARMA_DiagnoseBulk(carma, cstate, cam_out, state, pbuf, ptend, icol, do ibin = 1, NBIN call CARMASTATE_GetBin(cstate, ielem, ibin, mmr, rc, sedimentationFlux=sflx) - if (rc < 0) call endrun('CARMA_DiagnoseBulk::CARMA_GetBin failed.') + if (rc < 0) call endrun('CARMAMODEL_DiagnoseBulk::CARMA_GetBin failed.') if (carma_dustmap(ibin) == 1) then cam_out%dstdry1(icol) = cam_out%dstdry1(icol) + max(sflx, 0._r8) @@ -352,7 +362,7 @@ subroutine CARMA_DiagnoseBulk(carma, cstate, cam_out, state, pbuf, ptend, icol, end do return - end subroutine CARMA_DiagnoseBulk + end subroutine CARMAMODEL_DiagnoseBulk !! Calculates the emissions for CARMA aerosol particles. By default, there is no @@ -361,7 +371,7 @@ end subroutine CARMA_DiagnoseBulk !! !! @author Chuck Bardeen !! @version May-2009 - subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tendency, surfaceFlux, rc) + subroutine CARMAMODEL_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tendency, surfaceFlux, pbuf, rc) use shr_kind_mod, only: r8 => shr_kind_r8 use ppgrid, only: pcols, pver use physics_types, only: physics_state @@ -382,6 +392,7 @@ subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tend type(cam_in_t), intent(in) :: cam_in !! surface inputs real(r8), intent(out) :: tendency(pcols, pver) !! constituent tendency (kg/kg/s) real(r8), intent(out) :: surfaceFlux(pcols) !! constituent surface flux (kg/m^2/s) + type(physics_buffer_desc), pointer :: pbuf(:) !! physics buffer integer, intent(out) :: rc !! return code, negative indicates failure real(r8), parameter :: mu_dust_gnd = 1._r8 ! width parameter, dust, ground (km) @@ -563,7 +574,7 @@ subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tend end if return - end subroutine CARMA_EmitParticle + end subroutine CARMAMODEL_EmitParticle !! Allows the model to perform its own initialization in addition to what is done @@ -574,7 +585,7 @@ end subroutine CARMA_EmitParticle !! !! @author Chuck Bardeen !! @version May-2009 - subroutine CARMA_InitializeModel(carma, lq_carma, rc) + subroutine CARMAMODEL_InitializeModel(carma, lq_carma, pbuf2d, rc) use constituents, only: pcnst use phys_grid, only: get_rlat_all_p, get_rlon_all_p, get_area_all_p, get_ncols_p use shr_reprosum_mod, only: shr_reprosum_calc @@ -586,14 +597,15 @@ subroutine CARMA_InitializeModel(carma, lq_carma, rc) type(carma_type), intent(in) :: carma !! the carma object logical, intent(inout) :: lq_carma(pcnst) !! flags to indicate whether the constituent !! could have a CARMA tendency + type(physics_buffer_desc), pointer :: pbuf2d(:,:) integer, intent(out) :: rc !! return code, negative indicates failure ! NOTE: The dust distribution has not been specified yet, but it should be different ! from the soot. - real(kind=f), parameter :: rm_dust = 0.11 ! dust mean radius (um) - real(kind=f), parameter :: sigma_dust = 1.6 ! dust variance - real(kind=f), parameter :: rm_soot = 0.11 ! soot mean radius (um) - real(kind=f), parameter :: sigma_soot = 1.6 ! soot variance + real(kind=f), parameter :: rm_dust = 0.11_r8 ! dust mean radius (um) + real(kind=f), parameter :: sigma_dust = 1.6_r8 ! dust variance + real(kind=f), parameter :: rm_soot = 0.11_r8 ! soot mean radius (um) + real(kind=f), parameter :: sigma_soot = 1.6_r8 ! soot variance integer :: i real(kind=f) :: r(NBIN) @@ -735,7 +747,7 @@ subroutine CARMA_InitializeModel(carma, lq_carma, rc) end if return - end subroutine CARMA_InitializeModel + end subroutine CARMAMODEL_InitializeModel !! Sets the initial condition for CARMA aerosol particles. By default, there are no @@ -747,7 +759,7 @@ end subroutine CARMA_InitializeModel !! !! @author Chuck Bardeen !! @version May-2009 - subroutine CARMA_InitializeParticle(carma, ielem, ibin, latvals, lonvals, mask, q, rc) + subroutine CARMAMODEL_InitializeParticle(carma, ielem, ibin, latvals, lonvals, mask, q, rc) use shr_kind_mod, only: r8 => shr_kind_r8 implicit none @@ -767,15 +779,55 @@ subroutine CARMA_InitializeParticle(carma, ielem, ibin, latvals, lonvals, mask, ! Add initial condition here. return - end subroutine CARMA_InitializeParticle + end subroutine CARMAMODEL_InitializeParticle + !! This routine is an extension of CARMA_CreateOpticsFile() that allows for + !! model specific tables to be created in addition to the model independent + !! methods that are in carma_intr.F90. + !! + !! The opticsType that is specified for the group determines how the optical + !! properties will be generated for that group. Each group can use a different + !! optics method if needed. Refractive indices need for these calculation are + !! are specified in the group's elements rather than at the group level. This + !! allows various mixing approaches to be used to determine the refractive index + !! for the particle as a whole. If the refractive index for water is needed, + !! it is specific the the CARMAGAS object for H2O. + subroutine CARMAMODEL_CreateOpticsFile(carma, igroup, opticsType, rc) + + implicit none + + type(carma_type), intent(inout) :: carma !! the carma object + integer, intent(in) :: igroup !! group identifier + integer, intent(in) :: opticsType !! optics type (see I_OPTICS_... in carma_enums.F90) + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Local variables + logical :: do_mie + integer :: cnsttype ! constituent type + + ! Assume success. + rc = 0 + + ! What type of calculation is needed for this group? + ! + ! NOTE: Some of these calculations generate optical properties as single mass + ! coefficients, while others are lookup tables designed around multiple + ! dimensions. + select case (opticsType) + + case default + call endrun('carma_CreateOpticsFile:: Unknown optics type.') + end select + + return + end subroutine CARMAMODEL_CreateOpticsFile !! Called after wet deposition has been performed. Allows the specific model to add !! wet deposition of CARMA aerosols to the aerosols being communicated to the surface. !! !! @version July-2011 !! @author Chuck Bardeen - subroutine CARMA_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) + subroutine CARMAMODEL_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) use camsrfexch, only: cam_out_t implicit none @@ -817,6 +869,121 @@ subroutine CARMA_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) end if return - end subroutine CARMA_WetDeposition + end subroutine CARMAMODEL_WetDeposition + + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_CalculateCloudborneDiagnostics(carma, state, pbuf, aerclddiag, rc) + + type(carma_type), intent(in) :: carma !! the carma object + type(physics_state), intent(in) :: state !! Physics state variables - before pname + type(physics_buffer_desc), pointer, intent(in) :: pbuf(:) !! physics buffer + real(r8), intent(out) :: aerclddiag(pcols,MAXCLDAERDIAG) !! the total cloudborne aerosols, supports up to MAXCLDAERDIAG different values + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_CalculateCloudborneDiagnostics + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_OutputBudgetDiagnostics(carma, icnst4elem, icnst4gas, state, ptend, old_cflux, cflux, dt, pname, rc) + use cam_history, only: outfld + use constituents, only: pcnst, cnst_get_ind + + type(carma_type), intent(in) :: carma !! the carma object + integer, intent(in) :: icnst4elem(NELEM, NBIN) !! constituent index for a carma element + integer, intent(in) :: icnst4gas(NGAS) !! constituent index for a carma gas + type(physics_state), intent(in) :: state !! Physics state variables - before pname + type(physics_ptend), intent(in) :: ptend !! indivdual parameterization tendencies + real(r8) :: old_cflux(pcols,pcnst) !! cam_in%clfux from before the timestep_tend + real(r8) :: cflux(pcols,pcnst) !! cam_in%clfux from after the timestep_tend + real(r8), intent(in) :: dt !! timestep (s) + character(*), intent(in) :: pname !! short name of the physics package + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_OutputBudgetDiagnostics + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_OutputCloudborneDiagnostics(carma, state, pbuf, dt, pname, oldaerclddiag, rc) + use cam_history, only: outfld + + type(carma_type), intent(in) :: carma !! the carma object + type(physics_state), intent(in) :: state !! Physics state variables - before CARMA + type(physics_buffer_desc), pointer, intent(in) :: pbuf(:) !! physics buffer + real(r8), intent(in) :: dt !! timestep (s) + character(*), intent(in) :: pname !! short name of the physics package + real(r8), intent(in ) :: oldaerclddiag(pcols,MAXCLDAERDIAG) !! the before timestep cloudborne aerosol diags + integer, intent(out) :: rc !! return code, negative indicates failure + + real(r8) :: aerclddiag(pcols,MAXCLDAERDIAG) !! the after timestep cloudborne aerosol diags + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_OutputCloudborneDiagnostics + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_OutputDiagnostics(carma, icnst4elem, state, ptend, pbuf, cam_in, rc) + use cam_history, only: outfld + use constituents, only: cnst_get_ind + use camsrfexch, only: cam_in_t + + type(carma_type), intent(in) :: carma !! the carma object + integer, intent(in) :: icnst4elem(NELEM, NBIN) !! constituent index for a carma element + type(physics_state), intent(in) :: state !! Physics state variables - before CARMA + type(physics_ptend), intent(in) :: ptend !! indivdual parameterization tendencies + type(physics_buffer_desc), pointer, intent(in) :: pbuf(:) !! physics buffer + type(cam_in_t), intent(in) :: cam_in !! surface inputs + integer, intent(out) :: rc !! return code, negative indicates failure + + integer :: icol !! column index + integer :: ibin !! bin index + real(r8), pointer, dimension(:,:) :: soacm !! aerosol tendency due to gas-aerosol exchange kg/kg/s + real(r8), pointer, dimension(:,:) :: soapt !! aerosol tendency due to no2 photolysis kg/kg/s + character(len=16) :: binname !! names bins + real(r8) :: aerclddiag(pcols,MAXCLDAERDIAG) !! the before timestep cloudborne aerosol diags + integer :: i + integer :: icnst !! constituent index + integer :: ienconc !! concentration element index + integer :: ncore !! number of cores + integer :: icorelem(NELEM) !! core element index + real(r8) :: mair(pver) !! Mass of air column (kg/m2) + real(r8) :: pureso4(pcols) !! pure sulfate (kg/m2) + real(r8) :: mixso4(pcols) !! mix sulfate (kg/m2) + real(r8) :: cprflux(pcols) !! Surface Flux pure sulfate (kg/m2/s) + real(r8) :: cmxflux(pcols) !! Surface Flux mix sulfate (kg/m2/s) + real(r8) :: h2so4(pcols) !! H2SO4 gas (kg/m2) + real(r8) :: so2(pcols) !! SO2 gas (kg/m2) + real(r8) :: bdbc(pcols) !! Burden BC sulfate (kg/m2) + real(r8) :: bddust(pcols) !! Burden dust (kg/m2) + real(r8) :: bdoc(pcols) !! Burden OC sulfate (kg/m2) + real(r8) :: bdsalt(pcols) !! Burden SALT sulfate (kg/m2) + real(r8) :: bdsoa(pcols) !! Burden SOA sulfate (kg/m2) + character(len=16) :: shortname + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_OutputDiagnostics -end module +end module carma_model_mod diff --git a/src/physics/carma/models/meteor_smoke/carma_model_mod.F90 b/src/physics/carma/models/meteor_smoke/carma_model_mod.F90 index 0b6d83aba1..4ec2910f44 100644 --- a/src/physics/carma/models/meteor_smoke/carma_model_mod.F90 +++ b/src/physics/carma/models/meteor_smoke/carma_model_mod.F90 @@ -42,14 +42,19 @@ module carma_model_mod private ! Declare the public methods. - public CARMA_DefineModel - public CARMA_Detrain - public CARMA_DiagnoseBins - public CARMA_DiagnoseBulk - public CARMA_EmitParticle - public CARMA_InitializeModel - public CARMA_InitializeParticle - public CARMA_WetDeposition + public CARMAMODEL_CalculateCloudborneDiagnostics + public CARMAMODEL_CreateOpticsFile + public CARMAMODEL_DefineModel + public CARMAMODEL_Detrain + public CARMAMODEL_DiagnoseBins + public CARMAMODEL_DiagnoseBulk + public CARMAMODEL_EmitParticle + public CARMAMODEL_InitializeModel + public CARMAMODEL_InitializeParticle + public CARMAMODEL_OutputBudgetDiagnostics + public CARMAMODEL_OutputCloudborneDiagnostics + public CARMAMODEL_OutputDiagnostics + public CARMAMODEL_WetDeposition ! Declare public constants integer, public, parameter :: NGROUP = 1 !! Number of particle groups @@ -62,6 +67,10 @@ module carma_model_mod integer, public, parameter :: NMIE_RH = 8 !! Number of relative humidities for mie calculations real(kind=f), public :: mie_rh(NMIE_RH) + integer, public, parameter :: NMIE_WTP = 0 !! Number of weight percents for mie calculations + real(kind=f), public :: mie_wtp(NMIE_WTP) + integer, public, parameter :: NREFIDX = 1 !! Number of refractive indices per element + ! Defines whether the groups should undergo deep convection in phase 1 or phase 2. ! Water vapor and cloud particles are convected in phase 1, while all other constituents ! are done in phase 2. @@ -102,7 +111,7 @@ module carma_model_mod !! !! @version May-2009 !! @author Chuck Bardeen - subroutine CARMA_DefineModel(carma, rc) + subroutine CARMAMODEL_DefineModel(carma, rc) type(carma_type), intent(inout) :: carma !! the carma object integer, intent(out) :: rc !! return code, negative indicates failure @@ -120,7 +129,7 @@ subroutine CARMA_DefineModel(carma, rc) ! Report model specific namelist configuration parameters. if (masterproc) then call CARMA_Get(carma, rc, do_print=do_print, LUNOPRT=LUNOPRT) - if (rc < 0) call endrun("CARMA_InitializeModel: CARMA_Get failed.") + if (rc < 0) call endrun("CARMAMODEL_DefineModel: CARMA_Get failed.") if (do_print) write(LUNOPRT,*) '' if (do_print) write(LUNOPRT,*) 'CARMA ', trim(carma_model), ' specific settings :' @@ -139,7 +148,7 @@ subroutine CARMA_DefineModel(carma, rc) call CARMAGROUP_Create(carma, I_GRP_DUST, "meteor smoke", rmin, vmrat, I_SPHERE, 1._f, .false., & rc, do_wetdep=.true., do_drydep=.true., solfac=0.3_f, & scavcoef=0.1_f, shortname="DUST") - if (rc < 0) call endrun('CARMA_DefineModel::CARMA_AddGroup failed.') + if (rc < 0) call endrun('CARMAMODEL_DefineModel::CARMA_AddGroup failed.') ! Define the Elements @@ -148,7 +157,7 @@ subroutine CARMA_DefineModel(carma, rc) ! should be 6 characters or less and without spaces. call CARMAELEMENT_Create(carma, I_ELEM_DUST, I_GRP_DUST, "meteor smoke", RHO_METEOR_SMOKE, & I_INVOLATILE, I_METEOR_SMOKE, rc, shortname="DUST") - if (rc < 0) call endrun('CARMA_DefineModel::CARMA_AddElement failed.') + if (rc < 0) call endrun('CARMAMODEL_DefineModel::CARMA_AddElement failed.') ! Define the Solutes @@ -159,10 +168,10 @@ subroutine CARMA_DefineModel(carma, rc) ! Define the Processes call CARMA_AddCoagulation(carma, I_GRP_DUST, I_GRP_DUST, I_GRP_DUST, I_COLLEC_DATA, rc) - if (rc < 0) call endrun('CARMA_DefineModel::CARMA_AddCoagulation failed.') + if (rc < 0) call endrun('CARMAMODEL_DefineModel::CARMA_AddCoagulation failed.') return - end subroutine CARMA_DefineModel + end subroutine CARMAMODEL_DefineModel !! Defines all the CARMA components (groups, elements, solutes and gases) and process @@ -172,7 +181,7 @@ end subroutine CARMA_DefineModel !! @author Chuck Bardeen !! !! @see CARMASTATE_SetDetrain - subroutine CARMA_Detrain(carma, cstate, cam_in, dlf, state, icol, dt, rc, rliq, prec_str, snow_str, & + subroutine CARMAMODEL_Detrain(carma, cstate, cam_in, dlf, state, icol, dt, rc, rliq, prec_str, snow_str, & tnd_qsnow, tnd_nsnow) use camsrfexch, only: cam_in_t use physconst, only: latice, latvap, cpair @@ -197,14 +206,14 @@ subroutine CARMA_Detrain(carma, cstate, cam_in, dlf, state, icol, dt, rc, rliq, rc = RC_OK return - end subroutine CARMA_Detrain + end subroutine CARMAMODEL_Detrain !! For diagnostic groups, sets up up the CARMA bins based upon the CAM state. !! !! @version July-2009 !! @author Chuck Bardeen - subroutine CARMA_DiagnoseBins(carma, cstate, state, pbuf, icol, dt, rc, rliq, prec_str, snow_str) + subroutine CARMAMODEL_DiagnoseBins(carma, cstate, state, pbuf, icol, dt, rc, rliq, prec_str, snow_str) use time_manager, only: is_first_step implicit none @@ -230,14 +239,14 @@ subroutine CARMA_DiagnoseBins(carma, cstate, state, pbuf, icol, dt, rc, rliq, pr ! code to determine the mass in each bin from the CAM state. return - end subroutine CARMA_DiagnoseBins + end subroutine CARMAMODEL_DiagnoseBins !! For diagnostic groups, determines the tendencies on the CAM state from the CARMA bins. !! !! @version July-2009 !! @author Chuck Bardeen - subroutine CARMA_DiagnoseBulk(carma, cstate, cam_out, state, pbuf, ptend, icol, dt, rc, rliq, prec_str, snow_str, & + subroutine CARMAMODEL_DiagnoseBulk(carma, cstate, cam_out, state, pbuf, ptend, icol, dt, rc, rliq, prec_str, snow_str, & prec_sed, snow_sed, tnd_qsnow, tnd_nsnow, re_ice) use camsrfexch, only: cam_out_t @@ -268,7 +277,7 @@ subroutine CARMA_DiagnoseBulk(carma, cstate, cam_out, state, pbuf, ptend, icol, ! code to determine the bulk mass from the CARMA state. return - end subroutine CARMA_DiagnoseBulk + end subroutine CARMAMODEL_DiagnoseBulk !! Calculates the emissions for CARMA aerosol particles. By default, there is no @@ -277,7 +286,7 @@ end subroutine CARMA_DiagnoseBulk !! !! @author Chuck Bardeen !! @version Jan-2011 - subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tendency, surfaceFlux, rc) + subroutine CARMAMODEL_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tendency, surfaceFlux, pbuf, rc) use shr_kind_mod, only: r8 => shr_kind_r8 use ppgrid, only: pcols, pver use physics_types, only: physics_state @@ -296,6 +305,7 @@ subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tend type(cam_in_t), intent(in) :: cam_in !! surface inputs real(r8), intent(out) :: tendency(pcols, pver) !! constituent tendency (kg/kg/s) real(r8), intent(out) :: surfaceFlux(pcols) !! constituent surface flux (kg/m^2/s) + type(physics_buffer_desc), pointer :: pbuf(:) !! physics buffer integer, intent(out) :: rc !! return code, negative indicates failure integer :: ilat ! latitude index @@ -435,7 +445,7 @@ subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tend end if end do - if (abs((state%lat(icol) / DEG2RAD) - 90.0) <= 0.00001_r8) then + if (abs((state%lat(icol) / DEG2RAD) - 90.0_r8) <= 0.00001_r8) then rfScale(icol) = carma_escale_grf(carma_escale_nLats, doy) end if @@ -481,7 +491,7 @@ subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tend end if return - end subroutine CARMA_EmitParticle + end subroutine CARMAMODEL_EmitParticle !! Allows the model to perform its own initialization in addition to what is done @@ -489,7 +499,7 @@ end subroutine CARMA_EmitParticle !! !! @author Chuck Bardeen !! @version May-2009 - subroutine CARMA_InitializeModel(carma, lq_carma, rc) + subroutine CARMAMODEL_InitializeModel(carma, lq_carma, pbuf2d, rc) use ioFileMod, only: getfil use constituents, only: pcnst use wrap_nf @@ -499,6 +509,7 @@ subroutine CARMA_InitializeModel(carma, lq_carma, rc) type(carma_type), intent(in) :: carma !! the carma object logical, intent(inout) :: lq_carma(pcnst) !! flags to indicate whether the constituent !! could have a CARMA tendency + type(physics_buffer_desc), pointer :: pbuf2d(:,:) integer, intent(out) :: rc !! return code, negative indicates failure integer :: ilev ! level index @@ -524,7 +535,7 @@ subroutine CARMA_InitializeModel(carma, lq_carma, rc) ! Add initialization here. call CARMA_Get(carma, rc, do_print=do_print, LUNOPRT=LUNOPRT) - if (rc < 0) call endrun("CARMA_InitializeModel: CARMA_Get failed.") + if (rc < 0) call endrun("CARMAMODEL_InitializeModel: CARMA_Get failed.") ! Initialize the emissions rate table. if (carma_do_emission) then @@ -565,7 +576,7 @@ subroutine CARMA_InitializeModel(carma, lq_carma, rc) carma_emis_ilev_max = carma_emis_nLevs do ilev = 1, carma_emis_nLevs - if (carma_emis_rate(ilev) <= 0.0) then + if (carma_emis_rate(ilev) <= 0.0_r8) then carma_emis_ilev_min = ilev + 1 else exit @@ -573,7 +584,7 @@ subroutine CARMA_InitializeModel(carma, lq_carma, rc) end do do ilev = carma_emis_nLevs, 1, -1 - if (carma_emis_rate(ilev) <= 0.0) then + if (carma_emis_rate(ilev) <= 0.0_r8) then carma_emis_ilev_max = ilev - 1 else exit @@ -642,7 +653,7 @@ subroutine CARMA_InitializeModel(carma, lq_carma, rc) ! There should be one time for each day of the year, so ! quit if it isn't correct. if (carma_escale_nTimes .ne. 365) then - call endrun("CARMA_InitializeModel: Emission scaling file should have entries for 365 days, but doesn't.") + call endrun("CARMAMODEL_InitializeModel: Emission scaling file should have entries for 365 days, but doesn't.") endif call wrap_inq_dimid(fid, "ltime", ltime_did) @@ -665,7 +676,7 @@ subroutine CARMA_InitializeModel(carma, lq_carma, rc) call wrap_inq_varid(fid, 'SGRF', grf_vid) tmp = nf90_get_var (fid, grf_vid, carma_escale_grf) if (tmp/=NF90_NOERR) then - write(iulog,*) 'CARMA_InitializeModel: error reading varid =', grf_vid + write(iulog,*) 'CARMAMODEL_InitializeModel: error reading varid =', grf_vid call handle_error (tmp) end if @@ -701,7 +712,7 @@ subroutine CARMA_InitializeModel(carma, lq_carma, rc) endif return - end subroutine CARMA_InitializeModel + end subroutine CARMAMODEL_InitializeModel !! Sets the initial condition for CARMA aerosol particles. By default, there are no @@ -713,8 +724,9 @@ end subroutine CARMA_InitializeModel !! !! @author Chuck Bardeen !! @version May-2009 - subroutine CARMA_InitializeParticle(carma, ielem, ibin, latvals, lonvals, mask, q, rc) + subroutine CARMAMODEL_InitializeParticle(carma, ielem, ibin, latvals, lonvals, mask, q, rc) use shr_kind_mod, only: r8 => shr_kind_r8 + use pmgrid, only: plat, plev, plon implicit none @@ -735,15 +747,55 @@ subroutine CARMA_InitializeParticle(carma, ielem, ibin, latvals, lonvals, mask, ! NOTE: Initialized to 0. by the caller, so nothing needs to be done. return - end subroutine CARMA_InitializeParticle + end subroutine CARMAMODEL_InitializeParticle + + !! This routine is an extension of CARMA_CreateOpticsFile() that allows for + !! model specific tables to be created in addition to the model independent + !! methods that are in carma_intr.F90. + !! + !! The opticsType that is specified for the group determines how the optical + !! properties will be generated for that group. Each group can use a different + !! optics method if needed. Refractive indices need for these calculation are + !! are specified in the group's elements rather than at the group level. This + !! allows various mixing approaches to be used to determine the refractive index + !! for the particle as a whole. If the refractive index for water is needed, + !! it is specific the the CARMAGAS object for H2O. + subroutine CARMAMODEL_CreateOpticsFile(carma, igroup, opticsType, rc) + + implicit none + + type(carma_type), intent(inout) :: carma !! the carma object + integer, intent(in) :: igroup !! group identifier + integer, intent(in) :: opticsType !! optics type (see I_OPTICS_... in carma_enums.F90) + integer, intent(out) :: rc !! return code, negative indicates failure + ! Local variables + logical :: do_mie + integer :: cnsttype ! constituent type + + ! Assume success. + rc = 0 + + ! What type of calculation is needed for this group? + ! + ! NOTE: Some of these calculations generate optical properties as single mass + ! coefficients, while others are lookup tables designed around multiple + ! dimensions. + select case (opticsType) + + case default + call endrun('carma_CreateOpticsFile:: Unknown optics type.') + end select + + return + end subroutine CARMAMODEL_CreateOpticsFile !! Called after wet deposition has been performed. Allows the specific model to add !! wet deposition of CARMA aerosols to the aerosols being communicated to the surface. !! !! @version July-2011 !! @author Chuck Bardeen - subroutine CARMA_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) + subroutine CARMAMODEL_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) use camsrfexch, only: cam_out_t implicit none @@ -762,6 +814,121 @@ subroutine CARMA_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) rc = RC_OK return - end subroutine CARMA_WetDeposition + end subroutine CARMAMODEL_WetDeposition + + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_CalculateCloudborneDiagnostics(carma, state, pbuf, aerclddiag, rc) + + type(carma_type), intent(in) :: carma !! the carma object + type(physics_state), intent(in) :: state !! Physics state variables - before pname + type(physics_buffer_desc), pointer, intent(in) :: pbuf(:) !! physics buffer + real(r8), intent(out) :: aerclddiag(pcols,MAXCLDAERDIAG) !! the total cloudborne aerosols, supports up to MAXCLDAERDIAG different values + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_CalculateCloudborneDiagnostics + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_OutputBudgetDiagnostics(carma, icnst4elem, icnst4gas, state, ptend, old_cflux, cflux, dt, pname, rc) + use cam_history, only: outfld + use constituents, only: pcnst, cnst_get_ind + + type(carma_type), intent(in) :: carma !! the carma object + integer, intent(in) :: icnst4elem(NELEM, NBIN) !! constituent index for a carma element + integer, intent(in) :: icnst4gas(NGAS) !! constituent index for a carma gas + type(physics_state), intent(in) :: state !! Physics state variables - before pname + type(physics_ptend), intent(in) :: ptend !! indivdual parameterization tendencies + real(r8) :: old_cflux(pcols,pcnst) !! cam_in%clfux from before the timestep_tend + real(r8) :: cflux(pcols,pcnst) !! cam_in%clfux from after the timestep_tend + real(r8), intent(in) :: dt !! timestep (s) + character(*), intent(in) :: pname !! short name of the physics package + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_OutputBudgetDiagnostics + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_OutputCloudborneDiagnostics(carma, state, pbuf, dt, pname, oldaerclddiag, rc) + use cam_history, only: outfld + + type(carma_type), intent(in) :: carma !! the carma object + type(physics_state), intent(in) :: state !! Physics state variables - before CARMA + type(physics_buffer_desc), pointer, intent(in) :: pbuf(:) !! physics buffer + real(r8), intent(in) :: dt !! timestep (s) + character(*), intent(in) :: pname !! short name of the physics package + real(r8), intent(in ) :: oldaerclddiag(pcols,MAXCLDAERDIAG) !! the before timestep cloudborne aerosol diags + integer, intent(out) :: rc !! return code, negative indicates failure + + real(r8) :: aerclddiag(pcols,MAXCLDAERDIAG) !! the after timestep cloudborne aerosol diags + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_OutputCloudborneDiagnostics + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_OutputDiagnostics(carma, icnst4elem, state, ptend, pbuf, cam_in, rc) + use cam_history, only: outfld + use constituents, only: cnst_get_ind + use camsrfexch, only: cam_in_t + + type(carma_type), intent(in) :: carma !! the carma object + integer, intent(in) :: icnst4elem(NELEM, NBIN) !! constituent index for a carma element + type(physics_state), intent(in) :: state !! Physics state variables - before CARMA + type(physics_ptend), intent(in) :: ptend !! indivdual parameterization tendencies + type(physics_buffer_desc), pointer, intent(in) :: pbuf(:) !! physics buffer + type(cam_in_t), intent(in) :: cam_in !! surface inputs + integer, intent(out) :: rc !! return code, negative indicates failure + + integer :: icol !! column index + integer :: ibin !! bin index + real(r8), pointer, dimension(:,:) :: soacm !! aerosol tendency due to gas-aerosol exchange kg/kg/s + real(r8), pointer, dimension(:,:) :: soapt !! aerosol tendency due to no2 photolysis kg/kg/s + character(len=16) :: binname !! names bins + real(r8) :: aerclddiag(pcols,MAXCLDAERDIAG) !! the before timestep cloudborne aerosol diags + integer :: i + integer :: icnst !! constituent index + integer :: ienconc !! concentration element index + integer :: ncore !! number of cores + integer :: icorelem(NELEM) !! core element index + real(r8) :: mair(pver) !! Mass of air column (kg/m2) + real(r8) :: pureso4(pcols) !! pure sulfate (kg/m2) + real(r8) :: mixso4(pcols) !! mix sulfate (kg/m2) + real(r8) :: cprflux(pcols) !! Surface Flux pure sulfate (kg/m2/s) + real(r8) :: cmxflux(pcols) !! Surface Flux mix sulfate (kg/m2/s) + real(r8) :: h2so4(pcols) !! H2SO4 gas (kg/m2) + real(r8) :: so2(pcols) !! SO2 gas (kg/m2) + real(r8) :: bdbc(pcols) !! Burden BC sulfate (kg/m2) + real(r8) :: bddust(pcols) !! Burden dust (kg/m2) + real(r8) :: bdoc(pcols) !! Burden OC sulfate (kg/m2) + real(r8) :: bdsalt(pcols) !! Burden SALT sulfate (kg/m2) + real(r8) :: bdsoa(pcols) !! Burden SOA sulfate (kg/m2) + character(len=16) :: shortname + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_OutputDiagnostics -end module +end module carma_model_mod diff --git a/src/physics/carma/models/mixed_sulfate/carma_model_mod.F90 b/src/physics/carma/models/mixed_sulfate/carma_model_mod.F90 index 36ee1be358..5f21fbf4d9 100644 --- a/src/physics/carma/models/mixed_sulfate/carma_model_mod.F90 +++ b/src/physics/carma/models/mixed_sulfate/carma_model_mod.F90 @@ -50,14 +50,19 @@ module carma_model_mod private ! Declare the public methods. - public CARMA_DefineModel - public CARMA_Detrain - public CARMA_DiagnoseBins - public CARMA_DiagnoseBulk - public CARMA_EmitParticle - public CARMA_InitializeModel - public CARMA_InitializeParticle - public CARMA_WetDeposition + public CARMAMODEL_CalculateCloudborneDiagnostics + public CARMAMODEL_CreateOpticsFile + public CARMAMODEL_DefineModel + public CARMAMODEL_Detrain + public CARMAMODEL_DiagnoseBins + public CARMAMODEL_DiagnoseBulk + public CARMAMODEL_EmitParticle + public CARMAMODEL_InitializeModel + public CARMAMODEL_InitializeParticle + public CARMAMODEL_OutputBudgetDiagnostics + public CARMAMODEL_OutputCloudborneDiagnostics + public CARMAMODEL_OutputDiagnostics + public CARMAMODEL_WetDeposition ! Declare public constants integer, public, parameter :: NGROUP = 2 !! Number of particle groups @@ -70,6 +75,10 @@ module carma_model_mod integer, public, parameter :: NMIE_RH = 8 !! Number of relative humidities for mie calculations real(kind=f), public :: mie_rh(NMIE_RH) + integer, public, parameter :: NMIE_WTP = 0 !! Number of weight percents for mie calculations + real(kind=f), public :: mie_wtp(NMIE_WTP) + integer, public, parameter :: NREFIDX = 1 !! Number of refractive indices per element + ! Defines whether the groups should undergo deep convection in phase 1 or phase 2. ! Water vapor and cloud particles are convected in phase 1, while all other constituents ! are done in phase 2. @@ -121,7 +130,7 @@ module carma_model_mod !! !! @version May-2009 !! @author Chuck Bardeen - subroutine CARMA_DefineModel(carma, rc) + subroutine CARMAMODEL_DefineModel(carma, rc) use ioFileMod, only: getfil use wrap_nf @@ -144,7 +153,7 @@ subroutine CARMA_DefineModel(carma, rc) rc = RC_OK call CARMA_Get(carma, rc, do_print=do_print, LUNOPRT=LUNOPRT) - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMA_Get failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMA_Get failed.') ! Report model specific configuration parameters. if (masterproc) then @@ -167,7 +176,7 @@ subroutine CARMA_DefineModel(carma, rc) call CARMAGROUP_Create(carma, I_GRP_DUST, "meteor smoke", rmin, 2.0_f, I_SPHERE, 1._f, .false., & rc, do_wetdep=.true., do_drydep=.true., solfac=0.3_f, & scavcoef=0.1_f, shortname="DUST") - if (rc < 0) call endrun('CARMA_DefineModel::CARMA_AddGroup failed.') + if (rc < 0) call endrun('CARMAMODEL_DefineModel::CARMA_AddGroup failed.') ! NOTE: For CAM, the optional do_wetdep and do_drydep flags should be @@ -180,7 +189,7 @@ subroutine CARMA_DefineModel(carma, rc) call CARMAGROUP_Create(carma, I_GRP_SULFATE, "sulfate", rmin_sulfate, vmrat_sulfate, I_SPHERE, 1._f, .false., & rc, irhswell=I_WTPCT_H2SO4, do_wetdep=.true., do_drydep=.true., solfac=1.0_f, & scavcoef=0.1_f, is_sulfate=.true., shortname="SULF") - if (rc < 0) call endrun('CARMA_DefineModel::CARMA_AddGroup failed.') + if (rc < 0) call endrun('CARMAMODEL_DefineModel::CARMA_AddGroup failed.') ! Define the Elements @@ -189,15 +198,15 @@ subroutine CARMA_DefineModel(carma, rc) ! should be 6 characters or less and without spaces. call CARMAELEMENT_Create(carma, I_ELEM_DUST, I_GRP_DUST, "meteor smoke", RHO_METEOR_SMOKE, & I_INVOLATILE, I_METEOR_SMOKE, rc, shortname="DUST") - if (rc < 0) call endrun('CARMA_DefineModel::CARMA_AddElement failed.') + if (rc < 0) call endrun('CARMAMODEL_DefineModel::CARMA_AddElement failed.') call CARMAELEMENT_Create(carma, I_ELEM_SULFATE, I_GRP_SULFATE, "sulfate", RHO_SULFATE, & I_VOLATILE, I_H2SO4, rc, shortname="SULF") - if (rc < 0) call endrun('CARMA_DefineModel::CARMA_AddElement failed.') + if (rc < 0) call endrun('CARMAMODEL_DefineModel::CARMA_AddElement failed.') call CARMAELEMENT_Create(carma, I_ELEM_SULCORE, I_GRP_SULFATE, "sulfate core", RHO_METEOR_SMOKE, & I_COREMASS, I_METEOR_SMOKE, rc, shortname="SFCORE") - if (rc < 0) call endrun('CARMA_DefineModel::CARMA_AddElement failed.') + if (rc < 0) call endrun('CARMAMODEL_DefineModel::CARMA_AddElement failed.') ! Define the Solutes ! @@ -208,40 +217,40 @@ subroutine CARMA_DefineModel(carma, rc) call CARMAGAS_Create(carma, I_GAS_H2O, "Water Vapor", WTMOL_H2O, & I_VAPRTN_H2O_MURPHY2005, I_GCOMP_H2O, rc, shortname="Q", & ds_threshold=0.2_f) - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMAGAS_Create failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMAGAS_Create failed.') call CARMAGAS_Create(carma, I_GAS_H2SO4, "Sulfuric Acid", WTMOL_H2SO4, & I_VAPRTN_H2SO4_AYERS1980, I_GCOMP_H2SO4, rc, shortname = "H2SO4", & ds_threshold=-0.2_f) - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMAGAS_Create failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMAGAS_Create failed.') ! Define the Processes call CARMA_AddCoagulation(carma, I_GRP_DUST, I_GRP_DUST, I_GRP_DUST, I_COLLEC_DATA, rc) - if (rc < 0) call endrun('CARMA_DefineModel::CARMA_AddCoagulation failed.') + if (rc < 0) call endrun('CARMAMODEL_DefineModel::CARMA_AddCoagulation failed.') ! Set H2SO4 to be the condensing gas, water vapor is assumed to be in equilibrium ! and will be used to define the wet particle radius. call CARMA_AddGrowth(carma, I_ELEM_SULFATE, I_GAS_H2SO4, rc) - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMA_AddGrowth failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMA_AddGrowth failed.') call CARMA_AddNucleation(carma, I_ELEM_SULFATE, I_ELEM_SULFATE, I_HOMNUC, 0._f, rc, igas=I_GAS_H2SO4) - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMA_AddNucleation failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMA_AddNucleation failed.') ! Also need nucleation with meteor smoke. call CARMA_AddNucleation(carma, I_ELEM_DUST, I_ELEM_SULCORE, I_HETNUCSULF, 0._f, rc, igas=I_GAS_H2SO4, ievp2elem=I_ELEM_DUST) - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMA_AddNucleation failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMA_AddNucleation failed.') call CARMA_AddCoagulation(carma, I_GRP_SULFATE, I_GRP_SULFATE, I_GRP_SULFATE, I_COLLEC_FUCHS, rc) - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMA_AddCoagulation failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMA_AddCoagulation failed.') ! Dust-Sulfate Coagulation? call CARMA_AddCoagulation(carma, I_GRP_DUST, I_GRP_SULFATE, I_GRP_SULFATE, I_COLLEC_FUCHS, rc) - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMA_AddCoagulation failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMA_AddCoagulation failed.') return - end subroutine CARMA_DefineModel + end subroutine CARMAMODEL_DefineModel !! Defines all the CARMA components (groups, elements, solutes and gases) and process @@ -251,7 +260,7 @@ end subroutine CARMA_DefineModel !! @author Chuck Bardeen !! !! @see CARMASTATE_SetDetrain - subroutine CARMA_Detrain(carma, cstate, cam_in, dlf, state, icol, dt, rc, rliq, prec_str, snow_str, & + subroutine CARMAMODEL_Detrain(carma, cstate, cam_in, dlf, state, icol, dt, rc, rliq, prec_str, snow_str, & tnd_qsnow, tnd_nsnow) use camsrfexch, only: cam_in_t use physconst, only: latice, latvap, cpair @@ -276,14 +285,14 @@ subroutine CARMA_Detrain(carma, cstate, cam_in, dlf, state, icol, dt, rc, rliq, rc = RC_OK return - end subroutine CARMA_Detrain + end subroutine CARMAMODEL_Detrain !! For diagnostic groups, sets up up the CARMA bins based upon the CAM state. !! !! @version July-2009 !! @author Chuck Bardeen - subroutine CARMA_DiagnoseBins(carma, cstate, state, pbuf, icol, dt, rc, rliq, prec_str, snow_str) + subroutine CARMAMODEL_DiagnoseBins(carma, cstate, state, pbuf, icol, dt, rc, rliq, prec_str, snow_str) use time_manager, only: is_first_step implicit none @@ -309,14 +318,14 @@ subroutine CARMA_DiagnoseBins(carma, cstate, state, pbuf, icol, dt, rc, rliq, pr ! code to determine the mass in each bin from the CAM state. return - end subroutine CARMA_DiagnoseBins + end subroutine CARMAMODEL_DiagnoseBins !! For diagnostic groups, determines the tendencies on the CAM state from the CARMA bins. !! !! @version July-2009 !! @author Chuck Bardeen - subroutine CARMA_DiagnoseBulk(carma, cstate, cam_out, state, pbuf, ptend, icol, dt, rc, rliq, prec_str, snow_str, & + subroutine CARMAMODEL_DiagnoseBulk(carma, cstate, cam_out, state, pbuf, ptend, icol, dt, rc, rliq, prec_str, snow_str, & prec_sed, snow_sed, tnd_qsnow, tnd_nsnow, re_ice) use camsrfexch, only: cam_out_t @@ -347,10 +356,10 @@ subroutine CARMA_DiagnoseBulk(carma, cstate, cam_out, state, pbuf, ptend, icol, ! code to determine the bulk mass from the CARMA state. return - end subroutine CARMA_DiagnoseBulk + end subroutine CARMAMODEL_DiagnoseBulk - subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tendency, surfaceFlux, rc) + subroutine CARMAMODEL_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tendency, surfaceFlux, pbuf, rc) use shr_kind_mod, only: r8 => shr_kind_r8 use ppgrid, only: pcols, pver use physics_types, only: physics_state @@ -369,6 +378,7 @@ subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tend type(cam_in_t), intent(in) :: cam_in !! surface inputs real(r8), intent(out) :: tendency(pcols, pver) !! constituent tendency (kg/kg/s) real(r8), intent(out) :: surfaceFlux(pcols) !! constituent surface flux (kg/m^2/s) + type(physics_buffer_desc), pointer :: pbuf(:) !! physics buffer integer, intent(out) :: rc !! return code, negative indicates failure integer :: ilat ! latitude index @@ -508,7 +518,7 @@ subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tend end if end do - if (abs((state%lat(icol) / DEG2RAD) - 90.0) <= 0.00001_r8) then + if (abs((state%lat(icol) / DEG2RAD) - 90.0_r8) <= 0.00001_r8) then rfScale(icol) = carma_escale_grf(carma_escale_nLats, doy) end if @@ -560,7 +570,7 @@ subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tend end if return - end subroutine CARMA_EmitParticle + end subroutine CARMAMODEL_EmitParticle !! Allows the model to perform its own initialization in addition to what is done @@ -568,7 +578,7 @@ end subroutine CARMA_EmitParticle !! !! @author Chuck Bardeen !! @version May-2009 - subroutine CARMA_InitializeModel(carma, lq_carma, rc) + subroutine CARMAMODEL_InitializeModel(carma, lq_carma, pbuf2d, rc) use constituents, only: pcnst use ioFileMod, only: getfil use wrap_nf @@ -578,6 +588,7 @@ subroutine CARMA_InitializeModel(carma, lq_carma, rc) type(carma_type), intent(in) :: carma !! the carma object logical, intent(inout) :: lq_carma(pcnst) !! flags to indicate whether the constituent !! could have a CARMA tendency + type(physics_buffer_desc), pointer :: pbuf2d(:,:) integer, intent(out) :: rc !! return code, negative indicates failure integer :: ilev ! level index @@ -603,7 +614,7 @@ subroutine CARMA_InitializeModel(carma, lq_carma, rc) ! Add initialization here. call CARMA_Get(carma, rc, do_print=do_print, LUNOPRT=LUNOPRT) - if (rc < 0) call endrun("CARMA_InitializeModel: CARMA_Get failed.") + if (rc < 0) call endrun("CARMAMODEL_InitializeModel: CARMA_Get failed.") ! Initialize the emissions rate table. if (carma_do_emission) then @@ -644,7 +655,7 @@ subroutine CARMA_InitializeModel(carma, lq_carma, rc) carma_emis_ilev_max = carma_emis_nLevs do ilev = 1, carma_emis_nLevs - if (carma_emis_rate(ilev) <= 0.0) then + if (carma_emis_rate(ilev) <= 0.0_r8) then carma_emis_ilev_min = ilev + 1 else exit @@ -652,7 +663,7 @@ subroutine CARMA_InitializeModel(carma, lq_carma, rc) end do do ilev = carma_emis_nLevs, 1, -1 - if (carma_emis_rate(ilev) <= 0.0) then + if (carma_emis_rate(ilev) <= 0.0_r8) then carma_emis_ilev_max = ilev - 1 else exit @@ -721,7 +732,7 @@ subroutine CARMA_InitializeModel(carma, lq_carma, rc) ! There should be one time for each day of the year, so ! quit if it isn't correct. if (carma_escale_nTimes .ne. 365) then - call endrun("CARMA_InitializeModel: Emission scaling file should have entries for 365 days, but doesn't.") + call endrun("CARMAMODEL_InitializeModel: Emission scaling file should have entries for 365 days, but doesn't.") endif call wrap_inq_dimid(fid, "ltime", ltime_did) @@ -744,7 +755,7 @@ subroutine CARMA_InitializeModel(carma, lq_carma, rc) call wrap_inq_varid(fid, 'SGRF', grf_vid) tmp = nf90_get_var (fid, grf_vid, carma_escale_grf) if (tmp/=NF90_NOERR) then - write(iulog,*) 'CARMA_InitializeModel: error reading varid =', grf_vid + write(iulog,*) 'CARMAMODEL_InitializeModel: error reading varid =', grf_vid call handle_error (tmp) end if @@ -780,7 +791,7 @@ subroutine CARMA_InitializeModel(carma, lq_carma, rc) endif return - end subroutine CARMA_InitializeModel + end subroutine CARMAMODEL_InitializeModel !! Sets the initial condition for CARMA aerosol particles. By default, there are no @@ -792,8 +803,9 @@ end subroutine CARMA_InitializeModel !! !! @author Chuck Bardeen !! @version May-2009 - subroutine CARMA_InitializeParticle(carma, ielem, ibin, latvals, lonvals, mask, q, rc) + subroutine CARMAMODEL_InitializeParticle(carma, ielem, ibin, latvals, lonvals, mask, q, rc) use shr_kind_mod, only: r8 => shr_kind_r8 + use pmgrid, only: plat, plev, plon implicit none @@ -814,15 +826,55 @@ subroutine CARMA_InitializeParticle(carma, ielem, ibin, latvals, lonvals, mask, ! NOTE: Initialized to 0. by the caller, so nothing needs to be done. return - end subroutine CARMA_InitializeParticle + end subroutine CARMAMODEL_InitializeParticle + + !! This routine is an extension of CARMA_CreateOpticsFile() that allows for + !! model specific tables to be created in addition to the model independent + !! methods that are in carma_intr.F90. + !! + !! The opticsType that is specified for the group determines how the optical + !! properties will be generated for that group. Each group can use a different + !! optics method if needed. Refractive indices need for these calculation are + !! are specified in the group's elements rather than at the group level. This + !! allows various mixing approaches to be used to determine the refractive index + !! for the particle as a whole. If the refractive index for water is needed, + !! it is specific the the CARMAGAS object for H2O. + subroutine CARMAMODEL_CreateOpticsFile(carma, igroup, opticsType, rc) + + implicit none + + type(carma_type), intent(inout) :: carma !! the carma object + integer, intent(in) :: igroup !! group identifier + integer, intent(in) :: opticsType !! optics type (see I_OPTICS_... in carma_enums.F90) + integer, intent(out) :: rc !! return code, negative indicates failure + ! Local variables + logical :: do_mie + integer :: cnsttype ! constituent type + + ! Assume success. + rc = 0 + + ! What type of calculation is needed for this group? + ! + ! NOTE: Some of these calculations generate optical properties as single mass + ! coefficients, while others are lookup tables designed around multiple + ! dimensions. + select case (opticsType) + + case default + call endrun('carma_CreateOpticsFile:: Unknown optics type.') + end select + + return + end subroutine CARMAMODEL_CreateOpticsFile !! Called after wet deposition has been performed. Allows the specific model to add !! wet deposition of CARMA aerosols to the aerosols being communicated to the surface. !! !! @version July-2011 !! @author Chuck Bardeen - subroutine CARMA_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) + subroutine CARMAMODEL_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) use camsrfexch, only: cam_out_t implicit none @@ -841,6 +893,121 @@ subroutine CARMA_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) rc = RC_OK return - end subroutine CARMA_WetDeposition + end subroutine CARMAMODEL_WetDeposition + + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_CalculateCloudborneDiagnostics(carma, state, pbuf, aerclddiag, rc) + + type(carma_type), intent(in) :: carma !! the carma object + type(physics_state), intent(in) :: state !! Physics state variables - before pname + type(physics_buffer_desc), pointer, intent(in) :: pbuf(:) !! physics buffer + real(r8), intent(out) :: aerclddiag(pcols,MAXCLDAERDIAG) !! the total cloudborne aerosols, supports up to MAXCLDAERDIAG different values + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_CalculateCloudborneDiagnostics + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_OutputBudgetDiagnostics(carma, icnst4elem, icnst4gas, state, ptend, old_cflux, cflux, dt, pname, rc) + use cam_history, only: outfld + use constituents, only: pcnst, cnst_get_ind + + type(carma_type), intent(in) :: carma !! the carma object + integer, intent(in) :: icnst4elem(NELEM, NBIN) !! constituent index for a carma element + integer, intent(in) :: icnst4gas(NGAS) !! constituent index for a carma gas + type(physics_state), intent(in) :: state !! Physics state variables - before pname + type(physics_ptend), intent(in) :: ptend !! indivdual parameterization tendencies + real(r8) :: old_cflux(pcols,pcnst) !! cam_in%clfux from before the timestep_tend + real(r8) :: cflux(pcols,pcnst) !! cam_in%clfux from after the timestep_tend + real(r8), intent(in) :: dt !! timestep (s) + character(*), intent(in) :: pname !! short name of the physics package + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_OutputBudgetDiagnostics + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_OutputCloudborneDiagnostics(carma, state, pbuf, dt, pname, oldaerclddiag, rc) + use cam_history, only: outfld + + type(carma_type), intent(in) :: carma !! the carma object + type(physics_state), intent(in) :: state !! Physics state variables - before CARMA + type(physics_buffer_desc), pointer, intent(in) :: pbuf(:) !! physics buffer + real(r8), intent(in) :: dt !! timestep (s) + character(*), intent(in) :: pname !! short name of the physics package + real(r8), intent(in ) :: oldaerclddiag(pcols,MAXCLDAERDIAG) !! the before timestep cloudborne aerosol diags + integer, intent(out) :: rc !! return code, negative indicates failure + + real(r8) :: aerclddiag(pcols,MAXCLDAERDIAG) !! the after timestep cloudborne aerosol diags + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_OutputCloudborneDiagnostics + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_OutputDiagnostics(carma, icnst4elem, state, ptend, pbuf, cam_in, rc) + use cam_history, only: outfld + use constituents, only: cnst_get_ind + use camsrfexch, only: cam_in_t + + type(carma_type), intent(in) :: carma !! the carma object + integer, intent(in) :: icnst4elem(NELEM, NBIN) !! constituent index for a carma element + type(physics_state), intent(in) :: state !! Physics state variables - before CARMA + type(physics_ptend), intent(in) :: ptend !! indivdual parameterization tendencies + type(physics_buffer_desc), pointer, intent(in) :: pbuf(:) !! physics buffer + type(cam_in_t), intent(in) :: cam_in !! surface inputs + integer, intent(out) :: rc !! return code, negative indicates failure + + integer :: icol !! column index + integer :: ibin !! bin index + real(r8), pointer, dimension(:,:) :: soacm !! aerosol tendency due to gas-aerosol exchange kg/kg/s + real(r8), pointer, dimension(:,:) :: soapt !! aerosol tendency due to no2 photolysis kg/kg/s + character(len=16) :: binname !! names bins + real(r8) :: aerclddiag(pcols,MAXCLDAERDIAG) !! the before timestep cloudborne aerosol diags + integer :: i + integer :: icnst !! constituent index + integer :: ienconc !! concentration element index + integer :: ncore !! number of cores + integer :: icorelem(NELEM) !! core element index + real(r8) :: mair(pver) !! Mass of air column (kg/m2) + real(r8) :: pureso4(pcols) !! pure sulfate (kg/m2) + real(r8) :: mixso4(pcols) !! mix sulfate (kg/m2) + real(r8) :: cprflux(pcols) !! Surface Flux pure sulfate (kg/m2/s) + real(r8) :: cmxflux(pcols) !! Surface Flux mix sulfate (kg/m2/s) + real(r8) :: h2so4(pcols) !! H2SO4 gas (kg/m2) + real(r8) :: so2(pcols) !! SO2 gas (kg/m2) + real(r8) :: bdbc(pcols) !! Burden BC sulfate (kg/m2) + real(r8) :: bddust(pcols) !! Burden dust (kg/m2) + real(r8) :: bdoc(pcols) !! Burden OC sulfate (kg/m2) + real(r8) :: bdsalt(pcols) !! Burden SALT sulfate (kg/m2) + real(r8) :: bdsoa(pcols) !! Burden SOA sulfate (kg/m2) + character(len=16) :: shortname + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_OutputDiagnostics -end module +end module carma_model_mod diff --git a/src/physics/carma/models/pmc/carma_model_mod.F90 b/src/physics/carma/models/pmc/carma_model_mod.F90 index eb8c6e6667..41ac20fffe 100644 --- a/src/physics/carma/models/pmc/carma_model_mod.F90 +++ b/src/physics/carma/models/pmc/carma_model_mod.F90 @@ -45,14 +45,19 @@ module carma_model_mod private ! Declare the public methods. - public CARMA_DefineModel - public CARMA_Detrain - public CARMA_DiagnoseBins - public CARMA_DiagnoseBulk - public CARMA_EmitParticle - public CARMA_InitializeModel - public CARMA_InitializeParticle - public CARMA_WetDeposition + public CARMAMODEL_CalculateCloudborneDiagnostics + public CARMAMODEL_CreateOpticsFile + public CARMAMODEL_DefineModel + public CARMAMODEL_Detrain + public CARMAMODEL_DiagnoseBins + public CARMAMODEL_DiagnoseBulk + public CARMAMODEL_EmitParticle + public CARMAMODEL_InitializeModel + public CARMAMODEL_InitializeParticle + public CARMAMODEL_OutputBudgetDiagnostics + public CARMAMODEL_OutputCloudborneDiagnostics + public CARMAMODEL_OutputDiagnostics + public CARMAMODEL_WetDeposition ! Declare public constants integer, public, parameter :: NGROUP = 2 !! Number of particle groups @@ -65,6 +70,10 @@ module carma_model_mod integer, public, parameter :: NMIE_RH = 8 !! Number of relative humidities for mie calculations real(kind=f), public :: mie_rh(NMIE_RH) + integer, public, parameter :: NMIE_WTP = 0 !! Number of weight percents for mie calculations + real(kind=f), public :: mie_wtp(NMIE_WTP) + integer, public, parameter :: NREFIDX = 1 !! Number of refractive indices per element + ! Defines whether the groups should undergo deep convection in phase 1 or phase 2. ! Water vapor and cloud particles are convected in phase 1, while all other constituents ! are done in phase 2. @@ -117,7 +126,7 @@ module carma_model_mod !! !! @version May-2009 !! @author Chuck Bardeen - subroutine CARMA_DefineModel(carma, rc) + subroutine CARMAMODEL_DefineModel(carma, rc) use ioFileMod, only: getfil use wrap_nf @@ -137,7 +146,7 @@ subroutine CARMA_DefineModel(carma, rc) integer :: imag_vid character(len=256) :: efile ! refractive index file name real(kind=f) :: interp - complex(kind=f) :: refidx_ice(NWAVE) ! the refractive index at each CAM wavelength + complex(kind=f) :: refidx_ice(NWAVE,NREFIDX) ! the refractive index at each CAM wavelength integer :: LUNOPRT logical :: do_print @@ -145,7 +154,7 @@ subroutine CARMA_DefineModel(carma, rc) rc = RC_OK call CARMA_Get(carma, rc, do_print=do_print, LUNOPRT=LUNOPRT, wave=wave) - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMA_Get failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMA_Get failed.') ! Report model specific configuration parameters. if (masterproc) then @@ -203,7 +212,7 @@ subroutine CARMA_DefineModel(carma, rc) ! Read in the tables. call wrap_inq_varid(fid, 'wavelength', wave_vid) call wrap_get_var_realx(fid, wave_vid, warren_wave) - warren_wave = warren_wave * 1e-4 ! um -> cm + warren_wave = warren_wave * 1e-4_r8 ! um -> cm call wrap_inq_varid(fid, 'm_real', real_vid) call wrap_get_var_realx(fid, real_vid, warren_real) @@ -227,10 +236,10 @@ subroutine CARMA_DefineModel(carma, rc) if (wave(i) > warren_wave(j)) then if (j > 1) then interp = (wave(i) - warren_wave(j-1)) / (warren_wave(j) - warren_wave(j-1)) - refidx_ice(i) = cmplx(warren_real(j-1) + interp*(warren_real(j) - warren_real(j-1)), & - warren_imag(j-1) + interp*(warren_imag(j) - warren_imag(j-1))) + refidx_ice(i,1) = cmplx(warren_real(j-1) + interp*(warren_real(j) - warren_real(j-1)), & + warren_imag(j-1) + interp*(warren_imag(j) - warren_imag(j-1)), kind=f) else - refidx_ice(i) = cmplx(warren_real(j), warren_imag(j)) + refidx_ice(i,1) = cmplx(warren_real(j), warren_imag(j), kind=f) endif exit @@ -240,8 +249,8 @@ subroutine CARMA_DefineModel(carma, rc) end if call CARMAGROUP_Create(carma, I_GRP_CRICE, "ice crystal", rmin, 2.2_f, I_SPHERE, 1._f, .true., & - rc, do_mie=carma_do_pheat, refidx=refidx_ice, shortname="CRICE") - if (rc < 0) call endrun('CARMA_DefineModel::CARMAGROUP_Create failed.') + rc, do_mie=carma_do_pheat, shortname="CRICE") + if (rc < 0) call endrun('CARMAMODEL_DefineModel::CARMAGROUP_Create failed.') ! Define the Elements @@ -250,15 +259,15 @@ subroutine CARMA_DefineModel(carma, rc) ! should be 6 characters or less and without spaces. call CARMAELEMENT_Create(carma, I_ELEM_DUST, I_GRP_DUST, "meteor smoke", RHO_METEOR_SMOKE, & I_INVOLATILE, I_METEOR_SMOKE, rc, shortname="DUST") - if (rc < 0) call endrun('CARMA_DefineModel::CARMA_AddElement failed.') + if (rc < 0) call endrun('CARMAMODEL_DefineModel::CARMA_AddElement failed.') call CARMAELEMENT_Create(carma, I_ELEM_CRICE, I_GRP_CRICE, "ice crystal", RHO_I, & - I_VOLATILE, I_ICE, rc, shortname="CRICE") - if (rc < 0) call endrun('CARMA_DefineModel::CARMA_AddElement failed.') + I_VOLATILE, I_ICE, rc, shortname="CRICE", refidx=refidx_ice) + if (rc < 0) call endrun('CARMAMODEL_DefineModel::CARMA_AddElement failed.') call CARMAELEMENT_Create(carma, I_ELEM_CRCORE, I_GRP_CRICE, "ice core", RHO_METEOR_SMOKE, & I_COREMASS, I_METEOR_SMOKE, rc, shortname="CRCORE") - if (rc < 0) call endrun('CARMA_DefineModel::CARMA_AddElement failed.') + if (rc < 0) call endrun('CARMAMODEL_DefineModel::CARMA_AddElement failed.') ! Define the Solutes @@ -267,25 +276,25 @@ subroutine CARMA_DefineModel(carma, rc) ! Define the Gases call CARMAGAS_Create(carma, I_GAS_H2O, "Water Vapor", WTMOL_H2O, & I_VAPRTN_H2O_MURPHY2005, I_GCOMP_H2O, rc, shortname="Q", ds_threshold=0.2_f) - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMAGAS_Create failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMAGAS_Create failed.') ! Define the Processes call CARMA_AddCoagulation(carma, I_GRP_DUST, I_GRP_DUST, I_GRP_DUST, I_COLLEC_DATA, rc) - if (rc < 0) call endrun('CARMA_DefineModel::CARMA_AddCoagulation failed.') + if (rc < 0) call endrun('CARMAMODEL_DefineModel::CARMA_AddCoagulation failed.') call CARMA_AddNucleation(carma, I_ELEM_DUST, I_ELEM_CRCORE, I_HETNUC, 0._f, rc, & igas=I_GAS_H2O, ievp2elem=I_ELEM_DUST) - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMA_AddNucleation failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMA_AddNucleation failed.') call CARMA_AddGrowth(carma, I_ELEM_CRICE, I_GAS_H2O, rc) - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMA_AddGrowth failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMA_AddGrowth failed.') call CARMA_AddCoagulation(carma, I_GRP_DUST, I_GRP_CRICE, I_GRP_CRICE, I_COLLEC_DATA, rc) - if (rc < 0) call endrun('CARMA_DefineModel::CARMA_AddCoagulation failed.') + if (rc < 0) call endrun('CARMAMODEL_DefineModel::CARMA_AddCoagulation failed.') return - end subroutine CARMA_DefineModel + end subroutine CARMAMODEL_DefineModel !! Defines all the CARMA components (groups, elements, solutes and gases) and process @@ -295,7 +304,7 @@ end subroutine CARMA_DefineModel !! @author Chuck Bardeen !! !! @see CARMASTATE_SetDetrain - subroutine CARMA_Detrain(carma, cstate, cam_in, dlf, state, icol, dt, rc, rliq, prec_str, snow_str, & + subroutine CARMAMODEL_Detrain(carma, cstate, cam_in, dlf, state, icol, dt, rc, rliq, prec_str, snow_str, & tnd_qsnow, tnd_nsnow) use camsrfexch, only: cam_in_t use physconst, only: latice, latvap, cpair @@ -320,14 +329,14 @@ subroutine CARMA_Detrain(carma, cstate, cam_in, dlf, state, icol, dt, rc, rliq, rc = RC_OK return - end subroutine CARMA_Detrain + end subroutine CARMAMODEL_Detrain !! For diagnostic groups, sets up up the CARMA bins based upon the CAM state. !! !! @version July-2009 !! @author Chuck Bardeen - subroutine CARMA_DiagnoseBins(carma, cstate, state, pbuf, icol, dt, rc, rliq, prec_str, snow_str) + subroutine CARMAMODEL_DiagnoseBins(carma, cstate, state, pbuf, icol, dt, rc, rliq, prec_str, snow_str) use time_manager, only: is_first_step implicit none @@ -353,14 +362,14 @@ subroutine CARMA_DiagnoseBins(carma, cstate, state, pbuf, icol, dt, rc, rliq, pr ! code to determine the mass in each bin from the CAM state. return - end subroutine CARMA_DiagnoseBins + end subroutine CARMAMODEL_DiagnoseBins !! For diagnostic groups, determines the tendencies on the CAM state from the CARMA bins. !! !! @version July-2009 !! @author Chuck Bardeen - subroutine CARMA_DiagnoseBulk(carma, cstate, cam_out, state, pbuf, ptend, icol, dt, rc, rliq, prec_str, snow_str, & + subroutine CARMAMODEL_DiagnoseBulk(carma, cstate, cam_out, state, pbuf, ptend, icol, dt, rc, rliq, prec_str, snow_str, & prec_sed, snow_sed, tnd_qsnow, tnd_nsnow, re_ice) use camsrfexch, only: cam_out_t @@ -391,10 +400,10 @@ subroutine CARMA_DiagnoseBulk(carma, cstate, cam_out, state, pbuf, ptend, icol, ! code to determine the bulk mass from the CARMA state. return - end subroutine CARMA_DiagnoseBulk + end subroutine CARMAMODEL_DiagnoseBulk - subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tendency, surfaceFlux, rc) + subroutine CARMAMODEL_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tendency, surfaceFlux, pbuf, rc) use shr_kind_mod, only: r8 => shr_kind_r8 use ppgrid, only: pcols, pver use physics_types, only: physics_state @@ -413,6 +422,7 @@ subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tend type(cam_in_t), intent(in) :: cam_in !! surface inputs real(r8), intent(out) :: tendency(pcols, pver) !! constituent tendency (kg/kg/s) real(r8), intent(out) :: surfaceFlux(pcols) !! constituent surface flux (kg/m^2/s) + type(physics_buffer_desc), pointer :: pbuf(:) !! physics buffer integer, intent(out) :: rc !! return code, negative indicates failure integer :: ilat ! latitude index @@ -552,7 +562,7 @@ subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tend end if end do - if (abs((state%lat(icol) / DEG2RAD) - 90.0) <= 0.00001_r8) then + if (abs((state%lat(icol) / DEG2RAD) - 90.0_r8) <= 0.00001_r8) then rfScale(icol) = carma_escale_grf(carma_escale_nLats, doy) end if @@ -598,7 +608,7 @@ subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tend end if return - end subroutine CARMA_EmitParticle + end subroutine CARMAMODEL_EmitParticle !! Allows the model to perform its own initialization in addition to what is done @@ -606,7 +616,7 @@ end subroutine CARMA_EmitParticle !! !! @author Chuck Bardeen !! @version May-2009 - subroutine CARMA_InitializeModel(carma, lq_carma, rc) + subroutine CARMAMODEL_InitializeModel(carma, lq_carma, pbuf2d, rc) use ioFileMod, only: getfil use constituents, only: pcnst use wrap_nf @@ -616,6 +626,7 @@ subroutine CARMA_InitializeModel(carma, lq_carma, rc) type(carma_type), intent(in) :: carma !! the carma object logical, intent(inout) :: lq_carma(pcnst) !! flags to indicate whether the constituent !! could have a CARMA tendency + type(physics_buffer_desc), pointer :: pbuf2d(:,:) integer, intent(out) :: rc !! return code, negative indicates failure integer :: ilev ! level index @@ -641,7 +652,7 @@ subroutine CARMA_InitializeModel(carma, lq_carma, rc) ! Add initialization here. call CARMA_Get(carma, rc, do_print=do_print, LUNOPRT=LUNOPRT) - if (rc < 0) call endrun("CARMA_InitializeModel: CARMA_Get failed.") + if (rc < 0) call endrun("CARMAMODEL_InitializeModel: CARMA_Get failed.") ! Initialize the emissions rate table. if (carma_do_emission) then @@ -682,7 +693,7 @@ subroutine CARMA_InitializeModel(carma, lq_carma, rc) carma_emis_ilev_max = carma_emis_nLevs do ilev = 1, carma_emis_nLevs - if (carma_emis_rate(ilev) <= 0.0) then + if (carma_emis_rate(ilev) <= 0.0_r8) then carma_emis_ilev_min = ilev + 1 else exit @@ -690,7 +701,7 @@ subroutine CARMA_InitializeModel(carma, lq_carma, rc) end do do ilev = carma_emis_nLevs, 1, -1 - if (carma_emis_rate(ilev) <= 0.0) then + if (carma_emis_rate(ilev) <= 0.0_r8) then carma_emis_ilev_max = ilev - 1 else exit @@ -759,7 +770,7 @@ subroutine CARMA_InitializeModel(carma, lq_carma, rc) ! There should be one time for each day of the year, so ! quit if it isn't correct. if (carma_escale_nTimes .ne. 365) then - call endrun("CARMA_InitializeModel: Emission scaling file should have entries for 365 days, but doesn't.") + call endrun("CARMAMODEL_InitializeModel: Emission scaling file should have entries for 365 days, but doesn't.") endif call wrap_inq_dimid(fid, "ltime", ltime_did) @@ -782,7 +793,7 @@ subroutine CARMA_InitializeModel(carma, lq_carma, rc) call wrap_inq_varid(fid, 'SGRF', grf_vid) tmp = nf90_get_var (fid, grf_vid, carma_escale_grf) if (tmp/=NF90_NOERR) then - write(iulog,*) 'CARMA_InitializeModel: error reading varid =', grf_vid + write(iulog,*) 'CARMAMODEL_InitializeModel: error reading varid =', grf_vid call handle_error (tmp) end if @@ -818,7 +829,7 @@ subroutine CARMA_InitializeModel(carma, lq_carma, rc) endif return - end subroutine CARMA_InitializeModel + end subroutine CARMAMODEL_InitializeModel !! Sets the initial condition for CARMA aerosol particles. By default, there are no @@ -830,8 +841,9 @@ end subroutine CARMA_InitializeModel !! !! @author Chuck Bardeen !! @version May-2009 - subroutine CARMA_InitializeParticle(carma, ielem, ibin, latvals, lonvals, mask, q, rc) + subroutine CARMAMODEL_InitializeParticle(carma, ielem, ibin, latvals, lonvals, mask, q, rc) use shr_kind_mod, only: r8 => shr_kind_r8 + use pmgrid, only: plat, plev, plon implicit none @@ -852,15 +864,55 @@ subroutine CARMA_InitializeParticle(carma, ielem, ibin, latvals, lonvals, mask, ! NOTE: Initialized to 0. by the caller, so nothing needs to be done. return - end subroutine CARMA_InitializeParticle + end subroutine CARMAMODEL_InitializeParticle + + !! This routine is an extension of CARMA_CreateOpticsFile() that allows for + !! model specific tables to be created in addition to the model independent + !! methods that are in carma_intr.F90. + !! + !! The opticsType that is specified for the group determines how the optical + !! properties will be generated for that group. Each group can use a different + !! optics method if needed. Refractive indices need for these calculation are + !! are specified in the group's elements rather than at the group level. This + !! allows various mixing approaches to be used to determine the refractive index + !! for the particle as a whole. If the refractive index for water is needed, + !! it is specific the the CARMAGAS object for H2O. + subroutine CARMAMODEL_CreateOpticsFile(carma, igroup, opticsType, rc) + + implicit none + + type(carma_type), intent(inout) :: carma !! the carma object + integer, intent(in) :: igroup !! group identifier + integer, intent(in) :: opticsType !! optics type (see I_OPTICS_... in carma_enums.F90) + integer, intent(out) :: rc !! return code, negative indicates failure + ! Local variables + logical :: do_mie + integer :: cnsttype ! constituent type + + ! Assume success. + rc = 0 + + ! What type of calculation is needed for this group? + ! + ! NOTE: Some of these calculations generate optical properties as single mass + ! coefficients, while others are lookup tables designed around multiple + ! dimensions. + select case (opticsType) + + case default + call endrun('carma_CreateOpticsFile:: Unknown optics type.') + end select + + return + end subroutine CARMAMODEL_CreateOpticsFile !! Called after wet deposition has been performed. Allows the specific model to add !! wet deposition of CARMA aerosols to the aerosols being communicated to the surface. !! !! @version July-2011 !! @author Chuck Bardeen - subroutine CARMA_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) + subroutine CARMAMODEL_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) use camsrfexch, only: cam_out_t implicit none @@ -879,6 +931,121 @@ subroutine CARMA_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) rc = RC_OK return - end subroutine CARMA_WetDeposition + end subroutine CARMAMODEL_WetDeposition + + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_CalculateCloudborneDiagnostics(carma, state, pbuf, aerclddiag, rc) + + type(carma_type), intent(in) :: carma !! the carma object + type(physics_state), intent(in) :: state !! Physics state variables - before pname + type(physics_buffer_desc), pointer, intent(in) :: pbuf(:) !! physics buffer + real(r8), intent(out) :: aerclddiag(pcols,MAXCLDAERDIAG) !! the total cloudborne aerosols, supports up to MAXCLDAERDIAG different values + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_CalculateCloudborneDiagnostics + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_OutputBudgetDiagnostics(carma, icnst4elem, icnst4gas, state, ptend, old_cflux, cflux, dt, pname, rc) + use cam_history, only: outfld + use constituents, only: pcnst, cnst_get_ind + + type(carma_type), intent(in) :: carma !! the carma object + integer, intent(in) :: icnst4elem(NELEM, NBIN) !! constituent index for a carma element + integer, intent(in) :: icnst4gas(NGAS) !! constituent index for a carma gas + type(physics_state), intent(in) :: state !! Physics state variables - before pname + type(physics_ptend), intent(in) :: ptend !! indivdual parameterization tendencies + real(r8) :: old_cflux(pcols,pcnst) !! cam_in%clfux from before the timestep_tend + real(r8) :: cflux(pcols,pcnst) !! cam_in%clfux from after the timestep_tend + real(r8), intent(in) :: dt !! timestep (s) + character(*), intent(in) :: pname !! short name of the physics package + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_OutputBudgetDiagnostics + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_OutputCloudborneDiagnostics(carma, state, pbuf, dt, pname, oldaerclddiag, rc) + use cam_history, only: outfld + + type(carma_type), intent(in) :: carma !! the carma object + type(physics_state), intent(in) :: state !! Physics state variables - before CARMA + type(physics_buffer_desc), pointer, intent(in) :: pbuf(:) !! physics buffer + real(r8), intent(in) :: dt !! timestep (s) + character(*), intent(in) :: pname !! short name of the physics package + real(r8), intent(in ) :: oldaerclddiag(pcols,MAXCLDAERDIAG) !! the before timestep cloudborne aerosol diags + integer, intent(out) :: rc !! return code, negative indicates failure + + real(r8) :: aerclddiag(pcols,MAXCLDAERDIAG) !! the after timestep cloudborne aerosol diags + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_OutputCloudborneDiagnostics + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_OutputDiagnostics(carma, icnst4elem, state, ptend, pbuf, cam_in, rc) + use cam_history, only: outfld + use constituents, only: cnst_get_ind + use camsrfexch, only: cam_in_t + + type(carma_type), intent(in) :: carma !! the carma object + integer, intent(in) :: icnst4elem(NELEM, NBIN) !! constituent index for a carma element + type(physics_state), intent(in) :: state !! Physics state variables - before CARMA + type(physics_ptend), intent(in) :: ptend !! indivdual parameterization tendencies + type(physics_buffer_desc), pointer, intent(in) :: pbuf(:) !! physics buffer + type(cam_in_t), intent(in) :: cam_in !! surface inputs + integer, intent(out) :: rc !! return code, negative indicates failure + + integer :: icol !! column index + integer :: ibin !! bin index + real(r8), pointer, dimension(:,:) :: soacm !! aerosol tendency due to gas-aerosol exchange kg/kg/s + real(r8), pointer, dimension(:,:) :: soapt !! aerosol tendency due to no2 photolysis kg/kg/s + character(len=16) :: binname !! names bins + real(r8) :: aerclddiag(pcols,MAXCLDAERDIAG) !! the before timestep cloudborne aerosol diags + integer :: i + integer :: icnst !! constituent index + integer :: ienconc !! concentration element index + integer :: ncore !! number of cores + integer :: icorelem(NELEM) !! core element index + real(r8) :: mair(pver) !! Mass of air column (kg/m2) + real(r8) :: pureso4(pcols) !! pure sulfate (kg/m2) + real(r8) :: mixso4(pcols) !! mix sulfate (kg/m2) + real(r8) :: cprflux(pcols) !! Surface Flux pure sulfate (kg/m2/s) + real(r8) :: cmxflux(pcols) !! Surface Flux mix sulfate (kg/m2/s) + real(r8) :: h2so4(pcols) !! H2SO4 gas (kg/m2) + real(r8) :: so2(pcols) !! SO2 gas (kg/m2) + real(r8) :: bdbc(pcols) !! Burden BC sulfate (kg/m2) + real(r8) :: bddust(pcols) !! Burden dust (kg/m2) + real(r8) :: bdoc(pcols) !! Burden OC sulfate (kg/m2) + real(r8) :: bdsalt(pcols) !! Burden SALT sulfate (kg/m2) + real(r8) :: bdsoa(pcols) !! Burden SOA sulfate (kg/m2) + character(len=16) :: shortname + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_OutputDiagnostics -end module +end module carma_model_mod diff --git a/src/physics/carma/models/pmc_sulfate/carma_model_mod.F90 b/src/physics/carma/models/pmc_sulfate/carma_model_mod.F90 index 4a9e08d5be..166bb66f3d 100644 --- a/src/physics/carma/models/pmc_sulfate/carma_model_mod.F90 +++ b/src/physics/carma/models/pmc_sulfate/carma_model_mod.F90 @@ -223,7 +223,7 @@ subroutine CARMA_DefineModel(carma, rc) ! Read in the tables. call wrap_inq_varid(fid, 'wavelength', wave_vid) call wrap_get_var_realx(fid, wave_vid, warren_wave) - warren_wave = warren_wave * 1e-4 ! um -> cm + warren_wave = warren_wave * 1e-4_r8 ! um -> cm call wrap_inq_varid(fid, 'm_real', real_vid) call wrap_get_var_realx(fid, real_vid, warren_real) @@ -617,7 +617,7 @@ subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tend end if end do - if (abs((state%lat(icol) / DEG2RAD) - 90.0) <= 0.00001_r8) then + if (abs((state%lat(icol) / DEG2RAD) - 90.0_r8) <= 0.00001_r8) then rfScale(icol) = carma_escale_grf(carma_escale_nLats, doy) end if @@ -753,7 +753,7 @@ subroutine CARMA_InitializeModel(carma, lq_carma, rc) carma_emis_ilev_max = carma_emis_nLevs do ilev = 1, carma_emis_nLevs - if (carma_emis_rate(ilev) <= 0.0) then + if (carma_emis_rate(ilev) <= 0.0_r8) then carma_emis_ilev_min = ilev + 1 else exit @@ -761,7 +761,7 @@ subroutine CARMA_InitializeModel(carma, lq_carma, rc) end do do ilev = carma_emis_nLevs, 1, -1 - if (carma_emis_rate(ilev) <= 0.0) then + if (carma_emis_rate(ilev) <= 0.0_r8) then carma_emis_ilev_max = ilev - 1 else exit @@ -953,4 +953,4 @@ subroutine CARMA_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) return end subroutine CARMA_WetDeposition -end module +end module carma_model_mod diff --git a/src/physics/carma/models/sea_salt/carma_model_mod.F90 b/src/physics/carma/models/sea_salt/carma_model_mod.F90 index db01fb4b00..0f1aa889dd 100644 --- a/src/physics/carma/models/sea_salt/carma_model_mod.F90 +++ b/src/physics/carma/models/sea_salt/carma_model_mod.F90 @@ -44,14 +44,19 @@ module carma_model_mod private ! Declare the public methods. - public CARMA_DefineModel - public CARMA_Detrain - public CARMA_DiagnoseBins - public CARMA_DiagnoseBulk - public CARMA_EmitParticle - public CARMA_InitializeModel - public CARMA_InitializeParticle - public CARMA_WetDeposition + public CARMAMODEL_CalculateCloudborneDiagnostics + public CARMAMODEL_CreateOpticsFile + public CARMAMODEL_DefineModel + public CARMAMODEL_Detrain + public CARMAMODEL_DiagnoseBins + public CARMAMODEL_DiagnoseBulk + public CARMAMODEL_EmitParticle + public CARMAMODEL_InitializeModel + public CARMAMODEL_InitializeParticle + public CARMAMODEL_OutputBudgetDiagnostics + public CARMAMODEL_OutputCloudborneDiagnostics + public CARMAMODEL_OutputDiagnostics + public CARMAMODEL_WetDeposition ! Declare public constants integer, public, parameter :: NGROUP = 1 !! Number of particle groups @@ -64,6 +69,10 @@ module carma_model_mod integer, public, parameter :: NMIE_RH = 8 !! Number of relative humidities for mie calculations real(kind=f), public :: mie_rh(NMIE_RH) + integer, public, parameter :: NMIE_WTP = 0 !! Number of weight percents for mie calculations + real(kind=f), public :: mie_wtp(NMIE_WTP) + integer, public, parameter :: NREFIDX = 1 !! Number of refractive indices per element + ! Defines whether the groups should undergo deep convection in phase 1 or phase 2. ! Water vapor and cloud particles are convected in phase 1, while all other constituents ! are done in phase 2. @@ -83,7 +92,7 @@ module carma_model_mod !! !! @version May-2009 !! @author Chuck Bardeen - subroutine CARMA_DefineModel(carma, rc) + subroutine CARMAMODEL_DefineModel(carma, rc) type(carma_type), intent(inout) :: carma !! the carma object integer, intent(out) :: rc !! return code, negative indicates failure @@ -100,7 +109,7 @@ subroutine CARMA_DefineModel(carma, rc) ! Report model specific configuration parameters. if (masterproc) then call CARMA_Get(carma, rc, do_print=do_print, LUNOPRT=LUNOPRT) - if (rc < 0) call endrun('CARMA_DefineModel::CARMA_Get failed.') + if (rc < 0) call endrun('CARMAMODEL_DefineModel::CARMA_Get failed.') if (do_print) write(LUNOPRT,*) '' if (do_print) write(LUNOPRT,*) 'CARMA ', trim(carma_model), ' specific settings :' @@ -117,7 +126,7 @@ subroutine CARMA_DefineModel(carma, rc) rc, do_wetdep=.true., do_drydep=.true., solfac=0.3_f, & scavcoef=0.1_f, shortname="SALT", irhswell=I_GERBER, & irhswcomp=I_SWG_SEA_SALT) - if (rc < 0) call endrun('CARMA_DefineModel::CARMA_AddGroup failed.') + if (rc < 0) call endrun('CARMAMODEL_DefineModel::CARMA_AddGroup failed.') ! Define the Elements @@ -125,7 +134,7 @@ subroutine CARMA_DefineModel(carma, rc) ! NOTE: For CAM, the optional shortname needs to be provided for the group. These names ! should be 6 characters or less and without spaces. call CARMAELEMENT_Create(carma, 1, 1, "sea salt", RHO_SALT, I_INVOLATILE, I_SEA_SALT, rc, shortname="SALT") - if (rc < 0) call endrun('CARMA_DefineModel::CARMA_AddElement failed.') + if (rc < 0) call endrun('CARMAMODEL_DefineModel::CARMA_AddElement failed.') ! Define the Solutes @@ -137,7 +146,7 @@ subroutine CARMA_DefineModel(carma, rc) ! Define the Processes return - end subroutine CARMA_DefineModel + end subroutine CARMAMODEL_DefineModel !! Defines all the CARMA components (groups, elements, solutes and gases) and process @@ -147,7 +156,7 @@ end subroutine CARMA_DefineModel !! @author Chuck Bardeen !! !! @see CARMASTATE_SetDetrain - subroutine CARMA_Detrain(carma, cstate, cam_in, dlf, state, icol, dt, rc, rliq, prec_str, snow_str, & + subroutine CARMAMODEL_Detrain(carma, cstate, cam_in, dlf, state, icol, dt, rc, rliq, prec_str, snow_str, & tnd_qsnow, tnd_nsnow) use camsrfexch, only: cam_in_t use physconst, only: latice, latvap, cpair @@ -172,14 +181,14 @@ subroutine CARMA_Detrain(carma, cstate, cam_in, dlf, state, icol, dt, rc, rliq, rc = RC_OK return - end subroutine CARMA_Detrain + end subroutine CARMAMODEL_Detrain !! For diagnostic groups, sets up up the CARMA bins based upon the CAM state. !! !! @version July-2009 !! @author Chuck Bardeen - subroutine CARMA_DiagnoseBins(carma, cstate, state, pbuf, icol, dt, rc, rliq, prec_str, snow_str) + subroutine CARMAMODEL_DiagnoseBins(carma, cstate, state, pbuf, icol, dt, rc, rliq, prec_str, snow_str) use time_manager, only: is_first_step implicit none @@ -205,14 +214,14 @@ subroutine CARMA_DiagnoseBins(carma, cstate, state, pbuf, icol, dt, rc, rliq, pr ! code to determine the mass in each bin from the CAM state. return - end subroutine CARMA_DiagnoseBins + end subroutine CARMAMODEL_DiagnoseBins !! For diagnostic groups, determines the tendencies on the CAM state from the CARMA bins. !! !! @version July-2009 !! @author Chuck Bardeen - subroutine CARMA_DiagnoseBulk(carma, cstate, cam_out, state, pbuf, ptend, icol, dt, rc, rliq, prec_str, snow_str, & + subroutine CARMAMODEL_DiagnoseBulk(carma, cstate, cam_out, state, pbuf, ptend, icol, dt, rc, rliq, prec_str, snow_str, & prec_sed, snow_sed, tnd_qsnow, tnd_nsnow, re_ice) use camsrfexch, only: cam_out_t @@ -243,7 +252,7 @@ subroutine CARMA_DiagnoseBulk(carma, cstate, cam_out, state, pbuf, ptend, icol, ! code to determine the bulk mass from the CARMA state. return - end subroutine CARMA_DiagnoseBulk + end subroutine CARMAMODEL_DiagnoseBulk !! Calculates the emissions for CARMA aerosol particles. By default, there is no @@ -252,7 +261,7 @@ end subroutine CARMA_DiagnoseBulk !! !! @author Tianyi Fan, Chuck Bardeen !! @version Dec-2010 - subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tendency, surfaceFlux, rc) + subroutine CARMAMODEL_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tendency, surfaceFlux, pbuf, rc) use shr_kind_mod, only: r8 => shr_kind_r8 use ppgrid, only: pcols, pver use physics_types, only: physics_state @@ -270,6 +279,7 @@ subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tend type(cam_in_t), intent(in) :: cam_in !! surface inputs real(r8), intent(out) :: tendency(pcols, pver) !! constituent tendency (kg/kg/s) real(r8), intent(out) :: surfaceFlux(pcols) !! constituent surface flux (kg/m^2/s) + type(physics_buffer_desc), pointer :: pbuf(:) !! physics buffer integer, intent(out) :: rc !! return code, negative indicates failure integer :: lchnk ! chunk identifier @@ -439,7 +449,7 @@ subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tend !********************************** ! wet sea salt radius at RH = 80% !********************************** - r80cm = (c1 * (r(ibin)) ** c2 / (c3 * r(ibin) ** c4 - log10(0.8)) + (r(ibin))**3) ** (1./3.) ! [cm] + r80cm = (c1 * (r(ibin)) ** c2 / (c3 * r(ibin) ** c4 - log10(0.8_r8)) + (r(ibin))**3) ** (1._r8/3._r8) ! [cm] rdrycm = r(ibin) ! [cm] r80 = r80cm *1.e4_r8 ! [um] rdry = rdrycm*1.e4_r8 ! [um] @@ -452,7 +462,7 @@ subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tend !********************************** ! WIND for seasalt production !********************************** - call CARMA_SurfaceWind(carma, state, icol, cam_in, u10in, rc) + call CARMAMODEL_SurfaceWind(carma, state, icol, cam_in, u10in, rc) ! Add any surface flux here. ncflx = 0.0_r8 @@ -542,7 +552,7 @@ subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tend !Monahan B_mona = (0.38_r8 - log10(r80)) / 0.65_r8 Monahan = 1.373_r8 * (u10in**3.41_r8) * r80**(-3._r8) * & - (1._r8 + 0.057 *r80**1.05_r8) * 10._r8 ** (1.19_r8 * exp(-1. * B_mona**2)) ! dF/dr + (1._r8 + 0.057_r8 *r80**1.05_r8) * 10._r8 ** (1.19_r8 * exp(-1._r8 * B_mona**2)) ! dF/dr !Smith u14 = u10in * (1._r8 + cd_smith**0.5_r8 / xkar * log(14._r8 / 10._r8)) ! 14 meter wind @@ -641,7 +651,7 @@ subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tend end if return - end subroutine CARMA_EmitParticle + end subroutine CARMAMODEL_EmitParticle !! Allows the model to perform its own initialization in addition to what is done @@ -649,13 +659,14 @@ end subroutine CARMA_EmitParticle !! !! @author Chuck Bardeen !! @version May-2009 - subroutine CARMA_InitializeModel(carma, lq_carma, rc) + subroutine CARMAMODEL_InitializeModel(carma, lq_carma, pbuf2d, rc) use constituents, only: pcnst implicit none type(carma_type), intent(in) :: carma !! the carma object logical, intent(inout) :: lq_carma(pcnst) !! flags to indicate whether the constituent !! could have a CARMA tendency + type(physics_buffer_desc), pointer :: pbuf2d(:,:) integer, intent(out) :: rc !! return code, negative indicates failure ! Default return code. @@ -664,7 +675,7 @@ subroutine CARMA_InitializeModel(carma, lq_carma, rc) ! Add initialization here. return - end subroutine CARMA_InitializeModel + end subroutine CARMAMODEL_InitializeModel !! Sets the initial condition for CARMA aerosol particles. By default, there are no @@ -676,8 +687,9 @@ end subroutine CARMA_InitializeModel !! !! @author Chuck Bardeen !! @version May-2009 - subroutine CARMA_InitializeParticle(carma, ielem, ibin, latvals, lonvals, mask, q, rc) + subroutine CARMAMODEL_InitializeParticle(carma, ielem, ibin, latvals, lonvals, mask, q, rc) use shr_kind_mod, only: r8 => shr_kind_r8 + use pmgrid, only: plat, plev, plon implicit none @@ -698,15 +710,55 @@ subroutine CARMA_InitializeParticle(carma, ielem, ibin, latvals, lonvals, mask, ! NOTE: Initialized to 0. by the caller, so nothing needs to be done. return - end subroutine CARMA_InitializeParticle + end subroutine CARMAMODEL_InitializeParticle + + !! This routine is an extension of CARMA_CreateOpticsFile() that allows for + !! model specific tables to be created in addition to the model independent + !! methods that are in carma_intr.F90. + !! + !! The opticsType that is specified for the group determines how the optical + !! properties will be generated for that group. Each group can use a different + !! optics method if needed. Refractive indices need for these calculation are + !! are specified in the group's elements rather than at the group level. This + !! allows various mixing approaches to be used to determine the refractive index + !! for the particle as a whole. If the refractive index for water is needed, + !! it is specific the the CARMAGAS object for H2O. + subroutine CARMAMODEL_CreateOpticsFile(carma, igroup, opticsType, rc) + + implicit none + + type(carma_type), intent(inout) :: carma !! the carma object + integer, intent(in) :: igroup !! group identifier + integer, intent(in) :: opticsType !! optics type (see I_OPTICS_... in carma_enums.F90) + integer, intent(out) :: rc !! return code, negative indicates failure + ! Local variables + logical :: do_mie + integer :: cnsttype ! constituent type + + ! Assume success. + rc = 0 + + ! What type of calculation is needed for this group? + ! + ! NOTE: Some of these calculations generate optical properties as single mass + ! coefficients, while others are lookup tables designed around multiple + ! dimensions. + select case (opticsType) + + case default + call endrun('carma_CreateOpticsFile:: Unknown optics type.') + end select + + return + end subroutine CARMAMODEL_CreateOpticsFile !! Called after wet deposition has been performed. Allows the specific model to add !! wet deposition of CARMA aerosols to the aerosols being communicated to the surface. !! !! @version July-2011 !! @author Chuck Bardeen - subroutine CARMA_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) + subroutine CARMAMODEL_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) use camsrfexch, only: cam_out_t implicit none @@ -725,14 +777,14 @@ subroutine CARMA_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) rc = RC_OK return - end subroutine CARMA_WetDeposition + end subroutine CARMAMODEL_WetDeposition !! Calculate the sea surface wind with a Weibull distribution. !! !! @author Tianyi Fan !! @version August-2010 - subroutine CARMA_SurfaceWind(carma, state, icol, cam_in, u10in, rc) + subroutine CARMAMODEL_SurfaceWind(carma, state, icol, cam_in, u10in, rc) use ppgrid, only: pcols, pver use physics_types, only: physics_state use camsrfexch, only: cam_in_t @@ -765,7 +817,7 @@ subroutine CARMA_SurfaceWind(carma, state, icol, cam_in, u10in, rc) u10in = uWB341 ** (1._r8 / 3.41_r8) return - end subroutine CARMA_SurfaceWind + end subroutine CARMAMODEL_SurfaceWind !! Calculate the nth mean of u using Weibull wind distribution @@ -794,7 +846,7 @@ subroutine WeibullWind(u, uth, n, uwb, wbk) if (present(wbk)) then k = wbk else - k = 0.94*u**0.5_r8 ! follow Grini and Zender, 2004JGR + k = 0.94_r8*u**0.5_r8 ! follow Grini and Zender, 2004JGR ! k = 2.5_r8 ! Lansing's estimate end if @@ -809,4 +861,119 @@ subroutine WeibullWind(u, uth, n, uwb, wbk) end subroutine WeibullWind -end module + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_CalculateCloudborneDiagnostics(carma, state, pbuf, aerclddiag, rc) + + type(carma_type), intent(in) :: carma !! the carma object + type(physics_state), intent(in) :: state !! Physics state variables - before pname + type(physics_buffer_desc), pointer, intent(in) :: pbuf(:) !! physics buffer + real(r8), intent(out) :: aerclddiag(pcols,MAXCLDAERDIAG) !! the total cloudborne aerosols, supports up to MAXCLDAERDIAG different values + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_CalculateCloudborneDiagnostics + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_OutputBudgetDiagnostics(carma, icnst4elem, icnst4gas, state, ptend, old_cflux, cflux, dt, pname, rc) + use cam_history, only: outfld + use constituents, only: pcnst, cnst_get_ind + + type(carma_type), intent(in) :: carma !! the carma object + integer, intent(in) :: icnst4elem(NELEM, NBIN) !! constituent index for a carma element + integer, intent(in) :: icnst4gas(NGAS) !! constituent index for a carma gas + type(physics_state), intent(in) :: state !! Physics state variables - before pname + type(physics_ptend), intent(in) :: ptend !! indivdual parameterization tendencies + real(r8) :: old_cflux(pcols,pcnst) !! cam_in%clfux from before the timestep_tend + real(r8) :: cflux(pcols,pcnst) !! cam_in%clfux from after the timestep_tend + real(r8), intent(in) :: dt !! timestep (s) + character(*), intent(in) :: pname !! short name of the physics package + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_OutputBudgetDiagnostics + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_OutputCloudborneDiagnostics(carma, state, pbuf, dt, pname, oldaerclddiag, rc) + use cam_history, only: outfld + + type(carma_type), intent(in) :: carma !! the carma object + type(physics_state), intent(in) :: state !! Physics state variables - before CARMA + type(physics_buffer_desc), pointer, intent(in) :: pbuf(:) !! physics buffer + real(r8), intent(in) :: dt !! timestep (s) + character(*), intent(in) :: pname !! short name of the physics package + real(r8), intent(in ) :: oldaerclddiag(pcols,MAXCLDAERDIAG) !! the before timestep cloudborne aerosol diags + integer, intent(out) :: rc !! return code, negative indicates failure + + real(r8) :: aerclddiag(pcols,MAXCLDAERDIAG) !! the after timestep cloudborne aerosol diags + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_OutputCloudborneDiagnostics + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_OutputDiagnostics(carma, icnst4elem, state, ptend, pbuf, cam_in, rc) + use cam_history, only: outfld + use constituents, only: cnst_get_ind + use camsrfexch, only: cam_in_t + + type(carma_type), intent(in) :: carma !! the carma object + integer, intent(in) :: icnst4elem(NELEM, NBIN) !! constituent index for a carma element + type(physics_state), intent(in) :: state !! Physics state variables - before CARMA + type(physics_ptend), intent(in) :: ptend !! indivdual parameterization tendencies + type(physics_buffer_desc), pointer, intent(in) :: pbuf(:) !! physics buffer + type(cam_in_t), intent(in) :: cam_in !! surface inputs + integer, intent(out) :: rc !! return code, negative indicates failure + + integer :: icol !! column index + integer :: ibin !! bin index + real(r8), pointer, dimension(:,:) :: soacm !! aerosol tendency due to gas-aerosol exchange kg/kg/s + real(r8), pointer, dimension(:,:) :: soapt !! aerosol tendency due to no2 photolysis kg/kg/s + character(len=16) :: binname !! names bins + real(r8) :: aerclddiag(pcols,MAXCLDAERDIAG) !! the before timestep cloudborne aerosol diags + integer :: i + integer :: icnst !! constituent index + integer :: ienconc !! concentration element index + integer :: ncore !! number of cores + integer :: icorelem(NELEM) !! core element index + real(r8) :: mair(pver) !! Mass of air column (kg/m2) + real(r8) :: pureso4(pcols) !! pure sulfate (kg/m2) + real(r8) :: mixso4(pcols) !! mix sulfate (kg/m2) + real(r8) :: cprflux(pcols) !! Surface Flux pure sulfate (kg/m2/s) + real(r8) :: cmxflux(pcols) !! Surface Flux mix sulfate (kg/m2/s) + real(r8) :: h2so4(pcols) !! H2SO4 gas (kg/m2) + real(r8) :: so2(pcols) !! SO2 gas (kg/m2) + real(r8) :: bdbc(pcols) !! Burden BC sulfate (kg/m2) + real(r8) :: bddust(pcols) !! Burden dust (kg/m2) + real(r8) :: bdoc(pcols) !! Burden OC sulfate (kg/m2) + real(r8) :: bdsalt(pcols) !! Burden SALT sulfate (kg/m2) + real(r8) :: bdsoa(pcols) !! Burden SOA sulfate (kg/m2) + character(len=16) :: shortname + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_OutputDiagnostics + +end module carma_model_mod diff --git a/src/physics/carma/models/sulfate/carma_model_mod.F90 b/src/physics/carma/models/sulfate/carma_model_mod.F90 index abf98d1820..c19e013891 100644 --- a/src/physics/carma/models/sulfate/carma_model_mod.F90 +++ b/src/physics/carma/models/sulfate/carma_model_mod.F90 @@ -38,15 +38,19 @@ module carma_model_mod private ! Declare the public methods. - public CARMA_DefineModel - public CARMA_Detrain - public CARMA_DiagnoseBins - public CARMA_DiagnoseBulk - public CARMA_EmitParticle - public CARMA_InitializeModel - public CARMA_InitializeParticle - public CARMA_WetDeposition - + public CARMAMODEL_CalculateCloudborneDiagnostics + public CARMAMODEL_CreateOpticsFile + public CARMAMODEL_DefineModel + public CARMAMODEL_Detrain + public CARMAMODEL_DiagnoseBins + public CARMAMODEL_DiagnoseBulk + public CARMAMODEL_EmitParticle + public CARMAMODEL_InitializeModel + public CARMAMODEL_InitializeParticle + public CARMAMODEL_OutputBudgetDiagnostics + public CARMAMODEL_OutputCloudborneDiagnostics + public CARMAMODEL_OutputDiagnostics + public CARMAMODEL_WetDeposition ! Declare public constants integer, public, parameter :: NGROUP = 1 !! Number of particle groups @@ -59,6 +63,10 @@ module carma_model_mod integer, public, parameter :: NMIE_RH = 8 !! Number of relative humidities for mie calculations real(kind=f), public :: mie_rh(NMIE_RH) + integer, public, parameter :: NMIE_WTP = 0 !! Number of weight percents for mie calculations + real(kind=f), public :: mie_wtp(NMIE_WTP) + integer, public, parameter :: NREFIDX = 1 !! Number of refractive indices per element + ! Defines whether the groups should undergo deep convection in phase 1 or phase 2. ! Water vapor and cloud particles are convected in phase 1, while all other constituents ! are done in phase 2. @@ -90,7 +98,7 @@ module carma_model_mod !! !! @version May-2009 !! @author Chuck Bardeen - subroutine CARMA_DefineModel(carma, rc) + subroutine CARMAMODEL_DefineModel(carma, rc) use physics_buffer, only: pbuf_add_field, dtype_r8 type(carma_type), intent(inout) :: carma !! the carma object @@ -172,7 +180,7 @@ subroutine CARMA_DefineModel(carma, rc) call pbuf_add_field('VOLC_MMR', 'global', dtype_r8, (/pcols, pver/), ipbuf4so4mmr) endif - end subroutine CARMA_DefineModel + end subroutine CARMAMODEL_DefineModel !! Defines all the CARMA components (groups, elements, solutes and gases) and process @@ -182,7 +190,7 @@ end subroutine CARMA_DefineModel !! @author Chuck Bardeen !! !! @see CARMASTATE_SetDetrain - subroutine CARMA_Detrain(carma, cstate, cam_in, dlf, state, icol, dt, rc, rliq, prec_str, snow_str, & + subroutine CARMAMODEL_Detrain(carma, cstate, cam_in, dlf, state, icol, dt, rc, rliq, prec_str, snow_str, & tnd_qsnow, tnd_nsnow) use camsrfexch, only: cam_in_t use physconst, only: latice, latvap, cpair @@ -207,14 +215,14 @@ subroutine CARMA_Detrain(carma, cstate, cam_in, dlf, state, icol, dt, rc, rliq, rc = RC_OK return - end subroutine CARMA_Detrain + end subroutine CARMAMODEL_Detrain !! For diagnostic groups, sets up up the CARMA bins based upon the CAM state. !! !! @version July-2009 !! @author Chuck Bardeen - subroutine CARMA_DiagnoseBins(carma, cstate, state, pbuf, icol, dt, rc, rliq, prec_str, snow_str) + subroutine CARMAMODEL_DiagnoseBins(carma, cstate, state, pbuf, icol, dt, rc, rliq, prec_str, snow_str) use time_manager, only: is_first_step implicit none @@ -240,14 +248,14 @@ subroutine CARMA_DiagnoseBins(carma, cstate, state, pbuf, icol, dt, rc, rliq, pr ! code to determine the mass in each bin from the CAM state. return - end subroutine CARMA_DiagnoseBins + end subroutine CARMAMODEL_DiagnoseBins !! For diagnostic groups, determines the tendencies on the CAM state from the CARMA bins. !! !! @version July-2009 !! @author Chuck Bardeen - subroutine CARMA_DiagnoseBulk(carma, cstate, cam_out, state, pbuf, ptend, icol, dt, rc, rliq, prec_str, snow_str, & + subroutine CARMAMODEL_DiagnoseBulk(carma, cstate, cam_out, state, pbuf, ptend, icol, dt, rc, rliq, prec_str, snow_str, & prec_sed, snow_sed, tnd_qsnow, tnd_nsnow, re_ice) use camsrfexch, only: cam_out_t use physics_buffer, only: pbuf_get_field @@ -325,7 +333,7 @@ subroutine CARMA_DiagnoseBulk(carma, cstate, cam_out, state, pbuf, ptend, icol, end if - end subroutine CARMA_DiagnoseBulk + end subroutine CARMAMODEL_DiagnoseBulk !! Calculates the emissions for CARMA aerosol particles. By default, there is no @@ -334,7 +342,7 @@ end subroutine CARMA_DiagnoseBulk !! !! @author Tianyi Fan, Chuck Bardeen !! @version Dec-2010 - subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tendency, surfaceFlux, rc) + subroutine CARMAMODEL_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tendency, surfaceFlux, pbuf, rc) use shr_kind_mod, only: r8 => shr_kind_r8 use ppgrid, only: pcols, pver use physics_types, only: physics_state @@ -353,6 +361,7 @@ subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tend type(cam_in_t), intent(in) :: cam_in !! surface inputs real(r8), intent(out) :: tendency(pcols, pver) !! constituent tendency (kg/kg/s) real(r8), intent(out) :: surfaceFlux(pcols) !! constituent surface flux (kg/m^2/s) + type(physics_buffer_desc), pointer :: pbuf(:) !! physics buffer integer, intent(out) :: rc !! return code, negative indicates failure ! Default return code. @@ -365,7 +374,7 @@ subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tend tendency = 0._r8 return - end subroutine CARMA_EmitParticle + end subroutine CARMAMODEL_EmitParticle !! Allows the model to perform its own initialization in addition to what is done @@ -373,20 +382,21 @@ end subroutine CARMA_EmitParticle !! !! @author Chuck Bardeen !! @version May-2009 - subroutine CARMA_InitializeModel(carma, lq_carma, rc) + subroutine CARMAMODEL_InitializeModel(carma, lq_carma, pbuf2d, rc) use constituents, only : pcnst implicit none type(carma_type), intent(in) :: carma !! the carma object logical, intent(inout) :: lq_carma(pcnst) !! flags to indicate whether the constituent !! could have a CARMA tendency + type(physics_buffer_desc), pointer :: pbuf2d(:,:) integer, intent(out) :: rc !! return code, negative indicates failure ! Default return code. rc = RC_OK return - end subroutine CARMA_InitializeModel + end subroutine CARMAMODEL_InitializeModel !! Sets the initial condition for CARMA aerosol particles. By default, there are no @@ -398,7 +408,7 @@ end subroutine CARMA_InitializeModel !! !! @author Chuck Bardeen !! @version May-2009 - subroutine CARMA_InitializeParticle(carma, ielem, ibin, latvals, lonvals, mask, q, rc) + subroutine CARMAMODEL_InitializeParticle(carma, ielem, ibin, latvals, lonvals, mask, q, rc) use shr_kind_mod, only: r8 => shr_kind_r8 implicit none @@ -420,7 +430,49 @@ subroutine CARMA_InitializeParticle(carma, ielem, ibin, latvals, lonvals, mask, ! NOTE: Initialized to 0. by the caller, so nothing needs to be done. return - end subroutine CARMA_InitializeParticle + end subroutine CARMAMODEL_InitializeParticle + + + !! This routine is an extension of CARMA_CreateOpticsFile() that allows for + !! model specific tables to be created in addition to the model independent + !! methods that are in carma_intr.F90. + !! + !! The opticsType that is specified for the group determines how the optical + !! properties will be generated for that group. Each group can use a different + !! optics method if needed. Refractive indices need for these calculation are + !! are specified in the group's elements rather than at the group level. This + !! allows various mixing approaches to be used to determine the refractive index + !! for the particle as a whole. If the refractive index for water is needed, + !! it is specific the the CARMAGAS object for H2O. + subroutine CARMAMODEL_CreateOpticsFile(carma, igroup, opticsType, rc) + + implicit none + + type(carma_type), intent(inout) :: carma !! the carma object + integer, intent(in) :: igroup !! group identifier + integer, intent(in) :: opticsType !! optics type (see I_OPTICS_... in carma_enums.F90) + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Local variables + logical :: do_mie + integer :: cnsttype ! constituent type + + ! Assume success. + rc = 0 + + ! What type of calculation is needed for this group? + ! + ! NOTE: Some of these calculations generate optical properties as single mass + ! coefficients, while others are lookup tables designed around multiple + ! dimensions. + select case (opticsType) + + case default + call endrun('carma_CreateOpticsFile:: Unknown optics type.') + end select + + return + end subroutine CARMAMODEL_CreateOpticsFile !! Called after wet deposition has been performed. Allows the specific model to add @@ -428,7 +480,7 @@ end subroutine CARMA_InitializeParticle !! !! @version July-2011 !! @author Chuck Bardeen - subroutine CARMA_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) + subroutine CARMAMODEL_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) use camsrfexch, only: cam_out_t implicit none @@ -447,6 +499,94 @@ subroutine CARMA_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) rc = RC_OK return - end subroutine CARMA_WetDeposition + end subroutine CARMAMODEL_WetDeposition + + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_CalculateCloudborneDiagnostics(carma, state, pbuf, aerclddiag, rc) + + type(carma_type), intent(in) :: carma !! the carma object + type(physics_state), intent(in) :: state !! Physics state variables - before pname + type(physics_buffer_desc), pointer, intent(in) :: pbuf(:) !! physics buffer + real(r8), intent(out) :: aerclddiag(pcols,MAXCLDAERDIAG) !! the total cloudborne aerosols, supports up to MAXCLDAERDIAG different values + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_CalculateCloudborneDiagnostics + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_OutputBudgetDiagnostics(carma, icnst4elem, icnst4gas, state, ptend, old_cflux, cflux, dt, pname, rc) + use cam_history, only: outfld + use constituents, only: pcnst, cnst_get_ind + + type(carma_type), intent(in) :: carma !! the carma object + integer, intent(in) :: icnst4elem(NELEM, NBIN) !! constituent index for a carma element + integer, intent(in) :: icnst4gas(NGAS) !! constituent index for a carma gas + type(physics_state), intent(in) :: state !! Physics state variables - before pname + type(physics_ptend), intent(in) :: ptend !! indivdual parameterization tendencies + real(r8) :: old_cflux(pcols,pcnst) !! cam_in%clfux from before the timestep_tend + real(r8) :: cflux(pcols,pcnst) !! cam_in%clfux from after the timestep_tend + real(r8), intent(in) :: dt !! timestep (s) + character(*), intent(in) :: pname !! short name of the physics package + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_OutputBudgetDiagnostics + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_OutputCloudborneDiagnostics(carma, state, pbuf, dt, pname, oldaerclddiag, rc) + use cam_history, only: outfld + + type(carma_type), intent(in) :: carma !! the carma object + type(physics_state), intent(in) :: state !! Physics state variables - before CARMA + type(physics_buffer_desc), pointer, intent(in) :: pbuf(:) !! physics buffer + real(r8), intent(in) :: dt !! timestep (s) + character(*), intent(in) :: pname !! short name of the physics package + real(r8), intent(in ) :: oldaerclddiag(pcols,MAXCLDAERDIAG) !! the before timestep cloudborne aerosol diags + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_OutputCloudborneDiagnostics + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_OutputDiagnostics(carma, icnst4elem, state, ptend, pbuf, cam_in, rc) + use cam_history, only: outfld + use constituents, only: cnst_get_ind + use camsrfexch, only: cam_in_t + + type(carma_type), intent(in) :: carma !! the carma object + integer, intent(in) :: icnst4elem(NELEM, NBIN) !! constituent index for a carma element + type(physics_state), intent(in) :: state !! Physics state variables - before CARMA + type(physics_ptend), intent(in) :: ptend !! indivdual parameterization tendencies + type(physics_buffer_desc), pointer, intent(in) :: pbuf(:) !! physics buffer + type(cam_in_t), intent(in) :: cam_in !! surface inputs + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_OutputDiagnostics -end module +end module carma_model_mod diff --git a/src/physics/carma/models/test_detrain/carma_model_mod.F90 b/src/physics/carma/models/test_detrain/carma_model_mod.F90 index 16e6cb431f..fde34f8b20 100644 --- a/src/physics/carma/models/test_detrain/carma_model_mod.F90 +++ b/src/physics/carma/models/test_detrain/carma_model_mod.F90 @@ -472,4 +472,4 @@ subroutine CARMA_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) return end subroutine CARMA_WetDeposition -end module +end module carma_model_mod diff --git a/src/physics/carma/models/test_growth/carma_model_mod.F90 b/src/physics/carma/models/test_growth/carma_model_mod.F90 index ad57aed469..5b4a2b6ac7 100644 --- a/src/physics/carma/models/test_growth/carma_model_mod.F90 +++ b/src/physics/carma/models/test_growth/carma_model_mod.F90 @@ -10,10 +10,10 @@ !! the initial conditions of the particles. Each realization of CARMA !! microphysics has its own version of this file. !! -!! This file is a simple test case involving one group of dust particles and -!! 8 size bins. Optical properties are calculated, assuming a constant refractive -!! index of (1.55, 4e-3). The particles are not subject to particle swelling, but -!! do coagulate. +!! This file is a simple test case involving two groups: sulfate condensation nuclei +!! and ice particles. The sulfates are prescribed and the ice is prognostics. This +!! test exercises the nucleation and growth code. THe particles are sedimented, but +!! do not coagulate. !! !! @version May-2009 !! @author Chuck Bardeen @@ -43,14 +43,19 @@ module carma_model_mod private ! Declare the public methods. - public CARMA_DefineModel - public CARMA_Detrain - public CARMA_DiagnoseBins - public CARMA_DiagnoseBulk - public CARMA_EmitParticle - public CARMA_InitializeModel - public CARMA_InitializeParticle - public CARMA_WetDeposition + public CARMAMODEL_CalculateCloudborneDiagnostics + public CARMAMODEL_CreateOpticsFile + public CARMAMODEL_DefineModel + public CARMAMODEL_Detrain + public CARMAMODEL_DiagnoseBins + public CARMAMODEL_DiagnoseBulk + public CARMAMODEL_EmitParticle + public CARMAMODEL_InitializeModel + public CARMAMODEL_InitializeParticle + public CARMAMODEL_OutputBudgetDiagnostics + public CARMAMODEL_OutputCloudborneDiagnostics + public CARMAMODEL_OutputDiagnostics + public CARMAMODEL_WetDeposition ! Declare public constants integer, public, parameter :: NGROUP = 2 !! Number of particle groups @@ -63,6 +68,10 @@ module carma_model_mod integer, public, parameter :: NMIE_RH = 8 !! Number of relative humidities for mie calculations real(kind=f), public :: mie_rh(NMIE_RH) + integer, public, parameter :: NMIE_WTP = 0 !! Number of weight percents for mie calculations + real(kind=f), public :: mie_wtp(NMIE_WTP) + integer, public, parameter :: NREFIDX = 1 !! Number of refractive indices per element + ! Defines whether the groups should undergo deep convection in phase 1 or phase 2. ! Water vapor and cloud particles are convected in phase 1, while all other constituents ! are done in phase 2. @@ -93,7 +102,7 @@ module carma_model_mod !! !! @version May-2009 !! @author Chuck Bardeen - subroutine CARMA_DefineModel(carma, rc) + subroutine CARMAMODEL_DefineModel(carma, rc) type(carma_type), intent(inout) :: carma !! the carma object integer, intent(out) :: rc !! return code, negative indicates failure @@ -118,11 +127,11 @@ subroutine CARMA_DefineModel(carma, rc) call CARMAGROUP_Create(carma, I_GRP_CRCN, "Sulfate CN", rmin_cn, 4.0_f, I_SPHERE, 1._f, .false., & rc, shortname="CRCN", cnsttype=I_CNSTTYPE_DIAGNOSTIC, & do_vtran=.false.) - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMAGROUP_Create failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMAGROUP_Create failed.') call CARMAGROUP_Create(carma, I_GRP_CRICE, "Ice", rmin_ice, 2.8_f, I_HEXAGON, 1._f / 6._f, .true., & rc, shortname="CRICE", ifallrtn=I_FALLRTN_STD_SHAPE) - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMAGROUP_Create failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMAGROUP_Create failed.') @@ -132,30 +141,30 @@ subroutine CARMA_DefineModel(carma, rc) ! should be 6 characters or less and without spaces. call CARMAELEMENT_Create(carma, I_ELEM_CRCN, I_GRP_CRCN, "Sulfate CN", RHO_CN, & I_INVOLATILE, I_H2SO4, rc, shortname="CRCN", isolute=I_SOL_CRH2SO4) - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMAElement_Create failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMAElement_Create failed.') call CARMAELEMENT_Create(carma, I_ELEM_CRICE, I_GRP_CRICE, "Ice", RHO_I, & I_VOLATILE, I_ICE, rc, shortname="CRICE") - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMAElement_Create failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMAElement_Create failed.') call CARMAELEMENT_Create(carma, I_ELEM_CRCORE, I_GRP_CRICE, "Core Mass", RHO_CN, & I_COREMASS, I_H2SO4, rc, shortname="CRCORE", isolute=1) - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMAElement_Create failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMAElement_Create failed.') ! Define the Solutes call CARMASOLUTE_Create(carma, I_SOL_CRH2SO4, "Sulfuric Acid", 2, 98._f, 1.38_f, rc, shortname="CRH2SO4") - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMASOLUTE_Create failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMASOLUTE_Create failed.') ! Define the Gases call CARMAGAS_Create(carma, I_GAS_H2O, "Water Vapor", WTMOL_H2O, I_VAPRTN_H2O_MURPHY2005, I_GCOMP_H2O, rc, shortname="Q") - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMAGAS_Create failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMAGAS_Create failed.') ! Define the Processes call CARMA_AddGrowth(carma, I_ELEM_CRICE, I_GAS_H2O, rc) - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMA_AddGrowth failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMA_AddGrowth failed.') ! NOTE: For now, assume the latent heat for nucleation is the latent of of fusion of ! water, using the CAM constant (scaled from J/kg to erg/g). @@ -165,10 +174,10 @@ subroutine CARMA_DefineModel(carma, rc) ! the gas associated with nucleation is accounted for. call CARMA_AddNucleation(carma, I_ELEM_CRCN, I_ELEM_CRCORE, & I_AERFREEZE + I_AF_KOOP_2000, 0._f, rc, igas=I_GAS_H2O, ievp2elem=I_ELEM_CRCN) - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMA_AddNucleation failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMA_AddNucleation failed.') return - end subroutine CARMA_DefineModel + end subroutine CARMAMODEL_DefineModel !! Defines all the CARMA components (groups, elements, solutes and gases) and process @@ -178,7 +187,7 @@ end subroutine CARMA_DefineModel !! @author Chuck Bardeen !! !! @see CARMASTATE_SetDetrain - subroutine CARMA_Detrain(carma, cstate, cam_in, dlf, state, icol, dt, rc, rliq, prec_str, snow_str, & + subroutine CARMAMODEL_Detrain(carma, cstate, cam_in, dlf, state, icol, dt, rc, rliq, prec_str, snow_str, & tnd_qsnow, tnd_nsnow) use camsrfexch, only: cam_in_t use physconst, only: latice, latvap, cpair @@ -203,14 +212,14 @@ subroutine CARMA_Detrain(carma, cstate, cam_in, dlf, state, icol, dt, rc, rliq, rc = RC_OK return - end subroutine CARMA_Detrain + end subroutine CARMAMODEL_Detrain !! For diagnostic groups, sets up up the CARMA bins based upon the CAM state. !! !! @version July-2009 !! @author Chuck Bardeen - subroutine CARMA_DiagnoseBins(carma, cstate, state, pbuf, icol, dt, rc, rliq, prec_str, snow_str) + subroutine CARMAMODEL_DiagnoseBins(carma, cstate, state, pbuf, icol, dt, rc, rliq, prec_str, snow_str) use time_manager, only: is_first_step implicit none @@ -249,7 +258,7 @@ subroutine CARMA_DiagnoseBins(carma, cstate, state, pbuf, icol, dt, rc, rliq, pr ! Get the air density. call CARMASTATE_GetState(cstate, rc, rhoa_wet=rhoa_wet) - if (rc < RC_OK) call endrun('CARMA_DiagnoseBins::CARMASTATE_GetState failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DiagnoseBins::CARMASTATE_GetState failed.') ! Use a fixed sulfate size distribution. By doing this as a diagnostic group, ! the constituents for the sulfate bins do not need to be advected, which @@ -258,7 +267,7 @@ subroutine CARMA_DiagnoseBins(carma, cstate, state, pbuf, icol, dt, rc, rliq, pr ielem = 1 call CARMAGROUP_Get(carma, igroup, rc, r=r, dr=dr, rmass=rmass) - if (rc < RC_OK) call endrun('CARMA_DiagnoseBins::CARMAGROUP_Get failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DiagnoseBins::CARMAGROUP_Get failed.') arg1(:) = n * dr(:) / (sqrt(2._f*PI) * r(:) * log(rsig)) arg2(:) = -((log(r(:)) - log(r0))**2) / (2._f*(log(rsig))**2) @@ -268,18 +277,18 @@ subroutine CARMA_DiagnoseBins(carma, cstate, state, pbuf, icol, dt, rc, rliq, pr do ibin = 1, NBIN mmr(ibin, :) = rhop(ibin) / rhoa_wet(:) call CARMASTATE_SetBin(cstate, ielem, ibin, mmr(ibin, :), rc) - if (rc < RC_OK) call endrun('CARMA_DiagnoseBins::CARMAGROUP_SetBin failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DiagnoseBins::CARMAGROUP_SetBin failed.') end do return - end subroutine CARMA_DiagnoseBins + end subroutine CARMAMODEL_DiagnoseBins !! For diagnostic groups, determines the tendencies on the CAM state from the CARMA bins. !! !! @version July-2009 !! @author Chuck Bardeen - subroutine CARMA_DiagnoseBulk(carma, cstate, cam_out, state, pbuf, ptend, icol, dt, rc, rliq, prec_str, snow_str, & + subroutine CARMAMODEL_DiagnoseBulk(carma, cstate, cam_out, state, pbuf, ptend, icol, dt, rc, rliq, prec_str, snow_str, & prec_sed, snow_sed, tnd_qsnow, tnd_nsnow, re_ice) use camsrfexch, only: cam_out_t @@ -310,7 +319,7 @@ subroutine CARMA_DiagnoseBulk(carma, cstate, cam_out, state, pbuf, ptend, icol, ! code to determine the bulk mass from the CARMA state. return - end subroutine CARMA_DiagnoseBulk + end subroutine CARMAMODEL_DiagnoseBulk !! Calculates the emissions for CARMA aerosol particles. By default, there is no @@ -319,7 +328,7 @@ end subroutine CARMA_DiagnoseBulk !! !! @author Chuck Bardeen !! @version May-2009 - subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tendency, surfaceFlux, rc) + subroutine CARMAMODEL_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tendency, surfaceFlux, pbuf, rc) use shr_kind_mod, only: r8 => shr_kind_r8 use ppgrid, only: pcols, pver use physics_types, only: physics_state @@ -338,6 +347,7 @@ subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tend type(cam_in_t), intent(in) :: cam_in !! surface inputs real(r8), intent(out) :: tendency(pcols, pver) !! constituent tendency (kg/kg/s) real(r8), intent(out) :: surfaceFlux(pcols) !! constituent surface flux (kg/m^2/s) + type(physics_buffer_desc), pointer :: pbuf(:) !! physics buffer integer, intent(out) :: rc !! return code, negative indicates failure integer :: ncol ! number of columns in chunk @@ -370,7 +380,7 @@ subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tend tendency(:ncol, :pver) = 0.0_r8 return - end subroutine CARMA_EmitParticle + end subroutine CARMAMODEL_EmitParticle !! Allows the model to perform its own initialization in addition to what is done @@ -381,13 +391,14 @@ end subroutine CARMA_EmitParticle !! !! @author Chuck Bardeen !! @version May-2009 - subroutine CARMA_InitializeModel(carma, lq_carma, rc) + subroutine CARMAMODEL_InitializeModel(carma, lq_carma, pbuf2d, rc) use constituents, only : pcnst implicit none type(carma_type), intent(in) :: carma !! the carma object logical, intent(inout) :: lq_carma(pcnst) !! flags to indicate whether the constituent !! could have a CARMA tendency + type(physics_buffer_desc), pointer :: pbuf2d(:,:) integer, intent(out) :: rc !! return code, negative indicates failure ! Default return code. @@ -396,7 +407,7 @@ subroutine CARMA_InitializeModel(carma, lq_carma, rc) ! Add initialization here. return - end subroutine CARMA_InitializeModel + end subroutine CARMAMODEL_InitializeModel !! Sets the initial condition for CARMA aerosol particles. By default, there are no @@ -408,7 +419,7 @@ end subroutine CARMA_InitializeModel !! !! @author Chuck Bardeen !! @version May-2009 - subroutine CARMA_InitializeParticle(carma, ielem, ibin, latvals, lonvals, mask, q, rc) + subroutine CARMAMODEL_InitializeParticle(carma, ielem, ibin, latvals, lonvals, mask, q, rc) use shr_kind_mod, only: r8 => shr_kind_r8 use pmgrid, only: plev @@ -431,31 +442,65 @@ subroutine CARMA_InitializeParticle(carma, ielem, ibin, latvals, lonvals, mask, ! Put a horizontally uniform layer of the smallest bin size ! in the model. if (ibin == 1) then - if (ielem == I_ELEM_CRICE) then - where(mask) - q(:, plev/4) = 100e-7_r8 ! 1/4 - end where - end if - if (ielem == I_ELEM_CRCORE) then - where(mask) - q(:, plev/4) = 100e-9_r8 ! 1/4 - end where - end if + where(mask) +! q(:, 1) = 100e-9_r8 ! top + q(:, plev/4) = 100e-9_r8 ! 1/4 ! q(:, plev/2) = 100e-9_r8 ! middle ! q(:, 3*plev/4) = 100e-9_r8 ! 3/4 ! q(:, plev-1) = 100e-9_r8 ! bottom + end where end if return - end subroutine CARMA_InitializeParticle + end subroutine CARMAMODEL_InitializeParticle + + !! This routine is an extension of CARMA_CreateOpticsFile() that allows for + !! model specific tables to be created in addition to the model independent + !! methods that are in carma_intr.F90. + !! + !! The opticsType that is specified for the group determines how the optical + !! properties will be generated for that group. Each group can use a different + !! optics method if needed. Refractive indices need for these calculation are + !! are specified in the group's elements rather than at the group level. This + !! allows various mixing approaches to be used to determine the refractive index + !! for the particle as a whole. If the refractive index for water is needed, + !! it is specific the the CARMAGAS object for H2O. + subroutine CARMAMODEL_CreateOpticsFile(carma, igroup, opticsType, rc) + + implicit none + + type(carma_type), intent(inout) :: carma !! the carma object + integer, intent(in) :: igroup !! group identifier + integer, intent(in) :: opticsType !! optics type (see I_OPTICS_... in carma_enums.F90) + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Local variables + logical :: do_mie + integer :: cnsttype ! constituent type + + ! Assume success. + rc = 0 + + ! What type of calculation is needed for this group? + ! + ! NOTE: Some of these calculations generate optical properties as single mass + ! coefficients, while others are lookup tables designed around multiple + ! dimensions. + select case (opticsType) + case default + call endrun('carma_CreateOpticsFile:: Unknown optics type.') + end select + + return + end subroutine CARMAMODEL_CreateOpticsFile !! Called after wet deposition has been performed. Allows the specific model to add !! wet deposition of CARMA aerosols to the aerosols being communicated to the surface. !! !! @version July-2011 !! @author Chuck Bardeen - subroutine CARMA_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) + subroutine CARMAMODEL_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) use camsrfexch, only: cam_out_t implicit none @@ -474,6 +519,94 @@ subroutine CARMA_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) rc = RC_OK return - end subroutine CARMA_WetDeposition + end subroutine CARMAMODEL_WetDeposition + + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_CalculateCloudborneDiagnostics(carma, state, pbuf, aerclddiag, rc) + + type(carma_type), intent(in) :: carma !! the carma object + type(physics_state), intent(in) :: state !! Physics state variables - before pname + type(physics_buffer_desc), pointer, intent(in) :: pbuf(:) !! physics buffer + real(r8), intent(out) :: aerclddiag(pcols,MAXCLDAERDIAG) !! the total cloudborne aerosols, supports up to MAXCLDAERDIAG different values + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_CalculateCloudborneDiagnostics + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_OutputBudgetDiagnostics(carma, icnst4elem, icnst4gas, state, ptend, old_cflux, cflux, dt, pname, rc) + use cam_history, only: outfld + use constituents, only: pcnst, cnst_get_ind + + type(carma_type), intent(in) :: carma !! the carma object + integer, intent(in) :: icnst4elem(NELEM, NBIN) !! constituent index for a carma element + integer, intent(in) :: icnst4gas(NGAS) !! constituent index for a carma gas + type(physics_state), intent(in) :: state !! Physics state variables - before pname + type(physics_ptend), intent(in) :: ptend !! indivdual parameterization tendencies + real(r8) :: old_cflux(pcols,pcnst) !! cam_in%clfux from before the timestep_tend + real(r8) :: cflux(pcols,pcnst) !! cam_in%clfux from after the timestep_tend + real(r8), intent(in) :: dt !! timestep (s) + character(*), intent(in) :: pname !! short name of the physics package + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_OutputBudgetDiagnostics + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_OutputCloudborneDiagnostics(carma, state, pbuf, dt, pname, oldaerclddiag, rc) + use cam_history, only: outfld + + type(carma_type), intent(in) :: carma !! the carma object + type(physics_state), intent(in) :: state !! Physics state variables - before CARMA + type(physics_buffer_desc), pointer, intent(in) :: pbuf(:) !! physics buffer + real(r8), intent(in) :: dt !! timestep (s) + character(*), intent(in) :: pname !! short name of the physics package + real(r8), intent(in ) :: oldaerclddiag(pcols,MAXCLDAERDIAG) !! the before timestep cloudborne aerosol diags + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_OutputCloudborneDiagnostics + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_OutputDiagnostics(carma, icnst4elem, state, ptend, pbuf, cam_in, rc) + use cam_history, only: outfld + use constituents, only: cnst_get_ind + use camsrfexch, only: cam_in_t + + type(carma_type), intent(in) :: carma !! the carma object + integer, intent(in) :: icnst4elem(NELEM, NBIN) !! constituent index for a carma element + type(physics_state), intent(in) :: state !! Physics state variables - before CARMA + type(physics_ptend), intent(in) :: ptend !! indivdual parameterization tendencies + type(physics_buffer_desc), pointer, intent(in) :: pbuf(:) !! physics buffer + type(cam_in_t), intent(in) :: cam_in !! surface inputs + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_OutputDiagnostics -end module +end module carma_model_mod diff --git a/src/physics/carma/models/test_passive/carma_model_mod.F90 b/src/physics/carma/models/test_passive/carma_model_mod.F90 index 12f4a6168e..150f1d8a5f 100644 --- a/src/physics/carma/models/test_passive/carma_model_mod.F90 +++ b/src/physics/carma/models/test_passive/carma_model_mod.F90 @@ -42,14 +42,19 @@ module carma_model_mod private ! Declare the public methods. - public CARMA_DefineModel - public CARMA_Detrain - public CARMA_DiagnoseBins - public CARMA_DiagnoseBulk - public CARMA_EmitParticle - public CARMA_InitializeModel - public CARMA_InitializeParticle - public CARMA_WetDeposition + public CARMAMODEL_CalculateCloudborneDiagnostics + public CARMAMODEL_CreateOpticsFile + public CARMAMODEL_DefineModel + public CARMAMODEL_Detrain + public CARMAMODEL_DiagnoseBins + public CARMAMODEL_DiagnoseBulk + public CARMAMODEL_EmitParticle + public CARMAMODEL_InitializeModel + public CARMAMODEL_InitializeParticle + public CARMAMODEL_OutputBudgetDiagnostics + public CARMAMODEL_OutputCloudborneDiagnostics + public CARMAMODEL_OutputDiagnostics + public CARMAMODEL_WetDeposition ! Declare public constants integer, public, parameter :: NGROUP = 1 !! Number of particle groups @@ -62,6 +67,10 @@ module carma_model_mod integer, public, parameter :: NMIE_RH = 8 !! Number of relative humidities for mie calculations real(kind=f), public :: mie_rh(NMIE_RH) + integer, public, parameter :: NMIE_WTP = 0 !! Number of weight percents for mie calculations + real(kind=f), public :: mie_wtp(NMIE_WTP) + integer, public, parameter :: NREFIDX = 1 !! Number of refractive indices per element + ! Defines whether the groups should undergo deep convection in phase 1 or phase 2. ! Water vapor and cloud particles are convected in phase 1, while all other constituents ! are done in phase 2. @@ -79,7 +88,7 @@ module carma_model_mod !! !! @version May-2009 !! @author Chuck Bardeen - subroutine CARMA_DefineModel(carma, rc) + subroutine CARMAMODEL_DefineModel(carma, rc) type(carma_type), intent(inout) :: carma !! the carma object integer, intent(out) :: rc !! return code, negative indicates failure @@ -101,7 +110,7 @@ subroutine CARMA_DefineModel(carma, rc) call CARMAGROUP_Create(carma, 1, "Dust", rmin, vmrat, I_SPHERE, 1._f, .false., & rc, do_wetdep=.true., do_drydep=.true., solfac=0.15_f, & scavcoef=0.1_f, shortname="DUST") - if (rc < 0) call endrun('CARMA_DefineModel::CARMA_AddGroup failed.') + if (rc < 0) call endrun('CARMAMODEL_DefineModel::CARMA_AddGroup failed.') ! Define the Elements @@ -109,7 +118,7 @@ subroutine CARMA_DefineModel(carma, rc) ! NOTE: For CAM, the optional shortname needs to be provided for the group. These names ! should be 6 characters or less and without spaces. call CARMAELEMENT_Create(carma, 1, 1, "Dust", RHO_DUST, I_INVOLATILE, I_DUST, rc, shortname="DUST") - if (rc < 0) call endrun('CARMA_DefineModel::CARMA_AddElement failed.') + if (rc < 0) call endrun('CARMAMODEL_DefineModel::CARMA_AddElement failed.') ! Define the Solutes @@ -120,10 +129,10 @@ subroutine CARMA_DefineModel(carma, rc) ! Define the Processes call CARMA_AddCoagulation(carma, 1, 1, 1, I_COLLEC_DATA, rc) - if (rc < 0) call endrun('CARMA_DefineModel::CARMA_AddCoagulation failed.') + if (rc < 0) call endrun('CARMAMODEL_DefineModel::CARMA_AddCoagulation failed.') return - end subroutine CARMA_DefineModel + end subroutine CARMAMODEL_DefineModel !! Defines all the CARMA components (groups, elements, solutes and gases) and process @@ -133,7 +142,7 @@ end subroutine CARMA_DefineModel !! @author Chuck Bardeen !! !! @see CARMASTATE_SetDetrain - subroutine CARMA_Detrain(carma, cstate, cam_in, dlf, state, icol, dt, rc, rliq, prec_str, snow_str, & + subroutine CARMAMODEL_Detrain(carma, cstate, cam_in, dlf, state, icol, dt, rc, rliq, prec_str, snow_str, & tnd_qsnow, tnd_nsnow) use camsrfexch, only: cam_in_t use physconst, only: latice, latvap, cpair @@ -158,14 +167,14 @@ subroutine CARMA_Detrain(carma, cstate, cam_in, dlf, state, icol, dt, rc, rliq, rc = RC_OK return - end subroutine CARMA_Detrain + end subroutine CARMAMODEL_Detrain !! For diagnostic groups, sets up up the CARMA bins based upon the CAM state. !! !! @version July-2009 !! @author Chuck Bardeen - subroutine CARMA_DiagnoseBins(carma, cstate, state, pbuf, icol, dt, rc, rliq, prec_str, snow_str) + subroutine CARMAMODEL_DiagnoseBins(carma, cstate, state, pbuf, icol, dt, rc, rliq, prec_str, snow_str) use time_manager, only: is_first_step implicit none @@ -191,14 +200,14 @@ subroutine CARMA_DiagnoseBins(carma, cstate, state, pbuf, icol, dt, rc, rliq, pr ! code to determine the mass in each bin from the CAM state. return - end subroutine CARMA_DiagnoseBins + end subroutine CARMAMODEL_DiagnoseBins !! For diagnostic groups, determines the tendencies on the CAM state from the CARMA bins. !! !! @version July-2009 !! @author Chuck Bardeen - subroutine CARMA_DiagnoseBulk(carma, cstate, cam_out, state, pbuf, ptend, icol, dt, rc, rliq, prec_str, snow_str, & + subroutine CARMAMODEL_DiagnoseBulk(carma, cstate, cam_out, state, pbuf, ptend, icol, dt, rc, rliq, prec_str, snow_str, & prec_sed, snow_sed, tnd_qsnow, tnd_nsnow, re_ice) use camsrfexch, only: cam_out_t @@ -229,7 +238,7 @@ subroutine CARMA_DiagnoseBulk(carma, cstate, cam_out, state, pbuf, ptend, icol, ! code to determine the bulk mass from the CARMA state. return - end subroutine CARMA_DiagnoseBulk + end subroutine CARMAMODEL_DiagnoseBulk !! Calculates the emissions for CARMA aerosol particles. By default, there is no @@ -238,7 +247,7 @@ end subroutine CARMA_DiagnoseBulk !! !! @author Chuck Bardeen !! @version May-2009 - subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tendency, surfaceFlux, rc) + subroutine CARMAMODEL_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tendency, surfaceFlux, pbuf, rc) use shr_kind_mod, only: r8 => shr_kind_r8 use ppgrid, only: pcols, pver use physics_types, only: physics_state @@ -257,6 +266,7 @@ subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tend type(cam_in_t), intent(in) :: cam_in !! surface inputs real(r8), intent(out) :: tendency(pcols, pver) !! constituent tendency (kg/kg/s) real(r8), intent(out) :: surfaceFlux(pcols) !! constituent surface flux (kg/m^2/s) + type(physics_buffer_desc), pointer :: pbuf(:) !! physics buffer integer, intent(out) :: rc !! return code, negative indicates failure integer :: ncol ! number of columns in chunk @@ -289,7 +299,7 @@ subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tend tendency(:ncol, :pver) = 0.0_r8 return - end subroutine CARMA_EmitParticle + end subroutine CARMAMODEL_EmitParticle !! Allows the model to perform its own initialization in addition to what is done @@ -300,13 +310,14 @@ end subroutine CARMA_EmitParticle !! !! @author Chuck Bardeen !! @version May-2009 - subroutine CARMA_InitializeModel(carma, lq_carma, rc) + subroutine CARMAMODEL_InitializeModel(carma, lq_carma, pbuf2d, rc) use constituents, only : pcnst implicit none type(carma_type), intent(in) :: carma !! the carma object logical, intent(inout) :: lq_carma(pcnst) !! flags to indicate whether the constituent !! could have a CARMA tendency + type(physics_buffer_desc), pointer :: pbuf2d(:,:) integer, intent(out) :: rc !! return code, negative indicates failure ! Default return code. @@ -315,7 +326,7 @@ subroutine CARMA_InitializeModel(carma, lq_carma, rc) ! Add initialization here. return - end subroutine CARMA_InitializeModel + end subroutine CARMAMODEL_InitializeModel !! Sets the initial condition for CARMA aerosol particles. By default, there are no @@ -327,7 +338,7 @@ end subroutine CARMA_InitializeModel !! !! @author Chuck Bardeen !! @version May-2009 - subroutine CARMA_InitializeParticle(carma, ielem, ibin, latvals, lonvals, mask, q, rc) + subroutine CARMAMODEL_InitializeParticle(carma, ielem, ibin, latvals, lonvals, mask, q, rc) use shr_kind_mod, only: r8 => shr_kind_r8 use pmgrid, only: plev @@ -360,15 +371,55 @@ subroutine CARMA_InitializeParticle(carma, ielem, ibin, latvals, lonvals, mask, end if return - end subroutine CARMA_InitializeParticle + end subroutine CARMAMODEL_InitializeParticle + + !! This routine is an extension of CARMA_CreateOpticsFile() that allows for + !! model specific tables to be created in addition to the model independent + !! methods that are in carma_intr.F90. + !! + !! The opticsType that is specified for the group determines how the optical + !! properties will be generated for that group. Each group can use a different + !! optics method if needed. Refractive indices need for these calculation are + !! are specified in the group's elements rather than at the group level. This + !! allows various mixing approaches to be used to determine the refractive index + !! for the particle as a whole. If the refractive index for water is needed, + !! it is specific the the CARMAGAS object for H2O. + subroutine CARMAMODEL_CreateOpticsFile(carma, igroup, opticsType, rc) + + implicit none + + type(carma_type), intent(inout) :: carma !! the carma object + integer, intent(in) :: igroup !! group identifier + integer, intent(in) :: opticsType !! optics type (see I_OPTICS_... in carma_enums.F90) + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Local variables + logical :: do_mie + integer :: cnsttype ! constituent type + + ! Assume success. + rc = 0 + + ! What type of calculation is needed for this group? + ! + ! NOTE: Some of these calculations generate optical properties as single mass + ! coefficients, while others are lookup tables designed around multiple + ! dimensions. + select case (opticsType) + case default + call endrun('carma_CreateOpticsFile:: Unknown optics type.') + end select + + return + end subroutine CARMAMODEL_CreateOpticsFile !! Called after wet deposition has been performed. Allows the specific model to add !! wet deposition of CARMA aerosols to the aerosols being communicated to the surface. !! !! @version July-2011 !! @author Chuck Bardeen - subroutine CARMA_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) + subroutine CARMAMODEL_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) use camsrfexch, only: cam_out_t implicit none @@ -387,6 +438,95 @@ subroutine CARMA_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) rc = RC_OK return - end subroutine CARMA_WetDeposition + end subroutine CARMAMODEL_WetDeposition + + + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_CalculateCloudborneDiagnostics(carma, state, pbuf, aerclddiag, rc) + + type(carma_type), intent(in) :: carma !! the carma object + type(physics_state), intent(in) :: state !! Physics state variables - before pname + type(physics_buffer_desc), pointer, intent(in) :: pbuf(:) !! physics buffer + real(r8), intent(out) :: aerclddiag(pcols,MAXCLDAERDIAG) !! the total cloudborne aerosols, supports up to MAXCLDAERDIAG different values + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_CalculateCloudborneDiagnostics + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_OutputBudgetDiagnostics(carma, icnst4elem, icnst4gas, state, ptend, old_cflux, cflux, dt, pname, rc) + use cam_history, only: outfld + use constituents, only: pcnst, cnst_get_ind + + type(carma_type), intent(in) :: carma !! the carma object + integer, intent(in) :: icnst4elem(NELEM, NBIN) !! constituent index for a carma element + integer, intent(in) :: icnst4gas(NGAS) !! constituent index for a carma gas + type(physics_state), intent(in) :: state !! Physics state variables - before pname + type(physics_ptend), intent(in) :: ptend !! indivdual parameterization tendencies + real(r8) :: old_cflux(pcols,pcnst) !! cam_in%clfux from before the timestep_tend + real(r8) :: cflux(pcols,pcnst) !! cam_in%clfux from after the timestep_tend + real(r8), intent(in) :: dt !! timestep (s) + character(*), intent(in) :: pname !! short name of the physics package + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_OutputBudgetDiagnostics + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_OutputCloudborneDiagnostics(carma, state, pbuf, dt, pname, oldaerclddiag, rc) + use cam_history, only: outfld + + type(carma_type), intent(in) :: carma !! the carma object + type(physics_state), intent(in) :: state !! Physics state variables - before CARMA + type(physics_buffer_desc), pointer, intent(in) :: pbuf(:) !! physics buffer + real(r8), intent(in) :: dt !! timestep (s) + character(*), intent(in) :: pname !! short name of the physics package + real(r8), intent(in ) :: oldaerclddiag(pcols,MAXCLDAERDIAG) !! the before timestep cloudborne aerosol diags + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_OutputCloudborneDiagnostics + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_OutputDiagnostics(carma, icnst4elem, state, ptend, pbuf, cam_in, rc) + use cam_history, only: outfld + use constituents, only: cnst_get_ind + use camsrfexch, only: cam_in_t + + type(carma_type), intent(in) :: carma !! the carma object + integer, intent(in) :: icnst4elem(NELEM, NBIN) !! constituent index for a carma element + type(physics_state), intent(in) :: state !! Physics state variables - before CARMA + type(physics_ptend), intent(in) :: ptend !! indivdual parameterization tendencies + type(physics_buffer_desc), pointer, intent(in) :: pbuf(:) !! physics buffer + type(cam_in_t), intent(in) :: cam_in !! surface inputs + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_OutputDiagnostics -end module +end module carma_model_mod diff --git a/src/physics/carma/models/test_radiative/carma_model_mod.F90 b/src/physics/carma/models/test_radiative/carma_model_mod.F90 index 8acff28edb..d1b248df5a 100644 --- a/src/physics/carma/models/test_radiative/carma_model_mod.F90 +++ b/src/physics/carma/models/test_radiative/carma_model_mod.F90 @@ -42,14 +42,19 @@ module carma_model_mod private ! Declare the public methods. - public CARMA_DefineModel - public CARMA_Detrain - public CARMA_DiagnoseBins - public CARMA_DiagnoseBulk - public CARMA_EmitParticle - public CARMA_InitializeModel - public CARMA_InitializeParticle - public CARMA_WetDeposition + public CARMAMODEL_CalculateCloudborneDiagnostics + public CARMAMODEL_CreateOpticsFile + public CARMAMODEL_DefineModel + public CARMAMODEL_Detrain + public CARMAMODEL_DiagnoseBins + public CARMAMODEL_DiagnoseBulk + public CARMAMODEL_EmitParticle + public CARMAMODEL_InitializeModel + public CARMAMODEL_InitializeParticle + public CARMAMODEL_OutputBudgetDiagnostics + public CARMAMODEL_OutputCloudborneDiagnostics + public CARMAMODEL_OutputDiagnostics + public CARMAMODEL_WetDeposition ! Declare public constants integer, public, parameter :: NGROUP = 1 !! Number of particle groups @@ -65,6 +70,10 @@ module carma_model_mod integer, public, parameter :: NMIE_RH = 8 !! Number of relative humidities for mie calculations real(kind=f), public :: mie_rh(NMIE_RH) = (/ 0._f, 0.5_f, 0.7_f, 0.8_f, 0.9_f, 0.95_f, 0.98_f, 0.99_f /) + integer, public, parameter :: NMIE_WTP = 0 !! Number of weight percents for mie calculations + real(kind=f), public :: mie_wtp(NMIE_WTP) + integer, public, parameter :: NREFIDX = 1 !! Number of refractive indices per element + ! Defines whether the groups should undergo deep convection in phase 1 or phase 2. ! Water vapor and cloud particles are convected in phase 1, while all other constituents ! are done in phase 2. @@ -82,7 +91,7 @@ module carma_model_mod !! !! @version May-2009 !! @author Chuck Bardeen - subroutine CARMA_DefineModel(carma, rc) + subroutine CARMAMODEL_DefineModel(carma, rc) type(carma_type), intent(inout) :: carma !! the carma object integer, intent(out) :: rc !! return code, negative indicates failure @@ -90,14 +99,14 @@ subroutine CARMA_DefineModel(carma, rc) real(kind=f), parameter :: RHO_DUST = 2.0_f ! density of dust particles (g/cm) real(kind=f), parameter :: rmin = 1e-5_f ! minimum radius (cm) real(kind=f), parameter :: vmrat = 2.0_f ! volume ratio - complex(kind=f) :: refidx(NWAVE) ! refractice indices + complex(kind=f) :: refidx(NWAVE, NREFIDX) ! refractice indices ! Default return code. rc = RC_OK ! Use the same refractive index at all wavelengths. This value is typical of dust in ! the visible. - refidx(:) = (1.55_f, 4e-3_f) + refidx(:,1) = (1.55_f, 4e-3_f) ! Define the Groups ! @@ -108,16 +117,16 @@ subroutine CARMA_DefineModel(carma, rc) ! should also be defined. call CARMAGROUP_Create(carma, 1, "Dust", rmin, vmrat, I_SPHERE, 1._f, .false., & rc, do_wetdep=.true., do_drydep=.true., solfac=0.15_f, & - scavcoef=0.1_f, shortname="DUST", refidx=refidx, do_mie=.true.) - if (rc < 0) call endrun('CARMA_DefineModel::CARMA_AddGroup failed.') + scavcoef=0.1_f, shortname="DUST", do_mie=.true.) + if (rc < 0) call endrun('CARMAMODEL_DefineModel::CARMA_AddGroup failed.') ! Define the Elements ! ! NOTE: For CAM, the optional shortname needs to be provided for the group. These names ! should be 6 characters or less and without spaces. - call CARMAELEMENT_Create(carma, 1, 1, "Dust", RHO_DUST, I_INVOLATILE, I_DUST, rc, shortname="DUST") - if (rc < 0) call endrun('CARMA_DefineModel::CARMA_AddElement failed.') + call CARMAELEMENT_Create(carma, 1, 1, "Dust", RHO_DUST, I_INVOLATILE, I_DUST, rc, shortname="DUST", refidx=refidx) + if (rc < 0) call endrun('CARMAMODEL_DefineModel::CARMA_AddElement failed.') ! Define the Solutes @@ -128,10 +137,10 @@ subroutine CARMA_DefineModel(carma, rc) ! Define the Processes call CARMA_AddCoagulation(carma, 1, 1, 1, I_COLLEC_DATA, rc) - if (rc < 0) call endrun('CARMA_DefineModel::CARMA_AddCoagulation failed.') + if (rc < 0) call endrun('CARMAMODEL_DefineModel::CARMA_AddCoagulation failed.') return - end subroutine CARMA_DefineModel + end subroutine CARMAMODEL_DefineModel !! Defines all the CARMA components (groups, elements, solutes and gases) and process @@ -141,7 +150,7 @@ end subroutine CARMA_DefineModel !! @author Chuck Bardeen !! !! @see CARMASTATE_SetDetrain - subroutine CARMA_Detrain(carma, cstate, cam_in, dlf, state, icol, dt, rc, rliq, prec_str, snow_str, & + subroutine CARMAMODEL_Detrain(carma, cstate, cam_in, dlf, state, icol, dt, rc, rliq, prec_str, snow_str, & tnd_qsnow, tnd_nsnow) use camsrfexch, only: cam_in_t use physconst, only: latice, latvap, cpair @@ -166,14 +175,14 @@ subroutine CARMA_Detrain(carma, cstate, cam_in, dlf, state, icol, dt, rc, rliq, rc = RC_OK return - end subroutine CARMA_Detrain + end subroutine CARMAMODEL_Detrain !! For diagnostic groups, sets up up the CARMA bins based upon the CAM state. !! !! @version July-2009 !! @author Chuck Bardeen - subroutine CARMA_DiagnoseBins(carma, cstate, state, pbuf, icol, dt, rc, rliq, prec_str, snow_str) + subroutine CARMAMODEL_DiagnoseBins(carma, cstate, state, pbuf, icol, dt, rc, rliq, prec_str, snow_str) use time_manager, only: is_first_step implicit none @@ -199,14 +208,14 @@ subroutine CARMA_DiagnoseBins(carma, cstate, state, pbuf, icol, dt, rc, rliq, pr ! code to determine the mass in each bin from the CAM state. return - end subroutine CARMA_DiagnoseBins + end subroutine CARMAMODEL_DiagnoseBins !! For diagnostic groups, determines the tendencies on the CAM state from the CARMA bins. !! !! @version July-2009 !! @author Chuck Bardeen - subroutine CARMA_DiagnoseBulk(carma, cstate, cam_out, state, pbuf, ptend, icol, dt, rc, rliq, prec_str, snow_str, & + subroutine CARMAMODEL_DiagnoseBulk(carma, cstate, cam_out, state, pbuf, ptend, icol, dt, rc, rliq, prec_str, snow_str, & prec_sed, snow_sed, tnd_qsnow, tnd_nsnow, re_ice) use camsrfexch, only: cam_out_t @@ -237,7 +246,7 @@ subroutine CARMA_DiagnoseBulk(carma, cstate, cam_out, state, pbuf, ptend, icol, ! code to determine the bulk mass from the CARMA state. return - end subroutine CARMA_DiagnoseBulk + end subroutine CARMAMODEL_DiagnoseBulk !! Calculates the emissions for CARMA aerosol particles. By default, there is no @@ -246,7 +255,7 @@ end subroutine CARMA_DiagnoseBulk !! !! @author Chuck Bardeen !! @version May-2009 - subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tendency, surfaceFlux, rc) + subroutine CARMAMODEL_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tendency, surfaceFlux, pbuf, rc) use shr_kind_mod, only: r8 => shr_kind_r8 use ppgrid, only: pcols, pver use physics_types, only: physics_state @@ -265,6 +274,7 @@ subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tend type(cam_in_t), intent(in) :: cam_in !! surface inputs real(r8), intent(out) :: tendency(pcols, pver) !! constituent tendency (kg/kg/s) real(r8), intent(out) :: surfaceFlux(pcols) !! constituent surface flux (kg/m^2/s) + type(physics_buffer_desc), pointer :: pbuf(:) !! physics buffer integer, intent(out) :: rc !! return code, negative indicates failure integer :: ncol ! number of columns in chunk @@ -297,7 +307,7 @@ subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tend tendency(:ncol, :pver) = 0.0_r8 return - end subroutine CARMA_EmitParticle + end subroutine CARMAMODEL_EmitParticle !! Allows the model to perform its own initialization in addition to what is done @@ -308,13 +318,14 @@ end subroutine CARMA_EmitParticle !! !! @author Chuck Bardeen !! @version May-2009 - subroutine CARMA_InitializeModel(carma, lq_carma, rc) + subroutine CARMAMODEL_InitializeModel(carma, lq_carma, pbuf2d, rc) use constituents, only : pcnst implicit none type(carma_type), intent(in) :: carma !! the carma object logical, intent(inout) :: lq_carma(pcnst) !! flags to indicate whether the constituent !! could have a CARMA tendency + type(physics_buffer_desc), pointer :: pbuf2d(:,:) integer, intent(out) :: rc !! return code, negative indicates failure ! Default return code. @@ -323,7 +334,7 @@ subroutine CARMA_InitializeModel(carma, lq_carma, rc) ! Add initialization here. return - end subroutine CARMA_InitializeModel + end subroutine CARMAMODEL_InitializeModel !! Sets the initial condition for CARMA aerosol particles. By default, there are no @@ -335,7 +346,7 @@ end subroutine CARMA_InitializeModel !! !! @author Chuck Bardeen !! @version May-2009 - subroutine CARMA_InitializeParticle(carma, ielem, ibin, latvals, lonvals, mask, q, rc) + subroutine CARMAMODEL_InitializeParticle(carma, ielem, ibin, latvals, lonvals, mask, q, rc) use shr_kind_mod, only: r8 => shr_kind_r8 use pmgrid, only: plev @@ -368,15 +379,55 @@ subroutine CARMA_InitializeParticle(carma, ielem, ibin, latvals, lonvals, mask, end if return - end subroutine CARMA_InitializeParticle + end subroutine CARMAMODEL_InitializeParticle + + !! This routine is an extension of CARMA_CreateOpticsFile() that allows for + !! model specific tables to be created in addition to the model independent + !! methods that are in carma_intr.F90. + !! + !! The opticsType that is specified for the group determines how the optical + !! properties will be generated for that group. Each group can use a different + !! optics method if needed. Refractive indices need for these calculation are + !! are specified in the group's elements rather than at the group level. This + !! allows various mixing approaches to be used to determine the refractive index + !! for the particle as a whole. If the refractive index for water is needed, + !! it is specific the the CARMAGAS object for H2O. + subroutine CARMAMODEL_CreateOpticsFile(carma, igroup, opticsType, rc) + + implicit none + + type(carma_type), intent(inout) :: carma !! the carma object + integer, intent(in) :: igroup !! group identifier + integer, intent(in) :: opticsType !! optics type (see I_OPTICS_... in carma_enums.F90) + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Local variables + logical :: do_mie + integer :: cnsttype ! constituent type + + ! Assume success. + rc = 0 + + ! What type of calculation is needed for this group? + ! + ! NOTE: Some of these calculations generate optical properties as single mass + ! coefficients, while others are lookup tables designed around multiple + ! dimensions. + select case (opticsType) + case default + call endrun('carma_CreateOpticsFile:: Unknown optics type.') + end select + + return + end subroutine CARMAMODEL_CreateOpticsFile !! Called after wet deposition has been performed. Allows the specific model to add !! wet deposition of CARMA aerosols to the aerosols being communicated to the surface. !! !! @version July-2011 !! @author Chuck Bardeen - subroutine CARMA_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) + subroutine CARMAMODEL_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) use camsrfexch, only: cam_out_t implicit none @@ -395,6 +446,94 @@ subroutine CARMA_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) rc = RC_OK return - end subroutine CARMA_WetDeposition + end subroutine CARMAMODEL_WetDeposition + + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_CalculateCloudborneDiagnostics(carma, state, pbuf, aerclddiag, rc) + + type(carma_type), intent(in) :: carma !! the carma object + type(physics_state), intent(in) :: state !! Physics state variables - before pname + type(physics_buffer_desc), pointer, intent(in) :: pbuf(:) !! physics buffer + real(r8), intent(out) :: aerclddiag(pcols,MAXCLDAERDIAG) !! the total cloudborne aerosols, supports up to MAXCLDAERDIAG different values + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_CalculateCloudborneDiagnostics + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_OutputBudgetDiagnostics(carma, icnst4elem, icnst4gas, state, ptend, old_cflux, cflux, dt, pname, rc) + use cam_history, only: outfld + use constituents, only: pcnst, cnst_get_ind + + type(carma_type), intent(in) :: carma !! the carma object + integer, intent(in) :: icnst4elem(NELEM, NBIN) !! constituent index for a carma element + integer, intent(in) :: icnst4gas(NGAS) !! constituent index for a carma gas + type(physics_state), intent(in) :: state !! Physics state variables - before pname + type(physics_ptend), intent(in) :: ptend !! indivdual parameterization tendencies + real(r8) :: old_cflux(pcols,pcnst) !! cam_in%clfux from before the timestep_tend + real(r8) :: cflux(pcols,pcnst) !! cam_in%clfux from after the timestep_tend + real(r8), intent(in) :: dt !! timestep (s) + character(*), intent(in) :: pname !! short name of the physics package + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_OutputBudgetDiagnostics + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_OutputCloudborneDiagnostics(carma, state, pbuf, dt, pname, oldaerclddiag, rc) + use cam_history, only: outfld + + type(carma_type), intent(in) :: carma !! the carma object + type(physics_state), intent(in) :: state !! Physics state variables - before CARMA + type(physics_buffer_desc), pointer, intent(in) :: pbuf(:) !! physics buffer + real(r8), intent(in) :: dt !! timestep (s) + character(*), intent(in) :: pname !! short name of the physics package + real(r8), intent(in ) :: oldaerclddiag(pcols,MAXCLDAERDIAG) !! the before timestep cloudborne aerosol diags + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_OutputCloudborneDiagnostics + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_OutputDiagnostics(carma, icnst4elem, state, ptend, pbuf, cam_in, rc) + use cam_history, only: outfld + use constituents, only: cnst_get_ind + use camsrfexch, only: cam_in_t + + type(carma_type), intent(in) :: carma !! the carma object + integer, intent(in) :: icnst4elem(NELEM, NBIN) !! constituent index for a carma element + type(physics_state), intent(in) :: state !! Physics state variables - before CARMA + type(physics_ptend), intent(in) :: ptend !! indivdual parameterization tendencies + type(physics_buffer_desc), pointer, intent(in) :: pbuf(:) !! physics buffer + type(cam_in_t), intent(in) :: cam_in !! surface inputs + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_OutputDiagnostics -end module +end module carma_model_mod diff --git a/src/physics/carma/models/test_swelling/carma_model_mod.F90 b/src/physics/carma/models/test_swelling/carma_model_mod.F90 index ce55401475..4e98bb5cd1 100644 --- a/src/physics/carma/models/test_swelling/carma_model_mod.F90 +++ b/src/physics/carma/models/test_swelling/carma_model_mod.F90 @@ -43,14 +43,19 @@ module carma_model_mod private ! Declare the public methods. - public CARMA_DefineModel - public CARMA_Detrain - public CARMA_DiagnoseBins - public CARMA_DiagnoseBulk - public CARMA_EmitParticle - public CARMA_InitializeModel - public CARMA_InitializeParticle - public CARMA_WetDeposition + public CARMAMODEL_CalculateCloudborneDiagnostics + public CARMAMODEL_CreateOpticsFile + public CARMAMODEL_DefineModel + public CARMAMODEL_Detrain + public CARMAMODEL_DiagnoseBins + public CARMAMODEL_DiagnoseBulk + public CARMAMODEL_EmitParticle + public CARMAMODEL_InitializeModel + public CARMAMODEL_InitializeParticle + public CARMAMODEL_OutputBudgetDiagnostics + public CARMAMODEL_OutputCloudborneDiagnostics + public CARMAMODEL_OutputDiagnostics + public CARMAMODEL_WetDeposition ! Declare public constants integer, public, parameter :: NGROUP = 3 !! Number of particle groups @@ -63,6 +68,10 @@ module carma_model_mod integer, public, parameter :: NMIE_RH = 8 !! Number of relative humidities for mie calculations real(kind=f), public :: mie_rh(NMIE_RH) + integer, public, parameter :: NMIE_WTP = 0 !! Number of weight percents for mie calculations + real(kind=f), public :: mie_wtp(NMIE_WTP) + integer, public, parameter :: NREFIDX = 1 !! Number of refractive indices per element + ! Defines whether the groups should undergo deep convection in phase 1 or phase 2. ! Water vapor and cloud particles are convected in phase 1, while all other constituents ! are done in phase 2. @@ -80,7 +89,7 @@ module carma_model_mod !! !! @version May-2009 !! @author Chuck Bardeen - subroutine CARMA_DefineModel(carma, rc) + subroutine CARMAMODEL_DefineModel(carma, rc) type(carma_type), intent(inout) :: carma !! the carma object integer, intent(out) :: rc !! return code, negative indicates failure @@ -100,19 +109,19 @@ subroutine CARMA_DefineModel(carma, rc) call CARMAGROUP_Create(carma, 1, "None", rmin, vmrat, I_SPHERE, 1._f, .false., & rc, do_wetdep=.true., do_drydep=.true., solfac=0.3_f, & scavcoef=0.1_f, shortname="SALT") - if (rc < 0) call endrun('CARMA_DefineModel::CARMA_AddGroup failed.') + if (rc < 0) call endrun('CARMAMODEL_DefineModel::CARMA_AddGroup failed.') call CARMAGROUP_Create(carma, 2, "Fitzgerald", rmin, vmrat, I_SPHERE, 1._f, & .false., rc, do_wetdep=.true., do_drydep=.true., solfac=0.3_f, & scavcoef=0.1_f, shortname="SALTFZ", irhswell=I_FITZGERALD, & irhswcomp=I_SWF_NACL) - if (rc < 0) call endrun('CARMA_DefineModel::CARMA_AddGroup failed.') + if (rc < 0) call endrun('CARMAMODEL_DefineModel::CARMA_AddGroup failed.') call CARMAGROUP_Create(carma, 3, "Gerber", rmin, vmrat, I_SPHERE, 1._f, & .false., rc, do_wetdep=.true., do_drydep=.true., solfac=0.3_f, & scavcoef=0.1_f, shortname="SALTGB", irhswell=I_GERBER, & irhswcomp=I_SWG_SEA_SALT) - if (rc < 0) call endrun('CARMA_DefineModel::CARMA_AddGroup failed.') + if (rc < 0) call endrun('CARMAMODEL_DefineModel::CARMA_AddGroup failed.') ! Define the Elements @@ -120,13 +129,13 @@ subroutine CARMA_DefineModel(carma, rc) ! NOTE: For CAM, the optional shortname needs to be provided for the group. These names ! should be 6 characters or less and without spaces. call CARMAELEMENT_Create(carma, 1, 1, "None", RHO_SALT, I_INVOLATILE, I_SEA_SALT, rc, shortname="SALT") - if (rc < 0) call endrun('CARMA_DefineModel::CARMA_AddElement failed.') + if (rc < 0) call endrun('CARMAMODEL_DefineModel::CARMA_AddElement failed.') call CARMAELEMENT_Create(carma, 2, 2, "Fitz", RHO_SALT, I_INVOLATILE, I_SEA_SALT, rc, shortname="SALTFZ") - if (rc < 0) call endrun('CARMA_DefineModel::CARMA_AddElement failed.') + if (rc < 0) call endrun('CARMAMODEL_DefineModel::CARMA_AddElement failed.') call CARMAELEMENT_Create(carma, 3, 3, "Gerb", RHO_SALT, I_INVOLATILE, I_SEA_SALT, rc, shortname="SALTGB") - if (rc < 0) call endrun('CARMA_DefineModel::CARMA_AddElement failed.') + if (rc < 0) call endrun('CARMAMODEL_DefineModel::CARMA_AddElement failed.') ! Define the Solutes @@ -138,7 +147,7 @@ subroutine CARMA_DefineModel(carma, rc) ! Define the Processes return - end subroutine CARMA_DefineModel + end subroutine CARMAMODEL_DefineModel !! Defines all the CARMA components (groups, elements, solutes and gases) and process @@ -148,7 +157,7 @@ end subroutine CARMA_DefineModel !! @author Chuck Bardeen !! !! @see CARMASTATE_SetDetrain - subroutine CARMA_Detrain(carma, cstate, cam_in, dlf, state, icol, dt, rc, rliq, prec_str, snow_str, & + subroutine CARMAMODEL_Detrain(carma, cstate, cam_in, dlf, state, icol, dt, rc, rliq, prec_str, snow_str, & tnd_qsnow, tnd_nsnow) use camsrfexch, only: cam_in_t use physconst, only: latice, latvap, cpair @@ -173,14 +182,14 @@ subroutine CARMA_Detrain(carma, cstate, cam_in, dlf, state, icol, dt, rc, rliq, rc = RC_OK return - end subroutine CARMA_Detrain + end subroutine CARMAMODEL_Detrain !! For diagnostic groups, sets up up the CARMA bins based upon the CAM state. !! !! @version July-2009 !! @author Chuck Bardeen - subroutine CARMA_DiagnoseBins(carma, cstate, state, pbuf, icol, dt, rc, rliq, prec_str, snow_str) + subroutine CARMAMODEL_DiagnoseBins(carma, cstate, state, pbuf, icol, dt, rc, rliq, prec_str, snow_str) use time_manager, only: is_first_step implicit none @@ -206,14 +215,14 @@ subroutine CARMA_DiagnoseBins(carma, cstate, state, pbuf, icol, dt, rc, rliq, pr ! code to determine the mass in each bin from the CAM state. return - end subroutine CARMA_DiagnoseBins + end subroutine CARMAMODEL_DiagnoseBins !! For diagnostic groups, determines the tendencies on the CAM state from the CARMA bins. !! !! @version July-2009 !! @author Chuck Bardeen - subroutine CARMA_DiagnoseBulk(carma, cstate, cam_out, state, pbuf, ptend, icol, dt, rc, rliq, prec_str, snow_str, & + subroutine CARMAMODEL_DiagnoseBulk(carma, cstate, cam_out, state, pbuf, ptend, icol, dt, rc, rliq, prec_str, snow_str, & prec_sed, snow_sed, tnd_qsnow, tnd_nsnow, re_ice) use camsrfexch, only: cam_out_t @@ -244,7 +253,7 @@ subroutine CARMA_DiagnoseBulk(carma, cstate, cam_out, state, pbuf, ptend, icol, ! code to determine the bulk mass from the CARMA state. return - end subroutine CARMA_DiagnoseBulk + end subroutine CARMAMODEL_DiagnoseBulk !! Calculates the emissions for CARMA aerosol particles. By default, there is no @@ -253,7 +262,7 @@ end subroutine CARMA_DiagnoseBulk !! !! @author Chuck Bardeen !! @version May-2009 - subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tendency, surfaceFlux, rc) + subroutine CARMAMODEL_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tendency, surfaceFlux, pbuf, rc) use shr_kind_mod, only: r8 => shr_kind_r8 use ppgrid, only: pcols, pver use physics_types, only: physics_state @@ -272,6 +281,7 @@ subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tend type(cam_in_t), intent(in) :: cam_in !! surface inputs real(r8), intent(out) :: tendency(pcols, pver) !! constituent tendency (kg/kg/s) real(r8), intent(out) :: surfaceFlux(pcols) !! constituent surface flux (kg/m^2/s) + type(physics_buffer_desc), pointer :: pbuf(:) !! physics buffer integer, intent(out) :: rc !! return code, negative indicates failure integer :: ncol ! number of columns in chunk @@ -304,7 +314,7 @@ subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tend tendency(:ncol, :pver) = 0.0_r8 return - end subroutine CARMA_EmitParticle + end subroutine CARMAMODEL_EmitParticle !! Allows the model to perform its own initialization in addition to what is done @@ -312,13 +322,14 @@ end subroutine CARMA_EmitParticle !! !! @author Chuck Bardeen !! @version May-2009 - subroutine CARMA_InitializeModel(carma, lq_carma, rc) + subroutine CARMAMODEL_InitializeModel(carma, lq_carma, pbuf2d, rc) use constituents, only : pcnst implicit none type(carma_type), intent(in) :: carma !! the carma object logical, intent(inout) :: lq_carma(pcnst) !! flags to indicate whether the constituent !! could have a CARMA tendency + type(physics_buffer_desc), pointer :: pbuf2d(:,:) integer, intent(out) :: rc !! return code, negative indicates failure ! Default return code. @@ -327,7 +338,7 @@ subroutine CARMA_InitializeModel(carma, lq_carma, rc) ! Add initialization here. return - end subroutine CARMA_InitializeModel + end subroutine CARMAMODEL_InitializeModel !! Sets the initial condition for CARMA aerosol particles. By default, there are no @@ -339,7 +350,7 @@ end subroutine CARMA_InitializeModel !! !! @author Chuck Bardeen !! @version May-2009 - subroutine CARMA_InitializeParticle(carma, ielem, ibin, latvals, lonvals, mask, q, rc) + subroutine CARMAMODEL_InitializeParticle(carma, ielem, ibin, latvals, lonvals, mask, q, rc) use shr_kind_mod, only: r8 => shr_kind_r8 use pmgrid, only: plev @@ -369,15 +380,55 @@ subroutine CARMA_InitializeParticle(carma, ielem, ibin, latvals, lonvals, mask, end where return - end subroutine CARMA_InitializeParticle + end subroutine CARMAMODEL_InitializeParticle + + !! This routine is an extension of CARMA_CreateOpticsFile() that allows for + !! model specific tables to be created in addition to the model independent + !! methods that are in carma_intr.F90. + !! + !! The opticsType that is specified for the group determines how the optical + !! properties will be generated for that group. Each group can use a different + !! optics method if needed. Refractive indices need for these calculation are + !! are specified in the group's elements rather than at the group level. This + !! allows various mixing approaches to be used to determine the refractive index + !! for the particle as a whole. If the refractive index for water is needed, + !! it is specific the the CARMAGAS object for H2O. + subroutine CARMAMODEL_CreateOpticsFile(carma, igroup, opticsType, rc) + + implicit none + + type(carma_type), intent(inout) :: carma !! the carma object + integer, intent(in) :: igroup !! group identifier + integer, intent(in) :: opticsType !! optics type (see I_OPTICS_... in carma_enums.F90) + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Local variables + logical :: do_mie + integer :: cnsttype ! constituent type + + ! Assume success. + rc = 0 + + ! What type of calculation is needed for this group? + ! + ! NOTE: Some of these calculations generate optical properties as single mass + ! coefficients, while others are lookup tables designed around multiple + ! dimensions. + select case (opticsType) + case default + call endrun('carma_CreateOpticsFile:: Unknown optics type.') + end select + + return + end subroutine CARMAMODEL_CreateOpticsFile !! Called after wet deposition has been performed. Allows the specific model to add !! wet deposition of CARMA aerosols to the aerosols being communicated to the surface. !! !! @version July-2011 !! @author Chuck Bardeen - subroutine CARMA_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) + subroutine CARMAMODEL_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) use camsrfexch, only: cam_out_t implicit none @@ -396,6 +447,95 @@ subroutine CARMA_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) rc = RC_OK return - end subroutine CARMA_WetDeposition + end subroutine CARMAMODEL_WetDeposition + + + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_CalculateCloudborneDiagnostics(carma, state, pbuf, aerclddiag, rc) + + type(carma_type), intent(in) :: carma !! the carma object + type(physics_state), intent(in) :: state !! Physics state variables - before pname + type(physics_buffer_desc), pointer, intent(in) :: pbuf(:) !! physics buffer + real(r8), intent(out) :: aerclddiag(pcols,MAXCLDAERDIAG) !! the total cloudborne aerosols, supports up to MAXCLDAERDIAG different values + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_CalculateCloudborneDiagnostics + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_OutputBudgetDiagnostics(carma, icnst4elem, icnst4gas, state, ptend, old_cflux, cflux, dt, pname, rc) + use cam_history, only: outfld + use constituents, only: pcnst, cnst_get_ind + + type(carma_type), intent(in) :: carma !! the carma object + integer, intent(in) :: icnst4elem(NELEM, NBIN) !! constituent index for a carma element + integer, intent(in) :: icnst4gas(NGAS) !! constituent index for a carma gas + type(physics_state), intent(in) :: state !! Physics state variables - before pname + type(physics_ptend), intent(in) :: ptend !! indivdual parameterization tendencies + real(r8) :: old_cflux(pcols,pcnst) !! cam_in%clfux from before the timestep_tend + real(r8) :: cflux(pcols,pcnst) !! cam_in%clfux from after the timestep_tend + real(r8), intent(in) :: dt !! timestep (s) + character(*), intent(in) :: pname !! short name of the physics package + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_OutputBudgetDiagnostics + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_OutputCloudborneDiagnostics(carma, state, pbuf, dt, pname, oldaerclddiag, rc) + use cam_history, only: outfld + + type(carma_type), intent(in) :: carma !! the carma object + type(physics_state), intent(in) :: state !! Physics state variables - before CARMA + type(physics_buffer_desc), pointer, intent(in) :: pbuf(:) !! physics buffer + real(r8), intent(in) :: dt !! timestep (s) + character(*), intent(in) :: pname !! short name of the physics package + real(r8), intent(in ) :: oldaerclddiag(pcols,MAXCLDAERDIAG) !! the before timestep cloudborne aerosol diags + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_OutputCloudborneDiagnostics + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_OutputDiagnostics(carma, icnst4elem, state, ptend, pbuf, cam_in, rc) + use cam_history, only: outfld + use constituents, only: cnst_get_ind + use camsrfexch, only: cam_in_t + + type(carma_type), intent(in) :: carma !! the carma object + integer, intent(in) :: icnst4elem(NELEM, NBIN) !! constituent index for a carma element + type(physics_state), intent(in) :: state !! Physics state variables - before CARMA + type(physics_ptend), intent(in) :: ptend !! indivdual parameterization tendencies + type(physics_buffer_desc), pointer, intent(in) :: pbuf(:) !! physics buffer + type(cam_in_t), intent(in) :: cam_in !! surface inputs + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_OutputDiagnostics -end module +end module carma_model_mod diff --git a/src/physics/carma/models/test_tracers/carma_model_mod.F90 b/src/physics/carma/models/test_tracers/carma_model_mod.F90 index 9ed84a9471..40aa2b911c 100644 --- a/src/physics/carma/models/test_tracers/carma_model_mod.F90 +++ b/src/physics/carma/models/test_tracers/carma_model_mod.F90 @@ -49,14 +49,19 @@ module carma_model_mod private ! Declare the public methods. - public CARMA_DefineModel - public CARMA_Detrain - public CARMA_DiagnoseBins - public CARMA_DiagnoseBulk - public CARMA_EmitParticle - public CARMA_InitializeModel - public CARMA_InitializeParticle - public CARMA_WetDeposition + public CARMAMODEL_CalculateCloudborneDiagnostics + public CARMAMODEL_CreateOpticsFile + public CARMAMODEL_DefineModel + public CARMAMODEL_Detrain + public CARMAMODEL_DiagnoseBins + public CARMAMODEL_DiagnoseBulk + public CARMAMODEL_EmitParticle + public CARMAMODEL_InitializeModel + public CARMAMODEL_InitializeParticle + public CARMAMODEL_OutputBudgetDiagnostics + public CARMAMODEL_OutputCloudborneDiagnostics + public CARMAMODEL_OutputDiagnostics + public CARMAMODEL_WetDeposition ! Declare public constants integer, public, parameter :: NGROUP = 6 !! Number of particle groups @@ -69,6 +74,10 @@ module carma_model_mod integer, public, parameter :: NMIE_RH = 8 !! Number of relative humidities for mie calculations real(kind=f), public :: mie_rh(NMIE_RH) + integer, public, parameter :: NMIE_WTP = 0 !! Number of weight percents for mie calculations + real(kind=f), public :: mie_wtp(NMIE_WTP) + integer, public, parameter :: NREFIDX = 1 !! Number of refractive indices per element + ! Defines whether the groups should undergo deep convection in phase 1 or phase 2. ! Water vapor and cloud particles are convected in phase 1, while all other constituents ! are done in phase 2. @@ -98,7 +107,7 @@ module carma_model_mod !! !! @version May-2009 !! @author Chuck Bardeen - subroutine CARMA_DefineModel(carma, rc) + subroutine CARMAMODEL_DefineModel(carma, rc) type(carma_type), intent(inout) :: carma !! the carma object integer, intent(out) :: rc !! return code, negative indicates failure @@ -112,7 +121,7 @@ subroutine CARMA_DefineModel(carma, rc) rc = RC_OK call CARMA_Get(carma, rc, do_print=do_print, LUNOPRT=LUNOPRT) - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMA_Get failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMA_Get failed.') ! Report model specific configuration parameters. if (masterproc) then @@ -132,22 +141,22 @@ subroutine CARMA_DefineModel(carma, rc) ! defined. If wetdep is defined, then the optional solubility factor ! should also be defined. call CARMAGROUP_Create(carma, 1, "Region 1", rmin, vmrat, I_SPHERE, 1._f, .True., rc, shortname="CRRG1") - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMAGROUP_Create failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMAGROUP_Create failed.') call CARMAGROUP_Create(carma, 2, "Region 2", rmin, vmrat, I_SPHERE, 1._f, .True., rc, shortname="CRRG2") - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMAGROUP_Create failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMAGROUP_Create failed.') call CARMAGROUP_Create(carma, 3, "Region 3", rmin, vmrat, I_SPHERE, 1._f, .True., rc, shortname="CRRG3") - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMAGROUP_Create failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMAGROUP_Create failed.') call CARMAGROUP_Create(carma, 4, "Region 4", rmin, vmrat, I_SPHERE, 1._f, .True., rc, shortname="CRRG4") - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMAGROUP_Create failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMAGROUP_Create failed.') call CARMAGROUP_Create(carma, 5, "Region 5", rmin, vmrat, I_SPHERE, 1._f, .True., rc, shortname="CRRG5") - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMAGROUP_Create failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMAGROUP_Create failed.') call CARMAGROUP_Create(carma, 6, "Rest of World", rmin, vmrat, I_SPHERE, 1._f, .True., rc, shortname="CRRG6") - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMAGROUP_Create failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMAGROUP_Create failed.') ! Define the Elements @@ -155,22 +164,22 @@ subroutine CARMA_DefineModel(carma, rc) ! NOTE: For CAM, the optional shortname needs to be provided for the group. These names ! should be 6 characters or less and without spaces. call CARMAELEMENT_Create(carma, 1, 1, "Region 1", WTMOL_AIR, I_INVOLATILE, I_INERT, rc, shortname="CRRG1") - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMAElement_Create failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMAElement_Create failed.') call CARMAELEMENT_Create(carma, 2, 2, "Region 2", WTMOL_AIR, I_INVOLATILE, I_INERT, rc, shortname="CRRG2") - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMAElement_Create failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMAElement_Create failed.') call CARMAELEMENT_Create(carma, 3, 3, "Region 3", WTMOL_AIR, I_INVOLATILE, I_INERT, rc, shortname="CRRG3") - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMAElement_Create failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMAElement_Create failed.') call CARMAELEMENT_Create(carma, 4, 4, "Region 4", WTMOL_AIR, I_INVOLATILE, I_INERT, rc, shortname="CRRG4") - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMAElement_Create failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMAElement_Create failed.') call CARMAELEMENT_Create(carma, 5, 5, "Region 5", WTMOL_AIR, I_INVOLATILE, I_INERT, rc, shortname="CRRG5") - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMAElement_Create failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMAElement_Create failed.') call CARMAELEMENT_Create(carma, 6, 6, "Rest of World", WTMOL_AIR, I_INVOLATILE, I_INERT, rc, shortname="CRRG6") - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMAElement_Create failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMAElement_Create failed.') ! Define the Solutes @@ -183,7 +192,7 @@ subroutine CARMA_DefineModel(carma, rc) return - end subroutine CARMA_DefineModel + end subroutine CARMAMODEL_DefineModel !! Defines all the CARMA components (groups, elements, solutes and gases) and process @@ -193,7 +202,7 @@ end subroutine CARMA_DefineModel !! @author Chuck Bardeen !! !! @see CARMASTATE_SetDetrain - subroutine CARMA_Detrain(carma, cstate, cam_in, dlf, state, icol, dt, rc, rliq, prec_str, snow_str, & + subroutine CARMAMODEL_Detrain(carma, cstate, cam_in, dlf, state, icol, dt, rc, rliq, prec_str, snow_str, & tnd_qsnow, tnd_nsnow) use camsrfexch, only: cam_in_t use physconst, only: latice, latvap, cpair, cappa @@ -219,14 +228,14 @@ subroutine CARMA_Detrain(carma, cstate, cam_in, dlf, state, icol, dt, rc, rliq, rc = RC_OK return - end subroutine CARMA_Detrain + end subroutine CARMAMODEL_Detrain !! For diagnostic groups, sets up up the CARMA bins based upon the CAM state. !! !! @version July-2009 !! @author Chuck Bardeen - subroutine CARMA_DiagnoseBins(carma, cstate, state, pbuf, icol, dt, rc, rliq, prec_str, snow_str) + subroutine CARMAMODEL_DiagnoseBins(carma, cstate, state, pbuf, icol, dt, rc, rliq, prec_str, snow_str) use time_manager, only: is_first_step implicit none @@ -252,7 +261,7 @@ subroutine CARMA_DiagnoseBins(carma, cstate, state, pbuf, icol, dt, rc, rliq, pr ! code to determine the mass in each bin from the CAM state. return - end subroutine CARMA_DiagnoseBins + end subroutine CARMAMODEL_DiagnoseBins !! For diagnostic groups, determines the tendencies on the CAM state from the CARMA bins. @@ -262,7 +271,7 @@ end subroutine CARMA_DiagnoseBins !! !! @version July-2009 !! @author Chuck Bardeen - subroutine CARMA_DiagnoseBulk(carma, cstate, cam_out, state, pbuf, ptend, icol, dt, rc, rliq, prec_str, snow_str, & + subroutine CARMAMODEL_DiagnoseBulk(carma, cstate, cam_out, state, pbuf, ptend, icol, dt, rc, rliq, prec_str, snow_str, & prec_sed, snow_sed, tnd_qsnow, tnd_nsnow, re_ice) use shr_kind_mod, only: r8 => shr_kind_r8 use ppgrid, only: pcols, pver @@ -325,7 +334,7 @@ subroutine CARMA_DiagnoseBulk(carma, cstate, cam_out, state, pbuf, ptend, icol, end if return - end subroutine CARMA_DiagnoseBulk + end subroutine CARMAMODEL_DiagnoseBulk !! Calculates the emissions for CARMA aerosol particles. @@ -352,7 +361,7 @@ end subroutine CARMA_DiagnoseBulk !! !! @author Chuck Bardeen !! @version May-2009 - subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tendency, surfaceFlux, rc) + subroutine CARMAMODEL_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tendency, surfaceFlux, pbuf, rc) use shr_kind_mod, only: r8 => shr_kind_r8 use ppgrid, only: pcols, pver use physics_types, only: physics_state @@ -372,6 +381,7 @@ subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tend type(cam_in_t), intent(in) :: cam_in !! surface inputs real(r8), intent(out) :: tendency(pcols, pver) !! constituent tendency (kg/kg/s) real(r8), intent(out) :: surfaceFlux(pcols) !! constituent surface flux (kg/m^2/s) + type(physics_buffer_desc), pointer :: pbuf(:) !! physics buffer integer, intent(out) :: rc !! return code, negative indicates failure real(r8) :: lat(state%ncol) ! latitude (degrees) @@ -489,7 +499,7 @@ subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tend end if return - end subroutine CARMA_EmitParticle + end subroutine CARMAMODEL_EmitParticle !! Allows the model to perform its own initialization in addition to what is done @@ -500,20 +510,22 @@ end subroutine CARMA_EmitParticle !! !! @author Chuck Bardeen !! @version May-2009 - subroutine CARMA_InitializeModel(carma, lq_carma, rc) + subroutine CARMAMODEL_InitializeModel(carma, lq_carma, pbuf2d, rc) use constituents, only : pcnst + implicit none type(carma_type), intent(inout) :: carma !! the carma object logical, intent(inout) :: lq_carma(pcnst) !! flags to indicate whether the constituent !! could have a CARMA tendency + type(physics_buffer_desc), pointer :: pbuf2d(:,:) integer, intent(out) :: rc !! return code, negative indicates failure ! Default return code. rc = RC_OK return - end subroutine CARMA_InitializeModel + end subroutine CARMAMODEL_InitializeModel !! Sets the initial condition for CARMA aerosol particles. By default, there are no @@ -525,7 +537,7 @@ end subroutine CARMA_InitializeModel !! !! @author Chuck Bardeen !! @version May-2009 - subroutine CARMA_InitializeParticle(carma, ielem, ibin, latvals, lonvals, mask, q, rc) + subroutine CARMAMODEL_InitializeParticle(carma, ielem, ibin, latvals, lonvals, mask, q, rc) use shr_kind_mod, only: r8 => shr_kind_r8 implicit none @@ -552,15 +564,55 @@ subroutine CARMA_InitializeParticle(carma, ielem, ibin, latvals, lonvals, mask, end do return - end subroutine CARMA_InitializeParticle + end subroutine CARMAMODEL_InitializeParticle + + !! This routine is an extension of CARMA_CreateOpticsFile() that allows for + !! model specific tables to be created in addition to the model independent + !! methods that are in carma_intr.F90. + !! + !! The opticsType that is specified for the group determines how the optical + !! properties will be generated for that group. Each group can use a different + !! optics method if needed. Refractive indices need for these calculation are + !! are specified in the group's elements rather than at the group level. This + !! allows various mixing approaches to be used to determine the refractive index + !! for the particle as a whole. If the refractive index for water is needed, + !! it is specific the the CARMAGAS object for H2O. + subroutine CARMAMODEL_CreateOpticsFile(carma, igroup, opticsType, rc) + + implicit none + + type(carma_type), intent(inout) :: carma !! the carma object + integer, intent(in) :: igroup !! group identifier + integer, intent(in) :: opticsType !! optics type (see I_OPTICS_... in carma_enums.F90) + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Local variables + logical :: do_mie + integer :: cnsttype ! constituent type + + ! Assume success. + rc = 0 + + ! What type of calculation is needed for this group? + ! + ! NOTE: Some of these calculations generate optical properties as single mass + ! coefficients, while others are lookup tables designed around multiple + ! dimensions. + select case (opticsType) + case default + call endrun('carma_CreateOpticsFile:: Unknown optics type.') + end select + + return + end subroutine CARMAMODEL_CreateOpticsFile !! Called after wet deposition has been performed. Allows the specific model to add !! wet deposition of CARMA aerosols to the aerosols being communicated to the surface. !! !! @version July-2011 !! @author Chuck Bardeen - subroutine CARMA_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) + subroutine CARMAMODEL_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) use camsrfexch, only: cam_out_t implicit none @@ -579,6 +631,93 @@ subroutine CARMA_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) rc = RC_OK return - end subroutine CARMA_WetDeposition + end subroutine CARMAMODEL_WetDeposition + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_CalculateCloudborneDiagnostics(carma, state, pbuf, aerclddiag, rc) + + type(carma_type), intent(in) :: carma !! the carma object + type(physics_state), intent(in) :: state !! Physics state variables - before pname + type(physics_buffer_desc), pointer, intent(in) :: pbuf(:) !! physics buffer + real(r8), intent(out) :: aerclddiag(pcols,MAXCLDAERDIAG) !! the total cloudborne aerosols, supports up to MAXCLDAERDIAG different values + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_CalculateCloudborneDiagnostics + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_OutputBudgetDiagnostics(carma, icnst4elem, icnst4gas, state, ptend, old_cflux, cflux, dt, pname, rc) + use cam_history, only: outfld + use constituents, only: pcnst, cnst_get_ind + + type(carma_type), intent(in) :: carma !! the carma object + integer, intent(in) :: icnst4elem(NELEM, NBIN) !! constituent index for a carma element + integer, intent(in) :: icnst4gas(NGAS) !! constituent index for a carma gas + type(physics_state), intent(in) :: state !! Physics state variables - before pname + type(physics_ptend), intent(in) :: ptend !! indivdual parameterization tendencies + real(r8) :: old_cflux(pcols,pcnst) !! cam_in%clfux from before the timestep_tend + real(r8) :: cflux(pcols,pcnst) !! cam_in%clfux from after the timestep_tend + real(r8), intent(in) :: dt !! timestep (s) + character(*), intent(in) :: pname !! short name of the physics package + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_OutputBudgetDiagnostics + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_OutputCloudborneDiagnostics(carma, state, pbuf, dt, pname, oldaerclddiag, rc) + use cam_history, only: outfld + + type(carma_type), intent(in) :: carma !! the carma object + type(physics_state), intent(in) :: state !! Physics state variables - before CARMA + type(physics_buffer_desc), pointer, intent(in) :: pbuf(:) !! physics buffer + real(r8), intent(in) :: dt !! timestep (s) + character(*), intent(in) :: pname !! short name of the physics package + real(r8), intent(in ) :: oldaerclddiag(pcols,MAXCLDAERDIAG) !! the before timestep cloudborne aerosol diags + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_OutputCloudborneDiagnostics + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_OutputDiagnostics(carma, icnst4elem, state, ptend, pbuf, cam_in, rc) + use cam_history, only: outfld + use constituents, only: cnst_get_ind + use camsrfexch, only: cam_in_t + + type(carma_type), intent(in) :: carma !! the carma object + integer, intent(in) :: icnst4elem(NELEM, NBIN) !! constituent index for a carma element + type(physics_state), intent(in) :: state !! Physics state variables - before CARMA + type(physics_ptend), intent(in) :: ptend !! indivdual parameterization tendencies + type(physics_buffer_desc), pointer, intent(in) :: pbuf(:) !! physics buffer + type(cam_in_t), intent(in) :: cam_in !! surface inputs + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_OutputDiagnostics -end module +end module carma_model_mod diff --git a/src/physics/carma/models/test_tracers2/carma_model_mod.F90 b/src/physics/carma/models/test_tracers2/carma_model_mod.F90 index ecb3324ed8..d6a74c4d12 100644 --- a/src/physics/carma/models/test_tracers2/carma_model_mod.F90 +++ b/src/physics/carma/models/test_tracers2/carma_model_mod.F90 @@ -49,14 +49,19 @@ module carma_model_mod private ! Declare the public methods. - public CARMA_DefineModel - public CARMA_Detrain - public CARMA_DiagnoseBins - public CARMA_DiagnoseBulk - public CARMA_EmitParticle - public CARMA_InitializeModel - public CARMA_InitializeParticle - public CARMA_WetDeposition + public CARMAMODEL_CalculateCloudborneDiagnostics + public CARMAMODEL_CreateOpticsFile + public CARMAMODEL_DefineModel + public CARMAMODEL_Detrain + public CARMAMODEL_DiagnoseBins + public CARMAMODEL_DiagnoseBulk + public CARMAMODEL_EmitParticle + public CARMAMODEL_InitializeModel + public CARMAMODEL_InitializeParticle + public CARMAMODEL_OutputBudgetDiagnostics + public CARMAMODEL_OutputCloudborneDiagnostics + public CARMAMODEL_OutputDiagnostics + public CARMAMODEL_WetDeposition ! Declare public constants integer, public, parameter :: NGROUP = 7 !! Number of particle groups @@ -69,6 +74,10 @@ module carma_model_mod integer, public, parameter :: NMIE_RH = 8 !! Number of relative humidities for mie calculations real(kind=f), public :: mie_rh(NMIE_RH) + integer, public, parameter :: NMIE_WTP = 0 !! Number of weight percents for mie calculations + real(kind=f), public :: mie_wtp(NMIE_WTP) + integer, public, parameter :: NREFIDX = 1 !! Number of refractive indices per element + ! Defines whether the groups should undergo deep convection in phase 1 or phase 2. ! Water vapor and cloud particles are convected in phase 1, while all other constituents ! are done in phase 2. @@ -99,7 +108,7 @@ module carma_model_mod !! !! @version May-2009 !! @author Chuck Bardeen - subroutine CARMA_DefineModel(carma, rc) + subroutine CARMAMODEL_DefineModel(carma, rc) type(carma_type), intent(inout) :: carma !! the carma object integer, intent(out) :: rc !! return code, negative indicates failure @@ -113,7 +122,7 @@ subroutine CARMA_DefineModel(carma, rc) rc = RC_OK call CARMA_Get(carma, rc, do_print=do_print, LUNOPRT=LUNOPRT) - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMA_Get failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMA_Get failed.') ! Report model specific configuration parameters. if (masterproc) then @@ -133,25 +142,25 @@ subroutine CARMA_DefineModel(carma, rc) ! defined. If wetdep is defined, then the optional solubility factor ! should also be defined. call CARMAGROUP_Create(carma, 1, "Region 1", rmin, vmrat, I_SPHERE, 1._f, .True., rc, shortname="CRRG1") - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMAGROUP_Create failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMAGROUP_Create failed.') call CARMAGROUP_Create(carma, 2, "Region 2", rmin, vmrat, I_SPHERE, 1._f, .True., rc, shortname="CRRG2") - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMAGROUP_Create failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMAGROUP_Create failed.') call CARMAGROUP_Create(carma, 3, "Region 3", rmin, vmrat, I_SPHERE, 1._f, .True., rc, shortname="CRRG3") - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMAGROUP_Create failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMAGROUP_Create failed.') call CARMAGROUP_Create(carma, 4, "Region 4", rmin, vmrat, I_SPHERE, 1._f, .True., rc, shortname="CRRG4") - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMAGROUP_Create failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMAGROUP_Create failed.') call CARMAGROUP_Create(carma, 5, "Region 5", rmin, vmrat, I_SPHERE, 1._f, .True., rc, shortname="CRRG5") - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMAGROUP_Create failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMAGROUP_Create failed.') call CARMAGROUP_Create(carma, 6, "Region 6", rmin, vmrat, I_SPHERE, 1._f, .True., rc, shortname="CRRG6") - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMAGROUP_Create failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMAGROUP_Create failed.') call CARMAGROUP_Create(carma, 7, "Rest of World", rmin, vmrat, I_SPHERE, 1._f, .True., rc, shortname="CRRG7") - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMAGROUP_Create failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMAGROUP_Create failed.') ! Define the Elements @@ -159,25 +168,25 @@ subroutine CARMA_DefineModel(carma, rc) ! NOTE: For CAM, the optional shortname needs to be provided for the group. These names ! should be 6 characters or less and without spaces. call CARMAELEMENT_Create(carma, 1, 1, "Region 1", WTMOL_AIR, I_INVOLATILE, I_INERT, rc, shortname="CRRG1") - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMAElement_Create failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMAElement_Create failed.') call CARMAELEMENT_Create(carma, 2, 2, "Region 2", WTMOL_AIR, I_INVOLATILE, I_INERT, rc, shortname="CRRG2") - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMAElement_Create failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMAElement_Create failed.') call CARMAELEMENT_Create(carma, 3, 3, "Region 3", WTMOL_AIR, I_INVOLATILE, I_INERT, rc, shortname="CRRG3") - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMAElement_Create failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMAElement_Create failed.') call CARMAELEMENT_Create(carma, 4, 4, "Region 4", WTMOL_AIR, I_INVOLATILE, I_INERT, rc, shortname="CRRG4") - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMAElement_Create failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMAElement_Create failed.') call CARMAELEMENT_Create(carma, 5, 5, "Region 5", WTMOL_AIR, I_INVOLATILE, I_INERT, rc, shortname="CRRG5") - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMAElement_Create failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMAElement_Create failed.') call CARMAELEMENT_Create(carma, 6, 6, "Region 6", WTMOL_AIR, I_INVOLATILE, I_INERT, rc, shortname="CRRG6") - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMAElement_Create failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMAElement_Create failed.') call CARMAELEMENT_Create(carma, 7, 7, "Rest of World", WTMOL_AIR, I_INVOLATILE, I_INERT, rc, shortname="CRRG7") - if (rc < RC_OK) call endrun('CARMA_DefineModel::CARMAElement_Create failed.') + if (rc < RC_OK) call endrun('CARMAMODEL_DefineModel::CARMAElement_Create failed.') ! Define the Solutes @@ -190,7 +199,7 @@ subroutine CARMA_DefineModel(carma, rc) return - end subroutine CARMA_DefineModel + end subroutine CARMAMODEL_DefineModel !! Defines all the CARMA components (groups, elements, solutes and gases) and process @@ -200,7 +209,7 @@ end subroutine CARMA_DefineModel !! @author Chuck Bardeen !! !! @see CARMASTATE_SetDetrain - subroutine CARMA_Detrain(carma, cstate, cam_in, dlf, state, icol, dt, rc, rliq, prec_str, snow_str, & + subroutine CARMAMODEL_Detrain(carma, cstate, cam_in, dlf, state, icol, dt, rc, rliq, prec_str, snow_str, & tnd_qsnow, tnd_nsnow) use camsrfexch, only: cam_in_t use physconst, only: latice, latvap, cpair, cappa @@ -226,14 +235,14 @@ subroutine CARMA_Detrain(carma, cstate, cam_in, dlf, state, icol, dt, rc, rliq, rc = RC_OK return - end subroutine CARMA_Detrain + end subroutine CARMAMODEL_Detrain !! For diagnostic groups, sets up up the CARMA bins based upon the CAM state. !! !! @version July-2009 !! @author Chuck Bardeen - subroutine CARMA_DiagnoseBins(carma, cstate, state, pbuf, icol, dt, rc, rliq, prec_str, snow_str) + subroutine CARMAMODEL_DiagnoseBins(carma, cstate, state, pbuf, icol, dt, rc, rliq, prec_str, snow_str) use time_manager, only: is_first_step implicit none @@ -259,7 +268,7 @@ subroutine CARMA_DiagnoseBins(carma, cstate, state, pbuf, icol, dt, rc, rliq, pr ! code to determine the mass in each bin from the CAM state. return - end subroutine CARMA_DiagnoseBins + end subroutine CARMAMODEL_DiagnoseBins !! For diagnostic groups, determines the tendencies on the CAM state from the CARMA bins. @@ -269,7 +278,7 @@ end subroutine CARMA_DiagnoseBins !! !! @version July-2009 !! @author Chuck Bardeen - subroutine CARMA_DiagnoseBulk(carma, cstate, cam_out, state, pbuf, ptend, icol, dt, rc, rliq, prec_str, snow_str, & + subroutine CARMAMODEL_DiagnoseBulk(carma, cstate, cam_out, state, pbuf, ptend, icol, dt, rc, rliq, prec_str, snow_str, & prec_sed, snow_sed, tnd_qsnow, tnd_nsnow, re_ice) use shr_kind_mod, only: r8 => shr_kind_r8 use ppgrid, only: pcols, pver @@ -332,7 +341,7 @@ subroutine CARMA_DiagnoseBulk(carma, cstate, cam_out, state, pbuf, ptend, icol, end if return - end subroutine CARMA_DiagnoseBulk + end subroutine CARMAMODEL_DiagnoseBulk !! Calculates the emissions for CARMA aerosol particles. @@ -359,7 +368,7 @@ end subroutine CARMA_DiagnoseBulk !! !! @author Chuck Bardeen !! @version May-2009 - subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tendency, surfaceFlux, rc) + subroutine CARMAMODEL_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tendency, surfaceFlux, pbuf, rc) use shr_kind_mod, only: r8 => shr_kind_r8 use ppgrid, only: pcols, pver use physics_types, only: physics_state @@ -379,6 +388,7 @@ subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tend type(cam_in_t), intent(in) :: cam_in !! surface inputs real(r8), intent(out) :: tendency(pcols, pver) !! constituent tendency (kg/kg/s) real(r8), intent(out) :: surfaceFlux(pcols) !! constituent surface flux (kg/m^2/s) + type(physics_buffer_desc), pointer :: pbuf(:) !! physics buffer integer, intent(out) :: rc !! return code, negative indicates failure real(r8) :: lat(state%ncol) ! latitude (degrees) @@ -497,7 +507,7 @@ subroutine CARMA_EmitParticle(carma, ielem, ibin, icnst, dt, state, cam_in, tend end if return - end subroutine CARMA_EmitParticle + end subroutine CARMAMODEL_EmitParticle !! Allows the model to perform its own initialization in addition to what is done @@ -508,20 +518,21 @@ end subroutine CARMA_EmitParticle !! !! @author Chuck Bardeen !! @version May-2009 - subroutine CARMA_InitializeModel(carma, lq_carma, rc) + subroutine CARMAMODEL_InitializeModel(carma, lq_carma, pbuf2d, rc) use constituents, only : pcnst implicit none type(carma_type), intent(inout) :: carma !! the carma object logical, intent(inout) :: lq_carma(pcnst) !! flags to indicate whether the constituent !! could have a CARMA tendency + type(physics_buffer_desc), pointer :: pbuf2d(:,:) integer, intent(out) :: rc !! return code, negative indicates failure ! Default return code. rc = RC_OK return - end subroutine CARMA_InitializeModel + end subroutine CARMAMODEL_InitializeModel !! Sets the initial condition for CARMA aerosol particles. By default, there are no @@ -533,7 +544,7 @@ end subroutine CARMA_InitializeModel !! !! @author Chuck Bardeen !! @version May-2009 - subroutine CARMA_InitializeParticle(carma, ielem, ibin, latvals, lonvals, mask, q, rc) + subroutine CARMAMODEL_InitializeParticle(carma, ielem, ibin, latvals, lonvals, mask, q, rc) use shr_kind_mod, only: r8 => shr_kind_r8 implicit none @@ -560,15 +571,55 @@ subroutine CARMA_InitializeParticle(carma, ielem, ibin, latvals, lonvals, mask, end do return - end subroutine CARMA_InitializeParticle + end subroutine CARMAMODEL_InitializeParticle + + !! This routine is an extension of CARMA_CreateOpticsFile() that allows for + !! model specific tables to be created in addition to the model independent + !! methods that are in carma_intr.F90. + !! + !! The opticsType that is specified for the group determines how the optical + !! properties will be generated for that group. Each group can use a different + !! optics method if needed. Refractive indices need for these calculation are + !! are specified in the group's elements rather than at the group level. This + !! allows various mixing approaches to be used to determine the refractive index + !! for the particle as a whole. If the refractive index for water is needed, + !! it is specific the the CARMAGAS object for H2O. + subroutine CARMAMODEL_CreateOpticsFile(carma, igroup, opticsType, rc) + + implicit none + + type(carma_type), intent(inout) :: carma !! the carma object + integer, intent(in) :: igroup !! group identifier + integer, intent(in) :: opticsType !! optics type (see I_OPTICS_... in carma_enums.F90) + integer, intent(out) :: rc !! return code, negative indicates failure + ! Local variables + logical :: do_mie + integer :: cnsttype ! constituent type + + ! Assume success. + rc = 0 + + ! What type of calculation is needed for this group? + ! + ! NOTE: Some of these calculations generate optical properties as single mass + ! coefficients, while others are lookup tables designed around multiple + ! dimensions. + select case (opticsType) + + case default + call endrun('carma_CreateOpticsFile:: Unknown optics type.') + end select + + return + end subroutine CARMAMODEL_CreateOpticsFile !! Called after wet deposition has been performed. Allows the specific model to add !! wet deposition of CARMA aerosols to the aerosols being communicated to the surface. !! !! @version July-2011 !! @author Chuck Bardeen - subroutine CARMA_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) + subroutine CARMAMODEL_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) use camsrfexch, only: cam_out_t implicit none @@ -587,6 +638,94 @@ subroutine CARMA_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) rc = RC_OK return - end subroutine CARMA_WetDeposition + end subroutine CARMAMODEL_WetDeposition + + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_CalculateCloudborneDiagnostics(carma, state, pbuf, aerclddiag, rc) + + type(carma_type), intent(in) :: carma !! the carma object + type(physics_state), intent(in) :: state !! Physics state variables - before pname + type(physics_buffer_desc), pointer, intent(in) :: pbuf(:) !! physics buffer + real(r8), intent(out) :: aerclddiag(pcols,MAXCLDAERDIAG) !! the total cloudborne aerosols, supports up to MAXCLDAERDIAG different values + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_CalculateCloudborneDiagnostics + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_OutputBudgetDiagnostics(carma, icnst4elem, icnst4gas, state, ptend, old_cflux, cflux, dt, pname, rc) + use cam_history, only: outfld + use constituents, only: pcnst, cnst_get_ind + + type(carma_type), intent(in) :: carma !! the carma object + integer, intent(in) :: icnst4elem(NELEM, NBIN) !! constituent index for a carma element + integer, intent(in) :: icnst4gas(NGAS) !! constituent index for a carma gas + type(physics_state), intent(in) :: state !! Physics state variables - before pname + type(physics_ptend), intent(in) :: ptend !! indivdual parameterization tendencies + real(r8) :: old_cflux(pcols,pcnst) !! cam_in%clfux from before the timestep_tend + real(r8) :: cflux(pcols,pcnst) !! cam_in%clfux from after the timestep_tend + real(r8), intent(in) :: dt !! timestep (s) + character(*), intent(in) :: pname !! short name of the physics package + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_OutputBudgetDiagnostics + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_OutputCloudborneDiagnostics(carma, state, pbuf, dt, pname, oldaerclddiag, rc) + use cam_history, only: outfld + + type(carma_type), intent(in) :: carma !! the carma object + type(physics_state), intent(in) :: state !! Physics state variables - before CARMA + type(physics_buffer_desc), pointer, intent(in) :: pbuf(:) !! physics buffer + real(r8), intent(in) :: dt !! timestep (s) + character(*), intent(in) :: pname !! short name of the physics package + real(r8), intent(in ) :: oldaerclddiag(pcols,MAXCLDAERDIAG) !! the before timestep cloudborne aerosol diags + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_OutputCloudborneDiagnostics + + !! Called at the end of the timestep after all the columns have been processed to + !! to allow additional diagnostics that have been stored in pbuf to be output. + !! + !! Stub version + subroutine CARMAMODEL_OutputDiagnostics(carma, icnst4elem, state, ptend, pbuf, cam_in, rc) + use cam_history, only: outfld + use constituents, only: cnst_get_ind + use camsrfexch, only: cam_in_t + + type(carma_type), intent(in) :: carma !! the carma object + integer, intent(in) :: icnst4elem(NELEM, NBIN) !! constituent index for a carma element + type(physics_state), intent(in) :: state !! Physics state variables - before CARMA + type(physics_ptend), intent(in) :: ptend !! indivdual parameterization tendencies + type(physics_buffer_desc), pointer, intent(in) :: pbuf(:) !! physics buffer + type(cam_in_t), intent(in) :: cam_in !! surface inputs + integer, intent(out) :: rc !! return code, negative indicates failure + + ! Default return code. + rc = RC_OK + + return + end subroutine CARMAMODEL_OutputDiagnostics -end module +end module carma_model_mod diff --git a/src/physics/carma/models/tholin/carma_model_mod.F90 b/src/physics/carma/models/tholin/carma_model_mod.F90 index 460971db9d..ac5216f130 100755 --- a/src/physics/carma/models/tholin/carma_model_mod.F90 +++ b/src/physics/carma/models/tholin/carma_model_mod.F90 @@ -102,7 +102,7 @@ subroutine CARMA_DefineModel(carma, rc) integer, intent(out) :: rc !! return code, negative indicates failure ! Local variables - real(kind=f) :: RHO_THOLIN = 0.64 ! density of tholin particles (g/cm) + real(kind=f) :: RHO_THOLIN = 0.64_f ! density of tholin particles (g/cm) real(kind=f), parameter :: tholin_rmin = 1.e-7_f ! dust minimum radius (cm) real(kind=f), parameter :: tholin_vmrat = 2.5_f ! dust volume ratio @@ -509,7 +509,7 @@ subroutine CARMA_InitializeModel(carma, lq_carma, rc) carma_emis_ilev_max = carma_emis_nLevs do ilev = 1, carma_emis_nLevs - if (carma_emis_rate(ilev) <= 0.0) then + if (carma_emis_rate(ilev) <= 0.0_r8) then carma_emis_ilev_min = ilev + 1 else exit @@ -517,7 +517,7 @@ subroutine CARMA_InitializeModel(carma, lq_carma, rc) end do do ilev = carma_emis_nLevs, 1, -1 - if (carma_emis_rate(ilev) <= 0.0) then + if (carma_emis_rate(ilev) <= 0.0_r8) then carma_emis_ilev_max = ilev - 1 else exit @@ -639,4 +639,4 @@ subroutine CARMA_WetDeposition(carma, ielem, ibin, sflx, cam_out, state, rc) return end subroutine CARMA_WetDeposition -end module +end module carma_model_mod diff --git a/src/physics/rrtmgp/rrtmgp_inputs.F90 b/src/physics/rrtmgp/rrtmgp_inputs.F90 index 191b6ff8a0..4f73ae9029 100644 --- a/src/physics/rrtmgp/rrtmgp_inputs.F90 +++ b/src/physics/rrtmgp/rrtmgp_inputs.F90 @@ -178,8 +178,6 @@ subroutine rrtmgp_set_state( & tref_max = kdist_sw%get_temp_max() t_rad = merge(t_rad, tref_min, t_rad > tref_min) t_rad = merge(t_rad, tref_max, t_rad < tref_max) - t_sfc = merge(t_sfc, tref_min, t_sfc > tref_min) - t_sfc = merge(t_sfc, tref_max, t_sfc < tref_max) ! Construct arrays containing only daylight columns do i = 1, nday diff --git a/src/physics/simple/physpkg.F90 b/src/physics/simple/physpkg.F90 index 8c9c1586ef..c236f7f021 100644 --- a/src/physics/simple/physpkg.F90 +++ b/src/physics/simple/physpkg.F90 @@ -503,7 +503,7 @@ subroutine tphysac (ztodt, cam_in, cam_out, state, tend, pbuf) use air_composition, only: cpairv, cp_or_cv_dycore use time_manager, only: get_nstep use nudging, only: Nudge_Model, Nudge_ON, nudging_timestep_tend - use check_energy, only: check_energy_chng + use check_energy, only: check_energy_cam_chng ! Arguments ! @@ -595,7 +595,7 @@ subroutine tphysac (ztodt, cam_in, cam_out, state, tend, pbuf) if (Nudge_Model .and. Nudge_ON) then call nudging_timestep_tend(state,ptend) call physics_update(state, ptend, ztodt, tend) - call check_energy_chng(state, tend, "nudging", nstep, ztodt, zero, zero, zero, zero) + call check_energy_cam_chng(state, tend, "nudging", nstep, ztodt, zero, zero, zero, zero) endif call tot_energy_phys(state, 'phAP') @@ -728,7 +728,8 @@ subroutine tphysbc (ztodt, state, tend, pbuf, cam_out, cam_in ) use cam_diagnostics, only: diag_conv_tend_ini, diag_conv, diag_export use cam_history, only: outfld use time_manager, only: get_nstep - use check_energy, only: check_energy_chng, check_energy_fix, check_energy_timestep_init + use check_energy, only: check_energy_cam_chng, check_energy_cam_fix + use check_energy, only: check_energy_timestep_init use check_energy, only: check_tracers_data, check_tracers_init, check_tracers_chng use check_energy, only: tot_energy_phys use chemistry, only: chem_is_active, chem_timestep_tend @@ -831,9 +832,9 @@ subroutine tphysbc (ztodt, state, tend, pbuf, cam_out, cam_in ) call t_startf('energy_fixer') if (adiabatic .and. (.not. dycore_is('EUL'))) then - call check_energy_fix(state, ptend, nstep, flx_heat) + call check_energy_cam_fix(state, ptend, nstep, flx_heat) call physics_update(state, ptend, ztodt, tend) - call check_energy_chng(state, tend, "chkengyfix", nstep, ztodt, zero, zero, zero, flx_heat) + call check_energy_cam_chng(state, tend, "chkengyfix", nstep, ztodt, zero, zero, zero, flx_heat) call outfld( 'EFIX', flx_heat , pcols, lchnk ) end if @@ -968,7 +969,7 @@ subroutine tphysbc (ztodt, state, tend, pbuf, cam_out, cam_in ) ! surface flux is computed and supplied as an argument to ! check_energy_chng to account for how the simplified physics forcings are ! changing the total exnergy. - call check_energy_chng(state, tend, "tphysidl", nstep, ztodt, zero, zero, zero, zero) + call check_energy_cam_chng(state, tend, "tphysidl", nstep, ztodt, zero, zero, zero, zero) if (chem_is_active()) then call t_startf('simple_chem') diff --git a/src/physics/spcam/crm_physics.F90 b/src/physics/spcam/crm_physics.F90 index a1d9d2560d..8812d2be72 100644 --- a/src/physics/spcam/crm_physics.F90 +++ b/src/physics/spcam/crm_physics.F90 @@ -750,7 +750,7 @@ subroutine crm_physics_tend(ztodt, state, tend, ptend, pbuf, cam_in) use crmx_crm_module, only: crm use crmx_microphysics, only: nmicro_fields use physconst, only: latvap - use check_energy, only: check_energy_chng + use check_energy, only: check_energy_cam_chng use phys_grid, only: get_rlat_all_p, get_rlon_all_p, get_lon_all_p, get_lat_all_p use modal_aero_calcsize, only: modal_aero_calcsize_sub use micro_pumas_utils, only: size_dist_param_liq, mg_liq_props, mincld, qsmall @@ -2152,7 +2152,7 @@ subroutine crm_physics_tend(ztodt, state, tend, ptend, pbuf, cam_in) end if ! check water and energy conservation - call check_energy_chng(state_loc, tend_loc, "crm_tend", nstep, ztodt, zero, & + call check_energy_cam_chng(state_loc, tend_loc, "crm_tend", nstep, ztodt, zero, & prec_dp(:ncol)+(qli_hydro(:ncol,2)-qli_hydro(:ncol,1))/ztodt/1000._r8, & snow_dp(:ncol)+(qi_hydro(:ncol,2)-qi_hydro(:ncol,1))/ztodt/1000._r8, radflux) diff --git a/src/physics/spcam/spcam_drivers.F90 b/src/physics/spcam/spcam_drivers.F90 index ebe6507607..b9f7a596cc 100644 --- a/src/physics/spcam/spcam_drivers.F90 +++ b/src/physics/spcam/spcam_drivers.F90 @@ -300,7 +300,7 @@ subroutine tphysbc_spcam (ztodt, state, & use cam_history, only: outfld use constituents, only: pcnst, qmin, cnst_get_ind use time_manager, only: get_nstep - use check_energy, only: check_energy_chng, check_energy_fix + use check_energy, only: check_energy_cam_chng, check_energy_cam_fix use check_energy, only: check_tracers_data, check_tracers_init use dycore, only: dycore_is use radiation, only: radiation_tend @@ -441,9 +441,9 @@ subroutine tphysbc_spcam (ztodt, state, & call t_startf('energy_fixer') if (dycore_is('LR') .or. dycore_is('SE')) then - call check_energy_fix(state, ptend, nstep, flx_heat) + call check_energy_cam_fix(state, ptend, nstep, flx_heat) call physics_update(state, ptend, ztodt, tend) - call check_energy_chng(state, tend, "chkengyfix", nstep, ztodt, zero, zero, zero, flx_heat) + call check_energy_cam_chng(state, tend, "chkengyfix", nstep, ztodt, zero, zero, zero, flx_heat) call outfld('EFIX', flx_heat, pcols,lchnk) end if ! Save state for convective tendency calculations. @@ -557,7 +557,7 @@ subroutine tphysbc_spcam (ztodt, state, & call physics_update(state, ptend, ztodt, tend) - call check_energy_chng(state, tend, "spradheat", nstep, ztodt, zero, zero, zero, zero) + call check_energy_cam_chng(state, tend, "spradheat", nstep, ztodt, zero, zero, zero, zero) call t_stopf('radiation') diff --git a/src/utils/cam_pio_utils.F90 b/src/utils/cam_pio_utils.F90 index 350c421539..7fd58b13cd 100644 --- a/src/utils/cam_pio_utils.F90 +++ b/src/utils/cam_pio_utils.F90 @@ -1133,12 +1133,14 @@ subroutine cam_pio_openfile(file, fname, mode) integer :: ierr + if(pio_iotask_rank(pio_subsystem) == 0) then + write(iulog,*) 'Opening existing file ', trim(fname), file%fh + end if + ierr = pio_openfile(pio_subsystem, file, pio_iotype, fname, mode) if(ierr/= PIO_NOERR) then call endrun('Failed to open '//trim(fname)//' to read') - else if(pio_iotask_rank(pio_subsystem) == 0) then - write(iulog,*) 'Opened existing file ', trim(fname), file%fh end if end subroutine cam_pio_openfile diff --git a/src/utils/cam_thermo_formula.F90 b/src/utils/cam_thermo_formula.F90 new file mode 100644 index 0000000000..7781e9da9c --- /dev/null +++ b/src/utils/cam_thermo_formula.F90 @@ -0,0 +1,14 @@ +module cam_thermo_formula + + implicit none + private + save + + ! energy_formula options for use by CCPPized check_energy + integer, public, parameter :: ENERGY_FORMULA_DYCORE_FV = 0 ! vc_moist_pressure + integer, public, parameter :: ENERGY_FORMULA_DYCORE_SE = 1 ! vc_dry_pressure + integer, public, parameter :: ENERGY_FORMULA_DYCORE_MPAS = 2 ! vc_height + + !REMOVECAM: in CAM, energy_formula_physics and energy_formula_dycore still uses vc_physics + ! and vc_dycore in dyn_tests_utils. The values are the same. +end module cam_thermo_formula diff --git a/test/system/TR8.sh b/test/system/TR8.sh index cbdb400463..22ec597f5d 100755 --- a/test/system/TR8.sh +++ b/test/system/TR8.sh @@ -10,6 +10,8 @@ ruby $ADDREALKIND_EXE -r r8 -l 1 -d $CAM_ROOT/components/cam/src/physics/cam rc=$? ruby $ADDREALKIND_EXE -r r8 -l 1 -d $CAM_ROOT/components/cam/src/physics/camrt rc=`expr $? + $rc` +ruby $ADDREALKIND_EXE -r r8 -l 1 -d $CAM_ROOT/components/cam/src/physics/carma +rc=`expr $? + $rc` ruby $ADDREALKIND_EXE -r r8 -l 1 -d $CAM_ROOT/components/cam/src/physics/rrtmg -s aer_src rc=`expr $? + $rc` ruby $ADDREALKIND_EXE -r r8 -l 1 -d $CAM_ROOT/components/cam/src/physics/rrtmgp -s data,ext @@ -27,6 +29,8 @@ ruby $ADDREALKIND_EXE -r r8 -l 1 -d $CAM_ROOT/src/physics/cam rc=$? ruby $ADDREALKIND_EXE -r r8 -l 1 -d $CAM_ROOT/src/physics/camrt rc=`expr $? + $rc` +ruby $ADDREALKIND_EXE -r r8 -l 1 -d $CAM_ROOT/src/physics/carma +rc=$? ruby $ADDREALKIND_EXE -r r8 -l 1 -d $CAM_ROOT/src/physics/rrtmg -s aer_src rc=`expr $? + $rc` ruby $ADDREALKIND_EXE -r r8 -l 1 -d $CAM_ROOT/src/physics/rrtmgp -s data,ext diff --git a/test/system/archive_baseline.sh b/test/system/archive_baseline.sh index f64561dc4d..99a1003fb0 100755 --- a/test/system/archive_baseline.sh +++ b/test/system/archive_baseline.sh @@ -97,6 +97,7 @@ if [ -n "$CESM_TESTDIR" ]; then if [ -d $CESM_TESTDIR/baselines ]; then echo "Using cp to archive baselines." cp -r $CESM_TESTDIR/baselines/. $root_baselinedir/$cam_tag + chmod -R a+r ${baselinedir} else echo "Using bless_test_results to archive baselines." ../../cime/CIME/Tools/bless_test_results -p -t '' -c '' -r $CESM_TESTDIR --baseline-root $root_baselinedir -b $cam_tag -f -s diff --git a/test/system/da_cam_no_data_mod.sh b/test/system/da_cam_no_data_mod.sh deleted file mode 100755 index ef5313d4cc..0000000000 --- a/test/system/da_cam_no_data_mod.sh +++ /dev/null @@ -1,95 +0,0 @@ -#! /bin/bash - -############################################################################## -### -### A stub data assimilation script that prints out information but makes -### no modifications to model data. -### Script checks for proper pre and post data assimilation output -### Tests using this script should be BFB with a non-data assimilation run -### -############################################################################## - -errcode=0 -if [ $# -ne 2 ]; then - echo "ERROR: Wrong number of arguments, $# (should be 2)" - errcode=$(( errcode + 1 )) -else - caseroot=$1 - cycle=$2 - echo "caseroot: ${caseroot}" - echo "cycle: ${cycle}" - cd ${caseroot} - res=$? - if [ $res -ne 0 ]; then - echo "ERROR: Unable to cd to caseroot, ${caseroot}" - errcode=$(( errcode + 1 )) - else - ./xmlchange DATA_ASSIMILATION_ATM=TRUE - res=$? - if [ $res -ne 0 ]; then - echo "ERROR: Unable to change DATA_ASSIMILATION_ATM to TRUE" - errcode=$(( errcode + 1 )) - fi - rundir="`./xmlquery --value RUNDIR`" - ninst=`./xmlquery --value NINST_ATM` - if [ -n "${rundir}" -a -d "${rundir}" ]; then - cd ${rundir} - res=$? - if [ $res -ne 0 ]; then - echo "ERROR: Unable to cd to rundir, ${rundir}" - errcode=$(( errcode + 1 )) - else - # Check the latest log file for a resume signal - if [ $ninst -eq 1 ]; then - lfiles="`ls -t atm.log.* 2> /dev/null | head -1`" - else - # Multi-instance, look for wav_nnnn.log* - for inst in `seq 1 $ninst`; do - ifilename="`printf "atm_%04d.log.*" $inst`" - ifile="`ls -t ${ifilename} 2> /dev/null | head -1`" - if [ -z "${ifile}" ]; then - echo "No log files for instance $ninst found" - errcode=$(( errcode + 1 )) - elif [ -z "${lfiles}" ]; then - lfiles="${ifile}" - else - lfiles="${lfiles} ${ifile}" - fi - done - fi - if [ -z "${lfiles}" ]; then - echo "ERROR: Unable to find atm log file in `pwd -P`" - errcode=$(( errcode + 1 )) - else - for atmfile in ${lfiles}; do - dasig="`zgrep '^[ ]*DART run using CAM initial mode$' ${atmfile} 2> /dev/null`" - initsig="`zgrep '^[ ]*Initial run$' ${atmfile} 2> /dev/null`" - if [ $cycle -gt 0 ]; then - if [ -n "${dasig}" ]; then - echo "Post-DA resume signal found for cycle ${cycle}" - else - echo "No post-DA resume signal for cycle ${cycle}" - fi - elif [ -n "${dasig}" ]; then - echo "Bad Post-DA resume signal found for cycle ${cycle}" - fi - if [ $cycle -eq 0 ]; then - if [ -n "${initsig}" ]; then - echo "Initial run signal found for cycle ${cycle}" - else - echo "No initial run signal found for cycle ${cycle}" - fi - elif [ -n "${initsig}" ]; then - echo "Bad initial run signal found for cycle ${cycle}" - fi - done - fi - fi - else - echo "ERROR: RUNDIR (${rundir}) is not a valid directory" - errcode=$(( errcode + 1 )) - fi - fi -fi - -exit $errcode