-invalid file format
-"""
- with open(file_path, 'w') as fhandle:
- fhandle.write(contents)
- with self.assertRaises(RuntimeError):
- read_externals_description_file(root_dir, filename)
- os.remove(file_path)
-
-
-class TestCreateExternalsDescription(unittest.TestCase):
- """Test the application logic of creat_externals_description
- """
-
- def setUp(self):
- """Create config object used as basis for all tests
- """
- self._config = config_parser()
- self._gmconfig = config_parser()
- self.setup_config()
-
- def setup_config(self):
- """Boiler plate construction of xml string for componet 1
- """
- # Create a standard externals config with a single external
- name = 'test'
- self._config.add_section(name)
- self._config.set(name, ExternalsDescription.PATH, 'externals')
- self._config.set(name, ExternalsDescription.PROTOCOL, 'git')
- self._config.set(name, ExternalsDescription.REPO_URL, '/path/to/repo')
- self._config.set(name, ExternalsDescription.TAG, 'test_tag')
- self._config.set(name, ExternalsDescription.REQUIRED, 'True')
-
- self._config.add_section(DESCRIPTION_SECTION)
- self._config.set(DESCRIPTION_SECTION, VERSION_ITEM, '1.0.0')
-
- # Create a .gitmodules test
- name = 'submodule "gitmodules_test"'
- self._gmconfig.add_section(name)
- self._gmconfig.set(name, "path", 'externals/test')
- self._gmconfig.set(name, "url", '/path/to/repo')
- # NOTE(goldy, 2019-03) Should test other possible keywords such as
- # fetchRecurseSubmodules, ignore, and shallow
-
- @staticmethod
- def setup_dict_config():
- """Create the full container dictionary with simple and mixed use
- externals
-
- """
- rdatat = {ExternalsDescription.PROTOCOL: 'git',
- ExternalsDescription.REPO_URL: 'simple-ext.git',
- ExternalsDescription.TAG: 'tag1'}
- rdatab = {ExternalsDescription.PROTOCOL: 'git',
- ExternalsDescription.REPO_URL: 'simple-ext.git',
- ExternalsDescription.BRANCH: 'feature2'}
- rdatam = {ExternalsDescription.PROTOCOL: 'git',
- ExternalsDescription.REPO_URL: 'mixed-cont-ext.git',
- ExternalsDescription.BRANCH: 'master'}
- desc = {'simp_tag': {ExternalsDescription.REQUIRED: True,
- ExternalsDescription.PATH: 'simp_tag',
- ExternalsDescription.EXTERNALS: EMPTY_STR,
- ExternalsDescription.REPO: rdatat},
- 'simp_branch' : {ExternalsDescription.REQUIRED: True,
- ExternalsDescription.PATH: 'simp_branch',
- ExternalsDescription.EXTERNALS: EMPTY_STR,
- ExternalsDescription.REPO: rdatab},
- 'simp_opt': {ExternalsDescription.REQUIRED: False,
- ExternalsDescription.PATH: 'simp_opt',
- ExternalsDescription.EXTERNALS: EMPTY_STR,
- ExternalsDescription.REPO: rdatat},
- 'mixed_req': {ExternalsDescription.REQUIRED: True,
- ExternalsDescription.PATH: 'mixed_req',
- ExternalsDescription.EXTERNALS: 'sub-ext.cfg',
- ExternalsDescription.REPO: rdatam}}
-
- return desc
-
- def test_cfg_v1_ok(self):
- """Test that a correct cfg v1 object is created by create_externals_description
-
- """
- self._config.set(DESCRIPTION_SECTION, VERSION_ITEM, '1.0.3')
- ext = create_externals_description(self._config, model_format='cfg')
- self.assertIsInstance(ext, ExternalsDescriptionConfigV1)
-
- def test_cfg_v1_unknown_version(self):
- """Test that a config file with unknown schema version is rejected by
- create_externals_description.
-
- """
- self._config.set(DESCRIPTION_SECTION, VERSION_ITEM, '100.0.3')
- with self.assertRaises(RuntimeError):
- create_externals_description(self._config, model_format='cfg')
-
- def test_dict(self):
- """Test that a correct cfg v1 object is created by create_externals_description
-
- """
- rdata = {ExternalsDescription.PROTOCOL: 'git',
- ExternalsDescription.REPO_URL: '/path/to/repo',
- ExternalsDescription.TAG: 'tagv1',
- }
-
- desc = {
- 'test': {
- ExternalsDescription.REQUIRED: False,
- ExternalsDescription.PATH: '../fake',
- ExternalsDescription.EXTERNALS: EMPTY_STR,
- ExternalsDescription.REPO: rdata, },
- }
-
- ext = create_externals_description(desc, model_format='dict')
- self.assertIsInstance(ext, ExternalsDescriptionDict)
-
- def test_cfg_component_dict(self):
- """Verify that create_externals_description works with a dictionary
- """
- # create the top level externals file
- desc = self.setup_dict_config()
- # Check external with all repos
- external = create_externals_description(desc, model_format='dict')
- self.assertIsInstance(external, ExternalsDescriptionDict)
- self.assertTrue('simp_tag' in external)
- self.assertTrue('simp_branch' in external)
- self.assertTrue('simp_opt' in external)
- self.assertTrue('mixed_req' in external)
-
- def test_cfg_exclude_component_dict(self):
- """Verify that exclude component checkout works with a dictionary
- """
- # create the top level externals file
- desc = self.setup_dict_config()
- # Test an excluded repo
- external = create_externals_description(desc, model_format='dict',
- exclude=['simp_tag',
- 'simp_opt'])
- self.assertIsInstance(external, ExternalsDescriptionDict)
- self.assertFalse('simp_tag' in external)
- self.assertTrue('simp_branch' in external)
- self.assertFalse('simp_opt' in external)
- self.assertTrue('mixed_req' in external)
-
- def test_cfg_opt_component_dict(self):
- """Verify that exclude component checkout works with a dictionary
- """
- # create the top level externals file
- desc = self.setup_dict_config()
- # Test an excluded repo
- external = create_externals_description(desc, model_format='dict',
- components=['simp_tag',
- 'simp_opt'])
- self.assertIsInstance(external, ExternalsDescriptionDict)
- self.assertTrue('simp_tag' in external)
- self.assertFalse('simp_branch' in external)
- self.assertTrue('simp_opt' in external)
- self.assertFalse('mixed_req' in external)
-
- def test_cfg_unknown_version(self):
- """Test that a runtime error is raised when an unknown file version is
- received
-
- """
- self._config.set(DESCRIPTION_SECTION, VERSION_ITEM, '123.456.789')
- with self.assertRaises(RuntimeError):
- create_externals_description(self._config, model_format='cfg')
-
- def test_cfg_unknown_format(self):
- """Test that a runtime error is raised when an unknown format string is
- received
-
- """
- with self.assertRaises(RuntimeError):
- create_externals_description(self._config, model_format='unknown')
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/manage_externals/test/test_unit_externals_status.py b/manage_externals/test/test_unit_externals_status.py
deleted file mode 100644
index f019514e9e..0000000000
--- a/manage_externals/test/test_unit_externals_status.py
+++ /dev/null
@@ -1,299 +0,0 @@
-#!/usr/bin/env python3
-
-"""Unit test driver for the manic external status reporting module.
-
-Note: this script assumes the path to the manic package is already in
-the python path.
-
-"""
-
-from __future__ import absolute_import
-from __future__ import unicode_literals
-from __future__ import print_function
-
-import unittest
-
-from manic.externals_status import ExternalStatus
-
-
-class TestStatusObject(unittest.TestCase):
- """Verify that the Status object behaives as expected.
- """
-
- def test_exists_empty_all(self):
- """If the repository sync-state is empty (doesn't exist), and there is no
- clean state, then it is considered not to exist.
-
- """
- stat = ExternalStatus()
- stat.sync_state = ExternalStatus.EMPTY
- stat.clean_state = ExternalStatus.DEFAULT
- exists = stat.exists()
- self.assertFalse(exists)
-
- stat.clean_state = ExternalStatus.EMPTY
- exists = stat.exists()
- self.assertFalse(exists)
-
- stat.clean_state = ExternalStatus.UNKNOWN
- exists = stat.exists()
- self.assertFalse(exists)
-
- # this state represtens an internal logic error in how the
- # repo status was determined.
- stat.clean_state = ExternalStatus.STATUS_OK
- exists = stat.exists()
- self.assertTrue(exists)
-
- # this state represtens an internal logic error in how the
- # repo status was determined.
- stat.clean_state = ExternalStatus.DIRTY
- exists = stat.exists()
- self.assertTrue(exists)
-
- def test_exists_default_all(self):
- """If the repository sync-state is default, then it is considered to exist
- regardless of clean state.
-
- """
- stat = ExternalStatus()
- stat.sync_state = ExternalStatus.DEFAULT
- stat.clean_state = ExternalStatus.DEFAULT
- exists = stat.exists()
- self.assertTrue(exists)
-
- stat.clean_state = ExternalStatus.EMPTY
- exists = stat.exists()
- self.assertTrue(exists)
-
- stat.clean_state = ExternalStatus.UNKNOWN
- exists = stat.exists()
- self.assertTrue(exists)
-
- stat.clean_state = ExternalStatus.STATUS_OK
- exists = stat.exists()
- self.assertTrue(exists)
-
- stat.clean_state = ExternalStatus.DIRTY
- exists = stat.exists()
- self.assertTrue(exists)
-
- def test_exists_unknown_all(self):
- """If the repository sync-state is unknown, then it is considered to exist
- regardless of clean state.
-
- """
- stat = ExternalStatus()
- stat.sync_state = ExternalStatus.UNKNOWN
- stat.clean_state = ExternalStatus.DEFAULT
- exists = stat.exists()
- self.assertTrue(exists)
-
- stat.clean_state = ExternalStatus.EMPTY
- exists = stat.exists()
- self.assertTrue(exists)
-
- stat.clean_state = ExternalStatus.UNKNOWN
- exists = stat.exists()
- self.assertTrue(exists)
-
- stat.clean_state = ExternalStatus.STATUS_OK
- exists = stat.exists()
- self.assertTrue(exists)
-
- stat.clean_state = ExternalStatus.DIRTY
- exists = stat.exists()
- self.assertTrue(exists)
-
- def test_exists_modified_all(self):
- """If the repository sync-state is modified, then it is considered to exist
- regardless of clean state.
-
- """
- stat = ExternalStatus()
- stat.sync_state = ExternalStatus.MODEL_MODIFIED
- stat.clean_state = ExternalStatus.DEFAULT
- exists = stat.exists()
- self.assertTrue(exists)
-
- stat.clean_state = ExternalStatus.EMPTY
- exists = stat.exists()
- self.assertTrue(exists)
-
- stat.clean_state = ExternalStatus.UNKNOWN
- exists = stat.exists()
- self.assertTrue(exists)
-
- stat.clean_state = ExternalStatus.STATUS_OK
- exists = stat.exists()
- self.assertTrue(exists)
-
- stat.clean_state = ExternalStatus.DIRTY
- exists = stat.exists()
- self.assertTrue(exists)
-
- def test_exists_ok_all(self):
- """If the repository sync-state is ok, then it is considered to exist
- regardless of clean state.
-
- """
- stat = ExternalStatus()
- stat.sync_state = ExternalStatus.STATUS_OK
- stat.clean_state = ExternalStatus.DEFAULT
- exists = stat.exists()
- self.assertTrue(exists)
-
- stat.clean_state = ExternalStatus.EMPTY
- exists = stat.exists()
- self.assertTrue(exists)
-
- stat.clean_state = ExternalStatus.UNKNOWN
- exists = stat.exists()
- self.assertTrue(exists)
-
- stat.clean_state = ExternalStatus.STATUS_OK
- exists = stat.exists()
- self.assertTrue(exists)
-
- stat.clean_state = ExternalStatus.DIRTY
- exists = stat.exists()
- self.assertTrue(exists)
-
- def test_update_ok_all(self):
- """If the repository in-sync is ok, then it is safe to
- update only if clean state is ok
-
- """
- stat = ExternalStatus()
- stat.sync_state = ExternalStatus.STATUS_OK
- stat.clean_state = ExternalStatus.DEFAULT
- safe_to_update = stat.safe_to_update()
- self.assertFalse(safe_to_update)
-
- stat.clean_state = ExternalStatus.EMPTY
- safe_to_update = stat.safe_to_update()
- self.assertFalse(safe_to_update)
-
- stat.clean_state = ExternalStatus.UNKNOWN
- safe_to_update = stat.safe_to_update()
- self.assertFalse(safe_to_update)
-
- stat.clean_state = ExternalStatus.STATUS_OK
- safe_to_update = stat.safe_to_update()
- self.assertTrue(safe_to_update)
-
- stat.clean_state = ExternalStatus.DIRTY
- safe_to_update = stat.safe_to_update()
- self.assertFalse(safe_to_update)
-
- def test_update_modified_all(self):
- """If the repository in-sync is modified, then it is safe to
- update only if clean state is ok
-
- """
- stat = ExternalStatus()
- stat.sync_state = ExternalStatus.MODEL_MODIFIED
- stat.clean_state = ExternalStatus.DEFAULT
- safe_to_update = stat.safe_to_update()
- self.assertFalse(safe_to_update)
-
- stat.clean_state = ExternalStatus.EMPTY
- safe_to_update = stat.safe_to_update()
- self.assertFalse(safe_to_update)
-
- stat.clean_state = ExternalStatus.UNKNOWN
- safe_to_update = stat.safe_to_update()
- self.assertFalse(safe_to_update)
-
- stat.clean_state = ExternalStatus.STATUS_OK
- safe_to_update = stat.safe_to_update()
- self.assertTrue(safe_to_update)
-
- stat.clean_state = ExternalStatus.DIRTY
- safe_to_update = stat.safe_to_update()
- self.assertFalse(safe_to_update)
-
- def test_update_unknown_all(self):
- """If the repository in-sync is unknown, then it is not safe to
- update, regardless of the clean state.
-
- """
- stat = ExternalStatus()
- stat.sync_state = ExternalStatus.UNKNOWN
- stat.clean_state = ExternalStatus.DEFAULT
- safe_to_update = stat.safe_to_update()
- self.assertFalse(safe_to_update)
-
- stat.clean_state = ExternalStatus.EMPTY
- safe_to_update = stat.safe_to_update()
- self.assertFalse(safe_to_update)
-
- stat.clean_state = ExternalStatus.UNKNOWN
- safe_to_update = stat.safe_to_update()
- self.assertFalse(safe_to_update)
-
- stat.clean_state = ExternalStatus.STATUS_OK
- safe_to_update = stat.safe_to_update()
- self.assertFalse(safe_to_update)
-
- stat.clean_state = ExternalStatus.DIRTY
- safe_to_update = stat.safe_to_update()
- self.assertFalse(safe_to_update)
-
- def test_update_default_all(self):
- """If the repository in-sync is default, then it is not safe to
- update, regardless of the clean state.
-
- """
- stat = ExternalStatus()
- stat.sync_state = ExternalStatus.UNKNOWN
- stat.clean_state = ExternalStatus.DEFAULT
- safe_to_update = stat.safe_to_update()
- self.assertFalse(safe_to_update)
-
- stat.clean_state = ExternalStatus.EMPTY
- safe_to_update = stat.safe_to_update()
- self.assertFalse(safe_to_update)
-
- stat.clean_state = ExternalStatus.UNKNOWN
- safe_to_update = stat.safe_to_update()
- self.assertFalse(safe_to_update)
-
- stat.clean_state = ExternalStatus.STATUS_OK
- safe_to_update = stat.safe_to_update()
- self.assertFalse(safe_to_update)
-
- stat.clean_state = ExternalStatus.DIRTY
- safe_to_update = stat.safe_to_update()
- self.assertFalse(safe_to_update)
-
- def test_update_empty_all(self):
- """If the repository in-sync is empty, then it is not safe to
- update, regardless of the clean state.
-
- """
- stat = ExternalStatus()
- stat.sync_state = ExternalStatus.UNKNOWN
- stat.clean_state = ExternalStatus.DEFAULT
- safe_to_update = stat.safe_to_update()
- self.assertFalse(safe_to_update)
-
- stat.clean_state = ExternalStatus.EMPTY
- safe_to_update = stat.safe_to_update()
- self.assertFalse(safe_to_update)
-
- stat.clean_state = ExternalStatus.UNKNOWN
- safe_to_update = stat.safe_to_update()
- self.assertFalse(safe_to_update)
-
- stat.clean_state = ExternalStatus.STATUS_OK
- safe_to_update = stat.safe_to_update()
- self.assertFalse(safe_to_update)
-
- stat.clean_state = ExternalStatus.DIRTY
- safe_to_update = stat.safe_to_update()
- self.assertFalse(safe_to_update)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/manage_externals/test/test_unit_repository.py b/manage_externals/test/test_unit_repository.py
deleted file mode 100644
index 1b93861834..0000000000
--- a/manage_externals/test/test_unit_repository.py
+++ /dev/null
@@ -1,208 +0,0 @@
-#!/usr/bin/env python3
-
-"""Unit test driver for checkout_externals
-
-Note: this script assume the path to the checkout_externals.py module is
-already in the python path.
-
-"""
-
-from __future__ import absolute_import
-from __future__ import unicode_literals
-from __future__ import print_function
-
-import unittest
-
-from manic.repository_factory import create_repository
-from manic.repository_git import GitRepository
-from manic.repository_svn import SvnRepository
-from manic.repository import Repository
-from manic.externals_description import ExternalsDescription
-from manic.global_constants import EMPTY_STR
-
-
-class TestCreateRepositoryDict(unittest.TestCase):
- """Test the create_repository functionality to ensure it returns the
- propper type of repository and errors for unknown repository
- types.
-
- """
-
- def setUp(self):
- """Common data needed for all tests in this class
- """
- self._name = 'test_name'
- self._repo = {ExternalsDescription.PROTOCOL: None,
- ExternalsDescription.REPO_URL: 'junk_root',
- ExternalsDescription.TAG: 'junk_tag',
- ExternalsDescription.BRANCH: EMPTY_STR,
- ExternalsDescription.HASH: EMPTY_STR,
- ExternalsDescription.SPARSE: EMPTY_STR, }
-
- def test_create_repo_git(self):
- """Verify that several possible names for the 'git' protocol
- create git repository objects.
-
- """
- protocols = ['git', 'GIT', 'Git', ]
- for protocol in protocols:
- self._repo[ExternalsDescription.PROTOCOL] = protocol
- repo = create_repository(self._name, self._repo)
- self.assertIsInstance(repo, GitRepository)
-
- def test_create_repo_svn(self):
- """Verify that several possible names for the 'svn' protocol
- create svn repository objects.
- """
- protocols = ['svn', 'SVN', 'Svn', ]
- for protocol in protocols:
- self._repo[ExternalsDescription.PROTOCOL] = protocol
- repo = create_repository(self._name, self._repo)
- self.assertIsInstance(repo, SvnRepository)
-
- def test_create_repo_externals_only(self):
- """Verify that an externals only repo returns None.
- """
- protocols = ['externals_only', ]
- for protocol in protocols:
- self._repo[ExternalsDescription.PROTOCOL] = protocol
- repo = create_repository(self._name, self._repo)
- self.assertEqual(None, repo)
-
- def test_create_repo_unsupported(self):
- """Verify that an unsupported protocol generates a runtime error.
- """
- protocols = ['not_a_supported_protocol', ]
- for protocol in protocols:
- self._repo[ExternalsDescription.PROTOCOL] = protocol
- with self.assertRaises(RuntimeError):
- create_repository(self._name, self._repo)
-
-
-class TestRepository(unittest.TestCase):
- """Test the externals description processing used to create the Repository
- base class shared by protocol specific repository classes.
-
- """
-
- def test_tag(self):
- """Test creation of a repository object with a tag
- """
- name = 'test_repo'
- protocol = 'test_protocol'
- url = 'test_url'
- tag = 'test_tag'
- repo_info = {ExternalsDescription.PROTOCOL: protocol,
- ExternalsDescription.REPO_URL: url,
- ExternalsDescription.TAG: tag,
- ExternalsDescription.BRANCH: EMPTY_STR,
- ExternalsDescription.HASH: EMPTY_STR,
- ExternalsDescription.SPARSE: EMPTY_STR, }
- repo = Repository(name, repo_info)
- print(repo.__dict__)
- self.assertEqual(repo.tag(), tag)
- self.assertEqual(repo.url(), url)
-
- def test_branch(self):
- """Test creation of a repository object with a branch
- """
- name = 'test_repo'
- protocol = 'test_protocol'
- url = 'test_url'
- branch = 'test_branch'
- repo_info = {ExternalsDescription.PROTOCOL: protocol,
- ExternalsDescription.REPO_URL: url,
- ExternalsDescription.BRANCH: branch,
- ExternalsDescription.TAG: EMPTY_STR,
- ExternalsDescription.HASH: EMPTY_STR,
- ExternalsDescription.SPARSE: EMPTY_STR, }
- repo = Repository(name, repo_info)
- print(repo.__dict__)
- self.assertEqual(repo.branch(), branch)
- self.assertEqual(repo.url(), url)
-
- def test_hash(self):
- """Test creation of a repository object with a hash
- """
- name = 'test_repo'
- protocol = 'test_protocol'
- url = 'test_url'
- ref = 'deadc0de'
- sparse = EMPTY_STR
- repo_info = {ExternalsDescription.PROTOCOL: protocol,
- ExternalsDescription.REPO_URL: url,
- ExternalsDescription.BRANCH: EMPTY_STR,
- ExternalsDescription.TAG: EMPTY_STR,
- ExternalsDescription.HASH: ref,
- ExternalsDescription.SPARSE: sparse, }
- repo = Repository(name, repo_info)
- print(repo.__dict__)
- self.assertEqual(repo.hash(), ref)
- self.assertEqual(repo.url(), url)
-
- def test_tag_branch(self):
- """Test creation of a repository object with a tag and branch raises a
- runtimer error.
-
- """
- name = 'test_repo'
- protocol = 'test_protocol'
- url = 'test_url'
- branch = 'test_branch'
- tag = 'test_tag'
- ref = EMPTY_STR
- sparse = EMPTY_STR
- repo_info = {ExternalsDescription.PROTOCOL: protocol,
- ExternalsDescription.REPO_URL: url,
- ExternalsDescription.BRANCH: branch,
- ExternalsDescription.TAG: tag,
- ExternalsDescription.HASH: ref,
- ExternalsDescription.SPARSE: sparse, }
- with self.assertRaises(RuntimeError):
- Repository(name, repo_info)
-
- def test_tag_branch_hash(self):
- """Test creation of a repository object with a tag, branch and hash raises a
- runtimer error.
-
- """
- name = 'test_repo'
- protocol = 'test_protocol'
- url = 'test_url'
- branch = 'test_branch'
- tag = 'test_tag'
- ref = 'deadc0de'
- sparse = EMPTY_STR
- repo_info = {ExternalsDescription.PROTOCOL: protocol,
- ExternalsDescription.REPO_URL: url,
- ExternalsDescription.BRANCH: branch,
- ExternalsDescription.TAG: tag,
- ExternalsDescription.HASH: ref,
- ExternalsDescription.SPARSE: sparse, }
- with self.assertRaises(RuntimeError):
- Repository(name, repo_info)
-
- def test_no_tag_no_branch(self):
- """Test creation of a repository object without a tag or branch raises a
- runtimer error.
-
- """
- name = 'test_repo'
- protocol = 'test_protocol'
- url = 'test_url'
- branch = EMPTY_STR
- tag = EMPTY_STR
- ref = EMPTY_STR
- sparse = EMPTY_STR
- repo_info = {ExternalsDescription.PROTOCOL: protocol,
- ExternalsDescription.REPO_URL: url,
- ExternalsDescription.BRANCH: branch,
- ExternalsDescription.TAG: tag,
- ExternalsDescription.HASH: ref,
- ExternalsDescription.SPARSE: sparse, }
- with self.assertRaises(RuntimeError):
- Repository(name, repo_info)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/manage_externals/test/test_unit_repository_git.py b/manage_externals/test/test_unit_repository_git.py
deleted file mode 100644
index 1c01098acf..0000000000
--- a/manage_externals/test/test_unit_repository_git.py
+++ /dev/null
@@ -1,811 +0,0 @@
-#!/usr/bin/env python3
-
-"""Unit test driver for checkout_externals
-
-Note: this script assume the path to the checkout_externals.py module is
-already in the python path.
-
-"""
-# pylint: disable=too-many-lines,protected-access
-
-from __future__ import absolute_import
-from __future__ import unicode_literals
-from __future__ import print_function
-
-import os
-import shutil
-import unittest
-
-from manic.repository_git import GitRepository
-from manic.externals_status import ExternalStatus
-from manic.externals_description import ExternalsDescription
-from manic.externals_description import ExternalsDescriptionDict
-from manic.global_constants import EMPTY_STR
-
-# NOTE(bja, 2017-11) order is important here. origin should be a
-# subset of other to trap errors on processing remotes!
-GIT_REMOTE_OUTPUT_ORIGIN_UPSTREAM = '''
-upstream /path/to/other/repo (fetch)
-upstream /path/to/other/repo (push)
-other /path/to/local/repo2 (fetch)
-other /path/to/local/repo2 (push)
-origin /path/to/local/repo (fetch)
-origin /path/to/local/repo (push)
-'''
-
-
-class TestGitRepositoryCurrentRef(unittest.TestCase):
- """test the current_ref command on a git repository
- """
-
- def setUp(self):
- self._name = 'component'
- rdata = {ExternalsDescription.PROTOCOL: 'git',
- ExternalsDescription.REPO_URL:
- '/path/to/local/repo',
- ExternalsDescription.TAG:
- 'tag1',
- }
-
- data = {self._name:
- {
- ExternalsDescription.REQUIRED: False,
- ExternalsDescription.PATH: 'junk',
- ExternalsDescription.EXTERNALS: EMPTY_STR,
- ExternalsDescription.REPO: rdata,
- },
- }
-
- model = ExternalsDescriptionDict(data)
- repo = model[self._name][ExternalsDescription.REPO]
- self._repo = GitRepository('test', repo)
-
- #
- # mock methods replacing git system calls
- #
- @staticmethod
- def _git_current_branch(branch_found, branch_name):
- """Return a function that takes the place of
- repo._git_current_branch, which returns the given output."""
- def my_git_current_branch(dirname):
- """mock function that can take the place of repo._git_current_branch"""
- return branch_found, branch_name
- return my_git_current_branch
-
- @staticmethod
- def _git_current_tag(tag_found, tag_name):
- """Return a function that takes the place of
- repo._git_current_tag, which returns the given output."""
- def my_git_current_tag(dirname):
- """mock function that can take the place of repo._git_current_tag"""
- return tag_found, tag_name
- return my_git_current_tag
-
- @staticmethod
- def _git_current_hash(hash_found, hash_name):
- """Return a function that takes the place of
- repo._git_current_hash, which returns the given output."""
- def my_git_current_hash(dirname):
- """mock function that can take the place of repo._git_current_hash"""
- return hash_found, hash_name
- return my_git_current_hash
-
- # ------------------------------------------------------------------------
- # Begin tests
- # ------------------------------------------------------------------------
-
- def test_ref_branch(self):
- """Test that we correctly identify we are on a branch
- """
- self._repo._git_current_branch = self._git_current_branch(
- True, 'feature3')
- self._repo._git_current_tag = self._git_current_tag(True, 'foo_tag')
- self._repo._git_current_hash = self._git_current_hash(True, 'abc123')
- expected = 'foo_tag (branch feature3)'
- result = self._repo._current_ref(os.getcwd())
- self.assertEqual(result, expected)
-
- def test_ref_detached_tag(self):
- """Test that we correctly identify that the ref is detached at a tag
- """
- self._repo._git_current_branch = self._git_current_branch(False, '')
- self._repo._git_current_tag = self._git_current_tag(True, 'foo_tag')
- self._repo._git_current_hash = self._git_current_hash(True, 'abc123')
- expected = 'foo_tag'
- result = self._repo._current_ref(os.getcwd())
- self.assertEqual(result, expected)
-
- def test_ref_detached_hash(self):
- """Test that we can identify ref is detached at a hash
-
- """
- self._repo._git_current_branch = self._git_current_branch(False, '')
- self._repo._git_current_tag = self._git_current_tag(False, '')
- self._repo._git_current_hash = self._git_current_hash(True, 'abc123')
- expected = 'abc123'
- result = self._repo._current_ref(os.getcwd())
- self.assertEqual(result, expected)
-
- def test_ref_none(self):
- """Test that we correctly identify that we're not in a git repo.
- """
- self._repo._git_current_branch = self._git_current_branch(False, '')
- self._repo._git_current_tag = self._git_current_tag(False, '')
- self._repo._git_current_hash = self._git_current_hash(False, '')
- result = self._repo._current_ref(os.getcwd())
- self.assertEqual(result, EMPTY_STR)
-
-
-class TestGitRepositoryCheckSync(unittest.TestCase):
- """Test whether the GitRepository _check_sync_logic functionality is
- correct.
-
- Note: there are a lot of combinations of state:
-
- - external description - tag, branch
-
- - working copy
- - doesn't exist (not checked out)
- - exists, no git info - incorrect protocol, e.g. svn, or tarball?
- - exists, git info
- - as expected:
- - different from expected:
- - detached tag,
- - detached hash,
- - detached branch (compare remote and branch),
- - tracking branch (compare remote and branch),
- - same remote
- - different remote
- - untracked branch
-
- Test list:
- - doesn't exist
- - exists no git info
-
- - num_external * (working copy expected + num_working copy different)
- - total tests = 16
-
- """
-
- # NOTE(bja, 2017-11) pylint complains about long method names, but
- # it is hard to differentiate tests without making them more
- # cryptic. Also complains about too many public methods, but it
- # doesn't really make sense to break this up.
- # pylint: disable=invalid-name,too-many-public-methods
-
- TMP_FAKE_DIR = 'fake'
- TMP_FAKE_GIT_DIR = os.path.join(TMP_FAKE_DIR, '.git')
-
- def setUp(self):
- """Setup reusable git repository object
- """
- self._name = 'component'
- rdata = {ExternalsDescription.PROTOCOL: 'git',
- ExternalsDescription.REPO_URL:
- '/path/to/local/repo',
- ExternalsDescription.TAG: 'tag1',
- }
-
- data = {self._name:
- {
- ExternalsDescription.REQUIRED: False,
- ExternalsDescription.PATH: self.TMP_FAKE_DIR,
- ExternalsDescription.EXTERNALS: EMPTY_STR,
- ExternalsDescription.REPO: rdata,
- },
- }
-
- model = ExternalsDescriptionDict(data)
- repo = model[self._name][ExternalsDescription.REPO]
- self._repo = GitRepository('test', repo)
- # The unit tests here don't care about the result of
- # _current_ref, but we replace it here so that we don't need to
- # worry about calling a possibly slow and possibly
- # error-producing command (since _current_ref calls various git
- # functions):
- self._repo._current_ref = self._current_ref_empty
- self._create_tmp_git_dir()
-
- # We have to override this class method rather than the self._repo
- # instance method because it is called via
- # GitRepository._remote_name_for_url, which is itself a @classmethod
- # calls cls._git_remote_verbose().
- self._orignal_git_remote_verbose = GitRepository._git_remote_verbose
- GitRepository._git_remote_verbose = self._git_remote_origin_upstream
- def tearDown(self):
- """Cleanup tmp stuff on the file system
- """
- self._remove_tmp_git_dir()
-
- GitRepository._git_remote_verbose = self._orignal_git_remote_verbose
-
- def _create_tmp_git_dir(self):
- """Create a temporary fake git directory for testing purposes.
- """
- if not os.path.exists(self.TMP_FAKE_GIT_DIR):
- os.makedirs(self.TMP_FAKE_GIT_DIR)
-
- def _remove_tmp_git_dir(self):
- """Remove the temporary fake git directory
- """
- if os.path.exists(self.TMP_FAKE_DIR):
- shutil.rmtree(self.TMP_FAKE_DIR)
-
- #
- # mock methods replacing git system calls
- #
- @staticmethod
- def _current_ref_empty(dirname):
- """Return an empty string.
-
- Drop-in for GitRepository._current_ref
- """
- return EMPTY_STR
-
- @staticmethod
- def _git_remote_origin_upstream(dirname):
- """Return an info string that is a checkout hash.
-
- Drop-in for GitRepository._git_remote_verbose.
- """
- return GIT_REMOTE_OUTPUT_ORIGIN_UPSTREAM
-
- @staticmethod
- def _git_current_hash(myhash):
- """Return a function that takes the place of repo._git_current_hash,
- which returns the given hash
- """
- def my_git_current_hash(dirname):
- """mock function that can take the place of repo._git_current_hash"""
- return 0, myhash
- return my_git_current_hash
-
- def _git_revparse_commit(self, expected_ref, mystatus, myhash):
- """Return a function that takes the place of
- repo._git_revparse_commit, which returns a tuple:
- (mystatus, myhash).
-
- Expects the passed-in ref to equal expected_ref
-
- status = 0 implies success, non-zero implies failure
- """
- def my_git_revparse_commit(ref, dirname):
- """mock function that can take the place of repo._git_revparse_commit"""
- self.assertEqual(expected_ref, ref)
- return mystatus, myhash
- return my_git_revparse_commit
-
- # ----------------------------------------------------------------
- #
- # Tests where working copy doesn't exist or is invalid
- #
- # ----------------------------------------------------------------
- def test_sync_dir_not_exist(self):
- """Test that a directory that doesn't exist returns an error status
-
- Note: the Repository classes should be prevented from ever
- working on an empty directory by the _Source object.
-
- """
- stat = ExternalStatus()
- self._repo._check_sync(stat, 'invalid_directory_name')
- self.assertEqual(stat.sync_state, ExternalStatus.STATUS_ERROR)
- # check_dir should only modify the sync_state, not clean_state
- self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT)
-
- def test_sync_dir_exist_no_git_info(self):
- """Test that a non-existent git repo returns an unknown status
- """
- stat = ExternalStatus()
- self._repo._tag = 'tag1'
- self._repo._git_current_hash = self._git_current_hash('')
- self._repo._git_revparse_commit = self._git_revparse_commit(
- 'tag1', 1, '')
- self._repo._check_sync(stat, self.TMP_FAKE_DIR)
- self.assertEqual(stat.sync_state, ExternalStatus.UNKNOWN)
- # check_sync should only modify the sync_state, not clean_state
- self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT)
-
- # ------------------------------------------------------------------------
- #
- # Tests where version in configuration file is not a valid reference
- #
- # ------------------------------------------------------------------------
-
- def test_sync_invalid_reference(self):
- """Test that an invalid reference returns out-of-sync
- """
- stat = ExternalStatus()
- self._repo._tag = 'tag1'
- self._repo._git_current_hash = self._git_current_hash('abc123')
- self._repo._git_revparse_commit = self._git_revparse_commit(
- 'tag1', 1, '')
- self._repo._check_sync_logic(stat, self.TMP_FAKE_DIR)
- self.assertEqual(stat.sync_state, ExternalStatus.MODEL_MODIFIED)
- # check_sync should only modify the sync_state, not clean_state
- self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT)
-
- # ----------------------------------------------------------------
- #
- # Tests where external description specifies a tag
- #
- # ----------------------------------------------------------------
- def test_sync_tag_on_same_hash(self):
- """Test expect tag on same hash --> status ok
-
- """
- stat = ExternalStatus()
- self._repo._tag = 'tag1'
- self._repo._git_current_hash = self._git_current_hash('abc123')
- self._repo._git_revparse_commit = self._git_revparse_commit(
- 'tag1', 0, 'abc123')
- self._repo._check_sync_logic(stat, self.TMP_FAKE_DIR)
- self.assertEqual(stat.sync_state, ExternalStatus.STATUS_OK)
- # check_sync should only modify the sync_state, not clean_state
- self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT)
-
- def test_sync_tag_on_different_hash(self):
- """Test expect tag on a different hash --> status modified
-
- """
- stat = ExternalStatus()
- self._repo._tag = 'tag1'
- self._repo._git_current_hash = self._git_current_hash('def456')
- self._repo._git_revparse_commit = self._git_revparse_commit(
- 'tag1', 0, 'abc123')
- self._repo._check_sync_logic(stat, self.TMP_FAKE_DIR)
- self.assertEqual(stat.sync_state, ExternalStatus.MODEL_MODIFIED)
- # check_sync should only modify the sync_state, not clean_state
- self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT)
-
- # ----------------------------------------------------------------
- #
- # Tests where external description specifies a hash
- #
- # ----------------------------------------------------------------
- def test_sync_hash_on_same_hash(self):
- """Test expect hash on same hash --> status ok
-
- """
- stat = ExternalStatus()
- self._repo._tag = ''
- self._repo._hash = 'abc'
- self._repo._git_current_hash = self._git_current_hash('abc123')
- self._repo._git_revparse_commit = self._git_revparse_commit(
- 'abc', 0, 'abc123')
- self._repo._check_sync_logic(stat, self.TMP_FAKE_DIR)
- self.assertEqual(stat.sync_state, ExternalStatus.STATUS_OK)
- # check_sync should only modify the sync_state, not clean_state
- self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT)
-
- def test_sync_hash_on_different_hash(self):
- """Test expect hash on a different hash --> status modified
-
- """
- stat = ExternalStatus()
- self._repo._tag = ''
- self._repo._hash = 'abc'
- self._repo._git_current_hash = self._git_current_hash('def456')
- self._repo._git_revparse_commit = self._git_revparse_commit(
- 'abc', 0, 'abc123')
- self._repo._check_sync_logic(stat, self.TMP_FAKE_DIR)
- self.assertEqual(stat.sync_state, ExternalStatus.MODEL_MODIFIED)
- # check_sync should only modify the sync_state, not clean_state
- self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT)
-
- # ----------------------------------------------------------------
- #
- # Tests where external description specifies a branch
- #
- # ----------------------------------------------------------------
- def test_sync_branch_on_same_hash(self):
- """Test expect branch on same hash --> status ok
-
- """
- stat = ExternalStatus()
- self._repo._branch = 'feature-2'
- self._repo._tag = ''
- self._repo._git_current_hash = self._git_current_hash('abc123')
- self._repo._git_revparse_commit = (
- self._git_revparse_commit('origin/feature-2', 0, 'abc123'))
- self._repo._check_sync_logic(stat, self.TMP_FAKE_DIR)
- self.assertEqual(stat.sync_state, ExternalStatus.STATUS_OK)
- # check_sync should only modify the sync_state, not clean_state
- self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT)
-
- def test_sync_branch_on_diff_hash(self):
- """Test expect branch on diff hash --> status modified
-
- """
- stat = ExternalStatus()
- self._repo._branch = 'feature-2'
- self._repo._tag = ''
- self._repo._git_current_hash = self._git_current_hash('abc123')
- self._repo._git_revparse_commit = (
- self._git_revparse_commit('origin/feature-2', 0, 'def456'))
- self._repo._check_sync_logic(stat, self.TMP_FAKE_DIR)
- self.assertEqual(stat.sync_state, ExternalStatus.MODEL_MODIFIED)
- # check_sync should only modify the sync_state, not clean_state
- self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT)
-
- def test_sync_branch_diff_remote(self):
- """Test _remote_name_for_url with a different remote
-
- """
- stat = ExternalStatus()
- self._repo._branch = 'feature-2'
- self._repo._tag = ''
- self._repo._url = '/path/to/other/repo'
- self._repo._git_current_hash = self._git_current_hash('abc123')
- self._repo._git_revparse_commit = (
- self._git_revparse_commit('upstream/feature-2', 0, 'def456'))
- self._repo._check_sync_logic(stat, self.TMP_FAKE_DIR)
- # The test passes if _git_revparse_commit is called with the
- # expected argument
-
- def test_sync_branch_diff_remote2(self):
- """Test _remote_name_for_url with a different remote
-
- """
- stat = ExternalStatus()
- self._repo._branch = 'feature-2'
- self._repo._tag = ''
- self._repo._url = '/path/to/local/repo2'
- self._repo._git_current_hash = self._git_current_hash('abc123')
- self._repo._git_revparse_commit = (
- self._git_revparse_commit('other/feature-2', 0, 'def789'))
- self._repo._check_sync_logic(stat, self.TMP_FAKE_DIR)
- # The test passes if _git_revparse_commit is called with the
- # expected argument
-
- def test_sync_branch_on_unknown_remote(self):
- """Test expect branch, but remote is unknown --> status modified
-
- """
- stat = ExternalStatus()
- self._repo._branch = 'feature-2'
- self._repo._tag = ''
- self._repo._url = '/path/to/unknown/repo'
- self._repo._git_current_hash = self._git_current_hash('abc123')
- self._repo._git_revparse_commit = (
- self._git_revparse_commit('unknown_remote/feature-2', 1, ''))
- self._repo._check_sync_logic(stat, self.TMP_FAKE_DIR)
- self.assertEqual(stat.sync_state, ExternalStatus.MODEL_MODIFIED)
- # check_sync should only modify the sync_state, not clean_state
- self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT)
-
- def test_sync_branch_on_untracked_local(self):
- """Test expect branch, on untracked branch in local repo --> status ok
-
- Setting the externals description to '.' indicates that the
- user only wants to consider the current local repo state
- without fetching from remotes. This is required to preserve
- the current branch of a repository during an update.
-
- """
- stat = ExternalStatus()
- self._repo._branch = 'feature3'
- self._repo._tag = ''
- self._repo._url = '.'
- self._repo._git_current_hash = self._git_current_hash('abc123')
- self._repo._git_revparse_commit = (
- self._git_revparse_commit('feature3', 0, 'abc123'))
- self._repo._check_sync_logic(stat, self.TMP_FAKE_DIR)
- self.assertEqual(stat.sync_state, ExternalStatus.STATUS_OK)
- # check_sync should only modify the sync_state, not clean_state
- self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT)
-
-
-class TestGitStatusPorcelain(unittest.TestCase):
- """Test parsing of output from git status --porcelain=v1 -z
- """
- # pylint: disable=C0103
- GIT_STATUS_PORCELAIN_V1_ALL = (
- r' D INSTALL\0MM Makefile\0M README.md\0R cmakelists.txt\0'
- r'CMakeLists.txt\0D commit-message-template.txt\0A stuff.txt\0'
- r'?? junk.txt')
-
- GIT_STATUS_PORCELAIN_CLEAN = r''
-
- def test_porcelain_status_dirty(self):
- """Verify that git status output is considered dirty when there are
- listed files.
-
- """
- git_output = self.GIT_STATUS_PORCELAIN_V1_ALL
- is_dirty = GitRepository._status_v1z_is_dirty(git_output)
- self.assertTrue(is_dirty)
-
- def test_porcelain_status_clean(self):
- """Verify that git status output is considered clean when there are no
- listed files.
-
- """
- git_output = self.GIT_STATUS_PORCELAIN_CLEAN
- is_dirty = GitRepository._status_v1z_is_dirty(git_output)
- self.assertFalse(is_dirty)
-
-
-class TestGitCreateRemoteName(unittest.TestCase):
- """Test the create_remote_name method on the GitRepository class
- """
-
- def setUp(self):
- """Common infrastructure for testing _create_remote_name
- """
- self._rdata = {ExternalsDescription.PROTOCOL: 'git',
- ExternalsDescription.REPO_URL:
- 'empty',
- ExternalsDescription.TAG:
- 'very_useful_tag',
- ExternalsDescription.BRANCH: EMPTY_STR,
- ExternalsDescription.HASH: EMPTY_STR,
- ExternalsDescription.SPARSE: EMPTY_STR, }
- self._repo = GitRepository('test', self._rdata)
-
- def test_remote_git_proto(self):
- """Test remote with git protocol
- """
- self._repo._url = 'git@git.github.com:very_nice_org/useful_repo'
- remote_name = self._repo._create_remote_name()
- self.assertEqual(remote_name, 'very_nice_org_useful_repo')
-
- def test_remote_https_proto(self):
- """Test remote with git protocol
- """
- self._repo._url = 'https://www.github.com/very_nice_org/useful_repo'
- remote_name = self._repo._create_remote_name()
- self.assertEqual(remote_name, 'very_nice_org_useful_repo')
-
- def test_remote_local_abs(self):
- """Test remote with git protocol
- """
- self._repo._url = '/path/to/local/repositories/useful_repo'
- remote_name = self._repo._create_remote_name()
- self.assertEqual(remote_name, 'repositories_useful_repo')
-
- def test_remote_local_rel(self):
- """Test remote with git protocol
- """
- os.environ['TEST_VAR'] = '/my/path/to/repos'
- self._repo._url = '${TEST_VAR}/../../useful_repo'
- remote_name = self._repo._create_remote_name()
- self.assertEqual(remote_name, 'path_useful_repo')
- del os.environ['TEST_VAR']
-
-
-class TestVerifyTag(unittest.TestCase):
- """Test logic verifying that a tag exists and is unique
-
- """
-
- def setUp(self):
- """Setup reusable git repository object
- """
- self._name = 'component'
- rdata = {ExternalsDescription.PROTOCOL: 'git',
- ExternalsDescription.REPO_URL:
- '/path/to/local/repo',
- ExternalsDescription.TAG: 'tag1',
- }
-
- data = {self._name:
- {
- ExternalsDescription.REQUIRED: False,
- ExternalsDescription.PATH: 'tmp',
- ExternalsDescription.EXTERNALS: EMPTY_STR,
- ExternalsDescription.REPO: rdata,
- },
- }
-
- model = ExternalsDescriptionDict(data)
- repo = model[self._name][ExternalsDescription.REPO]
- self._repo = GitRepository('test', repo)
-
- @staticmethod
- def _shell_true(*args, **kwargs):
- return 0
-
- @staticmethod
- def _shell_false(*args, **kwargs):
- return 1
-
- @staticmethod
- def _mock_revparse_commit(ref, dirname):
- _ = ref
- return (TestValidRef._shell_true, '97ebc0e0deadc0de')
-
- @staticmethod
- def _mock_revparse_commit_false(ref, dirname):
- _ = ref
- return (TestValidRef._shell_false, '97ebc0e0deadc0de')
-
- def test_tag_not_tag_branch_commit(self):
- """Verify a non-tag returns false
- """
- self._repo._git_showref_tag = self._shell_false
- self._repo._git_showref_branch = self._shell_false
- self._repo._git_lsremote_branch = self._shell_false
- self._repo._git_revparse_commit = self._mock_revparse_commit_false
- self._repo._tag = 'something'
- remote_name = 'origin'
- received, _ = self._repo._is_unique_tag(self._repo._tag, remote_name,
- os.getcwd())
- self.assertFalse(received)
-
- def test_tag_not_tag(self):
- """Verify a non-tag, untracked remote returns false
- """
- self._repo._git_showref_tag = self._shell_false
- self._repo._git_showref_branch = self._shell_true
- self._repo._git_lsremote_branch = self._shell_true
- self._repo._git_revparse_commit = self._mock_revparse_commit_false
- self._repo._tag = 'tag1'
- remote_name = 'origin'
- received, _ = self._repo._is_unique_tag(self._repo._tag, remote_name,
- os.getcwd())
- self.assertFalse(received)
-
- def test_tag_indeterminant(self):
- """Verify an indeterminant tag/branch returns false
- """
- self._repo._git_showref_tag = self._shell_true
- self._repo._git_showref_branch = self._shell_true
- self._repo._git_lsremote_branch = self._shell_true
- self._repo._git_revparse_commit = self._mock_revparse_commit
- self._repo._tag = 'something'
- remote_name = 'origin'
- received, _ = self._repo._is_unique_tag(self._repo._tag, remote_name,
- os.getcwd())
- self.assertFalse(received)
-
- def test_tag_is_unique(self):
- """Verify a unique tag match returns true
- """
- self._repo._git_showref_tag = self._shell_true
- self._repo._git_showref_branch = self._shell_false
- self._repo._git_lsremote_branch = self._shell_false
- self._repo._git_revparse_commit = self._mock_revparse_commit
- self._repo._tag = 'tag1'
- remote_name = 'origin'
- received, _ = self._repo._is_unique_tag(self._repo._tag, remote_name,
- os.getcwd())
- self.assertTrue(received)
-
- def test_tag_is_not_hash(self):
- """Verify a commit hash is not classified as a tag
- """
- self._repo._git_showref_tag = self._shell_false
- self._repo._git_showref_branch = self._shell_false
- self._repo._git_lsremote_branch = self._shell_false
- self._repo._git_revparse_commit = self._mock_revparse_commit
- self._repo._tag = '97ebc0e0'
- remote_name = 'origin'
- received, _ = self._repo._is_unique_tag(self._repo._tag, remote_name,
- os.getcwd())
- self.assertFalse(received)
-
- def test_hash_is_commit(self):
- """Verify a commit hash is not classified as a tag
- """
- self._repo._git_showref_tag = self._shell_false
- self._repo._git_showref_branch = self._shell_false
- self._repo._git_lsremote_branch = self._shell_false
- self._repo._git_revparse_commit = self._mock_revparse_commit
- self._repo._tag = '97ebc0e0'
- remote_name = 'origin'
- received, _ = self._repo._is_unique_tag(self._repo._tag, remote_name,
- os.getcwd())
- self.assertFalse(received)
-
-
-class TestValidRef(unittest.TestCase):
- """Test logic verifying that a reference is a valid tag, branch or sha1
-
- """
-
- def setUp(self):
- """Setup reusable git repository object
- """
- self._name = 'component'
- rdata = {ExternalsDescription.PROTOCOL: 'git',
- ExternalsDescription.REPO_URL:
- '/path/to/local/repo',
- ExternalsDescription.TAG: 'tag1',
- }
-
- data = {self._name:
- {
- ExternalsDescription.REQUIRED: False,
- ExternalsDescription.PATH: 'tmp',
- ExternalsDescription.EXTERNALS: EMPTY_STR,
- ExternalsDescription.REPO: rdata,
- },
- }
-
- model = ExternalsDescriptionDict(data)
- repo = model[self._name][ExternalsDescription.REPO]
- self._repo = GitRepository('test', repo)
-
- @staticmethod
- def _shell_true(url, remote=None):
- _ = url
- _ = remote
- return 0
-
- @staticmethod
- def _shell_false(url, remote=None):
- _ = url
- _ = remote
- return 1
-
- @staticmethod
- def _mock_revparse_commit_false(ref, dirname):
- _ = ref
- return (TestValidRef._shell_false, '')
-
- @staticmethod
- def _mock_revparse_commit_true(ref, dirname):
- _ = ref
- _ = dirname
- return (TestValidRef._shell_true, '')
-
- def test_valid_ref_is_invalid(self):
- """Verify an invalid reference raises an exception
- """
- self._repo._git_showref_tag = self._shell_false
- self._repo._git_showref_branch = self._shell_false
- self._repo._git_lsremote_branch = self._shell_false
- self._repo._git_revparse_commit = self._mock_revparse_commit_false
- self._repo._tag = 'invalid_ref'
- with self.assertRaises(RuntimeError):
- self._repo._check_for_valid_ref(self._repo._tag,
- remote_name=None,
- dirname=os.getcwd())
-
- def test_valid_tag(self):
- """Verify a valid tag return true
- """
- self._repo._git_showref_tag = self._shell_true
- self._repo._git_showref_branch = self._shell_false
- self._repo._git_lsremote_branch = self._shell_false
- self._repo._git_revparse_commit = self._mock_revparse_commit_true
- self._repo._tag = 'tag1'
- received = self._repo._check_for_valid_ref(self._repo._tag,
- remote_name=None,
- dirname=os.getcwd())
- self.assertTrue(received)
-
- def test_valid_branch(self):
- """Verify a valid tag return true
- """
- self._repo._git_showref_tag = self._shell_false
- self._repo._git_showref_branch = self._shell_true
- self._repo._git_lsremote_branch = self._shell_false
- self._repo._git_revparse_commit = self._mock_revparse_commit_true
- self._repo._tag = 'tag1'
- received = self._repo._check_for_valid_ref(self._repo._tag,
- remote_name=None,
- dirname=os.getcwd())
- self.assertTrue(received)
-
- def test_valid_hash(self):
- """Verify a valid hash return true
- """
- def _mock_revparse_commit_true(ref, dirname):
- _ = ref
- return (0, '56cc0b539426eb26810af9e')
-
- self._repo._git_showref_tag = self._shell_false
- self._repo._git_showref_branch = self._shell_false
- self._repo._git_lsremote_branch = self._shell_false
- self._repo._git_revparse_commit = _mock_revparse_commit_true
- self._repo._hash = '56cc0b5394'
- received = self._repo._check_for_valid_ref(self._repo._hash,
- remote_name=None,
- dirname=os.getcwd())
- self.assertTrue(received)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/manage_externals/test/test_unit_repository_svn.py b/manage_externals/test/test_unit_repository_svn.py
deleted file mode 100755
index d9309df7f6..0000000000
--- a/manage_externals/test/test_unit_repository_svn.py
+++ /dev/null
@@ -1,501 +0,0 @@
-#!/usr/bin/env python3
-
-"""Unit test driver for checkout_externals
-
-Note: this script assume the path to the checkout_externals.py module is
-already in the python path.
-
-"""
-
-from __future__ import absolute_import
-from __future__ import unicode_literals
-from __future__ import print_function
-
-import unittest
-
-from manic.repository_svn import SvnRepository
-from manic.externals_status import ExternalStatus
-from manic.externals_description import ExternalsDescription
-from manic.externals_description import ExternalsDescriptionDict
-from manic.global_constants import EMPTY_STR
-
-# pylint: disable=W0212
-
-SVN_INFO_MOSART = """Path: components/mosart
-Working Copy Root Path: /Users/andreb/projects/ncar/git-conversion/clm-dev-experimental/components/mosart
-URL: https://svn-ccsm-models.cgd.ucar.edu/mosart/trunk_tags/mosart1_0_26
-Relative URL: ^/mosart/trunk_tags/mosart1_0_26
-Repository Root: https://svn-ccsm-models.cgd.ucar.edu
-Repository UUID: fe37f545-8307-0410-aea5-b40df96820b5
-Revision: 86711
-Node Kind: directory
-Schedule: normal
-Last Changed Author: erik
-Last Changed Rev: 86031
-Last Changed Date: 2017-07-07 12:28:10 -0600 (Fri, 07 Jul 2017)
-"""
-SVN_INFO_CISM = """
-Path: components/cism
-Working Copy Root Path: /Users/andreb/projects/ncar/git-conversion/clm-dev-experimental/components/cism
-URL: https://svn-ccsm-models.cgd.ucar.edu/glc/trunk_tags/cism2_1_37
-Relative URL: ^/glc/trunk_tags/cism2_1_37
-Repository Root: https://svn-ccsm-models.cgd.ucar.edu
-Repository UUID: fe37f545-8307-0410-aea5-b40df96820b5
-Revision: 86711
-Node Kind: directory
-Schedule: normal
-Last Changed Author: sacks
-Last Changed Rev: 85704
-Last Changed Date: 2017-06-15 05:59:28 -0600 (Thu, 15 Jun 2017)
-"""
-
-
-class TestSvnRepositoryCheckURL(unittest.TestCase):
- """Verify that the svn_check_url function is working as expected.
- """
-
- def setUp(self):
- """Setup reusable svn repository object
- """
- self._name = 'component'
- rdata = {ExternalsDescription.PROTOCOL: 'svn',
- ExternalsDescription.REPO_URL:
- 'https://svn-ccsm-models.cgd.ucar.edu',
- ExternalsDescription.TAG:
- 'mosart/trunk_tags/mosart1_0_26',
- }
-
- data = {self._name:
- {
- ExternalsDescription.REQUIRED: False,
- ExternalsDescription.PATH: 'junk',
- ExternalsDescription.EXTERNALS: '',
- ExternalsDescription.REPO: rdata,
- },
- }
-
- model = ExternalsDescriptionDict(data)
- repo = model[self._name][ExternalsDescription.REPO]
- self._repo = SvnRepository('test', repo)
-
- def test_check_url_same(self):
- """Test that we correctly identify that the correct URL.
- """
- svn_output = SVN_INFO_MOSART
- expected_url = self._repo.url()
- result, current_version = \
- self._repo._check_url(svn_output, expected_url)
- self.assertEqual(result, ExternalStatus.STATUS_OK)
- self.assertEqual(current_version, 'mosart/trunk_tags/mosart1_0_26')
-
- def test_check_url_different(self):
- """Test that we correctly reject an incorrect URL.
- """
- svn_output = SVN_INFO_CISM
- expected_url = self._repo.url()
- result, current_version = \
- self._repo._check_url(svn_output, expected_url)
- self.assertEqual(result, ExternalStatus.MODEL_MODIFIED)
- self.assertEqual(current_version, 'glc/trunk_tags/cism2_1_37')
-
- def test_check_url_none(self):
- """Test that we can handle an empty string for output, e.g. not an svn
- repo.
-
- """
- svn_output = EMPTY_STR
- expected_url = self._repo.url()
- result, current_version = \
- self._repo._check_url(svn_output, expected_url)
- self.assertEqual(result, ExternalStatus.UNKNOWN)
- self.assertEqual(current_version, '')
-
-
-class TestSvnRepositoryCheckSync(unittest.TestCase):
- """Test whether the SvnRepository svn_check_sync functionality is
- correct.
-
- """
-
- def setUp(self):
- """Setup reusable svn repository object
- """
- self._name = "component"
- rdata = {ExternalsDescription.PROTOCOL: 'svn',
- ExternalsDescription.REPO_URL:
- 'https://svn-ccsm-models.cgd.ucar.edu/',
- ExternalsDescription.TAG:
- 'mosart/trunk_tags/mosart1_0_26',
- }
-
- data = {self._name:
- {
- ExternalsDescription.REQUIRED: False,
- ExternalsDescription.PATH: 'junk',
- ExternalsDescription.EXTERNALS: EMPTY_STR,
- ExternalsDescription.REPO: rdata,
- },
- }
-
- model = ExternalsDescriptionDict(data)
- repo = model[self._name][ExternalsDescription.REPO]
- self._repo = SvnRepository('test', repo)
-
- @staticmethod
- def _svn_info_empty(*_):
- """Return an empty info string. Simulates svn info failing.
- """
- return ''
-
- @staticmethod
- def _svn_info_synced(*_):
- """Return an info sting that is synced with the setUp data
- """
- return SVN_INFO_MOSART
-
- @staticmethod
- def _svn_info_modified(*_):
- """Return and info string that is modified from the setUp data
- """
- return SVN_INFO_CISM
-
- def test_repo_dir_not_exist(self):
- """Test that a directory that doesn't exist returns an error status
-
- Note: the Repository classes should be prevented from ever
- working on an empty directory by the _Source object.
-
- """
- stat = ExternalStatus()
- self._repo._check_sync(stat, 'junk')
- self.assertEqual(stat.sync_state, ExternalStatus.STATUS_ERROR)
- # check_dir should only modify the sync_state, not clean_state
- self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT)
-
- def test_repo_dir_exist_no_svn_info(self):
- """Test that an empty info string returns an unknown status
- """
- stat = ExternalStatus()
- # Now we over-ride the _svn_info method on the repo to return
- # a known value without requiring access to svn.
- self._repo._svn_info = self._svn_info_empty
- self._repo._check_sync(stat, '.')
- self.assertEqual(stat.sync_state, ExternalStatus.UNKNOWN)
- # check_dir should only modify the sync_state, not clean_state
- self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT)
-
- def test_repo_dir_synced(self):
- """Test that a valid info string that is synced to the repo in the
- externals description returns an ok status.
-
- """
- stat = ExternalStatus()
- # Now we over-ride the _svn_info method on the repo to return
- # a known value without requiring access to svn.
- self._repo._svn_info = self._svn_info_synced
- self._repo._check_sync(stat, '.')
- self.assertEqual(stat.sync_state, ExternalStatus.STATUS_OK)
- # check_dir should only modify the sync_state, not clean_state
- self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT)
-
- def test_repo_dir_modified(self):
- """Test that a valid svn info string that is out of sync with the
- externals description returns a modified status.
-
- """
- stat = ExternalStatus()
- # Now we over-ride the _svn_info method on the repo to return
- # a known value without requiring access to svn.
- self._repo._svn_info = self._svn_info_modified
- self._repo._check_sync(stat, '.')
- self.assertEqual(stat.sync_state, ExternalStatus.MODEL_MODIFIED)
- # check_dir should only modify the sync_state, not clean_state
- self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT)
-
-
-class TestSVNStatusXML(unittest.TestCase):
- """Test parsing of svn status xml output
- """
- SVN_STATUS_XML_DIRTY_ALL = '''
-
-
-
-
-
-sacks
-2017-06-15T11:59:00.355419Z
-
-
-
-
-
-
-sacks
-2013-02-07T16:17:56.412878Z
-
-
-
-
-
-
-sacks
-2017-05-01T16:48:27.893741Z
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-'''
-
- SVN_STATUS_XML_DIRTY_MISSING = '''
-
-
-
-
-
-sacks
-2017-06-15T11:59:00.355419Z
-
-
-
-
-
-
-
-
-'''
-
- SVN_STATUS_XML_DIRTY_MODIFIED = '''
-
-
-
-
-
-sacks
-2013-02-07T16:17:56.412878Z
-
-
-
-
-
-
-
-
-'''
-
- SVN_STATUS_XML_DIRTY_DELETED = '''
-
-
-
-
-
-sacks
-2017-05-01T16:48:27.893741Z
-
-
-
-
-
-
-
-
-'''
-
- SVN_STATUS_XML_DIRTY_UNVERSION = '''
-
-
-
-
-
-
-
-
-
-
-
-'''
-
- SVN_STATUS_XML_DIRTY_ADDED = '''
-
-
-
-
-
-
-
-
-
-
-
-'''
-
- SVN_STATUS_XML_CLEAN = '''
-
-
-
-
-
-
-
-
-
-
-
-'''
-
- def test_xml_status_dirty_missing(self):
- """Verify that svn status output is consindered dirty when there is a
- missing file.
-
- """
- svn_output = self.SVN_STATUS_XML_DIRTY_MISSING
- is_dirty = SvnRepository.xml_status_is_dirty(
- svn_output)
- self.assertTrue(is_dirty)
-
- def test_xml_status_dirty_modified(self):
- """Verify that svn status output is consindered dirty when there is a
- modified file.
- """
- svn_output = self.SVN_STATUS_XML_DIRTY_MODIFIED
- is_dirty = SvnRepository.xml_status_is_dirty(
- svn_output)
- self.assertTrue(is_dirty)
-
- def test_xml_status_dirty_deleted(self):
- """Verify that svn status output is consindered dirty when there is a
- deleted file.
- """
- svn_output = self.SVN_STATUS_XML_DIRTY_DELETED
- is_dirty = SvnRepository.xml_status_is_dirty(
- svn_output)
- self.assertTrue(is_dirty)
-
- def test_xml_status_dirty_unversion(self):
- """Verify that svn status output ignores unversioned files when making
- the clean/dirty decision.
-
- """
- svn_output = self.SVN_STATUS_XML_DIRTY_UNVERSION
- is_dirty = SvnRepository.xml_status_is_dirty(
- svn_output)
- self.assertFalse(is_dirty)
-
- def test_xml_status_dirty_added(self):
- """Verify that svn status output is consindered dirty when there is a
- added file.
- """
- svn_output = self.SVN_STATUS_XML_DIRTY_ADDED
- is_dirty = SvnRepository.xml_status_is_dirty(
- svn_output)
- self.assertTrue(is_dirty)
-
- def test_xml_status_dirty_all(self):
- """Verify that svn status output is consindered dirty when there are
- multiple dirty files..
-
- """
- svn_output = self.SVN_STATUS_XML_DIRTY_ALL
- is_dirty = SvnRepository.xml_status_is_dirty(
- svn_output)
- self.assertTrue(is_dirty)
-
- def test_xml_status_dirty_clean(self):
- """Verify that svn status output is consindered clean when there are
- no 'dirty' files. This means accepting untracked and externals.
-
- """
- svn_output = self.SVN_STATUS_XML_CLEAN
- is_dirty = SvnRepository.xml_status_is_dirty(
- svn_output)
- self.assertFalse(is_dirty)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/manage_externals/test/test_unit_utils.py b/manage_externals/test/test_unit_utils.py
deleted file mode 100644
index 80e1636649..0000000000
--- a/manage_externals/test/test_unit_utils.py
+++ /dev/null
@@ -1,350 +0,0 @@
-#!/usr/bin/env python3
-
-"""Unit test driver for checkout_externals
-
-Note: this script assume the path to the checkout_externals.py module is
-already in the python path.
-
-"""
-
-from __future__ import absolute_import
-from __future__ import unicode_literals
-from __future__ import print_function
-
-import os
-import unittest
-
-from manic.utils import last_n_lines, indent_string
-from manic.utils import str_to_bool, execute_subprocess
-from manic.utils import is_remote_url, split_remote_url, expand_local_url
-
-
-class TestExecuteSubprocess(unittest.TestCase):
- """Test the application logic of execute_subprocess wrapper
- """
-
- def test_exesub_return_stat_err(self):
- """Test that execute_subprocess returns a status code when caller
- requests and the executed subprocess fails.
-
- """
- cmd = ['false']
- status = execute_subprocess(cmd, status_to_caller=True)
- self.assertEqual(status, 1)
-
- def test_exesub_return_stat_ok(self):
- """Test that execute_subprocess returns a status code when caller
- requests and the executed subprocess succeeds.
-
- """
- cmd = ['true']
- status = execute_subprocess(cmd, status_to_caller=True)
- self.assertEqual(status, 0)
-
- def test_exesub_except_stat_err(self):
- """Test that execute_subprocess raises an exception on error when
- caller doesn't request return code
-
- """
- cmd = ['false']
- with self.assertRaises(RuntimeError):
- execute_subprocess(cmd, status_to_caller=False)
-
-
-class TestLastNLines(unittest.TestCase):
- """Test the last_n_lines function.
-
- """
-
- def test_last_n_lines_short(self):
- """With a message with <= n lines, result of last_n_lines should
- just be the original message.
-
- """
- mystr = """three
-line
-string
-"""
-
- mystr_truncated = last_n_lines(
- mystr, 3, truncation_message='[truncated]')
- self.assertEqual(mystr, mystr_truncated)
-
- def test_last_n_lines_long(self):
- """With a message with > n lines, result of last_n_lines should
- be a truncated string.
-
- """
- mystr = """a
-big
-five
-line
-string
-"""
- expected = """[truncated]
-five
-line
-string
-"""
-
- mystr_truncated = last_n_lines(
- mystr, 3, truncation_message='[truncated]')
- self.assertEqual(expected, mystr_truncated)
-
-
-class TestIndentStr(unittest.TestCase):
- """Test the indent_string function.
-
- """
-
- def test_indent_string_singleline(self):
- """Test the indent_string function with a single-line string
-
- """
- mystr = 'foo'
- result = indent_string(mystr, 4)
- expected = ' foo'
- self.assertEqual(expected, result)
-
- def test_indent_string_multiline(self):
- """Test the indent_string function with a multi-line string
-
- """
- mystr = """hello
-hi
-goodbye
-"""
- result = indent_string(mystr, 2)
- expected = """ hello
- hi
- goodbye
-"""
- self.assertEqual(expected, result)
-
-
-class TestStrToBool(unittest.TestCase):
- """Test the string to boolean conversion routine.
-
- """
-
- def test_case_insensitive_true(self):
- """Verify that case insensitive variants of 'true' returns the True
- boolean.
-
- """
- values = ['true', 'TRUE', 'True', 'tRuE', 't', 'T', ]
- for value in values:
- received = str_to_bool(value)
- self.assertTrue(received)
-
- def test_case_insensitive_false(self):
- """Verify that case insensitive variants of 'false' returns the False
- boolean.
-
- """
- values = ['false', 'FALSE', 'False', 'fAlSe', 'f', 'F', ]
- for value in values:
- received = str_to_bool(value)
- self.assertFalse(received)
-
- def test_invalid_str_error(self):
- """Verify that a non-true/false string generates a runtime error.
- """
- values = ['not_true_or_false', 'A', '1', '0',
- 'false_is_not_true', 'true_is_not_false']
- for value in values:
- with self.assertRaises(RuntimeError):
- str_to_bool(value)
-
-
-class TestIsRemoteURL(unittest.TestCase):
- """Crude url checking to determine if a url is local or remote.
-
- """
-
- def test_url_remote_git(self):
- """verify that a remote git url is identified.
- """
- url = 'git@somewhere'
- is_remote = is_remote_url(url)
- self.assertTrue(is_remote)
-
- def test_url_remote_ssh(self):
- """verify that a remote ssh url is identified.
- """
- url = 'ssh://user@somewhere'
- is_remote = is_remote_url(url)
- self.assertTrue(is_remote)
-
- def test_url_remote_http(self):
- """verify that a remote http url is identified.
- """
- url = 'http://somewhere'
- is_remote = is_remote_url(url)
- self.assertTrue(is_remote)
-
- def test_url_remote_https(self):
- """verify that a remote https url is identified.
- """
- url = 'https://somewhere'
- is_remote = is_remote_url(url)
- self.assertTrue(is_remote)
-
- def test_url_local_user(self):
- """verify that a local path with '~/path/to/repo' gets rejected
-
- """
- url = '~/path/to/repo'
- is_remote = is_remote_url(url)
- self.assertFalse(is_remote)
-
- def test_url_local_var_curly(self):
- """verify that a local path with env var '${HOME}' gets rejected
- """
- url = '${HOME}/path/to/repo'
- is_remote = is_remote_url(url)
- self.assertFalse(is_remote)
-
- def test_url_local_var(self):
- """verify that a local path with an env var '$HOME' gets rejected
- """
- url = '$HOME/path/to/repo'
- is_remote = is_remote_url(url)
- self.assertFalse(is_remote)
-
- def test_url_local_abs(self):
- """verify that a local abs path gets rejected
- """
- url = '/path/to/repo'
- is_remote = is_remote_url(url)
- self.assertFalse(is_remote)
-
- def test_url_local_rel(self):
- """verify that a local relative path gets rejected
- """
- url = '../../path/to/repo'
- is_remote = is_remote_url(url)
- self.assertFalse(is_remote)
-
-
-class TestSplitRemoteURL(unittest.TestCase):
- """Crude url checking to determine if a url is local or remote.
-
- """
-
- def test_url_remote_git(self):
- """verify that a remote git url is identified.
- """
- url = 'git@somewhere.com:org/repo'
- received = split_remote_url(url)
- self.assertEqual(received, "org/repo")
-
- def test_url_remote_ssh(self):
- """verify that a remote ssh url is identified.
- """
- url = 'ssh://user@somewhere.com/path/to/repo'
- received = split_remote_url(url)
- self.assertEqual(received, 'somewhere.com/path/to/repo')
-
- def test_url_remote_http(self):
- """verify that a remote http url is identified.
- """
- url = 'http://somewhere.org/path/to/repo'
- received = split_remote_url(url)
- self.assertEqual(received, 'somewhere.org/path/to/repo')
-
- def test_url_remote_https(self):
- """verify that a remote http url is identified.
- """
- url = 'http://somewhere.gov/path/to/repo'
- received = split_remote_url(url)
- self.assertEqual(received, 'somewhere.gov/path/to/repo')
-
- def test_url_local_url_unchanged(self):
- """verify that a local path is unchanged
-
- """
- url = '/path/to/repo'
- received = split_remote_url(url)
- self.assertEqual(received, url)
-
-
-class TestExpandLocalURL(unittest.TestCase):
- """Crude url checking to determine if a url is local or remote.
-
- Remote should be unmodified.
-
- Local, should perform user and variable expansion.
-
- """
-
- def test_url_local_user1(self):
- """verify that a local path with '~/path/to/repo' gets expanded to an
- absolute path.
-
- NOTE(bja, 2017-11) we can't test for something like:
- '~user/path/to/repo' because the user has to be in the local
- machine password directory and we don't know a user name that
- is valid on every system....?
-
- """
- field = 'test'
- url = '~/path/to/repo'
- received = expand_local_url(url, field)
- print(received)
- self.assertTrue(os.path.isabs(received))
-
- def test_url_local_expand_curly(self):
- """verify that a local path with '${HOME}' gets expanded to an absolute path.
- """
- field = 'test'
- url = '${HOME}/path/to/repo'
- received = expand_local_url(url, field)
- self.assertTrue(os.path.isabs(received))
-
- def test_url_local_expand_var(self):
- """verify that a local path with '$HOME' gets expanded to an absolute path.
- """
- field = 'test'
- url = '$HOME/path/to/repo'
- received = expand_local_url(url, field)
- self.assertTrue(os.path.isabs(received))
-
- def test_url_local_env_missing(self):
- """verify that a local path with env var that is missing gets left as-is
-
- """
- field = 'test'
- url = '$TMP_VAR/path/to/repo'
- received = expand_local_url(url, field)
- print(received)
- self.assertEqual(received, url)
-
- def test_url_local_expand_env(self):
- """verify that a local path with another env var gets expanded to an
- absolute path.
-
- """
- field = 'test'
- os.environ['TMP_VAR'] = '/some/absolute'
- url = '$TMP_VAR/path/to/repo'
- received = expand_local_url(url, field)
- del os.environ['TMP_VAR']
- print(received)
- self.assertTrue(os.path.isabs(received))
- self.assertEqual(received, '/some/absolute/path/to/repo')
-
- def test_url_local_normalize_rel(self):
- """verify that a local path with another env var gets expanded to an
- absolute path.
-
- """
- field = 'test'
- url = '/this/is/a/long/../path/to/a/repo'
- received = expand_local_url(url, field)
- print(received)
- self.assertEqual(received, '/this/is/a/path/to/a/repo')
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/py_env_create b/py_env_create
index 9a9b8d940c..ac705edb3c 100755
--- a/py_env_create
+++ b/py_env_create
@@ -122,7 +122,7 @@ if [ "$verbose" == "Yes" ]; then
verbosity="--verbose"
loglevel="INFO"
fi
-cmd="conda install --yes $verbosity --channel conda-forge --name $ctsm_python $condadir/$condafile $option"
+cmd="conda install --yes $verbosity --channel conda-forge --name $ctsm_python --file $condadir/$condafile $option"
echo "$cmd"
$cmd
if [ $? != 0 ]; then
diff --git a/python/ctsm/.pylintrc b/python/ctsm/.pylintrc
index db78949288..230f8acba8 100644
--- a/python/ctsm/.pylintrc
+++ b/python/ctsm/.pylintrc
@@ -436,6 +436,8 @@ good-names=i,
ds,
m,
n,
+ ni,
+ nj,
l1,
l2,
ax,
diff --git a/python/ctsm/crop_calendars/check_constant_vars.py b/python/ctsm/crop_calendars/check_constant_vars.py
index aa25a412fe..be7718256a 100644
--- a/python/ctsm/crop_calendars/check_constant_vars.py
+++ b/python/ctsm/crop_calendars/check_constant_vars.py
@@ -382,4 +382,4 @@ def check_constant_vars(
raise RuntimeError("Stopping due to failed check_constant_vars().")
bad_patches = np.unique(bad_patches)
- return [int(p) for p in bad_patches]
+ return [int(p) for p in bad_patches], any_bad
diff --git a/python/ctsm/crop_calendars/check_rx_obeyed.py b/python/ctsm/crop_calendars/check_rx_obeyed.py
index 99b8d80bde..4d8ccd1788 100644
--- a/python/ctsm/crop_calendars/check_rx_obeyed.py
+++ b/python/ctsm/crop_calendars/check_rx_obeyed.py
@@ -104,6 +104,25 @@ def get_extreme_info(diff_array, rx_array, mxn, dims, gs_da, patches1d_lon, patc
return round(themxn, 3), round(this_lon, 3), round(this_lat, 3), this_gs, round(this_rx)
+def summarize_results(which_ds, output_var, verbose, all_ok, gdd_tolerance, diffs_eg_txt):
+ """
+ Summarize results
+ """
+ bad = True
+ if all_ok == 2:
+ bad = False
+ print(f"✅ {which_ds}: Prescribed {output_var} always obeyed")
+ elif all_ok == 1:
+ bad = False
+ print(
+ f"🟨 {which_ds}: Prescribed {output_var} *not* always obeyed, but acceptable (diffs <= "
+ + f"{gdd_tolerance})"
+ )
+ elif not verbose:
+ print(f"❌ {which_ds}: Prescribed {output_var} *not* always obeyed. E.g., {diffs_eg_txt}")
+ return bad
+
+
def check_rx_obeyed(
vegtype_list, rx_ds, dates_ds, which_ds, output_var, gdd_min=None, verbose=False
):
@@ -114,6 +133,7 @@ def check_rx_obeyed(
dates_ds, which_ds, output_var, verbose
)
+ diffs_eg_txt = None
for vegtype_str in vegtype_list:
thisveg_patches = np.where(dates_ds.patches1d_itype_veg_str == vegtype_str)[0]
if thisveg_patches.size == 0:
@@ -203,14 +223,6 @@ def check_rx_obeyed(
else:
break
- if all_ok == 2:
- print(f"✅ {which_ds}: Prescribed {output_var} always obeyed")
- elif all_ok == 1:
- # print(f"🟨 {which_ds}: Prescribed {output_var} *not* always obeyed, but acceptable:")
- # for x in diff_str_list: print(x)
- print(
- f"🟨 {which_ds}: Prescribed {output_var} *not* always obeyed, but acceptable (diffs <= "
- + f"{gdd_tolerance})"
- )
- elif not verbose:
- print(f"❌ {which_ds}: Prescribed {output_var} *not* always obeyed. E.g., {diffs_eg_txt}")
+ bad = summarize_results(which_ds, output_var, verbose, all_ok, gdd_tolerance, diffs_eg_txt)
+
+ return bad
diff --git a/python/ctsm/crop_calendars/check_rxboth_run.py b/python/ctsm/crop_calendars/check_rxboth_run.py
index ae4decde30..a1014b5e66 100644
--- a/python/ctsm/crop_calendars/check_rxboth_run.py
+++ b/python/ctsm/crop_calendars/check_rxboth_run.py
@@ -75,6 +75,8 @@ def main(argv):
"HARVEST_REASON_PERHARV",
]
+ any_bad = False
+
annual_outfiles = glob.glob(os.path.join(args.directory, "*.clm2.h1.*.nc"))
# These should be constant in a Prescribed Calendars (rxboth) run, as long as the inputs were
@@ -85,13 +87,19 @@ def main(argv):
"rx_gdds_file": args.rx_gdds_file,
}
- case["ds"] = cc.import_output(
+ case["ds"], any_bad_import_output = cc.import_output(
annual_outfiles,
my_vars=my_vars,
year_1=args.first_usable_year,
year_n=args.last_usable_year,
+ throw_errors=False,
+ )
+ any_bad = any_bad or any_bad_import_output
+
+ _, any_bad_check_const_vars = check_constant_vars(
+ case["ds"], case, ignore_nan=True, verbose=True, throw_error=True
)
- check_constant_vars(case["ds"], case, ignore_nan=True, verbose=True, throw_error=True)
+ any_bad = any_bad or any_bad_check_const_vars
# Import GGCMI sowing and harvest dates, and check sims
casename = "Prescribed Calendars"
@@ -128,15 +136,16 @@ def main(argv):
# Check
if case["rx_sdates_file"]:
- check_rx_obeyed(
+ sdate_not_obeyed = check_rx_obeyed(
case["ds"].vegtype_str.values,
case["rx_sdates_ds"].isel(time=0),
case["ds"],
casename,
"SDATES",
)
+ any_bad = any_bad or sdate_not_obeyed
if case["rx_gdds_file"]:
- check_rx_obeyed(
+ gdds_not_obeyed = check_rx_obeyed(
case["ds"].vegtype_str.values,
case["rx_gdds_ds"].isel(time=0),
case["ds"],
@@ -144,6 +153,10 @@ def main(argv):
"GDDHARV",
gdd_min=gdd_min,
)
+ any_bad = any_bad or gdds_not_obeyed
+
+ if any_bad:
+ raise RuntimeError("Unexpected behavior in rxboth run")
if __name__ == "__main__":
diff --git a/python/ctsm/crop_calendars/cropcal_module.py b/python/ctsm/crop_calendars/cropcal_module.py
index 3fe6942f94..b87d26816f 100644
--- a/python/ctsm/crop_calendars/cropcal_module.py
+++ b/python/ctsm/crop_calendars/cropcal_module.py
@@ -13,6 +13,8 @@
from ctsm.crop_calendars.cropcal_constants import DEFAULT_GDD_MIN
from ctsm.crop_calendars.import_ds import import_ds
+MISSING_RX_GDD_VAL = -1
+
def check_and_trim_years(year_1, year_n, ds_in):
"""
@@ -168,8 +170,10 @@ def check_v0_le_v1(this_ds, var_list, msg_txt=" ", both_nan_ok=False, throw_erro
if both_nan_ok:
gdd_lt_hui = gdd_lt_hui | (np.isnan(this_ds[var0]) & np.isnan(this_ds[var1]))
if np.all(gdd_lt_hui):
+ any_bad = False
print(f"✅{msg_txt}{var0} always <= {var1}")
else:
+ any_bad = True
msg = f"❌{msg_txt}{var0} *not* always <= {var1}"
gdd_lt_hui_vals = gdd_lt_hui.values
patch_index = np.where(~gdd_lt_hui_vals)[0][0]
@@ -185,6 +189,7 @@ def check_v0_le_v1(this_ds, var_list, msg_txt=" ", both_nan_ok=False, throw_erro
print(msg)
else:
raise RuntimeError(msg)
+ return any_bad
def get_gs_len_da(this_da):
@@ -231,6 +236,13 @@ def import_max_gs_length(paramfile_dir, my_clm_ver, my_clm_subver):
return mxmat_dict
+def unexpected_negative_rx_gdd(data_array):
+ """
+ Return True if there's a negative value not matching the designated missing value
+ """
+ return np.any((data_array.values < 0) & (data_array.values != MISSING_RX_GDD_VAL))
+
+
def import_rx_dates(var_prefix, date_infile, dates_ds, set_neg1_to_nan=True):
"""
Import prescribed sowing/harvest dates
@@ -260,19 +272,19 @@ def import_rx_dates(var_prefix, date_infile, dates_ds, set_neg1_to_nan=True):
v_new = var.replace(var_prefix, "gs")
this_ds = this_ds.rename({var: v_new})
- # Set -1 prescribed GDD values to NaN. Only warn the first time.
+ # Set GDD values matching MISSING_RX_GDD_VAL to NaN. Only warn the first time.
if (
set_neg1_to_nan
and var_prefix == "gdd"
and v_new != var
and np.any(this_ds[v_new].values < 0)
):
- if np.any((this_ds[v_new].values < 0) & (this_ds[v_new].values != -1)):
+ if unexpected_negative_rx_gdd(this_ds[v_new]):
raise RuntimeError(f"Unexpected negative value in {var}")
if not did_warn:
- print("Setting -1 rx GDD values to NaN")
+ print(f"Setting {MISSING_RX_GDD_VAL} rx GDD values to NaN")
did_warn = True
- this_ds[v_new] = this_ds[v_new].where(this_ds[v_new] != -1)
+ this_ds[v_new] = this_ds[v_new].where(this_ds[v_new] != MISSING_RX_GDD_VAL)
return this_ds
@@ -337,10 +349,13 @@ def import_output(
sdates_rx_ds=None,
gdds_rx_ds=None,
verbose=False,
+ throw_errors=True,
):
"""
Import CLM output
"""
+ any_bad = False
+
# Import
this_ds = import_ds(filename, my_vars=my_vars, my_vegtypes=my_vegtypes)
@@ -410,7 +425,9 @@ def import_output(
# Check that e.g., GDDACCUM <= HUI
for var_list in [["GDDACCUM", "HUI"], ["SYEARS", "HYEARS"]]:
if all(v in this_ds_gs for v in var_list):
- check_v0_le_v1(this_ds_gs, var_list, both_nan_ok=True, throw_error=True)
+ any_bad = check_v0_le_v1(
+ this_ds_gs, var_list, both_nan_ok=True, throw_error=throw_errors
+ )
# Check that prescribed calendars were obeyed
if sdates_rx_ds:
@@ -438,7 +455,7 @@ def import_output(
raise RuntimeError("How to get NHARVEST_DISCREP for NHARVESTS > 2?")
this_ds_gs["NHARVEST_DISCREP"] = (this_ds_gs["NHARVESTS"] == 2).astype(int)
- return this_ds_gs
+ return this_ds_gs, any_bad
def handle_zombie_crops(this_ds):
diff --git a/python/ctsm/crop_calendars/interpolate_gdds.py b/python/ctsm/crop_calendars/interpolate_gdds.py
new file mode 100755
index 0000000000..2aa0b79997
--- /dev/null
+++ b/python/ctsm/crop_calendars/interpolate_gdds.py
@@ -0,0 +1,154 @@
+"""
+Interpolate a maturity requirement (GDD) file
+"""
+
+import os
+import sys
+import argparse
+import logging
+import xarray as xr
+
+# -- add python/ctsm to path (needed if we want to run this stand-alone)
+_CTSM_PYTHON = os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir, os.pardir)
+sys.path.insert(1, _CTSM_PYTHON)
+
+from ctsm import ctsm_logging # pylint: disable=wrong-import-position
+from ctsm.crop_calendars.cropcal_module import ( # pylint: disable=wrong-import-position
+ unexpected_negative_rx_gdd,
+)
+
+logger = logging.getLogger(__name__)
+
+OUTPUT_FORMAT = "NETCDF3_CLASSIC"
+
+
+def _file_missing(filepath, descriptor):
+ if not os.path.exists(filepath) and not os.path.exists(os.path.realpath(filepath)):
+ raise FileNotFoundError(f"{descriptor} not found: {filepath}")
+ return os.path.realpath(filepath)
+
+
+def _setup_process_args():
+ """Process input arguments
+
+ Returns:
+ argparse.ArgumentParser: Arguments/options
+ """
+
+ # set up logging allowing user control
+ ctsm_logging.setup_logging_pre_config()
+
+ parser = argparse.ArgumentParser(
+ description=("Interpolate a maturity requirement (GDD) file."),
+ )
+
+ # Define arguments
+ parser.add_argument(
+ "-i",
+ "--input-file",
+ help="Maturity requirement file to interpolate",
+ type=lambda x: _file_missing(x, "Input file"),
+ required=True,
+ )
+ parser.add_argument(
+ "-t",
+ "--target-file",
+ help="File to whose coordinates the interpolation should take place",
+ type=lambda x: _file_missing(x, "Target file"),
+ required=True,
+ )
+ parser.add_argument(
+ "-o",
+ "--output-file",
+ help="Where to save interpolated result",
+ type=str,
+ required=True,
+ )
+ parser.add_argument(
+ "--overwrite",
+ help="If output file exists, overwrite it.",
+ action="store_true",
+ required=False,
+ )
+ parser.add_argument(
+ "--dry-run",
+ help="Check arguments but do not run.",
+ action="store_true",
+ required=False,
+ )
+ ctsm_logging.add_logging_args(parser)
+
+ # Get arguments
+ args = parser.parse_args(sys.argv[1:])
+ ctsm_logging.process_logging_args(args)
+
+ # Process arguments
+ if os.path.exists(os.path.realpath(args.output_file)) and not args.overwrite:
+ raise FileExistsError(f"Output file exists but --overwrite not given: {args.output_file}")
+ args.output_file = os.path.realpath(args.output_file)
+
+ # Make directory for output file, if needed
+ if not args.dry_run:
+ parent_dir = os.path.dirname(args.output_file)
+ if not os.path.exists(parent_dir):
+ os.makedirs(parent_dir)
+
+ return args
+
+
+def interpolate_gdds(args):
+ """
+ Do the interpolation and save
+ """
+
+ # Open inputs
+ ds_in = xr.open_dataset(args.input_file)
+ ds_target = xr.open_dataset(args.target_file)
+
+ # Interpolate
+ ds_out = xr.Dataset()
+ for var in ds_in:
+
+ # Check variable
+ if "gdd1_" not in var:
+ raise RuntimeError(f"Unexpected variable {var} on input file")
+ if args.dry_run:
+ continue
+
+ # Interpolate
+ da_out = ds_in[var].interp_like(
+ ds_target,
+ method="nearest",
+ kwargs={"fill_value": "extrapolate"}, # Otherwise you get NaNs at edges
+ )
+
+ if unexpected_negative_rx_gdd(da_out):
+ raise RuntimeError("Unexpected negative value")
+
+ # Add to dataset
+ ds_out[var] = da_out
+
+ # Finish up
+ ds_out.attrs["original"] = args.input_file
+ ds_out.attrs["interpolation_target"] = args.target_file
+ ds_out.attrs["interpolation_script"] = os.path.basename(__file__)
+ if not args.dry_run:
+ ds_out.to_netcdf(args.output_file, format=OUTPUT_FORMAT)
+ else:
+ print("Dry run looks good!")
+
+
+def main():
+ """
+ Description
+ -----------
+ Calls function that interpolates a maturity requirement (GDD) file.
+ """
+
+ args = _setup_process_args()
+
+ interpolate_gdds(args)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/python/ctsm/modify_input_files/fsurdat_modifier.py b/python/ctsm/modify_input_files/fsurdat_modifier.py
index bd060cb9dc..1a45590872 100644
--- a/python/ctsm/modify_input_files/fsurdat_modifier.py
+++ b/python/ctsm/modify_input_files/fsurdat_modifier.py
@@ -254,8 +254,8 @@ def modify_optional(
"""Modify the dataset according to the optional settings"""
# Set fsurdat variables in a rectangle that could be global (default).
- # Note that the land/ocean mask gets specified in the domain file for
- # MCT or the ocean mesh files for NUOPC. Here the user may specify
+ # Note that the land/ocean mask gets specified in
+ # the ocean mesh files. Here the user may specify
# fsurdat variables inside a box but cannot change which points will
# run as land and which as ocean.
if idealized:
diff --git a/python/ctsm/run_sys_tests.py b/python/ctsm/run_sys_tests.py
index de93081504..ecea2342a7 100644
--- a/python/ctsm/run_sys_tests.py
+++ b/python/ctsm/run_sys_tests.py
@@ -576,12 +576,12 @@ def _record_git_status(testroot, retry, dry_run):
if git_status.count("\n") == 1:
# Only line in git status is the branch info
output += "(clean sandbox)\n"
- manic = os.path.join("manage_externals", "checkout_externals")
- manage_externals_status = subprocess.check_output(
- [manic, "--status", "--verbose"], cwd=ctsm_root, universal_newlines=True
+ fleximod = os.path.join("bin", "git-fleximod")
+ fleximod_status = subprocess.check_output(
+ [fleximod, "status"], cwd=ctsm_root, universal_newlines=True
)
- output += 72 * "-" + "\n" + "manage_externals status:" + "\n"
- output += manage_externals_status
+ output += 72 * "-" + "\n" + "git-fleximod status:" + "\n"
+ output += fleximod_status
output += 72 * "-" + "\n"
print(output)
diff --git a/python/ctsm/site_and_regional/run_neon.py b/python/ctsm/site_and_regional/run_neon.py
index 4b0df2722d..3acbf435b1 100755
--- a/python/ctsm/site_and_regional/run_neon.py
+++ b/python/ctsm/site_and_regional/run_neon.py
@@ -41,7 +41,7 @@
# - [ ] Case dependency and the ability to check case status
# - [ ] If Case dependency works we don't need finidat given explicilty for post-ad and transient.
-# - [ ] checkout_externals instead of using env varaiable
+# - [ ] "./bin/git-fleximod update" instead of using env variable
# - [ ] wget the fields available and run for those available
# - [ ] Matrix spin-up if (SASU) Eric merged it in
diff --git a/python/ctsm/site_and_regional/single_point_case.py b/python/ctsm/site_and_regional/single_point_case.py
index 86dabe609d..2c2aebad52 100644
--- a/python/ctsm/site_and_regional/single_point_case.py
+++ b/python/ctsm/site_and_regional/single_point_case.py
@@ -14,7 +14,7 @@
# -- import local classes for this script
from ctsm.site_and_regional.base_case import BaseCase, USRDAT_DIR, DatmFiles
-from ctsm.utils import add_tag_to_filename
+from ctsm.utils import add_tag_to_filename, ensure_iterable
logger = logging.getLogger(__name__)
@@ -415,7 +415,10 @@ def modify_surfdata_atpoint(self, f_orig):
# f_mod["PCT_CROP"][:, :] = 0
# -- loop over all dom_pft and pct_pft
- zip_pfts = zip(self.dom_pft, self.pct_pft, self.cth, self.cbh)
+ iterable_length = len(self.dom_pft)
+ cth_to_zip = ensure_iterable(self.cth, iterable_length)
+ cbh_to_zip = ensure_iterable(self.cbh, iterable_length)
+ zip_pfts = zip(self.dom_pft, self.pct_pft, cth_to_zip, cbh_to_zip)
for dom_pft, pct_pft, cth, cbh in zip_pfts:
if cth is not None:
f_mod["MONTHLY_HEIGHT_TOP"][:, :, :, dom_pft] = cth
diff --git a/python/ctsm/test/test_unit_singlept_data_surfdata.py b/python/ctsm/test/test_unit_singlept_data_surfdata.py
index a29fa05b33..2106799a4b 100755
--- a/python/ctsm/test/test_unit_singlept_data_surfdata.py
+++ b/python/ctsm/test/test_unit_singlept_data_surfdata.py
@@ -47,8 +47,8 @@ class TestSinglePointCaseSurfaceNoCrop(unittest.TestCase):
evenly_split_cropland = False
pct_pft = None
num_pft = 16
- cth = [0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9]
- cbh = [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]
+ cth = 0.9
+ cbh = 0.1
include_nonveg = False
uni_snow = True
cap_saturation = True
@@ -668,8 +668,8 @@ class TestSinglePointCaseSurfaceCrop(unittest.TestCase):
evenly_split_cropland = False
pct_pft = None
num_pft = 78
- cth = [0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9]
- cbh = [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]
+ cth = 0.9
+ cbh = 0.1
include_nonveg = False
uni_snow = False
cap_saturation = False
diff --git a/python/ctsm/test/test_unit_utils.py b/python/ctsm/test/test_unit_utils.py
index 85ba2515dd..aed43cfede 100755
--- a/python/ctsm/test/test_unit_utils.py
+++ b/python/ctsm/test/test_unit_utils.py
@@ -9,7 +9,7 @@
import os
from ctsm import unit_testing
-from ctsm.utils import fill_template_file
+from ctsm.utils import fill_template_file, ensure_iterable
from ctsm.config_utils import lon_range_0_to_360, _handle_config_value
# Allow names that pylint doesn't like, because otherwise I find it hard
@@ -328,6 +328,38 @@ def test_handleConfigValue_isListFalse(self):
self.assertEqual(val_out, float(val_in))
+class TestUtilsEnsureIterable(unittest.TestCase):
+ """Tests of utils: ensure_iterable"""
+
+ def test_ensure_iterable_number(self):
+ """
+ Tests that ensure_iterable(NUMBER, 3) produces a list of 3 NUMBERs
+ """
+ val = 724.1987
+ self.assertEqual(ensure_iterable(val, 3), [val, val, val])
+
+ def test_ensure_iterable_none(self):
+ """
+ Tests that ensure_iterable(None, 2) produces a list of 2 Nones
+ """
+ val = None
+ self.assertEqual(ensure_iterable(val, 2), [val, val])
+
+ def test_ensure_iterable_already(self):
+ """
+ Tests that ensure_iterable() returns the input if it's already iterable
+ """
+ val = [11, 12]
+ self.assertEqual(ensure_iterable(val, 2), val)
+
+ def test_ensure_iterable_error_wrong_length(self):
+ """
+ Tests that ensure_iterable() errors if input is iterable but of the wrong length
+ """
+ with self.assertRaisesRegex(ValueError, "Input is iterable but wrong length"):
+ ensure_iterable([11, 12], 3)
+
+
if __name__ == "__main__":
unit_testing.setup_for_tests()
unittest.main()
diff --git a/python/ctsm/toolchain/gen_mksurfdata_jobscript_multi.py b/python/ctsm/toolchain/gen_mksurfdata_jobscript_multi.py
index 6deb50ebfb..6c38efdd0d 100755
--- a/python/ctsm/toolchain/gen_mksurfdata_jobscript_multi.py
+++ b/python/ctsm/toolchain/gen_mksurfdata_jobscript_multi.py
@@ -48,6 +48,7 @@
"crop-global-SSP2-4.5-f19",
"crop-global-SSP2-4.5-f10",
"crop-global-SSP2-4.5-f45",
+ "crop-global-SSP2-4.5-ne0np4",
"crop-global-SSP2-4.5-ne3",
"crop-global-SSP2-4.5-ne16",
"crop-global-SSP2-4.5-ne30",
@@ -204,6 +205,11 @@ def main():
"ne3": ["ne3np4.pg3"],
"ne16": ["ne16np4.pg3"],
"ne30": ["ne30np4.pg3", "ne30np4.pg2", "ne30np4"],
+ "ne0np4": [
+ "ne0np4.ARCTICGRIS.ne30x8",
+ "ne0np4.ARCTIC.ne30x4",
+ "ne0np4CONUS.ne30x8",
+ ],
"ne120": [
"ne0np4.ARCTICGRIS.ne30x8",
"ne0np4.ARCTIC.ne30x4",
@@ -333,6 +339,10 @@ def main():
"--start-year 1850 --end-year 2100 --nosurfdata --ssp-rcp SSP2-4.5 --res",
"f45",
),
+ "crop-global-SSP2-4.5-ne0np4": (
+ "--start-year 1979 --end-year 2026 --ssp-rcp SSP2-4.5 --res",
+ "ne0np4",
+ ),
"crop-global-SSP2-4.5-ne3": (
"--start-year 1850 --end-year 2100 --nosurfdata --ssp-rcp SSP2-4.5 --res",
"ne3",
diff --git a/python/ctsm/toolchain/gen_mksurfdata_namelist.py b/python/ctsm/toolchain/gen_mksurfdata_namelist.py
index 8a953c39df..361616419f 100755
--- a/python/ctsm/toolchain/gen_mksurfdata_namelist.py
+++ b/python/ctsm/toolchain/gen_mksurfdata_namelist.py
@@ -12,7 +12,7 @@
from datetime import datetime
import netCDF4
-from ctsm.path_utils import path_to_ctsm_root
+from ctsm.path_utils import path_to_ctsm_root, path_to_cime
from ctsm.ctsm_logging import setup_logging_pre_config, add_logging_args, process_logging_args
logger = logging.getLogger(__name__)
@@ -326,7 +326,7 @@ def main():
)
# determine output mesh
- determine_output_mesh(res, force_model_mesh_file, input_path, rawdata_files, tool_path)
+ determine_output_mesh(res, force_model_mesh_file, input_path, rawdata_files)
# Determine num_pft
if nocrop_flag:
@@ -752,11 +752,11 @@ def handle_transient_run(
return landuse_fname, must_run_download_input_data
-def determine_output_mesh(res, force_model_mesh_file, input_path, rawdata_files, tool_path):
+def determine_output_mesh(res, force_model_mesh_file, input_path, rawdata_files):
"""
determine output mesh
"""
- xml_path = os.path.join(tool_path, "../../ccs_config/component_grids_nuopc.xml")
+ xml_path = os.path.join(path_to_cime(), "../ccs_config/component_grids_nuopc.xml")
tree2 = ET.parse(xml_path)
root = tree2.getroot()
model_mesh = ""
diff --git a/python/ctsm/utils.py b/python/ctsm/utils.py
index 8578ea860c..a5a02a5c9d 100644
--- a/python/ctsm/utils.py
+++ b/python/ctsm/utils.py
@@ -26,6 +26,24 @@ def abort(errmsg):
sys.exit("ERROR: {}".format(errmsg))
+def ensure_iterable(thing_we_want_iterable, iterable_length):
+ """
+ Ensure that a variable is iterable
+ """
+ already_iterable = True
+ try:
+ iter(thing_we_want_iterable)
+ except TypeError:
+ already_iterable = False
+
+ if not already_iterable:
+ thing_we_want_iterable = [thing_we_want_iterable] * iterable_length
+ elif len(thing_we_want_iterable) != iterable_length:
+ raise ValueError("Input is iterable but wrong length")
+
+ return thing_we_want_iterable
+
+
def fill_template_file(path_to_template, path_to_final, substitutions):
"""Given a template file (based on python's template strings), write a copy of the
file with template values filled in.
diff --git a/share b/share
new file mode 160000
index 0000000000..4b9dc4871a
--- /dev/null
+++ b/share
@@ -0,0 +1 @@
+Subproject commit 4b9dc4871a259f00f35bb47708d876cb7dcdf75c
diff --git a/src/biogeochem/CMakeLists.txt b/src/biogeochem/CMakeLists.txt
index e31bbc80f8..50eb64cdb7 100644
--- a/src/biogeochem/CMakeLists.txt
+++ b/src/biogeochem/CMakeLists.txt
@@ -6,6 +6,9 @@ list(APPEND clm_sources
CNPhenologyMod.F90
CNSpeciesMod.F90
CNDVType.F90
+ DustEmisBase.F90
+ DustEmisZender2003.F90
+ DustEmisFactory.F90
CropReprPoolsMod.F90
CropType.F90
CNVegStateType.F90
diff --git a/src/biogeochem/CNDriverMod.F90 b/src/biogeochem/CNDriverMod.F90
index b23019eb23..0381711258 100644
--- a/src/biogeochem/CNDriverMod.F90
+++ b/src/biogeochem/CNDriverMod.F90
@@ -6,7 +6,7 @@ module CNDriverMod
!
! !USES:
use shr_kind_mod , only : r8 => shr_kind_r8
- use clm_varctl , only : use_c13, use_c14, use_fates, use_fates_bgc, use_dynroot
+ use clm_varctl , only : use_c13, use_c14, use_fates, use_fates_bgc
use dynSubgridControlMod , only : get_do_harvest, get_do_grossunrep
use decompMod , only : bounds_type
use perf_mod , only : t_startf, t_stopf
@@ -147,7 +147,6 @@ subroutine CNDriverNoLeaching(bounds,
use SoilBiogeochemNitrifDenitrifMod , only: SoilBiogeochemNitrifDenitrif
use SoilBiogeochemNStateUpdate1Mod , only: SoilBiogeochemNStateUpdate1
use NutrientCompetitionMethodMod , only: nutrient_competition_method_type
- use CNRootDynMod , only: CNRootDyn
use CNPrecisionControlMod , only: CNPrecisionControl
!
! !ARGUMENTS:
@@ -564,20 +563,6 @@ subroutine CNDriverNoLeaching(bounds,
call t_stopf('CNGResp')
- !--------------------------------------------
- ! Dynamic Roots
- !--------------------------------------------
-
- if( use_dynroot ) then
- call t_startf('CNRootDyn')
-
- call CNRootDyn(bounds, num_bgc_soilc, filter_bgc_soilc, num_bgc_vegp, filter_bgc_vegp, &
- cnveg_carbonstate_inst, cnveg_nitrogenstate_inst, cnveg_carbonflux_inst, &
- cnveg_state_inst, crop_inst, soilstate_inst, soilbiogeochem_nitrogenstate_inst)
-
- call t_stopf('CNRootDyn')
- end if
-
!--------------------------------------------------------------------------
! CNUpdate0
! The state updates are still called for the matrix solution (use_matrixn
diff --git a/src/biogeochem/CNRootDynMod.F90 b/src/biogeochem/CNRootDynMod.F90
deleted file mode 100644
index 3f43424cfa..0000000000
--- a/src/biogeochem/CNRootDynMod.F90
+++ /dev/null
@@ -1,271 +0,0 @@
-module CNRootDynMod
-
-!-----------------------------------------------------------------------
-! !DESCRIPTION:
-! Module holding routines used for determining fine root distribution for all pfts.
-! Includes dynamic root depth for crops
-!
-! !USES:
- use shr_kind_mod , only : r8 => shr_kind_r8
- use clm_time_manager , only : get_step_size_real
- use abortutils , only : endrun
- use clm_varpar , only : nlevsoi, nlevgrnd
- use clm_varctl , only : use_bedrock
- use decompMod , only : bounds_type
- use pftconMod , only : noveg, npcropmin, pftcon
- use ColumnType , only : col
- use PatchType , only : patch
- use CNVegStateType , only : cnveg_state_type
- use CNVegCarbonStateType , only : cnveg_carbonstate_type
- use CNVegCarbonFluxType , only : cnveg_carbonflux_type
- use CNVegnitrogenstateType , only : cnveg_nitrogenstate_type
- use SoilStateType , only : soilstate_type
- use SoilBiogeochemNitrogenStateType , only : soilbiogeochem_nitrogenstate_type
- use CropType , only : crop_type
-
-! !PUBLIC TYPES:
- implicit none
- save
- private
- public :: CNRootDyn
-!-----------------------------------------------------------------------
-
-contains
-
-!-----------------------------------------------------------------------
-!
-subroutine CNRootDyn(bounds, num_soilc, filter_soilc, num_soilp, filter_soilp, &
- cnveg_carbonstate_inst, cnveg_nitrogenstate_inst, cnveg_carbonflux_inst, &
- cnveg_state_inst, crop_inst, soilstate_inst, soilbiogeochem_nitrogenstate_inst)
-!
-! !DESCRIPTION:
-! This routine determine the fine root distribution
-! Needs to be called after the photosynthesis calculation
-! May need to update other subroutines that use the fixed root profile for calculations
-! i.e. CNVerticalProfileMod
-!
-! !USES:
-
-
-! !ARGUMENTS:
- type(bounds_type), intent(in) :: bounds ! bounds
- integer, intent(in) :: num_soilc
- integer, intent(in) :: filter_soilc(:)
- integer, intent(in) :: num_soilp ! number of soil pfts in filter
- integer, intent(in) :: filter_soilp(:) ! filter for soil pfts
- type(cnveg_state_type) , intent(in) :: cnveg_state_inst
- type(cnveg_carbonstate_type) , intent(in) :: cnveg_carbonstate_inst
- type(cnveg_carbonflux_type) , intent(in) :: cnveg_carbonflux_inst
- type(cnveg_nitrogenstate_type) , intent(in) :: cnveg_nitrogenstate_inst
- type(crop_type) , intent(in) :: crop_inst
- type(soilbiogeochem_nitrogenstate_type) , intent(in) :: soilbiogeochem_nitrogenstate_inst
- type(soilstate_type) , intent(inout) :: soilstate_inst
-
-!
-! !LOCAL VARIABLES:
-
- integer :: f,c,p,lev,j ! indices
- real(r8):: dt ! radiation time step delta t (seconds)
- real(r8), allocatable :: w_limit(:)
- real(r8), allocatable :: rswa(:,:) ! soil water availability in each soil layer
- real(r8), allocatable :: rsmn(:,:) ! soil nitrogen availability in each soil layer
- real(r8), allocatable :: sumrswa(:) ! scaling soil water availability in each soil layer
- real(r8), allocatable :: sumrsmn(:) ! scaling soil mineral N availability in each soil layer
- real(r8) :: frootc_dz(bounds%begp:bounds%endp, 1:nlevgrnd)
- real(r8), allocatable :: sumfrootc(:) ! fine root carbon total before turnover in each step
- real(r8):: minpsi ! minimum soil moisture potential
- real(r8):: psi
- real(r8):: maxpsi
- real(r8):: new_growth
-
-!-----------------------------------------------------------------------
- ! Assign local pointers to derived type arrays (in)
- associate(&
- ivt => patch%itype , & ! Input: [integer (:)] pft vegetation type
- pcolumn => patch%column , & ! Input: [integer (:)] pft's column index
- roota_par => pftcon%roota_par , & ! Input: [real(r8) (:)] pft's roota index
- rootb_par => pftcon%rootb_par , & ! Input: [real(r8) (:)] pft's rootb index
- root_dmx => pftcon%root_dmx , & ! Input: [real(r8) (:)] crop maximum root depth
- cpool_to_frootc => cnveg_carbonflux_inst%cpool_to_frootc_patch , & ! Input: [real(r8) (:)] allocation to fine root C (gC/m2/s)
- frootc_xfer_to_frootc => cnveg_carbonflux_inst%frootc_xfer_to_frootc_patch , & ! Input: [real(r8) (:)] fine root C growth from storage (gC/m2/s)
- dormant_flag => cnveg_state_inst%dormant_flag_patch , & ! Input: [real(r8) (:)] dormancy flag
- root_depth => soilstate_inst%root_depth_patch , & ! InOut: [real(r8) (:)] current root depth
- dz => col%dz , & ! Input: layer thickness (m) (-nlevsno+1:nlevgrnd)
- zi => col%zi , & ! Input: interface level below a "z" level (m) (-nlevsno+0:nlevgrnd)
- rootfr => soilstate_inst%rootfr_patch , & ! Output: [real(r8) (:,:)] fraction of roots in each soil layer
- sucsat => soilstate_inst%sucsat_col , & ! Input: minimum soil suction (mm)
- soilpsi => soilstate_inst%soilpsi_col , & ! Input: soil water potential in each soil layer (MPa)
- sminn_vr => soilbiogeochem_nitrogenstate_inst%sminn_vr_col , & ! Iniput: [real(r8) (:,:)] (gN/m3) soil mineral N
- frootc => cnveg_carbonstate_inst%frootc_patch , & ! Input: [real(r8) (:)] (gC/m2) fine root C
- hui => crop_inst%hui_patch , & ! Input: [real(r8) (:)] crop patch heat unit index (growing degree-days); set to 0 at sowing and accumulated until harvest
- croplive => crop_inst%croplive_patch , & ! Input: [logical (:)] flag, true if planted, not harvested
- huigrain => cnveg_state_inst%huigrain_patch & ! Input: [real(r8) (:)] same to reach vegetative maturity
- )
-
-! set time steps
- dt = get_step_size_real()
-
-! set minpsi to permanent wilting point
- minpsi = -1.5_r8
-
- allocate(sumrswa(bounds%begp:bounds%endp))
- allocate(sumrsmn(bounds%begp:bounds%endp))
- allocate(sumfrootc(bounds%begp:bounds%endp))
- allocate(rswa(bounds%begp:bounds%endp,nlevgrnd))
- allocate(rsmn(bounds%begp:bounds%endp,nlevgrnd))
- allocate(w_limit(bounds%begp:bounds%endp))
-
-!initialize to 0
- w_limit(bounds%begp:bounds%endp) = 0._r8
- sumrswa(bounds%begp:bounds%endp) = 0._r8
- sumrsmn(bounds%begp:bounds%endp) = 0._r8
- sumfrootc(bounds%begp:bounds%endp) = 0._r8
- rswa(bounds%begp:bounds%endp,:) = 0._r8
- rsmn(bounds%begp:bounds%endp,:) = 0._r8
-
- frootc_dz(bounds%begp:bounds%endp,1:nlevgrnd) = 0._r8
-
-
-!---------------------------------------------------------------
-! Set root depth, dynamic for crops, fixed for other vegetation
-!---------------------------------------------------------------
-
- do f = 1, num_soilp
- p = filter_soilp(f)
- c = pcolumn(p)
- if (ivt(p) /= noveg) then
- if((ivt(p)) >= npcropmin)then !skip generic crop types
- if (.not. croplive(p)) then
- root_depth(p) = 0._r8
- else if(huigrain(p) > 0._r8)then
- root_depth(p) = max(zi(c,2), min(hui(p)/huigrain(p)* root_dmx(ivt(p)), root_dmx(ivt(p))))
- end if
- else
- ! this can be changed to any depth (i.e. the maximum soil depth)
- root_depth(p) = zi(c,nlevsoi)
- end if
- if (use_bedrock) then
- root_depth(p) = min(root_depth(p),zi(c,col%nbedrock(c)))
- end if
- else
- root_depth(p) = 0._r8
- end if
- end do
-
-!----------------------------------------------------------------
-! ! calculate a weighting function by soil depth that depends on the
- ! fine root distribution per pft and depth and the pft weight on the column.
- ! This will be used to weight the temperature and water potential scalars
- ! for decomposition control.
-
- ! calculate the rate constant scalar for soil water content.
- ! Uses the log relationship with water potential given in
- ! Andren, O., and K. Paustian, 1987. Barley straw decomposition in the field:
- ! a comparison of models. Ecology, 68(5):1190-1200.
- ! and supported by data in
- ! Orchard, V.A., and F.J. Cook, 1983. Relationship between soil respiration
- ! and soil moisture. Soil Biol. Biochem., 15(4):447-453.
-
- do j = 1,nlevsoi
- do f = 1,num_soilp
- p = filter_soilp(f)
- c = pcolumn(p)
- maxpsi = sucsat(c,j) * (-9.8e-6_r8)
- psi = min(soilpsi(c,j),maxpsi)
- if (psi > minpsi) then
-! First calculate water in the root zone
- if(root_depth(p) > 0.15_r8 .and. (zi(c,j) <= root_depth(p) .or. &
- (zi(c,j-1) < root_depth(p) .and. zi(c,j) > root_depth(p)))) then
- w_limit(p) = w_limit(p) + max(0._r8,log(minpsi/psi)/log(minpsi/maxpsi))*rootfr(p,j)
- end if
-! Calculate the water in each soil layer
- if (root_depth(p) >= zi(c,j) .or. &
- (zi(c,j-1) < root_depth(p) .and. zi(c,j) > root_depth(p))) then
- rswa(p,j) = max(0._r8, (log(minpsi/psi)/log(minpsi/maxpsi)))
- end if
- end if
- sumrswa(p) = sumrswa(p) + rswa(p,j)
-
-! Calculate the nitrogen profile in each layer
-! For now, the profile for each PFT is equivilent to the
-! column profile, in the future, this could be changed to a weighted profile
- rsmn(p,j) = sminn_vr(c,j)
- if (root_depth(p) >= zi(c,j).or. &
- (zi(c,j-1) < root_depth(p) .and. zi(c,j) > root_depth(p))) then
- sumrsmn(p) = sumrsmn(p) + rsmn(p,j)
- end if
- end do
- end do
-
-
-!--------------------------------------------------------------------
-! Now calculate the density of roots in each soil layer for each pft
-! based on this timesteps growth
-!--------------------------------------------------------------------
- do lev = 1, nlevgrnd
-
- do f = 1, num_soilp
- p = filter_soilp(f)
- c = pcolumn(p)
-
- new_growth = (cpool_to_frootc(p) + frootc_xfer_to_frootc(p))*dt
- if(zi(c,lev) <= root_depth(p) .or. &
- (zi(c,lev-1) < root_depth(p) .and. zi(c,lev) > root_depth(p))) then
- if(sumrswa(p) <= 0._r8 .or. sumrsmn(p) <= 0._r8) then
-! when sumrswa or sumrsmn are less than or equal to 0 rootfr will not be updated
- else
- frootc_dz(p,lev) = (frootc(p))*rootfr(p,lev) &
- + new_growth * ((1._r8 - w_limit(p)) * rswa(p,lev) / sumrswa(p) &
- + w_limit(p) * rsmn(p,lev) / sumrsmn(p))
- end if
- else
- frootc_dz(p,lev) = 0._r8
- end if
-
- sumfrootc(p) = sumfrootc(p) + frootc_dz(p,lev)
-
- end do
- end do
-!----------------------------------
-!Calculate root fraction
-!----------------------------------
-
- do lev = 1, nlevgrnd
- do f = 1, num_soilp
- p = filter_soilp(f)
- c = pcolumn(p)
- if(sumfrootc(p) > 0._r8)then
- rootfr(p,lev) = frootc_dz(p,lev)/sumfrootc(p)
- end if
- if(ivt(p) >= npcropmin .and. .not. croplive(p))then
-! CROPS are dormant, there are no roots!
-! but, need an initial frootr so crops can start root production
- if (lev < 2)then
- rootfr(p,lev) = .5_r8*( exp(-roota_par(patch%itype(p)) * zi(c,lev-1)) &
- + exp(-rootb_par(patch%itype(p)) * zi(c,lev-1)) &
- - exp(-roota_par(patch%itype(p)) * zi(c,lev )) &
- - exp(-rootb_par(patch%itype(p)) * zi(c,lev )) )
- elseif (lev == 2) then
- rootfr(p,lev) = .5_r8*( exp(-roota_par(patch%itype(p)) * zi(c,lev-1)) &
- + exp(-rootb_par(patch%itype(p)) * zi(c,lev-1)) )
- else
- rootfr(p,lev) = 0.0_r8
- end if
-
- end if
- end do
- end do
-
-!**********************
- deallocate(sumrswa)
- deallocate(sumrsmn)
- deallocate(sumfrootc)
- deallocate(rsmn)
- deallocate(rswa)
- deallocate(w_limit)
-
- end associate
-
- end subroutine CNRootDyn
-
-end module CNRootDynMod
diff --git a/src/biogeochem/CNVegStateType.F90 b/src/biogeochem/CNVegStateType.F90
index c286c0344f..d63752c5b7 100644
--- a/src/biogeochem/CNVegStateType.F90
+++ b/src/biogeochem/CNVegStateType.F90
@@ -519,7 +519,7 @@ subroutine InitCold(this, bounds)
! --------------------------------------------------------------------
! Initialize terms needed for dust model
- ! TODO - move these terms to DUSTMod module variables
+ ! TODO - move these terms to DustEmisBase object variables
! --------------------------------------------------------------------
do c = bounds%begc, bounds%endc
diff --git a/src/biogeochem/CNVegetationFacade.F90 b/src/biogeochem/CNVegetationFacade.F90
index 61e2e9cf91..f42cf17d68 100644
--- a/src/biogeochem/CNVegetationFacade.F90
+++ b/src/biogeochem/CNVegetationFacade.F90
@@ -147,7 +147,7 @@ module CNVegetationFacade
! - ch4_inst
! - probably not: really seems to belong in soilbiogeochem
! - crop_inst
- ! - dust_inst
+ ! - dust_emis_inst
! - vocemis_inst
! - fireemis_inst
! - drydepvel_inst
diff --git a/src/biogeochem/DUSTMod.F90 b/src/biogeochem/DustEmisBase.F90
similarity index 54%
rename from src/biogeochem/DUSTMod.F90
rename to src/biogeochem/DustEmisBase.F90
index ffa2bfe6f0..47f2f32688 100644
--- a/src/biogeochem/DUSTMod.F90
+++ b/src/biogeochem/DustEmisBase.F90
@@ -1,18 +1,19 @@
-module DUSTMod
+module DustEmisBase
+#include "shr_assert.h"
- !-----------------------------------------------------------------------
- ! !DESCRIPTION:
+ !-----------------------------------------------------------------------
+ ! !DESCRIPTION:
! Routines in this module calculate Dust mobilization and dry deposition for dust.
- ! Simulates dust mobilization due to wind from the surface into the
- ! lowest atmospheric layer. On output flx_mss_vrt_dst(ndst) is the surface dust
+ ! Simulates dust mobilization due to wind from the surface into the
+ ! lowest atmospheric layer. On output flx_mss_vrt_dst(ndst) is the surface dust
! emission (kg/m**2/s) [ + = to atm].
- ! Calculates the turbulent component of dust dry deposition, (the turbulent deposition
- ! velocity through the lowest atmospheric layer). CAM will calculate the settling
- ! velocity through the whole atmospheric column. The two calculations will determine
+ ! Calculates the turbulent component of dust dry deposition, (the turbulent deposition
+ ! velocity through the lowest atmospheric layer). CAM will calculate the settling
+ ! velocity through the whole atmospheric column. The two calculations will determine
! the dust dry deposition flux to the surface.
- !
+ !
! !USES:
- use shr_kind_mod , only : r8 => shr_kind_r8
+ use shr_kind_mod , only : r8 => shr_kind_r8
use shr_log_mod , only : errMsg => shr_log_errMsg
use shr_infnan_mod , only : nan => shr_infnan_nan, assignment(=)
use clm_varpar , only : dst_src_nbr, ndst, sz_nbr
@@ -24,83 +25,148 @@ module DUSTMod
use atm2lndType , only : atm2lnd_type
use SoilStateType , only : soilstate_type
use CanopyStateType , only : canopystate_type
- use WaterStateBulkType , only : waterstatebulk_type
- use WaterDiagnosticBulkType , only : waterdiagnosticbulk_type
+ use WaterStateBulkType , only : waterstatebulk_type
+ use WaterDiagnosticBulkType, only : waterdiagnosticbulk_type
use FrictionVelocityMod , only : frictionvel_type
use LandunitType , only : lun
use ColumnType , only : col
use PatchType , only : patch
- use ZenderSoilErodStreamType, only : soil_erod_stream_type
- use clm_varctl , only : dust_emis_method
- !
+ !
! !PUBLIC TYPES
implicit none
private
!
- ! !PUBLIC MEMBER FUNCTIONS:
- !
- public DustEmission ! Dust mobilization
- public DustDryDep ! Turbulent dry deposition for dust
+ ! !PRIVATE DATA:
!
- ! !PUBLIC DATA:
- !
- real(r8) , allocatable :: ovr_src_snk_mss(:,:)
- real(r8) , allocatable :: dmt_vwr(:) ![m] Mass-weighted mean diameter resolved
- real(r8) , allocatable :: stk_crc(:) ![frc] Correction to Stokes settling velocity
- real(r8) tmp1 !Factor in saltation computation (named as in Charlie's code)
- real(r8) dns_aer ![kg m-3] Aerosol density
+ real(r8), parameter :: dns_aer = 2.5e+3_r8 ![kg m-3] Aerosol density
!
! !PUBLIC DATA TYPES:
!
- type, public :: dust_type
-
- real(r8), pointer, PUBLIC :: flx_mss_vrt_dst_patch (:,:) ! surface dust emission (kg/m**2/s) [ + = to atm] (ndst)
- real(r8), pointer, private :: flx_mss_vrt_dst_tot_patch (:) ! total dust flux into atmosphere
- real(r8), pointer, private :: vlc_trb_patch (:,:) ! turbulent deposition velocity (m/s) (ndst)
+ type, abstract, public :: dust_emis_base_type
+
+ real(r8) , allocatable, public :: ovr_src_snk_mss(:,:) ! overlap factors between the source and sin
+ real(r8) , allocatable, private :: dmt_vwr(:) ! [m] Mass-weighted mean diameter resolved
+ real(r8) , allocatable, private :: stk_crc(:) ! [frc] Correction to Stokes settling velocity
+ real(r8), public :: saltation_factor ! Factor in saltation computation (named as in Charlie's code)
+ real(r8), pointer, PUBLIC :: flx_mss_vrt_dst_patch (:,:) ! surface dust emission (kg/m**2/s) [ + = to atm] (ndst)
+ real(r8), pointer, public :: flx_mss_vrt_dst_tot_patch (:) ! total dust flux into atmosphere
+ real(r8), pointer, private :: vlc_trb_patch (:,:) ! turbulent deposition velocity (m/s) (ndst)
real(r8), pointer, private :: vlc_trb_1_patch (:) ! turbulent deposition velocity 1(m/s)
real(r8), pointer, private :: vlc_trb_2_patch (:) ! turbulent deposition velocity 2(m/s)
real(r8), pointer, private :: vlc_trb_3_patch (:) ! turbulent deposition velocity 3(m/s)
real(r8), pointer, private :: vlc_trb_4_patch (:) ! turbulent deposition velocity 4(m/s)
- type(soil_erod_stream_type), private :: soil_erod_stream ! Zender soil erodibility stream data
- real(r8), pointer, private :: mbl_bsn_fct_col (:) ! [dimensionless] basin factor, or soil erodibility, time-constant
contains
- procedure , public :: Init
- procedure , private :: InitAllocate
- procedure , private :: InitHistory
- procedure , private :: InitCold
- procedure , private :: InitDustVars ! Initialize variables used in subroutine Dust
+ procedure , public :: InitBase ! Base object initiatlization (allows it to be extended)
+ procedure , public :: Init => InitBase ! Initialization name used by callers
+ procedure(DustEmission_interface) , public, deferred :: DustEmission ! Dust mobilization
+ procedure , public :: CheckDustEmisIsValid ! Check that the dust emission type is valid
+ procedure , public :: DustDryDep ! Turbulent dry deposition for dust
+ procedure , public :: WritePatchToLog ! Write information on the given patch to the log file
+ procedure , public :: GetPatchVars ! Get important variables on a given patch
+ procedure , public :: GetConstVars ! Get important constant variables
+ procedure , public :: CleanBase ! Base object deallocation (allows extension)
+ procedure , public :: Clean => CleanBase ! Deallocation used by callers
+ procedure , private :: InitAllocateBase
+ procedure , private :: InitHistoryBase
+ procedure , private :: InitDustVars ! Initialize variables used in DustEmission method
+
+ end type dust_emis_base_type
+ !------------------------------------------------------------------------
- end type dust_type
+ abstract interface
!------------------------------------------------------------------------
+ subroutine DustEmission_interface (this, bounds, &
+ num_nolakep, filter_nolakep, &
+ atm2lnd_inst, soilstate_inst, canopystate_inst, waterstatebulk_inst, waterdiagnosticbulk_inst, &
+ frictionvel_inst)
+ !
+ ! !DESCRIPTION:
+ ! Dust mobilization. This code simulates dust mobilization due to wind
+ ! from the surface into the lowest atmospheric layer
+ ! On output flx_mss_vrt_dst(ndst) is the surface dust emission
+ ! (kg/m**2/s) [ + = to atm]
+ !
+ ! !USES
+ use decompMod , only : bounds_type
+ use atm2lndType , only : atm2lnd_type
+ use SoilStateType , only : soilstate_type
+ use CanopyStateType , only : canopystate_type
+ use WaterStateBulkType , only : waterstatebulk_type
+ use WaterDiagnosticBulkType, only : waterdiagnosticbulk_type
+ use FrictionVelocityMod , only : frictionvel_type
+
+ import :: dust_emis_base_type
+ !
+ ! !ARGUMENTS:
+ class (dust_emis_base_type) :: this
+ type(bounds_type) , intent(in) :: bounds
+ integer , intent(in) :: num_nolakep ! number of column non-lake points in patch filter
+ integer , intent(in) :: filter_nolakep(num_nolakep) ! patch filter for non-lake points
+ type(atm2lnd_type) , intent(in) :: atm2lnd_inst
+ type(soilstate_type) , intent(in) :: soilstate_inst
+ type(canopystate_type) , intent(in) :: canopystate_inst
+ type(waterstatebulk_type) , intent(in) :: waterstatebulk_inst
+ type(waterdiagnosticbulk_type) , intent(in) :: waterdiagnosticbulk_inst
+ type(frictionvel_type) , intent(in) :: frictionvel_inst
+
+ end subroutine DustEmission_interface
+
+ end interface
+
character(len=*), parameter, private :: sourcefile = &
__FILE__
contains
!------------------------------------------------------------------------
- subroutine Init(this, bounds, NLFilename)
+ subroutine InitBase(this, bounds, NLFilename)
- class(dust_type) :: this
- type(bounds_type), intent(in) :: bounds
+ ! Base level initialization of this base object, this allows classes that extend
+ ! this base class to use this one and extend it with additional initialization
+ class(dust_emis_base_type) :: this
+ type(bounds_type), intent(in) :: bounds
character(len=*), intent(in) :: NLFilename
- call this%soil_erod_stream%Init( bounds, NLFilename )
- call this%InitAllocate (bounds)
- call this%InitHistory (bounds)
- call this%InitCold (bounds)
+ call this%InitAllocateBase (bounds)
+ call this%InitHistoryBase (bounds)
call this%InitDustVars (bounds)
- end subroutine Init
+ end subroutine InitBase
!------------------------------------------------------------------------
- subroutine InitAllocate(this, bounds)
+ subroutine CleanBase(this)
+ !
+ ! Base level deallocation of this base object, this allows classes that extend
+ ! this base class to use this one and extend it with additional deallocation.
+ ! !ARGUMENTS:
+ class (dust_emis_base_type) :: this
+ !
+ ! !LOCAL VARIABLES:
+ !------------------------------------------------------------------------
+
+ deallocate(this%flx_mss_vrt_dst_patch)
+ deallocate(this%flx_mss_vrt_dst_tot_patch)
+ deallocate(this%vlc_trb_patch)
+ deallocate(this%vlc_trb_1_patch)
+ deallocate(this%vlc_trb_2_patch)
+ deallocate(this%vlc_trb_3_patch)
+ deallocate(this%vlc_trb_4_patch)
+
+ deallocate (this%ovr_src_snk_mss)
+ deallocate (this%dmt_vwr)
+ deallocate (this%stk_crc)
+
+ end subroutine CleanBase
+
+ !------------------------------------------------------------------------
+ subroutine InitAllocateBase(this, bounds)
!
! !ARGUMENTS:
- class (dust_type) :: this
- type(bounds_type), intent(in) :: bounds
+ class (dust_emis_base_type) :: this
+ type(bounds_type), intent(in) :: bounds
!
! !LOCAL VARIABLES:
integer :: begp,endp
@@ -114,23 +180,26 @@ subroutine InitAllocate(this, bounds)
allocate(this%flx_mss_vrt_dst_tot_patch (begp:endp)) ; this%flx_mss_vrt_dst_tot_patch (:) = nan
allocate(this%vlc_trb_patch (begp:endp,1:ndst)) ; this%vlc_trb_patch (:,:) = nan
allocate(this%vlc_trb_1_patch (begp:endp)) ; this%vlc_trb_1_patch (:) = nan
- allocate(this%vlc_trb_2_patch (begp:endp)) ; this%vlc_trb_2_patch (:) = nan
+ allocate(this%vlc_trb_2_patch (begp:endp)) ; this%vlc_trb_2_patch (:) = nan
allocate(this%vlc_trb_3_patch (begp:endp)) ; this%vlc_trb_3_patch (:) = nan
allocate(this%vlc_trb_4_patch (begp:endp)) ; this%vlc_trb_4_patch (:) = nan
- allocate(this%mbl_bsn_fct_col (begc:endc)) ; this%mbl_bsn_fct_col (:) = nan
- end subroutine InitAllocate
+ allocate (this%ovr_src_snk_mss(1:dst_src_nbr,1:ndst)) ; this%ovr_src_snk_mss (:,:) = nan
+ allocate (this%dmt_vwr(1:ndst)) ; this%dmt_vwr (:) = nan
+ allocate (this%stk_crc(1:ndst)) ; this%stk_crc (:) = nan
+
+ end subroutine InitAllocateBase
!------------------------------------------------------------------------
- subroutine InitHistory(this, bounds)
+ subroutine InitHistoryBase(this, bounds)
!
! !USES:
use histFileMod, only : hist_addfld1d
!
!
! !ARGUMENTS:
- class (dust_type) :: this
- type(bounds_type), intent(in) :: bounds
+ class (dust_emis_base_type) :: this
+ type(bounds_type), intent(in) :: bounds
!
! !LOCAL VARIABLES:
integer :: begp,endp
@@ -165,348 +234,122 @@ subroutine InitHistory(this, bounds)
avgflag='A', long_name='turbulent deposition velocity 4', &
ptr_patch=this%vlc_trb_4_patch, default='inactive')
- if (dust_emis_method == 'Zender_2003') then
- if ( this%soil_erod_stream%UseStreams() )then
- this%mbl_bsn_fct_col(begc:endc) = spval
- call hist_addfld1d (fname='LND_MBL', units='fraction', &
- avgflag='A', long_name='Soil erodibility factor', &
- ptr_col=this%mbl_bsn_fct_col, default='inactive')
- end if
- end if
-
- end subroutine InitHistory
+ end subroutine InitHistoryBase
!-----------------------------------------------------------------------
- subroutine InitCold(this, bounds)
- !
- ! !ARGUMENTS:
- class (dust_type) :: this
- type(bounds_type), intent(in) :: bounds
- !
- ! !LOCAL VARIABLES:
- integer :: c,l
- !-----------------------------------------------------------------------
-
- ! Set basin factor to 1 for now
-
- if (dust_emis_method == 'Leung_2023') then
- !do c = bounds%begc, bounds%endc
- ! l = col%landunit(c)
-
- ! if (.not.lun%lakpoi(l)) then
- ! this%mbl_bsn_fct_col(c) = 1.0_r8
- ! end if
- !end do
- call endrun( msg="Leung_2023 dust_emis_method is currently not available"//errMsg(sourcefile, __LINE__))
- else if (dust_emis_method == 'Zender_2003') then
- if ( this%soil_erod_stream%UseStreams() )then
- call this%soil_erod_stream%CalcDustSource( bounds, &
- this%mbl_bsn_fct_col(bounds%begc:bounds%endc) )
- else
- this%mbl_bsn_fct_col(:) = 1.0_r8
- end if
- else
- write(iulog,*) 'dust_emis_method not recognized = ', trim(dust_emis_method)
- call endrun( msg="dust_emis_method namelist item is not valid "//errMsg(sourcefile, __LINE__))
- end if
-
- end subroutine InitCold
- !------------------------------------------------------------------------
- subroutine DustEmission (bounds, &
- num_nolakep, filter_nolakep, &
- atm2lnd_inst, soilstate_inst, canopystate_inst, waterstatebulk_inst, waterdiagnosticbulk_inst, &
- frictionvel_inst, dust_inst)
- !
- ! !DESCRIPTION:
- ! Dust mobilization. This code simulates dust mobilization due to wind
- ! from the surface into the lowest atmospheric layer
- ! On output flx_mss_vrt_dst(ndst) is the surface dust emission
- ! (kg/m**2/s) [ + = to atm]
- ! Source: C. Zender's dust model
- !
- ! !USES
- use shr_const_mod, only : SHR_CONST_RHOFW
- use subgridaveMod, only : p2g
+ subroutine WritePatchToLog(this, p)
!
+ ! !DESCRIPTION:
+ ! Write out information on dust emisisons for this patch to the log file
! !ARGUMENTS:
- type(bounds_type) , intent(in) :: bounds
- integer , intent(in) :: num_nolakep ! number of column non-lake points in patch filter
- integer , intent(in) :: filter_nolakep(num_nolakep) ! patch filter for non-lake points
- type(atm2lnd_type) , intent(in) :: atm2lnd_inst
- type(soilstate_type) , intent(in) :: soilstate_inst
- type(canopystate_type) , intent(in) :: canopystate_inst
- type(waterstatebulk_type) , intent(in) :: waterstatebulk_inst
- type(waterdiagnosticbulk_type) , intent(in) :: waterdiagnosticbulk_inst
- type(frictionvel_type) , intent(in) :: frictionvel_inst
- type(dust_type) , intent(inout) :: dust_inst
-
- !
- ! !LOCAL VARIABLES
- integer :: fp,p,c,l,g,m,n ! indices
- real(r8) :: liqfrac ! fraction of total water that is liquid
- real(r8) :: wnd_frc_rat ! [frc] Wind friction threshold over wind friction
- real(r8) :: wnd_frc_slt_dlt ! [m s-1] Friction velocity increase from saltatn
- real(r8) :: wnd_rfr_dlt ! [m s-1] Reference windspeed excess over threshld
- real(r8) :: dst_slt_flx_rat_ttl
- real(r8) :: flx_mss_hrz_slt_ttl
- real(r8) :: flx_mss_vrt_dst_ttl(bounds%begp:bounds%endp)
- real(r8) :: frc_thr_wet_fct
- real(r8) :: frc_thr_rgh_fct
- real(r8) :: wnd_frc_thr_slt
- real(r8) :: wnd_rfr_thr_slt
- real(r8) :: wnd_frc_slt
- real(r8) :: lnd_frc_mbl(bounds%begp:bounds%endp)
- real(r8) :: bd
- real(r8) :: gwc_sfc
- real(r8) :: ttlai(bounds%begp:bounds%endp)
- real(r8) :: tlai_lu(bounds%begl:bounds%endl)
- real(r8) :: sumwt(bounds%begl:bounds%endl) ! sum of weights
- logical :: found ! temporary for error check
- integer :: index
- !
- ! constants
- !
- real(r8), parameter :: cst_slt = 2.61_r8 ! [frc] Saltation constant
- real(r8), parameter :: flx_mss_fdg_fct = 5.0e-4_r8 ! [frc] Empir. mass flx tuning eflx_lh_vegt
- real(r8), parameter :: vai_mbl_thr = 0.3_r8 ! [m2 m-2] VAI threshold quenching dust mobilization
- character(len=*),parameter :: subname = 'DUSTEmission'
- !------------------------------------------------------------------------
-
- associate( &
- forc_rho => atm2lnd_inst%forc_rho_downscaled_col , & ! Input: [real(r8) (:) ] downscaled density (kg/m**3)
-
- gwc_thr => soilstate_inst%gwc_thr_col , & ! Input: [real(r8) (:) ] threshold gravimetric soil moisture based on clay content
- mss_frc_cly_vld => soilstate_inst%mss_frc_cly_vld_col , & ! Input: [real(r8) (:) ] [frc] Mass fraction clay limited to 0.20
- watsat => soilstate_inst%watsat_col , & ! Input: [real(r8) (:,:) ] saturated volumetric soil water
-
- tlai => canopystate_inst%tlai_patch , & ! Input: [real(r8) (:) ] one-sided leaf area index, no burying by snow
- tsai => canopystate_inst%tsai_patch , & ! Input: [real(r8) (:) ] one-sided stem area index, no burying by snow
-
- frac_sno => waterdiagnosticbulk_inst%frac_sno_col , & ! Input: [real(r8) (:) ] fraction of ground covered by snow (0 to 1)
- h2osoi_vol => waterstatebulk_inst%h2osoi_vol_col , & ! Input: [real(r8) (:,:) ] volumetric soil water (0<=h2osoi_vol<=watsat)
- h2osoi_liq => waterstatebulk_inst%h2osoi_liq_col , & ! Input: [real(r8) (:,:) ] liquid soil water (kg/m2)
- h2osoi_ice => waterstatebulk_inst%h2osoi_ice_col , & ! Input: [real(r8) (:,:) ] frozen soil water (kg/m2)
-
- fv => frictionvel_inst%fv_patch , & ! Input: [real(r8) (:) ] friction velocity (m/s) (for dust model)
- u10 => frictionvel_inst%u10_patch , & ! Input: [real(r8) (:) ] 10-m wind (m/s) (created for dust model)
-
- mbl_bsn_fct => dust_inst%mbl_bsn_fct_col , & ! Input: [real(r8) (:) ] basin factor
- flx_mss_vrt_dst => dust_inst%flx_mss_vrt_dst_patch , & ! Output: [real(r8) (:,:) ] surface dust emission (kg/m**2/s)
- flx_mss_vrt_dst_tot => dust_inst%flx_mss_vrt_dst_tot_patch & ! Output: [real(r8) (:) ] total dust flux back to atmosphere (pft)
- )
-
- ttlai(bounds%begp : bounds%endp) = 0._r8
- ! make lai average at landunit level
- do fp = 1,num_nolakep
- p = filter_nolakep(fp)
- ttlai(p) = tlai(p)+tsai(p)
- enddo
-
- tlai_lu(bounds%begl : bounds%endl) = spval
- sumwt(bounds%begl : bounds%endl) = 0._r8
- do p = bounds%begp,bounds%endp
- if (ttlai(p) /= spval .and. patch%active(p) .and. patch%wtlunit(p) /= 0._r8) then
- c = patch%column(p)
- l = patch%landunit(p)
- if (sumwt(l) == 0._r8) tlai_lu(l) = 0._r8
- tlai_lu(l) = tlai_lu(l) + ttlai(p) * patch%wtlunit(p)
- sumwt(l) = sumwt(l) + patch%wtlunit(p)
- end if
- end do
- found = .false.
- do l = bounds%begl,bounds%endl
- if (sumwt(l) > 1.0_r8 + 1.e-6_r8) then
- found = .true.
- index = l
- exit
- else if (sumwt(l) /= 0._r8) then
- tlai_lu(l) = tlai_lu(l)/sumwt(l)
- end if
- end do
- if (found) then
- write(iulog,*) subname//':: error: sumwt is greater than 1.0 at l= ',index
- call endrun(subgrid_index=index, subgrid_level=subgrid_level_landunit, msg=errMsg(sourcefile, __LINE__))
- end if
-
- ! Loop through patches
-
- ! initialize variables which get passed to the atmosphere
- flx_mss_vrt_dst(bounds%begp:bounds%endp,:)=0._r8
-
- do fp = 1,num_nolakep
- p = filter_nolakep(fp)
- c = patch%column(p)
- l = patch%landunit(p)
-
- ! the following code from subr. lnd_frc_mbl_get was adapted for lsm use
- ! purpose: return fraction of each gridcell suitable for dust mobilization
-
- ! the "bare ground" fraction of the current sub-gridscale cell decreases
- ! linearly from 1 to 0 as VAI(=tlai+tsai) increases from 0 to vai_mbl_thr
- ! if ice sheet, wetland, or lake, no dust allowed
-
- if (lun%itype(l) == istsoil .or. lun%itype(l) == istcrop) then
- if (tlai_lu(l) < vai_mbl_thr) then
- lnd_frc_mbl(p) = 1.0_r8 - (tlai_lu(l))/vai_mbl_thr
- else
- lnd_frc_mbl(p) = 0.0_r8
- endif
- lnd_frc_mbl(p) = lnd_frc_mbl(p) * (1.0_r8 - frac_sno(c))
- else
- lnd_frc_mbl(p) = 0.0_r8
- end if
- end do
-
- do fp = 1,num_nolakep
- p = filter_nolakep(fp)
- if (lnd_frc_mbl(p)>1.0_r8 .or. lnd_frc_mbl(p)<0.0_r8) then
- write(iulog,*)'Error dstmbl: pft= ',p,' lnd_frc_mbl(p)= ',lnd_frc_mbl(p)
- call endrun(subgrid_index=p, subgrid_level=subgrid_level_patch, msg=errMsg(sourcefile, __LINE__))
- end if
- end do
+ class(dust_emis_base_type), intent(in) :: this
+ integer , intent(in) :: p ! Patch to display
- ! reset history output variables before next if-statement to avoid output = inf
+ write(iulog,*) 'flx_mss_vrt_dst_tot', this%flx_mss_vrt_dst_tot_patch(p)
+ write(iulog,*) 'vlc_trb_1', this%vlc_trb_1_patch(p)
+ write(iulog,*) 'vlc_trb_2', this%vlc_trb_2_patch(p)
+ write(iulog,*) 'vlc_trb_3', this%vlc_trb_3_patch(p)
+ write(iulog,*) 'vlc_trb_4', this%vlc_trb_4_patch(p)
+ end subroutine WritePatchToLog
- do fp = 1,num_nolakep
- p = filter_nolakep(fp)
- flx_mss_vrt_dst_tot(p) = 0.0_r8
- end do
- do n = 1, ndst
- do fp = 1,num_nolakep
- p = filter_nolakep(fp)
- flx_mss_vrt_dst(p,n) = 0.0_r8
- end do
- end do
-
- do fp = 1,num_nolakep
- p = filter_nolakep(fp)
- c = patch%column(p)
- l = patch%landunit(p)
- g = patch%gridcell(p)
-
- ! only perform the following calculations if lnd_frc_mbl is non-zero
-
- if (lnd_frc_mbl(p) > 0.0_r8) then
-
- ! the following comes from subr. frc_thr_rgh_fct_get
- ! purpose: compute factor by which surface roughness increases threshold
- ! friction velocity (currently a constant)
-
- frc_thr_rgh_fct = 1.0_r8
-
- ! the following comes from subr. frc_thr_wet_fct_get
- ! purpose: compute factor by which soil moisture increases threshold friction velocity
- ! adjust threshold velocity for inhibition by moisture
- ! modified 4/5/2002 (slevis) to use gravimetric instead of volumetric
- ! water content
-
- bd = (1._r8-watsat(c,1))*2.7e3_r8 ![kg m-3] Bulk density of dry surface soil
- gwc_sfc = h2osoi_vol(c,1)*SHR_CONST_RHOFW/bd ![kg kg-1] Gravimetric H2O cont
- if (gwc_sfc > gwc_thr(c)) then
- frc_thr_wet_fct = sqrt(1.0_r8 + 1.21_r8 * (100.0_r8*(gwc_sfc - gwc_thr(c)))**0.68_r8)
- else
- frc_thr_wet_fct = 1.0_r8
- end if
-
- ! slevis: adding liqfrac here, because related to effects from soil water
-
- liqfrac = max( 0.0_r8, min( 1.0_r8, h2osoi_liq(c,1) / (h2osoi_ice(c,1)+h2osoi_liq(c,1)+1.0e-6_r8) ) )
-
- ! the following lines come from subr. dst_mbl
- ! purpose: adjust threshold friction velocity to acct for moisture and
- ! roughness. The ratio tmp1 / sqrt(forc_rho) comes from
- ! subr. wnd_frc_thr_slt_get which computes dry threshold
- ! friction velocity for saltation
-
- wnd_frc_thr_slt = tmp1 / sqrt(forc_rho(c)) * frc_thr_wet_fct * frc_thr_rgh_fct
-
- ! reset these variables which will be updated in the following if-block
-
- wnd_frc_slt = fv(p)
- flx_mss_hrz_slt_ttl = 0.0_r8
- flx_mss_vrt_dst_ttl(p) = 0.0_r8
-
- ! the following line comes from subr. dst_mbl
- ! purpose: threshold saltation wind speed
-
- wnd_rfr_thr_slt = u10(p) * wnd_frc_thr_slt / fv(p)
-
- ! the following if-block comes from subr. wnd_frc_slt_get
- ! purpose: compute the saltating friction velocity
- ! theory: saltation roughens the boundary layer, AKA "Owen's effect"
-
- if (u10(p) >= wnd_rfr_thr_slt) then
- wnd_rfr_dlt = u10(p) - wnd_rfr_thr_slt
- wnd_frc_slt_dlt = 0.003_r8 * wnd_rfr_dlt * wnd_rfr_dlt
- wnd_frc_slt = fv(p) + wnd_frc_slt_dlt
- end if
-
- ! the following comes from subr. flx_mss_hrz_slt_ttl_Whi79_get
- ! purpose: compute vertically integrated streamwise mass flux of particles
-
- if (wnd_frc_slt > wnd_frc_thr_slt) then
- wnd_frc_rat = wnd_frc_thr_slt / wnd_frc_slt
- flx_mss_hrz_slt_ttl = cst_slt * forc_rho(c) * (wnd_frc_slt**3.0_r8) * &
- (1.0_r8 - wnd_frc_rat) * (1.0_r8 + wnd_frc_rat) * (1.0_r8 + wnd_frc_rat) / grav
-
- ! the following loop originates from subr. dst_mbl
- ! purpose: apply land sfc and veg limitations and global tuning factor
- ! slevis: multiply flx_mss_hrz_slt_ttl by liqfrac to incude the effect
- ! of frozen soil
-
- flx_mss_hrz_slt_ttl = flx_mss_hrz_slt_ttl * lnd_frc_mbl(p) * mbl_bsn_fct(c) * &
- flx_mss_fdg_fct * liqfrac
- end if
-
- ! the following comes from subr. flx_mss_vrt_dst_ttl_MaB95_get
- ! purpose: diagnose total vertical mass flux of dust from vertically
- ! integrated streamwise mass flux
-
- dst_slt_flx_rat_ttl = 100.0_r8 * exp( log(10.0_r8) * (13.4_r8 * mss_frc_cly_vld(c) - 6.0_r8) )
- flx_mss_vrt_dst_ttl(p) = flx_mss_hrz_slt_ttl * dst_slt_flx_rat_ttl
+ !-----------------------------------------------------------------------
- end if ! lnd_frc_mbl > 0.0
+ subroutine GetPatchVars(this, p, flx_mss_vrt_dst, flx_mss_vrt_dst_tot, vlc_trb, vlc_trb_1, &
+ vlc_trb_2, vlc_trb_3, vlc_trb_4)
+ !
+ ! !DESCRIPTION:
+ ! Get important variables on the given patch
+ ! !ARGUMENTS:
+ class(dust_emis_base_type) , intent(in) :: this
+ integer , intent(in) :: p ! Patch to get
+ real(r8), optional, intent(out) :: flx_mss_vrt_dst(ndst)
+ real(r8), optional, intent(out) :: flx_mss_vrt_dst_tot
+ real(r8), optional, intent(out) :: vlc_trb(ndst)
+ real(r8), optional, intent(out) :: vlc_trb_1
+ real(r8), optional, intent(out) :: vlc_trb_2
+ real(r8), optional, intent(out) :: vlc_trb_3
+ real(r8), optional, intent(out) :: vlc_trb_4
+
+ if ( present(flx_mss_vrt_dst ) ) flx_mss_vrt_dst = this%flx_mss_vrt_dst_patch(p,:)
+ if ( present(flx_mss_vrt_dst_tot) ) flx_mss_vrt_dst_tot = this%flx_mss_vrt_dst_tot_patch(p)
+ if ( present(vlc_trb ) ) vlc_trb = this%vlc_trb_patch(p,:)
+ if ( present(vlc_trb_1) ) vlc_trb_1 = this%vlc_trb_1_patch(p)
+ if ( present(vlc_trb_2) ) vlc_trb_2 = this%vlc_trb_2_patch(p)
+ if ( present(vlc_trb_3) ) vlc_trb_3 = this%vlc_trb_3_patch(p)
+ if ( present(vlc_trb_4) ) vlc_trb_4 = this%vlc_trb_4_patch(p)
+ end subroutine GetPatchVars
- end do
-
- ! the following comes from subr. flx_mss_vrt_dst_prt in C. Zender's code
- ! purpose: partition total vertical mass flux of dust into transport bins
+ !------------------------------------------------------------------------
+ subroutine CheckDustEmisIsValid( this, p )
+ ! Check that dust emission state for this patch is valid
+ ! This means ensuring that total dust is the sum of all the dust bins
+ ! And that dry deposition for each dust bins agrees with the array of all
+ class(dust_emis_base_type) :: this
+ integer , intent(in) :: p ! Patch to display
+ integer :: i
+
+ if ( abs(sum(this%flx_mss_vrt_dst_patch(p,:)) - this%flx_mss_vrt_dst_tot_patch(p)) > 0.0_r8 )then
+ write(iulog,*) 'sum(flx_mss_vrt_dst(:)) /=flx_mss_vrt_dst_tot for p = ', p, &
+ errMsg(sourcefile, __LINE__)
+ call endrun(msg="Sum over dust bins does NOT equal total dust")
+ return
+ end if
+ i = 1
+ if ( this%vlc_trb_patch(p,i) /= this%vlc_trb_1_patch(p) )then
+ write(iulog,*) 'vlc_trb(i)) /= glc_trb for p = ', p, 'dust bin = ', i, &
+ errMsg(sourcefile, __LINE__)
+ call endrun(msg="Dry deposition for dust bin not equal to the array bin for it")
+ return
+ end if
+ i = 2
+ if ( this%vlc_trb_patch(p,i) /= this%vlc_trb_2_patch(p) )then
+ write(iulog,*) 'vlc_trb(i) /= glc_trb for p = ', p, 'dust bin = ', i, &
+ errMsg(sourcefile, __LINE__)
+ call endrun(msg="Dry deposition for dust bin not equal to the array bin for it")
+ return
+ end if
+ i = 3
+ if ( this%vlc_trb_patch(p,i) /= this%vlc_trb_3_patch(p) )then
+ write(iulog,*) 'vlc_trb(i)) /= glc_trb for p = ', p, 'dust bin = ', i, &
+ errMsg(sourcefile, __LINE__)
+ call endrun(msg="Dry deposition for dust bin not equal to the array bin for it")
+ return
+ end if
+ i = 4
+ if ( this%vlc_trb_patch(p,i) /= this%vlc_trb_4_patch(p) )then
+ write(iulog,*) 'vlc_trb(i)) /= glc_trb for p = ', p, 'dust bin = ', i, &
+ errMsg(sourcefile, __LINE__)
+ call endrun(msg="Dry deposition for dust bin not equal to the array bin for it")
+ return
+ end if
+
+ end subroutine CheckDustEmisIsValid
- do n = 1, ndst
- do m = 1, dst_src_nbr
- do fp = 1,num_nolakep
- p = filter_nolakep(fp)
- if (lnd_frc_mbl(p) > 0.0_r8) then
- flx_mss_vrt_dst(p,n) = flx_mss_vrt_dst(p,n) + ovr_src_snk_mss(m,n) * flx_mss_vrt_dst_ttl(p)
- end if
- end do
- end do
- end do
+ !-----------------------------------------------------------------------
- do n = 1, ndst
- do fp = 1,num_nolakep
- p = filter_nolakep(fp)
- if (lnd_frc_mbl(p) > 0.0_r8) then
- flx_mss_vrt_dst_tot(p) = flx_mss_vrt_dst_tot(p) + flx_mss_vrt_dst(p,n)
- end if
- end do
- end do
+ subroutine GetConstVars(this, SaltationFactor )
+ !
+ ! !DESCRIPTION:
+ ! Get important constant variables
+ ! !ARGUMENTS:
+ class(dust_emis_base_type) , intent(in) :: this
+ real(r8) , intent(out) :: SaltationFactor
- end associate
+ SaltationFactor = this%saltation_factor
+ end subroutine GetConstVars
- end subroutine DustEmission
+ !------------------------------------------------------------------------
- !------------------------------------------------------------------------
- subroutine DustDryDep (bounds, &
- atm2lnd_inst, frictionvel_inst, dust_inst)
+ subroutine DustDryDep (this, bounds, &
+ atm2lnd_inst, frictionvel_inst)
!
- ! !DESCRIPTION:
+ ! !DESCRIPTION:
!
- ! Determine Turbulent dry deposition for dust. Calculate the turbulent
- ! component of dust dry deposition, (the turbulent deposition velocity
- ! through the lowest atmospheric layer. CAM will calculate the settling
- ! velocity through the whole atmospheric column. The two calculations
+ ! Determine Turbulent dry deposition for dust. Calculate the turbulent
+ ! component of dust dry deposition, (the turbulent deposition velocity
+ ! through the lowest atmospheric layer. CAM will calculate the settling
+ ! velocity through the whole atmospheric column. The two calculations
! will determine the dust dry deposition flux to the surface.
! Note: Same process should occur over oceans. For the coupled CESM,
! we may find it more efficient to let CAM calculate the turbulent dep
@@ -520,10 +363,10 @@ subroutine DustDryDep (bounds, &
use shr_const_mod, only : SHR_CONST_PI, SHR_CONST_RDAIR, SHR_CONST_BOLTZ
!
! !ARGUMENTS:
- type(bounds_type) , intent(in) :: bounds
+ class (dust_emis_base_type) :: this
+ type(bounds_type) , intent(in) :: bounds
type(atm2lnd_type) , intent(in) :: atm2lnd_inst
type(frictionvel_type) , intent(in) :: frictionvel_inst
- type(dust_type) , intent(inout) :: dust_inst
!
! !LOCAL VARIABLES
integer :: p,c,g,m,n ! indices
@@ -538,23 +381,23 @@ subroutine DustDryDep (bounds, &
real(r8) :: slp_crc(bounds%begp:bounds%endp,ndst) ! [frc] Slip correction factor
real(r8) :: vlc_grv(bounds%begp:bounds%endp,ndst) ! [m s-1] Settling velocity
real(r8) :: rss_lmn(bounds%begp:bounds%endp,ndst) ! [s m-1] Quasi-laminar layer resistance
- real(r8) :: tmp ! temporary
+ real(r8) :: tmp ! temporary
real(r8), parameter::shm_nbr_xpn_lnd=-2._r8/3._r8 ![frc] shm_nbr_xpn over land
!------------------------------------------------------------------------
- associate( &
- forc_pbot => atm2lnd_inst%forc_pbot_downscaled_col , & ! Input: [real(r8) (:) ] atm pressure (Pa)
- forc_rho => atm2lnd_inst%forc_rho_downscaled_col , & ! Input: [real(r8) (:) ] atm density (kg/m**3)
- forc_t => atm2lnd_inst%forc_t_downscaled_col , & ! Input: [real(r8) (:) ] atm temperature (K)
-
- ram1 => frictionvel_inst%ram1_patch , & ! Input: [real(r8) (:) ] aerodynamical resistance (s/m)
- fv => frictionvel_inst%fv_patch , & ! Input: [real(r8) (:) ] friction velocity (m/s)
-
- vlc_trb => dust_inst%vlc_trb_patch , & ! Output: [real(r8) (:,:) ] Turbulent deposn velocity (m/s)
- vlc_trb_1 => dust_inst%vlc_trb_1_patch , & ! Output: [real(r8) (:) ] Turbulent deposition velocity 1
- vlc_trb_2 => dust_inst%vlc_trb_2_patch , & ! Output: [real(r8) (:) ] Turbulent deposition velocity 2
- vlc_trb_3 => dust_inst%vlc_trb_3_patch , & ! Output: [real(r8) (:) ] Turbulent deposition velocity 3
- vlc_trb_4 => dust_inst%vlc_trb_4_patch & ! Output: [real(r8) (:) ] Turbulent deposition velocity 4
+ associate( &
+ forc_pbot => atm2lnd_inst%forc_pbot_downscaled_col , & ! Input: [real(r8) (:) ] atm pressure (Pa)
+ forc_rho => atm2lnd_inst%forc_rho_downscaled_col , & ! Input: [real(r8) (:) ] atm density (kg/m**3)
+ forc_t => atm2lnd_inst%forc_t_downscaled_col , & ! Input: [real(r8) (:) ] atm temperature (K)
+
+ ram1 => frictionvel_inst%ram1_patch , & ! Input: [real(r8) (:) ] aerodynamical resistance (s/m)
+ fv => frictionvel_inst%fv_patch , & ! Input: [real(r8) (:) ] friction velocity (m/s)
+
+ vlc_trb => this%vlc_trb_patch , & ! Output: [real(r8) (:,:) ] Turbulent deposn velocity (m/s)
+ vlc_trb_1 => this%vlc_trb_1_patch , & ! Output: [real(r8) (:) ] Turbulent deposition velocity 1
+ vlc_trb_2 => this%vlc_trb_2_patch , & ! Output: [real(r8) (:) ] Turbulent deposition velocity 2
+ vlc_trb_3 => this%vlc_trb_3_patch , & ! Output: [real(r8) (:) ] Turbulent deposition velocity 3
+ vlc_trb_4 => this%vlc_trb_4_patch & ! Output: [real(r8) (:) ] Turbulent deposition velocity 4
)
do p = bounds%begp,bounds%endp
@@ -577,11 +420,11 @@ subroutine DustDryDep (bounds, &
do m = 1, ndst
slp_crc(p,m) = 1.0_r8 + 2.0_r8 * mfp_atm * &
- (1.257_r8+0.4_r8*exp(-1.1_r8*dmt_vwr(m)/(2.0_r8*mfp_atm))) / &
- dmt_vwr(m) ![frc] Slip correction factor SeP97 p. 464
- vlc_grv(p,m) = (1.0_r8/18.0_r8) * dmt_vwr(m) * dmt_vwr(m) * dns_aer * &
+ (1.257_r8+0.4_r8*exp(-1.1_r8*this%dmt_vwr(m)/(2.0_r8*mfp_atm))) / &
+ this%dmt_vwr(m) ![frc] Slip correction factor SeP97 p. 464
+ vlc_grv(p,m) = (1.0_r8/18.0_r8) * this%dmt_vwr(m) * this%dmt_vwr(m) * dns_aer * &
grav * slp_crc(p,m) / vsc_dyn_atm(p) ![m s-1] Stokes' settling velocity SeP97 p. 466
- vlc_grv(p,m) = vlc_grv(p,m) * stk_crc(m) ![m s-1] Correction to Stokes settling velocity
+ vlc_grv(p,m) = vlc_grv(p,m) * this%stk_crc(m) ![m s-1] Correction to Stokes settling velocity
end do
end if
end do
@@ -594,7 +437,7 @@ subroutine DustDryDep (bounds, &
stk_nbr = vlc_grv(p,m) * fv(p) * fv(p) / (grav * vsc_knm_atm(p)) ![frc] SeP97 p.965
dff_aer = SHR_CONST_BOLTZ * forc_t(c) * slp_crc(p,m) / & ![m2 s-1]
- (3.0_r8*SHR_CONST_PI * vsc_dyn_atm(p) * dmt_vwr(m)) !SeP97 p.474
+ (3.0_r8*SHR_CONST_PI * vsc_dyn_atm(p) * this%dmt_vwr(m)) !SeP97 p.474
shm_nbr = vsc_knm_atm(p) / dff_aer ![frc] SeP97 p.972
shm_nbr_xpn = shm_nbr_xpn_lnd ![frc]
@@ -603,7 +446,7 @@ subroutine DustDryDep (bounds, &
! Schmidt number exponent is -2/3 over solid surfaces and
! -1/2 over liquid surfaces SlS80 p. 1014
! if (oro(i)==0.0) shm_nbr_xpn=shm_nbr_xpn_ocn else shm_nbr_xpn=shm_nbr_xpn_lnd
- ! [frc] Surface-dependent exponent for aerosol-diffusion dependence on Schmidt #
+ ! [frc] Surface-dependent exponent for aerosol-diffusion dependence on Schmidt #
tmp = shm_nbr**shm_nbr_xpn + 10.0_r8**(-3.0_r8/stk_nbr)
rss_lmn(p,m) = 1.0_r8 / (tmp * fv(p)) ![s m-1] SeP97 p.972,965
@@ -635,14 +478,15 @@ subroutine DustDryDep (bounds, &
end subroutine DustDryDep
- !------------------------------------------------------------------------
- subroutine InitDustVars(this, bounds)
+ !------------------------------------------------------------------------
+
+ subroutine InitDustVars(this, bounds)
!
- ! !DESCRIPTION:
+ ! !DESCRIPTION:
!
! Compute source efficiency factor from topography
! Initialize other variables used in subroutine Dust:
- ! ovr_src_snk_mss(m,n) and tmp1.
+ ! ovr_src_snk_mss(m,n) and saltation_factor.
! Define particle diameter and density needed by atm model
! as well as by dry dep model
! Source: Paul Ginoux (for source efficiency factor)
@@ -655,8 +499,8 @@ subroutine InitDustVars(this, bounds)
use decompMod , only : get_proc_bounds
!
! !ARGUMENTS:
- class(dust_type) :: this
- type(bounds_type), intent(in) :: bounds
+ class(dust_emis_base_type) :: this
+ type(bounds_type), intent(in) :: bounds
!
! !LOCAL VARIABLES
integer :: fc,c,l,m,n ! indices
@@ -678,7 +522,7 @@ subroutine InitDustVars(this, bounds)
real(r8) :: vlc_grv(ndst) ! [m s-1] Settling velocity
real(r8) :: ryn_nbr_grv(ndst) ! [frc] Reynolds number at terminal velocity
real(r8) :: cff_drg_grv(ndst) ! [frc] Drag coefficient at terminal velocity
- real(r8) :: tmp ! temporary
+ real(r8) :: tmp ! temporary
real(r8) :: ln_gsd ! [frc] ln(gsd)
real(r8) :: gsd_anl ! [frc] Geometric standard deviation
real(r8) :: dmt_vma ! [m] Mass median diameter analytic She84 p.75 Tabl.1
@@ -698,7 +542,7 @@ subroutine InitDustVars(this, bounds)
real(r8) :: sz_max(sz_nbr) ! [m] Size Bin maxima
real(r8) :: sz_ctr(sz_nbr) ! [m] Size Bin centers
real(r8) :: sz_dlt(sz_nbr) ! [m] Size Bin widths
-
+
! constants
real(r8), allocatable :: dmt_vma_src(:) ! [m] Mass median diameter BSM96 p. 73 Table 2
real(r8), allocatable :: gsd_anl_src(:) ! [frc] Geometric std deviation BSM96 p. 73 Table 2
@@ -710,19 +554,16 @@ subroutine InitDustVars(this, bounds)
real(r8), parameter :: dns_slt = 2650.0_r8 ! [kg m-3] Density of optimal saltation particles
!------------------------------------------------------------------------
- ! allocate module variable
- allocate (ovr_src_snk_mss(dst_src_nbr,ndst))
- allocate (dmt_vwr(ndst))
- allocate (stk_crc(ndst))
-
+ call shr_assert_all((lbound(this%ovr_src_snk_mss) == (/1,1/) ), file=sourcefile, line=__LINE__)
+ call shr_assert_all((ubound(this%ovr_src_snk_mss) == (/dst_src_nbr,ndst/) ), file=sourcefile, line=__LINE__)
! allocate local variable
- allocate (dmt_vma_src(dst_src_nbr))
- allocate (gsd_anl_src(dst_src_nbr))
- allocate (mss_frc_src(dst_src_nbr))
+ allocate (dmt_vma_src(dst_src_nbr))
+ allocate (gsd_anl_src(dst_src_nbr))
+ allocate (mss_frc_src(dst_src_nbr))
- dmt_vma_src(:) = (/ 0.832e-6_r8 , 4.82e-6_r8 , 19.38e-6_r8 /)
- gsd_anl_src(:) = (/ 2.10_r8 , 1.90_r8 , 1.60_r8 /)
- mss_frc_src(:) = (/ 0.036_r8 , 0.957_r8 , 0.007_r8 /)
+ dmt_vma_src(:) = (/ 0.832e-6_r8 , 4.82e-6_r8 , 19.38e-6_r8 /)
+ gsd_anl_src(:) = (/ 2.10_r8 , 1.90_r8 , 1.60_r8 /)
+ mss_frc_src(:) = (/ 0.036_r8 , 0.957_r8 , 0.007_r8 /)
! the following comes from (1) szdstlgn.F subroutine ovr_src_snk_frc_get
! and (2) dstszdst.F subroutine dst_szdst_ini
@@ -738,12 +579,12 @@ subroutine InitDustVars(this, bounds)
lndminjovrdmdni = log(dmt_grd(n )/dmt_vma_src(m))
ovr_src_snk_frc = 0.5_r8 * (erf(lndmaxjovrdmdni/sqrt2lngsdi) - &
erf(lndminjovrdmdni/sqrt2lngsdi))
- ovr_src_snk_mss(m,n) = ovr_src_snk_frc * mss_frc_src(m)
+ this%ovr_src_snk_mss(m,n) = ovr_src_snk_frc * mss_frc_src(m)
end do
end do
- ! The following code from subroutine wnd_frc_thr_slt_get was placed
- ! here because tmp1 needs to be defined just once
+ ! The following code from subroutine wnd_frc_thr_slt_get was placed
+ ! here because saltation_factor needs to be defined just once
ryn_nbr_frc_thr_prx_opt = 0.38_r8 + 1331.0_r8 * (100.0_r8*dmt_slt_opt)**1.56_r8
@@ -760,7 +601,7 @@ subroutine InitDustVars(this, bounds)
icf_fct = 1.0_r8 + 6.0e-07_r8 / (dns_slt * grav * (dmt_slt_opt**2.5_r8))
dns_fct = dns_slt * grav * dmt_slt_opt
- tmp1 = sqrt(icf_fct * dns_fct * ryn_nbr_frc_thr_opt_fnc)
+ this%saltation_factor = sqrt(icf_fct * dns_fct * ryn_nbr_frc_thr_opt_fnc)
! Introducing particle diameter. Needed by atm model and by dry dep model.
! Taken from Charlie Zender's subroutines dst_psd_ini, dst_sz_rsl,
@@ -794,7 +635,6 @@ subroutine InitDustVars(this, bounds)
gsd_anl = 2.0_r8 ! [frc] Geometric std dev PaG77 p. 2080 Table1
ln_gsd = log(gsd_anl)
- dns_aer = 2.5e+3_r8 ! [kg m-3] Aerosol density
! Set a fundamental statistic for each bin
@@ -829,7 +669,7 @@ subroutine InitDustVars(this, bounds)
end do
lngsdsqrttwopi_rcp = 1.0_r8 / (ln_gsd*sqrt(2.0_r8*SHR_CONST_PI))
- dmt_vwr(n) = 0.0_r8 ! [m] Mass wgted diameter resolved
+ this%dmt_vwr(n) = 0.0_r8 ! [m] Mass wgted diameter resolved
vlm_rsl(n) = 0.0_r8 ! [m3 m-3] Volume concentration resolved
do m = 1, sz_nbr
@@ -839,7 +679,7 @@ subroutine InitDustVars(this, bounds)
lgn_dst = lngsdsqrttwopi_rcp * exp(-0.5_r8*tmp*tmp) / sz_ctr(m)
! Integrate moments of size distribution
- dmt_vwr(n) = dmt_vwr(n) + sz_ctr(m) * &
+ this%dmt_vwr(n) = this%dmt_vwr(n) + sz_ctr(m) * &
SHR_CONST_PI / 6.0_r8 * (sz_ctr(m)**3.0_r8) * & ![m3] Volume
lgn_dst * sz_dlt(m) ![# m-3] Number concentrn
vlm_rsl(n) = vlm_rsl(n) + &
@@ -848,7 +688,7 @@ subroutine InitDustVars(this, bounds)
end do
- dmt_vwr(n) = dmt_vwr(n) / vlm_rsl(n) ![m] Mass weighted diameter resolved
+ this%dmt_vwr(n) = this%dmt_vwr(n) / vlm_rsl(n) ![m] Mass weighted diameter resolved
end do
@@ -867,9 +707,9 @@ subroutine InitDustVars(this, bounds)
do m = 1, ndst
slp_crc(m) = 1.0_r8 + 2.0_r8 * mfp_atm * &
- (1.257_r8+0.4_r8*exp(-1.1_r8*dmt_vwr(m)/(2.0_r8*mfp_atm))) / &
- dmt_vwr(m) ! [frc] Slip correction factor SeP97 p.464
- vlc_stk(m) = (1.0_r8/18.0_r8) * dmt_vwr(m) * dmt_vwr(m) * dns_aer * &
+ (1.257_r8+0.4_r8*exp(-1.1_r8*this%dmt_vwr(m)/(2.0_r8*mfp_atm))) / &
+ this%dmt_vwr(m) ! [frc] Slip correction factor SeP97 p.464
+ vlc_stk(m) = (1.0_r8/18.0_r8) * this%dmt_vwr(m) * this%dmt_vwr(m) * dns_aer * &
grav * slp_crc(m) / vsc_dyn_atm ! [m s-1] SeP97 p.466
end do
@@ -894,7 +734,7 @@ subroutine InitDustVars(this, bounds)
! Save terminal velocity for convergence test
vlc_grv_old = vlc_grv(m) ![m s-1]
- ryn_nbr_grv(m) = vlc_grv(m) * dmt_vwr(m) / vsc_knm_atm !SeP97 p.460
+ ryn_nbr_grv(m) = vlc_grv(m) * this%dmt_vwr(m) / vsc_knm_atm !SeP97 p.460
! Update drag coefficient based on new Reynolds number
if (ryn_nbr_grv(m) < 0.1_r8) then
@@ -918,8 +758,8 @@ subroutine InitDustVars(this, bounds)
! Update terminal velocity based on new Reynolds number and drag coeff
! [m s-1] Terminal veloc SeP97 p.467 (8.44)
- vlc_grv(m) = sqrt(4.0_r8 * grav * dmt_vwr(m) * slp_crc(m) * dns_aer / &
- (3.0_r8*cff_drg_grv(m)*dns_mdp))
+ vlc_grv(m) = sqrt(4.0_r8 * grav * this%dmt_vwr(m) * slp_crc(m) * dns_aer / &
+ (3.0_r8*cff_drg_grv(m)*dns_mdp))
eps_crr = abs((vlc_grv(m)-vlc_grv_old)/vlc_grv(m)) !Relative convergence
if (itr_idx == 12) then
! Numerical pingpong may occur when Re = 0.1, 2.0, or 500.0
@@ -942,9 +782,11 @@ subroutine InitDustVars(this, bounds)
! actual settling velocities
do m = 1, ndst
- stk_crc(m) = vlc_grv(m) / vlc_stk(m)
+ this%stk_crc(m) = vlc_grv(m) / vlc_stk(m)
end do
end subroutine InitDustVars
-end module DUSTMod
+ !------------------------------------------------------------------------
+
+end module DustEmisBase
diff --git a/src/biogeochem/DustEmisFactory.F90 b/src/biogeochem/DustEmisFactory.F90
new file mode 100644
index 0000000000..24162fde24
--- /dev/null
+++ b/src/biogeochem/DustEmisFactory.F90
@@ -0,0 +1,60 @@
+module DustEmisFactory
+ !---------------------------------------------------------------------------
+ !
+ ! Factory to figure out whihc dust emission method to instantiate
+ !
+ !---------------------------------------------------------------------------
+ use abortutils , only : endrun
+ use shr_log_mod , only : errMsg => shr_log_errMsg
+ use clm_varctl , only : iulog
+
+ implicit none
+ save
+ private
+ !
+ public :: create_dust_emissions ! create an object of class dust_emis_base
+
+ character(len=*), parameter, private :: sourcefile = &
+ __FILE__
+
+contains
+
+ !---------------------------------------------------------------------------
+
+ function create_dust_emissions(bounds, NLFilename) result(dust_emis)
+ !---------------------------------------------------------------------------
+ ! Create a dust_emission base class objecct
+ ! The method implemented depends on namelist input
+ !---------------------------------------------------------------------------
+ use DustEmisBase , only : dust_emis_base_type
+ use DustEmisZender2003, only : dust_emis_zender2003_type
+ use decompMod , only : bounds_type
+ use shr_kind_mod , only : CL => shr_kind_cl
+ use shr_dust_emis_mod , only : is_dust_emis_zender, is_dust_emis_leung
+ implicit none
+ ! Arguments
+ class(dust_emis_base_type), allocatable :: dust_emis
+ type(bounds_type), intent(in) :: bounds
+ character(len=*), intent(in) :: NLFilename
+ ! Local variables
+
+ if ( is_dust_emis_zender() )then
+ allocate(dust_emis, source=dust_emis_zender2003_type() )
+
+ ! This will be added when the Leung2023 comes in
+ !else if ( is_dust_emis_leung() )
+ ! allocate(dust_emis, source=dust_emis_zender2003_type() )
+ else
+ write(iulog,*) 'ERROR: unknown dust_emis_method: ', &
+ errMsg(sourcefile, __LINE__)
+ call endrun( "Unrecognized dust_emis_method" )
+
+ end if
+
+ call dust_emis%Init(bounds, NLFilename)
+
+ end function create_dust_emissions
+
+ !---------------------------------------------------------------------------
+
+end module DustEmisFactory
diff --git a/src/biogeochem/DustEmisZender2003.F90 b/src/biogeochem/DustEmisZender2003.F90
new file mode 100644
index 0000000000..cee704ad47
--- /dev/null
+++ b/src/biogeochem/DustEmisZender2003.F90
@@ -0,0 +1,470 @@
+module DustEmisZender2003
+
+ !-----------------------------------------------------------------------
+ ! !DESCRIPTION:
+ ! Routines in this module calculate Dust mobilization and dry deposition for dust.
+ ! Simulates dust mobilization due to wind from the surface into the
+ ! lowest atmospheric layer. On output flx_mss_vrt_dst(ndst) is the surface dust
+ ! emission (kg/m**2/s) [ + = to atm].
+ ! Calculates the turbulent component of dust dry deposition, (the turbulent deposition
+ ! velocity through the lowest atmospheric layer). CAM will calculate the settling
+ ! velocity through the whole atmospheric column. The two calculations will determine
+ ! the dust dry deposition flux to the surface.
+ !
+ ! !USES:
+ use shr_kind_mod , only : r8 => shr_kind_r8
+ use shr_log_mod , only : errMsg => shr_log_errMsg
+ use shr_infnan_mod , only : nan => shr_infnan_nan, assignment(=)
+ use clm_varpar , only : dst_src_nbr, ndst
+ use clm_varcon , only : grav, spval
+ use landunit_varcon , only : istcrop, istsoil
+ use clm_varctl , only : iulog
+ use abortutils , only : endrun
+ use decompMod , only : bounds_type, subgrid_level_landunit
+ use atm2lndType , only : atm2lnd_type
+ use SoilStateType , only : soilstate_type
+ use CanopyStateType , only : canopystate_type
+ use WaterStateBulkType , only : waterstatebulk_type
+ use WaterDiagnosticBulkType , only : waterdiagnosticbulk_type
+ use FrictionVelocityMod , only : frictionvel_type
+ use LandunitType , only : lun
+ use PatchType , only : patch
+ use ZenderSoilErodStreamType, only : soil_erod_stream_type
+ use DustEmisBase , only : dust_emis_base_type
+ !
+ ! !PUBLIC TYPES
+ implicit none
+ private
+ !
+ ! !PRIVATE DATA:
+ !
+ !
+ ! !PUBLIC DATA TYPES:
+ !
+ type, public, extends(dust_emis_base_type) :: dust_emis_zender2003_type
+
+ real(r8), pointer, private :: mbl_bsn_fct_col (:) ! [dimensionless] basin factor, or soil rodibility, time-constant
+ type(soil_erod_stream_type), private :: soil_erod_stream ! Zender soil erodibility stream data
+
+ contains
+
+ procedure , public :: Init => InitZender2003
+ procedure , public :: DustEmission ! Dust mobilization
+ procedure , public :: Clean => CleanZender2003
+ procedure , private :: InitAllocate ! Allocate data
+ procedure , private :: InitHistory ! History initialization
+ procedure , private :: InitCold
+
+ end type dust_emis_zender2003_type
+
+ interface dust_emis_zender2003_type
+ ! initialize a new dust emission object
+ module procedure constructor
+ end interface dust_emis_zender2003_type
+ !------------------------------------------------------------------------
+
+ character(len=*), parameter, private :: sourcefile = &
+ __FILE__
+
+contains
+
+ !-----------------------------------------------------------------------
+ type(dust_emis_zender2003_type) function constructor()
+ !
+ ! Creates a dust emission object for Zender-2003 type
+ ! For now this is just a placeholder
+ !-----------------------------------------------------------------------
+
+ end function constructor
+
+ !------------------------------------------------------------------------
+
+ subroutine InitZender2003(this, bounds, NLFilename)
+
+ ! Initialization for this extended class, calling base level initiation and adding to it
+ class(dust_emis_zender2003_type) :: this
+ type(bounds_type), intent(in) :: bounds
+ character(len=*), intent(in) :: NLFilename
+
+ call this%soil_erod_stream%Init( bounds, NLFilename )
+ call this%InitBase(bounds, NLFilename)
+ call this%InitAllocate (bounds)
+ call this%InitHistory (bounds)
+ call this%InitCold (bounds)
+
+ end subroutine InitZender2003
+
+ !------------------------------------------------------------------------
+
+ subroutine InitAllocate(this, bounds)
+ !
+ ! !ARGUMENTS:
+ class (dust_emis_zender2003_type) :: this
+ type(bounds_type), intent(in) :: bounds
+ !
+ ! !LOCAL VARIABLES:
+ integer :: begc,endc
+ !------------------------------------------------------------------------
+
+ begc = bounds%begc ; endc = bounds%endc
+
+ allocate(this%mbl_bsn_fct_col (begc:endc)) ; this%mbl_bsn_fct_col (:) = nan
+
+ end subroutine InitAllocate
+
+ !------------------------------------------------------------------------
+
+ subroutine CleanZender2003(this)
+ !
+ ! Deallocation for this extended class, calling base level deallocation and adding to it
+ ! !ARGUMENTS:
+ class (dust_emis_zender2003_type) :: this
+ !
+ ! !LOCAL VARIABLES:
+ !------------------------------------------------------------------------
+
+ call this%CleanBase()
+ deallocate(this%mbl_bsn_fct_col)
+
+ end subroutine CleanZender2003
+
+ !------------------------------------------------------------------------
+
+ subroutine InitHistory(this, bounds)
+ !
+ ! !USES:
+ use histFileMod, only : hist_addfld1d
+ !
+ !
+ ! !ARGUMENTS:
+ class (dust_emis_zender2003_type) :: this
+ type(bounds_type), intent(in) :: bounds
+ !
+ ! !LOCAL VARIABLES:
+ integer :: begc,endc
+ !------------------------------------------------------------------------
+
+ begc = bounds%begc; endc = bounds%endc
+
+ if ( this%soil_erod_stream%UseStreams() )then
+ this%mbl_bsn_fct_col(begc:endc) = spval
+ call hist_addfld1d (fname='LND_MBL', units='fraction', &
+ avgflag='A', long_name='Soil erodibility factor', &
+ ptr_col=this%mbl_bsn_fct_col, default='inactive')
+ end if
+
+ end subroutine InitHistory
+
+ !-----------------------------------------------------------------------
+
+ subroutine InitCold(this, bounds)
+ !
+ ! Initialize values from a cold start
+ ! !ARGUMENTS:
+ class (dust_emis_zender2003_type) :: this
+ type(bounds_type), intent(in) :: bounds
+ !
+ ! !LOCAL VARIABLES:
+ integer :: c,l
+ !-----------------------------------------------------------------------
+
+ if ( this%soil_erod_stream%UseStreams() )then
+ call this%soil_erod_stream%CalcDustSource( bounds, &
+ this%mbl_bsn_fct_col(bounds%begc:bounds%endc) )
+ else
+ this%mbl_bsn_fct_col(:) = 1.0_r8
+ end if
+
+ end subroutine InitCold
+
+ !------------------------------------------------------------------------
+
+ subroutine DustEmission (this, bounds, &
+ num_nolakep, filter_nolakep, &
+ atm2lnd_inst, soilstate_inst, canopystate_inst, waterstatebulk_inst, waterdiagnosticbulk_inst, &
+ frictionvel_inst)
+ !
+ ! !DESCRIPTION:
+ ! Dust mobilization. This code simulates dust mobilization due to wind
+ ! from the surface into the lowest atmospheric layer
+ ! On output flx_mss_vrt_dst(ndst) is the surface dust emission
+ ! (kg/m**2/s) [ + = to atm]
+ ! Source: C. Zender's dust model
+ !
+ ! !USES
+ use shr_const_mod, only : SHR_CONST_RHOFW
+ use subgridaveMod, only : p2g
+ !
+ ! !ARGUMENTS:
+ class (dust_emis_zender2003_type) :: this
+ type(bounds_type) , intent(in) :: bounds
+ integer , intent(in) :: num_nolakep ! number of column non-lake points in patch filter
+ integer , intent(in) :: filter_nolakep(num_nolakep) ! patch filter for non-lake points
+ type(atm2lnd_type) , intent(in) :: atm2lnd_inst
+ type(soilstate_type) , intent(in) :: soilstate_inst
+ type(canopystate_type) , intent(in) :: canopystate_inst
+ type(waterstatebulk_type) , intent(in) :: waterstatebulk_inst
+ type(waterdiagnosticbulk_type) , intent(in) :: waterdiagnosticbulk_inst
+ type(frictionvel_type) , intent(in) :: frictionvel_inst
+
+ !
+ ! !LOCAL VARIABLES
+ integer :: fp,p,c,l,g,m,n ! indices
+ real(r8) :: liqfrac ! fraction of total water that is liquid
+ real(r8) :: wnd_frc_rat ! [frc] Wind friction threshold over wind friction
+ real(r8) :: wnd_frc_slt_dlt ! [m s-1] Friction velocity increase from saltatn
+ real(r8) :: wnd_rfr_dlt ! [m s-1] Reference windspeed excess over threshld
+ real(r8) :: dst_slt_flx_rat_ttl
+ real(r8) :: flx_mss_hrz_slt_ttl
+ real(r8) :: flx_mss_vrt_dst_ttl(bounds%begp:bounds%endp)
+ real(r8) :: frc_thr_wet_fct
+ real(r8) :: frc_thr_rgh_fct
+ real(r8) :: wnd_frc_thr_slt
+ real(r8) :: wnd_rfr_thr_slt
+ real(r8) :: wnd_frc_slt
+ real(r8) :: lnd_frc_mbl(bounds%begp:bounds%endp)
+ real(r8) :: bd
+ real(r8) :: gwc_sfc
+ real(r8) :: ttlai(bounds%begp:bounds%endp)
+ real(r8) :: tlai_lu(bounds%begl:bounds%endl)
+ real(r8) :: sumwt(bounds%begl:bounds%endl) ! sum of weights
+ logical :: found ! temporary for error check
+ integer :: index
+ !
+ ! constants
+ !
+ real(r8), parameter :: cst_slt = 2.61_r8 ! [frc] Saltation constant
+ real(r8), parameter :: flx_mss_fdg_fct = 5.0e-4_r8 ! [frc] Empir. mass flx tuning eflx_lh_vegt
+ real(r8), parameter :: vai_mbl_thr = 0.3_r8 ! [m2 m-2] VAI threshold quenching dust mobilization
+ character(len=*),parameter :: subname = 'DUSTEmission'
+ !------------------------------------------------------------------------
+
+ associate( &
+ forc_rho => atm2lnd_inst%forc_rho_downscaled_col , & ! Input: [real(r8) (:) ] downscaled density (kg/m**3)
+
+ gwc_thr => soilstate_inst%gwc_thr_col , & ! Input: [real(r8) (:) ] threshold gravimetric soil moisture based on clay content
+ mss_frc_cly_vld => soilstate_inst%mss_frc_cly_vld_col , & ! Input: [real(r8) (:) ] [frc] Mass fraction clay limited to 0.20
+ watsat => soilstate_inst%watsat_col , & ! Input: [real(r8) (:,:) ] saturated volumetric soil water
+
+ tlai => canopystate_inst%tlai_patch , & ! Input: [real(r8) (:) ] one-sided leaf area index, no burying by snow
+ tsai => canopystate_inst%tsai_patch , & ! Input: [real(r8) (:) ] one-sided stem area index, no burying by snow
+
+ frac_sno => waterdiagnosticbulk_inst%frac_sno_col , & ! Input: [real(r8) (:) ] fraction of ground covered by snow (0 to 1)
+ h2osoi_vol => waterstatebulk_inst%h2osoi_vol_col , & ! Input: [real(r8) (:,:) ] volumetric soil water (0<=h2osoi_vol<=watsat)
+ h2osoi_liq => waterstatebulk_inst%h2osoi_liq_col , & ! Input: [real(r8) (:,:) ] liquid soil water (kg/m2)
+ h2osoi_ice => waterstatebulk_inst%h2osoi_ice_col , & ! Input: [real(r8) (:,:) ] frozen soil water (kg/m2)
+
+ fv => frictionvel_inst%fv_patch , & ! Input: [real(r8) (:) ] friction velocity (m/s) (for dust model)
+ u10 => frictionvel_inst%u10_patch , & ! Input: [real(r8) (:) ] 10-m wind (m/s) (created for dust model)
+
+ mbl_bsn_fct => this%mbl_bsn_fct_col , & ! Input: [real(r8) (:) ] basin factor
+ flx_mss_vrt_dst => this%flx_mss_vrt_dst_patch , & ! Output: [real(r8) (:,:) ] surface dust emission (kg/m**2/s)
+ flx_mss_vrt_dst_tot => this%flx_mss_vrt_dst_tot_patch & ! Output: [real(r8) (:) ] total dust flux back to atmosphere (pft)
+ )
+
+ ttlai(bounds%begp : bounds%endp) = 0._r8
+ ! make lai average at landunit level
+ do fp = 1,num_nolakep
+ p = filter_nolakep(fp)
+ ttlai(p) = tlai(p)+tsai(p)
+ enddo
+
+ tlai_lu(bounds%begl : bounds%endl) = spval
+ sumwt(bounds%begl : bounds%endl) = 0._r8
+ do p = bounds%begp,bounds%endp
+ if (ttlai(p) /= spval .and. patch%active(p) .and. patch%wtlunit(p) /= 0._r8) then
+ c = patch%column(p)
+ l = patch%landunit(p)
+ if (sumwt(l) == 0._r8) tlai_lu(l) = 0._r8
+ tlai_lu(l) = tlai_lu(l) + ttlai(p) * patch%wtlunit(p)
+ sumwt(l) = sumwt(l) + patch%wtlunit(p)
+ end if
+ end do
+ found = .false.
+ do l = bounds%begl,bounds%endl
+ if (sumwt(l) > 1.0_r8 + 1.e-6_r8) then
+ found = .true.
+ index = l
+ exit
+ else if (sumwt(l) /= 0._r8) then
+ tlai_lu(l) = tlai_lu(l)/sumwt(l)
+ end if
+ end do
+ if (found) then
+ write(iulog,*) subname//':: error: sumwt is greater than 1.0 at l= ',index
+ call endrun(subgrid_index=index, subgrid_level=subgrid_level_landunit, msg=errMsg(sourcefile, __LINE__))
+ end if
+
+ ! Loop through patches
+
+ ! initialize variables which get passed to the atmosphere
+ flx_mss_vrt_dst(bounds%begp:bounds%endp,:)=0._r8
+
+ do fp = 1,num_nolakep
+ p = filter_nolakep(fp)
+ c = patch%column(p)
+ l = patch%landunit(p)
+
+ ! the following code from subr. lnd_frc_mbl_get was adapted for lsm use
+ ! purpose: return fraction of each gridcell suitable for dust mobilization
+
+ ! the "bare ground" fraction of the current sub-gridscale cell decreases
+ ! linearly from 1 to 0 as VAI(=tlai+tsai) increases from 0 to vai_mbl_thr
+ ! if ice sheet, wetland, or lake, no dust allowed
+
+ if (lun%itype(l) == istsoil .or. lun%itype(l) == istcrop) then
+ if (tlai_lu(l) < vai_mbl_thr) then
+ lnd_frc_mbl(p) = 1.0_r8 - (tlai_lu(l))/vai_mbl_thr
+ else
+ lnd_frc_mbl(p) = 0.0_r8
+ endif
+ lnd_frc_mbl(p) = lnd_frc_mbl(p) * (1.0_r8 - frac_sno(c))
+ else
+ lnd_frc_mbl(p) = 0.0_r8
+ end if
+ end do
+
+ do fp = 1,num_nolakep
+ p = filter_nolakep(fp)
+ if (lnd_frc_mbl(p)>1.0_r8 .or. lnd_frc_mbl(p)<0.0_r8) then
+ write(iulog,*)'Error dstmbl: pft= ',p,' lnd_frc_mbl(p)= ',lnd_frc_mbl(p), &
+ errMsg(sourcefile, __LINE__)
+ call endrun("Bad value for dust mobilization fraction")
+ return
+ end if
+ end do
+
+ ! reset history output variables before next if-statement to avoid output = inf
+
+ do fp = 1,num_nolakep
+ p = filter_nolakep(fp)
+ flx_mss_vrt_dst_tot(p) = 0.0_r8
+ end do
+ do n = 1, ndst
+ do fp = 1,num_nolakep
+ p = filter_nolakep(fp)
+ flx_mss_vrt_dst(p,n) = 0.0_r8
+ end do
+ end do
+
+ do fp = 1,num_nolakep
+ p = filter_nolakep(fp)
+ c = patch%column(p)
+ l = patch%landunit(p)
+ g = patch%gridcell(p)
+
+ ! only perform the following calculations if lnd_frc_mbl is non-zero
+
+ if (lnd_frc_mbl(p) > 0.0_r8) then
+
+ ! the following comes from subr. frc_thr_rgh_fct_get
+ ! purpose: compute factor by which surface roughness increases threshold
+ ! friction velocity (currently a constant)
+
+ frc_thr_rgh_fct = 1.0_r8
+
+ ! the following comes from subr. frc_thr_wet_fct_get
+ ! purpose: compute factor by which soil moisture increases threshold friction velocity
+ ! adjust threshold velocity for inhibition by moisture
+ ! modified 4/5/2002 (slevis) to use gravimetric instead of volumetric
+ ! water content
+
+ bd = (1._r8-watsat(c,1))*2.7e3_r8 ![kg m-3] Bulk density of dry surface soil
+ gwc_sfc = h2osoi_vol(c,1)*SHR_CONST_RHOFW/bd ![kg kg-1] Gravimetric H2O cont
+ if (gwc_sfc > gwc_thr(c)) then
+ frc_thr_wet_fct = sqrt(1.0_r8 + 1.21_r8 * (100.0_r8*(gwc_sfc - gwc_thr(c)))**0.68_r8)
+ else
+ frc_thr_wet_fct = 1.0_r8
+ end if
+
+ ! slevis: adding liqfrac here, because related to effects from soil water
+
+ liqfrac = max( 0.0_r8, min( 1.0_r8, h2osoi_liq(c,1) / (h2osoi_ice(c,1)+h2osoi_liq(c,1)+1.0e-6_r8) ) )
+
+ ! the following lines come from subr. dst_mbl
+ ! purpose: adjust threshold friction velocity to acct for moisture and
+ ! roughness. The ratio saltation_factor / sqrt(forc_rho) comes from
+ ! subr. wnd_frc_thr_slt_get which computes dry threshold
+ ! friction velocity for saltation
+
+ wnd_frc_thr_slt = this%saltation_factor / sqrt(forc_rho(c)) * frc_thr_wet_fct * frc_thr_rgh_fct
+
+ ! reset these variables which will be updated in the following if-block
+
+ wnd_frc_slt = fv(p)
+ flx_mss_hrz_slt_ttl = 0.0_r8
+ flx_mss_vrt_dst_ttl(p) = 0.0_r8
+
+ ! the following line comes from subr. dst_mbl
+ ! purpose: threshold saltation wind speed
+
+ wnd_rfr_thr_slt = u10(p) * wnd_frc_thr_slt / fv(p)
+
+ ! the following if-block comes from subr. wnd_frc_slt_get
+ ! purpose: compute the saltating friction velocity
+ ! theory: saltation roughens the boundary layer, AKA "Owen's effect"
+
+ if (u10(p) >= wnd_rfr_thr_slt) then
+ wnd_rfr_dlt = u10(p) - wnd_rfr_thr_slt
+ wnd_frc_slt_dlt = 0.003_r8 * wnd_rfr_dlt * wnd_rfr_dlt
+ wnd_frc_slt = fv(p) + wnd_frc_slt_dlt
+ end if
+
+ ! the following comes from subr. flx_mss_hrz_slt_ttl_Whi79_get
+ ! purpose: compute vertically integrated streamwise mass flux of particles
+
+ if (wnd_frc_slt > wnd_frc_thr_slt) then
+ wnd_frc_rat = wnd_frc_thr_slt / wnd_frc_slt
+ flx_mss_hrz_slt_ttl = cst_slt * forc_rho(c) * (wnd_frc_slt**3.0_r8) * &
+ (1.0_r8 - wnd_frc_rat) * (1.0_r8 + wnd_frc_rat) * (1.0_r8 + wnd_frc_rat) / grav
+
+ ! the following loop originates from subr. dst_mbl
+ ! purpose: apply land sfc and veg limitations and global tuning factor
+ ! slevis: multiply flx_mss_hrz_slt_ttl by liqfrac to incude the effect
+ ! of frozen soil
+
+ flx_mss_hrz_slt_ttl = flx_mss_hrz_slt_ttl * lnd_frc_mbl(p) * mbl_bsn_fct(c) * &
+ flx_mss_fdg_fct * liqfrac
+ end if
+
+ ! the following comes from subr. flx_mss_vrt_dst_ttl_MaB95_get
+ ! purpose: diagnose total vertical mass flux of dust from vertically
+ ! integrated streamwise mass flux
+
+ dst_slt_flx_rat_ttl = 100.0_r8 * exp( log(10.0_r8) * (13.4_r8 * mss_frc_cly_vld(c) - 6.0_r8) )
+ flx_mss_vrt_dst_ttl(p) = flx_mss_hrz_slt_ttl * dst_slt_flx_rat_ttl
+
+ end if ! lnd_frc_mbl > 0.0
+
+ end do
+
+ ! the following comes from subr. flx_mss_vrt_dst_prt in C. Zender's code
+ ! purpose: partition total vertical mass flux of dust into transport bins
+
+ do n = 1, ndst
+ do m = 1, dst_src_nbr
+ do fp = 1,num_nolakep
+ p = filter_nolakep(fp)
+ if (lnd_frc_mbl(p) > 0.0_r8) then
+ flx_mss_vrt_dst(p,n) = flx_mss_vrt_dst(p,n) + this%ovr_src_snk_mss(m,n) * flx_mss_vrt_dst_ttl(p)
+ end if
+ end do
+ end do
+ end do
+
+ do n = 1, ndst
+ do fp = 1,num_nolakep
+ p = filter_nolakep(fp)
+ if (lnd_frc_mbl(p) > 0.0_r8) then
+ flx_mss_vrt_dst_tot(p) = flx_mss_vrt_dst_tot(p) + flx_mss_vrt_dst(p,n)
+ end if
+ end do
+ end do
+
+ end associate
+
+ end subroutine DustEmission
+
+ !------------------------------------------------------------------------
+
+end module DustEmisZender2003
\ No newline at end of file
diff --git a/src/biogeochem/test/CMakeLists.txt b/src/biogeochem/test/CMakeLists.txt
index 81fe9bbaf0..e22a720523 100644
--- a/src/biogeochem/test/CMakeLists.txt
+++ b/src/biogeochem/test/CMakeLists.txt
@@ -2,3 +2,4 @@ add_subdirectory(Species_test)
add_subdirectory(CNVegComputeSeed_test)
add_subdirectory(CNPhenology_test)
add_subdirectory(Latbaset_test)
+add_subdirectory(DustEmis_test)
diff --git a/src/biogeochem/test/DustEmis_test/CMakeLists.txt b/src/biogeochem/test/DustEmis_test/CMakeLists.txt
new file mode 100644
index 0000000000..9239d16e22
--- /dev/null
+++ b/src/biogeochem/test/DustEmis_test/CMakeLists.txt
@@ -0,0 +1,6 @@
+set (pfunit_sources
+ test_DustEmisZender2003.pf)
+
+add_pfunit_ctest(DustEmis
+ TEST_SOURCES "${pfunit_sources}"
+ LINK_LIBRARIES clm csm_share esmf_wrf_timemgr)
diff --git a/src/biogeochem/test/DustEmis_test/test_DustEmisZender2003.pf b/src/biogeochem/test/DustEmis_test/test_DustEmisZender2003.pf
new file mode 100644
index 0000000000..0289cadabc
--- /dev/null
+++ b/src/biogeochem/test/DustEmis_test/test_DustEmisZender2003.pf
@@ -0,0 +1,293 @@
+module test_DustEmisZender2003
+
+ ! Tests of DustEmisZender2003
+
+ use funit
+ use unittestDustEmisInputs, only : unittest_dust_emis_input_type
+ use unittestSubgridMod, only : bounds
+ use DustEmisBase
+ use DustEmisZender2003
+ use shr_kind_mod , only : r8 => shr_kind_r8
+ use DustEmisFactory, only : create_dust_emissions
+ use shr_dust_emis_mod, only : dust_emis_set_options
+
+ implicit none
+
+ real(r8), parameter :: tol = 1.e-18_r8
+
+ @TestCase
+ type, extends(TestCase) :: TestDustEmisZender2003
+ class(dust_emis_base_type), allocatable :: dust_emis
+ type(unittest_dust_emis_input_type) :: input
+ contains
+ procedure :: setUp
+ procedure :: tearDown
+ procedure :: print_values
+ procedure :: validate_patch
+ end type TestDustEmisZender2003
+
+contains
+
+ !-----------------------------------------------------------------------
+
+ subroutine setUp(this)
+ class(TestDustEmisZender2003), intent(inout) :: this
+ ! Allocate and initialize the test object for input objects dust-emission needs
+ character(len=5) :: NLFilename = 'none'
+
+ call this%input%setUp()
+
+ ! Create the dust emission object last
+ call dust_emis_set_options( 'Zender_2003', 'atm')
+ allocate(this%dust_emis, source = create_dust_emissions(bounds, NLFilename))
+ end subroutine setUp
+
+ !-----------------------------------------------------------------------
+
+ subroutine tearDown(this)
+ class(TestDustEmisZender2003), intent(inout) :: this
+
+ call this%dust_emis%Clean()
+ call this%input%tearDown()
+ end subroutine tearDown
+
+ !-----------------------------------------------------------------------
+
+ subroutine print_values(this)
+ ! For debugging
+ use PatchType, only : patch
+ class(TestDustEmisZender2003), intent(inout) :: this
+ real(r8) :: SaltationFactor
+ integer :: p, c
+
+ call this%input%print_values()
+ call this%dust_emis%GetConstVars( SaltationFactor )
+ do c = bounds%begc, bounds%endc
+ print *, 'saltation per rho = ', (SaltationFactor / this%input%atm2lnd_inst%forc_rho_downscaled_col(c))
+ end do
+ do p = bounds%begp, bounds%endp
+ c = patch%column(p)
+ print *, 'Wind threshold fraction = ', (SaltationFactor / this%input%atm2lnd_inst%forc_rho_downscaled_col(c)) &
+ / this%input%frictionvel_inst%fv_patch(p)
+ call this%dust_emis%WritePatchToLog( p )
+ end do
+ end subroutine print_values
+
+ !-----------------------------------------------------------------------
+
+ subroutine validate_patch(this, p)
+ class(TestDustEmisZender2003), intent(inout) :: this
+ integer, intent(in) :: p
+
+ call this%dust_emis%CheckDustEmisIsValid( p )
+ end subroutine validate_patch
+
+ !-----------------------------------------------------------------------
+
+ @Test
+ subroutine check_dust_emis(this)
+ ! Check dust emissions for default values
+ class(TestDustEmisZender2003), intent(inout) :: this
+ integer :: p
+ real(r8) :: flx_mss_vrt_dst_tot
+ real(r8) :: vlc_trb_1
+ real(r8) :: vlc_trb_2
+ real(r8) :: vlc_trb_3
+ real(r8) :: vlc_trb_4
+
+ call this%input%create_atm2lnd()
+ call this%input%create_fv()
+ call this%dust_emis%DustEmission(bounds, this%input%num_nolakep, this%input%filter_nolakep, this%input%atm2lnd_inst, &
+ this%input%soilstate_inst, this%input%canopystate_inst, this%input%water_inst%waterstatebulk_inst, &
+ this%input%water_inst%waterdiagnosticbulk_inst, this%input%frictionvel_inst)
+ call this%dust_emis%DustDryDep(bounds, this%input%atm2lnd_inst, this%input%frictionvel_inst)
+ call this%print_values() ! Call print subroutine just to make sure it can be used for debugging
+ do p = bounds%begp, bounds%endp
+ call this%validate_patch(p)
+ call this%dust_emis%GetPatchVars( p, flx_mss_vrt_dst_tot=flx_mss_vrt_dst_tot, &
+ vlc_trb_1=vlc_trb_1, vlc_trb_2=vlc_trb_2, vlc_trb_3=vlc_trb_3, &
+ vlc_trb_4=vlc_trb_4)
+ @assertEqual( flx_mss_vrt_dst_tot, 2.583480541056971d-6, tolerance=tol )
+ @assertEqual( vlc_trb_1, 3.407721147709135d-003, tolerance=tol )
+ @assertEqual( vlc_trb_2, 4.961153753164878d-003, tolerance=tol )
+ @assertEqual( vlc_trb_3, 4.980100969983446d-003, tolerance=tol )
+ @assertEqual( vlc_trb_4, 4.977071672163210d-003, tolerance=tol )
+ end do
+
+ end subroutine check_dust_emis
+
+ !-----------------------------------------------------------------------
+
+ @Test
+ subroutine dust_zero_for_fixed_ratio(this)
+ ! Check dust emissions are zero for a no wind
+ class(TestDustEmisZender2003), intent(inout) :: this
+ integer :: p
+ real(r8) :: flx_mss_vrt_dst_tot
+ real(r8) :: fv
+ real(r8) :: SaltationFactor
+
+ call this%input%create_atm2lnd()
+ call this%dust_emis%GetConstVars( SaltationFactor )
+ ! Figure out what fv needs to be so that the wind threshold will be u10*(1/(1-eps))
+ fv = ( SaltationFactor / sqrt( this%input%atm2lnd_inst%forc_rho_downscaled_col(bounds%begc)) ) - 1.d-15
+ call this%input%create_fv( fv=fv )
+ call this%dust_emis%DustEmission(bounds, this%input%num_nolakep, this%input%filter_nolakep, this%input%atm2lnd_inst, &
+ this%input%soilstate_inst, this%input%canopystate_inst, this%input%water_inst%waterstatebulk_inst, &
+ this%input%water_inst%waterdiagnosticbulk_inst, this%input%frictionvel_inst)
+ call this%dust_emis%DustDryDep(bounds, this%input%atm2lnd_inst, this%input%frictionvel_inst)
+ do p = bounds%begp, bounds%endp
+ call this%validate_patch(p)
+ call this%dust_emis%GetPatchVars( p, flx_mss_vrt_dst_tot=flx_mss_vrt_dst_tot )
+ @assertEqual( flx_mss_vrt_dst_tot, 0.0_r8 )
+ end do
+
+ end subroutine dust_zero_for_fixed_ratio
+
+ !-----------------------------------------------------------------------
+
+ @Test
+ subroutine dust_zero_when_fsno_one(this)
+ ! Check dust emissions are zero when snow fraction is identically 1
+ class(TestDustEmisZender2003), intent(inout) :: this
+ integer :: p
+ real(r8) :: flx_mss_vrt_dst_tot
+
+ call this%input%create_atm2lnd()
+ this%input%water_inst%waterdiagnosticbulk_inst%frac_sno_col(:) = 1.0_r8
+ call this%input%create_fv( )
+ call this%dust_emis%DustEmission(bounds, this%input%num_nolakep, this%input%filter_nolakep, this%input%atm2lnd_inst, &
+ this%input%soilstate_inst, this%input%canopystate_inst, this%input%water_inst%waterstatebulk_inst, &
+ this%input%water_inst%waterdiagnosticbulk_inst, this%input%frictionvel_inst)
+ call this%dust_emis%DustDryDep(bounds, this%input%atm2lnd_inst, this%input%frictionvel_inst)
+ do p = bounds%begp, bounds%endp
+ call this%dust_emis%GetPatchVars( p, flx_mss_vrt_dst_tot=flx_mss_vrt_dst_tot )
+ @assertEqual( flx_mss_vrt_dst_tot, 0.0_r8 )
+ end do
+
+ end subroutine dust_zero_when_fsno_one
+
+ !-----------------------------------------------------------------------
+
+ @Test
+ subroutine dust_zero_non_veg_lu(this)
+ ! Check dust emissions are zero for non-veg landunits
+ use landunit_varcon, only: istcrop, max_lunit
+ use LandunitType, only : lun
+ class(TestDustEmisZender2003), intent(inout) :: this
+ integer :: p, l
+ real(r8) :: flx_mss_vrt_dst_tot
+
+ call this%input%create_atm2lnd()
+ call this%input%create_fv( )
+ ! Set the lanunit type for
+ do l = istcrop+1, max_lunit
+ lun%itype(bounds%begl:bounds%endl) = l
+ call this%dust_emis%DustEmission(bounds, this%input%num_nolakep, this%input%filter_nolakep, this%input%atm2lnd_inst, &
+ this%input%soilstate_inst, this%input%canopystate_inst, this%input%water_inst%waterstatebulk_inst, &
+ this%input%water_inst%waterdiagnosticbulk_inst, this%input%frictionvel_inst)
+ call this%dust_emis%DustDryDep(bounds, this%input%atm2lnd_inst, this%input%frictionvel_inst)
+ do p = bounds%begp, bounds%endp
+ call this%dust_emis%GetPatchVars( p, flx_mss_vrt_dst_tot=flx_mss_vrt_dst_tot )
+ @assertEqual( flx_mss_vrt_dst_tot, 0.0_r8 )
+ end do
+ end do
+
+ end subroutine dust_zero_non_veg_lu
+
+ !-----------------------------------------------------------------------
+
+ @Test
+ subroutine aborts_on_bad_dust_mobility(this)
+ ! Check dust abort when dust mobility is bad
+ class(TestDustEmisZender2003), intent(inout) :: this
+ real(r8) :: flx_mss_vrt_dst_tot
+ character(100) :: expected_msg
+
+ call this%input%create_atm2lnd()
+ call this%input%create_fv( )
+ ! Dust should abort with an error on dust mobility when snow fraction greater than 1
+ this%input%water_inst%waterdiagnosticbulk_inst%frac_sno_col(:) = 1.0_r8 + 1.e-15_r8
+ call this%dust_emis%DustEmission(bounds, this%input%num_nolakep, this%input%filter_nolakep, this%input%atm2lnd_inst, &
+ this%input%soilstate_inst, this%input%canopystate_inst, this%input%water_inst%waterstatebulk_inst, &
+ this%input%water_inst%waterdiagnosticbulk_inst, this%input%frictionvel_inst)
+ expected_msg = "ABORTED: Bad value for dust mobilization fraction"
+ @assertExceptionRaised(expected_msg)
+
+ end subroutine aborts_on_bad_dust_mobility
+
+ !-----------------------------------------------------------------------
+
+ @Test
+ subroutine dust_zero_when_tlai_high(this)
+ use PatchType, only : patch
+ ! Check dust emissions are zero when LAI is high enough
+ class(TestDustEmisZender2003), intent(inout) :: this
+ integer :: p
+ real(r8) :: flx_mss_vrt_dst_tot
+
+ ! Explicitly set the patch type to a hard-coded 1 (so NOT bare-soil)
+ ! pft indices can't be used without reading them from the parameter file
+ !
+ ! To do this fully the subgrid setup in unittestDustEmisInputs to baresoil
+ ! should really be run again. But, just doing this is likely sufficient for testing
+ patch%itype(bounds%begp:bounds%endp) = 1
+ call this%input%create_atm2lnd()
+ call this%input%create_fv( )
+ this%input%canopystate_inst%tlai_patch(:) = 0.3_r8
+ call this%dust_emis%DustEmission(bounds, this%input%num_nolakep, this%input%filter_nolakep, this%input%atm2lnd_inst, &
+ this%input%soilstate_inst, this%input%canopystate_inst, this%input%water_inst%waterstatebulk_inst, &
+ this%input%water_inst%waterdiagnosticbulk_inst, this%input%frictionvel_inst)
+ call this%dust_emis%DustDryDep(bounds, this%input%atm2lnd_inst, this%input%frictionvel_inst)
+ do p = bounds%begp, bounds%endp
+ call this%validate_patch(p)
+ call this%dust_emis%GetPatchVars( p, flx_mss_vrt_dst_tot=flx_mss_vrt_dst_tot )
+ @assertEqual( flx_mss_vrt_dst_tot, 0.0_r8 )
+ end do
+
+ end subroutine dust_zero_when_tlai_high
+
+ !-----------------------------------------------------------------------
+
+ @Test
+ subroutine check_dust_emis_increasing_wind(this)
+ ! Check dust emissions with increasing wind
+ class(TestDustEmisZender2003), intent(inout) :: this
+ integer :: p, c
+ real(r8) :: flx_mss_vrt_dst_tot
+ real(r8) :: fv = 4.0_r8
+ real(r8) :: u10 = 10._r8
+ real(r8) :: total_dust0, total_dust_higher
+
+ ! Run baseline u10
+ call this%input%create_atm2lnd()
+ call this%input%create_fv( u10=u10, fv=fv )
+ call this%dust_emis%DustEmission(bounds, this%input%num_nolakep, this%input%filter_nolakep, this%input%atm2lnd_inst, &
+ this%input%soilstate_inst, this%input%canopystate_inst, this%input%water_inst%waterstatebulk_inst, &
+ this%input%water_inst%waterdiagnosticbulk_inst, this%input%frictionvel_inst)
+ call this%dust_emis%DustDryDep(bounds, this%input%atm2lnd_inst, this%input%frictionvel_inst)
+ do p = bounds%begp, bounds%endp
+ call this%validate_patch(p)
+ call this%dust_emis%GetPatchVars( p, flx_mss_vrt_dst_tot=flx_mss_vrt_dst_tot )
+ total_dust0 = flx_mss_vrt_dst_tot
+ @assertEqual( flx_mss_vrt_dst_tot, 2.273879554711299d-5, tolerance=tol )
+ end do
+ ! Double u10 and show result is higher
+ call this%input%create_fv( u10=u10*2.0_r8, fv=fv)
+ call this%dust_emis%DustEmission(bounds, this%input%num_nolakep, this%input%filter_nolakep, this%input%atm2lnd_inst, &
+ this%input%soilstate_inst, this%input%canopystate_inst, this%input%water_inst%waterstatebulk_inst, &
+ this%input%water_inst%waterdiagnosticbulk_inst, this%input%frictionvel_inst)
+ call this%dust_emis%DustDryDep(bounds, this%input%atm2lnd_inst, this%input%frictionvel_inst)
+ do p = bounds%begp, bounds%endp
+ call this%validate_patch(p)
+ call this%dust_emis%GetPatchVars( p, flx_mss_vrt_dst_tot=flx_mss_vrt_dst_tot )
+ total_dust_higher = flx_mss_vrt_dst_tot
+ @assertEqual( flx_mss_vrt_dst_tot, 3.792794484764924d-5, tolerance=tol )
+ end do
+ @assertGreaterThan( total_dust_higher, total_dust0 )
+
+ end subroutine check_dust_emis_increasing_wind
+
+ !-----------------------------------------------------------------------
+
+end module test_DustEmisZender2003
\ No newline at end of file
diff --git a/src/biogeophys/CMakeLists.txt b/src/biogeophys/CMakeLists.txt
index 2ffc346670..07b88b07bf 100644
--- a/src/biogeophys/CMakeLists.txt
+++ b/src/biogeophys/CMakeLists.txt
@@ -7,6 +7,7 @@ list(APPEND clm_sources
BalanceCheckMod.F90
CanopyStateType.F90
EnergyFluxType.F90
+ FrictionVelocityMod.F90
GlacierSurfaceMassBalanceMod.F90
HillslopeHydrologyUtilsMod.F90
HumanIndexMod.F90
@@ -24,6 +25,7 @@ list(APPEND clm_sources
SoilHydrologyType.F90
SoilStateType.F90
SoilWaterRetentionCurveMod.F90
+ SoilStateInitTimeConstMod.F90
SolarAbsorbedType.F90
PhotosynthesisMod.F90
SurfaceAlbedoType.F90
diff --git a/src/biogeophys/CanopyStateType.F90 b/src/biogeophys/CanopyStateType.F90
index 313f7a83f3..4bfc08fc80 100644
--- a/src/biogeophys/CanopyStateType.F90
+++ b/src/biogeophys/CanopyStateType.F90
@@ -72,6 +72,8 @@ module CanopyStateType
procedure, public :: UpdateAccVars
procedure, public :: Restart
+ procedure, public :: SetNMLForTesting ! Set namelist for unit-testing
+
end type CanopyState_type
character(len=*), parameter, private :: sourcefile = &
@@ -442,6 +444,21 @@ subroutine ReadNML( this, NLFilename )
end subroutine ReadNML
+ !-----------------------------------------------------------------------
+
+ subroutine SetNMLForTesting( this )
+ !
+ ! Set canopy parameter namelist control settings for unit-testing
+ !
+ class(canopystate_type) :: this
+ ! LOCAL VARIABLES:
+ !-----------------------------------------------------------------------
+
+
+ this%leaf_mr_vcm = 0.015_r8
+
+ end subroutine SetNMLForTesting
+
!-----------------------------------------------------------------------
subroutine UpdateAccVars (this, bounds)
!
diff --git a/src/biogeophys/FrictionVelocityMod.F90 b/src/biogeophys/FrictionVelocityMod.F90
index 7cea2a22f9..042415f545 100644
--- a/src/biogeophys/FrictionVelocityMod.F90
+++ b/src/biogeophys/FrictionVelocityMod.F90
@@ -89,6 +89,8 @@ module FrictionVelocityMod
procedure, public :: FrictionVelocity ! Calculate friction velocity
procedure, public :: MoninObukIni ! Initialization of the Monin-Obukhov length
+ procedure, public :: InitForTesting ! version of Init meant for unit testing
+
! Private procedures
procedure, private :: InitAllocate
procedure, private :: InitHistory
@@ -122,6 +124,22 @@ subroutine Init(this, bounds, NLFilename, params_ncid)
end subroutine Init
+ !------------------------------------------------------------------------
+ subroutine InitForTesting(this, bounds)
+ ! Initialization for unit testing, hardcodes namelist and parameter file settings
+ class(frictionvel_type) :: this
+ type(bounds_type), intent(in) :: bounds
+
+ call this%InitAllocate(bounds)
+ call this%InitHistory(bounds)
+ call this%InitCold(bounds)
+ this%zetamaxstable = 0.5_r8
+ this%zsno = 0.00085_r8
+ this%zlnd = 0.000775_r8
+ this%zglc = 0.00230000005_r8
+
+ end subroutine InitForTesting
+
!------------------------------------------------------------------------
subroutine InitAllocate(this, bounds)
!
diff --git a/src/biogeophys/IrrigationMod.F90 b/src/biogeophys/IrrigationMod.F90
index 27cf050dd3..11c9132eea 100644
--- a/src/biogeophys/IrrigationMod.F90
+++ b/src/biogeophys/IrrigationMod.F90
@@ -221,9 +221,8 @@ module IrrigationMod
! There is no reason to make this a tunable parameter, because the behavior it governs
! (the trigger for irrigation) can be tuned via other parameters.
!
- ! TODO(wjs, 2016-09-08) It looks like there is other code in CLM that also uses an
- ! assumed wilting point (CNRootDynMod, maybe others). We should probably make this a
- ! shared parameter, e.g., in clm_varcon.
+ ! TODO(wjs, 2016-09-08, updated by slevis 2024-07-06) assumed wilting point:
+ ! Make this a shared parameter? E.g., in clm_varcon
real(r8), parameter, private :: wilting_point_smp = -150000._r8
! Conversion factors
diff --git a/src/biogeophys/SoilStateInitTimeConstMod.F90 b/src/biogeophys/SoilStateInitTimeConstMod.F90
index 9122b56890..e47577c9b9 100644
--- a/src/biogeophys/SoilStateInitTimeConstMod.F90
+++ b/src/biogeophys/SoilStateInitTimeConstMod.F90
@@ -17,6 +17,11 @@ module SoilStateInitTimeConstMod
! !PUBLIC MEMBER FUNCTIONS:
public :: SoilStateInitTimeConst
public :: readParams
+
+ ! PRIVATE FUNCTIONS MADE PUBLIC Just for unit-testing:
+ public :: ThresholdSoilMoistZender2003
+ public :: ThresholdSoilMoistKok2014
+ public :: MassFracClay
!
! !PRIVATE MEMBER FUNCTIONS:
private :: ReadNL
@@ -702,8 +707,8 @@ subroutine SoilStateInitTimeConst(bounds, soilstate_inst, nlfilename)
do c = begc,endc
g = col%gridcell(c)
- soilstate_inst%gwc_thr_col(c) = 0.17_r8 + 0.14_r8 * clay3d(g,1) * 0.01_r8
- soilstate_inst%mss_frc_cly_vld_col(c) = min(clay3d(g,1) * 0.01_r8, 0.20_r8)
+ soilstate_inst%gwc_thr_col(c) = ThresholdSoilMoistZender2003( clay3d(g,1) )
+ soilstate_inst%mss_frc_cly_vld_col(c) = MassFracClay( clay3d(g,1) )
end do
! --------------------------------------------------------------------
@@ -715,4 +720,77 @@ subroutine SoilStateInitTimeConst(bounds, soilstate_inst, nlfilename)
end subroutine SoilStateInitTimeConst
+ !------------------------------------------------------------------------------
+
+ real(r8) function ThresholdSoilMoistZender2003( clay )
+ !------------------------------------------------------------------------------
+ !
+ ! Calculate the threshold soil moisture needed for dust emission, based on clay content
+ ! This was the original equation with a = 1 / (%clay) being the tuning factor for soil
+ ! moisture effect in Zender's 2003 dust emission scheme.
+ !
+ ! 0.17 and 0.14 are fitting coefficients in Fecan et al. (1999), and 0.01 is used to
+ ! convert surface clay fraction from percentage to fraction.
+ !
+ !------------------------------------------------------------------------------
+ ! For future developments Danny M. Leung decided (Dec, 2023) that the Leung et al. (2023) o
+ ! dust emission scheme in the CESM will use Zender's tuning as well, which overall
+ ! encourages more dust emissions from seriamid and more marginal dust sources.
+ ! Another advantage of using this tuning factor instead of a = 1 is that the dust emission
+ ! threshold is linearly dependent on the clay fraction instead of parabolically dependent
+ ! on clay fraction as in the above line. This means that dust emission becomes a little
+ ! less sensitive to clay content (soil texture).
+ !
+ ! Also see the notes below for ThresholdSoilMoistKok2014.
+ !
+ ! Notes from: dmleung 19 Feb 2024.
+ !
+ !------------------------------------------------------------------------------
+ use abortUtils , only : endrun
+ use shr_infnan_mod, only : nan => shr_infnan_nan, assignment(=)
+ real(r8), intent(IN) :: clay ! Fraction of clay in the soil (%)
+
+ if ( clay < 0.0_r8 .or. clay > 100.0_r8 )then
+ ThresholdSoilMoistZender2003 = nan
+ call endrun( 'Clay fraction is out of bounds (0 to 100)')
+ return
+ end if
+ ThresholdSoilMoistZender2003 = 0.17_r8 + 0.14_r8 * clay * 0.01_r8
+ end function ThresholdSoilMoistZender2003
+
+ !------------------------------------------------------------------------------
+
+ real(r8) function ThresholdSoilMoistKok2014( clay )
+ !------------------------------------------------------------------------------
+ ! Calculate the threshold soil moisture needed for dust emission, based on clay content
+ !
+ ! The below calculates the threshold gravimetric water content for the dust emission
+ ! calculation in DustEmis. The equation comes from Eq. 14 of Fecan et al.
+ ! (1999; https://doi.org/10.1007/s00585-999-0149-7).
+ ! gwc_thr_col = 0.17*clay3d + 0.0014*(clay3d**2), and we only concern the topmost
+ ! soil layer. Charlie Zender later on added a tuning factor (a) such that the
+ ! equation becomes gwc_thr_col = a*[0.17*clay3d + 0.0014*(clay3d**2)].
+ ! (Zender et al., 2003a; https://doi.org/10.1029/2002JD002775)
+ ! Kok et al. (2014a, b) chose to use a = 1. Resulting in this function
+ ! Charlie Zender (2003a) chose: a = 1/clay3d, which gives the ThresholdSoilMoistZender2003
+ ! function above.
+ !
+ ! Notes from: dmleung 24 May 2024.
+ !------------------------------------------------------------------------------
+ real(r8), intent(IN) :: clay ! Fraction of clay in the soil (%)
+
+ ThresholdSoilMoistKok2014 = 0.01_r8*(0.17_r8*clay + 0.0014_r8*clay*clay)
+ end function ThresholdSoilMoistKok2014
+
+ !------------------------------------------------------------------------------
+
+ real(r8) function MassFracClay( clay )
+ ! Calculate the mass fraction of clay needed for dust emission, based on clay content
+ real(r8), intent(IN) :: clay ! Fraction of lay in the soil (%)
+
+ MassFracClay = min(clay * 0.01_r8, 0.20_r8)
+ end function MassFracClay
+
+ !------------------------------------------------------------------------------
+
end module SoilStateInitTimeConstMod
diff --git a/src/biogeophys/SoilStateType.F90 b/src/biogeophys/SoilStateType.F90
index e301cc27b9..2e7225f962 100644
--- a/src/biogeophys/SoilStateType.F90
+++ b/src/biogeophys/SoilStateType.F90
@@ -9,7 +9,7 @@ module SoilStateType
use abortutils , only : endrun
use clm_varpar , only : nlevsoi, nlevgrnd, nlevlak, nlayer, nlevsno, nlevmaxurbgrnd
use clm_varcon , only : spval
- use clm_varctl , only : use_hydrstress, use_cn, use_lch4, use_dynroot, use_fates
+ use clm_varctl , only : use_hydrstress, use_cn, use_lch4, use_fates
use clm_varctl , only : iulog, hist_wrtch4diag
use LandunitType , only : lun
use ColumnType , only : col
@@ -231,20 +231,6 @@ subroutine InitHistory(this, bounds)
ptr_col=this%bsw_col, default='inactive')
end if
- if (use_dynroot) then
- this%rootfr_patch(begp:endp,:) = spval
- call hist_addfld2d (fname='ROOTFR', units='proportion', type2d='levgrnd', &
- avgflag='A', long_name='fraction of roots in each soil layer', &
- ptr_patch=this%rootfr_patch, default='active')
- end if
-
- if ( use_dynroot ) then
- this%root_depth_patch(begp:endp) = spval
- call hist_addfld1d (fname='ROOT_DEPTH', units="m", &
- avgflag='A', long_name='rooting depth', &
- ptr_patch=this%root_depth_patch )
- end if
-
if (use_cn) then
this%rootr_patch(begp:endp,:) = spval
call hist_addfld2d (fname='ROOTR', units='proportion', type2d='levgrnd', &
@@ -393,15 +379,7 @@ subroutine Restart(this, bounds, ncid, flag)
scale_by_thickness=.true., &
interpinic_flag='interp', readvar=readvar, data=this%hk_l_col)
- if( use_dynroot ) then
- call restartvar(ncid=ncid, flag=flag, varname='rootfr', xtype=ncd_double, &
- dim1name='pft', dim2name='levgrnd', switchdim=.true., &
- long_name='root fraction', units='', &
- scale_by_thickness=.false., &
- interpinic_flag='interp', readvar=readrootfr, data=this%rootfr_patch)
- else
- readrootfr = .false.
- end if
+ readrootfr = .false.
if (flag=='read' .and. .not. readrootfr ) then
if (masterproc) then
write(iulog,*) "can't find rootfr in restart (or initial) file..."
diff --git a/src/biogeophys/SurfaceAlbedoType.F90 b/src/biogeophys/SurfaceAlbedoType.F90
index ddb57d88f7..e90caeecbb 100644
--- a/src/biogeophys/SurfaceAlbedoType.F90
+++ b/src/biogeophys/SurfaceAlbedoType.F90
@@ -226,7 +226,7 @@ subroutine InitHistory(this, bounds)
this%azsun_grc(begg:endg) = spval
call hist_addfld1d (fname='AZSUN', units='radians', &
- avgflag='A', long_name='cosine of solar zenith angle', &
+ avgflag='A', long_name='azimuth angle of the sun', &
ptr_lnd=this%azsun_grc, default='inactive')
this%coszen_grc(begg:endg) = spval
diff --git a/src/biogeophys/WaterDiagnosticBulkType.F90 b/src/biogeophys/WaterDiagnosticBulkType.F90
index dd556a2df6..f91aaca761 100644
--- a/src/biogeophys/WaterDiagnosticBulkType.F90
+++ b/src/biogeophys/WaterDiagnosticBulkType.F90
@@ -346,7 +346,7 @@ subroutine InitBulkHistory(this, bounds)
fname=this%info%fname('RH2M_R'), &
units='%', &
avgflag='A', &
- long_name=this%info%lname('Rural 2m specific humidity'), &
+ long_name=this%info%lname('Rural 2m relative humidity'), &
ptr_patch=this%rh_ref2m_r_patch, set_spec=spval, default='inactive')
this%rh_ref2m_u_patch(begp:endp) = spval
diff --git a/src/biogeophys/test/CMakeLists.txt b/src/biogeophys/test/CMakeLists.txt
index 5c15858210..7a0a1e8fbb 100644
--- a/src/biogeophys/test/CMakeLists.txt
+++ b/src/biogeophys/test/CMakeLists.txt
@@ -5,6 +5,7 @@ add_subdirectory(HillslopeHydrology_test)
add_subdirectory(SnowHydrology_test)
add_subdirectory(Photosynthesis_test)
add_subdirectory(Balance_test)
+add_subdirectory(SoilStateInitTimeConst_test)
add_subdirectory(TotalWaterAndHeat_test)
add_subdirectory(Wateratm2lnd_test)
add_subdirectory(WaterTracerContainerType_test)
diff --git a/src/biogeophys/test/SoilStateInitTimeConst_test/CMakeLists.txt b/src/biogeophys/test/SoilStateInitTimeConst_test/CMakeLists.txt
new file mode 100644
index 0000000000..df58da9875
--- /dev/null
+++ b/src/biogeophys/test/SoilStateInitTimeConst_test/CMakeLists.txt
@@ -0,0 +1,6 @@
+set (pfunit_sources
+ test_dust_soil_clay_functions.pf)
+
+add_pfunit_ctest(SoilStateInit
+ TEST_SOURCES "${pfunit_sources}"
+ LINK_LIBRARIES clm csm_share)
diff --git a/src/biogeophys/test/SoilStateInitTimeConst_test/test_dust_soil_clay_functions.pf b/src/biogeophys/test/SoilStateInitTimeConst_test/test_dust_soil_clay_functions.pf
new file mode 100644
index 0000000000..5a8f858286
--- /dev/null
+++ b/src/biogeophys/test/SoilStateInitTimeConst_test/test_dust_soil_clay_functions.pf
@@ -0,0 +1,81 @@
+module test_dust_soil_clay_functions
+
+ ! Tests of SoilStateInitTimeConst functions for dust emission in regard to clay content
+
+ use funit
+ use SoilStateInitTimeConstMod
+ use shr_kind_mod , only : r8 => shr_kind_r8
+
+ implicit none
+
+ @TestCase
+ type, extends(TestCase) :: TestDustEmisSoilFunctions
+ contains
+ procedure :: setUp
+ procedure :: tearDown
+ end type TestDustEmisSoilFunctions
+
+ real(r8), parameter :: tol = 1.e-16_r8
+
+contains
+
+ subroutine setUp(this)
+ class(TestDustEmisSoilFunctions), intent(inout) :: this
+ end subroutine setUp
+
+ subroutine tearDown(this)
+ class(TestDustEmisSoilFunctions), intent(inout) :: this
+ end subroutine tearDown
+
+ @Test
+ subroutine TestClayOutOfRangeThreshold(this)
+ class(TestDustEmisSoilFunctions), intent(inout) :: this
+ real(r8) :: value
+ character(len=100) :: expected_msg
+
+ value = ThresholdSoilMoistZender2003( -1.e-15_r8 )
+ expected_msg = "ABORTED: Clay fraction is out of bounds (0 to 100)"
+ @assertExceptionRaised(expected_msg)
+ value = ThresholdSoilMoistZender2003( 1._r8 + 1.-15_r8 )
+ @assertExceptionRaised(expected_msg)
+ end subroutine TestClayOutOfRangeThreshold
+
+ @Test
+ subroutine TestThresholdValues(this)
+ class(TestDustEmisSoilFunctions), intent(inout) :: this
+ real(r8) :: value
+
+ value = ThresholdSoilMoistZender2003( 0.0_r8 )
+ @assertEqual( value, 0.17_r8, tolerance=tol )
+ value = ThresholdSoilMoistZender2003( 100.0_r8 )
+ @assertEqual( value, 0.31_r8, tolerance=tol )
+ end subroutine TestThresholdValues
+
+ @Test
+ subroutine TestThresholdKok2014Values(this)
+ class(TestDustEmisSoilFunctions), intent(inout) :: this
+ real(r8) :: value
+
+ value = ThresholdSoilMoistKok2014( 0.0_r8 )
+ @assertEqual( value, 0.0_r8, tolerance=tol )
+ value = ThresholdSoilMoistKok2014( 100.0_r8 )
+ @assertEqual( value, 0.31_r8, tolerance=tol )
+ value = ThresholdSoilMoistKok2014( 1.0_r8 )
+ @assertEqual( value, 0.001714_r8, tolerance=tol )
+ end subroutine TestThresholdKok2014Values
+
+ @Test
+ subroutine TestClayMassFracValues(this)
+ class(TestDustEmisSoilFunctions), intent(inout) :: this
+ real(r8) :: value
+
+ value = MassFracClay( 0.0_r8 )
+ @assertEqual( value, 0.0_r8, tolerance=tol )
+ value = MassFracClay( 20.0_r8 )
+ @assertEqual( value, 0.20_r8, tolerance=tol )
+ value = MassFracClay( 25.0_r8 )
+ @assertEqual( value, 0.20_r8, tolerance=tol )
+
+ end subroutine TestClayMassFracValues
+
+end module test_dust_soil_clay_functions
diff --git a/src/cpl/mct/ExcessIceStreamType.F90 b/src/cpl/mct/ExcessIceStreamType.F90
deleted file mode 100644
index 5c5394233c..0000000000
--- a/src/cpl/mct/ExcessIceStreamType.F90
+++ /dev/null
@@ -1,144 +0,0 @@
-module ExcessIceStreamType
-
- !-----------------------------------------------------------------------
- ! !DESCRIPTION:
- ! Stub for ExcessIceStreams for the MCT driver. So that MCT can be used
- ! without excess ice streams.
- !
- ! !USES
- use shr_kind_mod , only : r8 => shr_kind_r8, CL => shr_kind_CL
- use shr_log_mod , only : errMsg => shr_log_errMsg
- use spmdMod , only : mpicom, masterproc
- use clm_varctl , only : iulog
- use abortutils , only : endrun
- use decompMod , only : bounds_type
-
- ! !PUBLIC TYPES:
- implicit none
- private
-
- public :: UseExcessIceStreams ! If streams will be used
-
- type, public :: excessicestream_type
- contains
-
- ! !PUBLIC MEMBER FUNCTIONS:
- procedure, public :: Init ! Initialize and read data in
- procedure, public :: CalcExcessIce ! Calculate excess ice ammount
-
- ! !PRIVATE MEMBER FUNCTIONS:
- procedure, private :: ReadNML ! Read in namelist
-
- end type excessicestream_type
- ! ! PRIVATE DATA:
-
- character(len=*), parameter, private :: sourcefile = &
- __FILE__
-
-!==============================================================================
-contains
-!==============================================================================
-
- subroutine Init(this, bounds, NLFilename)
- !
- !
- ! arguments
- implicit none
- class(excessicestream_type) :: this
- type(bounds_type), intent(in) :: bounds
- character(len=*), intent(in) :: NLFilename ! Namelist filename
-
- !
- ! local variables
-
- call this%ReadNML( bounds, NLFileName )
- end subroutine Init
-
- subroutine CalcExcessIce(this,bounds,exice_bulk_init)
-
- ! only transfers grid values to columns
- implicit none
- class(excessicestream_type) :: this
- type(bounds_type), intent(in) :: bounds
- real(r8) , intent(inout) :: exice_bulk_init(bounds%begc:bounds%endc)
- !
- ! !LOCAL VARIABLES:
-
- end subroutine CalcExcessIce
-
- logical function UseExcessIceStreams()
- !
- ! !DESCRIPTION:
- ! Return true if
- !
- ! !USES:
- !
- ! !ARGUMENTS:
- implicit none
- !
- ! !LOCAL VARIABLES:
- UseExcessIceStreams = .false.
-end function UseExcessIceStreams
-
-subroutine ReadNML(this, bounds, NLFilename)
- !
- ! Read the namelist data stream information.
- !
- ! Uses:
- use shr_nl_mod , only : shr_nl_find_group_name
- use shr_log_mod , only : errMsg => shr_log_errMsg
- use shr_mpi_mod , only : shr_mpi_bcast
- !
- ! arguments
- implicit none
- class(excessicestream_type) :: this
- type(bounds_type), intent(in) :: bounds
- character(len=*), intent(in) :: NLFilename ! Namelist filename
- !
- ! local variables
- integer :: nu_nml ! unit for namelist file
- integer :: nml_error ! namelist i/o error flag
- logical :: use_excess_ice_streams = .false. ! logical to turn on use of excess ice streams
- character(len=CL) :: stream_fldFileName_exice = ' '
- character(len=CL) :: stream_mapalgo_exice = 'none'
- character(len=*), parameter :: namelist_name = 'exice_streams' ! MUST agree with name in namelist and read
- character(len=*), parameter :: subName = "('exice_streams::ReadNML')"
- !-----------------------------------------------------------------------
-
- namelist /exice_streams/ & ! MUST agree with namelist_name above
- stream_mapalgo_exice, stream_fldFileName_exice, use_excess_ice_streams
- !-----------------------------------------------------------------------
- ! Default values for namelist
-
- ! Read excess ice namelist
- if (masterproc) then
- open( newunit=nu_nml, file=trim(NLFilename), status='old', iostat=nml_error )
- call shr_nl_find_group_name(nu_nml, namelist_name, status=nml_error)
- if (nml_error == 0) then
- read(nu_nml, nml=exice_streams,iostat=nml_error) ! MUST agree with namelist_name above
- if (nml_error /= 0) then
- call endrun(msg=' ERROR reading '//namelist_name//' namelist'//errMsg(sourcefile, __LINE__))
- end if
- else
- call endrun(msg=' ERROR finding '//namelist_name//' namelist'//errMsg(sourcefile, __LINE__))
- end if
- close(nu_nml)
- endif
-
- call shr_mpi_bcast(use_excess_ice_streams , mpicom)
-
- if (masterproc) then
- if ( use_excess_ice_streams ) then
- call endrun(msg=' ERROR excess ice streams can NOT be on for the MCT driver'//errMsg(sourcefile, __LINE__))
- end if
- if ( trim(stream_fldFileName_exice) /= '' ) then
- call endrun(msg=' ERROR stream_fldFileName_exice can NOT be set for the MCT driver'//errMsg(sourcefile, __LINE__))
- end if
- if ( trim(stream_mapalgo_exice) /= 'none' ) then
- call endrun(msg=' ERROR stream_mapalgo_exice can only be none for the MCT driver'//errMsg(sourcefile, __LINE__))
- end if
- endif
-
-end subroutine ReadNML
-
-end module ExcessIceStreamType
diff --git a/src/cpl/mct/FireDataBaseType.F90 b/src/cpl/mct/FireDataBaseType.F90
deleted file mode 100644
index 0ee635b2fa..0000000000
--- a/src/cpl/mct/FireDataBaseType.F90
+++ /dev/null
@@ -1,561 +0,0 @@
-module FireDataBaseType
-
-#include "shr_assert.h"
-
- !-----------------------------------------------------------------------
- ! !DESCRIPTION:
- ! module for handling of fire data
- !
- ! !USES:
- use shr_kind_mod , only : r8 => shr_kind_r8, CL => shr_kind_CL
- use shr_strdata_mod , only : shr_strdata_type, shr_strdata_create, shr_strdata_print
- use shr_strdata_mod , only : shr_strdata_advance
- use shr_log_mod , only : errMsg => shr_log_errMsg
- use clm_varctl , only : iulog, inst_name
- use spmdMod , only : masterproc, mpicom, comp_id
- use fileutils , only : getavu, relavu
- use domainMod , only : ldomain
- use abortutils , only : endrun
- use decompMod , only : bounds_type
- use FireMethodType , only : fire_method_type
- use lnd_set_decomp_and_domain, only : gsmap_global
- use mct_mod
- !
- implicit none
- private
- !
- ! !PUBLIC TYPES:
- public :: fire_base_type
-
- !
- type, abstract, extends(fire_method_type) :: fire_base_type
- private
- ! !PRIVATE MEMBER DATA:
-
- real(r8), public, pointer :: forc_lnfm(:) ! Lightning frequency
- real(r8), public, pointer :: forc_hdm(:) ! Human population density
-
- real(r8), public, pointer :: gdp_lf_col(:) ! col global real gdp data (k US$/capita)
- real(r8), public, pointer :: peatf_lf_col(:) ! col global peatland fraction data (0-1)
- integer , public, pointer :: abm_lf_col(:) ! col global peak month of crop fire emissions
-
- type(shr_strdata_type) :: sdat_hdm ! Human population density input data stream
- type(shr_strdata_type) :: sdat_lnfm ! Lightning input data stream
-
- contains
- !
- ! !PUBLIC MEMBER FUNCTIONS:
- procedure, public :: FireInit => BaseFireInit ! Initialization of Fire
- procedure, public :: BaseFireInit ! Initialization of Fire
- procedure(FireReadNML_interface), public, deferred :: FireReadNML ! Read in namelist for Fire
- procedure, public :: FireInterp ! Interpolate fire data
- procedure(need_lightning_and_popdens_interface), public, deferred :: &
- need_lightning_and_popdens ! Returns true if need lightning & popdens
- !
- ! !PRIVATE MEMBER FUNCTIONS:
- procedure, private :: hdm_init ! position datasets for dynamic human population density
- procedure, private :: hdm_interp ! interpolates between two years of human pop. density file data
- procedure, private :: lnfm_init ! position datasets for Lightning
- procedure, private :: lnfm_interp ! interpolates between two years of Lightning file data
- procedure, private :: surfdataread ! read fire related data from surface data set
- end type fire_base_type
- !-----------------------------------------------------------------------
-
- abstract interface
- !-----------------------------------------------------------------------
- function need_lightning_and_popdens_interface(this) result(need_lightning_and_popdens)
- !
- ! !DESCRIPTION:
- ! Returns true if need lightning and popdens, false otherwise
- !
- ! USES
- import :: fire_base_type
- !
- ! !ARGUMENTS:
- class(fire_base_type), intent(in) :: this
- logical :: need_lightning_and_popdens ! function result
- !-----------------------------------------------------------------------
- end function need_lightning_and_popdens_interface
- end interface
-
- character(len=*), parameter, private :: sourcefile = &
- __FILE__
-
-contains
-
- !-----------------------------------------------------------------------
- subroutine FireReadNML_interface( this, NLFilename )
- !
- ! !DESCRIPTION:
- ! Read the namelist for Fire
- !
- ! !USES:
- !
- ! !ARGUMENTS:
- class(fire_base_type) :: this
- character(len=*), intent(in) :: NLFilename ! Namelist filename
- end subroutine FireReadNML_interface
-
- !-----------------------------------------------------------------------
- subroutine BaseFireInit( this, bounds, NLFilename )
- !
- ! !DESCRIPTION:
- ! Initialize CN Fire module
- ! !USES:
- use shr_infnan_mod , only : nan => shr_infnan_nan, assignment(=)
- !
- ! !ARGUMENTS:
- class(fire_base_type) :: this
- type(bounds_type), intent(in) :: bounds
- character(len=*), intent(in) :: NLFilename
- !-----------------------------------------------------------------------
-
- if ( this%need_lightning_and_popdens() ) then
- ! Allocate lightning forcing data
- allocate( this%forc_lnfm(bounds%begg:bounds%endg) )
- this%forc_lnfm(bounds%begg:) = nan
- ! Allocate pop dens forcing data
- allocate( this%forc_hdm(bounds%begg:bounds%endg) )
- this%forc_hdm(bounds%begg:) = nan
-
- ! Allocate real gdp data
- allocate(this%gdp_lf_col(bounds%begc:bounds%endc))
- ! Allocate peatland fraction data
- allocate(this%peatf_lf_col(bounds%begc:bounds%endc))
- ! Allocates peak month of crop fire emissions
- allocate(this%abm_lf_col(bounds%begc:bounds%endc))
-
-
- call this%hdm_init(bounds, NLFilename)
- call this%hdm_interp(bounds)
- call this%lnfm_init(bounds, NLFilename)
- call this%lnfm_interp(bounds)
- call this%surfdataread(bounds)
- end if
-
- end subroutine BaseFireInit
-
- !-----------------------------------------------------------------------
- subroutine FireInterp(this,bounds)
- !
- ! !DESCRIPTION:
- ! Interpolate CN Fire datasets
- !
- ! !ARGUMENTS:
- class(fire_base_type) :: this
- type(bounds_type), intent(in) :: bounds
- !-----------------------------------------------------------------------
-
- if ( this%need_lightning_and_popdens() ) then
- call this%hdm_interp(bounds)
- call this%lnfm_interp(bounds)
- end if
-
- end subroutine FireInterp
-
- !-----------------------------------------------------------------------
- subroutine hdm_init( this, bounds, NLFilename )
- !
- ! !DESCRIPTION:
- ! Initialize data stream information for population density.
- !
- ! !USES:
- use clm_time_manager , only : get_calendar
- use ncdio_pio , only : pio_subsystem
- use shr_pio_mod , only : shr_pio_getiotype
- use clm_nlUtilsMod , only : find_nlgroup_name
- use ndepStreamMod , only : clm_domain_mct
- use histFileMod , only : hist_addfld1d
- !
- ! !ARGUMENTS:
- implicit none
- class(fire_base_type) :: this
- type(bounds_type), intent(in) :: bounds
- character(len=*), intent(in) :: NLFilename ! Namelist filename
- !
- ! !LOCAL VARIABLES:
- integer :: stream_year_first_popdens ! first year in pop. dens. stream to use
- integer :: stream_year_last_popdens ! last year in pop. dens. stream to use
- integer :: model_year_align_popdens ! align stream_year_first_hdm with
- integer :: nu_nml ! unit for namelist file
- integer :: nml_error ! namelist i/o error flag
- type(mct_ggrid) :: dom_clm ! domain information
- character(len=CL) :: stream_fldFileName_popdens ! population density streams filename
- character(len=CL) :: popdensmapalgo = 'bilinear' ! mapping alogrithm for population density
- character(len=CL) :: popdens_tintalgo = 'nearest'! time interpolation alogrithm for population density
- character(len=CL) :: stream_meshfile_popdens ! not used
- character(*), parameter :: subName = "('hdmdyn_init')"
- character(*), parameter :: F00 = "('(hdmdyn_init) ',4a)"
- !-----------------------------------------------------------------------
-
- namelist /popd_streams/ &
- stream_year_first_popdens, &
- stream_year_last_popdens, &
- model_year_align_popdens, &
- popdensmapalgo, &
- stream_fldFileName_popdens, &
- stream_meshfile_popdens , &
- popdens_tintalgo
-
- ! Default values for namelist
- stream_year_first_popdens = 1 ! first year in stream to use
- stream_year_last_popdens = 1 ! last year in stream to use
- model_year_align_popdens = 1 ! align stream_year_first_popdens with this model year
- stream_fldFileName_popdens = ' '
-
- ! Read popd_streams namelist
- if (masterproc) then
- nu_nml = getavu()
- open( nu_nml, file=trim(NLFilename), status='old', iostat=nml_error )
- call find_nlgroup_name(nu_nml, 'popd_streams', status=nml_error)
- if (nml_error == 0) then
- read(nu_nml, nml=popd_streams,iostat=nml_error)
- if (nml_error /= 0) then
- call endrun(msg='ERROR reading popd_streams namelist'//errMsg(sourcefile, __LINE__))
- end if
- end if
- close(nu_nml)
- call relavu( nu_nml )
- endif
-
- call shr_mpi_bcast(stream_year_first_popdens, mpicom)
- call shr_mpi_bcast(stream_year_last_popdens, mpicom)
- call shr_mpi_bcast(model_year_align_popdens, mpicom)
- call shr_mpi_bcast(stream_fldFileName_popdens, mpicom)
- call shr_mpi_bcast(popdens_tintalgo, mpicom)
-
- if (masterproc) then
- write(iulog,*) ' '
- write(iulog,*) 'popdens_streams settings:'
- write(iulog,*) ' stream_year_first_popdens = ',stream_year_first_popdens
- write(iulog,*) ' stream_year_last_popdens = ',stream_year_last_popdens
- write(iulog,*) ' model_year_align_popdens = ',model_year_align_popdens
- write(iulog,*) ' stream_fldFileName_popdens = ',stream_fldFileName_popdens
- write(iulog,*) ' popdens_tintalgo = ',popdens_tintalgo
- write(iulog,*) ' '
- endif
-
- call clm_domain_mct (bounds, dom_clm)
-
- call shr_strdata_create(this%sdat_hdm,name="clmhdm", &
- pio_subsystem=pio_subsystem, &
- pio_iotype=shr_pio_getiotype(inst_name), &
- mpicom=mpicom, compid=comp_id, &
- gsmap=gsmap_global, ggrid=dom_clm, &
- nxg=ldomain%ni, nyg=ldomain%nj, &
- yearFirst=stream_year_first_popdens, &
- yearLast=stream_year_last_popdens, &
- yearAlign=model_year_align_popdens, &
- offset=0, &
- domFilePath='', &
- domFileName=trim(stream_fldFileName_popdens), &
- domTvarName='time', &
- domXvarName='lon' , &
- domYvarName='lat' , &
- domAreaName='area', &
- domMaskName='mask', &
- filePath='', &
- filename=(/trim(stream_fldFileName_popdens)/) , &
- fldListFile='hdm', &
- fldListModel='hdm', &
- fillalgo='none', &
- mapalgo=popdensmapalgo, &
- calendar=get_calendar(), &
- tintalgo=popdens_tintalgo, &
- taxmode='extend' )
-
- if (masterproc) then
- call shr_strdata_print(this%sdat_hdm,'population density data')
- endif
-
- ! Add history fields
- call hist_addfld1d (fname='HDM', units='counts/km^2', &
- avgflag='A', long_name='human population density', &
- ptr_lnd=this%forc_hdm, default='inactive')
-
- end subroutine hdm_init
-
- !-----------------------------------------------------------------------
- subroutine hdm_interp( this, bounds)
- !
- ! !DESCRIPTION:
- ! Interpolate data stream information for population density.
- !
- ! !USES:
- use clm_time_manager, only : get_curr_date
- !
- ! !ARGUMENTS:
- class(fire_base_type) :: this
- type(bounds_type), intent(in) :: bounds
- !
- ! !LOCAL VARIABLES:
- integer :: g, ig
- integer :: year ! year (0, ...) for nstep+1
- integer :: mon ! month (1, ..., 12) for nstep+1
- integer :: day ! day of month (1, ..., 31) for nstep+1
- integer :: sec ! seconds into current date for nstep+1
- integer :: mcdate ! Current model date (yyyymmdd)
- !-----------------------------------------------------------------------
-
- call get_curr_date(year, mon, day, sec)
- mcdate = year*10000 + mon*100 + day
-
- call shr_strdata_advance(this%sdat_hdm, mcdate, sec, mpicom, 'hdmdyn')
-
- ig = 0
- do g = bounds%begg,bounds%endg
- ig = ig+1
- this%forc_hdm(g) = this%sdat_hdm%avs(1)%rAttr(1,ig)
- end do
-
- end subroutine hdm_interp
-
- !-----------------------------------------------------------------------
- subroutine lnfm_init( this, bounds, NLFilename )
- !
- ! !DESCRIPTION:
- !
- ! Initialize data stream information for Lightning.
- !
- ! !USES:
- use clm_time_manager , only : get_calendar
- use ncdio_pio , only : pio_subsystem
- use shr_pio_mod , only : shr_pio_getiotype
- use clm_nlUtilsMod , only : find_nlgroup_name
- use ndepStreamMod , only : clm_domain_mct
- use histFileMod , only : hist_addfld1d
- !
- ! !ARGUMENTS:
- implicit none
- class(fire_base_type) :: this
- type(bounds_type), intent(in) :: bounds
- character(len=*), intent(in) :: NLFilename
- !
- ! !LOCAL VARIABLES:
- integer :: stream_year_first_lightng ! first year in Lightning stream to use
- integer :: stream_year_last_lightng ! last year in Lightning stream to use
- integer :: model_year_align_lightng ! align stream_year_first_lnfm with
- integer :: nu_nml ! unit for namelist file
- integer :: nml_error ! namelist i/o error flag
- type(mct_ggrid) :: dom_clm ! domain information
- character(len=CL) :: stream_fldFileName_lightng ! lightning stream filename to read
- character(len=CL) :: lightng_tintalgo = 'linear'! time interpolation alogrithm
- character(len=CL) :: lightngmapalgo = 'bilinear'! Mapping alogrithm
- character(*), parameter :: subName = "('lnfmdyn_init')"
- character(*), parameter :: F00 = "('(lnfmdyn_init) ',4a)"
- !-----------------------------------------------------------------------
-
- namelist /light_streams/ &
- stream_year_first_lightng, &
- stream_year_last_lightng, &
- model_year_align_lightng, &
- lightngmapalgo, &
- stream_fldFileName_lightng, &
- lightng_tintalgo
-
- ! Default values for namelist
- stream_year_first_lightng = 1 ! first year in stream to use
- stream_year_last_lightng = 1 ! last year in stream to use
- model_year_align_lightng = 1 ! align stream_year_first_lnfm with this model year
- stream_fldFileName_lightng = ' '
-
- ! Read light_streams namelist
- if (masterproc) then
- nu_nml = getavu()
- open( nu_nml, file=trim(NLFilename), status='old', iostat=nml_error )
- call find_nlgroup_name(nu_nml, 'light_streams', status=nml_error)
- if (nml_error == 0) then
- read(nu_nml, nml=light_streams,iostat=nml_error)
- if (nml_error /= 0) then
- call endrun(msg='ERROR reading light_streams namelist'//errMsg(sourcefile, __LINE__))
- end if
- end if
- close(nu_nml)
- call relavu( nu_nml )
- endif
-
- call shr_mpi_bcast(stream_year_first_lightng, mpicom)
- call shr_mpi_bcast(stream_year_last_lightng, mpicom)
- call shr_mpi_bcast(model_year_align_lightng, mpicom)
- call shr_mpi_bcast(stream_fldFileName_lightng, mpicom)
- call shr_mpi_bcast(lightng_tintalgo, mpicom)
-
- if (masterproc) then
- write(iulog,*) ' '
- write(iulog,*) 'light_stream settings:'
- write(iulog,*) ' stream_year_first_lightng = ',stream_year_first_lightng
- write(iulog,*) ' stream_year_last_lightng = ',stream_year_last_lightng
- write(iulog,*) ' model_year_align_lightng = ',model_year_align_lightng
- write(iulog,*) ' stream_fldFileName_lightng = ',stream_fldFileName_lightng
- write(iulog,*) ' lightng_tintalgo = ',lightng_tintalgo
- write(iulog,*) ' '
- endif
-
- call clm_domain_mct (bounds, dom_clm)
-
- call shr_strdata_create(this%sdat_lnfm,name="clmlnfm", &
- pio_subsystem=pio_subsystem, &
- pio_iotype=shr_pio_getiotype(inst_name), &
- mpicom=mpicom, compid=comp_id, &
- gsmap=gsmap_global, ggrid=dom_clm, &
- nxg=ldomain%ni, nyg=ldomain%nj, &
- yearFirst=stream_year_first_lightng, &
- yearLast=stream_year_last_lightng, &
- yearAlign=model_year_align_lightng, &
- offset=0, &
- domFilePath='', &
- domFileName=trim(stream_fldFileName_lightng), &
- domTvarName='time', &
- domXvarName='lon' , &
- domYvarName='lat' , &
- domAreaName='area', &
- domMaskName='mask', &
- filePath='', &
- filename=(/trim(stream_fldFileName_lightng)/), &
- fldListFile='lnfm', &
- fldListModel='lnfm', &
- fillalgo='none', &
- tintalgo=lightng_tintalgo, &
- mapalgo=lightngmapalgo, &
- calendar=get_calendar(), &
- taxmode='cycle' )
-
- if (masterproc) then
- call shr_strdata_print(this%sdat_lnfm,'Lightning data')
- endif
-
- ! Add history fields
- call hist_addfld1d (fname='LNFM', units='counts/km^2/hr', &
- avgflag='A', long_name='Lightning frequency', &
- ptr_lnd=this%forc_lnfm, default='inactive')
-
- end subroutine lnfm_init
-
- !-----------------------------------------------------------------------
- subroutine lnfm_interp(this, bounds )
- !
- ! !DESCRIPTION:
- ! Interpolate data stream information for Lightning.
- !
- ! !USES:
- use clm_time_manager, only : get_curr_date
- !
- ! !ARGUMENTS:
- class(fire_base_type) :: this
- type(bounds_type), intent(in) :: bounds
- !
- ! !LOCAL VARIABLES:
- integer :: g, ig
- integer :: year ! year (0, ...) for nstep+1
- integer :: mon ! month (1, ..., 12) for nstep+1
- integer :: day ! day of month (1, ..., 31) for nstep+1
- integer :: sec ! seconds into current date for nstep+1
- integer :: mcdate ! Current model date (yyyymmdd)
- !-----------------------------------------------------------------------
-
- call get_curr_date(year, mon, day, sec)
- mcdate = year*10000 + mon*100 + day
-
- call shr_strdata_advance(this%sdat_lnfm, mcdate, sec, mpicom, 'lnfmdyn')
-
- ig = 0
- do g = bounds%begg,bounds%endg
- ig = ig+1
- this%forc_lnfm(g) = this%sdat_lnfm%avs(1)%rAttr(1,ig)
- end do
-
- end subroutine lnfm_interp
-
- !-----------------------------------------------------------------------
- subroutine surfdataread(this, bounds)
- !
- ! !DESCRIPTION:
- ! Read surface data set to populate relevant fire-related variables
- !
- ! !USES:
- use spmdMod , only : masterproc
- use clm_varctl , only : nsrest, nsrStartup, fsurdat
- use clm_varcon , only : grlnd
- use ColumnType , only : col
- use fileutils , only : getfil
- use ncdio_pio
- !
- ! !ARGUMENTS:
- class(fire_base_type) :: this
- type(bounds_type), intent(in) :: bounds
- !
- ! !LOCAL VARIABLES:
- integer :: g,c ! indices
- type(file_desc_t) :: ncid ! netcdf id
- logical :: readvar ! true => variable is on initial dataset
- character(len=256) :: locfn ! local filename
- real(r8), pointer :: gdp(:) ! global gdp data (needs to be a pointer for use in ncdio)
- real(r8), pointer :: peatf(:) ! global peatf data (needs to be a pointer for use in ncdio)
- integer, pointer :: abm(:) ! global abm data (needs to be a pointer for use in ncdio)
- !-----------------------------------------------------------------------
-
- ! --------------------------------------------------------------------
- ! Open surface dataset
- ! --------------------------------------------------------------------
-
- call getfil (fsurdat, locfn, 0)
- call ncd_pio_openfile (ncid, locfn, 0)
-
- ! --------------------------------------------------------------------
- ! Read in GDP data
- ! --------------------------------------------------------------------
-
- allocate(gdp(bounds%begg:bounds%endg))
- call ncd_io(ncid=ncid, varname='gdp', flag='read', data=gdp, dim1name=grlnd, readvar=readvar)
- if (.not. readvar) then
- call endrun(msg=' ERROR: gdp NOT on surfdata file'//errMsg(sourcefile, __LINE__))
- end if
- do c = bounds%begc, bounds%endc
- g = col%gridcell(c)
- this%gdp_lf_col(c) = gdp(g)
- end do
- deallocate(gdp)
-
- ! --------------------------------------------------------------------
- ! Read in peatf data
- ! --------------------------------------------------------------------
-
- allocate(peatf(bounds%begg:bounds%endg))
- call ncd_io(ncid=ncid, varname='peatf', flag='read', data=peatf, dim1name=grlnd, readvar=readvar)
- if (.not. readvar) then
- call endrun(msg=' ERROR: peatf NOT on surfdata file'//errMsg(sourcefile, __LINE__))
- end if
- do c = bounds%begc, bounds%endc
- g = col%gridcell(c)
- this%peatf_lf_col(c) = peatf(g)
- end do
- deallocate(peatf)
-
- ! --------------------------------------------------------------------
- ! Read in ABM data
- ! --------------------------------------------------------------------
-
- allocate(abm(bounds%begg:bounds%endg))
- call ncd_io(ncid=ncid, varname='abm', flag='read', data=abm, dim1name=grlnd, readvar=readvar)
- if (.not. readvar) then
- call endrun(msg=' ERROR: abm NOT on surfdata file'//errMsg(sourcefile, __LINE__))
- end if
- do c = bounds%begc, bounds%endc
- g = col%gridcell(c)
- this%abm_lf_col(c) = abm(g)
- end do
- deallocate(abm)
-
- ! Close file
-
- call ncd_pio_closefile(ncid)
-
- if (masterproc) then
- write(iulog,*) 'Successfully read fmax, soil color, sand and clay boundary data'
- write(iulog,*)
- endif
-
- end subroutine surfdataread
-
-
-end module FireDataBaseType
diff --git a/src/cpl/mct/SoilMoistureStreamMod.F90 b/src/cpl/mct/SoilMoistureStreamMod.F90
deleted file mode 100644
index 8b366d6c8e..0000000000
--- a/src/cpl/mct/SoilMoistureStreamMod.F90
+++ /dev/null
@@ -1,418 +0,0 @@
-module SoilMoistureStreamMod
-
- ! **********************************************************************
- ! --------------------------- IMPORTANT NOTE ---------------------------
- !
- ! In cases using the NUOPC driver/mediator, we use a different version of this module,
- ! based on CDEPS, which resides in src/cpl/nuopc/. Changes to the science here should
- ! also be made in the similar file in src/cpl/nuopc. Once we start using CDEPS by
- ! default, we can remove this version and move the CDEPS-based version into its place.
- ! **********************************************************************
-
-#include "shr_assert.h"
-
- !-----------------------------------------------------------------------
- ! !DESCRIPTION:
- ! Read in soil moisture from data stream
- !
- ! !USES:
- use shr_strdata_mod , only : shr_strdata_type, shr_strdata_create
- use shr_strdata_mod , only : shr_strdata_print, shr_strdata_advance
- use shr_kind_mod , only : r8 => shr_kind_r8
- use shr_kind_mod , only : CL => shr_kind_CL, CXX => shr_kind_CXX
- use shr_log_mod , only : errMsg => shr_log_errMsg
- use decompMod , only : bounds_type, subgrid_level_column
- use abortutils , only : endrun
- use clm_varctl , only : iulog, use_soil_moisture_streams, inst_name
- use clm_varcon , only : grlnd
- use controlMod , only : NLFilename
- use domainMod , only : ldomain
- use LandunitType , only : lun
- use ColumnType , only : col
- use SoilStateType , only : soilstate_type
- use WaterStateBulkType , only : waterstatebulk_type
- use perf_mod , only : t_startf, t_stopf
- use spmdMod , only : masterproc, mpicom, comp_id
- use lnd_set_decomp_and_domain , only : gsMap_lnd2Dsoi_gdc2glo
- use mct_mod
- use ncdio_pio
- !
- ! !PUBLIC TYPES:
- implicit none
- private
- !
- ! !PUBLIC MEMBER FUNCTIONS:
- public :: PrescribedSoilMoistureInit ! position datasets for soil moisture
- public :: PrescribedSoilMoistureAdvance ! Advance the soil moisture stream (outside of Open-MP loops)
- public :: PrescribedSoilMoistureInterp ! interpolates between two periods of soil moisture data
-
- ! !PRIVATE MEMBER DATA:
- type(shr_strdata_type) :: sdat_soilm ! soil moisture input data stream
- integer :: ism ! Soil moisture steram index
- integer, allocatable :: g_to_ig(:) ! Array matching gridcell index to data index
- logical :: soilm_ignore_data_if_missing ! If should ignore overridding a point with soil moisture data
- ! from the streams file, if the streams file shows that point
- ! as missing (namelist item)
- !
- ! !PRIVATE TYPES:
-
- character(len=*), parameter, private :: sourcefile = &
- __FILE__
- !-----------------------------------------------------------------------
-
-contains
-
- !-----------------------------------------------------------------------
- !
- ! soil_moisture_init
- !
- !-----------------------------------------------------------------------
- subroutine PrescribedSoilMoistureInit(bounds)
- !
- ! Initialize data stream information for soil moisture.
- !
- !
- ! !USES:
- use clm_time_manager , only : get_calendar
- use ncdio_pio , only : pio_subsystem
- use shr_pio_mod , only : shr_pio_getiotype
- use clm_nlUtilsMod , only : find_nlgroup_name
- use ndepStreamMod , only : clm_domain_mct
- use shr_stream_mod , only : shr_stream_file_null
- use shr_string_mod , only : shr_string_listCreateField
- use clm_varpar , only : nlevsoi
- !
- ! !ARGUMENTS:
- implicit none
- type(bounds_type), intent(in) :: bounds ! bounds
- !
- ! !LOCAL VARIABLES:
- integer :: i ! index
- integer :: stream_year_first_soilm ! first year in Ustar stream to use
- integer :: stream_year_last_soilm ! last year in Ustar stream to use
- integer :: model_year_align_soilm ! align stream_year_first_soilm with
- integer :: nu_nml ! unit for namelist file
- integer :: nml_error ! namelist i/o error flag
- integer :: soilm_offset ! Offset in time for dataset (sec)
- type(mct_ggrid) :: dom_clm ! domain information
- character(len=CL) :: stream_fldfilename_soilm ! ustar stream filename to read
- character(len=CL) :: soilm_tintalgo = 'linear' ! Time interpolation alogrithm
-
- character(*), parameter :: subName = "('PrescribedSoilMoistureInit')"
- character(*), parameter :: F00 = "('(PrescribedSoilMoistureInit) ',4a)"
- character(*), parameter :: soilmString = "H2OSOI" ! base string for field string
- character(CXX) :: fldList ! field string
- !-----------------------------------------------------------------------
- !
- ! deal with namelist variables here in init
- !
- namelist /soil_moisture_streams/ &
- stream_year_first_soilm, &
- stream_year_last_soilm, &
- model_year_align_soilm, &
- soilm_tintalgo, &
- soilm_offset, &
- soilm_ignore_data_if_missing, &
- stream_fldfilename_soilm
-
- ! Default values for namelist
- stream_year_first_soilm = 1 ! first year in stream to use
- stream_year_last_soilm = 1 ! last year in stream to use
- model_year_align_soilm = 1 ! align stream_year_first_soilm with this model year
- stream_fldfilename_soilm = shr_stream_file_null
- soilm_offset = 0
- soilm_ignore_data_if_missing = .false.
-
- ! Read soilm_streams namelist
- if (masterproc) then
- open( newunit=nu_nml, file=trim(NLFilename), status='old', iostat=nml_error )
- call find_nlgroup_name(nu_nml, 'soil_moisture_streams', status=nml_error)
- if (nml_error == 0) then
- read(nu_nml, nml=soil_moisture_streams,iostat=nml_error)
- if (nml_error /= 0) then
- call endrun(subname // ':: ERROR reading soil_moisture_streams namelist')
- end if
- else
- call endrun(subname // ':: ERROR finding soilm_streams namelist')
- end if
- close(nu_nml)
- endif
-
- call shr_mpi_bcast(stream_year_first_soilm, mpicom)
- call shr_mpi_bcast(stream_year_last_soilm, mpicom)
- call shr_mpi_bcast(model_year_align_soilm, mpicom)
- call shr_mpi_bcast(stream_fldfilename_soilm, mpicom)
- call shr_mpi_bcast(soilm_tintalgo, mpicom)
- call shr_mpi_bcast(soilm_offset, mpicom)
- call shr_mpi_bcast(soilm_ignore_data_if_missing, mpicom)
-
- if (masterproc) then
-
- write(iulog,*) ' '
- write(iulog,*) 'soil_moisture_stream settings:'
- write(iulog,*) ' stream_year_first_soilm = ',stream_year_first_soilm
- write(iulog,*) ' stream_year_last_soilm = ',stream_year_last_soilm
- write(iulog,*) ' model_year_align_soilm = ',model_year_align_soilm
- write(iulog,*) ' stream_fldfilename_soilm = ',trim(stream_fldfilename_soilm)
- write(iulog,*) ' soilm_tintalgo = ',trim(soilm_tintalgo)
- write(iulog,*) ' soilm_offset = ',soilm_offset
- if ( soilm_ignore_data_if_missing )then
- write(iulog,*) ' Do NOT override a point with streams data if the streams data is missing'
- else
- write(iulog,*) ' Abort, if you find a model point where the input streams data is set to missing value'
- end if
-
- endif
-
- call clm_domain_mct (bounds, dom_clm, nlevels=nlevsoi)
-
- ! create the field list for these fields...use in shr_strdata_create
- fldList = trim(soilmString)
- if (masterproc) write(iulog,*) 'fieldlist: ', trim(fldList)
-
- call shr_strdata_create(sdat_soilm,name="soil_moisture", &
- pio_subsystem=pio_subsystem, &
- pio_iotype=shr_pio_getiotype(inst_name), &
- mpicom=mpicom, compid=comp_id, &
- gsmap=gsMap_lnd2Dsoi_gdc2glo, ggrid=dom_clm, &
- nxg=ldomain%ni, nyg=ldomain%nj, &
- nzg=nlevsoi, &
- yearFirst=stream_year_first_soilm, &
- yearLast=stream_year_last_soilm, &
- yearAlign=model_year_align_soilm, &
- offset=soilm_offset, &
- domFilePath='', &
- domFileName=trim(stream_fldFileName_soilm), &
- domTvarName='time', &
- domXvarName='lon' , &
- domYvarName='lat' , &
- domZvarName='levsoi' , &
- domAreaName='area', &
- domMaskName='mask', &
- filePath='', &
- filename=(/stream_fldFileName_soilm/), &
- fldListFile=fldList, &
- fldListModel=fldList, &
- fillalgo='none', &
- mapalgo='none', &
- tintalgo=soilm_tintalgo, &
- calendar=get_calendar(), &
- dtlimit = 15._r8, &
- taxmode='cycle' )
-
- if (masterproc) then
- call shr_strdata_print(sdat_soilm,'soil moisture data')
- endif
-
- end subroutine PrescribedSoilMoistureInit
-
-
- !-----------------------------------------------------------------------
- !
- ! PrescribedSoilMoistureAdvance
- !
- !-----------------------------------------------------------------------
- subroutine PrescribedSoilMoistureAdvance( bounds )
- !
- ! Advanace the prescribed soil moisture stream
- !
- ! !USES:
- use clm_time_manager, only : get_curr_date
- !
- ! !ARGUMENTS:
- type(bounds_type) , intent(in) :: bounds
- !
- ! !LOCAL VARIABLES:
- character(len=CL) :: stream_var_name
- integer :: g, ig
- integer :: ier ! error code
- integer :: year ! year (0, ...) for nstep+1
- integer :: mon ! month (1, ..., 12) for nstep+1
- integer :: day ! day of month (1, ..., 31) for nstep+1
- integer :: sec ! seconds into current date for nstep+1
- integer :: mcdate ! Current model date (yyyymmdd)
-
- call get_curr_date(year, mon, day, sec)
- mcdate = year*10000 + mon*100 + day
-
- stream_var_name = 'H2OSOI'
-
- ! Determine variable index
- ism = mct_aVect_indexRA(sdat_soilm%avs(1),trim(stream_var_name))
-
- call shr_strdata_advance(sdat_soilm, mcdate, sec, mpicom, trim(stream_var_name))
-
- ! Map gridcell to AV index
- ier = 0
- if ( .not. allocated(g_to_ig) )then
- allocate (g_to_ig(bounds%begg:bounds%endg), stat=ier)
- if (ier /= 0) then
- write(iulog,*) 'Prescribed soil moisture allocation error'
- call endrun(msg=errMsg(sourcefile, __LINE__))
- end if
-
- ig = 0
- do g = bounds%begg,bounds%endg
- ig = ig+1
- g_to_ig(g) = ig
- end do
- end if
-
- end subroutine PrescribedSoilMoistureAdvance
-
- !-----------------------------------------------------------------------
- !
- ! PrescribedSoilMoistureInterp
- !
- !-----------------------------------------------------------------------
- subroutine PrescribedSoilMoistureInterp(bounds, soilstate_inst, &
- waterstatebulk_inst)
- !
- ! Assign data stream information for prescribed soil moisture.
- !
- ! !USES:
- use clm_time_manager, only : get_curr_date
- use clm_varpar , only : nlevsoi
- use clm_varcon , only : denh2o, denice, watmin, spval
- use landunit_varcon , only : istsoil, istcrop
- !
- ! !ARGUMENTS:
- implicit none
- type(bounds_type) , intent(in) :: bounds
- type(soilstate_type) , intent(in) :: soilstate_inst
- type(waterstatebulk_type) , intent(inout) :: waterstatebulk_inst
- !
- ! !LOCAL VARIABLES:
- integer :: c, g, j, ig, n
- real(r8) :: soilm_liq_frac ! liquid fraction of soil moisture
- real(r8) :: soilm_ice_frac ! ice fraction of soil moisture
- real(r8) :: moisture_increment ! soil moisture adjustment increment
- real(r8) :: h2osoi_vol_initial ! initial vwc value
- character(*), parameter :: subName = "('PrescribedSoilMoistureInterp')"
-
- !-----------------------------------------------------------------------
-
- SHR_ASSERT_FL( (lbound(sdat_soilm%avs(1)%rAttr,1) == ism ), sourcefile, __LINE__)
- SHR_ASSERT_FL( (ubound(sdat_soilm%avs(1)%rAttr,1) == ism ), sourcefile, __LINE__)
- SHR_ASSERT_FL( (lbound(g_to_ig,1) <= bounds%begg ), sourcefile, __LINE__)
- SHR_ASSERT_FL( (ubound(g_to_ig,1) >= bounds%endg ), sourcefile, __LINE__)
- SHR_ASSERT_FL( (lbound(sdat_soilm%avs(1)%rAttr,2) <= g_to_ig(bounds%begg) ), sourcefile, __LINE__)
- SHR_ASSERT_FL( (ubound(sdat_soilm%avs(1)%rAttr,2) >= g_to_ig(bounds%endg)+(nlevsoi-1)*size(g_to_ig) ), sourcefile, __LINE__)
- associate( &
- dz => col%dz , & ! Input: [real(r8) (:,:) ] layer depth (m)
- watsat => soilstate_inst%watsat_col , & ! Input: [real(r8) (:,:) ] volumetric soil water at saturation (porosity)
- h2osoi_liq => waterstatebulk_inst%h2osoi_liq_col , & ! Input/Output: [real(r8) (:,:) ] liquid water (kg/m2)
- h2osoi_ice => waterstatebulk_inst%h2osoi_ice_col , & ! Input/Output: [real(r8) (:,:) ] ice water (kg/m2)
- h2osoi_vol => waterstatebulk_inst%h2osoi_vol_col , & ! Output: volumetric soil water (m3/m3)
- h2osoi_vol_prs => waterstatebulk_inst%h2osoi_vol_prs_grc & ! Output: prescribed volumetric soil water (m3/m3)
- )
- SHR_ASSERT_FL( (lbound(h2osoi_vol,1) <= bounds%begc ), sourcefile, __LINE__)
- SHR_ASSERT_FL( (ubound(h2osoi_vol,1) >= bounds%endc ), sourcefile, __LINE__)
- SHR_ASSERT_FL( (lbound(h2osoi_vol,2) == 1 ), sourcefile, __LINE__)
- SHR_ASSERT_FL( (ubound(h2osoi_vol,2) >= nlevsoi ), sourcefile, __LINE__)
- SHR_ASSERT_FL( (lbound(dz,1) <= bounds%begc ), sourcefile, __LINE__)
- SHR_ASSERT_FL( (ubound(dz,1) >= bounds%endc ), sourcefile, __LINE__)
- SHR_ASSERT_FL( (lbound(dz,2) <= 1 ), sourcefile, __LINE__)
- SHR_ASSERT_FL( (ubound(dz,2) >= nlevsoi ), sourcefile, __LINE__)
- SHR_ASSERT_FL( (lbound(watsat,1) <= bounds%begc ), sourcefile, __LINE__)
- SHR_ASSERT_FL( (ubound(watsat,1) >= bounds%endc ), sourcefile, __LINE__)
- SHR_ASSERT_FL( (lbound(watsat,2) <= 1 ), sourcefile, __LINE__)
- SHR_ASSERT_FL( (ubound(watsat,2) >= nlevsoi ), sourcefile, __LINE__)
- SHR_ASSERT_FL( (lbound(h2osoi_liq,1) <= bounds%begc ), sourcefile, __LINE__)
- SHR_ASSERT_FL( (ubound(h2osoi_liq,1) >= bounds%endc ), sourcefile, __LINE__)
- SHR_ASSERT_FL( (lbound(h2osoi_liq,2) <= 1 ), sourcefile, __LINE__)
- SHR_ASSERT_FL( (ubound(h2osoi_liq,2) >= nlevsoi ), sourcefile, __LINE__)
- SHR_ASSERT_FL( (lbound(h2osoi_ice,1) <= bounds%begc ), sourcefile, __LINE__)
- SHR_ASSERT_FL( (ubound(h2osoi_ice,1) >= bounds%endc ), sourcefile, __LINE__)
- SHR_ASSERT_FL( (lbound(h2osoi_ice,2) <= 1 ), sourcefile, __LINE__)
- SHR_ASSERT_FL( (ubound(h2osoi_ice,2) >= nlevsoi ), sourcefile, __LINE__)
- SHR_ASSERT_FL( (lbound(h2osoi_vol_prs,1) <= bounds%begg ), sourcefile, __LINE__)
- SHR_ASSERT_FL( (ubound(h2osoi_vol_prs,1) >= bounds%endg ), sourcefile, __LINE__)
- SHR_ASSERT_FL( (lbound(h2osoi_vol_prs,2) == 1 ), sourcefile, __LINE__)
- SHR_ASSERT_FL( (ubound(h2osoi_vol_prs,2) >= nlevsoi ), sourcefile, __LINE__)
- !
- ! Set the prescribed soil moisture read from the file everywhere
- !
- do g = bounds%begg, bounds%endg
- ig = g_to_ig(g)
- do j = 1, nlevsoi
-
- !n = ig + (j-1)*size(g_to_ig)
- n = ig + (j-1)*size(g_to_ig)
-
- h2osoi_vol_prs(g,j) = sdat_soilm%avs(1)%rAttr(ism,n)
-
- ! If soil moiture is being interpolated in time and the result is
- ! large that probably means one of the two data points is missing (set to spval)
- if ( h2osoi_vol_prs(g,j) > 10.0_r8 .and. (h2osoi_vol_prs(g,j) /= spval) )then
- h2osoi_vol_prs(g,j) = spval
- end if
-
- end do
- end do
-
- do c = bounds%begc, bounds%endc
- !
- ! Set variable for each gridcell/column combination
- !
- g = col%gridcell(c)
- ig = g_to_ig(g)
-
- ! EBK Jan/2020, also check weights on gridcell (See https://github.com/ESCOMP/CTSM/issues/847)
- if ( (lun%itype(col%landunit(c)) == istsoil) .or. (lun%itype(col%landunit(c)) == istcrop) .and. &
- (col%wtgcell(c) /= 0._r8) ) then
- ! this is a 2d field (gridcell/nlevsoi) !
- do j = 1, nlevsoi
-
- n = ig + (j-1)*size(g_to_ig)
-
- ! if soil water is zero, liq/ice fractions cannot be calculated
- if((h2osoi_liq(c, j) + h2osoi_ice(c, j)) > 0._r8) then
-
- ! save original soil moisture value
- h2osoi_vol_initial = h2osoi_vol(c,j)
-
- ! Check if the vegetated land mask from the dataset on the
- ! file is different
- if ( (h2osoi_vol_prs(g,j) == spval) .and. (h2osoi_vol_initial /= spval) )then
- if ( soilm_ignore_data_if_missing )then
- cycle
- else
- write(iulog,*) 'Input soil moisture dataset is not vegetated as expected: gridcell=', &
- g, ' active = ', col%active(c)
- call endrun(subgrid_index=c, subgrid_level=subgrid_level_column, &
- msg = subname // &
- ' ERROR:: The input soil moisture stream is NOT vegetated for one of the land points' )
- end if
- end if
-
- ! update volumetric soil moisture from data prescribed from the file
- h2osoi_vol(c,j) = h2osoi_vol_prs(g,j)
-
-
- ! calculate liq/ice mass fractions
- soilm_liq_frac = h2osoi_liq(c, j) /(h2osoi_liq(c, j) + h2osoi_ice(c, j))
- soilm_ice_frac = h2osoi_ice(c, j) /(h2osoi_liq(c, j) + h2osoi_ice(c, j))
-
- ! calculate moisture increment
- moisture_increment = h2osoi_vol(c,j) - h2osoi_vol_initial
- ! add limitation check
- moisture_increment = min((watsat(c,j) - h2osoi_vol_initial),max(-(h2osoi_vol_initial-watmin),moisture_increment))
-
- ! update liq/ice water mass due to (volumetric) moisture increment
- h2osoi_liq(c,j) = h2osoi_liq(c,j) + (soilm_liq_frac * moisture_increment * dz(c, j) * denh2o)
- h2osoi_ice(c,j) = h2osoi_ice(c,j) + (soilm_ice_frac * moisture_increment * dz(c, j) * denice)
-
- else
- call endrun(subgrid_index=c, subgrid_level=subgrid_level_column, &
- msg = subname // ':: ERROR h2osoil liquid plus ice is zero')
- endif
- enddo
- endif
- end do
-
- end associate
-
- end subroutine PrescribedSoilMoistureInterp
-
-end module SoilMoistureStreamMod
diff --git a/src/cpl/mct/UrbanTimeVarType.F90 b/src/cpl/mct/UrbanTimeVarType.F90
deleted file mode 100644
index 805ac47fbf..0000000000
--- a/src/cpl/mct/UrbanTimeVarType.F90
+++ /dev/null
@@ -1,314 +0,0 @@
-module UrbanTimeVarType
-
- !------------------------------------------------------------------------------
- ! !DESCRIPTION:
- ! Urban Time Varying Data
- !
- ! !USES:
- use shr_kind_mod , only : r8 => shr_kind_r8, CL => shr_kind_CL
- use shr_log_mod , only : errMsg => shr_log_errMsg
- use abortutils , only : endrun
- use decompMod , only : bounds_type, subgrid_level_landunit
- use clm_varctl , only : iulog, inst_name
- use landunit_varcon , only : isturb_MIN, isturb_MAX
- use clm_varcon , only : spval
- use LandunitType , only : lun
- use GridcellType , only : grc
- use mct_mod
- use shr_strdata_mod , only : shr_strdata_type
- !
- implicit none
- save
- private
- !
- !
-
- ! !PUBLIC TYPE
- type, public :: urbantv_type
-
- real(r8), public, pointer :: t_building_max(:) ! lun maximum internal building air temperature (K)
- type(shr_strdata_type) :: sdat_urbantv ! urban time varying input data stream
- contains
-
- ! !PUBLIC MEMBER FUNCTIONS:
- procedure, public :: Init ! Allocate and initialize urbantv
- procedure, public :: urbantv_init ! Initialize urban time varying stream
- procedure, public :: urbantv_interp ! Interpolate urban time varying stream
-
- end type urbantv_type
-
- !-----------------------------------------------------------------------
- character(15), private :: stream_var_name(isturb_MIN:isturb_MAX)
-
- character(len=*), parameter, private :: sourcefile = &
- __FILE__
-
-contains
-
- !-----------------------------------------------------------------------
- subroutine Init(this, bounds, NLFilename)
- !
- ! Allocate module variables and data structures
- !
- ! !USES:
- use shr_infnan_mod , only : nan => shr_infnan_nan, assignment(=)
- use histFileMod , only : hist_addfld1d
- !
- ! !ARGUMENTS:
- class(urbantv_type) :: this
- type(bounds_type) , intent(in) :: bounds
- character(len=*) , intent(in) :: NLFilename ! Namelist filename
- !
- ! !LOCAL VARIABLES:
- integer :: begl, endl
- !---------------------------------------------------------------------
-
- begl = bounds%begl; endl = bounds%endl
-
- ! Allocate urbantv data structure
-
- allocate(this%t_building_max (begl:endl)) ; this%t_building_max (:) = nan
-
- call this%urbantv_init(bounds, NLFilename)
- call this%urbantv_interp(bounds)
-
- ! Add history fields
- call hist_addfld1d (fname='TBUILD_MAX', units='K', &
- avgflag='A', long_name='prescribed maximum interior building temperature', &
- ptr_lunit=this%t_building_max, default='inactive', set_nourb=spval, &
- l2g_scale_type='unity')
-
-
- end subroutine Init
-
- !-----------------------------------------------------------------------
-
- !-----------------------------------------------------------------------
- subroutine urbantv_init(this, bounds, NLFilename)
- !
- ! !DESCRIPTION:
- ! Initialize data stream information for urban time varying data
- !
- ! !USES:
- use clm_time_manager , only : get_calendar
- use ncdio_pio , only : pio_subsystem
- use shr_pio_mod , only : shr_pio_getiotype
- use clm_nlUtilsMod , only : find_nlgroup_name
- use ndepStreamMod , only : clm_domain_mct
- use spmdMod , only : masterproc, mpicom, comp_id
- use fileutils , only : getavu, relavu
- use shr_mpi_mod , only : shr_mpi_bcast
- use shr_string_mod , only : shr_string_listAppend
- use shr_strdata_mod , only : shr_strdata_create, shr_strdata_print
- use domainMod , only : ldomain
- use shr_infnan_mod , only : nan => shr_infnan_nan, assignment(=)
- use landunit_varcon , only : isturb_TBD, isturb_HD, isturb_MD
- use lnd_set_decomp_and_domain , only : gsmap_global
- !
- ! !ARGUMENTS:
- implicit none
- class(urbantv_type) :: this
- type(bounds_type), intent(in) :: bounds
- character(len=*), intent(in) :: NLFilename ! Namelist filename
- !
- ! !LOCAL VARIABLES:
- integer :: begl, endl ! landunits
- integer :: ifield ! field index
- integer :: stream_year_first_urbantv ! first year in urban tv stream to use
- integer :: stream_year_last_urbantv ! last year in urban tv stream to use
- integer :: model_year_align_urbantv ! align stream_year_first_urbantv
- ! with this model year
- integer :: nu_nml ! unit for namelist file
- integer :: nml_error ! namelist i/o error flag
- type(mct_ggrid) :: dom_clm ! domain information
- character(len=CL) :: stream_fldFileName_urbantv ! urban tv streams filename
- character(len=CL) :: urbantvmapalgo = 'nn' ! mapping alogrithm for urban ac
- character(len=CL) :: urbantv_tintalgo = 'linear' ! time interpolation alogrithm
- character(len=CL) :: fldList ! field string
- character(*), parameter :: urbantvString = "tbuildmax_" ! base string for field string
- character(*), parameter :: subName = "('urbantv_init')"
- character(*), parameter :: F00 = "('(urbantv_init) ',4a)"
- !-----------------------------------------------------------------------
- namelist /urbantv_streams/ &
- stream_year_first_urbantv, &
- stream_year_last_urbantv, &
- model_year_align_urbantv, &
- urbantvmapalgo, &
- stream_fldFileName_urbantv, &
- urbantv_tintalgo
- !-----------------------------------------------------------------------
-
- begl = bounds%begl; endl = bounds%endl
-
- ! Default values for namelist
- stream_year_first_urbantv = 1 ! first year in stream to use
- stream_year_last_urbantv = 1 ! last year in stream to use
- model_year_align_urbantv = 1 ! align stream_year_first_urbantv with this model year
- stream_fldFileName_urbantv = ' '
-
- ! Read urbantv_streams namelist
- if (masterproc) then
- nu_nml = getavu()
- open( nu_nml, file=trim(NLFilename), status='old', iostat=nml_error )
- call find_nlgroup_name(nu_nml, 'urbantv_streams', status=nml_error)
- if (nml_error == 0) then
- read(nu_nml, nml=urbantv_streams,iostat=nml_error)
- if (nml_error /= 0) then
- call endrun(msg='ERROR reading urbantv_streams namelist'//errMsg(sourcefile, __LINE__))
- end if
- end if
- close(nu_nml)
- call relavu( nu_nml )
- endif
-
- call shr_mpi_bcast(stream_year_first_urbantv, mpicom)
- call shr_mpi_bcast(stream_year_last_urbantv, mpicom)
- call shr_mpi_bcast(model_year_align_urbantv, mpicom)
- call shr_mpi_bcast(stream_fldFileName_urbantv, mpicom)
- call shr_mpi_bcast(urbantv_tintalgo, mpicom)
-
- if (masterproc) then
- write(iulog,*) ' '
- write(iulog,*) 'urbantv_streams settings:'
- write(iulog,*) ' stream_year_first_urbantv = ',stream_year_first_urbantv
- write(iulog,*) ' stream_year_last_urbantv = ',stream_year_last_urbantv
- write(iulog,*) ' model_year_align_urbantv = ',model_year_align_urbantv
- write(iulog,*) ' stream_fldFileName_urbantv = ',stream_fldFileName_urbantv
- write(iulog,*) ' urbantv_tintalgo = ',urbantv_tintalgo
- write(iulog,*) ' '
- endif
-
- call clm_domain_mct (bounds, dom_clm)
-
- ! create the field list for these urbantv fields...use in shr_strdata_create
- stream_var_name(:) = "NOT_SET"
- stream_var_name(isturb_TBD) = urbantvString//"TBD"
- stream_var_name(isturb_HD) = urbantvString//"HD"
- stream_var_name(isturb_MD) = urbantvString//"MD"
- fldList = ""
- do ifield = isturb_MIN, isturb_MAX
- call shr_string_listAppend( fldList, stream_var_name(ifield) )
- end do
-
- call shr_strdata_create(this%sdat_urbantv,name="clmurbantv", &
- pio_subsystem=pio_subsystem, &
- pio_iotype=shr_pio_getiotype(inst_name), &
- mpicom=mpicom, compid=comp_id, &
- gsmap=gsmap_global, ggrid=dom_clm, &
- nxg=ldomain%ni, nyg=ldomain%nj, &
- yearFirst=stream_year_first_urbantv, &
- yearLast=stream_year_last_urbantv, &
- yearAlign=model_year_align_urbantv, &
- offset=0, &
- domFilePath='', &
- domFileName=trim(stream_fldFileName_urbantv), &
- domTvarName='time', &
- domXvarName='lon' , &
- domYvarName='lat' , &
- domAreaName='area', &
- domMaskName='LANDMASK', &
- filePath='', &
- filename=(/trim(stream_fldFileName_urbantv)/) , &
- fldListFile=fldList, &
- fldListModel=fldList, &
- fillalgo='none', &
- mapalgo=urbantvmapalgo, &
- calendar=get_calendar(), &
- tintalgo=urbantv_tintalgo, &
- taxmode='extend' )
-
- if (masterproc) then
- call shr_strdata_print(this%sdat_urbantv,'urban time varying data')
- endif
-
-
- end subroutine urbantv_init
-
- !-----------------------------------------------------------------------
- subroutine urbantv_interp(this, bounds)
- !
- ! !DESCRIPTION:
- ! Interpolate data stream information for urban time varying data.
- !
- ! !USES:
- use clm_time_manager, only : get_curr_date
- use spmdMod , only : mpicom
- use shr_strdata_mod , only : shr_strdata_advance
- use clm_instur , only : urban_valid
- !
- ! !ARGUMENTS:
- class(urbantv_type) :: this
- type(bounds_type), intent(in) :: bounds
- !
- ! !LOCAL VARIABLES:
- logical :: found
- integer :: l, glun, ig, g, ip
- integer :: year ! year (0, ...) for nstep+1
- integer :: mon ! month (1, ..., 12) for nstep+1
- integer :: day ! day of month (1, ..., 31) for nstep+1
- integer :: sec ! seconds into current date for nstep+1
- integer :: mcdate ! Current model date (yyyymmdd)
- integer :: lindx ! landunit index
- integer :: gindx ! gridcell index
- !-----------------------------------------------------------------------
-
- call get_curr_date(year, mon, day, sec)
- mcdate = year*10000 + mon*100 + day
-
- call shr_strdata_advance(this%sdat_urbantv, mcdate, sec, mpicom, 'urbantvdyn')
-
- do l = bounds%begl,bounds%endl
- if (lun%urbpoi(l)) then
- glun = lun%gridcell(l)
- ip = mct_aVect_indexRA(this%sdat_urbantv%avs(1),trim(stream_var_name(lun%itype(l))))
- !
- ! Determine vector index corresponding to glun
- !
- ig = 0
- do g = bounds%begg,bounds%endg
- ig = ig+1
- if (g == glun) exit
- end do
-
- this%t_building_max(l) = this%sdat_urbantv%avs(1)%rAttr(ip,ig)
- else
- this%t_building_max(l) = spval
- end if
- end do
-
- found = .false.
- do l = bounds%begl,bounds%endl
- if (lun%urbpoi(l)) then
- glun = lun%gridcell(l)
- !
- ! Determine vector index corresponding to glun
- !
- ig = 0
- do g = bounds%begg,bounds%endg
- ig = ig+1
- if (g == glun) exit
- end do
-
- if ( .not. urban_valid(g) .or. (this%t_building_max(l) <= 0._r8)) then
- found = .true.
- gindx = g
- lindx = l
- exit
- end if
- end if
- end do
- if ( found ) then
- write(iulog,*)'ERROR: no valid urban data for g= ',gindx
- write(iulog,*)'landunit type: ',lun%itype(lindx)
- write(iulog,*)'urban_valid: ',urban_valid(gindx)
- write(iulog,*)'t_building_max: ',this%t_building_max(lindx)
- call endrun(subgrid_index=lindx, subgrid_level=subgrid_level_landunit, &
- msg=errmsg(sourcefile, __LINE__))
- end if
-
-
- end subroutine urbantv_interp
-
- !-----------------------------------------------------------------------
-
-end module UrbanTimeVarType
diff --git a/src/cpl/mct/ch4FInundatedStreamType.F90 b/src/cpl/mct/ch4FInundatedStreamType.F90
deleted file mode 100644
index 3c26f4d109..0000000000
--- a/src/cpl/mct/ch4FInundatedStreamType.F90
+++ /dev/null
@@ -1,389 +0,0 @@
-module ch4FInundatedStreamType
-
-#include "shr_assert.h"
-
- !-----------------------------------------------------------------------
- ! !DESCRIPTION:
- ! Contains methods for reading in finundated streams file for methane code.
- !
- ! !USES
- use shr_kind_mod , only: r8 => shr_kind_r8, CL => shr_kind_cl
- use spmdMod , only: mpicom, masterproc
- use clm_varctl , only: iulog, inst_name
- use abortutils , only: endrun
- use decompMod , only: bounds_type
- use ch4varcon , only: finundation_mtd
-
- ! !PUBLIC TYPES:
- implicit none
- private
- save
-
- type, public :: ch4finundatedstream_type
- real(r8), pointer, private :: zwt0_gdc (:) ! col coefficient for determining finundated (m)
- real(r8), pointer, private :: f0_gdc (:) ! col maximum inundated fraction for a gridcell (for methane code)
- real(r8), pointer, private :: p3_gdc (:) ! col coefficient for determining finundated (m)
- real(r8), pointer, private :: fws_slope_gdc (:) ! col slope in fws = slope * tws + intercept (A coefficient)
- real(r8), pointer, private :: fws_intercept_gdc (:) ! col slope in fws = slope * tws + intercept (B coefficient)
- contains
-
- ! !PUBLIC MEMBER FUNCTIONS:
- procedure, public :: Init ! Initialize and read data in
- procedure, public :: CalcFinundated ! Calculate finundated based on input streams
- procedure, public :: UseStreams ! If streams will be used
-
- ! !PRIVATE MEMBER FUNCTIONS:
- procedure, private :: InitAllocate ! Allocate data
-
- end type ch4finundatedstream_type
-
-
- ! ! PRIVATE DATA:
-
- type, private :: streamcontrol_type
- character(len=CL) :: stream_fldFileName_ch4finundated ! Filename
- character(len=CL) :: ch4finundatedmapalgo ! map algo
- character(len=CL) :: fldList ! List of fields to read
- contains
- procedure, private :: ReadNML ! Read in namelist
- end type streamcontrol_type
-
- type(streamcontrol_type), private :: control ! Stream control data
-
- character(len=*), parameter, private :: sourcefile = &
- __FILE__
- !==============================================================================
-
-contains
-
- !==============================================================================
-
- subroutine Init(this, bounds, NLFilename)
- !
- ! Initialize the ch4 finundated stream object
- !
- ! Uses:
- use clm_time_manager , only : get_calendar, get_curr_date
- use ncdio_pio , only : pio_subsystem
- use shr_pio_mod , only : shr_pio_getiotype
- use shr_nl_mod , only : shr_nl_find_group_name
- use shr_mpi_mod , only : shr_mpi_bcast
- use ndepStreamMod , only : clm_domain_mct
- use domainMod , only : ldomain
- use decompMod , only : bounds_type
- use mct_mod , only : mct_ggrid, mct_avect_indexra
- use shr_strdata_mod , only : shr_strdata_type, shr_strdata_create
- use shr_strdata_mod , only : shr_strdata_print, shr_strdata_advance
- use spmdMod , only : comp_id, iam
- use ch4varcon , only : finundation_mtd_h2osfc
- use ch4varcon , only : finundation_mtd_ZWT_inversion, finundation_mtd_TWS_inversion
- use lnd_set_decomp_and_domain , only : gsmap_global
- !
- ! arguments
- implicit none
- class(ch4finundatedstream_type) :: this
- type(bounds_type), intent(in) :: bounds
- character(len=*), intent(in) :: NLFilename ! Namelist filename
- !
- ! local variables
- integer :: ig, g ! Indices
- type(mct_ggrid) :: dom_clm ! domain information
- type(shr_strdata_type) :: sdat ! input data stream
- integer :: index_ZWT0 = 0 ! Index of ZWT0 field
- integer :: index_F0 = 0 ! Index of F0 field
- integer :: index_P3 = 0 ! Index of P3 field
- integer :: index_FWS_TWS_A = 0 ! Index of FWS_TWS_A field
- integer :: index_FWS_TWS_B = 0 ! Index of FWS_TWS_B field
- integer :: year ! year (0, ...) for nstep+1
- integer :: mon ! month (1, ..., 12) for nstep+1
- integer :: day ! day of month (1, ..., 31) for nstep+1
- integer :: sec ! seconds into current date for nstep+1
- integer :: mcdate ! Current model date (yyyymmdd)
- character(len=*), parameter :: stream_name = 'ch4finundated'
- character(*), parameter :: subName = "('ch4finundatedstream::Init')"
- !-----------------------------------------------------------------------
- if ( finundation_mtd /= finundation_mtd_h2osfc )then
- call this%InitAllocate( bounds )
- call control%ReadNML( bounds, NLFileName )
-
- if ( this%useStreams() )then
- call clm_domain_mct (bounds, dom_clm)
-
- call shr_strdata_create(sdat,name=stream_name, &
- pio_subsystem=pio_subsystem, &
- pio_iotype=shr_pio_getiotype(inst_name), &
- mpicom=mpicom, compid=comp_id, &
- gsmap=gsmap_global, ggrid=dom_clm, &
- nxg=ldomain%ni, nyg=ldomain%nj, &
- yearFirst=1996, &
- yearLast=1996, &
- yearAlign=1, &
- offset=0, &
- domFilePath='', &
- domFileName=trim(control%stream_fldFileName_ch4finundated), &
- domTvarName='time', &
- domXvarName='LONGXY' , &
- domYvarName='LATIXY' , &
- domAreaName='AREA', &
- domMaskName='LANDMASK', &
- filePath='', &
- filename=(/trim(control%stream_fldFileName_ch4finundated)/), &
- fldListFile=control%fldList, &
- fldListModel=control%fldList, &
- fillalgo='none', &
- mapalgo=control%ch4finundatedmapalgo, &
- calendar=get_calendar(), &
- taxmode='extend' )
-
- if (masterproc) then
- call shr_strdata_print(sdat,'CLM '//stream_name//' data')
- endif
-
- if( finundation_mtd == finundation_mtd_ZWT_inversion )then
- index_ZWT0 = mct_avect_indexra(sdat%avs(1),'ZWT0')
- index_F0 = mct_avect_indexra(sdat%avs(1),'F0' )
- index_P3 = mct_avect_indexra(sdat%avs(1),'P3' )
- else if( finundation_mtd == finundation_mtd_TWS_inversion )then
- index_FWS_TWS_A = mct_avect_indexra(sdat%avs(1),'FWS_TWS_A')
- index_FWS_TWS_B = mct_avect_indexra(sdat%avs(1),'FWS_TWS_B')
- end if
-
-
- ! Explicitly set current date to a hardcoded constant value. Otherwise
- ! using the real date can cause roundoff differences that are
- ! detrected as issues with exact restart. EBK M05/20/2017
- !call get_curr_date(year, mon, day, sec)
- year = 1996
- mon = 12
- day = 31
- sec = 0
- mcdate = year*10000 + mon*100 + day
-
- call shr_strdata_advance(sdat, mcdate, sec, mpicom, 'ch4finundated')
-
- ! Get the data
- ig = 0
- do g = bounds%begg,bounds%endg
- ig = ig+1
- if ( index_ZWT0 > 0 )then
- this%zwt0_gdc(g) = sdat%avs(1)%rAttr(index_ZWT0,ig)
- end if
- if ( index_F0 > 0 )then
- this%f0_gdc(g) = sdat%avs(1)%rAttr(index_F0,ig)
- end if
- if ( index_P3 > 0 )then
- this%p3_gdc(g) = sdat%avs(1)%rAttr(index_P3,ig)
- end if
- if ( index_FWS_TWS_A > 0 )then
- this%fws_slope_gdc(g) = sdat%avs(1)%rAttr(index_FWS_TWS_A,ig)
- end if
- if ( index_FWS_TWS_B > 0 )then
- this%fws_intercept_gdc(g) = sdat%avs(1)%rAttr(index_FWS_TWS_B,ig)
- end if
- end do
- end if
- end if
-
- end subroutine Init
-
- !-----------------------------------------------------------------------
- logical function UseStreams(this)
- !
- ! !DESCRIPTION:
- ! Return true if
- !
- ! !USES:
- !
- ! !ARGUMENTS:
- implicit none
- class(ch4finundatedstream_type) :: this
- !
- ! !LOCAL VARIABLES:
- if ( trim(control%stream_fldFileName_ch4finundated) == '' )then
- UseStreams = .false.
- else
- UseStreams = .true.
- end if
- end function UseStreams
-
- !-----------------------------------------------------------------------
- subroutine InitAllocate(this, bounds)
- !
- ! !DESCRIPTION:
- ! Allocate module variables and data structures
- !
- ! !USES:
- use shr_infnan_mod, only: nan => shr_infnan_nan, assignment(=)
- use ch4varcon , only: finundation_mtd_ZWT_inversion, finundation_mtd_TWS_inversion
- !
- ! !ARGUMENTS:
- implicit none
- class(ch4finundatedstream_type) :: this
- type(bounds_type), intent(in) :: bounds
- !
- ! !LOCAL VARIABLES:
- integer :: begc, endc
- integer :: begg, endg
- !---------------------------------------------------------------------
-
- begc = bounds%begc; endc = bounds%endc
- begg = bounds%begg; endg = bounds%endg
-
- if( finundation_mtd == finundation_mtd_ZWT_inversion )then
- allocate(this%zwt0_gdc (begg:endg)) ; this%zwt0_gdc (:) = nan
- allocate(this%f0_gdc (begg:endg)) ; this%f0_gdc (:) = nan
- allocate(this%p3_gdc (begg:endg)) ; this%p3_gdc (:) = nan
- else if( finundation_mtd == finundation_mtd_TWS_inversion )then
- allocate(this%fws_slope_gdc (begg:endg)) ; this%fws_slope_gdc (:) = nan
- allocate(this%fws_intercept_gdc(begg:endg)) ; this%fws_intercept_gdc(:) = nan
- end if
-
- end subroutine InitAllocate
-
- !-----------------------------------------------------------------------
- subroutine CalcFinundated(this, bounds, num_soilc, filter_soilc, soilhydrology_inst, &
- waterdiagnosticbulk_inst, qflx_surf_lag_col, finundated )
- !
- ! !DESCRIPTION:
- !
- ! Calculate finundated according to the appropriate methodology
- !
- ! !USES:
- use ColumnType , only : col
- use ch4varcon , only : finundation_mtd_h2osfc, finundation_mtd_ZWT_inversion
- use ch4varcon , only : finundation_mtd_TWS_inversion
- use clm_varpar , only : nlevsoi
- use SoilHydrologyType, only : soilhydrology_type
- use WaterDiagnosticBulkType , only : waterdiagnosticbulk_type
- !
- ! !ARGUMENTS:
- implicit none
- class(ch4finundatedstream_type) :: this
- type(bounds_type) , intent(in) :: bounds
- integer , intent(in) :: num_soilc ! number of column soil points in column filter
- integer , intent(in) :: filter_soilc(:) ! column filter for soil points
- type(soilhydrology_type) , intent(in) :: soilhydrology_inst
- type(waterdiagnosticbulk_type) , intent(in) :: waterdiagnosticbulk_inst
- real(r8) , intent(in) :: qflx_surf_lag_col(bounds%begc:) !time-lagged surface runoff (mm H2O /s)
- real(r8) , intent(inout) :: finundated(bounds%begc:) ! fractional inundated area in soil column (excluding dedicated wetland columns)
- !
- ! !LOCAL VARIABLES:
- integer :: g, c, fc ! Indices
- real(r8) :: zwt_actual ! Total water storage (ZWT) to use either perched or total depending on conditions
-
- SHR_ASSERT_ALL_FL((ubound(qflx_surf_lag_col) == (/bounds%endc/)), sourcefile, __LINE__)
- SHR_ASSERT_ALL_FL((ubound(finundated) == (/bounds%endc/)), sourcefile, __LINE__)
-
- associate( &
- z => col%z , & ! Input: [real(r8) (:,:) ] layer depth (m) (-nlevsno+1:nlevsoi)
- zwt => soilhydrology_inst%zwt_col , & ! Input: [real(r8) (:) ] water table depth (m)
- zwt_perched => soilhydrology_inst%zwt_perched_col , & ! Input: [real(r8) (:) ] perched water table depth (m)
- tws => waterdiagnosticbulk_inst%tws_grc , & ! Input: [real(r8) (:) ] total water storage (kg m-2)
- frac_h2osfc => waterdiagnosticbulk_inst%frac_h2osfc_col & ! Input: [real(r8) (:) ] fraction of ground covered by surface water (0 to 1)
- )
-
- ! Calculate finundated
- do fc = 1, num_soilc
- c = filter_soilc(fc)
- g = col%gridcell(c)
- select case( finundation_mtd )
- case ( finundation_mtd_h2osfc )
- finundated(c) = frac_h2osfc(c)
- case ( finundation_mtd_ZWT_inversion )
- if (this%zwt0_gdc(g) > 0._r8) then
- if (zwt_perched(c) < z(c,nlevsoi)-1.e-5_r8 .and. zwt_perched(c) < zwt(c)) then
- zwt_actual = zwt_perched(c)
- else
- zwt_actual = zwt(c)
- end if
- finundated(c) = this%f0_gdc(g) * exp(-zwt_actual/this%zwt0_gdc(g)) + this%p3_gdc(g)*qflx_surf_lag_col(c)
- else
- finundated(c) = this%p3_gdc(g)*qflx_surf_lag_col(c)
- end if
- case ( finundation_mtd_TWS_inversion )
- finundated(c) = this%fws_slope_gdc(g) * tws(g) + this%fws_intercept_gdc(g)
- end select
- finundated(c) = min( 1.0_r8, max( 0.0_r8, finundated(c) ) )
- end do
- end associate
-
- end subroutine CalcFinundated
- !==============================================================================
-
- subroutine ReadNML(this, bounds, NLFilename)
- !
- ! Read the namelist data stream information.
- !
- ! Uses:
- use clm_time_manager , only : get_calendar
- use ncdio_pio , only : pio_subsystem
- use shr_pio_mod , only : shr_pio_getiotype
- use shr_nl_mod , only : shr_nl_find_group_name
- use shr_log_mod , only : errMsg => shr_log_errMsg
- use shr_mpi_mod , only : shr_mpi_bcast
- use fileutils , only : getavu, relavu
- use ch4varcon , only : finundation_mtd_ZWT_inversion, finundation_mtd_TWS_inversion
- !
- ! arguments
- implicit none
- class(streamcontrol_type) :: this
- type(bounds_type), intent(in) :: bounds
- character(len=*), intent(in) :: NLFilename ! Namelist filename
- !
- ! local variables
- integer :: nu_nml ! unit for namelist file
- integer :: nml_error ! namelist i/o error flag
- character(len=CL) :: stream_fldFileName_ch4finundated = ' '
- character(len=CL) :: ch4finundatedmapalgo = 'bilinear'
- character(len=*), parameter :: namelist_name = 'ch4finundated' ! MUST agree with name in namelist and read
- character(len=*), parameter :: shr_strdata_unset = 'NOT_SET'
- character(len=*), parameter :: subName = "('ch4finundated::ReadNML')"
- character(len=*), parameter :: F00 = "('(ch4finundated_readnml) ',4a)"
- !-----------------------------------------------------------------------
-
- namelist /ch4finundated/ & ! MUST agree with namelist_name above
- ch4finundatedmapalgo, stream_fldFileName_ch4finundated
-
- ! Default values for namelist
-
- ! Read ch4finundated namelist
- if (masterproc) then
- nu_nml = getavu()
- open( nu_nml, file=trim(NLFilename), status='old', iostat=nml_error )
- call shr_nl_find_group_name(nu_nml, namelist_name, status=nml_error)
- if (nml_error == 0) then
- read(nu_nml, nml=ch4finundated,iostat=nml_error) ! MUST agree with namelist_name above
- if (nml_error /= 0) then
- call endrun(msg=' ERROR reading '//namelist_name//' namelist'//errMsg(sourcefile, __LINE__))
- end if
- else
- call endrun(msg=' ERROR finding '//namelist_name//' namelist'//errMsg(sourcefile, __LINE__))
- end if
- close(nu_nml)
- call relavu( nu_nml )
- endif
-
- call shr_mpi_bcast(stream_fldFileName_ch4finundated, mpicom)
- call shr_mpi_bcast(ch4finundatedmapalgo , mpicom)
-
- if (masterproc) then
- write(iulog,*) ' '
- write(iulog,*) namelist_name, ' stream settings:'
- write(iulog,*) ' stream_fldFileName_ch4finundated = ',stream_fldFileName_ch4finundated
- write(iulog,*) ' ch4finundatedmapalgo = ',ch4finundatedmapalgo
- write(iulog,*) ' '
- endif
- this%stream_fldFileName_ch4finundated = stream_fldFileName_ch4finundated
- this%ch4finundatedmapalgo = ch4finundatedmapalgo
- if ( finundation_mtd == finundation_mtd_ZWT_inversion )then
- this%fldList = "ZWT0:F0:P3"
- else if ( finundation_mtd == finundation_mtd_TWS_inversion )then
- this%fldList = "FWS_TWS_A:FWS_TWS_B"
- else
- call endrun(msg=' ERROR do NOT know what list of variables to read for this finundation_mtd type'// &
- errMsg(sourcefile, __LINE__))
- end if
-
- end subroutine ReadNML
-
-end module ch4FInundatedStreamType
diff --git a/src/cpl/mct/clm_cpl_indices.F90 b/src/cpl/mct/clm_cpl_indices.F90
deleted file mode 100644
index 09ed89e92d..0000000000
--- a/src/cpl/mct/clm_cpl_indices.F90
+++ /dev/null
@@ -1,330 +0,0 @@
-module clm_cpl_indices
- !-----------------------------------------------------------------------
- ! !DESCRIPTION:
- ! Module containing the indices for the fields passed between CLM and
- ! the driver. Includes the River Transport Model fields (RTM) and the
- ! fields needed by the land-ice component (sno).
- !
- ! !USES:
-
- use shr_sys_mod, only : shr_sys_abort
- implicit none
-
- SAVE
- private ! By default make data private
- !
- ! !PUBLIC MEMBER FUNCTIONS:
- public :: clm_cpl_indices_set ! Set the coupler indices
- !
- ! !PUBLIC DATA MEMBERS:
- !
- integer , public :: glc_nec ! number of elevation classes for glacier_mec landunits
- ! (from coupler) - must equal maxpatch_glc from namelist
-
- ! lnd -> drv (required)
-
- integer, public ::index_l2x_Flrl_rofsur ! lnd->rtm input liquid surface fluxes
- integer, public ::index_l2x_Flrl_rofgwl ! lnd->rtm input liquid gwl fluxes
- integer, public ::index_l2x_Flrl_rofsub ! lnd->rtm input liquid subsurface fluxes
- integer, public ::index_l2x_Flrl_rofi ! lnd->rtm input frozen fluxes
- integer, public ::index_l2x_Flrl_irrig ! irrigation withdrawal
-
- integer, public ::index_l2x_Sl_t ! temperature
- integer, public ::index_l2x_Sl_tref ! 2m reference temperature
- integer, public ::index_l2x_Sl_qref ! 2m reference specific humidity
- integer, public ::index_l2x_Sl_avsdr ! albedo: direct , visible
- integer, public ::index_l2x_Sl_anidr ! albedo: direct , near-ir
- integer, public ::index_l2x_Sl_avsdf ! albedo: diffuse, visible
- integer, public ::index_l2x_Sl_anidf ! albedo: diffuse, near-ir
- integer, public ::index_l2x_Sl_snowh ! snow height
- integer, public ::index_l2x_Sl_u10 ! 10m wind
- integer, public ::index_l2x_Sl_ddvel ! dry deposition velocities (optional)
- integer, public ::index_l2x_Sl_fv ! friction velocity
- integer, public ::index_l2x_Sl_ram1 ! aerodynamical resistance
- integer, public ::index_l2x_Sl_soilw ! volumetric soil water
- integer, public ::index_l2x_Fall_taux ! wind stress, zonal
- integer, public ::index_l2x_Fall_tauy ! wind stress, meridional
- integer, public ::index_l2x_Fall_lat ! latent heat flux
- integer, public ::index_l2x_Fall_sen ! sensible heat flux
- integer, public ::index_l2x_Fall_lwup ! upward longwave heat flux
- integer, public ::index_l2x_Fall_evap ! evaporation water flux
- integer, public ::index_l2x_Fall_swnet ! heat flux shortwave net
- integer, public ::index_l2x_Fall_fco2_lnd ! co2 flux **For testing set to 0
- integer, public ::index_l2x_Fall_flxdst1 ! dust flux size bin 1
- integer, public ::index_l2x_Fall_flxdst2 ! dust flux size bin 2
- integer, public ::index_l2x_Fall_flxdst3 ! dust flux size bin 3
- integer, public ::index_l2x_Fall_flxdst4 ! dust flux size bin 4
- integer, public ::index_l2x_Fall_flxvoc ! MEGAN fluxes
- integer, public ::index_l2x_Fall_flxfire ! Fire fluxes
- integer, public ::index_l2x_Sl_ztopfire ! Top of fire emissions (m)
-
- ! In the following, index 0 is bare land, other indices are glc elevation classes
- integer, allocatable, public ::index_l2x_Sl_tsrf(:) ! glc MEC temperature
- integer, allocatable, public ::index_l2x_Sl_topo(:) ! glc MEC topo height
- integer, allocatable, public ::index_l2x_Flgl_qice(:) ! glc MEC ice flux
-
- integer, public ::index_x2l_Sa_methane
- integer, public ::index_l2x_Fall_methane
-
- integer, public :: nflds_l2x = 0
-
- ! drv -> lnd (required)
-
- integer, public ::index_x2l_Sa_z ! bottom atm level height
- integer, public ::index_x2l_Sa_topo ! atm surface height (m)
- integer, public ::index_x2l_Sa_u ! bottom atm level zon wind
- integer, public ::index_x2l_Sa_v ! bottom atm level mer wind
- integer, public ::index_x2l_Sa_ptem ! bottom atm level pot temp
- integer, public ::index_x2l_Sa_shum ! bottom atm level spec hum
- integer, public ::index_x2l_Sa_pbot ! bottom atm level pressure
- integer, public ::index_x2l_Sa_tbot ! bottom atm level temp
- integer, public ::index_x2l_Faxa_lwdn ! downward lw heat flux
- integer, public ::index_x2l_Faxa_rainc ! prec: liquid "convective"
- integer, public ::index_x2l_Faxa_rainl ! prec: liquid "large scale"
- integer, public ::index_x2l_Faxa_snowc ! prec: frozen "convective"
- integer, public ::index_x2l_Faxa_snowl ! prec: frozen "large scale"
- integer, public ::index_x2l_Faxa_swndr ! sw: nir direct downward
- integer, public ::index_x2l_Faxa_swvdr ! sw: vis direct downward
- integer, public ::index_x2l_Faxa_swndf ! sw: nir diffuse downward
- integer, public ::index_x2l_Faxa_swvdf ! sw: vis diffuse downward
- integer, public ::index_x2l_Sa_co2prog ! bottom atm level prognostic co2
- integer, public ::index_x2l_Sa_co2diag ! bottom atm level diagnostic co2
- integer, public ::index_x2l_Faxa_bcphidry ! flux: Black Carbon hydrophilic dry deposition
- integer, public ::index_x2l_Faxa_bcphodry ! flux: Black Carbon hydrophobic dry deposition
- integer, public ::index_x2l_Faxa_bcphiwet ! flux: Black Carbon hydrophilic wet deposition
- integer, public ::index_x2l_Faxa_ocphidry ! flux: Organic Carbon hydrophilic dry deposition
- integer, public ::index_x2l_Faxa_ocphodry ! flux: Organic Carbon hydrophobic dry deposition
- integer, public ::index_x2l_Faxa_ocphiwet ! flux: Organic Carbon hydrophilic dry deposition
- integer, public ::index_x2l_Faxa_dstwet1 ! flux: Size 1 dust -- wet deposition
- integer, public ::index_x2l_Faxa_dstwet2 ! flux: Size 2 dust -- wet deposition
- integer, public ::index_x2l_Faxa_dstwet3 ! flux: Size 3 dust -- wet deposition
- integer, public ::index_x2l_Faxa_dstwet4 ! flux: Size 4 dust -- wet deposition
- integer, public ::index_x2l_Faxa_dstdry1 ! flux: Size 1 dust -- dry deposition
- integer, public ::index_x2l_Faxa_dstdry2 ! flux: Size 2 dust -- dry deposition
- integer, public ::index_x2l_Faxa_dstdry3 ! flux: Size 3 dust -- dry deposition
- integer, public ::index_x2l_Faxa_dstdry4 ! flux: Size 4 dust -- dry deposition
-
- integer, public ::index_x2l_Faxa_nhx ! flux nhx from atm
- integer, public ::index_x2l_Faxa_noy ! flux noy from atm
-
- integer, public ::index_x2l_Flrr_flood ! rtm->lnd rof flood flux
- integer, public ::index_x2l_Flrr_volr ! rtm->lnd rof volr total volume
- integer, public ::index_x2l_Flrr_volrmch ! rtm->lnd rof volr main channel volume
-
- ! In the following, index 0 is bare land, other indices are glc elevation classes
- integer, allocatable, public ::index_x2l_Sg_ice_covered(:) ! Fraction of glacier from glc model
- integer, allocatable, public ::index_x2l_Sg_topo(:) ! Topo height from glc model
- integer, allocatable, public ::index_x2l_Flgg_hflx(:) ! Heat flux from glc model
-
- integer, public ::index_x2l_Sg_icemask
- integer, public ::index_x2l_Sg_icemask_coupled_fluxes
-
- integer, public :: nflds_x2l = 0
-
- !-----------------------------------------------------------------------
-
-contains
-
- !-----------------------------------------------------------------------
- subroutine clm_cpl_indices_set( )
- !
- ! !DESCRIPTION:
- ! Set the coupler indices needed by the land model coupler
- ! interface.
- !
- ! !USES:
- use seq_flds_mod , only: seq_flds_x2l_fields, seq_flds_l2x_fields
- use mct_mod , only: mct_aVect, mct_aVect_init, mct_avect_indexra
- use mct_mod , only: mct_aVect_clean, mct_avect_nRattr
- use shr_drydep_mod , only: drydep_fields_token, n_drydep
- use shr_megan_mod , only: shr_megan_fields_token, shr_megan_mechcomps_n
- use shr_fire_emis_mod,only: shr_fire_emis_fields_token, shr_fire_emis_ztop_token, shr_fire_emis_mechcomps_n
- use clm_varctl , only: ndep_from_cpl
- use glc_elevclass_mod, only: glc_get_num_elevation_classes, glc_elevclass_as_string
- !
- ! !ARGUMENTS:
- implicit none
- !
- ! !REVISION HISTORY:
- ! Author: Mariana Vertenstein
- ! 01/2011, Erik Kluzek: Added protex headers
- !
- ! !LOCAL VARIABLES:
- type(mct_aVect) :: l2x ! temporary, land to coupler
- type(mct_aVect) :: x2l ! temporary, coupler to land
- integer :: num
- character(len=:), allocatable :: nec_str ! string version of glc elev. class number
- character(len=64) :: name
- character(len=32) :: subname = 'clm_cpl_indices_set' ! subroutine name
- !-----------------------------------------------------------------------
-
- ! Determine attribute vector indices
-
- ! create temporary attribute vectors
- call mct_aVect_init(x2l, rList=seq_flds_x2l_fields, lsize=1)
- nflds_x2l = mct_avect_nRattr(x2l)
-
- call mct_aVect_init(l2x, rList=seq_flds_l2x_fields, lsize=1)
- nflds_l2x = mct_avect_nRattr(l2x)
-
- !-------------------------------------------------------------
- ! clm -> drv
- !-------------------------------------------------------------
-
- index_l2x_Flrl_rofsur = mct_avect_indexra(l2x,'Flrl_rofsur')
- index_l2x_Flrl_rofgwl = mct_avect_indexra(l2x,'Flrl_rofgwl')
- index_l2x_Flrl_rofsub = mct_avect_indexra(l2x,'Flrl_rofsub')
- index_l2x_Flrl_rofi = mct_avect_indexra(l2x,'Flrl_rofi')
- index_l2x_Flrl_irrig = mct_avect_indexra(l2x,'Flrl_irrig')
-
- index_l2x_Sl_t = mct_avect_indexra(l2x,'Sl_t')
- index_l2x_Sl_snowh = mct_avect_indexra(l2x,'Sl_snowh')
- index_l2x_Sl_avsdr = mct_avect_indexra(l2x,'Sl_avsdr')
- index_l2x_Sl_anidr = mct_avect_indexra(l2x,'Sl_anidr')
- index_l2x_Sl_avsdf = mct_avect_indexra(l2x,'Sl_avsdf')
- index_l2x_Sl_anidf = mct_avect_indexra(l2x,'Sl_anidf')
- index_l2x_Sl_tref = mct_avect_indexra(l2x,'Sl_tref')
- index_l2x_Sl_qref = mct_avect_indexra(l2x,'Sl_qref')
- index_l2x_Sl_u10 = mct_avect_indexra(l2x,'Sl_u10')
- index_l2x_Sl_ram1 = mct_avect_indexra(l2x,'Sl_ram1')
- index_l2x_Sl_fv = mct_avect_indexra(l2x,'Sl_fv')
- index_l2x_Sl_soilw = mct_avect_indexra(l2x,'Sl_soilw',perrwith='quiet')
-
- if ( n_drydep>0 )then
- index_l2x_Sl_ddvel = mct_avect_indexra(l2x, trim(drydep_fields_token))
- else
- index_l2x_Sl_ddvel = 0
- end if
-
- index_l2x_Fall_taux = mct_avect_indexra(l2x,'Fall_taux')
- index_l2x_Fall_tauy = mct_avect_indexra(l2x,'Fall_tauy')
- index_l2x_Fall_lat = mct_avect_indexra(l2x,'Fall_lat')
- index_l2x_Fall_sen = mct_avect_indexra(l2x,'Fall_sen')
- index_l2x_Fall_lwup = mct_avect_indexra(l2x,'Fall_lwup')
- index_l2x_Fall_evap = mct_avect_indexra(l2x,'Fall_evap')
- index_l2x_Fall_swnet = mct_avect_indexra(l2x,'Fall_swnet')
- index_l2x_Fall_flxdst1 = mct_avect_indexra(l2x,'Fall_flxdst1')
- index_l2x_Fall_flxdst2 = mct_avect_indexra(l2x,'Fall_flxdst2')
- index_l2x_Fall_flxdst3 = mct_avect_indexra(l2x,'Fall_flxdst3')
- index_l2x_Fall_flxdst4 = mct_avect_indexra(l2x,'Fall_flxdst4')
-
- index_l2x_Fall_fco2_lnd = mct_avect_indexra(l2x,'Fall_fco2_lnd',perrwith='quiet')
-
- index_l2x_Fall_methane = mct_avect_indexra(l2x,'Fall_methane',perrWith='quiet')
-
- ! MEGAN fluxes
- if (shr_megan_mechcomps_n>0) then
- index_l2x_Fall_flxvoc = mct_avect_indexra(l2x,trim(shr_megan_fields_token))
- else
- index_l2x_Fall_flxvoc = 0
- endif
-
- ! Fire fluxes
- if (shr_fire_emis_mechcomps_n>0) then
- index_l2x_Fall_flxfire = mct_avect_indexra(l2x,trim(shr_fire_emis_fields_token))
- index_l2x_Sl_ztopfire = mct_avect_indexra(l2x,trim(shr_fire_emis_ztop_token))
- else
- index_l2x_Fall_flxfire = 0
- index_l2x_Sl_ztopfire = 0
- endif
-
- !-------------------------------------------------------------
- ! drv -> clm
- !-------------------------------------------------------------
-
- index_x2l_Sa_z = mct_avect_indexra(x2l,'Sa_z')
- index_x2l_Sa_topo = mct_avect_indexra(x2l,'Sa_topo')
- index_x2l_Sa_u = mct_avect_indexra(x2l,'Sa_u')
- index_x2l_Sa_v = mct_avect_indexra(x2l,'Sa_v')
- index_x2l_Sa_ptem = mct_avect_indexra(x2l,'Sa_ptem')
- index_x2l_Sa_pbot = mct_avect_indexra(x2l,'Sa_pbot')
- index_x2l_Sa_tbot = mct_avect_indexra(x2l,'Sa_tbot')
- index_x2l_Sa_shum = mct_avect_indexra(x2l,'Sa_shum')
- index_x2l_Sa_co2prog = mct_avect_indexra(x2l,'Sa_co2prog',perrwith='quiet')
- index_x2l_Sa_co2diag = mct_avect_indexra(x2l,'Sa_co2diag',perrwith='quiet')
-
- index_x2l_Sa_methane = mct_avect_indexra(x2l,'Sa_methane',perrWith='quiet')
-
- index_x2l_Flrr_volr = mct_avect_indexra(x2l,'Flrr_volr')
- index_x2l_Flrr_volrmch = mct_avect_indexra(x2l,'Flrr_volrmch')
-
- index_x2l_Faxa_lwdn = mct_avect_indexra(x2l,'Faxa_lwdn')
- index_x2l_Faxa_rainc = mct_avect_indexra(x2l,'Faxa_rainc')
- index_x2l_Faxa_rainl = mct_avect_indexra(x2l,'Faxa_rainl')
- index_x2l_Faxa_snowc = mct_avect_indexra(x2l,'Faxa_snowc')
- index_x2l_Faxa_snowl = mct_avect_indexra(x2l,'Faxa_snowl')
- index_x2l_Faxa_swndr = mct_avect_indexra(x2l,'Faxa_swndr')
- index_x2l_Faxa_swvdr = mct_avect_indexra(x2l,'Faxa_swvdr')
- index_x2l_Faxa_swndf = mct_avect_indexra(x2l,'Faxa_swndf')
- index_x2l_Faxa_swvdf = mct_avect_indexra(x2l,'Faxa_swvdf')
- index_x2l_Faxa_bcphidry = mct_avect_indexra(x2l,'Faxa_bcphidry')
- index_x2l_Faxa_bcphodry = mct_avect_indexra(x2l,'Faxa_bcphodry')
- index_x2l_Faxa_bcphiwet = mct_avect_indexra(x2l,'Faxa_bcphiwet')
- index_x2l_Faxa_ocphidry = mct_avect_indexra(x2l,'Faxa_ocphidry')
- index_x2l_Faxa_ocphodry = mct_avect_indexra(x2l,'Faxa_ocphodry')
- index_x2l_Faxa_ocphiwet = mct_avect_indexra(x2l,'Faxa_ocphiwet')
- index_x2l_Faxa_dstdry1 = mct_avect_indexra(x2l,'Faxa_dstdry1')
- index_x2l_Faxa_dstdry2 = mct_avect_indexra(x2l,'Faxa_dstdry2')
- index_x2l_Faxa_dstdry3 = mct_avect_indexra(x2l,'Faxa_dstdry3')
- index_x2l_Faxa_dstdry4 = mct_avect_indexra(x2l,'Faxa_dstdry4')
- index_x2l_Faxa_dstwet1 = mct_avect_indexra(x2l,'Faxa_dstwet1')
- index_x2l_Faxa_dstwet2 = mct_avect_indexra(x2l,'Faxa_dstwet2')
- index_x2l_Faxa_dstwet3 = mct_avect_indexra(x2l,'Faxa_dstwet3')
- index_x2l_Faxa_dstwet4 = mct_avect_indexra(x2l,'Faxa_dstwet4')
-
- index_x2l_Faxa_nhx = mct_avect_indexra(x2l,'Faxa_nhx', perrWith='quiet')
- index_x2l_Faxa_noy = mct_avect_indexra(x2l,'Faxa_noy', perrWith='quiet')
-
- if (index_x2l_Faxa_nhx > 0 .and. index_x2l_Faxa_noy > 0) then
- ndep_from_cpl = .true.
- end if
-
- index_x2l_Flrr_flood = mct_avect_indexra(x2l,'Flrr_flood')
-
- !-------------------------------------------------------------
- ! glc coupling
- !-------------------------------------------------------------
-
- index_x2l_Sg_icemask = mct_avect_indexra(x2l,'Sg_icemask')
- index_x2l_Sg_icemask_coupled_fluxes = mct_avect_indexra(x2l,'Sg_icemask_coupled_fluxes')
-
- glc_nec = glc_get_num_elevation_classes()
- if (glc_nec < 1) then
- call shr_sys_abort('ERROR: In CLM4.5 and later, glc_nec must be at least 1.')
- end if
-
- ! Create coupling fields for all glc elevation classes (1:glc_nec) plus bare land
- ! (index 0).
- allocate(index_l2x_Sl_tsrf(0:glc_nec))
- allocate(index_l2x_Sl_topo(0:glc_nec))
- allocate(index_l2x_Flgl_qice(0:glc_nec))
- allocate(index_x2l_Sg_ice_covered(0:glc_nec))
- allocate(index_x2l_Sg_topo(0:glc_nec))
- allocate(index_x2l_Flgg_hflx(0:glc_nec))
-
- do num = 0,glc_nec
- nec_str = glc_elevclass_as_string(num)
-
- name = 'Sg_ice_covered' // nec_str
- index_x2l_Sg_ice_covered(num) = mct_avect_indexra(x2l,trim(name))
- name = 'Sg_topo' // nec_str
- index_x2l_Sg_topo(num) = mct_avect_indexra(x2l,trim(name))
- name = 'Flgg_hflx' // nec_str
- index_x2l_Flgg_hflx(num) = mct_avect_indexra(x2l,trim(name))
-
- name = 'Sl_tsrf' // nec_str
- index_l2x_Sl_tsrf(num) = mct_avect_indexra(l2x,trim(name))
- name = 'Sl_topo' // nec_str
- index_l2x_Sl_topo(num) = mct_avect_indexra(l2x,trim(name))
- name = 'Flgl_qice' // nec_str
- index_l2x_Flgl_qice(num) = mct_avect_indexra(l2x,trim(name))
- end do
-
- call mct_aVect_clean(x2l)
- call mct_aVect_clean(l2x)
-
- end subroutine clm_cpl_indices_set
-
-!=======================================================================
-
-end module clm_cpl_indices
diff --git a/src/cpl/mct/laiStreamMod.F90 b/src/cpl/mct/laiStreamMod.F90
deleted file mode 100644
index 47d25287b7..0000000000
--- a/src/cpl/mct/laiStreamMod.F90
+++ /dev/null
@@ -1,241 +0,0 @@
-module laiStreamMod
-
-#include "shr_assert.h"
-
- !-----------------------------------------------------------------------
- ! !DESCRIPTION:
- ! Read LAI from stream
- !
- ! !USES:
- use shr_strdata_mod , only : shr_strdata_type, shr_strdata_create
- use shr_strdata_mod , only : shr_strdata_print, shr_strdata_advance
- use shr_kind_mod , only : r8=>shr_kind_r8, CL=>shr_kind_CL, CS=>shr_kind_CS, CXX=>shr_kind_CXX
- use shr_log_mod , only : errMsg => shr_log_errMsg
- use decompMod , only : bounds_type
- use abortutils , only : endrun
- use clm_varctl , only : iulog, inst_name
- use perf_mod , only : t_startf, t_stopf
- use spmdMod , only : masterproc, mpicom, comp_id
- use ncdio_pio
- use mct_mod
- !
- ! !PUBLIC TYPES:
- implicit none
- private
-
- ! !PUBLIC MEMBER FUNCTIONS:
- public :: lai_init ! position datasets for LAI
- public :: lai_advance ! Advance the LAI streams (outside of a Open-MP threading loop)
- public :: lai_interp ! interpolates between two years of LAI data (when LAI streams
-
- ! !PRIVATE MEMBER DATA:
- integer, allocatable :: g_to_ig(:) ! Array matching gridcell index to data index
- type(shr_strdata_type) :: sdat_lai ! LAI input data stream
-
- character(len=*), parameter :: sourcefile = &
- __FILE__
-
-!==============================================================================
-contains
-!==============================================================================
-
- subroutine lai_init(bounds)
- !
- ! Initialize data stream information for LAI.
- !
- ! !USES:
- use clm_time_manager , only : get_calendar
- use ncdio_pio , only : pio_subsystem
- use shr_pio_mod , only : shr_pio_getiotype
- use shr_stream_mod , only : shr_stream_file_null
- use shr_string_mod , only : shr_string_listCreateField
- use clm_nlUtilsMod , only : find_nlgroup_name
- use ndepStreamMod , only : clm_domain_mct
- use histFileMod , only : hist_addfld1d
- use domainMod , only : ldomain
- use controlMod , only : NLFilename
- use lnd_set_decomp_and_domain , only : gsmap_global
- !
- ! !ARGUMENTS:
- implicit none
- type(bounds_type), intent(in) :: bounds ! bounds
- !
- ! !LOCAL VARIABLES:
- integer :: stream_year_first_lai ! first year in Lai stream to use
- integer :: stream_year_last_lai ! last year in Lai stream to use
- integer :: model_year_align_lai ! align stream_year_first_lai with
- integer :: nu_nml ! unit for namelist file
- integer :: nml_error ! namelist i/o error flag
- type(mct_ggrid) :: dom_clm ! domain information
- character(len=CL) :: stream_fldFileName_lai ! lai stream filename to read
- character(len=CL) :: lai_mapalgo = 'bilinear' ! Mapping alogrithm
- character(len=CL) :: lai_tintalgo = 'linear' ! Time interpolation alogrithm
- character(len=CXX) :: fldList ! field string
- character(*), parameter :: laiString = "LAI" ! base string for field string
- integer , parameter :: numLaiFields = 16 ! number of fields to build field string
- character(*), parameter :: subName = "('laidyn_init')"
- !-----------------------------------------------------------------------
- !
- ! deal with namelist variables here in init
- !
- namelist /lai_streams/ &
- stream_year_first_lai, &
- stream_year_last_lai, &
- model_year_align_lai, &
- lai_mapalgo, &
- stream_fldFileName_lai, &
- lai_tintalgo
-
- ! Default values for namelist
- stream_year_first_lai = 1 ! first year in stream to use
- stream_year_last_lai = 1 ! last year in stream to use
- model_year_align_lai = 1 ! align stream_year_first_lai with this model year
- stream_fldFileName_lai = shr_stream_file_null
-
- ! Read lai_streams namelist
- if (masterproc) then
- open( newunit=nu_nml, file=trim(NLFilename), status='old', iostat=nml_error )
- call find_nlgroup_name(nu_nml, 'lai_streams', status=nml_error)
- if (nml_error == 0) then
- read(nu_nml, nml=lai_streams,iostat=nml_error)
- if (nml_error /= 0) then
- call endrun(subname // ':: ERROR reading lai_streams namelist')
- end if
- else
- call endrun(subname // ':: ERROR finding lai_streams namelist')
- end if
- close(nu_nml)
- endif
- call shr_mpi_bcast(stream_year_first_lai , mpicom)
- call shr_mpi_bcast(stream_year_last_lai , mpicom)
- call shr_mpi_bcast(model_year_align_lai , mpicom)
- call shr_mpi_bcast(stream_fldFileName_lai , mpicom)
- call shr_mpi_bcast(lai_tintalgo , mpicom)
-
- if (masterproc) then
- write(iulog,*) ' '
- write(iulog,*) 'lai_stream settings:'
- write(iulog,*) ' stream_year_first_lai = ',stream_year_first_lai
- write(iulog,*) ' stream_year_last_lai = ',stream_year_last_lai
- write(iulog,*) ' model_year_align_lai = ',model_year_align_lai
- write(iulog,*) ' stream_fldFileName_lai = ',trim(stream_fldFileName_lai)
- write(iulog,*) ' lai_tintalgo = ',trim(lai_tintalgo)
- endif
-
- call clm_domain_mct (bounds, dom_clm)
-
- ! create the field list for these lai fields...use in shr_strdata_create
- fldList = shr_string_listCreateField( numLaiFields, laiString )
-
- call shr_strdata_create(sdat_lai,name="laidyn", &
- pio_subsystem=pio_subsystem, &
- pio_iotype=shr_pio_getiotype(inst_name), &
- mpicom=mpicom, compid=comp_id, &
- gsmap=gsmap_global, ggrid=dom_clm, &
- nxg=ldomain%ni, nyg=ldomain%nj, &
- yearFirst=stream_year_first_lai, &
- yearLast=stream_year_last_lai, &
- yearAlign=model_year_align_lai, &
- offset=0, &
- domFilePath='', &
- domFileName=trim(stream_fldFileName_lai), &
- domTvarName='time', &
- domXvarName='lon' , &
- domYvarName='lat' , &
- domAreaName='area', &
- domMaskName='mask', &
- filePath='', &
- filename=(/stream_fldFileName_lai/), &
- fldListFile=fldList, &
- fldListModel=fldList, &
- fillalgo='none', &
- mapalgo=lai_mapalgo, &
- tintalgo=lai_tintalgo, &
- calendar=get_calendar(), &
- taxmode='cycle' )
-
- if (masterproc) then
- call shr_strdata_print(sdat_lai,'LAI data')
- endif
-
- end subroutine lai_init
-
- !==============================================================================
- subroutine lai_advance( bounds )
- !
- ! Advance LAI streams
- !
- ! !USES:
- use clm_time_manager, only : get_curr_date
- !
- ! !ARGUMENTS:
- implicit none
- type(bounds_type) , intent(in) :: bounds
- !
- ! !LOCAL VARIABLES:
- integer :: g, ig ! Indices
- integer :: year ! year (0, ...) for nstep+1
- integer :: mon ! month (1, ..., 12) for nstep+1
- integer :: day ! day of month (1, ..., 31) for nstep+1
- integer :: sec ! seconds into current date for nstep+1
- integer :: mcdate ! Current model date (yyyymmdd)
- !-----------------------------------------------------------------------
-
- call get_curr_date(year, mon, day, sec)
- mcdate = year*10000 + mon*100 + day
-
- call shr_strdata_advance(sdat_lai, mcdate, sec, mpicom, 'laidyn')
- if ( .not. allocated(g_to_ig) )then
- allocate (g_to_ig(bounds%begg:bounds%endg) )
- ig = 0
- do g = bounds%begg,bounds%endg
- ig = ig+1
- g_to_ig(g) = ig
- end do
- end if
-
- end subroutine lai_advance
-
- !==============================================================================
- subroutine lai_interp(bounds, canopystate_inst)
- !
- ! Interpolate data stream information for Lai.
- !
- ! !USES:
- use pftconMod , only : noveg
- use CanopyStateType , only : canopystate_type
- use PatchType , only : patch
- !
- ! !ARGUMENTS:
- implicit none
- type(bounds_type) , intent(in) :: bounds
- type(canopystate_type) , intent(inout) :: canopystate_inst
- !
- ! !LOCAL VARIABLES:
- integer :: ivt, p, ip, ig
- character(len=CL) :: stream_var_name
- !-----------------------------------------------------------------------
- SHR_ASSERT_FL( (lbound(g_to_ig,1) <= bounds%begg ), sourcefile, __LINE__)
- SHR_ASSERT_FL( (ubound(g_to_ig,1) >= bounds%endg ), sourcefile, __LINE__)
- SHR_ASSERT_FL( (lbound(sdat_lai%avs(1)%rAttr,2) <= g_to_ig(bounds%begg) ), sourcefile, __LINE__)
- SHR_ASSERT_FL( (ubound(sdat_lai%avs(1)%rAttr,2) >= g_to_ig(bounds%endg) ), sourcefile, __LINE__)
-
- do p = bounds%begp, bounds%endp
- ivt = patch%itype(p)
- ! Set lai for each gridcell/patch combination
- if (ivt /= noveg) then
- ! vegetated pft
- write(stream_var_name,"(i6)") ivt
- stream_var_name = 'LAI_'//trim(adjustl(stream_var_name))
- ip = mct_aVect_indexRA(sdat_lai%avs(1),trim(stream_var_name))
- ig = g_to_ig(patch%gridcell(p))
- canopystate_inst%tlai_patch(p) = sdat_lai%avs(1)%rAttr(ip,ig)
- else
- ! non-vegetated pft
- canopystate_inst%tlai_patch(p) = 0._r8
- endif
- end do
-
- end subroutine lai_interp
-
-end module LaiStreamMod
diff --git a/src/cpl/mct/lnd_comp_mct.F90 b/src/cpl/mct/lnd_comp_mct.F90
deleted file mode 100644
index e50602a378..0000000000
--- a/src/cpl/mct/lnd_comp_mct.F90
+++ /dev/null
@@ -1,632 +0,0 @@
-module lnd_comp_mct
-
- !---------------------------------------------------------------------------
- ! !DESCRIPTION:
- ! Interface of the active land model component of CESM the CLM (Community Land Model)
- ! with the main CESM driver. This is a thin interface taking CESM driver information
- ! in MCT (Model Coupling Toolkit) format and converting it to use by CLM.
- !
- ! !uses:
- use shr_kind_mod , only : r8 => shr_kind_r8
- use shr_sys_mod , only : shr_sys_flush
- use shr_log_mod , only : errMsg => shr_log_errMsg
- use mct_mod , only : mct_avect, mct_gsmap, mct_gGrid
- use decompmod , only : bounds_type
- use lnd_import_export, only : lnd_import, lnd_export
- !
- ! !public member functions:
- implicit none
- private ! by default make data private
- !
- ! !public member functions:
- public :: lnd_init_mct ! clm initialization
- public :: lnd_run_mct ! clm run phase
- public :: lnd_final_mct ! clm finalization/cleanup
- !
- ! !private member functions:
- private :: lnd_domain_mct ! set the land model domain information
- private :: lnd_handle_resume ! handle pause/resume signals from the coupler
-
- character(len=*), parameter, private :: sourcefile = &
- __FILE__
-
-!====================================================================================
-contains
-!====================================================================================
-
- subroutine lnd_init_mct( EClock, cdata_l, x2l_l, l2x_l, NLFilename )
- !
- ! !DESCRIPTION:
- ! Initialize land surface model and obtain relevant atmospheric model arrays
- ! back from (i.e. albedos, surface temperature and snow cover over land).
- !
- ! !USES:
- use shr_kind_mod , only : shr_kind_cl
- use abortutils , only : endrun
- use clm_time_manager , only : get_nstep, set_timemgr_init
- use clm_initializeMod, only : initialize1, initialize2
- use clm_instMod , only : water_inst, lnd2atm_inst, lnd2glc_inst
- use clm_varctl , only : finidat, single_column, clm_varctl_set, iulog
- use clm_varctl , only : inst_index, inst_suffix, inst_name
- use clm_varorb , only : eccen, obliqr, lambm0, mvelpp
- use controlMod , only : control_setNL
- use decompMod , only : get_proc_bounds
- use domainMod , only : ldomain
- use shr_file_mod , only : shr_file_setLogUnit, shr_file_setLogLevel
- use shr_file_mod , only : shr_file_getLogUnit, shr_file_getLogLevel
- use shr_file_mod , only : shr_file_getUnit, shr_file_setIO
- use seq_cdata_mod , only : seq_cdata, seq_cdata_setptrs
- use seq_timemgr_mod , only : seq_timemgr_EClockGetData
- use seq_infodata_mod , only : seq_infodata_type, seq_infodata_GetData, seq_infodata_PutData, &
- seq_infodata_start_type_start, seq_infodata_start_type_cont, &
- seq_infodata_start_type_brnch
- use seq_comm_mct , only : seq_comm_suffix, seq_comm_inst, seq_comm_name
- use seq_flds_mod , only : seq_flds_x2l_fields, seq_flds_l2x_fields
- use spmdMod , only : masterproc, spmd_init
- use clm_varctl , only : nsrStartup, nsrContinue, nsrBranch
- use clm_cpl_indices , only : clm_cpl_indices_set
- use mct_mod , only : mct_aVect_init, mct_aVect_zero, mct_gsMap, mct_gsMap_init
- use decompMod , only : gindex_global
- use lnd_set_decomp_and_domain, only : lnd_set_decomp_and_domain_from_surfrd, gsmap_global
- use ESMF
- !
- ! !ARGUMENTS:
- type(ESMF_Clock), intent(inout) :: EClock ! Input synchronization clock
- type(seq_cdata), intent(inout) :: cdata_l ! Input land-model driver data
- type(mct_aVect), intent(inout) :: x2l_l, l2x_l ! land model import and export states
- character(len=*), optional, intent(in) :: NLFilename ! Namelist filename to read
- !
- ! !LOCAL VARIABLES:
- integer :: LNDID ! Land identifyer
- integer :: mpicom_lnd ! MPI communicator
- type(mct_gsMap), pointer :: GSMap_lnd ! Land model MCT GS map
- type(mct_gGrid), pointer :: dom_l ! Land model domain
- type(seq_infodata_type), pointer :: infodata ! CESM driver level info data
- integer :: lsize ! size of attribute vector
- integer :: gsize ! global size
- integer :: g,i,j ! indices
- integer :: dtime_sync ! coupling time-step from the input synchronization clock
- logical :: exists ! true if file exists
- logical :: atm_aero ! Flag if aerosol data sent from atm model
- real(r8) :: scmlat ! single-column latitude
- real(r8) :: scmlon ! single-column longitude
- character(len=SHR_KIND_CL) :: caseid ! case identifier name
- character(len=SHR_KIND_CL) :: ctitle ! case description title
- character(len=SHR_KIND_CL) :: starttype ! start-type (startup, continue, branch, hybrid)
- character(len=SHR_KIND_CL) :: calendar ! calendar type name
- character(len=SHR_KIND_CL) :: hostname ! hostname of machine running on
- character(len=SHR_KIND_CL) :: version ! Model version
- character(len=SHR_KIND_CL) :: username ! user running the model
- integer :: nsrest ! clm restart type
- integer :: ref_ymd ! reference date (YYYYMMDD)
- integer :: ref_tod ! reference time of day (sec)
- integer :: start_ymd ! start date (YYYYMMDD)
- integer :: start_tod ! start time of day (sec)
- logical :: brnch_retain_casename ! flag if should retain the case name on a branch start type
- integer :: lbnum ! input to memory diagnostic
- integer :: shrlogunit,shrloglev ! old values for log unit and log level
- type(bounds_type) :: bounds ! bounds
- logical :: noland
- integer :: ni,nj
- real(r8) , parameter :: rundef = -9999999._r8
- character(len=32), parameter :: sub = 'lnd_init_mct'
- character(len=*), parameter :: format = "('("//trim(sub)//") :',A)"
- !-----------------------------------------------------------------------
-
- ! Set cdata data
- call seq_cdata_setptrs(cdata_l, ID=LNDID, mpicom=mpicom_lnd, &
- gsMap=GSMap_lnd, dom=dom_l, infodata=infodata)
-
- ! Determine attriute vector indices
- call clm_cpl_indices_set()
-
- ! Initialize clm MPI communicator
- call spmd_init( mpicom_lnd, LNDID )
-
-#if (defined _MEMTRACE)
- if(masterproc) then
- lbnum=1
- call memmon_dump_fort('memmon.out','lnd_init_mct:start::',lbnum)
- endif
-#endif
-
- inst_name = seq_comm_name(LNDID)
- inst_index = seq_comm_inst(LNDID)
- inst_suffix = seq_comm_suffix(LNDID)
- ! Initialize io log unit
-
- call shr_file_getLogUnit (shrlogunit)
- if (masterproc) then
- inquire(file='lnd_modelio.nml'//trim(inst_suffix),exist=exists)
- if (exists) then
- iulog = shr_file_getUnit()
- call shr_file_setIO('lnd_modelio.nml'//trim(inst_suffix),iulog)
- end if
- write(iulog,format) "CLM land model initialization"
- else
- iulog = shrlogunit
- end if
-
- call shr_file_getLogLevel(shrloglev)
- call shr_file_setLogUnit (iulog)
-
- ! Use infodata to set orbital values
- call seq_infodata_GetData( infodata, orb_eccen=eccen, orb_mvelpp=mvelpp, &
- orb_lambm0=lambm0, orb_obliqr=obliqr )
-
- ! Consistency check on namelist filename
- call control_setNL("lnd_in"//trim(inst_suffix))
-
- ! Initialize clm
- ! initialize1 reads namelists
- ! decomp and domain are set in lnd_set_decomp_and_domain_from_surfrd
- ! initialize2 performs the rest of initialization
- call seq_timemgr_EClockGetData(EClock, &
- start_ymd=start_ymd, &
- start_tod=start_tod, ref_ymd=ref_ymd, &
- ref_tod=ref_tod, &
- calendar=calendar, &
- dtime=dtime_sync)
- if (masterproc) then
- write(iulog,*)'dtime = ',dtime_sync
- end if
- call seq_infodata_GetData(infodata, case_name=caseid, &
- case_desc=ctitle, single_column=single_column, &
- scmlat=scmlat, scmlon=scmlon, &
- brnch_retain_casename=brnch_retain_casename, &
- start_type=starttype, model_version=version, &
- hostname=hostname, username=username )
-
- ! Single Column
- if ( single_column .and. (scmlat == rundef .or. scmlon == rundef ) ) then
- call endrun(msg=' ERROR:: single column mode on -- but scmlat and scmlon are NOT set'//&
- errMsg(sourcefile, __LINE__))
- end if
-
- ! Note that we assume that CTSM's internal dtime matches the coupling time step.
- ! i.e., we currently do NOT allow sub-cycling within a coupling time step.
- call set_timemgr_init( calendar_in=calendar, start_ymd_in=start_ymd, start_tod_in=start_tod, &
- ref_ymd_in=ref_ymd, ref_tod_in=ref_tod, dtime_in=dtime_sync)
-
- if ( trim(starttype) == trim(seq_infodata_start_type_start)) then
- nsrest = nsrStartup
- else if (trim(starttype) == trim(seq_infodata_start_type_cont) ) then
- nsrest = nsrContinue
- else if (trim(starttype) == trim(seq_infodata_start_type_brnch)) then
- nsrest = nsrBranch
- else
- call endrun( sub//' ERROR: unknown starttype' )
- end if
-
- ! set default values for run control variables
- call clm_varctl_set(caseid_in=caseid, ctitle_in=ctitle, &
- brnch_retain_casename_in=brnch_retain_casename, &
- single_column_in=single_column, scmlat_in=scmlat, &
- scmlon_in=scmlon, nsrest_in=nsrest, version_in=version, &
- hostname_in=hostname, username_in=username)
-
- ! Read namelists
- call initialize1(dtime=dtime_sync)
-
- ! Initialize decomposition and domain (ldomain) type
- call lnd_set_decomp_and_domain_from_surfrd(noland, ni, nj)
-
- ! If no land then exit out of initialization
- if ( noland ) then
-
- call seq_infodata_PutData( infodata, lnd_present =.false.)
- call seq_infodata_PutData( infodata, lnd_prognostic=.false.)
-
- else
-
- ! Determine if aerosol and dust deposition come from atmosphere component
- call seq_infodata_GetData(infodata, atm_aero=atm_aero )
- if ( .not. atm_aero )then
- call endrun( sub//' ERROR: atmosphere model MUST send aerosols to CLM' )
- end if
-
- ! Initialize clm gsMap, clm domain and clm attribute vectors
- call get_proc_bounds( bounds )
- lsize = bounds%endg - bounds%begg + 1
- gsize = ldomain%ni * ldomain%nj
- call mct_gsMap_init( gsMap_lnd, gindex_global, mpicom_lnd, LNDID, lsize, gsize )
- gsmap_global => gsmap_lnd ! module variable in lnd_set_decomp_and_domain
- call lnd_domain_mct( bounds, lsize, gsMap_lnd, dom_l )
- call mct_aVect_init(x2l_l, rList=seq_flds_x2l_fields, lsize=lsize)
- call mct_aVect_zero(x2l_l)
- call mct_aVect_init(l2x_l, rList=seq_flds_l2x_fields, lsize=lsize)
- call mct_aVect_zero(l2x_l)
-
- ! Finish initializing clm
- call initialize2(ni,nj)
-
- ! Create land export state
- call lnd_export(bounds, water_inst%waterlnd2atmbulk_inst, lnd2atm_inst, lnd2glc_inst, l2x_l%rattr)
-
- ! Fill in infodata settings
- call seq_infodata_PutData(infodata, lnd_prognostic=.true.)
- call seq_infodata_PutData(infodata, lnd_nx=ldomain%ni, lnd_ny=ldomain%nj)
- call lnd_handle_resume( cdata_l )
-
- ! Reset shr logging to original values
- call shr_file_setLogUnit (shrlogunit)
- call shr_file_setLogLevel(shrloglev)
-
-#if (defined _MEMTRACE)
- if(masterproc) then
- write(iulog,*) TRIM(Sub) // ':end::'
- lbnum=1
- call memmon_dump_fort('memmon.out','lnd_int_mct:end::',lbnum)
- call memmon_reset_addr()
- endif
-#endif
- end if
-
- end subroutine lnd_init_mct
-
- !====================================================================================
- subroutine lnd_run_mct(EClock, cdata_l, x2l_l, l2x_l)
- !
- ! !DESCRIPTION:
- ! Run clm model
- !
- ! !USES:
- use shr_kind_mod , only : r8 => shr_kind_r8
- use clm_instMod , only : water_inst, lnd2atm_inst, atm2lnd_inst, lnd2glc_inst, glc2lnd_inst
- use clm_driver , only : clm_drv
- use clm_time_manager, only : get_curr_date, get_nstep, get_curr_calday, get_step_size
- use clm_time_manager, only : advance_timestep, update_rad_dtime
- use decompMod , only : get_proc_bounds
- use abortutils , only : endrun
- use clm_varctl , only : iulog
- use clm_varorb , only : eccen, obliqr, lambm0, mvelpp
- use shr_file_mod , only : shr_file_setLogUnit, shr_file_setLogLevel
- use shr_file_mod , only : shr_file_getLogUnit, shr_file_getLogLevel
- use seq_cdata_mod , only : seq_cdata, seq_cdata_setptrs
- use seq_timemgr_mod , only : seq_timemgr_EClockGetData, seq_timemgr_StopAlarmIsOn
- use seq_timemgr_mod , only : seq_timemgr_RestartAlarmIsOn, seq_timemgr_EClockDateInSync
- use seq_infodata_mod, only : seq_infodata_type, seq_infodata_GetData
- use spmdMod , only : masterproc, mpicom
- use perf_mod , only : t_startf, t_stopf, t_barrierf
- use shr_orb_mod , only : shr_orb_decl
- use ESMF
- !
- ! !ARGUMENTS:
- type(ESMF_Clock) , intent(inout) :: EClock ! Input synchronization clock from driver
- type(seq_cdata) , intent(inout) :: cdata_l ! Input driver data for land model
- type(mct_aVect) , intent(inout) :: x2l_l ! Import state to land model
- type(mct_aVect) , intent(inout) :: l2x_l ! Export state from land model
- !
- ! !LOCAL VARIABLES:
- integer :: ymd_sync ! Sync date (YYYYMMDD)
- integer :: yr_sync ! Sync current year
- integer :: mon_sync ! Sync current month
- integer :: day_sync ! Sync current day
- integer :: tod_sync ! Sync current time of day (sec)
- integer :: ymd ! CLM current date (YYYYMMDD)
- integer :: yr ! CLM current year
- integer :: mon ! CLM current month
- integer :: day ! CLM current day
- integer :: tod ! CLM current time of day (sec)
- integer :: dtime ! time step increment (sec)
- integer :: nstep ! time step index
- logical :: rstwr_sync ! .true. ==> write restart file before returning
- logical :: rstwr ! .true. ==> write restart file before returning
- logical :: nlend_sync ! Flag signaling last time-step
- logical :: nlend ! .true. ==> last time-step
- logical :: dosend ! true => send data back to driver
- logical :: doalb ! .true. ==> do albedo calculation on this time step
- logical :: rof_prognostic ! .true. => running with a prognostic ROF model
- logical :: glc_present ! .true. => running with a non-stub GLC model
- real(r8) :: nextsw_cday ! calday from clock of next radiation computation
- real(r8) :: caldayp1 ! clm calday plus dtime offset
- integer :: shrlogunit,shrloglev ! old values for share log unit and log level
- integer :: lbnum ! input to memory diagnostic
- integer :: g,i,lsize ! counters
- real(r8) :: calday ! calendar day for nstep
- real(r8) :: declin ! solar declination angle in radians for nstep
- real(r8) :: declinp1 ! solar declination angle in radians for nstep+1
- real(r8) :: eccf ! earth orbit eccentricity factor
- real(r8) :: recip ! reciprical
- logical,save :: first_call = .true. ! first call work
- type(seq_infodata_type),pointer :: infodata ! CESM information from the driver
- type(mct_gGrid), pointer :: dom_l ! Land model domain data
- type(bounds_type) :: bounds ! bounds
- character(len=32) :: rdate ! date char string for restart file names
- character(len=32), parameter :: sub = "lnd_run_mct"
- !---------------------------------------------------------------------------
-
- ! Determine processor bounds
-
- call get_proc_bounds(bounds)
-
-#if (defined _MEMTRACE)
- if(masterproc) then
- lbnum=1
- call memmon_dump_fort('memmon.out','lnd_run_mct:start::',lbnum)
- endif
-#endif
-
- ! Reset shr logging to my log file
- call shr_file_getLogUnit (shrlogunit)
- call shr_file_getLogLevel(shrloglev)
- call shr_file_setLogUnit (iulog)
-
- ! Determine time of next atmospheric shortwave calculation
- call seq_cdata_setptrs(cdata_l, infodata=infodata, dom=dom_l)
- call seq_timemgr_EClockGetData(EClock, &
- curr_ymd=ymd, curr_tod=tod_sync, &
- curr_yr=yr_sync, curr_mon=mon_sync, curr_day=day_sync)
- call seq_infodata_GetData(infodata, nextsw_cday=nextsw_cday )
-
- dtime = get_step_size()
-
- ! Handle pause/resume signals from coupler
- call lnd_handle_resume( cdata_l )
-
- write(rdate,'(i4.4,"-",i2.2,"-",i2.2,"-",i5.5)') yr_sync,mon_sync,day_sync,tod_sync
- nlend_sync = seq_timemgr_StopAlarmIsOn( EClock )
- rstwr_sync = seq_timemgr_RestartAlarmIsOn( EClock )
-
- ! Determine if we're running with a prognostic ROF model, and if we're running with a
- ! non-stub GLC model. These won't change throughout the run, but we can't count on
- ! their being set in initialization, so need to get them in the run method.
-
- call seq_infodata_GetData( infodata, &
- rof_prognostic=rof_prognostic, &
- glc_present=glc_present)
-
- ! Map MCT to land data type
- ! Perform downscaling if appropriate
-
-
- ! Map to clm (only when state and/or fluxes need to be updated)
-
- call t_startf ('lc_lnd_import')
- call lnd_import( bounds, &
- x2l = x2l_l%rattr, &
- glc_present = glc_present, &
- atm2lnd_inst = atm2lnd_inst, &
- glc2lnd_inst = glc2lnd_inst, &
- wateratm2lndbulk_inst = water_inst%wateratm2lndbulk_inst)
- call t_stopf ('lc_lnd_import')
-
- ! Use infodata to set orbital values if updated mid-run
-
- call seq_infodata_GetData( infodata, orb_eccen=eccen, orb_mvelpp=mvelpp, &
- orb_lambm0=lambm0, orb_obliqr=obliqr )
-
- ! Loop over time steps in coupling interval
-
- dosend = .false.
- do while(.not. dosend)
-
- ! Determine if dosend
- ! When time is not updated at the beginning of the loop - then return only if
- ! are in sync with clock before time is updated
- !
- ! NOTE(wjs, 2020-03-09) I think the do while (.not. dosend) loop only is important
- ! for the first time step (when we run 2 steps). After that, we now assume that we
- ! run one time step per coupling interval (based on setting the model's dtime from
- ! the driver). (According to Mariana Vertenstein, sub-cycling (running multiple
- ! land model time steps per coupling interval) used to be supported, but hasn't
- ! been fully supported for a long time.) We may want to rework this logic to make
- ! this more explicit, or - ideally - get rid of this extra time step at the start
- ! of the run, at which point I think we could do away with this looping entirely.
-
- call get_curr_date( yr, mon, day, tod )
- ymd = yr*10000 + mon*100 + day
- tod = tod
- dosend = (seq_timemgr_EClockDateInSync( EClock, ymd, tod))
-
- ! Determine doalb based on nextsw_cday sent from atm model
-
- nstep = get_nstep()
- caldayp1 = get_curr_calday(offset=dtime, reuse_day_365_for_day_366=.true.)
- if (nstep == 0) then
- doalb = .false.
- else if (nstep == 1) then
- doalb = (abs(nextsw_cday- caldayp1) < 1.e-10_r8)
- else
- doalb = (nextsw_cday >= -0.5_r8)
- end if
- call update_rad_dtime(doalb)
-
- ! Determine if time to write restart and stop
-
- rstwr = .false.
- if (rstwr_sync .and. dosend) rstwr = .true.
- nlend = .false.
- if (nlend_sync .and. dosend) nlend = .true.
-
- ! Run clm
-
- call t_barrierf('sync_clm_run1', mpicom)
- call t_startf ('clm_run')
- call t_startf ('shr_orb_decl')
- calday = get_curr_calday(reuse_day_365_for_day_366=.true.)
- call shr_orb_decl( calday , eccen, mvelpp, lambm0, obliqr, declin , eccf )
- call shr_orb_decl( nextsw_cday, eccen, mvelpp, lambm0, obliqr, declinp1, eccf )
- call t_stopf ('shr_orb_decl')
- call clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, rof_prognostic)
- call t_stopf ('clm_run')
-
- ! Create l2x_l export state - add river runoff input to l2x_l if appropriate
-
- call t_startf ('lc_lnd_export')
- call lnd_export(bounds, water_inst%waterlnd2atmbulk_inst, lnd2atm_inst, lnd2glc_inst, l2x_l%rattr)
- call t_stopf ('lc_lnd_export')
-
- ! Advance clm time step
-
- call t_startf ('lc_clm2_adv_timestep')
- call advance_timestep()
- call t_stopf ('lc_clm2_adv_timestep')
-
- end do
-
- ! Check that internal clock is in sync with master clock
-
- call get_curr_date( yr, mon, day, tod, offset=-dtime )
- ymd = yr*10000 + mon*100 + day
- tod = tod
- if ( .not. seq_timemgr_EClockDateInSync( EClock, ymd, tod ) )then
- call seq_timemgr_EclockGetData( EClock, curr_ymd=ymd_sync, curr_tod=tod_sync )
- write(iulog,*)' clm ymd=',ymd ,' clm tod= ',tod
- write(iulog,*)'sync ymd=',ymd_sync,' sync tod= ',tod_sync
- call endrun( sub//":: CLM clock not in sync with Master Sync clock" )
- end if
-
- ! Reset shr logging to my original values
-
- call shr_file_setLogUnit (shrlogunit)
- call shr_file_setLogLevel(shrloglev)
-
-#if (defined _MEMTRACE)
- if(masterproc) then
- lbnum=1
- call memmon_dump_fort('memmon.out','lnd_run_mct:end::',lbnum)
- call memmon_reset_addr()
- endif
-#endif
-
- first_call = .false.
-
- end subroutine lnd_run_mct
-
- !====================================================================================
- subroutine lnd_final_mct( EClock, cdata_l, x2l_l, l2x_l)
- !
- ! !DESCRIPTION:
- ! Finalize land surface model
-
- use seq_cdata_mod ,only : seq_cdata, seq_cdata_setptrs
- use seq_timemgr_mod ,only : seq_timemgr_EClockGetData, seq_timemgr_StopAlarmIsOn
- use seq_timemgr_mod ,only : seq_timemgr_RestartAlarmIsOn, seq_timemgr_EClockDateInSync
- use esmf
- !
- ! !ARGUMENTS:
- type(ESMF_Clock) , intent(inout) :: EClock ! Input synchronization clock from driver
- type(seq_cdata) , intent(inout) :: cdata_l ! Input driver data for land model
- type(mct_aVect) , intent(inout) :: x2l_l ! Import state to land model
- type(mct_aVect) , intent(inout) :: l2x_l ! Export state from land model
- !---------------------------------------------------------------------------
-
- ! fill this in
- end subroutine lnd_final_mct
-
- !====================================================================================
- subroutine lnd_domain_mct( bounds, lsize, gsMap_l, dom_l )
- !
- ! !DESCRIPTION:
- ! Send the land model domain information to the coupler
- !
- ! !USES:
- use clm_varcon , only: re
- use domainMod , only: ldomain
- use spmdMod , only: iam
- use mct_mod , only: mct_gGrid_importIAttr
- use mct_mod , only: mct_gGrid_importRAttr, mct_gGrid_init, mct_gsMap_orderedPoints
- use seq_flds_mod, only: seq_flds_dom_coord, seq_flds_dom_other
- !
- ! !ARGUMENTS:
- type(bounds_type), intent(in) :: bounds ! bounds
- integer , intent(in) :: lsize ! land model domain data size
- type(mct_gsMap), intent(inout) :: gsMap_l ! Output land model MCT GS map
- type(mct_ggrid), intent(out) :: dom_l ! Output domain information for land model
- !
- ! Local Variables
- integer :: g,i,j ! index
- real(r8), pointer :: data(:) ! temporary
- integer , pointer :: idata(:) ! temporary
- !---------------------------------------------------------------------------
- !
- ! Initialize mct domain type
- ! lat/lon in degrees, area in radians^2, mask is 1 (land), 0 (non-land)
- ! Note that in addition land carries around landfrac for the purposes of domain checking
- !
- call mct_gGrid_init( GGrid=dom_l, CoordChars=trim(seq_flds_dom_coord), &
- OtherChars=trim(seq_flds_dom_other), lsize=lsize )
- !
- ! Allocate memory
- !
- allocate(data(lsize))
- !
- ! Determine global gridpoint number attribute, GlobGridNum, which is set automatically by MCT
- !
- call mct_gsMap_orderedPoints(gsMap_l, iam, idata)
- call mct_gGrid_importIAttr(dom_l,'GlobGridNum',idata,lsize)
- !
- ! Determine domain (numbering scheme is: West to East and South to North to South pole)
- ! Initialize attribute vector with special value
- !
- data(:) = -9999.0_R8
- call mct_gGrid_importRAttr(dom_l,"lat" ,data,lsize)
- call mct_gGrid_importRAttr(dom_l,"lon" ,data,lsize)
- call mct_gGrid_importRAttr(dom_l,"area" ,data,lsize)
- call mct_gGrid_importRAttr(dom_l,"aream",data,lsize)
- data(:) = 0.0_R8
- call mct_gGrid_importRAttr(dom_l,"mask" ,data,lsize)
- !
- ! Fill in correct values for domain components
- ! Note aream will be filled in in the atm-lnd mapper
- !
- do g = bounds%begg,bounds%endg
- i = 1 + (g - bounds%begg)
- data(i) = ldomain%lonc(g)
- end do
- call mct_gGrid_importRattr(dom_l,"lon",data,lsize)
-
- do g = bounds%begg,bounds%endg
- i = 1 + (g - bounds%begg)
- data(i) = ldomain%latc(g)
- end do
- call mct_gGrid_importRattr(dom_l,"lat",data,lsize)
-
- do g = bounds%begg,bounds%endg
- i = 1 + (g - bounds%begg)
- data(i) = ldomain%area(g)/(re*re)
- end do
- call mct_gGrid_importRattr(dom_l,"area",data,lsize)
-
- do g = bounds%begg,bounds%endg
- i = 1 + (g - bounds%begg)
- data(i) = real(ldomain%mask(g), r8)
- end do
- call mct_gGrid_importRattr(dom_l,"mask",data,lsize)
-
- do g = bounds%begg,bounds%endg
- i = 1 + (g - bounds%begg)
- data(i) = real(ldomain%frac(g), r8)
- end do
- call mct_gGrid_importRattr(dom_l,"frac",data,lsize)
-
- deallocate(data)
- deallocate(idata)
-
- end subroutine lnd_domain_mct
-
- !====================================================================================
- subroutine lnd_handle_resume( cdata_l )
- !
- ! !DESCRIPTION:
- ! Handle resume signals for Data Assimilation (DA)
- !
- ! !USES:
- use clm_time_manager , only : update_DA_nstep
- use seq_cdata_mod , only : seq_cdata, seq_cdata_setptrs
- implicit none
- ! !ARGUMENTS:
- type(seq_cdata), intent(inout) :: cdata_l ! Input land-model driver data
- ! !LOCAL VARIABLES:
- logical :: resume_from_data_assim ! flag if we are resuming after data assimulation was done
- !---------------------------------------------------------------------------
-
- ! Check to see if restart was modified and we are resuming from data
- ! assimilation
- call seq_cdata_setptrs(cdata_l, post_assimilation=resume_from_data_assim)
- if ( resume_from_data_assim ) call update_DA_nstep()
-
- end subroutine lnd_handle_resume
-
-end module lnd_comp_mct
diff --git a/src/cpl/mct/lnd_import_export.F90 b/src/cpl/mct/lnd_import_export.F90
deleted file mode 100644
index 537abd49d9..0000000000
--- a/src/cpl/mct/lnd_import_export.F90
+++ /dev/null
@@ -1,354 +0,0 @@
-module lnd_import_export
-
- use shr_kind_mod , only: r8 => shr_kind_r8, cl=>shr_kind_cl
- use abortutils , only: endrun
- use decompmod , only: bounds_type, subgrid_level_gridcell
- use lnd2atmType , only: lnd2atm_type
- use lnd2glcMod , only: lnd2glc_type
- use atm2lndType , only: atm2lnd_type
- use glc2lndMod , only: glc2lnd_type
- use Waterlnd2atmBulkType , only: waterlnd2atmbulk_type
- use Wateratm2lndBulkType , only: wateratm2lndbulk_type
- use clm_cpl_indices
- use GridcellType , only : grc
- !
- implicit none
- !===============================================================================
-
-contains
-
- !===============================================================================
- subroutine lnd_import( bounds, x2l, glc_present, atm2lnd_inst, glc2lnd_inst, wateratm2lndbulk_inst)
-
- !---------------------------------------------------------------------------
- ! !DESCRIPTION:
- ! Convert the input data from the coupler to the land model
- !
- ! !USES:
- use seq_flds_mod , only: seq_flds_x2l_fields
- use clm_varctl , only: co2_type, co2_ppmv, iulog, use_c13
- use clm_varctl , only: ndep_from_cpl
- use clm_varcon , only: c13ratio
- use domainMod , only: ldomain
- use lnd_import_export_utils, only : derive_quantities, check_for_errors, check_for_nans
- !
- ! !ARGUMENTS:
- type(bounds_type) , intent(in) :: bounds ! bounds
- real(r8) , intent(in) :: x2l(:,:) ! driver import state to land model
- logical , intent(in) :: glc_present ! .true. => running with a non-stub GLC model
- type(atm2lnd_type) , intent(inout) :: atm2lnd_inst ! clm internal input data type
- type(glc2lnd_type) , intent(inout) :: glc2lnd_inst ! clm internal input data type
- type(wateratm2lndbulk_type), intent(inout) :: wateratm2lndbulk_inst ! clm internal input data type
- !
- ! !LOCAL VARIABLES:
- integer :: begg, endg ! bounds
- integer :: g,i,k,nstep,ier ! indices, number of steps, and error code
- real(r8) :: qsat_kg_kg ! saturation specific humidity (kg/kg)
- real(r8) :: forc_pbot ! atmospheric pressure (Pa)
- real(r8) :: forc_rainc(bounds%begg:bounds%endg) ! rainxy Atm flux mm/s
- real(r8) :: forc_rainl(bounds%begg:bounds%endg) ! rainxy Atm flux mm/s
- real(r8) :: forc_snowc(bounds%begg:bounds%endg) ! snowfxy Atm flux mm/s
- real(r8) :: forc_snowl(bounds%begg:bounds%endg) ! snowfxl Atm flux mm/s
- real(r8) :: co2_ppmv_diag ! temporary
- real(r8) :: co2_ppmv_prog ! temporary
- real(r8) :: co2_ppmv_val ! temporary
- integer :: co2_type_idx ! integer flag for co2_type options
- character(len=32) :: fname ! name of field that is NaN
- character(len=32), parameter :: sub = 'lnd_import'
-
- !---------------------------------------------------------------------------
-
- ! Set bounds
- begg = bounds%begg; endg = bounds%endg
-
- co2_type_idx = 0
- if (co2_type == 'prognostic') then
- co2_type_idx = 1
- else if (co2_type == 'diagnostic') then
- co2_type_idx = 2
- end if
- if (co2_type == 'prognostic' .and. index_x2l_Sa_co2prog == 0) then
- call endrun( sub//' ERROR: must have nonzero index_x2l_Sa_co2prog for co2_type equal to prognostic' )
- else if (co2_type == 'diagnostic' .and. index_x2l_Sa_co2diag == 0) then
- call endrun( sub//' ERROR: must have nonzero index_x2l_Sa_co2diag for co2_type equal to diagnostic' )
- end if
-
- ! Note that the precipitation fluxes received from the coupler
- ! are in units of kg/s/m^2. To convert these precipitation rates
- ! in units of mm/sec, one must divide by 1000 kg/m^3 and multiply
- ! by 1000 mm/m resulting in an overall factor of unity.
- ! Below the units are therefore given in mm/s.
-
- do g = begg,endg
- i = 1 + (g - begg)
-
- ! Determine flooding input, sign convention is positive downward and
- ! hierarchy is atm/glc/lnd/rof/ice/ocn. so water sent from rof to land is negative,
- ! change the sign to indicate addition of water to system.
-
- wateratm2lndbulk_inst%forc_flood_grc(g) = -x2l(index_x2l_Flrr_flood,i)
-
- wateratm2lndbulk_inst%volr_grc(g) = x2l(index_x2l_Flrr_volr,i) * (ldomain%area(g) * 1.e6_r8)
- wateratm2lndbulk_inst%volrmch_grc(g)= x2l(index_x2l_Flrr_volrmch,i) * (ldomain%area(g) * 1.e6_r8)
-
- ! Determine required receive fields
-
- atm2lnd_inst%forc_hgt_grc(g) = x2l(index_x2l_Sa_z,i) ! zgcmxy Atm state m
- atm2lnd_inst%forc_topo_grc(g) = x2l(index_x2l_Sa_topo,i) ! Atm surface height (m)
- atm2lnd_inst%forc_u_grc(g) = x2l(index_x2l_Sa_u,i) ! forc_uxy Atm state m/s
- atm2lnd_inst%forc_v_grc(g) = x2l(index_x2l_Sa_v,i) ! forc_vxy Atm state m/s
- atm2lnd_inst%forc_solad_not_downscaled_grc(g,2) = x2l(index_x2l_Faxa_swndr,i) ! forc_sollxy Atm flux W/m^2
- atm2lnd_inst%forc_solad_not_downscaled_grc(g,1) = x2l(index_x2l_Faxa_swvdr,i) ! forc_solsxy Atm flux W/m^2
- atm2lnd_inst%forc_solai_grc(g,2) = x2l(index_x2l_Faxa_swndf,i) ! forc_solldxy Atm flux W/m^2
- atm2lnd_inst%forc_solai_grc(g,1) = x2l(index_x2l_Faxa_swvdf,i) ! forc_solsdxy Atm flux W/m^2
-
- atm2lnd_inst%forc_th_not_downscaled_grc(g) = x2l(index_x2l_Sa_ptem,i) ! forc_thxy Atm state K
- wateratm2lndbulk_inst%forc_q_not_downscaled_grc(g) = x2l(index_x2l_Sa_shum,i) ! forc_qxy Atm state kg/kg
- atm2lnd_inst%forc_pbot_not_downscaled_grc(g) = x2l(index_x2l_Sa_pbot,i) ! ptcmxy Atm state Pa
- atm2lnd_inst%forc_t_not_downscaled_grc(g) = x2l(index_x2l_Sa_tbot,i) ! forc_txy Atm state K
- atm2lnd_inst%forc_lwrad_not_downscaled_grc(g) = x2l(index_x2l_Faxa_lwdn,i) ! flwdsxy Atm flux W/m^2
-
- forc_rainc(g) = x2l(index_x2l_Faxa_rainc,i) ! mm/s
- forc_rainl(g) = x2l(index_x2l_Faxa_rainl,i) ! mm/s
- forc_snowc(g) = x2l(index_x2l_Faxa_snowc,i) ! mm/s
- forc_snowl(g) = x2l(index_x2l_Faxa_snowl,i) ! mm/s
-
- ! atmosphere coupling, for prognostic/prescribed aerosols
- atm2lnd_inst%forc_aer_grc(g,1) = x2l(index_x2l_Faxa_bcphidry,i)
- atm2lnd_inst%forc_aer_grc(g,2) = x2l(index_x2l_Faxa_bcphodry,i)
- atm2lnd_inst%forc_aer_grc(g,3) = x2l(index_x2l_Faxa_bcphiwet,i)
- atm2lnd_inst%forc_aer_grc(g,4) = x2l(index_x2l_Faxa_ocphidry,i)
- atm2lnd_inst%forc_aer_grc(g,5) = x2l(index_x2l_Faxa_ocphodry,i)
- atm2lnd_inst%forc_aer_grc(g,6) = x2l(index_x2l_Faxa_ocphiwet,i)
- atm2lnd_inst%forc_aer_grc(g,7) = x2l(index_x2l_Faxa_dstwet1,i)
- atm2lnd_inst%forc_aer_grc(g,8) = x2l(index_x2l_Faxa_dstdry1,i)
- atm2lnd_inst%forc_aer_grc(g,9) = x2l(index_x2l_Faxa_dstwet2,i)
- atm2lnd_inst%forc_aer_grc(g,10) = x2l(index_x2l_Faxa_dstdry2,i)
- atm2lnd_inst%forc_aer_grc(g,11) = x2l(index_x2l_Faxa_dstwet3,i)
- atm2lnd_inst%forc_aer_grc(g,12) = x2l(index_x2l_Faxa_dstdry3,i)
- atm2lnd_inst%forc_aer_grc(g,13) = x2l(index_x2l_Faxa_dstwet4,i)
- atm2lnd_inst%forc_aer_grc(g,14) = x2l(index_x2l_Faxa_dstdry4,i)
-
- if (index_x2l_Sa_methane /= 0) then
- atm2lnd_inst%forc_pch4_grc(g) = x2l(index_x2l_Sa_methane,i)
- endif
-
- !--------------------------
- ! Check for nans from coupler
- !--------------------------
-
- call check_for_nans(x2l(:,i), fname, begg, "x2l")
-
- end do
-
- !--------------------------
- ! Derived quantities for required fields
- ! and corresponding error checks
- !--------------------------
-
- call derive_quantities(bounds, atm2lnd_inst, wateratm2lndbulk_inst, &
- forc_rainc, forc_rainl, forc_snowc, forc_snowl)
-
- call check_for_errors(bounds, atm2lnd_inst, wateratm2lndbulk_inst)
-
- ! Determine derived quantities for optional fields
- ! Note that the following does unit conversions from ppmv to partial pressures (Pa)
- ! Note that forc_pbot is in Pa
-
- do g = begg,endg
- i = 1 + (g - begg)
-
- forc_pbot = atm2lnd_inst%forc_pbot_not_downscaled_grc(g)
-
- ! Determine optional receive fields
- if (index_x2l_Sa_co2prog /= 0) then
- co2_ppmv_prog = x2l(index_x2l_Sa_co2prog,i) ! co2 atm state prognostic
- else
- co2_ppmv_prog = co2_ppmv
- end if
- if (index_x2l_Sa_co2diag /= 0) then
- co2_ppmv_diag = x2l(index_x2l_Sa_co2diag,i) ! co2 atm state diagnostic
- else
- co2_ppmv_diag = co2_ppmv
- end if
-
- if (co2_type_idx == 1) then
- co2_ppmv_val = co2_ppmv_prog
- else if (co2_type_idx == 2) then
- co2_ppmv_val = co2_ppmv_diag
- else
- co2_ppmv_val = co2_ppmv
- end if
- if ( (co2_ppmv_val < 10.0_r8) .or. (co2_ppmv_val > 15000.0_r8) )then
- call endrun(subgrid_index=g, subgrid_level=subgrid_level_gridcell, &
- msg = sub//' ERROR: CO2 is outside of an expected range' )
- end if
- atm2lnd_inst%forc_pco2_grc(g) = co2_ppmv_val * 1.e-6_r8 * forc_pbot
- if (use_c13) then
- atm2lnd_inst%forc_pc13o2_grc(g) = co2_ppmv_val * c13ratio * 1.e-6_r8 * forc_pbot
- end if
-
- if (ndep_from_cpl) then
- ! The coupler is sending ndep in units if kgN/m2/s - and clm uses units of gN/m2/sec - so the
- ! following conversion needs to happen
- atm2lnd_inst%forc_ndep_grc(g) = (x2l(index_x2l_Faxa_nhx, i) + x2l(index_x2l_faxa_noy, i))*1000._r8
- end if
-
- end do
-
- call glc2lnd_inst%set_glc2lnd_fields_mct( &
- bounds = bounds, &
- glc_present = glc_present, &
- ! NOTE(wjs, 2017-12-13) the x2l argument doesn't have the typical bounds
- ! subsetting (bounds%begg:bounds%endg). This mirrors the lack of these bounds in
- ! the call to lnd_import from lnd_run_mct. This is okay as long as this code is
- ! outside a clump loop.
- x2l = x2l, &
- index_x2l_Sg_ice_covered = index_x2l_Sg_ice_covered, &
- index_x2l_Sg_topo = index_x2l_Sg_topo, &
- index_x2l_Flgg_hflx = index_x2l_Flgg_hflx, &
- index_x2l_Sg_icemask = index_x2l_Sg_icemask, &
- index_x2l_Sg_icemask_coupled_fluxes = index_x2l_Sg_icemask_coupled_fluxes)
-
- end subroutine lnd_import
-
- !===============================================================================
-
- subroutine lnd_export( bounds, waterlnd2atmbulk_inst, lnd2atm_inst, lnd2glc_inst, l2x)
-
- !---------------------------------------------------------------------------
- ! !DESCRIPTION:
- ! Convert the data to be sent from the clm model to the coupler
- !
- ! !USES:
- use shr_kind_mod , only : r8 => shr_kind_r8
- use seq_flds_mod , only : seq_flds_l2x_fields
- use clm_varctl , only : iulog
- use shr_drydep_mod , only : n_drydep
- use shr_megan_mod , only : shr_megan_mechcomps_n
- use shr_fire_emis_mod , only : shr_fire_emis_mechcomps_n
- use lnd_import_export_utils, only : check_for_nans
- !
- ! !ARGUMENTS:
- implicit none
- type(bounds_type) , intent(in) :: bounds ! bounds
- type(lnd2atm_type), intent(inout) :: lnd2atm_inst ! clm land to atmosphere exchange data type
- type(lnd2glc_type), intent(inout) :: lnd2glc_inst ! clm land to atmosphere exchange data type
- type(waterlnd2atmbulk_type), intent(in) :: waterlnd2atmbulk_inst
- real(r8) , intent(out) :: l2x(:,:)! land to coupler export state on land grid
- !
- ! !LOCAL VARIABLES:
- integer :: begg, endg ! bounds
- integer :: g,i,k ! indices
- integer :: ier ! error status
- integer :: nstep ! time step index
- integer :: dtime ! time step
- integer :: num ! counter
- character(len=32) :: fname ! name of field that is NaN
- character(len=32), parameter :: sub = 'lnd_export'
- !---------------------------------------------------------------------------
-
- ! Set bounds
- begg = bounds%begg; endg = bounds%endg
-
- ! cesm sign convention is that fluxes are positive downward
-
- l2x(:,:) = 0.0_r8
-
- do g = begg,endg
- i = 1 + (g-begg)
- l2x(index_l2x_Sl_t,i) = lnd2atm_inst%t_rad_grc(g)
- l2x(index_l2x_Sl_snowh,i) = waterlnd2atmbulk_inst%h2osno_grc(g)
- l2x(index_l2x_Sl_avsdr,i) = lnd2atm_inst%albd_grc(g,1)
- l2x(index_l2x_Sl_anidr,i) = lnd2atm_inst%albd_grc(g,2)
- l2x(index_l2x_Sl_avsdf,i) = lnd2atm_inst%albi_grc(g,1)
- l2x(index_l2x_Sl_anidf,i) = lnd2atm_inst%albi_grc(g,2)
- l2x(index_l2x_Sl_tref,i) = lnd2atm_inst%t_ref2m_grc(g)
- l2x(index_l2x_Sl_qref,i) = waterlnd2atmbulk_inst%q_ref2m_grc(g)
- l2x(index_l2x_Sl_u10,i) = lnd2atm_inst%u_ref10m_grc(g)
- l2x(index_l2x_Fall_taux,i) = -lnd2atm_inst%taux_grc(g)
- l2x(index_l2x_Fall_tauy,i) = -lnd2atm_inst%tauy_grc(g)
- l2x(index_l2x_Fall_lat,i) = -lnd2atm_inst%eflx_lh_tot_grc(g)
- l2x(index_l2x_Fall_sen,i) = -lnd2atm_inst%eflx_sh_tot_grc(g)
- l2x(index_l2x_Fall_lwup,i) = -lnd2atm_inst%eflx_lwrad_out_grc(g)
- l2x(index_l2x_Fall_evap,i) = -waterlnd2atmbulk_inst%qflx_evap_tot_grc(g)
- l2x(index_l2x_Fall_swnet,i) = lnd2atm_inst%fsa_grc(g)
- if (index_l2x_Fall_fco2_lnd /= 0) then
- l2x(index_l2x_Fall_fco2_lnd,i) = -lnd2atm_inst%net_carbon_exchange_grc(g)
- end if
-
- ! Additional fields for DUST, PROGSSLT, dry-deposition and VOC
- ! These are now standard fields, but the check on the index makes sure the driver handles them
- if (index_l2x_Sl_ram1 /= 0 ) l2x(index_l2x_Sl_ram1,i) = lnd2atm_inst%ram1_grc(g)
- if (index_l2x_Sl_fv /= 0 ) l2x(index_l2x_Sl_fv,i) = lnd2atm_inst%fv_grc(g)
- if (index_l2x_Sl_soilw /= 0 ) l2x(index_l2x_Sl_soilw,i) = waterlnd2atmbulk_inst%h2osoi_vol_grc(g,1)
- if (index_l2x_Fall_flxdst1 /= 0 ) l2x(index_l2x_Fall_flxdst1,i)= -lnd2atm_inst%flxdst_grc(g,1)
- if (index_l2x_Fall_flxdst2 /= 0 ) l2x(index_l2x_Fall_flxdst2,i)= -lnd2atm_inst%flxdst_grc(g,2)
- if (index_l2x_Fall_flxdst3 /= 0 ) l2x(index_l2x_Fall_flxdst3,i)= -lnd2atm_inst%flxdst_grc(g,3)
- if (index_l2x_Fall_flxdst4 /= 0 ) l2x(index_l2x_Fall_flxdst4,i)= -lnd2atm_inst%flxdst_grc(g,4)
-
-
- ! for dry dep velocities
- if (index_l2x_Sl_ddvel /= 0 ) then
- l2x(index_l2x_Sl_ddvel:index_l2x_Sl_ddvel+n_drydep-1,i) = &
- lnd2atm_inst%ddvel_grc(g,:n_drydep)
- end if
-
- ! for MEGAN VOC emis fluxes
- if (index_l2x_Fall_flxvoc /= 0 ) then
- l2x(index_l2x_Fall_flxvoc:index_l2x_Fall_flxvoc+shr_megan_mechcomps_n-1,i) = &
- -lnd2atm_inst%flxvoc_grc(g,:shr_megan_mechcomps_n)
- end if
-
-
- ! for fire emis fluxes
- if (index_l2x_Fall_flxfire /= 0 ) then
- l2x(index_l2x_Fall_flxfire:index_l2x_Fall_flxfire+shr_fire_emis_mechcomps_n-1,i) = &
- -lnd2atm_inst%fireflx_grc(g,:shr_fire_emis_mechcomps_n)
- l2x(index_l2x_Sl_ztopfire,i) = lnd2atm_inst%fireztop_grc(g)
- end if
-
- if (index_l2x_Fall_methane /= 0) then
- l2x(index_l2x_Fall_methane,i) = -lnd2atm_inst%ch4_surf_flux_tot_grc(g)
- endif
-
- ! sign convention is positive downward with
- ! hierarchy of atm/glc/lnd/rof/ice/ocn.
- ! I.e. water sent from land to rof is positive
-
- l2x(index_l2x_Flrl_rofsur,i) = waterlnd2atmbulk_inst%qflx_rofliq_qsur_grc(g)
-
- ! subsurface runoff is the sum of qflx_drain and qflx_perched_drain
- l2x(index_l2x_Flrl_rofsub,i) = waterlnd2atmbulk_inst%qflx_rofliq_qsub_grc(g) &
- + waterlnd2atmbulk_inst%qflx_rofliq_drain_perched_grc(g)
-
- ! qgwl sent individually to coupler
- l2x(index_l2x_Flrl_rofgwl,i) = waterlnd2atmbulk_inst%qflx_rofliq_qgwl_grc(g)
-
- ! ice sent individually to coupler
- l2x(index_l2x_Flrl_rofi,i) = waterlnd2atmbulk_inst%qflx_rofice_grc(g)
-
- ! irrigation flux to be removed from main channel storage (negative)
- l2x(index_l2x_Flrl_irrig,i) = - waterlnd2atmbulk_inst%qirrig_grc(g)
-
- ! glc coupling
- ! We could avoid setting these fields if glc_present is .false., if that would
- ! help with performance. (The downside would be that we wouldn't have these fields
- ! available for diagnostic purposes or to force a later T compset with dlnd.)
- do num = 0,glc_nec
- l2x(index_l2x_Sl_tsrf(num),i) = lnd2glc_inst%tsrf_grc(g,num)
- l2x(index_l2x_Sl_topo(num),i) = lnd2glc_inst%topo_grc(g,num)
- l2x(index_l2x_Flgl_qice(num),i) = lnd2glc_inst%qice_grc(g,num)
- end do
-
- !--------------------------
- ! Check for nans to coupler
- !--------------------------
-
- call check_for_nans(l2x(:,i), fname, begg, "l2x")
-
- end do
-
- end subroutine lnd_export
-
-end module lnd_import_export
diff --git a/src/cpl/mct/lnd_set_decomp_and_domain.F90 b/src/cpl/mct/lnd_set_decomp_and_domain.F90
deleted file mode 100644
index 0a37554313..0000000000
--- a/src/cpl/mct/lnd_set_decomp_and_domain.F90
+++ /dev/null
@@ -1,352 +0,0 @@
-module lnd_set_decomp_and_domain
-
- use shr_kind_mod , only : r8 => shr_kind_r8
- use spmdMod , only : masterproc
- use clm_varctl , only : iulog
- use mct_mod , only : mct_gsMap
-
- implicit none
- private ! except
-
- ! public member routines
- public :: lnd_set_decomp_and_domain_from_surfrd
-
- ! private member routines
- private :: surfrd_get_globmask ! Reads global land mask (needed for setting domain decomp)
- private :: surfrd_get_grid ! Read grid/ladnfrac data into domain (after domain decomp)
-
- ! translation between local and global indices at gridcell level
- type(mct_gsmap), pointer, public :: gsmap_global
-
- ! translation between local and global indices at gridcell level for multiple levels
- ! needed for 3d soil moisture stream
- type(mct_gsmap), target , public :: gsMap_lnd2Dsoi_gdc2glo
-
- character(len=*), parameter, private :: sourcefile = &
- __FILE__
-
-!===============================================================================
-contains
-!===============================================================================
-
- subroutine lnd_set_decomp_and_domain_from_surfrd(noland, ni, nj)
-
- ! Initialize ldomain data types
-
- use clm_varpar , only: nlevsoi
- use clm_varctl , only: fatmlndfrc, use_soil_moisture_streams
- use decompInitMod , only: decompInit_lnd
- use decompMod , only: bounds_type, get_proc_bounds
- use domainMod , only: ldomain, domain_check
-
- ! input/output variables
- logical, intent(out) :: noland
- integer, intent(out) :: ni, nj ! global grid sizes
-
- ! local variables
- integer ,pointer :: amask(:) ! global land mask
- integer :: begg, endg ! processor bounds
- type(bounds_type) :: bounds ! bounds
- character(len=32) :: subname = 'lnd_set_decomp_and_domain_from_surfrd'
- !-----------------------------------------------------------------------
-
- ! Read in global land grid and land mask (amask)- needed to set decomposition
- ! global memory for amask is allocate in surfrd_get_glomask - must be deallocated below
- if (masterproc) then
- write(iulog,*) 'Attempting to read global land mask from ',trim(fatmlndfrc)
- endif
-
- ! Get global mask, ni and nj
- call surfrd_get_globmask(filename=fatmlndfrc, mask=amask, ni=ni, nj=nj)
-
- ! Exit early if no valid land points
- if ( all(amask == 0) )then
- if (masterproc) write(iulog,*) trim(subname)//': no valid land points do NOT run clm'
- noland = .true.
- return
- else
- noland = .false.
- end if
-
- ! Determine ctsm gridcell decomposition and processor bounds for gridcells
- call decompInit_lnd(ni, nj, amask)
- deallocate(amask)
- if (use_soil_moisture_streams) call decompInit_lnd3D(ni, nj, nlevsoi)
-
- ! Initialize bounds for just gridcells
- ! Remaining bounds (landunits, columns, patches) will be determined
- ! after the call to decompInit_glcp - so get_proc_bounds is called
- ! twice and the gridcell information is just filled in twice
- call get_proc_bounds(bounds)
-
- ! Get grid cell bounds values
- begg = bounds%begg
- endg = bounds%endg
-
- ! Initialize ldomain data type
- if (masterproc) then
- write(iulog,*) 'Attempting to read ldomain from ',trim(fatmlndfrc)
- endif
- call surfrd_get_grid(begg, endg, ldomain, fatmlndfrc)
- if (masterproc) then
- call domain_check(ldomain)
- endif
- ldomain%mask = 1 !!! TODO - is this needed?
-
- end subroutine lnd_set_decomp_and_domain_from_surfrd
-
- !-----------------------------------------------------------------------
- subroutine surfrd_get_globmask(filename, mask, ni, nj)
-
- ! Read the surface dataset grid related information
- ! This is used to set the domain decomposition - so global data is read here
-
- use fileutils , only : getfil
- use ncdio_pio , only : ncd_io, ncd_pio_openfile, ncd_pio_closefile, ncd_inqfdims, file_desc_t
- use abortutils , only : endrun
- use shr_log_mod, only : errMsg => shr_log_errMsg
-
- ! input/output variables
- character(len=*), intent(in) :: filename ! grid filename
- integer , pointer :: mask(:) ! grid mask
- integer , intent(out) :: ni, nj ! global grid sizes
-
- ! local variables
- logical :: isgrid2d
- integer :: dimid,varid ! netCDF id's
- integer :: ns ! size of grid on file
- integer :: n,i,j ! index
- integer :: ier ! error status
- type(file_desc_t) :: ncid ! netcdf id
- character(len=256) :: locfn ! local file name
- logical :: readvar ! read variable in or not
- integer , allocatable :: idata2d(:,:)
- character(len=32) :: subname = 'surfrd_get_globmask' ! subroutine name
- !-----------------------------------------------------------------------
-
- if (filename == ' ') then
- mask(:) = 1
- else
- ! Check if file exists
- if (masterproc) then
- if (filename == ' ') then
- write(iulog,*) trim(subname),' ERROR: filename must be specified '
- call endrun(msg=errMsg(sourcefile, __LINE__))
- endif
- end if
-
- ! Open file
- call getfil( filename, locfn, 0 )
- call ncd_pio_openfile (ncid, trim(locfn), 0)
-
- ! Determine dimensions and if grid file is 2d or 1d
- call ncd_inqfdims(ncid, isgrid2d, ni, nj, ns)
- if (masterproc) then
- write(iulog,*)'lat/lon grid flag (isgrid2d) is ',isgrid2d
- end if
- allocate(mask(ns))
- mask(:) = 1
- if (isgrid2d) then
- ! Grid is 2d
- allocate(idata2d(ni,nj))
- idata2d(:,:) = 1
- call ncd_io(ncid=ncid, varname='LANDMASK', data=idata2d, flag='read', readvar=readvar)
- if (.not. readvar) then
- call ncd_io(ncid=ncid, varname='mask', data=idata2d, flag='read', readvar=readvar)
- end if
- if (readvar) then
- do j = 1,nj
- do i = 1,ni
- n = (j-1)*ni + i
- mask(n) = idata2d(i,j)
- enddo
- enddo
- end if
- deallocate(idata2d)
- else
- ! Grid is not 2d
- call ncd_io(ncid=ncid, varname='LANDMASK', data=mask, flag='read', readvar=readvar)
- if (.not. readvar) then
- call ncd_io(ncid=ncid, varname='mask', data=mask, flag='read', readvar=readvar)
- end if
- end if
- if (.not. readvar) call endrun( msg=' ERROR: landmask not on fatmlndfrc file'//errMsg(sourcefile, __LINE__))
-
- ! Close file
- call ncd_pio_closefile(ncid)
- end if
-
- end subroutine surfrd_get_globmask
-
- !-----------------------------------------------------------------------
- subroutine surfrd_get_grid(begg, endg, ldomain, filename)
-
- ! Read the surface dataset grid related information:
- ! This is called after the domain decomposition has been created
- ! - real latitude of grid cell (degrees)
- ! - real longitude of grid cell (degrees)
-
- use clm_varcon , only : spval, re, grlnd
- use domainMod , only : domain_type, lon1d, lat1d, domain_init
- use fileutils , only : getfil
- use abortutils , only : endrun
- use shr_log_mod , only : errMsg => shr_log_errMsg
- use ncdio_pio , only : file_desc_t, ncd_pio_openfile, ncd_pio_closefile
- use ncdio_pio , only : ncd_io, check_var, ncd_inqfdims, check_dim_size
- use pio
-
- ! input/output variables
- integer , intent(in) :: begg, endg
- type(domain_type) , intent(inout) :: ldomain ! domain to init
- character(len=*) , intent(in) :: filename ! grid filename
-
- ! local variables
- type(file_desc_t) :: ncid ! netcdf id
- integer :: beg ! local beg index
- integer :: end ! local end index
- integer :: ni,nj,ns ! size of grid on file
- logical :: readvar ! true => variable is on input file
- logical :: isgrid2d ! true => file is 2d lat/lon
- logical :: istype_domain ! true => input file is of type domain
- real(r8), allocatable :: rdata2d(:,:) ! temporary
- character(len=16) :: vname ! temporary
- character(len=256) :: locfn ! local file name
- integer :: n ! indices
- character(len=32) :: subname = 'surfrd_get_grid' ! subroutine name
- !-----------------------------------------------------------------------
-
- if (masterproc) then
- if (filename == ' ') then
- write(iulog,*) trim(subname),' ERROR: filename must be specified '
- call endrun(msg=errMsg(sourcefile, __LINE__))
- endif
- end if
-
- call getfil( filename, locfn, 0 )
- call ncd_pio_openfile (ncid, trim(locfn), 0)
-
- ! Determine dimensions
- call ncd_inqfdims(ncid, isgrid2d, ni, nj, ns)
-
- ! Determine isgrid2d flag for domain
- call domain_init(ldomain, isgrid2d=isgrid2d, ni=ni, nj=nj, nbeg=begg, nend=endg)
-
- ! Determine type of file - old style grid file or new style domain file
- call check_var(ncid=ncid, varname='xc', readvar=readvar)
- if (readvar)then
- istype_domain = .true.
- else
- istype_domain = .false.
- end if
-
- ! Read in area, lon, lat
- if (istype_domain) then
- call ncd_io(ncid=ncid, varname= 'area', flag='read', data=ldomain%area, &
- dim1name=grlnd, readvar=readvar)
- ! convert from radians**2 to km**2
- ldomain%area = ldomain%area * (re**2)
- if (.not. readvar) call endrun( msg=' ERROR: area NOT on file'//errMsg(sourcefile, __LINE__))
- call ncd_io(ncid=ncid, varname= 'xc', flag='read', data=ldomain%lonc, &
- dim1name=grlnd, readvar=readvar)
- if (.not. readvar) call endrun( msg=' ERROR: xc NOT on file'//errMsg(sourcefile, __LINE__))
- call ncd_io(ncid=ncid, varname= 'yc', flag='read', data=ldomain%latc, &
- dim1name=grlnd, readvar=readvar)
- if (.not. readvar) call endrun( msg=' ERROR: yc NOT on file'//errMsg(sourcefile, __LINE__))
- else
- call endrun( msg=" ERROR: can no longer read non domain files" )
- end if
-
- if (isgrid2d) then
- allocate(rdata2d(ni,nj), lon1d(ni), lat1d(nj))
- if (istype_domain) vname = 'xc'
- call ncd_io(ncid=ncid, varname=trim(vname), data=rdata2d, flag='read', readvar=readvar)
- lon1d(:) = rdata2d(:,1)
- if (istype_domain) vname = 'yc'
- call ncd_io(ncid=ncid, varname=trim(vname), data=rdata2d, flag='read', readvar=readvar)
- lat1d(:) = rdata2d(1,:)
- deallocate(rdata2d)
- end if
-
- ! Check lat limited to -90,90
- if (minval(ldomain%latc) < -90.0_r8 .or. &
- maxval(ldomain%latc) > 90.0_r8) then
- write(iulog,*) trim(subname),' WARNING: lat/lon min/max is ', &
- minval(ldomain%latc),maxval(ldomain%latc)
- endif
- if ( any(ldomain%lonc < 0.0_r8) )then
- call endrun( msg=' ERROR: lonc is negative (see https://github.com/ESCOMP/ctsm/issues/507)' &
- //errMsg(sourcefile, __LINE__))
- endif
- call ncd_io(ncid=ncid, varname='mask', flag='read', data=ldomain%mask, &
- dim1name=grlnd, readvar=readvar)
- if (.not. readvar) then
- call endrun( msg=' ERROR: LANDMASK NOT on fracdata file'//errMsg(sourcefile, __LINE__))
- end if
- call ncd_io(ncid=ncid, varname='frac', flag='read', data=ldomain%frac, &
- dim1name=grlnd, readvar=readvar)
- if (.not. readvar) then
- call endrun( msg=' ERROR: LANDFRAC NOT on fracdata file'//errMsg(sourcefile, __LINE__))
- end if
-
- call ncd_pio_closefile(ncid)
-
- end subroutine surfrd_get_grid
-
- !------------------------------------------------------------------------------
- subroutine decompInit_lnd3D(lni,lnj,lnk)
- !
- ! !DESCRIPTION:
- ! Create a 3D decomposition gsmap for the global 2D grid with soil levels
- ! as the 3rd dimesnion.
- !
- ! !USES:
- use decompMod, only : gindex_global, bounds_type, get_proc_bounds
- use spmdMod , only : comp_id, mpicom
- use mct_mod , only : mct_gsmap_init
- !
- ! !ARGUMENTS:
- integer , intent(in) :: lni,lnj,lnk ! domain global size
- !
- ! !LOCAL VARIABLES:
- integer :: m,n,k ! indices
- integer :: begg,endg,lsize,gsize ! used for gsmap init
- integer :: begg3d,endg3d
- integer, pointer :: gindex(:) ! global index for gsmap init
- type(bounds_type) :: bounds
- !------------------------------------------------------------------------------
-
- ! Initialize gsmap_lnd2dsoi_gdc2glo
- call get_proc_bounds(bounds)
- begg = bounds%begg; endg=bounds%endg
-
- begg3d = (begg-1)*lnk + 1
- endg3d = endg*lnk
- lsize = (endg3d - begg3d + 1 )
- allocate(gindex(begg3d:endg3d))
- do k = 1, lnk
- do n = begg,endg
- m = (begg-1)*lnk + (k-1)*(endg-begg+1) + (n-begg+1)
- gindex(m) = gindex_global(n-begg+1) + (k-1)*(lni*lnj)
- enddo
- enddo
- gsize = lni * lnj * lnk
- call mct_gsMap_init(gsMap_lnd2Dsoi_gdc2glo, gindex, mpicom, comp_id, lsize, gsize)
-
- ! Diagnostic output
-
- if (masterproc) then
- write(iulog,*)' 3D GSMap'
- write(iulog,*)' longitude points = ',lni
- write(iulog,*)' latitude points = ',lnj
- write(iulog,*)' soil levels = ',lnk
- write(iulog,*)' gsize = ',gsize
- write(iulog,*)' lsize = ',lsize
- write(iulog,*)' bounds(gindex) = ',size(gindex)
- write(iulog,*)
- end if
-
- deallocate(gindex)
-
- end subroutine decompInit_lnd3D
-
-end module lnd_set_decomp_and_domain
diff --git a/src/cpl/mct/ndepStreamMod.F90 b/src/cpl/mct/ndepStreamMod.F90
deleted file mode 100644
index d26ff7c95e..0000000000
--- a/src/cpl/mct/ndepStreamMod.F90
+++ /dev/null
@@ -1,376 +0,0 @@
-module ndepStreamMod
-
- !-----------------------------------------------------------------------
- ! !DESCRIPTION:
- ! Contains methods for reading in nitrogen deposition data file
- ! Also includes functions for dynamic ndep file handling and
- ! interpolation.
- !
- ! !USES
- use shr_kind_mod, only: r8 => shr_kind_r8, CL => shr_kind_cl
- use shr_strdata_mod, only: shr_strdata_type, shr_strdata_create
- use shr_strdata_mod, only: shr_strdata_print, shr_strdata_advance
- use mct_mod , only: mct_ggrid
- use spmdMod , only: mpicom, masterproc, comp_id, iam
- use clm_varctl , only: iulog, inst_name
- use abortutils , only: endrun
- use decompMod , only: bounds_type
- use domainMod , only: ldomain
-
- ! !PUBLIC TYPES:
- implicit none
- private
-
- ! !PUBLIC MEMBER FUNCTIONS:
- public :: ndep_init ! position datasets for dynamic ndep
- public :: ndep_interp ! interpolates between two years of ndep file data
- public :: clm_domain_mct ! Sets up MCT domain for this resolution
-
- ! !PRIVATE MEMBER FUNCTIONS:
- private :: check_units ! Check the units and make sure they can be used
-
- ! ! PRIVATE TYPES
- type(shr_strdata_type) :: sdat ! input data stream
- integer :: stream_year_first_ndep ! first year in stream to use
- integer :: stream_year_last_ndep ! last year in stream to use
- integer :: model_year_align_ndep ! align stream_year_firstndep with
- logical :: divide_by_secs_per_yr = .true. ! divide by the number of seconds per year
-
- character(len=*), parameter, private :: sourcefile = &
- __FILE__
- !==============================================================================
-
-contains
-
- !==============================================================================
-
- subroutine ndep_init(bounds, NLFilename)
- !
- ! Initialize data stream information.
- !
- ! Uses:
- use shr_kind_mod , only : CS => shr_kind_cs
- use clm_time_manager , only : get_calendar
- use ncdio_pio , only : pio_subsystem
- use shr_pio_mod , only : shr_pio_getiotype
- use shr_nl_mod , only : shr_nl_find_group_name
- use shr_log_mod , only : errMsg => shr_log_errMsg
- use shr_mpi_mod , only : shr_mpi_bcast
- use lnd_set_decomp_and_domain , only : gsMap_lnd2Dsoi_gdc2glo, gsmap_global
- !
- ! arguments
- implicit none
- type(bounds_type), intent(in) :: bounds
- character(len=*), intent(in) :: NLFilename ! Namelist filename
- !
- ! local variables
- integer :: nu_nml ! unit for namelist file
- integer :: nml_error ! namelist i/o error flag
- type(mct_ggrid) :: dom_clm ! domain information
- character(len=CL) :: stream_fldFileName_ndep
- character(len=CL) :: ndepmapalgo = 'bilinear'
- character(len=CL) :: ndep_tintalgo = 'linear'
- character(len=CS) :: ndep_taxmode = 'extend'
- character(len=CL) :: ndep_varlist = 'NDEP_year'
- character(*), parameter :: shr_strdata_unset = 'NOT_SET'
- character(*), parameter :: subName = "('ndepdyn_init')"
- character(*), parameter :: F00 = "('(ndepdyn_init) ',4a)"
- !-----------------------------------------------------------------------
-
- namelist /ndepdyn_nml/ &
- stream_year_first_ndep, &
- stream_year_last_ndep, &
- model_year_align_ndep, &
- ndepmapalgo, ndep_taxmode, &
- ndep_varlist, &
- stream_fldFileName_ndep, &
- ndep_tintalgo
-
- ! Default values for namelist
- stream_year_first_ndep = 1 ! first year in stream to use
- stream_year_last_ndep = 1 ! last year in stream to use
- model_year_align_ndep = 1 ! align stream_year_first_ndep with this model year
- stream_fldFileName_ndep = ' '
-
- ! Read ndepdyn_nml namelist
- if (masterproc) then
- open( newunit=nu_nml, file=trim(NLFilename), status='old', iostat=nml_error )
- call shr_nl_find_group_name(nu_nml, 'ndepdyn_nml', status=nml_error)
- if (nml_error == 0) then
- read(nu_nml, nml=ndepdyn_nml,iostat=nml_error)
- if (nml_error /= 0) then
- call endrun(msg=' ERROR reading ndepdyn_nml namelist'//errMsg(sourcefile, __LINE__))
- end if
- else
- call endrun(msg=' ERROR finding ndepdyn_nml namelist'//errMsg(sourcefile, __LINE__))
- end if
- close(nu_nml)
- endif
-
- call shr_mpi_bcast(stream_year_first_ndep , mpicom)
- call shr_mpi_bcast(stream_year_last_ndep , mpicom)
- call shr_mpi_bcast(model_year_align_ndep , mpicom)
- call shr_mpi_bcast(stream_fldFileName_ndep, mpicom)
- call shr_mpi_bcast(ndep_varlist , mpicom)
- call shr_mpi_bcast(ndep_taxmode , mpicom)
- call shr_mpi_bcast(ndep_tintalgo , mpicom)
-
- if (masterproc) then
- write(iulog,*) ' '
- write(iulog,*) 'ndepdyn stream settings:'
- write(iulog,*) ' stream_year_first_ndep = ',stream_year_first_ndep
- write(iulog,*) ' stream_year_last_ndep = ',stream_year_last_ndep
- write(iulog,*) ' model_year_align_ndep = ',model_year_align_ndep
- write(iulog,*) ' stream_fldFileName_ndep = ',stream_fldFileName_ndep
- write(iulog,*) ' ndep_varList = ',ndep_varList
- write(iulog,*) ' ndep_taxmode = ',ndep_taxmode
- write(iulog,*) ' ndep_tintalgo = ',ndep_tintalgo
- write(iulog,*) ' '
- endif
- ! Read in units
- call check_units( stream_fldFileName_ndep, ndep_varList )
-
- ! Set domain and create streams
- call clm_domain_mct (bounds, dom_clm)
-
- call shr_strdata_create(sdat,name="clmndep", &
- pio_subsystem=pio_subsystem, &
- pio_iotype=shr_pio_getiotype(inst_name), &
- mpicom=mpicom, compid=comp_id, &
- gsmap=gsmap_global, ggrid=dom_clm, &
- nxg=ldomain%ni, nyg=ldomain%nj, &
- yearFirst=stream_year_first_ndep, &
- yearLast=stream_year_last_ndep, &
- yearAlign=model_year_align_ndep, &
- offset=0, &
- domFilePath='', &
- domFileName=trim(stream_fldFileName_ndep), &
- domTvarName='time', &
- domXvarName='lon' , &
- domYvarName='lat' , &
- domAreaName='area', &
- domMaskName='mask', &
- filePath='', &
- filename=(/trim(stream_fldFileName_ndep)/),&
- fldListFile=ndep_varlist, &
- fldListModel=ndep_varlist, &
- fillalgo='none', &
- mapalgo=ndepmapalgo, &
- tintalgo=ndep_tintalgo, &
- calendar=get_calendar(), &
- taxmode=ndep_taxmode )
-
-
- if (masterproc) then
- call shr_strdata_print(sdat,'CLMNDEP data')
- endif
-
- end subroutine ndep_init
- !================================================================
-
- subroutine check_units( stream_fldFileName_ndep, ndep_varList )
- !-------------------------------------------------------------------
- ! Check that units are correct on the file and if need any conversion
- use ncdio_pio , only : ncd_pio_openfile, ncd_inqvid, ncd_getatt, ncd_pio_closefile, ncd_nowrite
- use ncdio_pio , only : file_desc_t, var_desc_t
- use shr_kind_mod , only : CS => shr_kind_cs
- use shr_log_mod , only : errMsg => shr_log_errMsg
- use shr_string_mod, only : shr_string_listGetName
- implicit none
-
- !-----------------------------------------------------------------------
- !
- ! Arguments
- character(len=*), intent(IN) :: stream_fldFileName_ndep ! ndep filename
- character(len=*), intent(IN) :: ndep_varList ! ndep variable list to examine
- !
- ! Local variables
- type(file_desc_t) :: ncid ! NetCDF filehandle for ndep file
- type(var_desc_t) :: vardesc ! variable descriptor
- integer :: varid ! variable index
- logical :: readvar ! If variable was read
- character(len=CS) :: ndepunits! ndep units
- character(len=CS) :: fname ! ndep field name
- !-----------------------------------------------------------------------
- call ncd_pio_openfile( ncid, trim(stream_fldFileName_ndep), ncd_nowrite )
- call shr_string_listGetName( ndep_varList, 1, fname )
- call ncd_inqvid( ncid, fname, varid, vardesc, readvar=readvar )
- if ( readvar ) then
- call ncd_getatt( ncid, varid, "units", ndepunits )
- else
- call endrun(msg=' ERROR finding variable: '//trim(fname)//" in file: "// &
- trim(stream_fldFileName_ndep)//errMsg(sourcefile, __LINE__))
- end if
- call ncd_pio_closefile( ncid )
-
- ! Now check to make sure they are correct
- if ( trim(ndepunits) == "g(N)/m2/s" )then
- divide_by_secs_per_yr = .false.
- else if ( trim(ndepunits) == "g(N)/m2/yr" )then
- divide_by_secs_per_yr = .true.
- else
- call endrun(msg=' ERROR in units for nitrogen deposition equal to: '//trim(ndepunits)//" not units expected"// &
- errMsg(sourcefile, __LINE__))
- end if
-
- end subroutine check_units
-
- !================================================================
- subroutine ndep_interp(bounds, atm2lnd_inst)
-
- !-----------------------------------------------------------------------
- use clm_time_manager, only : get_curr_date, get_curr_days_per_year
- use clm_varcon , only : secspday
- use atm2lndType , only : atm2lnd_type
- !
- ! Arguments
- type(bounds_type) , intent(in) :: bounds
- type(atm2lnd_type), intent(inout) :: atm2lnd_inst
- !
- ! Local variables
- integer :: g, ig
- integer :: year ! year (0, ...) for nstep+1
- integer :: mon ! month (1, ..., 12) for nstep+1
- integer :: day ! day of month (1, ..., 31) for nstep+1
- integer :: sec ! seconds into current date for nstep+1
- integer :: mcdate ! Current model date (yyyymmdd)
- integer :: dayspyr ! days per year
- !-----------------------------------------------------------------------
-
- call get_curr_date(year, mon, day, sec)
- mcdate = year*10000 + mon*100 + day
-
- call shr_strdata_advance(sdat, mcdate, sec, mpicom, 'ndepdyn')
-
- if ( divide_by_secs_per_yr )then
- ig = 0
- dayspyr = get_curr_days_per_year( )
- do g = bounds%begg,bounds%endg
- ig = ig+1
- atm2lnd_inst%forc_ndep_grc(g) = sdat%avs(1)%rAttr(1,ig) / (secspday * dayspyr)
- end do
- else
- ig = 0
- do g = bounds%begg,bounds%endg
- ig = ig+1
- atm2lnd_inst%forc_ndep_grc(g) = sdat%avs(1)%rAttr(1,ig)
- end do
- end if
-
- end subroutine ndep_interp
-
- !==============================================================================
- subroutine clm_domain_mct(bounds, dom_clm, nlevels)
-
- !-------------------------------------------------------------------
- ! Set domain data type for internal clm grid
- use clm_varcon , only : re
- use domainMod , only : ldomain
- use mct_mod , only : mct_ggrid, mct_gsMap_lsize, mct_gGrid_init
- use mct_mod , only : mct_gsMap_orderedPoints, mct_gGrid_importIAttr
- use mct_mod , only : mct_gGrid_importRAttr, mct_gsMap
- use lnd_set_decomp_and_domain , only : gsMap_lnd2Dsoi_gdc2glo, gsmap_global
- implicit none
- !
- ! arguments
- type(bounds_type), intent(in) :: bounds
- type(mct_ggrid), intent(out) :: dom_clm ! Output domain information for land model
- integer, intent(in), optional :: nlevels ! Number of levels if this is a 3D field
- !
- ! local variables
- integer :: g,i,j,k ! index
- integer :: lsize ! land model domain data size
- real(r8), pointer :: data(:) ! temporary
- integer , pointer :: idata(:) ! temporary
- integer :: nlevs ! Number of vertical levels
- type(mct_gsMap), pointer :: gsmap => null() ! MCT GS map
- !-------------------------------------------------------------------
- ! SEt number of levels, and get the GS map for either the 2D or 3D grid
- nlevs = 1
- if ( present(nlevels) ) nlevs = nlevels
- if ( nlevs == 1 ) then
- gsmap => gsmap_global
- else
- gsmap => gsMap_lnd2Dsoi_gdc2glo
- end if
- !
- ! Initialize mct domain type
- ! lat/lon in degrees, area in radians^2, mask is 1 (land), 0 (non-land)
- ! Note that in addition land carries around landfrac for the purposes of domain checking
- !
- lsize = mct_gsMap_lsize(gsmap, mpicom)
- call mct_gGrid_init( GGrid=dom_clm, &
- CoordChars='lat:lon:hgt', OtherChars='area:aream:mask:frac', lsize=lsize )
- !
- ! Allocate memory
- !
- allocate(data(lsize))
- !
- ! Determine global gridpoint number attribute, GlobGridNum, which is set automatically by MCT
- !
- call mct_gsMap_orderedPoints(gsmap, iam, idata)
- gsmap => null()
- call mct_gGrid_importIAttr(dom_clm,'GlobGridNum',idata,lsize)
- !
- ! Determine domain (numbering scheme is: West to East and South to North to South pole)
- ! Initialize attribute vector with special value
- !
- data(:) = -9999.0_R8
- call mct_gGrid_importRAttr(dom_clm,"lat" ,data,lsize)
- call mct_gGrid_importRAttr(dom_clm,"lon" ,data,lsize)
- call mct_gGrid_importRAttr(dom_clm,"area" ,data,lsize)
- call mct_gGrid_importRAttr(dom_clm,"aream",data,lsize)
- data(:) = 0.0_R8
- call mct_gGrid_importRAttr(dom_clm,"mask" ,data,lsize)
- !
- ! Determine bounds
- !
- ! Fill in correct values for domain components
- ! Note aream will be filled in in the atm-lnd mapper
- !
- do k = 1, nlevs
- do g = bounds%begg,bounds%endg
- i = 1 + (g - bounds%begg)
- data(i) = ldomain%lonc(g)
- end do
- end do
- call mct_gGrid_importRattr(dom_clm,"lon",data,lsize)
-
- do k = 1, nlevs
- do g = bounds%begg,bounds%endg
- i = 1 + (g - bounds%begg)
- data(i) = ldomain%latc(g)
- end do
- end do
- call mct_gGrid_importRattr(dom_clm,"lat",data,lsize)
-
- do k = 1, nlevs
- do g = bounds%begg,bounds%endg
- i = 1 + (g - bounds%begg)
- data(i) = ldomain%area(g)/(re*re)
- end do
- end do
- call mct_gGrid_importRattr(dom_clm,"area",data,lsize)
-
- do k = 1, nlevs
- do g = bounds%begg,bounds%endg
- i = 1 + (g - bounds%begg)
- data(i) = real(ldomain%mask(g), r8)
- end do
- end do
- call mct_gGrid_importRattr(dom_clm,"mask",data,lsize)
-
- do k = 1, nlevs
- do g = bounds%begg,bounds%endg
- i = 1 + (g - bounds%begg)
- data(i) = real(ldomain%frac(g), r8)
- end do
- end do
- call mct_gGrid_importRattr(dom_clm,"frac",data,lsize)
-
- deallocate(data)
- deallocate(idata)
-
- end subroutine clm_domain_mct
-
-end module ndepStreamMod
diff --git a/src/cpl/nuopc/lnd_import_export.F90 b/src/cpl/nuopc/lnd_import_export.F90
index 11cc807640..624590b9a6 100644
--- a/src/cpl/nuopc/lnd_import_export.F90
+++ b/src/cpl/nuopc/lnd_import_export.F90
@@ -160,9 +160,11 @@ subroutine advertise_fields(gcomp, flds_scalar_name, glc_present, cism_evolve, r
use shr_carma_mod , only : shr_carma_readnl
use shr_ndep_mod , only : shr_ndep_readnl
+ use shr_dust_emis_mod , only : shr_dust_emis_readnl
use shr_fire_emis_mod , only : shr_fire_emis_readnl
use clm_varctl , only : ndep_from_cpl
use controlMod , only : NLFilename
+ use spmdMod , only : mpicom
! input/output variables
type(ESMF_GridComp) :: gcomp
@@ -237,6 +239,9 @@ subroutine advertise_fields(gcomp, flds_scalar_name, glc_present, cism_evolve, r
! The following namelist reads should always be called regardless of the send_to_atm value
+ ! Dust emissions from land to atmosphere
+ call shr_dust_emis_readnl( mpicom, "drv_flds_in")
+
! Dry Deposition velocities from land - ALSO initialize drydep here
call shr_drydep_readnl("drv_flds_in", drydep_nflds)
@@ -248,7 +253,6 @@ subroutine advertise_fields(gcomp, flds_scalar_name, glc_present, cism_evolve, r
if (shr_megan_mechcomps_n .ne. megan_nflds) call shr_sys_abort('ERROR: megan field count mismatch')
! CARMA volumetric soil water from land
- ! TODO: is the following correct - the CARMA field exchange is very confusing in mct
call shr_carma_readnl('drv_flds_in', carma_fields)
! export to atm
diff --git a/src/cpl/share_esmf/ZenderSoilErodStreamType.F90 b/src/cpl/share_esmf/ZenderSoilErodStreamType.F90
index 194e022132..32e776063b 100644
--- a/src/cpl/share_esmf/ZenderSoilErodStreamType.F90
+++ b/src/cpl/share_esmf/ZenderSoilErodStreamType.F90
@@ -42,7 +42,6 @@ module ZenderSoilErodStreamType
! ! PRIVATE DATA:
type, private :: streamcontrol_type
- character(len=CL) :: zender_soil_erod_source ! if calculed in lnd or atm
character(len=CL) :: stream_fldFileName_zendersoilerod ! data Filename
character(len=CL) :: stream_meshfile_zendersoilerod ! mesh Filename
character(len=CL) :: zendersoilerod_mapalgo ! map algo
@@ -179,7 +178,7 @@ logical function UseStreams(this)
! file is being used with it
!
! !USES:
- use clm_varctl, only : dust_emis_method
+ use shr_dust_emis_mod, only : is_dust_emis_zender, is_zender_soil_erod_from_land
!
! !ARGUMENTS:
implicit none
@@ -189,7 +188,7 @@ logical function UseStreams(this)
if ( .not. control%namelist_set )then
call endrun(msg=' ERROR namelist NOT set before being used'//errMsg(sourcefile, __LINE__))
end if
- if ( (trim(dust_emis_method) == 'Zender_2003') .and. (control%zender_soil_erod_source == "lnd") )then
+ if ( is_dust_emis_zender() .and. is_zender_soil_erod_from_land() )then
UseStreams = .true.
else
UseStreams = .false.
@@ -289,6 +288,7 @@ subroutine ReadNML(this, bounds, NLFilename)
use shr_nl_mod , only : shr_nl_find_group_name
use shr_log_mod , only : errMsg => shr_log_errMsg
use shr_mpi_mod , only : shr_mpi_bcast
+ use shr_dust_emis_mod, only : is_zender_soil_erod_from_land
!
! arguments
implicit none
@@ -304,14 +304,13 @@ subroutine ReadNML(this, bounds, NLFilename)
character(len=CL) :: stream_meshfile_zendersoilerod = ' '
character(len=CL) :: zendersoilerod_mapalgo = ' '
character(len=CL) :: tmp_file_array(3)
- character(len=3) :: zender_soil_erod_source = 'atm'
character(len=*), parameter :: namelist_name = 'zendersoilerod' ! MUST agree with group name in namelist definition to read.
character(len=*), parameter :: subName = "('zendersoilerod::ReadNML')"
!-----------------------------------------------------------------------
namelist /zendersoilerod/ & ! MUST agree with namelist_name above
zendersoilerod_mapalgo, stream_fldFileName_zendersoilerod, &
- stream_meshfile_zendersoilerod, zender_soil_erod_source
+ stream_meshfile_zendersoilerod
! Default values for namelist
@@ -330,12 +329,11 @@ subroutine ReadNML(this, bounds, NLFilename)
close(nu_nml)
endif
- call shr_mpi_bcast(zender_soil_erod_source , mpicom)
call shr_mpi_bcast(zendersoilerod_mapalgo , mpicom)
call shr_mpi_bcast(stream_fldFileName_zendersoilerod , mpicom)
call shr_mpi_bcast(stream_meshfile_zendersoilerod , mpicom)
- if (masterproc .and. (zender_soil_erod_source == "lnd") ) then
+ if (masterproc .and. is_zender_soil_erod_from_land() ) then
write(iulog,*) ' '
write(iulog,*) namelist_name, ' stream settings:'
write(iulog,*) ' stream_fldFileName_zendersoilerod = ',stream_fldFileName_zendersoilerod
@@ -343,13 +341,10 @@ subroutine ReadNML(this, bounds, NLFilename)
write(iulog,*) ' zendersoilerod_mapalgo = ',zendersoilerod_mapalgo
endif
- if ( (trim(zender_soil_erod_source) /= 'atm') .and. (trim(zender_soil_erod_source) /= 'lnd') )then
- call endrun(msg=' ERROR zender_soil_erod_source must be either lnd or atm and is NOT'//errMsg(sourcefile, __LINE__))
- end if
tmp_file_array(1) = stream_fldFileName_zendersoilerod
tmp_file_array(2) = stream_meshfile_zendersoilerod
tmp_file_array(3) = zendersoilerod_mapalgo
- if ( trim(zender_soil_erod_source) == 'lnd' )then
+ if ( is_zender_soil_erod_from_land() ) then
do i = 1, size(tmp_file_array)
if ( len_trim(tmp_file_array(i)) == 0 )then
call endrun(msg=' ERROR '//trim(tmp_file_array(i))//' must be set when Zender_2003 is being used and zender_soil_erod_source is lnd'//errMsg(sourcefile, __LINE__))
@@ -365,7 +360,6 @@ subroutine ReadNML(this, bounds, NLFilename)
this%stream_fldFileName_zendersoilerod = stream_fldFileName_zendersoilerod
this%stream_meshfile_zendersoilerod = stream_meshfile_zendersoilerod
this%zendersoilerod_mapalgo = zendersoilerod_mapalgo
- this%zender_soil_erod_source = zender_soil_erod_source
this%namelist_set = .true.
diff --git a/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf b/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf
index 467d00de59..c811cab5f5 100644
--- a/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf
+++ b/src/drv_test/shr_dust_emis_test/test_shr_dust_emis.pf
@@ -59,7 +59,7 @@ contains
@assertFalse(not_init)
end subroutine check_when_initialized_runs
-
+
@Test
subroutine check_dust_emis(this)
! Test that the dust_emis logical functions work as expected
@@ -75,7 +75,6 @@ contains
end subroutine check_dust_emis
-
@Test
subroutine check_zender_soil(this)
! Test that the dust_emis_Zender logical functions work as expected
@@ -91,7 +90,6 @@ contains
end subroutine check_zender_soil
-
@Test
subroutine check_options(this)
! Test that the check_options subroutine catches errors that should die
@@ -110,5 +108,5 @@ contains
@assertExceptionRaised(endrun_msg('(check_options_finish_init) ERROR: zender_soil_erod_source can only be lnd or atm'))
end subroutine check_options
-
+
end module test_shr_dust_emis
diff --git a/src/fates b/src/fates
new file mode 160000
index 0000000000..adfa664806
--- /dev/null
+++ b/src/fates
@@ -0,0 +1 @@
+Subproject commit adfa6648063408d443f5cae671bd37f713d3e3e8
diff --git a/src/main/clm_driver.F90 b/src/main/clm_driver.F90
index 00a98e61b4..c1845d0de6 100644
--- a/src/main/clm_driver.F90
+++ b/src/main/clm_driver.F90
@@ -62,7 +62,6 @@ module clm_driver
use ndepStreamMod , only : ndep_interp
use cropcalStreamMod , only : cropcal_advance, cropcal_interp
use ch4Mod , only : ch4, ch4_init_gridcell_balance_check, ch4_init_column_balance_check
- use DUSTMod , only : DustDryDep, DustEmission
use VOCEmissionMod , only : VOCEmission
!
use filterMod , only : setFilters
@@ -806,15 +805,15 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro
call t_startf('bgc')
! Dust mobilization (C. Zender's modified codes)
- call DustEmission(bounds_clump, &
+ call dust_emis_inst%DustEmission(bounds_clump, &
filter(nc)%num_nolakep, filter(nc)%nolakep, &
atm2lnd_inst, soilstate_inst, canopystate_inst, &
water_inst%waterstatebulk_inst, water_inst%waterdiagnosticbulk_inst, &
- frictionvel_inst, dust_inst)
+ frictionvel_inst)
! Dust dry deposition (C. Zender's modified codes)
- call DustDryDep(bounds_clump, &
- atm2lnd_inst, frictionvel_inst, dust_inst)
+ call dust_emis_inst%DustDryDep(bounds_clump, &
+ atm2lnd_inst, frictionvel_inst)
! VOC emission (A. Guenther's MEGAN (2006) model)
call VOCEmission(bounds_clump, &
@@ -1308,7 +1307,7 @@ subroutine clm_drv(doalb, nextsw_cday, declinp1, declin, rstwr, nlend, rdate, ro
atm2lnd_inst, surfalb_inst, temperature_inst, frictionvel_inst, &
water_inst, &
energyflux_inst, solarabs_inst, drydepvel_inst, &
- vocemis_inst, fireemis_inst, dust_inst, ch4_inst, glc_behavior, &
+ vocemis_inst, fireemis_inst, dust_emis_inst, ch4_inst, glc_behavior, &
lnd2atm_inst, &
net_carbon_exchange_grc = net_carbon_exchange_grc(bounds_proc%begg:bounds_proc%endg))
deallocate(net_carbon_exchange_grc)
diff --git a/src/main/clm_instMod.F90 b/src/main/clm_instMod.F90
index b9d74c418a..ab690a92a6 100644
--- a/src/main/clm_instMod.F90
+++ b/src/main/clm_instMod.F90
@@ -45,7 +45,7 @@ module clm_instMod
use SoilBiogeochemNitrogenStateType , only : soilbiogeochem_nitrogenstate_type
use CropType , only : crop_type
use DryDepVelocity , only : drydepvel_type
- use DUSTMod , only : dust_type
+ use DustEmisBase , only : dust_emis_base_type
use EnergyFluxType , only : energyflux_type
use FrictionVelocityMod , only : frictionvel_type
use GlacierSurfaceMassBalanceMod , only : glacier_smb_type
@@ -151,7 +151,7 @@ module clm_instMod
! General biogeochem types
type(ch4_type) , public :: ch4_inst
type(crop_type) , public :: crop_inst
- type(dust_type) , public :: dust_inst
+ class(dust_emis_base_type), public, allocatable :: dust_emis_inst
type(vocemis_type) , public :: vocemis_inst
type(fireemis_type) , public :: fireemis_inst
type(drydepvel_type), public :: drydepvel_inst
@@ -203,6 +203,7 @@ subroutine clm_instInit(bounds)
use clm_varctl , only : use_hillslope
use HillslopeHydrologyMod , only : SetHillslopeSoilThickness
use initVerticalMod , only : setSoilLayerClass
+ use DustEmisFactory , only : create_dust_emissions
!
! !ARGUMENTS
type(bounds_type), intent(in) :: bounds ! processor bounds
@@ -296,11 +297,11 @@ subroutine clm_instInit(bounds)
! Initialization of public data types
call temperature_inst%Init(bounds, &
- urbanparams_inst%em_roof(begl:endl), &
- urbanparams_inst%em_wall(begl:endl), &
- urbanparams_inst%em_improad(begl:endl), &
- urbanparams_inst%em_perroad(begl:endl), &
- IsSimpleBuildTemp(), IsProgBuildTemp() )
+ em_roof_lun=urbanparams_inst%em_roof(begl:endl), &
+ em_wall_lun=urbanparams_inst%em_wall(begl:endl), &
+ em_improad_lun=urbanparams_inst%em_improad(begl:endl), &
+ em_perroad_lun=urbanparams_inst%em_perroad(begl:endl), &
+ is_simple_buildtemp=IsSimpleBuildTemp(), is_prog_buildtemp=IsProgBuildTemp() )
call active_layer_inst%Init(bounds)
@@ -350,7 +351,7 @@ subroutine clm_instInit(bounds)
call surfrad_inst%Init(bounds)
- call dust_inst%Init(bounds, NLFilename)
+ allocate(dust_emis_inst, source = create_dust_emissions(bounds, NLFilename))
allocate(scf_method, source = CreateAndInitSnowCoverFraction( &
snow_cover_fraction_method = snow_cover_fraction_method, &
diff --git a/src/main/clm_varctl.F90 b/src/main/clm_varctl.F90
index 7d0b2b55ad..97c818af94 100644
--- a/src/main/clm_varctl.F90
+++ b/src/main/clm_varctl.F90
@@ -115,7 +115,7 @@ module clm_varctl
character(len=fname_len), public :: fsnowaging = ' ' ! snow aging parameters file name
character(len=fname_len), public :: fatmlndfrc = ' ' ! lnd frac file on atm grid
- ! only needed for LILAC and MCT drivers
+ ! only needed for LILAC
!----------------------------------------------------------
! Flag to read ndep rather than obtain it from coupler
@@ -276,11 +276,6 @@ module clm_varctl
! option to activate OC in snow in SNICAR
logical, public :: do_sno_oc = .false. ! control to include organic carbon (OC) in snow
- !----------------------------------------------------------
- ! DUST emission method
- !----------------------------------------------------------
- character(len=25), public :: dust_emis_method = 'Zender_2003' ! Dust emisison method to use: Zender_2003 or Leung_2023
-
!----------------------------------------------------------
! C isotopes
!----------------------------------------------------------
@@ -426,12 +421,6 @@ module clm_varctl
logical, public :: use_hydrstress = .false. ! true => use plant hydraulic stress calculation
- !----------------------------------------------------------
- ! dynamic root switch
- !----------------------------------------------------------
-
- logical, public :: use_dynroot = .false. ! true => use dynamic root module
-
!----------------------------------------------------------
! glacier_mec control variables: default values (may be overwritten by namelist)
!----------------------------------------------------------
diff --git a/src/main/controlMod.F90 b/src/main/controlMod.F90
index 46d9e9958a..c92732806c 100644
--- a/src/main/controlMod.F90
+++ b/src/main/controlMod.F90
@@ -207,12 +207,6 @@ subroutine control_init(dtime)
for_testing_no_crop_seed_replenishment, &
z0param_method, use_z0m_snowmelt
- ! NOTE: EBK 02/26/2024: dust_emis_method is here in CTSM temporarily until it's moved to CMEPS
- ! See: https://github.com/ESCOMP/CMEPS/pull/429
- ! Normally this should also need error checking and a broadcast, but since
- ! there is only one hardcoded option right now that is unneeded.
- namelist /clm_inparm/ dust_emis_method
-
! vertical soil mixing variables
namelist /clm_inparm/ &
som_adv_flux, max_depth_cryoturb
@@ -272,8 +266,6 @@ subroutine control_init(dtime)
namelist /clm_inparm/ use_hydrstress
- namelist /clm_inparm/ use_dynroot
-
namelist /clm_inparm/ &
use_c14_bombspike, atm_c14_filename, use_c13_timeseries, atm_c13_filename
@@ -613,11 +605,6 @@ subroutine control_init(dtime)
errMsg(sourcefile, __LINE__))
end if
- if ( use_dynroot .and. use_hydrstress ) then
- call endrun(msg=' ERROR:: dynroot and hydrstress can NOT be on at the same time'//&
- errMsg(sourcefile, __LINE__))
- end if
-
! Check on run type
if (nsrest == iundef) then
call endrun(msg=' ERROR:: must set nsrest'//&
@@ -842,8 +829,6 @@ subroutine control_spmd()
call mpi_bcast (use_hydrstress, 1, MPI_LOGICAL, 0, mpicom, ier)
- call mpi_bcast (use_dynroot, 1, MPI_LOGICAL, 0, mpicom, ier)
-
if (use_cn .or. use_fates) then
! vertical soil mixing variables
call mpi_bcast (som_adv_flux, 1, MPI_REAL8, 0, mpicom, ier)
@@ -1130,7 +1115,6 @@ subroutine control_print ()
write(iulog,*) ' user-defined soil layer structure = ', soil_layerstruct_userdefined
write(iulog,*) ' user-defined number of soil layers = ', soil_layerstruct_userdefined_nlevsoi
write(iulog,*) ' plant hydraulic stress = ', use_hydrstress
- write(iulog,*) ' dynamic roots = ', use_dynroot
if (nsrest == nsrContinue) then
write(iulog,*) 'restart warning:'
write(iulog,*) ' Namelist not checked for agreement with initial run.'
diff --git a/src/main/glc2lndMod.F90 b/src/main/glc2lndMod.F90
index ecd6818210..2d0dbb5791 100644
--- a/src/main/glc2lndMod.F90
+++ b/src/main/glc2lndMod.F90
@@ -78,7 +78,6 @@ module glc2lndMod
! - set_glc2lnd_fields
! - update_glc2lnd_fracs
! - update_glc2lnd_topo
- procedure, public :: set_glc2lnd_fields_mct ! set coupling fields sent from glc to lnd
procedure, public :: set_glc2lnd_fields_nuopc ! set coupling fields sent from glc to lnd
procedure, public :: update_glc2lnd_fracs ! update subgrid fractions based on input from GLC
procedure, public :: update_glc2lnd_topo ! update topographic heights
@@ -242,61 +241,6 @@ subroutine Clean(this)
end subroutine Clean
- !-----------------------------------------------------------------------
- subroutine set_glc2lnd_fields_mct(this, bounds, glc_present, x2l, &
- index_x2l_Sg_ice_covered, index_x2l_Sg_topo, index_x2l_Flgg_hflx, &
- index_x2l_Sg_icemask, index_x2l_Sg_icemask_coupled_fluxes)
- !
- ! !DESCRIPTION:
- ! Set coupling fields sent from glc to lnd
- !
- ! If glc_present is true, then the given fields are all assumed to be valid; if
- ! glc_present is false, then these fields are ignored.
- !
- ! !ARGUMENTS:
- class(glc2lnd_type), intent(inout) :: this
- type(bounds_type) , intent(in) :: bounds
- logical , intent(in) :: glc_present ! true if running with a non-stub glc model
- real(r8) , intent(in) :: x2l(:, bounds%begg: ) ! driver import state to land model [field, gridcell]
- integer , intent(in) :: index_x2l_Sg_ice_covered( 0: ) ! indices of ice-covered field in x2l, for each elevation class
- integer , intent(in) :: index_x2l_Sg_topo( 0: ) ! indices of topo field in x2l, for each elevation class
- integer , intent(in) :: index_x2l_Flgg_hflx( 0: ) ! indices of heat flux field in x2l, for each elevation class
- integer , intent(in) :: index_x2l_Sg_icemask ! index of icemask field in x2l
- integer , intent(in) :: index_x2l_Sg_icemask_coupled_fluxes ! index of icemask_coupled_fluxes field in x2l
- !
- ! !LOCAL VARIABLES:
- integer :: g
- integer :: ice_class
-
- character(len=*), parameter :: subname = 'set_glc2lnd_fields_mct'
- !-----------------------------------------------------------------------
-
- SHR_ASSERT_FL((ubound(x2l, 2) == bounds%endg), sourcefile, __LINE__)
- SHR_ASSERT_ALL_FL((ubound(index_x2l_Sg_ice_covered) == (/maxpatch_glc/)), sourcefile, __LINE__)
- SHR_ASSERT_ALL_FL((ubound(index_x2l_Sg_topo) == (/maxpatch_glc/)), sourcefile, __LINE__)
- SHR_ASSERT_ALL_FL((ubound(index_x2l_Flgg_hflx) == (/maxpatch_glc/)), sourcefile, __LINE__)
-
- if (glc_present) then
- do g = bounds%begg, bounds%endg
- do ice_class = 0, maxpatch_glc
- this%frac_grc(g,ice_class) = x2l(index_x2l_Sg_ice_covered(ice_class),g)
- this%topo_grc(g,ice_class) = x2l(index_x2l_Sg_topo(ice_class),g)
- this%hflx_grc(g,ice_class) = x2l(index_x2l_Flgg_hflx(ice_class),g)
- end do
- this%icemask_grc(g) = x2l(index_x2l_Sg_icemask,g)
- this%icemask_coupled_fluxes_grc(g) = x2l(index_x2l_Sg_icemask_coupled_fluxes,g)
- end do
-
- call this%set_glc2lnd_fields_wrapup(bounds)
- else
- if (glc_do_dynglacier) then
- call endrun(' ERROR: With glc_present false (e.g., a stub glc model), glc_do_dynglacier must be false '// &
- errMsg(sourcefile, __LINE__))
- end if
- end if
-
- end subroutine set_glc2lnd_fields_mct
-
!-----------------------------------------------------------------------
subroutine set_glc2lnd_fields_nuopc(this, bounds, glc_present, &
frac_grc, topo_grc, hflx_grc, icemask_grc, icemask_coupled_fluxes_grc)
diff --git a/src/main/lnd2atmMod.F90 b/src/main/lnd2atmMod.F90
index 1cda0cff91..503f4b9585 100644
--- a/src/main/lnd2atmMod.F90
+++ b/src/main/lnd2atmMod.F90
@@ -20,7 +20,7 @@ module lnd2atmMod
use lnd2atmType , only : lnd2atm_type
use atm2lndType , only : atm2lnd_type
use ch4Mod , only : ch4_type
- use DUSTMod , only : dust_type
+ use DustEmisBase , only : dust_emis_base_type
use DryDepVelocity , only : drydepvel_type
use VocEmissionMod , only : vocemis_type
use CNFireEmissionsMod , only : fireemis_type
@@ -150,7 +150,7 @@ subroutine lnd2atm(bounds, &
atm2lnd_inst, surfalb_inst, temperature_inst, frictionvel_inst, &
water_inst, &
energyflux_inst, solarabs_inst, drydepvel_inst, &
- vocemis_inst, fireemis_inst, dust_inst, ch4_inst, glc_behavior, &
+ vocemis_inst, fireemis_inst, dust_emis_inst, ch4_inst, glc_behavior, &
lnd2atm_inst, &
net_carbon_exchange_grc)
!
@@ -173,7 +173,7 @@ subroutine lnd2atm(bounds, &
type(drydepvel_type) , intent(in) :: drydepvel_inst
type(vocemis_type) , intent(in) :: vocemis_inst
type(fireemis_type) , intent(in) :: fireemis_inst
- type(dust_type) , intent(in) :: dust_inst
+ class(dust_emis_base_type) , intent(in) :: dust_emis_inst
type(ch4_type) , intent(in) :: ch4_inst
type(glc_behavior_type) , intent(in) :: glc_behavior
type(lnd2atm_type) , intent(inout) :: lnd2atm_inst
@@ -332,7 +332,7 @@ subroutine lnd2atm(bounds, &
! dust emission flux
call p2g(bounds, ndst, &
- dust_inst%flx_mss_vrt_dst_patch(bounds%begp:bounds%endp, :), &
+ dust_emis_inst%flx_mss_vrt_dst_patch(bounds%begp:bounds%endp, :), &
lnd2atm_inst%flxdst_grc (bounds%begg:bounds%endg, :), &
p2c_scale_type='unity', c2l_scale_type= 'unity', l2g_scale_type='unity')
diff --git a/src/main/pftconMod.F90 b/src/main/pftconMod.F90
index e5379100e0..7988b57e75 100644
--- a/src/main/pftconMod.F90
+++ b/src/main/pftconMod.F90
@@ -280,9 +280,6 @@ module pftconMod
real(r8), allocatable :: FUN_fracfixers(:) ! Fraction of C that can be used for fixation.
- ! pft parameters for dynamic root code
- real(r8), allocatable :: root_dmx(:) !maximum root depth
-
contains
procedure, public :: Init
@@ -494,7 +491,6 @@ subroutine InitAllocate (this)
allocate( this%kn_nonmyc (0:mxpft) )
allocate( this%kr_resorb (0:mxpft) )
allocate( this%perecm (0:mxpft) )
- allocate( this%root_dmx (0:mxpft) )
allocate( this%fun_cn_flex_a (0:mxpft) )
allocate( this%fun_cn_flex_b (0:mxpft) )
allocate( this%fun_cn_flex_c (0:mxpft) )
@@ -520,7 +516,7 @@ subroutine InitRead(this)
use fileutils , only : getfil
use ncdio_pio , only : ncd_io, ncd_pio_closefile, ncd_pio_openfile, file_desc_t
use ncdio_pio , only : ncd_inqdid, ncd_inqdlen
- use clm_varctl , only : paramfile, use_fates, use_flexibleCN, use_dynroot, use_biomass_heat_storage, z0param_method
+ use clm_varctl , only : paramfile, use_fates, use_flexibleCN, use_biomass_heat_storage, z0param_method
use spmdMod , only : masterproc
use CLMFatesParamInterfaceMod, only : FatesReadPFTs
use SoilBiogeochemDecompCascadeConType, only : mimics_decomp, decomp_method
@@ -1105,13 +1101,8 @@ subroutine InitRead(this)
end if
!
- ! Dynamic Root variables for crops
!
- if ( use_crop .and. use_dynroot )then
- call ncd_io('root_dmx', this%root_dmx, 'read', ncid, readvar=readv)
- if ( .not. readv ) call endrun(msg=' ERROR: error in reading in pft data'//errMsg(sourcefile, __LINE__))
- end if
-
+ !
call ncd_io('nstem',this%nstem, 'read', ncid, readvar=readv)
if ( .not. readv ) call endrun(msg=' ERROR: error in reading in pft data'//errMsg(sourcefile, __LINE__))
call ncd_io('taper',this%taper, 'read', ncid, readvar=readv)
@@ -1583,7 +1574,6 @@ subroutine Clean(this)
deallocate( this%kn_nonmyc)
deallocate( this%kr_resorb)
deallocate( this%perecm)
- deallocate( this%root_dmx)
deallocate( this%fun_cn_flex_a)
deallocate( this%fun_cn_flex_b)
deallocate( this%fun_cn_flex_c)
diff --git a/src/unit_test_shr/CMakeLists.txt b/src/unit_test_shr/CMakeLists.txt
index 9bf95c728f..f6a204bd72 100644
--- a/src/unit_test_shr/CMakeLists.txt
+++ b/src/unit_test_shr/CMakeLists.txt
@@ -9,6 +9,7 @@ sourcelist_to_parent(clm_genf90_sources)
list(APPEND clm_sources "${clm_genf90_sources}")
list(APPEND clm_sources
+ unittestDustEmisInputs.F90
unittestFilterBuilderMod.F90
unittestGlcMec.F90
unittestSimpleSubgridSetupsMod.F90
diff --git a/src/unit_test_shr/unittestDustEmisInputs.F90 b/src/unit_test_shr/unittestDustEmisInputs.F90
new file mode 100644
index 0000000000..6b15680ef7
--- /dev/null
+++ b/src/unit_test_shr/unittestDustEmisInputs.F90
@@ -0,0 +1,251 @@
+module unittestDustEmisInputs
+
+ ! unit testing dust emission inputs
+
+ use unittestSubgridMod, only : bounds, unittest_subgrid_teardown
+ use unittestSimpleSubgridSetupsMod, only : setup_single_veg_patch
+ use clm_varpar, only : nlevsoi, nlevgrnd, clm_varpar_init
+ use clm_varctl, only : soil_layerstruct_predefined, create_crop_landunit, use_crop, create_crop_landunit
+ use shr_kind_mod , only : r8 => shr_kind_r8
+ use unittestFilterBuilderMod, only : filter_from_range
+ use atm2lndType, only : atm2lnd_type, atm2lnd_params_type
+ use SoilStateType, only : soilstate_type
+ use CanopyStateType, only : canopystate_type
+ use TemperatureType, only : temperature_type
+ use WaterType, only : water_type
+ use FrictionVelocityMod, only : frictionvel_type
+ use unittestWaterTypeFactory, only : unittest_water_type_factory_type
+ use SoilStateInitTimeConstMod, only : ThresholdSoilMoistZender2003, MassFracClay
+
+ implicit none
+ private
+
+ type, public :: unittest_dust_emis_input_type
+ integer, allocatable :: filter_nolakep(:) ! non-lake filter (patches)
+ integer :: num_nolakep ! number of patches in non-lake filter
+ type(atm2lnd_type) :: atm2lnd_inst
+ type(soilstate_type) :: soilstate_inst
+ type(canopystate_type) :: canopystate_inst
+ type(temperature_type), private :: temperature_inst
+ type(unittest_water_type_factory_type), private :: water_factory
+ type(water_type) :: water_inst
+ type(frictionvel_type) :: frictionvel_inst
+ contains
+ procedure, public :: setUp
+ procedure, public :: tearDown
+ procedure, private:: setupSoilState
+ procedure, public :: create_atm2lnd
+ procedure, public :: create_fv
+ procedure, public :: print_values
+ end type unittest_dust_emis_input_type
+
+contains
+
+ !-----------------------------------------------------------------------
+
+ subroutine setUp(this)
+ use ColumnType, only : col
+ class(unittest_dust_emis_input_type), intent(inout) :: this
+ ! Allocate and initiatlize the test object for input objects dust-emission needs
+
+ character(len=5) :: NLFilename = 'none'
+ real(r8), allocatable :: urb_em(:)
+ integer :: begl, endl, begc, endc
+ integer :: c
+ type(atm2lnd_params_type) :: atm2lnd_params
+ integer, parameter :: snl = 3
+
+ ! Settings needed for clm_varpar
+ soil_layerstruct_predefined = '20SL_8.5m'
+ create_crop_landunit = .true.
+ use_crop = .false.
+ call clm_varpar_init( actual_maxsoil_patches=17, surf_numpft=15, surf_numcft=2, actual_nlevurb=5 )
+ ! Water object initialization -- before subgrid
+ call this%water_factory%init()
+ call this%water_factory%setup_before_subgrid( &
+ my_nlevsoi = nlevsoi, &
+ nlevgrnd_additional = nlevgrnd - nlevsoi, &
+ my_nlevsno = snl)
+ ! Setup the subgrid structure for a single bare-soil patch
+ call setup_single_veg_patch( pft_type=0 )
+ begl = bounds%begl
+ endl = bounds%endl
+ begc = bounds%begc
+ endc = bounds%endc
+
+ ! Create the nolake filter
+ call filter_from_range(start=bounds%begp, end=bounds%endp, numf=this%num_nolakep, filter=this%filter_nolakep)
+ ! atmosphere to land parameter object
+ atm2lnd_params = atm2lnd_params_type( repartition_rain_snow = .false., &
+ glcmec_downscale_longwave = .false., &
+ lapse_rate = 0.01_r8 & ! arbitrary (this is unused for these tests)
+ )
+ call this%atm2lnd_inst%InitForTesting(bounds, atm2lnd_params)
+ ! Water and soil state -- after the subgrid setup
+ call this%water_factory%setup_after_subgrid(snl = snl)
+ call this%setupSoilState( ) ! This needs to happen before the water_type object creation
+ call this%water_factory%create_water_type(this%water_inst, watsat_col=this%soilstate_inst%watsat_col)
+ ! Canopy state, friction velocity, and temperature state ojects
+ call this%canopystate_inst%SetNMLForTesting()
+ call this%canopystate_inst%Init(bounds)
+ call this%frictionvel_inst%InitForTesting(bounds)
+ allocate( urb_em(begl:endl) )
+ urb_em(begl:endl) = 0.99_r8 ! Arbitrary won't matter here
+ call this%temperature_inst%Init(bounds, &
+ em_roof_lun=urb_em(begl:endl), &
+ em_wall_lun=urb_em(begl:endl), &
+ em_improad_lun=urb_em(begl:endl), &
+ em_perroad_lun=urb_em(begl:endl), &
+ is_simple_buildtemp=.true., is_prog_buildtemp=.false.)
+ deallocate( urb_em )
+ end subroutine setUp
+
+ !-----------------------------------------------------------------------
+
+ subroutine tearDown(this)
+ class(unittest_dust_emis_input_type), intent(inout) :: this
+
+ call this%water_factory%teardown(this%water_inst)
+ call unittest_subgrid_teardown()
+ call this%atm2lnd_inst%Clean()
+ deallocate( this%filter_nolakep )
+ end subroutine tearDown
+
+ !-----------------------------------------------------------------------
+
+ subroutine setupSoilState(this)
+ !
+ ! !DESCRIPTION:
+ ! Sets up the external environment used by Dust emissions - i.e., things accessed via
+ ! 'use' statements.
+ !
+ ! Assumes nlevgrnd and nlevsoi have been set, and that all necessary subgrid setup has
+ ! been completed.
+ !
+ use ColumnType, only : col
+ use GridcellType, only : grc
+ class(unittest_dust_emis_input_type), intent(in) :: this
+ !
+ integer :: c,j
+ real(r8), parameter :: clay = 10.0_r8
+
+ !-----------------------------------------------------------------------
+ ! Setting the soil structrure is needed for water_state types
+ col%dz(:,1:nlevgrnd) = 1.0_r8
+ do j = 1, nlevgrnd
+ do c = bounds%begc, bounds%endc
+ col%z(c,j) = sum(col%dz(c,1:j-1)) + 0.5_r8*col%dz(c,j)
+ end do
+ end do
+
+ call this%soilstate_inst%Init(bounds)
+ do c = bounds%begc, bounds%endc
+ this%soilstate_inst%watsat_col(c,:) = 0.05_r8 * (c - bounds%begc + 1)
+ end do
+ ! These are needed for dust emissions initialization
+ do c = bounds%begc, bounds%endc
+ this%soilstate_inst%gwc_thr_col(c) = ThresholdSoilMoistZender2003( clay )
+ this%soilstate_inst%mss_frc_cly_vld_col(c) = MassFracClay( clay )
+ end do
+
+ end subroutine setupSoilState
+
+ !-----------------------------------------------------------------------
+
+ subroutine create_atm2lnd(this, forc_t, forc_pbot, forc_rho )
+ ! Initializes some fields needed for dust emissions in this%atm2lnd_inst, and sets
+ ! forcing fields based on inputs. Excluded inputs are given a default value
+ class(unittest_dust_emis_input_type), intent(inout) :: this
+ real(r8), intent(in), optional :: forc_t(:)
+ real(r8), intent(in), optional :: forc_pbot(:)
+ real(r8), intent(in), optional :: forc_rho(:)
+
+ real(r8), parameter :: forc_t_default = 301._r8
+ real(r8), parameter :: forc_pbot_default = 100000._r8
+ real(r8), parameter :: forc_rho_default = 1.1_r8
+ ! ------------------------------------------------------------------------
+
+ if (present(forc_t)) then
+ this%atm2lnd_inst%forc_t_downscaled_col(bounds%begc:bounds%endc) = forc_t(:)
+ else
+ this%atm2lnd_inst%forc_t_downscaled_col(bounds%begc:bounds%endc) = forc_t_default
+ end if
+
+ if (present(forc_pbot)) then
+ this%atm2lnd_inst%forc_pbot_downscaled_col(bounds%begc:bounds%endc) = forc_pbot(:)
+ else
+ this%atm2lnd_inst%forc_pbot_downscaled_col(bounds%begc:bounds%endc) = forc_pbot_default
+ end if
+
+ if (present(forc_rho)) then
+ this%atm2lnd_inst%forc_rho_downscaled_col(bounds%begc:bounds%endc) = forc_rho(:)
+ else
+ this%atm2lnd_inst%forc_rho_downscaled_col(bounds%begc:bounds%endc) = forc_rho_default
+ end if
+
+ end subroutine create_atm2lnd
+
+ !-----------------------------------------------------------------------
+
+ subroutine create_fv(this, fv, u10, ram1)
+ ! Initializes some fields needed for dust emissions in this%frictionvel_inst, and sets
+ ! fields based on inputs. Excluded inputs are given a default value
+ class(unittest_dust_emis_input_type), intent(inout) :: this
+ real(r8), intent(in), optional :: fv
+ real(r8), intent(in), optional :: u10
+ real(r8), intent(in), optional :: ram1
+
+ real(r8), parameter :: fv_default = 2.0_r8
+ real(r8), parameter :: u10_default = 4._r8
+ real(r8), parameter :: ram1_default = 200._r8
+ ! ------------------------------------------------------------------------
+
+ if (present(fv)) then
+ this%frictionvel_inst%fv_patch(bounds%begp:bounds%endp) = fv
+ else
+ this%frictionvel_inst%fv_patch(bounds%begp:bounds%endp) = fv_default
+ end if
+
+ if (present(u10)) then
+ this%frictionvel_inst%u10_patch(bounds%begp:bounds%endp) = u10
+ else
+ this%frictionvel_inst%u10_patch(bounds%begp:bounds%endp) = u10_default
+ end if
+
+ if (present(ram1)) then
+ this%frictionvel_inst%ram1_patch(bounds%begp:bounds%endp) = ram1
+ else
+ this%frictionvel_inst%ram1_patch(bounds%begp:bounds%endp) = ram1_default
+ end if
+
+ end subroutine create_fv
+
+ !-----------------------------------------------------------------------
+
+ subroutine print_values(this)
+ use LandunitType, only : lun
+ use PatchType, only : patch
+ class(unittest_dust_emis_input_type), intent(inout) :: this
+ integer :: p, c, l
+
+ do l = bounds%begl, bounds%endl
+ print *, 'landunit type= ', lun%itype(l)
+ end do
+ do c = bounds%begc, bounds%endc
+ print *, 'watsat = ', this%soilstate_inst%watsat_col(c,1)
+ print *, 'h2osoi_vol = ', this%water_inst%waterstatebulk_inst%h2osoi_vol_col(c,1)
+ print *, 'frac_sno = ', this%water_inst%waterdiagnosticbulk_inst%frac_sno_col(c)
+ print *, 'mss_frac_clay_vld = ', this%soilstate_inst%mss_frc_cly_vld_col(c)
+ end do
+ do p = bounds%begp, bounds%endp
+ print *, 'patch type= ', patch%itype(p)
+ print *, 'patch weight= ', patch%wtgcell(p)
+ print *, 'patch active= ', patch%active(p)
+ print *, 'tlai = ', this%canopystate_inst%tlai_patch(p)
+ print *, 'tsai = ', this%canopystate_inst%tsai_patch(p)
+ end do
+ end subroutine print_values
+
+ !-----------------------------------------------------------------------
+
+end module unittestDustEmisInputs
\ No newline at end of file
diff --git a/src/unit_test_stubs/share_esmf/CMakeLists.txt b/src/unit_test_stubs/share_esmf/CMakeLists.txt
index 5eb2d42415..5ffce0ba94 100644
--- a/src/unit_test_stubs/share_esmf/CMakeLists.txt
+++ b/src/unit_test_stubs/share_esmf/CMakeLists.txt
@@ -1,5 +1,6 @@
list(APPEND clm_sources
ExcessIceStreamType.F90
+ ZenderSoilErodStreamType.F90
)
sourcelist_to_parent(clm_sources)
diff --git a/src/unit_test_stubs/share_esmf/ZenderSoilErodStreamType.F90 b/src/unit_test_stubs/share_esmf/ZenderSoilErodStreamType.F90
new file mode 100644
index 0000000000..570fcec05f
--- /dev/null
+++ b/src/unit_test_stubs/share_esmf/ZenderSoilErodStreamType.F90
@@ -0,0 +1,88 @@
+module ZenderSoilErodStreamType
+
+ !-----------------------------------------------------------------------
+ ! !DESCRIPTION:
+ ! UNIT-TEST STUB for ZenderSoilErodStreamType
+ !
+ ! !USES
+ use shr_kind_mod , only : r8 => shr_kind_r8, CL => shr_kind_cl
+ use shr_log_mod , only : errMsg => shr_log_errMsg
+ use abortutils , only : endrun
+ use decompMod , only : bounds_type
+
+ ! !PUBLIC TYPES:
+ implicit none
+ private
+
+ type, public :: soil_erod_stream_type
+ contains
+
+ ! !PUBLIC MEMBER FUNCTIONS:
+ procedure, public :: Init ! Initialize and read data in
+ procedure, public :: CalcDustSource ! Calculate dust source spatial filter (basically truncating stream data value smaller than 0.1 following CAM's practice) based on input streams
+ procedure, public :: UseStreams ! If streams will be used
+
+ end type soil_erod_stream_type
+
+ character(len=*), parameter, private :: sourcefile = &
+ __FILE__
+
+!==============================================================================
+contains
+!==============================================================================
+
+ subroutine Init(this, bounds, NLFilename)
+ !
+ ! Initialize the Zender soil eroditability stream object
+ !
+ ! Uses:
+ !
+ ! arguments
+ implicit none
+ class(soil_erod_stream_type) :: this
+ type(bounds_type), intent(in) :: bounds
+ character(len=*), intent(in) :: NLFilename ! Namelist filename
+ !
+ ! local variables
+ !-----------------------------------------------------------------------
+
+ end subroutine Init
+
+ !==============================================================================
+ logical function UseStreams(this)
+ !
+ ! !DESCRIPTION:
+ ! Return true if the Zender method is being used and the soil erodability
+ ! file is being used with it
+ !
+ ! !USES:
+ !
+ ! !ARGUMENTS:
+ implicit none
+ class(soil_erod_stream_type) :: this
+ !
+ ! !LOCAL VARIABLES:
+ UseStreams = .false.
+ end function UseStreams
+
+ !==============================================================================
+ subroutine CalcDustSource(this, bounds, soil_erod)
+ !
+ ! !DESCRIPTION:
+ ! Calculate the soil eroditability for the Zender dust method.
+ !
+ ! !USES:
+ !USES
+ !
+ ! !ARGUMENTS:
+ implicit none
+ class(soil_erod_stream_type) :: this
+ type(bounds_type) , intent(in) :: bounds
+ real(r8) , intent(inout) :: soil_erod(bounds%begc:) ! [fraction] rock drag partition factor (roughness effect)
+ !
+ ! !LOCAL VARIABLES:
+ !---------------------------------------------------------------------
+
+ end subroutine CalcDustSource
+
+end module ZenderSoilErodStreamType
diff --git a/test/tools/CLM_compare.sh b/test/tools/CLM_compare.sh
deleted file mode 100755
index 38f547c3ab..0000000000
--- a/test/tools/CLM_compare.sh
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/bin/sh
-#
-
-if [ $# -ne 2 ]; then
- echo "CLM_compare.sh: incorrect number of input arguments"
- exit 1
-fi
-
-echo "CLM_compare.sh: comparing $1 "
-echo " with $2"
-
-##note syntax here as stderr and stdout from cprnc command go
-##to separate places!
-${CPRNC_EXE} ${CPRNC_OPT} $1 $2 2>&1 > cprnc.out
-rc=$?
-if [ $rc -ne 0 ]; then
- echo "CLM_compare.sh: error doing comparison, cprnc error= $rc"
- exit 2
-fi
-
-result_old=`perl -e 'while (my $ll = <>) \
- { if ($ll =~ /(\d+)[^0-9]+compared[^0-9]+(\d+)/) \
- { print "PASS" if $1>0 && $2==0 }}' cprnc.out`
-if grep -c "the two files seem to be IDENTICAL" cprnc.out > /dev/null; then
- result=PASS
-elif grep -c "the two files seem to be DIFFERENT" cprnc.out > /dev/null; then
- result=FAIL
-else
- result=$result_old
-fi
-
-if [ "$result" = "PASS" ]; then
- echo "CLM_compare.sh: files are b4b"
-else
- echo "CLM_compare.sh: files are NOT b4b"
- exit 3
-fi
-
-exit 0
diff --git a/test/tools/Makefile b/test/tools/Makefile
deleted file mode 100644
index b5031abdba..0000000000
--- a/test/tools/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-#
-# Makefile to build clm testing documentation
-#
-
-# Get list of tests_ files
-SOURCES = $(wildcard tests_*)
-
-all: test_table.html
-
-test_table.html: $(SOURCES)
- gen_test_table.sh
-
diff --git a/test/tools/README b/test/tools/README
deleted file mode 100644
index c545f625b8..0000000000
--- a/test/tools/README
+++ /dev/null
@@ -1,73 +0,0 @@
-$CTSMROOT/clm/test/tools/README 06/08/2018
-
-Scripts for testing the CLM support tools with many different
-configurations and run-time options.
-
-I. MAIN SCRIPTS:
-
-test_driver.sh - Test the CLM offline tools
-
-To use...
-
-./test_driver.sh -i
-
-on Derecho
-
-qcmd -l walltime=08:00:00 -- ./test_driver.sh -i >& run.out &
-
-And to for example to compare to another baseline code (in this case ctsm5.1.dev066, which would need to be cloned at the given
-path) ...
-
-qcmd -l walltime=08:00:00 -- env BL_ROOT=/glade/scratch/erik/ctsm5.1.dev066 ./test_driver.sh -i >& run.out &
-
-on izumi
-
-nohup ./test_driver.sh -i >& run.out &
-
-release tests
-
-qcmd -l walltime=10:00:00 -- env CLM_INPUT_TESTS=`pwd`/tests_posttag_nompi_regression \
-./test_driver.sh -i >& run_regress.out &
-
-To run neon-specific tests, please use login nodes:
-env CLM_INPUT_TESTS=`pwd`/tests_pretag_nompi_neon ./test_driver.sh -i > & run_neon.out &
-
-
-Intended for use on NCAR machines Derecho, Casper (DAV) and izumi.
-
-II. RUNNING test_driver.sh TOOLS TESTING:
-
-Basic use:
-
-./test_driver.sh -i
-./test_driver.sh -h # to get help on options
-
-Important environment variables (just used by test_driver.sh)
-
-BL_ROOT ---------------- Root directory of CLM baseline code to compare to
- (if not set BL test will not be performed)
-BL_TESTDIR ------------- Root directory of where to put baseline tests
-CLM_INPUT_TESTS -------- Filename of file with list of tests to perform
-CLM_TESTDIR ------------ Root directory of where to put most tests
-CLM_RETAIN_FILES ------- If set to TRUE -- don't cleanup files after testing
-CLM_FC ----------------- Use given compiler
-CLM_JOBID -------------- Job identification number to use (rather than process ID)
-CLM_THREADS ------------ Number of open-MP threads to use
- (by default this is set differently by machine)
-CLM_SOFF --------------- If set to TRUE -- stop on first failed test (default FALSE)
-
-Important files for test_driver tools testing:
-
-test_driver.sh ------- Main test script for tools
-nl_files ------------- Directory with various namelists to test
-config_files --------- Directory with various configurations to test
-input_tests_master --- Master list of tests
-tests_pretag_* ------- Tests for specific machines to do by default before a tag is done
-tests_posttag_* ------ Tests for specific machines to do for more extensive testing
- after a tag is done
-CLM_compare.sh ------- Compares output history files between two cases
-T*.sh ---------------- Basic test script to do a specific type of test
-gen_test_table.sh ---- Creates HTML table of tests
-Makefile ------------- Will build the HTML table of tests
-
-../../tools/README.testing - Information on how the testing works for the CLM tools
diff --git a/test/tools/README.testnames b/test/tools/README.testnames
deleted file mode 100644
index 74dbe8e5f3..0000000000
--- a/test/tools/README.testnames
+++ /dev/null
@@ -1,69 +0,0 @@
-Tests for test_driver are for the CLM tools only.
-
-Test naming conventions for the test_driver.sh script:
-
-Test names are:
-
-xxnmi
-
-Where: xx is the two-letter test type
- sm=smoke, br=branch, er=exact restart, bl=base-line comparision,
- cb=configure-build, rp=reproducibility, op=OpenMP threading for tools
-
-n is the configuration type:
-
-1 -- unused
-2 -- unused
-3 -- unused
-4 -- unused
-5 -- unused
-6 -- unused
-7 -- unused
-8 -- unused
-9 -- mesh_maker
-0 -- run_neon
-a -- modify_data
-b -- subset_data
-c -- mkprocdata_map
-d -- mkmapgrids
-e -- unused
-f -- unused
-g -- unused
-h -- unused
-i -- tools scripts
-
-m is the resolution
-
-0 -- 0.9x1.25
-1 -- 48x96
-5 -- 10x15
-6 -- 5x5_amazon
-7 -- 1x1 brazil
-8 -- US-UMB
-9 -- 4x5
-a -- NEON YELL
-b -- NEON KONA
-c -- NEON OSBS
-d -- SouthAmerica
-e -- 1850PanTropics
-f -- PanBoreal
-g -- AlaskaTananaValley
-h -- single point from the 0.9x1.25 grid (Township SD)
-y -- 1.9x2.5 with transient 1850-2100 for rcp=2.6 and glacier-MEC on
-T -- 1x1_numaIA
-Z -- 10x15 with crop on
-@ -- ne120np4
-# -- ne30np4
-
-i is the specific test (usually this implies...)
-
-1 -- Serial script
-2 -- Serial
-3 -- OpenMP only
-4 -- serial, DEBUG
-7 -- OpenMP only second test, DEBUG
-8 -- OpenMP only third test, DEBUG
-9 -- Serial Script
-0 -- Serial Script
-
-
diff --git a/test/tools/TBLCFGtools.sh b/test/tools/TBLCFGtools.sh
deleted file mode 100755
index 6276c885e2..0000000000
--- a/test/tools/TBLCFGtools.sh
+++ /dev/null
@@ -1,120 +0,0 @@
-#!/bin/sh
-#
-
-if [ $# -ne 3 ]; then
- echo "TBLCFGtools.sh: incorrect number of input arguments"
- exit 1
-fi
-
-if [ -z "$BL_ROOT" ] && [ -z "$BL_TESTDIR" ]; then
- echo "TBL.sh: no environment variables set for baseline test - will skip"
- exit 255
-fi
-
-tool=$(basename $1)
-test_name=TBLCFGtools.$tool.$2.$3
-
-if [ -f ${CLM_TESTDIR}/${test_name}/TestStatus ]; then
- if grep -c PASS ${CLM_TESTDIR}/${test_name}/TestStatus > /dev/null; then
- echo "TBLCFGtools.sh: smoke test has already passed; results are in "
- echo " ${CLM_TESTDIR}/${test_name}"
- exit 0
- elif grep -c GEN ${CLM_TESTDIR}/${test_name}/TestStatus > /dev/null; then
- echo "TBLCFGtools.sh: test already generated"
- else
- read fail_msg < ${CLM_TESTDIR}/${test_name}/TestStatus
- prev_jobid=${fail_msg#*job}
-
- if [ $JOBID = $prev_jobid ]; then
- echo "TBLCFGtools.sh: smoke test has already failed for this job - will not reattempt; "
- echo " results are in: ${CLM_TESTDIR}/${test_name}"
- exit 2
- else
- echo "TBLCFGtools.sh: this smoke test failed under job ${prev_jobid} - moving those results to "
- echo " ${CLM_TESTDIR}/${test_name}_FAIL.job$prev_jobid and trying again"
- cp -rp ${CLM_TESTDIR}/${test_name} ${CLM_TESTDIR}/${test_name}_FAIL.job$prev_jobid
- fi
- fi
-fi
-
-rundir=${CLM_TESTDIR}/${test_name}
-if [ -d ${rundir} ]; then
- rm -r ${rundir}
-fi
-mkdir -p ${rundir}
-if [ $? -ne 0 ]; then
- echo "TBLCFGtools.sh: error, unable to create work subdirectory"
- exit 3
-fi
-cd ${rundir}
-
-echo "TBLCFGtools.sh: calling TSMCFGtools.sh to run $tool executable"
-${CLM_SCRIPTDIR}/TSMCFGtools.sh $1 $2 $3
-rc=$?
-if [ $rc -ne 0 ]; then
- echo "TBLCFGtools.sh: error from TSMCFGtools.sh= $rc"
- echo "FAIL.job${JOBID}" > TestStatus
- exit 4
-fi
-
-if [ -n "${BL_ROOT}" ]; then
- if [ -z "$BL_TESTDIR" ]; then
- BL_TESTDIR=${CLM_TESTDIR}.bl
- fi
- echo "TBLCFGtools.sh: generating baseline data from root $BL_ROOT - results in $BL_TESTDIR"
-
- echo "TBLCFGtools.sh: calling ****baseline**** TSMCFGtools.sh for smoke test"
- bl_dir=`/bin/ls -1d ${BL_ROOT}/test/tools`
- env CLM_TESTDIR=${BL_TESTDIR} \
- CLM_ROOT=${BL_ROOT} \
- CLM_SCRIPTDIR=$bl_dir \
- $bl_dir/TSMCFGtools.sh $1 $2 $3
- rc=$?
- if [ $rc -ne 0 ]; then
- echo "TBLCFGtools.sh: error from *baseline* TSMCFGtools.sh= $rc"
- echo "FAIL.job${JOBID}" > TestStatus
- exit 5
- fi
-fi
-
-echo "TBLCFGtools.sh: starting b4b comparisons "
-files_to_compare=`cd ${CLM_TESTDIR}/TSMCFGtools.$tool.$2.$3; ls *.nc`
-if [ -z "${files_to_compare}" ] && [ "$debug" != "YES" ]; then
- echo "TBLCFGtools.sh: error locating files to compare"
- echo "FAIL.job${JOBID}" > TestStatus
- exit 6
-fi
-
-all_comparisons_good="TRUE"
-for compare_file in ${files_to_compare}; do
-
- env CPRNC_OPT="-m" \
- ${CLM_SCRIPTDIR}/CLM_compare.sh \
- ${BL_TESTDIR}/TSMCFGtools.$tool.$2.$3/${compare_file} \
- ${CLM_TESTDIR}/TSMCFGtools.$tool.$2.$3/${compare_file}
- rc=$?
- mv cprnc.out cprnc.${compare_file}.out
- if [ $rc -eq 0 ]; then
- echo "TBLCFGtools.sh: comparison successful; output in ${rundir}/cprnc.${compare_file}.out"
- else
- echo "TBLCFGtools.sh: error from CLM_compare.sh= $rc; see ${rundir}/cprnc.${compare_file}.out for details
-"
- all_comparisons_good="FALSE"
- fi
-done
-
-if [ ${all_comparisons_good} = "TRUE" ]; then
- echo "TBLCFGtools.sh: baseline test passed"
- echo "PASS" > TestStatus
- if [ $CLM_RETAIN_FILES != "TRUE" ]; then
- echo "TBLCFGtools.sh: removing some unneeded files to save disc space"
- rm *.nc
- rm *.r*
- fi
-else
- echo "TBLCFGtools.sh: at least one file comparison did not pass"
- echo "FAIL.job${JOBID}" > TestStatus
- exit 7
-fi
-
-exit 0
diff --git a/test/tools/TBLscript_tools.sh b/test/tools/TBLscript_tools.sh
deleted file mode 100755
index d05492c687..0000000000
--- a/test/tools/TBLscript_tools.sh
+++ /dev/null
@@ -1,122 +0,0 @@
-#!/bin/sh
-#
-
-if [ $# -ne 3 ]; then
- echo "TBLscript_tools.sh: incorrect number of input arguments"
- exit 1
-fi
-
-if [ -z "$BL_ROOT" ] && [ -z "$BL_TESTDIR" ]; then
- echo "TBLscript_tools.sh: no environment variables set for baseline test - will skip"
- exit 255
-fi
-
-test_name=TBLscript_tools.$1.$2.$3
-
-if [ -f ${CLM_TESTDIR}/${test_name}/TestStatus ]; then
- if grep -c PASS ${CLM_TESTDIR}/${test_name}/TestStatus > /dev/null; then
- echo "TBLscript_tools.sh: smoke test has already passed; results are in "
- echo " ${CLM_TESTDIR}/${test_name}"
- exit 0
- elif grep -c GEN ${CLM_TESTDIR}/${test_name}/TestStatus > /dev/null; then
- echo "TBLscript_tools.sh: test already generated"
- else
- read fail_msg < ${CLM_TESTDIR}/${test_name}/TestStatus
- prev_jobid=${fail_msg#*job}
-
- if [ $JOBID = $prev_jobid ]; then
- echo "TBLscript_tools.sh: smoke test has already failed for this job - will not reattempt; "
- echo " results are in: ${CLM_TESTDIR}/${test_name}"
- exit 2
- else
- echo "TBLscript_tools.sh: this smoke test failed under job ${prev_jobid} - moving those results to "
- echo " ${CLM_TESTDIR}/${test_name}_FAIL.job$prev_jobid and trying again"
- cp -rp ${CLM_TESTDIR}/${test_name} ${CLM_TESTDIR}/${test_name}_FAIL.job$prev_jobid
- fi
- fi
-fi
-
-rundir=${CLM_TESTDIR}/${test_name}
-if [ -d ${rundir} ]; then
- rm -r ${rundir}
-fi
-mkdir -p ${rundir}
-if [ $? -ne 0 ]; then
- echo "TBLscript_tools.sh: error, unable to create work subdirectory"
- exit 3
-fi
-cd ${rundir}
-
-echo "TBLscript_tools.sh: calling TSMscript_tools.sh to run $1 executable"
-${CLM_SCRIPTDIR}/TSMscript_tools.sh $1 $2 $3
-rc=$?
-if [ $rc -ne 0 ]; then
- echo "TBLscript_tools.sh: error from TSMtools.sh= $rc"
- echo "FAIL.job${JOBID}" > TestStatus
- exit 4
-fi
-
-if [ -n "${BL_ROOT}" ]; then
- if [ -z "$BL_TESTDIR" ]; then
- BL_TESTDIR=${CLM_TESTDIR}.bl
- fi
- echo "TBLscript_tools.sh: generating baseline data from root $BL_ROOT - results in $BL_TESTDIR"
-
- echo "TBLscript_tools.sh: calling ****baseline**** TSMtools.sh for smoke test"
- bl_dir=`/bin/ls -1d ${BL_ROOT}/test/tools`
- env CLM_TESTDIR=${BL_TESTDIR} \
- CLM_SCRIPTDIR=$bl_dir \
- CLM_ROOT=$BL_ROOT \
- CTSM_ROOT=$BL_ROOT \
- CIME_ROOT=$BL_ROOT/cime \
- $bl_dir/TSMscript_tools.sh $1 $2 $3
- rc=$?
- if [ $rc -ne 0 ]; then
- echo "TBLscript_tools.sh: error from *baseline* TSMscript_tools.sh= $rc"
- echo "FAIL.job${JOBID}" > TestStatus
- exit 5
- fi
-fi
-
-echo "TBLscript_tools.sh: starting b4b comparisons "
-files_to_compare=`cd ${CLM_TESTDIR}/TSMscript_tools.$1.$2.$3; ls *.nc`
-if [ -z "${files_to_compare}" ] && [ "$debug" != "YES" ]; then
- echo "TBLscript_tools.sh: error locating files to compare"
- echo "FAIL.job${JOBID}" > TestStatus
- exit 6
-fi
-
-all_comparisons_good="TRUE"
-for compare_file in ${files_to_compare}; do
-
- env CPRNC_OPT="-m" \
- ${CLM_SCRIPTDIR}/CLM_compare.sh \
- ${BL_TESTDIR}/TSMscript_tools.$1.$2.$3/${compare_file} \
- ${CLM_TESTDIR}/TSMscript_tools.$1.$2.$3/${compare_file}
- rc=$?
- mv cprnc.out cprnc.${compare_file}.out
- if [ $rc -eq 0 ]; then
- echo "TBLscript_tools.sh: comparison successful; output in ${rundir}/cprnc.${compare_file}.out"
- else
- echo "TBLscript_tools.sh: error from CLM_compare.sh= $rc; see ${rundir}/cprnc.${compare_file}.out for details"
- all_comparisons_good="FALSE"
- fi
-done
-
-if [ ${all_comparisons_good} = "TRUE" ]; then
- echo "TBLscript_tools.sh: baseline test passed"
- echo "PASS" > TestStatus
- if [ $CLM_RETAIN_FILES != "TRUE" ]; then
- echo "TBLscript_tools.sh: removing some unneeded files to save disc space"
- rm *.nc
- rm *.r*
- fi
-else
- echo "TBLscript_tools.sh: at least one file comparison did not pass"
- echo "FAIL.job${JOBID}" > TestStatus
- exit 7
-fi
-
-
-
-exit 0
diff --git a/test/tools/TBLtools.sh b/test/tools/TBLtools.sh
deleted file mode 100755
index 555ea7d1be..0000000000
--- a/test/tools/TBLtools.sh
+++ /dev/null
@@ -1,119 +0,0 @@
-#!/bin/sh
-#
-
-if [ $# -ne 3 ]; then
- echo "TBLtools.sh: incorrect number of input arguments"
- exit 1
-fi
-
-if [ -z "$BL_ROOT" ] && [ -z "$BL_TESTDIR" ]; then
- echo "TBL.sh: no environment variables set for baseline test - will skip"
- exit 255
-fi
-
-test_name=TBLtools.$1.$2.$3
-
-if [ -f ${CLM_TESTDIR}/${test_name}/TestStatus ]; then
- if grep -c PASS ${CLM_TESTDIR}/${test_name}/TestStatus > /dev/null; then
- echo "TBLtools.sh: smoke test has already passed; results are in "
- echo " ${CLM_TESTDIR}/${test_name}"
- exit 0
- elif grep -c GEN ${CLM_TESTDIR}/${test_name}/TestStatus > /dev/null; then
- echo "TBLtools.sh: test already generated"
- else
- read fail_msg < ${CLM_TESTDIR}/${test_name}/TestStatus
- prev_jobid=${fail_msg#*job}
-
- if [ $JOBID = $prev_jobid ]; then
- echo "TBLtools.sh: smoke test has already failed for this job - will not reattempt; "
- echo " results are in: ${CLM_TESTDIR}/${test_name}"
- exit 2
- else
- echo "TBLtools.sh: this smoke test failed under job ${prev_jobid} - moving those results to "
- echo " ${CLM_TESTDIR}/${test_name}_FAIL.job$prev_jobid and trying again"
- cp -rp ${CLM_TESTDIR}/${test_name} ${CLM_TESTDIR}/${test_name}_FAIL.job$prev_jobid
- fi
- fi
-fi
-
-rundir=${CLM_TESTDIR}/${test_name}
-if [ -d ${rundir} ]; then
- rm -r ${rundir}
-fi
-mkdir -p ${rundir}
-if [ $? -ne 0 ]; then
- echo "TBLtools.sh: error, unable to create work subdirectory"
- exit 3
-fi
-cd ${rundir}
-
-echo "TBLtools.sh: calling TSMtools.sh to run $1 executable"
-${CLM_SCRIPTDIR}/TSMtools.sh $1 $2 $3
-rc=$?
-if [ $rc -ne 0 ]; then
- echo "TBLtools.sh: error from TSMtools.sh= $rc"
- echo "FAIL.job${JOBID}" > TestStatus
- exit 4
-fi
-
-if [ -n "${BL_ROOT}" ]; then
- if [ -z "$BL_TESTDIR" ]; then
- BL_TESTDIR=${CLM_TESTDIR}.bl
- fi
- echo "TBLtools.sh: generating baseline data from root $BL_ROOT - results in $BL_TESTDIR"
-
- echo "TBLtools.sh: calling ****baseline**** TSMtools.sh for smoke test"
- bl_dir=`/bin/ls -1d ${BL_ROOT}/test/tools`
- env CLM_TESTDIR=${BL_TESTDIR} \
- CLM_ROOT=${BL_ROOT} \
- CLM_SCRIPTDIR=$bl_dir \
- $bl_dir/TSMtools.sh $1 $2 $3
- rc=$?
- if [ $rc -ne 0 ]; then
- echo "TBLtools.sh: error from *baseline* TSMtools.sh= $rc"
- echo "FAIL.job${JOBID}" > TestStatus
- exit 5
- fi
-fi
-
-echo "TBLtools.sh: starting b4b comparisons "
-files_to_compare=`cd ${CLM_TESTDIR}/TSMtools.$1.$2.$3; ls *.nc`
-if [ -z "${files_to_compare}" ] && [ "$debug" != "YES" ]; then
- echo "TBLtools.sh: error locating files to compare"
- echo "FAIL.job${JOBID}" > TestStatus
- exit 6
-fi
-
-all_comparisons_good="TRUE"
-for compare_file in ${files_to_compare}; do
-
- env CPRNC_OPT="-m" \
- ${CLM_SCRIPTDIR}/CLM_compare.sh \
- ${BL_TESTDIR}/TSMtools.$1.$2.$3/${compare_file} \
- ${CLM_TESTDIR}/TSMtools.$1.$2.$3/${compare_file}
- rc=$?
- mv cprnc.out cprnc.${compare_file}.out
- if [ $rc -eq 0 ]; then
- echo "TBLtools.sh: comparison successful; output in ${rundir}/cprnc.${compare_file}.out"
- else
- echo "TBLtools.sh: error from CLM_compare.sh= $rc; see ${rundir}/cprnc.${compare_file}.out for details
-"
- all_comparisons_good="FALSE"
- fi
-done
-
-if [ ${all_comparisons_good} = "TRUE" ]; then
- echo "TBLtools.sh: baseline test passed"
- echo "PASS" > TestStatus
- if [ $CLM_RETAIN_FILES != "TRUE" ]; then
- echo "TBLtools.sh: removing some unneeded files to save disc space"
- rm *.nc
- rm *.r*
- fi
-else
- echo "TBLtools.sh: at least one file comparison did not pass"
- echo "FAIL.job${JOBID}" > TestStatus
- exit 7
-fi
-
-exit 0
diff --git a/test/tools/TCBCFGtools.sh b/test/tools/TCBCFGtools.sh
deleted file mode 100755
index 5c0b015123..0000000000
--- a/test/tools/TCBCFGtools.sh
+++ /dev/null
@@ -1,135 +0,0 @@
-#!/bin/sh
-#
-
-if [ $# -ne 2 ]; then
- echo "TCBCFGtools.sh: incorrect number of input arguments"
- exit 1
-fi
-
-tool=$(basename $1)
-test_name=TCBCFGtools.$tool.$2
-
-if [ -f ${CLM_TESTDIR}/${test_name}/TestStatus ]; then
- if grep -c PASS ${CLM_TESTDIR}/${test_name}/TestStatus > /dev/null; then
- echo "TCBCFGtools.sh: build test has already passed; results are in "
- echo " ${CLM_TESTDIR}/${test_name}"
- exit 0
- elif grep -c GEN ${CLM_TESTDIR}/${test_name}/TestStatus > /dev/null; then
- echo "TCBCFGtools.sh: test already generated"
- else
- read fail_msg < ${CLM_TESTDIR}/${test_name}/TestStatus
- prev_jobid=${fail_msg#*job}
-
- if [ $JOBID = $prev_jobid ]; then
- echo "TCBCFGtools.sh: build test has already failed for this job - will not reattempt; "
- echo " results are in: ${CLM_TESTDIR}/${test_name}"
- exit 2
- else
- echo "TCBCFGtools.sh: this build test failed under job ${prev_jobid} - moving those results to "
- echo " ${CLM_TESTDIR}/${test_name}_FAIL.job$prev_jobid and trying again"
- cp -rp ${CLM_TESTDIR}/${test_name} ${CLM_TESTDIR}/${test_name}_FAIL.job$prev_jobid
- fi
- fi
-fi
-
-cfgdir=`ls -1d ${CLM_ROOT}/tools/${1}`
-if [ $? -ne 0 ];then
- cfgdir=`ls -1d ${CIME_ROOT}/tools/mapping/${1}*`
- echo "use: $cfgdir"
-fi
-blddir=${CLM_TESTDIR}/${test_name}/src
-if [ -d ${blddir} ]; then
- rm -r ${blddir}
-fi
-mkdir -p ${blddir}
-if [ $? -ne 0 ]; then
- echo "TCBCFGtools.sh: error, unable to create work subdirectory"
- exit 3
-fi
-cd ${blddir}
-
-echo "TCBCFGtools.sh: building $tool executable; output in ${blddir}/test.log"
-#
-# Copy build files over
-#
-cp $cfgdir/src/Makefile .
-cp $cfgdir/src/Filepath .
-#
-# Add cfgdir path to beginning of each path in Filepath
-#
-touch Filepath
-while read filepath_arg; do
- echo "${cfgdir}/src/${filepath_arg}" >> Filepath
-done < ${cfgdir}/src/Filepath
-
-#
-# Figure out configuration
-#
-if [ ! -f ${CLM_SCRIPTDIR}/config_files/$tool ]; then
- echo "TCB.sh: configure options file ${CLM_SCRIPTDIR}/config_files/$tool not found"
- echo "FAIL.job${JOBID}" > TestStatus
- exit 4
-fi
-
-##construct string of args to configure
-config_string=" "
-while read config_arg; do
- config_string="${config_string}${config_arg} "
-done < ${CLM_SCRIPTDIR}/config_files/$tool
-
-if [ "$TOOLSLIBS" != "" ]; then
- export SLIBS=$TOOLSLIBS
-fi
-echo "env CIMEROOT=$CLM_ROOT/cime COMPILER=$CESM_COMP $config_string $CLM_ROOT/cime/tools/configure --macros-format Makefile --machine $CESM_MACH $TOOLS_CONF_STRING"
-env CIMEROOT=$CLM_ROOT/cime COMPILER=$CESM_COMP $config_string $CLM_ROOT/cime/tools/configure --macros-format Makefile --machine $CESM_MACH $TOOLS_CONF_STRING >> test.log 2>&1
-rc=$?
-if [ $rc -ne 0 ]; then
- echo "TCBCFGtools.sh: configure failed, error from configure= $rc"
- echo "TCBCFGtools.sh: see ${blddir}/test.log for details"
- echo "FAIL.job${JOBID}" > TestStatus
- exit 5
-fi
-
-. $INITMODULES
-. ./.env_mach_specific.sh
-
-attempt=1
-still_compiling="TRUE"
-while [ $still_compiling = "TRUE" ]; do
-
- echo "TCBCFGtools.sh: call to make:"
- echo " ${MAKE_CMD} USER_CPPDEFS=-DLINUX"
- if [ "$debug" != "YES" ]; then
- ${MAKE_CMD} USER_CPPDEFS=-DLINUX >> test.log 2>&1
- status="PASS"
- rc=$?
- else
- status="GEN"
- rc=0
- fi
- if [ $rc -eq 0 ]; then
- echo "TCBCFGtools.sh: make was successful"
- echo "TCBCFGtools.sh: configure and build test passed"
- echo "$status" > TestStatus
- if [ $CLM_RETAIN_FILES != "TRUE" ]; then
- echo "TCBCFGtools.sh: removing some unneeded files to save disc space"
- rm *.o
- rm *.mod
- fi
- still_compiling="FALSE"
- elif [ $attempt -lt 10 ] && \
- grep -c "LICENSE MANAGER PROBLEM" test.log > /dev/null; then
- attempt=`expr $attempt + 1`
- echo "TCBCFGtools.sh: encountered License Manager Problem; launching attempt #$attempt"
- else
- echo "TCBCFGtools.sh: clm build failed, error from make= $rc"
- echo "TCBCFGtools.sh: see ${blddir}/test.log for details"
- echo "FAIL.job${JOBID}" > TestStatus
- exit 6
- fi
-done
-if [ "$TOOLSLIBS" != "" ]; then
- export -n SLIBS
-fi
-
-exit 0
diff --git a/test/tools/TCBtools.sh b/test/tools/TCBtools.sh
deleted file mode 100755
index 205b2e9da0..0000000000
--- a/test/tools/TCBtools.sh
+++ /dev/null
@@ -1,121 +0,0 @@
-#!/bin/sh
-#
-
-if [ $# -ne 2 ]; then
- echo "TCBtools.sh: incorrect number of input arguments"
- exit 1
-fi
-
-test_name=TCBtools.$1.$2
-
-if [ -f ${CLM_TESTDIR}/${test_name}/TestStatus ]; then
- if grep -c PASS ${CLM_TESTDIR}/${test_name}/TestStatus > /dev/null; then
- echo "TCBtools.sh: build test has already passed; results are in "
- echo " ${CLM_TESTDIR}/${test_name}"
- exit 0
- elif grep -c GEN ${CLM_TESTDIR}/${test_name}/TestStatus > /dev/null; then
- echo "TCBtools.sh: test already generated"
- else
- read fail_msg < ${CLM_TESTDIR}/${test_name}/TestStatus
- prev_jobid=${fail_msg#*job}
-
- if [ $JOBID = $prev_jobid ]; then
- echo "TCBtools.sh: build test has already failed for this job - will not reattempt; "
- echo " results are in: ${CLM_TESTDIR}/${test_name}"
- exit 2
- else
- echo "TCBtools.sh: this build test failed under job ${prev_jobid} - moving those results to "
- echo " ${CLM_TESTDIR}/${test_name}_FAIL.job$prev_jobid and trying again"
- cp -rp ${CLM_TESTDIR}/${test_name} ${CLM_TESTDIR}/${test_name}_FAIL.job$prev_jobid
- fi
- fi
-fi
-
-cfgdir=`ls -1d ${CLM_ROOT}/tools/$1`
-blddir=${CLM_TESTDIR}/${test_name}/src
-if [ -d ${blddir} ]; then
- rm -r ${blddir}
-fi
-mkdir -p ${blddir}
-if [ $? -ne 0 ]; then
- echo "TCBtools.sh: error, unable to create work subdirectory"
- exit 3
-fi
-cd ${blddir}
-
-echo "TCBtools.sh: building $1 executable; output in ${blddir}/test.log"
-#
-# Copy build files over
-#
-cp $cfgdir/src/Makefile .
-cp $cfgdir/src/Srcfiles .
-cp $cfgdir/src/Mkdepends .
-cp $cfgdir/src/Makefile.common .
-#
-# Add cfgdir path to beginning of each path in Filepath
-#
-touch Filepath
-while read filepath_arg; do
- echo "${cfgdir}/src/${filepath_arg}" >> Filepath
-done < ${cfgdir}/src/Filepath
-
-#
-# Figure out configuration
-#
-if [ ! -f ${CLM_SCRIPTDIR}/config_files/$2 ]; then
- echo "TCB.sh: configure options file ${CLM_SCRIPTDIR}/config_files/$2 not found"
- echo "FAIL.job${JOBID}" > TestStatus
- exit 4
-fi
-
-##construct string of args to configure
-config_string="$TOOLS_MAKE_STRING TOOLROOT=$cfgdir "
-while read config_arg; do
- config_string="${config_string}${config_arg} "
-done < ${CLM_SCRIPTDIR}/config_files/$2
-
-attempt=1
-still_compiling="TRUE"
-if [ "$TOOLSLIBS" != "" ]; then
- export SLIBS=$TOOLSLIBS
-fi
-while [ $still_compiling = "TRUE" ]; do
-
- ln -s Macros.make Macros
-
- echo "TCBtools.sh: call to make:"
- echo " ${MAKE_CMD} ${config_string} "
- if [ "$debug" != "YES" ]; then
- ${MAKE_CMD} ${config_string} >> test.log 2>&1
- status="PASS"
- rc=$(( $rc + $? ))
- else
- status="GEN"
- rc=0
- fi
- if [ $rc -eq 0 ]; then
- echo "TCBtools.sh: make was successful"
- echo "TCBtools.sh: configure and build test passed"
- echo "$status" > TestStatus
- if [ $CLM_RETAIN_FILES != "TRUE" ]; then
- echo "TCBtools.sh: removing some unneeded files to save disc space"
- rm *.o
- rm *.mod
- fi
- still_compiling="FALSE"
- elif [ $attempt -lt 10 ] && \
- grep -c "LICENSE MANAGER PROBLEM" test.log > /dev/null; then
- attempt=`expr $attempt + 1`
- echo "TCBtools.sh: encountered License Manager Problem; launching attempt #$attempt"
- else
- echo "TCBtools.sh: clm build failed, error from make= $rc"
- echo "TCBtools.sh: see ${CLM_TESTDIR}/${test_name}/test.log for details"
- echo "FAIL.job${JOBID}" > TestStatus
- exit 6
- fi
-done
-if [ "$TOOLSLIBS" != "" ]; then
- export -n SLIBS
-fi
-
-exit 0
diff --git a/test/tools/TSMCFGtools.sh b/test/tools/TSMCFGtools.sh
deleted file mode 100755
index b667a4c6ec..0000000000
--- a/test/tools/TSMCFGtools.sh
+++ /dev/null
@@ -1,113 +0,0 @@
-#!/bin/sh
-#
-
-if [ $# -ne 3 ]; then
- echo "TSMCFGtools.sh: incorrect number of input arguments"
- exit 1
-fi
-
-tool=$(basename $1)
-test_name=TSMCFGtools.$tool.$2.$3
-
-
-if [ -z "$CLM_RERUN" ]; then
- CLM_RERUN="no"
-fi
-
-if [ "$CLM_RERUN" != "yes" ] && [ -f ${CLM_TESTDIR}/${test_name}/TestStatus ]; then
- if grep -c PASS ${CLM_TESTDIR}/${test_name}/TestStatus > /dev/null; then
- echo "TSMCFGtools.sh: smoke test has already passed; results are in "
- echo " ${CLM_TESTDIR}/${test_name}"
- exit 0
- elif grep -c GEN ${CLM_TESTDIR}/${test_name}/TestStatus > /dev/null; then
- echo "TSMCFGtools.sh: test already generated"
- else
- read fail_msg < ${CLM_TESTDIR}/${test_name}/TestStatus
- prev_jobid=${fail_msg#*job}
-
- if [ $JOBID = $prev_jobid ]; then
- echo "TSMCFGtools.sh: smoke test has already failed for this job - will not reattempt; "
- echo " results are in: ${CLM_TESTDIR}/${test_name}"
- exit 2
- else
- echo "TSMCFGtools.sh: this smoke test failed under job ${prev_jobid} - moving those results to "
- echo " ${CLM_TESTDIR}/${test_name}_FAIL.job$prev_jobid and trying again"
- cp -rp ${CLM_TESTDIR}/${test_name} ${CLM_TESTDIR}/${test_name}_FAIL.job$prev_jobid
- fi
- fi
-fi
-
-cfgdir=`ls -1d ${CLM_ROOT}/tools/${1}*`
-rundir=${CLM_TESTDIR}/${test_name}
-if [ -d ${rundir} ]; then
- rm -r ${rundir}
-fi
-mkdir -p ${rundir}
-if [ $? -ne 0 ]; then
- echo "TSMCFGtools.sh: error, unable to create work subdirectory"
- exit 3
-fi
-cd ${rundir}
-
-echo "TSMCFGtools.sh: calling TCBCFGtools.sh to prepare $tool executable"
-${CLM_SCRIPTDIR}/TCBCFGtools.sh $1 $2
-rc=$?
-if [ $rc -ne 0 ]; then
- echo "TSMCFGtools.sh: error from TCBtools.sh= $rc"
- echo "FAIL.job${JOBID}" > TestStatus
- exit 4
-fi
-
-echo "TSMCFGtools.sh: running $tool output in ${rundir}/test.log"
-
-if [ "$2" = "CFGtools__o" ] || [ "$2" = "CFGtools__do" ]; then
- toolrun="env OMP_NUM_THREADS=${CLM_THREADS} ${CLM_TESTDIR}/TCBCFGtools.$tool.$2/${tool}*"
-else
- toolrun="${CLM_TESTDIR}/TCBCFGtools.$tool.$2/${tool}*"
-fi
-
-runfile="${CLM_SCRIPTDIR}/nl_files/$tool.$3"
-if [ ! -f "${runfile}" ]; then
- echo "TSMCFGtools.sh: error ${runfile} input run file not found"
- echo "FAIL.job${JOBID}" > TestStatus
- exit 5
-fi
-
-echo "Run file type = ${3#*.}"
-if [ ${3#*.} == "runoptions" ]; then
- runopts=`cat ${runfile} | sed -e "s|CSMDATA|$CSMDATA|g"`
- echo "$toolrun $runopts"
- cp $cfgdir/*.nc .
- if [ "$debug" != "YES" ] && [ "$compile_only" != "YES" ]; then
- $toolrun $runopts >> test.log 2>&1
- rc=$?
- status="PASS"
- else
- echo "Successfully created file" > test.log
- status="GEN"
- rc=0
- fi
-else
- echo "$toolrun < ${runfile}"
- if [ "$debug" != "YES" ] && [ "$compile_only" != "YES" ]; then
- $toolrun < ${runfile} >> test.log 2>&1
- rc=$?
- status="PASS"
- else
- echo "Successfully created file" > test.log
- status="GEN"
- rc=0
- fi
-fi
-
-if [ $rc -eq 0 ] && grep -ci "Successfully created " test.log > /dev/null; then
- echo "TSMCFGtools.sh: smoke test passed"
- echo "$status" > TestStatus
-else
- echo "TSMCFGtools.sh: error running $tool, error= $rc"
- echo "TSMCFGtools.sh: see ${CLM_TESTDIR}/${test_name}/test.log for details"
- echo "FAIL.job${JOBID}" > TestStatus
- exit 6
-fi
-
-exit 0
diff --git a/test/tools/TSMscript_tools.sh b/test/tools/TSMscript_tools.sh
deleted file mode 100755
index 943fec97f2..0000000000
--- a/test/tools/TSMscript_tools.sh
+++ /dev/null
@@ -1,98 +0,0 @@
-#!/bin/sh
-#
-
-if [ $# -ne 3 ]; then
- echo "TSMscript_tools.sh: incorrect number of input arguments"
- exit 1
-fi
-
-test_name=TSMscript_tools.$1.$2.$3
-
-if [ -f ${CLM_TESTDIR}/${test_name}/TestStatus ]; then
- if grep -c PASS ${CLM_TESTDIR}/${test_name}/TestStatus > /dev/null; then
- echo "TSMscript_tools.sh: smoke test has already passed; results are in "
- echo " ${CLM_TESTDIR}/${test_name}"
- exit 0
- elif grep -c GEN ${CLM_TESTDIR}/${test_name}/TestStatus > /dev/null; then
- echo "TSMscript_tools.sh: test already generated"
- else
- read fail_msg < ${CLM_TESTDIR}/${test_name}/TestStatus
- prev_jobid=${fail_msg#*job}
-
- if [ $JOBID = $prev_jobid ]; then
- echo "TSMscript_tools.sh: smoke test has already failed for this job - will not reattempt; "
- echo " results are in: ${CLM_TESTDIR}/${test_name}"
- exit 2
- else
- echo "TSMscript_tools.sh: this smoke test failed under job ${prev_jobid} - moving those results to "
- echo " ${CLM_TESTDIR}/${test_name}_FAIL.job$prev_jobid and trying again"
- cp -rp ${CLM_TESTDIR}/${test_name} ${CLM_TESTDIR}/${test_name}_FAIL.job$prev_jobid
- fi
- fi
-fi
-
-cfgdir=`ls -1d ${CLM_ROOT}/tools/$1`
-rundir=${CLM_TESTDIR}/${test_name}
-if [ -d ${rundir} ]; then
- rm -r ${rundir}
-fi
-mkdir -p ${rundir}
-if [ $? -ne 0 ]; then
- echo "TSMscript_tools.sh: error, unable to create work subdirectory"
- exit 3
-fi
-cd ${rundir}
-
-optfile=${3%^*}
-cfgfile=${3#*^}
-
-if [ "$optfile" != "$3" ]; then
- echo "TSMscript_tools.sh: calling TCBtools.sh to prepare $1 executable"
- ${CLM_SCRIPTDIR}/TCBtools.sh $1 $cfgfile
- rc=$?
- if [ $rc -ne 0 ]; then
- echo "TSMscript_tools.sh: error from TCBtools.sh= $rc"
- echo "FAIL.job${JOBID}" > TestStatus
- exit 4
- fi
- tcbtools=${CLM_TESTDIR}/TCBtools.$1.$cfgfile
-else
- tcbtools="$rundir"
-fi
-
-scopts=`cat ${CLM_SCRIPTDIR}/nl_files/$optfile | sed -e "s|CSMDATA|$CSMDATA|g" | sed -e "s|EXEDIR|$tcbtools|g" | sed -e "s|CFGDIR|$cfgdir|g"`
-scopts=`echo $scopts | sed -e "s|CTSM_ROOT|$CTSM_ROOT|g" | sed -e "s|CIME_ROOT|$CIME_ROOT|g"`
-
-echo "TSMscript_tools.sh: running ${cfgdir}/$2 with $scopts; output in ${rundir}/test.log"
-
-if [ ! -f "${cfgdir}/$2" ]; then
- echo "TSMscript_tools.sh: error ${cfgdir}/$2 input script not found"
- echo "FAIL.job${JOBID}" > TestStatus
- exit 5
-fi
-
-if [ "$debug" != "YES" ] && [ "$compile_only" != "YES" ]; then
- ${cfgdir}/$2 $scopts >> test.log 2>&1
- rc=$?
- status="PASS"
-else
- echo "success" > test.log
- status="GEN"
- rc=0
-fi
-
-if [ $rc -eq 0 ] && grep -ci "Successfully " test.log > /dev/null; then
- echo "TSMscript_tools.sh: smoke test passed"
- echo "$status" > TestStatus
- # Copy files from subdirectories up...
- # (use hard links rather than symbolic links because 'ln -s' does funny
- # things when there are no matching files)
- ln */*.nc */*/*.nc .
-else
- echo "TSMscript_tools.sh: error running $2, error= $rc"
- echo "TSMscript_tools.sh: see ${CLM_TESTDIR}/${test_name}/test.log for details"
- echo "FAIL.job${JOBID}" > TestStatus
- exit 6
-fi
-
-exit 0
diff --git a/test/tools/TSMtools.sh b/test/tools/TSMtools.sh
deleted file mode 100755
index 33a2316973..0000000000
--- a/test/tools/TSMtools.sh
+++ /dev/null
@@ -1,117 +0,0 @@
-#!/bin/sh
-#
-
-if [ $# -ne 3 ]; then
- echo "TSMtools.sh: incorrect number of input arguments"
- exit 1
-fi
-
-test_name=TSMtools.$1.$2.$3
-
-if [ -z "$CLM_RERUN" ]; then
- CLM_RERUN="no"
-fi
-
-if [ "$CLM_RERUN" != "yes" ] && [ -f ${CLM_TESTDIR}/${test_name}/TestStatus ]; then
- if grep -c PASS ${CLM_TESTDIR}/${test_name}/TestStatus > /dev/null; then
- echo "TSMtools.sh: smoke test has already passed; results are in "
- echo " ${CLM_TESTDIR}/${test_name}"
- exit 0
- elif grep -c GEN ${CLM_TESTDIR}/${test_name}/TestStatus > /dev/null; then
- echo "TSMtools.sh: test already generated"
- else
- read fail_msg < ${CLM_TESTDIR}/${test_name}/TestStatus
- prev_jobid=${fail_msg#*job}
-
- if [ $JOBID = $prev_jobid ]; then
- echo "TSMtools.sh: smoke test has already failed for this job - will not reattempt; "
- echo " results are in: ${CLM_TESTDIR}/${test_name}"
- exit 2
- else
- echo "TSMtools.sh: this smoke test failed under job ${prev_jobid} - moving those results to "
- echo " ${CLM_TESTDIR}/${test_name}_FAIL.job$prev_jobid and trying again"
- cp -rp ${CLM_TESTDIR}/${test_name} ${CLM_TESTDIR}/${test_name}_FAIL.job$prev_jobid
- fi
- fi
-fi
-
-cfgdir=`ls -1d ${CLM_ROOT}/tools/$1`
-rundir=${CLM_TESTDIR}/${test_name}
-if [ -d ${rundir} ]; then
- rm -r ${rundir}
-fi
-mkdir -p ${rundir}
-if [ $? -ne 0 ]; then
- echo "TSMtools.sh: error, unable to create work subdirectory"
- exit 3
-fi
-cd ${rundir}
-
-echo "Copy any text files over"
-cp $cfgdir/*.txt $rundir
-
-echo "TSMtools.sh: calling TCBtools.sh to prepare $1 executable"
-${CLM_SCRIPTDIR}/TCBtools.sh $1 $2
-rc=$?
-if [ $rc -ne 0 ]; then
- echo "TSMtools.sh: error from TCBtools.sh= $rc"
- echo "FAIL.job${JOBID}" > TestStatus
- exit 4
-fi
-
-echo "TSMtools.sh: running $1; output in ${rundir}/test.log"
-
-if [ "$3" = "tools__o" ] || [ "$3" = "tools__do" ]; then
- toolrun="env OMP_NUM_THREADS=${CLM_THREADS} ${CLM_TESTDIR}/TCBtools.$1.$2/$1"
-else
- toolrun="${CLM_TESTDIR}/TCBtools.$1.$2/$1"
-fi
-
-runfile="${cfgdir}/$1.$3"
-
-if [ ! -f "${runfile}" ]; then
- runfile="${CLM_SCRIPTDIR}/nl_files/$1.$3"
- if [ ! -f "${runfile}" ]; then
- echo "TSMtools.sh: error ${runfile} input run file not found"
- echo "FAIL.job${JOBID}" > TestStatus
- exit 5
- fi
-fi
-
-echo "Run file type = ${3#*.}"
-if [ ${3#*.} == "runoptions" ]; then
- echo "$toolrun "`cat ${runfile}`
- cp $cfgdir/*.nc .
- if [ "$debug" != "YES" ] && [ "$compile_only" != "YES" ]; then
- $toolrun `cat ${runfile}` >> test.log 2>&1
- rc=$?
- status="PASS"
- else
- echo "Successfully created file" > test.log
- status="GEN"
- rc=0
- fi
-else
- echo "$toolrun < ${runfile}"
- if [ "$debug" != "YES" ] && [ "$compile_only" != "YES" ]; then
- $toolrun < ${runfile} >> test.log 2>&1
- rc=$?
- status="PASS"
- else
- echo "Successfully created file" > test.log
- status="GEN"
- rc=0
- fi
-fi
-
-if [ $rc -eq 0 ] && grep -ci "Successfully created " test.log > /dev/null; then
- echo "TSMtools.sh: smoke test passed"
- echo "$status" > TestStatus
-else
- echo "TSMtools.sh: error running $1, error= $rc"
- echo "TSMtools.sh: see ${CLM_TESTDIR}/${test_name}/test.log for details"
- echo "FAIL.job${JOBID}" > TestStatus
- exit 6
-fi
-
-exit 0
diff --git a/test/tools/config_files/CFGtools__ds b/test/tools/config_files/CFGtools__ds
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/test/tools/config_files/README b/test/tools/config_files/README
deleted file mode 100644
index bdfe5e0dd0..0000000000
--- a/test/tools/config_files/README
+++ /dev/null
@@ -1,9 +0,0 @@
-_do => debug on, omp only on
-_ds => debug on, serial mode (neither mpi nor omp)
-
-_o => debug off, omp only on
-_s => debug off, serial mode (neither mpi nor omp)
-
-tools__ds => options for tools, debug on, serial mode
-tools__do => options for tools, debug on, omp only on
-tools__o => options for tools, debug off, omp only on
diff --git a/test/tools/config_files/tools__do b/test/tools/config_files/tools__do
deleted file mode 100644
index 7f061ed65d..0000000000
--- a/test/tools/config_files/tools__do
+++ /dev/null
@@ -1 +0,0 @@
-SMP=TRUE OPT=FALSE
diff --git a/test/tools/config_files/tools__ds b/test/tools/config_files/tools__ds
deleted file mode 100644
index cf2d414b28..0000000000
--- a/test/tools/config_files/tools__ds
+++ /dev/null
@@ -1 +0,0 @@
-OPT=FALSE
diff --git a/test/tools/config_files/tools__o b/test/tools/config_files/tools__o
deleted file mode 100644
index 8821e0bc5a..0000000000
--- a/test/tools/config_files/tools__o
+++ /dev/null
@@ -1 +0,0 @@
-SMP=TRUE OPT=TRUE
diff --git a/test/tools/config_files/tools__s b/test/tools/config_files/tools__s
deleted file mode 100644
index 507973f8be..0000000000
--- a/test/tools/config_files/tools__s
+++ /dev/null
@@ -1 +0,0 @@
-OPT=TRUE
diff --git a/test/tools/gen_test_table.sh b/test/tools/gen_test_table.sh
deleted file mode 100755
index 0791ad0447..0000000000
--- a/test/tools/gen_test_table.sh
+++ /dev/null
@@ -1,80 +0,0 @@
-#!/bin/sh
-#
-
-# this script, when executed in the directory containing the test-driver
-# scripts (~/test/system) will loop through the default test
-# lists for pre and post tag testing of clm and create an html file
-# (test_table.html) with the specifics of each test detailed
-
-outfile="./test_table.html"
-
-echo '' > $outfile
-echo '' >> $outfile
-echo '' >> $outfile
-echo '' >> $outfile
-echo 'CLM Testing Information Page' >> $outfile
-echo '' >> $outfile
-echo '' >> $outfile
-
-#########################################################################################
-for input_file in `ls tests_*` ; do
- echo '' >> $outfile
- echo "$input_file" >> $outfile
- echo "" >> $outfile
- echo "test# | " >> $outfile
- echo "testid | " >> $outfile
- echo "test script | " >> $outfile
- echo "arg1 | " >> $outfile
- echo "arg2 | " >> $outfile
- echo "arg3 | " >> $outfile
- echo "
" >> $outfile
-
- test_list=""
- while read input_line; do
- test_list="${test_list}${input_line} "
- done < ./${input_file}
-
- count=0
- ##loop through the tests of input file
- for test_id in ${test_list}; do
- echo "" >> $outfile
- count=`expr $count + 1`
- while [ ${#count} -lt 3 ]; do
- count="0${count}"
- done
- echo " $count | " >> $outfile
-
- master_line=`grep $test_id ./input_tests_master`
- dir=""
- for arg in ${master_line}; do
- arg1=${arg%^*}
- arg2=${arg#*^}
- if [ -d ../../tools/$arg ]; then
- dir=$arg
- elif [ -f ./nl_files/$arg ]; then
- echo "$arg | " >> $outfile
- elif [ -f ./config_files/$arg ]; then
- echo "$arg | " >> $outfile
- elif [ -f ./nl_files/$arg1 ] && [ -f ./nl_files/$arg2 ]; then
- echo "$arg1^" \
- "$arg2 | " >> $outfile
- elif [ -f ./nl_files/$arg1 ] && [ -f ./config_files/$arg2 ]; then
- echo "$arg1^" \
- "$arg2 | " >> $outfile
- elif [ -f ../../tools/$dir/$dir.$arg ]; then
- echo "$arg | " >> $outfile
- else
- echo "$arg | " >> $outfile
- fi
- done
- echo '
' >> $outfile
- done
- echo '
' >> $outfile
- echo '' >> $outfile
- echo ' ' >> $outfile
- echo '
' >> $outfile
-done
-echo '' >> $outfile
-echo '' >> $outfile
-
-exit 0
diff --git a/test/tools/get_cprnc_diffs.sh b/test/tools/get_cprnc_diffs.sh
deleted file mode 100755
index 360220cb71..0000000000
--- a/test/tools/get_cprnc_diffs.sh
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/bin/bash
-
-# This script extracts lines from the output of cprnc that tell us
-# which variables differ between two files
-#
-# Usage: get_cprnc_diffs filename
-
-# ----------------------------------------------------------------------
-# SET PARAMETERS HERE
-# ----------------------------------------------------------------------
-
-# maximum number of differences to extract from the cprnc output
-maxdiffs=200
-
-# ----------------------------------------------------------------------
-# LOCAL FUNCTIONS DEFINED HERE
-# ----------------------------------------------------------------------
-
-# This function gets differences for one prefix (e.g., "RMS")
-# Usage: get_diffs prefix
-# (also uses $infile and $maxdiffs from the parent script)
-function get_diffs {
- prefix=$1
- outfile=${infile}.${prefix}.$$
- grep "$prefix" $infile > $outfile
- numlines=`wc -l $outfile | awk '{print $1}'`
- if [ $numlines -gt $maxdiffs ]; then
- echo "WARNING: Too many instances of $prefix - only printing last $maxdiffs"
- tail -$maxdiffs $outfile
- else
- cat $outfile
- fi
- rm $outfile
-}
-
-# ----------------------------------------------------------------------
-# BEGIN MAIN SCRIPT
-# ----------------------------------------------------------------------
-
-# ----------------------------------------------------------------------
-# Handle command-line arguments
-# ----------------------------------------------------------------------
-
-if [[ $# -ne 1 ]]; then
- echo "Usage: get_cprnc_diffs filename"
- exit 1
-fi
-
-infile=$1
-
-# ----------------------------------------------------------------------
-# Do the processing
-# ----------------------------------------------------------------------
-
-get_diffs RMS
-get_diffs FILLDIFF
diff --git a/test/tools/input_tests_master b/test/tools/input_tests_master
deleted file mode 100644
index 7da8c19803..0000000000
--- a/test/tools/input_tests_master
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
-smc#4 TSMscript_tools.sh mkprocdata_map mkprocdata_map_wrap mkprocdata_ne30_to_f19_I2000^tools__ds
-blc#4 TBLscript_tools.sh mkprocdata_map mkprocdata_map_wrap mkprocdata_ne30_to_f19_I2000^tools__ds
-
-sm0c1 TSMscript_tools.sh site_and_regional run_neon.py run_neon_OSBS
-bl0c1 TBLscript_tools.sh site_and_regional run_neon.py run_neon_OSBS
-sm0a1 TSMscript_tools.sh site_and_regional run_neon.py run_neon_YELL_PRISM
-bl0a1 TBLscript_tools.sh site_and_regional run_neon.py run_neon_YELL_PRISM
-
-smba1 TSMscript_tools.sh site_and_regional subset_data subset_data_YELL
-blba1 TBLscript_tools.sh site_and_regional subset_data subset_data_YELL
-smbb1 TSMscript_tools.sh site_and_regional subset_data subset_data_KONA
-blbb1 TBLscript_tools.sh site_and_regional subset_data subset_data_KONA
-smb81 TSMscript_tools.sh site_and_regional subset_data subset_data_US-UMB
-blb81 TBLscript_tools.sh site_and_regional subset_data subset_data_US-UMB
-smbh1 TSMscript_tools.sh site_and_regional subset_data subset_data_f09_1x1pt_townshipSD
-blbh1 TBLscript_tools.sh site_and_regional subset_data subset_data_f09_1x1pt_townshipSD
-smbd1 TSMscript_tools.sh site_and_regional subset_data subset_data_f09_58x45pt_SouthAmerica
-blbd1 TBLscript_tools.sh site_and_regional subset_data subset_data_f09_58x45pt_SouthAmerica
-smbe1 TSMscript_tools.sh site_and_regional subset_data subset_data_f09_90x288pt_1850PanTropics
-blbe1 TBLscript_tools.sh site_and_regional subset_data subset_data_f09_90x288pt_1850PanTropics
-smbf1 TSMscript_tools.sh site_and_regional subset_data subset_data_f09_37x288pt_PanBoreal
-blbf1 TBLscript_tools.sh site_and_regional subset_data subset_data_f09_37x288pt_PanBoreal
-smbg1 TSMscript_tools.sh site_and_regional subset_data subset_data_f09_4x9pt_AlaskaTananaValley
-blbg1 TBLscript_tools.sh site_and_regional subset_data subset_data_f09_4x9pt_AlaskaTananaValley
-
-sm901 TSMscript_tools.sh site_and_regional mesh_maker mesh_maker_fv09
-bl901 TBLscript_tools.sh site_and_regional mesh_maker mesh_maker_fv09
-
-smaa2 TSMscript_tools.sh site_and_regional modify_singlept_site_neon.py modify_data_YELL
-blaa2 TBLscript_tools.sh site_and_regional modify_singlept_site_neon.py modify_data_YELL
diff --git a/test/tools/nl_files/mesh_maker_fv09 b/test/tools/nl_files/mesh_maker_fv09
deleted file mode 100644
index 7de951fee1..0000000000
--- a/test/tools/nl_files/mesh_maker_fv09
+++ /dev/null
@@ -1 +0,0 @@
- --input CSMDATA/atm/datm7/domain.lnd.fv0.9x1.25_gx1v6.090309.nc --lat yc --lon xc --overwrite --mask mask --area area --verbose
diff --git a/test/tools/nl_files/mkmapdata_if10 b/test/tools/nl_files/mkmapdata_if10
deleted file mode 100644
index f726ea34e7..0000000000
--- a/test/tools/nl_files/mkmapdata_if10
+++ /dev/null
@@ -1 +0,0 @@
--r 10x15 --fast --batch
diff --git a/test/tools/nl_files/mkmapdata_ne30np4 b/test/tools/nl_files/mkmapdata_ne30np4
deleted file mode 100644
index ae435ac2bc..0000000000
--- a/test/tools/nl_files/mkmapdata_ne30np4
+++ /dev/null
@@ -1 +0,0 @@
--r ne30np4 --fast --batch
diff --git a/test/tools/nl_files/mkprocdata_ne30_to_f19_I2000 b/test/tools/nl_files/mkprocdata_ne30_to_f19_I2000
deleted file mode 100644
index af85dcf226..0000000000
--- a/test/tools/nl_files/mkprocdata_ne30_to_f19_I2000
+++ /dev/null
@@ -1 +0,0 @@
--i CSMDATA/lnd/clm2/test_mkprocdata_map/clm4054_ne30g16_I2000.clm2.h0.2000-01_c170430.nc -o ne30output_onf19grid.nc -m CSMDATA/lnd/clm2/test_mkprocdata_map/map_ne30np4_nomask_to_fv1.9x2.5_nomask_aave_da_c121107.nc -t CSMDATA/lnd/clm2/test_mkprocdata_map/clm4054_f19g16_I2000.clm2.h0.2000-01_c170430.nc -e EXEDIR
diff --git a/test/tools/nl_files/modify_data_YELL b/test/tools/nl_files/modify_data_YELL
deleted file mode 100644
index 0d180e8bf6..0000000000
--- a/test/tools/nl_files/modify_data_YELL
+++ /dev/null
@@ -1 +0,0 @@
---neon_site YELL --surf_dir CSMDATA/lnd/clm2/surfdata_esmf/NEON --out_dir EXEDIR --inputdata-dir CSMDATA
diff --git a/test/tools/nl_files/run_neon_OSBS b/test/tools/nl_files/run_neon_OSBS
deleted file mode 100644
index 0c274b13ad..0000000000
--- a/test/tools/nl_files/run_neon_OSBS
+++ /dev/null
@@ -1 +0,0 @@
---verbose --run-type ad --setup-only --neon-site OSBS
diff --git a/test/tools/nl_files/run_neon_YELL_PRISM b/test/tools/nl_files/run_neon_YELL_PRISM
deleted file mode 100644
index f5ebdf9fdf..0000000000
--- a/test/tools/nl_files/run_neon_YELL_PRISM
+++ /dev/null
@@ -1 +0,0 @@
---verbose --run-type transient --setup-only --neon-site YELL --prism --neon-version v2 --experiment toolstest
diff --git a/test/tools/nl_files/subset_data_KONA b/test/tools/nl_files/subset_data_KONA
deleted file mode 100644
index 0df59b1b17..0000000000
--- a/test/tools/nl_files/subset_data_KONA
+++ /dev/null
@@ -1 +0,0 @@
-point --lon 263.38956 --lat 39.1082 --site KONA --dompft 17 19 23 45 --pctpft 28 12 32 28 --crop --create-surface --outdir EXEDIR/KONA_user-mod_and_data --user-mods-dir EXEDIR/KONA_user-mod_and_data --verbose --inputdata-dir CSMDATA
diff --git a/test/tools/nl_files/subset_data_US-UMB b/test/tools/nl_files/subset_data_US-UMB
deleted file mode 100644
index 935b0dc99d..0000000000
--- a/test/tools/nl_files/subset_data_US-UMB
+++ /dev/null
@@ -1 +0,0 @@
-point --lon 275.28626 --lat 45.5598 --site 1x1_US-UMB --dompft 7 --cap-saturation --uniform-snowpack --create-surface --outdir EXEDIR/US-UMB_user-mod_and_data --user-mods-dir EXEDIR/US-UMB_user-mod_and_data --verbose --inputdata-dir CSMDATA
diff --git a/test/tools/nl_files/subset_data_YELL b/test/tools/nl_files/subset_data_YELL
deleted file mode 100644
index 0d6960e7f5..0000000000
--- a/test/tools/nl_files/subset_data_YELL
+++ /dev/null
@@ -1 +0,0 @@
-point --lon 250.45804 --lat 44.95597 --site YELL --dompft 1 --crop --uniform-snowpack --cap-saturation --create-surface --outdir EXEDIR/YELL_user-mod_and_data --user-mods-dir EXEDIR/YELL_user-mod_and_data --silent --inputdata-dir CSMDATA
diff --git a/test/tools/nl_files/subset_data_f09_1x1pt_townshipSD b/test/tools/nl_files/subset_data_f09_1x1pt_townshipSD
deleted file mode 100644
index aa25c07d1e..0000000000
--- a/test/tools/nl_files/subset_data_f09_1x1pt_townshipSD
+++ /dev/null
@@ -1 +0,0 @@
-point --lon 257.5 --lat 43.822 --site f09_1x1pt_townshipSD --include-nonveg --crop --create-datm --create-user-mods --datm-syr 2000 --datm-eyr 2000 --create-surface --outdir EXEDIR/f09_US_pt_user-mod_and_data --user-mods-dir EXEDIR/f09_US_pt_user-mod_and_data --verbose --inputdata-dir CSMDATA
diff --git a/test/tools/nl_files/subset_data_f09_37x288pt_PanBoreal b/test/tools/nl_files/subset_data_f09_37x288pt_PanBoreal
deleted file mode 100644
index 448b5052d6..0000000000
--- a/test/tools/nl_files/subset_data_f09_37x288pt_PanBoreal
+++ /dev/null
@@ -1 +0,0 @@
-region --lat1 55 --lat2 89.1 --lon1 0 --lon2 360 --create-mesh --create-surface --create-domain --create-user-mods --verbose --overwrite --reg f09_37x288pt_PanBoreal --inputdata-dir CSMDATA
diff --git a/test/tools/nl_files/subset_data_f09_4x9pt_AlaskaTananaValley b/test/tools/nl_files/subset_data_f09_4x9pt_AlaskaTananaValley
deleted file mode 100644
index 9928d78429..0000000000
--- a/test/tools/nl_files/subset_data_f09_4x9pt_AlaskaTananaValley
+++ /dev/null
@@ -1 +0,0 @@
-region --lat1 62 --lat2 66 --lon1 -152 --lon2 -141 --create-mesh --create-domain --create-surface --create-user-mods --verbose --overwrite --reg f09_4x9pt_AlaskaTananaValley --inputdata-dir CSMDATA
diff --git a/test/tools/nl_files/subset_data_f09_58x45pt_SouthAmerica b/test/tools/nl_files/subset_data_f09_58x45pt_SouthAmerica
deleted file mode 100644
index 201dd2c76c..0000000000
--- a/test/tools/nl_files/subset_data_f09_58x45pt_SouthAmerica
+++ /dev/null
@@ -1 +0,0 @@
-region --lat1 -40 --lat2 15 --lon1 275 --lon2 330 --create-mesh --create-surface --create-user-mods --create-domain --create-landuse --verbose --overwrite --reg f09_58x45_SouthAmerica --inputdata-dir CSMDATA
diff --git a/test/tools/nl_files/subset_data_f09_90x288pt_1850PanTropics b/test/tools/nl_files/subset_data_f09_90x288pt_1850PanTropics
deleted file mode 100644
index 1c9d5eace9..0000000000
--- a/test/tools/nl_files/subset_data_f09_90x288pt_1850PanTropics
+++ /dev/null
@@ -1 +0,0 @@
-region --lat1 -55 --lat2 30 --lon1 0 --lon2 360 --crop --create-surface --create-domain --create-mesh --overwrite --reg f09_90x288pt_1850PanTropics --inputdata-dir CSMDATA --cfg-file CTSM_ROOT/tools/mksurfdata_map/default_data_1850.cfg --verbose
diff --git a/test/tools/show_var_diffs.sh b/test/tools/show_var_diffs.sh
deleted file mode 100755
index f462d4ad0c..0000000000
--- a/test/tools/show_var_diffs.sh
+++ /dev/null
@@ -1,79 +0,0 @@
-#!/bin/bash
-
-# This script processes a log file that was output by test_driver,
-# giving lists of all variables with differences in values (those with
-# RMS errors), and all variables with differences in fill patterns.
-#
-# This assumes that the log file contains output like:
-# RMS foo
-# RMS bar
-# FILLDIFF foo
-# FILLDIFF bar
-# Some characteristics of these output lines are:
-# - they begin with a leading space, followed by RMS or FILLDIFF
-# - the variable name is in the second column of the line
-#
-# Note that (as of 4-5-12) the log file only contains output from the
-# last file that didn't match, so this could potentially miss
-# something -- especially if there are both h0 and h1 files in the
-# comparison.
-
-# Usage: show_var_diffs logfile
-
-# ----------------------------------------------------------------------
-# LOCAL FUNCTIONS DEFINED HERE
-# ----------------------------------------------------------------------
-
-# This function shows the differences for one prefix (e.g., "RMS")
-# Usage: show_diffs prefix
-# (also uses $logfile from the parent script)
-#
-# Matches lines that start with the regular expression "^ ${prefix}"
-# (note that one leading space is expected before the prefix)
-#
-# Assumes that the variable name is in the second column of matching lines
-function show_diffs {
- prefix=$1
-
- # first determine if there were warnings relating to this prefix
- grep "WARNING: Too many instances of ${prefix}" $logfile > /dev/null
- if [ $? -eq 0 ]; then # found a warning
- echo "WARNING: Some output was truncated; this may not be a complete list"
- fi
-
- # now make a list of all variables matching this prefix
- grep "^ ${prefix}" $logfile > $logfile.tmp.$$
- if [ $? -eq 0 ]; then
- awk '{print $2}' $logfile.tmp.$$ | sort | uniq
- else
- echo "(no differences)"
- fi
-
- rm $logfile.tmp.$$
-}
-
-# ----------------------------------------------------------------------
-# BEGIN MAIN SCRIPT
-# ----------------------------------------------------------------------
-
-# ----------------------------------------------------------------------
-# Handle command-line arguments
-# ----------------------------------------------------------------------
-
-if [[ $# -ne 1 ]]; then
- echo "Usage: show_var_diffs logfile"
- exit 1
-fi
-
-logfile=$1
-
-# ----------------------------------------------------------------------
-# Do the processing
-# ----------------------------------------------------------------------
-
-echo "Variables with differences in values:"
-show_diffs "RMS"
-
-echo ""
-echo "Variables with differences in fill patterns:"
-show_diffs "FILLDIFF"
\ No newline at end of file
diff --git a/test/tools/test_driver.sh b/test/tools/test_driver.sh
deleted file mode 100755
index f93301a530..0000000000
--- a/test/tools/test_driver.sh
+++ /dev/null
@@ -1,722 +0,0 @@
-#!/bin/sh
-#
-# test_driver.sh: driver script for the offline testing of CLM of tools
-#
-# interactive usage on all machines:
-#
-# env ./test_driver.sh -i
-#
-# valid arguments:
-# -i interactive usage
-# -d debug usage -- display tests that will run -- but do NOT actually execute them
-# -f force batch submission (avoids user prompt)
-# -h displays this help message
-#
-#
-# **pass environment variables by preceding above commands
-# with 'env var1=setting var2=setting '
-# **more details in the CLM testing user's guide, accessible
-# from the CLM developers web page
-
-
-#will attach timestamp onto end of script name to prevent overwriting
-cur_time=`date '+%H:%M:%S'`
-
-hostname=`hostname`
-echo $hostname
-case $hostname in
-
- ##Derecho
- derecho* | dec*)
- submit_script="test_driver_derecho${cur_time}.sh"
-
-##vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv writing to batch script vvvvvvvvvvvvvvvvvvv
-cat > ./${submit_script} << EOF
-#!/bin/sh
-#
-
-interactive="YES"
-input_file="tests_pretag_derecho_nompi"
-c_threads=128
-
-export INITMODULES="/glade/u/apps/derecho/23.06/spack/opt/spack/lmod/8.7.20/gcc/7.5.0/pdxb/lmod/lmod/init/sh"
-. \$INITMODULES
-
-module --force purge
-module load ncarenv
-module load craype
-module load intel
-module load mkl
-module load ncarcompilers
-module load netcdf
-module load nco
-module load ncl
-
-#omp threads
-if [ -z "\$CLM_THREADS" ]; then #threads NOT set on command line
- export CLM_THREADS=\$c_threads
-fi
-
-# Stop on first failed test
-if [ -z "\$CLM_SOFF" ]; then #CLM_SOFF NOT set
- export CLM_SOFF=FALSE
-fi
-
-export CESM_MACH="derecho"
-export CESM_COMP="intel"
-
-export NETCDF_DIR=\$NETCDF
-export INC_NETCDF=\$NETCDF/include
-export LIB_NETCDF=\$NETCDF/lib
-export MAKE_CMD="gmake -j "
-export CFG_STRING=""
-export TOOLS_MAKE_STRING="USER_FC=ifort USER_LINKER=ifort USER_CPPDEFS=-DLINUX"
-export MACH_WORKSPACE=\$SCRATCH
-export CPRNC_EXE="$CESMDATAROOT/cprnc/cprnc"
-dataroot="$CESMDATAROOT/inputdata"
-export TOOLSLIBS=""
-export REGRID_PROC=1
-export TOOLS_CONF_STRING="--mpilib mpi-serial"
-
-
-echo_arg=""
-
-EOF
-#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ writing to batch script ^^^^^^^^^^^^^^^^^^^
- ;;
-
- ##cheyenne
- cheyenne* | r*i*n*)
- submit_script="test_driver_cheyenne${cur_time}.sh"
-
-#vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv writing to batch script vvvvvvvvvvvvvvvvvvv
-at > ./${submit_script} << EOF
-!/bin/sh
-
-
-interactive="YES"
-input_file="tests_pretag_cheyenne_nompi"
-c_threads=36
-
-
-export INITMODULES="/glade/u/apps/ch/opt/lmod/8.1.7/lmod/lmod/init/sh"
-. \$INITMODULES
-
-module purge
-module load ncarenv
-module load intel
-module load mkl
-module load ncarcompilers
-module load netcdf
-
-module load nco
-module load ncl
-
-module load conda
-
-
-##omp threads
-if [ -z "\$CLM_THREADS" ]; then #threads NOT set on command line
- export CLM_THREADS=\$c_threads
-fi
-
-# Stop on first failed test
-if [ -z "\$CLM_SOFF" ]; then #CLM_SOFF NOT set
- export CLM_SOFF=FALSE
-fi
-
-export CESM_MACH="cheyenne"
-export CESM_COMP="intel"
-
-export NETCDF_DIR=\$NETCDF
-export INC_NETCDF=\$NETCDF/include
-export LIB_NETCDF=\$NETCDF/lib
-export MAKE_CMD="gmake -j "
-export CFG_STRING=""
-export TOOLS_MAKE_STRING="USER_FC=ifort USER_LINKER=ifort USER_CPPDEFS=-DLINUX"
-export MACH_WORKSPACE="/glade/scratch"
-export CPRNC_EXE="$CESMDATAROOT/tools/cime/tools/cprnc/cprnc.cheyenne"
-dataroot="$CESMDATAROOT"
-export TOOLSLIBS=""
-export REGRID_PROC=1
-export TOOLS_CONF_STRING="--mpilib mpi-serial"
-
-
-echo_arg=""
-
-EOF
-##^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ writing to batch script ^^^^^^^^^^^^^^^^^^^
- ;;
-
- ## DAV cluster
- casper* | pronghorn*)
- submit_script="test_driver_dav${cur_time}.sh"
-
-##vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv writing to batch script vvvvvvvvvvvvvvvvvvv
-cat > ./${submit_script} << EOF
-#!/bin/sh
-#
-
-interactive="YES"
-input_file="tests_posttag_dav_mpi"
-c_threads=36
-
-
-export INITMODULES="/glade/u/apps/ch/opt/lmod/8.1.7/lmod/lmod/init/sh"
-. \$INITMODULES
-
-module purge
-module load ncarenv
-module load intel
-module load mkl
-module load ncarcompilers
-module load netcdf
-module load openmpi
-
-module load nco
-module load conda
-module load ncl
-
-
-##omp threads
-if [ -z "\$CLM_THREADS" ]; then #threads NOT set on command line
- export CLM_THREADS=\$c_threads
-fi
-
-# Stop on first failed test
-if [ -z "\$CLM_SOFF" ]; then #CLM_SOFF NOT set
- export CLM_SOFF=FALSE
-fi
-
-export CESM_MACH="cheyenne"
-export CESM_COMP="intel"
-
-export NETCDF_DIR=\$NETCDF
-export INC_NETCDF=\$NETCDF/include
-export LIB_NETCDF=\$NETCDF/lib
-export MAKE_CMD="gmake -j "
-export CFG_STRING=""
-export TOOLS_MAKE_STRING="USER_FC=ifort USER_LINKER=ifort USER_CPPDEFS=-DLINUX"
-export MACH_WORKSPACE="/glade/scratch"
-export CPRNC_EXE="$CESMDATAROOT/tools/cime/tools/cprnc/cprnc.cheyenne"
-dataroot="$CESMDATAROOT"
-export TOOLSLIBS=""
-export TOOLS_CONF_STRING="--mpilib mpich"
-
-
-echo_arg=""
-
-EOF
-##^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ writing to batch script ^^^^^^^^^^^^^^^^^^^
- ;;
-
- ## hobart
- hobart* | h*.cgd.ucar.edu)
- submit_script="test_driver_hobart_${cur_time}.sh"
- export PATH=/cluster/torque/bin:${PATH}
-
-##vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv writing to batch script vvvvvvvvvvvvvvvvvvv
-cat > ./${submit_script} << EOF
-#!/bin/sh
-#
-
-# Name of the queue (CHANGE THIS if needed)
-#PBS -q long
-# Number of nodes (CHANGE THIS if needed)
-#PBS -l nodes=1:ppn=24
-# output file base name
-#PBS -N test_dr
-# Put standard error and standard out in same file
-#PBS -j oe
-# Export all Environment variables
-#PBS -V
-# End of options
-
-if [ -n "\$PBS_JOBID" ]; then #batch job
- export JOBID=\`echo \${PBS_JOBID} | cut -f1 -d'.'\`
- initdir=\${PBS_O_WORKDIR}
-fi
-
-if [ "\$PBS_ENVIRONMENT" = "PBS_BATCH" ]; then
- interactive="NO"
- input_file="tests_posttag_hobart"
-else
- interactive="YES"
- input_file="tests_posttag_hobart_nompi"
-fi
-
-##omp threads
-if [ -z "\$CLM_THREADS" ]; then #threads NOT set on command line
- export CLM_THREADS=2
-fi
-export CLM_RESTART_THREADS=1
-
-##mpi tasks
-export CLM_TASKS=24
-export CLM_RESTART_TASKS=20
-
-export P4_GLOBMEMSIZE=500000000
-
-
-export CESM_MACH="hobart"
-
-ulimit -s unlimited
-ulimit -c unlimited
-
-export CESM_COMP="intel"
-export TOOLS_MAKE_STRING="USER_FC=ifort USER_CC=icc "
-export TOOLS_CONF_STRING=" -mpilib mpi-serial"
-export CFG_STRING=""
-export INITMODULES="/usr/share/Modules/init/sh"
-
-. \$INITMODULES
-module purge
-module load compiler/intel
-module load tool/nco
-module load tool/netcdf
-module load lang/python
-
-export NETCDF_DIR=\$NETCDF_PATH
-export INC_NETCDF=\${NETCDF_PATH}/include
-export LIB_NETCDF=\${NETCDF_PATH}/lib
-export MAKE_CMD="gmake -j 5" ##using hyper-threading on hobart
-export MACH_WORKSPACE="/scratch/cluster"
-export CPRNC_EXE=/fs/cgd/csm/tools/cprnc/cprnc
-export DATM_QIAN_DATA_DIR="/project/tss/atm_forcing.datm7.Qian.T62.c080727"
-dataroot="/fs/cgd/csm"
-export TOOLSSLIBS=""
-echo_arg="-e"
-
-EOF
-##^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ writing to batch script ^^^^^^^^^^^^^^^^^^^
- ;;
-
- ## izumi
- izumi* | i*.unified.ucar.edu)
- submit_script="test_driver_izumi_${cur_time}.sh"
- export PATH=/cluster/torque/bin:${PATH}
-
-##vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv writing to batch script vvvvvvvvvvvvvvvvvvv
-cat > ./${submit_script} << EOF
-#!/bin/sh
-#
-
-# Name of the queue (CHANGE THIS if needed)
-#PBS -q long
-# Number of nodes (CHANGE THIS if needed)
-#PBS -l nodes=1:ppn=24
-# output file base name
-#PBS -N test_dr
-# Put standard error and standard out in same file
-#PBS -j oe
-# Export all Environment variables
-#PBS -V
-# End of options
-
-if [ -n "\$PBS_JOBID" ]; then #batch job
- export JOBID=\`echo \${PBS_JOBID} | cut -f1 -d'.'\`
- initdir=\${PBS_O_WORKDIR}
-fi
-
-if [ "\$PBS_ENVIRONMENT" = "PBS_BATCH" ]; then
- interactive="NO"
- input_file="tests_posttag_izumi"
-else
- interactive="YES"
- input_file="tests_posttag_izumi_nompi"
-fi
-
-##omp threads
-if [ -z "\$CLM_THREADS" ]; then #threads NOT set on command line
- export CLM_THREADS=2
-fi
-export CLM_RESTART_THREADS=1
-
-##mpi tasks
-export CLM_TASKS=24
-export CLM_RESTART_TASKS=20
-
-export P4_GLOBMEMSIZE=500000000
-
-
-export CESM_MACH="izumi"
-
-ulimit -s unlimited
-ulimit -c unlimited
-
-export CESM_COMP="intel"
-export TOOLS_MAKE_STRING="USER_FC=ifort USER_CC=icc "
-export TOOLS_CONF_STRING=" -mpilib mpi-serial"
-export CFG_STRING=""
-export INITMODULES="/usr/share/Modules/init/sh"
-
-. \$INITMODULES
-module purge
-module load compiler/intel
-module load tool/nco
-module load tool/netcdf
-module load lang/python
-
-export NETCDF_DIR=\$NETCDF_PATH
-export INC_NETCDF=\${NETCDF_PATH}/include
-export LIB_NETCDF=\${NETCDF_PATH}/lib
-export MAKE_CMD="gmake -j 5" ##using hyper-threading on izumi
-export MACH_WORKSPACE="/scratch/cluster"
-export CPRNC_EXE=/fs/cgd/csm/tools/cprnc/cprnc.izumi
-export DATM_QIAN_DATA_DIR="/project/tss/atm_forcing.datm7.Qian.T62.c080727"
-dataroot="/fs/cgd/csm"
-export TOOLSSLIBS=""
-echo_arg="-e"
-
-EOF
-##^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ writing to batch script ^^^^^^^^^^^^^^^^^^^
- ;;
-
- * )
- echo "Only setup to work on: derecho, cheyenne, hobart and izumi"
- exit
-
-
-esac
-
-##vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv writing to batch script vvvvvvvvvvvvvvvvvvv
-cat >> ./${submit_script} << EOF
-
-export CPRNC_OPT=""
-if [ -n "\${CLM_JOBID}" ]; then
- export JOBID=\${CLM_JOBID}
-fi
-##check if interactive job
-
-if [ "\$interactive" = "YES" ]; then
-
- if [ -z "\${JOBID}" ]; then
- export JOBID=\$\$
- fi
- echo "test_driver.sh: interactive run - setting JOBID to \$JOBID"
- if [ \$0 = "test_driver.sh" ]; then
- initdir="."
- else
- initdir=\${0%/*}
- fi
-else
- echo "ERROR: you *always* need to use the interactive option (-i)"
- echo " currently doesn't work without it"
- exit 3
-fi
-
-##establish script dir and clm_root
-if [ -f \${initdir}/test_driver.sh ]; then
- export CLM_SCRIPTDIR=\`cd \${initdir}; pwd \`
- export CLM_ROOT=\`cd \${CLM_SCRIPTDIR}/../..; pwd \`
- export CTSM_ROOT=\${CLM_ROOT}
- if [ -d \${CLM_ROOT}/cime ]; then
- export CIME_ROOT=\${CLM_ROOT}/cime
- else
- export CIME_ROOT=\${CLM_ROOT}/../../cime
- fi
- if [ ! -d \${CIME_ROOT} ]; then
- echo "ERROR: trouble finding the CIME_ROOT directory: \$CIME_ROOT"
- exit 3
- fi
-else
- if [ -n "\${CLM_ROOT}" ] && [ -f \${CLM_ROOT}/test/tools/test_driver.sh ]; then
- export CLM_SCRIPTDIR=\`cd \${CLM_ROOT}/test/tools; pwd \`
- else
- echo "ERROR: unable to determine script directory "
- echo " if initiating batch job from directory other than the one containing test_driver.sh, "
- echo " you must set the environment variable CLM_ROOT to the full path of directory containing "
- echo " . "
- exit 3
- fi
-fi
-
-# Setup conda environment
-conda activate ctsm_pylib
-if [ \$? -ne 0 ]; then
- echo "ERROR: Trouble activating the ctsm_pylib conda environment, be sure it's setup with \$CLM_ROOT/py_env_create, then rerun"
- exit 4
-fi
-
-##output files
-clm_log=\${initdir}/td.\${JOBID}.log
-if [ -f \$clm_log ]; then
- rm \$clm_log
-fi
-clm_status=\${initdir}/td.\${JOBID}.status
-if [ -f \$clm_status ]; then
- rm \$clm_status
-fi
-
-##setup test work directory
-if [ -z "\$CLM_TESTDIR" ]; then
- export CLM_TESTDIR=\${MACH_WORKSPACE}/\$LOGNAME/clmTests/test-driver.\${JOBID}
- if [ -d \$CLM_TESTDIR ] && [ \$CLM_RETAIN_FILES != "TRUE" ]; then
- rm -r \$CLM_TESTDIR
- fi
-fi
-if [ ! -d \$CLM_TESTDIR ]; then
- mkdir -p \$CLM_TESTDIR
- if [ \$? -ne 0 ]; then
- echo "ERROR: unable to create work directory \$CLM_TESTDIR"
- exit 4
- fi
-fi
-
-## MCT and PIO build directorys
-export MCT_LIBDIR=\$CLM_TESTDIR/mct
-export PIO_LIBDIR=\$CLM_TESTDIR/pio
-
-##set our own environment vars
-export CSMDATA=\${dataroot}/inputdata
-export DIN_LOC_ROOT=\${CSMDATA}
-export MPI_TYPE_MAX=100000
-
-##process other env vars possibly coming in
-if [ -z "\$CLM_RETAIN_FILES" ]; then
- export CLM_RETAIN_FILES=FALSE
-fi
-if [ -n "\${CLM_INPUT_TESTS}" ]; then
- input_file=\$CLM_INPUT_TESTS
-else
- input_file=\${CLM_SCRIPTDIR}/\${input_file}
-fi
-if [ ! -f \${input_file} ]; then
- echo "ERROR: unable to locate input file \${input_file}"
- exit 5
-fi
-
-if [ \$interactive = "YES" ]; then
- echo "reading tests from \${input_file}"
-else
- echo "reading tests from \${input_file}" >> \${clm_log}
-fi
-
-num_tests=\`wc -w < \${input_file}\`
-echo "STATUS OF CLM TESTING UNDER JOB \${JOBID}; scheduled to run \$num_tests tests from:" >> \${clm_status}
-echo "\$input_file" >> \${clm_status}
-echo "" >> \${clm_status}
-echo " on machine: $hostname" >> \${clm_status}
-if [ -n "${BL_ROOT}" ]; then
- echo "tests of baseline will use source code from:" >> \${clm_status}
- echo "\$BL_ROOT" >> \${clm_status}
-fi
-if [ \$interactive = "NO" ]; then
- echo "see \${clm_log} for more detailed output" >> \${clm_status}
-fi
-echo "" >> \${clm_status}
-
-test_list=""
-while read input_line; do
- test_list="\${test_list}\${input_line} "
-done < \${input_file}
-
-
-##initialize flags, counter
-skipped_tests="NO"
-pending_tests="NO"
-count=0
-
-##loop through the tests of input file
-for test_id in \${test_list}; do
- count=\`expr \$count + 1\`
- while [ \${#count} -lt 3 ]; do
- count="0\${count}"
- done
-
- master_line=\`grep \$test_id \${CLM_SCRIPTDIR}/input_tests_master\`
- status_out=""
- for arg in \${master_line}; do
- status_out="\${status_out}\${arg} "
- done
-
- if [ -z "\$status_out" ]; then
- echo "No test matches \$test_id in \${CLM_SCRIPTDIR}/input_tests_master"
- exit 3
- fi
-
- test_cmd=\${status_out#* }
-
- status_out="\${count} \${status_out}"
-
- if [ \$interactive = "YES" ]; then
- echo ""
- echo "***********************************************************************************"
- echo "\${status_out}"
- echo "***********************************************************************************"
- else
- echo "" >> \${clm_log}
- echo "***********************************************************************************"\
- >> \${clm_log}
- echo "\$status_out" >> \${clm_log}
- echo "***********************************************************************************"\
- >> \${clm_log}
- fi
-
- if [ \${#status_out} -gt 94 ]; then
- status_out=\`echo "\${status_out}" | cut -c1-100\`
- fi
- while [ \${#status_out} -lt 97 ]; do
- status_out="\${status_out}."
- done
-
- echo \$echo_arg "\$status_out\c" >> \${clm_status}
-
- if [ \$interactive = "YES" ]; then
- \${CLM_SCRIPTDIR}/\${test_cmd}
- rc=\$?
- else
- \${CLM_SCRIPTDIR}/\${test_cmd} >> \${clm_log} 2>&1
- rc=\$?
- fi
- if [ \$rc -eq 0 ]; then
- echo "PASS" >> \${clm_status}
- elif [ \$rc -eq 255 ]; then
- echo "SKIPPED*" >> \${clm_status}
- skipped_tests="YES"
- elif [ \$rc -eq 254 ]; then
- echo "PENDING**" >> \${clm_status}
- pending_tests="YES"
- else
- echo " rc=\$rc FAIL" >> \${clm_status}
- if [ "\$CLM_SOFF" = "TRUE" ]; then
- echo "stopping on first failure" >> \${clm_status}
- echo "stopping on first failure" >> \${clm_log}
- exit 6
- fi
- fi
-done
-
-echo "end of input" >> \${clm_status}
-if [ \$interactive = "YES" ]; then
- echo "end of input"
-else
- echo "end of input" >> \${clm_log}
-fi
-
-if [ \$skipped_tests = "YES" ]; then
- echo "* please verify that any skipped tests are not required of your clm commit" >> \${clm_status}
-fi
-if [ \$pending_tests = "YES" ]; then
- echo "** tests that are pending must be checked manually for a successful completion" >> \${clm_status}
- if [ \$interactive = "NO" ]; then
- echo " see the test's output in \${clm_log} " >> \${clm_status}
- echo " for the location of test results" >> \${clm_status}
- fi
-fi
-
-if [ "\$interactive" = "YES" ]; then
- passInt="test_driver.sh-i"
-else
- passInt="test_driver.sh"
-fi
-
-../../bld/unit_testers/xFail/wrapClmTests.pl -statusFile "\${clm_status}" -numberOfTests "\${num_tests}" -callingScript "\${passInt}"
-
-exit 0
-
-EOF
-##^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ writing to batch script ^^^^^^^^^^^^^^^^^^^
-
-
-chmod a+x $submit_script
-if [ ! -z "$CLM_RETAIN_FILES" ]; then
- export CLM_RETAIN_FILES="FALSE"
-fi
-arg1=${1##*-}
-case $arg1 in
- [iI]* )
- debug="NO"
- interactive="YES"
- compile_only="NO"
- export debug
- export interactive
- export compile_only
- ./${submit_script}
- exit 0
- ;;
-
- [cC]* )
- debug="NO"
- interactive="YES"
- compile_only="YES"
- export debug
- export CLM_RETAIN_FILES="TRUE"
- export interactive
- export compile_only
- export CLM_RETAIN_FILES="TRUE"
- ./${submit_script}
- exit 0
- ;;
-
- [dD]* )
- debug="YES"
- interactive="YES"
- compile_only="NO"
- export debug
- export interactive
- export compile_only
- ./${submit_script}
- exit 0
- ;;
-
- [fF]* )
- debug="NO"
- interactive="NO"
- compile_only="NO"
- export debug
- export interactive
- export compile_only
- ;;
-
- "" )
- echo ""
- echo "**********************"
- echo "$submit_script has been created and will be submitted to the batch queue..."
- echo "(ret) to continue, (a) to abort"
- read ans
- case $ans in
- [aA]* )
- echo "aborting...type ./test_driver.sh -h for help message"
- exit 0
- ;;
- esac
- debug="NO"
- interactive="NO"
- compile_only="NO"
- export debug
- export interactive
- export compile_only
- ;;
-
- * )
- echo ""
- echo "**********************"
- echo "usage on derecho, cheyenne, hobart, and izumi: "
- echo "./test_driver.sh -i"
- echo ""
- echo "valid arguments: "
- echo "-i interactive usage"
- echo "-c compile-only usage (run configure and compile do not run clm)"
- echo "-d debug-only usage (run configure and build-namelist do NOT compile or run clm)"
- echo "-f force batch submission (avoids user prompt)"
- echo "-h displays this help message"
- echo ""
- echo "**pass environment variables by preceding above commands "
- echo " with 'env var1=setting var2=setting '"
- echo ""
- echo "**********************"
- exit 0
- ;;
-esac
-
-echo "submitting..."
-case $hostname in
- #default
- * )
- echo "no submission capability on this machine use the interactive option: -i"
- exit 0
- ;;
-
-esac
-exit 0
diff --git a/test/tools/tests_posttag_hobart_nompi b/test/tools/tests_posttag_hobart_nompi
deleted file mode 100644
index c185428868..0000000000
--- a/test/tools/tests_posttag_hobart_nompi
+++ /dev/null
@@ -1 +0,0 @@
-smc#4 blc#4
diff --git a/test/tools/tests_posttag_nompi_regression b/test/tools/tests_posttag_nompi_regression
deleted file mode 100644
index c185428868..0000000000
--- a/test/tools/tests_posttag_nompi_regression
+++ /dev/null
@@ -1 +0,0 @@
-smc#4 blc#4
diff --git a/test/tools/tests_pretag_cheyenne_nompi b/test/tools/tests_pretag_cheyenne_nompi
deleted file mode 100644
index e92ffaaaad..0000000000
--- a/test/tools/tests_pretag_cheyenne_nompi
+++ /dev/null
@@ -1,3 +0,0 @@
-smc#4 blc#4
-smba1 blba1
-smbd1 blbd1
diff --git a/test/tools/tests_pretag_derecho_nompi b/test/tools/tests_pretag_derecho_nompi
deleted file mode 100644
index 5fdaf335ae..0000000000
--- a/test/tools/tests_pretag_derecho_nompi
+++ /dev/null
@@ -1,9 +0,0 @@
-smba1 blba1
-smbd1 blbd1
-sm0a1 bl0a1
-sm0c1 bl0c1
-smaa2 blaa2
-smba1 blba1
-smb81 blb81
-smbc1 blbc1
-smbd1 blbd1
diff --git a/test/tools/tests_pretag_nompi_neon b/test/tools/tests_pretag_nompi_neon
deleted file mode 100644
index e5fa27e6c4..0000000000
--- a/test/tools/tests_pretag_nompi_neon
+++ /dev/null
@@ -1,8 +0,0 @@
-sm0a1 bl0a1
-sm0c1 bl0c1
-smaa2 blaa2
-smba1 blba1
-smbb1 blbb1
-smb81 blb81
-smbc1 blbc1
-smbd1 blbd1
diff --git a/tools/mksurfdata_esmf/Makefile b/tools/mksurfdata_esmf/Makefile
index fc81d48079..d8bacdc5dd 100644
--- a/tools/mksurfdata_esmf/Makefile
+++ b/tools/mksurfdata_esmf/Makefile
@@ -275,6 +275,7 @@ crop-global-SSP2-4.5 : crop-global-SSP2-4.5-f09 \
crop-global-SSP2-4.5-hcru \
crop-global-SSP2-4.5-ne16 \
crop-global-SSP2-4.5-ne30 \
+ crop-global-SSP2-4.5-ne0np4 \
crop-global-SSP2-4.5-C96 \
crop-global-SSP2-4.5-mpasa120
@@ -318,6 +319,10 @@ crop-global-SSP2-4.5-ne30 : FORCE
$(MKSURFDATA) --number-of-nodes 9 --scenario $@ --jobscript-file $@.sh --walltime 12:00:00
$(BATCHJOBS) $@.sh
+crop-global-SSP2-4.5-ne0np4 : FORCE
+ $(MKSURFDATA) --number-of-nodes 2 --scenario $@ --jobscript-file $@.sh --walltime 12:00:00
+ $(BATCHJOBS) $@.sh
+
crop-global-SSP2-4.5-C96 : FORCE
$(MKSURFDATA) --number-of-nodes 9 --scenario $@ --jobscript-file $@.sh --walltime 12:00:00
$(BATCHJOBS) $@.sh
diff --git a/tools/mksurfdata_esmf/README.md b/tools/mksurfdata_esmf/README.md
index 11cb69c681..3d19c88ff0 100644
--- a/tools/mksurfdata_esmf/README.md
+++ b/tools/mksurfdata_esmf/README.md
@@ -93,7 +93,7 @@ https://github.com/ESCOMP/CTSM/issues/2341
``` shell
# Assuming pwd is the tools/mksurfdata_esmf directory
- ./manage_externals/checkout_externals # Assuming at the top level of the CTSM/CESM checkout
+ ./bin/git-fleximod update # Assuming at the top level of the CTSM/CESM checkout
```
This will bring in CIME and ccs_config which are required for building.
diff --git a/tools/mksurfdata_esmf/gen_mksurfdata_build b/tools/mksurfdata_esmf/gen_mksurfdata_build
index 974c1929a5..864b5915b9 100755
--- a/tools/mksurfdata_esmf/gen_mksurfdata_build
+++ b/tools/mksurfdata_esmf/gen_mksurfdata_build
@@ -127,7 +127,16 @@ if [ "$existing_bld" = "No" ]; then
if [ "$verbose" != "YES" ]; then
options="$options --silent"
fi
- $cwd/../../cime/CIME/scripts/configure --macros-format CMake --machine $MACH $options
+ # Try finding configure file assuming a CTSM standalone checkout and then try for a CESM checkout
+ configure="$cwd/../../cime/CIME/scripts/configure"
+ if [ ! -f "$configure" ]; then
+ configure="$cwd/../../../../cime/CIME/scripts/configure"
+ if [ ! -f "$configure" ]; then
+ echo "Error $configure file does NOT exist in expected location, either for a standalone checkout or CESM/CAM checkout"
+ exit 1
+ fi
+ fi
+ $configure --macros-format CMake --machine $MACH $options
if [ $? != 0 ]; then
echo "Error doing configure for machine name: $MACH"