diff --git a/.cicd/Jenkinsfile b/.cicd/Jenkinsfile new file mode 100644 index 0000000000..1b3535b644 --- /dev/null +++ b/.cicd/Jenkinsfile @@ -0,0 +1,221 @@ +matchedNode = [] +generateBaselineNode = [] +for (label in pullRequest.labels) { + listOfLabelNodeNames = jenkins.model.Jenkins.instance.nodes.collect { + node -> node.getLabelString().contains(label) ? node.name : null + + if ((label.matches(node.getLabelString()+"-(.*)"))) { + matchedNode += node.getLabelString() + } + + if ((label.matches(node.getLabelString()+"(.*)-BL"))) { + generateBaselineNode += node.getLabelString() + } + } +} + +modifiedLabels = matchedNode.collect{"'" + it + "'"} +baselineLabels = generateBaselineNode.collect{"'" + it + "'"} +def generateStage(nodeLabel) { + return { + stage("Initialize on ${nodeLabel.replaceAll("'","")}") { + node(nodeLabel) { + script { + currentBuild.displayName = "#${BUILD_NUMBER} ${nodeLabel.replaceAll("'","")} test=${params.WM_OPERATIONAL_TESTS}" + } + cleanWs() + checkout scm + script { + def UFS_PLATFORM = nodeLabel.replaceAll("'","") + echo "nodeLabel=${nodeLabel} NODE_NAME=${NODE_NAME} UFS_PLATFORM=${UFS_PLATFORM} UFS_COMPILER=${env.UFS_COMPILER}" + sh 'bash --login "${WORKSPACE}/.cicd/scripts/wm_init.sh"' + sh "STAGE_NAME='${env.STAGE_NAME}' " + 'bash --login "${WORKSPACE}/.cicd/scripts/disk_usage.sh"' + s3Upload consoleLogLevel: 'INFO', dontSetBuildResultOnFailure: false, dontWaitForConcurrentBuildCompletion: false, entries: [[bucket: 'noaa-epic-prod-jenkins-artifacts', excludedFile: '', flatten: false, gzipFiles: false, keepForever: false, managedArtifacts: true, noUploadOnFailure: false, selectedRegion: 'us-east-1', showDirectlyInBrowser: false, sourceFile: "${UFS_PLATFORM}-*-time-wm_init.json", storageClass: 'STANDARD', uploadFromSlave: false, useServerSideEncryption: false]], pluginFailureResultConstraint: 'FAILURE', profileName: 'main', userMetadata: [] + s3Upload consoleLogLevel: 'INFO', dontSetBuildResultOnFailure: false, dontWaitForConcurrentBuildCompletion: false, entries: [[bucket: 'noaa-epic-prod-jenkins-artifacts', excludedFile: '', flatten: false, gzipFiles: false, keepForever: false, managedArtifacts: true, noUploadOnFailure: false, selectedRegion: 'us-east-1', showDirectlyInBrowser: false, sourceFile: "${UFS_PLATFORM}-*-disk-usageInit*.csv", storageClass: 'STANDARD', uploadFromSlave: false, useServerSideEncryption: false]], pluginFailureResultConstraint: 'FAILURE', profileName: 'main', userMetadata: [] + } + } + } + stage("Build on ${nodeLabel.replaceAll("'","")}") { + if (params.WM_BUILD == true ) { + node(nodeLabel) { + script { + def UFS_PLATFORM = nodeLabel.replaceAll("'","") + //currentBuild.displayName = "#${BUILD_NUMBER} ${nodeLabel.replaceAll("'","")} ${UFS_COMPILER}" + currentBuild.description = "build ${UFS_PLATFORM}-${UFS_COMPILER}" + + echo "Building on ${nodeLabel}" + sh 'bash --login "${WORKSPACE}/.cicd/scripts/wm_build.sh"' + sh "STAGE_NAME='${env.STAGE_NAME}' " + 'bash --login "${WORKSPACE}/.cicd/scripts/disk_usage.sh"' + s3Upload consoleLogLevel: 'INFO', dontSetBuildResultOnFailure: false, dontWaitForConcurrentBuildCompletion: false, entries: [[bucket: 'noaa-epic-prod-jenkins-artifacts', excludedFile: '', flatten: false, gzipFiles: false, keepForever: false, managedArtifacts: true, noUploadOnFailure: false, selectedRegion: 'us-east-1', showDirectlyInBrowser: false, sourceFile: "${UFS_PLATFORM}-*-time-wm_build.json", storageClass: 'STANDARD', uploadFromSlave: false, useServerSideEncryption: false]], pluginFailureResultConstraint: 'FAILURE', profileName: 'main', userMetadata: [] + s3Upload consoleLogLevel: 'INFO', dontSetBuildResultOnFailure: false, dontWaitForConcurrentBuildCompletion: false, entries: [[bucket: 'noaa-epic-prod-jenkins-artifacts', excludedFile: '', flatten: false, gzipFiles: false, keepForever: false, managedArtifacts: true, noUploadOnFailure: false, selectedRegion: 'us-east-1', showDirectlyInBrowser: false, sourceFile: "${UFS_PLATFORM}-*-disk-usageBuild.csv", storageClass: 'STANDARD', uploadFromSlave: false, useServerSideEncryption: false]], pluginFailureResultConstraint: 'FAILURE', profileName: 'main', userMetadata: [] + } + } + } else { + echo "Building on ${nodeLabel} skipped" + } + } + stage("Test on ${nodeLabel.replaceAll("'","")}") { + if (params.WM_OPERATIONAL_TESTS != 'none' ) { + node(nodeLabel) { + script { + def UFS_PLATFORM = nodeLabel.replaceAll("'","") + try { + echo "Running Tests on ${nodeLabel}" + if (baselineLabels.contains(nodeLabel)) { + sh "WM_CREATE_BASELINE=true " + 'bash --login "${WORKSPACE}/.cicd/scripts/wm_test.sh"' + } + else { + sh "WM_CREATE_BASELINE=false " + 'bash --login "${WORKSPACE}/.cicd/scripts/wm_test.sh"' + } + s3Upload consoleLogLevel: 'INFO', dontSetBuildResultOnFailure: false, dontWaitForConcurrentBuildCompletion: false, entries: [[bucket: 'noaa-epic-prod-jenkins-artifacts', excludedFile: '', flatten: false, gzipFiles: false, keepForever: false, managedArtifacts: true, noUploadOnFailure: false, selectedRegion: 'us-east-1', showDirectlyInBrowser: false, sourceFile: "wm_test_results-*-*.txt", storageClass: 'STANDARD', uploadFromSlave: false, useServerSideEncryption: false]], pluginFailureResultConstraint: 'FAILURE', profileName: 'main', userMetadata: [] + } + catch(err) { + sh ''' + export machine=${NODE_NAME} + export CHANGE_ID=${CHANGE_ID} + GIT_OWNER=$(echo $GIT_URL | cut -d '/' -f4) + GIT_REPO_NAME=$(echo $GIT_URL | cut -d '/' -f5 | cut -d '.' -f1) + set +x + + echo "Testing concluded...removing labels for $machine from $GIT_URL" + echo "https://api.github.com/repos/${GIT_OWNER}/${GIT_REPO_NAME}/issues/${CHANGE_ID}/labels /{$machine-RT,$machine-BL}" + curl --silent -X DELETE -H "Accept: application/vnd.github.v3+json" -H "Authorization: Bearer ${GITHUB_TOKEN}" https://api.github.com/repos/${GIT_OWNER}/${GIT_REPO_NAME}/issues/${CHANGE_ID}/labels/{$machine-RT,$machine-BL} + ''' + currentBuild.result = 'FAILURE' + } + + sh ''' + export machine=${NODE_NAME} + export CHANGE_ID=${CHANGE_ID} + cd ${WORKSPACE}/tests + export machine_name_logs=$(echo $machine | awk '{ print tolower($1) }') + tar --create --gzip --verbose --dereference --file "${machine_name_logs}.tgz" ${WORKSPACE}/tests/logs/*.log + ''' + s3Upload consoleLogLevel: 'INFO', dontSetBuildResultOnFailure: false, dontWaitForConcurrentBuildCompletion: false, entries: [[bucket: 'noaa-epic-prod-jenkins-artifacts', excludedFile: '', flatten: true, gzipFiles: false, keepForever: false, managedArtifacts: true, noUploadOnFailure: false, selectedRegion: 'us-east-1', showDirectlyInBrowser: false, sourceFile: "**/*tgz*", storageClass: 'STANDARD', uploadFromSlave: false, useServerSideEncryption: false]], pluginFailureResultConstraint: 'FAILURE', profileName: 'main', userMetadata: [] + + sh "STAGE_NAME='${env.STAGE_NAME}' " + 'bash --login "${WORKSPACE}/.cicd/scripts/disk_usage.sh"' + s3Upload consoleLogLevel: 'INFO', dontSetBuildResultOnFailure: false, dontWaitForConcurrentBuildCompletion: false, entries: [[bucket: 'noaa-epic-prod-jenkins-artifacts', excludedFile: '', flatten: false, gzipFiles: false, keepForever: false, managedArtifacts: true, noUploadOnFailure: false, selectedRegion: 'us-east-1', showDirectlyInBrowser: false, sourceFile: "${UFS_PLATFORM}-*-time-wm_test.json", storageClass: 'STANDARD', uploadFromSlave: false, useServerSideEncryption: false]], pluginFailureResultConstraint: 'FAILURE', profileName: 'main', userMetadata: [] + s3Upload consoleLogLevel: 'INFO', dontSetBuildResultOnFailure: false, dontWaitForConcurrentBuildCompletion: false, entries: [[bucket: 'noaa-epic-prod-jenkins-artifacts', excludedFile: '', flatten: false, gzipFiles: false, keepForever: false, managedArtifacts: true, noUploadOnFailure: false, selectedRegion: 'us-east-1', showDirectlyInBrowser: false, sourceFile: "${UFS_PLATFORM}-*-disk-usageTest.csv", storageClass: 'STANDARD', uploadFromSlave: false, useServerSideEncryption: false]], pluginFailureResultConstraint: 'FAILURE', profileName: 'main', userMetadata: [] + + sh "[[ -d tests/logs ]] && cd tests/logs && tar --create --gzip --verbose --dereference --file ../../wm_test_logs-${UFS_PLATFORM}-${env.UFS_COMPILER}.tgz log_${UFS_PLATFORM}/* RegressionTests_${UFS_PLATFORM}.log || cat /dev/null > ../../wm_test_logs-${UFS_PLATFORM}-${env.UFS_COMPILER}.tgz" + s3Upload consoleLogLevel: 'INFO', dontSetBuildResultOnFailure: false, dontWaitForConcurrentBuildCompletion: false, entries: [[bucket: 'noaa-epic-prod-jenkins-artifacts', excludedFile: '', flatten: false, gzipFiles: false, keepForever: false, managedArtifacts: true, noUploadOnFailure: false, selectedRegion: 'us-east-1', showDirectlyInBrowser: false, sourceFile: "wm_test_logs-${UFS_PLATFORM}-${env.UFS_COMPILER}.tgz", storageClass: 'STANDARD', uploadFromSlave: false, useServerSideEncryption: false]], pluginFailureResultConstraint: 'FAILURE', profileName: 'main', userMetadata: [] + } + } + } else { + echo "Running Tests on ${nodeLabel} skipped" + } + } + stage("Post from ${nodeLabel.replaceAll("'","")}") { + if (params.WM_OPERATIONAL_TESTS != 'none' ) { + node(nodeLabel) { + script { + def UFS_PLATFORM = nodeLabel.replaceAll("'","") + try { + echo "Post Results from ${nodeLabel}" + if (baselineLabels.contains(nodeLabel)) { + //sh 'bash --login "${WORKSPACE}/.cicd/scripts/post_test_results.sh ${NODE_NAME} BL"' + sh "WM_TEST_LABEL=BL " + 'bash --login "${WORKSPACE}/.cicd/scripts/post_test_results.sh"' + } + else { + sh "WM_TEST_LABEL=RT " + 'bash --login "${WORKSPACE}/.cicd/scripts/post_test_results.sh"' + } + } + catch(err) { + echo "Error: Post Results from ${nodeLabel}" + } + sh ''' + export machine=${NODE_NAME} + export CHANGE_ID=${CHANGE_ID} + GIT_OWNER=$(echo $GIT_URL | cut -d '/' -f4) + GIT_REPO_NAME=$(echo $GIT_URL | cut -d '/' -f5 | cut -d '.' -f1) + set +x + + echo "Testing concluded...removing label ${label} for ${machine} from ${GIT_URL}" + echo "https://api.github.com/repos/${GIT_OWNER}/${GIT_REPO_NAME}/issues/${CHANGE_ID}/labels /${machine}-${label}" + curl --silent -X DELETE -H "Accept: application/vnd.github.v3+json" -H "Authorization: Bearer ${GITHUB_TOKEN}" https://api.github.com/repos/${GIT_OWNER}/${GIT_REPO_NAME}/issues/${CHANGE_ID}/labels/{$machine-RT,$machine-BL} + ''' + } + } + } + } + } +} + +def parallelStagesMap = modifiedLabels.collectEntries { + ["${it}" : generateStage(it)] +} + +pipeline { + agent none + parameters { + booleanParam name: 'WM_BUILD', defaultValue: false, description: 'Whether to attempt to compile the model code tests' + // Regression Test Suite ? + choice(name: 'WM_OPERATIONAL_TESTS', choices: ['default', 'control_p8', 'cpld_control_p8', 'comprehensive', 'rt.sh', 'none'], description: 'Specify the suite of tests to run') + } + environment { + ACCNR = 'epic' + AWS_PROD_ACCOUNT_ID = credentials('AWS_PROD_ACCOUNT_ID') + AWS_PROD_SNS_TOPIC = credentials('AWS_PROD_SNS_TOPIC') + GITHUB_TOKEN = credentials('GithubJenkinsNew') + GIT_URL = 'https://github.com/ufs-community/ufs-weather-model.git' + UFS_COMPILER = 'intel' + } + stages { + stage('Launch SonarQube') { + steps { + script { + echo "BRANCH_NAME=${env.CHANGE_BRANCH}" + echo "FORK_NAME=${env.CHANGE_FORK}" + echo "CHANGE_URL=${env.CHANGE_URL}" + echo "CHANGE_ID=${env.CHANGE_ID}" + build job: '/ufs-weather-model/ufs-wm-sonarqube', parameters: [ + string(name: 'BRANCH_NAME', value: env.CHANGE_BRANCH ?: 'develop'), + string(name: 'FORK_NAME', value: env.CHANGE_FORK ?: ''), + string(name: 'CHANGE_URL', value: env.CHANGE_URL ?: ''), + string(name: 'CHANGE_ID', value: env.CHANGE_ID ?: '') + ], wait: false + } + } + } + stage('Run Regression Tests in Parallel') { + steps { + script { + parallel parallelStagesMap + } + } + } + } + post { + success { + node('built-in') { + echo 'This will run only if successful.' + sh ''' + aws sns publish --topic-arn "arn:aws:sns:us-east-1:${AWS_PROD_ACCOUNT_ID}:${AWS_PROD_SNS_TOPIC}" --region us-east-1 --message '{"version":"1.0","source":"custom","content":{"description":":sunny: Jenkins build *'"$JOB_NAME"' '"$BUILD_NUMBER"'* with *PR-'"$CHANGE_ID"'* *succeeded*"}}' + ''' + } + } + failure { + node('built-in') { + echo 'This will run only if the run was marked as unstable.' + sh ''' + aws sns publish --topic-arn "arn:aws:sns:us-east-1:${AWS_PROD_ACCOUNT_ID}:${AWS_PROD_SNS_TOPIC}" --region us-east-1 --message '{"version":"1.0","source":"custom","content":{"description":":warning: Jenkins build *'"$JOB_NAME"' '"$BUILD_NUMBER"'* with *PR-'"$CHANGE_ID"'* *failed!*"}}' + ''' + } + } + always { + script { + // Trigger another job to collect all build statistics + CI_JOB_NAME=env.JOB_NAME.replace("/${env.BRANCH_NAME}","") + CI_BRANCH_NAME=env.BRANCH_NAME.replace("%2F","%252F") + echo "post: Triggering ufs-weather-model/ufs-wm-metrics job for ${CI_JOB_NAME} on branch build ${CI_BRANCH_NAME}/${env.BUILD_NUMBER} ..." + + build job: '/ufs-weather-model/ufs-wm-metrics', parameters: [ + string(name: 'CI_JOB_NAME', value: "${CI_JOB_NAME}"), + string(name: 'CI_BUILD_NUMBER', value: "${CI_BRANCH_NAME}/${env.BUILD_NUMBER}") + ], wait: false + + echo "#### post: ufs-weather-model/ufs-wm-metrics COMPLETE." + } + } + } +} diff --git a/.cicd/Jenkinsfile.combined b/.cicd/Jenkinsfile.combined new file mode 100644 index 0000000000..b92bb07d2d --- /dev/null +++ b/.cicd/Jenkinsfile.combined @@ -0,0 +1,388 @@ +matchedNode = [] +generateBaselineNode = [] +for (label in pullRequest.labels) { + listOfLabelNodeNames = jenkins.model.Jenkins.instance.nodes.collect { + node -> node.getLabelString().contains(label) ? node.name : null + + if ((label.matches(node.getLabelString()+"-(.*)"))) { + matchedNode += node.getLabelString() + } + + if ((label.matches(node.getLabelString()+"(.*)-BL"))) { + generateBaselineNode += node.getLabelString() + } + } +} + +modifiedLabels = matchedNode.collect{"'" + it + "'"} +baselineLabels = generateBaselineNode.collect{"'" + it + "'"} +def generateStage(nodeLabel) { + return { + stage("Running on ${nodeLabel}") { + node(nodeLabel) { + cleanWs() + checkout scm + script { + try { + echo "Running on ${nodeLabel}" + if (baselineLabels.contains(nodeLabel)) { + sh ''' + git submodule update --init --recursive + cd tests + pwd + export BL_DATE=$(cat bl_date.conf | cut -d '=' -f2) + export machine=${NODE_NAME} + export PATH=$PATH:~/bin + echo $CHANGE_ID + export SSH_ORIGIN=$(curl --silent https://api.github.com/repos/ufs-community/ufs-weather-model/pulls/$CHANGE_ID | jq -r '.head.repo.ssh_url') + export FORK_BRANCH=$(curl --silent https://api.github.com/repos/ufs-community/ufs-weather-model/pulls/$CHANGE_ID | jq -r '.head.ref') + + if [[ $machine =~ "Jet" ]] + then + echo "Creating baselines on $machine" + export dprefix=/lfs1/NAGAPE/$ACCNR/$USER + ./rt.sh -a ${ACCNR} -c -r -l rt.conf | tee $WORKSPACE/tests/logs/RT-run-$machine.log + elif [[ $machine =~ "Hercules" ]] + then + echo "Creating baselines on $machine" + export dprefix=/work2/noaa/$ACCNR/$USER + sed "s|/noaa/stmp/|/noaa/$ACCNR/stmp/|g" -i rt.sh + export ACCNR=epic + ./rt.sh -a ${ACCNR} -c -e -l rt.conf | tee $WORKSPACE/tests/logs/RT-run-$machine.log + export DISKNM=/work/noaa/epic/hercules/UFS-WM_RT + cd ${DISKNM}/NEMSfv3gfs/ + mkdir develop-${BL_DATE} + cd /work2/noaa/epic/stmp/role-epic/stmp/role-epic/FV3_RT + rsync -a REGRESSION_TEST/ ${DISKNM}/NEMSfv3gfs/develop-${BL_DATE} + cd ${DISKNM}/NEMSfv3gfs/ + ./adjust_permissions.sh hercules develop-${BL_DATE} + chgrp noaa-hpc develop-${BL_DATE} + cd $WORKSPACE/tests + ./rt.sh -a ${ACCNR} -e -l rt.conf | tee $WORKSPACE/tests/logs/RT-run-$machine.log + cd logs/ + cp RegressionTests_hercules.log /work/noaa/epic/role-epic/jenkins/workspace + git remote -v + git fetch --no-recurse-submodules origin + git reset FETCH_HEAD --hard + cd .. && cd .. && cd .. + cp RegressionTests_hercules.log $WORKSPACE/tests/logs/ + cd $WORKSPACE/tests/ + elif [[ $machine =~ "Orion" ]] + then + cd .. + #module load git/2.28.0 + git submodule update --init --recursive + cd tests + echo "Creating baselines on $machine" + export dprefix=/work2/noaa/$ACCNR/$USER + sed -i 's|/work/noaa/stmp/${USER}|/work/noaa/epic/stmp/role-epic/|g' rt.sh + export ACCNR=epic + ./rt.sh -a ${ACCNR} -c -e -l rt.conf | tee $WORKSPACE/tests/logs/RT-run-$machine.log + export DISKNM=/work/noaa/epic/UFS-WM_RT + cd ${DISKNM}/NEMSfv3gfs/ + mkdir develop-${BL_DATE} + cd /work/noaa/epic/stmp/role-epic/stmp/role-epic/FV3_RT/ + rsync -a REGRESSION_TEST/ ${DISKNM}/NEMSfv3gfs/develop-${BL_DATE} + cd ${DISKNM}/NEMSfv3gfs/ + ./adjust_permissions.sh orion develop-${BL_DATE} + chgrp noaa-hpc develop-${BL_DATE} + cd $WORKSPACE/tests + ./rt.sh -a ${ACCNR} -e -l rt.conf | tee $WORKSPACE/tests/logs/RT-run-$machine.log + cd logs/ + cp RegressionTests_orion.log /work/noaa/epic/role-epic/jenkins/workspace + git remote -v + git fetch --no-recurse-submodules origin + git reset FETCH_HEAD --hard + cd .. && cd .. && cd .. + cp RegressionTests_orion.log $WORKSPACE/tests/logs/ + cd $WORKSPACE/tests/ + elif [[ $machine =~ "Gaea" ]] + then + echo "Creating baselines on $machine" + ./rt.sh -a ${ACCNR} -c -e -l rt.conf | tee $WORKSPACE/tests/logs/RT-run-$machine.log + unset LD_LIBRARY_PATH + export DISKNM=/gpfs/f5/epic/world-shared/UFS-WM_RT + cd ${DISKNM}/NEMSfv3gfs/ + mkdir develop-${BL_DATE} + cd /gpfs/f5/epic/scratch/role.epic/FV3_RT + rsync -a REGRESSION_TEST/ ${DISKNM}/NEMSfv3gfs/develop-${BL_DATE} + cd ${DISKNM}/NEMSfv3gfs/ + chgrp ncep develop-${BL_DATE} + cd $WORKSPACE/tests + ./rt.sh -a ${ACCNR} -e -l rt.conf | tee $WORKSPACE/tests/logs/RT-run-$machine.log + cd logs/ + cp RegressionTests_gaea.log /gpfs/f5/epic/scratch/role.epic/jenkins/workspace + git remote -v + git fetch --no-recurse-submodules origin + git reset FETCH_HEAD --hard + cd .. && cd .. && cd .. + cp RegressionTests_gaea.log $WORKSPACE/tests/logs/ + cd $WORKSPACE/tests/ + elif [[ $machine =~ "Hera" ]] + then + echo "Creating baselines on $machine" + export ACCNR=epic + ./rt.sh -a ${ACCNR} -c -r -l rt.conf + export DISKNM=/scratch2/NAGAPE/epic/UFS-WM_RT + cd ${DISKNM}/NEMSfv3gfs/ + mkdir develop-${BL_DATE} + cd /scratch1/NCEPDEV/stmp4/role.epic/FV3_RT + rsync -a REGRESSION_TEST/ ${DISKNM}/NEMSfv3gfs/develop-${BL_DATE} + cd $WORKSPACE/tests + ./rt.sh -a ${ACCNR} -r -l rt.conf | tee $WORKSPACE/tests/logs/RT-run-$machine.log + cd logs/ + cp RegressionTests_hera.log /scratch2/NAGAPE/epic/role.epic/jenkins/workspace + git remote -v + git fetch --no-recurse-submodules origin + git reset FETCH_HEAD --hard + cd .. && cd .. && cd .. + cp RegressionTests_hera.log $WORKSPACE/tests/logs/ + cd $WORKSPACE/tests/ + elif [[ $machine =~ "Derecho" ]] + then + echo "Creating baselines on $machine" + export ACCNR=nral0032 + ./rt.sh -a ${ACCNR} -c -e -l rt.conf | tee $WORKSPACE/tests/logs/RT-run-$machine.log + export DISKNM=/glade/derecho/scratch/epicufsrt/ufs-weather-model/RT/ + cd ${DISKNM}/NEMSfv3gfs/ + mkdir develop-${BL_DATE} + cd /glade/derecho/scratch/epicufsrt/FV3_RT + rsync -a REGRESSION_TEST/ ${DISKNM}/NEMSfv3gfs/develop-${BL_DATE} + cd $WORKSPACE/tests + ./rt.sh -a ${ACCNR} -e -l rt.conf | tee $WORKSPACE/tests/logs/RT-run-$machine.log + cd logs/ + cp RegressionTests_derecho.log /glade/derecho/scratch/epicufsrt/jenkins/workspace + git remote -v + git fetch --no-recurse-submodules origin + git reset FETCH_HEAD --hard + cd .. && cd .. && cd .. + cp RegressionTests_derecho.log $WORKSPACE/tests/logs/ + cd $WORKSPACE/tests/ + else + echo "Creating baselines on $machine" + ./rt.sh -a ${ACCNR} -c -r -l rt.conf | tee $WORKSPACE/tests/logs/RT-run-$machine.log + fi + git config user.email "ecc.platform@noaa.gov" + git config user.name "epic-cicd-jenkins" + echo "Testing concluded...removing labels for $machine from $GIT_URL" + + export machine_name_logs=$(echo $machine | awk '{ print tolower($1) }') + git remote -v | grep -w sshorigin > /dev/null 2>&1 && git remote remove sshorigin > /dev/null 2>&1 + git remote add sshorigin $SSH_ORIGIN > /dev/null 2>&1 + git add logs/RegressionTests_$machine_name_logs.log + git commit -m "[AutoRT] $machine Job Completed.\n\n\n on-behalf-of @ufs-community " + git pull sshorigin $FORK_BRANCH + git push sshorigin HEAD:$FORK_BRANCH + + tar --create --gzip --verbose --dereference --file "${machine_name_logs}.tgz" ${WORKSPACE}/tests/logs/*.log + + GIT_OWNER=$(echo $GIT_URL | cut -d '/' -f4) + GIT_REPO_NAME=$(echo $GIT_URL | cut -d '/' -f5 | cut -d '.' -f1) + + curl --silent -X DELETE -H "Accept: application/vnd.github.v3+json" -H "Authorization: Bearer ${GITHUB_TOKEN}" https://api.github.com/repos/${GIT_OWNER}/${GIT_REPO_NAME}/issues/${CHANGE_ID}/labels/$machine-BL + ''' + s3Upload consoleLogLevel: 'INFO', dontSetBuildResultOnFailure: false, dontWaitForConcurrentBuildCompletion: false, entries: [[bucket: 'noaa-epic-prod-jenkins-artifacts', excludedFile: '', flatten: true, gzipFiles: false, keepForever: false, managedArtifacts: true, noUploadOnFailure: false, selectedRegion: 'us-east-1', showDirectlyInBrowser: false, sourceFile: "**/*tgz*", storageClass: 'STANDARD', uploadFromSlave: false, useServerSideEncryption: false]], pluginFailureResultConstraint: 'FAILURE', profileName: 'main', userMetadata: [] + + } + else { + sh ''' + git submodule update --init --recursive + pwd + cd tests + export machine=${NODE_NAME} + export PATH=$PATH:~/bin + echo $CHANGE_ID + export SSH_ORIGIN=$(curl --silent https://api.github.com/repos/ufs-community/ufs-weather-model/pulls/$CHANGE_ID | jq -r '.head.repo.ssh_url') + export FORK_BRANCH=$(curl --silent https://api.github.com/repos/ufs-community/ufs-weather-model/pulls/$CHANGE_ID | jq -r '.head.ref') + + if [[ $machine =~ "Jet" ]] + then + echo "Running regression tests on $machine" + export dprefix=/lfs1/NAGAPE/$ACCNR/$USER + ./rt.sh -a ${ACCNR} -r -l rt.conf | tee $WORKSPACE/tests/logs/RT-run-$machine.log + elif [[ $machine =~ "Hercules" ]] + then + echo "Running regression tests on $machine" + export dprefix=/work2/noaa/$ACCNR/$USER + sed "s|/noaa/stmp/|/noaa/$ACCNR/stmp/|g" -i rt.sh + export ACCNR=epic + ./rt.sh -a ${ACCNR} -e -l rt.conf | tee $WORKSPACE/tests/logs/RT-run-$machine.log + cd logs/ + cp RegressionTests_hercules.log /work/noaa/epic/role-epic/jenkins/workspace + git remote -v + git fetch --no-recurse-submodules origin + git reset FETCH_HEAD --hard + cd .. && cd .. && cd .. + cp RegressionTests_hercules.log $WORKSPACE/tests/logs/ + cd $WORKSPACE/tests/ + elif [[ $machine =~ "Orion" ]] + then + echo "Running regression tests on $machine" + cd .. + #module load git/2.28.0 + git submodule update --init --recursive + cd tests + export dprefix=/work2/noaa/$ACCNR/$USER + sed "s|/noaa/stmp/|/noaa/$ACCNR/stmp/|g" -i rt.sh + ./rt.sh -a ${ACCNR} -e -l rt.conf | tee $WORKSPACE/tests/logs/RT-run-$machine.log + cd logs/ + cp RegressionTests_orion.log /work/noaa/epic/role-epic/jenkins/workspace + git remote -v + git fetch --no-recurse-submodules origin + git reset FETCH_HEAD --hard + cd .. && cd .. && cd .. + cp RegressionTests_orion.log $WORKSPACE/tests/logs/ + cd $WORKSPACE/tests/ + elif [[ $machine =~ "Gaea" ]] + then + echo "Running regression tests on $machine" + ./rt.sh -a ${ACCNR} -e -l rt.conf | tee $WORKSPACE/tests/logs/RT-run-$machine.log + unset LD_LIBRARY_PATH + cd logs/ + cp RegressionTests_gaea.log /gpfs/f5/epic/scratch/role.epic/jenkins/workspace + git remote -v + git fetch --no-recurse-submodules origin + git reset FETCH_HEAD --hard + cd .. && cd .. && cd .. + cp RegressionTests_gaea.log $WORKSPACE/tests/logs/ + cd $WORKSPACE/tests/ + elif [[ $machine =~ "Hera" ]] + then + echo "Running regression tests on $machine" + export ACCNR=epic + ./rt.sh -a ${ACCNR} -r -l rt.conf | tee $WORKSPACE/tests/logs/RT-run-$machine.log + cd logs/ + cp RegressionTests_hera.log /scratch2/NAGAPE/epic/role.epic/jenkins/workspace + git remote -v + git fetch --no-recurse-submodules origin + git reset FETCH_HEAD --hard + cd .. && cd .. && cd .. + cp RegressionTests_hera.log $WORKSPACE/tests/logs/ + cd $WORKSPACE/tests/ + elif [[ $machine =~ "Derecho" ]] + then + echo "Running regression tests on $machine" + export ACCNR=nral0032 + ./rt.sh -a ${ACCNR} -e -l rt.conf | tee $WORKSPACE/tests/logs/RT-run-$machine.log + cd logs/ + cp RegressionTests_derecho.log /glade/derecho/scratch/epicufsrt/jenkins/workspace + git remote -v + git fetch --no-recurse-submodules origin + git reset FETCH_HEAD --hard + cd .. && cd .. && cd .. + cp RegressionTests_derecho.log $WORKSPACE/tests/logs/ + cd $WORKSPACE/tests/ + else + echo "Running regression tests on $machine" + ./rt.sh -a ${ACCNR} -r -l rt.conf | tee $WORKSPACE/tests/logs/RT-run-$machine.log + fi + + git config user.email "ecc.platform@noaa.gov" + git config user.name "epic-cicd-jenkins" + export machine_name_logs=$(echo $machine | awk '{ print tolower($1) }') + echo "Testing concluded...removing labels for $machine from $GIT_URL" + git remote -v | grep -w sshorigin > /dev/null 2>&1 && git remote remove sshorigin > /dev/null 2>&1 + git remote add sshorigin $SSH_ORIGIN > /dev/null 2>&1 + git add logs/RegressionTests_$machine_name_logs.log + git commit -m "[AutoRT] $machine Job Completed.\n\n\n on-behalf-of @ufs-community " + git pull sshorigin $FORK_BRANCH + git push sshorigin HEAD:$FORK_BRANCH + + tar --create --gzip --verbose --dereference --file "${machine_name_logs}.tgz" ${WORKSPACE}/tests/logs/*.log + + GIT_OWNER=$(echo $GIT_URL | cut -d '/' -f4) + GIT_REPO_NAME=$(echo $GIT_URL | cut -d '/' -f5 | cut -d '.' -f1) + + curl --silent -X DELETE -H "Accept: application/vnd.github.v3+json" -H "Authorization: Bearer ${GITHUB_TOKEN}" https://api.github.com/repos/${GIT_OWNER}/${GIT_REPO_NAME}/issues/${CHANGE_ID}/labels/$machine-RT + + ''' + s3Upload consoleLogLevel: 'INFO', dontSetBuildResultOnFailure: false, dontWaitForConcurrentBuildCompletion: false, entries: [[bucket: 'noaa-epic-prod-jenkins-artifacts', excludedFile: '', flatten: true, gzipFiles: false, keepForever: false, managedArtifacts: true, noUploadOnFailure: false, selectedRegion: 'us-east-1', showDirectlyInBrowser: false, sourceFile: "**/*tgz*", storageClass: 'STANDARD', uploadFromSlave: false, useServerSideEncryption: false]], pluginFailureResultConstraint: 'FAILURE', profileName: 'main', userMetadata: [] + } + } + catch(err) { + sh ''' + export machine=${NODE_NAME} + export CHANGE_ID=${CHANGE_ID} + export SSH_ORIGIN=$(curl --silent https://api.github.com/repos/ufs-community/ufs-weather-model/pulls/$CHANGE_ID | jq -r '.head.repo.ssh_url') + export FORK_BRANCH=$(curl --silent https://api.github.com/repos/ufs-community/ufs-weather-model/pulls/$CHANGE_ID | jq -r '.head.ref') + cd $WORKSPACE/tests + git config user.email "ecc.platform@noaa.gov" + git config user.name "epic-cicd-jenkins" + export machine_name_logs=$(echo $machine | awk '{ print tolower($1) }') + echo "Testing concluded...removing labels for $machine from $GIT_URL" + git remote -v | grep -w sshorigin > /dev/null 2>&1 && git remote remove sshorigin > /dev/null 2>&1 + git remote add sshorigin $SSH_ORIGIN > /dev/null 2>&1 + + tar --create --gzip --verbose --dereference --file "${machine_name_logs}.tgz" ${WORKSPACE}/tests/logs/*.log + + GIT_OWNER=$(echo $GIT_URL | cut -d '/' -f4) + GIT_REPO_NAME=$(echo $GIT_URL | cut -d '/' -f5 | cut -d '.' -f1) + + curl --silent -X DELETE -H "Accept: application/vnd.github.v3+json" -H "Authorization: Bearer ${GITHUB_TOKEN}" https://api.github.com/repos/${GIT_OWNER}/${GIT_REPO_NAME}/issues/${CHANGE_ID}/labels/{$machine-RT,$machine-BL} + ''' + s3Upload consoleLogLevel: 'INFO', dontSetBuildResultOnFailure: false, dontWaitForConcurrentBuildCompletion: false, entries: [[bucket: 'noaa-epic-prod-jenkins-artifacts', excludedFile: '', flatten: true, gzipFiles: false, keepForever: false, managedArtifacts: true, noUploadOnFailure: false, selectedRegion: 'us-east-1', showDirectlyInBrowser: false, sourceFile: "**/*tgz*", storageClass: 'STANDARD', uploadFromSlave: false, useServerSideEncryption: false]], pluginFailureResultConstraint: 'FAILURE', profileName: 'main', userMetadata: [] + currentBuild.result = 'FAILURE' + } + } + } + } + } +} + +def parallelStagesMap = modifiedLabels.collectEntries { + ["${it}" : generateStage(it)] +} + +pipeline { + agent none + environment { + ACCNR = 'epic' + AWS_PROD_ACCOUNT_ID = credentials('AWS_PROD_ACCOUNT_ID') + AWS_PROD_SNS_TOPIC = credentials('AWS_PROD_SNS_TOPIC') + GITHUB_TOKEN = credentials('GithubJenkinsNew') + GIT_URL = 'https://github.com/ufs-community/ufs-weather-model.git' + } + stages { + stage('Launch SonarQube') { + steps { + script { + echo "BRANCH_NAME=${env.CHANGE_BRANCH}" + echo "FORK_NAME=${env.CHANGE_FORK}" + echo "CHANGE_URL=${env.CHANGE_URL}" + echo "CHANGE_ID=${env.CHANGE_ID}" + build job: '/ufs-weather-model/ufs-wm-sonarqube', parameters: [ + string(name: 'BRANCH_NAME', value: env.CHANGE_BRANCH ?: 'develop'), + string(name: 'FORK_NAME', value: env.CHANGE_FORK ?: ''), + string(name: 'CHANGE_URL', value: env.CHANGE_URL ?: ''), + string(name: 'CHANGE_ID', value: env.CHANGE_ID ?: '') + ], wait: false + } + } + } + stage('Run Regression Tests in Parallel') { + steps { + script { + parallel parallelStagesMap + } + } + } + } + post { + success { + node('built-in') { + echo 'This will run only if successful.' + sh ''' + aws sns publish --topic-arn "arn:aws:sns:us-east-1:${AWS_PROD_ACCOUNT_ID}:${AWS_PROD_SNS_TOPIC}" --region us-east-1 --message '{"version":"1.0","source":"custom","content":{"description":":sunny: Jenkins build *'"$JOB_NAME"' '"$BUILD_NUMBER"'* with *PR-'"$CHANGE_ID"'* *succeeded*"}}' + ''' + } + } + failure { + node('built-in') { + echo 'This will run only if the run was marked as unstable.' + sh ''' + aws sns publish --topic-arn "arn:aws:sns:us-east-1:${AWS_PROD_ACCOUNT_ID}:${AWS_PROD_SNS_TOPIC}" --region us-east-1 --message '{"version":"1.0","source":"custom","content":{"description":":warning: Jenkins build *'"$JOB_NAME"' '"$BUILD_NUMBER"'* with *PR-'"$CHANGE_ID"'* *failed!*"}}' + ''' + } + } + } +} diff --git a/.cicd/scripts/.shellcheckrc b/.cicd/scripts/.shellcheckrc new file mode 100644 index 0000000000..83d6166add --- /dev/null +++ b/.cicd/scripts/.shellcheckrc @@ -0,0 +1,22 @@ +# Shellcheck is used by Super-Linter to flag BASH shell oddities during CI pipeline. +# global settings are at top-level: ../../.shellcheckrc +# https://github.com/koalaman/shellcheck +# https://github.com/super-linter/super-linter + +# Allow to assign with local VAR=... +disable=SC2155 + +# Ignore source-able files from the varyious platforms in our matrix +disable=SC1091 + +# Disable info on pipe-ing commands +disable=SC2312 + +# Disable info sed with single quote string litteral +disable=SC2016 + +# Disable info on not double-quoting variables +disable=SC2086 + +# Disable info on &&, || chaining +disable=SC2015 diff --git a/.cicd/scripts/create_baseline.sh b/.cicd/scripts/create_baseline.sh new file mode 100755 index 0000000000..2ceed2f1fe --- /dev/null +++ b/.cicd/scripts/create_baseline.sh @@ -0,0 +1,223 @@ +#!/bin/bash -x + +export PATH=${PATH}:~/bin +echo "USER=${USER}" +echo "WORKSPACE=${WORKSPACE}" +export ACCNR=epic + +export account="-a ${ACCNR}" +export workflow="-e" + #[[ ${UFS_PLATFORM} = jet ]] && workflow="-r" + #[[ ${UFS_PLATFORM} = hera ]] && workflow="-r" + #[[ ${UFS_PLATFORM} =~ clusternoaa ]] && workflow="" + +export opt="-l" +export suite="rt.conf" + [[ -n ${WM_OPERATIONAL_TESTS} ]] && opt="-n" && suite="${WM_OPERATIONAL_TESTS} ${UFS_COMPILER}" || return 0 + [[ ${WM_OPERATIONAL_TESTS} = default ]] && opt="-n" && suite="control_p8 ${UFS_COMPILER}" + [[ ${WM_OPERATIONAL_TESTS} = comprehensive ]] && opt="-l" && suite="rt.conf" + [[ ${WM_OPERATIONAL_TESTS} = rt.conf ]] && opt="-l" && suite="rt.conf" + [[ "${suite}" = rt.conf ]] && opt="-l" + +set -eu + +export machine=${NODE_NAME} + +SCRIPT_REALPATH=$(realpath "${BASH_SOURCE[0]}") +SCRIPTS_DIR=$(dirname "${SCRIPT_REALPATH}") +UFS_MODEL_DIR=$(realpath "${SCRIPTS_DIR}/../..") +readonly UFS_MODEL_DIR +echo "UFS MODEL DIR: ${UFS_MODEL_DIR}" + +export CC=${CC:-mpicc} +export CXX=${CXX:-mpicxx} +export FC=${FC:-mpif90} + +BUILD_DIR=${BUILD_DIR:-${UFS_MODEL_DIR}/build} +TESTS_DIR=${TESTS_DIR:-${UFS_MODEL_DIR}/tests} + +pwd +ls -al .cicd/* +ls -al ${TESTS_DIR}/rt.sh + +function create_baseline() { + local machine=${1:-${NODE_NAME}} + local machine_id=${machine,,} # tolower + local WORKSPACE + WORKSPACE="$(pwd)" + local status=0 + + git submodule update --init --recursive + pwd + ls -al .cicd/* + cd tests + pwd + + [[ ${UFS_PLATFORM} =~ clusternoaa ]] && echo "export BL_DATE=20240426" > bl_date.conf || cat bl_date.conf + + mkdir -p logs/ + BL_DATE=$(cut -d '=' -f2 bl_date.conf) + export BL_DATE + + if [[ ${machine} =~ "Jet" ]] + then + echo "Creating baselines on ${machine}" + export dprefix=/lfs5/NAGAPE/${ACCNR}/${USER} + sed 's|/lfs4/HFIP/${ACCNR}/${USER}|/lfs4/HFIP/hfv3gfs/${USER}|g' -i rt.sh + sed 's|/lfs5/HFIP/${ACCNR}/${USER}|/lfs5/NAGAPE/${ACCNR}/${USER}|g' -i rt.sh + local workflow="-r" + ./rt.sh -a "${ACCNR}" -c "${workflow}" "${opt}" "${suite}" | tee "${WORKSPACE}/tests/logs/RT-run-${machine}.log" + status=${PIPESTATUS[0]} + elif [[ ${machine} =~ "Hercules" ]] + then + echo "Creating baselines on ${machine}" + export dprefix=/work2/noaa/${ACCNR}/${USER} + sed "s|/noaa/stmp/|/noaa/${ACCNR}/stmp/|g" -i rt.sh + export ACCNR=epic + ./rt.sh -a "${ACCNR}" -c "${workflow}" "${opt}" "${suite}" | tee "${WORKSPACE}/tests/logs/RT-run-${machine}.log" + status=${PIPESTATUS[0]} + export DISKNM=/work/noaa/epic/hercules/UFS-WM_RT + cd ${DISKNM}/NEMSfv3gfs/ + mkdir -p develop-${BL_DATE} + cd /work2/noaa/epic/stmp/role-epic/stmp/role-epic/FV3_RT + ls -l REGRESSION_TEST/. + rsync -a --no-t REGRESSION_TEST/ "${DISKNM}/NEMSfv3gfs/develop-${BL_DATE}" || echo "#### Warning! rsync $(pwd)/REGRESSION_TEST/ incomplete." + cd ${DISKNM}/NEMSfv3gfs/ + ./adjust_permissions.sh hercules "develop-${BL_DATE}" || : + chgrp noaa-hpc "develop-${BL_DATE}" || : + cd ${WORKSPACE}/tests + ./rt.sh -a "${ACCNR}" "${workflow}" "${opt}" "${suite}" | tee "${WORKSPACE}/tests/logs/RT-run-${machine}.log" + status=${PIPESTATUS[0]} + cd logs/ + cp "RegressionTests_${machine_id}.log" "$(dirname "${WORKSPACE}")" #/work/noaa/epic/role-epic/jenkins/workspace + git remote -v + git fetch --no-recurse-submodules origin + git reset FETCH_HEAD --hard + cd .. && cd .. && cd .. + pwd + cp "$(dirname "${WORKSPACE}")/RegressionTests_${machine_id}.log" "${WORKSPACE}/tests/logs/" + cd ${WORKSPACE}/tests/ + elif [[ ${machine} =~ "Orion" ]] + then + cd .. + #module load git/2.28.0 + git --version + git submodule update --init --recursive + cd tests + echo "Creating baselines on ${machine}" + export dprefix=/work2/noaa/${ACCNR}/${USER} + sed "s|/noaa/stmp/|/noaa/${ACCNR}/stmp/|g" -i rt.sh + export ACCNR=epic + ./rt.sh -a "${ACCNR}" -c "${workflow}" "${opt}" "${suite}" | tee "${WORKSPACE}/tests/logs/RT-run-${machine}.log" + status=${PIPESTATUS[0]} + export DISKNM=/work/noaa/epic/UFS-WM_RT + cd ${DISKNM}/NEMSfv3gfs/ + mkdir -p develop-${BL_DATE} + cd /work/noaa/epic/stmp/role-epic/stmp/role-epic/FV3_RT/ + ls -l REGRESSION_TEST/. + rsync -a --no-t REGRESSION_TEST/ "${DISKNM}/NEMSfv3gfs/develop-${BL_DATE}" || echo "#### Warning! rsync $(pwd)/REGRESSION_TEST/ incomplete." + cd ${DISKNM}/NEMSfv3gfs/ + ./adjust_permissions.sh orion "develop-${BL_DATE}" || : + chgrp noaa-hpc "develop-${BL_DATE}" || : + cd ${WORKSPACE}/tests + ./rt.sh -a "${ACCNR}" "${workflow}" "${opt}" "${suite}" | tee "${WORKSPACE}/tests/logs/RT-run-${machine}.log" + status=${PIPESTATUS[0]} + cd logs/ + cp "RegressionTests_${machine_id}.log" "$(dirname "${WORKSPACE}")" #/work/noaa/epic/role-epic/jenkins/workspace + git remote -v + git fetch --no-recurse-submodules origin + git reset FETCH_HEAD --hard + cd .. && cd .. && cd .. + pwd + cp "$(dirname "${WORKSPACE}")/RegressionTests_${machine_id}.log" "${WORKSPACE}/tests/logs/" + cd ${WORKSPACE}/tests/ + elif [[ ${machine} =~ "Gaea" ]] + then + echo "Creating baselines on ${machine}" + ./rt.sh -a "${ACCNR}" -c "${workflow}" "${opt}" "${suite}" | tee "${WORKSPACE}/tests/logs/RT-run-${machine}.log" + status=${PIPESTATUS[0]} + unset LD_LIBRARY_PATH + export DISKNM=/gpfs/f5/epic/world-shared/UFS-WM_RT + cd ${DISKNM}/NEMSfv3gfs/ + mkdir -p develop-${BL_DATE} + cd /gpfs/f5/epic/scratch/role.epic/FV3_RT + ls -l REGRESSION_TEST/. + rsync -a --no-t REGRESSION_TEST/ "${DISKNM}/NEMSfv3gfs/develop-${BL_DATE}" || echo "#### Warning! rsync $(pwd)/REGRESSION_TEST/ incomplete." + cd ${DISKNM}/NEMSfv3gfs/ + chgrp ncep "develop-${BL_DATE}" || : + cd ${WORKSPACE}/tests + ./rt.sh -a "${ACCNR}" "${workflow}" "${opt}" "${suite}" | tee "${WORKSPACE}/tests/logs/RT-run-${machine}.log" + status=${PIPESTATUS[0]} + cd logs/ + cp "RegressionTests_${machine_id}.log" "$(dirname "${WORKSPACE}")" #/gpfs/f5/epic/scratch/role.epic/jenkins/workspace + git remote -v + git fetch --no-recurse-submodules origin + git reset FETCH_HEAD --hard + cd .. && cd .. && cd .. + pwd + cp "$(dirname "${WORKSPACE}")/RegressionTests_${machine_id}.log" "${WORKSPACE}/tests/logs/" + cd ${WORKSPACE}/tests/ + elif [[ ${machine} =~ "Hera" ]] + then + echo "Creating baselines on ${machine}" + export ACCNR=epic + sed "s|QUEUE=batch|QUEUE=windfall|g" -i rt.sh + local workflow="-r" + ./rt.sh -a "${ACCNR}" -c "${workflow}" "${opt}" "${suite}" | tee "${WORKSPACE}/tests/logs/RT-run-${machine}.log" + status=${PIPESTATUS[0]} + export DISKNM=/scratch2/NAGAPE/epic/UFS-WM_RT + cd ${DISKNM}/NEMSfv3gfs/ + mkdir -p develop-${BL_DATE} + cd /scratch1/NCEPDEV/stmp4/role.epic/FV3_RT + ls -l REGRESSION_TEST/. + rsync -a --no-t REGRESSION_TEST/ "${DISKNM}/NEMSfv3gfs/develop-${BL_DATE}" || echo "#### Warning! rsync $(pwd)/REGRESSION_TEST/ incomplete." + cd ${WORKSPACE}/tests + ./rt.sh -a "${ACCNR}" "${workflow}" "${opt}" "${suite}" | tee "${WORKSPACE}/tests/logs/RT-run-${machine}.log" + status=${PIPESTATUS[0]} + cd logs/ + cp "RegressionTests_${machine_id}.log" "$(dirname "${WORKSPACE}")" #/scratch2/NAGAPE/epic/role.epic/jenkins/workspace + git remote -v + git fetch --no-recurse-submodules origin + git reset FETCH_HEAD --hard + cd .. && cd .. && cd .. + pwd + cp "$(dirname "${WORKSPACE}")/RegressionTests_${machine_id}.log" "${WORKSPACE}/tests/logs/" + cd ${WORKSPACE}/tests/ + elif [[ ${machine} =~ "Derecho" ]] + then + echo "Creating baselines on ${machine}" + export ACCNR=nral0032 + ./rt.sh -a "${ACCNR}" -c "${workflow}" "${opt}" "${suite}" | tee "${WORKSPACE}/tests/logs/RT-run-${machine}.log" + status=${PIPESTATUS[0]} + export DISKNM=/glade/derecho/scratch/epicufsrt/ufs-weather-model/RT/ + cd ${DISKNM}/NEMSfv3gfs/ + mkdir -p develop-${BL_DATE} + cd /glade/derecho/scratch/epicufsrt/FV3_RT + ls -l REGRESSION_TEST/. + rsync -a --no-t REGRESSION_TEST/ "${DISKNM}/NEMSfv3gfs/develop-${BL_DATE}" || echo "#### Warning! rsync $(pwd)/REGRESSION_TEST/ incomplete." + cd ${WORKSPACE}/tests + ./rt.sh -a "${ACCNR}" "${workflow}" "${opt}" "${suite}" | tee "${WORKSPACE}/tests/logs/RT-run-${machine}.log" + status=${PIPESTATUS[0]} + cd logs/ + cp "RegressionTests_${machine_id}.log" "$(dirname "${WORKSPACE}")" #/glade/derecho/scratch/epicufsrt/jenkins/workspace + git remote -v + git fetch --no-recurse-submodules origin + git reset FETCH_HEAD --hard + cd .. && cd .. && cd .. + pwd + cp "$(dirname "${WORKSPACE}")/RegressionTests_${machine_id}.log" "${WORKSPACE}/tests/logs/" + cd ${WORKSPACE}/tests/ + else + echo "Creating baselines on ${machine}" + local workflow="-r" + ./rt.sh -a "${ACCNR}" -c "${workflow}" "${opt}" "${suite}" | tee "${WORKSPACE}/tests/logs/RT-run-${machine}.log" + status=${PIPESTATUS[0]} + fi + + cd ${WORKSPACE} + + echo "Testing concluded for ${machine}. status=${status}" + return ${status} +} + +create_baseline "${machine}" diff --git a/.cicd/scripts/disk_usage.sh b/.cicd/scripts/disk_usage.sh new file mode 100755 index 0000000000..533897c8cb --- /dev/null +++ b/.cicd/scripts/disk_usage.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash + +# Output a CSV report of disk usage on subdirs of some path +# Usage: +# [JOB_NAME=] [BUILD_NUMBER=] [UFS_COMPILER=] [UFS_PLATFORM=] disk_usage path depth size outfile.csv +# +# args: +# directory=$1 +# depth=$2 +# size=$3 +# outfile=$4 + +export UFS_PLATFORM=${UFS_PLATFORM:-${NODE_NAME,,}} +export UFS_COMPILER=${UFS_COMPILER:-intel} +[[ -n ${WORKSPACE} ]] || WORKSPACE="$(pwd)" +[[ -n ${UFS_PLATFORM} ]] || UFS_PLATFORM="$(hostname -s 2>/dev/null)" || UFS_PLATFORM="$(hostname 2>/dev/null)" +[[ -n ${UFS_COMPILER} ]] || UFS_COMPILER="compiler" +echo "STAGE_NAME=${STAGE_NAME%% *}" # from pipeline + +script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" > /dev/null 2>&1 && pwd)" +echo "script_dir=${script_dir}" + +# Get repository root from Jenkins WORKSPACE variable if set, otherwise, set +# relative to script directory. +declare workspace +if [[ -d "${WORKSPACE}/${UFS_PLATFORM}" ]]; then + workspace="${WORKSPACE}/${UFS_PLATFORM}" + outfile="${4:-${workspace}-${UFS_PLATFORM}-${UFS_COMPILER}-disk-usage${STAGE_NAME%% *}.csv}" +else + workspace="$(cd -- "${script_dir}/../.." && pwd)" + outfile="${4:-${workspace}/${UFS_PLATFORM}-${UFS_COMPILER}-disk-usage${STAGE_NAME%% *}.csv}" +fi +echo "workspace=${workspace}" +echo "outfile=${outfile}" + +function disk_usage() { + local directory="${1:-${PWD}}" + local depth="${2:-1}" + local size="${3:-k}" + echo "Disk usage: ${JOB_NAME:-ci}/${UFS_PLATFORM}/$(basename ${directory})" + ( + cd ${directory} || exit 1 + echo "Platform,Build,Owner,Group,Inodes,${size:-k}bytes,Access Time,Filename" + du -Px -d ${depth:-1} --inode --exclude='./workspace' | \ + while read -r line ; do + read -ra arr<<<"${line}"; inode="${arr[0]}"; filename="${arr[1]}"; + echo "${UFS_PLATFORM}-${UFS_COMPILER:-compiler},${JOB_NAME:-ci}/${BUILD_NUMBER:-0},$(stat -c '%U,%G' "${filename:-.}" || true),${inode:-0},$(du -Px -s -${size:-k} --time "${filename:-null}" 2>/dev/null || true)" | tr '\t' ',' || true; + done | sort -t, -k5 -n #-r + ) + echo "" +} + +disk_usage "${1}" "${2}" "${3}" | tee ${outfile} diff --git a/.cicd/scripts/post_test_results.sh b/.cicd/scripts/post_test_results.sh new file mode 100755 index 0000000000..b36aaa985b --- /dev/null +++ b/.cicd/scripts/post_test_results.sh @@ -0,0 +1,62 @@ +#!/bin/bash +# RT - RegressionTest label +# BL - Baseline label + +set -x +export machine=${1:-${NODE_NAME}} +label=${2:-${WM_TEST_LABEL}} +[[ -n "${label}" ]] || exit 1 + +export PATH=${PATH}:~/bin +echo "USER=${USER}" +echo "WORKSPACE=${WORKSPACE}" +export ACCNR=epic + +export account="-a ${ACCNR}" + +which jq + +set -eu + +SCRIPT_REALPATH=$(realpath "${BASH_SOURCE[0]}") +SCRIPTS_DIR=$(dirname "${SCRIPT_REALPATH}") +UFS_MODEL_DIR=$(realpath "${SCRIPTS_DIR}/../..") +readonly UFS_MODEL_DIR +echo "UFS MODEL DIR: ${UFS_MODEL_DIR}" + +export CC=${CC:-mpicc} +export CXX=${CXX:-mpicxx} +export FC=${FC:-mpif90} + +BUILD_DIR=${BUILD_DIR:-${UFS_MODEL_DIR}/build} +TESTS_DIR=${TESTS_DIR:-${UFS_MODEL_DIR}/tests} + +function post_test() { + local machine=${1:-${NODE_NAME}} + #local machine_id=${machine,,} # tolower + #local machine_name_logs=$(echo "${machine}" | awk '{ print tolower($1) }') + local label=${2:-"undef"} + local WORKSPACE + WORKSPACE="$(pwd)" + GIT_URL=${GIT_URL:-"ufs-weather-model"} + CHANGE_ID=${CHANGE_ID:-"develop"} + + git config user.email "ecc.platform@noaa.gov" + git config user.name "epic-cicd-jenkins" + + git add tests/logs/RegressionTests_${machine,,}.log + git status + git commit -m "[AutoRT] ${machine} Job Completed.\n\n\n on-behalf-of @ufs-community " + + SSH_ORIGIN=$(curl --silent "https://api.github.com/repos/ufs-community/ufs-weather-model/pulls/${CHANGE_ID}" | jq -r '.head.repo.ssh_url') + git remote -v | grep -w sshorigin > /dev/null 2>&1 && git remote remove sshorigin > /dev/null 2>&1 + git remote add sshorigin ${SSH_ORIGIN} > /dev/null 2>&1 || return 0 + + FORK_BRANCH=$(curl --silent "https://api.github.com/repos/ufs-community/ufs-weather-model/pulls/${CHANGE_ID}" | jq -r '.head.ref') + git pull sshorigin ${FORK_BRANCH} || return 0 + git status + git push sshorigin HEAD:${FORK_BRANCH} || return 0 +} + +pwd +post_test "${machine}" "${label}" diff --git a/.cicd/scripts/regression_test.sh b/.cicd/scripts/regression_test.sh new file mode 100755 index 0000000000..4ed79eec40 --- /dev/null +++ b/.cicd/scripts/regression_test.sh @@ -0,0 +1,169 @@ +#!/bin/bash -x + +export PATH=${PATH}:~/bin +echo "USER=${USER}" +echo "WORKSPACE=${WORKSPACE}" +export ACCNR=epic + +export account="-a ${ACCNR}" +export workflow="-e" + #[[ ${UFS_PLATFORM} = jet ]] && workflow="-r" + #[[ ${UFS_PLATFORM} = hera ]] && workflow="-r" + #[[ ${UFS_PLATFORM} =~ clusternoaa ]] && workflow="" + +export opt="-l" +export suite="rt.conf" + [[ -n ${WM_OPERATIONAL_TESTS} ]] && opt="-n" && suite="${WM_OPERATIONAL_TESTS} ${UFS_COMPILER}" || return 0 + [[ ${WM_OPERATIONAL_TESTS} = default ]] && opt="-n" && suite="control_p8 ${UFS_COMPILER}" + [[ ${WM_OPERATIONAL_TESTS} = comprehensive ]] && opt="-l" && suite="rt.conf" + [[ ${WM_OPERATIONAL_TESTS} = rt.conf ]] && opt="-l" && suite="rt.conf" + [[ "${suite}" = rt.conf ]] && opt="-l" + +set -eu + +export machine=${NODE_NAME} + +SCRIPT_REALPATH=$(realpath "${BASH_SOURCE[0]}") +SCRIPTS_DIR=$(dirname "${SCRIPT_REALPATH}") +UFS_MODEL_DIR=$(realpath "${SCRIPTS_DIR}/../..") +readonly UFS_MODEL_DIR +echo "UFS MODEL DIR: ${UFS_MODEL_DIR}" + +export CC=${CC:-mpicc} +export CXX=${CXX:-mpicxx} +export FC=${FC:-mpif90} + +BUILD_DIR=${BUILD_DIR:-${UFS_MODEL_DIR}/build} +TESTS_DIR=${TESTS_DIR:-${UFS_MODEL_DIR}/tests} + +pwd +ls -al .cicd/* +ls -al ${TESTS_DIR}/rt.sh + +function regression_test() { + local machine=${1:-${NODE_NAME}} + local machine_id=${machine,,} # tolower + local WORKSPACE + WORKSPACE="$(pwd)" + local status=0 + + git submodule update --init --recursive + pwd + ls -al .cicd/* + cd tests + pwd + + [[ ${UFS_PLATFORM} =~ clusternoaa ]] && echo "export BL_DATE=20240426" > bl_date.conf || cat bl_date.conf + + mkdir -p logs/ + BL_DATE=$(cut -d '=' -f2 bl_date.conf) + export BL_DATE + + if [[ ${machine} =~ "Jet" ]] + then + echo "Running regression tests on ${machine}" + export dprefix=/lfs5/NAGAPE/${ACCNR}/${USER} + sed 's|/lfs4/HFIP/${ACCNR}/${USER}|/lfs4/HFIP/hfv3gfs/${USER}|g' -i rt.sh + sed 's|/lfs5/HFIP/${ACCNR}/${USER}|/lfs5/NAGAPE/${ACCNR}/${USER}|g' -i rt.sh + local workflow="-r" + ./rt.sh -a "${ACCNR}" "${workflow}" "${opt}" "${suite}" | tee "${WORKSPACE}/tests/logs/RT-run-${machine}.log" + status=${PIPESTATUS[0]} + elif [[ ${machine} =~ "Hercules" ]] + then + echo "Running regression tests on ${machine}" + export dprefix=/work2/noaa/${ACCNR}/${USER} + sed "s|/noaa/stmp/|/noaa/${ACCNR}/stmp/|g" -i rt.sh + export ACCNR=epic + ./rt.sh -a "${ACCNR}" "${workflow}" "${opt}" "${suite}" | tee "${WORKSPACE}/tests/logs/RT-run-${machine}.log" + status=${PIPESTATUS[0]} + cd logs/ + cp "RegressionTests_${machine_id}.log" "$(dirname "${WORKSPACE}")" #/work/noaa/epic/role-epic/jenkins/workspace + git remote -v + git fetch --no-recurse-submodules origin + git reset FETCH_HEAD --hard + cd .. && cd .. && cd .. + pwd + cp "$(dirname "${WORKSPACE}")/RegressionTests_${machine_id}.log" "${WORKSPACE}/tests/logs/" + cd ${WORKSPACE}/tests/ + elif [[ ${machine} =~ "Orion" ]] + then + echo "Running regression tests on ${machine}" + cd .. + #module load git/2.28.0 + git --version + git submodule update --init --recursive + cd tests + export dprefix=/work2/noaa/${ACCNR}/${USER} + sed "s|/noaa/stmp/|/noaa/${ACCNR}/stmp/|g" -i rt.sh + ./rt.sh -a "${ACCNR}" "${workflow}" "${opt}" "${suite}" | tee "${WORKSPACE}/tests/logs/RT-run-${machine}.log" + status=${PIPESTATUS[0]} + cd logs/ + cp "RegressionTests_${machine_id}.log" "$(dirname "${WORKSPACE}")" #/work/noaa/epic/role-epic/jenkins/workspace + git remote -v + git fetch --no-recurse-submodules origin + git reset FETCH_HEAD --hard + cd .. && cd .. && cd .. + pwd + cp "$(dirname "${WORKSPACE}")/RegressionTests_${machine_id}.log" "${WORKSPACE}/tests/logs/" + cd ${WORKSPACE}/tests/ + elif [[ ${machine} =~ "Gaea" ]] + then + echo "Running regression tests on ${machine}" + ./rt.sh -a "${ACCNR}" "${workflow}" "${opt}" "${suite}" | tee "${WORKSPACE}/tests/logs/RT-run-${machine}.log" + status=${PIPESTATUS[0]} + unset LD_LIBRARY_PATH + cd logs/ + cp "RegressionTests_${machine_id}.log" "$(dirname "${WORKSPACE}")" #/gpfs/f5/epic/scratch/role.epic/jenkins/workspace + git remote -v + git fetch --no-recurse-submodules origin + git reset FETCH_HEAD --hard + cd .. && cd .. && cd .. + pwd + cp "$(dirname "${WORKSPACE}")/RegressionTests_${machine_id}.log" "${WORKSPACE}/tests/logs/" + cd ${WORKSPACE}/tests/ + elif [[ ${machine} =~ "Hera" ]] + then + echo "Running regression tests on ${machine}" + export ACCNR=epic + sed "s|QUEUE=batch|QUEUE=windfall|g" -i rt.sh + local workflow="-r" + ./rt.sh -a "${ACCNR}" "${workflow}" "${opt}" "${suite}" | tee "${WORKSPACE}/tests/logs/RT-run-${machine}.log" + status=${PIPESTATUS[0]} + cd logs/ + cp "RegressionTests_${machine_id}.log" "$(dirname "${WORKSPACE}")" #/scratch2/NAGAPE/epic/role.epic/jenkins/workspace + git remote -v + git fetch --no-recurse-submodules origin + git reset FETCH_HEAD --hard + cd .. && cd .. && cd .. + pwd + cp "$(dirname "${WORKSPACE}")/RegressionTests_${machine_id}.log" "${WORKSPACE}/tests/logs/" + cd ${WORKSPACE}/tests/ + elif [[ ${machine} =~ "Derecho" ]] + then + echo "Running regression tests on ${machine}" + export ACCNR=nral0032 + ./rt.sh -a "${ACCNR}" "${workflow}" "${opt}" "${suite}" | tee "${WORKSPACE}/tests/logs/RT-run-${machine}.log" + status=${PIPESTATUS[0]} + cd logs/ + cp "RegressionTests_${machine_id}.log" "$(dirname "${WORKSPACE}")" #/glade/derecho/scratch/epicufsrt/jenkins/workspace + git remote -v + git fetch --no-recurse-submodules origin + git reset FETCH_HEAD --hard + cd .. && cd .. && cd .. + pwd + cp "$(dirname "${WORKSPACE}")/RegressionTests_${machine_id}.log" "${WORKSPACE}/tests/logs/" + cd ${WORKSPACE}/tests/ + else + echo "Running regression tests on ${machine}" + local workflow="-r" + ./rt.sh -a "${ACCNR}" "${workflow}" "${opt}" "${suite}" | tee "${WORKSPACE}/tests/logs/RT-run-${machine}.log" + status=${PIPESTATUS[0]} + fi + + cd ${WORKSPACE} + + echo "Testing concluded for ${machine}. status=${status}" + return ${status} +} + +regression_test "${machine}" diff --git a/.cicd/scripts/wm_build.sh b/.cicd/scripts/wm_build.sh new file mode 100755 index 0000000000..e4a4c0822a --- /dev/null +++ b/.cicd/scripts/wm_build.sh @@ -0,0 +1,72 @@ +#!/bin/bash +set -eu +export UFS_PLATFORM=${UFS_PLATFORM:-${NODE_NAME,,}} +export UFS_COMPILER=${UFS_COMPILER:-intel} + +SCRIPT_REALPATH=$(realpath "${BASH_SOURCE[0]}") +SCRIPTS_DIR=$(dirname "${SCRIPT_REALPATH}") +UFS_MODEL_DIR=$(realpath "${SCRIPTS_DIR}/../..") +readonly UFS_MODEL_DIR +echo "UFS MODEL DIR: ${UFS_MODEL_DIR}" + +export CC=${CC:-mpicc} +export CXX=${CXX:-mpicxx} +export FC=${FC:-mpif90} + +cd "${UFS_MODEL_DIR}" +pwd +ls -l ./build.sh + +BUILD_DIR=${BUILD_DIR:-${UFS_MODEL_DIR}/build} +TESTS_DIR=${TESTS_DIR:-${UFS_MODEL_DIR}/tests} +mkdir -p "${BUILD_DIR}" + +( + cd "${BUILD_DIR}" + pwd +) + +pwd +echo "NODE_NAME=${NODE_NAME}" +echo "UFS_PLATFORM=${UFS_PLATFORM}" +echo "UFS_COMPILER=${UFS_COMPILER}" +workspace=$(pwd) +export workspace +machine=${NODE_NAME} +echo "machine=<${machine}>" +machine_id=${UFS_PLATFORM,,} +if [[ ${UFS_PLATFORM} =~ clusternoaa ]] ; then + machine_id="noaacloud" + sed -e "s|EPIC/spack-stack/spack-stack-1.5.0|spack-stack/spack-stack-1.5.1|g" -i modulefiles/ufs_noaacloud.intel.lua +fi +echo "machine_id=<${machine_id}>" + +if [[ ${UFS_PLATFORM} = derecho ]] ; then + export ACCNR=nral0032 +else + export ACCNR=epic +fi +echo "ACCNR=${ACCNR}" + +export LMOD_SH_DBG_ON=0 +echo "LMOD_VERSION=${LMOD_VERSION}" +if [[ ${UFS_PLATFORM} = gaea ]] ; then + source /gpfs/f5/epic/scratch/role.epic/contrib/Lmod_init_C5.sh + echo "LMOD_VERSION=${LMOD_VERSION}" +fi +set +x +module use ${PWD}/modulefiles >/dev/null 2>&1 +module load ufs_${machine_id}.${UFS_COMPILER} || true +[[ ${UFS_PLATFORM} = gaea ]] && module load cmake/3.23.1 || true +module list + +echo "Pipeline Building WM on ${UFS_PLATFORM} ${UFS_COMPILER} with Account=${ACCNR}." +export CMAKE_FLAGS="-DAPP=ATM -DCCPP_SUITES=FV3_GFS_v16" +/usr/bin/time -p \ + -o ${workspace}/${UFS_PLATFORM}-${UFS_COMPILER}-time-wm_build.json \ + -f '{\n "cpu": "%P"\n, "memMax": "%M"\n, "mem": {"text": "%X", "data": "%D", "swaps": "%W", "context": "%c", "waits": "%w"}\n, "pagefaults": {"major": "%F", "minor": "%R"}\n, "filesystem": {"inputs": "%I", "outputs": "%O"}\n, "time": {"real": "%e", "user": "%U", "sys": "%S"}\n}' \ + ./build.sh | tee ${workspace}/${UFS_PLATFORM}-${UFS_COMPILER}-wm_build-log.txt +status=${PIPESTATUS[0]} +echo "Pipeline Completed WM build on ${UFS_PLATFORM} ${UFS_COMPILER}. status=${status}" + +ls -l build/ufs_model diff --git a/.cicd/scripts/wm_init.sh b/.cicd/scripts/wm_init.sh new file mode 100755 index 0000000000..2146b9e7ae --- /dev/null +++ b/.cicd/scripts/wm_init.sh @@ -0,0 +1,40 @@ +#!/bin/bash +set -eu +export UFS_PLATFORM=${UFS_PLATFORM:-${NODE_NAME,,}} +export UFS_COMPILER=${UFS_COMPILER:-intel} + +SCRIPT_REALPATH=$(realpath "${BASH_SOURCE[0]}") +SCRIPTS_DIR=$(dirname "${SCRIPT_REALPATH}") +UFS_MODEL_DIR=$(realpath "${SCRIPTS_DIR}/../..") +readonly UFS_MODEL_DIR +echo "UFS MODEL DIR: ${UFS_MODEL_DIR}" + +export CC=${CC:-mpicc} +export CXX=${CXX:-mpicxx} +export FC=${FC:-mpif90} + +BUILD_DIR=${BUILD_DIR:-${UFS_MODEL_DIR}/build} +TESTS_DIR=${TESTS_DIR:-${UFS_MODEL_DIR}/tests} + +cd "${UFS_MODEL_DIR}" +echo "UFS_PLATFORM=<${UFS_PLATFORM}>" +echo "UFS_COMPILER=<${UFS_COMPILER}>" + +pwd +echo "NODE_NAME=${NODE_NAME}" +echo "UFS_PLATFORM=${UFS_PLATFORM}" +echo "UFS_COMPILER=${UFS_COMPILER}" +workspace=$(pwd) +export workspace +machine=${NODE_NAME} +echo "machine=<${machine}>" +machine_id=${UFS_PLATFORM,,} +if [[ ${UFS_PLATFORM} =~ clusternoaa ]] ; then + machine_id="noaacloud" +fi +echo "machine_id=<${machine_id}>" + +/usr/bin/time -p \ + -o ${workspace}/${UFS_PLATFORM}-${UFS_COMPILER}-time-wm_init.json \ + -f '{\n "cpu": "%P"\n, "memMax": "%M"\n, "mem": {"text": "%X", "data": "%D", "swaps": "%W", "context": "%c", "waits": "%w"}\n, "pagefaults": {"major": "%F", "minor": "%R"}\n, "filesystem": {"inputs": "%I", "outputs": "%O"}\n, "time": {"real": "%e", "user": "%U", "sys": "%S"}\n}' \ + pwd diff --git a/.cicd/scripts/wm_test.sh b/.cicd/scripts/wm_test.sh new file mode 100755 index 0000000000..1377696730 --- /dev/null +++ b/.cicd/scripts/wm_test.sh @@ -0,0 +1,143 @@ +#!/bin/bash -x +set -eu +export UFS_PLATFORM=${UFS_PLATFORM:-${NODE_NAME,,}} +export UFS_COMPILER=${UFS_COMPILER:-intel} + +SCRIPT_REALPATH=$(realpath "${BASH_SOURCE[0]}") +SCRIPTS_DIR=$(dirname "${SCRIPT_REALPATH}") +UFS_MODEL_DIR=$(realpath "${SCRIPTS_DIR}/../..") +readonly UFS_MODEL_DIR +echo "UFS MODEL DIR: ${UFS_MODEL_DIR}" + +export CC=${CC:-mpicc} +export CXX=${CXX:-mpicxx} +export FC=${FC:-mpif90} + +BUILD_DIR=${BUILD_DIR:-${UFS_MODEL_DIR}/build} +TESTS_DIR=${TESTS_DIR:-${UFS_MODEL_DIR}/tests} + +( + cd "${TESTS_DIR}" + pwd + ls -al ./rt.sh +) + +export GIT_URL=${GIT_URL:-"ufs-weather-model"} +export CHANGE_ID=${CHANGE_ID:-"develop"} + +pwd +echo "GIT_URL=${GIT_URL}" +echo "CHANGE_ID=${CHANGE_ID}" +echo "NODE_NAME=${NODE_NAME}" +echo "USER=${USER}" +echo "UFS_PLATFORM=<${UFS_PLATFORM}>" +echo "UFS_COMPILER=<${UFS_COMPILER}>" +echo "WM_REGRESSION_TESTS=<${WM_REGRESSION_TESTS:-""}>" +echo "WM_OPERATIONAL_TESTS=<${WM_OPERATIONAL_TESTS:-""}>" +echo "WM_CREATE_BASELINE=<${WM_CREATE_BASELINE:-""}>" +echo "WM_POST_TEST_RESULTS=<${WM_POST_TEST_RESULTS:-""}>" + +machine=${NODE_NAME} +echo "machine=<${machine}>" +machine_id=${UFS_PLATFORM,,} +if [[ ${UFS_PLATFORM} =~ clusternoaa ]] ; then + machine_id="noaacloud" + #sed -i -e "s|EPIC/spack-stack/spack-stack-1.5.0|spack-stack/spack-stack-1.5.1|g" modulefiles/ufs_noaacloud.intel.lua +fi +echo "machine_id=<${machine_id}>" + +workspace=$(pwd) +export workspace + +status=0 + +ls -l build/ufs_model || : # just checking +status=$? + +[[ -n "${WM_REGRESSION_TESTS:-""}" ]] || WM_REGRESSION_TESTS=true # default +#[[ ${UFS_PLATFORM} == jet ]] && WM_REGRESSION_TESTS=false # takes too long +#[[ ${UFS_PLATFORM} == derecho ]] && WM_REGRESSION_TESTS=false +#[[ ${UFS_PLATFORM} =~ clusternoaa ]] && WM_REGRESSION_TESTS=false || : +export WM_REGRESSION_TESTS +[[ -n "${WM_CREATE_BASELINE:-""}" ]] || WM_CREATE_BASELINE=false # default +export WM_CREATE_BASELINE +[[ -n "${WM_POST_TEST_RESULTS:-""}" ]] || WM_POST_TEST_RESULTS=false # default +export WM_POST_TEST_RESULTS + +rm -f ${workspace}/wm_test_results-${UFS_PLATFORM}-${UFS_COMPILER}.txt + +if [[ ${WM_REGRESSION_TESTS} = true ]] ; then + echo "Pipeline Reqression Tests on ${UFS_PLATFORM} starting." + + export LMOD_SH_DBG_ON=0 + echo "LMOD_VERSION=${LMOD_VERSION}" + + set +x + if [[ ${UFS_PLATFORM} = orion ]] ; then + #module --ignore_cache load git/2.28.0 + git --version + git submodule update --init --recursive + fi + + if [[ ${UFS_PLATFORM} = gaea ]] ; then + source /gpfs/f5/epic/scratch/role.epic/contrib/Lmod_init_C5.sh + echo "LMOD_VERSION=${LMOD_VERSION}" + fi + + module use ${PWD}/modulefiles >/dev/null 2>&1 + module load ufs_${machine_id}.${UFS_COMPILER} || true + [[ ${UFS_PLATFORM} = gaea ]] && module load cmake/3.23.1 + module list + set -x + + echo "CHANGE_ID=${CHANGE_ID:-null}" + echo "ACCNR=${ACCNR}" + + [[ ! -f tests/logs/RegressionTests_${UFS_PLATFORM}.log ]] || mv tests/logs/RegressionTests_${UFS_PLATFORM}.log tests/logs/RegressionTests_${UFS_PLATFORM}.log.orig + + rm -f ${workspace}/${UFS_PLATFORM}-${UFS_COMPILER}-wm_*-log.txt + umask 002 + if [[ ${WM_CREATE_BASELINE} = true ]] ; then + echo "start Creating baseline on ${UFS_PLATFORM} ..." + ls -al .cicd/* + echo "Pipeline Creating Baseline Tests ${WM_OPERATIONAL_TESTS:=default} on ${UFS_PLATFORM} ${UFS_COMPILER}" + /usr/bin/time -p \ + -o ${workspace}/${UFS_PLATFORM}-${UFS_COMPILER}-time-wm_test.json \ + -f '{\n "cpu": "%P"\n, "memMax": "%M"\n, "mem": {"text": "%X", "data": "%D", "swaps": "%W", "context": "%c", "waits": "%w"}\n, "pagefaults": {"major": "%F", "minor": "%R"}\n, "filesystem": {"inputs": "%I", "outputs": "%O"}\n, "time": {"real": "%e", "user": "%U", "sys": "%S"}\n}' \ + ./.cicd/scripts/create_baseline.sh | tee -a ${workspace}/${UFS_PLATFORM}-${UFS_COMPILER}-wm_test-log.txt + status=${PIPESTATUS[0]} + echo "Pipeline Completed Baseline Tests ${WM_OPERATIONAL_TESTS} on ${UFS_PLATFORM} ${UFS_COMPILER}. status=${status}" + [[ ${WM_POST_TEST_RESULTS} = true ]] && ./.cicd/scripts/post_test_results.sh "${UFS_PLATFORM}" "BL" || echo "post test results seprately" + else + echo "skip Creating baseline on ${UFS_PLATFORM}." + ls -al .cicd/* + echo "Pipeline Running Regression Tests ${WM_OPERATIONAL_TESTS:=default} on ${UFS_PLATFORM} ${UFS_COMPILER}" + /usr/bin/time -p \ + -o ${workspace}/${UFS_PLATFORM}-${UFS_COMPILER}-time-wm_test.json \ + -f '{\n "cpu": "%P"\n, "memMax": "%M"\n, "mem": {"text": "%X", "data": "%D", "swaps": "%W", "context": "%c", "waits": "%w"}\n, "pagefaults": {"major": "%F", "minor": "%R"}\n, "filesystem": {"inputs": "%I", "outputs": "%O"}\n, "time": {"real": "%e", "user": "%U", "sys": "%S"}\n}' \ + ./.cicd/scripts/regression_test.sh | tee -a ${workspace}/${UFS_PLATFORM}-${UFS_COMPILER}-wm_test-log.txt + status=${PIPESTATUS[0]} + echo "Pipeline Completed Regression Tests ${WM_OPERATIONAL_TESTS} on ${UFS_PLATFORM} ${UFS_COMPILER}. status=${status}" + [[ ${WM_POST_TEST_RESULTS} = true ]] && ./.cicd/scripts/post_test_results.sh "${UFS_PLATFORM}" "RT" || echo "post test results seprately" + fi + + cd tests/ + pwd + ls -al . + ## Check for log files ... + ls -al logs/. + + ## Test Results ... + echo "ExperimentName: ${WM_OPERATIONAL_TESTS:=default}" | tee -a ${workspace}/${UFS_PLATFORM}-${UFS_COMPILER}-wm_test-log.txt | tee ${workspace}/wm_test_results-${UFS_PLATFORM}-${UFS_COMPILER}.txt + grep -E " DIRECTORY: |Time: | Completed: |Result: " logs/RegressionTests_${UFS_PLATFORM}.log | tee -a ${workspace}/wm_test_results-${UFS_PLATFORM}-${UFS_COMPILER}.txt + grep -E " -- COMPILE | -- TEST " logs/RegressionTests_${UFS_PLATFORM}.log | tee -a ${workspace}/wm_test_results-${UFS_PLATFORM}-${UFS_COMPILER}.txt + + cd ${workspace} + find ${workspace}/tests/logs -ls + echo "Pipeline Reqression Tests on ${UFS_PLATFORM} complete. status=${status}" +else + echo "Pipeline Regression Tests on ${UFS_PLATFORM} (${machine}) skipped." + echo "ExperimentName: null" > ${workspace}/wm_test_results-${UFS_PLATFORM}-${UFS_COMPILER}.txt +fi + +exit ${status} diff --git a/.github/linters/.python-lint b/.github/linters/.python-lint new file mode 100644 index 0000000000..748b19b49c --- /dev/null +++ b/.github/linters/.python-lint @@ -0,0 +1,473 @@ +[MASTER] +errors-only= + +# A comma-separated list of package or module names from where C extensions may +# be loaded. Extensions are loading into the active Python interpreter and may +# run arbitrary code +extension-pkg-whitelist= + +# Add files or directories to the blacklist. They should be base names, not +# paths. +ignore=CVS + +# Add files or directories matching the regex patterns to the blacklist. The +# regex matches against base names, not paths. +ignore-patterns= + +# Python code to execute, usually for sys.path manipulation such as +# pygtk.require(). +#init-hook= + +# Use multiple processes to speed up Pylint. +jobs=1 + +# List of plugins (as comma separated values of python modules names) to load, +# usually to register additional checkers. +load-plugins= + +# Pickle collected data for later comparisons. +persistent=yes + +# Specify a configuration file. +#rcfile= + +# When enabled, pylint would attempt to guess common misconfiguration and emit +# user-friendly hints instead of false-positive error messages +suggestion-mode=yes + +# Allow loading of arbitrary C extensions. Extensions are imported into the +# active Python interpreter and may run arbitrary code. +unsafe-load-any-extension=no + + +[MESSAGES CONTROL] + +# Only show warnings with the listed confidence levels. Leave empty to show +# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED +confidence= + +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifiers separated by comma (,) or put this +# option multiple times (only on the command line, not in the configuration +# file where it should appear only once).You can also use "--disable=all" to +# disable everything first and then reenable specific checks. For example, if +# you want to run only the similarities checker, you can use "--disable=all +# --enable=similarities". If you want to run only the classes checker, but have +# no Warning level messages displayed, use"--disable=all --enable=classes +# --disable=W" +disable=raw-checker-failed, + bad-inline-option, + locally-disabled, + file-ignored, + suppressed-message, + useless-suppression, + deprecated-pragma, + E0401, + +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time (only on the command line, not in the configuration file where +# it should appear only once). See also the "--disable" option for examples. +enable=c-extension-no-member + + +[REPORTS] + +# Python expression which should return a note less than 10 (10 is the highest +# note). You have access to the variables errors warning, statement which +# respectively contain the number of errors / warnings messages and the total +# number of statements analyzed. This is used by the global evaluation report +# (RP0004). +evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) + +# Template used to display messages. This is a python new-style format string +# used to format the message information. See doc for all details +#msg-template= + +# Set the output format. Available formats are text, parseable, colorized, json +# and msvs (visual studio).You can also give a reporter class, eg +# mypackage.mymodule.MyReporterClass. +output-format=text + +# Tells whether to display a full report or only the messages +reports=no + +# Activate the evaluation score. +score=no + + +[REFACTORING] + +# Maximum number of nested blocks for function / method body +max-nested-blocks=5 + +# Complete name of functions that never returns. When checking for +# inconsistent-return-statements if a never returning function is called then +# it will be considered as an explicit return statement and no message will be +# printed. +never-returning-functions=optparse.Values,sys.exit + + +[VARIABLES] + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid to define new builtins when possible. +additional-builtins= + +# Tells whether unused global variables should be treated as a violation. +allow-global-unused-variables=yes + +# List of strings which can identify a callback function by name. A callback +# name must start or end with one of those strings. +callbacks=cb_, + _cb + +# A regular expression matching the name of dummy variables (i.e. expectedly +# not used). +dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ + +# Argument names that match this expression will be ignored. Default to name +# with leading underscore +ignored-argument-names=_.*|^ignored_|^unused_ + +# Tells whether we should check for unused import in __init__ files. +init-import=no + +# List of qualified module names which can have objects that can redefine +# builtins. +redefining-builtins-modules=six.moves,past.builtins,future.builtins + + +[LOGGING] + +# Logging modules to check that the string format arguments are in logging +# function parameter format +logging-modules=logging + + +[TYPECHECK] + +# List of decorators that produce context managers, such as +# contextlib.contextmanager. Add to this list to register other decorators that +# produce valid context managers. +contextmanager-decorators=contextlib.contextmanager + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E1101 when accessed. Python regular +# expressions are accepted. +generated-members= + +# Tells whether missing members accessed in mixin class should be ignored. A +# mixin class is detected if its name ends with "mixin" (case insensitive). +ignore-mixin-members=yes + +# This flag controls whether pylint should warn about no-member and similar +# checks whenever an opaque object is returned when inferring. The inference +# can return multiple potential results while evaluating a Python object, but +# some branches might not be evaluated, which results in partial inference. In +# that case, it might be useful to still emit no-member and other checks for +# the rest of the inferred objects. +ignore-on-opaque-inference=yes + +# List of class names for which member attributes should not be checked (useful +# for classes with dynamically set attributes). This supports the use of +# qualified names. +ignored-classes=optparse.Values,thread._local,_thread._local + +# List of module names for which member attributes should not be checked +# (useful for modules/projects where namespaces are manipulated during runtime +# and thus existing member attributes cannot be deduced by static analysis. It +# supports qualified module names, as well as Unix pattern matching. +ignored-modules= + +# Show a hint with possible names when a member name was not found. The aspect +# of finding the hint is based on edit distance. +missing-member-hint=yes + +# The minimum edit distance a name should have in order to be considered a +# similar match for a missing member name. +missing-member-hint-distance=1 + +# The total number of similar names that should be taken in consideration when +# showing a hint for a missing member. +missing-member-max-choices=1 + + +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +notes=FIXME, + XXX, + TODO + + +[BASIC] + +# Naming style matching correct argument names +argument-naming-style=snake_case + +# Regular expression matching correct argument names. Overrides argument- +# naming-style +#argument-rgx= + +# Naming style matching correct attribute names +attr-naming-style=snake_case + +# Regular expression matching correct attribute names. Overrides attr-naming- +# style +#attr-rgx= + +# Bad variable names which should always be refused, separated by a comma +bad-names=foo, + bar, + baz, + toto, + tutu, + tata + +# Naming style matching correct class attribute names +class-attribute-naming-style=any + +# Regular expression matching correct class attribute names. Overrides class- +# attribute-naming-style +#class-attribute-rgx= + +# Naming style matching correct class names +class-naming-style=PascalCase + +# Regular expression matching correct class names. Overrides class-naming-style +#class-rgx= + +# Naming style matching correct constant names +const-naming-style=UPPER_CASE + +# Regular expression matching correct constant names. Overrides const-naming- +# style +#const-rgx= + +# Minimum line length for functions/classes that require docstrings, shorter +# ones are exempt. +docstring-min-length=-1 + +# Naming style matching correct function names +function-naming-style=snake_case + +# Regular expression matching correct function names. Overrides function- +# naming-style +#function-rgx= + +# Good variable names which should always be accepted, separated by a comma +good-names=i, + j, + k, + ex, + Run, + _ + +# Include a hint for the correct naming format with invalid-name +include-naming-hint=no + +# Naming style matching correct inline iteration names +inlinevar-naming-style=any + +# Regular expression matching correct inline iteration names. Overrides +# inlinevar-naming-style +#inlinevar-rgx= + +# Naming style matching correct method names +method-naming-style=snake_case + +# Regular expression matching correct method names. Overrides method-naming- +# style +#method-rgx= + +# Naming style matching correct module names +module-naming-style=snake_case + +# Regular expression matching correct module names. Overrides module-naming- +# style +#module-rgx= + +# Colon-delimited sets of names that determine each other's naming style when +# the name regexes allow several styles. +name-group= + +# Regular expression which should only match function or class names that do +# not require a docstring. +no-docstring-rgx=^_ + +# List of decorators that produce properties, such as abc.abstractproperty. Add +# to this list to register other decorators that produce valid properties. +property-classes=abc.abstractproperty + +# Naming style matching correct variable names +variable-naming-style=snake_case + +# Regular expression matching correct variable names. Overrides variable- +# naming-style +#variable-rgx= + + +[SPELLING] + +# Limits count of emitted suggestions for spelling mistakes +max-spelling-suggestions=4 + +# Spelling dictionary name. Available dictionaries: none. To make it working +# install python-enchant package. +spelling-dict= + +# List of comma separated words that should not be checked. +spelling-ignore-words= + +# A path to a file that contains private dictionary; one word per line. +spelling-private-dict-file= + +# Tells whether to store unknown words to indicated private dictionary in +# --spelling-private-dict-file option instead of raising a message. +spelling-store-unknown-words=no + + +[FORMAT] + +# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. +expected-line-ending-format= + +# Regexp for a line that is allowed to be longer than the limit. +ignore-long-lines=^\s*(# )??$ + +# Number of spaces of indent required inside a hanging or continued line. +indent-after-paren=4 + +# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 +# tab). +indent-string=' ' + +# Maximum number of characters on a single line. +max-line-length=150 + +# Maximum number of lines in a module +max-module-lines=1000 + +# Allow the body of a class to be on the same line as the declaration if body +# contains single statement. +single-line-class-stmt=no + +# Allow the body of an if to be on the same line as the test if there is no +# else. +single-line-if-stmt=no + + +[SIMILARITIES] + +# Ignore comments when computing similarities. +ignore-comments=yes + +# Ignore docstrings when computing similarities. +ignore-docstrings=yes + +# Ignore imports when computing similarities. +ignore-imports=no + +# Minimum lines number of a similarity. +min-similarity-lines=4 + + +[DESIGN] + +# Maximum number of arguments for function / method +max-args=5 + +# Maximum number of attributes for a class (see R0902). +max-attributes=7 + +# Maximum number of boolean expressions in a if statement +max-bool-expr=5 + +# Maximum number of branch for function / method body +max-branches=12 + +# Maximum number of locals for function / method body +max-locals=15 + +# Maximum number of parents for a class (see R0901). +max-parents=7 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=20 + +# Maximum number of return / yield for function / method body +max-returns=6 + +# Maximum number of statements in function / method body +max-statements=50 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=2 + + +[IMPORTS] + +# Allow wildcard imports from modules that define __all__. +allow-wildcard-with-all=no + +# Analyse import fallback blocks. This can be used to support both Python 2 and +# 3 compatible code, which means that the block might have code that exists +# only in one or another interpreter, leading to false positives when analysed. +analyse-fallback-blocks=no + +# Deprecated modules which should not be used, separated by a comma +deprecated-modules=regsub, + TERMIOS, + Bastion, + rexec + +# Create a graph of external dependencies in the given file (report RP0402 must +# not be disabled) +ext-import-graph= + +# Create a graph of every (i.e. internal and external) dependencies in the +# given file (report RP0402 must not be disabled) +import-graph= + +# Create a graph of internal dependencies in the given file (report RP0402 must +# not be disabled) +int-import-graph= + +# Force import order to recognize a module as part of the standard +# compatibility libraries. +known-standard-library= + +# Force import order to recognize a module as part of a third party library. +known-third-party=enchant + + +[CLASSES] + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__, + __new__, + setUp + +# List of member names, which should be excluded from the protected access +# warning. +exclude-protected=_asdict, + _fields, + _replace, + _source, + _make + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg=cls + +# List of valid names for the first argument in a metaclass class method. +valid-metaclass-classmethod-first-arg=mcs + + +[EXCEPTIONS] + +# Exceptions that will emit a warning when being caught. Defaults to +# "Exception" +overgeneral-exceptions=builtins.Exception + + diff --git a/.github/linters/.yaml-lint.yml b/.github/linters/.yaml-lint.yml new file mode 100644 index 0000000000..afcac43957 --- /dev/null +++ b/.github/linters/.yaml-lint.yml @@ -0,0 +1,28 @@ +--- + +extends: default + +rules: + braces: + level: warning + max-spaces-inside: 1 + brackets: + level: warning + max-spaces-inside: 1 + colons: + level: warning + commas: disable + comments: disable + comments-indentation: disable + document-start: disable + empty-lines: + level: warning + hyphens: + level: warning + indentation: + level: warning + indent-sequences: consistent + line-length: disable + truthy: disable + trailing-spaces: disable + diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index f287387a35..1c2f4ee990 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -42,6 +42,7 @@ Please delete what is not needed. * MOM6 - * NOAHMP - * WW3 - + * fire_behavior * stochastic_physics - ``` @@ -89,6 +90,7 @@ Example: * MOM6: * NOAHMP: * WW3: +* fire_behavior: * stochastic_physics: * None @@ -144,10 +146,11 @@ Please delete what is not needed. - [ ] Orion - [ ] Hercules - [ ] Jet - - [ ] Gaea + - [ ] GaeaC5 + - [ ] GaeaC6 - [ ] Derecho - WCOSS2 - [ ] Dogwood/Cactus - [ ] Acorn - [ ] CI -- [ ] opnReqTest (complete task if unnecessary) \ No newline at end of file +- [ ] opnReqTest (complete task if unnecessary) diff --git a/.github/workflows/aux.yml b/.github/workflows/aux.yml index 49449097a3..816c7fc28b 100644 --- a/.github/workflows/aux.yml +++ b/.github/workflows/aux.yml @@ -18,43 +18,42 @@ jobs: runs-on: ubuntu-20.04 steps: - - name: Share helper id - run: echo -n ${{ github.run_id }} >~/id_file + - name: Share helper id + run: echo -n ${{ github.run_id }} >~/id_file - - uses: actions/cache@v2 - with: - path: ~/id_file - key: helperid-${{ github.event.workflow_run.id }} + - uses: actions/cache@v4 + with: + path: ~/id_file + key: helperid-${{ github.event.workflow_run.id }} repocheck: name: Repo check runs-on: ubuntu-20.04 steps: - - name: Check up-to-dateness and post comment - run: | - trap 'echo "exit-code=$?" >> "$GITHUB_OUTPUT"' EXIT - head_sha=${{ github.event.pull_request.head.sha }} - head_brc=${{ github.event.pull_request.head.ref }} - head_url=${{ github.event.pull_request.head.repo.html_url }} - git clone -q -b $head_brc $head_url . - git checkout -q $head_sha - git submodule -q update --init --recursive - cd ${{ github.workspace }}/tests/ci - url=$GITHUB_API_URL/repos/$GITHUB_REPOSITORY - pr_number=$(curl -sS -H $app $url/pulls \ - | jq -r '.[] | select(.head.sha == "'"$head_sha"'") | .number') - echo "pr_number is $pr_number" - pr_uid=${{ github.event.pull_request.head.repo.owner.login }} - echo "pr_uid is $pr_uid" - ./repo_check.sh - #comment="$(./repo_check.sh 2>/dev/null)" - #echo "comment is $comment" - #if [[ -n $comment ]]; then - # curl -sS -X POST -H $app -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ - # $url/issues/$pr_number/comments -d '{"body": "'"${comment}"'"}' - # echo -n "failure" >~/repocheck_file - #else - # echo -n "success" >~/repocheck_file - #fi - + - name: Check up-to-dateness and post comment + run: | + trap 'echo "exit-code=$?" >> "$GITHUB_OUTPUT"' EXIT + head_sha=${{ github.event.pull_request.head.sha }} + head_brc=${{ github.event.pull_request.head.ref }} + head_url=${{ github.event.pull_request.head.repo.html_url }} + git clone -q -b $head_brc $head_url . + git checkout -q $head_sha + git submodule -q update --init --recursive + cd ${{ github.workspace }}/tests/ci + url=$GITHUB_API_URL/repos/$GITHUB_REPOSITORY + pr_number=$(curl -sS -H $app $url/pulls \ + | jq -r '.[] | select(.head.sha == "'"$head_sha"'") | .number') + echo "pr_number is $pr_number" + pr_uid=${{ github.event.pull_request.head.repo.owner.login }} + echo "pr_uid is $pr_uid" + ./repo_check.sh + #comment="$(./repo_check.sh 2>/dev/null)" + #echo "comment is $comment" + #if [[ -n $comment ]]; then + # curl -sS -X POST -H $app -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ + # $url/issues/$pr_number/comments -d '{"body": "'"${comment}"'"}' + # echo -n "failure" >~/repocheck_file + #else + # echo -n "success" >~/repocheck_file + #fi diff --git a/.github/workflows/build_test.yml b/.github/workflows/build_test._yml similarity index 93% rename from .github/workflows/build_test.yml rename to .github/workflows/build_test._yml index 94df20a235..21de1f26bc 100644 --- a/.github/workflows/build_test.yml +++ b/.github/workflows/build_test._yml @@ -16,12 +16,12 @@ jobs: current: ${{ steps.check.outputs.current }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Wait for caching source run: sleep 30 - - uses: actions/cache@v2 + - uses: actions/cache@v4 with: path: ~/id_file key: helperid-${{ github.run_id }} diff --git a/.github/workflows/superlinter.yml b/.github/workflows/superlinter.yml index 4b1ffea8d2..a3d92fc835 100644 --- a/.github/workflows/superlinter.yml +++ b/.github/workflows/superlinter.yml @@ -24,7 +24,7 @@ jobs: - name: Super-Linter uses: super-linter/super-linter@v6.3.0 env: - LINTER_RULES_PATH: / + LINTER_RULES_PATH: '.github/linters/' DEFAULT_BRANCH: origin/develop GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} FILTER_REGEX_EXCLUDE: .*(tests/fv3_conf/.*|tests/ci/.*|tests/auto/.*|tests/auto-jenkins/.*|tests/opnReqTests/.*|tests/opnReqTest|tests/atparse.bash).* @@ -33,5 +33,5 @@ jobs: #VALIDATE_GITHUB_ACTIONS: true #VALIDATE_LUA: true #VALIDATE_MARKDOWN: true - #VALIDATE_PYTHON_PYLINT: true - #VALIDATE_YAML: true + VALIDATE_PYTHON_PYLINT: true + VALIDATE_YAML: true diff --git a/.gitignore b/.gitignore index bf7d81b1c6..ef8248e775 100644 --- a/.gitignore +++ b/.gitignore @@ -72,9 +72,13 @@ tests/fv3_conf/compile_slurm.IN tests/fv3_conf/compile_qsub.IN tests/fv3_conf/fv3_slurm.IN tests/fv3_conf/fv3_qsub.IN +tests/rt_temp.conf build*.log* rocoto_workflow* fail_compile_* fail_test_* tests/run_dir tests/logs/log_* +compile_0_time.log +tests/modules.ufs_model.lua +tests/ufs_common.lua diff --git a/.gitmodules b/.gitmodules index 2e3ddb38c3..02c2dad4d5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,8 +4,8 @@ branch = global-workflow [submodule "WW3"] path = WW3 - url = https://github.com/NOAA-EMC/WW3 - branch = dev/ufs-weather-model + url = https://github.com/kayeekayee/ww3.git + branch = 2025Feb05_8e67627 [submodule "stochastic_physics"] path = stochastic_physics url = https://github.com/NOAA-PSL/stochastic_physics @@ -28,8 +28,8 @@ branch = dev/emc [submodule "CICE"] path = CICE-interface/CICE - url = https://github.com/NOAA-EMC/CICE - branch = emc/develop + url = https://github.com/kayeekayee/CICE.git + branch = 2024Dec11_ff7fd7 [submodule "CDEPS"] path = CDEPS-interface/CDEPS url = https://github.com/NOAA-EMC/CDEPS @@ -46,3 +46,11 @@ path = NOAHMP-interface/noahmp url = https://github.com/NOAA-EMC/noahmp branch = develop +[submodule "LM4-driver"] + path = LM4-driver + url = https://github.com/NOAA-GFDL/LM4-NUOPC-driver + branch = develop +[submodule "fire_behavior"] + path = fire_behavior + url = https://github.com/NOAA-EMC/fire_behavior + branch = emc/develop diff --git a/CDEPS-interface/CDEPS b/CDEPS-interface/CDEPS deleted file mode 160000 index fbdf6843d6..0000000000 --- a/CDEPS-interface/CDEPS +++ /dev/null @@ -1 +0,0 @@ -Subproject commit fbdf6843d6bde852d97f1547591d90136103f669 diff --git a/CDEPS-interface/CDEPS/.github/PULL_REQUEST_TEMPLATE.md b/CDEPS-interface/CDEPS/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000000..678ad8b537 --- /dev/null +++ b/CDEPS-interface/CDEPS/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,18 @@ +### Description of changes + +### Specific notes + +Contributors other than yourself, if any: + +CDEPS Issues Fixed (include github issue #): + +Are there dependencies on other component PRs (if so list): + +Are changes expected to change answers (bfb, different to roundoff, more substantial): + +Any User Interface Changes (namelist or namelist defaults changes): + +Testing performed (e.g. aux_cdeps, CESM prealpha, etc): + +Hashes used for testing: + diff --git a/CDEPS-interface/CDEPS/.github/workflows/bumpversion.yml b/CDEPS-interface/CDEPS/.github/workflows/bumpversion.yml new file mode 100644 index 0000000000..0094d46d68 --- /dev/null +++ b/CDEPS-interface/CDEPS/.github/workflows/bumpversion.yml @@ -0,0 +1,19 @@ +name: Bump version +on: + push: + branches: + - main +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Bump version and push tag + id: tag_version + uses: mathieudutour/github-tag-action@v5.5 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + create_annotated_tag: true + default_bump: patch + dry_run: false + tag_prefix: cdeps diff --git a/CDEPS-interface/CDEPS/.github/workflows/extbuild.yml b/CDEPS-interface/CDEPS/.github/workflows/extbuild.yml new file mode 100644 index 0000000000..185f6d85d0 --- /dev/null +++ b/CDEPS-interface/CDEPS/.github/workflows/extbuild.yml @@ -0,0 +1,79 @@ +# This is a workflow to compile the cdeps source without cime +name: extbuild +# Controls when the action will run. Triggers the workflow on push or pull request +# events but only for the main branch +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + build-cdeps: + runs-on: ubuntu-latest + env: + CC: mpicc + FC: mpifort + CXX: mpicxx + CPPFLAGS: "-I/usr/include -I/usr/local/include " + LDFLAGS: "-L/usr/lib/x86_64-linux-gnu " + # Versions of all dependencies can be updated here - these match tag names in the github repo + ESMF_VERSION: v8.6.1 + ParallelIO_VERSION: pio2_6_2 + steps: + - id: checkout-CDEPS + uses: actions/checkout@v4 + with: + submodules: recursive + - id: load-env + run: | + sudo apt-get update + sudo apt-get install gfortran + sudo apt-get install wget + sudo apt-get install openmpi-bin libopenmpi-dev + sudo apt-get install netcdf-bin libnetcdf-dev libnetcdff-dev + sudo apt-get install pnetcdf-bin libpnetcdf-dev + sudo apt-get install autotools-dev autoconf + - name: Cache PARALLELIO + id: cache-PARALLELIO + uses: actions/cache@v4 + with: + path: ${GITHUB_WORKSPACE}/pio + key: ${{ runner.os }}-${{ env.ParallelIO_VERSION }}-parallelio2 + - name: Build ParallelIO + if: steps.cache-PARALLELIO.outputs.cache-hit != 'true' + uses: NCAR/ParallelIO/.github/actions/parallelio_cmake@9390e30e29d4ebbfbef0fc72162cacd9e8f25e4e + with: + parallelio_version: ${{ env.ParallelIO_VERSION }} + enable_fortran: True + install_prefix: ${GITHUB_WORKSPACE}/pio + - name: Install ESMF + uses: esmf-org/install-esmf-action@v1 + env: + ESMF_COMPILER: gfortran + ESMF_BOPT: g + ESMF_COMM: openmpi + ESMF_NETCDF: nc-config + ESMF_PNETCDF: pnetcdf-config + ESMF_INSTALL_PREFIX: ${GITHUB_WORKSPACE}/ESMF + ESMF_PIO: external + ESMF_PIO_INCLUDE: ${GITHUB_WORKSPACE}/pio/include + ESMF_PIO_LIBPATH: ${GITHUB_WORKSPACE}/pio/lib + with: + version: ${{ env.ESMF_VERSION }} + esmpy: false + cache: true + + - name: Build CDEPS + uses: ./.github/actions/buildcdeps + with: + esmfmkfile: $ESMFMKFILE + pio_path: ${GITHUB_WORKSPACE}/pio + src_root: ${GITHUB_WORKSPACE} + cmake_flags: " -Wno-dev -DCMAKE_BUILD_TYPE=DEBUG -DWERROR=ON -DCMAKE_Fortran_FLAGS=\"-DCPRGNU -g -Wall \ + -ffree-form -ffree-line-length-none -fallow-argument-mismatch \"" + - name: Test CDEPS + run: | + cd build-cdeps + make VERBOSE=1 diff --git a/CDEPS-interface/CDEPS/.gitignore b/CDEPS-interface/CDEPS/.gitignore new file mode 100644 index 0000000000..625692541d --- /dev/null +++ b/CDEPS-interface/CDEPS/.gitignore @@ -0,0 +1,39 @@ +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +# Externals +fox +share/genf90 + +# ignore pycache +__pycache__ diff --git a/CDEPS-interface/CDEPS/.gitmodules b/CDEPS-interface/CDEPS/.gitmodules new file mode 100644 index 0000000000..45cad096cc --- /dev/null +++ b/CDEPS-interface/CDEPS/.gitmodules @@ -0,0 +1,3 @@ +# This is a git-fleximod adapted .gitmodules file. Any field with a name starting in fx is a git-fleximod +# specific field. See https://github.com/ESMCI/git-fleximod for details. + diff --git a/CDEPS-interface/CDEPS/CMakeLists.txt b/CDEPS-interface/CDEPS/CMakeLists.txt new file mode 100644 index 0000000000..a4e0aa82e8 --- /dev/null +++ b/CDEPS-interface/CDEPS/CMakeLists.txt @@ -0,0 +1,128 @@ +cmake_minimum_required(VERSION 3.10) +include(ExternalProject) +include(FetchContent) + +set(DISABLE_FoX OFF CACHE BOOL "Disable FoX library to process XML files.") +message("DISABLE_FoX = ${DISABLE_FoX}") +if(DISABLE_FoX) + add_definitions(-DDISABLE_FoX) +endif() + +if (DEFINED CIMEROOT) + message("Using CIME in ${CIMEROOT} with compiler ${COMPILER}") + include(${CASEROOT}/Macros.cmake) + if (${PIO_VERSION} LESS 2) + message( FATAL_ERROR "Version 2 of the PIO library required") + endif() + if (MPILIB STREQUAL mpi-serial) + set(CMAKE_Fortran_COMPILER ${SFC}) + set(CMAKE_C_COMPILER ${SCC}) + else() + set(CMAKE_Fortran_COMPILER ${MPIFC}) + set(CMAKE_C_COMPILER ${MPICC}) + endif() + set(CMAKE_Fortran_FLAGS "${FFLAGS} ${CPPDEFS} -I${LIBROOT}/include -I${LIBROOT}/nuopc/esmf/${NINST_VALUE}/include") + add_compile_definitions(CESMCOUPLED) + list(APPEND CMAKE_MODULE_PATH ${SRC_ROOT}/components/cdeps/cmake) + set(FOX_ROOT ${SRC_ROOT}/components/cdeps/fox) +else() + set(BLD_STANDALONE TRUE) + project(NUOPC_DATA_MODELS LANGUAGES Fortran VERSION 0.1) + list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) + if(NOT DISABLE_FoX) + set(FOX_ROOT ${CMAKE_SOURCE_DIR}/fox) + endif() +endif() +message("CMAKE_MODULE_PATH is ${CMAKE_MODULE_PATH}, CMAKE_Fortran_COMPILER is ${CMAKE_Fortran_COMPILER}") +enable_language(Fortran) + +if (TARGET esmf) + message("Target esmf is already found. Skip find_package ...") +else() + find_package(ESMF REQUIRED) +endif() + +option(WERROR "add the -Werror flag to compiler (works with gcc and intel)" OFF) + + +if (DEFINED ENV{PIO_ROOT}) + message("PIO_ROOT is $ENV{PIO_ROOT}") +else() + if (DEFINED PIO) + set(PIO_PATH ${PIO}) + else() + set(PIO_PATH $ENV{PIO}) + endif() + find_package(PIO REQUIRED COMPONENT C Fortran PATH ${PIO_PATH}) +endif() + +if (NOT DEFINED MPILIB OR NOT ${MPILIB} STREQUAL "mpi-serial") + find_package(MPI REQUIRED) +endif() + +if(BLD_STANDALONE) + add_subdirectory(share) + list(APPEND EXTRA_LIBS cdeps_share) +endif() +if("${COMPILER}" STREQUAL "nag") + set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -D__NAG__") +endif() +add_subdirectory(streams) +add_subdirectory(dshr) + +if(NOT DISABLE_FoX) + add_subdirectory(fox) + + target_include_directories(streams PUBLIC $ + $) + target_include_directories(dshr PUBLIC $ + $) +endif() + +target_include_directories(dshr PUBLIC $ + $) + +foreach(COMP datm dice dglc dlnd docn drof dwav) + add_subdirectory("${COMP}") + if(BLD_STANDALONE) + target_include_directories(${COMP} PUBLIC $ + $) + endif() + target_include_directories(${COMP} PUBLIC $ + $) + target_include_directories(${COMP} PUBLIC $ + $) + + if(WERROR) + target_compile_options(${COMP} PRIVATE -Werror --warn-no-unused-dummy-argument --warn-no-missing-include-dirs) + endif() + install(TARGETS ${COMP} + EXPORT ${COMP} + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + COMPONENT Library) + install(EXPORT ${COMP} + DESTINATION lib/cmake) +endforeach(COMP) + +foreach(DEPS streams dshr cdeps_share FoX_dom FoX_wxml FoX_sax FoX_common FoX_utils FoX_fsys) + if(DISABLE_FoX AND ${DEPS} MATCHES "^FoX") + continue() + endif() + if(NOT BLD_STANDALONE AND ${DEPS} STREQUAL "cdeps_share") + continue() + endif() + string(SUBSTRING ${DEPS} 0 3 fox) + if(WERROR AND NOT ${fox} STREQUAL "FoX") + message("Adding Werror flag to ${DEPS} (fox = ${fox})") + target_compile_options(${DEPS} PRIVATE -Werror --warn-no-unused-dummy-argument --warn-no-missing-include-dirs) + endif() + + install(TARGETS ${DEPS} + EXPORT ${DEPS} + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + COMPONENT Library) + install(EXPORT ${DEPS} + DESTINATION lib/cmake) +endforeach(DEPS) diff --git a/CDEPS-interface/CDEPS/Externals_CDEPS.cfg b/CDEPS-interface/CDEPS/Externals_CDEPS.cfg new file mode 100644 index 0000000000..ac2839ed9f --- /dev/null +++ b/CDEPS-interface/CDEPS/Externals_CDEPS.cfg @@ -0,0 +1,16 @@ +[fox] +tag = 4.1.2.1 +protocol = git +repo_url = https://github.com/ESMCI/fox.git +local_path = fox +required = True + +[genf90] +tag = 4816965 +protocol = git +repo_url = https://github.com/PARALLELIO/genf90 +local_path = share/genf90 +required = True + +[externals_description] +schema_version = 1.0.0 diff --git a/CDEPS-interface/CDEPS/README.md b/CDEPS-interface/CDEPS/README.md new file mode 100644 index 0000000000..00da8d28c5 --- /dev/null +++ b/CDEPS-interface/CDEPS/README.md @@ -0,0 +1,14 @@ +# CDEPS +Community Data Models for Earth Prediction Systems + +For documentation see + +https://escomp.github.io/CDEPS/versions/master/html/index.html + +## A note on github tag action + +This repository is setup to automatically create tags on merge to +main using .github/workflows/bumpversion.yml It uses +https://github.com/mathieudutour/github-tag-action to look for +keywords in commit messages and determine what the new version should +be. The default if no keywords is found is to bump the patch version. diff --git a/CDEPS-interface/CDEPS/cime_config/buildlib b/CDEPS-interface/CDEPS/cime_config/buildlib new file mode 100755 index 0000000000..536bdae661 --- /dev/null +++ b/CDEPS-interface/CDEPS/cime_config/buildlib @@ -0,0 +1,231 @@ +#!/usr/bin/env python3 +""" +build cime component model library. This buildlib script is used by all CDEPS components. +""" + +import sys, os, time + +_CIMEROOT = os.environ.get("CIMEROOT") +if _CIMEROOT is None: + raise SystemExit("ERROR: must set CIMEROOT environment variable") +sys.path.append(os.path.join(_CIMEROOT, "CIME", "Tools")) + +_LIBDIR = os.path.join(_CIMEROOT) +sys.path.append(_LIBDIR) + +from standard_script_setup import * +from CIME.case import Case +from CIME.utils import run_cmd, symlink_force, expect +from CIME.build import get_standard_cmake_args + +# pylint: disable=undefined-variable +logger = logging.getLogger(__name__) + + +def parse_command_line(args, description): + ############################################################################### + parser = argparse.ArgumentParser( + usage="""\n{0} [--debug] +OR +{0} --verbose +OR +{0} --help + +\033[1mEXAMPLES:\033[0m + \033[1;32m# Run \033[0m + > {0} +""".format( + os.path.basename(args[0]) + ), + description=description, + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + ) + + CIME.utils.setup_standard_logging_options(parser) + + parser.add_argument("buildroot", help="build path root") + + parser.add_argument("installpath", help="install path ") + + parser.add_argument( + "caseroot", nargs="?", default=os.getcwd(), help="Case directory to build" + ) + + args = CIME.utils.parse_args_and_handle_standard_logging_options(args, parser) + + return args.buildroot, args.installpath, args.caseroot + + +def buildlib(bldroot, libroot, case): + expect( + not bldroot.endswith("obj"), + "It appears that the main CDEPS buildlib is being called for a specific component\n" + "(specific data model components should use buildlib_comps)", + ) + + if case.get_value("DEBUG"): + strdebug = "debug" + else: + strdebug = "nodebug" + if case.get_value("BUILD_THREADED"): + strthread = "threads" + else: + strthread = "nothreads" + mpilib = case.get_value("MPILIB") + compiler = case.get_value("COMPILER") + sharedpath = os.path.join(compiler, mpilib, strdebug, strthread) + sharedroot = case.get_value("SHAREDLIBROOT") + cdepsblddir = os.path.join(sharedroot, sharedpath, "CDEPS") + + logger.info("Running cmake for CDEPS") + srcpath = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir)) + cmake_flags = get_standard_cmake_args(case, os.path.join(sharedpath, "cdeps")) + # base path of install to be completed by setting DESTDIR in make install + cmake_flags += " -DCMAKE_INSTALL_PREFIX:PATH=/" + cmake_flags += " -DLIBROOT={} ".format(libroot) + cmake_flags += " -DMPILIB={} ".format(mpilib) + cmake_flags += " -DSRCROOT={} ".format(case.get_value("SRCROOT")) + if compiler == "gnu" and strdebug == "debug": + cmake_flags += " -DWERROR=ON " + piolibdir = os.getenv("PIO_LIBDIR") + if piolibdir: + pioincdir = os.getenv("PIO_INCDIR") + logger.info(f"Using installed pio {piolibdir} {pioincdir}") + cmake_flags += " -DPIO_C_LIBRARY={libdir} -DPIO_C_INCLUDE_DIR={incdir} ".format( + libdir=piolibdir, incdir=pioincdir + ) + cmake_flags += " -DPIO_Fortran_LIBRARY={libdir} -DPIO_Fortran_INCLUDE_DIR={incdir} ".format( + libdir=piolibdir, incdir=pioincdir + ) + else: + cmake_flags += ( + " -DPIO_C_LIBRARY={path}/lib -DPIO_C_INCLUDE_DIR={path}/include ".format( + path=os.path.join(case.get_value("EXEROOT"), sharedpath) + ) + ) + cmake_flags += " -DPIO_Fortran_LIBRARY={path}/lib -DPIO_Fortran_INCLUDE_DIR={path}/include ".format( + path=os.path.join(case.get_value("EXEROOT"), sharedpath) + ) + cmake_flags += srcpath + all_src_files = list( + all_files_under( + srcpath, + ignoredirs=[".git", "cmake", "test", ".github", "cime_config", "fox"], + ) + ) + # Search SourceMods path for CDEPS files. We only look in the data component directories for these, files in cdeps share + # directories should be added to one of the data component directories + srcmodsdir = os.path.join(case.get_value("CASEROOT"), "SourceMods") + all_files_in_srcmods = [] + for comp_class in case.get_values("COMP_CLASSES"): + if comp_class == "CPL": + continue + comp = case.get_value("COMP_{}".format(comp_class)) + cdeps_comp_name = "d" + comp_class.lower() + if comp == cdeps_comp_name: + all_files_in_srcmods.extend( + list( + all_files_under(os.path.join(srcmodsdir, "src." + cdeps_comp_name)) + ) + ) + + basenames1 = [os.path.basename(f) for f in all_src_files] + basenames2 = [os.path.basename(f) for f in all_files_in_srcmods] + srcmods = list(set(basenames1).intersection(set(basenames2))) + if srcmods: + logger.info("Found SourceMods {}".format(srcmods)) + for i, v in enumerate(all_src_files): + for sfile in all_files_in_srcmods: + if os.path.basename(sfile) == os.path.basename(v): + all_src_files[i] = v.replace( + os.path.dirname(v), os.path.dirname(sfile) + ) + logger.debug("all_src_files: {}".format(all_src_files)) + latest_src_file = max(all_src_files, key=os.path.getmtime) + + src_time = os.path.getmtime(latest_src_file) + if os.path.exists(os.path.join(bldroot, "CMakeFiles")): + bld_time = os.path.getmtime(os.path.join(bldroot, "CMakeFiles")) + else: + bld_time = src_time - 1 + + # Make sure that no other process is currently trying to build this library, done with a simple lockfile + if os.path.exists(cdepsblddir): + logger.info("{} already exists, checking for lockfile".format(cdepsblddir)) + while os.path.exists(os.path.join(cdepsblddir,"lockfile")): + logger.info("Waiting for lockfile in {}".format(cdepsblddir)) + time.sleep(10) + else: + logger.info("{} does not exist, creating lockfile".format(cdepsblddir)) + os.makedirs(cdepsblddir) + with open(os.path.join(cdepsblddir,"lockfile"),"w") as fd: + fd.write(str(os.getpid())) + + try: + # if any file in src is newer than CmakeFiles in the build directory, rerun cmake + if src_time > bld_time: + logger.info("cmake_flags {}".format(cmake_flags)) + s, o, e = run_cmd( + "cmake {} ".format(cmake_flags), from_dir=bldroot, verbose=True + ) + expect(not s, "ERROR from cmake output={}, error={}".format(o, e)) + else: + # The dwav_lib is the last file built in cdeps, wait for it to be built + dwav_lib = os.path.join(bldroot, "dwav", "libdwav.a") + time_to_wait = 600 + time_counter = 0 + while not os.path.exists(dwav_lib): + time.sleep(1) + time_counter += 1 + if time_counter > time_to_wait: + break + expect(time_counter <= time_to_wait, " Timeout waiting for {}".format(dwav_lib)) + + s, o, e = run_cmd( + "make install VERBOSE=1 DESTDIR={}".format(libroot), + from_dir=bldroot, + verbose=True, + ) + finally: + if os.path.exists(os.path.join(cdepsblddir,"lockfile")): + os.remove(os.path.join(cdepsblddir,"lockfile")) + + expect(not s, "ERROR from make output={}, error={}".format(o, e)) + logger.info("make output={}\nerror={}".format(o, e)) + if compiler == "gnu" and case.get_value("DEBUG"): + # Do not allow any warnings except from fox external + nextline = "" + for line in e.split("\n"): + if "f90" in line.lower() and not "fox" in line.lower(): + nextline = nextline + line + if len(nextline) > 0: + expect(False, nextline) + + # Link the CDEPS component directories to the location expected by cime + for comp in ("atm", "glc", "lnd", "ice", "ocn", "rof", "wav"): + compname = case.get_value("COMP_{}".format(comp.upper())) + comppath = os.path.join(case.get_value("EXEROOT"), comp, "obj") + if compname == "d" + comp: + if not os.path.islink(comppath): + os.rmdir(comppath) + symlink_force(os.path.join(bldroot, compname), comppath) + + +def all_files_under(path, ignoredirs=None): + """Iterates through all files that are under the given path.""" + if not ignoredirs: + ignoredirs = [] + for cur_path, dirnames, filenames in os.walk(path, topdown=True): + _ = [dirnames.remove(d) for d in list(dirnames) if d in ignoredirs] + for filename in filenames: + yield os.path.join(cur_path, filename) + + +def _main_func(args): + bldroot, installpath, caseroot = parse_command_line(args, __doc__) + with Case(caseroot) as case: + buildlib(bldroot, installpath, case) + + +if __name__ == "__main__": + _main_func(sys.argv) diff --git a/CDEPS-interface/CDEPS/cime_config/buildlib_comps b/CDEPS-interface/CDEPS/cime_config/buildlib_comps new file mode 100755 index 0000000000..281f0d4e97 --- /dev/null +++ b/CDEPS-interface/CDEPS/cime_config/buildlib_comps @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 + +""" +build cime component model library. This buildlib script is used by all CDEPS components. +""" + +import sys, os + +_CIMEROOT = os.environ.get("CIMEROOT") +if _CIMEROOT is None: + raise SystemExit("ERROR: must set CIMEROOT environment variable") +sys.path.append(os.path.join(_CIMEROOT, "CIME", "Tools")) + +_LIBDIR = os.path.join(_CIMEROOT, "CIME") +sys.path.append(_LIBDIR) + +from standard_script_setup import * +from CIME.buildlib import parse_input +from CIME.case import Case +from CIME.utils import run_cmd, symlink_force, expect + +# pragma pylint: disable=unused-argument,undefined-variable + +logger = logging.getLogger(__name__) + + +def buildlib(bldroot, libroot, case, compname=None): + if not compname: + expect( + bldroot.endswith("obj"), + "It appears that buildlib_comps is being called for the main CDEPS build\n" + "(the main CDEPS build should use buildlib, not buildlib_comps)", + ) + compname = os.path.basename(os.path.abspath(os.path.join(bldroot, os.pardir))) + + _, o, e = run_cmd("make d{}".format(compname), from_dir=bldroot, verbose=True) + libname = "lib{}.a".format(compname) + dlibname = "libd{}.a".format(compname) + dlibpath = os.path.join(bldroot, dlibname) + if os.path.exists(dlibpath): + symlink_force(os.path.join(bldroot, dlibname), os.path.join(libroot, libname)) + else: + expect(False, "ERROR in {} build {} {}".format(compname, o, e)) + logger.info(f"build successful for comp={compname}") + + +def _main_func(args): + caseroot, libroot, bldroot = parse_input(args) + with Case(caseroot) as case: + buildlib(bldroot, libroot, case) + + +if __name__ == "__main__": + _main_func(sys.argv) diff --git a/CDEPS-interface/CDEPS/cime_config/stream_cdeps.py b/CDEPS-interface/CDEPS/cime_config/stream_cdeps.py new file mode 100644 index 0000000000..3d653745a3 --- /dev/null +++ b/CDEPS-interface/CDEPS/cime_config/stream_cdeps.py @@ -0,0 +1,700 @@ +""" +Interface to the streams.xml style files. This class inherits from GenericXML.py + +stream files predate cime and so do not conform to entry id format +""" +import datetime +import re +import hashlib + +from CIME.XML.standard_module_setup import * +from CIME.XML.generic_xml import GenericXML +from CIME.utils import expect + +# pragma pylint: disable=undefined-variable +logger = logging.getLogger(__name__) + +_var_ref_re = re.compile(r"\$(\{)?(?P\w+)(?(1)\})") + +_ymd_re = re.compile(r"%(?P[1-9][0-9]*)?y(?Pm(?Pd)?)?") + +_stream_file_template = """ + + {stream_taxmode} + {stream_tintalgo} + {stream_readmode} + {stream_mapalgo} + {stream_dtlimit} + {stream_year_first} + {stream_year_last} + {stream_year_align} + {stream_vectors} + {stream_meshfile} + {stream_lev_dimname} + + {stream_datafiles} + + + {stream_datavars} + + {stream_offset} + + +""" + +valid_values = {} +valid_values["mapalgo"] = ["bilinear", "nn", "redist", "mapconsd", "mapconf", "none"] +valid_values["tintalgo"] = ["lower", "upper", "nearest", "linear", "coszen"] +valid_values["taxmode"] = ["cycle", "extend", "limit"] + +xml_scalar_names = [ + "stream_meshfile", + "stream_mapalgo", + "stream_tintalgo", + "stream_taxmode", + "stream_dtlimit", +] + + +class StreamCDEPS(GenericXML): + def __init__(self, infile, schema): + """ + Initialize a CDEPS stream object + """ + logger.debug("Verifying using schema {}".format(schema)) + GenericXML.__init__(self, infile, schema) + self.stream_nodes = None + + if os.path.exists(infile): + GenericXML.read(self, infile, schema) + + def create_stream_xml( + self, + stream_names, + case, + streams_xml_file, + data_list_file, + user_mods_file, + available_neon_data=None, + available_plumber_data=None + ): + """ + Create the stream xml file and append the required stream input data to the input data list file + available_neon_data is an optional list of NEON tower data available for the given case, if provided + this data will be used to populate the NEON streamdata list + """ + + # determine if there are user mods + lines_input = [] + expect( + os.path.isfile(user_mods_file), + "No file {} found in case directory".format(user_mods_file), + ) + with open(user_mods_file, "r", encoding="utf-8") as stream_mods_file: + lines_input = stream_mods_file.readlines() + stream_mod_dict = {} + n = len(lines_input) + + index = 0 + lines_input_new = [] + while index < n: + line = lines_input[index].strip() + if line.startswith("!") or (not line): + index = index + 1 + continue + while line[-1] == "\\": + index += 1 + if index < n: + line = line[:-1].strip() + " " + lines_input[index].strip() + else: + line = line.replace("\\", "").strip() + break + # endif + # end while + index += 1 + line = case.get_resolved_value(line) + lines_input_new.append(line) + # end while + + for line in lines_input_new: + # read in a single line in user_nl_xxx_streams and parse it if it is not a comment + stream_mods = [x.strip() for x in line.strip().split(":", maxsplit=1) if x] + expect( + len(stream_mods) == 2, + "input stream mod can only be of the form streamname:var=value(s)", + ) + stream, varmod = stream_mods + expect( + stream in stream_names, + "{} contains a streamname '{}' that is not part of valid streamnames {}".format( + user_mods_file, stream, stream_names + ), + ) + if stream not in stream_mod_dict: + stream_mod_dict[stream] = {} + # var=value and check the validity + varmod_args = [x.strip() for x in varmod.split("=") if x] + expect( + len(varmod_args) == 2, + "input stream mod can only be of the form streamname:var=value(s)", + ) + # allow multiple entries for varmod_args, most recent wins + varname, varval = varmod_args + if varname in stream_mod_dict[stream]: + logger.warning( + "varname {} is already in stream mod dictionary".format(varname) + ) + + if varname == "datavars" or varname == "datafiles": + if varname == "datavars": + varvals = [ + "{}".format(x.strip()) + for x in varval.split(",") + if x + ] + if varname == "datafiles": + varvals = [ + "{}".format(x.strip()) + for x in varval.split(",") + if x + ] + varval = " " + "\n ".join(varvals) + varval = varval.strip() + stream_mod_dict[stream][varname] = varval + + # write header of stream file + with open(streams_xml_file, "w", encoding="utf-8") as stream_file: + stream_file.write('\n') + stream_file.write('\n') + + # write contents of stream file + for stream_name in stream_names: + # include NEON.$NEONSITE non-precipitation data streams whether use PRISM or NEON precip + if stream_name.startswith("NEON.") and ("PRECIP" not in stream_name): + self.stream_nodes = super(StreamCDEPS, self).get_child( + "stream_entry", + {"name": "NEON.$NEONSITE"}, + err_msg="No stream_entry {} found".format(stream_name), + ) + elif stream_name.startswith("NEON.PRISM_PRECIP"): + self.stream_nodes = super(StreamCDEPS, self).get_child( + "stream_entry", + {"name": "NEON.PRISM_PRECIP.$NEONSITE"}, + err_msg="No stream_entry {} found".format(stream_name), + ) + elif stream_name.startswith("NEON.NEON_PRECIP"): + self.stream_nodes = super(StreamCDEPS, self).get_child( + "stream_entry", + {"name": "NEON.NEON_PRECIP.$NEONSITE"}, + err_msg="No stream_entry {} found".format(stream_name), + ) + elif stream_name.startswith("PLUMBER2"): + self.stream_nodes = super(StreamCDEPS, self).get_child( + "stream_entry", + {"name": "PLUMBER2.$PLUMBER2SITE"}, + err_msg="No stream_entry {} found".format(stream_name), + ) + elif stream_name.startswith("CLM_USRDAT."): + if 'PLUMBER2' in stream_name: + # if PLUMBER2 is in the stream name + # we want to use PLUMBER2.PLUMBER2SITE instead of CLM_USRDAT.PLUMBER2 + continue + self.stream_nodes = super(StreamCDEPS, self).get_child( + "stream_entry", + {"name": "CLM_USRDAT.$CLM_USRDAT_NAME"}, + err_msg="No stream_entry {} found".format(stream_name), + ) + elif stream_name: + self.stream_nodes = super(StreamCDEPS, self).get_child( + "stream_entry", + {"name": stream_name}, + err_msg="No stream_entry {} found".format(stream_name), + ) + + # determine stream_year_first and stream_year_list + data_year_first, data_year_last = self._get_stream_first_and_last_dates( + self.stream_nodes, case + ) + + # now write the data model streams xml file + stream_vars = {} + stream_vars["streamname"] = stream_name + attributes = {} + for node in self.get_children(root=self.stream_nodes): + node_name = node.xml_element.tag.strip() + + if node_name == "stream_datavars": + # Get the resolved stream data variables + stream_vars[node_name] = None + for child in self.get_children(root=node): + datavars = child.xml_element.text.strip() + datavars = self._resolve_values(case, datavars) + datavars = self._sub_glc_fields(datavars, case) + datavars = self._add_xml_delimiter(datavars.split("\n"), "var") + if stream_vars[node_name]: + stream_vars[node_name] = ( + stream_vars[node_name] + "\n " + datavars.strip() + ) + else: + stream_vars[node_name] = datavars.strip() + # endif + + elif node_name == "stream_datafiles": + # Get the resolved stream data files + stream_vars[node_name] = "" + stream_datafiles_list = [] # to join stream_datafiles if multiple entries are present + stream_datafiles = "" + for child in self.get_children(root=node): + if ( + available_neon_data + and stream_name.startswith("NEON") + and ("PRISM" not in stream_name) + ): + rundir = case.get_value("RUNDIR") + for neon in available_neon_data: + stream_datafiles += ( + os.path.join(rundir, "inputdata", "atm", neon) + + "\n" + ) + elif available_plumber_data and stream_name.startswith("PLUMBER2"): + rundir = case.get_value("RUNDIR") + for plumber in available_plumber_data: + stream_datafiles += ( + os.path.join(rundir, "inputdata", "atm", plumber) + + "\n" + ) + else: + stream_datafiles = child.xml_element.text + stream_datafiles = self._resolve_values( + case, stream_datafiles + ) + # endif neon + if ( + "first_year" in child.xml_element.attrib + and "last_year" in child.xml_element.attrib + ): + value = child.xml_element.get("first_year") + value = self._resolve_values(case, value) + stream_year_first = int(value) + value = child.xml_element.get("last_year") + value = self._resolve_values(case, value) + stream_year_last = int(value) + year_first = max(stream_year_first, data_year_first) + year_last = min(stream_year_last, data_year_last) + if "filename_advance_days" in child.xml_element.attrib: + filename_advance_days = int( + child.xml_element.get("filename_advance_days") + ) + else: + filename_advance_days = 0 + stream_datafiles = self._sub_paths( + stream_name, + stream_datafiles, + year_first, + year_last, + filename_advance_days, + ) + stream_datafiles = stream_datafiles.strip() + # endif + if stream_vars[node_name]: + stream_vars[ + node_name + ] += "\n " + self._add_xml_delimiter( + stream_datafiles.split("\n"), "file" + ) + else: + stream_vars[node_name] = self._add_xml_delimiter( + stream_datafiles.split("\n"), "file" + ) + # endif + stream_datafiles_list.append(stream_datafiles) + stream_datafiles = "\n".join(stream_datafiles_list) + elif node_name in xml_scalar_names: + attributes["model_grid"] = case.get_value("GRID") + attributes["compset"] = case.get_value("COMPSET") + value = self._get_value_match( + node, node_name[7:], attributes=attributes + ) + if value: + value = self._resolve_values(case, value) + value = value.strip() + stream_vars[node_name] = value + + elif node_name.strip(): + # Get the other dependencies + self._add_value_to_dict(stream_vars, case, node) + + # substitute user_mods in generated stream file (i.e. stream_vars) + mod_dict = {} + if stream_vars["streamname"] in stream_mod_dict: + mod_dict = stream_mod_dict[stream_vars["streamname"]] + for var_key in mod_dict: + expect( + "stream_" + var_key in stream_vars, + "stream mod {} is not a valid name in {}".format( + var_key, user_mods_file + ), + ) + if var_key in valid_values: + expect( + mod_dict[var_key] in valid_values[var_key], + "{} can only have values of {} for stream {} in file {}".format( + var_key, + valid_values[var_key], + stream_name, + user_mods_file, + ), + ) + stream_vars["stream_" + var_key] = mod_dict[var_key] + if var_key == "datafiles": + stream_datafiles = mod_dict[var_key] + stream_datafiles = stream_datafiles.replace( + "", "" + ).replace("", "") + + # append to stream xml file + stream_file_text = _stream_file_template.format(**stream_vars) + with open(streams_xml_file, "a", encoding="utf-8") as stream_file: + stream_file.write(case.get_resolved_value(stream_file_text)) + + # append to input_data_list + if stream_vars["stream_meshfile"]: + stream_meshfile = stream_vars["stream_meshfile"].strip() + self._add_entries_to_inputdata_list( + stream_meshfile, stream_datafiles.split("\n"), data_list_file + ) + + # write close of stream xml file + with open(streams_xml_file, "a", encoding="utf-8") as stream_file: + stream_file.write("\n") + + def _get_stream_first_and_last_dates(self, stream, case): + """ + Get first and last dates for data for the stream file + """ + for node in self.get_children(root=stream): + if node.xml_element.tag == "stream_year_first": + data_year_first = node.xml_element.text.strip() + data_year_first = int(self._resolve_values(case, data_year_first)) + if node.xml_element.tag == "stream_year_last": + data_year_last = node.xml_element.text.strip() + data_year_last = int(self._resolve_values(case, data_year_last)) + return data_year_first, data_year_last + + def _add_entries_to_inputdata_list( + self, stream_meshfile, stream_datafiles, data_list_file + ): + """ + Appends input data information entries to input data list file + and writes out the new file + """ + lines_hash = self._get_input_file_hash(data_list_file) + with open(data_list_file, "a", encoding="utf-8") as input_data_list: + # write out the mesh file separately + string = "mesh = {}\n".format(stream_meshfile) + hashValue = hashlib.md5(string.rstrip().encode("utf-8")).hexdigest() + if hashValue not in lines_hash: + input_data_list.write(string) + # now append the stream_datafile entries + for i, filename in enumerate(stream_datafiles): + if filename.strip() == "": + continue + string = "file{:d} = {}\n".format(i + 1, filename.strip()) + hashValue = hashlib.md5(string.rstrip().encode("utf-8")).hexdigest() + if hashValue not in lines_hash: + input_data_list.write(string) + + def _get_input_file_hash(self, data_list_file): + """ + Determine a hash for the input data file + """ + lines_hash = set() + if os.path.isfile(data_list_file): + with open(data_list_file, "r", encoding="utf-8") as input_data_list: + for line in input_data_list: + hashValue = hashlib.md5(line.rstrip().encode("utf-8")).hexdigest() + logger.debug("Found line {} with hash {}".format(line, hashValue)) + lines_hash.add(hashValue) + return lines_hash + + def _get_value_match(self, node, child_name, attributes=None, exact_match=False): + """ + Get the first best match for multiple tags in child_name based on the + attributes input + + + X + Y + Z + + + """ + # Store nodes that match the attributes and their scores. + matches = [] + nodes = self.get_children(child_name, root=node) + for vnode in nodes: + # For each node in the list start a score. + score = 0 + if attributes: + for attribute in self.attrib(vnode).keys(): + # For each attribute, add to the score. + score += 1 + # If some attribute is specified that we don't know about, + # or the values don't match, it's not a match we want. + if exact_match: + if attribute not in attributes or attributes[ + attribute + ] != self.get(vnode, attribute): + score = -1 + break + else: + if attribute not in attributes or not re.search( + self.get(vnode, attribute), attributes[attribute] + ): + score = -1 + break + + # Add valid matches to the list. + if score >= 0: + matches.append((score, vnode)) + + if not matches: + return None + + # Get maximum score using either a "last" or "first" match in case of a tie + max_score = -1 + mnode = None + for score, node in matches: + # take the *first* best match + if score > max_score: + max_score = score + mnode = node + + return self.text(mnode) + + def _add_value_to_dict(self, stream_dict, case, node): + """ + Adds a value to the input stream dictionary needed for the + stream file output Returns the uppdated stream_dict + """ + name = node.xml_element.tag + value = node.xml_element.text + value = self._resolve_values(case, value) + stream_dict[name] = value + return stream_dict + + def _resolve_values(self, case, value): + """ + Substitues $CASEROOT env_xxx.xml variables if they appear in "value" + Returns a string + """ + match = _var_ref_re.search(value) + while match: + env_val = case.get_value(match.group("name")) + expect( + env_val is not None, + "Namelist default for variable {} refers to unknown XML variable {}.".format( + value, match.group("name") + ), + ) + value = value.replace(match.group(0), str(env_val), 1) + match = _var_ref_re.search(value) + return value + + def _sub_glc_fields(self, datavars, case): + """Substitute indicators with given values in a list of fields. + + Replace any instance of the following substring indicators with the + appropriate values: + %glc = two-digit GLC elevation class from 00 through glc_nec + + The difference between this function and `_sub_paths` is that this + function is intended to be used for variable names (especially from the + `strm_datvar` defaults), whereas `_sub_paths` is intended for use on + input data file paths. + + Returns a string. + + Example: If `_sub_fields` is called with an array containing two + elements, each of which contains two strings, and glc_nec=3: + foo bar + s2x_Ss_tsrf%glc tsrf%glc + then the returned array will be: + foo bar + s2x_Ss_tsrf00 tsrf00 + s2x_Ss_tsrf01 tsrf01 + s2x_Ss_tsrf02 tsrf02 + s2x_Ss_tsrf03 tsrf03 + """ + lines = datavars.split("\n") + new_lines = [] + for line in lines: + if not line: + continue + if "%glc" in line: + if case.get_value("GLC_NEC") == 0: + glc_nec_indices = [] + else: + glc_nec_indices = range(case.get_value("GLC_NEC") + 1) + for i in glc_nec_indices: + new_lines.append(line.replace("%glc", "{:02d}".format(i))) + else: + new_lines.append(line) + return "\n".join(new_lines) + + @staticmethod + def _days_in_month(month, year=1): + """Number of days in the given month (specified as an int, 1-12). + + The `year` argument gives the year for which to request the number of + days, in a Gregorian calendar. Defaults to `1` (not a leap year). + """ + month_start = datetime.date(year, month, 1) + if month == 12: + next_year = year + 1 + next_month = 1 + else: + next_year = year + next_month = month + 1 + next_month_start = datetime.date(next_year, next_month, 1) + return (next_month_start - month_start).days + + @classmethod + def _add_day(cls, year, month, day): + """Given a year, month and day, add 1 day + + Returns a new tuple, (adjusted_year, adjusted_month, adjusted_day) + + Assumes a no-leap calendar + + >>> StreamCDEPS._add_day(1999, 1, 1) + (1999, 1, 2) + >>> StreamCDEPS._add_day(1999, 1, 31) + (1999, 2, 1) + >>> StreamCDEPS._add_day(1999, 12, 31) + (2000, 1, 1) + """ + adjusted_year = year + adjusted_month = month + adjusted_day = day + 1 + if adjusted_day > cls._days_in_month(month): + adjusted_day = 1 + adjusted_month = adjusted_month + 1 + if adjusted_month > 12: + adjusted_month = 1 + adjusted_year = adjusted_year + 1 + return (adjusted_year, adjusted_month, adjusted_day) + + def _sub_paths( + self, stream_name, filenames, year_start, year_end, filename_advance_days + ): + """Substitute indicators with given values in a list of filenames. + + Replace any instance of the following substring indicators with the + appropriate values: + %y = year from the range year_start to year_end + %ym = year-month from the range year_start to year_end with all 12 + months + %ymd = year-month-day from the range year_start to year_end with + all 12 months + + For the date indicators, the year may be prefixed with a number of + digits to use (the default is 4). E.g. `%2ymd` can be used to change the + number of year digits from 4 to 2. + + Note that we assume that there is no mixing and matching of date + indicators, i.e. you cannot use `%4ymd` and `%2y` in the same line. Note + also that we use a no-leap calendar, i.e. every month has the same + number of days every year. + + filename_advance_days is an integer specifying the number of days to add to the date + portion of the file name when using %ymd. Currently only values of 0 or 1 are + supported. This is typically 0 but can be 1 to indicate that the dates have a + one-day offset, starting with day 2 in the first year and ending with day 1 in the + year following the last year. This can be the case, for example, for daily coupler + history files. + + The difference between this function and `_sub_fields` is that this + function is intended to be used for file names (especially from the + `strm_datfil` defaults), whereas `_sub_fields` is intended for use on + variable names. + + Returns a string (filenames separated by newlines). + """ + expect( + filename_advance_days == 0 or filename_advance_days == 1, + "Bad filename_advance_days attribute ({}) for {}: must be 0 or 1".format( + filename_advance_days, stream_name + ), + ) + + lines = [line for line in filenames.split("\n") if line] + new_lines = [] + for line in lines: + match = _ymd_re.search(filenames) + if match is None: + new_lines.append(line) + continue + if match.group("digits"): + year_format = "{:0" + match.group("digits") + "d}" + else: + year_format = "{:04d}" + for year in range(year_start, year_end + 1): + if match.group("day"): + for month in range(1, 13): + days = self._days_in_month(month) + for day in range(1, days + 1): + if filename_advance_days == 1: + ( + adjusted_year, + adjusted_month, + adjusted_day, + ) = self._add_day(year, month, day) + else: + (adjusted_year, adjusted_month, adjusted_day) = ( + year, + month, + day, + ) + date_string = (year_format + "-{:02d}-{:02d}").format( + adjusted_year, adjusted_month, adjusted_day + ) + new_line = line.replace(match.group(0), date_string) + new_lines.append(new_line) + elif match.group("month"): + for month in range(1, 13): + date_string = (year_format + "-{:02d}").format(year, month) + new_line = line.replace(match.group(0), date_string) + new_lines.append(new_line) + else: + date_string = year_format.format(year) + new_line = line.replace(match.group(0), date_string) + new_lines.append(new_line) + return "\n".join(new_lines) + + @staticmethod + def _add_xml_delimiter(list_to_deliminate, delimiter): + expect(delimiter and not " " in delimiter, "Missing or badly formed delimiter") + pred = "<{}>".format(delimiter) + postd = "".format(delimiter) + for n, item in enumerate(list_to_deliminate): + if item.strip(): + list_to_deliminate[n] = pred + item.strip() + postd + # endif + # endfor + return "\n ".join(list_to_deliminate) + + def update_input_data_list(self, data_list_file): + """From the stream object parse out and list required input files""" + sinodes = self.scan_children("stream_info") + for node in sinodes: + meshnode = self.scan_child("stream_mesh_file", root=node) + stream_meshfile = self.text(meshnode) + data_file_node = self.scan_child("stream_data_files", root=node) + filenodes = self.scan_children("file", root=data_file_node) + stream_datafiles = [] + for fnode in filenodes: + stream_datafiles.append(self.text(fnode)) + self._add_entries_to_inputdata_list( + stream_meshfile, stream_datafiles, data_list_file + ) diff --git a/CDEPS-interface/CDEPS/cime_config/stream_definition_v2.0.xsd b/CDEPS-interface/CDEPS/cime_config/stream_definition_v2.0.xsd new file mode 100644 index 0000000000..d6ec747681 --- /dev/null +++ b/CDEPS-interface/CDEPS/cime_config/stream_definition_v2.0.xsd @@ -0,0 +1,239 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CDEPS-interface/CDEPS/cime_config/streams.xsd b/CDEPS-interface/CDEPS/cime_config/streams.xsd new file mode 100644 index 0000000000..d9415c7211 --- /dev/null +++ b/CDEPS-interface/CDEPS/cime_config/streams.xsd @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CDEPS-interface/CDEPS/cmake/FindESMF.cmake b/CDEPS-interface/CDEPS/cmake/FindESMF.cmake new file mode 100644 index 0000000000..175a394885 --- /dev/null +++ b/CDEPS-interface/CDEPS/cmake/FindESMF.cmake @@ -0,0 +1,47 @@ + +if (DEFINED ENV{ESMFMKFILE}) + message("ESMFMKFILE: $ENV{ESMFMKFILE}") +else() + message(FATAL_ERROR "ESMFMKFILE env variable is not defined") +endif() + +set(ESMFMKFILE $ENV{ESMFMKFILE}) + +# convert esmf.mk makefile variables to cmake variables until ESMF +# provides proper cmake package +file(STRINGS ${ESMFMKFILE} esmf_mk_text) +foreach(line ${esmf_mk_text}) + string(REGEX REPLACE "^[ ]+" "" line ${line}) # strip leading spaces + if (line MATCHES "^ESMF_*") # process only line starting with ESMF_ + string(REGEX MATCH "^ESMF_[^=]+" esmf_name ${line}) + string(REPLACE "${esmf_name}=" "" emsf_value ${line}) + set(${esmf_name} "${emsf_value}") + endif() +endforeach() +string(REPLACE "-I" "" ESMF_F90COMPILEPATHS ${ESMF_F90COMPILEPATHS}) +string(REPLACE " " ";" ESMF_F90COMPILEPATHS ${ESMF_F90COMPILEPATHS}) + +# We use only these 4 variables in our build system. Make sure they are all set +if(ESMF_VERSION_MAJOR AND + ESMF_F90COMPILEPATHS AND + ESMF_F90ESMFLINKRPATHS AND + ESMF_F90ESMFLINKLIBS) + message(" Found ESMF:") + message("ESMF_VERSION_MAJOR: ${ESMF_VERSION_MAJOR}") + message("ESMF_F90COMPILEPATHS: ${ESMF_F90COMPILEPATHS}") + message("ESMF_F90ESMFLINKRPATHS: ${ESMF_F90ESMFLINKRPATHS}") + message("ESMF_F90ESMFLINKLIBS: ${ESMF_F90ESMFLINKLIBS}") +else() + message("One of the ESMF_ variables is not defined") +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(ESMF + FOUND_VAR + ESMF_FOUND + REQUIRED_VARS + ESMF_F90COMPILEPATHS + ESMF_F90ESMFLINKRPATHS + ESMF_F90ESMFLINKLIBS + VERSION_VAR + ESMF_VERSION_STRING) diff --git a/CDEPS-interface/CDEPS/cmake/FindPIO.cmake b/CDEPS-interface/CDEPS/cmake/FindPIO.cmake new file mode 100644 index 0000000000..2a7af648aa --- /dev/null +++ b/CDEPS-interface/CDEPS/cmake/FindPIO.cmake @@ -0,0 +1,103 @@ +# - Try to find PIO +# +# This can be controled by setting PIO_PATH or PIO__PATH Cmake variables, +# where is the COMPONENT language one needs. +# +# Once done, this will define: +# +# PIO__FOUND (BOOL) - system has PIO +# PIO__IS_SHARED (BOOL) - whether the library is shared/dynamic +# PIO__INCLUDE_DIR (PATH) - Location of the header files and modules +# PIO__LIBRARY (File) - Path to the library files +# PIO__LIBRARIES (List) - link these to use PIO +# +# Available COMPONENTS are: C Fortran +# If no components are specified only C is assumed +include (LibFind) +include (LibCheck) + +# Define PIO C Component +define_package_component(PIO DEFAULT + COMPONENT C + INCLUDE_NAMES pio.h + LIBRARY_NAMES pioc) + +# Define PIO Fortran Component +define_package_component(PIO + COMPONENT Fortran + INCLUDE_NAMES pio.mod pio.inc + LIBRARY_NAMES piof) + +# Search for list of valid components requested +find_valid_components(PIO) + +#============================================================================== +# SEARCH FOR VALIDATED COMPONENTS +foreach (pcomp IN LISTS PIO_FIND_VALID_COMPONENTS) + + # If not found already, search... + if (NOT PIO_${pcomp}_FOUND) + + # Manually add the MPI include and library dirs to search paths + # and search for the package component + if (MPI_${pcomp}_FOUND) + initialize_paths (PIO_${pcomp}_PATHS + INCLUDE_DIRECTORIES ${MPI_${pcomp}_INCLUDE_PATH} + LIBRARIES ${MPI_${pcomp}_LIBRARIES}) + find_package_component(PIO COMPONENT ${pcomp} + PATHS ${PIO_${pcomp}_PATHS}) + else () + find_package_component(PIO COMPONENT ${pcomp} HINT PIO_${pcomp}_PATH=${PIO_PATH}) + endif () + + # Continue only if component found + if (PIO_${pcomp}_FOUND) + + # Checks + if (pcomp STREQUAL C) + + # Check version + check_version (PIO + NAME "pio_meta.h" + HINTS ${PIO_C_INCLUDE_DIRS} + MACRO_REGEX "PIO_VERSION_") + + endif () + + # Dependencies + if (pcomp STREQUAL C AND NOT PIO_C_IS_SHARED) + + # DEPENDENCY: PnetCDF (if PnetCDF enabled) + check_macro (PIO_HAS_PNETCDF + NAME TryPIO_PNETCDF.c + HINTS ${CMAKE_MODULE_PATH} + DEFINITIONS -I${PIO_C_INCLUDE_DIR} + COMMENT "whether PIO has PnetCDF support") + if (PIO_HAS_PNETCDF) + find_package (PnetCDF COMPONENTS C) + endif () + + + elseif (pcomp STREQUAL Fortran AND NOT PIO_Fortran_IS_SHARED) + + # DEPENDENCY: PIO + set (orig_comp ${pcomp}) + set (orig_comps ${PIO_FIND_VALID_COMPONENTS}) + find_package (PIO COMPONENTS C) + set (PIO_FIND_VALID_COMPONENTS ${orig_comps}) + set (pcomp ${orig_comp}) + if (PIO_C_FOUND) + list (APPEND PIO_Fortran_INCLUDE_DIRS ${PIO_C_INCLUDE_DIRS}) + list (APPEND PIO_Fortran_LIBRARIES ${PIO_C_LIBRARIES}) + endif () + + endif () + + endif () + + endif () + +endforeach () +message("PIO_C_FOUND ${PIO_C_FOUND}") +message("PIO_Fortran_FOUND ${PIO_Fortran_FOUND}") +message("PIO_Fortran_INCLUDE_DIR ${PIO_Fortran_INCLUDE_DIR}") diff --git a/CDEPS-interface/CDEPS/cmake/LibCheck.cmake b/CDEPS-interface/CDEPS/cmake/LibCheck.cmake new file mode 100644 index 0000000000..3f12bdf796 --- /dev/null +++ b/CDEPS-interface/CDEPS/cmake/LibCheck.cmake @@ -0,0 +1,104 @@ +include (CMakeParseArguments) +include (CheckFunctionExists) +#============================================================================== +# +# FUNCTIONS TO HELP WITH Check* MODULES +# +#============================================================================== + +#______________________________________________________________________________ +# - Basic function to check a property of a package using a try_compile step +# +# SYNTAX: check_macro ( +# NAME +# HINTS ... +# DEFINITIONS ... +# COMMENT ) +# +function (check_macro VARIABLE) + + # Parse the input arguments + set (oneValueArgs COMMENT NAME) + set (multiValueArgs HINTS DEFINITIONS) + cmake_parse_arguments (${VARIABLE} "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + # If the return variable is defined, already, don't continue + if (NOT DEFINED ${VARIABLE}) + + message (STATUS "Checking ${${VARIABLE}_COMMENT}") + find_file (${VARIABLE}_TRY_FILE + NAMES ${${VARIABLE}_NAME} + HINTS ${${VARIABLE}_HINTS}) + if (${VARIABLE}_TRY_FILE) + try_compile (COMPILE_RESULT + ${CMAKE_CURRENT_BINARY_DIR}/try${VARIABLE} + SOURCES ${${VARIABLE}_TRY_FILE} + COMPILE_DEFINITIONS ${${VARIABLE}_DEFINITIONS} + OUTPUT_VARIABLE TryOUT) + if (COMPILE_RESULT) + message (STATUS "Checking ${${VARIABLE}_COMMENT} - yes") + else () + message (STATUS "Checking ${${VARIABLE}_COMMENT} - no") + endif () + + set (${VARIABLE} ${COMPILE_RESULT} + CACHE BOOL "${${VARIABLE}_COMMENT}") + + else () + message (STATUS "Checking ${${VARIABLE}_COMMENT} - failed") + endif () + + unset (${VARIABLE}_TRY_FILE CACHE) + endif () + +endfunction () + +#______________________________________________________________________________ +# - Basic function to check the version of a package using a try_run step +# +# SYNTAX: check_version ( +# NAME +# HINTS ... +# DEFINITIONS ...) +# +function (check_version PKG) + + # Parse the input arguments + set (oneValueArgs NAME MACRO_REGEX) + set (multiValueArgs HINTS) + cmake_parse_arguments (${PKG} "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + # If the return variable is defined, already, don't continue + if (NOT DEFINED ${PKG}_VERSION) + + message (STATUS "Checking ${PKG} version") + find_file (${PKG}_VERSION_HEADER + NAMES ${${PKG}_NAME} + HINTS ${${PKG}_HINTS}) + if (${PKG}_VERSION_HEADER) + set (def) + file (STRINGS ${${PKG}_VERSION_HEADER} deflines + REGEX "^#define[ \\t]+${${PKG}_MACRO_REGEX}") + foreach (defline IN LISTS deflines) + string (REPLACE "\"" "" defline "${defline}") + string (REPLACE "." "" defline "${defline}") + string (REGEX REPLACE "[ \\t]+" ";" deflist "${defline}") + list (GET deflist 2 arg) + list (APPEND def ${arg}) + endforeach () + string (REPLACE ";" "." vers "${def}") + message (STATUS "Checking ${PKG} version - ${vers}") + set (${PKG}_VERSION ${vers} + CACHE STRING "${PKG} version string") + if (${PKG}_VERSION VERSION_LESS ${PKG}_FIND_VERSION}) + message (FATAL_ERROR "${PKG} version insufficient") + endif () + else () + message (STATUS "Checking ${PKG} version - failed") + endif () + + unset (${PKG}_VERSION_HEADER CACHE) + + endif () + +endfunction () \ No newline at end of file diff --git a/CDEPS-interface/CDEPS/cmake/LibFind.cmake b/CDEPS-interface/CDEPS/cmake/LibFind.cmake new file mode 100644 index 0000000000..61cd93aa37 --- /dev/null +++ b/CDEPS-interface/CDEPS/cmake/LibFind.cmake @@ -0,0 +1,333 @@ +include (CMakeParseArguments) +include(FindPackageHandleStandardArgs) + +#============================================================================== +# +# FUNCTIONS TO HELP WITH Find* MODULES +# +#============================================================================== + +#______________________________________________________________________________ +# - Wrapper for finding static libraries ONLY +# +macro (find_static_library) + set (_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) + set (CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_STATIC_LIBRARY_SUFFIX}) + find_library(${ARGN}) + set (CMAKE_FIND_LIBRARY_SUFFIXES ${_CMAKE_FIND_LIBRARY_SUFFIXES}) + unset (_CMAKE_FIND_LIBRARY_SUFFIXES) +endmacro () + + +#______________________________________________________________________________ +# - Wrapper for finding shared/dynamic libraries ONLY +# +macro (find_shared_library) + set (_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) + set (CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_SHARED_LIBRARY_SUFFIX}) + find_library(${ARGN}) + set (CMAKE_FIND_LIBRARY_SUFFIXES ${_CMAKE_FIND_LIBRARY_SUFFIXES}) + unset (_CMAKE_FIND_LIBRARY_SUFFIXES) +endmacro () + + +#______________________________________________________________________________ +# - Function to determine type (SHARED or STATIC) of library +# +# Input: +# LIB (FILE) +# +# Returns: +# RETURN_VAR (BOOL) +# +function (is_shared_library RETURN_VAR LIB) + get_filename_component(libext ${LIB} EXT) + if (libext MATCHES ${CMAKE_SHARED_LIBRARY_SUFFIX}) + set (${RETURN_VAR} TRUE PARENT_SCOPE) + else () + set (${RETURN_VAR} FALSE PARENT_SCOPE) + endif () +endfunction () + + +#______________________________________________________________________________ +# - Function to define a valid package component +# +# Input: +# ${PKG}_DEFAULT (BOOL) +# ${PKG}_COMPONENT (STRING) +# ${PKG}_INCLUDE_NAMES (LIST) +# ${PKG}_LIBRARY_NAMES (LIST) +# +# Returns: +# ${PKG}_DEFAULT_COMPONENT (STRING) +# ${PKG}_VALID_COMPONENTS (LIST) +# ${PKG}_${COMPONENT}_INCLUDE_NAMES (LIST) +# ${PKG}_${COMPONENT}_LIBRARY_NAMES (LIST) +# +function (define_package_component PKG) + + # Parse the input arguments + set (options DEFAULT) + set (oneValueArgs COMPONENT) + set (multiValueArgs INCLUDE_NAMES LIBRARY_NAMES) + cmake_parse_arguments (${PKG} "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + if (${PKG}_COMPONENT) + set (PKGCOMP ${PKG}_${${PKG}_COMPONENT}) + else () + set (PKGCOMP ${PKG}) + endif () + + # Set return values + if (${PKG}_COMPONENT) + if (${PKG}_DEFAULT) + set (${PKG}_DEFAULT_COMPONENT ${${PKG}_COMPONENT} PARENT_SCOPE) + endif () + set (VALID_COMPONENTS ${${PKG}_VALID_COMPONENTS}) + list (APPEND VALID_COMPONENTS ${${PKG}_COMPONENT}) + set (${PKG}_VALID_COMPONENTS ${VALID_COMPONENTS} PARENT_SCOPE) + endif () + set (${PKGCOMP}_INCLUDE_NAMES ${${PKG}_INCLUDE_NAMES} PARENT_SCOPE) + set (${PKGCOMP}_LIBRARY_NAMES ${${PKG}_LIBRARY_NAMES} PARENT_SCOPE) + +endfunction () + + +#______________________________________________________________________________ +# - Function to find valid package components +# +# Assumes pre-defined variables: +# ${PKG}_FIND_COMPONENTS (LIST) +# ${PKG}_DEFAULT_COMPONENT (STRING) +# ${PKG}_VALID_COMPONENTS (LIST) +# +# Returns: +# ${PKG}_FIND_VALID_COMPONENTS (LIST) +# +function (find_valid_components PKG) + + if (NOT ${PKG}_FIND_COMPONENTS) + set (${PKG}_FIND_COMPONENTS ${${PKG}_DEFAULT_COMPONENT}) + endif () + + set (FIND_VALID_COMPONENTS) + foreach (comp IN LISTS ${PKG}_FIND_COMPONENTS) + if (";${${PKG}_VALID_COMPONENTS};" MATCHES ";${comp};") + list (APPEND FIND_VALID_COMPONENTS ${comp}) + endif () + endforeach () + + set (${PKG}_FIND_VALID_COMPONENTS ${FIND_VALID_COMPONENTS} PARENT_SCOPE) + +endfunction () + + +#______________________________________________________________________________ +# - Initialize a list of paths from a list of includes and libraries +# +# Input: +# INCLUDE_DIRECTORIES +# LIBRARIES +# +# Ouput: +# ${PATHLIST} +# +function (initialize_paths PATHLIST) + + # Parse the input arguments + set (multiValueArgs INCLUDE_DIRECTORIES LIBRARIES) + cmake_parse_arguments (INIT "" "" "${multiValueArgs}" ${ARGN}) + + set (paths) + foreach (inc IN LISTS INIT_INCLUDE_DIRECTORIES) + list (APPEND paths ${inc}) + get_filename_component (dname ${inc} NAME) + if (dname MATCHES "include") + get_filename_component (prefx ${inc} PATH) + list (APPEND paths ${prefx}) + endif () + endforeach () + foreach (lib IN LISTS INIT_LIBRARIES) + get_filename_component (libdir ${lib} PATH) + list (APPEND paths ${libdir}) + get_filename_component (dname ${libdir} PATH) + if (dname MATCHES "lib") + get_filename_component (prefx ${libdir} PATH) + list (APPEND paths ${prefx}) + endif () + endforeach () + + set (${PATHLIST} ${paths} PARENT_SCOPE) + +endfunction () + + +#______________________________________________________________________________ +# - Basic find package macro for a specific component +# +# Assumes pre-defined variables: +# ${PKG}_${COMP}_INCLUDE_NAMES or ${PKG}_INCLUDE_NAMES +# ${PKG}_${COMP}_LIBRARY_NAMES or ${PKG}_LIBRARY_NAMES +# +# Input: +# ${PKG}_COMPONENT +# ${PKG}_HINTS +# ${PKG}_PATHS +# +function (find_package_component PKG) + + # Parse the input arguments + set (options) + set (oneValueArgs COMPONENT) + set (multiValueArgs HINTS PATHS) + cmake_parse_arguments (${PKG} "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + set (COMP ${${PKG}_COMPONENT}) + if (COMP) + set (PKGCOMP ${PKG}_${COMP}) + else () + set (PKGCOMP ${PKG}) + endif () + string (TOUPPER ${PKG} PKGUP) + string (TOUPPER ${PKGCOMP} PKGCOMPUP) + + # Only continue if package not found already + if (NOT ${PKGCOMP}_FOUND) + + # Handle QUIET and REQUIRED arguments + if (${${PKG}_FIND_QUIETLY}) + set (${PKGCOMP}_FIND_QUIETLY TRUE) + endif () + if (${${PKG}_FIND_REQUIRED}) + set (${PKGCOMP}_FIND_REQUIRED TRUE) + endif () + + # Determine search order + set (SEARCH_DIRS) + if (${PKG}_HINTS) + list (APPEND SEARCH_DIRS ${${PKG}_HINTS}) + endif () + if (${PKGCOMP}_PATH) + list (APPEND SEARCH_DIRS ${${PKGCOMP}_PATH}) + endif () + if (${PKG}_PATH) + list (APPEND SEARCH_DIRS ${${PKG}_PATH}) + endif () + if (DEFINED ENV{${PKGCOMPUP}}) + list (APPEND SEARCH_DIRS $ENV{${PKGCOMPUP}}) + endif () + if (DEFINED ENV{${PKGUP}}) + list (APPEND SEARCH_DIRS $ENV{${PKGUP}}) + endif () + if (CMAKE_SYSTEM_PREFIX_PATH) + list (APPEND SEARCH_DIRS ${CMAKE_SYSTEM_PREFIX_PATH}) + endif () + if (${PKG}_PATHS) + list (APPEND SEARCH_DIRS ${${PKG}_PATHS}) + endif () + + # Start the search for the include file and library file. Only overload + # if the variable is not defined. + foreach (suffix PREFIX LIBRARY INCLUDE_DIR) + if (NOT DEFINED ${PKGCOMP}_${suffix}) + set (${PKGCOMP}_${suffix} ${PKGCOMP}_${suffix}-NOTFOUND) + endif () + endforeach () + + foreach (dir IN LISTS SEARCH_DIRS) + + # Search for include file names in current dirrectory + foreach (iname IN LISTS ${PKGCOMP}_INCLUDE_NAMES) + if (EXISTS ${dir}/${iname}) + set (${PKGCOMP}_PREFIX ${dir}) + set (${PKGCOMP}_INCLUDE_DIR ${dir}) + break () + endif () + if (EXISTS ${dir}/include/${iname}) + set (${PKGCOMP}_PREFIX ${dir}) + set (${PKGCOMP}_INCLUDE_DIR ${dir}/include) + break () + endif () + endforeach () + + # Search for library file names in the found prefix only! + if (${PKGCOMP}_PREFIX) + find_library (${PKGCOMP}_LIBRARY + NAMES ${${PKGCOMP}_LIBRARY_NAMES} + PATHS ${${PKGCOMP}_PREFIX} + PATH_SUFFIXES lib + NO_DEFAULT_PATH) + + # If found, check if library is static or dynamic + if (${PKGCOMP}_LIBRARY) + is_shared_library (${PKGCOMP}_IS_SHARED ${${PKGCOMP}_LIBRARY}) + + # If we want only shared libraries, and it isn't shared... + if (PREFER_SHARED AND NOT ${PKGCOMP}_IS_SHARED) + find_shared_library (${PKGCOMP}_SHARED_LIBRARY + NAMES ${${PKGCOMP}_LIBRARY_NAMES} + PATHS ${${PKGCOMP}_PREFIX} + PATH_SUFFIXES lib + NO_DEFAULT_PATH) + if (${PKGCOMP}_SHARED_LIBRARY) + set (${PKGCOMP}_LIBRARY ${${PKGCOMP}_SHARED_LIBRARY}) + set (${PKGCOMP}_IS_SHARED TRUE) + endif () + + # If we want only static libraries, and it is shared... + elseif (PREFER_STATIC AND ${PKGCOMP}_IS_SHARED) + find_static_library (${PKGCOMP}_STATIC_LIBRARY + NAMES ${${PKGCOMP}_LIBRARY_NAMES} + PATHS ${${PKGCOMP}_PREFIX} + PATH_SUFFIXES lib + NO_DEFAULT_PATH) + if (${PKGCOMP}_STATIC_LIBRARY) + set (${PKGCOMP}_LIBRARY ${${PKGCOMP}_STATIC_LIBRARY}) + set (${PKGCOMP}_IS_SHARED FALSE) + endif () + endif () + endif () + + # If include dir and library both found, then we're done + if (${PKGCOMP}_INCLUDE_DIR AND ${PKGCOMP}_LIBRARY) + break () + + # Otherwise, reset the search variables and continue + else () + set (${PKGCOMP}_PREFIX ${PKGCOMP}_PREFIX-NOTFOUND) + set (${PKGCOMP}_INCLUDE_DIR ${PKGCOMP}_INCLUDE_DIR-NOTFOUND) + set (${PKGCOMP}_LIBRARY ${PKGCOMP}_LIBRARY-NOTFOUND) + endif () + endif () + + endforeach () + + # handle the QUIETLY and REQUIRED arguments and + # set NetCDF_C_FOUND to TRUE if all listed variables are TRUE + find_package_handle_standard_args (${PKGCOMP} DEFAULT_MSG + ${PKGCOMP}_LIBRARY + ${PKGCOMP}_INCLUDE_DIR) + mark_as_advanced (${PKGCOMP}_INCLUDE_DIR ${PKGCOMP}_LIBRARY) + + # HACK For bug in CMake v3.0: + set (${PKGCOMP}_FOUND ${${PKGCOMPUP}_FOUND}) + + # Set return variables + if (${PKGCOMP}_FOUND) + set (${PKGCOMP}_INCLUDE_DIRS ${${PKGCOMP}_INCLUDE_DIR}) + set (${PKGCOMP}_LIBRARIES ${${PKGCOMP}_LIBRARY}) + endif () + + # Set variables in parent scope + set (${PKGCOMP}_FOUND ${${PKGCOMP}_FOUND} PARENT_SCOPE) + set (${PKGCOMP}_INCLUDE_DIR ${${PKGCOMP}_INCLUDE_DIR} PARENT_SCOPE) + set (${PKGCOMP}_INCLUDE_DIRS ${${PKGCOMP}_INCLUDE_DIRS} PARENT_SCOPE) + set (${PKGCOMP}_LIBRARY ${${PKGCOMP}_LIBRARY} PARENT_SCOPE) + set (${PKGCOMP}_LIBRARIES ${${PKGCOMP}_LIBRARIES} PARENT_SCOPE) + set (${PKGCOMP}_IS_SHARED ${${PKGCOMP}_IS_SHARED} PARENT_SCOPE) + + endif () + +endfunction () + + + diff --git a/CDEPS-interface/CDEPS/datm/CMakeLists.txt b/CDEPS-interface/CDEPS/datm/CMakeLists.txt new file mode 100644 index 0000000000..b22ee6be92 --- /dev/null +++ b/CDEPS-interface/CDEPS/datm/CMakeLists.txt @@ -0,0 +1,40 @@ +project(datm Fortran) +set(SRCFILES atm_comp_nuopc.F90 + datm_datamode_clmncep_mod.F90 + datm_datamode_cplhist_mod.F90 + datm_datamode_core2_mod.F90 + datm_datamode_jra_mod.F90 + datm_datamode_gefs_mod.F90 + datm_datamode_era5_mod.F90 + datm_datamode_simple_mod.F90) + +foreach(FILE ${SRCFILES}) + if(EXISTS "${CASEROOT}/SourceMods/src.datm/${FILE}") + list(REMOVE_ITEM SRCFILES ${FILE}) + list(APPEND SRCFILES "${CASEROOT}/SourceMods/src.datm/${FILE}") + message("Using ${FILE} from ${CASEROOT}/SourceMods/src.datm") + endif() +endforeach() + +message("DATM srcfiles are ${SRCFILES}") + +add_library(datm ${SRCFILES}) + +add_dependencies(datm dshr streams) +target_include_directories (datm PRIVATE ${ESMF_F90COMPILEPATHS}) +target_include_directories (datm PRIVATE ${CMAKE_SOURCE_DIR}) +target_include_directories (datm PRIVATE ${PIO_Fortran_INCLUDE_DIR}) +if(NOT DISABLE_FoX) + target_include_directories (datm PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/../fox/include) +endif() + +if(BLD_STANDALONE) + # ESMX requires mod files + foreach (SRC ${SRCFILES}) + string(REGEX REPLACE "[.]F90$" ".mod" MOD ${SRC}) + if (NOT DEFINED CIMEROOT AND MOD STREQUAL atm_comp_nuopc.mod) + set(MOD cdeps_datm_comp.mod) + endif() + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${MOD}" DESTINATION include) + endforeach () +endif() diff --git a/CDEPS-interface/CDEPS/datm/atm_comp_nuopc.F90 b/CDEPS-interface/CDEPS/datm/atm_comp_nuopc.F90 new file mode 100644 index 0000000000..3f42df4776 --- /dev/null +++ b/CDEPS-interface/CDEPS/datm/atm_comp_nuopc.F90 @@ -0,0 +1,909 @@ +#ifdef CESMCOUPLED +module atm_comp_nuopc +#else +module cdeps_datm_comp +#endif + + !---------------------------------------------------------------------------- + ! This is the NUOPC cap for DATM + !---------------------------------------------------------------------------- + + use ESMF , only : ESMF_VM, ESMF_VMBroadcast + use ESMF , only : ESMF_Mesh, ESMF_GridComp, ESMF_SUCCESS, ESMF_LogWrite + use ESMF , only : ESMF_GridCompSetEntryPoint, ESMF_METHOD_INITIALIZE + use ESMF , only : ESMF_MethodRemove, ESMF_State, ESMF_Clock, ESMF_TimeInterval + use ESMF , only : ESMF_State, ESMF_Field, ESMF_LOGMSG_INFO, ESMF_ClockGet + use ESMF , only : ESMF_Time, ESMF_Alarm, ESMF_TimeGet, ESMF_TimeInterval + use ESMF , only : operator(+), ESMF_TimeIntervalGet, ESMF_ClockGetAlarm + use ESMF , only : ESMF_AlarmIsRinging, ESMF_AlarmRingerOff, ESMF_StateGet + use ESMF , only : ESMF_FieldGet, ESMF_MAXSTR, ESMF_VMBroadcast + use ESMF , only : ESMF_TraceRegionEnter, ESMF_TraceRegionExit, ESMF_GridCompGet + use NUOPC , only : NUOPC_CompDerive, NUOPC_CompSetEntryPoint, NUOPC_CompSpecialize + use NUOPC , only : NUOPC_CompAttributeGet, NUOPC_Advertise + use NUOPC_Model , only : model_routine_SS => SetServices + use NUOPC_Model , only : model_label_Advance => label_Advance + use NUOPC_Model , only : model_label_SetRunClock => label_SetRunClock + use NUOPC_Model , only : model_label_Finalize => label_Finalize + use NUOPC_Model , only : NUOPC_ModelGet, setVM + use shr_kind_mod , only : r8=>shr_kind_r8, i8=>shr_kind_i8, cl=>shr_kind_cl, cs=>shr_kind_cs + use shr_const_mod , only : shr_const_cday + use shr_sys_mod , only : shr_sys_abort + use shr_cal_mod , only : shr_cal_ymd2date + use shr_log_mod , only : shr_log_setLogUnit + use dshr_methods_mod , only : dshr_state_diagnose, chkerr, memcheck + use dshr_strdata_mod , only : shr_strdata_type, shr_strdata_init_from_config, shr_strdata_advance + use dshr_strdata_mod , only : shr_strdata_get_stream_pointer, shr_strdata_setOrbs + use dshr_mod , only : dshr_model_initphase, dshr_init, dshr_restart_write + use dshr_mod , only : dshr_state_setscalar, dshr_set_runclock, dshr_log_clock_advance + use dshr_mod , only : dshr_mesh_init, dshr_check_restart_alarm, dshr_restart_read + use dshr_mod , only : dshr_orbital_init, dshr_orbital_update + use dshr_dfield_mod , only : dfield_type, dshr_dfield_add, dshr_dfield_copy + use dshr_fldlist_mod , only : fldlist_type, dshr_fldlist_add, dshr_fldlist_realize + + use datm_datamode_core2_mod , only : datm_datamode_core2_advertise + use datm_datamode_core2_mod , only : datm_datamode_core2_init_pointers + use datm_datamode_core2_mod , only : datm_datamode_core2_advance + + use datm_datamode_jra_mod , only : datm_datamode_jra_advertise + use datm_datamode_jra_mod , only : datm_datamode_jra_init_pointers + use datm_datamode_jra_mod , only : datm_datamode_jra_advance + + use datm_datamode_clmncep_mod , only : datm_datamode_clmncep_advertise + use datm_datamode_clmncep_mod , only : datm_datamode_clmncep_init_pointers + use datm_datamode_clmncep_mod , only : datm_datamode_clmncep_advance + + use datm_datamode_cplhist_mod , only : datm_datamode_cplhist_advertise + use datm_datamode_cplhist_mod , only : datm_datamode_cplhist_init_pointers + use datm_datamode_cplhist_mod , only : datm_datamode_cplhist_advance + + use datm_datamode_era5_mod , only : datm_datamode_era5_advertise + use datm_datamode_era5_mod , only : datm_datamode_era5_init_pointers + use datm_datamode_era5_mod , only : datm_datamode_era5_advance + + use datm_datamode_gefs_mod , only : datm_datamode_gefs_advertise + use datm_datamode_gefs_mod , only : datm_datamode_gefs_init_pointers + use datm_datamode_gefs_mod , only : datm_datamode_gefs_advance + + use datm_datamode_simple_mod , only : datm_datamode_simple_advertise + use datm_datamode_simple_mod , only : datm_datamode_simple_init_pointers + use datm_datamode_simple_mod , only : datm_datamode_simple_advance + + implicit none + private ! except + + public :: SetServices + public :: SetVM + private :: InitializeAdvertise + private :: InitializeRealize + private :: ModelAdvance + private :: datm_comp_run + private :: ModelFinalize + + !-------------------------------------------------------------------------- + ! Private module data + !-------------------------------------------------------------------------- + + type(shr_strdata_type) :: sdat + type(ESMF_Mesh) :: model_mesh ! model mesh + character(len=128) :: flds_scalar_name = '' + integer :: flds_scalar_num = 0 + integer :: flds_scalar_index_nx = 0 + integer :: flds_scalar_index_ny = 0 + integer :: flds_scalar_index_nextsw_cday = 0 + integer :: mpicom ! mpi communicator + integer :: my_task ! my task in mpi communicator mpicom + logical :: mainproc ! true of my_task == main_task + integer :: inst_index ! number of current instance (ie. 1) + character(len=16) :: inst_suffix = "" ! char string associated with instance (ie. "_0001" or "") + integer :: logunit ! logging unit number + logical :: restart_read ! start from restart + character(CL) :: case_name ! case name + character(len=*) , parameter :: nullstr = 'null' + + ! datm_in namelist input + character(CL) :: nlfilename = nullstr ! filename to obtain namelist info from + character(CL) :: streamfilename = nullstr ! filename to obtain stream info from + character(CL) :: dataMode = nullstr ! flags physics options wrt input data + character(CL) :: model_meshfile = nullstr ! full pathname to model meshfile + character(CL) :: model_maskfile = nullstr ! full pathname to obtain mask from + integer :: iradsw = 0 ! radiation interval (input namelist) + logical :: nextsw_cday_calc_cam7 ! true => use logic appropriate to cam7 (and later) for calculating nextsw_cday + character(CL) :: factorFn_mesh = 'null' ! file containing correction factors mesh + character(CL) :: factorFn_data = 'null' ! file containing correction factors data + logical :: flds_presaero = .false. ! true => send valid prescribed aero fields to mediator + logical :: flds_presndep = .false. ! true => send valid prescribed ndep fields to mediator + logical :: flds_preso3 = .false. ! true => send valid prescribed ozone fields to mediator + logical :: flds_co2 = .false. ! true => send prescribed co2 to mediator + logical :: flds_wiso = .false. ! true => send water isotopes to mediator + + character(CL) :: bias_correct = nullstr ! send bias correction fields to coupler + character(CL) :: anomaly_forcing(8) = nullstr ! send anomaly forcing fields to coupler + + character(CL) :: restfilm = nullstr ! model restart file namelist + integer :: nx_global ! global nx + integer :: ny_global ! global ny + logical :: skip_restart_read = .false. ! true => skip restart read in continuation run + logical :: export_all = .false. ! true => export all fields, do not check connected or not + + ! linked lists + type(fldList_type) , pointer :: fldsImport => null() + type(fldList_type) , pointer :: fldsExport => null() + type(dfield_type) , pointer :: dfields => null() + + ! model mask and model fraction + real(r8), pointer :: model_frac(:) => null() + integer , pointer :: model_mask(:) => null() + + ! constants + integer :: idt ! integer model timestep + logical :: diagnose_data = .true. + integer , parameter :: main_task = 0 ! task number of main task +#ifdef CESMCOUPLED + character(*) , parameter :: modName = "(atm_comp_nuopc)" +#else + character(*) , parameter :: modName = "(cdeps_datm_comp)" +#endif + + character(*), parameter :: u_FILE_u = & + __FILE__ + +!=============================================================================== +contains +!=============================================================================== + + subroutine SetServices(gcomp, rc) + type(ESMF_GridComp) :: gcomp + integer, intent(out) :: rc + + ! local variables + character(len=*),parameter :: subname=trim(modName)//':(SetServices) ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + call ESMF_LogWrite(subname//' called', ESMF_LOGMSG_INFO) + + ! the NUOPC gcomp component will register the generic methods + call NUOPC_CompDerive(gcomp, model_routine_SS, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! switching to IPD versions + call ESMF_GridCompSetEntryPoint(gcomp, ESMF_METHOD_INITIALIZE, & + userRoutine=dshr_model_initphase, phase=0, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! set entry point for methods that require specific implementation + call NUOPC_CompSetEntryPoint(gcomp, ESMF_METHOD_INITIALIZE, & + phaseLabelList=(/"IPDv01p1"/), userRoutine=InitializeAdvertise, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call NUOPC_CompSetEntryPoint(gcomp, ESMF_METHOD_INITIALIZE, & + phaseLabelList=(/"IPDv01p3"/), userRoutine=InitializeRealize, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! attach specializing method(s) + call NUOPC_CompSpecialize(gcomp, specLabel=model_label_Advance, specRoutine=ModelAdvance, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_MethodRemove(gcomp, label=model_label_SetRunClock, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call NUOPC_CompSpecialize(gcomp, specLabel=model_label_SetRunClock, specRoutine=dshr_set_runclock, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call NUOPC_CompSpecialize(gcomp, specLabel=model_label_Finalize, specRoutine=ModelFinalize, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_LogWrite(subname//' done', ESMF_LOGMSG_INFO) + + end subroutine SetServices + + !=============================================================================== + + subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) + use shr_nl_mod, only: shr_nl_find_group_name + ! input/output variables + type(ESMF_GridComp) :: gcomp + type(ESMF_State) :: importState, exportState + type(ESMF_Clock) :: clock + integer, intent(out) :: rc + + ! local variables + integer :: nu ! unit number + integer :: ierr ! error code + integer :: bcasttmp(10) + character(CL) :: nextsw_cday_calc + type(ESMF_VM) :: vm + character(len=*),parameter :: subname=trim(modName) // ':(InitializeAdvertise) ' + character(*) ,parameter :: F00 = "('(" // trim(modName) // ") ',8a)" + character(*) ,parameter :: F01 = "('(" // trim(modName) // ") ',a,2x,i8)" + character(*) ,parameter :: F02 = "('(" // trim(modName) // ") ',a,l6)" + !------------------------------------------------------------------------------- + + namelist / datm_nml / & + datamode, & + model_meshfile, & + model_maskfile, & + nx_global, & + ny_global, & + restfilm, & + iradsw, & + nextsw_cday_calc, & + factorFn_data, & + factorFn_mesh, & + flds_presaero, & + flds_co2, & + flds_wiso, & + bias_correct, & + anomaly_forcing, & + skip_restart_read, & + flds_presndep, & + flds_preso3, & + export_all + + rc = ESMF_SUCCESS + + ! Initialize locally-declared namelist items to default values + nextsw_cday_calc = 'cam6' + + call NUOPC_CompAttributeGet(gcomp, name='case_name', value=case_name, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! Obtain flds_scalar values, mpi values, multi-instance values and + ! set logunit and set shr logging to my log file + call dshr_init(gcomp, 'ATM', mpicom, my_task, inst_index, inst_suffix, & + flds_scalar_name, flds_scalar_num, flds_scalar_index_nx, flds_scalar_index_ny, & + logunit, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! Determine logical mainproc + mainproc = (my_task == main_task) + + ! Read atm_nml from nlfilename + if (my_task == main_task) then + nlfilename = "datm_in"//trim(inst_suffix) + open (newunit=nu,file=trim(nlfilename),status="old",action="read") + call shr_nl_find_group_name(nu, 'datm_nml', status=ierr) + if (ierr > 0) then + write(logunit,*) 'ERROR: reading input namelist, '//trim(nlfilename)//' iostat=',ierr + call shr_sys_abort(subName//': namelist read error '//trim(nlfilename)) + end if + read (nu,nml=datm_nml,iostat=ierr) + close(nu) + if (ierr > 0) then + write(logunit,*) 'ERROR: reading input namelist, '//trim(nlfilename)//' iostat=',ierr + call shr_sys_abort(subName//': namelist read error '//trim(nlfilename)) + end if + bcasttmp = 0 + bcasttmp(1) = nx_global + bcasttmp(2) = ny_global + bcasttmp(3) = iradsw + if(flds_presaero) bcasttmp(4) = 1 + if(flds_presndep) bcasttmp(5) = 1 + if(flds_preso3) bcasttmp(6) = 1 + if(flds_co2) bcasttmp(7) = 1 + if(flds_wiso) bcasttmp(8) = 1 + if(skip_restart_read) bcasttmp(9) = 1 + if(export_all) bcasttmp(10) = 1 + end if + + call ESMF_GridCompGet(gcomp, vm=vm, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_VMBroadcast(vm, datamode, CL, main_task, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_VMBroadcast(vm, bias_correct, CL, main_task, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_VMBroadcast(vm, anomaly_forcing, CL*8, main_task, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_VMBroadcast(vm, model_meshfile, CL, main_task, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_VMBroadcast(vm, model_maskfile, CL, main_task, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_VMBroadcast(vm, factorFn_data, CL, main_task, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_VMBroadcast(vm, factorFn_mesh, CL, main_task, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_VMBroadcast(vm, restfilm, CL, main_task, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_VMBroadcast(vm, nextsw_cday_calc, CL, main_task, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_VMBroadcast(vm, bcasttmp, 10, main_task, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + nx_global = bcasttmp(1) + ny_global = bcasttmp(2) + iradsw = bcasttmp(3) + flds_presaero = (bcasttmp(4) == 1) + flds_presndep = (bcasttmp(5) == 1) + flds_preso3 = (bcasttmp(6) == 1) + flds_co2 = (bcasttmp(7) == 1) + flds_wiso = (bcasttmp(8) == 1) + skip_restart_read = (bcasttmp(9) == 1) + export_all = (bcasttmp(10) == 1) + + if (nextsw_cday_calc == 'cam7') then + nextsw_cday_calc_cam7 = .true. + else if (nextsw_cday_calc == 'cam6') then + nextsw_cday_calc_cam7 = .false. + else + call shr_sys_abort(' ERROR illegal datm nextsw_cday_calc = '//trim(nextsw_cday_calc)) + end if + + ! write namelist input to standard out + if (my_task == main_task) then + write(logunit,F00)' case_name = ',trim(case_name) + write(logunit,F00)' datamode = ',trim(datamode) + write(logunit,F00)' model_meshfile = ',trim(model_meshfile) + write(logunit,F00)' model_maskfile = ',trim(model_maskfile) + write(logunit,F01)' nx_global = ',nx_global + write(logunit,F01)' ny_global = ',ny_global + write(logunit,F00)' restfilm = ',trim(restfilm) + write(logunit,F01)' iradsw = ',iradsw + write(logunit,F00)' nextsw_cday_calc = ', trim(nextsw_cday_calc) + write(logunit,F00)' factorFn_data = ',trim(factorFn_data) + write(logunit,F00)' factorFn_mesh = ',trim(factorFn_mesh) + write(logunit,F02)' flds_presaero = ',flds_presaero + write(logunit,F02)' flds_presndep = ',flds_presndep + write(logunit,F02)' flds_preso3 = ',flds_preso3 + write(logunit,F02)' flds_co2 = ',flds_co2 + write(logunit,F02)' flds_wiso = ',flds_wiso + write(logunit,F02)' skip_restart_read = ',skip_restart_read + write(logunit,F02)' export_all = ',export_all + end if + + ! Validate sdat datamode + if (mainproc) write(logunit,*) ' datm datamode = ',trim(datamode) + if ( trim(datamode) == 'CORE2_NYF' .or. & + trim(datamode) == 'CORE2_IAF' .or. & + trim(datamode) == 'CORE_IAF_JRA' .or. & + trim(datamode) == 'CLMNCEP' .or. & + trim(datamode) == 'CPLHIST' .or. & + trim(datamode) == 'GEFS' .or. & + trim(datamode) == 'ERA5' .or. & + trim(datamode) == 'SIMPLE') then + else + call shr_sys_abort(' ERROR illegal datm datamode = '//trim(datamode)) + endif + + ! Advertise datm fields + select case (trim(datamode)) + case ('CORE2_NYF', 'CORE2_IAF') + call datm_datamode_core2_advertise(exportState, fldsExport, flds_scalar_name, & + flds_co2, flds_wiso, flds_presaero, flds_presndep, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + case ('CORE_IAF_JRA') + call datm_datamode_jra_advertise(exportState, fldsExport, flds_scalar_name, & + flds_co2, flds_wiso, flds_presaero, flds_presndep, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + case ('CLMNCEP') + call datm_datamode_clmncep_advertise(exportState, fldsExport, flds_scalar_name, & + flds_co2, flds_wiso, flds_presaero, flds_presndep, flds_preso3, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + case ('CPLHIST') + call datm_datamode_cplhist_advertise(exportState, fldsExport, flds_scalar_name, & + flds_co2, flds_wiso, flds_presaero, flds_presndep, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + case ('ERA5') + call datm_datamode_era5_advertise(exportState, fldsExport, flds_scalar_name, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + case ('GEFS') + call datm_datamode_gefs_advertise(exportState, fldsExport, flds_scalar_name, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + case ('SIMPLE') + call datm_datamode_simple_advertise(exportState, fldsExport, flds_scalar_name, & + nlfilename, my_task, vm, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end select + + end subroutine InitializeAdvertise + + !=============================================================================== + + subroutine InitializeRealize(gcomp, importState, exportState, clock, rc) + + ! input/output variables + type(ESMF_GridComp) :: gcomp + type(ESMF_State) :: importState, exportState + type(ESMF_Clock) :: clock + integer, intent(out) :: rc + + ! local variables + type(ESMF_TimeInterval) :: timeStep + type(ESMF_TIME) :: currTime + integer :: current_ymd ! model date + integer :: current_year ! model year + integer :: current_mon ! model month + integer :: current_day ! model day + integer :: current_tod ! model sec into model date + integer(i8) :: stepno ! step number + real(r8) :: nextsw_cday ! calendar of next atm sw + character(CL) :: cvalue ! character string for input config + real(R8) :: orbEccen ! orb eccentricity (unist-less) + real(R8) :: orbMvelpp ! orb moving vernal eqa (radians) + real(R8) :: orbLambm0 ! orb mean long of perhelion (radians) + real(R8) :: orbObliqr ! orb obliquity (radians) + logical :: isPresent, isSet + real(R8) :: dayofYear + character(len=*), parameter :: subname=trim(modName)//':(InitializeRealize) ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + call ESMF_LogWrite(subname//' called', ESMF_LOGMSG_INFO) + + ! Initialize mesh, restart flag, compid, and logunit + call ESMF_TraceRegionEnter('datm_strdata_init') + call dshr_mesh_init(gcomp, sdat, nullstr, logunit, 'ATM', nx_global, ny_global, & + model_meshfile, model_maskfile, model_mesh, model_mask, model_frac, restart_read, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! Initialize stream data type + streamfilename = 'datm.streams'//trim(inst_suffix) +#ifndef DISABLE_FoX + streamfilename = trim(streamfilename)//'.xml' +#endif + call shr_strdata_init_from_config(sdat, streamfilename, model_mesh, clock, 'ATM', logunit, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_TraceRegionExit('datm_strdata_init') + + ! NUOPC_Realize "realizes" a previously advertised field in the importState and exportState + ! by replacing the advertised fields with the newly created fields of the same name. + call dshr_fldlist_realize( exportState, fldsExport, flds_scalar_name, flds_scalar_num, model_mesh, & + subname//':datmExport', export_all, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_fldlist_realize( importState, fldsImport, flds_scalar_name, flds_scalar_num, model_mesh, & + subname//':datmImport', .false., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! Get the time to interpolate the stream data to + call ESMF_ClockGet( clock, currTime=currTime, timeStep=timeStep, advanceCount=stepno, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_TimeGet(currTime, yy=current_year, mm=current_mon, dd=current_day, s=current_tod, & + dayofYear_r8=dayofYear, rc=rc ) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_cal_ymd2date(current_year, current_mon, current_day, current_ymd) + + ! Get model timestep (idt is module variable) + call ESMF_TimeIntervalGet( timeStep, s=idt, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! Initialize and update orbital values + call dshr_orbital_init(gcomp, logunit, my_task == main_task, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_orbital_update(currTime, logunit, my_task == main_task, & + orbEccen, orbObliqr, orbLambm0, orbMvelpp, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! Run datm + call datm_comp_run(gcomp, importstate, exportstate, current_ymd, current_tod, current_mon, & + orbEccen, orbMvelpp, orbLambm0, orbObliqr, restart_write=.false., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! Add scalars to export state + call dshr_state_SetScalar(dble(nx_global),flds_scalar_index_nx, exportState, flds_scalar_name, flds_scalar_num, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_SetScalar(dble(ny_global),flds_scalar_index_ny, exportState, flds_scalar_name, flds_scalar_num, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call NUOPC_CompAttributeGet(gcomp, name="ScalarFieldIdxNextSwCday", value=cvalue, & + isPresent=isPresent, isSet=isSet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (isPresent .and. isSet) then + read (cvalue,*) flds_scalar_index_nextsw_cday + else + call shr_sys_abort(subname//'Need to set attribute ScalarFieldIdxNextSwCday') + endif + + nextsw_cday = getNextRadCDay(dayofYear, current_tod, stepno, idt, iradsw) + call dshr_state_SetScalar(nextsw_cday, flds_scalar_index_nextsw_cday, exportState, flds_scalar_name, flds_scalar_num, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + end subroutine InitializeRealize + + !=============================================================================== + subroutine ModelAdvance(gcomp, rc) + + ! input/output variables + type(ESMF_GridComp) :: gcomp + integer, intent(out) :: rc + + ! local variables + type(ESMF_State) :: importState, exportState + type(ESMF_Clock) :: clock + type(ESMF_Time) :: currTime + type(ESMF_Time) :: nextTime + type(ESMF_TimeInterval) :: timeStep + real(r8) :: nextsw_cday + logical :: restart_write ! restart alarm is ringing + integer :: next_ymd ! model date + integer :: next_tod ! model sec into model date + integer :: yr, mon, day ! year, month, day + integer(i8) :: stepno ! step number + real(R8) :: orbEccen ! orb eccentricity (unit-less) + real(R8) :: orbMvelpp ! orb moving vernal eq (radians) + real(R8) :: orbLambm0 ! orb mean long of perhelion (radians) + real(R8) :: orbObliqr ! orb obliquity (radians) + real(R8) :: dayofYear + character(len=*),parameter :: subname=trim(modName)//':(ModelAdvance) ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + call ESMF_TraceRegionEnter(subname) + call shr_log_setLogUnit(logunit) + call memcheck(subname, 5, my_task==main_task) + + ! Query the Component for its clock, importState and exportState + call NUOPC_ModelGet(gcomp, modelClock=clock, importState=importState, exportState=exportState, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! For nuopc - the component clock is advanced at the end of the time interval + ! For these to match for now - need to advance nuopc one timestep ahead for + ! shr_strdata time interpolation + call ESMF_ClockGet( clock, currTime=currTime, timeStep=timeStep, advanceCount=stepno, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + nextTime = currTime + timeStep + call ESMF_TimeGet( nextTime, yy=yr, mm=mon, dd=day, s=next_tod, dayofYear_r8=dayofYear, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_cal_ymd2date(yr, mon, day, next_ymd) + + ! Update the orbital values + call dshr_orbital_update(nextTime, logunit, my_task == main_task, & + orbEccen, orbObliqr, orbLambm0, orbMvelpp, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + restart_write = dshr_check_restart_alarm(clock, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! Run datm + call ESMF_TraceRegionEnter('datm_run') + call datm_comp_run(gcomp, importstate, exportstate, next_ymd, next_tod, mon, & + orbEccen, orbMvelpp, orbLambm0, orbObliqr, restart_write, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_TraceRegionExit('datm_run') + + ! Update nextsw_cday for scalar data + ! Use nextYMD and nextTOD here since since the component - clock is advance at the END of the time interval + + nextsw_cday = getNextRadCDay(dayofYear, next_tod, stepno, idt, iradsw) + + call dshr_state_SetScalar(nextsw_cday, flds_scalar_index_nextsw_cday, exportState, flds_scalar_name, flds_scalar_num, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_TraceRegionExit(subname) + + end subroutine ModelAdvance + + !=============================================================================== + subroutine datm_comp_run(gcomp, importState, exportState, target_ymd, target_tod, target_mon, & + orbEccen, orbMvelpp, orbLambm0, orbObliqr, restart_write, rc) + use nuopc_shr_methods, only : shr_get_rpointer_name + ! ---------------------------------- + ! run method for datm model + ! ---------------------------------- + + ! input/output variables + type(ESMF_GridComp) , intent(inout) :: gcomp + type(ESMF_State) , intent(inout) :: importState + type(ESMF_State) , intent(inout) :: exportState + integer , intent(in) :: target_ymd ! model date + integer , intent(in) :: target_tod ! model sec into model date + integer , intent(in) :: target_mon ! model month + real(R8) , intent(in) :: orbEccen ! orb eccentricity (unit-less) + real(R8) , intent(in) :: orbMvelpp ! orb moving vernal eq (radians) + real(R8) , intent(in) :: orbLambm0 ! orb mean long of perhelion (radians) + real(R8) , intent(in) :: orbObliqr ! orb obliquity (radians) + logical , intent(in) :: restart_write + integer , intent(out) :: rc + + ! local variables + logical :: first_time = .true. + character(len=CL) :: rpfile + character(*), parameter :: subName = '(datm_comp_run) ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + call ESMF_TraceRegionEnter('DATM_RUN') + + !-------------------- + ! First time initialization + !-------------------- + + if (first_time) then + ! Initialize dfields + call datm_init_dfields(rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! Initialize datamode module ponters + select case (trim(datamode)) + case('CORE2_NYF','CORE2_IAF') + call datm_datamode_core2_init_pointers(exportState, sdat, datamode, factorfn_mesh, factorfn_data, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + case('CORE_IAF_JRA') + call datm_datamode_jra_init_pointers(exportState, sdat, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + case('CLMNCEP') + call datm_datamode_clmncep_init_pointers(importState, exportState, sdat, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + case('CPLHIST') + call datm_datamode_cplhist_init_pointers(importState, exportState, sdat, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + case('ERA5') + call datm_datamode_era5_init_pointers(exportState, sdat, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + case('GEFS') + call datm_datamode_gefs_init_pointers(exportState, sdat, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + case('SIMPLE') + call datm_datamode_simple_init_pointers(exportState, sdat, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end select + + ! Read restart if needed + if (restart_read .and. .not. skip_restart_read) then + call shr_get_rpointer_name(gcomp, 'atm', target_ymd, target_tod, rpfile, 'read', rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + select case (trim(datamode)) + case('CORE2_NYF','CORE2_IAF','CORE_IAF_JRA','CLMNCEP','CPLHIST','ERA5','GEFS','SIMPLE') + call dshr_restart_read(restfilm, rpfile, logunit, my_task, mpicom, sdat, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + case default + call shr_sys_abort(subName//'datamode '//trim(datamode)//' not recognized') + end select + end if + + ! reset first_time + first_time = .false. + end if + + !-------------------- + ! Advance datm streams + !-------------------- + + ! set data needed for cosz t-interp method + call shr_strdata_setOrbs(sdat, orbEccen, orbMvelpp, orbLambm0, orbObliqr, idt) + + ! time and spatially interpolate to model time and grid + call ESMF_TraceRegionEnter('datm_strdata_advance') + call shr_strdata_advance(sdat, target_ymd, target_tod, logunit, 'datm', rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_TraceRegionExit('datm_strdata_advance') + + ! copy all fields from streams to export state as default + ! This automatically will update the fields in the export state + call ESMF_TraceRegionEnter('datm_dfield_copy') + call dshr_dfield_copy(dfields, sdat, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_TraceRegionExit('datm_dfield_copy') + + ! Determine data model behavior based on the mode + call ESMF_TraceRegionEnter('datm_datamode') + select case (trim(datamode)) + case('CORE2_NYF','CORE2_IAF') + call datm_datamode_core2_advance(datamode, target_ymd, target_tod, target_mon, & + sdat%model_calendar, factorfn_mesh, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + case('CORE_IAF_JRA') + call datm_datamode_jra_advance(exportstate, target_ymd, target_tod, sdat%model_calendar, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + case('CLMNCEP') + call datm_datamode_clmncep_advance(mainproc, logunit, mpicom, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + case('CPLHIST') + call datm_datamode_cplhist_advance(mainproc, logunit, mpicom, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + case('ERA5') + call datm_datamode_era5_advance(exportstate, mainproc, logunit, mpicom, target_ymd, & + target_tod, sdat%model_calendar, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + case('GEFS') + call datm_datamode_gefs_advance(exportstate, mainproc, logunit, mpicom, target_ymd, & + target_tod, sdat%model_calendar, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + case('SIMPLE') + call datm_datamode_simple_advance(target_ymd, target_tod, target_mon, & + sdat%model_calendar, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end select + + ! Write restarts if needed + if (restart_write) then + call shr_get_rpointer_name(gcomp, 'atm', target_ymd, target_tod, rpfile, 'write', rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + select case (trim(datamode)) + case('CORE2_NYF','CORE2_IAF','CORE_IAF_JRA','CLMNCEP','CPLHIST','ERA5','GEFS','SIMPLE') + call dshr_restart_write(rpfile, case_name, 'datm', inst_suffix, target_ymd, target_tod, logunit, & + my_task, sdat, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + case default + call shr_sys_abort(subName//'datamode '//trim(datamode)//' not recognized') + end select + end if + + ! Log output for model date + if (mainproc) write(logunit,*) 'atm : model date ', target_ymd, target_tod + + ! Diagnostics + if (diagnose_data) then + call dshr_state_diagnose(exportState, flds_scalar_name, subname//':ES', rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + call ESMF_TraceRegionExit('datm_datamode') + call ESMF_TraceRegionExit('DATM_RUN') + + !-------- + contains + !-------- + + subroutine datm_init_dfields(rc) + ! ----------------------------- + ! Initialize dfields arrays + ! (for export fields that have a corresponding stream field) + ! ----------------------------- + + ! input/output parameters + integer, intent(out) :: rc + + ! local variables + integer :: n + character(CS) :: strm_flds2(2) + character(CS) :: strm_flds3(3) + character(CS) :: strm_flds4(4) + integer :: rank + integer :: fieldcount + type(ESMF_Field) :: lfield + character(ESMF_MAXSTR) ,pointer :: lfieldnames(:) + character(*), parameter :: subName = "(datm_init_dfields) " + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + call ESMF_StateGet(exportState, itemCount=fieldCount, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + allocate(lfieldnames(fieldCount)) + call ESMF_StateGet(exportState, itemNameList=lfieldnames, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + do n = 1, fieldCount + call ESMF_LogWrite(trim(subname)//': field name = '//trim(lfieldnames(n)), ESMF_LOGMSG_INFO) + call ESMF_StateGet(exportState, itemName=trim(lfieldnames(n)), field=lfield, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call ESMF_FieldGet(lfield, rank=rank, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + if (rank == 1) then + call dshr_dfield_add( dfields, sdat, trim(lfieldnames(n)), trim(lfieldnames(n)), & + exportState, logunit, mainproc, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + else if (rank == 2) then + ! The following maps stream input fields to export fields that have an ungridded dimension + ! TODO: in the future it might be better to change the format of the streams file to have two more entries + ! that could denote how the stream variables are mapped to export fields that have an ungridded dimension + + select case (trim(lfieldnames(n))) + case('Faxa_bcph') + strm_flds3 = (/'Faxa_bcphidry', 'Faxa_bcphodry', 'Faxa_bcphiwet'/) + call dshr_dfield_add(dfields, sdat, trim(lfieldnames(n)), strm_flds3, exportState, logunit, mainproc, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + case('Faxa_ocph') + strm_flds3 = (/'Faxa_ocphidry', 'Faxa_ocphodry', 'Faxa_ocphiwet'/) + call dshr_dfield_add(dfields, sdat, trim(lfieldnames(n)), strm_flds3, exportState, logunit, mainproc, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + case('Faxa_dstwet') + strm_flds4 = (/'Faxa_dstwet1', 'Faxa_dstwet2', 'Faxa_dstwet3', 'Faxa_dstwet4'/) + call dshr_dfield_add(dfields, sdat, trim(lfieldnames(n)), strm_flds4, exportState, logunit, mainproc, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + case('Faxa_dstdry') + strm_flds4 = (/'Faxa_dstdry1', 'Faxa_dstdry2', 'Faxa_dstdry3', 'Faxa_dstdry4'/) + call dshr_dfield_add(dfields, sdat, trim(lfieldnames(n)), strm_flds4, exportState, logunit, mainproc, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + case('Faxa_rainc_wiso') + strm_flds3 = (/'Faxa_rainc_16O', 'Faxa_rainc_18O', 'Faxa_rainc_HDO'/) + call dshr_dfield_add(dfields, sdat, trim(lfieldnames(n)), strm_flds3, exportState, logunit, mainproc, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + case('Faxa_rainl_wiso') + strm_flds3 = (/'Faxa_rainl_16O', 'Faxa_rainl_18O', 'Faxa_rainl_HDO'/) + call dshr_dfield_add(dfields, sdat, trim(lfieldnames(n)), strm_flds3, exportState, logunit, mainproc, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + case('Faxa_snowc_wiso') + strm_flds3 = (/'Faxa_snowc_16O', 'Faxa_snowc_18O', 'Faxa_snowc_HDO'/) + call dshr_dfield_add(dfields, sdat, trim(lfieldnames(n)), strm_flds3, exportState, logunit, mainproc, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + case('Faxa_snowl_wiso') + strm_flds3 = (/'Faxa_snowl_16O', 'Faxa_snowl_18O', 'Faxa_snowl_HDO'/) + call dshr_dfield_add(dfields, sdat, trim(lfieldnames(n)), strm_flds3, exportState, logunit, mainproc, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + case('Faxa_ndep') + strm_flds2 = (/'Faxa_ndep_nhx', 'Faxa_ndep_noy'/) + call dshr_dfield_add(dfields, sdat, trim(lfieldnames(n)), strm_flds2, exportState, logunit, mainproc, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + case('cpl_scalars') + continue + case default + call shr_sys_abort(subName//'field '//trim(lfieldnames(n))//' not recognized') + end select + end if + end do + end subroutine datm_init_dfields + + end subroutine datm_comp_run + + !=============================================================================== + real(R8) function getNextRadCDay( julday, tod, stepno, dtime, iradsw ) + + ! Return the calendar day of the next radiation time-step. + ! General Usage: nextswday = getNextRadCDay(curr_date). iradsw is + ! the frequency to update the next shortwave in number of steps + ! (or hours if negative). + ! -- values greater than 1 set the next radiation to the present time plus either 1 or + ! 2 timesteps (depending on the value of nextsw_cday_calc_cam7) every iradsw timesteps. + ! -- values less than 0 set the next radiation to the present time plus either 1 or 2 + ! timesteps (depending on the value of nextsw_cday_calc_cam7) every -iradsw hours. + ! -- if iradsw is either 0 or 1, the next radiation time is the present time plus 1 timestep. + + ! input/output variables + real(r8) , intent(in) :: julday + integer , intent(in) :: tod + integer(i8) , intent(in) :: stepno + integer , intent(in) :: dtime + integer , intent(in) :: iradsw + + ! local variables + real(R8) :: nextsw_cday + integer :: liradsw + integer :: delta_radsw + character(*),parameter :: subName = '(getNextRadCDay) ' + !------------------------------------------------------------------------------- + + ! Note that stepno is obtained via the advancecount argument to + ! ESMF_GetClock and is the number of times the ESMF_Clock has been + ! advanced. The ESMF clock is actually advanced an additional time + ! (in order to trigger alarms) in the routine dshr_set_runclock + ! which is the specialized routine for the model_lable_SetRunClock. + ! This is called each time the ModelAdvance phase is called. Hence + ! stepno is not used to trigger the calculation of nextsw_cday. + + liradsw = iradsw + if (liradsw < 0) liradsw = nint((-liradsw *3600._r8)/dtime) + + if (liradsw > 1) then + delta_radsw = liradsw * dtime + if (nextsw_cday_calc_cam7) then + ! The logic in this block is consistent with the driver ordering in CAM7 and + ! later. So this is appropriate when using cplhist forcings generated from CAM7 + ! or later. + if (mod(tod,delta_radsw) == 0 .and. stepno > 0) then + nextsw_cday = julday + 1*dtime/shr_const_cday + else + nextsw_cday = -1._r8 + end if + else + if (mod(tod+dtime,delta_radsw) == 0 .and. stepno > 0) then + nextsw_cday = julday + 2*dtime/shr_const_cday + else + nextsw_cday = -1._r8 + end if + end if + else + nextsw_cday = julday + dtime/shr_const_cday + end if + getNextRadCDay = nextsw_cday + + end function getNextRadCDay + + !=============================================================================== + subroutine ModelFinalize(gcomp, rc) + type(ESMF_GridComp) :: gcomp + integer, intent(out) :: rc + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + if (my_task == main_task) then + write(logunit,*) + write(logunit,*) 'datm : end of main integration loop' + write(logunit,*) + end if + end subroutine ModelFinalize + +#ifdef CESMCOUPLED +end module atm_comp_nuopc +#else +end module cdeps_datm_comp +#endif diff --git a/CDEPS-interface/CDEPS/datm/cime_config/buildlib b/CDEPS-interface/CDEPS/datm/cime_config/buildlib new file mode 120000 index 0000000000..0c5e984ac2 --- /dev/null +++ b/CDEPS-interface/CDEPS/datm/cime_config/buildlib @@ -0,0 +1 @@ +../../cime_config/buildlib_comps \ No newline at end of file diff --git a/CDEPS-interface/CDEPS/datm/cime_config/buildnml b/CDEPS-interface/CDEPS/datm/cime_config/buildnml new file mode 100755 index 0000000000..28e341c022 --- /dev/null +++ b/CDEPS-interface/CDEPS/datm/cime_config/buildnml @@ -0,0 +1,341 @@ +#!/usr/bin/env python3 + +"""Namelist creator for CDEPS data atm model. +""" + +# Typically ignore this. +# pylint: disable=invalid-name + +# Disable these because this is our standard setup +# pylint: disable=wildcard-import,unused-wildcard-import,wrong-import-position + +import os, sys + +_CDEPS_CONFIG = os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir,os.pardir,"cime_config") +_CIMEROOT = os.environ.get("CIMEROOT") +if _CIMEROOT is None: + raise SystemExit("ERROR: must set CIMEROOT environment variable") +_LIBDIR = os.path.join(_CIMEROOT, "CIME", "Tools") +sys.path.append(_LIBDIR) +sys.path.append(_CDEPS_CONFIG) + +from datetime import datetime +from standard_script_setup import * +from CIME.case import Case +from CIME.nmlgen import NamelistGenerator +from CIME.utils import expect, safe_copy, SharedArea +from CIME.buildnml import create_namelist_infile, parse_input, copy_inputs_to_rundir +from CIME.XML.files import Files +from CIME.XML.inputdata import Inputdata +from stream_cdeps import StreamCDEPS + +logger = logging.getLogger(__name__) + +def _get_neon_data_availability(case, neonsite): + """ + Read the NEON inventory file and check availablity of tower data for this case. + Put available data in datavaliddate list and return it + Currently the valid date information is not used + """ + rundir = case.get_value("RUNDIR") + fullpath = os.path.join(rundir,"listing.csv") + if not os.path.exists(fullpath): + inputdata = Inputdata() + protocol, address, user, passwd, _, _, inventory = inputdata.get_next_server(attributes={'CLM_USRDAT_NAME':'NEON'}) + success = case.check_input_data(protocol=protocol, address=address, download=True) + logger.debug("_get_neon_data_availablity: address {} inventory is {} success {}".format(address, inventory, success)) + + server = CIME.Servers.WGET.wget_login(address, user, passwd) + if server: + with SharedArea(): + success = server.getfile(inventory, fullpath) + expect(success, "Could not download NEON data listing file from server") + + expect(os.path.exists(fullpath), "Could not download NEON data listing file from server") + datavaliddate = [] + oldestdate = None + newestdate = None + neonatm = None + dataversion = case.get_value("NEONVERSION") + if dataversion == "latest": + dataversions = ["v3", "v2", "v1"] + else: + dataversions = [dataversion] + + for version in dataversions: + # Once a date range for a version has been determined for any version, the loop is complete. + # Eg, if data is available for v3, the loop will not continue to v2; + # however, if data is not available for v3, it will check for v2. + # Thus, it is important for dataversions to be listed from newest to oldest. + if not newestdate: + with open(fullpath, "r") as fd: + for line in fd.readlines(): + fpath, fname = os.path.split(line) + if fpath.endswith(f'cdeps/{version}/{neonsite}'): + neonatm, date, _ = line.strip().split(',') + if neonatm.endswith('.nc'): + neonatm = neonatm.split('/')[-1] + newestdate = datetime.strptime(neonatm[-10:],"%Y-%m.nc") + if not oldestdate: + oldestdate = datetime.strptime(neonatm[-10:],"%Y-%m.nc") + neonatm = f'cdeps/{version}/{neonsite}/'+neonatm + datavaliddate.append(neonatm) + if newestdate: + logger.info("Found tower data version {} for {} through {}".format(version, oldestdate, newestdate)) + datavaliddate.sort() + return datavaliddate + + expect(newestdate, "No tower data found on server for NEON site {}".format(neonsite)) + return None + +# pylint: disable=too-many-arguments,too-many-locals,too-many-branches,too-many-statements +#################################################################################### +def _create_namelists(case, confdir, inst_string, infile, nmlgen, data_list_path): +#################################################################################### + """Write out the namelist for this component. + + Most arguments are the same as those for `NamelistGenerator`. The + `inst_string` argument is used as a suffix to distinguish files for + different instances. The `confdir` argument is used to specify the directory + in which output files will be placed. + """ + + #---------------------------------------------------- + # Write out datm_in and datm.streams.xml + #---------------------------------------------------- + + caseroot = case.get_value("CASEROOT") + datm_mode = case.get_value("DATM_MODE") + datm_topo = case.get_value("DATM_TOPO") + datm_presaero = case.get_value("DATM_PRESAERO") + datm_presndep = case.get_value("DATM_PRESNDEP") + datm_preso3 = case.get_value("DATM_PRESO3") + clm_usrdat_name = case.get_value("CLM_USRDAT_NAME") + datm_co2_tseries = case.get_value("DATM_CO2_TSERIES") + atm_grid = case.get_value("ATM_GRID") + model_grid = case.get_value("GRID") + comp_lnd = case.get_value("COMP_LND") + + # Check for incompatible options. + if "CLM" in datm_mode and comp_lnd == "clm": + expect(datm_presaero != "none", + "A DATM_MODE for CLM is incompatible with DATM_PRESAERO=none.") + expect(datm_presndep != "none", + "A DATM_MODE for CLM is incompatible with DATM_PRESNDEP=none.") + expect(datm_preso3 != "none", + "A DATM_MODE for CLM is incompatible with DATM_PRESO3=none.") + expect(datm_topo != "none", + "A DATM_MODE for CLM is incompatible with DATM_TOPO=none.") + + # Log some settings. + logger.debug("DATM mode is {}".format(datm_mode)) + logger.debug("DATM grid is {}".format(atm_grid)) + logger.debug("DATM presaero mode is {}".format(datm_presaero)) + logger.debug("DATM presndep mode is {}".format(datm_presndep)) + logger.debug("DATM preso3 mode is {}".format(datm_preso3)) + logger.debug("DATM topo mode is {}".format(datm_topo)) + logger.debug("CLM_USRDAT_NAME is {}".format(clm_usrdat_name)) + + # Initialize namelist defaults + config = {} + available_neon_data = None + if 'CLM_USRDAT' in model_grid: + config['model_grid'] = 'CLM_USRDAT' + if 'NEON' in clm_usrdat_name: + neonsite = case.get_value("NEONSITE") + if neonsite: + config['neon'] = "True" + # download and use the listing.csv file to determine data availablity + available_neon_data = _get_neon_data_availability(case, neonsite) + if 'PLUMBER2' in clm_usrdat_name: + plumber2site = case.get_value('PLUMBER2SITE') + if plumber2site: + config['plumber'] = "True" + else: + config['model_grid'] = model_grid + + config['datm_mode'] = datm_mode + config['datm_co2_tseries'] = datm_co2_tseries + config['datm_presaero'] = datm_presaero + config['datm_presndep'] = datm_presndep + config['datm_preso3'] = datm_preso3 + config['clm_usrdat_name'] = clm_usrdat_name + + if case.get_value('PTS_LON'): + scol_lon = float(case.get_value('PTS_LON')) + else: + scol_lon = -999. + if case.get_value('PTS_LAT'): + scol_lat = float(case.get_value('PTS_LAT')) + else: + scol_lat = -999. + if case.get_value('ATM_DOMAIN_FILE'): + if scol_lon > -999. and scol_lat > -999. and case.get_value("ATM_DOMAIN_FILE") != "UNSET": + config['single_column'] = 'true' + else: + config['single_column'] = 'false' + + nmlgen.init_defaults(infile, config) + + # Generate datm_in + namelist_file = os.path.join(confdir, "datm_in") + nmlgen.write_output_file(namelist_file, data_list_path, groups=['datm_nml','const_forcing_nml']) + + # Determine streams + streamlist = nmlgen.get_streams() + if type(streamlist) == type(str()): + streamlist = [] + if datm_presaero != "none": + streamlist.append("presaero.{}".format(datm_presaero)) + if datm_presndep != "none": + streamlist.append("presndep.{}".format(datm_presndep)) + if datm_preso3 != "none": + streamlist.append("preso3.{}".format(datm_preso3)) + if datm_topo != "none": + streamlist.append("topo.{}".format(datm_topo)) + if datm_co2_tseries != "none": + streamlist.append("co2tseries.{}".format(datm_co2_tseries)) + if clm_usrdat_name == 'NEON.PRISM': + streamlist.append(clm_usrdat_name+"_PRECIP."+neonsite) + if clm_usrdat_name == 'NEON': + streamlist.append(clm_usrdat_name+".NEON_PRECIP."+neonsite) + if clm_usrdat_name == 'PLUMBER2': + streamlist.append(clm_usrdat_name+"."+plumber2site) + + bias_correct = nmlgen.get_value("bias_correct") + if bias_correct is not None: + streamlist.append(bias_correct) + anomaly_forcing = nmlgen.get_value("anomaly_forcing") + if anomaly_forcing[0] is not None: + streamlist += anomaly_forcing + + # Generate datm.streams.xml + outfile = os.path.join(confdir, "datm.streams"+inst_string+".xml" ) + schema_file = os.path.join(_CDEPS_CONFIG,"stream_definition_v2.0.xsd") + stream_file = os.path.join(_CDEPS_CONFIG,os.pardir, "datm","cime_config","stream_definition_datm.xml") + streams = StreamCDEPS(stream_file, schema_file) + streams.create_stream_xml(streamlist, case, outfile, data_list_path, + os.path.join(caseroot,'user_nl_datm_streams'+inst_string), + available_neon_data=available_neon_data) + + +#################################################################################### +def _create_drv_flds_in(case, confdir): +#################################################################################### + datm_preso3 = case.get_value("DATM_PRESO3") + + # for now we are hard-coding this file name and values because we only need it for ozone + if datm_preso3 != "none": + + # Generate drv_flds_in file + outfile = os.path.join(confdir, "drv_flds_in") + ozone_nl_name = "&ozone_coupling_nl" + ozone_freq_par = "atm_ozone_frequency" + ozone_freq_val = "'multiday_average'" + nl_fin = "/" + + with open(outfile, "w") as drv_fl: + drv_fl.write("{}\n".format(ozone_nl_name)) + drv_fl.write(" {} = {}\n".format(ozone_freq_par, ozone_freq_val)) + drv_fl.write("{}\n".format(nl_fin)) + + + +############################################################################### +def buildnml(case, caseroot, compname): +############################################################################### + rundir = case.get_value("RUNDIR") + inst_name = compname.upper()[1:] + ninst = case.get_value("NINST_"+inst_name) + if ninst is None: + ninst = case.get_value("NINST") + + # Determine configuration directory + confdir = os.path.join(caseroot,"Buildconf",compname + "conf") + if not os.path.isdir(confdir): + os.makedirs(confdir) + + #---------------------------------------------------- + # Construct the namelist generator + #---------------------------------------------------- + # Determine directory for user modified namelist_definitions.xml and namelist_defaults.xml + user_xml_dir = os.path.join(caseroot, "SourceMods", "src." + compname) + expect (os.path.isdir(user_xml_dir), + "user_xml_dir {} does not exist ".format(user_xml_dir)) + + # NOTE: User definition *replaces* existing definition. + files = Files(comp_interface="nuopc") + definition_file = [files.get_value("NAMELIST_DEFINITION_FILE", {"component":compname})] + + user_definition = os.path.join(user_xml_dir, "namelist_definition_"+compname+".xml") + if os.path.isfile(user_definition): + definition_file = [user_definition] + for file_ in definition_file: + expect(os.path.isfile(file_), "Namelist XML file {} not found!".format(file_)) + + # Create the namelist generator object - independent of instance + nmlgen = NamelistGenerator(case, definition_file, files=files) + + #---------------------------------------------------- + # Clear out old data. + #---------------------------------------------------- + data_list_path = os.path.join(caseroot, "Buildconf", compname+".input_data_list") + if os.path.exists(data_list_path): + os.remove(data_list_path) + + #---------------------------------------------------- + # Loop over instances + #---------------------------------------------------- + for inst_counter in range(1, ninst+1): + # determine instance string + inst_string = "" + if ninst > 1: + inst_string = '_' + '{:04d}'.format(inst_counter) + + # If multi-instance case does not have restart file, use + # single-case restart for each instance + rpointer = "rpointer." + compname + if (os.path.isfile(os.path.join(rundir,rpointer)) and + (not os.path.isfile(os.path.join(rundir,rpointer + inst_string)))): + safe_copy(os.path.join(rundir, rpointer), + os.path.join(rundir, rpointer + inst_string)) + + inst_string_label = inst_string + if not inst_string_label: + inst_string_label = "\"\"" + + # create namelist output infile using user_nl_file as input + user_nl_file = os.path.join(caseroot, "user_nl_" + compname + inst_string) + expect(os.path.isfile(user_nl_file), + "Missing required user_nl_file {} ".format(user_nl_file)) + infile = os.path.join(confdir, "namelist_infile") + create_namelist_infile(case, user_nl_file, infile) + namelist_infile = [infile] + + # create namelist and stream file(s) data component + _create_namelists(case, confdir, inst_string, namelist_infile, nmlgen, data_list_path) + + _create_drv_flds_in(case, confdir) + + # copy namelist files and stream text files, to rundir + copy_inputs_to_rundir(caseroot, compname, confdir, rundir, inst_string) + +############################################################################### +def get_user_nl_list(case): +############################################################################### + """Returns a list of user_nl_datm* files needed in this case + This function is called by CIME to stage the user_nl_datm* files in the case + directory. + """ + user_nl_list = ["user_nl_datm", "user_nl_datm_streams"] + return user_nl_list + +############################################################################### +def _main_func(): + caseroot = parse_input(sys.argv) + with Case(caseroot) as case: + buildnml(case, caseroot, "datm") + + +if __name__ == "__main__": + _main_func() diff --git a/CDEPS-interface/CDEPS/datm/cime_config/config_archive.xml b/CDEPS-interface/CDEPS/datm/cime_config/config_archive.xml new file mode 100644 index 0000000000..e4c0c87bd7 --- /dev/null +++ b/CDEPS-interface/CDEPS/datm/cime_config/config_archive.xml @@ -0,0 +1,11 @@ + + + r + rs1 + unset + + rpointer.atm$NINST_STRING + $CASE.datm$NINST_STRING.r.$DATENAME.nc,$CASE.datm$NINST_STRING.rs1.$DATENAME.bin + + + diff --git a/CDEPS-interface/CDEPS/datm/cime_config/config_component.xml b/CDEPS-interface/CDEPS/datm/cime_config/config_component.xml new file mode 100644 index 0000000000..1079296163 --- /dev/null +++ b/CDEPS-interface/CDEPS/datm/cime_config/config_component.xml @@ -0,0 +1,372 @@ + + + + + + Data driven ATM + QIAN data set + QIAN with water isotopes + CRUNCEP data set + CLM CRU NCEP v7 data set + GSWP3v1 data set + NLDAS2 regional 0.125 degree data set over the U.S. (25-53N, 235-293E). WARNING: Garbage data will be produced for runs extending beyond this regional domain. + Coupler hist data set (in this mode, it is strongly recommended that the model domain and the coupler history forcing are on the same domain) + single point tower site data set + COREv2 normal year forcing + COREv2 interannual forcing + interannual JRA55 forcing + interannual JRA55 forcing, v1.4, through 2018 + interannual JRA55 forcing, v1.5, through 2023 + JRA55 Repeat Year Forcing v1.3 1984-1985 + JRA55 Repeat Year Forcing v1.3 1990-1991 + JRA55 Repeat Year Forcing v1.3 2003-2004 + ERA5 interannual forcing + Namelist-configurable, constant datm forcing for simple experiments + + + + char + datm + datm + case_comp + env_case.xml + Name of atmospheric component + + + + char + CORE2_NYF,CORE2_IAF,CLM_QIAN,CLM_QIAN_WISO,1PT,CLMCRUNCEP,CLMCRUNCEPv7,CLMGSWP3v1,CLMNLDAS2,CPLHIST,CORE_IAF_JRA,CORE_IAF_JRA_1p4_2018,CORE_IAF_JRA_1p5_2023,ERA5,SIMPLE + CORE2_NYF + run_component_datm + env_run.xml + Mode for data atmosphere component. + CORE2_NYF (CORE2 normal year forcing) are modes used in forcing prognostic ocean/sea-ice components. + CLMCRUNCEPv7, CLMGSWP3v1, CLMNLDAS2 and 1PT are modes using observational data for forcing prognostic land components. + WARNING for CLMNLDAS2: This is a regional forcing dataset over the U.S. (25-53N, 235-293E). Garbage data will be produced for runs extending beyond this regional domain. + + CORE2_NYF + CORE2_IAF + CORE_IAF_JRA + CORE_IAF_JRA_1p4_2018 + CORE_IAF_JRA_1p5_2023 + CLM_QIAN + CLM_QIAN_WISO + CLMCRUNCEPv7 + CLMGSWP3v1 + CLMNLDAS2 + 1PT + ERA5 + CPLHIST + SIMPLE + + + + + char + none,clim_1850,clim_2000,clim_2010,hist,SSP1-1.9,SSP1-2.6,SSP2-4.5,SSP3-7.0,SSP4-3.4,SSP4-6.0,SSP5-3.4,SSP5-8.5,cplhist + clim_2000 + + clim_1850 + clim_2000 + clim_2010 + SSP1-1.9 + SSP1-2.6 + SSP2-4.5 + SSP3-7.0 + SSP4-3.4 + SSP4-6.0 + SSP5-3.4 + SSP5-8.5 + hist + hist + cplhist + none + + run_component_datm + env_run.xml + DATM prescribed aerosol forcing + + + + char + none,clim_1850,clim_2000,clim_2010,hist,SSP1-2.6,SSP2-4.5,SSP3-7.0,SSP5-3.4,SSP5-8.5,cplhist + clim_2000 + + clim_1850 + clim_2000 + clim_2010 + SSP1-2.6 + SSP2-4.5 + SSP3-7.0 + SSP5-8.5 + hist + hist + cplhist + none + + run_component_datm + env_run.xml + DATM prescribed nitrogen deposition forcing + + + + char + none,clim_1850,clim_2000,clim_2010,hist,SSP2-4.5,SSP3-7.0,SSP5-8.5 + clim_2000 + + clim_1850 + clim_2000 + clim_2010 + SSP2-4.5 + SSP3-7.0 + SSP5-8.5 + hist + hist + + none + none + + run_component_datm + env_run.xml + DATM prescribed ozone forcing + + + + char + none,observed,cplhist + observed + + + none + none + cplhist + + run_component_datm + env_run.xml + DATM surface topography forcing + + + + char + none,20tr,20tr.latbnd,omip.iaf,omip.jra,SSP1-1.9,SSP1-2.6,SSP2-4.5,SSP3-7.0,SSP4-3.4,SSP4-6.0,SSP5-3.4,SSP5-8.5,SSP1-1.9.latbnd,SSP1-2.6.latbnd,SSP2-4.5.latbnd,SSP3-7.0.latbnd,SSP4-3.4.latbnd,SSP4-6.0.latbnd,SSP5-3.4.latbnd,SSP5-8.5.latbnd + none + + SSP1-1.9 + SSP1-2.6 + SSP2-4.5 + SSP3-7.0 + SSP4-3.4 + SSP4-6.0 + SSP5-3.4 + SSP5-8.5 + 20tr + 20tr + omip.iaf + omip.jra + + run_component_datm + env_run.xml + DATM CO2 time series + + + + char + + null + run_component_datm + env_run.xml + + Full pathname for domain file for datm when DATM_MODE is + CPLHIST, NOTE: if this is set to 'null' (the default), then + domain information is read in from the first coupler history + file in the target stream and it is assumed that the first + coupler stream file that is pointed to contains the domain + information for that stream. + + + + + char + + UNSET + run_component_datm + env_run.xml + directory for coupler history data mode (only used for when DATM_MODE is CPLHIST) + + + + char + + UNSET + run_component_datm + env_run.xml + case name used to determine stream filenames when DATM_MODE is CPLHIST + + + + integer + + 1 + + $DATM_YR_START + 1 + 1 + 1 + 1895 + 1901 + 1901 + $DATM_YR_START + 1895 + 1901 + 1901 + $DATM_YR_START + $DATM_YR_START + $DATM_YR_START + 1 + 1 + $DATM_YR_START + $DATM_YR_START + $DATM_YR_START + $DATM_YR_START + + run_component_datm + env_run.xml + + Simulation year corresponding to DATM_YR_START. A common usage + is to set this to RUN_STARTDATE. With this setting, the forcing + in the first year of the run will be the forcing of year + DATM_YR_START. Another use case is to align the calendar + of transient forcing with the model calendar. For example, + setting DATM_YR_ALIGN=DATM_YR_START will lead to + the forcing calendar being the same as the model calendar. The + forcing for a given model year would be the forcing of the same + year. This would be appropriate in transient runs where the + model calendar is setup to span the same year range as the + forcing data. + + + + + integer + + 2004 + + 2018 + 1993 + 1992 + 1 + 1948 + 1901 + 1901 + 0 + 2000 + 1972 + 1948 + 1901 + 1901 + 0 + 1948 + 1901 + 1901 + 0 + 1948 + 1995 + 2001 + 2001 + 2002 + 1901 + 1991 + 2002 + 2005 + 1901 + 1991 + 2005 + 2002 + 1980 + 2005 + 2002 + + run_component_datm + env_run.xml + starting year to loop data over + + + + integer + + 9999 + run_component_datm + env_run.xml + Start year listed in PLUMBER2 filenames for certain datm_modes. Currently only used in PLUMBER2; leave as the default value (9999) for other cases. + + + + integer + + 2004 + + 2019 + 1993 + 1992 + 2 + 1972 + 1920 + 1920 + -1 + 2004 + 2004 + 1972 + 1920 + 1920 + -1 + 1972 + 1920 + 1920 + -1 + 2004 + 2004 + 2016 + 2014 + 2003 + 1920 + 2010 + 2003 + 2014 + 1920 + 2010 + 2014 + 2003 + 2018 + 2014 + 2003 + + run_component_datm + env_run.xml + ending year to loop data over + + + + logical + TRUE,FALSE + FALSE + run_component_datm + env_run.xml + If set to true, than datm restarts will not be read on a continuation run. + This capability is used, for example, in CTSM spinup runs. + + + + + ========================================= + DATM naming conventions in compset name + ========================================= + + + diff --git a/CDEPS-interface/CDEPS/datm/cime_config/namelist_definition_datm.xml b/CDEPS-interface/CDEPS/datm/cime_config/namelist_definition_datm.xml new file mode 100644 index 0000000000..17be1c1f88 --- /dev/null +++ b/CDEPS-interface/CDEPS/datm/cime_config/namelist_definition_datm.xml @@ -0,0 +1,509 @@ + + + + + + + + + + + char(100) + streams + streams_file + List of streams used for the given DATM_MODE + + + CLM_QIAN.Solar,CLM_QIAN.Precip,CLM_QIAN.TPQW + + + CLM_QIAN_WISO.Solar,CLM_QIAN_WISO.Precip,CLM_QIAN_WISO.TPQW + + + CLMCRUNCEPv7.Solar,CLMCRUNCEPv7.Precip,CLMCRUNCEPv7.TPQW + + + CLMGSWP3v1.Solar,CLMGSWP3v1.Precip,CLMGSWP3v1.TPQW + + + CLMNLDAS2.Solar,CLMNLDAS2.Precip,CLMNLDAS2.TPQW + + + 1PT.mexicocityMEX + + + 1PT.vancouverCAN + + + 1PT.urbanc_alpha + + + NEON.$NEONSITE + + + PLUMBER2.$PLUMBER2SITE + + + CLM_USRDAT.$CLM_USRDAT_NAME + + + CORE2_NYF.GISS,CORE2_NYF.GXGXS,CORE2_NYF.NCEP + + + CORE2_IAF.GCGCS.PREC,CORE2_IAF.GISS.LWDN,CORE2_IAF.GISS.SWDN,CORE2_IAF.GISS.SWUP,CORE2_IAF.NCEP.DN10,CORE2_IAF.NCEP.Q_10,CORE2_IAF.NCEP.SLP_,CORE2_IAF.NCEP.T_10,CORE2_IAF.NCEP.U_10,CORE2_IAF.NCEP.V_10,CORE2_IAF.CORE2.ArcFactor + + + CORE_IAF_JRA_1p4_2018.GCGCS.PREC,CORE_IAF_JRA_1p4_2018.GISS.LWDN,CORE_IAF_JRA_1p4_2018.GISS.SWDN,CORE_IAF_JRA_1p4_2018.NCEP.Q_10,CORE_IAF_JRA_1p4_2018.NCEP.SLP_,CORE_IAF_JRA_1p4_2018.NCEP.T_10,CORE_IAF_JRA_1p4_2018.NCEP.U_10,CORE_IAF_JRA_1p4_2018.NCEP.V_10 + + + CORE_IAF_JRA_1p5_2023.GCGCS.PREC,CORE_IAF_JRA_1p5_2023.GISS.LWDN,CORE_IAF_JRA_1p5_2023.GISS.SWDN,CORE_IAF_JRA_1p5_2023.NCEP.Q_10,CORE_IAF_JRA_1p5_2023.NCEP.SLP_,CORE_IAF_JRA_1p5_2023.NCEP.T_10,CORE_IAF_JRA_1p5_2023.NCEP.U_10,CORE_IAF_JRA_1p5_2023.NCEP.V_10 + + + CORE_RYF8485_JRA.GISS.LWDN,CORE_RYF8485_JRA.GISS.SWDN,CORE_RYF8485_JRA.GCGCS,CORE_RYF8485_JRA.NCEP + + + CORE_RYF9091_JRA.GISS.LWDN,CORE_RYF9091_JRA.GISS.SWDN,CORE_RYF9091_JRA.GCGCS,CORE_RYF9091_JRA.NCEP + + + CORE_RYF0304_JRA.GISS.LWDN,CORE_RYF0304_JRA.GISS.SWDN,CORE_RYF0304_JRA.GCGCS,CORE_RYF0304_JRA.NCEP + + + CORE_IAF_JRA.PREC,CORE_IAF_JRA.LWDN,CORE_IAF_JRA.SWDN,CORE_IAF_JRA.Q_10,CORE_IAF_JRA.SLP_,CORE_IAF_JRA.T_10,CORE_IAF_JRA.U_10,CORE_IAF_JRA.V_10 + + + CORE2_IAF.NCEP.DENS.SOFS,CORE2_IAF.NCEP.PSLV.SOFS,CORE2_IAF.PREC.SOFS.DAILY,CORE2_IAF.LWDN.SOFS.DAILY,CORE2_IAF.SWDN.SOFS.DAILY,CORE2_IAF.SWUP.SOFS.DAILY,CORE2_IAF.SHUM.SOFS.6HOUR,CORE2_IAF.TBOT.SOFS.6HOUR,CORE2_IAF.U.SOFS.6HOUR,CORE2_IAF.V.SOFS.6HOUR,CORE2_IAF.CORE2.ArcFactor + + + ERA5_HOURLY + + + + CPLHISTForcing.Solar,CPLHISTForcing.nonSolarFlux,CPLHISTForcing.State3hr,CPLHISTForcing.State1hr + + + + + + char + datm + datm_nml + CLMNCEP,CORE2_NYF,CORE2_IAF,CORE_IAF_JRA,ERA5,SIMPLE,CPLHIST,1PT + + general method that operates on the data. + ----datamode = "CPLHIST"---- + CPLHIST mode will examine the fields found in all input data streams, + if any input field names match the field names used internally, they + are copied into the export array and passed directly to the coupler + without any special user code. Any required fields not found on an + input stream will be set to zero except for aerosol deposition fields + which will be set to a special value. + ----datamode = "CORE2_NYF"---- + Coordinated Ocean-ice Reference Experiments (CORE) Version 2 Normal Year Forcing. + ----datamode = "CORE2_IAF"---- + In conjunction with with CORE Version 2 atmospheric forcing data, + provides the atmosphere forcing favored by the Ocean Model Working + Group when coupling an active ocean model with observed atmospheric + forcing. This mode and associated data sets implement the CORE-IAF + Version 2 forcing data, as developed by Large and Yeager (2008) at + NCAR. See the documentation for CORE version 2 datasets at + http://data1.gfdl.noaa.gov/nomads/forms/mom4/COREv2.html Also see + W.G.Large, S.G.Yeager (2008), The global climatology of an + interannually varying air-sea flux data set. + Clm Dyn doi 10.1007/s00382-008-0441-3. + ----datamode = "CORE_IAF_JRA"---- + JRA55 intra-annual year forcing + ----datamode = "CLMNCEP"---- + In conjunction with NCEP climatological atmosphere data, provides the + atmosphere forcing favored by the Land Model Working Group when + coupling an active land model with observed atmospheric forcing. This + mode replicates code previously found in CLM (circa 2005), before the + LMWG started using the CCSM flux coupler and data models to do + active-land-only simulations. + ----datamode = "ERA5"---- + Fifth generation ECMWF atmospheric reanalysis of the global climate + ----datamode = "SIMPLE"---- + Namelist-configurable, constant datm forcing for simple experiments + ----datamode = "CPLHIST" ---- + + + + CLMNCEP + + + CLMNCEP + + + CORE2_IAF + + + CORE_IAF_JRA + + + ERA5 + + + SIMPLE + + + CPLHIST + + + $DATM_MODE + + + + + + char + streams + abs + datm_nml + + file specifying model mesh + + + $ATM_DOMAIN_MESH + null + + + + + char + streams + abs + datm_nml + + file specifying model mask if not obtained from input model mesh + + + $ATM_DOMAIN_MESH + null + + + + + integer + streams + datm_nml + + global size of nx + + + $ATM_NX + 1 + + + + + integer + streams + datm_nml + + global size of ny + + + $ATM_NY + 1 + + + + + char + datm + datm_nml + BC.QIAN.CMAP.Precip,BC.QIAN.GPCP.Precip,BC.CRUNCEP.CMAP.Precip,BC.CRUNCEP.GPCP.Precip + + If set, include bias correction streams in namelist. + + + + + + + + char(10) + datm + datm_nml + Anomaly.Forcing.Precip,Anomaly.Forcing.Temperature,Anomaly.Forcing.Pressure,Anomaly.Forcing.Humidity,Anomaly.Forcing.Uwind,Anomaly.Forcing.Vwind,Anomaly.Forcing.Shortwave,Anomaly.Forcing.Longwave + + If set, include anomaly forcing streams in namelist. + + + + + + + + char + datm + datm_nml + abs + + filename containing correction factor data for use only with CORE2 modes (CORE2_IAF and CORE2_NYF). + + + null + $DIN_LOC_ROOT/atm/datm7/CORE2/COREv2.correction_factors.T62.121007.nc + $DIN_LOC_ROOT/atm/datm7/CORE2/COREv2.correction_factors.T62.121007.nc + null + + + + + char + datm + datm_nml + abs + + filename containing correction factor data for use only with CORE2 modes (CORE2_IAF and CORE2_NYF). + + + null + $DIN_LOC_ROOT/share/meshes/T62_040121_ESMFmesh_c20190714.nc + $DIN_LOC_ROOT/share/meshes/T62_040121_ESMFmesh_c20190714.nc + null + + + + + logical + datm + datm_nml + + If true, prescribed aerosols are sent from datm (must be true for running with CLM). + + + .true. + .false. + + + + + logical + datm + datm_nml + + If true, prescribed nitrogen deposition fluxes are sent from datm (must be true for running with CLM). + + + .true. + .false. + + + + + logical + datm + datm_nml + + If true, prescribed o3 is sent from datm (must be true for running with CLM). + + + .true. + .false. + + + + + logical + datm + datm_nml + + If true, prescribed co2 is sent from datm (must be true for running with CLM). + + + .true. + .false. + + + + + logical + datm + datm_nml + + If true, prescribed water isotopes are sent from datm (must be true for running with CLM). + + + .false. + + + + + + integer + datm + datm_nml + + Frequency to update radiation in number of steps (or hours if negative). + + irdasw is the radiation setting used to compute the next shortwave Julian date. + Values greater than 1 set the next radiation to the present time plus either 1 or 2 + timesteps (depending on the value of nextsw_cday_calc) every iradsw timesteps. + Values less than 0 set the next radiation to the present time plus either 1 or 2 + timesteps (depending on the value of nextsw_cday_calc) every -iradsw hours. If + iradsw is either 0 or 1, the next radiation time is the present time plus 1 + timestep. (default=1 for non-CPLHIST cases, and -1 for CPLHIST cases.) + + + 1 + -1 + + + + + char + datm + datm_nml + cam6,cam7 + + Logic to use for calculating nextsw_cday. This variable has no effect when iradsw is + 0 or 1, so by default this only applies in CPLHIST cases. + + For CPLHIST cases, this should agree with the version of CAM (or other atmosphere + model) used to generate the CPLHIST forcings; the valid values for this variable are + based on this: 'cam6' is appropriate for cases generated with the driver ordering in + CAM6 and earlier, and 'cam7' is appropriate for cases generated with the driver + ordering in CAM7 and later. + + For 'cam6', the next radiation timestep is set to the present time plus 2 timesteps + when mod(tod+dtime,delta_radsw)==0. For 'cam7', the next radiation timestep is set + to the present time plus 1 timestep when mod(tod,delta_radsw)==0. + + + cam6 + cam7 + + + + + char + datm + datm_nml + + Model restart filename for the data atmosphere model data. This is + optional. If restfilm is null, the restart + filename will be read from the DATM restart pointer file (or files for multiple instances). + + + null + + + + + logical + datm + datm_nml + + If set to true, than datm restarts will not be read on a continuation run. + This capability is used, for example, in CTSM spinup runs. + + + $DATM_SKIP_RESTART_READ + + + + + real + datm + const_forcing_nml + + density at the lowest model layer + units: kg m-3 + + + 1.204 + + + + + real + datm + const_forcing_nml + + inst_pres_height_surface + units: Pa + + + 101325.0 + + + + + real + datm + const_forcing_nml + + Constant bottom layer specific humidity + units: kg kg-1 + + + 0.0 + + + + + real + datm + const_forcing_nml + + Constant air temperature at lowest model layer + units: K + + + 273.15 + + + + + real + datm + const_forcing_nml + + Constant zonal wind speed forcing for simple models. + units: m s-1 + + + 0.0 + + + + + real + datm + const_forcing_nml + + Constant meridional wind speed forcing for simple models. + units: m s-1 + + + 0.0 + + + + + real + datm + const_forcing_nml + + Peak idealized shortwave radiation to be passed to ice/ocean surface. + units: W m-2 + + + 330.0 + + + + + real + datm + const_forcing_nml + + Peak idealized longwave radiation to be passed to ice/ocean surface. + units: W m-2 + + + 450.0 + + + diff --git a/CDEPS-interface/CDEPS/datm/cime_config/stream_definition_datm.xml b/CDEPS-interface/CDEPS/datm/cime_config/stream_definition_datm.xml new file mode 100644 index 0000000000..07be39a6db --- /dev/null +++ b/CDEPS-interface/CDEPS/datm/cime_config/stream_definition_datm.xml @@ -0,0 +1,5227 @@ + + + + + + + + + + + + + + + + + none + + + + $DIN_LOC_ROOT/atm/cdeps/v1/$NEONSITE/%ym.nc + + + FSDS Faxa_swdn + ZBOT Sa_z + TBOT Sa_tbot + WIND Sa_wind + RH Sa_rh + PSRF Sa_pbot + FLDS Faxa_lwdn + + null + + none + + null + $DATM_YR_ALIGN + $DATM_YR_START + $DATM_YR_END + 0 + + linear + + + cycle + limit + + + 1.5 + + single + + + + + + + + + none + + + $DIN_LOC_ROOT/atm/cdeps/PRISM/${NEONSITE}_%y.nc + + + PRECIP Faxa_precn + + null + + none + + null + $DATM_YR_ALIGN + $DATM_YR_START + $DATM_YR_END + 0 + + linear + + + cycle + limit + + + 1.5 + + single + + + + + + + + + none + + + + $DIN_LOC_ROOT/atm/cdeps/v1/$NEONSITE/%ym.nc + + + PRECTmms Faxa_precn + + null + + none + + null + $DATM_YR_ALIGN + $DATM_YR_START + $DATM_YR_END + 0 + + linear + + + cycle + limit + + + 1.5 + + single + + + + + + + + + + none + + + $DIN_LOC_ROOT/atm/datm7/CLM1PT_data/PLUMBER2/${PLUMBER2SITE}/CLM1PT_data/CTSM_DATM_${PLUMBER2SITE}_${DATM_YR_START_FILENAME}-${DATM_YR_END}.nc + + + ZBOT Sa_z + TBOT Sa_tbot + QBOT Sa_shum + WIND Sa_wind + PRECTmms Faxa_precn + FSDS Faxa_swdn + PSRF Sa_pbot + FLDS Faxa_lwdn + + null + + none + + null + $DATM_YR_ALIGN + $DATM_YR_START + $DATM_YR_END + 0 + + linear + + + cycle + limit + + + 1.5 + + single + + + + + + + + + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516/clmforc.GSWP3.c2011.0.5x0.5.TPQWL.SCRIP.210520_ESMFmesh.nc + + + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516/Solar/clmforc.GSWP3.c2011.0.5x0.5.Solr.%ym.nc + + + FSDS Faxa_swdn + + null + + bilinear + + null + $DATM_YR_ALIGN + $DATM_YR_START + $DATM_YR_END + 0 + + coszen + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516/clmforc.GSWP3.c2011.0.5x0.5.TPQWL.SCRIP.210520_ESMFmesh.nc + + + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516/Precip/clmforc.GSWP3.c2011.0.5x0.5.Prec.%ym.nc + + + PRECTmms Faxa_precn + + null + + bilinear + + null + $DATM_YR_ALIGN + $DATM_YR_START + $DATM_YR_END + 0 + + nearest + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516/clmforc.GSWP3.c2011.0.5x0.5.TPQWL.SCRIP.210520_ESMFmesh.nc + + + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.GSWP3.0.5d.v1.c170516/TPHWL/clmforc.GSWP3.c2011.0.5x0.5.TPQWL.%ym.nc + + + TBOT Sa_tbot + WIND Sa_wind + QBOT Sa_shum + PSRF Sa_pbot + FLDS Faxa_lwdn + + null + + bilinear + + null + $DATM_YR_ALIGN + $DATM_YR_START + $DATM_YR_END + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + + + + + $DIN_LOC_ROOT/atm/datm7/atm_forcing.datm7.cruncep_qianFill.0.5d.v7.c160715/clmforc.cruncep.V7.cdf5.c2016.0.5d.ESMFmesh_c210330.nc + + + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.cruncep_qianFill.0.5d.v7.c160715/Solar6Hrly/clmforc.cruncep.V7.c2016.0.5d.Solr.%ym.nc + + + FSDS Faxa_swdn + + null + + bilinear + + null + $DATM_YR_ALIGN + $DATM_YR_START + $DATM_YR_END + 0 + + coszen + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/atm/datm7/atm_forcing.datm7.cruncep_qianFill.0.5d.v7.c160715/clmforc.cruncep.V7.cdf5.c2016.0.5d.ESMFmesh_c210330.nc + + + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.cruncep_qianFill.0.5d.v7.c160715/Precip6Hrly/clmforc.cruncep.V7.c2016.0.5d.Prec.%ym.nc + + + PRECTmms Faxa_precn + + null + + bilinear + + null + $DATM_YR_ALIGN + $DATM_YR_START + $DATM_YR_END + 0 + + nearest + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/atm/datm7/atm_forcing.datm7.cruncep_qianFill.0.5d.v7.c160715/clmforc.cruncep.V7.cdf5.c2016.0.5d.ESMFmesh_c210330.nc + + + $DIN_LOC_ROOT_CLMFORC/atm_forcing.datm7.cruncep_qianFill.0.5d.v7.c160715/TPHWL6Hrly/clmforc.cruncep.V7.c2016.0.5d.TPQWL.%ym.nc + + + TBOT Sa_tbot + WIND Sa_wind + QBOT Sa_shum + PSRF Sa_pbot + + null + + bilinear + + null + $DATM_YR_ALIGN + $DATM_YR_START + $DATM_YR_END + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + + + + + $DIN_LOC_ROOT/atm/datm7/atm_forcing.datm7.Qian.T62.c080727/clmforc.Qian.c2006.T62.ESMFmesh_120620.nc + + + $DIN_LOC_ROOT/atm/datm7/atm_forcing.datm7.Qian.T62.c080727/Solar6Hrly/clmforc.Qian.c2006.T62.Solr.%ym.nc + + + FSDS Faxa_swdn + + null + + bilinear + + null + $DATM_YR_ALIGN + $DATM_YR_START + $DATM_YR_END + 0 + + coszen + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/atm/datm7/atm_forcing.datm7.Qian.T62.c080727/clmforc.Qian.c2006.T62.ESMFmesh_120620.nc + + + $DIN_LOC_ROOT/atm/datm7/atm_forcing.datm7.Qian.T62.c080727/Precip6Hrly/clmforc.Qian.c2006.T62.Prec.%ym.nc + + + PRECTmms Faxa_precn + + null + + bilinear + + null + $DATM_YR_ALIGN + $DATM_YR_START + $DATM_YR_END + 0 + + nearest + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/atm/datm7/atm_forcing.datm7.Qian.T62.c080727/clmforc.Qian.c2006.T62.ESMFmesh_120620.nc + + + $DIN_LOC_ROOT/atm/datm7/atm_forcing.datm7.Qian.T62.c080727/TmpPrsHumWnd3Hrly/clmforc.Qian.c2006.T62.TPQW.%ym.nc + + + TBOT Sa_tbot + WIND Sa_wind + QBOT Sa_shum + PSRF Sa_pbot + + null + + bilinear + + null + $DATM_YR_ALIGN + $DATM_YR_START + $DATM_YR_END + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + + + + + $DIN_LOC_ROOT/atm/datm7/atm_forcing.datm7.Qian.T62.c080727/clmforc.Qian.c2006.T62.ESMFmesh_120620.nc + + + $DIN_LOC_ROOT/atm/datm7/atm_forcing_iso.datm7.Qian.T62.c080727/Solar6Hrly/clmforc.Qian.c2006.T62.Solr.%ym.nc + + + FSDS Faxaswdn + + null + + bilinear + + null + 2000 + 2000 + 2004 + 0 + + coszen + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/atm/datm7/atm_forcing.datm7.Qian.T62.c080727/clmforc.Qian.c2006.T62.ESMFmesh_120620.nc + + + $DIN_LOC_ROOT/atm/datm7/atm_forcing_iso.datm7.Qian.T62.c080727/Precip6Hrly/clmforc.Qian.c2006.T62.Prec.%ym.nc + + + PRECTmms Faxa_precn + + null + + bilinear + + null + 2000 + 2000 + 2004 + 0 + + nearest + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/atm/datm7/atm_forcing.datm7.Qian.T62.c080727/clmforc.Qian.c2006.T62.ESMFmesh_120620.nc + + + $DIN_LOC_ROOT/atm/datm7/atm_forcing_iso.datm7.Qian.T62.c080727/TmpPrsHumWnd3Hrly/clmforc.Qian.c2006.T62.TPQW.%ym.nc + + + TBOT Sa_tbot + WIND Sa_wind + QBOT Sa_shum + PSRF Sa_pbot + + null + + bilinear + + null + 2000 + 2000 + 2004 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + + + + + $DIN_LOC_ROOT/atm/datm7/atm_forcing.datm7.NLDAS2.0.125d.v1/ctsmforc.NLDAS2.cdf5.0.125d.v1.ESMFmesh_120620_c210330.nc + + + $DIN_LOC_ROOT/atm/datm7/atm_forcing.datm7.NLDAS2.0.125d.v1/Solar/ctsmforc.NLDAS2.0.125d.v1.Solr.%ym.nc + + + FSDS Faxa_swdn + + null + + bilinear + + null + $DATM_YR_ALIGN + $DATM_YR_START + $DATM_YR_END + 0 + + coszen + + + cycle + limit + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/atm/datm7/atm_forcing.datm7.NLDAS2.0.125d.v1/ctsmforc.NLDAS2.cdf5.0.125d.v1.ESMFmesh_120620_c210330.nc + + + $DIN_LOC_ROOT/atm/datm7/atm_forcing.datm7.NLDAS2.0.125d.v1/Precip/ctsmforc.NLDAS2.0.125d.v1.Prec.%ym.nc + + + PRECTmms Faxa_precn + + null + + bilinear + + null + $DATM_YR_ALIGN + $DATM_YR_START + $DATM_YR_END + 0 + + nearest + + + cycle + limit + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/atm/datm7/atm_forcing.datm7.NLDAS2.0.125d.v1/ctsmforc.NLDAS2.cdf5.0.125d.v1.ESMFmesh_120620_c210330.nc + + + $DIN_LOC_ROOT/atm/datm7/atm_forcing.datm7.NLDAS2.0.125d.v1/TPQWL/ctsmforc.NLDAS2.0.125d.v1.TPQWL.%ym.nc + + + TBOT Sa_tbot + WIND Sa_wind + QBOT Sa_shum + PSRF Sa_pbot + FLDS Faxa_lwdn + + null + + bilinear + + null + $DATM_YR_ALIGN + $DATM_YR_START + $DATM_YR_END + 0 + + linear + + + cycle + limit + + + 1.5 + + single + + + + + + + + + + + none + + + $DIN_LOC_ROOT_CLMFORC/$CLM_USRDAT_NAME/CLM1PT_data/%ym.nc + + + PRECTmms Faxa_precn + FSDS Faxa_swdn + ZBOT Sa_z + TBOT Sa_tbot + WIND Sa_wind + RH Sa_rh + PSRF Sa_pbot + FLDS Faxa_lwdn + + null + + none + + null + $DATM_YR_ALIGN + $DATM_YR_START + $DATM_YR_END + 0 + + linear + + + cycle + limit + + + 1.5 + + single + + + + + none + + + $DIN_LOC_ROOT/atm/datm7/CLM1PT_data/mexicocityMEX.c080124/clm1pt-1993-12.nc + + + ZBOT Sa_z + TBOT Sa_tbot + RH Sa_rh + WIND Sa_wind + PSRF Sa_pbot + PRECTmms Faxa_precn + FSDS Faxa_swdn + FSDSdir Faxa_swdndr + FSDSdif Faxa_swdndf + FLDS Faxa_lwdn + + null + + none + + null + $DATM_YR_ALIGN + $DATM_YR_START + $DATM_YR_END + 0 + + nearest + + + limit + + + 1.5 + + single + + + + + none + + + $DIN_LOC_ROOT/atm/datm7/CLM1PT_data/vancouverCAN.c080124/clm1pt-1992-08.nc + + + ZBOT Sa_z + TBOT Sa_tbot + RH Sa_rh + WIND Sa_wind + PSRF Sa_pbot + PRECTmms Faxa_precn + FSDS Faxa_swdn + FSDSdir Faxa_swdndr + FSDSdif Faxa_swdndf + FLDS Faxa_lwdn + + null + + none + + null + $DATM_YR_ALIGN + $DATM_YR_START + $DATM_YR_END + 0 + + nearest + + + limit + + + 1.5 + + single + + + + + none + + + $DIN_LOC_ROOT/atm/datm7/CLM1PT_data/urbanc_alpha.c080416/clm1pt-0001-08.nc + $DIN_LOC_ROOT/atm/datm7/CLM1PT_data/urbanc_alpha.c080416/clm1pt-0001-09.nc + $DIN_LOC_ROOT/atm/datm7/CLM1PT_data/urbanc_alpha.c080416/clm1pt-0001-10.nc + $DIN_LOC_ROOT/atm/datm7/CLM1PT_data/urbanc_alpha.c080416/clm1pt-0001-11.nc + $DIN_LOC_ROOT/atm/datm7/CLM1PT_data/urbanc_alpha.c080416/clm1pt-0001-12.nc + $DIN_LOC_ROOT/atm/datm7/CLM1PT_data/urbanc_alpha.c080416/clm1pt-0002-01.nc + $DIN_LOC_ROOT/atm/datm7/CLM1PT_data/urbanc_alpha.c080416/clm1pt-0002-02.nc + $DIN_LOC_ROOT/atm/datm7/CLM1PT_data/urbanc_alpha.c080416/clm1pt-0002-03.nc + $DIN_LOC_ROOT/atm/datm7/CLM1PT_data/urbanc_alpha.c080416/clm1pt-0002-04.nc + $DIN_LOC_ROOT/atm/datm7/CLM1PT_data/urbanc_alpha.c080416/clm1pt-0002-05.nc + $DIN_LOC_ROOT/atm/datm7/CLM1PT_data/urbanc_alpha.c080416/clm1pt-0002-06.nc + $DIN_LOC_ROOT/atm/datm7/CLM1PT_data/urbanc_alpha.c080416/clm1pt-0002-07.nc + $DIN_LOC_ROOT/atm/datm7/CLM1PT_data/urbanc_alpha.c080416/clm1pt-0002-08.nc + $DIN_LOC_ROOT/atm/datm7/CLM1PT_data/urbanc_alpha.c080416/clm1pt-0002-09.nc + $DIN_LOC_ROOT/atm/datm7/CLM1PT_data/urbanc_alpha.c080416/clm1pt-0002-10.nc + $DIN_LOC_ROOT/atm/datm7/CLM1PT_data/urbanc_alpha.c080416/clm1pt-0002-11.nc + + + ZBOT Sa_z + TBOT Sa_tbot + RH Sa_rh + WIND Sa_wind + PSRF Sa_pbot + PRECTmms Faxa_precn + FSDS Faxa_swdn + FSDSdir Faxa_swdndr + FSDSdif Faxa_swdndf + FLDS Faxa_lwdn + + null + + none + + null + $DATM_YR_ALIGN + $DATM_YR_START + $DATM_YR_END + 0 + + nearest + + + limit + + + 1.5 + + single + + + + + + + + + $DIN_LOC_ROOT/share/meshes/bias_correction_gpcp_qian.Prec_ESMFmesh_cdf5_110121.nc + + + $DIN_LOC_ROOT/atm/datm7/bias_correction/precip/gpcp/qian/bias_correction.Prec.%y.nc + + + BC_PREC Faxa_precsf + + null + + bilinear + + null + 1979 + 1979 + 2004 + 0 + + nearest + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/bias_correction_gpcp_cruncep.Prec_ESMFmesh_cdf5_110121.nc + + + $DIN_LOC_ROOT/atm/datm7/clm_output/cruncep_precip_1deg/gpcp_1deg_bias_correction/bias_correction.Prec.%y.nc + + + BC_PREC Faxa_precsf + + null + + bilinear + + null + 1979 + 1979 + 2012 + 0 + + nearest + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/bias_correction_gpcp_cmap.Prec_ESMFmesh_cdf5_110121.nc + + + $DIN_LOC_ROOT/atm/datm7/bias_correction/precip/cmap/cruncep/bias_correction.Prec.%y.nc + + + BC_PREC Faxa_precsf + + null + + bilinear + + null + 1979 + 1979 + 2010 + 0 + + nearest + + + cycle + + + 1.5 + + single + + + + + + + + + $DIN_LOC_ROOT/atm/datm7/anomaly_forcing/domain.permafrostRCN_P2.c2013.nc + + + $DIN_LOC_ROOT/atm/datm7/anomaly_forcing/af.pr.ccsm4.rcp45.2006-2300.nc + + + pr Faxa_prec_af + + null + + bilinear + + null + 2006 + 2006 + 2300 + 0 + + nearest + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/atm/datm7/anomaly_forcing/domain.permafrostRCN_P2.c2013.nc + + + $DIN_LOC_ROOT/atm/datm7/anomaly_forcing/af.tas.ccsm4.rcp45.2006-2300.nc + + + tas Sa_tbot_af + + null + + bilinear + + null + 2006 + 2006 + 2300 + 0 + + nearest + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/atm/datm7/anomaly_forcing/domain.permafrostRCN_P2.c2013.nc + + + $DIN_LOC_ROOT/atm/datm7/anomaly_forcing/af.ps.ccsm4.rcp45.2006-2300.nc + + + ps Sa_pbot_af + + null + + bilinear + + null + 2006 + 2006 + 2300 + 0 + + nearest + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/atm/datm7/anomaly_forcing/domain.permafrostRCN_P2.c2013.nc + + + $DIN_LOC_ROOT/atm/datm7/anomaly_forcing/af.huss.ccsm4.rcp45.2006-2300.nc + + + huss Sa_shum_af + + null + + bilinear + + null + 2006 + 2300 + 2300 + 0 + + nearest + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/atm/datm7/anomaly_forcing/domain.permafrostRCN_P2.c2013.nc + + + $DIN_LOC_ROOT/atm/datm7/anomaly_forcing/af.uas.ccsm4.rcp45.2006-2300.nc + + + uas Sa_u_af + + null + + bilinear + + null + 2006 + 2006 + 2300 + 0 + + nearest + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/atm/datm7/anomaly_forcing/domain.permafrostRCN_P2.c2013.nc + + + $DIN_LOC_ROOT/atm/datm7/anomaly_forcing/af.vas.ccsm4.rcp45.2006-2300.nc + + + vas Sa_v_af + + null + + bilinear + + null + 2006 + 2006 + 2300 + 0 + + nearest + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/atm/datm7/anomaly_forcing/domain.permafrostRCN_P2.c2013.nc + + + $DIN_LOC_ROOT/atm/datm7/anomaly_forcing/af.rsds.ccsm4.rcp45.2006-2300.nc + + + rsds Faxa_swdn_af + + null + + bilinear + + null + 2006 + 2006 + 2300 + 0 + + nearest + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/atm/datm7/anomaly_forcing/domain.permafrostRCN_P2.c2013.nc + + + $DIN_LOC_ROOT/atm/datm7/anomaly_forcing/af.rlds.ccsm4.rcp45.2006-2300.nc + + + rlds Faxa_lwdn_af + + null + + bilinear + + null + 2006 + 2006 + 2300 + 0 + + nearest + + + cycle + + + 1.5 + + single + + + + + + + + + $DIN_LOC_ROOT/share/meshes/T62_040121_ESMFmesh_c20190714.nc + + + $DIN_LOC_ROOT/atm/datm7/NYF/nyf.giss.T62.051007.nc + + + lwdn Faxa_lwdn + swdn Faxa_swdn + swup Faxa_swup + + null + + bilinear + + null + 1 + 1 + 1 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/T62_040121_ESMFmesh_c20190714.nc + + + $DIN_LOC_ROOT/atm/datm7/NYF/nyf.gxgxs.T62.051007.nc + + + prc Faxa_prec + + null + + bilinear + + null + 1 + 1 + 1 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/T62_040121_ESMFmesh_c20190714.nc + + + $DIN_LOC_ROOT/atm/datm7/NYF/nyf.ncep.T62.050923.nc + + + dn10 Sa_dens + slp_ Sa_pslv + q_10 Sa_shum + t_10 Sa_tbot + u_10 Sa_u + v_10 Sa_v + + null + + bilinear + + Sa_u:Sa_v + 1 + 1 + 1 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + + + + + $DIN_LOC_ROOT/share/meshes/T62_040121_ESMFmesh_c20190714.nc + + + $DIN_LOC_ROOT/ocn/iaf/ncep.SOFS.2010.nc + + + dn10 Sa_dens + + null + + bilinear + + null + 1 + 2010 + 2011 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/T62_040121_ESMFmesh_c20190714.nc + + + $DIN_LOC_ROOT/ocn/iaf/ncep.SOFS.2010.nc + + + slp_ Sa_pslv + + null + + bilinear + + null + 1 + 2010 + 2011 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/T62_040121_ESMFmesh_c20190714.nc + + + $DIN_LOC_ROOT/ocn/iaf/SOFS.daily.03-09.2010.nc + + + prec Faxa_prec + + null + + bilinear + + null + 1 + 2010 + 2011 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/T62_040121_ESMFmesh_c20190714.nc + + + $DIN_LOC_ROOT/ocn/iaf/SOFS.daily.03-09.2010.nc + + + lwdn Faxa_lwdn + + null + + bilinear + + null + 1 + 2010 + 2011 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/T62_040121_ESMFmesh_c20190714.nc + + + $DIN_LOC_ROOT/ocn/iaf/SOFS.daily.03-09.2010.nc + + + swdn Faxa_swdn + + null + + bilinear + + null + 1 + 2010 + 2011 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/T62_040121_ESMFmesh_c20190714.nc + + + $DIN_LOC_ROOT/ocn/iaf/SOFS.daily.03-09.2010.nc + + + swup Faxa_swup + + null + + bilinear + + null + 1 + 2010 + 2011 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/T62_040121_ESMFmesh_c20190714.nc + + + $DIN_LOC_ROOT/ocn/iaf/SOFS.6hour.03-09.2010.nc + + + q3_5 Faxa_shum + + null + + bilinear + + null + 1 + 2010 + 2011 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/T62_040121_ESMFmesh_c20190714.nc + + + $DIN_LOC_ROOT/ocn/iaf/SOFS.6hour.03-09.2010.nc + + + t3_5 Sa_tbot + + null + + bilinear + + null + 1 + 2010 + 2011 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/T62_040121_ESMFmesh_c20190714.nc + + + $DIN_LOC_ROOT/ocn/iaf/SOFS.6hour.03-09.2010.nc + + + u3_5 Sa_u + + null + + bilinear + + null + 1 + 2010 + 2011 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/T62_040121_ESMFmesh_c20190714.nc + + + $DIN_LOC_ROOT/ocn/iaf/SOFS.6hour.03-09.2010.nc + + + v3_5 Sa_v + + null + + bilinear + + null + 1 + 2010 + 2011 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/T62_040121_ESMFmesh_c20190714.nc + + + $DIN_LOC_ROOT/ocn/iaf/gcgcs.prec.T62.%y.nc + $DIN_LOC_ROOT/ocn/iaf/gcgcs.prec.T62.%y.20120412.nc + + + prc Faxa_prec + + null + + bilinear + + null + 1 + 1948 + 2009 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/T62_040121_ESMFmesh_c20190714.nc + + + $DIN_LOC_ROOT/ocn/iaf/giss.lwdn.T62.%y.nc + $DIN_LOC_ROOT/ocn/iaf/giss.lwdn.T62.%y.20120412.nc + + + lwdn Faxa_lwdn + + null + + bilinear + + null + 1 + 1948 + 2009 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/T62_040121_ESMFmesh_c20190714.nc + + + $DIN_LOC_ROOT/ocn/iaf/giss.swdn.T62.%y.nc + $DIN_LOC_ROOT/ocn/iaf/giss.swdn.T62.%y.20120412.nc + + + swdn Faxa_swdn + + null + + bilinear + + null + 1 + 1948 + 2009 + 0 + + coszen + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/T62_040121_ESMFmesh_c20190714.nc + + + $DIN_LOC_ROOT/ocn/iaf/giss.swup.T62.%y.nc + $DIN_LOC_ROOT/ocn/iaf/giss.swup.T62.%y.20120412.nc + + + swup Faxa_swup + + null + + bilinear + + null + 1 + 1948 + 2009 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/T62_040121_ESMFmesh_c20190714.nc + + + $DIN_LOC_ROOT/ocn/iaf/ncep.dn10.T62.%y.nc + $DIN_LOC_ROOT/ocn/iaf/ncep.dn10.T62.%y.20120414.nc + $DIN_LOC_ROOT/ocn/iaf/ncep.dn10.T62.%y.nc + $DIN_LOC_ROOT/ocn/iaf/ncep.dn10.T62.%y.20120412.nc + + + dn10 Sa_dens + + null + + bilinear + + null + 1 + 1948 + 2009 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/T62_040121_ESMFmesh_c20190714.nc + + + $DIN_LOC_ROOT/ocn/iaf/ncep.q_10.T62.%y.nc + $DIN_LOC_ROOT/ocn/iaf/ncep.q_10.T62.2005.20120414.nc + $DIN_LOC_ROOT/ocn/iaf/ncep.q_10.T62.%y.nc + $DIN_LOC_ROOT/ocn/iaf/ncep.q_10.T62.%y.20120412.nc + + + q_10 Sa_shum + + null + + bilinear + + null + 1 + 1948 + 2009 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/T62_040121_ESMFmesh_c20190714.nc + + + $DIN_LOC_ROOT/ocn/iaf/ncep.slp_.T62.%y.nc + $DIN_LOC_ROOT/ocn/iaf/ncep.slp_.T62.2005.20120414.nc + $DIN_LOC_ROOT/ocn/iaf/ncep.slp_.T62.%y.nc + $DIN_LOC_ROOT/ocn/iaf/ncep.slp_.T62.%y.20120412.nc + + + slp_ Sa_pslv + + null + + bilinear + + null + 1 + 1948 + 2009 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/T62_040121_ESMFmesh_c20190714.nc + + + $DIN_LOC_ROOT/ocn/iaf/ncep.t_10.T62.%y.nc + $DIN_LOC_ROOT/ocn/iaf/ncep.t_10.T62.2005.20120414.nc + $DIN_LOC_ROOT/ocn/iaf/ncep.t_10.T62.%y.nc + $DIN_LOC_ROOT/ocn/iaf/ncep.t_10.T62.%y.20120412.nc + + + t_10 Sa_tbot + + null + + bilinear + + null + 1 + 1948 + 2009 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/T62_040121_ESMFmesh_c20190714.nc + + + $DIN_LOC_ROOT/ocn/iaf/ncep.u_10.T62.%y.nc + $DIN_LOC_ROOT/ocn/iaf/ncep.u_10.T62.2005.20120414.nc + $DIN_LOC_ROOT/ocn/iaf/ncep.u_10.T62.%y.nc + $DIN_LOC_ROOT/ocn/iaf/ncep.u_10.T62.%y.20120412.nc + + + u_10 Sa_u + + null + + bilinear + + null + 1 + 1948 + 2009 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/T62_040121_ESMFmesh_c20190714.nc + + + $DIN_LOC_ROOT/ocn/iaf/ncep.v_10.T62.%y.nc + $DIN_LOC_ROOT/ocn/iaf/ncep.v_10.T62.2005.20120414.nc + $DIN_LOC_ROOT/ocn/iaf/ncep.v_10.T62.%y.nc + $DIN_LOC_ROOT/ocn/iaf/ncep.v_10.T62.%y.20120412.nc + + + v_10 Sa_v + + null + + bilinear + + null + 1 + 1948 + 2009 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/T62_040121_ESMFmesh_c20190714.nc + + + $DIN_LOC_ROOT/atm/datm7/CORE2/CORE2.t_10.ArcFactor.T62.1997-2004.nc + + + TarcFactor tarcf + + null + + bilinear + + null + 1 + 1948 + 2009 + 0 + + linear + + + cycle + + + 1.e30 + + single + + + + + + + + + + + + + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.3_noleap/JRA.v1.3.prec.TL319.%y.190528.nc + + + prec Faxa_prec + + null + + bilinear + + null + 1 + 1958 + 2018 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.3_noleap/JRA.v1.3.lwdn.TL319.%y.190528.nc + + + lwdn Faxa_lwdn + + null + + bilinear + + null + 1 + 1958 + 2018 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.3_noleap/JRA.v1.3.swdn.TL319.%y.190528.nc + + + swdn Faxa_swdn + + null + + bilinear + + null + 1 + 1958 + 2018 + -5400 + + coszen + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.3_noleap/JRA.v1.3.q_10.TL319.%y.190528.nc + + + q_10 Sa_shum + + null + + bilinear + + null + 1 + 1958 + 2018 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.3_noleap/JRA.v1.3.slp.TL319.%y.190528.nc + + + slp Sa_pslv + + null + + bilinear + + null + 1 + 1958 + 2018 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.3_noleap/JRA.v1.3.t_10.TL319.%y.190528.nc + + + t_10 Sa_tbot + + null + + bilinear + + null + 1 + 1958 + 2018 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.3_noleap/JRA.v1.3.u_10.TL319.%y.190528.nc + + + u_10 Sa_u + + null + + bilinear + + null + 1 + 1958 + 2018 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.3_noleap/JRA.v1.3.v_10.TL319.%y.190528.nc + + + v_10 Sa_v + + null + + bilinear + + null + 1 + 1958 + 2018 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.5_noleap/JRA.v1.5.prec.TL319.%y.210504.nc + $DIN_LOC_ROOT/ocn/jra55/v1.5_noleap/JRA.v1.5.prec.TL319.%y.220505.nc + $DIN_LOC_ROOT/ocn/jra55/v1.5_noleap/JRA.v1.5.prec.TL319.%y.230718.nc + $DIN_LOC_ROOT/ocn/jra55/v1.5_noleap/JRA.v1.5.prec.TL319.%y.240531.nc + + + prec Faxa_prec + + null + + bilinear + + null + 1 + 1958 + 2023 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.5_noleap/JRA.v1.5.lwdn.TL319.%y.210504.nc + $DIN_LOC_ROOT/ocn/jra55/v1.5_noleap/JRA.v1.5.lwdn.TL319.%y.220505.nc + $DIN_LOC_ROOT/ocn/jra55/v1.5_noleap/JRA.v1.5.lwdn.TL319.%y.230718.nc + $DIN_LOC_ROOT/ocn/jra55/v1.5_noleap/JRA.v1.5.lwdn.TL319.%y.240531.nc + + + lwdn Faxa_lwdn + + null + + bilinear + + null + 1 + 1958 + 2023 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.5_noleap/JRA.v1.5.swdn.TL319.%y.210504.nc + $DIN_LOC_ROOT/ocn/jra55/v1.5_noleap/JRA.v1.5.swdn.TL319.%y.220505.nc + $DIN_LOC_ROOT/ocn/jra55/v1.5_noleap/JRA.v1.5.swdn.TL319.%y.230718.nc + $DIN_LOC_ROOT/ocn/jra55/v1.5_noleap/JRA.v1.5.swdn.TL319.%y.240531.nc + + + swdn Faxa_swdn + + null + + bilinear + + null + 1 + 1958 + 2023 + -5400 + + coszen + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.5_noleap/JRA.v1.5.q_10.TL319.%y.210504.nc + $DIN_LOC_ROOT/ocn/jra55/v1.5_noleap/JRA.v1.5.q_10.TL319.%y.220505.nc + $DIN_LOC_ROOT/ocn/jra55/v1.5_noleap/JRA.v1.5.q_10.TL319.%y.230718.nc + $DIN_LOC_ROOT/ocn/jra55/v1.5_noleap/JRA.v1.5.q_10.TL319.%y.240531.nc + + + q_10 Sa_shum + + null + + bilinear + + null + 1 + 1958 + 2023 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.5_noleap/JRA.v1.5.slp.TL319.%y.210504.nc + $DIN_LOC_ROOT/ocn/jra55/v1.5_noleap/JRA.v1.5.slp.TL319.%y.220505.nc + $DIN_LOC_ROOT/ocn/jra55/v1.5_noleap/JRA.v1.5.slp.TL319.%y.230718.nc + $DIN_LOC_ROOT/ocn/jra55/v1.5_noleap/JRA.v1.5.slp.TL319.%y.240531.nc + + + slp Sa_pslv + + null + + bilinear + + null + 1 + 1958 + 2023 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.5_noleap/JRA.v1.5.t_10.TL319.%y.210504.nc + $DIN_LOC_ROOT/ocn/jra55/v1.5_noleap/JRA.v1.5.t_10.TL319.%y.220505.nc + $DIN_LOC_ROOT/ocn/jra55/v1.5_noleap/JRA.v1.5.t_10.TL319.%y.230718.nc + $DIN_LOC_ROOT/ocn/jra55/v1.5_noleap/JRA.v1.5.t_10.TL319.%y.240531.nc + + + t_10 Sa_tbot + + null + + bilinear + + null + 1 + 1958 + 2023 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.5_noleap/JRA.v1.5.u_10.TL319.%y.210504.nc + $DIN_LOC_ROOT/ocn/jra55/v1.5_noleap/JRA.v1.5.u_10.TL319.%y.220505.nc + $DIN_LOC_ROOT/ocn/jra55/v1.5_noleap/JRA.v1.5.u_10.TL319.%y.230718.nc + $DIN_LOC_ROOT/ocn/jra55/v1.5_noleap/JRA.v1.5.u_10.TL319.%y.240531.nc + + + u_10 Sa_u + + null + + bilinear + + null + 1 + 1958 + 2023 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.5_noleap/JRA.v1.5.v_10.TL319.%y.210504.nc + $DIN_LOC_ROOT/ocn/jra55/v1.5_noleap/JRA.v1.5.v_10.TL319.%y.220505.nc + $DIN_LOC_ROOT/ocn/jra55/v1.5_noleap/JRA.v1.5.v_10.TL319.%y.230718.nc + $DIN_LOC_ROOT/ocn/jra55/v1.5_noleap/JRA.v1.5.v_10.TL319.%y.240531.nc + + + v_10 Sa_v + + null + + bilinear + + null + 1 + 1958 + 2023 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.3_ryf/RAF_8485.JRA.v1.3.radiation.lwdn.TL319.180404.nc + + + lwdn Faxa_lwdn + + null + + bilinear + + null + 1 + 1984 + 1984 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.3_ryf/RAF_8485.JRA.v1.3.radiation.swdn.TL319.180404.nc + + + swdn Faxa_swdn + + null + + bilinear + + null + 1 + 1984 + 1984 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.3_ryf/RAF_8485.JRA.v1.3.prec.TL319.180404.nc + + + prec Faxa_prec + + null + + bilinear + + null + 1 + 1984 + 1984 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.3_ryf/RAF_8485.JRA.v1.3.states.TL319.180404.nc + + + u_10 Sa_u + v_10 Sa_v + t_10 Sa_tbot + q_10 Sa_shum + slp Sa_pslv + + null + + bilinear + + Sa_u:Sa_v + 1 + 1984 + 1984 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.3_ryf/RAF_9091.JRA.v1.3.radiation.lwdn.TL319.180404.nc + + + lwdn Faxa_lwdn + + null + + bilinear + + null + 1 + 1990 + 1990 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.3_ryf/RAF_9091.JRA.v1.3.radiation.swdn.TL319.180404.nc + + + swdn Faxa_swdn + + null + + bilinear + + null + 1 + 1990 + 1990 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.3_ryf/RAF_9091.JRA.v1.3.prec.TL319.180404.nc + + + prec Faxa_prec + + null + + bilinear + + null + 1 + 1990 + 1990 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.3_ryf/RAF_9091.JRA.v1.3.states.TL319.180404.nc + + + u_10 Sa_u + v_10 Sa_v + t_10 Sa_tbot + q_10 Sa_shum + slp Sa_pslv + + null + + bilinear + + Sa_u:Sa_v + 1 + 1990 + 1990 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.3_ryf/RAF_0304.JRA.v1.3.radiation.lwdn.TL319.180404.nc + + + lwdn Faxa_lwdn + + null + + bilinear + + null + 1 + 2003 + 2003 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.3_ryf/RAF_0304.JRA.v1.3.radiation.swdn.TL319.180404.nc + + + swdn Faxa_swdn + + null + + bilinear + + null + 1 + 2003 + 2003 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.3_ryf/RAF_0304.JRA.v1.3.prec.TL319.180404.nc + + + prec Faxa_prec + + null + + bilinear + + null + 1 + 2003 + 2003 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.3_ryf/RAF_0304.JRA.v1.3.states.TL319.180404.nc + + + u_10 Sa_u + v_10 Sa_v + t_10 Sa_tbot + q_10 Sa_shum + slp Sa_pslv + + null + + bilinear + + Sa_u:Sa_v + 1 + 2003 + 2003 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.3_noleap/JRA.v1.3.prec.TL319.%y.171019.nc + + + prec Faxa_prec + + null + + bilinear + + null + 1 + 1958 + 2016 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.3_noleap/JRA.v1.3.lwdn.TL319.%y.171019.nc + + + lwdn Faxa_lwdn + + null + + bilinear + + null + 1 + 1958 + 2016 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.3_noleap/JRA.v1.3.swdn.TL319.%y.171019.nc + + + swdn Faxa_swdn + + null + + bilinear + + null + 1 + 1958 + 2016 + -5400 + + coszen + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.3_noleap/JRA.v1.3.q_10.TL319.%y.171019.nc + + + q_10 Sa_shum + + null + + bilinear + + null + 1 + 1958 + 2016 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.3_noleap/JRA.v1.3.slp.TL319.%y.171019.nc + + + slp Sa_pslv + + null + + bilinear + + null + 1 + 1958 + 2016 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.3_noleap/JRA.v1.3.t_10.TL319.%y.171019.nc + + + t_10 Sa_tbot + + null + + bilinear + + null + 1 + 1958 + 2016 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.3_noleap/JRA.v1.3.u_10.TL319.%y.171019.nc + + + u_10 Sa_u + + null + + bilinear + + null + 1 + 1958 + 2016 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.3_noleap/JRA.v1.3.v_10.TL319.%y.171019.nc + + + v_10 Sa_v + + null + + bilinear + + null + 1 + 1958 + 2016 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + + + + + $DIN_LOC_ROOT/share/meshes/TL639_200618_ESMFmesh.nc + + + $DIN_LOC_ROOT/atm/datm7/ERA5/ERA5.TL639.2019.01.200618.nc + $DIN_LOC_ROOT/atm/datm7/ERA5/ERA5.TL639.2019.02.200618.nc + $DIN_LOC_ROOT/atm/datm7/ERA5/ERA5.TL639.2019.03.200618.nc + $DIN_LOC_ROOT/atm/datm7/ERA5/ERA5.TL639.2019.04.200618.nc + $DIN_LOC_ROOT/atm/datm7/ERA5/ERA5.TL639.2019.05.200618.nc + $DIN_LOC_ROOT/atm/datm7/ERA5/ERA5.TL639.2019.06.200618.nc + $DIN_LOC_ROOT/atm/datm7/ERA5/ERA5.TL639.2019.07.200618.nc + $DIN_LOC_ROOT/atm/datm7/ERA5/ERA5.TL639.2019.08.200618.nc + $DIN_LOC_ROOT/atm/datm7/ERA5/ERA5.TL639.2019.09.200618.nc + $DIN_LOC_ROOT/atm/datm7/ERA5/ERA5.TL639.2019.10.200618.nc + $DIN_LOC_ROOT/atm/datm7/ERA5/ERA5.TL639.2019.11.200618.nc + $DIN_LOC_ROOT/atm/datm7/ERA5/ERA5.TL639.2019.12.200618.nc + + + u10 Sa_u10m + v10 Sa_v10m + t2m Sa_t2m + skt Sa_tskn + d2m Sa_tdew + msl Sa_pslv + tp Faxa_rain + cp Faxa_rainc + lsp Faxa_rainl + csf Faxa_snowc + lsf Faxa_snowl + ssrd Faxa_swdn + ssr Faxa_swnet + strd Faxa_lwdn + str Faxa_lwnet + aluvp Faxa_swvdr + aluvd Faxa_swvdf + alnip Faxa_swndr + alnid Faxa_swndf + sshf Faxa_sen + slhf Faxa_lat + ewss Faxa_taux + nsss Faxa_tauy + + null + + bilinear + + + u:v + 2019 + 2019 + 2019 + 0 + + linear + + + limit + + + 1.5 + + single + + + + + + + + + + + none + + + $DIN_LOC_ROOT/atm/datm7/CO2/fco2_datm_global_simyr_1750-2014_CMIP6_c180929.nc + + + CO2 Sa_co2diag + + null + + none + + null + 1850 + 1850 + 2014 + 0 + + linear + + + extend + + + 1.e30 + + single + + + + + none + + + $DIN_LOC_ROOT/atm/datm7/CO2/fco2_datm_global_ssp585_simyr_1750-2020_CMIP6_c200324.nc + + + CO2 Sa_co2diag + + null + + none + + null + 213 + 1850 + 2010 + 0 + + linear + + + extend + + + 1.e30 + + single + + + + + none + + + $DIN_LOC_ROOT/atm/datm7/CO2/fco2_datm_global_ssp585_simyr_1750-2020_CMIP6_c200324.nc + + + CO2 Sa_co2diag + + null + + none + + null + 198 + 1850 + 2019 + 0 + + linear + + + extend + + + 1.e30 + + single + + + + + none + + + $DIN_LOC_ROOT/atm/datm7/CO2/fco2_datm_lat-bandsSSP1-1.9_simyr_2014-2500_CMIP6_c190514.nc + + + CO2 Sa_co2diag + + null + + none + + null + 2015 + 2015 + 2500 + 0 + + linear + + + extend + + + 1.e30 + + single + + + + + none + + + $DIN_LOC_ROOT/atm/datm7/CO2/fco2_datm_lat-bandsSSP1-2.6__simyr_2014-2500_CMIP6_c190506.nc + + + CO2 Sa_co2diag + + null + + none + + null + 2015 + 2015 + 2500 + 0 + + linear + + + extend + + + 1.e30 + + single + + + + + none + + + $DIN_LOC_ROOT/atm/datm7/CO2/fco2_datm_lat-bandsSSP2-4.5__simyr_2014-2500_CMIP6_c190506.nc + + + CO2 Sa_co2diag + + null + + none + + null + 2015 + 2015 + 2500 + 0 + + linear + + + extend + + + 1.e30 + + single + + + + + none + + + $DIN_LOC_ROOT/atm/datm7/CO2/co2_datm_lat-bandsSSP3-7.0__simyr_2014-2500_CMIP6_c190506.nc + + + CO2 Sa_co2diag + + null + + none + + null + 2015 + 2015 + 2500 + 0 + + linear + + + extend + + + 1.e30 + + single + + + + + none + + + $DIN_LOC_ROOT/atm/datm7/CO2/fco2_datm_lat-bandsSSP4-3.4_simyr_2014-2500_CMIP6_c190514.nc + + + CO2 Sa_co2diag + + null + + none + + null + 2015 + 2015 + 2500 + 0 + + linear + + + extend + + + 1.e30 + + single + + + + + none + + + $DIN_LOC_ROOT/atm/datm7/CO2/fco2_datm_lat-bandsSSP4-6.0__simyr_2014-2500_CMIP6_c190506.nc + + + CO2 Sa_co2diag + + null + + none + + null + 2015 + 2015 + 2500 + 0 + + linear + + + extend + + + 1.e30 + + single + + + + + none + + + $DIN_LOC_ROOT/atm/datm7/CO2/fco2_datm_lat-bandsSSP5-3.4__simyr_2014-2500_CMIP6_c190506.nc + + + CO2 Sa_co2diag + + null + + none + + null + 2015 + 2015 + 2500 + 0 + + linear + + + extend + + + 1.e30 + + single + + + + + none + + + $DIN_LOC_ROOT/atm/datm7/CO2/fco2_datm_lat-bandsSSP5-8.5__simyr_2014-2500_CMIP6_c190506.nc + + + CO2 Sa_co2diag + + null + + none + + null + 2015 + 2015 + 2500 + 0 + + linear + + + extend + + + 1.e30 + + single + + + + + none + + + $DIN_LOC_ROOT/atm/datm7/CO2/fco2_datm_globalSSP1-1.9_simyr_2014-2501_CMIP6_c190514.nc + + + CO2 Sa_co2diag + + null + + none + + null + 2015 + 2015 + 2500 + 0 + + linear + + + extend + + + 1.e30 + + single + + + + + none + + + $DIN_LOC_ROOT/atm/datm7/CO2/fco2_datm_globalSSP1-2.6__simyr_2014-2501_CMIP6_c190506.nc + + + CO2 Sa_co2diag + + null + + none + + null + 2015 + 2015 + 2500 + 0 + + linear + + + extend + + + 1.e30 + + single + + + + + none + + + $DIN_LOC_ROOT/atm/datm7/CO2/fco2_datm_globalSSP2-4.5__simyr_2014-2501_CMIP6_c190506.nc + + + CO2 Sa_co2diag + + null + + none + + null + 2015 + 2015 + 2500 + 0 + + linear + + + extend + + + 1.e30 + + single + + + + + none + + + $DIN_LOC_ROOT/atm/datm7/CO2/fco2_datm_globalSSP3-7.0_simyr_1750-2501_CMIP6_c201101.nc + + + CO2 Sa_co2diag + + null + + none + + null + 2015 + 2015 + 2500 + 0 + + linear + + + extend + + + 1.e30 + + single + + + + + none + + + $DIN_LOC_ROOT/atm/datm7/CO2/fco2_datm_globalSSP4-3.4_simyr_2014-2501_CMIP6_c190514.nc + + + CO2 Sa_co2diag + + null + + none + + null + 2015 + 2015 + 2500 + 0 + + linear + + + extend + + + 1.e30 + + single + + + + + none + + + $DIN_LOC_ROOT/atm/datm7/CO2/fco2_datm_globalSSP4-6.0__simyr_2014-2501_CMIP6_c190506.nc + + + CO2 Sa_co2diag + + null + + none + + null + 2015 + 2015 + 2500 + 0 + + linear + + + extend + + + 1.e30 + + single + + + + + none + + + $DIN_LOC_ROOT/atm/datm7/CO2/fco2_datm_globalSSP5-3.4__simyr_2014-2501_CMIP6_c190506.nc + + + CO2 Sa_co2diag + + null + + none + + null + 2015 + 2015 + 2500 + 0 + + linear + + + extend + + + 1.e30 + + single + + + + + none + + + $DIN_LOC_ROOT/atm/datm7/CO2/fco2_datm_globalSSP5-8.5__simyr_2014-2501_CMIP6_c190506.nc + + + CO2 Sa_co2diag + + null + + none + + null + 2015 + 2015 + 2500 + 0 + + linear + + + extend + + + 1.e30 + + single + + + + + + + + + $DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc + + + $DIN_LOC_ROOT/atm/cam/chem/trop_mozart_aero/aero/aerosoldep_WACCM.ensmean_monthly_hist_1849-2015_0.9x1.25_CMIP6_c180926.nc + + + BCDEPWET Faxa_bcphiwet + BCPHODRY Faxa_bcphodry + BCPHIDRY Faxa_bcphidry + OCDEPWET Faxa_ocphiwet + OCPHIDRY Faxa_ocphidry + OCPHODRY Faxa_ocphodry + DSTX01WD Faxa_dstwet1 + DSTX01DD Faxa_dstdry1 + DSTX02WD Faxa_dstwet2 + DSTX02DD Faxa_dstdry2 + DSTX03WD Faxa_dstwet3 + DSTX03DD Faxa_dstdry3 + DSTX04WD Faxa_dstwet4 + DSTX04DD Faxa_dstdry4 + + null + + bilinear + + null + 1 + 1850 + 1850 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc + + + $DIN_LOC_ROOT/atm/cam/chem/trop_mozart_aero/aero/aerosoldep_WACCM.ensmean_monthly_hist_1849-2015_0.9x1.25_CMIP6_c180926.nc + + + BCDEPWET Faxa_bcphiwet + BCPHODRY Faxa_bcphodry + BCPHIDRY Faxa_bcphidry + OCDEPWET Faxa_ocphiwet + OCPHIDRY Faxa_ocphidry + OCPHODRY Faxa_ocphodry + DSTX01WD Faxa_dstwet1 + DSTX01DD Faxa_dstdry1 + DSTX02WD Faxa_dstwet2 + DSTX02DD Faxa_dstdry2 + DSTX03WD Faxa_dstwet3 + DSTX03DD Faxa_dstdry3 + DSTX04WD Faxa_dstwet4 + DSTX04DD Faxa_dstdry4 + + null + + bilinear + + null + 1 + 2000 + 2000 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc + + + $DIN_LOC_ROOT/atm/cam/chem/trop_mozart_aero/aero/aerosoldep_WACCM.ensmean_monthly_hist_1849-2015_0.9x1.25_CMIP6_c180926.nc + + + BCDEPWET Faxa_bcphiwet + BCPHODRY Faxa_bcphodry + BCPHIDRY Faxa_bcphidry + OCDEPWET Faxa_ocphiwet + OCPHIDRY Faxa_ocphidry + OCPHODRY Faxa_ocphodry + DSTX01WD Faxa_dstwet1 + DSTX01DD Faxa_dstdry1 + DSTX02WD Faxa_dstwet2 + DSTX02DD Faxa_dstdry2 + DSTX03WD Faxa_dstwet3 + DSTX03DD Faxa_dstdry3 + DSTX04WD Faxa_dstwet4 + DSTX04DD Faxa_dstdry4 + + null + + bilinear + + null + 1 + 2010 + 2010 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc + + + $DIN_LOC_ROOT/atm/cam/chem/trop_mozart_aero/aero/aerosoldep_WACCM.ensmean_monthly_hist_1849-2015_0.9x1.25_CMIP6_c180926.nc + + + BCDEPWET Faxa_bcphiwet + BCPHODRY Faxa_bcphodry + BCPHIDRY Faxa_bcphidry + OCDEPWET Faxa_ocphiwet + OCPHIDRY Faxa_ocphidry + OCPHODRY Faxa_ocphodry + DSTX01WD Faxa_dstwet1 + DSTX01DD Faxa_dstdry1 + DSTX02WD Faxa_dstwet2 + DSTX02DD Faxa_dstdry2 + DSTX03WD Faxa_dstwet3 + DSTX03DD Faxa_dstdry3 + DSTX04WD Faxa_dstwet4 + DSTX04DD Faxa_dstdry4 + + null + + bilinear + + null + 1849 + 1849 + 2014 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc + + + $DIN_LOC_ROOT/atm/cam/chem/trop_mozart_aero/aero/aerodep_clm_SSP126_b.e21.BSSP126cmip6.f09_g17.CMIP6-SSP1-2.6.001_2014-2101_monthly_0.9x1.25_c190523.nc + + + BCDEPWET Faxa_bcphiwet + BCPHODRY Faxa_bcphodry + BCPHIDRY Faxa_bcphidry + OCDEPWET Faxa_ocphiwet + OCPHIDRY Faxa_ocphidry + OCPHODRY Faxa_ocphodry + DSTX01WD Faxa_dstwet1 + DSTX01DD Faxa_dstdry1 + DSTX02WD Faxa_dstwet2 + DSTX02DD Faxa_dstdry2 + DSTX03WD Faxa_dstwet3 + DSTX03DD Faxa_dstdry3 + DSTX04WD Faxa_dstwet4 + DSTX04DD Faxa_dstdry4 + + null + + bilinear + + null + 2015 + 2015 + 2101 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc + + + $DIN_LOC_ROOT/atm/cam/chem/trop_mozart_aero/aero/aerodep_clm_SSP245_b.e21.BWSSP245cmip6.f09_g17.CMIP6-SSP2-4.5-WACCM.001_2014-2101_monthly_0.9x1.25_c190401.nc + + + BCDEPWET Faxa_bcphiwet + BCPHODRY Faxa_bcphodry + BCPHIDRY Faxa_bcphidry + OCDEPWET Faxa_ocphiwet + OCPHIDRY Faxa_ocphidry + OCPHODRY Faxa_ocphodry + DSTX01WD Faxa_dstwet1 + DSTX01DD Faxa_dstdry1 + DSTX02WD Faxa_dstwet2 + DSTX02DD Faxa_dstdry2 + DSTX03WD Faxa_dstwet3 + DSTX03DD Faxa_dstdry3 + DSTX04WD Faxa_dstwet4 + DSTX04DD Faxa_dstdry4 + + null + + bilinear + + null + 2015 + 2015 + 2101 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc + + + $DIN_LOC_ROOT/atm/cam/chem/trop_mozart_aero/aero/aerodep_clm_SSP370_b.e21.BWSSP370cmip6.f09_g17.CMIP6-SSP3-7.0-WACCM.001_1849-2101_monthly_0.9x1.25_c201103.nc + + + BCDEPWET Faxa_bcphiwet + BCPHODRY Faxa_bcphodry + BCPHIDRY Faxa_bcphidry + OCDEPWET Faxa_ocphiwet + OCPHIDRY Faxa_ocphidry + OCPHODRY Faxa_ocphodry + DSTX01WD Faxa_dstwet1 + DSTX01DD Faxa_dstdry1 + DSTX02WD Faxa_dstwet2 + DSTX02DD Faxa_dstdry2 + DSTX03WD Faxa_dstwet3 + DSTX03DD Faxa_dstdry3 + DSTX04WD Faxa_dstwet4 + DSTX04DD Faxa_dstdry4 + + null + + bilinear + + null + 2014 + 2014 + 2101 + 0 + + linear + + + cycle + + + 1.5 + 30 + + single + + + + + $DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc + + + null + + + BCDEPWET Faxa_bcphiwet + BCPHODRY Faxa_bcphodry + BCPHIDRY Faxa_bcphidry + OCDEPWET Faxa_ocphiwet + OCPHIDRY Faxa_ocphidry + OCPHODRY Faxa_ocphodry + DSTX01WD Faxa_dstwet1 + DSTX01DD Faxa_dstdry1 + DSTX02WD Faxa_dstwet2 + DSTX02DD Faxa_dstdry2 + DSTX03WD Faxa_dstwet3 + DSTX03DD Faxa_dstdry3 + DSTX04WD Faxa_dstwet4 + DSTX04DD Faxa_dstdry4 + + null + + bilinear + + null + 2015 + 2015 + 2101 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc + + + $DIN_LOC_ROOT/atm/cam/chem/trop_mozart_aero/aero/aerodep_clm_SSP585_b.e21.BSSP585cmip6.f09_g17.CMIP6-SSP5-8.5.001_2014-2101_monthly_0.9x1.25_c190419.nc + + + BCDEPWET Faxa_bcphiwet + BCPHODRY Faxa_bcphodry + BCPHIDRY Faxa_bcphidry + OCDEPWET Faxa_ocphiwet + OCPHIDRY Faxa_ocphidry + OCPHODRY Faxa_ocphodry + DSTX01WD Faxa_dstwet1 + DSTX01DD Faxa_dstdry1 + DSTX02WD Faxa_dstwet2 + DSTX02DD Faxa_dstdry2 + DSTX03WD Faxa_dstwet3 + DSTX03DD Faxa_dstdry3 + DSTX04WD Faxa_dstwet4 + DSTX04DD Faxa_dstdry4 + + null + + bilinear + + null + 2015 + 2015 + 2101 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + + + + + $DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc + + + $DIN_LOC_ROOT/cdeps/datm/ozone/O3_surface.f09_g17.CMIP6-historical-WACCM.001.monthly.185001-201412.nc + + + O3 Sa_o3 + + null + + bilinear + + null + 1 + 1850 + 1850 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc + + + $DIN_LOC_ROOT/cdeps/datm/ozone/O3_surface.f09_g17.CMIP6-historical-WACCM.001.monthly.185001-201412.nc + + + O3 Sa_o3 + + null + + bilinear + + null + 1 + 2000 + 2000 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc + + + $DIN_LOC_ROOT/cdeps/datm/ozone/O3_surface.f09_g17.CMIP6-historical-WACCM.001.monthly.185001-201412.nc + + + O3 Sa_o3 + + null + + bilinear + + null + 1 + 2010 + 2010 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc + + + $DIN_LOC_ROOT/cdeps/datm/ozone/O3_surface.f09_g17.CMIP6-historical-WACCM.001.monthly.185001-201412.nc + + + O3 Sa_o3 + + null + + bilinear + + null + 1850 + 1850 + 2014 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc + + + $DIN_LOC_ROOT/cdeps/datm/ozone/O3_surface.f09_g17.CMIP6-SSP2-4.5-WACCM.001.monthly.201501-210012.nc + + + O3 Sa_o3 + + null + + bilinear + + null + 2015 + 2015 + 2100 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc + + + $DIN_LOC_ROOT/cdeps/datm/ozone/O3_surface.f09_g17.CMIP6-SSP3-7.0-WACCM.001.monthly.201501-210012.nc + + + O3 Sa_o3 + + null + + bilinear + + null + 2015 + 2015 + 2100 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc + + + $DIN_LOC_ROOT/cdeps/datm/ozone/O3_surface.f09_g17.CMIP6-SSP5-8.5-WACCM.001.monthly.201501-210012.nc + + + O3 Sa_o3 + + null + + bilinear + + null + 2015 + 2015 + 2100 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + + + + + + + $DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc + + + $DIN_LOC_ROOT/lnd/clm2/ndepdata/fndep_clm_WACCM6_CMIP6piControl001_y21-50avg_1850monthly_0.95x1.25_c180802.nc + + + NDEP_NHx_month Faxa_ndep_nhx + NDEP_NOy_month Faxa_ndep_noy + + null + + bilinear + + null + 1 + 1850 + 1850 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc + + + $DIN_LOC_ROOT/lnd/clm2/ndepdata/fndep_clm_hist_b.e21.BWHIST.f09_g17.CMIP6-historical-WACCM.ensmean_1849-2015_monthly_0.9x1.25_c180926.nc + + + NDEP_NHx_month Faxa_ndep_nhx + NDEP_NOy_month Faxa_ndep_noy + + null + + bilinear + + null + 1 + 2000 + 2000 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc + + + $DIN_LOC_ROOT/lnd/clm2/ndepdata/fndep_clm_hist_b.e21.BWHIST.f09_g17.CMIP6-historical-WACCM.ensmean_1849-2015_monthly_0.9x1.25_c180926.nc + + + NDEP_NHx_month Faxa_ndep_nhx + NDEP_NOy_month Faxa_ndep_noy + + null + + bilinear + + null + 1 + 2010 + 2010 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc + + + $DIN_LOC_ROOT/lnd/clm2/ndepdata/fndep_clm_hist_b.e21.BWHIST.f09_g17.CMIP6-historical-WACCM.ensmean_1849-2015_monthly_0.9x1.25_c180926.nc + + + NDEP_NHx_month Faxa_ndep_nhx + NDEP_NOy_month Faxa_ndep_noy + + null + + bilinear + + null + 1849 + 1849 + 2014 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc + + + $DIN_LOC_ROOT/lnd/clm2/ndepdata/fndep_clm_f09_g17.CMIP6-SSP1-2.6-WACCM_1849-2101_monthly_c191007.nc + + + NDEP_NHx_month Faxa_ndep_nhx + NDEP_NOy_month Faxa_ndep_noy + + null + + bilinear + + null + 2015 + 2015 + 2101 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc + + + $DIN_LOC_ROOT/lnd/clm2/ndepdata/fndep_clm_f09_g17.CMIP6-SSP2-4.5-WACCM_1849-2101_monthly_c191007.nc + + + NDEP_NHx_month Faxa_ndep_nhx + NDEP_NOy_month Faxa_ndep_noy + + null + + bilinear + + null + 2015 + 2015 + 2101 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc + + + $DIN_LOC_ROOT/lnd/clm2/ndepdata/fndep_clm_SSP370_b.e21.BWSSP370cmip6.f09_g17.CMIP6-SSP3-7.0-WACCM.002_1849-2101_monthly_0.9x1.25_c211216.nc + + + NDEP_NHx_month Faxa_ndep_nhx + NDEP_NOy_month Faxa_ndep_noy + + null + + bilinear + + null + 2015 + 2015 + 2101 + 0 + + linear + + + cycle + + + 1.5 + 30 + + single + + + + + $DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc + + + $DIN_LOC_ROOT/lnd/clm2/ndepdata/fndep_clm_f09_g17.CMIP6-SSP5-8.5-WACCM_1849-2101_monthly_c191007.nc + + + NDEP_NHx_month Faxa_ndep_nhx + NDEP_NOy_month Faxa_ndep_noy + + null + + bilinear + + null + 2015 + 2015 + 2101 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + + + + + $ATM_DOMAIN_MESH + + + $DATM_CPLHIST_DIR/$DATM_CPLHIST_CASE.cpl.hx.atm.3h.avrg.%ymd-10800.nc + + + atmImp_Sa_topo Sa_topo + + null + + bilinear + + null + $DATM_YR_ALIGN + $DATM_YR_START + $DATM_YR_END + 0 + + nearest + + + cycle + + + 3.0 + + single + + + + $ATM_DOMAIN_MESH + + + $DATM_CPLHIST_DIR/$DATM_CPLHIST_CASE.cpl.hx.atm.24h.avrg.%ymd-00000.nc + + + atmImp_Faxa_bcph1 Faxa_bcphidry + atmImp_Faxa_bcph2 Faxa_bcphodry + atmImp_Faxa_bcph3 Faxa_bcphiwet + atmImp_Faxa_ocph1 Faxa_ocphidry + atmImp_Faxa_ocph2 Faxa_ocphodry + atmImp_Faxa_ocph3 Faxa_ocphiwet + atmImp_Faxa_dstwet1 Faxa_dstwet1 + atmImp_Faxa_dstdry1 Faxa_dstdry1 + atmImp_Faxa_dstwet2 Faxa_dstwet2 + atmImp_Faxa_dstdry2 Faxa_dstdry2 + atmImp_Faxa_dstwet3 Faxa_dstwet3 + atmImp_Faxa_dstdry3 Faxa_dstdry3 + atmImp_Faxa_dstwet4 Faxa_dstwet4 + atmImp_Faxa_dstdry4 Faxa_dstdry4 + + null + + bilinear + + null + $DATM_YR_ALIGN + $DATM_YR_START + $DATM_YR_END + 0 + + nearest + + + cycle + + + 3.0 + + single + + + + + $ATM_DOMAIN_MESH + + + $DATM_CPLHIST_DIR/$DATM_CPLHIST_CASE.cpl.ha2x1d.%ym.nc + + + a2x1d_Faxa_ndep Faxa_ndep + + null + + bilinear + + null + $DATM_YR_ALIGN + $DATM_YR_START + $DATM_YR_END + 0 + + nearest + + + cycle + + + 3.0 + + single + + + + + $ATM_DOMAIN_MESH + + + $DATM_CPLHIST_DIR/$DATM_CPLHIST_CASE.cpl.hx.atm.1h.inst.%ymd-03600.nc + + + atmImp_Faxa_swndr Faxa_swndr + atmImp_Faxa_swvdr Faxa_swvdr + atmImp_Faxa_swndf Faxa_swndf + atmImp_Faxa_swvdf Faxa_swvdf + + null + + bilinear + + null + $DATM_YR_ALIGN + $DATM_YR_START + $DATM_YR_END + -900 + + nearest + + + cycle + + + 3.0 + + single + + + + + $ATM_DOMAIN_MESH + + + $DATM_CPLHIST_DIR/$DATM_CPLHIST_CASE.cpl.hx.atm.3h.avrg.%ymd-10800.nc + + + atmImp_Faxa_rainc Faxa_rainc + atmImp_Faxa_rainl Faxa_rainl + atmImp_Faxa_snowc Faxa_snowc + atmImp_Faxa_snowl Faxa_snowl + atmImp_Faxa_lwdn Faxa_lwdn + + null + + bilinear + + null + $DATM_YR_ALIGN + $DATM_YR_START + $DATM_YR_END + 900 + + nearest + + + cycle + + + 3.0 + + single + + + + + $ATM_DOMAIN_MESH + + + $DATM_CPLHIST_DIR/$DATM_CPLHIST_CASE.cpl.hx.atm.3h.avrg.%ymd-10800.nc + + + atmImp_Sa_z Sa_z + atmImp_Sa_tbot Sa_tbot + atmImp_Sa_ptem Sa_ptem + atmImp_Sa_shum Sa_shum + atmImp_Sa_pbot Sa_pbot + atmImp_Sa_dens Sa_dens + atmImp_Sa_pslv Sa_pslv + atmImp_Sa_co2diag Sa_co2diag + atmImp_Sa_co2prog Sa_co2prog + + null + + bilinear + + null + $DATM_YR_ALIGN + $DATM_YR_START + $DATM_YR_END + 900 + + linear + + + cycle + + + 3.0 + + single + + + + + $ATM_DOMAIN_MESH + + + $DATM_CPLHIST_DIR/$DATM_CPLHIST_CASE.cpl.hx.atm.1h.avrg.%ymd-03600.nc + + + atmImp_Sa_u Sa_u + atmImp_Sa_v Sa_v + + null + + bilinear + + null + $DATM_YR_ALIGN + $DATM_YR_START + $DATM_YR_END + 900 + + linear + + + cycle + + + 3.0 + + single + + + + + + + + + $DIN_LOC_ROOT/atm/datm7/topo_forcing/topodata_0.9x1.SCRIP.210520_ESMFmesh.nc + + + $DIN_LOC_ROOT/atm/datm7/topo_forcing/topodata_0.9x1.25_USGS_070110_stream_c151201.nc + + + TOPO Sa_topo + + null + + bilinear + + null + 1 + 1 + 1 + 0 + + + + + + lower + + + cycle + + + 1.5 + + single + + + diff --git a/CDEPS-interface/CDEPS/datm/cime_config/testdefs/testlist_datm.xml b/CDEPS-interface/CDEPS/datm/cime_config/testdefs/testlist_datm.xml new file mode 100644 index 0000000000..34bbe3fcff --- /dev/null +++ b/CDEPS-interface/CDEPS/datm/cime_config/testdefs/testlist_datm.xml @@ -0,0 +1,119 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CDEPS-interface/CDEPS/datm/cime_config/testdefs/testmods_dirs/datm/1PT/shell_commands b/CDEPS-interface/CDEPS/datm/cime_config/testdefs/testmods_dirs/datm/1PT/shell_commands new file mode 100644 index 0000000000..90d44b812b --- /dev/null +++ b/CDEPS-interface/CDEPS/datm/cime_config/testdefs/testmods_dirs/datm/1PT/shell_commands @@ -0,0 +1,12 @@ +if [ "`./xmlquery ATM_GRID --value`" == "1x1_vancouverCAN" ]; then + # Go one day in, so don't have to set the TOD as well + ./xmlchange RUN_STARTDATE="1992-08-13" +elif [ "`./xmlquery ATM_GRID --value`" == "1x1_mexicocityMEX" ]; then + # Go one day in, so don't have to set the TOD as well + ./xmlchange RUN_STARTDATE="1993-12-02" +elif [ "`./xmlquery ATM_GRID --value`" == "1x1_urbanc_alpha" ]; then + # Go one day in, so don't have to set the TOD as well + ./xmlchange RUN_STARTDATE="0001-08-13" +else + ./xmlchange RUN_STARTDATE="2018-01-01" +fi diff --git a/CDEPS-interface/CDEPS/datm/cime_config/testdefs/testmods_dirs/datm/scam/shell_commands b/CDEPS-interface/CDEPS/datm/cime_config/testdefs/testmods_dirs/datm/scam/shell_commands new file mode 100755 index 0000000000..3ebb269f8f --- /dev/null +++ b/CDEPS-interface/CDEPS/datm/cime_config/testdefs/testmods_dirs/datm/scam/shell_commands @@ -0,0 +1,13 @@ +# setup SCAM lon and lat for this iop +# this should correspond to the forcing IOP coordinates +./xmlchange PTS_LON=206.0 +./xmlchange PTS_LAT=70.5 + +# Specify the starting/ending time for the IOP +# The complete time slice of IOP file is specified below +# but you may simulate any within the IOP start and end times. +./xmlchange RUN_STARTDATE=2004-10-05 +./xmlchange START_TOD=7171 +./xmlchange STOP_OPTION=nsteps +./xmlchange STOP_N=10 + diff --git a/CDEPS-interface/CDEPS/datm/cime_config/user_nl_datm b/CDEPS-interface/CDEPS/datm/cime_config/user_nl_datm new file mode 100644 index 0000000000..fb8503100b --- /dev/null +++ b/CDEPS-interface/CDEPS/datm/cime_config/user_nl_datm @@ -0,0 +1,13 @@ +!------------------------------------------------------------------------ +! Users should ONLY USE user_nl_datm to change namelists variables +! Users should add all user specific namelist changes below in the form of +! namelist_var = new_namelist_value +! Note that any namelist variable from shr_strdata_nml and datm_nml can +! be modified below using the above syntax +! User preview_namelists to view (not modify) the output namelist in the +! directory $CASEROOT/CaseDocs +! To modify the contents of a stream txt file, first use preview_namelists +! to obtain the contents of the stream txt files in CaseDocs, and then +! place a copy of the modified stream txt file in $CASEROOT with the string +! user_ prepended. +!------------------------------------------------------------------------ diff --git a/CDEPS-interface/CDEPS/datm/cime_config/user_nl_datm_streams b/CDEPS-interface/CDEPS/datm/cime_config/user_nl_datm_streams new file mode 100644 index 0000000000..b01a4fe80a --- /dev/null +++ b/CDEPS-interface/CDEPS/datm/cime_config/user_nl_datm_streams @@ -0,0 +1,33 @@ +!------------------------------------------------------------------------ +! This file is used to modify datm.streams.xml generated in $RUNDIR +! Entries should have the form +! := (NO Quotes!!!) +! The following are accepted values for a stream named foo +! foo:meshfile = character string +! foo:datafiles = comma separated string of full pathnames (e.g. file1,file2,file3...) +! foo:datavars = comma separated string of field pairs (e.g. foo foobar,foo2 foobar2...) +! foo:taxmode = one of [cycle, extend, limit] +! foo:tintalgo = one of [lower,upper,nearest,linear,coszen] +! foo:readmode = single (only suported mode right now) +! foo:mapalgo = one of [bilinear,redist,nn,consf,consd,none] +! foo:dtlimit = real (1.5 is default) +! foo:year_first = integer +! foo:year_last = integer +! foo:year_align = integer +! foo:vectors = null or the names of the vector fields in the model (i.e. Sa_u:Sa_v) +! foo:lev_dimname: = one of [null,name of level dimenion name] +! foo:offset = integer +! As an example: +! foo:year_first = 1950 +! would change the stream year_first stream_entry to 1950 for the foo stream block +! NOTE: multi-line inputs are enabled by adding a \ at the end of the line +! As an emaple: +! foo:datafiles=foo1,foo2, \ +! foo3 +! Will yield the following new entry for datafiles in stream foo +! +! foo1 +! foo2 +! foo3 +! +!------------------------------------------------------------------------ diff --git a/CDEPS-interface/CDEPS/datm/datm_datamode_clmncep_mod.F90 b/CDEPS-interface/CDEPS/datm/datm_datamode_clmncep_mod.F90 new file mode 100644 index 0000000000..78b3bf4dbf --- /dev/null +++ b/CDEPS-interface/CDEPS/datm/datm_datamode_clmncep_mod.F90 @@ -0,0 +1,634 @@ +module datm_datamode_clmncep_mod + + use ESMF , only : ESMF_SUCCESS, ESMF_LogWrite, ESMF_State, ESMF_StateItem_Flag + use ESMF , only : ESMF_STATEITEM_NOTFOUND, ESMF_LOGMSG_INFO, ESMF_StateGet, operator(/=) + use NUOPC , only : NUOPC_Advertise + use shr_kind_mod , only : r8=>shr_kind_r8, i8=>shr_kind_i8, cl=>shr_kind_cl, cs=>shr_kind_cs + use shr_sys_mod , only : shr_sys_abort + use shr_precip_mod , only : shr_precip_partition_rain_snow_ramp + use shr_const_mod , only : shr_const_spval, shr_const_tkfrz, shr_const_pi + use shr_const_mod , only : shr_const_pstd, shr_const_stebol, shr_const_rdair + use dshr_methods_mod , only : dshr_state_getfldptr, chkerr + use dshr_strdata_mod , only : shr_strdata_type, shr_strdata_get_stream_pointer + use dshr_strdata_mod , only : shr_strdata_type + use dshr_fldlist_mod , only : fldlist_type, dshr_fldlist_add + + implicit none + private ! except + + public :: datm_datamode_clmncep_advertise + public :: datm_datamode_clmncep_init_pointers + public :: datm_datamode_clmncep_advance + private :: datm_esat ! determine saturation vapor pressure + + ! export state data + real(r8), pointer :: Sa_z(:) => null() + real(r8), pointer :: Sa_u(:) => null() + real(r8), pointer :: Sa_v(:) => null() + real(r8), pointer :: Sa_tbot(:) => null() + real(r8), pointer :: Sa_ptem(:) => null() + real(r8), pointer :: Sa_shum(:) => null() +! TODO: water isotope support +! real(r8), pointer :: Sa_shum_wiso(:,:) => null() ! water isotopes + real(r8), pointer :: Sa_dens(:) => null() + real(r8), pointer :: Sa_pbot(:) => null() + real(r8), pointer :: Sa_pslv(:) => null() + real(r8), pointer :: Sa_o3(:) => null() + real(r8), pointer :: Faxa_lwdn(:) => null() + real(r8), pointer :: Faxa_rainc(:) => null() + real(r8), pointer :: Faxa_rainl(:) => null() + real(r8), pointer :: Faxa_snowc(:) => null() + real(r8), pointer :: Faxa_snowl(:) => null() + real(r8), pointer :: Faxa_swndr(:) => null() + real(r8), pointer :: Faxa_swndf(:) => null() + real(r8), pointer :: Faxa_swvdr(:) => null() + real(r8), pointer :: Faxa_swvdf(:) => null() + real(r8), pointer :: Faxa_swnet(:) => null() + real(r8), pointer :: Faxa_ndep(:,:) => null() + + ! stream data + real(r8), pointer :: strm_z(:) => null() + real(r8), pointer :: strm_wind(:) => null() + real(r8), pointer :: strm_tdew(:) => null() + real(r8), pointer :: strm_tbot(:) => null() + real(r8), pointer :: strm_pbot(:) => null() + real(r8), pointer :: strm_shum(:) => null() + real(r8), pointer :: strm_lwdn(:) => null() + real(r8), pointer :: strm_rh(:) => null() + real(r8), pointer :: strm_swdn(:) => null() + real(r8), pointer :: strm_swdndf(:) => null() + real(r8), pointer :: strm_swdndr(:) => null() + real(r8), pointer :: strm_precc(:) => null() + real(r8), pointer :: strm_precl(:) => null() + real(r8), pointer :: strm_precn(:) => null() + + ! stream data - water isotopes + real(r8), pointer :: strm_rh_16O(:) => null() ! water isoptopes + real(r8), pointer :: strm_rh_18O(:) => null() ! water isoptopes + real(r8), pointer :: strm_rh_HDO(:) => null() ! water isoptopes + real(r8), pointer :: strm_precn_16O(:) => null() ! water isoptopes + real(r8), pointer :: strm_precn_18O(:) => null() ! water isoptopes + real(r8), pointer :: strm_precn_HDO(:) => null() ! water isoptopes + + ! stream data bias correction + real(r8), pointer :: strm_precsf(:) => null() + + ! stream data anomonly forcing + real(r8), pointer :: strm_u_af(:) => null() ! anomoly forcing + real(r8), pointer :: strm_v_af(:) => null() ! anomoly forcing + real(r8), pointer :: strm_prec_af(:) => null() ! anomoly forcing + real(r8), pointer :: strm_tbot_af(:) => null() ! anomoly forcing + real(r8), pointer :: strm_pbot_af(:) => null() ! anomoly forcing + real(r8), pointer :: strm_shum_af(:) => null() ! anomoly forcing + real(r8), pointer :: strm_swdn_af(:) => null() ! anomoly forcing + real(r8), pointer :: strm_lwdn_af(:) => null() ! anomoly forcing + + ! import state data + real(r8), pointer :: Sx_avsdr(:) => null() + real(r8), pointer :: Sx_anidr(:) => null() + real(r8), pointer :: Sx_avsdf(:) => null() + real(r8), pointer :: Sx_anidf(:) => null() + + logical :: atm_prognostic = .false. + real(r8) :: tbotmax ! units detector + real(r8) :: tdewmax ! units detector + real(r8) :: anidrmax ! existance detector + + real(r8) , parameter :: tKFrz = SHR_CONST_TKFRZ + real(r8) , parameter :: degtorad = SHR_CONST_PI/180.0_r8 + real(r8) , parameter :: pstd = SHR_CONST_PSTD ! standard pressure ~ Pa + real(r8) , parameter :: stebol = SHR_CONST_STEBOL ! Stefan-Boltzmann constant ~ W/m^2/K^4 + real(r8) , parameter :: rdair = SHR_CONST_RDAIR ! dry air gas constant ~ J/K/kg + + + character(*), parameter :: nullstr = 'null' + character(*), parameter :: u_FILE_u = & + __FILE__ + +!=============================================================================== +contains +!=============================================================================== + + subroutine datm_datamode_clmncep_advertise(exportState, fldsexport, flds_scalar_name, & + flds_co2, flds_wiso, flds_presaero, flds_presndep, flds_preso3, rc) + + ! input/output variables + type(esmf_State) , intent(inout) :: exportState + type(fldlist_type) , pointer :: fldsexport + logical , intent(in) :: flds_co2 + logical , intent(in) :: flds_wiso + logical , intent(in) :: flds_presaero + logical , intent(in) :: flds_presndep + logical , intent(in) :: flds_preso3 + character(len=*) , intent(in) :: flds_scalar_name + integer , intent(out) :: rc + + ! local variables + type(fldlist_type), pointer :: fldList + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + call dshr_fldList_add(fldsExport, trim(flds_scalar_name)) + call dshr_fldList_add(fldsExport, 'Sa_topo' ) + call dshr_fldList_add(fldsExport, 'Sa_z' ) + call dshr_fldList_add(fldsExport, 'Sa_u' ) + call dshr_fldList_add(fldsExport, 'Sa_v' ) + call dshr_fldList_add(fldsExport, 'Sa_ptem' ) + call dshr_fldList_add(fldsExport, 'Sa_dens' ) + call dshr_fldList_add(fldsExport, 'Sa_pslv' ) + call dshr_fldList_add(fldsExport, 'Sa_tbot' ) + call dshr_fldList_add(fldsExport, 'Sa_pbot' ) + call dshr_fldList_add(fldsExport, 'Sa_shum' ) + call dshr_fldList_add(fldsExport, 'Faxa_rainc' ) + call dshr_fldList_add(fldsExport, 'Faxa_rainl' ) + call dshr_fldList_add(fldsExport, 'Faxa_snowc' ) + call dshr_fldList_add(fldsExport, 'Faxa_snowl' ) + call dshr_fldList_add(fldsExport, 'Faxa_swndr' ) + call dshr_fldList_add(fldsExport, 'Faxa_swvdr' ) + call dshr_fldList_add(fldsExport, 'Faxa_swndf' ) + call dshr_fldList_add(fldsExport, 'Faxa_swvdf' ) + call dshr_fldList_add(fldsExport, 'Faxa_swnet' ) + call dshr_fldList_add(fldsExport, 'Faxa_lwdn' ) + call dshr_fldList_add(fldsExport, 'Faxa_swdn' ) + if (flds_co2) then + call dshr_fldList_add(fldsExport, 'Sa_co2prog') + call dshr_fldList_add(fldsExport, 'Sa_co2diag') + end if + if (flds_preso3) then + call dshr_fldList_add(fldsExport, 'Sa_o3') + end if + if (flds_presaero) then + call dshr_fldList_add(fldsExport, 'Faxa_bcph' , ungridded_lbound=1, ungridded_ubound=3) + call dshr_fldList_add(fldsExport, 'Faxa_ocph' , ungridded_lbound=1, ungridded_ubound=3) + call dshr_fldList_add(fldsExport, 'Faxa_dstwet' , ungridded_lbound=1, ungridded_ubound=4) + call dshr_fldList_add(fldsExport, 'Faxa_dstdry' , ungridded_lbound=1, ungridded_ubound=4) + end if + if (flds_presndep) then + call dshr_fldList_add(fldsExport, 'Faxa_ndep', ungridded_lbound=1, ungridded_ubound=2) + end if + if (flds_wiso) then + call dshr_fldList_add(fldsExport, 'Faxa_rainc_wiso', ungridded_lbound=1, ungridded_ubound=3) + call dshr_fldList_add(fldsExport, 'Faxa_rainl_wiso', ungridded_lbound=1, ungridded_ubound=3) + call dshr_fldList_add(fldsExport, 'Faxa_snowc_wiso', ungridded_lbound=1, ungridded_ubound=3) + call dshr_fldList_add(fldsExport, 'Faxa_snowl_wiso', ungridded_lbound=1, ungridded_ubound=3) + call dshr_fldList_add(fldsExport, 'Faxa_shum_wiso' , ungridded_lbound=1, ungridded_ubound=3) + end if + + fldlist => fldsExport ! the head of the linked list + do while (associated(fldlist)) + call NUOPC_Advertise(exportState, standardName=fldlist%stdname, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_LogWrite('(datm_comp_advertise): Fr_atm'//trim(fldList%stdname), ESMF_LOGMSG_INFO) + fldList => fldList%next + enddo + + end subroutine datm_datamode_clmncep_advertise + + !=============================================================================== + subroutine datm_datamode_clmncep_init_pointers(importState, exportState, sdat, rc) + + ! input/output variables + type(ESMF_State) , intent(inout) :: importState + type(ESMF_State) , intent(inout) :: exportState + type(shr_strdata_type) , intent(in) :: sdat + integer , intent(out) :: rc + + ! local variables + type(ESMF_StateItem_Flag) :: itemFlag + character(len=*), parameter :: subname='(datm_init_pointers): ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + ! initialize pointers for module level stream arrays + call shr_strdata_get_stream_pointer( sdat, 'Sa_pbot' , strm_pbot , rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_strdata_get_stream_pointer( sdat, 'Sa_tbot' , strm_tbot , rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_strdata_get_stream_pointer( sdat, 'Sa_shum' , strm_shum , rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_strdata_get_stream_pointer( sdat, 'Sa_wind' , strm_wind , rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_strdata_get_stream_pointer( sdat, 'Sa_tdew' , strm_tdew , rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_strdata_get_stream_pointer( sdat, 'Sa_rh' , strm_rh , rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_strdata_get_stream_pointer( sdat, 'Sa_z' , strm_z , rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_strdata_get_stream_pointer( sdat, 'Faxa_swdndf' , strm_swdndf, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_strdata_get_stream_pointer( sdat, 'Faxa_swdndr' , strm_swdndr, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_strdata_get_stream_pointer( sdat, 'Faxa_lwdn' , strm_lwdn , rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_strdata_get_stream_pointer( sdat, 'Faxa_swdn' , strm_swdn , rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_strdata_get_stream_pointer( sdat, 'Faxa_precn' , strm_precn , rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_strdata_get_stream_pointer( sdat, 'Faxa_rh_16O' , strm_rh_16O, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_strdata_get_stream_pointer( sdat, 'Faxa_rh_18O' , strm_rh_18O , rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_strdata_get_stream_pointer( sdat, 'Faxa_rh_HDO' , strm_rh_HDO , rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_strdata_get_stream_pointer( sdat, 'Faxa_precn_16O' , strm_precn_16O, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_strdata_get_stream_pointer( sdat, 'Faxa_precn_18O' , strm_precn_18O, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_strdata_get_stream_pointer( sdat, 'Faxa_precn_HDO' , strm_precn_HDO, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_strdata_get_stream_pointer( sdat, 'Faxa_precn_HDO' , strm_precn_HDO, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! initialize pointers for module level stream arrays for bias correction + call shr_strdata_get_stream_pointer( sdat, 'Faxa_precsf' , strm_precsf , rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! initialize pointers for module level stream arrays for anomonly forcing + call shr_strdata_get_stream_pointer( sdat, 'Sa_u_af' , strm_u_af , rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_strdata_get_stream_pointer( sdat, 'Sa_v_af' , strm_v_af , rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_strdata_get_stream_pointer( sdat, 'Sa_shum_af' , strm_shum_af, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_strdata_get_stream_pointer( sdat, 'Sa_tbot_af' , strm_tbot_af, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_strdata_get_stream_pointer( sdat, 'Sa_pbot_af' , strm_pbot_af, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_strdata_get_stream_pointer( sdat, 'Faxa_prec_af' , strm_prec_af, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_strdata_get_stream_pointer( sdat, 'Faxa_swdn_af' , strm_swdn_af, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_strdata_get_stream_pointer( sdat, 'Faxa_lwdn_af' , strm_lwdn_af, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! get export state pointers + call dshr_state_getfldptr(exportState, 'Sa_z' , fldptr1=Sa_z , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_u' , fldptr1=Sa_u , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_v' , fldptr1=Sa_v , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_tbot' , fldptr1=Sa_tbot , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_pbot' , fldptr1=Sa_pbot , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_pslv' , fldptr1=Sa_pslv , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_ptem' , fldptr1=Sa_ptem , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_shum' , fldptr1=Sa_shum , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_dens' , fldptr1=Sa_dens , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_rainc' , fldptr1=Faxa_rainc , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_rainl' , fldptr1=Faxa_rainl , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_snowc' , fldptr1=Faxa_snowc , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_snowl' , fldptr1=Faxa_snowl , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swvdr' , fldptr1=Faxa_swvdr , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swvdf' , fldptr1=Faxa_swvdf , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swndr' , fldptr1=Faxa_swndr , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swndf' , fldptr1=Faxa_swndf , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swnet' , fldptr1=Faxa_swnet , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_lwdn' , fldptr1=Faxa_lwdn , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_StateGet(exportstate, 'Faxa_ndep', itemFlag, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (itemflag /= ESMF_STATEITEM_NOTFOUND) then + call dshr_state_getfldptr(exportState, 'Faxa_ndep', fldptr2=Faxa_ndep, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + call ESMF_StateGet(exportstate, 'Sa_o3', itemFlag, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (itemflag /= ESMF_STATEITEM_NOTFOUND) then + call dshr_state_getfldptr(exportState, 'Sa_o3', fldptr1=Sa_o3, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + ! error check + if (.not. associated(strm_wind) .or. .not. associated(strm_tbot)) then + call shr_sys_abort(trim(subname)//' ERROR: wind and tbot must be in streams for CLMNCEP') + endif + + ! determine anidrmax (see below for use) + call ESMF_StateGet(importstate, 'Sx_anidr', itemFlag, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (itemflag /= ESMF_STATEITEM_NOTFOUND) then + atm_prognostic = .true. + call dshr_state_getfldptr(importState, 'Sx_anidr', fldptr1=Sx_anidr, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(importState, 'Sx_anidf', fldptr1=Sx_anidf, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(importState, 'Sx_avsdr', fldptr1=Sx_avsdr, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(importState, 'Sx_avsdf', fldptr1=Sx_avsdf, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + end subroutine datm_datamode_clmncep_init_pointers + + !=============================================================================== + subroutine datm_datamode_clmncep_advance(mainproc, logunit, mpicom, rc) + use ESMF, only: ESMF_VMGetCurrent, ESMF_VMAllReduce, ESMF_REDUCE_MAX, ESMF_VM + + ! input/output variables + logical , intent(in) :: mainproc + integer , intent(in) :: logunit + integer , intent(in) :: mpicom + integer , intent(out) :: rc + + ! local variables + logical :: first_time = .true. + integer :: n ! indices + integer :: lsize ! size of attr vect + real(r8) :: rtmp(2) + real(r8) :: swndr + real(r8) :: swndf + real(r8) :: swvdr + real(r8) :: swvdf + real(r8) :: ratio_rvrf + real(r8) :: tbot, pbot + real(r8) :: vp + real(r8) :: ea, e, qsat, frac + type(ESMF_VM) :: vm + character(len=*), parameter :: subname='(datm_datamode_clmncep_advance): ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + lsize = size(Sa_u) + + if (first_time) then + call ESMF_VMGetCurrent(vm, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + ! determine tbotmax (see below for use) + rtmp(1) = maxval(Sa_tbot(:)) + call ESMF_VMAllReduce(vm, rtmp, rtmp(2:), 1, ESMF_REDUCE_MAX, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + tbotmax = rtmp(2) + if (mainproc) write(logunit,*) trim(subname),' tbotmax = ',tbotmax + if(tbotmax <= 0) then + call shr_sys_abort(subname//'ERROR: bad value in tbotmax') + endif + + ! determine anidrmax (see below for use) + if (atm_prognostic) then + rtmp(1) = maxval(Sx_anidr(:)) + call ESMF_VMAllReduce(vm, rtmp, rtmp(2:), 1, ESMF_REDUCE_MAX, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + anidrmax = rtmp(2) + else + anidrmax = SHR_CONST_SPVAL + end if + if (mainproc) write(logunit,*) trim(subname),' anidrmax = ',anidrmax + + ! determine tdewmax (see below for use) + if (associated(strm_tdew)) then + rtmp(1) = maxval(strm_tdew(:)) + call ESMF_VMAllReduce(vm, rtmp, rtmp(2:), 1, ESMF_REDUCE_MAX, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + tdewmax = rtmp(2) + if (mainproc) write(logunit,*) trim(subname),' tdewmax = ',tdewmax + endif + + ! reset first_time + first_time = .false. + end if + + do n = 1,lsize + !--- bottom layer height --- + if (.not. associated(strm_z)) Sa_z(n) = 30.0_r8 + + !--- temperature --- + if (tbotmax < 50.0_r8) Sa_tbot(n) = Sa_tbot(n) + tkFrz + ! Limit very cold forcing to 180K + Sa_tbot(n) = max(180._r8, Sa_tbot(n)) + Sa_ptem(n) = Sa_tbot(n) + + !--- pressure --- + if (.not. associated(strm_pbot)) then + Sa_pbot(n) = pstd + else if (Sa_pbot(n) == 0._r8) then + ! This happens if you are using points over ocean where the mask is 0 + Sa_pbot(n) = pstd + end if + + Sa_pslv(n) = Sa_pbot(n) + + !--- u, v wind velocity --- + Sa_u(n) = strm_wind(n)/sqrt(2.0_r8) + Sa_v(n) = Sa_u(n) + + !--- specific humidity --- + tbot = Sa_tbot(n) + pbot = Sa_pbot(n) + if (associated(strm_shum)) then + e = datm_esat(tbot,tbot) + qsat = (0.622_r8 * e)/(pbot - 0.378_r8 * e) + if (qsat < Sa_shum(n)) then + Sa_shum(n) = qsat + endif + else if (associated(strm_rh)) then + e = strm_rh(n) * 0.01_r8 * datm_esat(tbot,tbot) + qsat = (0.622_r8 * e)/(pbot - 0.378_r8 * e) + Sa_shum(n) = qsat + ! for isotopic tracer specific humidity, expect a delta, just keep the delta from the input file + ! if (associated(strm_rh_16O) .and. associated(strm_rh_18O) .and. associated(strm_rh_HDO)) then + ! Sa_shum_wiso(1,n) = strm_rh_16O(n) + ! Sa_shum_wiso(2,n) = strm_rh_18O(n) + ! Sa_shum_wiso(3,n) = strm_rh_HDO(n) + ! end if + else if (associated(strm_tdew)) then + if (tdewmax < 50.0_r8) strm_tdew(n) = strm_tdew(n) + tkFrz + e = datm_esat(strm_tdew(n),tbot) + qsat = (0.622_r8 * e)/(pbot - 0.378_r8 * e) + Sa_shum(n) = qsat + else + call shr_sys_abort(subname//'ERROR: cannot compute shum') + endif + !--- density --- + vp = (Sa_shum(n)*pbot) / (0.622_r8 + 0.378_r8 * Sa_shum(n)) + Sa_dens(n) = (pbot - 0.378_r8 * vp) / (tbot*rdair) + + !--- downward longwave --- + if (.not. associated(strm_lwdn)) then + e = Sa_pslv(n) * Sa_shum(n) / (0.622_r8 + 0.378_r8 * Sa_shum(n)) + ea = 0.70_r8 + 5.95e-05_r8 * 0.01_r8 * e * exp(1500.0_r8/tbot) + Faxa_lwdn(n) = ea * stebol * tbot**4 + endif + + !--- shortwave radiation --- + if (associated(strm_swdndf) .and. associated(strm_swdndr)) then + Faxa_swndr(n) = strm_swdndr(n) * 0.50_r8 + Faxa_swvdr(n) = strm_swdndr(n) * 0.50_r8 + Faxa_swndf(n) = strm_swdndf(n) * 0.50_r8 + Faxa_swvdf(n) = strm_swdndf(n) * 0.50_r8 + elseif (associated(strm_swdn)) then + ! relationship between incoming NIR or VIS radiation and ratio of + ! direct to diffuse radiation calculated based on one year's worth of + ! hourly CAM output from CAM version cam3_5_55 + swndr = strm_swdn(n) * 0.50_r8 + ratio_rvrf = min(0.99_r8,max(0.29548_r8 + 0.00504_r8*swndr & + -1.4957e-05_r8*swndr**2 + 1.4881e-08_r8*swndr**3,0.01_r8)) + Faxa_swndr(n) = ratio_rvrf*swndr + swndf = strm_swdn(n) * 0.50_r8 + Faxa_swndf(n) = (1._r8 - ratio_rvrf)*swndf + + swvdr = strm_swdn(n) * 0.50_r8 + ratio_rvrf = min(0.99_r8,max(0.17639_r8 + 0.00380_r8*swvdr & + -9.0039e-06_r8*swvdr**2 + 8.1351e-09_r8*swvdr**3,0.01_r8)) + Faxa_swvdr(n) = ratio_rvrf*swvdr + swvdf = strm_swdn(n) * 0.50_r8 + Faxa_swvdf(n) = (1._r8 - ratio_rvrf)*swvdf + else + call shr_sys_abort(subName//'ERROR: cannot compute short-wave down') + endif + + !--- swnet: a diagnostic quantity --- + if (anidrmax < 1.0e-8 .or. anidrmax > SHR_CONST_SPVAL * 0.9_r8) then + Faxa_swnet(n) = 0.0_r8 + else if ( associated(Sx_anidr) .and. associated(Sx_anidf) .and. & + associated(Sx_avsdr) .and. associated(Sx_avsdf)) then + Faxa_swnet(n) = (1.0_r8-Sx_anidr(n))*Faxa_swndr(n) + & + (1.0_r8-Sx_avsdr(n))*Faxa_swvdr(n) + & + (1.0_r8-Sx_anidf(n))*Faxa_swndf(n) + & + (1.0_r8-Sx_avsdf(n))*Faxa_swvdf(n) + else + Faxa_swnet(n) = Faxa_swndr(n) + Faxa_swvdr(n) + Faxa_swndf(n) + Faxa_swvdf(n) + endif + + !--- rain and snow --- + if (associated(strm_precc) .and. associated(strm_precl)) then + Faxa_rainc(n) = strm_precc(n) + Faxa_rainl(n) = strm_precl(n) + else if (associated(strm_precn)) then + Faxa_rainc(n) = strm_precn(n)*0.1_r8 + Faxa_rainl(n) = strm_precn(n)*0.9_r8 + else + call shr_sys_abort(subName//'ERROR: cannot compute rain and snow') + endif + + !--- split precip between rain & snow --- + call shr_precip_partition_rain_snow_ramp(tbot, frac) + Faxa_snowc(n) = max(0.0_r8, Faxa_rainc(n)*(1.0_r8 - frac)) + Faxa_snowl(n) = max(0.0_r8, Faxa_rainl(n)*(1.0_r8 - frac)) + Faxa_rainc(n) = max(0.0_r8, Faxa_rainc(n)*( frac)) + Faxa_rainl(n) = max(0.0_r8, Faxa_rainl(n)*( frac)) + + end do + + !---------------------------------------------------------- + ! bias correction / anomaly forcing ( start block ) + ! modify atmospheric input fields if streams exist + !---------------------------------------------------------- + + ! bias correct precipitation relative to observed + ! (via bias_correct nameslist option) + if (associated(strm_precsf)) then + Faxa_snowc(:) = Faxa_snowc(:) * min(1.e2_r8,strm_precsf(:)) + Faxa_snowl(:) = Faxa_snowl(:) * min(1.e2_r8,strm_precsf(:)) + Faxa_rainc(:) = Faxa_rainc(:) * min(1.e2_r8,strm_precsf(:)) + Faxa_rainl(:) = Faxa_rainl(:) * min(1.e2_r8,strm_precsf(:)) + endif + + ! adjust atmospheric input fields if anomaly forcing streams exist + ! (via anomaly_forcing namelist option) + if (associated(strm_u_af) .and. associated(strm_v_af)) then ! wind + Sa_u(:) = Sa_u(:) + strm_u_af(:) + Sa_v(:) = Sa_v(:) + strm_v_af(:) + endif + if (associated(strm_shum_af)) then ! specific humidity + Sa_shum(:) = Sa_shum(:) + strm_shum_af(:) + ! avoid possible negative q values + where (Sa_shum < 0._r8) + Sa_shum = 1.e-6_r8 + end where + endif + if (associated(strm_pbot_af)) then ! pressure + Sa_pbot(:) = Sa_pbot(:) + strm_pbot_af(:) + endif + if (associated(strm_tbot_af)) then ! temperature + Sa_tbot(:) = Sa_tbot(:) + strm_tbot_af(:) + endif + if (associated(strm_lwdn_af)) then ! longwave + Faxa_lwdn(:) = Faxa_lwdn(:) * strm_lwdn_af(:) + endif + if (associated(strm_prec_af)) then ! precipitation + Faxa_snowc(:) = Faxa_snowc(:) * strm_prec_af(:) + Faxa_snowl(:) = Faxa_snowl(:) * strm_prec_af(:) + Faxa_rainc(:) = Faxa_rainc(:) * strm_prec_af(:) + Faxa_rainl(:) = Faxa_rainl(:) * strm_prec_af(:) + end if + if (associated(strm_swdn_af)) then ! shortwave + Faxa_swndr(:) = Faxa_swndr(:) * strm_swdn_af(:) + Faxa_swvdr(:) = Faxa_swvdr(:) * strm_swdn_af(:) + Faxa_swndf(:) = Faxa_swndf(:) * strm_swdn_af(:) + Faxa_swvdf(:) = Faxa_swvdf(:) * strm_swdn_af(:) + endif + ! bias correction / anomaly forcing ( end block ) + + if (associated(Faxa_ndep)) then + ! convert ndep flux to units of kgN/m2/s (input is in gN/m2/s) + Faxa_ndep(:,:) = Faxa_ndep(:,:) / 1000._r8 + end if + + end subroutine datm_datamode_clmncep_advance + + !=============================================================================== + + real(r8) function datm_eSat(tK,tKbot) + + !---------------------------------------------------------------------------- + ! use polynomials to calculate saturation vapor pressure and derivative with + ! respect to temperature: over water when t > 0 c and over ice when t <= 0 c + ! required to convert relative humidity to specific humidity + !---------------------------------------------------------------------------- + + ! input/output variables + real(r8),intent(in) :: tK ! temp used in polynomial calculation + real(r8),intent(in) :: tKbot ! bottom atm temp + + ! local variables + real(r8) :: t ! tK converted to Celcius + real(r8),parameter :: tkFrz = shr_const_tkfrz ! freezing T of fresh water ~ K + + !--- coefficients for esat over water --- + real(r8),parameter :: a0=6.107799961_r8 + real(r8),parameter :: a1=4.436518521e-01_r8 + real(r8),parameter :: a2=1.428945805e-02_r8 + real(r8),parameter :: a3=2.650648471e-04_r8 + real(r8),parameter :: a4=3.031240396e-06_r8 + real(r8),parameter :: a5=2.034080948e-08_r8 + real(r8),parameter :: a6=6.136820929e-11_r8 + + !--- coefficients for esat over ice --- + real(r8),parameter :: b0=6.109177956_r8 + real(r8),parameter :: b1=5.034698970e-01_r8 + real(r8),parameter :: b2=1.886013408e-02_r8 + real(r8),parameter :: b3=4.176223716e-04_r8 + real(r8),parameter :: b4=5.824720280e-06_r8 + real(r8),parameter :: b5=4.838803174e-08_r8 + real(r8),parameter :: b6=1.838826904e-10_r8 + + t = min( 50.0_r8, max(-50.0_r8,(tK-tKfrz)) ) + if ( tKbot < tKfrz) then + datm_eSat = 100.0_r8*(b0+t*(b1+t*(b2+t*(b3+t*(b4+t*(b5+t*b6)))))) + else + datm_eSat = 100.0_r8*(a0+t*(a1+t*(a2+t*(a3+t*(a4+t*(a5+t*a6)))))) + end if + + end function datm_eSat + +end module datm_datamode_clmncep_mod diff --git a/CDEPS-interface/CDEPS/datm/datm_datamode_core2_mod.F90 b/CDEPS-interface/CDEPS/datm/datm_datamode_core2_mod.F90 new file mode 100644 index 0000000000..8b041f0848 --- /dev/null +++ b/CDEPS-interface/CDEPS/datm/datm_datamode_core2_mod.F90 @@ -0,0 +1,556 @@ +module datm_datamode_core2_mod + + use ESMF , only : ESMF_State, ESMF_StateGet, ESMF_Field, ESMF_FieldBundle + use ESMF , only : ESMF_DistGrid, ESMF_RouteHandle, ESMF_MeshCreate + use ESMF , only : ESMF_Mesh, ESMF_MeshGet, ESMF_MeshCreate + use ESMF , only : ESMF_SUCCESS, ESMF_LogWrite, ESMF_FILEFORMAT_ESMFMESH + use ESMF , only : ESMF_StateItem_Flag, ESMF_STATEITEM_NOTFOUND, operator(/=) + use ESMF , only : ESMF_FieldBundleCreate, ESMF_FieldCreate, ESMF_MESHLOC_ELEMENT + use ESMF , only : ESMF_FieldBundleAdd, ESMF_LOGMSG_INFO, ESMF_TYPEKIND_R8 + use ESMF , only : ESMF_RouteHandleDestroy, ESMF_EXTRAPMETHOD_NEAREST_STOD + use ESMF , only : ESMF_POLEMETHOD_ALLAVG, ESMF_REGRIDMETHOD_BILINEAR + use ESMF , only : ESMF_DistGridGet, ESMF_FieldRegridStore, ESMF_FieldRedistStore + use pio , only : Var_Desc_t, file_desc_t, io_desc_t, pio_read_darray, pio_freedecomp + use pio , only : pio_openfile, PIO_NOWRITE, pio_seterrorhandling, PIO_BCAST_ERROR + use pio , only : pio_initdecomp, pio_inq_dimlen, pio_inq_varid + use pio , only : pio_inq_varndims, pio_inq_vardimid, pio_double + use pio , only : pio_closefile + use NUOPC , only : NUOPC_Advertise + use shr_kind_mod , only : r8=>shr_kind_r8, i8=>shr_kind_i8, cl=>shr_kind_cl, cs=>shr_kind_cs + use shr_sys_mod , only : shr_sys_abort + use shr_cal_mod , only : shr_cal_date2julian + use shr_const_mod , only : shr_const_tkfrz, shr_const_pi + use dshr_strdata_mod , only : shr_strdata_get_stream_pointer, shr_strdata_type + use dshr_methods_mod , only : dshr_state_getfldptr, dshr_fldbun_getfldptr, dshr_fldbun_regrid, chkerr + use dshr_strdata_mod , only : shr_strdata_type + use dshr_fldlist_mod , only : fldlist_type, dshr_fldlist_add + + implicit none + private ! except + + public :: datm_datamode_core2_advertise + public :: datm_datamode_core2_init_pointers + public :: datm_datamode_core2_advance + + private :: datm_get_adjustment_factors + + ! export state pointers + real(r8), pointer :: Sa_u(:) => null() + real(r8), pointer :: Sa_v(:) => null() + real(r8), pointer :: Sa_u10m(:) => null() + real(r8), pointer :: Sa_v10m(:) => null() + real(r8), pointer :: Sa_z(:) => null() + real(r8), pointer :: Sa_tbot(:) => null() + real(r8), pointer :: Sa_ptem(:) => null() + real(r8), pointer :: Sa_shum(:) => null() + real(r8), pointer :: Sa_pbot(:) => null() + real(r8), pointer :: Sa_pslv(:) => null() + real(r8), pointer :: Faxa_lwdn(:) => null() + real(r8), pointer :: Faxa_rainc(:) => null() + real(r8), pointer :: Faxa_rainl(:) => null() + real(r8), pointer :: Faxa_snowc(:) => null() + real(r8), pointer :: Faxa_snowl(:) => null() + real(r8), pointer :: Faxa_swndr(:) => null() + real(r8), pointer :: Faxa_swndf(:) => null() + real(r8), pointer :: Faxa_swvdr(:) => null() + real(r8), pointer :: Faxa_swvdf(:) => null() + real(r8), pointer :: Faxa_swnet(:) => null() + real(r8), pointer :: Faxa_ndep(:,:) => null() + + ! stream data + real(r8), pointer :: strm_prec(:) => null() + real(r8), pointer :: strm_swdn(:) => null() + real(r8), pointer :: strm_tarcf(:) => null() + + ! othe module arrays + real(R8), pointer :: windFactor(:) + real(R8), pointer :: winddFactor(:) + real(R8), pointer :: qsatFactor(:) + real(R8), pointer :: yc(:) ! array of model latitudes + + ! constants + real(R8) , parameter :: tKFrz = SHR_CONST_TKFRZ + real(R8) , parameter :: degtorad = SHR_CONST_PI/180.0_R8 + real(R8) , parameter :: avg_c0 = 61.846_R8 + real(R8) , parameter :: avg_c1 = 1.107_R8 + real(R8) , parameter :: amp_c0 = -21.841_R8 + real(R8) , parameter :: amp_c1 = -0.447_R8 + real(R8) , parameter :: phs_c0 = 0.298_R8 + real(R8) , parameter :: dLWarc = -5.000_R8 + + real(R8) :: dTarc(12) + data dTarc / 0.49_R8, 0.06_R8,-0.73_R8, -0.89_R8,-0.77_R8,-1.02_R8, & + -1.99_R8,-0.91_R8, 1.72_R8, 2.30_R8, 1.81_R8, 1.06_R8/ + + character(*), parameter :: nullstr = 'null' + character(*), parameter :: u_FILE_u = & + __FILE__ + +!=============================================================================== +contains +!=============================================================================== + + subroutine datm_datamode_core2_advertise(exportState, fldsexport, flds_scalar_name, & + flds_co2, flds_wiso, flds_presaero, flds_presndep, rc) + + ! input/output variables + type(esmf_State) , intent(inout) :: exportState + type(fldlist_type) , pointer :: fldsexport + character(len=*) , intent(in) :: flds_scalar_name + logical , intent(in) :: flds_co2 + logical , intent(in) :: flds_wiso + logical , intent(in) :: flds_presaero + logical , intent(in) :: flds_presndep + integer , intent(out) :: rc + + ! local variables + type(fldlist_type), pointer :: fldList + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + call dshr_fldList_add(fldsExport, trim(flds_scalar_name)) + call dshr_fldList_add(fldsExport, 'Sa_z' ) + call dshr_fldList_add(fldsExport, 'Sa_u' ) + call dshr_fldList_add(fldsExport, 'Sa_v' ) + call dshr_fldList_add(fldsExport, 'Sa_u10m' ) + call dshr_fldList_add(fldsExport, 'Sa_v10m' ) + call dshr_fldList_add(fldsExport, 'Sa_ptem' ) + call dshr_fldList_add(fldsExport, 'Sa_dens' ) + call dshr_fldList_add(fldsExport, 'Sa_pslv' ) + call dshr_fldList_add(fldsExport, 'Sa_tbot' ) + call dshr_fldList_add(fldsExport, 'Sa_pbot' ) + call dshr_fldList_add(fldsExport, 'Sa_shum' ) + call dshr_fldList_add(fldsExport, 'Faxa_rainc' ) + call dshr_fldList_add(fldsExport, 'Faxa_rainl' ) + call dshr_fldList_add(fldsExport, 'Faxa_snowc' ) + call dshr_fldList_add(fldsExport, 'Faxa_snowl' ) + call dshr_fldList_add(fldsExport, 'Faxa_swndr' ) + call dshr_fldList_add(fldsExport, 'Faxa_swvdr' ) + call dshr_fldList_add(fldsExport, 'Faxa_swndf' ) + call dshr_fldList_add(fldsExport, 'Faxa_swvdf' ) + call dshr_fldList_add(fldsExport, 'Faxa_swnet' ) + call dshr_fldList_add(fldsExport, 'Faxa_lwdn' ) + call dshr_fldList_add(fldsExport, 'Faxa_swdn' ) + + if (flds_co2) then + call dshr_fldList_add(fldsExport, 'Sa_co2prog') + call dshr_fldList_add(fldsExport, 'Sa_co2diag') + end if + if (flds_presaero) then + call dshr_fldList_add(fldsExport, 'Faxa_bcph' , ungridded_lbound=1, ungridded_ubound=3) + call dshr_fldList_add(fldsExport, 'Faxa_ocph' , ungridded_lbound=1, ungridded_ubound=3) + call dshr_fldList_add(fldsExport, 'Faxa_dstwet' , ungridded_lbound=1, ungridded_ubound=4) + call dshr_fldList_add(fldsExport, 'Faxa_dstdry' , ungridded_lbound=1, ungridded_ubound=4) + end if + if (flds_presndep) then + call dshr_fldList_add(fldsExport, 'Faxa_ndep', ungridded_lbound=1, ungridded_ubound=2) + end if + if (flds_wiso) then + call dshr_fldList_add(fldsExport, 'Faxa_rainc_wiso', ungridded_lbound=1, ungridded_ubound=3) + call dshr_fldList_add(fldsExport, 'Faxa_rainl_wiso', ungridded_lbound=1, ungridded_ubound=3) + call dshr_fldList_add(fldsExport, 'Faxa_snowc_wiso', ungridded_lbound=1, ungridded_ubound=3) + call dshr_fldList_add(fldsExport, 'Faxa_snowl_wiso', ungridded_lbound=1, ungridded_ubound=3) + call dshr_fldList_add(fldsExport, 'Faxa_shum_wiso' , ungridded_lbound=1, ungridded_ubound=3) + end if + + fldlist => fldsExport ! the head of the linked list + do while (associated(fldlist)) + call NUOPC_Advertise(exportState, standardName=fldlist%stdname, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_LogWrite('(datm_comp_advertise): Fr_atm'//trim(fldList%stdname), ESMF_LOGMSG_INFO) + fldList => fldList%next + enddo + + end subroutine datm_datamode_core2_advertise + + !=============================================================================== + subroutine datm_datamode_core2_init_pointers(exportState, sdat, datamode, factorfn_mesh, factorfn_data, rc) + + ! input/output variables + type(ESMF_State) , intent(inout) :: exportState + type(shr_strdata_type) , intent(in) :: sdat + character(len=*) , intent(in) :: datamode + character(len=*) , intent(in) :: factorfn_mesh + character(len=*) , intent(in) :: factorfn_data + integer , intent(out) :: rc + + ! local variables + integer :: n + integer :: lsize + integer :: spatialDim ! number of dimension in mesh + integer :: numOwnedElements ! size of mesh + real(r8), pointer :: ownedElemCoords(:) ! mesh lat and lons + type(ESMF_StateItem_Flag) :: itemFlag + character(len=*), parameter :: subname='(datm_init_pointers): ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + lsize = sdat%model_lsize + + ! allocate module arrays + allocate(windFactor(lsize)) + allocate(winddFactor(lsize)) + allocate(qsatFactor(lsize)) + + call ESMF_MeshGet(sdat%model_mesh, spatialDim=spatialDim, numOwnedElements=numOwnedElements, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + allocate(ownedElemCoords(spatialDim*numOwnedElements)) + allocate(yc(numOwnedElements)) + call ESMF_MeshGet(sdat%model_mesh, ownedElemCoords=ownedElemCoords) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + do n = 1,numOwnedElements + yc(n) = ownedElemCoords(2*n) + end do + + ! get stream pointers + call shr_strdata_get_stream_pointer( sdat, 'Faxa_prec' , strm_prec , rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_strdata_get_stream_pointer( sdat, 'Faxa_swdn' , strm_swdn , rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_strdata_get_stream_pointer( sdat, 'tarcf' , strm_tarcf , rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! get export state pointers + call dshr_state_getfldptr(exportState, 'Sa_z' , fldptr1=Sa_z , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_u' , fldptr1=Sa_u , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_v' , fldptr1=Sa_v , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_u10m' , fldptr1=Sa_u10m , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_v10m' , fldptr1=Sa_v10m , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_tbot' , fldptr1=Sa_tbot , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_pbot' , fldptr1=Sa_pbot , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_pslv' , fldptr1=Sa_pslv , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_ptem' , fldptr1=Sa_ptem , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_shum' , fldptr1=Sa_shum , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_rainc' , fldptr1=Faxa_rainc , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_rainl' , fldptr1=Faxa_rainl , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_snowc' , fldptr1=Faxa_snowc , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_snowl' , fldptr1=Faxa_snowl , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swvdr' , fldptr1=Faxa_swvdr , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swvdf' , fldptr1=Faxa_swvdf , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swndr' , fldptr1=Faxa_swndr , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swndf' , fldptr1=Faxa_swndf , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swnet' , fldptr1=Faxa_swnet , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_lwdn' , fldptr1=Faxa_lwdn , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_StateGet(exportstate, 'Faxa_ndep', itemFlag, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (itemflag /= ESMF_STATEITEM_NOTFOUND) then + call dshr_state_getfldptr(exportState, 'Faxa_ndep', fldptr2=Faxa_ndep, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + if (.not. associated(strm_prec) .or. .not. associated(strm_swdn)) then + call shr_sys_abort(trim(subname)//'ERROR: prec and swdn must be in streams for CORE2') + endif + + if (trim(datamode) == 'CORE2_IAF' ) then + if (.not. associated(strm_tarcf)) then + call shr_sys_abort(trim(subname)//'tarcf must be in an input stream for CORE2_IAF') + endif + endif + + ! create adjustment factor arrays + call datm_get_adjustment_factors(sdat, factorFn_mesh, factorFn_data, windFactor, winddFactor, qsatFactor, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + end subroutine datm_datamode_core2_init_pointers + + !=============================================================================== + subroutine datm_datamode_core2_advance(datamode, target_ymd, target_tod, target_mon, & + model_calendar, factorfn_mesh, rc) + + ! input/output variables + character(len=*) , intent(in) :: datamode + integer , intent(in) :: target_ymd + integer , intent(in) :: target_tod + integer , intent(in) :: target_mon + character(len=*) , intent(in) :: model_calendar + character(len=*) , intent(in) :: factorfn_mesh + integer , intent(out) :: rc + + ! local variables + integer :: n + integer :: lsize + real(R8) :: avg_alb ! average albedo + real(R8) :: rday ! elapsed day + real(R8) :: cosFactor ! cosine factor + real(R8) :: factor ! generic/temporary correction factor + real(R8) :: tMin ! minimum temperature + real(R8) :: uprime,vprime + character(len=*), parameter :: subname='(datm_datamode_core2): ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + lsize = size(Sa_z) + + call shr_cal_date2julian(target_ymd, target_tod, rday, model_calendar) + rday = mod((rday - 1.0_R8),365.0_R8) + cosfactor = cos((2.0_R8*SHR_CONST_PI*rday)/365 - phs_c0) + + do n = 1,lsize + Sa_z(n) = 10.0_R8 + + !--- correction to NCEP winds based on QSCAT --- + uprime = Sa_u(n)*windFactor(n) + vprime = Sa_v(n)*windFactor(n) + Sa_u(n) = uprime*cos(winddFactor(n)*degtorad) - vprime*sin(winddFactor(n)*degtorad) + Sa_v(n) = uprime*sin(winddFactor(n)*degtorad) + vprime*cos(winddFactor(n)*degtorad) + + ! Set Sa_u10m and Sa_v10m to Sa_u and Sa_v + Sa_u10m(n) = Sa_u(n) + Sa_v10m(n) = Sa_v(n) + + !--- density and pslv taken directly from input stream, set pbot --- + Sa_pbot(n) = Sa_pslv(n) + + !--- correction to NCEP Arctic & Antarctic air T & potential T --- + if ( yc(n) < -60.0_R8 ) then + tMin = (avg_c0 + avg_c1*yc(n)) + (amp_c0 + amp_c1*yc(n))*cosFactor + tKFrz + Sa_tbot(n) = max(Sa_tbot(n), tMin) + else if ( yc(n) > 60.0_R8 ) then + factor = MIN(1.0_R8, 0.1_R8*(yc(n)-60.0_R8) ) + Sa_tbot(n) = Sa_tbot(n) + factor * dTarc(target_mon) + endif + Sa_ptem(n) = Sa_tbot(n) + + !--- correction to NCEP relative humidity for heat budget balance --- + Sa_shum(n) = Sa_shum(n) + qsatFactor(n) + + !--- Dupont correction to NCEP Arctic air T --- + !--- don't correct during summer months (July-September) + !--- ONLY correct when forcing year is 1997->2004 + if (trim(datamode) == 'CORE2_IAF' ) then + Sa_tbot(n) = Sa_tbot(n) + strm_tarcf(n) + Sa_ptem(n) = Sa_tbot(n) + end if + + ! PRECIPITATION DATA + strm_prec(n) = strm_prec(n)/86400.0_R8 ! convert mm/day to kg/m^2/s + ! only correct satellite products, do not correct Serreze Arctic data + if ( yc(n) < 58. ) then + strm_prec(n) = strm_prec(n)*1.14168_R8 + endif + if ( yc(n) >= 58. .and. yc(n) < 68. ) then + factor = MAX(0.0_R8, 1.0_R8 - 0.1_R8*(yc(n)-58.0_R8) ) + strm_prec(n) = strm_prec(n)*(factor*(1.14168_R8 - 1.0_R8) + 1.0_R8) + endif + Faxa_rainc(n) = 0.0_R8 ! default zero + Faxa_snowc(n) = 0.0_R8 + if (Sa_tbot(n) < tKFrz ) then ! assign precip to rain/snow components + Faxa_rainl(n) = 0.0_R8 + Faxa_snowl(n) = strm_prec(n) + else + Faxa_rainl(n) = strm_prec(n) + Faxa_snowl(n) = 0.0_R8 + endif + + ! RADIATION DATA + !--- fabricate required swdn components from net swdn --- + Faxa_swvdr(n) = strm_swdn(n)*(0.28_R8) + Faxa_swndr(n) = strm_swdn(n)*(0.31_R8) + Faxa_swvdf(n) = strm_swdn(n)*(0.24_R8) + Faxa_swndf(n) = strm_swdn(n)*(0.17_R8) + !--- compute net short-wave based on LY08 latitudinally-varying albedo --- + avg_alb = ( 0.069 - 0.011*cos(2.0_R8*yc(n)*degtorad ) ) + Faxa_swnet(n) = strm_swdn(n)*(1.0_R8 - avg_alb) + !--- corrections to GISS sswdn for heat budget balancing --- + factor = 1.0_R8 + if ( -60.0_R8 < yc(n) .and. yc(n) < -50.0_R8 ) then + factor = 1.0_R8 - (yc(n) + 60.0_R8)*(0.05_R8/10.0_R8) + else if ( -50.0_R8 < yc(n) .and. yc(n) < 30.0_R8 ) then + factor = 0.95_R8 + else if ( 30.0_R8 < yc(n) .and. yc(n) < 40._R8 ) then + factor = 1.0_R8 - (40.0_R8 - yc(n))*(0.05_R8/10.0_R8) + endif + Faxa_swnet(n) = Faxa_swnet(n)*factor + Faxa_swvdr(n) = Faxa_swvdr(n)*factor + Faxa_swndr(n) = Faxa_swndr(n)*factor + Faxa_swvdf(n) = Faxa_swvdf(n)*factor + Faxa_swndf(n) = Faxa_swndf(n)*factor + !--- correction to GISS lwdn in Arctic --- + if ( yc(n) > 60._R8 ) then + factor = MIN(1.0_R8, 0.1_R8*(yc(n)-60.0_R8) ) + Faxa_lwdn(n) = Faxa_lwdn(n) + factor * dLWarc + endif + + enddo ! lsize + + if (associated(Faxa_ndep)) then + ! convert ndep flux to units of kgN/m2/s (input is in gN/m2/s) + Faxa_ndep(:,:) = Faxa_ndep(:,:) / 1000._r8 + end if + + end subroutine datm_datamode_core2_advance + + !=============================================================================== + subroutine datm_get_adjustment_factors(sdat, fileName_mesh, fileName_data, windF, winddF, qsatF, rc) + + ! input/output variables + type(shr_strdata_type) , intent(in) :: sdat + character(*) , intent(in) :: fileName_mesh ! file name string + character(*) , intent(in) :: fileName_data ! file name string + real(R8) , pointer :: windF(:) ! wind adjustment factor + real(R8) , pointer :: winddF(:) ! wind adjustment factor + real(r8) , pointer :: qsatF(:) ! rel humidty adjustment factor + integer , intent(out) :: rc + + ! local variables + type(ESMF_Mesh) :: mesh ! mesh read in from fileName_mesh + type(ESMF_DistGrid) :: distgrid + type(ESMF_FieldBundle) :: fldbun_src + type(ESMF_FieldBundle) :: fldbun_dst + type(ESMF_RouteHandle) :: route_handle + type(ESMF_Field) :: field_src + type(ESMF_Field) :: field_dst + integer :: lsize + integer, pointer :: gindex(:) ! domain decomposition of data + integer :: ndims ! number of dims + integer, allocatable :: dimid(:) + type(var_desc_t) :: varid + type(file_desc_t) :: pioid + type(io_desc_t) :: pio_iodesc + integer :: rcode + integer :: nxg, nyg + real(r8), pointer :: data(:) + integer :: srcTermProcessing_Value = 0 + character(*) ,parameter :: subName = '(datm_get_adjustment_factors) ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + ! read in the factors mesh + mesh = ESMF_MeshCreate(trim(filename_mesh), fileformat=ESMF_FILEFORMAT_ESMFMESH, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! Create input and output field bundles + fldbun_src = ESMF_FieldBundleCreate(rc=rc) ! input field bundle + field_src = ESMF_FieldCreate(mesh, ESMF_TYPEKIND_R8, name='windFactor', & + meshloc=ESMF_MESHLOC_ELEMENT, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call ESMF_FieldBundleAdd(fldbun_src, (/field_src/), rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + field_src = ESMF_FieldCreate(mesh, ESMF_TYPEKIND_R8, name='winddFactor', & + meshloc=ESMF_MESHLOC_ELEMENT, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call ESMF_FieldBundleAdd(fldbun_src, (/field_src/), rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + field_src = ESMF_FieldCreate(mesh, ESMF_TYPEKIND_R8, name='qsatFactor', & + meshloc=ESMF_MESHLOC_ELEMENT, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call ESMF_FieldBundleAdd(fldbun_src, (/field_src/), rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + + fldbun_dst = ESMF_FieldBundleCreate(rc=rc) ! output field bundle + field_dst = ESMF_FieldCreate(sdat%model_mesh, ESMF_TYPEKIND_R8, name='windFactor', & + meshloc=ESMF_MESHLOC_ELEMENT, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call ESMF_FieldBundleAdd(fldbun_dst, (/field_dst/), rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + field_dst = ESMF_FieldCreate(sdat%model_mesh, ESMF_TYPEKIND_R8, name='winddFactor', & + meshloc=ESMF_MESHLOC_ELEMENT, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call ESMF_FieldBundleAdd(fldbun_dst, (/field_dst/), rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + field_dst = ESMF_FieldCreate(sdat%model_mesh, ESMF_TYPEKIND_R8, name='qsatFactor', & + meshloc=ESMF_MESHLOC_ELEMENT, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call ESMF_FieldBundleAdd(fldbun_dst, (/field_dst/), rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + + ! Get mesh info + call ESMF_MeshGet(mesh, elementdistGrid=distGrid, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_DistGridGet(distGrid, localDe=0, elementCount=lsize, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + allocate(gindex(lsize)) + call ESMF_DistGridGet(distGrid, localDe=0, seqIndexList=gindex, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! Create_pio_iodesc + rcode = pio_openfile(sdat%pio_subsystem, pioid, sdat%io_type, trim(filename_data), pio_nowrite) + call pio_seterrorhandling(pioid, PIO_BCAST_ERROR) + rcode = pio_inq_varid(pioid, 'windFactor', varid) + rcode = pio_inq_varndims(pioid, varid, ndims) + allocate(dimid(ndims)) + rcode = pio_inq_varid(pioid, 'windFactor', varid) + rcode = pio_inq_vardimid(pioid, varid, dimid(1:ndims)) + rcode = pio_inq_dimlen(pioid, dimid(1), nxg) + rcode = pio_inq_dimlen(pioid, dimid(2), nyg) + call pio_initdecomp(sdat%pio_subsystem, pio_double, (/nxg,nyg/), gindex, pio_iodesc) + deallocate(gindex) + + ! Read in the data into the appropriate field bundle pointers + call dshr_fldbun_getFldPtr(fldbun_src, 'windFactor', data, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + rcode = pio_inq_varid(pioid, 'windFactor', varid) + call pio_read_darray(pioid, varid, pio_iodesc, data, rcode) + + call dshr_fldbun_getFldPtr(fldbun_src, 'winddFactor', data, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + rcode = pio_inq_varid(pioid, 'winddFactor', varid) + call pio_read_darray(pioid, varid, pio_iodesc, data, rcode) + + call dshr_fldbun_getFldPtr(fldbun_src, 'qsatFactor', data, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + rcode = pio_inq_varid(pioid, 'qsatFactor', varid) + call pio_read_darray(pioid, varid, pio_iodesc, data, rcode) + + if (nxg*nyg /= sdat%model_gsize) then + ! TODO: this needs a mask that needs to be read in to have the mapping be accurate + ! create bilinear route handle - + call ESMF_FieldRegridStore(field_src, field_dst, routehandle=route_handle, & + regridmethod=ESMF_REGRIDMETHOD_BILINEAR, & + polemethod=ESMF_POLEMETHOD_ALLAVG, & + extrapMethod=ESMF_EXTRAPMETHOD_NEAREST_STOD, & + srcTermProcessing=srcTermProcessing_Value, & + ignoreDegenerate=.true., rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + else + call ESMF_FieldRedistStore(field_src, field_dst, routehandle=route_handle, & + ignoreUnmatchedIndices=.true., rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + end if + + ! apply the route handle + call dshr_fldbun_regrid(fldbun_src, fldbun_dst, route_handle, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! obtain output data + call dshr_fldbun_getFldPtr(fldbun_dst, 'windFactor', windF, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_fldbun_getFldPtr(fldbun_dst, 'winddFactor', winddF, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_fldbun_getFldPtr(fldbun_dst, 'qsatFactor', qsatF, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call pio_closefile(pioid) + call pio_freedecomp(sdat%pio_subsystem, pio_iodesc) + call ESMF_RouteHandleDestroy(route_handle, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + end subroutine datm_get_adjustment_factors + +end module datm_datamode_core2_mod diff --git a/CDEPS-interface/CDEPS/datm/datm_datamode_cplhist_mod.F90 b/CDEPS-interface/CDEPS/datm/datm_datamode_cplhist_mod.F90 new file mode 100644 index 0000000000..ca53ed78d1 --- /dev/null +++ b/CDEPS-interface/CDEPS/datm/datm_datamode_cplhist_mod.F90 @@ -0,0 +1,199 @@ +module datm_datamode_cplhist_mod + + use ESMF , only : ESMF_SUCCESS, ESMF_LOGMSG_INFO, ESMF_LogWrite, ESMF_State + use ESMF , only : ESMF_StateItem_Flag + use NUOPC , only : NUOPC_Advertise + use shr_kind_mod , only : r8=>shr_kind_r8, i8=>shr_kind_i8, cl=>shr_kind_cl, cs=>shr_kind_cs + use shr_sys_mod , only : shr_sys_abort + use dshr_methods_mod , only : dshr_state_getfldptr, chkerr + use dshr_strdata_mod , only : shr_strdata_type, shr_strdata_get_stream_pointer + use dshr_strdata_mod , only : shr_strdata_type + use dshr_fldlist_mod , only : fldlist_type, dshr_fldlist_add + + implicit none + private ! except + + public :: datm_datamode_cplhist_advertise + public :: datm_datamode_cplhist_init_pointers + public :: datm_datamode_cplhist_advance + + ! export state data + real(r8), pointer :: Sa_z(:) => null() + real(r8), pointer :: Sa_u(:) => null() + real(r8), pointer :: Sa_v(:) => null() + real(r8), pointer :: Sa_tbot(:) => null() + real(r8), pointer :: Sa_ptem(:) => null() + real(r8), pointer :: Sa_shum(:) => null() + ! TODO: water isotope support + ! real(r8), pointer :: Sa_shum_wiso(:,:) => null() ! water isotopes + real(r8), pointer :: Sa_dens(:) => null() + real(r8), pointer :: Sa_pbot(:) => null() + real(r8), pointer :: Sa_pslv(:) => null() + real(r8), pointer :: Faxa_lwdn(:) => null() + real(r8), pointer :: Faxa_rainc(:) => null() + real(r8), pointer :: Faxa_rainl(:) => null() + real(r8), pointer :: Faxa_snowc(:) => null() + real(r8), pointer :: Faxa_snowl(:) => null() + real(r8), pointer :: Faxa_swndr(:) => null() + real(r8), pointer :: Faxa_swndf(:) => null() + real(r8), pointer :: Faxa_swvdr(:) => null() + real(r8), pointer :: Faxa_swvdf(:) => null() + real(r8), pointer :: Faxa_swnet(:) => null() + + character(*), parameter :: nullstr = 'null' + character(*), parameter :: u_FILE_u = & + __FILE__ + +!=============================================================================== +contains +!=============================================================================== + + subroutine datm_datamode_cplhist_advertise(exportState, fldsexport, flds_scalar_name, & + flds_co2, flds_wiso, flds_presaero, flds_presndep, rc) + + ! input/output variables + type(esmf_State) , intent(inout) :: exportState + type(fldlist_type) , pointer :: fldsexport + logical , intent(in) :: flds_co2 + logical , intent(in) :: flds_wiso + logical , intent(in) :: flds_presaero + logical , intent(in) :: flds_presndep + character(len=*) , intent(in) :: flds_scalar_name + integer , intent(out) :: rc + + ! local variables + type(fldlist_type), pointer :: fldList + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + call dshr_fldList_add(fldsExport, trim(flds_scalar_name)) + call dshr_fldList_add(fldsExport, 'Sa_topo' ) + call dshr_fldList_add(fldsExport, 'Sa_z' ) + call dshr_fldList_add(fldsExport, 'Sa_u' ) + call dshr_fldList_add(fldsExport, 'Sa_v' ) + call dshr_fldList_add(fldsExport, 'Sa_ptem' ) + call dshr_fldList_add(fldsExport, 'Sa_dens' ) + call dshr_fldList_add(fldsExport, 'Sa_pslv' ) + call dshr_fldList_add(fldsExport, 'Sa_tbot' ) + call dshr_fldList_add(fldsExport, 'Sa_pbot' ) + call dshr_fldList_add(fldsExport, 'Sa_shum' ) + call dshr_fldList_add(fldsExport, 'Faxa_rainc' ) + call dshr_fldList_add(fldsExport, 'Faxa_rainl' ) + call dshr_fldList_add(fldsExport, 'Faxa_snowc' ) + call dshr_fldList_add(fldsExport, 'Faxa_snowl' ) + call dshr_fldList_add(fldsExport, 'Faxa_swndr' ) + call dshr_fldList_add(fldsExport, 'Faxa_swvdr' ) + call dshr_fldList_add(fldsExport, 'Faxa_swndf' ) + call dshr_fldList_add(fldsExport, 'Faxa_swvdf' ) + call dshr_fldList_add(fldsExport, 'Faxa_swnet' ) + call dshr_fldList_add(fldsExport, 'Faxa_lwdn' ) + call dshr_fldList_add(fldsExport, 'Faxa_swdn' ) + if (flds_co2) then + call dshr_fldList_add(fldsExport, 'Sa_co2prog') + call dshr_fldList_add(fldsExport, 'Sa_co2diag') + end if + if (flds_presaero) then + call dshr_fldList_add(fldsExport, 'Faxa_bcph' , ungridded_lbound=1, ungridded_ubound=3) + call dshr_fldList_add(fldsExport, 'Faxa_ocph' , ungridded_lbound=1, ungridded_ubound=3) + call dshr_fldList_add(fldsExport, 'Faxa_dstwet' , ungridded_lbound=1, ungridded_ubound=4) + call dshr_fldList_add(fldsExport, 'Faxa_dstdry' , ungridded_lbound=1, ungridded_ubound=4) + end if + if (flds_presndep) then + call dshr_fldList_add(fldsExport, 'Faxa_ndep', ungridded_lbound=1, ungridded_ubound=2) + end if + if (flds_wiso) then + call dshr_fldList_add(fldsExport, 'Faxa_rainc_wiso', ungridded_lbound=1, ungridded_ubound=3) + call dshr_fldList_add(fldsExport, 'Faxa_rainl_wiso', ungridded_lbound=1, ungridded_ubound=3) + call dshr_fldList_add(fldsExport, 'Faxa_snowc_wiso', ungridded_lbound=1, ungridded_ubound=3) + call dshr_fldList_add(fldsExport, 'Faxa_snowl_wiso', ungridded_lbound=1, ungridded_ubound=3) + call dshr_fldList_add(fldsExport, 'Faxa_shum_wiso' , ungridded_lbound=1, ungridded_ubound=3) + end if + + fldlist => fldsExport ! the head of the linked list + do while (associated(fldlist)) + call NUOPC_Advertise(exportState, standardName=fldlist%stdname, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_LogWrite('(datm_comp_advertise): Fr_atm'//trim(fldList%stdname), ESMF_LOGMSG_INFO) + fldList => fldList%next + enddo + + end subroutine datm_datamode_cplhist_advertise + + !=============================================================================== + subroutine datm_datamode_cplhist_init_pointers(importState, exportState, sdat, rc) + + ! input/output variables + type(ESMF_State) , intent(inout) :: importState + type(ESMF_State) , intent(inout) :: exportState + type(shr_strdata_type) , intent(in) :: sdat + integer , intent(out) :: rc + + ! local variables + character(len=*), parameter :: subname='(datm_init_pointers): ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + ! get export state pointers + call dshr_state_getfldptr(exportState, 'Sa_z' , fldptr1=Sa_z , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_u' , fldptr1=Sa_u , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_v' , fldptr1=Sa_v , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_tbot' , fldptr1=Sa_tbot , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_pbot' , fldptr1=Sa_pbot , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_pslv' , fldptr1=Sa_pslv , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_ptem' , fldptr1=Sa_ptem , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_shum' , fldptr1=Sa_shum , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_dens' , fldptr1=Sa_dens , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_rainc' , fldptr1=Faxa_rainc , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_rainl' , fldptr1=Faxa_rainl , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_snowc' , fldptr1=Faxa_snowc , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_snowl' , fldptr1=Faxa_snowl , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swvdr' , fldptr1=Faxa_swvdr , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swvdf' , fldptr1=Faxa_swvdf , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swndr' , fldptr1=Faxa_swndr , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swndf' , fldptr1=Faxa_swndf , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swnet' , fldptr1=Faxa_swnet , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_lwdn' , fldptr1=Faxa_lwdn , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + end subroutine datm_datamode_cplhist_init_pointers + + !=============================================================================== + subroutine datm_datamode_cplhist_advance(mainproc, logunit, mpicom, rc) + + ! input/output variables + logical , intent(in) :: mainproc + integer , intent(in) :: logunit + integer , intent(in) :: mpicom + integer , intent(out) :: rc + + ! local variables + character(len=*), parameter :: subname='(datm_datamode_cplhist_advance): ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + ! For now - do nothing special + + end subroutine datm_datamode_cplhist_advance + +end module datm_datamode_cplhist_mod diff --git a/CDEPS-interface/CDEPS/datm/datm_datamode_era5_mod.F90 b/CDEPS-interface/CDEPS/datm/datm_datamode_era5_mod.F90 new file mode 100644 index 0000000000..86e2dd5e9b --- /dev/null +++ b/CDEPS-interface/CDEPS/datm/datm_datamode_era5_mod.F90 @@ -0,0 +1,481 @@ +module datm_datamode_era5_mod + + use ESMF , only : ESMF_State, ESMF_SUCCESS, ESMF_LogWrite, ESMF_LOGMSG_INFO + use NUOPC , only : NUOPC_Advertise + use shr_kind_mod , only : r8=>shr_kind_r8, i8=>shr_kind_i8, cl=>shr_kind_cl, cs=>shr_kind_cs + use shr_sys_mod , only : shr_sys_abort + use shr_precip_mod , only : shr_precip_partition_rain_snow_ramp + use shr_const_mod , only : shr_const_tkfrz, shr_const_rhofw, shr_const_rdair + use dshr_methods_mod , only : dshr_state_getfldptr, chkerr + use dshr_strdata_mod , only : shr_strdata_type, shr_strdata_get_stream_pointer + use dshr_strdata_mod , only : shr_strdata_type + use dshr_fldlist_mod , only : fldlist_type, dshr_fldlist_add + + implicit none + private ! except + + public :: datm_datamode_era5_advertise + public :: datm_datamode_era5_init_pointers + public :: datm_datamode_era5_advance + private :: datm_eSat ! determine saturation vapor pressure + + ! export state data + real(r8), pointer :: Sa_z(:) => null() + real(r8), pointer :: Sa_u10m(:) => null() + real(r8), pointer :: Sa_v10m(:) => null() + real(r8), pointer :: Sa_u(:) => null() + real(r8), pointer :: Sa_v(:) => null() + real(r8), pointer :: Sa_wspd10m(:) => null() + real(r8), pointer :: Sa_wspd(:) => null() + real(r8), pointer :: Sa_t2m(:) => null() + real(r8), pointer :: Sa_tbot(:) => null() + real(r8), pointer :: Sa_tskn(:) => null() + real(r8), pointer :: Sa_q2m(:) => null() + real(r8), pointer :: Sa_shum(:) => null() + real(r8), pointer :: Sa_pslv(:) => null() + real(r8), pointer :: Sa_pbot(:) => null() + real(r8), pointer :: Faxa_rain(:) => null() + real(r8), pointer :: Faxa_rainc(:) => null() + real(r8), pointer :: Faxa_rainl(:) => null() + real(r8), pointer :: Faxa_snowc(:) => null() + real(r8), pointer :: Faxa_snowl(:) => null() + real(r8), pointer :: Faxa_swndr(:) => null() + real(r8), pointer :: Faxa_swndf(:) => null() + real(r8), pointer :: Faxa_swvdr(:) => null() + real(r8), pointer :: Faxa_swvdf(:) => null() + real(r8), pointer :: Faxa_swdn(:) => null() + real(r8), pointer :: Faxa_swnet(:) => null() + real(r8), pointer :: Faxa_lwdn(:) => null() + real(r8), pointer :: Faxa_lwnet(:) => null() + real(r8), pointer :: Faxa_sen(:) => null() + real(r8), pointer :: Faxa_lat(:) => null() + real(r8), pointer :: Faxa_taux(:) => null() + real(r8), pointer :: Faxa_tauy(:) => null() +! +! real(r8), pointer :: Faxa_ndep(:,:) => null() + + ! stream data + real(r8), pointer :: strm_z(:) => null() + real(r8), pointer :: strm_tdew(:) => null() + real(r8), pointer :: strm_wind(:) => null() + real(r8), pointer :: strm_wind10m(:) => null() + real(r8), pointer :: strm_u(:) => null() + real(r8), pointer :: strm_v(:) => null() + real(r8), pointer :: strm_u10m(:) => null() + real(r8), pointer :: strm_v10m(:) => null() + + real(r8) :: t2max ! units detector + real(r8) :: td2max ! units detector + real(r8) :: lwmax ! units detector + real(r8) :: precmax ! units detector + + real(r8) , parameter :: tKFrz = SHR_CONST_TKFRZ + real(r8) , parameter :: rdair = SHR_CONST_RDAIR ! dry air gas constant ~ J/K/kg + real(r8) , parameter :: rhofw = SHR_CONST_RHOFW ! density of fresh water ~ kg/m^3 + + character(*), parameter :: nullstr = 'undefined' + character(*), parameter :: u_FILE_u = & + __FILE__ + +!=============================================================================== +contains +!=============================================================================== + + subroutine datm_datamode_era5_advertise(exportState, fldsexport, & + flds_scalar_name, rc) + + ! input/output variables + type(esmf_State) , intent(inout) :: exportState + type(fldlist_type) , pointer :: fldsexport + character(len=*) , intent(in) :: flds_scalar_name + integer , intent(out) :: rc + + ! local variables + type(fldlist_type), pointer :: fldList + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + call dshr_fldList_add(fldsExport, trim(flds_scalar_name)) + call dshr_fldList_add(fldsExport, 'Sa_z' ) + call dshr_fldList_add(fldsExport, 'Sa_u10m' ) + call dshr_fldList_add(fldsExport, 'Sa_v10m' ) + call dshr_fldList_add(fldsExport, 'Sa_u' ) + call dshr_fldList_add(fldsExport, 'Sa_v' ) + call dshr_fldList_add(fldsExport, 'Sa_wspd10m' ) + call dshr_fldList_add(fldsExport, 'Sa_wspd' ) + call dshr_fldList_add(fldsExport, 'Sa_t2m' ) + call dshr_fldList_add(fldsExport, 'Sa_tbot' ) + call dshr_fldList_add(fldsExport, 'Sa_tskn' ) + call dshr_fldList_add(fldsExport, 'Sa_q2m' ) + call dshr_fldList_add(fldsExport, 'Sa_shum' ) + call dshr_fldList_add(fldsExport, 'Sa_pslv' ) + call dshr_fldList_add(fldsExport, 'Sa_pbot' ) + call dshr_fldList_add(fldsExport, 'Faxa_rain' ) + call dshr_fldList_add(fldsExport, 'Faxa_rainc' ) + call dshr_fldList_add(fldsExport, 'Faxa_rainl' ) + call dshr_fldList_add(fldsExport, 'Faxa_snowc' ) + call dshr_fldList_add(fldsExport, 'Faxa_snowl' ) + call dshr_fldList_add(fldsExport, 'Faxa_swndr' ) + call dshr_fldList_add(fldsExport, 'Faxa_swvdr' ) + call dshr_fldList_add(fldsExport, 'Faxa_swndf' ) + call dshr_fldList_add(fldsExport, 'Faxa_swvdf' ) + call dshr_fldList_add(fldsExport, 'Faxa_swdn' ) + call dshr_fldList_add(fldsExport, 'Faxa_swnet' ) + call dshr_fldList_add(fldsExport, 'Faxa_lwdn' ) + call dshr_fldList_add(fldsExport, 'Faxa_lwnet' ) + call dshr_fldList_add(fldsExport, 'Faxa_sen' ) + call dshr_fldList_add(fldsExport, 'Faxa_lat' ) + call dshr_fldList_add(fldsExport, 'Faxa_taux' ) + call dshr_fldList_add(fldsExport, 'Faxa_tauy' ) + + fldlist => fldsExport ! the head of the linked list + do while (associated(fldlist)) + call NUOPC_Advertise(exportState, standardName=fldlist%stdname, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_LogWrite('(datm_comp_advertise): Fr_atm '//trim(fldList%stdname), ESMF_LOGMSG_INFO) + fldList => fldList%next + enddo + + end subroutine datm_datamode_era5_advertise + + !=============================================================================== + subroutine datm_datamode_era5_init_pointers(exportState, sdat, rc) + + ! input/output variables + type(ESMF_State) , intent(inout) :: exportState + type(shr_strdata_type) , intent(in) :: sdat + integer , intent(out) :: rc + + ! local variables + character(len=*), parameter :: subname='(datm_init_pointers): ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + ! initialize pointers for module level stream arrays + call shr_strdata_get_stream_pointer(sdat, 'Sa_z' , strm_z , rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_strdata_get_stream_pointer(sdat, 'Sa_tdew' , strm_tdew, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_strdata_get_stream_pointer(sdat, 'Sa_wspd' , strm_wind, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_strdata_get_stream_pointer(sdat, 'Sa_wspd10m', strm_wind10m, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_strdata_get_stream_pointer(sdat, 'Sa_u' , strm_u, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_strdata_get_stream_pointer(sdat, 'Sa_v' , strm_v, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_strdata_get_stream_pointer(sdat, 'Sa_u10m' , strm_u10m, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_strdata_get_stream_pointer(sdat, 'Sa_v10m' , strm_v10m, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! get export state pointers + call dshr_state_getfldptr(exportState, 'Sa_z' , fldptr1=Sa_z , allowNullReturn=.true., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_u10m' , fldptr1=Sa_u10m , allowNullReturn=.true., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_v10m' , fldptr1=Sa_v10m , allowNullReturn=.true., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_u' , fldptr1=Sa_u , allowNullReturn=.true., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_v' , fldptr1=Sa_v , allowNullReturn=.true., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_wspd10m' , fldptr1=Sa_wspd10m , allowNullReturn=.true., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_wspd' , fldptr1=Sa_wspd , allowNullReturn=.true., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_t2m' , fldptr1=Sa_t2m , allowNullReturn=.true., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_tbot' , fldptr1=Sa_tbot , allowNullReturn=.true., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_tskn' , fldptr1=Sa_tskn , allowNullReturn=.true., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_q2m' , fldptr1=Sa_q2m , allowNullReturn=.true., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_shum' , fldptr1=Sa_shum , allowNullReturn=.true., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_pslv' , fldptr1=Sa_pslv , allowNullReturn=.true., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_pbot' , fldptr1=Sa_pbot , allowNullReturn=.true., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_rain' , fldptr1=Faxa_rain , allowNullReturn=.true., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_rainc' , fldptr1=Faxa_rainc , allowNullReturn=.true., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_rainl' , fldptr1=Faxa_rainl , allowNullReturn=.true., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_snowc' , fldptr1=Faxa_snowc , allowNullReturn=.true., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_snowl' , fldptr1=Faxa_snowl , allowNullReturn=.true., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swvdr' , fldptr1=Faxa_swvdr , allowNullReturn=.true., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swvdf' , fldptr1=Faxa_swvdf , allowNullReturn=.true., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swndr' , fldptr1=Faxa_swndr , allowNullReturn=.true., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swndf' , fldptr1=Faxa_swndf , allowNullReturn=.true., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swdn' , fldptr1=Faxa_swdn , allowNullReturn=.true., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swnet' , fldptr1=Faxa_swnet , allowNullReturn=.true., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_lwdn' , fldptr1=Faxa_lwdn , allowNullReturn=.true., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_lwnet' , fldptr1=Faxa_lwnet , allowNullReturn=.true., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_sen' , fldptr1=Faxa_sen , allowNullReturn=.true., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_lat' , fldptr1=Faxa_lat , allowNullReturn=.true., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_taux' , fldptr1=Faxa_taux , allowNullReturn=.true., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_tauy' , fldptr1=Faxa_tauy , allowNullReturn=.true., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + end subroutine datm_datamode_era5_init_pointers + + !=============================================================================== + subroutine datm_datamode_era5_advance(exportstate, mainproc, logunit, mpicom, target_ymd, target_tod, model_calendar, rc) + use ESMF, only: ESMF_VMGetCurrent, ESMF_VMAllReduce, ESMF_REDUCE_MAX, ESMF_VM + + ! input/output variables + type(ESMF_State) , intent(inout) :: exportState + logical , intent(in) :: mainproc + integer , intent(in) :: logunit + integer , intent(in) :: mpicom + integer , intent(in) :: target_ymd + integer , intent(in) :: target_tod + character(len=*) , intent(in) :: model_calendar + integer , intent(out) :: rc + + ! local variables + logical :: first_time = .true. + integer :: n ! indices + integer :: lsize = 0 ! size of attr vect + real(r8) :: rtmp(2) + real(r8) :: tbot, pbot + real(r8) :: e, qsat + type(ESMF_VM) :: vm + character(len=*), parameter :: subname='(datm_datamode_era5_advance): ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + ! one of the following needs to be in the stream + if (associated(Sa_z)) lsize = size(Sa_z) + if (associated(strm_tdew)) lsize = size(strm_tdew) + if (mainproc .and. lsize == 0) then + write(logunit,*) trim(subname),' Sa_z or Sa_tdew need to be in the stream! Exiting ...' + end if + + if (first_time) then + call ESMF_VMGetCurrent(vm, rc=rc) + ! determine t2max (see below for use) + if (associated(Sa_t2m)) then + rtmp(1) = maxval(Sa_t2m(:)) + call ESMF_VMAllReduce(vm, rtmp, rtmp(2:), 1, ESMF_REDUCE_MAX, rc=rc) + t2max = rtmp(2) + if (mainproc) write(logunit,*) trim(subname),' t2max = ',t2max + end if + + ! determine tdewmax (see below for use) + if (associated(strm_tdew)) then + rtmp(1) = maxval(strm_tdew(:)) + call ESMF_VMAllReduce(vm, rtmp, rtmp(2:), 1, ESMF_REDUCE_MAX, rc=rc) + td2max = rtmp(2) + if (mainproc) write(logunit,*) trim(subname),' td2max = ',td2max + end if + + ! determine lwmax / lwmax + if (associated(Faxa_lwdn)) then + rtmp(1) = maxval(Faxa_lwdn(:)) + call ESMF_VMAllReduce(vm, rtmp, rtmp(2:), 1, ESMF_REDUCE_MAX, rc=rc) + lwmax = rtmp(2) + if (mainproc) write(logunit,*) trim(subname),' lwmax = ',lwmax + else + ! try with other variable since Faxa_lwdn is not available + if (associated(Faxa_lwnet)) then + rtmp(1) = maxval(Faxa_lwnet(:)) + call ESMF_VMAllReduce(vm, rtmp, rtmp(2:), 1, ESMF_REDUCE_MAX, rc=rc) + lwmax = rtmp(2) + if (mainproc) write(logunit,*) trim(subname),' lwmax = ',lwmax + else + lwmax = 0.0_r8 + end if + end if + + ! determine precmax + if (associated(Faxa_rain)) then + rtmp(1) = maxval(Faxa_rain(:)) + call ESMF_VMAllReduce(vm, rtmp, rtmp(2:), 1, ESMF_REDUCE_MAX, rc=rc) + precmax = rtmp(2) + if (mainproc) write(logunit,*) trim(subname),' precmax = ', precmax + else + ! try with other variable since Faxa_rain is not available + if (associated(Faxa_rainl)) then + rtmp(1) = maxval(Faxa_rainl(:)) + call ESMF_VMAllReduce(vm, rtmp, rtmp(2:), 1, ESMF_REDUCE_MAX, rc=rc) + precmax = rtmp(2) + if (mainproc) write(logunit,*) trim(subname),' precmax = ', precmax + else + precmax = 0.0_r8 + end if + end if + + ! reset first_time + first_time = .false. + end if + + do n = 1, lsize + !--- bottom layer height --- + if (.not. associated(strm_z) .and. associated(Sa_z)) then + Sa_z(n) = 10.0_r8 + end if + + !--- calculate wind components if wind speed is provided --- + if (associated(strm_wind)) then + Sa_u(n) = strm_wind(n)/sqrt(2.0_r8) + Sa_v(n) = Sa_u(n) + end if + if (associated(strm_wind10m)) then + Sa_u10m(n) = strm_wind10m(n)/sqrt(2.0_r8) + Sa_v10m(n) = Sa_u10m(n) + end if + + !--- calculate wind speed if wind components are provided --- + if (associated(strm_u10m) .and. associated(strm_v10m) .and. associated(Sa_wspd10m)) then + Sa_wspd10m(n) = sqrt(Sa_u10m(n)*Sa_u10m(n)+Sa_v10m(n)*Sa_v10m(n)) + end if + if (associated(strm_u) .and. associated(strm_v) .and. associated(Sa_wspd)) then + Sa_wspd(n) = sqrt(Sa_u(n)*Sa_u(n)+Sa_v(n)*Sa_v(n)) + end if + + !--- calculate specific humidity from dew point temperature --- + if (associated(strm_tdew)) then + if (associated(Sa_t2m)) then + tbot = Sa_t2m(n) + else if (associated(Sa_tbot)) then + tbot = Sa_tbot(n) + end if + + if (associated(Sa_pslv)) then + pbot = Sa_pslv(n) + else if (associated(Sa_pbot)) then + pbot = Sa_pbot(n) + end if + + if (td2max < 50.0_r8) strm_tdew(n) = strm_tdew(n) + tkFrz + e = datm_eSat(strm_tdew(n), tbot) + qsat = (0.622_r8 * e)/(pbot - 0.378_r8 * e) + if (associated(Sa_q2m)) Sa_q2m(n) = qsat + if (associated(Sa_shum)) Sa_shum(n) = qsat + end if + end do + + !---------------------------------------------------------- + ! shortwave bands + !---------------------------------------------------------- + + !--- shortwave radiation (Faxa_* basically holds albedo) --- + !--- see comments for Faxa_swnet + if (associated(Faxa_swvdr)) Faxa_swvdr(:) = Faxa_swdn(:)*Faxa_swvdr(:) + if (associated(Faxa_swndr)) Faxa_swndr(:) = Faxa_swdn(:)*Faxa_swndr(:) + if (associated(Faxa_swvdf)) Faxa_swvdf(:) = Faxa_swdn(:)*Faxa_swvdf(:) + if (associated(Faxa_swndf)) Faxa_swndf(:) = Faxa_swdn(:)*Faxa_swndf(:) + + !--- TODO: need to understand relationship between shortwave bands and + !--- net shortwave rad. currently it is provided directly from ERA5 + !--- and the total of the bands are not consistent with the swnet + !--- swnet: a diagnostic quantity --- + !if (associated(Faxa_swnet)) then + ! if (associated(Faxa_swndr) .and. associated(Faxa_swvdr) .and. & + ! associated(Faxa_swndf) .and. associated(Faxa_swvdf)) then + ! Faxa_swnet(:) = Faxa_swndr(:) + Faxa_swvdr(:) + Faxa_swndf(:) + Faxa_swvdf(:) + ! end if + !end if + + !---------------------------------------------------------- + ! unit conversions (temporal resolution is hourly) + !---------------------------------------------------------- + + ! convert J/m^2 to W/m^2 + if (lwmax < 1.0e4_r8) then + if (mainproc) write(logunit,*) trim(subname),' flux related variables are already in W/m^2 unit!' + else + if (associated(Faxa_lwdn)) Faxa_lwdn(:) = Faxa_lwdn(:)/3600.0_r8 + if (associated(Faxa_lwnet)) Faxa_lwnet(:) = Faxa_lwnet(:)/3600.0_r8 + if (associated(Faxa_swvdr)) Faxa_swvdr(:) = Faxa_swvdr(:)/3600.0_r8 + if (associated(Faxa_swndr)) Faxa_swndr(:) = Faxa_swndr(:)/3600.0_r8 + if (associated(Faxa_swvdf)) Faxa_swvdf(:) = Faxa_swvdf(:)/3600.0_r8 + if (associated(Faxa_swndf)) Faxa_swndf(:) = Faxa_swndf(:)/3600.0_r8 + if (associated(Faxa_swdn)) Faxa_swdn(:) = Faxa_swdn(:)/3600.0_r8 + if (associated(Faxa_swnet)) Faxa_swnet(:) = Faxa_swnet(:)/3600.0_r8 + if (associated(Faxa_sen)) Faxa_sen(:) = Faxa_sen(:)/3600.0_r8 + if (associated(Faxa_lat)) Faxa_lat(:) = Faxa_lat(:)/3600.0_r8 + end if + + ! convert m to kg/m^2/s + if (precmax < 0.01_r8) then + if (mainproc) write(logunit,*) trim(subname),' precipitation related variables are already in kg/m^2/s unit!' + else + if (associated(Faxa_rain)) Faxa_rain(:) = Faxa_rain(:)/3600.0_r8*rhofw + if (associated(Faxa_rainc)) Faxa_rainc(:) = Faxa_rainc(:)/3600.0_r8*rhofw + if (associated(Faxa_rainl)) Faxa_rainl(:) = Faxa_rainl(:)/3600.0_r8*rhofw + if (associated(Faxa_snowc)) Faxa_snowc(:) = Faxa_snowc(:)/3600.0_r8*rhofw + if (associated(Faxa_snowl)) Faxa_snowl(:) = Faxa_snowl(:)/3600.0_r8*rhofw + end if + + ! convert N/m^2 s to N/m^2 + if (associated(Faxa_taux)) Faxa_taux(:) = Faxa_taux(:)/3600.0_r8 + if (associated(Faxa_tauy)) Faxa_tauy(:) = Faxa_tauy(:)/3600.0_r8 + + end subroutine datm_datamode_era5_advance + + !=============================================================================== + real(r8) function datm_eSat(tK,tKbot) + + !---------------------------------------------------------------------------- + ! use polynomials to calculate saturation vapor pressure and derivative with + ! respect to temperature: over water when t > 0 c and over ice when t <= 0 c + ! required to convert relative humidity to specific humidity + !---------------------------------------------------------------------------- + + ! input/output variables + real(r8),intent(in) :: tK ! temp used in polynomial calculation + real(r8),intent(in) :: tKbot ! bottom atm temp + + ! local variables + real(r8) :: t ! tK converted to Celcius + real(r8),parameter :: tkFrz = shr_const_tkfrz ! freezing T of fresh water ~ K + + !--- coefficients for esat over water --- + real(r8),parameter :: a0=6.107799961_r8 + real(r8),parameter :: a1=4.436518521e-01_r8 + real(r8),parameter :: a2=1.428945805e-02_r8 + real(r8),parameter :: a3=2.650648471e-04_r8 + real(r8),parameter :: a4=3.031240396e-06_r8 + real(r8),parameter :: a5=2.034080948e-08_r8 + real(r8),parameter :: a6=6.136820929e-11_r8 + + !--- coefficients for esat over ice --- + real(r8),parameter :: b0=6.109177956_r8 + real(r8),parameter :: b1=5.034698970e-01_r8 + real(r8),parameter :: b2=1.886013408e-02_r8 + real(r8),parameter :: b3=4.176223716e-04_r8 + real(r8),parameter :: b4=5.824720280e-06_r8 + real(r8),parameter :: b5=4.838803174e-08_r8 + real(r8),parameter :: b6=1.838826904e-10_r8 + + t = min( 50.0_r8, max(-50.0_r8,(tK-tKfrz)) ) + if ( tKbot < tKfrz) then + datm_eSat = 100.0_r8*(b0+t*(b1+t*(b2+t*(b3+t*(b4+t*(b5+t*b6)))))) + else + datm_eSat = 100.0_r8*(a0+t*(a1+t*(a2+t*(a3+t*(a4+t*(a5+t*a6)))))) + end if + + end function datm_eSat + +end module datm_datamode_era5_mod diff --git a/CDEPS-interface/CDEPS/datm/datm_datamode_gefs_mod.F90 b/CDEPS-interface/CDEPS/datm/datm_datamode_gefs_mod.F90 new file mode 100644 index 0000000000..fb7a0b4dca --- /dev/null +++ b/CDEPS-interface/CDEPS/datm/datm_datamode_gefs_mod.F90 @@ -0,0 +1,219 @@ +module datm_datamode_gefs_mod + + use ESMF , only : ESMF_State, ESMF_SUCCESS, ESMF_LogWrite, ESMF_LOGMSG_INFO + use NUOPC , only : NUOPC_Advertise + use shr_kind_mod , only : r8=>shr_kind_r8, i8=>shr_kind_i8, cl=>shr_kind_cl, cs=>shr_kind_cs + use shr_sys_mod , only : shr_sys_abort + use shr_precip_mod , only : shr_precip_partition_rain_snow_ramp + use shr_const_mod , only : shr_const_tkfrz, shr_const_rhofw, shr_const_rdair + use dshr_methods_mod , only : dshr_state_getfldptr, chkerr + use dshr_strdata_mod , only : shr_strdata_type, shr_strdata_get_stream_pointer + use dshr_strdata_mod , only : shr_strdata_type + use dshr_fldlist_mod , only : fldlist_type, dshr_fldlist_add + + implicit none + private ! except + + public :: datm_datamode_gefs_advertise + public :: datm_datamode_gefs_init_pointers + public :: datm_datamode_gefs_advance + + ! export state data + real(r8), pointer :: Sa_z(:) => null() + real(r8), pointer :: Sa_u(:) => null() + real(r8), pointer :: Sa_v(:) => null() + real(r8), pointer :: Sa_tbot(:) => null() + real(r8), pointer :: Sa_shum(:) => null() + real(r8), pointer :: Sa_pbot(:) => null() + real(r8), pointer :: Sa_u10m(:) => null() + real(r8), pointer :: Sa_v10m(:) => null() + real(r8), pointer :: Sa_t2m(:) => null() + real(r8), pointer :: Sa_q2m(:) => null() + real(r8), pointer :: Sa_pslv(:) => null() + real(r8), pointer :: Faxa_lwdn(:) => null() + real(r8), pointer :: Faxa_rain(:) => null() + real(r8), pointer :: Faxa_snow(:) => null() + real(r8), pointer :: Faxa_swndr(:) => null() + real(r8), pointer :: Faxa_swndf(:) => null() + real(r8), pointer :: Faxa_swvdr(:) => null() + real(r8), pointer :: Faxa_swvdf(:) => null() + + ! stream data + real(r8), pointer :: strm_mask(:) => null() + + real(r8) :: tbotmax ! units detector + real(r8) :: maskmax ! units detector + + real(r8) , parameter :: tKFrz = SHR_CONST_TKFRZ + real(r8) , parameter :: rdair = SHR_CONST_RDAIR ! dry air gas constant ~ J/K/kg + real(r8) , parameter :: rhofw = SHR_CONST_RHOFW ! density of fresh water ~ kg/m^3 + + character(*), parameter :: nullstr = 'undefined' + character(*), parameter :: u_FILE_u = & + __FILE__ + +!=============================================================================== +contains +!=============================================================================== + + subroutine datm_datamode_gefs_advertise(exportState, fldsexport, & + flds_scalar_name, rc) + + ! input/output variables + type(esmf_State) , intent(inout) :: exportState + type(fldlist_type) , pointer :: fldsexport + character(len=*) , intent(in) :: flds_scalar_name + integer , intent(out) :: rc + + ! local variables + type(fldlist_type), pointer :: fldList + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + call dshr_fldList_add(fldsExport, trim(flds_scalar_name)) + call dshr_fldList_add(fldsExport, 'Sa_z' ) + call dshr_fldList_add(fldsExport, 'Sa_u' ) + call dshr_fldList_add(fldsExport, 'Sa_v' ) + call dshr_fldList_add(fldsExport, 'Sa_tbot' ) + call dshr_fldList_add(fldsExport, 'Sa_pbot' ) + call dshr_fldList_add(fldsExport, 'Sa_shum' ) + call dshr_fldList_add(fldsExport, 'Sa_u10m' ) + call dshr_fldList_add(fldsExport, 'Sa_v10m' ) + call dshr_fldList_add(fldsExport, 'Sa_t2m' ) + call dshr_fldList_add(fldsExport, 'Sa_q2m' ) + call dshr_fldList_add(fldsExport, 'Sa_pslv' ) + call dshr_fldList_add(fldsExport, 'Faxa_rain' ) + call dshr_fldList_add(fldsExport, 'Faxa_snow' ) + call dshr_fldList_add(fldsExport, 'Faxa_swndr' ) + call dshr_fldList_add(fldsExport, 'Faxa_swvdr' ) + call dshr_fldList_add(fldsExport, 'Faxa_swndf' ) + call dshr_fldList_add(fldsExport, 'Faxa_swvdf' ) + call dshr_fldList_add(fldsExport, 'Faxa_lwdn' ) + + fldlist => fldsExport ! the head of the linked list + do while (associated(fldlist)) + call NUOPC_Advertise(exportState, standardName=fldlist%stdname, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_LogWrite('(datm_comp_advertise): Fr_atm '//trim(fldList%stdname), ESMF_LOGMSG_INFO) + fldList => fldList%next + enddo + + end subroutine datm_datamode_gefs_advertise + + !=============================================================================== + subroutine datm_datamode_gefs_init_pointers(exportState, sdat, rc) + + ! input/output variables + type(ESMF_State) , intent(inout) :: exportState + type(shr_strdata_type) , intent(in) :: sdat + integer , intent(out) :: rc + + ! local variables + character(len=*), parameter :: subname='(datm_init_pointers): ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + ! initialize pointers for module level stream arrays + call shr_strdata_get_stream_pointer( sdat, 'Sa_mask' , strm_mask , rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! get export state pointers + call dshr_state_getfldptr(exportState, 'Sa_z' , fldptr1=Sa_z , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_u' , fldptr1=Sa_u , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_v' , fldptr1=Sa_v , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_tbot' , fldptr1=Sa_tbot , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_pbot' , fldptr1=Sa_pbot , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_shum' , fldptr1=Sa_shum , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_u10m' , fldptr1=Sa_u10m , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_v10m' , fldptr1=Sa_v10m , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_t2m' , fldptr1=Sa_t2m , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_q2m' , fldptr1=Sa_q2m , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_pslv' , fldptr1=Sa_pslv , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_rain' , fldptr1=Faxa_rain , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_snow' , fldptr1=Faxa_snow, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swvdr' , fldptr1=Faxa_swvdr , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swvdf' , fldptr1=Faxa_swvdf , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swndr' , fldptr1=Faxa_swndr , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swndf' , fldptr1=Faxa_swndf , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_lwdn' , fldptr1=Faxa_lwdn , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + end subroutine datm_datamode_gefs_init_pointers + + !=============================================================================== + subroutine datm_datamode_gefs_advance(exportstate, mainproc, logunit, mpicom, target_ymd, target_tod, model_calendar, rc) + use ESMF, only: ESMF_VMGetCurrent, ESMF_VMAllReduce, ESMF_REDUCE_MAX, ESMF_VM + ! input/output variables + type(ESMF_State) , intent(inout) :: exportState + logical , intent(in) :: mainproc + integer , intent(in) :: logunit + integer , intent(in) :: mpicom + integer , intent(in) :: target_ymd + integer , intent(in) :: target_tod + character(len=*) , intent(in) :: model_calendar + integer , intent(out) :: rc + + ! local variables + logical :: first_time = .true. + integer :: n ! indices + integer :: lsize ! size of attr vect + real(r8) :: rtmp(2) + type(ESMF_VM) :: vm + character(len=*), parameter :: subname='(datm_datamode_gefs_advance): ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + lsize = size(strm_mask) + + if (first_time) then + call ESMF_VMGetCurrent(vm, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + ! determine tbotmax (see below for use) + rtmp(1) = maxval(Sa_tbot(:)) + call ESMF_VMAllReduce(vm, rtmp, rtmp(2:), 1, ESMF_REDUCE_MAX, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + tbotmax = rtmp(2) + + if (mainproc) write(logunit,*) trim(subname),' tbotmax = ',tbotmax + + ! determine maskmax (see below for use) + rtmp(1) = maxval(strm_mask(:)) + call ESMF_VMAllReduce(vm, rtmp, rtmp(2:), 1, ESMF_REDUCE_MAX, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + maskmax = rtmp(2) + if (mainproc) write(logunit,*) trim(subname),' maskmax = ',maskmax + + ! reset first_time + first_time = .false. + end if + + do n = 1, lsize + !--- temperature --- + if (tbotmax < 50.0_r8) Sa_tbot(n) = Sa_tbot(n) + tkFrz + ! Limit very cold forcing to 180K + Sa_tbot(n) = max(180._r8, Sa_tbot(n)) + end do + + end subroutine datm_datamode_gefs_advance + +end module datm_datamode_gefs_mod diff --git a/CDEPS-interface/CDEPS/datm/datm_datamode_jra_mod.F90 b/CDEPS-interface/CDEPS/datm/datm_datamode_jra_mod.F90 new file mode 100644 index 0000000000..2e0e5ee67e --- /dev/null +++ b/CDEPS-interface/CDEPS/datm/datm_datamode_jra_mod.F90 @@ -0,0 +1,302 @@ +module datm_datamode_jra_mod + + use ESMF , only : ESMF_State, ESMF_StateGet, ESMF_SUCCESS, ESMF_LogWrite, ESMF_LOGMSG_INFO + use ESMF , only : ESMF_MeshGet + use ESMF , only : ESMF_StateItem_Flag, ESMF_STATEITEM_NOTFOUND, operator(/=) + use NUOPC , only : NUOPC_Advertise + use shr_kind_mod , only : r8=>shr_kind_r8, i8=>shr_kind_i8, cl=>shr_kind_cl, cs=>shr_kind_cs + use shr_sys_mod , only : shr_sys_abort + use shr_cal_mod , only : shr_cal_date2julian + use shr_const_mod , only : shr_const_tkfrz, shr_const_pi, shr_const_rdair + use dshr_strdata_mod , only : shr_strdata_get_stream_pointer, shr_strdata_type + use dshr_methods_mod , only : dshr_state_getfldptr, dshr_fldbun_getfldptr, dshr_fldbun_regrid, chkerr + use dshr_strdata_mod , only : shr_strdata_type + use dshr_fldlist_mod , only : fldlist_type, dshr_fldlist_add + + implicit none + private ! except + + public :: datm_datamode_jra_advertise + public :: datm_datamode_jra_init_pointers + public :: datm_datamode_jra_advance + + ! export state pointers + real(r8), pointer :: Sa_z(:) => null() + real(r8), pointer :: Sa_u(:) => null() + real(r8), pointer :: Sa_v(:) => null() + real(r8), pointer :: Sa_u10m(:) => null() + real(r8), pointer :: Sa_v10m(:) => null() + real(r8), pointer :: Sa_tbot(:) => null() + real(r8), pointer :: Sa_ptem(:) => null() + real(r8), pointer :: Sa_shum(:) => null() + real(r8), pointer :: Sa_dens(:) => null() + real(r8), pointer :: Sa_pbot(:) => null() + real(r8), pointer :: Sa_pslv(:) => null() + real(r8), pointer :: Faxa_rainc(:) => null() + real(r8), pointer :: Faxa_rainl(:) => null() + real(r8), pointer :: Faxa_snowc(:) => null() + real(r8), pointer :: Faxa_snowl(:) => null() + real(r8), pointer :: Faxa_swndr(:) => null() + real(r8), pointer :: Faxa_swndf(:) => null() + real(r8), pointer :: Faxa_swvdr(:) => null() + real(r8), pointer :: Faxa_swvdf(:) => null() + real(r8), pointer :: Faxa_swnet(:) => null() + real(r8), pointer :: Faxa_ndep(:,:) => null() + + ! stream data + real(r8), pointer :: strm_prec(:) => null() + real(r8), pointer :: strm_swdn(:) => null() + + ! othe module arrays + real(R8), pointer :: yc(:) ! array of model latitudes + + ! constants + real(R8) , parameter :: tKFrz = SHR_CONST_TKFRZ + real(R8) , parameter :: rdair = SHR_CONST_RDAIR ! dry air gas constant ~ J/K/kg + real(R8) , parameter :: degtorad = SHR_CONST_PI/180.0_R8 + real(R8) , parameter :: phs_c0 = 0.298_R8 + real(R8) , parameter :: dLWarc = -5.000_R8 + + character(*), parameter :: nullstr = 'null' + character(*), parameter :: u_FILE_u = & + __FILE__ + +!=============================================================================== +contains +!=============================================================================== + + subroutine datm_datamode_jra_advertise(exportState, fldsexport, flds_scalar_name, & + flds_co2, flds_wiso, flds_presaero, flds_presndep, rc) + + ! input/output variables + type(esmf_State) , intent(inout) :: exportState + type(fldlist_type) , pointer :: fldsexport + character(len=*) , intent(in) :: flds_scalar_name + logical , intent(in) :: flds_co2 + logical , intent(in) :: flds_wiso + logical , intent(in) :: flds_presaero + logical , intent(in) :: flds_presndep + integer , intent(out) :: rc + + ! local variables + type(fldlist_type), pointer :: fldList + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + call dshr_fldList_add(fldsExport, trim(flds_scalar_name)) + call dshr_fldList_add(fldsExport, 'Sa_z' ) + call dshr_fldList_add(fldsExport, 'Sa_u' ) + call dshr_fldList_add(fldsExport, 'Sa_v' ) + call dshr_fldList_add(fldsExport, 'Sa_u10m' ) + call dshr_fldList_add(fldsExport, 'Sa_v10m' ) + call dshr_fldList_add(fldsExport, 'Sa_ptem' ) + call dshr_fldList_add(fldsExport, 'Sa_dens' ) + call dshr_fldList_add(fldsExport, 'Sa_pslv' ) + call dshr_fldList_add(fldsExport, 'Sa_tbot' ) + call dshr_fldList_add(fldsExport, 'Sa_pbot' ) + call dshr_fldList_add(fldsExport, 'Sa_shum' ) + call dshr_fldList_add(fldsExport, 'Faxa_rainc' ) + call dshr_fldList_add(fldsExport, 'Faxa_rainl' ) + call dshr_fldList_add(fldsExport, 'Faxa_snowc' ) + call dshr_fldList_add(fldsExport, 'Faxa_snowl' ) + call dshr_fldList_add(fldsExport, 'Faxa_swndr' ) + call dshr_fldList_add(fldsExport, 'Faxa_swvdr' ) + call dshr_fldList_add(fldsExport, 'Faxa_swndf' ) + call dshr_fldList_add(fldsExport, 'Faxa_swvdf' ) + call dshr_fldList_add(fldsExport, 'Faxa_swnet' ) + call dshr_fldList_add(fldsExport, 'Faxa_lwdn' ) + call dshr_fldList_add(fldsExport, 'Faxa_swdn' ) + + if (flds_co2) then + call dshr_fldList_add(fldsExport, 'Sa_co2prog') + call dshr_fldList_add(fldsExport, 'Sa_co2diag') + end if + if (flds_presaero) then + call dshr_fldList_add(fldsExport, 'Faxa_bcph' , ungridded_lbound=1, ungridded_ubound=3) + call dshr_fldList_add(fldsExport, 'Faxa_ocph' , ungridded_lbound=1, ungridded_ubound=3) + call dshr_fldList_add(fldsExport, 'Faxa_dstwet' , ungridded_lbound=1, ungridded_ubound=4) + call dshr_fldList_add(fldsExport, 'Faxa_dstdry' , ungridded_lbound=1, ungridded_ubound=4) + end if + if (flds_presndep) then + call dshr_fldList_add(fldsExport, 'Faxa_ndep', ungridded_lbound=1, ungridded_ubound=2) + end if + if (flds_wiso) then + call dshr_fldList_add(fldsExport, 'Faxa_rainc_wiso', ungridded_lbound=1, ungridded_ubound=3) + call dshr_fldList_add(fldsExport, 'Faxa_rainl_wiso', ungridded_lbound=1, ungridded_ubound=3) + call dshr_fldList_add(fldsExport, 'Faxa_snowc_wiso', ungridded_lbound=1, ungridded_ubound=3) + call dshr_fldList_add(fldsExport, 'Faxa_snowl_wiso', ungridded_lbound=1, ungridded_ubound=3) + call dshr_fldList_add(fldsExport, 'Faxa_shum_wiso' , ungridded_lbound=1, ungridded_ubound=3) + end if + + fldlist => fldsExport ! the head of the linked list + do while (associated(fldlist)) + call NUOPC_Advertise(exportState, standardName=fldlist%stdname, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_LogWrite('(datm_comp_advertise): Fr_atm'//trim(fldList%stdname), ESMF_LOGMSG_INFO) + fldList => fldList%next + enddo + + end subroutine datm_datamode_jra_advertise + + !=============================================================================== + subroutine datm_datamode_jra_init_pointers(exportState, sdat, rc) + + ! input/output variables + type(ESMF_State) , intent(inout) :: exportState + type(shr_strdata_type) , intent(in) :: sdat + integer , intent(out) :: rc + + ! local variables + integer :: n + integer :: lsize + integer :: spatialDim ! number of dimension in mesh + integer :: numOwnedElements ! size of mesh + real(r8), pointer :: ownedElemCoords(:) ! mesh lat and lons + type(ESMF_StateItem_Flag) :: itemFlag + character(len=*), parameter :: subname='(datm_init_pointers): ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + lsize = sdat%model_lsize + + call ESMF_MeshGet(sdat%model_mesh, spatialDim=spatialDim, numOwnedElements=numOwnedElements, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + allocate(ownedElemCoords(spatialDim*numOwnedElements)) + allocate(yc(numOwnedElements)) + call ESMF_MeshGet(sdat%model_mesh, ownedElemCoords=ownedElemCoords) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + do n = 1,numOwnedElements + yc(n) = ownedElemCoords(2*n) + end do + + call shr_strdata_get_stream_pointer( sdat, 'Faxa_prec' , strm_prec , rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_strdata_get_stream_pointer( sdat, 'Faxa_swdn' , strm_swdn , rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call dshr_state_getfldptr(exportState, 'Sa_u' , fldptr1=Sa_u , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_v' , fldptr1=Sa_v , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_u10m' , fldptr1=Sa_u10m , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_v10m' , fldptr1=Sa_v10m , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_z' , fldptr1=Sa_z , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_tbot' , fldptr1=Sa_tbot , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_pbot' , fldptr1=Sa_pbot , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_pslv' , fldptr1=Sa_pslv , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_ptem' , fldptr1=Sa_ptem , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_shum' , fldptr1=Sa_shum , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_dens' , fldptr1=Sa_dens , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_rainc' , fldptr1=Faxa_rainc , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_rainl' , fldptr1=Faxa_rainl , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_snowc' , fldptr1=Faxa_snowc , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_snowl' , fldptr1=Faxa_snowl , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swvdr' , fldptr1=Faxa_swvdr , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swvdf' , fldptr1=Faxa_swvdf , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swndr' , fldptr1=Faxa_swndr , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swndf' , fldptr1=Faxa_swndf , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swnet' , fldptr1=Faxa_swnet , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_StateGet(exportState, 'Faxa_ndep', itemFlag, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (itemflag /= ESMF_STATEITEM_NOTFOUND) then + call dshr_state_getfldptr(exportState, 'Faxa_ndep', fldptr2=Faxa_ndep, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + ! erro check + if (.not. associated(strm_prec) .or. .not. associated(strm_swdn)) then + call shr_sys_abort(trim(subname)//'ERROR: prec and swdn must be in streams for CORE_IAF_JRA') + endif + + end subroutine datm_datamode_jra_init_pointers + + !=============================================================================== + subroutine datm_datamode_jra_advance(exportstate, target_ymd, target_tod, model_calendar, rc) + + ! input/output variables + type(ESMF_State) , intent(inout) :: exportState + integer , intent(in) :: target_ymd + integer , intent(in) :: target_tod + character(len=*) , intent(in) :: model_calendar + integer , intent(out) :: rc + + ! local variables + integer :: n + integer :: lsize + real(R8) :: avg_alb ! average albedo + real(R8) :: rday ! elapsed day + real(R8) :: cosFactor ! cosine factor + character(len=*), parameter :: subname='(datm_datamode_jra): ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + lsize = size(Sa_z) + + call shr_cal_date2julian(target_ymd, target_tod, rday, model_calendar) + rday = mod((rday - 1.0_R8),365.0_R8) + cosfactor = cos((2.0_R8*SHR_CONST_PI*rday)/365 - phs_c0) + + do n = 1,lsize + Sa_z(n) = 10.0_R8 + Sa_pbot(n) = Sa_pslv(n) + Sa_ptem(n) = Sa_tbot(n) + + ! Set Sa_u10m and Sa_v10m to Sa_u and Sa_v + Sa_u10m(n) = Sa_u(n) + Sa_v10m(n) = Sa_v(n) + + ! density computation for JRA55 forcing + Sa_dens(n) = Sa_pbot(n)/(rdair*Sa_tbot(n)*(1 + 0.608*Sa_shum(n))) + + ! precipitation data + Faxa_rainc(n) = 0.0_R8 ! default zero + Faxa_snowc(n) = 0.0_R8 + if (Sa_tbot(n) < tKFrz ) then ! assign precip to rain/snow components + Faxa_rainl(n) = 0.0_R8 + Faxa_snowl(n) = strm_prec(n) + else + Faxa_rainl(n) = strm_prec(n) + Faxa_snowl(n) = 0.0_R8 + endif + + ! radiation data - fabricate required swdn components from net swdn + Faxa_swvdr(n) = strm_swdn(n)*(0.28_R8) + Faxa_swndr(n) = strm_swdn(n)*(0.31_R8) + Faxa_swvdf(n) = strm_swdn(n)*(0.24_R8) + Faxa_swndf(n) = strm_swdn(n)*(0.17_R8) + + ! radiation data - compute net short-wave based on LY08 latitudinally-varying albedo + avg_alb = ( 0.069 - 0.011*cos(2.0_R8*yc(n)*degtorad ) ) + Faxa_swnet(n) = strm_swdn(n)*(1.0_R8 - avg_alb) + enddo ! lsize + + if (associated(Faxa_ndep)) then + ! convert ndep flux to units of kgN/m2/s (input is in gN/m2/s) + Faxa_ndep(:,:) = Faxa_ndep(:,:) / 1000._r8 + end if + + end subroutine datm_datamode_jra_advance + +end module datm_datamode_jra_mod diff --git a/CDEPS-interface/CDEPS/datm/datm_datamode_simple_mod.F90 b/CDEPS-interface/CDEPS/datm/datm_datamode_simple_mod.F90 new file mode 100644 index 0000000000..454bceeac1 --- /dev/null +++ b/CDEPS-interface/CDEPS/datm/datm_datamode_simple_mod.F90 @@ -0,0 +1,340 @@ +module datm_datamode_simple_mod + + use ESMF , only : ESMF_State, ESMF_StateGet, ESMF_Field, ESMF_FieldBundle + use ESMF , only : ESMF_DistGrid, ESMF_RouteHandle, ESMF_MeshCreate + use ESMF , only : ESMF_Mesh, ESMF_MeshGet, ESMF_MeshCreate + use ESMF , only : ESMF_SUCCESS, ESMF_LogWrite, ESMF_FILEFORMAT_ESMFMESH + use ESMF , only : ESMF_StateItem_Flag, ESMF_STATEITEM_NOTFOUND, operator(/=) + use ESMF , only : ESMF_FieldBundleCreate, ESMF_FieldCreate, ESMF_MESHLOC_ELEMENT + use ESMF , only : ESMF_FieldBundleAdd, ESMF_LOGMSG_INFO, ESMF_TYPEKIND_R8 + use ESMF , only : ESMF_RouteHandleDestroy, ESMF_EXTRAPMETHOD_NEAREST_STOD + use ESMF , only : ESMF_POLEMETHOD_ALLAVG, ESMF_REGRIDMETHOD_BILINEAR + use ESMF , only : ESMF_DistGridGet, ESMF_FieldRegridStore, ESMF_FieldRedistStore + use ESMF , only : ESMF_VM, ESMF_VMBroadcast + use pio , only : Var_Desc_t, file_desc_t, io_desc_t, pio_read_darray, pio_freedecomp + use pio , only : pio_openfile, PIO_NOWRITE, pio_seterrorhandling, PIO_BCAST_ERROR + use pio , only : pio_initdecomp, pio_inq_dimlen, pio_inq_varid + use pio , only : pio_inq_varndims, pio_inq_vardimid, pio_double + use pio , only : pio_closefile + use NUOPC , only : NUOPC_Advertise + use shr_kind_mod , only : r8=>shr_kind_r8, i8=>shr_kind_i8, cl=>shr_kind_cl, cs=>shr_kind_cs + use shr_sys_mod , only : shr_sys_abort + use shr_cal_mod , only : shr_cal_date2julian + use shr_const_mod , only : shr_const_tkfrz, shr_const_pi + use dshr_strdata_mod , only : shr_strdata_get_stream_pointer, shr_strdata_type + use dshr_methods_mod , only : dshr_state_getfldptr, dshr_fldbun_getfldptr, dshr_fldbun_regrid, chkerr + use dshr_strdata_mod , only : shr_strdata_type + use dshr_fldlist_mod , only : fldlist_type, dshr_fldlist_add + + implicit none + private ! except + + public :: datm_datamode_simple_advertise + public :: datm_datamode_simple_init_pointers + public :: datm_datamode_simple_advance + + ! export state pointers + real(r8), pointer :: Sa_u(:) => null() + real(r8), pointer :: Sa_v(:) => null() + real(r8), pointer :: Sa_z(:) => null() + real(r8), pointer :: Sa_tbot(:) => null() + real(r8), pointer :: Sa_ptem(:) => null() + real(r8), pointer :: Sa_shum(:) => null() + real(r8), pointer :: Sa_pbot(:) => null() + real(r8), pointer :: Sa_dens(:) => null() + real(r8), pointer :: Sa_pslv(:) => null() + real(r8), pointer :: Faxa_lwdn(:) => null() + real(r8), pointer :: Faxa_rainc(:) => null() + real(r8), pointer :: Faxa_rainl(:) => null() + real(r8), pointer :: Faxa_snowc(:) => null() + real(r8), pointer :: Faxa_snowl(:) => null() + real(r8), pointer :: Faxa_swndr(:) => null() + real(r8), pointer :: Faxa_swndf(:) => null() + real(r8), pointer :: Faxa_swvdr(:) => null() + real(r8), pointer :: Faxa_swvdf(:) => null() + real(r8), pointer :: Faxa_swnet(:) => null() + real(r8), pointer :: Faxa_ndep(:,:) => null() + + ! othe module arrays + real(R8), pointer :: yc(:) ! array of model latitudes + real(R8), pointer :: xc(:) ! array of model longitudes + + ! constant forcing values to be set via const_forcing_nml + real(R8) :: dn10 = 1.204_R8 + real(R8) :: slp = 101325.0_R8 + real(R8) :: q = 0.0_R8 + real(R8) :: t = 273.15_R8 + real(R8) :: u = 0.0_R8 + real(R8) :: v = 0.0_R8 + real(R8) :: peak_swdn = 330.0_R8 + real(R8) :: peak_lwdn = 450.0_R8 + + ! constants + real(R8) , parameter :: tKFrz = SHR_CONST_TKFRZ + real(R8) , parameter :: degtorad = SHR_CONST_PI/180.0_R8 + real(R8) , parameter :: phs_c0 = 0.298_R8 + real(R8) , parameter :: dLWarc = -5.000_R8 + + character(*), parameter :: nullstr = 'null' + character(*), parameter :: u_FILE_u = & + __FILE__ + +!=============================================================================== +contains +!=============================================================================== + + subroutine datm_datamode_simple_advertise(exportState, fldsexport, flds_scalar_name, & + nlfilename, my_task, vm, rc) + use shr_nl_mod, only: shr_nl_find_group_name + + ! input/output variables + type(esmf_State) , intent(inout) :: exportState + type(fldlist_type) , pointer :: fldsexport + character(len=*) , intent(in) :: flds_scalar_name + character(len=*) , intent(in) :: nlfilename + integer , intent(in) :: my_task + type(ESMF_VM) , intent(in) :: vm + integer , intent(out) :: rc + + ! local variables + type(fldlist_type), pointer :: fldList + integer , parameter :: main_task = 0 ! task number of main task + integer :: ierr ! error code + integer :: nu ! unit number + character(len=*) , parameter :: subname='(datm_datamode_simple_advertise): ' + real(R8) :: bcasttmp(8) + + !------------------------------------------------------------------------------- + + namelist / const_forcing_nml / dn10, slp, q, t, u, v, peak_swdn, peak_lwdn + + rc = ESMF_SUCCESS + + ! Read const_forcing_nml from nlfilename + if (my_task == main_task) then + open (newunit=nu,file=trim(nlfilename),status="old",action="read") + call shr_nl_find_group_name(nu, 'const_forcing_nml', status=ierr) + read (nu,nml=const_forcing_nml,iostat=ierr) + close(nu) + if (ierr > 0) then + call shr_sys_abort(subName//': namelist read error '//trim(nlfilename)) + end if + + bcasttmp = 0 + bcasttmp(1) = dn10 + bcasttmp(2) = slp + bcasttmp(3) = q + bcasttmp(4) = t + bcasttmp(5) = u + bcasttmp(6) = v + bcasttmp(7) = peak_swdn + bcasttmp(8) = peak_lwdn + end if + + call ESMF_VMBroadcast(vm, bcasttmp, 8, main_task, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + dn10 = bcasttmp(1) + slp = bcasttmp(2) + q = bcasttmp(3) + t = bcasttmp(4) + u = bcasttmp(5) + v = bcasttmp(6) + peak_swdn = bcasttmp(7) + peak_lwdn = bcasttmp(8) + + call dshr_fldList_add(fldsExport, trim(flds_scalar_name)) + call dshr_fldList_add(fldsExport, 'Sa_z' ) + call dshr_fldList_add(fldsExport, 'Sa_u' ) + call dshr_fldList_add(fldsExport, 'Sa_v' ) + call dshr_fldList_add(fldsExport, 'Sa_ptem' ) + call dshr_fldList_add(fldsExport, 'Sa_dens' ) + call dshr_fldList_add(fldsExport, 'Sa_pslv' ) + call dshr_fldList_add(fldsExport, 'Sa_tbot' ) + call dshr_fldList_add(fldsExport, 'Sa_pbot' ) + call dshr_fldList_add(fldsExport, 'Sa_shum' ) + call dshr_fldList_add(fldsExport, 'Faxa_rainc' ) + call dshr_fldList_add(fldsExport, 'Faxa_rainl' ) + call dshr_fldList_add(fldsExport, 'Faxa_snowc' ) + call dshr_fldList_add(fldsExport, 'Faxa_snowl' ) + call dshr_fldList_add(fldsExport, 'Faxa_swndr' ) + call dshr_fldList_add(fldsExport, 'Faxa_swvdr' ) + call dshr_fldList_add(fldsExport, 'Faxa_swndf' ) + call dshr_fldList_add(fldsExport, 'Faxa_swvdf' ) + call dshr_fldList_add(fldsExport, 'Faxa_swnet' ) + call dshr_fldList_add(fldsExport, 'Faxa_lwdn' ) + call dshr_fldList_add(fldsExport, 'Faxa_swdn' ) + + fldlist => fldsExport ! the head of the linked list + do while (associated(fldlist)) + call NUOPC_Advertise(exportState, standardName=fldlist%stdname, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_LogWrite('(datm_comp_advertise): Fr_atm'//trim(fldList%stdname), ESMF_LOGMSG_INFO) + fldList => fldList%next + enddo + + end subroutine datm_datamode_simple_advertise + + !=============================================================================== + subroutine datm_datamode_simple_init_pointers(exportState, sdat, rc) + + ! input/output variables + type(ESMF_State) , intent(inout) :: exportState + type(shr_strdata_type) , intent(in) :: sdat + integer , intent(out) :: rc + + ! local variables + integer :: n + integer :: lsize + integer :: spatialDim ! number of dimension in mesh + integer :: numOwnedElements ! size of mesh + real(r8), pointer :: ownedElemCoords(:) ! mesh lat and lons + type(ESMF_StateItem_Flag) :: itemFlag + character(len=*), parameter :: subname='(datm_init_pointers): ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + lsize = sdat%model_lsize + + call ESMF_MeshGet(sdat%model_mesh, spatialDim=spatialDim, numOwnedElements=numOwnedElements, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + allocate(ownedElemCoords(spatialDim*numOwnedElements)) + allocate(yc(numOwnedElements)) + allocate(xc(numOwnedElements)) + call ESMF_MeshGet(sdat%model_mesh, ownedElemCoords=ownedElemCoords) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + do n = 1,numOwnedElements + yc(n) = ownedElemCoords(2*n) + xc(n) = ownedElemCoords(2*n-1) + end do + + ! get export state pointers + call dshr_state_getfldptr(exportState, 'Sa_z' , fldptr1=Sa_z , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_u' , fldptr1=Sa_u , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_v' , fldptr1=Sa_v , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_tbot' , fldptr1=Sa_tbot , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_pbot' , fldptr1=Sa_pbot , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_dens' , fldptr1=Sa_dens , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_pslv' , fldptr1=Sa_pslv , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_ptem' , fldptr1=Sa_ptem , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_shum' , fldptr1=Sa_shum , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_rainc' , fldptr1=Faxa_rainc , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_rainl' , fldptr1=Faxa_rainl , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_snowc' , fldptr1=Faxa_snowc , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_snowl' , fldptr1=Faxa_snowl , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swvdr' , fldptr1=Faxa_swvdr , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swvdf' , fldptr1=Faxa_swvdf , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swndr' , fldptr1=Faxa_swndr , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swndf' , fldptr1=Faxa_swndf , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swnet' , fldptr1=Faxa_swnet , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_lwdn' , fldptr1=Faxa_lwdn , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_StateGet(exportstate, 'Faxa_ndep', itemFlag, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (itemflag /= ESMF_STATEITEM_NOTFOUND) then + call dshr_state_getfldptr(exportState, 'Faxa_ndep', fldptr2=Faxa_ndep, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + end subroutine datm_datamode_simple_init_pointers + + !=============================================================================== + subroutine datm_datamode_simple_advance(target_ymd, target_tod, target_mon, & + model_calendar, rc) + + ! input/output variables + integer , intent(in) :: target_ymd + integer , intent(in) :: target_tod + integer , intent(in) :: target_mon + character(len=*) , intent(in) :: model_calendar + integer , intent(out) :: rc + + ! local variables + integer :: n + integer :: lsize + real(R8) :: rday ! elapsed day + character(len=*), parameter :: subname='(datm_datamode_simple): ' + real(R8), parameter :: epsilon_deg = 23.45 ! axial tilt of the Earth + real(R8) :: solar_decl ! solar declination angle (rad) to be used in idealized radiation calculations + real(R8) :: hour_angle ! hour angle (rad) to be used in idealized radiation calculations + real(R8) :: zenith_angle ! solar senith angle (rad) to be used in idealized radiation calculations + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + lsize = size(Sa_z) + + call shr_cal_date2julian(target_ymd, target_tod, rday, model_calendar) + rday = mod((rday - 1.0_R8),365.0_R8) + + do n = 1,lsize + Sa_z(n) = 10.0_R8 + + !--- (i) Set forcing fields to constant values read from the namelist file --- + Sa_dens(n) = dn10 + Sa_pslv(n) = slp + Sa_pbot(n) = Sa_pslv(n) + Sa_shum(n) = q + Sa_tbot(n) = t + Sa_ptem(n) = Sa_tbot(n) + Sa_u(n) = u + Sa_v(n) = v + + !--- (ii) Set precipitation (currently all zeros) --- + + Faxa_rainc(n) = 0.0_R8 ! default zero + Faxa_snowc(n) = 0.0_R8 + if (Sa_tbot(n) < tKFrz ) then ! assign precip to rain/snow components + Faxa_rainl(n) = 0.0_R8 + Faxa_snowl(n) = 0.0_R8 ! todo + else + Faxa_rainl(n) = 0.0_R8 ! todo + Faxa_snowl(n) = 0.0_R8 + endif + + !--- (iii) RADIATION DATA --- + + ! long wave + solar_decl = (epsilon_deg * degtorad) * sin( 2.0_R8 * shr_const_pi * (int(rday) + 284.0_R8) / 365.0_R8) + zenith_angle = acos(sin(yc(n) * degtorad ) * sin(solar_decl) + cos(yc(n) * degtorad) * cos(solar_decl) ) + Faxa_lwdn(n) = max(0.0_R8, peak_lwdn * cos(zenith_angle)) + + ! short wave + hour_angle = (15.0_R8 * (target_tod/3600.0_R8 - 12.0_R8) + xc(n) ) * degtorad + zenith_angle = acos(sin(yc(n) * degtorad ) * sin(solar_decl) + cos(yc(n) * degtorad) * cos(solar_decl) * cos(hour_angle) ) + Faxa_swnet(n) = max(0.0_R8, peak_swdn * cos(zenith_angle)) + Faxa_swvdr(n) = Faxa_swnet(n)*(0.28_R8) + Faxa_swndr(n) = Faxa_swnet(n)*(0.31_R8) + Faxa_swvdf(n) = Faxa_swnet(n)*(0.24_R8) + Faxa_swndf(n) = Faxa_swnet(n)*(0.17_R8) + + enddo ! lsize + + if (associated(Faxa_ndep)) then + ! convert ndep flux to units of kgN/m2/s (input is in gN/m2/s) + Faxa_ndep(:,:) = Faxa_ndep(:,:) / 1000._r8 + end if + + end subroutine datm_datamode_simple_advance + +end module datm_datamode_simple_mod diff --git a/CDEPS-interface/CDEPS/datm/setservices.inc b/CDEPS-interface/CDEPS/datm/setservices.inc new file mode 100644 index 0000000000..010c94ce4f --- /dev/null +++ b/CDEPS-interface/CDEPS/datm/setservices.inc @@ -0,0 +1,44 @@ + subroutine SetServices(gcomp, rc) + type(ESMF_GridComp) :: gcomp + integer, intent(out) :: rc + + ! local variables + character(len=*),parameter :: subname=trim(modName)//':(SetServices) ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + call ESMF_LogWrite(subname//' called', ESMF_LOGMSG_INFO) + + ! the NUOPC gcomp component will register the generic methods + call NUOPC_CompDerive(gcomp, model_routine_SS, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! switching to IPD versions + call ESMF_GridCompSetEntryPoint(gcomp, ESMF_METHOD_INITIALIZE, & + userRoutine=dshr_model_initphase, phase=0, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! set entry point for methods that require specific implementation + call NUOPC_CompSetEntryPoint(gcomp, ESMF_METHOD_INITIALIZE, & + phaseLabelList=(/"IPDv01p1"/), userRoutine=InitializeAdvertise, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call NUOPC_CompSetEntryPoint(gcomp, ESMF_METHOD_INITIALIZE, & + phaseLabelList=(/"IPDv01p3"/), userRoutine=InitializeRealize, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! attach specializing method(s) + call NUOPC_CompSpecialize(gcomp, specLabel=model_label_Advance, specRoutine=ModelAdvance, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_MethodRemove(gcomp, label=model_label_SetRunClock, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call NUOPC_CompSpecialize(gcomp, specLabel=model_label_SetRunClock, specRoutine=dshr_set_runclock, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call NUOPC_CompSpecialize(gcomp, specLabel=model_label_Finalize, specRoutine=ModelFinalize, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_LogWrite(subname//' done', ESMF_LOGMSG_INFO) + + end subroutine SetServices diff --git a/CDEPS-interface/CDEPS/dglc/CMakeLists.txt b/CDEPS-interface/CDEPS/dglc/CMakeLists.txt new file mode 100644 index 0000000000..2c62d04b00 --- /dev/null +++ b/CDEPS-interface/CDEPS/dglc/CMakeLists.txt @@ -0,0 +1,34 @@ +project(dglc Fortran) +set(SRCFILES glc_comp_nuopc.F90 + dglc_datamode_noevolve_mod.F90) + +foreach(FILE ${SRCFILES}) + if(EXISTS "${CASEROOT}/SourceMods/src.dglc/${FILE}") + list(REMOVE_ITEM SRCFILES ${FILE}) + list(APPEND SRCFILES "${CASEROOT}/SourceMods/src.dglc/${FILE}") + message("Using ${FILE} from ${CASEROOT}/SourceMods/src.dglc") + endif() +endforeach() + +message("DGLC srcfiles are ${SRCFILES}") + +add_library(dglc ${SRCFILES}) + +add_dependencies(dglc dshr streams) +target_include_directories (dglc PRIVATE ${ESMF_F90COMPILEPATHS}) +target_include_directories (dglc PRIVATE ${CMAKE_SOURCE_DIR}) +target_include_directories (dglc PRIVATE ${PIO_Fortran_INCLUDE_DIR}) +if(NOT DISABLE_FoX) + target_include_directories (dglc PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/../fox/include) +endif() + +if(BLD_STANDALONE) + # ESMX requires mod files + foreach (SRC ${SRCFILES}) + string(REGEX REPLACE "[.]F90$" ".mod" MOD ${SRC}) + if (NOT DEFINED CIMEROOT AND MOD STREQUAL glc_comp_nuopc.mod) + set(MOD cdeps_dglc_comp.mod) + endif() + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${MOD}" DESTINATION include) + endforeach () +endif() diff --git a/CDEPS-interface/CDEPS/dglc/cime_config/buildlib b/CDEPS-interface/CDEPS/dglc/cime_config/buildlib new file mode 120000 index 0000000000..0c5e984ac2 --- /dev/null +++ b/CDEPS-interface/CDEPS/dglc/cime_config/buildlib @@ -0,0 +1 @@ +../../cime_config/buildlib_comps \ No newline at end of file diff --git a/CDEPS-interface/CDEPS/dglc/cime_config/buildnml b/CDEPS-interface/CDEPS/dglc/cime_config/buildnml new file mode 100755 index 0000000000..b685164297 --- /dev/null +++ b/CDEPS-interface/CDEPS/dglc/cime_config/buildnml @@ -0,0 +1,197 @@ +#!/usr/bin/env python3 + +"""Namelist creator for CIME's data glc model. +""" + +# Typically ignore this. +# pylint: disable=invalid-name + +# Disable these because this is our standard setup +# pylint: disable=wildcard-import,unused-wildcard-import,wrong-import-position + +import os, sys + +_CDEPS_CONFIG = os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir,os.pardir,"cime_config") +_CIMEROOT = os.environ.get("CIMEROOT") +if _CIMEROOT is None: + raise SystemExit("ERROR: must set CIMEROOT environment variable") +_LIBDIR = os.path.join(_CIMEROOT, "CIME", "Tools") +sys.path.append(_LIBDIR) +sys.path.append(_CDEPS_CONFIG) + +from standard_script_setup import * +from CIME.case import Case +from CIME.nmlgen import NamelistGenerator +from CIME.utils import expect, safe_copy +from CIME.XML.files import Files +from CIME.buildnml import create_namelist_infile, parse_input, copy_inputs_to_rundir +from stream_cdeps import StreamCDEPS + +logger = logging.getLogger(__name__) + +# pylint: disable=too-many-arguments,too-many-locals,too-many-branches,too-many-statements +#################################################################################### +def _create_namelists(case, confdir, inst_string, infile, nmlgen, data_list_path): +#################################################################################### + """Write out the namelist and stream xml files for this component. + + Most arguments are the same as those for `NamelistGenerator`. The + `inst_string` argument is used as a suffix to distinguish files for + different instances. The `confdir` argument is used to specify the directory + in which output files will be placed. + """ + #---------------------------------------------------- + # Write out dglc_in and dglc.streams.xml + #---------------------------------------------------- + caseroot = case.get_value("CASEROOT") + dglc_mode = case.get_value("DGLC_MODE") + glc_grid = case.get_value("GLC_GRID") + + # Check for incompatible options. + expect(glc_grid != "null", + "DGLC_GRID cannot be null") + + # Do not allow single column mode for dglc + if case.get_value('PTS_LON'): + scol_lon = float(case.get_value('PTS_LON')) + else: + scol_lon = -999. + if case.get_value('PTS_LAT'): + scol_lat = float(case.get_value('PTS_LAT')) + else: + scol_lat = -999. + if (scol_lon > -999. or scol_lat > -999.): + expect(False, + "single column mode for DGLC is not currently allowed") + + # Log some settings. + logger.debug("DGLC mode is {}".format(dglc_mode)) + + # Initialize namelist defaults + config = {} + config['dglc_mode'] = dglc_mode + config['glc_grid'] = glc_grid + + # Initialize nmlgen + nmlgen.init_defaults(infile, config) + + # Generate dglc_in + namelist_file = os.path.join(confdir, "dglc_in") + nmlgen.write_output_file(namelist_file, data_list_path, groups=['dglc_nml']) + + # Generate dglc.streams.xml + logger.debug("dglc_mode is {}".format(dglc_mode)) + + if 'noevolve' in dglc_mode: + generate_stream_file = False + else: + generate_stream_file = True + #endif + if generate_stream_file: + # Determine streams + streamlist = nmlgen.get_streams() + if type(streamlist) == type(str()): + streamlist = [] + outfile = os.path.join(confdir, "dglc.streams"+inst_string+".xml" ) + schema_file = os.path.join(_CDEPS_CONFIG,"stream_definition_v2.0.xsd") + stream_file = os.path.join(_CDEPS_CONFIG,os.pardir, "dglc","cime_config","stream_definition_dglc.xml") + streams = StreamCDEPS(stream_file, schema_file) + streams.create_stream_xml(streamlist, case, outfile, data_list_path, + os.path.join(caseroot,'user_nl_dglc_streams'+inst_string)) + #endif + +############################################################################### +def buildnml(case, caseroot, compname): +############################################################################### + rundir = case.get_value("RUNDIR") + inst_name = compname.upper()[1:] + ninst = case.get_value("NINST_"+inst_name) + if ninst is None: + ninst = case.get_value("NINST") + confdir = os.path.join(caseroot,"Buildconf",compname + "conf") + if not os.path.isdir(confdir): + os.makedirs(confdir) + + #---------------------------------------------------- + # Construct the namelist generator + #---------------------------------------------------- + # determine directory for user modified namelist_definitions.xml + user_xml_dir = os.path.join(caseroot, "SourceMods", "src." + compname) + expect (os.path.isdir(user_xml_dir), + "user_xml_dir {} does not exist ".format(user_xml_dir)) + + # NOTE: User definition *replaces* existing definition. + files = Files(comp_interface="nuopc") + definition_file = [files.get_value("NAMELIST_DEFINITION_FILE", {"component":compname})] + + user_definition = os.path.join(user_xml_dir, "namelist_definition_"+compname+".xml") + if os.path.isfile(user_definition): + definition_file = [user_definition] + for file_ in definition_file: + expect(os.path.isfile(file_), "Namelist XML file {} not found!".format(file_)) + + # Create the namelist generator object - independent of instance + nmlgen = NamelistGenerator(case, definition_file, files=files) + + #---------------------------------------------------- + # Clear out old data. + #---------------------------------------------------- + + data_list_path = os.path.join(caseroot, "Buildconf", compname+".input_data_list") + if os.path.exists(data_list_path): + os.remove(data_list_path) + + #---------------------------------------------------- + # Loop over instances + #---------------------------------------------------- + for inst_counter in range(1, ninst+1): + # determine instance string + inst_string = "" + if ninst > 1: + inst_string = '_' + "{:04d}".format(inst_counter) + + # If multi-instance case does not have restart file, use + # single-case restart for each instance + rpointer = "rpointer." + compname + if (os.path.isfile(os.path.join(rundir,rpointer)) and + (not os.path.isfile(os.path.join(rundir,rpointer + inst_string)))): + safe_copy(os.path.join(rundir, rpointer), + os.path.join(rundir, rpointer + inst_string)) + + inst_string_label = inst_string + if not inst_string_label: + inst_string_label = "\"\"" + + # create namelist output infile using user_nl_file as input + user_nl_file = os.path.join(caseroot, "user_nl_" + compname + inst_string) + expect(os.path.isfile(user_nl_file), + "Missing required user_nl_file {} ".format(user_nl_file)) + infile = os.path.join(confdir, "namelist_infile") + create_namelist_infile(case, user_nl_file, infile) + namelist_infile = [infile] + + # create namelist and xml stream file(s) + _create_namelists(case, confdir, inst_string, namelist_infile, nmlgen, data_list_path) + + # copy namelist files and stream text files, to rundir + copy_inputs_to_rundir(caseroot, compname, confdir, rundir, inst_string) + +############################################################################### +def get_user_nl_list(case): +############################################################################### + """Returns a list of user_nl_dglc* files needed in this case + This function is called by CIME to stage the user_nl_dglc* files in the case + directory. + """ + user_nl_list = ["user_nl_dglc", "user_nl_dglc_streams"] + return user_nl_list + +############################################################################### +def _main_func(): + # Build the component namelist and required stream xml files + caseroot = parse_input(sys.argv) + with Case(caseroot) as case: + buildnml(case, caseroot, "dglc") + +if __name__ == "__main__": + _main_func() diff --git a/CDEPS-interface/CDEPS/dglc/cime_config/config_archive.xml b/CDEPS-interface/CDEPS/dglc/cime_config/config_archive.xml new file mode 100644 index 0000000000..f61daec798 --- /dev/null +++ b/CDEPS-interface/CDEPS/dglc/cime_config/config_archive.xml @@ -0,0 +1,11 @@ + + + r + rs1 + unset + + rpointer.glc$NINST_STRING + $CASE.dglc$NINST_STRING.r.$DATENAME.nc,$CASE.dglc$NINST_STRING.rs1.$DATENAME.bin + + + diff --git a/CDEPS-interface/CDEPS/dglc/cime_config/config_component.xml b/CDEPS-interface/CDEPS/dglc/cime_config/config_component.xml new file mode 100644 index 0000000000..a47b9d5e94 --- /dev/null +++ b/CDEPS-interface/CDEPS/dglc/cime_config/config_component.xml @@ -0,0 +1,92 @@ + + + + + + + + Data glc model (DGLC) + no evolve mode + + + + char + dglc + dglc + case_comp + env_case.xml + Name of land component + + + + char + noevolve + noevolve + + noevolve + + run_component_dglc + env_run.xml + + NOEVOLVE mode is used in CESM as follows. + In typical runs, CISM is not evolving; CLM computes the surface mass + balance (SMB) and sends it to CISM, but CISM’s ice sheet geometry + remains fixed over the course of the run. In these runs, CISM serves + two roles in the system: + + + + + logical + FALSE + run_component_dglc + env_run.xml + + TRUE + + Whether to include the Greenland Ice Sheet in this DGLC simulation + This should generally be set at create_newcase time (via the compset). In principle it + can be changed later, but great care is needed to change a number of other variables + to be consistent (GLC_GRID, GLC_DOMAIN_MESH and possibly others). + + + + + logical + FALSE + run_component_dglc + env_run.xml + + TRUE + + Whether to include the Antarctica Ice Sheet in this DGLC simulation + This should generally be set at create_newcase time (via the compset). In principle it + can be changed later, but great care is needed to change a number of other variables + to be consistent (GLC_GRID, GLC_DOMAIN_MESH and possibly others). + + + + + logical + TRUE,FALSE + FALSE + run_component_dglc + env_run.xml + If set to true, than dglc restarts will not be read on a continuation run. + + + + + ========================================= + DGLC naming conventions + ========================================= + + + diff --git a/CDEPS-interface/CDEPS/dglc/cime_config/namelist_definition_dglc.xml b/CDEPS-interface/CDEPS/dglc/cime_config/namelist_definition_dglc.xml new file mode 100644 index 0000000000..8bc4e0c0e6 --- /dev/null +++ b/CDEPS-interface/CDEPS/dglc/cime_config/namelist_definition_dglc.xml @@ -0,0 +1,140 @@ + + + + + + + + + + char(100) + streams + streams_file + List of streams used for each supported dglc_mode + + none + + + + + char + dglc + dglc_nml + noevolve + + Copies all fields directly from the input data streams Any required + fields not found on an input stream will be set to zero. + + + noevolve + + + + + char + streams + abs + dglc_nml + + $DIN_LOC_ROOT/glc/cism/Antarctica/ISMIP6_Antarctica_8km.init.c210908.nc:$DIN_LOC_ROOT/glc/cism/Greenland/greenland_4km_epsg3413_c171126.nc + $DIN_LOC_ROOT/glc/cism/Greenland/greenland_4km_epsg3413_c171126.nc + $DIN_LOC_ROOT/glc/cism/Antarctica/ISMIP6_Antarctica_8km.init.c210908.nc + + + colon deliminted string of inputdata files + + + + + char + streams + abs + dglc_nml + + $GLC_DOMAIN_MESH + + + colon deliminted string of file(s) specifying model mesh + for more than one ice sheets this will contain an array of mesh file names + + + + + real(20) + streams + dglc_nml + + 8000,4000 + 4000 + 8000 + + + model internal grid size(s) in m which is used to compute the internal model + model area in radians**2 using the formula (model_internal_gridsize/shr_const_rearth)**2 - + for more than one ice sheet this will contain an array of model_internal_gridsize values. + + + + + integer(20) + streams + dglc_nml + + 704,416 + 704 + 416 + 76 + + + global size(s) of nx where for more than one ice sheet this + will contain an array of nx values + + + + + integer(20) + streams + dglc_nml + + 576,704 + 576 + 704 + 141 + + + global size(s) of ny where for more than one ice sheet this + will contain an array of ny values + + + + + char + dglc + dglc_nml + + main restart file name for dglc model + + + null + + + + + logical + dglc + dglc_nml + + If set to true, than dglc restarts will not be read on a continuation run. + This capability is used, for example, in CTSM spinup runs. + + + $DGLC_SKIP_RESTART_READ + + + + diff --git a/CDEPS-interface/CDEPS/dglc/cime_config/stream_definition_dglc.xml b/CDEPS-interface/CDEPS/dglc/cime_config/stream_definition_dglc.xml new file mode 100644 index 0000000000..80ba75c5bb --- /dev/null +++ b/CDEPS-interface/CDEPS/dglc/cime_config/stream_definition_dglc.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + unset + + + unset + + + unset unset + + null + + bilinear + + null + 0 + 0 + 0 + 0 + + lower + + + cycle + + + 1.5 + + single + + + diff --git a/CDEPS-interface/CDEPS/dglc/cime_config/testdefs/testlist_dglc.xml b/CDEPS-interface/CDEPS/dglc/cime_config/testdefs/testlist_dglc.xml new file mode 100644 index 0000000000..f87182fbae --- /dev/null +++ b/CDEPS-interface/CDEPS/dglc/cime_config/testdefs/testlist_dglc.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CDEPS-interface/CDEPS/dglc/cime_config/user_nl_dglc b/CDEPS-interface/CDEPS/dglc/cime_config/user_nl_dglc new file mode 100644 index 0000000000..2cbcf3997e --- /dev/null +++ b/CDEPS-interface/CDEPS/dglc/cime_config/user_nl_dglc @@ -0,0 +1,13 @@ +!------------------------------------------------------------------------ +! Users should ONLY USE user_nl_dglc to change namelists variables +! Users should add all user specific namelist changes below in the form of +! namelist_var = new_namelist_value +! Note that any namelist variable from shr_strdata_nml and dglc_nml can +! be modified below using the above syntax +! User preview_namelists to view (not modify) the output namelist in the +! directory $CASEROOT/CaseDocs +! To modify the contents of a stream txt file, first use preview_namelists +! to obtain the contents of the stream txt files in CaseDocs, and then +! place a copy of the modified stream txt file in $CASEROOT with the string +! user_ prepended. +!------------------------------------------------------------------------ diff --git a/CDEPS-interface/CDEPS/dglc/cime_config/user_nl_dglc_streams b/CDEPS-interface/CDEPS/dglc/cime_config/user_nl_dglc_streams new file mode 100644 index 0000000000..856ee89446 --- /dev/null +++ b/CDEPS-interface/CDEPS/dglc/cime_config/user_nl_dglc_streams @@ -0,0 +1,33 @@ +!------------------------------------------------------------------------ +! This file is used to modify datm.streams.xml generated in $RUNDIR +! Entries should have the form +! :<= new stream_value> +! The following are accepted values for an assume streamname of foo +! foo:meshfile = character string +! foo:datafiles = comma separated string of full pathnames (e.g. file1,file2,file3...) +! foo:datavars = comma separated string of field pairs (e.g. foo foobar,foo2 foobar2...) +! foo:taxmode = one of [cycle, extend, limit] +! foo:tintalgo = one of [lower,upper,nearest,linear,coszen] +! foo:readmode = single (only suported mode right now) +! foo:mapalgo = one of [bilinear,redist,nn,consf,consd,none] +! foo:dtlimit = real (1.5 is default) +! foo:year_first = integer +! foo:year_last = integer +! foo:year_align = integer +! foo:vectors = one of [none,u:v] +! foo:lev_dimname: = one of [null,name of level dimenion name] +! foo:offset = integer +! As an example: +! foo:year_first = 1950 +! would change the stream year_first stream_entry to 1950 for the foo stream block +! NOTE: multi-line inputs are enabled by adding a \ at the end of the line +! As an emaple: +! foo:datafiles=foo1,foo2, \ +! foo3 +! Will yield the following new entry for datafiles in stream foo +! +! foo1 +! foo2 +! foo3 +! +!------------------------------------------------------------------------ diff --git a/CDEPS-interface/CDEPS/dglc/dglc_datamode_noevolve_mod.F90 b/CDEPS-interface/CDEPS/dglc/dglc_datamode_noevolve_mod.F90 new file mode 100644 index 0000000000..a7ed13592d --- /dev/null +++ b/CDEPS-interface/CDEPS/dglc/dglc_datamode_noevolve_mod.F90 @@ -0,0 +1,697 @@ +module dglc_datamode_noevolve_mod + + use ESMF , only : ESMF_State, ESMF_LOGMSG_INFO, ESMF_LogWrite, ESMF_SUCCESS + use ESMF , only : ESMF_Mesh, ESMF_DistGrid, ESMF_FieldBundle, ESMF_Field + use ESMF , only : ESMF_FieldBundleCreate, ESMF_FieldCreate, ESMF_MeshLoc_Element + use ESMF , only : ESMF_FieldBundleAdd, ESMF_MeshGet, ESMF_DistGridGet, ESMF_Typekind_R8 + use ESMF , only : ESMF_GridComp, ESMF_GridCompGet + use ESMF , only : ESMF_VM, ESMF_VMAllreduce, ESMF_REDUCE_SUM + use ESMF , only : ESMF_VMGetCurrent, ESMF_VMBroadCast + use NUOPC , only : NUOPC_Advertise, NUOPC_IsConnected + use shr_kind_mod , only : r8=>shr_kind_r8, i8=>shr_kind_i8, cl=>shr_kind_cl, cs=>shr_kind_cs + use shr_sys_mod , only : shr_sys_abort + use shr_const_mod , only : SHR_CONST_RHOICE, SHR_CONST_RHOSW, SHR_CONST_REARTH, SHR_CONST_TKFRZ + use shr_const_mod , only : SHR_CONST_SPVAL + use shr_cal_mod , only : shr_cal_datetod2string + use dshr_methods_mod , only : dshr_state_getfldptr, dshr_fldbun_getfldptr, chkerr + use dshr_fldlist_mod , only : fldlist_type, dshr_fldlist_add + use dshr_strdata_mod , only : shr_strdata_type + use pio , only : file_desc_t, io_desc_t, var_desc_t, iosystem_desc_t + use pio , only : pio_openfile, pio_inq_varid, pio_inq_varndims, pio_inq_vardimid + use pio , only : pio_inq_dimlen, pio_initdecomp, pio_read_darray, pio_double + use pio , only : pio_closefile, pio_freedecomp, PIO_BCAST_ERROR, PIO_NOWRITE, PIO_CLOBBER + use pio , only : pio_createfile, pio_def_dim, pio_def_var, pio_put_att, pio_fill + use pio , only : pio_set_fill, pio_put_att, pio_enddef, pio_write_darray, PIO_GLOBAL + use pio , only : pio_seterrorhandling + + implicit none + private ! except + + public :: dglc_datamode_noevolve_advertise + public :: dglc_datamode_noevolve_init_pointers + public :: dglc_datamode_noevolve_advance + public :: dglc_datamode_noevolve_restart_write + public :: dglc_datamode_noevolve_restart_read + + logical :: initialized_noevolve = .false. + integer :: num_icesheets + real(r8) :: thk0 = 1._r8 + + ! Data structure to enable multiple ice sheets + type icesheet_ptr_t + real(r8), pointer :: ptr(:) => null() ! pointer to array + real(r8), pointer :: ptr2d(:,:) => null() ! pointer to 2d array + endtype icesheet_ptr_t + + ! Export fields + type(icesheet_ptr_t), allocatable :: Sg_area(:) + type(icesheet_ptr_t), allocatable :: Sg_topo(:) + type(icesheet_ptr_t), allocatable :: Sg_ice_covered(:) + type(icesheet_ptr_t), allocatable :: Sg_icemask(:) + type(icesheet_ptr_t), allocatable :: Sg_icemask_coupled_fluxes(:) + type(icesheet_ptr_t), allocatable :: Fgrg_rofi(:) + + ! Import fields + integer, parameter :: nlev_import = 30 + type(icesheet_ptr_t), allocatable :: Sl_tsrf(:) + type(icesheet_ptr_t), allocatable :: Flgl_qice(:) + ! type(icesheet_ptr_t), allocatable :: So_t(:) + ! type(icesheet_ptr_t), allocatable :: So_q(:) + + ! Export Field names + character(len=*), parameter :: field_out_area = 'Sg_area' + character(len=*), parameter :: field_out_topo = 'Sg_topo' + character(len=*), parameter :: field_out_ice_covered = 'Sg_ice_covered' + character(len=*), parameter :: field_out_icemask = 'Sg_icemask' + character(len=*), parameter :: field_out_icemask_coupled_fluxes = 'Sg_icemask_coupled_fluxes' + character(len=*), parameter :: field_out_rofi = 'Fgrg_rofi' + + ! Import Field names + character(len=*), parameter :: field_in_tsrf = 'Sl_tsrf' + character(len=*), parameter :: field_in_qice = 'Flgl_qice' + character(len=*), parameter :: field_in_so_t_depth = 'So_t_depth' + character(len=*), parameter :: field_in_so_s_depth = 'So_s_depth' + + character(*) , parameter :: nullstr = 'null' + character(*) , parameter :: u_FILE_u = & + __FILE__ + +!=============================================================================== +contains +!=============================================================================== + + subroutine dglc_datamode_noevolve_advertise(NStateExp, fldsexport, NStateImp, fldsimport, & + flds_scalar_name, rc) + + ! input/output variables + type(ESMF_State) , intent(inout) :: NStateExp(:) + type(fldlist_type), pointer :: fldsexport + type(ESMF_State) , intent(inout) :: NStateImp(:) + type(fldlist_type), pointer :: fldsimport + character(len=*) , intent(in) :: flds_scalar_name + integer , intent(out) :: rc + + ! local variables + integer :: ns + character(len=CS) :: cnum + type(fldlist_type), pointer :: fldList + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + !-------------------------------- + ! Create nested state for active ice sheets only + !-------------------------------- + + ! Set module variable for number of ice sheets + num_icesheets = size(NStateExp) + + ! Advertise export fields + call dshr_fldList_add(fldsExport, trim(flds_scalar_name)) + call dshr_fldList_add(fldsExport, field_out_area) + call dshr_fldList_add(fldsExport, field_out_ice_covered) + call dshr_fldList_add(fldsExport, field_out_topo) + call dshr_fldList_add(fldsExport, field_out_icemask) + call dshr_fldList_add(fldsExport, field_out_icemask_coupled_fluxes) + call dshr_fldList_add(fldsExport, field_out_rofi) + + do ns = 1,num_icesheets + write(cnum,'(i0)') ns + fldlist => fldsExport ! the head of the linked list + do while (associated(fldlist)) + call NUOPC_Advertise(NStateExp(ns), standardName=fldlist%stdname, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_LogWrite('(dglc_comp_advertise): Fr_glc'//trim(cnum)//"_"//trim(fldList%stdname), ESMF_LOGMSG_INFO) + fldList => fldList%next + end do + enddo + + ! Advertise import fields if appropriate + call dshr_fldList_add(fldsImport, trim(flds_scalar_name)) + call dshr_fldList_add(fldsImport, field_in_tsrf) + call dshr_fldList_add(fldsImport, field_in_qice) + ! TODO: Add namelist for this + call dshr_fldList_add(fldsImport, field_in_so_t_depth, ungridded_lbound=1, ungridded_ubound=nlev_import) + call dshr_fldList_add(fldsImport, field_in_so_s_depth, ungridded_lbound=1, ungridded_ubound=nlev_import) + + do ns = 1,num_icesheets + write(cnum,'(i0)') ns + fldlist => fldsImport ! the head of the linked list + do while (associated(fldlist)) + call NUOPC_Advertise(NStateImp(ns), standardName=fldlist%stdname, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_LogWrite('(dglc_comp_advertise): To_glc'//trim(cnum)//"_"//trim(fldList%stdname), ESMF_LOGMSG_INFO) + fldList => fldList%next + end do + enddo + + end subroutine dglc_datamode_noevolve_advertise + + !=============================================================================== + subroutine dglc_datamode_noevolve_init_pointers(NStateExp, NstateImp, rc) + + ! input/output variables + type(ESMF_State) , intent(inout) :: NStateExp(:) + type(ESMF_State) , intent(inout) :: NStateImp(:) + integer , intent(out) :: rc + + ! local variables + integer :: ns + character(len=*), parameter :: subname='(dglc_init_pointers): ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + ! So this is tricky since you need pointers to fields in the nested state + ! So this will have to be done below in a loop + + ! initialize pointers to export fields + allocate(Sg_area(num_icesheets)) + allocate(Sg_topo(num_icesheets)) + allocate(Sg_ice_covered(num_icesheets)) + allocate(Sg_icemask(num_icesheets)) + allocate(Sg_icemask_coupled_fluxes(num_icesheets)) + allocate(Fgrg_rofi(num_icesheets)) + + do ns = 1,num_icesheets + call dshr_state_getfldptr(NStateExp(ns), field_out_area, & + fldptr1=Sg_area(ns)%ptr, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(NStateExp(ns), field_out_topo, & + fldptr1=Sg_topo(ns)%ptr, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(NStateExp(ns), field_out_ice_covered, & + fldptr1=Sg_ice_covered(ns)%ptr, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(NStateExp(ns), field_out_icemask, & + fldptr1=Sg_icemask(ns)%ptr, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(NStateExp(ns), field_out_icemask_coupled_fluxes, & + fldptr1=Sg_icemask_coupled_fluxes(ns)%ptr, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(NStateExp(ns), field_out_rofi, & + fldptr1=Fgrg_rofi(ns)%ptr, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + + Fgrg_rofi(ns)%ptr(:) = 0._r8 + end do + + ! initialize pointers to import fields if appropriate + allocate(Sl_tsrf(num_icesheets)) + allocate(Flgl_qice(num_icesheets)) + + do ns = 1,num_icesheets + if (.not. NUOPC_IsConnected(NStateImp(ns), fieldName=field_in_tsrf)) then + ! NOTE: the field is connected ONLY if the MED->GLC entry is in the nuopc.runconfig file + ! This restriction occurs even if the field was advertised + call shr_sys_abort(trim(subname)//": MED->GLC must appear in run sequence") + end if + call dshr_state_getfldptr(NStateImp(ns), field_in_tsrf, fldptr1=Sl_tsrf(ns)%ptr, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(NStateImp(ns), field_in_qice, fldptr1=Flgl_qice(ns)%ptr, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + + Sl_tsrf(ns)%ptr(:) = SHR_CONST_TKFRZ + Flgl_qice(ns)%ptr(:) = 0._r8 + end do + + end subroutine dglc_datamode_noevolve_init_pointers + + !=============================================================================== + subroutine dglc_datamode_noevolve_advance(gcomp, pio_subsystem, io_type, io_format, & + logunit, model_meshes, model_internal_gridsize, model_datafiles, rc) + + ! Assume that the model mesh is the same as the input data mesh + + ! input/output variables + type(ESMF_GridComp) :: gcomp + type(iosystem_desc_t) , pointer :: pio_subsystem ! pio info + integer , intent(in) :: io_type ! pio info + integer , intent(in) :: io_format ! pio info + integer , intent(in) :: logunit ! For writing logs + type(ESMF_Mesh) , intent(in) :: model_meshes(:) ! ice sheets meshes + real(r8) , intent(in) :: model_internal_gridsize(:) ! internal model gridsizes (m) + character(len=*) , intent(in) :: model_datafiles(:) ! input file names + integer , intent(out) :: rc + + ! local variables + type(ESMF_FieldBundle) :: fldbun_noevolve + type(ESMF_DistGrid) :: distgrid + type(ESMF_Field) :: field_noevolve + type(ESMF_VM) :: vm + type(file_desc_t) :: pioid + type(io_desc_t) :: pio_iodesc + integer :: ns ! ice sheet index + integer :: ng ! grid cell index + integer :: lsize ! local size + integer, pointer :: gindex(:) ! domain decomposition of data + integer :: ndims ! number of dims + integer, allocatable :: dimid(:) + type(var_desc_t) :: varid + integer :: rcode + integer :: nxg, nyg + real(r8), pointer :: topog(:) + real(r8), pointer :: thck(:) + logical :: exists + real(r8) :: rhoi ! density of ice ~ kg/m^3 + real(r8) :: rhoo ! density of sea water ~ kg/m^3 + real(r8) :: eus ! eustatic sea level + real(r8) :: lsrf ! lower surface elevation (m) on ice grid + real(r8) :: usrf ! upper surface elevation (m) on ice grid + real(r8) :: loc_pos_smb(1), Tot_pos_smb(1) ! Sum of positive smb values on each ice sheet for hole-filling + real(r8) :: loc_neg_smb(1), Tot_neg_smb(1) ! Sum of negative smb values on each ice sheet for hole-filling + real(r8) :: rat ! Ratio of hole-filling flux to apply + + character(len=*), parameter :: subname='(dglc_datamode_noevolve_advance): ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + if (.not. initialized_noevolve) then + + ! Loop over ice sheets + do ns = 1,num_icesheets + + ! Determine lsize and gindex + call ESMF_MeshGet(model_meshes(ns), elementdistGrid=distGrid, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_DistGridGet(distGrid, localDe=0, elementCount=lsize, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + allocate(gindex(lsize)) + call ESMF_DistGridGet(distGrid, localDe=0, seqIndexList=gindex, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! Determine "glc_area" ; + ! Sg_areas is in radians + ! SHR_CONST_REARTH is the radius of earth in m + ! model_internal_gridsize is the internal model gridsize in m + do ng = 1,lsize + Sg_area(ns)%ptr(ng) = (model_internal_gridsize(ns)/SHR_CONST_REARTH)**2 + end do + + ! Create module level field bundle + fldbun_noevolve = ESMF_FieldBundleCreate(rc=rc) ! input field bundle + + ! "ice thickness" ; + field_noevolve = ESMF_FieldCreate(model_meshes(ns), ESMF_TYPEKIND_R8, & + name='thk', meshloc=ESMF_MESHLOC_ELEMENT, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call ESMF_FieldBundleAdd(fldbun_noevolve, (/field_noevolve/), rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + + ! "bed topography" ; + field_noevolve = ESMF_FieldCreate(model_meshes(ns), ESMF_TYPEKIND_R8, & + name='topg', meshloc=ESMF_MESHLOC_ELEMENT, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call ESMF_FieldBundleAdd(fldbun_noevolve, (/field_noevolve/), rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + + ! Create pioid and pio_iodesc at the module level + inquire(file=trim(model_datafiles(ns)), exist=exists) + if (.not.exists) then + write(6,'(a)')' ERROR: model input file '//trim(model_datafiles(ns))//' does not exist' + call shr_sys_abort() + end if + rcode = pio_openfile(pio_subsystem, pioid, io_type, trim(model_datafiles(ns)), pio_nowrite) + call pio_seterrorhandling(pioid, PIO_BCAST_ERROR) + rcode = pio_inq_varid(pioid, 'thk', varid) + rcode = pio_inq_varndims(pioid, varid, ndims) + allocate(dimid(ndims)) + rcode = pio_inq_vardimid(pioid, varid, dimid(1:ndims)) + rcode = pio_inq_dimlen(pioid, dimid(1), nxg) + rcode = pio_inq_dimlen(pioid, dimid(2), nyg) + call pio_initdecomp(pio_subsystem, pio_double, (/nxg,nyg/), gindex, pio_iodesc) + deallocate(dimid) + + ! Read in the data into the appropriate field bundle pointers + ! Note that Sg_ice_covered(ns)%ptr points into the data for + ! the Sg_ice_covered field in NStateExp(ns) + ! Note that Sg_topo(ns)%ptr points into the data for + ! the Sg_topon NStateExp(ns) + ! Note that topog is bedrock topography + + call dshr_fldbun_getFldPtr(fldbun_noevolve, 'topg', topog, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + rcode = pio_inq_varid(pioid, 'topg', varid) + call pio_read_darray(pioid, varid, pio_iodesc, topog, rcode) + + call dshr_fldbun_getFldPtr(fldbun_noevolve, 'thk', thck, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + rcode = pio_inq_varid(pioid, 'thk', varid) + call pio_read_darray(pioid, varid, pio_iodesc, thck, rcode) + + rhoi = SHR_CONST_RHOICE ! 0.917e3 + rhoo = SHR_CONST_RHOSW ! 1.026e3 + eus = 0 + do ng = 1,lsize + if (topog(ng) - eus < (-rhoi/rhoo) * thck(ng)) then + lsrf = (-rhoi/rhoo) * thck(ng) + else + lsrf = topog(ng) + end if + usrf = max(0.d0, thck(ng) + lsrf) + + ! The export field 'ice_mask_coupled_fluxes' determines who is handling the + ! runoff associated with the surface mass balance + ! If its 0 -then ctsm needs to handle it. + ! Since we want dglc to handle it no evolve mode - then + ! ice_mask_coupled_fluxes to be identical to the mask + + if (is_in_active_grid(usrf)) then + Sg_icemask(ns)%ptr(ng) = 1.d0 + Sg_icemask_coupled_fluxes(ns)%ptr(ng) = 1.d0 + if (is_ice_covered(thck(ng))) then + Sg_ice_covered(ns)%ptr(ng) = 1.d0 + else + Sg_ice_covered(ns)%ptr(ng) = 0.d0 + end if + ! Note that we use the same method for computing topo whether this point is + ! ice-covered or ice-free. This is in contrast to the method for computing + ! ice-free topo in glint_upscaling_gcm. + Sg_topo(ns)%ptr(ng) = thk0 * usrf + else + ! Note that this logic implies that if (in theory) we had an ice-covered + ! point outside the "active grid", it will get classified as ice-free for + ! these purposes. This mimics the logic currently in glint_upscaling_gcm. + Sg_icemask(ns)%ptr(ng) = 0.d0 + Sg_icemask_coupled_fluxes(ns)%ptr(ng) = 0.d0 + Sg_ice_covered(ns)%ptr(ng) = 0.d0 + Sg_topo(ns)%ptr(ng) = 0.d0 + end if + end do + + call pio_closefile(pioid) + call pio_freedecomp(pio_subsystem, pio_iodesc) + + end do ! end loop over ice sheets + + end if + + if (initialized_noevolve) then + + ! Compute Fgrg_rofi + do ns = 1,num_icesheets + + ! Get number of grid cells per ice sheet + lsize = size(Fgrg_rofi(ns)%ptr) + + ! reset output variables to zero + Fgrg_rofi(ns)%ptr(:) = 0.d0 + loc_pos_smb(1) = 0.d0 + Tot_pos_smb(1) = 0.d0 + loc_neg_smb(1) = 0.d0 + Tot_neg_smb(1) = 0.d0 + rat = 0.d0 + + ! For No Evolve to reduce negative ice fluxes from DGLC, we will + ! Calculate the total positive and total negative fluxes on each + ! processor first (local totals). + do ng = 1,lsize + if (Sg_icemask_coupled_fluxes(ns)%ptr(ng) > 0.d0) then + if(Flgl_qice(ns)%ptr(ng) > 0.d0) then + loc_pos_smb(1) = loc_pos_smb(1)+Flgl_qice(ns)%ptr(ng)*Sg_area(ns)%ptr(ng) + end if + ! Ignore places that are exactly 0.d0 + if(Flgl_qice(ns)%ptr(ng) < 0.d0) then + loc_neg_smb(1) = loc_neg_smb(1)+Flgl_qice(ns)%ptr(ng)*Sg_area(ns)%ptr(ng) + end if + end if + end do + ! Now do two global sums to get the ice sheet total positive + ! and negative ice fluxes + call ESMF_GridCompGet(gcomp, vm=vm, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_VMAllreduce(vm, senddata=loc_pos_smb, recvdata=Tot_pos_smb, count=1, & + reduceflag=ESMF_REDUCE_SUM, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_VMAllreduce(vm, senddata=loc_neg_smb, recvdata=Tot_neg_smb, count=1, & + reduceflag=ESMF_REDUCE_SUM, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! If there's more positive than negative, then set all + ! negative to zero and destribute the negative flux amount + ! across the positive values, scaled by the size of the + ! positive value. This section also applies to any chunks + ! where there is no negative smb. In that case the ice + ! runoff is exactly equal to the input smb. + if(abs(Tot_pos_smb(1)) >= abs(Tot_neg_smb(1))) then + do ng = 1,lsize + if (Sg_icemask_coupled_fluxes(ns)%ptr(ng) > 0.d0) then + if(Flgl_qice(ns)%ptr(ng) > 0.d0) then + rat = Flgl_qice(ns)%ptr(ng)/Tot_pos_smb(1) + Fgrg_rofi(ns)%ptr(ng) = Flgl_qice(ns)%ptr(ng) + rat*Tot_neg_smb(1) + else + Fgrg_rofi(ns)%ptr(ng) = 0.d0 + end if + else + Fgrg_rofi(ns)%ptr(ng) = 0.d0 + end if + end do + else + ! If there's more negative than positive, set the positive to zero + ! and distribute the positive amount to the negative spaces to + ! reduce their negativity a bit. This shouldn't happen often. + ! This section of code also applies if Tot_pos_smb is zero. + do ng = 1,lsize + if (Sg_icemask_coupled_fluxes(ns)%ptr(ng) > 0.d0) then + if(Flgl_qice(ns)%ptr(ng) < 0.d0) then + rat = Flgl_qice(ns)%ptr(ng)/Tot_neg_smb(1) + Fgrg_rofi(ns)%ptr(ng) = Flgl_qice(ns)%ptr(ng) + rat*Tot_pos_smb(1) + else + Fgrg_rofi(ns)%ptr(ng) = 0.d0 + end if + else + Fgrg_rofi(ns)%ptr(ng) = 0.d0 + end if + end do + + end if ! More neg or pos smb + + end do ! Each ice sheet + end if ! if initialized + + ! Set initialized flag + initialized_noevolve = .true. + + end subroutine dglc_datamode_noevolve_advance + + !=============================================================================== + logical function is_in_active_grid(usrf) + ! Return true if the given point is inside the "active grid". The active grid includes + ! any point that can receive a positive surface mass balance, which includes any + ! point classified as land or ice sheet. + + real(r8), intent(in) :: usrf ! surface elevation (m) + + if (thk0 * usrf > 0.d0) then + ! points not at sea level are assumed to be land or ice sheet + is_in_active_grid = .true. + else + is_in_active_grid = .false. + end if + end function is_in_active_grid + + !=============================================================================== + logical function is_ice_covered(thck) + ! Return true if the given point is ice-covered + + real(r8), intent(in) :: thck ! ice thickness (m) + real(r8), parameter :: min_thck = 0.d0 + + if (thk0 * thck > min_thck) then + is_ice_covered = .true. + else + is_ice_covered = .false. + end if + end function is_ice_covered + + !=============================================================================== + subroutine dglc_datamode_noevolve_restart_write(model_meshes, case_name, & + rpfile, inst_suffix, ymd, tod, logunit, my_task, main_task, & + pio_subsystem, io_type, nx_global, ny_global, rc) + + ! input/output variables + type(ESMF_Mesh) , intent(in) :: model_meshes(:) ! ice sheets meshes + character(len=*) , intent(in) :: case_name + character(len=*) , intent(in) :: rpfile + character(len=*) , intent(in) :: inst_suffix + integer , intent(in) :: ymd ! model date + integer , intent(in) :: tod ! model sec into model date + integer , intent(in) :: logunit + integer , intent(in) :: my_task + integer , intent(in) :: main_task + type(iosystem_desc_t) , pointer :: pio_subsystem ! pio info + integer , intent(in) :: io_type ! pio info + integer , intent(in) :: nx_global(:) + integer , intent(in) :: ny_global(:) + integer , intent(out) :: rc + + ! local variables + type(ESMF_DistGrid) :: distgrid + integer :: ns + character(len=CS) :: cnum + integer :: lsize + integer, pointer :: gindex(:) ! domain decomposition of data + integer :: nu + character(len=CL) :: rest_file_model + character(len=CS) :: date_str + type(file_desc_t) :: pioid + integer :: dimid2(2) + type(var_desc_t), allocatable :: varid(:) + type(io_desc_t), allocatable :: pio_iodesc(:) + integer :: oldmode + integer :: rcode + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + call shr_cal_datetod2string(date_str, ymd, tod) + write(rest_file_model ,"(7a)") trim(case_name),'.','dglc',trim(inst_suffix),'.r.',trim(date_str),'.nc' + ! write restart info to rpointer file + if (my_task == main_task) then + open(newunit=nu, file=trim(rpfile)//trim(inst_suffix), form='formatted') + write(nu,'(a)') rest_file_model + close(nu) + write(logunit,'(a,2x,i0,2x,i0)')' writing with no streams '//trim(rest_file_model), ymd, tod + endif + + ! write data model restart data + rcode = pio_createfile(pio_subsystem, pioid, io_type, trim(rest_file_model), pio_clobber) + allocate(varid(num_icesheets)) + do ns = 1,num_icesheets + ! Need to explicitly write restart since noevolve mode does not read a stream + write(cnum,'(i0)') ns + + rcode = pio_def_dim(pioid, '_nx'//trim(cnum), nx_global(ns), dimid2(1)) + rcode = pio_def_dim(pioid, '_ny'//trim(cnum), ny_global(ns), dimid2(2)) + rcode = pio_def_var(pioid, 'flgl_rofi'//cnum, PIO_DOUBLE, (/dimid2/), varid(ns)) + rcode = pio_put_att(pioid, varid(ns), "_FillValue", shr_const_spval) + rcode = pio_set_fill(pioid, PIO_FILL, oldmode) + rcode = pio_put_att(pioid, pio_global, "version", "nuopc_data_models_v0") + enddo + rcode = pio_enddef(pioid) + allocate(pio_iodesc(num_icesheets)) + do ns = 1,num_icesheets + + ! Determine gindex for this ice sheet + call ESMF_MeshGet(model_meshes(ns), elementdistGrid=distGrid, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_DistGridGet(distGrid, localDe=0, elementCount=lsize, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + allocate(gindex(lsize)) + call ESMF_DistGridGet(distGrid, localDe=0, seqIndexList=gindex, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call pio_initdecomp(pio_subsystem, pio_double, (/nx_global(ns),ny_global(ns)/), gindex, pio_iodesc(ns)) + call pio_write_darray(pioid, varid(ns), pio_iodesc(ns), Fgrg_rofi(ns)%ptr, rcode, fillval=shr_const_spval) + + ! Deallocate gindex + deallocate (gindex) + end do + call pio_closefile(pioid) + do ns = 1,num_icesheets + call pio_freedecomp(pio_subsystem, pio_iodesc(ns)) + enddo + + end subroutine dglc_datamode_noevolve_restart_write + + !=============================================================================== + subroutine dglc_datamode_noevolve_restart_read(model_meshes, restfilem, rpfile, & + logunit, my_task, main_task, mpicom, & + pio_subsystem, io_type, nx_global, ny_global, rc) + + ! input/output arguments + type(ESMF_Mesh) , intent(in) :: model_meshes(:) ! ice sheets meshes + character(len=*) , intent(inout) :: restfilem + character(len=*) , intent(in) :: rpfile + integer , intent(in) :: logunit + integer , intent(in) :: my_task + integer , intent(in) :: main_task + integer , intent(in) :: mpicom + type(iosystem_desc_t) , pointer :: pio_subsystem ! pio info + integer , intent(in) :: io_type ! pio info + integer , intent(in) :: nx_global(:) + integer , intent(in) :: ny_global(:) + integer , intent(out) :: rc + + ! local variables + type(ESMF_DistGrid) :: distgrid + integer :: ns + character(len=CS) :: cnum + integer :: lsize + integer, pointer :: gindex(:) ! domain decomposition of data + type(ESMF_VM) :: vm + integer :: nu + logical :: exists ! file existance + type(file_desc_t) :: pioid + type(var_desc_t) :: varid + type(io_desc_t) :: pio_iodesc + integer :: rcode + integer :: tmp(1) + character(*), parameter :: subName = "(dglc_datamode_noevolve_restart_read) " + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + ! Determine restart file + + + if (trim(restfilem) == trim(nullstr)) then + exists = .false. + call ESMF_VMGetCurrent(vm, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (my_task == main_task) then + write(logunit,'(a)') trim(subname)//' restart filename from rpointer '//trim(rpfile) + open(newunit=nu, file=trim(rpfile), form='formatted') + read(nu,'(a)') restfilem + close(nu) + inquire(file=trim(restfilem), exist=exists) + endif + call ESMF_VMBroadCast(vm, restfilem, CL, main_task, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + else + ! use namelist already read + if (my_task == main_task) then + write(logunit, '(a)') trim(subname)//' restart filenames from namelist ' + inquire(file=trim(restfilem), exist=exists) + endif + endif + tmp = 0 + if(exists) tmp=1 + exists = (tmp(1) == 1) + if (.not. exists .and. my_task == main_task) then + write(logunit, '(a)') trim(subname)//' file not found, skipping '//trim(restfilem) + return + end if + + ! Read restart file + if (my_task == main_task) then + write(logunit, '(a)') trim(subname)//' reading data model restart '//trim(restfilem) + end if + + rcode = pio_openfile(pio_subsystem, pioid, io_type, trim(restfilem), pio_nowrite) + do ns = 1,num_icesheets + + write(cnum,'(i0)') ns + + ! Determine gindex for this ice sheet + call ESMF_MeshGet(model_meshes(ns), elementdistGrid=distGrid, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_DistGridGet(distGrid, localDe=0, elementCount=lsize, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + allocate(gindex(lsize)) + call ESMF_DistGridGet(distGrid, localDe=0, seqIndexList=gindex, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + + call pio_initdecomp(pio_subsystem, pio_double, (/nx_global(ns),ny_global(ns)/), gindex, pio_iodesc) + rcode = pio_inq_varid(pioid, 'flgl_rofi'//cnum, varid) + call pio_read_darray(pioid, varid, pio_iodesc, Fgrg_rofi(ns)%ptr, rcode) + call pio_freedecomp(pio_subsystem, pio_iodesc) + + ! Deallocate gindex + deallocate(gindex) + + end do ! loop over ice sheets + call pio_closefile(pioid) + + end subroutine dglc_datamode_noevolve_restart_read + +end module dglc_datamode_noevolve_mod diff --git a/CDEPS-interface/CDEPS/dglc/glc_comp_nuopc.F90 b/CDEPS-interface/CDEPS/dglc/glc_comp_nuopc.F90 new file mode 100644 index 0000000000..39c6620fa7 --- /dev/null +++ b/CDEPS-interface/CDEPS/dglc/glc_comp_nuopc.F90 @@ -0,0 +1,842 @@ +#ifdef CESMCOUPLED +module glc_comp_nuopc +#else +module cdeps_dglc_comp +#endif + + !---------------------------------------------------------------------------- + ! This is the NUOPC cap for DGLC + !---------------------------------------------------------------------------- + use ESMF , only : ESMF_VM, ESMF_VmGet, ESMF_VMBroadcast, ESMF_GridCompGet + use ESMF , only : ESMF_Mesh, ESMF_GridComp, ESMF_State, ESMF_Clock, ESMF_Time + use ESMF , only : ESMF_SUCCESS, ESMF_FAILURE, ESMF_LogWrite, ESMF_LOGMSG_INFO, ESMF_METHOD_INITIALIZE + use ESMF , only : ESMF_TraceRegionEnter, ESMF_TraceRegionExit + use ESMF , only : ESMF_TimeGet, ESMF_TimeInterval, ESMF_TimeIntervalGet, ESMF_Field, ESMF_MAXSTR + use ESMF , only : ESMF_MethodRemove, ESMF_MethodAdd + use ESMF , only : ESMF_GridCompSetEntryPoint + use ESMF , only : ESMF_Alarm, ESMF_AlarmSet, ESMF_AlarmIsRinging, ESMF_ALARMLIST_ALL + use ESMF , only : ESMF_ClockGet, ESMF_ClockSet, ESMF_ClockAdvance, ESMF_ClockGetAlarm, ESMF_ClockGetAlarmList + use ESMF , only : ESMF_StateGet, operator(+), ESMF_AlarmRingerOff, ESMF_LogWrite + use ESMF , only : ESMF_Field, ESMF_FieldGet, ESMF_VmLogMemInfo + use ESMF , only : ESMF_MeshCreate, ESMF_FILEFORMAT_ESMFMESH + use NUOPC , only : NUOPC_CompDerive, NUOPC_CompSetEntryPoint, NUOPC_CompSpecialize + use NUOPC , only : NUOPC_Advertise, NUOPC_CompAttributeGet, NUOPC_CompAttributeSet + use NUOPC , only : NUOPC_AddNestedState, NUOPC_IsConnected + use NUOPC_Model , only : model_routine_SS => SetServices + use NUOPC_Model , only : model_label_Advance => label_Advance + use NUOPC_Model , only : model_label_SetRunClock => label_SetRunClock + use NUOPC_Model , only : model_label_Finalize => label_Finalize + use NUOPC_Model , only : NUOPC_ModelGet, SetVM + use shr_kind_mod , only : r8=>shr_kind_r8, i8=>shr_kind_i8, cl=>shr_kind_cl, cs=>shr_kind_cs + use shr_sys_mod , only : shr_sys_abort + use shr_cal_mod , only : shr_cal_ymd2date + use shr_log_mod , only : shr_log_setLogUnit + use shr_string_mod , only : shr_string_listGetNum, shr_string_listGetName +#ifdef CESMCOUPLED + use shr_pio_mod , only : shr_pio_getiosys, shr_pio_getiotype, shr_pio_getioformat +#endif + use dshr_methods_mod , only : dshr_state_diagnose, chkerr, memcheck + use dshr_strdata_mod , only : shr_strdata_type, shr_strdata_advance, shr_strdata_init_from_config + use dshr_mod , only : dshr_model_initphase, dshr_init, dshr_mesh_init, dshr_alarm_init + use dshr_mod , only : dshr_state_setscalar, dshr_set_runclock, dshr_check_restart_alarm + use dshr_dfield_mod , only : dfield_type, dshr_dfield_add, dshr_dfield_copy + use dshr_fldlist_mod , only : fldlist_type, dshr_fldlist_realize + use nuopc_shr_methods, only : shr_get_rpointer_name + ! Datamode specialized modules + use dglc_datamode_noevolve_mod, only : dglc_datamode_noevolve_advertise + use dglc_datamode_noevolve_mod, only : dglc_datamode_noevolve_init_pointers + use dglc_datamode_noevolve_mod, only : dglc_datamode_noevolve_advance + use dglc_datamode_noevolve_mod, only : dglc_datamode_noevolve_restart_read + use dglc_datamode_noevolve_mod, only : dglc_datamode_noevolve_restart_write + + implicit none + private ! except + + public :: SetServices + public :: SetVM + private :: InitializeAdvertise + private :: InitializeRealize + private :: ModelSetRunClock + private :: ModelAdvance + private :: dglc_comp_run + private :: ModelFinalize + + !-------------------------------------------------------------------------- + ! Private module data + !-------------------------------------------------------------------------- + + character(*) , parameter :: nullstr = 'null' + integer , parameter :: max_icesheets = 10 ! maximum number of ice sheets for namelist input + integer :: num_icesheets ! actual number of ice sheets + + ! namelist input + character(CL) :: model_meshfiles(max_icesheets) = nullstr + character(CL) :: model_datafiles(max_icesheets) = nullstr + integer :: nx_global(max_icesheets) = 0 + integer :: ny_global(max_icesheets) = 0 + real(r8) :: model_internal_gridsize(max_icesheets) = 1.e36 + + ! module variables for multiple ice sheets + type(shr_strdata_type) , allocatable :: sdat(:) + type(ESMF_State) , allocatable :: NStateImp(:) + type(ESMF_State) , allocatable :: NStateExp(:) + type(ESMF_Mesh) , allocatable :: model_meshes(:) + + ! module variables common to all data models + character(CS) :: flds_scalar_name = '' + integer :: flds_scalar_num = 0 + integer :: flds_scalar_index_nx = 0 + integer :: flds_scalar_index_ny = 0 + integer :: mpicom ! mpi communicator + integer :: my_task ! my task in mpi communicator mpicom + logical :: mainproc ! true of my_task == main_task + character(len=16) :: inst_suffix = "" ! char string associated with instance (ie. "_0001" or "") + integer :: logunit ! logging unit number + logical :: restart_read ! start from restart + character(CL) :: case_name + + ! dglc_in namelist input + character(CL) :: streamfilename = nullstr ! filename to obtain stream info from + character(CL) :: nlfilename = nullstr ! filename to obtain namelist info from + character(CL) :: datamode = nullstr ! flags physics options wrt input data + character(CL) :: restfilm = nullstr ! model restart file namelist + logical :: skip_restart_read = .false. ! true => skip restart read in continuation run + logical :: export_all = .false. ! true => export all fields, do not check connected or not + + ! linked lists + type(fldList_type) , pointer :: fldsImport => null() + type(fldList_type) , pointer :: fldsExport => null() + + type dfields_icesheets_type + type(dfield_type), pointer :: dfields => null() + end type dfields_icesheets_type + type(dfields_icesheets_type), allocatable :: dfields_icesheets(:) + + ! constants + logical :: diagnose_data = .true. + integer , parameter :: main_task = 0 ! task number of main task +#ifdef CESMCOUPLED + character(*) , parameter :: module_name = "(glc_comp_nuopc)" +#else + character(*) , parameter :: module_name = "(cdeps_dglc_comp)" +#endif + character(*) , parameter :: modelname = 'dglc' + character(*) , parameter :: u_FILE_u = & + __FILE__ + +!=============================================================================== +contains +!=============================================================================== + + subroutine SetServices(gcomp, rc) + type(ESMF_GridComp) :: gcomp + integer, intent(out) :: rc + + ! Local varaibles + character(len=*),parameter :: subname=trim(module_name)//':(SetServices) ' + !-------------------------------- + + rc = ESMF_SUCCESS + call ESMF_LogWrite(subname//' called', ESMF_LOGMSG_INFO) + + ! the NUOPC gcomp component will register the generic methods + call NUOPC_CompDerive(gcomp, model_routine_SS, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! switching to IPD versions + call ESMF_GridCompSetEntryPoint(gcomp, ESMF_METHOD_INITIALIZE, & + userRoutine=dshr_model_initphase, phase=0, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + ! set entry point for methods that require specific implementation + call NUOPC_CompSetEntryPoint(gcomp, ESMF_METHOD_INITIALIZE, & + phaseLabelList=(/"IPDv01p1"/), userRoutine=InitializeAdvertise, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call NUOPC_CompSetEntryPoint(gcomp, ESMF_METHOD_INITIALIZE, & + phaseLabelList=(/"IPDv01p3"/), userRoutine=InitializeRealize, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! attach specializing method(s) + call NUOPC_CompSpecialize(gcomp, specLabel=model_label_Advance, specRoutine=ModelAdvance, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_MethodRemove(gcomp, label=model_label_SetRunClock, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + ! The following specialization does not use dshr_set_runclock since we also need to add an alarm + ! to determine if the model inputs are valid + call NUOPC_CompSpecialize(gcomp, specLabel=model_label_SetRunClock, specRoutine=ModelSetRunClock, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call NUOPC_CompSpecialize(gcomp, specLabel=model_label_Finalize, specRoutine=ModelFinalize, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_LogWrite(subname//' done', ESMF_LOGMSG_INFO) + + end subroutine SetServices + + !=============================================================================== + subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) + + use shr_nl_mod, only: shr_nl_find_group_name + + ! input/output variables + type(ESMF_GridComp) :: gcomp + type(ESMF_State) :: importState, exportState + type(ESMF_Clock) :: clock + integer, intent(out) :: rc + + ! local variables + type(ESMF_VM) :: vm + integer :: inst_index ! number of current instance (ie. 1) + integer :: nu ! unit number + integer :: ierr ! error code + integer :: bcasttmp(2) + integer :: ns + character(len=CS) :: cnum + character(len=ESMF_MAXSTR) :: model_datafiles_list ! colon separated string containing input datafiles + character(len=ESMF_MAXSTR) :: model_meshfiles_list ! colon separated string containing model meshfiles + character(len=*),parameter :: subname=trim(module_name)//':(InitializeAdvertise) ' + !------------------------------------------------------------------------------- + + ! Note that the suffix '-list' refers to a colon delimited string of names + namelist / dglc_nml / datamode, & + model_meshfiles_list, model_datafiles_list, model_internal_gridsize, nx_global, ny_global, & + restfilm, skip_restart_read + + rc = ESMF_SUCCESS + + call NUOPC_CompAttributeGet(gcomp, name='case_name', value=case_name, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! Determine logical mainproc + mainproc = (my_task == main_task) + + ! Obtain flds_scalar values, mpi values, multi-instance values and + ! set logunit and set shr logging to my log file + call dshr_init(gcomp, 'GLC', mpicom, my_task, inst_index, inst_suffix, & + flds_scalar_name, flds_scalar_num, flds_scalar_index_nx, flds_scalar_index_ny, logunit, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! Read dglc_nml from nlfilename + if (my_task == main_task) then + nlfilename = "dglc_in"//trim(inst_suffix) + open (newunit=nu,file=trim(nlfilename),status="old",action="read") + call shr_nl_find_group_name(nu, 'dglc_nml', status=ierr) + read (nu,nml=dglc_nml,iostat=ierr) + close(nu) + if (ierr > 0) then + write(logunit,'(a,i8)') 'ERROR: reading input namelist, '//trim(nlfilename)//' iostat=',ierr + call shr_sys_abort(subName//': namelist read error '//trim(nlfilename)) + end if + + ! Determine number of ice sheets + num_icesheets = shr_string_listGetNum(model_meshfiles_list) + + ! Determine array of model meshfile(s) and model input datafile(s) + do ns = 1,num_icesheets + ! determine mesh filename(s) + call shr_string_listGetName(model_meshfiles_list, ns, model_meshfiles(ns)) + ! determine input datafile name(s) + call shr_string_listGetName(model_datafiles_list, ns, model_datafiles(ns)) + end do + + ! Write diagnostics + write(logunit,'(a,a)')' case_name = ',trim(case_name) + write(logunit,'(a,a)')' datamode = ',trim(datamode) + do ns = 1,num_icesheets + write(logunit,'(a,i4 )') ' ice_sheet index = ',ns + write(logunit,'(a,a )') ' model_meshfile = ',trim(model_meshfiles(ns)) + write(logunit,'(a,a )') ' model_datafile = ',trim(model_datafiles(ns)) + write(logunit,'(a,d13.5)')' model_internal_gridsize = ',model_internal_gridsize(ns) + write(logunit,'(a,i10)') ' nx_global = ',nx_global(ns) + write(logunit,'(a,i10)') ' ny_global = ',ny_global(ns) + end do + write(logunit,'(a,a )')' restfilm = ',trim(restfilm) + write(logunit,'(a,l6)')' skip_restart_read = ',skip_restart_read + bcasttmp(1) = 0 + if(skip_restart_read) bcasttmp(1) = 1 + bcasttmp(2) = num_icesheets + endif + + ! Broadcast namelist input + call ESMF_GridCompGet(gcomp, vm=vm, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_VMBroadcast(vm, datamode, CL, main_task, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_VMBroadcast(vm, restfilm, CL, main_task, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_VMBroadcast(vm, model_meshfiles, CL*max_icesheets, main_task, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_VMBroadcast(vm, model_datafiles, CL*max_icesheets, main_task, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_VMBroadcast(vm, model_internal_gridsize, max_icesheets, main_task, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_VMBroadcast(vm, nx_global, max_icesheets, main_task, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_VMBroadcast(vm, ny_global, max_icesheets, main_task, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_VMBroadcast(vm, bcasttmp, 3, main_task, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + skip_restart_read = (bcasttmp(1) == 1) + num_icesheets = bcasttmp(2) + + ! Validate datamode + if ( trim(datamode) == 'noevolve') then ! read stream, no import data + ! do nothing + else + call shr_sys_abort(' ERROR illegal dglc datamode = '//trim(datamode)) + endif + + ! Allocate module variables + allocate(sdat(num_icesheets)) + allocate(NStateImp(num_icesheets)) + allocate(NStateExp(num_icesheets)) + allocate(model_meshes(num_icesheets)) + + ! Create nested states + do ns = 1,num_icesheets + write(cnum,'(i0)') ns + call NUOPC_AddNestedState(importState, CplSet="GLC"//trim(cnum), nestedState=NStateImp(ns), rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call NUOPC_AddNestedState(exportState, CplSet="GLC"//trim(cnum), nestedState=NStateExp(ns), rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end do + + ! Advertise dglc fields + if (trim(datamode)=='noevolve') then + call dglc_datamode_noevolve_advertise(NStateExp, fldsexport, NStateImp, fldsimport, & + flds_scalar_name, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + end subroutine InitializeAdvertise + + !=============================================================================== + subroutine InitializeRealize(gcomp, importState, exportState, clock, rc) + + ! input/output variables + type(ESMF_GridComp) :: gcomp + type(ESMF_State) :: importState, exportState + type(ESMF_Clock) :: clock + integer, intent(out) :: rc + + ! local variables + type(ESMF_VM) :: vm + type(ESMF_Time) :: currTime + integer :: current_ymd ! model date + integer :: current_year ! model year + integer :: current_mon ! model month + integer :: current_day ! model day + integer :: current_tod ! model sec into model date + integer :: ns + character(CL) :: cvalue + character(CS) :: cns + logical :: ispresent, isset + logical :: exists + character(len=*), parameter :: subname=trim(module_name)//':(InitializeRealize) ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + ! Initialize model mesh, restart flag, logunit, model_mask and model_frac + call ESMF_VMLogMemInfo("Entering "//trim(subname)) + call ESMF_TraceRegionEnter('dglc_strdata_init') + + ! Determine stream filename + streamfilename = trim(modelname)//'.streams'//trim(inst_suffix) +#ifndef DISABLE_FoX + streamfilename = trim(streamfilename)//'.xml' +#endif + + ! generate local mpi comm + call ESMF_GridCompGet(gcomp, vm=vm, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_VMGet(vm, localPet=my_task, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + mainproc = (my_task == main_task) + call shr_log_setLogUnit(logunit) + + ! Set restart flag (sets module variable restart_read) + call NUOPC_CompAttributeGet(gcomp, name='read_restart', value=cvalue, isPresent=isPresent, isSet=isSet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (isPresent .and. isSet) then + read(cvalue,*) restart_read + else + call shr_sys_abort(subname//' ERROR: read restart flag must be present') + end if + + ! Get the time to interpolate the stream data to + call ESMF_ClockGet(clock, currTime=currTime, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_TimeGet(currTime, yy=current_year, mm=current_mon, dd=current_day, s=current_tod, rc=rc ) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_cal_ymd2date(current_year, current_mon, current_day, current_ymd) + + ! Loop over ice sheets + do ns = 1,num_icesheets + + write(cns,'(i0)') ns + + ! Initialize pio subsystem +#ifdef CESMCOUPLED + sdat(ns)%pio_subsystem => shr_pio_getiosys('GLC') + sdat(ns)%io_type = shr_pio_getiotype('GLC') + sdat(ns)%io_format = shr_pio_getioformat('GLC') +#else + call dshr_pio_init(gcomp, sdat(ns), logunit, rc) +#endif + + ! Check that model_meshfile exists + if (my_task == main_task) then + inquire(file=trim(model_meshfiles(ns)), exist=exists) + if (.not.exists) then + write(logunit,'(a)')' ERROR: model_meshfile '//trim(model_meshfiles(ns))//' does not exist' + call shr_sys_abort(trim(subname)//' ERROR: model_meshfile '//trim(model_meshfiles(ns))//' does not exist') + end if + endif + + ! Read in model mesh for given ice sheet + model_meshes(ns) = ESMF_MeshCreate(trim(model_meshfiles(ns)), fileformat=ESMF_FILEFORMAT_ESMFMESH, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! Initialize stream data type + if (trim(datamode) /= 'noevolve') then + call shr_strdata_init_from_config(sdat(ns), streamfilename, model_meshes(ns), clock, 'GLC', logunit, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + ! Realize the actively coupled fields, now that a mesh is established and + ! NUOPC_Realize "realizes" a previously advertised field in the importState and exportState + ! by replacing the advertised fields with the newly created fields of the same name. + + call ESMF_LogWrite(subname//' calling dshr_fldlist_realize export for ice sheet '//trim(cns), ESMF_LOGMSG_INFO) + call dshr_fldlist_realize( NStateExp(ns), fldsExport, flds_scalar_name, flds_scalar_num, model_meshes(ns), & + subname//trim(modelname)//':Export', export_all, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_LogWrite(subname//' calling dshr_fldlist_realize importfor ice sheet '//trim(cns), ESMF_LOGMSG_INFO) + call dshr_fldlist_realize( NStateImp(ns), fldsImport, flds_scalar_name, flds_scalar_num, model_meshes(ns), & + subname//trim(modelname)//':Import', .false., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! Add scalars to export state + call dshr_state_SetScalar(dble(nx_global(ns)),flds_scalar_index_nx, & + NStateExp(ns), flds_scalar_name, flds_scalar_num, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_SetScalar(dble(ny_global(ns)),flds_scalar_index_ny,& + NStateExp(ns), flds_scalar_name, flds_scalar_num, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + end do ! end loop over ice sheets + + ! Run dglc + call dglc_comp_run(gcomp, clock, current_ymd, current_tod, restart_write=.false., valid_inputs=.true., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_TraceRegionExit('dglc_strdata_init') + call ESMF_VMLogMemInfo("Leaving "//trim(subname)) + + end subroutine InitializeRealize + + !=============================================================================== + subroutine ModelAdvance(gcomp, rc) + + ! input/output variables + type(ESMF_GridComp) :: gcomp + integer, intent(out) :: rc + + ! local variables + type(ESMF_Clock) :: clock + type(ESMF_TimeInterval) :: timeStep + type(ESMF_Time) :: currTime, nextTime + integer :: next_ymd ! model date + integer :: next_tod ! model sec into model date + integer :: yr ! year + integer :: mon ! month + integer :: day ! day in month + logical :: restart_write + type(ESMF_Alarm) :: valid_alarm + logical :: valid_inputs ! if true, inputs from mediator are valid + character(len=CS) :: timestring + character(len=*),parameter :: subname=trim(module_name)//':(ModelAdvance) ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + call shr_log_setLogUnit(logunit) + + call ESMF_TraceRegionEnter(subname) + call memcheck(subname, 5, my_task == main_task) + + ! query the Component for its clock + call NUOPC_ModelGet(gcomp, modelClock=clock, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! Determine if inputs from mediator are valid + call ESMF_ClockGetAlarm(clock, alarmname='alarm_valid_inputs', alarm=valid_alarm, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (ESMF_AlarmIsRinging(valid_alarm, rc=rc)) then + valid_inputs = .true. + call ESMF_AlarmRingerOff( valid_alarm, rc=rc ) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + else + valid_inputs = .false. + endif + + ! Need to advance nuopc one timestep ahead for shr_strdata time interpolation + call ESMF_ClockGet( clock, currTime=currTime, timeStep=timeStep, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + nextTime = currTime + timeStep + call ESMF_TimeGet( nextTime, yy=yr, mm=mon, dd=day, s=next_tod, rc=rc ) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_cal_ymd2date(yr, mon, day, next_ymd) + if (my_task == main_task) then + call ESMF_TimeGet(currTime, timestring=timestring, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + write(logunit,'(a,l6)') trim(timestring)//': valid_input for dglc is ',valid_inputs + end if + + ! determine if will write restart + restart_write = dshr_check_restart_alarm(clock, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (my_task == main_task) then + write(logunit,'(a,l6)') trim(timestring)//': restart write is ',restart_write + end if + + ! run dglc + call dglc_comp_run(gcomp, clock, next_ymd, next_tod, restart_write, valid_inputs, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_TraceRegionExit(subname) + + end subroutine ModelAdvance + + !=============================================================================== + subroutine dglc_comp_run(gcomp, clock, target_ymd, target_tod, restart_write, valid_inputs, rc) + + ! -------------------------- + ! advance dglc + ! -------------------------- + + ! input/output variables: + type(ESMF_GridComp) ,intent(in) :: gcomp + type(ESMF_Clock) , intent(in) :: clock + integer , intent(in) :: target_ymd ! model date + integer , intent(in) :: target_tod ! model sec into model date + logical , intent(in) :: restart_write + logical , intent(in) :: valid_inputs + integer , intent(out) :: rc + + ! local variables + character(len=CS) :: cnum + integer :: ns ! ice sheet index + logical :: first_time = .true. + character(len=CS) :: rpfile + character(*), parameter :: subName = "(dglc_comp_run) " + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + call ESMF_TraceRegionEnter('DGLC_RUN') + + !-------------------- + ! First time initialization + !-------------------- + + if (first_time) then + ! Initialize dfields for all ice sheets + if (trim(datamode) /= 'noevolve') then + call dglc_init_dfields(rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + ! Initialize datamode module ponters + select case (trim(datamode)) + case('noevolve') + call dglc_datamode_noevolve_init_pointers(NStateExp, NStateImp, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end select + + ! Read restart if needed + if (restart_read .and. .not. skip_restart_read) then + call shr_get_rpointer_name(gcomp, 'glc', target_ymd, target_tod, rpfile, 'read', rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dglc_datamode_noevolve_restart_read(model_meshes, restfilm, rpfile, & + logunit, my_task, main_task, mpicom, & + sdat(1)%pio_subsystem, sdat(1)%io_type, nx_global, ny_global, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + ! Reset first_time + first_time = .false. + end if + + !-------------------- + ! Update export (and possibly import data model states) + !-------------------- + + if (trim(datamode) /= 'noevolve') then + if (.not. allocated(dfields_icesheets)) then + allocate(dfields_icesheets(num_icesheets)) + end if + + ! Loop over ice sheets + do ns = 1,num_icesheets + ! Advance data model streams - time and spatially interpolate to model time and grid + ! Note that loop over ice sheets is done inside shr_strdata_advance + call ESMF_TraceRegionEnter('dglc_strdata_advance') + call shr_strdata_advance(sdat(ns), target_ymd, target_tod, logunit, 'dglc', rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_TraceRegionExit('dglc_strdata_advance') + + ! Copy all fields from streams to export state as default + ! This automatically will update the fields in the export state + call ESMF_TraceRegionEnter('dglc_dfield_copy') + call dshr_dfield_copy(dfields_icesheets(ns)%dfields, sdat(ns), rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_TraceRegionExit('dglc_dfield_copy') + end do + end if + + ! Perform data mode specific calculations + select case (trim(datamode)) + case('noevolve') + if (valid_inputs) then + call dglc_datamode_noevolve_advance(gcomp, sdat(1)%pio_subsystem, sdat(1)%io_type, sdat(1)%io_format, & + logunit, model_meshes, model_internal_gridsize, model_datafiles, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + end select + + ! Write restarts if needed + + if (restart_write) then + if (trim(datamode) == 'noevolve') then + if (my_task == main_task) then + write(logunit,'(a)') 'calling dglc_datamode_noevolve_restart_write' + end if + call shr_get_rpointer_name(gcomp, 'glc', target_ymd, target_tod, rpfile, 'write', rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dglc_datamode_noevolve_restart_write(model_meshes, case_name, rpfile, & + inst_suffix, target_ymd, target_tod, logunit, my_task, main_task, & + sdat(1)%pio_subsystem, sdat(1)%io_type, nx_global, ny_global, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + end if + + ! Write diagnostics + if (diagnose_data) then + do ns = 1,num_icesheets + write(cnum,'(i0)') ns + call dshr_state_diagnose(NStateExp(ns), flds_scalar_name, trim(subname)//':ES_'//trim(cnum), rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end do + end if + + call ESMF_TraceRegionExit('DGLC_RUN') + + contains + + subroutine dglc_init_dfields(rc) + ! ----------------------------- + ! Initialize dfields arrays + ! ----------------------------- + + ! input/output variables + integer, intent(out) :: rc + + ! local variables + integer :: nf, ns + integer :: fieldcount + type(ESMF_Field) :: lfield + character(ESMF_MAXSTR) ,pointer :: lfieldnamelist(:) + character(*), parameter :: subName = "(dglc_init_dfields) " + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + ! Loop over ice sheets + ! Initialize dfields data type (to map streams to export state fields) + ! Create dfields linked list - used for copying stream fields to export state fields + do ns = 1,num_icesheets + call ESMF_StateGet(NStateExp(ns), itemCount=fieldCount, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + allocate(lfieldnamelist(fieldCount)) + call ESMF_StateGet(NStateExp(ns), itemNameList=lfieldnamelist, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + do nf = 1, fieldCount + call ESMF_StateGet(NStateExp(ns), itemName=trim(lfieldNameList(nf)), field=lfield, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + if (trim(lfieldnamelist(nf)) /= flds_scalar_name) then + call dshr_dfield_add( dfields_icesheets(ns)%dfields, sdat(ns), & + trim(lfieldnamelist(nf)), trim(lfieldnamelist(nf)), NStateExp(ns), logunit, mainproc, rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + end if + end do + deallocate(lfieldnamelist) + end do + end subroutine dglc_init_dfields + + end subroutine dglc_comp_run + + !=============================================================================== + + subroutine ModelSetRunClock(gcomp, rc) + + ! input/output variables + type(ESMF_GridComp) :: gcomp + integer, intent(out) :: rc + + ! local variables + type(ESMF_Clock) :: mclock, dclock + type(ESMF_Time) :: mcurrtime, dcurrtime + type(ESMF_Time) :: mstoptime + type(ESMF_TimeInterval) :: mtimestep, dtimestep + character(len=256) :: cvalue + character(len=256) :: restart_option ! Restart option units + integer :: restart_n ! Number until restart interval + integer :: restart_ymd ! Restart date (YYYYMMDD) + type(ESMF_ALARM) :: restart_alarm + character(len=256) :: stop_option ! Stop option units + integer :: stop_n ! Number until stop interval + integer :: stop_ymd ! Stop date (YYYYMMDD) + type(ESMF_ALARM) :: stop_alarm + integer :: alarmcount + character(len=CS) :: glc_avg_period ! averaging period in mediator + type(ESMF_ALARM) :: valid_alarm ! model alarm + integer :: dtime + character(len=*),parameter :: subname='glc_comp_nuopc:(dglc_set_runclock) ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + ! query the Component for its clocks + call NUOPC_ModelGet(gcomp, driverClock=dclock, modelClock=mclock, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_ClockGet(dclock, currTime=dcurrtime, timeStep=dtimestep, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_ClockGet(mclock, currTime=mcurrtime, timeStep=mtimestep, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! force model clock currtime and timestep to match driver and set stoptime + mstoptime = mcurrtime + dtimestep + call ESMF_ClockSet(mclock, currTime=dcurrtime, timeStep=dtimestep, stopTime=mstoptime, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! determine number of alarms + call ESMF_ClockGetAlarmList(mclock, alarmlistflag=ESMF_ALARMLIST_ALL, alarmCount=alarmCount, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + if (alarmCount == 0) then + + !---------------- + ! glc valid input alarm + !---------------- + call NUOPC_CompAttributeGet(gcomp, name="glc_avg_period", value=glc_avg_period, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + if (trim(glc_avg_period) == 'hour') then + call dshr_alarm_init(mclock, valid_alarm, 'nhours', opt_n=1, alarmname='alarm_valid_inputs', rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + else if (trim(glc_avg_period) == 'day') then + call dshr_alarm_init(mclock, valid_alarm, 'ndays' , opt_n=1, alarmname='alarm_valid_inputs', rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + else if (trim(glc_avg_period) == 'yearly') then + call dshr_alarm_init(mclock, valid_alarm, 'yearly', alarmname='alarm_valid_inputs', rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + else if (trim(glc_avg_period) == 'glc_coupling_period') then + call ESMF_TimeIntervalGet(mtimestep, s=dtime, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_alarm_init(mclock, valid_alarm, 'nseconds', opt_n=dtime, alarmname='alarm_valid_inputs', rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + else + call ESMF_LogWrite(trim(subname)// ": ERROR glc_avg_period = "//trim(glc_avg_period)//" not supported", & + ESMF_LOGMSG_INFO, rc=rc) + rc = ESMF_FAILURE + RETURN + end if + + call ESMF_AlarmSet(valid_alarm, clock=mclock, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + !---------------- + ! Restart alarm + !---------------- + call ESMF_LogWrite(subname//'setting restart alarm for dglc' , ESMF_LOGMSG_INFO) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call NUOPC_CompAttributeGet(gcomp, name="restart_option", value=restart_option, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call NUOPC_CompAttributeGet(gcomp, name="restart_n", value=cvalue, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + read(cvalue,*) restart_n + + call NUOPC_CompAttributeGet(gcomp, name="restart_ymd", value=cvalue, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + read(cvalue,*) restart_ymd + + call dshr_alarm_init(mclock, restart_alarm, restart_option, & + opt_n = restart_n, & + opt_ymd = restart_ymd, & + RefTime = mcurrTime, & + alarmname = 'alarm_restart', rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_AlarmSet(restart_alarm, clock=mclock, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + !---------------- + ! Stop alarm + !---------------- + call ESMF_LogWrite(subname//'setting stop alarm for dglc' , ESMF_LOGMSG_INFO) + call NUOPC_CompAttributeGet(gcomp, name="stop_option", value=stop_option, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call NUOPC_CompAttributeGet(gcomp, name="stop_n", value=cvalue, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + read(cvalue,*) stop_n + + call NUOPC_CompAttributeGet(gcomp, name="stop_ymd", value=cvalue, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + read(cvalue,*) stop_ymd + + call dshr_alarm_init(mclock, stop_alarm, stop_option, & + opt_n = stop_n, & + opt_ymd = stop_ymd, & + RefTime = mcurrTime, & + alarmname = 'alarm_stop', rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_AlarmSet(stop_alarm, clock=mclock, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + end if + + ! Advance model clock to trigger alarms then reset model clock back to currtime + call ESMF_ClockAdvance(mclock,rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_ClockSet(mclock, currTime=dcurrtime, timeStep=dtimestep, stopTime=mstoptime, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + end subroutine ModelSetRunClock + + !=============================================================================== + subroutine ModelFinalize(gcomp, rc) + type(ESMF_GridComp) :: gcomp + integer, intent(out) :: rc + !------------------------------------------------------------------------------- + rc = ESMF_SUCCESS + if (my_task == main_task) then + write(logunit,*) + write(logunit,*) 'dglc : end of main integration loop' + write(logunit,*) + end if + end subroutine ModelFinalize + +#ifdef CESMCOUPLED +end module glc_comp_nuopc +#else +end module cdeps_dglc_comp +#endif diff --git a/CDEPS-interface/CDEPS/dice/CMakeLists.txt b/CDEPS-interface/CDEPS/dice/CMakeLists.txt new file mode 100644 index 0000000000..aabb443127 --- /dev/null +++ b/CDEPS-interface/CDEPS/dice/CMakeLists.txt @@ -0,0 +1,36 @@ +project(dice Fortran) +set(SRCFILES ice_comp_nuopc.F90 + dice_datamode_ssmi_mod.F90 + dice_datamode_cplhist_mod.F90 + dice_flux_atmice_mod.F90) + +foreach(FILE ${SRCFILES}) + if(EXISTS "${CASEROOT}/SourceMods/src.dice/${FILE}") + list(REMOVE_ITEM SRCFILES ${FILE}) + list(APPEND SRCFILES "${CASEROOT}/SourceMods/src.dice/${FILE}") + message("Using ${FILE} from ${CASEROOT}/SourceMods/src.dice") + endif() +endforeach() + +message("DICE srcfiles are ${SRCFILES}") + +add_library(dice ${SRCFILES}) + +add_dependencies(dice dshr streams) +target_include_directories (dice PRIVATE ${ESMF_F90COMPILEPATHS}) +target_include_directories (dice PRIVATE "${CMAKE_SOURCE_DIR}") +target_include_directories (dice PRIVATE "${PIO_Fortran_INCLUDE_DIR}") +if(NOT DISABLE_FoX) + target_include_directories (dice PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/../fox/include) +endif() + +if(BLD_STANDALONE) + # ESMX requires mod files + foreach (SRC ${SRCFILES}) + string(REGEX REPLACE "[.]F90$" ".mod" MOD ${SRC}) + if (NOT DEFINED CIMEROOT AND MOD STREQUAL ice_comp_nuopc.mod) + set(MOD cdeps_dice_comp.mod) + endif() + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${MOD}" DESTINATION include) + endforeach () +endif() diff --git a/CDEPS-interface/CDEPS/dice/cime_config/buildlib b/CDEPS-interface/CDEPS/dice/cime_config/buildlib new file mode 120000 index 0000000000..0c5e984ac2 --- /dev/null +++ b/CDEPS-interface/CDEPS/dice/cime_config/buildlib @@ -0,0 +1 @@ +../../cime_config/buildlib_comps \ No newline at end of file diff --git a/CDEPS-interface/CDEPS/dice/cime_config/buildnml b/CDEPS-interface/CDEPS/dice/cime_config/buildnml new file mode 100755 index 0000000000..c59539b561 --- /dev/null +++ b/CDEPS-interface/CDEPS/dice/cime_config/buildnml @@ -0,0 +1,197 @@ +#!/usr/bin/env python3 + +"""Namelist creator for CDEPS data ice model. +""" + +# Typically ignore this. +# pylint: disable=invalid-name + +# Disable these because this is our standard setup +# pylint: disable=wildcard-import,unused-wildcard-import,wrong-import-position + +import os, sys + +_CDEPS_CONFIG = os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir,os.pardir,"cime_config") +_CIMEROOT = os.environ.get("CIMEROOT") +if _CIMEROOT is None: + raise SystemExit("ERROR: must set CIMEROOT environment variable") +_LIBDIR = os.path.join(_CIMEROOT, "CIME", "Tools") +sys.path.append(_LIBDIR) +sys.path.append(_CDEPS_CONFIG) + +from standard_script_setup import * +from CIME.case import Case +from CIME.XML.files import Files +from CIME.nmlgen import NamelistGenerator +from CIME.utils import expect, safe_copy +from CIME.buildnml import create_namelist_infile, parse_input, copy_inputs_to_rundir +from stream_cdeps import StreamCDEPS + +logger = logging.getLogger(__name__) + +# pylint: disable=too-many-arguments,too-many-locals,too-many-branches,too-many-statements +#################################################################################### +def _create_namelists(case, confdir, inst_string, infile, nmlgen, data_list_path): +#################################################################################### + """Write out the namelist for this component. + + Most arguments are the same as those for `NamelistGenerator`. The + `inst_string` argument is used as a suffix to distinguish files for + different instances. The `confdir` argument is used to specify the directory + in which output files will be placed. + """ + #---------------------------------------------------- + # Write out dice_in and dice.streams.xml + #---------------------------------------------------- + + caseroot = case.get_value("CASEROOT") + dice_mode = case.get_value("DICE_MODE") + ice_grid = case.get_value("ICE_GRID") + ice_nx = case.get_value("ICE_NX") + ice_ny = case.get_value("ICE_NY") + atm_nx = case.get_value("ATM_NX") + atm_ny = case.get_value("ATM_NY") + + # Check for incompatible options. + expect(ice_grid != "null", + "ICE_GRID cannot be null") + + # Log some settings. + logger.debug("DICE mode is {}".format(dice_mode)) + logger.debug("DICE grid is {}".format(ice_grid)) + + # Initialize namelist defaults + config = {} + config['ice_grid'] = ice_grid + config['dice_mode'] = dice_mode + + if case.get_value('PTS_LON'): + scol_lon = float(case.get_value('PTS_LON')) + else: + scol_lon = -999. + if case.get_value('PTS_LAT'): + scol_lat = float(case.get_value('PTS_LAT')) + else: + scol_lat = -999. + if case.get_value('ATM_DOMAIN_FILE'): + if scol_lon > -999. and scol_lat >= -999. and case.get_value("ATM_DOMAIN_FILE") != "UNSET": + config['single_column'] = 'true' + else: + config['single_column'] = 'false' + + # Initialize nmlgen + nmlgen.init_defaults(infile, config) + + # Generate dice_in + namelist_file = os.path.join(confdir, "dice_in") + nmlgen.write_output_file(namelist_file, data_list_path, groups=['dice_nml']) + + # Determine streams + streamlist = nmlgen.get_streams() + if type(streamlist) == type(str()): + streamlist = [] + + # Generate dice.streams.xml + outfile = os.path.join(confdir, "dice.streams"+inst_string+".xml" ) + schema_file = os.path.join(_CDEPS_CONFIG,"stream_definition_v2.0.xsd") + stream_file = os.path.join(_CDEPS_CONFIG,os.pardir, "dice","cime_config","stream_definition_dice.xml") + streams = StreamCDEPS(stream_file, schema_file) + streams.create_stream_xml(streamlist, case, outfile, data_list_path, + os.path.join(caseroot,'user_nl_dice_streams'+inst_string)) + +############################################################################### +def buildnml(case, caseroot, compname): +############################################################################### + rundir = case.get_value("RUNDIR") + inst_name = compname.upper()[1:] + ninst = case.get_value("NINST_"+inst_name) + if ninst is None: + ninst = case.get_value("NINST") + + # Determine configuration directory + confdir = os.path.join(caseroot,"Buildconf",compname + "conf") + if not os.path.isdir(confdir): + os.makedirs(confdir) + + #---------------------------------------------------- + # Construct the namelist generator + #---------------------------------------------------- + # determine directory for user modified namelist_definitions.xml and namelist_defaults.xml + user_xml_dir = os.path.join(caseroot, "SourceMods", "src." + compname) + expect (os.path.isdir(user_xml_dir), + "user_xml_dir {} does not exist ".format(user_xml_dir)) + + # NOTE: User definition *replaces* existing definition. + files = Files(comp_interface="nuopc") + definition_file = [files.get_value("NAMELIST_DEFINITION_FILE", {"component":compname})] + + user_definition = os.path.join(user_xml_dir, "namelist_definition_"+compname+".xml") + if os.path.isfile(user_definition): + definition_file = [user_definition] + for file_ in definition_file: + expect(os.path.isfile(file_), "Namelist XML file {} not found!".format(file_)) + + # Create the namelist generator object - independent of instance + nmlgen = NamelistGenerator(case, definition_file, files=files) + + #---------------------------------------------------- + # Clear out old data. + #---------------------------------------------------- + data_list_path = os.path.join(caseroot, "Buildconf", compname+".input_data_list") + if os.path.exists(data_list_path): + os.remove(data_list_path) + + #---------------------------------------------------- + # Loop over instances + #---------------------------------------------------- + for inst_counter in range(1, ninst+1): + # determine instance string + inst_string = "" + if ninst > 1: + inst_string = '_' + "{:04d}".format(inst_counter) + + # If multi-instance case does not have restart file, use + # single-case restart for each instance + rpointer = "rpointer." + compname + if (os.path.isfile(os.path.join(rundir,rpointer)) and + (not os.path.isfile(os.path.join(rundir,rpointer + inst_string)))): + safe_copy(os.path.join(rundir, rpointer), + os.path.join(rundir, rpointer + inst_string)) + + inst_string_label = inst_string + if not inst_string_label: + inst_string_label = "\"\"" + + # create namelist output infile using user_nl_file as input + user_nl_file = os.path.join(caseroot, "user_nl_" + compname + inst_string) + expect(os.path.isfile(user_nl_file), + "Missing required user_nl_file {} ".format(user_nl_file)) + infile = os.path.join(confdir, "namelist_infile") + create_namelist_infile(case, user_nl_file, infile) + namelist_infile = [infile] + + # create namelist and stream file(s) data component + _create_namelists(case, confdir, inst_string, namelist_infile, nmlgen, data_list_path) + + # copy namelist files and stream text files, to rundir + copy_inputs_to_rundir(caseroot, compname, confdir, rundir, inst_string) + +############################################################################### +def get_user_nl_list(case): +############################################################################### + """Returns a list of user_nl_dice* files needed in this case + This function is called by CIME to stage the user_nl_dice* files in the case + directory. + """ + user_nl_list = ["user_nl_dice", "user_nl_dice_streams"] + return user_nl_list + +############################################################################### +def _main_func(): + # Build the component namelist and required stream txt files + caseroot = parse_input(sys.argv) + with Case(caseroot) as case: + buildnml(case, caseroot, "dice") + +if __name__ == "__main__": + _main_func() diff --git a/CDEPS-interface/CDEPS/dice/cime_config/config_archive.xml b/CDEPS-interface/CDEPS/dice/cime_config/config_archive.xml new file mode 100644 index 0000000000..893bd44819 --- /dev/null +++ b/CDEPS-interface/CDEPS/dice/cime_config/config_archive.xml @@ -0,0 +1,16 @@ + + + r + rs1 + unset + + rpointer.ice$NINST_STRING + $CASE.dice$NINST_STRING.r.$DATENAME.nc,$CASE.dice$NINST_STRING.rs1.$DATENAME.bin + + + casename.dice.r.1976-01-01-00000.nc + rpointer.ice_0001 + rpointer.ice + + + diff --git a/CDEPS-interface/CDEPS/dice/cime_config/config_component.xml b/CDEPS-interface/CDEPS/dice/cime_config/config_component.xml new file mode 100644 index 0000000000..70e342f11f --- /dev/null +++ b/CDEPS-interface/CDEPS/dice/cime_config/config_component.xml @@ -0,0 +1,63 @@ + + + + + + + + + dice mode + is ssmi + is siaf + + + + char + dice + dice + case_comp + env_case.xml + Name of ice component + + + + char + ssmi,ssmi_iaf + ssmi + + ssmi + ssmi_iaf + + run_component_dice + env_run.xml + DICE mode. DICE is a combination of a data model and a prognostic model. + The data functionality reads in ice coverage. The prognostic functionality + calculates the ice/atmosphere and ice/ocean fluxes. DICE receives the same + atmospheric input from the coupler as the active CICE model (i.e., atmospheric + states, shortwave fluxes, and ocean ice melt flux). + This component is only used to drive POP in C compsets. + If DICE_MODE is set to ssmi or ssmi_iaf, it is a prognostic mode. + It requires data be sent to the ice model. + Ice fraction (extent) data is read from an input stream, + atmosphere state variables are received from the coupler, and then + an atmosphere-ice surface flux is computed and sent to the + coupler. Normally the ice fraction data is found in the same data files + that provide SST data to the data ocean model. They are normally found + in the same file because the SST and ice fraction data are derived from the + same observational data sets and are consistent with each other. + + + + ========================================= + DICE naming conventions + ========================================= + + + diff --git a/CDEPS-interface/CDEPS/dice/cime_config/namelist_definition_dice.xml b/CDEPS-interface/CDEPS/dice/cime_config/namelist_definition_dice.xml new file mode 100644 index 0000000000..64f68881a8 --- /dev/null +++ b/CDEPS-interface/CDEPS/dice/cime_config/namelist_definition_dice.xml @@ -0,0 +1,163 @@ + + + + + + + + + + char(100) + streams + streams_file + List of streams used for the given dice_mode. + + ssmi_iaf + ssmi_nyf + + + + + char + streams + dice_nml + ssmi,ssmi_iaf + + general method that operates on the data. + Is a prognostic mode. It requires data be sent to the ice model. + Ice fraction (extent) data is read from an input stream, + atmosphere state variables are received from the mediator, and then + atmosphere-ice surface fluxes are computed and sent to the mediator. + + + ssmi_iaf + ssmi + + + + + char + streams + abs + dice_nml + file specifying model mesh + + $ICE_DOMAIN_MESH + null + + + + + char + streams + abs + dice_nml + + file specifying model mask if not obtained from input model mesh + + + $MASK_MESH + null + + + + + integer + streams + dice_nml + + global size of nx + + + $ICE_NX + 1 + + + + + integer + streams + dice_nml + + global size of ny + + + $ICE_NY + 1 + + + + + logical + dice + dice_nml + + activates water accumulation/melt wrt Q + + + .true. + + + + + real + dice + dice_nml + + initial water accumulation value + + + 0. + + + + + real + dice + dice_nml + + bound on melt rate + + + -300.e0 + + + + + real + dice + dice_nml + + short-wave penatration factor + + + 0. + + + + + char + dice + dice_nml + + Model restart filename for the data ice model data. This is optional. + If restfilm is null, the restart filename will + be read from the ICE restart pointer file (or files for multiple instances). + + + null + + + + diff --git a/CDEPS-interface/CDEPS/dice/cime_config/stream_definition_dice.xml b/CDEPS-interface/CDEPS/dice/cime_config/stream_definition_dice.xml new file mode 100644 index 0000000000..553065ab43 --- /dev/null +++ b/CDEPS-interface/CDEPS/dice/cime_config/stream_definition_dice.xml @@ -0,0 +1,70 @@ + + + + + + + + + $DIN_LOC_ROOT/ice/dice7/SSMI/ssmi.ifrac.0.5x0.5_ESMFmesh_120520.nc + + + $DIN_LOC_ROOT/ice/dice7/SSMI/ssmi_ifrac.clim.x0.5.090319.nc + + + ifrac Si_ifrac + + null + + bilinear + + null + 1 + 1 + 1 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/ocn/iaf/ssmi.ifrac.0.5x0.5_ESMFmesh_120520.nc + + + $DIN_LOC_ROOT/ocn/iaf/ssmi.ifrac.0.5x0.5.%y.nc + $DIN_LOC_ROOT/ocn/iaf/ssmi.ifrac.0.5x0.5.%y.20120420.nc + + + ifrac Si_ifrac + + null + + bilinear + + null + 1 + 1948 + 2009 + 0 + + linear + + + cycle + + + 1.5 + + single + + + diff --git a/CDEPS-interface/CDEPS/dice/cime_config/testdefs/testlist_dice.xml b/CDEPS-interface/CDEPS/dice/cime_config/testdefs/testlist_dice.xml new file mode 100644 index 0000000000..948dc092d5 --- /dev/null +++ b/CDEPS-interface/CDEPS/dice/cime_config/testdefs/testlist_dice.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CDEPS-interface/CDEPS/dice/cime_config/user_nl_dice b/CDEPS-interface/CDEPS/dice/cime_config/user_nl_dice new file mode 100644 index 0000000000..b497393570 --- /dev/null +++ b/CDEPS-interface/CDEPS/dice/cime_config/user_nl_dice @@ -0,0 +1,13 @@ +!------------------------------------------------------------------------ +! Users should ONLY USE user_nl_dice to change namelists variables +! Users should add all user specific namelist changes below in the form of +! namelist_var = new_namelist_value +! Note that any namelist variable from shr_strdata_nml and dice_nml can +! be modified below using the above syntax +! User preview_namelists to view (not modify) the output namelist in the +! directory $CASEROOT/CaseDocs +! To modify the contents of a stream txt file, first use preview_namelists +! to obtain the contents of the stream txt files in CaseDocs, and then +! place a copy of the modified stream txt file in $CASEROOT with the string +! user_ prepended. +!------------------------------------------------------------------------ diff --git a/CDEPS-interface/CDEPS/dice/cime_config/user_nl_dice_streams b/CDEPS-interface/CDEPS/dice/cime_config/user_nl_dice_streams new file mode 100644 index 0000000000..856ee89446 --- /dev/null +++ b/CDEPS-interface/CDEPS/dice/cime_config/user_nl_dice_streams @@ -0,0 +1,33 @@ +!------------------------------------------------------------------------ +! This file is used to modify datm.streams.xml generated in $RUNDIR +! Entries should have the form +! :<= new stream_value> +! The following are accepted values for an assume streamname of foo +! foo:meshfile = character string +! foo:datafiles = comma separated string of full pathnames (e.g. file1,file2,file3...) +! foo:datavars = comma separated string of field pairs (e.g. foo foobar,foo2 foobar2...) +! foo:taxmode = one of [cycle, extend, limit] +! foo:tintalgo = one of [lower,upper,nearest,linear,coszen] +! foo:readmode = single (only suported mode right now) +! foo:mapalgo = one of [bilinear,redist,nn,consf,consd,none] +! foo:dtlimit = real (1.5 is default) +! foo:year_first = integer +! foo:year_last = integer +! foo:year_align = integer +! foo:vectors = one of [none,u:v] +! foo:lev_dimname: = one of [null,name of level dimenion name] +! foo:offset = integer +! As an example: +! foo:year_first = 1950 +! would change the stream year_first stream_entry to 1950 for the foo stream block +! NOTE: multi-line inputs are enabled by adding a \ at the end of the line +! As an emaple: +! foo:datafiles=foo1,foo2, \ +! foo3 +! Will yield the following new entry for datafiles in stream foo +! +! foo1 +! foo2 +! foo3 +! +!------------------------------------------------------------------------ diff --git a/CDEPS-interface/CDEPS/dice/dice_datamode_cplhist_mod.F90 b/CDEPS-interface/CDEPS/dice/dice_datamode_cplhist_mod.F90 new file mode 100644 index 0000000000..8b42feb2f8 --- /dev/null +++ b/CDEPS-interface/CDEPS/dice/dice_datamode_cplhist_mod.F90 @@ -0,0 +1,201 @@ +module dice_datamode_cplhist_mod + + use ESMF , only : ESMF_State, ESMF_LOGMSG_INFO, ESMF_LogWrite, ESMF_SUCCESS + use NUOPC , only : NUOPC_Advertise + use shr_kind_mod , only : r8=>shr_kind_r8, i8=>shr_kind_i8, cl=>shr_kind_cl, cs=>shr_kind_cs + use shr_const_mod , only : shr_const_TkFrzsw + use shr_sys_mod , only : shr_sys_abort + use dshr_methods_mod , only : dshr_state_getfldptr, dshr_fldbun_getfldptr, chkerr + use dshr_fldlist_mod , only : fldlist_type, dshr_fldlist_add + use dshr_mod , only : dshr_restart_read, dshr_restart_write + use dshr_strdata_mod , only : shr_strdata_type + + implicit none + private ! except + + public :: dice_datamode_cplhist_advertise + public :: dice_datamode_cplhist_init_pointers + public :: dice_datamode_cplhist_advance + public :: dice_datamode_cplhist_restart_read + public :: dice_datamode_cplhist_restart_write + + ! export fields + ! ice to atm in CMEPS/mediator/esmFldsExchange_ufs_mod.F90 + real(r8), pointer :: Si_ifrac(:) => null() + real(r8), pointer :: Si_imask(:) => null() + real(r8), pointer :: Faii_taux(:) => null() + real(r8), pointer :: Faii_tauy(:) => null() + real(r8), pointer :: Faii_lat(:) => null() + real(r8), pointer :: Faii_sen(:) => null() + real(r8), pointer :: Faii_lwup(:) => null() + real(r8), pointer :: Faii_evap(:) => null() + real(r8), pointer :: Si_vice(:) => null() + real(r8), pointer :: Si_vsno(:) => null() + real(r8), pointer :: Si_t(:) => null() + real(r8), pointer :: Si_avsdr(:) => null() + real(r8), pointer :: Si_avsdf(:) => null() + real(r8), pointer :: Si_anidr(:) => null() + real(r8), pointer :: Si_anidf(:) => null() + + character(*) , parameter :: nullstr = 'null' + character(*) , parameter :: u_FILE_u = & + __FILE__ + +!=============================================================================== +contains +!=============================================================================== + + subroutine dice_datamode_cplhist_advertise(exportState, fldsexport, flds_scalar_name, rc) + + ! input/output variables + type(esmf_State) , intent(inout) :: exportState + type(fldlist_type) , pointer :: fldsexport + character(len=*) , intent(in) :: flds_scalar_name + integer , intent(out) :: rc + + ! local variables + type(fldlist_type), pointer :: fldList + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + ! Advertise export fields + call dshr_fldList_add(fldsExport, trim(flds_scalar_name)) + call dshr_fldList_add(fldsExport, 'Si_ifrac' ) + call dshr_fldList_add(fldsExport, 'Si_imask' ) + call dshr_fldList_add(fldsExport, 'Faii_taux' ) + call dshr_fldList_add(fldsExport, 'Faii_tauy' ) + call dshr_fldList_add(fldsExport, 'Faii_lat' ) + call dshr_fldList_add(fldsExport, 'Faii_sen' ) + call dshr_fldList_add(fldsExport, 'Faii_lwup' ) + call dshr_fldList_add(fldsExport, 'Faii_evap' ) + call dshr_fldList_add(fldsExport, 'Si_vice' ) + call dshr_fldList_add(fldsExport, 'Si_vsno' ) + call dshr_fldList_add(fldsExport, 'Si_t' ) + call dshr_fldList_add(fldsExport, 'Si_avsdr' ) + call dshr_fldList_add(fldsExport, 'Si_avsdf' ) + call dshr_fldList_add(fldsExport, 'Si_anidr' ) + call dshr_fldList_add(fldsExport, 'Si_anidf' ) + + fldlist => fldsExport ! the head of the linked list + do while (associated(fldlist)) + call NUOPC_Advertise(exportState, standardName=fldlist%stdname, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_LogWrite('(dice_comp_advertise): Fr_ice'//trim(fldList%stdname), ESMF_LOGMSG_INFO) + fldList => fldList%next + enddo + + end subroutine dice_datamode_cplhist_advertise + + !=============================================================================== + subroutine dice_datamode_cplhist_init_pointers(importState, exportState,sdat,rc) + + ! input/output variables + type(ESMF_State) , intent(inout) :: importState + type(ESMF_State) , intent(inout) :: exportState + type(shr_strdata_type) , intent(in) :: sdat + integer , intent(out) :: rc + + ! local variables + character(len=*), parameter :: subname='(dice_init_pointers): ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + ! initialize pointers to export fields + call dshr_state_getfldptr(exportState, 'Si_ifrac' , fldptr1=Si_ifrac , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Si_imask' , fldptr1=Si_imask , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faii_taux' , fldptr1=Faii_taux , allowNullReturn=.true., rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faii_tauy' , fldptr1=Faii_tauy , allowNullReturn=.true., rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faii_lat' , fldptr1=Faii_lat , allowNullReturn=.true., rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faii_sen', fldptr1=Faii_sen, allowNullReturn=.true., rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faii_lwup', fldptr1=Faii_lwup, allowNullReturn=.true., rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faii_evap', fldptr1=Faii_evap, allowNullReturn=.true., rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Si_vice', fldptr1=Si_vice, allowNullReturn=.true., rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Si_vsno', fldptr1=Si_vsno, allowNullReturn=.true., rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Si_t', fldptr1=Si_t, allowNullReturn=.true., rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Si_avsdr', fldptr1=Si_avsdr, allowNullReturn=.true., rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Si_avsdf', fldptr1=Si_avsdf, allowNullReturn=.true., rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Si_anidr', fldptr1=Si_anidr, allowNullReturn=.true., rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Si_anidf', fldptr1=Si_anidf, allowNullReturn=.true., rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + + !Initialize (e.g., =0)? + + end subroutine dice_datamode_cplhist_init_pointers + + !=============================================================================== + subroutine dice_datamode_cplhist_advance(rc) + + ! input/output variables + integer, intent(out) :: rc + + ! local variables + character(len=*), parameter :: subname='(dice_datamode_cplhist_advance): ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + !Unit conversions, calculations,.... + !Where aice=0, Si_t=0K (as missing value). Interpolation in time between ice that comes or goes then has issues + where(Si_t .LT. 10) Si_t = shr_const_TkFrzsw + + end subroutine dice_datamode_cplhist_advance + + !=============================================================================== + subroutine dice_datamode_cplhist_restart_write(rpfile, case_name, inst_suffix, ymd, tod, & + logunit, my_task, sdat) + + ! input/output variables + character(len=*) , intent(in) :: rpfile + character(len=*) , intent(in) :: case_name + character(len=*) , intent(in) :: inst_suffix + integer , intent(in) :: ymd ! model date + integer , intent(in) :: tod ! model sec into model date + integer , intent(in) :: logunit + integer , intent(in) :: my_task + type(shr_strdata_type) , intent(inout) :: sdat + !------------------------------------------------------------------------------- + + integer :: rc + + call dshr_restart_write(rpfile, case_name, 'dice', inst_suffix, ymd, tod, & + logunit, my_task, sdat, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + end subroutine dice_datamode_cplhist_restart_write + + !=============================================================================== + subroutine dice_datamode_cplhist_restart_read(rest_filem, rpfile, logunit, my_task, mpicom, sdat) + + ! input/output arguments + character(len=*) , intent(inout) :: rest_filem + character(len=*) , intent(in) :: rpfile + integer , intent(in) :: logunit + integer , intent(in) :: my_task + integer , intent(in) :: mpicom + type(shr_strdata_type) , intent(inout) :: sdat + !------------------------------------------------------------------------------- + + integer :: rc + + call dshr_restart_read(rest_filem, rpfile, logunit, my_task, mpicom, sdat, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + end subroutine dice_datamode_cplhist_restart_read + +end module dice_datamode_cplhist_mod diff --git a/CDEPS-interface/CDEPS/dice/dice_datamode_ssmi_mod.F90 b/CDEPS-interface/CDEPS/dice/dice_datamode_ssmi_mod.F90 new file mode 100644 index 0000000000..79c4ac3725 --- /dev/null +++ b/CDEPS-interface/CDEPS/dice/dice_datamode_ssmi_mod.F90 @@ -0,0 +1,612 @@ +module dice_datamode_ssmi_mod + + use ESMF , only : ESMF_State, ESMF_LogWrite, ESMF_Array, ESMF_MeshGet + use ESMF , only : ESMF_SUCCESS, ESMF_LOGMSG_INFO, ESMF_DistGrid + use ESMF , only : ESMF_ArrayCreate, ESMF_ArrayDestroy, ESMF_GridComp + use NUOPC , only : NUOPC_Advertise + use shr_kind_mod , only : r8=>shr_kind_r8, i8=>shr_kind_i8, cl=>shr_kind_cl, cs=>shr_kind_cs + use shr_sys_mod , only : shr_sys_abort + use shr_const_mod , only : shr_const_pi, shr_const_spval, shr_const_tkfrz, shr_const_latice + use shr_frz_mod , only : shr_frz_freezetemp + use dshr_strdata_mod , only : shr_strdata_get_stream_pointer, shr_strdata_type + use dshr_methods_mod , only : dshr_state_getfldptr, dshr_fldbun_getfldptr, dshr_fldbun_regrid, chkerr + use dshr_mod , only : dshr_restart_read, dshr_restart_write + use dice_flux_atmice_mod , only : dice_flux_atmice + use dshr_fldlist_mod , only : fldlist_type, dshr_fldlist_add + + implicit none + private ! except + + public :: dice_datamode_ssmi_advertise + public :: dice_datamode_ssmi_init_pointers + public :: dice_datamode_ssmi_advance + public :: dice_datamode_ssmi_restart_write + public :: dice_datamode_ssmi_restart_read + + ! restart fields + real(r8), pointer, public :: water(:) => null() + + ! internal fields + real(r8), pointer :: yc(:) => null() ! mesh lats (degrees) + integer , pointer :: imask(:) => null() + !real(r8), pointer:: ifrac0(:) => null() + + ! export fields + real(r8), pointer :: Si_imask(:) => null() + real(r8), pointer :: Si_ifrac(:) => null() + real(r8), pointer :: Si_t(:) => null() + real(r8), pointer :: Si_tref(:) => null() + real(r8), pointer :: Si_qref(:) => null() + real(r8), pointer :: Si_avsdr(:) => null() + real(r8), pointer :: Si_anidr(:) => null() + real(r8), pointer :: Si_avsdf(:) => null() + real(r8), pointer :: Si_anidf(:) => null() + real(r8), pointer :: Faii_swnet(:) => null() + real(r8), pointer :: Faii_sen(:) => null() + real(r8), pointer :: Faii_lat(:) => null() + real(r8), pointer :: Faii_lwup(:) => null() + real(r8), pointer :: Faii_evap(:) => null() + real(r8), pointer :: Faii_taux(:) => null() + real(r8), pointer :: Faii_tauy(:) => null() + real(r8), pointer :: Fioi_melth(:) => null() + real(r8), pointer :: Fioi_meltw(:) => null() + real(r8), pointer :: Fioi_swpen(:) => null() + real(r8), pointer :: Fioi_taux(:) => null() + real(r8), pointer :: Fioi_tauy(:) => null() + real(r8), pointer :: Fioi_salt(:) => null() + real(r8), pointer :: Fioi_bcpho(:) => null() + real(r8), pointer :: Fioi_bcphi(:) => null() + real(r8), pointer :: Fioi_flxdst(:) => null() + real(r8), pointer :: Si_ifrac_n(:,:) => null() + real(r8), pointer :: Fioi_swpen_ifrac_n(:,:) => null() + + ! import fields + real(r8), pointer :: Faxa_swvdr(:) => null() + real(r8), pointer :: Faxa_swvdf(:) => null() + real(r8), pointer :: Faxa_swndr(:) => null() + real(r8), pointer :: Faxa_swndf(:) => null() + real(r8), pointer :: Fioo_q(:) => null() + real(r8), pointer :: Sa_z(:) => null() + real(r8), pointer :: Sa_u(:) => null() + real(r8), pointer :: Sa_v(:) => null() + real(r8), pointer :: Sa_ptem(:) => null() + real(r8), pointer :: Sa_shum(:) => null() + real(r8), pointer :: Sa_dens(:) => null() + real(r8), pointer :: Sa_tbot(:) => null() + real(r8), pointer :: So_s(:) => null() + real(r8), pointer :: Faxa_bcph(:,:) => null() + real(r8), pointer :: Faxa_ocph(:,:) => null() + real(r8), pointer :: Faxa_dstdry(:,:) => null() + real(r8), pointer :: Faxa_dstwet(:,:) => null() + + ! surface albedo constants + real(r8) , parameter :: snwfrac = 0.286_r8 ! snow cover fraction ~ [0,1] + real(r8) , parameter :: as_nidf = 0.950_r8 ! albedo: snow,near-infr,diffuse + real(r8) , parameter :: as_vsdf = 0.700_r8 ! albedo: snow,visible ,diffuse + real(r8) , parameter :: as_nidr = 0.960_r8 ! albedo: snow,near-infr,direct + real(r8) , parameter :: as_vsdr = 0.800_r8 ! albedo: snow,visible ,direct + real(r8) , parameter :: ai_nidf = 0.700_r8 ! albedo: ice, near-infr,diffuse + real(r8) , parameter :: ai_vsdf = 0.500_r8 ! albedo: ice, visible ,diffuse + real(r8) , parameter :: ai_nidr = 0.700_r8 ! albedo: ice, near-infr,direct + real(r8) , parameter :: ai_vsdr = 0.500_r8 ! albedo: ice, visible ,direct + real(r8) , parameter :: ax_nidf = ai_nidf*(1.0_r8-snwfrac) + as_nidf*snwfrac + real(r8) , parameter :: ax_vsdf = ai_vsdf*(1.0_r8-snwfrac) + as_vsdf*snwfrac + real(r8) , parameter :: ax_nidr = ai_nidr*(1.0_r8-snwfrac) + as_nidr*snwfrac + real(r8) , parameter :: ax_vsdr = ai_vsdr*(1.0_r8-snwfrac) + as_vsdr*snwfrac + + ! other parameters + real(r8) , parameter :: pi = shr_const_pi ! pi + real(r8) , parameter :: spval = shr_const_spval ! flags invalid data + real(r8) , parameter :: tFrz = shr_const_tkfrz ! temp of freezing + real(r8) , parameter :: latice = shr_const_latice ! latent heat of fusion + real(r8) , parameter :: waterMax = 1000.0_r8 ! wrt iFrac comp & frazil ice (kg/m^2) + + character(*) , parameter :: nullstr = 'null' + character(*) , parameter :: u_FILE_u = & + __FILE__ + +!=============================================================================== +contains +!=============================================================================== + + subroutine dice_datamode_ssmi_advertise(importState, exportState, fldsimport, fldsexport, & + flds_scalar_name, flds_i2o_per_cat, rc) + + ! -------------------------------------------------------------- + ! determine export and import fields to advertise to mediator + ! -------------------------------------------------------------- + + ! input/output arguments + type(ESMF_State) , intent(inout) :: importState + type(ESMF_State) , intent(inout) :: exportState + type(fldlist_type) , pointer :: fldsimport + type(fldlist_type) , pointer :: fldsexport + character(len=*) , intent(in) :: flds_scalar_name + logical , intent(in) :: flds_i2o_per_cat ! .true. if select per ice thickness + integer , intent(out) :: rc + + ! local variables + type(fldlist_type), pointer :: fldList + !------------------------------------------------------------------------------- + + ! Advertise export fields + call dshr_fldList_add(fldsExport , trim(flds_scalar_name)) + call dshr_fldList_add(fldsExport ,'Si_ifrac' ) + call dshr_fldList_add(fldsExport ,'Si_imask' ) + call dshr_fldList_add(fldsExport ,'Si_t' ) + call dshr_fldList_add(fldsExport ,'Si_tref' ) + call dshr_fldList_add(fldsExport ,'Si_qref' ) + call dshr_fldList_add(fldsExport ,'Si_avsdr' ) + call dshr_fldList_add(fldsExport ,'Si_anidr' ) + call dshr_fldList_add(fldsExport ,'Si_avsdf' ) + call dshr_fldList_add(fldsExport ,'Si_anidf' ) + call dshr_fldList_add(fldsExport ,'Faii_swnet' ) + call dshr_fldList_add(fldsExport ,'Faii_sen' ) + call dshr_fldList_add(fldsExport ,'Faii_lat' ) + call dshr_fldList_add(fldsExport ,'Faii_lwup' ) + call dshr_fldList_add(fldsExport ,'Faii_evap' ) + call dshr_fldList_add(fldsExport ,'Faii_taux' ) + call dshr_fldList_add(fldsExport ,'Faii_tauy' ) + call dshr_fldList_add(fldsExport ,'Fioi_melth' ) + call dshr_fldList_add(fldsExport ,'Fioi_meltw' ) + call dshr_fldList_add(fldsExport ,'Fioi_swpen' ) + call dshr_fldList_add(fldsExport ,'Fioi_taux' ) + call dshr_fldList_add(fldsExport ,'Fioi_tauy' ) + call dshr_fldList_add(fldsExport ,'Fioi_salt' ) + call dshr_fldList_add(fldsExport ,'Fioi_bcpho' ) + call dshr_fldList_add(fldsExport ,'Fioi_bcphi' ) + call dshr_fldList_add(fldsExport ,'Fioi_flxdst' ) + if (flds_i2o_per_cat) then + call dshr_fldList_add(fldsExport, 'Si_ifrac_n' , ungridded_lbound=1, ungridded_ubound=1) + call dshr_fldList_add(fldsExport, 'Fioi_swpen_ifrac_n', ungridded_lbound=1, ungridded_ubound=1) + end if + + ! Advertise import fields + call dshr_fldList_add(fldsImport , trim(flds_scalar_name)) + call dshr_fldList_add(fldsImport, 'Faxa_swvdr' ) + call dshr_fldList_add(fldsImport, 'Faxa_swvdf' ) + call dshr_fldList_add(fldsImport, 'Faxa_swndr' ) + call dshr_fldList_add(fldsImport, 'Faxa_swndf' ) + call dshr_fldList_add(fldsImport, 'Fioo_q' ) + call dshr_fldList_add(fldsImport, 'Sa_z' ) + call dshr_fldList_add(fldsImport, 'Sa_u' ) + call dshr_fldList_add(fldsImport, 'Sa_v' ) + call dshr_fldList_add(fldsImport, 'Sa_ptem' ) + call dshr_fldList_add(fldsImport, 'Sa_shum' ) + call dshr_fldList_add(fldsImport, 'Sa_dens' ) + call dshr_fldList_add(fldsImport, 'Sa_tbot' ) + call dshr_fldList_add(fldsImport, 'So_s' ) + call dshr_fldList_add(fldsImport, 'Faxa_bcph' , ungridded_lbound=1, ungridded_ubound=3) + call dshr_fldList_add(fldsImport, 'Faxa_ocph' , ungridded_lbound=1, ungridded_ubound=3) + call dshr_fldList_add(fldsImport, 'Faxa_dstdry', ungridded_lbound=1, ungridded_ubound=4) + call dshr_fldList_add(fldsImport, 'Faxa_dstwet', ungridded_lbound=1, ungridded_ubound=4) + + fldlist => fldsExport ! the head of the linked list + do while (associated(fldlist)) + call NUOPC_Advertise(exportState, standardName=fldlist%stdname, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_LogWrite('(dice_comp_advertise): Fr_ice'//trim(fldList%stdname), ESMF_LOGMSG_INFO) + fldList => fldList%next + enddo + + fldlist => fldsImport ! the head of the linked list + do while (associated(fldlist)) + call NUOPC_Advertise(importState, standardName=fldlist%stdname, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_LogWrite('(dice_comp_advertise): Fr_ice'//trim(fldList%stdname), ESMF_LOGMSG_INFO) + fldList => fldList%next + enddo + + end subroutine dice_datamode_ssmi_advertise + + !=============================================================================== + subroutine dice_datamode_ssmi_init_pointers(importState, exportState, sdat, flds_i2o_per_cat, rc) + + ! input/output variables + type(ESMF_State) , intent(inout) :: importState + type(ESMF_State) , intent(inout) :: exportState + type(shr_strdata_type) , intent(in) :: sdat + logical , intent(in) :: flds_i2o_per_cat ! .true. if select per ice thickness + integer , intent(out) :: rc + + ! local variables + integer :: n + integer :: lsize + type(ESMF_DistGrid) :: distGrid + type(ESMF_Array) :: elemMaskArray + integer :: spatialDim ! number of dimension in mesh + integer :: numOwnedElements ! size of mesh + real(r8), pointer :: ownedElemCoords(:) ! mesh lat and lons + character(len=*), parameter :: subname='(dice_init_pointers): ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + lsize = sdat%model_lsize + + ! Set Si_imask (this corresponds to the ocean mask) + call dshr_state_getfldptr(exportState, fldname='Si_imask' , fldptr1=Si_imask , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + allocate(imask(sdat%model_lsize)) + call ESMF_MeshGet(sdat%model_mesh, numOwnedElements=numOwnedElements, elementdistGrid=distGrid, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + elemMaskArray = ESMF_ArrayCreate(distGrid, imask, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_MeshGet(sdat%model_mesh, elemMaskArray=elemMaskArray, rc=rc) ! set the varues of imask + if (ChkErr(rc,__LINE__,u_FILE_u)) return + Si_imask(:) = real(imask(:), kind=r8) ! set the mask as real + call ESMF_ArrayDestroy(elemMaskArray, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! Set export state module pointers + call dshr_state_getfldptr(exportState, fldname='Si_ifrac' , fldptr1=Si_ifrac , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, fldname='Si_t' , fldptr1=Si_t , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, fldname='Si_tref' , fldptr1=Si_tref , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, fldname='Si_qref' , fldptr1=Si_qref , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, fldname='Si_avsdr' , fldptr1=Si_avsdr , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, fldname='Si_anidr' , fldptr1=Si_anidr , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, fldname='Si_avsdf' , fldptr1=Si_avsdf , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, fldname='Si_anidf' , fldptr1=Si_anidf , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, fldname='Faii_swnet' , fldptr1=Faii_swnet , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, fldname='Faii_sen' , fldptr1=Faii_sen , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, fldname='Faii_lat' , fldptr1=Faii_lat , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, fldname='Faii_lwup' , fldptr1=Faii_lwup , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, fldname='Faii_evap' , fldptr1=Faii_evap , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, fldname='Faii_taux' , fldptr1=Faii_taux , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, fldname='Faii_tauy' , fldptr1=Faii_tauy , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, fldname='Fioi_melth' , fldptr1=Fioi_melth , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, fldname='Fioi_meltw' , fldptr1=Fioi_meltw , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, fldname='Fioi_swpen' , fldptr1=Fioi_swpen , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, fldname='Fioi_taux' , fldptr1=Fioi_taux , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, fldname='Fioi_tauy' , fldptr1=Fioi_tauy , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, fldname='Fioi_salt' , fldptr1=Fioi_salt , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, fldname='Fioi_bcpho' , fldptr1=Fioi_bcpho , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, fldname='Fioi_bcphi' , fldptr1=Fioi_bcphi , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, fldname='Fioi_flxdst' , fldptr1=Fioi_flxdst , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + if (flds_i2o_per_cat) then + call dshr_state_getfldptr(exportState, fldname='Si_ifrac_n', fldptr2=Si_ifrac_n, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, fldname='Fioi_swpen_ifrac_n', fldptr2=Fioi_swpen_ifrac_n, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + end if + + ! Set pointers to importState fields + call dshr_state_getfldptr(importState, fldname='Faxa_swvdr' , fldptr1=Faxa_swvdr , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(importState, fldname='Faxa_swvdf' , fldptr1=Faxa_swvdf , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(importState, fldname='Faxa_swndr' , fldptr1=Faxa_swndr , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(importState, fldname='Faxa_swndf' , fldptr1=Faxa_swndf , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(importState, fldname='Faxa_bcph' , fldptr2=Faxa_bcph , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(importState, fldname='Faxa_ocph' , fldptr2=Faxa_ocph , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(importState, fldname='Faxa_dstdry' , fldptr2=Faxa_dstdry , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(importState, fldname='Faxa_dstwet' , fldptr2=Faxa_dstwet , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(importState, fldname='Fioo_q' , fldptr1=Fioo_q , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(importState, fldname='Sa_z' , fldptr1=Sa_z , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(importState, fldname='Sa_u' , fldptr1=Sa_u , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(importState, fldname='Sa_v' , fldptr1=Sa_v , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(importState, fldname='Sa_ptem' , fldptr1=Sa_ptem , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(importState, fldname='Sa_tbot' , fldptr1=Sa_tbot , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(importState, fldname='Sa_shum' , fldptr1=Sa_shum , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(importState, fldname='Sa_dens' , fldptr1=Sa_dens , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(importState, fldname='So_s' , fldptr1=So_s , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + + ! initialize import arrays + ! used for the first use in generating the export state and should have no impact on the solution + Faxa_swvdr(:) = 0._r8 + Faxa_swvdf(:) = 0._r8 + Faxa_swndr(:) = 0._r8 + Faxa_swndf(:) = 0._r8 + Faxa_bcph(:,:) = 0._r8 + Faxa_ocph(:,:) = 0._r8 + Faxa_dstdry(:,:) = 0._r8 + Faxa_dstwet(:,:) = 0._r8 + Fioo_q(:) = 0._r8 + Sa_z(:) = 10.0_r8 + Sa_u(:) = 5.0_r8 + Sa_v(:) = 5.0_r8 + Sa_ptem(:) = 260.0_r8 + Sa_tbot(:) = 260.0_r8 + Sa_shum(:) = 0.0014_r8 + Sa_dens(:) = 1.3_r8 + So_s(:) = 0._r8 + + ! Determine water from restart if needed + ! allocate module arrays that are not part of import and export state + + ! Determine model latitudes + allocate(yc(lsize)) + call ESMF_MeshGet(sdat%model_mesh, spatialDim=spatialDim, numOwnedElements=numOwnedElements, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + allocate(ownedElemCoords(spatialDim*numOwnedElements)) + call ESMF_MeshGet(sdat%model_mesh, ownedElemCoords=ownedElemCoords) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + do n = 1,numOwnedElements + yc(n) = ownedElemCoords(2*n) + end do + deallocate(ownedElemCoords) + + end subroutine dice_datamode_ssmi_init_pointers + + !=============================================================================== + subroutine dice_datamode_ssmi_advance(exportState, importState, cosarg, flds_i2o_per_cat, & + flux_swpf, flux_Qmin, flux_Qacc, flux_Qacc0, dt, logunit, restart_read, rc) + + ! input/output variables + type(ESMF_State) , intent(inout) :: exportState + type(ESMF_State) , intent(inout) :: importState + real(r8) , intent(in) :: cosarg ! for setting ice temp pattern + logical , intent(in) :: flds_i2o_per_cat + real(r8) , intent(in) :: flux_swpf ! short-wave penatration factor + real(r8) , intent(in) :: flux_Qmin ! bound on melt rate + logical , intent(in) :: flux_Qacc ! activates water accumulation/melt wrt Q + real(r8) , intent(in) :: flux_Qacc0 ! initial water accumulation value + real(r8) , intent(in) :: dt + integer , intent(in) :: logunit + logical , intent(in) :: restart_read + integer , intent(out) :: rc + + ! local variables + logical :: first_time = .true. + integer :: n + integer :: lsize + real(r8) :: qmeltall ! q that would melt all accumulated water + real(r8), allocatable :: tfreeze(:) + character(len=*), parameter :: subname='(dice_datamode_ssmi_advance): ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + lsize = size(Si_ifrac) + + if (first_time) then + + ! initialize water(n) + if (.not. restart_read) then + ! Note that if restart is read, water is allocated before + ! the call to this routine in docn_datamode_ssmi_restart_read + allocate(water(lsize)) + do n = 1,lsize + if (Si_ifrac(n) > 0.0_r8) then + water(n) = flux_Qacc0 + else + water(n) = 0.0_r8 + end if + end do + ! iFrac0 = iFrac ! previous step's ice fraction + endif + + ! reset first time + first_time = .false. + end if + + allocate(tfreeze(lsize)) + do n = 1,lsize + !--- convert to Kelvin + tfreeze(n) = shr_frz_freezetemp(So_s(n)) + tFrz + + !--- fix erroneous iFrac --- + Si_ifrac(n) = min(1.0_r8,max(0.0_r8,Si_ifrac(n))) + + !--- fabricate ice surface T, fix erroneous iFrac --- + if ( yc(n) > 0.0_r8) then + Si_t(n) = 260.0_r8 + 10.0_r8*cos(cosArg) + else + Si_t(n) = 260.0_r8 - 10.0_r8*cos(cosArg) + end if + + !--- set albedos (constant) --- + Si_avsdr(n) = ax_vsdr + Si_anidr(n) = ax_nidr + Si_avsdf(n) = ax_vsdf + Si_anidf(n) = ax_nidf + + !--- swnet is sent to cpl as a diagnostic quantity only --- + !--- newly recv'd swdn goes with previously sent albedo --- + !--- but albedos are (currently) time invariant --- + Faii_swnet(n) = (1.0_r8 - Si_avsdr(n))*Faxa_swvdr(n) & + + (1.0_r8 - Si_anidr(n))*Faxa_swndr(n) & + + (1.0_r8 - Si_avsdf(n))*Faxa_swvdf(n) & + + (1.0_r8 - Si_anidf(n))*Faxa_swndf(n) + + !--- compute melt/freeze water balance, adjust iFrac ------------- + if ( .not. flux_Qacc ) then ! Q accumulation option is OFF + Fioi_melth(n) = min(Fioo_q(n),0.0_r8 ) ! q<0 => melt potential + Fioi_melth(n) = max(Fioi_melth(n),Flux_Qmin ) ! limit the melt rate + Fioi_meltw(n) = -Fioi_melth(n)/latice ! corresponding water flux + + else ! Q accumulation option is ON + !-------------------------------------------------------------- + ! 1a) Q<0 & iFrac > 0 => infinite supply of water to melt + ! 1b) Q<0 & iFrac = 0 => melt accumulated water only + ! 2a) Q>0 & iFrac > 0 => zero-out accumulated water + ! 2b) Q>0 & iFrac = 0 => accumulated water + !-------------------------------------------------------------- + + if ( Fioo_q(n) < 0.0_r8 ) then ! Q<0 => melt + if (Si_ifrac(n) > 0.0_r8 ) then + Fioi_melth(n) = Si_ifrac(n)*max(Fioo_q(n),Flux_Qmin) + Fioi_meltw(n) = -Fioi_melth(n)/latice + ! water(n) = < don't change this value > + else + Qmeltall = -water(n)*latice/dt + Fioi_melth(n) = max(Fioo_q(n), Qmeltall, Flux_Qmin ) + Fioi_meltw(n) = -Fioi_melth(n)/latice + water(n) = water(n) - Fioi_meltw(n)*dt + end if + else ! Q>0 => freeze + if (Si_ifrac(n) > 0.0_r8 ) then + Fioi_melth(n) = 0.0_r8 + Fioi_meltw(n) = 0.0_r8 + water(n) = 0.0_r8 + else + Fioi_melth(n) = 0.0_r8 + Fioi_meltw(n) = 0.0_r8 + water(n) = water(n) + dt*Fioo_q(n)/latice + end if + end if + + if (water(n) < 1.0e-16_r8 ) water(n) = 0.0_r8 + + !--- non-zero water => non-zero iFrac --- + if (Si_ifrac(n) <= 0.0_r8 .and. water(n) > 0.0_r8) then + Si_ifrac(n) = min(1.0_r8,water(n)/waterMax) + ! Si_t(n) = tfreeze(n) ! T can be above freezing?!? + end if + + !--- cpl multiplies Fioi_melth & Fioi_meltw by iFrac --- + !--- divide by iFrac here => fixed quantity flux (not per area) --- + if (Si_ifrac(n) > 0.0_r8) then + Si_ifrac(n) = max( 0.01_r8, Si_ifrac(n)) ! min iFrac + Fioi_melth(n) = Fioi_melth(n)/Si_ifrac(n) + Fioi_meltw(n) = Fioi_meltw(n)/Si_ifrac(n) + else + Fioi_melth(n) = 0.0_r8 + Fioi_meltw(n) = 0.0_r8 + end if + end if + + !--- modify T wrt iFrac: (iFrac -> 0) => (T -> tfreeze) --- + Si_t(n) = tfreeze(n) + Si_ifrac(n)*(Si_t(n)-tfreeze(n)) + end do + + ! compute ice/ice surface fluxes + call dice_flux_atmice( & + imask ,Sa_z ,Sa_u ,Sa_v , & + Sa_ptem ,Sa_shum ,Sa_dens ,Sa_tbot , & + Si_t ,Faii_sen ,Faii_lat ,Faii_lwup, & + Faii_evap ,Faii_taux ,Faii_tauy ,Si_tref , & + Si_qref ,logunit ) + + ! compute ice/oce surface fluxes (except melth & meltw, see above) + do n=1,lsize + if (imask(n) == 0) then + Fioi_swpen(n) = spval + Fioi_melth(n) = spval + Fioi_meltw(n) = spval + Fioi_salt (n) = spval + Fioi_taux(n) = spval + Fioi_tauy(n) = spval + Si_ifrac(n) = 0.0_r8 + else + !--- penetrating short wave --- + Fioi_swpen(n) = max(0.0_r8, flux_swpf*Faii_swnet(n) ) ! must be non-negative + + !--- i/o surface stress ( = atm/ice stress) --- + Fioi_taux(n) = Faii_taux(n) + Fioi_tauy(n) = Faii_tauy(n) + + !--- salt flux --- + Fioi_salt(n) = 0.0_r8 + end if + ! !--- save ifrac for next timestep + ! iFrac0(n) = Si_ifrac(n) + end do + + ! Compute outgoing aerosol fluxes + do n = 1,lsize + Fioi_bcpho(n) = Faxa_bcph(2,n) + Fioi_bcphi(n) = Faxa_bcph(1,n) + Faxa_bcph(3,n) + Fioi_flxdst(n) = Faxa_dstdry(1,n) + Faxa_dstwet(1,n) + Faxa_dstdry(2,n) + Faxa_dstwet(2,n) & + + Faxa_dstdry(3,n) + Faxa_dstwet(3,n) + Faxa_dstdry(4,n) + Faxa_dstwet(4,n) + end do + + ! optional per thickness category fields + if (flds_i2o_per_cat) then + do n = 1,lsize + Si_iFrac_n(1,n) = Si_ifrac(n) + Fioi_swpen_iFrac_n(1,n) = Fioi_swpen(n) * Si_ifrac(n) + end do + end if + + ! Reset first_time + first_time = .false. + + deallocate(tfreeze) + + end subroutine dice_datamode_ssmi_advance + + !=============================================================================== + subroutine dice_datamode_ssmi_restart_write(rpfile, case_name, inst_suffix, ymd, tod, & + logunit, my_task, sdat) + + ! input/output variables + character(len=*) , intent(in) :: rpfile + character(len=*) , intent(in) :: case_name + character(len=*) , intent(in) :: inst_suffix + integer , intent(in) :: ymd ! model date + integer , intent(in) :: tod ! model sec into model date + integer , intent(in) :: logunit + integer , intent(in) :: my_task + type(shr_strdata_type) , intent(inout) :: sdat + !------------------------------------------------------------------------------- + integer :: rc + call dshr_restart_write(rpfile, case_name, 'dice', inst_suffix, ymd, tod, & + logunit, my_task, sdat, rc, fld=water, fldname='water') + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + end subroutine dice_datamode_ssmi_restart_write + + !=============================================================================== + subroutine dice_datamode_ssmi_restart_read(gcomp, rest_filem, rpfile, logunit, my_task, mpicom, sdat) + + ! input/output arguments + type(ESMF_GridComp) , intent(in) :: gcomp + character(len=*) , intent(inout) :: rest_filem + character(len=*) , intent(in) :: rpfile + integer , intent(in) :: logunit + integer , intent(in) :: my_task + integer , intent(in) :: mpicom + type(shr_strdata_type) , intent(inout) :: sdat + !------------------------------------------------------------------------------- + integer :: rc + ! allocate module memory for restart fields that are read in + allocate(water(sdat%model_lsize)) + + ! read restart + call dshr_restart_read(rest_filem, rpfile, logunit, my_task, mpicom, sdat, rc,& + fld=water, fldname='water') + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + end subroutine dice_datamode_ssmi_restart_read + +end module dice_datamode_ssmi_mod diff --git a/CDEPS-interface/CDEPS/dice/dice_flux_atmice_mod.F90 b/CDEPS-interface/CDEPS/dice/dice_flux_atmice_mod.F90 new file mode 100644 index 0000000000..4d660765bc --- /dev/null +++ b/CDEPS-interface/CDEPS/dice/dice_flux_atmice_mod.F90 @@ -0,0 +1,270 @@ +module dice_flux_atmice_mod + + use shr_kind_mod, only : r8=>shr_kind_r8, cxx=>shr_kind_cxx, cl=>shr_kind_cl, cs=>shr_kind_cs + ! shared constants + use shr_const_mod, only : loc_zvir => shr_const_zvir, loc_cpdair => shr_const_cpdair + use shr_const_mod, only : loc_cpvir => shr_const_cpvir, loc_karman => shr_const_karman + use shr_const_mod, only : loc_g => shr_const_g, loc_latvap => shr_const_latvap + use shr_const_mod, only : loc_latice => shr_const_latice, loc_stebol => shr_const_stebol + use shr_const_mod, only : spval => shr_const_spval + implicit none + + integer,parameter :: dbug = 0 ! internal debug level + +!=============================================================================== +contains +!=============================================================================== + + subroutine dice_flux_atmice( & + mask ,zbot ,ubot ,vbot ,thbot, & + qbot ,rbot ,tbot ,ts ,sen, & + lat ,lwup ,evap ,taux ,tauy, & + tref ,qref ,logunit ) + + !------------------------------------------------------------------------------- + ! PURPOSE: + ! using atm & ice state variables, compute atm/ice fluxes + ! and diagnostic 10m air temperature and humidity + ! + ! NOTE: + ! o all fluxes are positive downward + ! o net heat flux = net sw + lw up + lw down + sen + lat + ! o here, tstar = /U*, and qstar = /U*. + ! o wind speeds should all be above a minimum speed (eg. 1.0 m/s) + ! + ! ASSUME: + ! o The saturation humidity of air at T(K): qsat(T) (kg/m^3) + !------------------------------------------------------------------------------- + + !--- input arguments -------------------------------- + integer ,intent(in) :: mask (:) ! 0 <=> cell NOT in model domain + real(R8) ,intent(in) :: zbot (:) ! atm level height (m) + real(R8) ,intent(in) :: ubot (:) ! atm u wind (m/s) + real(R8) ,intent(in) :: vbot (:) ! atm v wind (m/s) + real(R8) ,intent(in) :: thbot(:) ! atm potential T (K) + real(R8) ,intent(in) :: qbot (:) ! atm specific humidity (kg/kg) + real(R8) ,intent(in) :: rbot (:) ! atm air density (kg/m^3) + real(R8) ,intent(in) :: tbot (:) ! atm T (K) + real(R8) ,intent(in) :: ts (:) ! surface temperature + integer ,intent(in) :: logunit ! logging unit number + + !--- output arguments ------------------------------- + real(R8) ,intent(out) :: sen (:) ! sensible heat flux (W/m^2) + real(R8) ,intent(out) :: lat (:) ! latent heat flux (W/m^2) + real(R8) ,intent(out) :: lwup (:) ! long-wave upward heat flux (W/m^2) + real(R8) ,intent(out) :: evap (:) ! evaporative water flux ((kg/s)/m^2) + real(R8) ,intent(out) :: taux (:) ! x surface stress (N) + real(R8) ,intent(out) :: tauy (:) ! y surface stress (N) + real(R8) ,intent(out) :: tref (:) ! 2m reference height temperature + real(R8) ,intent(out) :: qref (:) ! 2m reference height humidity + + !--- local constants -------------------------------- + real(R8),parameter :: umin = 1.0_R8 ! minimum wind speed (m/s) + real(R8),parameter :: zref = 10.0_R8 ! ref height ~ m + real(R8),parameter :: ztref = 2.0_R8 ! ref height for air T ~ m + real(R8),parameter :: zzsice = 0.0005_R8 ! ice surface roughness + + !--- local variables -------------------------------- + integer :: lsize ! array dimensions + integer :: n ! array indicies + real(R8) :: vmag ! surface wind magnitude (m/s) + real(R8) :: thvbot ! virtual temperature (K) + real(R8) :: ssq ! sea surface humidity (kg/kg) + real(R8) :: dssqdt ! derivative of ssq wrt Ts (kg/kg/K) + real(R8) :: delt ! potential T difference (K) + real(R8) :: delq ! humidity difference (kg/kg) + real(R8) :: stable ! stability factor + real(R8) :: rdn ! sqrt of neutral exchange coefficient (momentum) + real(R8) :: rhn ! sqrt of neutral exchange coefficient (heat) + real(R8) :: ren ! sqrt of neutral exchange coefficient (water) + real(R8) :: rd ! sqrt of exchange coefficient (momentum) + real(R8) :: rh ! sqrt of exchange coefficient (heat) + real(R8) :: re ! sqrt of exchange coefficient (water) + real(R8) :: ustar ! ustar + real(R8) :: qstar ! qstar + real(R8) :: tstar ! tstar + real(R8) :: hol ! H (at zbot) over L + real(R8) :: xsq ! temporary variable + real(R8) :: xqq ! temporary variable + real(R8) :: psimh ! stability function at zbot (momentum) + real(R8) :: psixh ! stability function at zbot (heat and water) + real(R8) :: alz ! ln(zbot/z10) + real(R8) :: ltheat ! latent heat for surface + real(R8) :: tau ! stress at zbot + real(R8) :: cp ! specific heat of moist air + + real(R8) :: bn ! exchange coef funct for interpolation + real(R8) :: bh ! exchange coef funct for interpolation + real(R8) :: fac ! interpolation factor + real(R8) :: ln0 ! log factor for interpolation + real(R8) :: ln3 ! log factor for interpolation + + !--- local functions -------------------------------- + real(R8) :: Tk ! temperature (K) + real(R8) :: qsat ! the saturation humidity of air (kg/m^3) + real(R8) :: dqsatdt ! derivative of qsat wrt surface temperature + real(R8) :: xd ! dummy argument + real(R8) :: psimhu ! unstable part of psimh + real(R8) :: psixhu ! unstable part of psimx + + qsat(Tk) = 627572.4_R8 / exp(5107.4_R8/Tk) + dqsatdt(Tk) = (5107.4_R8 / Tk**2) * 627572.4_R8 / exp(5107.4_R8/Tk) + psimhu(xd) = log((1.0_R8+xd*(2.0_R8+xd))*(1.0_R8+xd*xd)/8.0_R8) - 2.0_R8*atan(xd) + 1.571_R8 + psixhu(xd) = 2.0_R8 * log((1.0_R8 + xd*xd)/2.0_R8) + + !--- formats ---------------------------------------- + character(*),parameter :: F01 = "('(dice_flux_atmIce) ',a, i7,2x,d21.14)" + character(*),parameter :: subName = "(dice_flux_atmIce) " + !------------------------------------------------------------------------------- + + lsize = size(tbot) + + do n = 1,lsize + + if (mask(n) == 0) then + sen (n) = spval + lat (n) = spval + lwup (n) = spval + evap (n) = spval + taux (n) = spval + tauy (n) = spval + tref (n) = spval + qref (n) = spval + else + !--- define some needed variables --- + vmag = max(umin, sqrt(ubot(n)**2+vbot(n)**2)) + thvbot = thbot(n)*(1.0_R8 + loc_zvir * qbot(n)) ! virtual pot temp (K) + ssq = qsat (ts(n)) / rbot(n) ! sea surf hum (kg/kg) + dssqdt = dqsatdt(ts(n)) / rbot(n) ! deriv of ssq wrt Ts + delt = thbot(n) - ts(n) ! pot temp diff (K) + delq = qbot(n) - ssq ! spec hum dif (kg/kg) + alz = log(zbot(n)/zref) + cp = loc_cpdair*(1.0_R8 + loc_cpvir*ssq) + ltheat = loc_latvap + loc_latice + + !---------------------------------------------------------- + ! first estimate of Z/L and ustar, tstar and qstar + !---------------------------------------------------------- + + !--- neutral coefficients, z/L = 0.0 --- + rdn = loc_karman/log(zref/zzsice) + rhn = rdn + ren = rdn + + !--- ustar,tstar,qstar ---- + ustar = rdn * vmag + tstar = rhn * delt + qstar = ren * delq + + !--- compute stability & evaluate all stability functions --- + hol = loc_karman * loc_g * zbot(n) & + & * (tstar/thvbot+qstar/(1.0_R8/loc_zvir+qbot(n))) / ustar**2 + hol = sign( min(abs(hol),10.0_R8), hol ) + stable = 0.5_R8 + sign(0.5_R8 , hol) + xsq = max(sqrt(abs(1.0_R8 - 16.0_R8*hol)) , 1.0_R8) + xqq = sqrt(xsq) + psimh = -5.0_R8*hol*stable + (1.0_R8-stable)*psimhu(xqq) + psixh = -5.0_R8*hol*stable + (1.0_R8-stable)*psixhu(xqq) + + !--- shift all coeffs to measurement height and stability --- + rd = rdn / (1.0_R8+rdn/loc_karman*(alz-psimh)) + rh = rhn / (1.0_R8+rhn/loc_karman*(alz-psixh)) + re = ren / (1.0_R8+ren/loc_karman*(alz-psixh)) + + !--- update ustar, tstar, qstar w/ updated, shifted coeffs -- + ustar = rd * vmag + tstar = rh * delt + qstar = re * delq + + !---------------------------------------------------------- + ! iterate to converge on Z/L, ustar, tstar and qstar + !---------------------------------------------------------- + + !--- compute stability & evaluate all stability functions --- + hol = loc_karman * loc_g * zbot(n) & + & * (tstar/thvbot+qstar/(1.0_R8/loc_zvir+qbot(n))) / ustar**2 + hol = sign( min(abs(hol),10.0_R8), hol ) + stable = 0.5_R8 + sign(0.5_R8 , hol) + xsq = max(sqrt(abs(1.0_R8 - 16.0_R8*hol)) , 1.0_R8) + xqq = sqrt(xsq) + psimh = -5.0_R8*hol*stable + (1.0_R8-stable)*psimhu(xqq) + psixh = -5.0_R8*hol*stable + (1.0_R8-stable)*psixhu(xqq) + + !--- shift all coeffs to measurement height and stability --- + rd = rdn / (1.0_R8+rdn/loc_karman*(alz-psimh)) + rh = rhn / (1.0_R8+rhn/loc_karman*(alz-psixh)) + re = ren / (1.0_R8+ren/loc_karman*(alz-psixh)) + + !--- update ustar, tstar, qstar w/ updated, shifted coeffs -- + ustar = rd * vmag + tstar = rh * delt + qstar = re * delq + + !---------------------------------------------------------- + ! compute the fluxes + !---------------------------------------------------------- + + tau = rbot(n) * ustar * ustar + + !--- momentum flux --- + taux(n) = tau * ubot(n) / vmag + tauy(n) = tau * vbot(n) / vmag + + !--- heat flux --- + sen (n) = cp * tau * tstar / ustar + lat (n) = ltheat * tau * qstar / ustar + lwup(n) = -loc_stebol * ts(n)**4 + + !--- water flux --- + evap(n) = lat(n)/ltheat + + !---------------------------------------------------------- + ! compute diagnostic: 2m reference height temperature + !---------------------------------------------------------- + + !--- Compute function of exchange coefficients. Assume that + !--- cn = rdn*rdn, cm=rd*rd and ch=rh*rd, and therefore + !--- 1/sqrt(cn(n))=1/rdn and sqrt(cm(n))/ch(n)=1/rh + bn = loc_karman/rdn + bh = loc_karman/rh + + !--- Interpolation factor for stable and unstable cases + ln0 = log(1.0_R8 + (ztref/zbot(n))*(exp(bn) - 1.0_R8)) + ln3 = log(1.0_R8 + (ztref/zbot(n))*(exp(bn - bh) - 1.0_R8)) + fac = (ln0 - ztref/zbot(n)*(bn - bh))/bh * stable & + & + (ln0 - ln3)/bh * (1.0_R8-stable) + fac = min(max(fac,0.0_R8),1.0_R8) + + !--- actual interpolation + tref(n) = ts(n) + (tbot(n) - ts(n))*fac + qref(n) = qbot(n) - delq*fac + + endif + enddo + + if (dbug > 0) then + do n = 1,lsize + if (mask(n) /= 0) then + write(logunit, F01)'n,mask = ',n,mask(n) + write(logunit, F01)'n,zbot = ',n,zbot(n) + write(logunit, F01)'n,ubot = ',n,ubot(n) + write(logunit, F01)'n,vbot = ',n,vbot(n) + write(logunit, F01)'n,thbot = ',n,thbot(n) + write(logunit, F01)'n,qbot = ',n,qbot(n) + write(logunit, F01)'n,tbot = ',n,tbot(n) + write(logunit, F01)'n,ts = ',n,ts(n) + write(logunit, F01)'n,lat = ',n,lat(n) + write(logunit, F01)'n,sen = ',n,sen(n) + write(logunit, F01)'n,taux = ',n,taux(n) + write(logunit, F01)'n,taux = ',n,tauy(n) + write(logunit, F01)'n,lwup = ',n,lwup(n) + write(logunit, F01)'n,evap = ',n,evap(n) + write(logunit, F01)'n,tref = ',n,tref(n) + write(logunit, F01)'n,qref = ',n,qref(n) + end if + end do + end if + + end subroutine dice_flux_atmIce + +end module dice_flux_atmice_mod diff --git a/CDEPS-interface/CDEPS/dice/ice_comp_nuopc.F90 b/CDEPS-interface/CDEPS/dice/ice_comp_nuopc.F90 new file mode 100644 index 0000000000..62186f2c84 --- /dev/null +++ b/CDEPS-interface/CDEPS/dice/ice_comp_nuopc.F90 @@ -0,0 +1,667 @@ +#ifdef CESMCOUPLED +module ice_comp_nuopc +#else +module cdeps_dice_comp +#endif + + !---------------------------------------------------------------------------- + ! This is the NUOPC cap for DICE + !---------------------------------------------------------------------------- + + use ESMF , only : ESMF_VM, ESMF_VMBroadcast, ESMF_GridCompGet + use ESMF , only : ESMF_Mesh, ESMF_GridComp, ESMF_State, ESMF_Clock + use ESMF , only : ESMF_SUCCESS, ESMF_Time, ESMF_LogWrite, ESMF_LOGMSG_INFO + use ESMF , only : ESMF_TraceRegionEnter, ESMF_TraceRegionExit + use ESMF , only : ESMF_Alarm, ESMF_TimeInterval, ESMF_TimeIntervalGet + use ESMF , only : ESMF_AlarmIsRinging, ESMF_METHOD_INITIALIZE + use ESMF , only : ESMF_ClockGet, ESMF_TimeGet, ESMF_MethodRemove, ESMF_MethodAdd + use ESMF , only : ESMF_GridCompSetEntryPoint, operator(+), ESMF_AlarmRingerOff + use ESMF , only : ESMF_ClockGetAlarm, ESMF_StateGet, ESMF_Field, ESMF_FieldGet, ESMF_MAXSTR + use NUOPC , only : NUOPC_CompDerive, NUOPC_CompSetEntryPoint, NUOPC_CompSpecialize + use NUOPC , only : NUOPC_CompAttributeGet, NUOPC_Advertise + use NUOPC_Model , only : model_routine_SS => SetServices + use NUOPC_Model , only : model_label_Advance => label_Advance + use NUOPC_Model , only : model_label_SetRunClock => label_SetRunClock + use NUOPC_Model , only : model_label_Finalize => label_Finalize + use NUOPC_Model , only : NUOPC_ModelGet, SetVM + use shr_kind_mod , only : r8=>shr_kind_r8, cxx=>shr_kind_cxx, cl=>shr_kind_cl, cs=>shr_kind_cs + use shr_const_mod , only : shr_const_pi + use shr_log_mod , only : shr_log_setLogUnit + use shr_sys_mod , only : shr_sys_abort + use shr_cal_mod , only : shr_cal_ymd2date, shr_cal_ymd2julian + use dshr_mod , only : dshr_model_initphase, dshr_init, dshr_mesh_init, dshr_check_restart_alarm + use dshr_mod , only : dshr_state_setscalar, dshr_set_runclock, dshr_log_clock_advance + use dshr_methods_mod , only : dshr_state_diagnose, chkerr, memcheck + use dshr_strdata_mod , only : shr_strdata_type, shr_strdata_init_from_config, shr_strdata_advance + use dshr_dfield_mod , only : dfield_type, dshr_dfield_add, dshr_dfield_copy + use dshr_fldlist_mod , only : fldlist_type, dshr_fldlist_add, dshr_fldlist_realize + + use dice_datamode_ssmi_mod , only : dice_datamode_ssmi_advertise + use dice_datamode_ssmi_mod , only : dice_datamode_ssmi_init_pointers + use dice_datamode_ssmi_mod , only : dice_datamode_ssmi_advance + use dice_datamode_ssmi_mod , only : dice_datamode_ssmi_restart_read + use dice_datamode_ssmi_mod , only : dice_datamode_ssmi_restart_write + ! + use dice_datamode_cplhist_mod , only : dice_datamode_cplhist_advertise + use dice_datamode_cplhist_mod , only : dice_datamode_cplhist_init_pointers + use dice_datamode_cplhist_mod , only : dice_datamode_cplhist_advance + use dice_datamode_cplhist_mod , only : dice_datamode_cplhist_restart_read + use dice_datamode_cplhist_mod , only : dice_datamode_cplhist_restart_write + + implicit none + private ! except + + public :: SetServices + public :: SetVM + private :: InitializeAdvertise + private :: InitializeRealize + private :: ModelAdvance + private :: dice_comp_run + private :: ModelFinalize + + !-------------------------------------------------------------------------- + ! Module data + !-------------------------------------------------------------------------- + + type(shr_strdata_type) :: sdat + type(ESMF_Mesh) :: model_mesh + character(len=CS) :: flds_scalar_name = '' + integer :: flds_scalar_num = 0 + integer :: flds_scalar_index_nx = 0 + integer :: flds_scalar_index_ny = 0 + integer :: mpicom ! mpi communicator + integer :: my_task ! my task in mpi communicator mpicom + logical :: mainproc ! true of my_task == main_task + character(len=16) :: inst_suffix = "" ! char string associated with instance (ie. "_0001" or "") + integer :: logunit ! logging unit number + logical :: restart_read ! start from restart + character(CL) :: case_name ! case name + character(*) , parameter :: nullstr = 'null' + + ! dice_in namelist input + character(CL) :: streamfilename = nullstr ! filename to obtain stream info from + character(CL) :: nlfilename = nullstr ! filename to obtain namelist info from + character(CL) :: dataMode ! flags physics options wrt input data + character(CL) :: model_meshfile = nullstr ! full pathname to model meshfile + character(CL) :: model_maskfile = nullstr ! full pathname to obtain mask from + real(R8) :: flux_swpf ! short-wave penatration factor + real(R8) :: flux_Qmin ! bound on melt rate + logical :: flux_Qacc ! activates water accumulation/melt wrt Q + real(R8) :: flux_Qacc0 ! initial water accumulation value + character(CL) :: restfilm = nullstr ! model restart file namelist + integer :: nx_global + integer :: ny_global + logical :: export_all = .false. ! true => export all fields, do not check connected or not + + ! linked lists + type(fldList_type) , pointer :: fldsImport => null() + type(fldList_type) , pointer :: fldsExport => null() + type(dfield_type) , pointer :: dfields => null() + + ! model mask and model fraction + real(r8), pointer :: model_frac(:) => null() + integer , pointer :: model_mask(:) => null() + logical :: valid_ice = .true. ! used for single column logic (ocn mask > 0) + + ! constants + logical :: flds_i2o_per_cat ! .true. if select per ice thickness + real(R8) :: dt ! real model timestep + + logical :: diagnose_data = .true. + integer , parameter :: main_task=0 ! task number of main task +#ifdef CESMCOUPLED + character(*) , parameter :: modName = "(ice_comp_nuopc)" +#else + character(*) , parameter :: modName = "(cdeps_dice_comp)" +#endif + character(*) , parameter :: u_FILE_u = & + __FILE__ + +!=============================================================================== +contains +!=============================================================================== + + subroutine SetServices(gcomp, rc) + type(ESMF_GridComp) :: gcomp + integer, intent(out) :: rc + + ! Local varaibles + character(len=*),parameter :: subname=trim(modName)//':(SetServices) ' + !-------------------------------- + + rc = ESMF_SUCCESS + + ! the NUOPC gcomp component will register the generic methods + call NUOPC_CompDerive(gcomp, model_routine_SS, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! switching to IPD versions + call ESMF_GridCompSetEntryPoint(gcomp, ESMF_METHOD_INITIALIZE, & + userRoutine=dshr_model_initphase, phase=0, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! set entry point for methods that require specific implementation + call NUOPC_CompSetEntryPoint(gcomp, ESMF_METHOD_INITIALIZE, & + phaseLabelList=(/"IPDv01p1"/), userRoutine=InitializeAdvertise, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call NUOPC_CompSetEntryPoint(gcomp, ESMF_METHOD_INITIALIZE, & + phaseLabelList=(/"IPDv01p3"/), userRoutine=InitializeRealize, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! attach specializing method(s) + call NUOPC_CompSpecialize(gcomp, specLabel=model_label_Advance, specRoutine=ModelAdvance, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_MethodRemove(gcomp, label=model_label_SetRunClock, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call NUOPC_CompSpecialize(gcomp, specLabel=model_label_SetRunClock, specRoutine=dshr_set_runclock, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call NUOPC_CompSpecialize(gcomp, specLabel=model_label_Finalize, specRoutine=ModelFinalize, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + end subroutine SetServices + + !=============================================================================== + + subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) + use shr_nl_mod, only: shr_nl_find_group_name + + ! input/output variables + type(ESMF_GridComp) :: gcomp + type(ESMF_State) :: importState, exportState + type(ESMF_Clock) :: clock + integer, intent(out) :: rc + + ! local variables + integer :: inst_index ! number of current instance (ie. 1) + character(len=CL) :: cvalue ! temporary + integer :: nu ! unit number + integer :: ierr ! error code + integer :: bcasttmp(4) + real(r8) :: rbcasttmp(3) + type(ESMF_VM) :: vm + logical :: isPresent, isSet + character(len=*),parameter :: subname=trim(modName)//':(InitializeAdvertise) ' + character(*) ,parameter :: F00 = "('(" // trim(modName) // ") ',8a)" + character(*) ,parameter :: F01 = "('(" // trim(modName) // ") ',a,2x,i8)" + character(*) ,parameter :: F02 = "('(" // trim(modName) // ") ',a,l6)" + character(*) ,parameter :: F03 = "('(" // trim(modName) // ") ',a,d13.5)" + !------------------------------------------------------------------------------- + + namelist / dice_nml / datamode, & + model_meshfile, model_maskfile, & + restfilm, nx_global, ny_global, & + flux_swpf, flux_Qmin, flux_Qacc, flux_Qacc0, export_all + + rc = ESMF_SUCCESS + + call NUOPC_CompAttributeGet(gcomp, name='case_name', value=case_name, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! Obtain flds_scalar values, mpi values, multi-instance values and + ! set logunit and set shr logging to my log file + call dshr_init(gcomp, 'ICE', mpicom, my_task, inst_index, inst_suffix, & + flds_scalar_name, flds_scalar_num, flds_scalar_index_nx, flds_scalar_index_ny, & + logunit, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! determine logical mainproc + mainproc = (my_task == main_task) + + ! Read dice_nml from nlfilename + if (my_task == main_task) then + nlfilename = "dice_in"//trim(inst_suffix) + open (newunit=nu,file=trim(nlfilename),status="old",action="read") + call shr_nl_find_group_name(nu, 'dice_nml', status=ierr) + + read (nu,nml=dice_nml,iostat=ierr) + close(nu) + if (ierr > 0) then + write(logunit,*) 'ERROR: reading input namelist, '//trim(nlfilename)//' iostat=',ierr + call shr_sys_abort(subName//': namelist read error '//trim(nlfilename)) + end if + + ! write namelist input to standard out + write(logunit,F00)' datamode = ',trim(datamode) + write(logunit,F00)' model_meshfile = ',trim(model_meshfile) + write(logunit,F00)' model_maskfile = ',trim(model_maskfile) + write(logunit,F01)' nx_global = ',nx_global + write(logunit,F01)' ny_global = ',ny_global + write(logunit,F03)' flux_swpf = ',flux_swpf + write(logunit,F03)' flux_Qmin = ',flux_Qmin + write(logunit,F02)' flux_Qacc = ',flux_Qacc + write(logunit,F03)' flux_Qacc0 = ',flux_Qacc0 + write(logunit,F00)' restfilm = ',trim(restfilm) + write(logunit,F02)' export_all = ',export_all + bcasttmp = 0 + bcasttmp(1) = nx_global + bcasttmp(2) = ny_global + if(flux_Qacc) bcasttmp(3) = 1 + if(export_all) bcasttmp(4) = 1 + rbcasttmp(1) = flux_swpf + rbcasttmp(2) = flux_Qmin + rbcasttmp(3) = flux_Qacc0 + if(export_all) bcasttmp(4) = 1 + endif + + ! broadcast namelist input + call ESMF_GridCompGet(gcomp, vm=vm, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_VMBroadcast(vm, datamode, CL, main_task, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_VMBroadcast(vm, model_meshfile, CL, main_task, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_VMBroadcast(vm, model_maskfile, CL, main_task, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_VMBroadcast(vm, restfilm, CL, main_task, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_VMBroadcast(vm, bcasttmp, 4, main_task, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_VMBroadcast(vm, rbcasttmp, 3, main_task, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + nx_global = bcasttmp(1) + ny_global = bcasttmp(2) + flux_Qacc = (bcasttmp(3) == 1) + export_all= (bcasttmp(4) == 1) + + flux_swpf = rbcasttmp(1) + flux_Qmin = rbcasttmp(2) + flux_Qacc0 = rbcasttmp(3) + + ! Validate datamode + if ( trim(datamode) == 'ssmi' .or. trim(datamode) == 'ssmi_iaf' .or. trim(datamode) == 'cplhist') then + if (my_task == main_task) write(logunit,*) ' dice datamode = ',trim(datamode) + else + call shr_sys_abort(' ERROR illegal dice datamode = '//trim(datamode)) + endif + + ! Advertise import and export fields + if ( trim(datamode) == 'ssmi' .or. trim(datamode) == 'ssmi_iaf') then + call NUOPC_CompAttributeGet(gcomp, name='flds_i2o_per_cat', value=cvalue, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (isPresent .and. isSet) read(cvalue,*) flds_i2o_per_cat ! module variable + endif + + !datamode already validated + select case (trim(datamode)) + case('ssmi','ssmi_iaf') + call dice_datamode_ssmi_advertise(importState, exportState, fldsimport, fldsexport, & + flds_scalar_name, flds_i2o_per_cat, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + case('cplhist') + call dice_datamode_cplhist_advertise(exportState, fldsexport, flds_scalar_name, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end select + + end subroutine InitializeAdvertise + + !=============================================================================== + subroutine InitializeRealize(gcomp, importState, exportState, clock, rc) + + ! input/output variables + type(ESMF_GridComp) :: gcomp + type(ESMF_State) :: importState, exportState + type(ESMF_Clock) :: clock + integer, intent(out) :: rc + + ! local variables + type(ESMF_TimeInterval) :: TimeStep + type(ESMF_Time) :: currTime + integer :: current_ymd ! model date + integer :: current_year ! model year + integer :: current_mon ! model month + integer :: current_day ! model day + integer :: current_tod ! model sec into model date + real(R8) :: cosarg ! for setting ice temp pattern + real(R8) :: jday, jday0 ! elapsed day counters + integer :: model_dt ! integer model timestep + type(ESMF_Field) :: lfield + character(CL) ,pointer :: lfieldnamelist(:) => null() + integer :: fieldcount + real(r8), pointer :: fldptr(:) + integer :: n + character(len=*), parameter :: F00 = "('" // trim(modName) // ": ')',8a)" + character(len=*), parameter :: subname=trim(modName)//':(InitializeRealize) ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + ! Initialize mesh, restart flag, logunit + call ESMF_TraceRegionEnter('dice_strdata_init') + call dshr_mesh_init(gcomp, sdat, nullstr, logunit, 'ICE', nx_global, ny_global, & + model_meshfile, model_maskfile, model_mesh, model_mask, model_frac, restart_read, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! Initialize stream data type + streamfilename = 'dice.streams'//trim(inst_suffix) +#ifndef DISABLE_FoX + streamfilename = trim(streamfilename)//'.xml' +#endif + call shr_strdata_init_from_config(sdat, streamfilename, model_mesh, clock, 'ICE', logunit, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_TraceRegionExit('dice_strdata_init') + + ! NUOPC_Realize "realizes" a previously advertised field in the importState and exportState + ! by replacing the advertised fields with the newly created fields of the same name. + call dshr_fldlist_realize( exportState, fldsExport, flds_scalar_name, flds_scalar_num, model_mesh, & + subname//':diceExport', export_all, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_fldlist_realize( importState, fldsImport, flds_scalar_name, flds_scalar_num, model_mesh, & + subname//':diceImport', .false., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! for single column, the target point might not be a point where the ice/ocn mask is > 0 + if (size(model_frac) == 1 .and. model_frac(1) == 0._r8) then + valid_ice = .false. + call ESMF_StateGet(exportState, itemCount=fieldCount, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + allocate(lfieldnamelist(fieldCount)) + call ESMF_StateGet(exportState, itemNameList=lfieldnamelist, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + do n = 1, fieldCount + if (trim(lfieldnamelist(n)) /= flds_scalar_name) then + call ESMF_StateGet(exportState, itemName=trim(lfieldnamelist(n)), field=lfield, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call ESMF_FieldGet(lfield, farrayPtr=fldptr, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + fldptr(:) = 0._r8 + end if + enddo + deallocate(lfieldnamelist) + ! ******************* + ! *** RETURN HERE *** + ! ******************* + RETURN + end if + + ! Get the time to interpolate the stream data to + call ESMF_ClockGet(clock, currTime=currTime, timeStep=timeStep, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_TimeGet(currTime, yy=current_year, mm=current_mon, dd=current_day, s=current_tod, rc=rc ) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_cal_ymd2date(current_year, current_mon, current_day, current_ymd) + + ! Get model timestep + call ESMF_TimeIntervalGet( timeStep, s=model_dt, rc=rc ) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + dt = model_dt * 1.0_r8 + + ! Get cosarg + call shr_cal_ymd2julian(0, current_mon, current_day, current_tod, jDay , sdat%model_calendar) ! julian day for model + call shr_cal_ymd2julian(0, 9, 1, 0, jDay0, sdat%model_calendar) ! julian day for Sept 1 + cosArg = 2.0_R8*shr_const_pi*(jday - jday0)/365.0_R8 + + ! Run dice + call dice_comp_run(gcomp, importState, exportState, current_ymd, current_tod, cosarg, restart_write=.false., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! Add scalars to export state + call dshr_state_SetScalar(dble(nx_global), flds_scalar_index_nx, exportState, flds_scalar_name, flds_scalar_num, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_SetScalar(dble(ny_global), flds_scalar_index_ny, exportState, flds_scalar_name, flds_scalar_num, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + end subroutine InitializeRealize + + !=============================================================================== + subroutine ModelAdvance(gcomp, rc) + ! input/output variables + type(ESMF_GridComp) :: gcomp + integer, intent(out) :: rc + + ! local variables + type(ESMF_State) :: importState, exportState + type(ESMF_Clock) :: clock + type(ESMF_TimeInterval) :: timeStep + type(ESMF_Time) :: currTime, nextTime + real(R8) :: cosarg ! for setting ice temp pattern + real(R8) :: jday, jday0 ! elapsed day counters + integer :: next_ymd ! model date + integer :: next_tod ! model sec into model date + integer :: yr ! year + integer :: mon ! month + integer :: day ! day in month + logical :: restart_write + character(len=*),parameter :: subname=trim(modName)//':(ModelAdvance) ' + !------------------------------------------------------------------------------- + + if (.not. valid_ice) then + RETURN + end if + call shr_log_setLogUnit(logunit) + + rc = ESMF_SUCCESS + + call ESMF_TraceRegionEnter(subname) + call memcheck(subname, 5, my_task == main_task) + + ! Query the Component for its clock, importState and exportState + call NUOPC_ModelGet(gcomp, modelClock=clock, importState=importState, exportState=exportState, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! For nuopc - the component clock is advanced at the end of the time interval + ! For these to match for now - need to advance nuopc one timestep ahead for + ! shr_strdata time interpolation + call ESMF_ClockGet( clock, currTime=currTime, timeStep=timeStep, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + nextTime = currTime + timeStep + call ESMF_TimeGet( nextTime, yy=yr, mm=mon, dd=day, s=next_tod, rc=rc ) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_cal_ymd2date(yr, mon, day, next_ymd) + + ! Get cosarg + call shr_cal_ymd2julian(0, mon, day, next_tod, jDay , sdat%model_calendar) ! julian day for model + call shr_cal_ymd2julian(0, 9, 1, 0, jDay0, sdat%model_calendar) ! julian day for Sept 1 + cosArg = 2.0_R8*shr_const_pi*(jday - jday0)/365.0_R8 + + ! Determine if will write restarts + restart_write = dshr_check_restart_alarm(clock, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! Run dice + call dice_comp_run(gcomp, importState, exportState, next_ymd, next_tod, cosarg, restart_write, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_TraceRegionExit(subname) + + end subroutine ModelAdvance + + !=============================================================================== + subroutine dice_comp_run(gcomp, importstate, exportstate, target_ymd, target_tod, cosarg, restart_write, rc) + use nuopc_shr_methods, only : shr_get_rpointer_name + + ! -------------------------- + ! advance dice + ! -------------------------- + + ! input/output variables: + type(ESMF_GridComp), intent(in) :: gcomp + type(ESMF_State) , intent(inout) :: exportState + type(ESMF_State) , intent(inout) :: importState + integer , intent(in) :: target_ymd ! model date + integer , intent(in) :: target_tod ! model sec into model date + real(R8) , intent(in) :: cosarg ! for setting ice temp pattern + logical , intent(in) :: restart_write + integer , intent(out) :: rc + + ! local variables + logical :: first_time = .true. + character(len=CL) :: rpfile + character(*), parameter :: subName = "(dice_comp_run) " + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + call ESMF_TraceRegionEnter('DICE_RUN') + + !-------------------- + ! first time initialization + !-------------------- + + if (first_time) then + + ! Initialize dfields with export state data that has corresponding stream fieldi + select case (trim(datamode)) + case('ssmi','ssmi_iaf') + call dshr_dfield_add(dfields, sdat, state_fld='Si_ifrac', strm_fld='Si_ifrac', & + state=exportState, logunit=logunit, mainproc=mainproc, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + case('cplhist') + call dice_init_dfields(importState, exportState, rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + end select + + ! Initialize datamode module ponters + select case (trim(datamode)) + case('ssmi', 'ssmi_iaf') + call dice_datamode_ssmi_init_pointers(importState, exportState, sdat, flds_i2o_per_cat, rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + case('cplhist') + call dice_datamode_cplhist_init_pointers(importState,exportState,sdat,rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + end select + + ! read restart if needed + if (restart_read) then + call shr_get_rpointer_name(gcomp, 'ice', target_ymd, target_tod, rpfile, 'read', rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + select case (trim(datamode)) + case('ssmi', 'ssmi_iaf') + call dice_datamode_ssmi_restart_read(gcomp, restfilm, rpfile, logunit, my_task, mpicom, sdat) + case('cplhist') + call dice_datamode_cplhist_restart_read(restfilm, rpfile, logunit, my_task, mpicom, sdat) + end select + end if + + ! reset first_time + first_time = .false. + end if + + !-------------------- + ! advance dice streams + !-------------------- + + ! time and spatially interpolate to model time and grid + + call ESMF_TraceRegionEnter('dice_strdata_advance') + call shr_strdata_advance(sdat, target_ymd, target_tod, logunit, 'dice', rc=rc) + call ESMF_TraceRegionExit('dice_strdata_advance') + + !-------------------- + ! copy all fields from streams to export state as default + !-------------------- + + ! This automatically will update the fields in the export state + + call ESMF_TraceRegionEnter('dice_dfield_copy') + call dshr_dfield_copy(dfields, sdat, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_TraceRegionExit('dice_dfield_copy') + + !------------------------------------------------- + ! Determine data model behavior based on the mode + !------------------------------------------------- + + call ESMF_TraceRegionEnter('dice_datamode') + + ! Perform data mode specific calculations + select case (trim(datamode)) + case ('ssmi', 'ssmi_iaf') + call dice_datamode_ssmi_advance(exportState, importState, cosarg, flds_i2o_per_cat, & + flux_swpf, flux_Qmin, flux_Qacc, flux_Qacc0, dt, logunit, restart_read, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + case ('cplhist') + call dice_datamode_cplhist_advance(rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end select + + ! Write restarts if needed + if (restart_write) then + call shr_get_rpointer_name(gcomp, 'ice', target_ymd, target_tod, rpfile, 'write', rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + select case (trim(datamode)) + case('ssmi', 'ssmi_iaf') + call dice_datamode_ssmi_restart_write(rpfile, case_name, inst_suffix, target_ymd, target_tod, & + logunit, my_task, sdat) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + case ('cplhist') + call dice_datamode_cplhist_restart_write(rpfile, case_name, inst_suffix, target_ymd, target_tod, & + logunit, my_task, sdat) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end select + end if + + ! Write diagnostics + if (diagnose_data) then + call dshr_state_diagnose(exportState, flds_scalar_name, subname//':ES',rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + call ESMF_TraceRegionExit('dice_datamode') + call ESMF_TraceRegionExit('DICE_RUN') + + contains + subroutine dice_init_dfields(importState, exportState, rc) + ! ----------------------------- + ! Initialize dfields arrays + ! ----------------------------- + + ! input/output variables + type(ESMF_State) , intent(inout) :: importState + type(ESMF_State) , intent(inout) :: exportState + integer , intent(out) :: rc + + ! local variables + integer :: n + integer :: fieldcount + type(ESMF_Field) :: lfield + character(ESMF_MAXSTR) ,pointer :: lfieldnamelist(:) + character(*), parameter :: subName = "(dice_init_dfields) " + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + ! Initialize dfields data type (to map streams to export state fields) + ! Create dfields linked list - used for copying stream fields to export + ! state fields + call ESMF_StateGet(exportState, itemCount=fieldCount, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + allocate(lfieldnamelist(fieldCount)) + call ESMF_StateGet(exportState, itemNameList=lfieldnamelist, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + do n = 1, fieldCount + call ESMF_StateGet(exportState, itemName=trim(lfieldNameList(n)), field=lfield, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + if (trim(lfieldnamelist(n)) /= flds_scalar_name) then + call dshr_dfield_add( dfields, sdat, trim(lfieldnamelist(n)), trim(lfieldnamelist(n)), exportState, & + logunit, mainproc, rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + end if + end do + end subroutine dice_init_dfields + + end subroutine dice_comp_run + + !=============================================================================== + subroutine ModelFinalize(gcomp, rc) + type(ESMF_GridComp) :: gcomp + integer, intent(out) :: rc + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + if (my_task == main_task) then + write(logunit,*) + write(logunit,*) 'dice : end of main integration loop' + write(logunit,*) + end if + end subroutine ModelFinalize + +#ifdef CESMCOUPLED +end module ice_comp_nuopc +#else +end module cdeps_dice_comp +#endif diff --git a/CDEPS-interface/CDEPS/dlnd/CMakeLists.txt b/CDEPS-interface/CDEPS/dlnd/CMakeLists.txt new file mode 100644 index 0000000000..865f31e6b9 --- /dev/null +++ b/CDEPS-interface/CDEPS/dlnd/CMakeLists.txt @@ -0,0 +1,33 @@ +project(dlnd Fortran) +set(SRCFILES lnd_comp_nuopc.F90) + +foreach(FILE ${SRCFILES}) + if(EXISTS "${CASEROOT}/SourceMods/src.dlnd/${FILE}") + list(REMOVE_ITEM SRCFILES ${FILE}) + list(APPEND SRCFILES "${CASEROOT}/SourceMods/src.dlnd/${FILE}") + message("Using ${FILE} from ${CASEROOT}/SourceMods/src.dlnd") + endif() +endforeach() + +message("DLND srcfiles are ${SRCFILES}") + +add_library(dlnd ${SRCFILES}) + +add_dependencies(dlnd dshr streams) +target_include_directories (dlnd PRIVATE ${ESMF_F90COMPILEPATHS}) +target_include_directories (dlnd PRIVATE "${CMAKE_SOURCE_DIR}") +target_include_directories (dlnd PRIVATE "${PIO_Fortran_INCLUDE_DIR}") +if(NOT DISABLE_FoX) + target_include_directories (dlnd PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/../fox/include) +endif() + +if(BLD_STANDALONE) + # ESMX requires mod files + foreach (SRC ${SRCFILES}) + string(REGEX REPLACE "[.]F90$" ".mod" MOD ${SRC}) + if (NOT DEFINED CIMEROOT AND MOD STREQUAL lnd_comp_nuopc.mod) + set(MOD cdeps_dlnd_comp.mod) + endif() + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${MOD}" DESTINATION include) + endforeach () +endif() diff --git a/CDEPS-interface/CDEPS/dlnd/cime_config/buildlib b/CDEPS-interface/CDEPS/dlnd/cime_config/buildlib new file mode 120000 index 0000000000..0c5e984ac2 --- /dev/null +++ b/CDEPS-interface/CDEPS/dlnd/cime_config/buildlib @@ -0,0 +1 @@ +../../cime_config/buildlib_comps \ No newline at end of file diff --git a/CDEPS-interface/CDEPS/dlnd/cime_config/buildnml b/CDEPS-interface/CDEPS/dlnd/cime_config/buildnml new file mode 100755 index 0000000000..058c01339a --- /dev/null +++ b/CDEPS-interface/CDEPS/dlnd/cime_config/buildnml @@ -0,0 +1,192 @@ +#!/usr/bin/env python3 + +"""Namelist creator for CIME's data land model. +""" + +# Typically ignore this. +# pylint: disable=invalid-name + +# Disable these because this is our standard setup +# pylint: disable=wildcard-import,unused-wildcard-import,wrong-import-position + +import os, sys + +_CDEPS_CONFIG = os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir,os.pardir,"cime_config") +_CIMEROOT = os.environ.get("CIMEROOT") +if _CIMEROOT is None: + raise SystemExit("ERROR: must set CIMEROOT environment variable") +_LIBDIR = os.path.join(_CIMEROOT, "CIME", "Tools") +sys.path.append(_LIBDIR) +sys.path.append(_CDEPS_CONFIG) + +from standard_script_setup import * +from CIME.case import Case +from CIME.nmlgen import NamelistGenerator +from CIME.utils import expect, safe_copy +from CIME.XML.files import Files +from CIME.buildnml import create_namelist_infile, parse_input, copy_inputs_to_rundir +from stream_cdeps import StreamCDEPS + +logger = logging.getLogger(__name__) + +# pylint: disable=too-many-arguments,too-many-locals,too-many-branches,too-many-statements +#################################################################################### +def _create_namelists(case, confdir, inst_string, infile, nmlgen, data_list_path): +#################################################################################### + """Write out the namelist and stream xml files for this component. + + Most arguments are the same as those for `NamelistGenerator`. The + `inst_string` argument is used as a suffix to distinguish files for + different instances. The `confdir` argument is used to specify the directory + in which output files will be placed. + """ + #---------------------------------------------------- + # Write out dlnd_in and dlnd.streams.xml + #---------------------------------------------------- + caseroot = case.get_value("CASEROOT") + dlnd_mode = case.get_value("DLND_MODE") + lnd_grid = case.get_value("LND_GRID") + glc_nec = case.get_value("GLC_NEC") + + # Check for incompatible options. + expect(lnd_grid != "null", + "DLND_GRID cannot be null") + + # Log some settings. + logger.debug("DLND mode is {}".format(dlnd_mode)) + logger.debug("DLND glc_nec is {}".format(glc_nec)) + + # Initialize namelist defaults + # Note: always use model mesh file to set mask for drof + config = {} + config['dlnd_mode'] = dlnd_mode + config['create_mesh'] = 'true' if case.get_value("LND_DOMAIN_MESH") == 'create_mesh' else 'false' + + # Do not allow single column mode for dlnd + if case.get_value('PTS_LON'): + scol_lon = float(case.get_value('PTS_LON')) + else: + scol_lon = -999. + if case.get_value('PTS_LAT'): + scol_lat = float(case.get_value('PTS_LAT')) + else: + scol_lat = -999. + if (scol_lon > -999. and scol_lat > 999.): + expect(False, + "single column mode for DLND is not currently allowed") + + # Initialize nmlgen + nmlgen.init_defaults(infile, config) + + # Generate dlnd_in + namelist_file = os.path.join(confdir, "dlnd_in") + nmlgen.write_output_file(namelist_file, data_list_path, groups=['dlnd_nml']) + + # Determine streams + streamlist = nmlgen.get_streams() + if type(streamlist) == type(str()): + streamlist = [] + + # Generate dlnd.streams.xml + outfile = os.path.join(confdir, "dlnd.streams"+inst_string+".xml" ) + schema_file = os.path.join(_CDEPS_CONFIG,"stream_definition_v2.0.xsd") + stream_file = os.path.join(_CDEPS_CONFIG,os.pardir, "dlnd","cime_config","stream_definition_dlnd.xml") + streams = StreamCDEPS(stream_file, schema_file) + streams.create_stream_xml(streamlist, case, outfile, data_list_path, + os.path.join(caseroot,'user_nl_dlnd_streams'+inst_string)) + +############################################################################### +def buildnml(case, caseroot, compname): +############################################################################### + rundir = case.get_value("RUNDIR") + inst_name = compname.upper()[1:] + ninst = case.get_value("NINST_"+inst_name) + if ninst is None: + ninst = case.get_value("NINST") + confdir = os.path.join(caseroot,"Buildconf",compname + "conf") + if not os.path.isdir(confdir): + os.makedirs(confdir) + + #---------------------------------------------------- + # Construct the namelist generator + #---------------------------------------------------- + # determine directory for user modified namelist_definitions.xml + user_xml_dir = os.path.join(caseroot, "SourceMods", "src." + compname) + expect (os.path.isdir(user_xml_dir), + "user_xml_dir {} does not exist ".format(user_xml_dir)) + + # NOTE: User definition *replaces* existing definition. + files = Files(comp_interface="nuopc") + definition_file = [files.get_value("NAMELIST_DEFINITION_FILE", {"component":compname})] + + user_definition = os.path.join(user_xml_dir, "namelist_definition_"+compname+".xml") + if os.path.isfile(user_definition): + definition_file = [user_definition] + for file_ in definition_file: + expect(os.path.isfile(file_), "Namelist XML file {} not found!".format(file_)) + + # Create the namelist generator object - independent of instance + nmlgen = NamelistGenerator(case, definition_file, files=files) + + #---------------------------------------------------- + # Clear out old data. + #---------------------------------------------------- + + data_list_path = os.path.join(caseroot, "Buildconf", compname+".input_data_list") + if os.path.exists(data_list_path): + os.remove(data_list_path) + + #---------------------------------------------------- + # Loop over instances + #---------------------------------------------------- + for inst_counter in range(1, ninst+1): + # determine instance string + inst_string = "" + if ninst > 1: + inst_string = '_' + "{:04d}".format(inst_counter) + + # If multi-instance case does not have restart file, use + # single-case restart for each instance + rpointer = "rpointer." + compname + if (os.path.isfile(os.path.join(rundir,rpointer)) and + (not os.path.isfile(os.path.join(rundir,rpointer + inst_string)))): + safe_copy(os.path.join(rundir, rpointer), + os.path.join(rundir, rpointer + inst_string)) + + inst_string_label = inst_string + if not inst_string_label: + inst_string_label = "\"\"" + + # create namelist output infile using user_nl_file as input + user_nl_file = os.path.join(caseroot, "user_nl_" + compname + inst_string) + expect(os.path.isfile(user_nl_file), + "Missing required user_nl_file {} ".format(user_nl_file)) + infile = os.path.join(confdir, "namelist_infile") + create_namelist_infile(case, user_nl_file, infile) + namelist_infile = [infile] + + # create namelist and xml stream file(s) + _create_namelists(case, confdir, inst_string, namelist_infile, nmlgen, data_list_path) + + # copy namelist files and stream text files, to rundir + copy_inputs_to_rundir(caseroot, compname, confdir, rundir, inst_string) + +############################################################################### +def get_user_nl_list(case): +############################################################################### + """Returns a list of user_nl_dlnd* files needed in this case + This function is called by CIME to stage the user_nl_dlnd* files in the case + directory. + """ + user_nl_list = ["user_nl_dlnd", "user_nl_dlnd_streams"] + return user_nl_list + +############################################################################### +def _main_func(): + # Build the component namelist and required stream xml files + caseroot = parse_input(sys.argv) + with Case(caseroot) as case: + buildnml(case, caseroot, "dlnd") + +if __name__ == "__main__": + _main_func() diff --git a/CDEPS-interface/CDEPS/dlnd/cime_config/config_archive.xml b/CDEPS-interface/CDEPS/dlnd/cime_config/config_archive.xml new file mode 100644 index 0000000000..6f86569bec --- /dev/null +++ b/CDEPS-interface/CDEPS/dlnd/cime_config/config_archive.xml @@ -0,0 +1,11 @@ + + + r + rs1 + unset + + rpointer.lnd$NINST_STRING + $CASE.dlnd$NINST_STRING.r.$DATENAME.nc,$CASE.dlnd$NINST_STRING.rs1.$DATENAME.bin + + + diff --git a/CDEPS-interface/CDEPS/dlnd/cime_config/config_component.xml b/CDEPS-interface/CDEPS/dlnd/cime_config/config_component.xml new file mode 100644 index 0000000000..ab40fa5831 --- /dev/null +++ b/CDEPS-interface/CDEPS/dlnd/cime_config/config_component.xml @@ -0,0 +1,131 @@ + + + + + + + + Data land model (DLND) + snow coupling mode + non-snow coupling + + + + char + dlnd + dlnd + case_comp + env_case.xml + Name of land component + + + + char + SCPL,LCPL + SCPL + + SCPL + LCPL + + run_component_dlnd + env_run.xml + + model mode. + In SCPL, glc coupling data (produced by CISM) from a previous + model run is read in from a coupler history file. + In LCPL, land forcing data (produced by CLM) from a previous + model run is read in from a coupler history file. + + + + + char + UNSET + + $DIN_LOC_ROOT/lnd/dlnd7/CPLHIST_SNO/b.e21.B1850.f09_g17.CMIP6-piControl.001_c210324 + + run_component_dlnd + env_run.xml + directory for coupler history data mode (only used for CPLHIST mode) + + + + char + UNSET + + b.e21.B1850.f09_g17.CMIP6-piControl.001 + + run_component_dlnd + env_run.xml + case name for coupler history data mode (only used for CPLHIST mode) + + + + integer + -999 + + 1 + + run_component_dlnd + env_run.xml + + Simulation year corresponding to DLND_CPLHIST_YR_START (only used + when DLND_MODE is CPLHIST or GLC_CPLHIST). A common usage is to + set this to RUN_STARTDATE. With this setting, the forcing in the + first year of the run will be the forcing of year + DLND_CPLHIST_YR_START. Another use case is to align the calendar + of transient forcing with the model calendar. For example, setting + DLND_CPLHIST_YR_ALIGN=DLND_CPLHIST_YR_START will lead to the + forcing calendar being the same as the model calendar. The forcing + for a given model year would be the forcing of the same year. This + would be appropriate in transient runs where the model calendar is + setup to span the same year range as the forcing data. + + + + + integer + -999 + + 1971 + + run_component_dlnd + env_run.xml + starting year to loop data over (only used when DLND_MODE is CPLHIST or GLC_CPLHIST) + + + + integer + -999 + + 2000 + + run_component_dlnd + env_run.xml + ending year to loop data over (only used when DLND_MODE is CPLHIST or GLC_CPLHIST) + + + + logical + TRUE,FALSE + FALSE + run_component_dlnd + env_run.xml + If set to true, than dlnd restarts will not be read on a continuation run. + + + + + ========================================= + DLND naming conventions + ========================================= + + + diff --git a/CDEPS-interface/CDEPS/dlnd/cime_config/namelist_definition_dlnd.xml b/CDEPS-interface/CDEPS/dlnd/cime_config/namelist_definition_dlnd.xml new file mode 100644 index 0000000000..b10350b749 --- /dev/null +++ b/CDEPS-interface/CDEPS/dlnd/cime_config/namelist_definition_dlnd.xml @@ -0,0 +1,115 @@ + + + + + + + + + + char(100) + streams + streams_file + List of streams used for each supported dlnd_mode + + lnd.cplhist + sno.cplhist + + + + + char + dlnd + dlnd_nml + copyall + + Copies all fields directly from the input data streams Any required + fields not found on an input stream will be set to zero. + + + copyall + + + + + char + streams + abs + dlnd_nml + + file specifying model mesh + + + $LND_DOMAIN_MESH + null + + + + + char + streams + abs + dlnd_nml + + file specifying file to use to obtain model mask + + + $MASK_MESH + + + + + integer + streams + dlnd_nml + + global size of nx + + + $LND_NX + + + + + integer + streams + dlnd_nml + + global size of ny + + + $LND_NY + + + + + char + dlnd + dlnd_nml + + main restart file name for dlnd model + + + null + + + + + logical + dlnd + dlnd_nml + + If set to true, than dlnd restarts will not be read on a continuation run. + This capability is used, for example, in CTSM spinup runs. + + + $DLND_SKIP_RESTART_READ + + + + diff --git a/CDEPS-interface/CDEPS/dlnd/cime_config/stream_definition_dlnd.xml b/CDEPS-interface/CDEPS/dlnd/cime_config/stream_definition_dlnd.xml new file mode 100644 index 0000000000..292d8834d2 --- /dev/null +++ b/CDEPS-interface/CDEPS/dlnd/cime_config/stream_definition_dlnd.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + $LND_DOMAIN_MESH + + + + $DLND_CPLHIST_DIR/$DLND_CPLHIST_CASE.cpl.hl2x1yr_glc.%y-01-01.nc + + + l2x1yr_glc_Sl_tsrf%glc Sl_tsrf_elev%glc + l2x1yr_glc_Sl_topo%glc Sl_topo_elev%glc + l2x1yr_glc_Flgl_qice%glc Flgl_qice_elev%glc + + null + + bilinear + + null + $DLND_CPLHIST_YR_ALIGN + $DLND_CPLHIST_YR_START + $DLND_CPLHIST_YR_END + 0 + + lower + + + cycle + + + 1.5 + + single + + + diff --git a/CDEPS-interface/CDEPS/dlnd/cime_config/testdefs/testlist_dlnd.xml b/CDEPS-interface/CDEPS/dlnd/cime_config/testdefs/testlist_dlnd.xml new file mode 100644 index 0000000000..59026878c7 --- /dev/null +++ b/CDEPS-interface/CDEPS/dlnd/cime_config/testdefs/testlist_dlnd.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/CDEPS-interface/CDEPS/dlnd/cime_config/user_nl_dlnd b/CDEPS-interface/CDEPS/dlnd/cime_config/user_nl_dlnd new file mode 100644 index 0000000000..69b4ba55b0 --- /dev/null +++ b/CDEPS-interface/CDEPS/dlnd/cime_config/user_nl_dlnd @@ -0,0 +1,13 @@ +!------------------------------------------------------------------------ +! Users should ONLY USE user_nl_dlnd to change namelists variables +! Users should add all user specific namelist changes below in the form of +! namelist_var = new_namelist_value +! Note that any namelist variable from shr_strdata_nml and dlnd_nml can +! be modified below using the above syntax +! User preview_namelists to view (not modify) the output namelist in the +! directory $CASEROOT/CaseDocs +! To modify the contents of a stream txt file, first use preview_namelists +! to obtain the contents of the stream txt files in CaseDocs, and then +! place a copy of the modified stream txt file in $CASEROOT with the string +! user_ prepended. +!------------------------------------------------------------------------ diff --git a/CDEPS-interface/CDEPS/dlnd/cime_config/user_nl_dlnd_streams b/CDEPS-interface/CDEPS/dlnd/cime_config/user_nl_dlnd_streams new file mode 100644 index 0000000000..856ee89446 --- /dev/null +++ b/CDEPS-interface/CDEPS/dlnd/cime_config/user_nl_dlnd_streams @@ -0,0 +1,33 @@ +!------------------------------------------------------------------------ +! This file is used to modify datm.streams.xml generated in $RUNDIR +! Entries should have the form +! :<= new stream_value> +! The following are accepted values for an assume streamname of foo +! foo:meshfile = character string +! foo:datafiles = comma separated string of full pathnames (e.g. file1,file2,file3...) +! foo:datavars = comma separated string of field pairs (e.g. foo foobar,foo2 foobar2...) +! foo:taxmode = one of [cycle, extend, limit] +! foo:tintalgo = one of [lower,upper,nearest,linear,coszen] +! foo:readmode = single (only suported mode right now) +! foo:mapalgo = one of [bilinear,redist,nn,consf,consd,none] +! foo:dtlimit = real (1.5 is default) +! foo:year_first = integer +! foo:year_last = integer +! foo:year_align = integer +! foo:vectors = one of [none,u:v] +! foo:lev_dimname: = one of [null,name of level dimenion name] +! foo:offset = integer +! As an example: +! foo:year_first = 1950 +! would change the stream year_first stream_entry to 1950 for the foo stream block +! NOTE: multi-line inputs are enabled by adding a \ at the end of the line +! As an emaple: +! foo:datafiles=foo1,foo2, \ +! foo3 +! Will yield the following new entry for datafiles in stream foo +! +! foo1 +! foo2 +! foo3 +! +!------------------------------------------------------------------------ diff --git a/CDEPS-interface/CDEPS/dlnd/lnd_comp_nuopc.F90 b/CDEPS-interface/CDEPS/dlnd/lnd_comp_nuopc.F90 new file mode 100644 index 0000000000..6ae70c6f10 --- /dev/null +++ b/CDEPS-interface/CDEPS/dlnd/lnd_comp_nuopc.F90 @@ -0,0 +1,605 @@ +#ifdef CESMCOUPLED +module lnd_comp_nuopc +#else +module cdeps_dlnd_comp +#endif + + !---------------------------------------------------------------------------- + ! This is the NUOPC cap for DLND + !---------------------------------------------------------------------------- + use ESMF , only : ESMF_VM, ESMF_VMBroadcast, ESMF_GridCompGet + use ESMF , only : ESMF_Mesh, ESMF_GridComp, ESMF_SUCCESS, ESMF_LOGMSG_INFO + use ESMF , only : ESMF_LogWrite, ESMF_TraceRegionExit, ESMF_TraceRegionEnter + use ESMF , only : ESMF_Clock, ESMF_Alarm, ESMF_State, ESMF_ClockGet, ESMF_timeGet + use ESMF , only : ESMF_Time, ESMF_TimeInterval, ESMF_METHOD_INITIALIZE + use ESMF , only : ESMF_MethodAdd, ESMF_MethodRemove + use ESMF , only : ESMF_ClockGetAlarm, ESMF_AlarmIsRinging, ESMF_AlarmRingerOff + use ESMF , only : ESMF_GridCompSetEntryPoint, operator(+) + use NUOPC , only : NUOPC_CompDerive, NUOPC_CompSetEntryPoint, NUOPC_CompSpecialize + use NUOPC , only : NUOPC_CompAttributeGet, NUOPC_Advertise + use NUOPC_Model , only : model_routine_SS => SetServices + use NUOPC_Model , only : model_label_Advance => label_Advance + use NUOPC_Model , only : model_label_SetRunClock => label_SetRunClock + use NUOPC_Model , only : model_label_Finalize => label_Finalize + use NUOPC_Model , only : NUOPC_ModelGet, SetVM + use shr_kind_mod , only : r8=>shr_kind_r8, i8=>shr_kind_i8, cl=>shr_kind_cl, cs=>shr_kind_cs + use shr_sys_mod , only : shr_sys_abort + use shr_cal_mod , only : shr_cal_ymd2date + use shr_log_mod , only : shr_log_setLogUnit + use dshr_methods_mod , only : dshr_state_getfldptr, dshr_state_diagnose, chkerr, memcheck + use dshr_strdata_mod , only : shr_strdata_type, shr_strdata_advance, shr_strdata_get_stream_domain + use dshr_strdata_mod , only : shr_strdata_init_from_config + use dshr_mod , only : dshr_model_initphase, dshr_init, dshr_check_restart_alarm + use dshr_mod , only : dshr_state_setscalar, dshr_set_runclock, dshr_log_clock_advance + use dshr_mod , only : dshr_restart_read, dshr_restart_write, dshr_mesh_init + use dshr_dfield_mod , only : dfield_type, dshr_dfield_add, dshr_dfield_copy + use dshr_fldlist_mod , only : fldlist_type, dshr_fldlist_add, dshr_fldlist_realize + use glc_elevclass_mod , only : glc_elevclass_as_string, glc_elevclass_init + use nuopc_shr_methods , only : shr_get_rpointer_name + + implicit none + private ! except + + public :: SetServices + public :: SetVM + private :: InitializeAdvertise + private :: InitializeRealize + private :: ModelAdvance + private :: ModelFinalize + private :: dlnd_comp_advertise + private :: dlnd_comp_realize + private :: dlnd_comp_run + + !-------------------------------------------------------------------------- + ! Private module data + !-------------------------------------------------------------------------- + + type(shr_strdata_type) :: sdat ! instantiation of shr_strdata_type + type(ESMF_Mesh) :: model_mesh ! model mesh + character(len=CS) :: flds_scalar_name = '' + integer :: flds_scalar_num = 0 + integer :: flds_scalar_index_nx = 0 + integer :: flds_scalar_index_ny = 0 + integer :: mpicom ! mpi communicator + integer :: my_task ! my task in mpi communicator mpicom + logical :: mainproc ! true of my_task == main_task + integer :: inst_index ! number of current instance (ie. 1) + character(len=16) :: inst_suffix = "" ! char string associated with instance (ie. "_0001" or "") + integer :: logunit ! logging unit number + logical :: restart_read ! start from restart + character(CL) :: case_name ! case name + character(*) , parameter :: nullstr = 'null' + + ! dlnd_in namelist input + character(CL) :: dataMode = nullstr ! flags physics options wrt input data + character(CL) :: model_meshfile = nullstr ! full pathname to model meshfile + character(CL) :: model_maskfile = nullstr ! full pathname to obtain mask from + character(CL) :: streamfilename ! filename to obtain stream info from + character(CL) :: nlfilename = nullstr ! filename to obtain namelist info from +! not currently used +! logical :: force_prognostic_true = .false. ! if true set prognostic true + character(CL) :: restfilm = nullstr ! model restart file namelist + integer :: nx_global ! global nx dimension of model mesh + integer :: ny_global ! global ny dimension of model mesh + logical :: skip_restart_read = .false. ! true => skip restart read in continuation + logical :: export_all = .false. ! true => export all fields, do not check connected or not + + ! linked lists + type(fldList_type) , pointer :: fldsExport => null() + type(dfield_type) , pointer :: dfields => null() + + ! model mask and model fraction + real(r8), pointer :: model_frac(:) => null() + integer , pointer :: model_mask(:) => null() + + ! module pointer arrays + real(r8), pointer :: lfrac(:) + + ! module constants + integer :: glc_nec + logical :: diagnose_data = .true. + integer , parameter :: main_task=0 ! task number of main task +#ifdef CESMCOUPLED + character(*) , parameter :: modName = "(lnd_comp_nuopc)" +#else + character(*) , parameter :: modName = "(cdeps_dlnd_comp)" +#endif + character(*) , parameter :: u_FILE_u = & + __FILE__ + +!=============================================================================== +contains +!=============================================================================== + + subroutine SetServices(gcomp, rc) + type(ESMF_GridComp) :: gcomp + integer, intent(out) :: rc + + character(len=*),parameter :: subname=trim(modName)//':(SetServices) ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + call ESMF_LogWrite(subname//' called', ESMF_LOGMSG_INFO) + + ! the NUOPC gcomp component will register the generic methods + call NUOPC_CompDerive(gcomp, model_routine_SS, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! switching to IPD versions + call ESMF_GridCompSetEntryPoint(gcomp, ESMF_METHOD_INITIALIZE, & + userRoutine=dshr_model_initphase, phase=0, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! set entry point for methods that require specific implementation + call NUOPC_CompSetEntryPoint(gcomp, ESMF_METHOD_INITIALIZE, & + phaseLabelList=(/"IPDv01p1"/), userRoutine=InitializeAdvertise, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call NUOPC_CompSetEntryPoint(gcomp, ESMF_METHOD_INITIALIZE, & + phaseLabelList=(/"IPDv01p3"/), userRoutine=InitializeRealize, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! attach specializing method(s) + call NUOPC_CompSpecialize(gcomp, specLabel=model_label_Advance, specRoutine=ModelAdvance, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_MethodRemove(gcomp, label=model_label_SetRunClock, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call NUOPC_CompSpecialize(gcomp, specLabel=model_label_SetRunClock, specRoutine=dshr_set_runclock, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call NUOPC_CompSpecialize(gcomp, specLabel=model_label_Finalize, specRoutine=ModelFinalize, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_LogWrite(subname//' done', ESMF_LOGMSG_INFO) + + end subroutine SetServices + + !=============================================================================== + subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) + use shr_nl_mod, only: shr_nl_find_group_name + + ! input/output variables + type(ESMF_GridComp) :: gcomp + type(ESMF_State) :: importState, exportState + type(ESMF_Clock) :: clock + integer, intent(out) :: rc + + ! local variables + type(ESMF_VM) :: vm + character(CL) :: cvalue + integer :: nu ! unit number + integer :: bcasttmp(4) + integer :: ierr ! error code + character(len=*) , parameter :: subname=trim(modName)//':(InitializeAdvertise) ' + character(*) , parameter :: F00 = "('(" // trim(modName) // ") ',8a)" + character(*) , parameter :: F01 = "('(" // trim(modName) // ") ',a,2x,i8)" + character(*) , parameter :: F02 = "('(" // trim(modName) // ") ',a,l6)" + !------------------------------------------------------------------------------- + + namelist / dlnd_nml / datamode, model_meshfile, model_maskfile, & + nx_global, ny_global, restfilm, skip_restart_read, export_all + + rc = ESMF_SUCCESS + + call NUOPC_CompAttributeGet(gcomp, name='case_name', value=case_name, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! Obtain flds_scalar values, mpi values, multi-instance values and + ! set logunit and set shr logging to my log file + call dshr_init(gcomp, 'LND', mpicom, my_task, inst_index, inst_suffix, & + flds_scalar_name, flds_scalar_num, flds_scalar_index_nx, flds_scalar_index_ny, & + logunit, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! Determine logical mainproc + mainproc = (my_task == main_task) + + ! Read dlnd_nml from nlfilename + if (my_task == main_task) then + nlfilename = "dlnd_in"//trim(inst_suffix) + open (newunit=nu, file=trim(nlfilename), status="old", action="read") + call shr_nl_find_group_name(nu, 'dlnd_nml', status=ierr) + + read (nu,nml=dlnd_nml,iostat=ierr) + close(nu) + if (ierr > 0) then + write(logunit,*) 'ERROR: reading input namelist, '//trim(nlfilename)//' iostat=',ierr + call shr_sys_abort(subName//': namelist read error '//trim(nlfilename)) + end if + bcasttmp = 0 + bcasttmp(1) = nx_global + bcasttmp(2) = ny_global + if(skip_restart_read) bcasttmp(3) = 1 + if(export_all) bcasttmp(4) = 1 + end if + + call ESMF_GridCompGet(gcomp, vm=vm, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_VMBroadcast(vm, datamode, CL, main_task, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_VMBroadcast(vm, model_meshfile, CL, main_task, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_VMBroadcast(vm, model_maskfile, CL, main_task, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_VMBroadcast(vm, restfilm, CL, main_task, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_VMBroadcast(vm, bcasttmp, 4, main_task, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + nx_global = bcasttmp(1) + ny_global = bcasttmp(2) + skip_restart_read = (bcasttmp(3) == 1) + export_all = (bcasttmp(4) == 1) + + ! write namelist input to standard out + if (my_task == main_task) then + write(logunit,F00)' model_meshfile = ',trim(model_meshfile) + write(logunit,F00)' model_maskfile = ',trim(model_maskfile) + write(logunit,F00)' datamode = ',datamode + write(logunit,F01)' nx_global = ',nx_global + write(logunit,F01)' ny_global = ',ny_global + write(logunit,F00)' restfilm = ',trim(restfilm) + write(logunit,F02)' skip_restart_read = ',skip_restart_read + write(logunit,F02)' export_all = ',export_all + endif + + ! Validate sdat datamode + if (trim(datamode) == 'copyall') then + if (my_task == main_task) write(logunit,*) 'dlnd datamode = ',trim(datamode) + else + call shr_sys_abort(' ERROR illegal dlnd datamode = '//trim(datamode)) + end if + call NUOPC_CompAttributeGet(gcomp, name='glc_nec', value=cvalue, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + read(cvalue,*) glc_nec + call ESMF_LogWrite('glc_nec = '// trim(cvalue), ESMF_LOGMSG_INFO) + + ! Advertise the export fields + call dlnd_comp_advertise(importState, exportState, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + end subroutine InitializeAdvertise + + !=============================================================================== + subroutine InitializeRealize(gcomp, importState, exportState, clock, rc) + + ! input/output variables + type(ESMF_GridComp) :: gcomp + type(ESMF_State) :: importState, exportState + type(ESMF_Clock) :: clock + integer, intent(out) :: rc + + ! local variables + type(ESMF_TIME) :: currTime + integer :: current_ymd ! model date + integer :: current_year ! model year + integer :: current_mon ! model month + integer :: current_day ! model day + integer :: current_tod ! model sec into model date + character(len=cl) :: rpfile ! restart pointer file name + character(len=*),parameter :: subname=trim(modName)//':(InitializeRealize) ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + ! Initialize sdat + call ESMF_TraceRegionEnter('dlnd_strdata_init') + call dshr_mesh_init(gcomp, sdat, nullstr, logunit, 'LND', nx_global, ny_global, & + model_meshfile, model_maskfile, model_mesh, model_mask, model_frac, restart_read, rc=rc) + + ! Initialize stream data type + streamfilename = 'dlnd.streams'//trim(inst_suffix) +#ifndef DISABLE_FoX + streamfilename = trim(streamfilename)//'.xml' +#endif + call shr_strdata_init_from_config(sdat, streamfilename, model_mesh, clock, 'LND', logunit, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_TraceRegionExit('dlnd_strdata_init') + + ! Realize the actively coupled fields, now that a mesh is established and + ! initialize dfields data type (to map streams to export state fields) + call dlnd_comp_realize(importState, exportState, export_all, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! get the time to interpolate the stream data to + call ESMF_ClockGet(clock, currTime=currTime, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_TimeGet(currTime, yy=current_year, mm=current_mon, dd=current_day, s=current_tod, rc=rc ) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_cal_ymd2date(current_year, current_mon, current_day, current_ymd) + + ! Read restart if necessary + if (restart_read .and. .not. skip_restart_read) then + call shr_get_rpointer_name(gcomp, 'lnd', current_ymd, current_tod, rpfile, 'read', rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_restart_read(restfilm, rpfile, logunit, my_task, mpicom, sdat, rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + end if + + + ! Run dlnd to create export state + call dlnd_comp_run(importState, exportState, current_ymd, current_tod, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! add scalars to export state + call dshr_state_SetScalar(dble(nx_global),flds_scalar_index_nx, exportState, flds_scalar_name, flds_scalar_num, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_SetScalar(dble(ny_global),flds_scalar_index_ny, exportState, flds_scalar_name, flds_scalar_num, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! diagnostics + if (diagnose_data) then + call dshr_state_diagnose(exportState, flds_scalar_name, subname//':ES',rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + end subroutine InitializeRealize + + !=============================================================================== + subroutine ModelAdvance(gcomp, rc) + use nuopc_shr_methods, only : shr_get_rpointer_name + ! input/output variables + type(ESMF_GridComp) :: gcomp + integer, intent(out) :: rc + + ! local variables + type(ESMF_State) :: importState, exportState + type(ESMF_Clock) :: clock + type(ESMF_TimeInterval) :: timeStep + type(ESMF_Time) :: currTime, nextTime + integer :: next_ymd ! model date + integer :: next_tod ! model sec into model date + integer :: yr ! year + integer :: mon ! month + integer :: day ! day in month + logical :: write_restart + character(len=CL) :: rpfile + character(len=*),parameter :: subname=trim(modName)//':(ModelAdvance) ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + call shr_log_setLogUnit(logunit) + call memcheck(subname, 5, my_task==main_task) + + ! query the Component for its clock, importState and exportState + call NUOPC_ModelGet(gcomp, modelClock=clock, importState=importState, exportState=exportState, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! For nuopc - the component clock is advanced at the end of the time interval + ! For these to match for now - need to advance nuopc one timestep ahead for + ! shr_strdata time interpolation + call ESMF_ClockGet( clock, currTime=currTime, timeStep=timeStep, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + nextTime = currTime + timeStep + call ESMF_TimeGet( nextTime, yy=yr, mm=mon, dd=day, s=next_tod, rc=rc ) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_cal_ymd2date(yr, mon, day, next_ymd) + + ! run dlnd + call dlnd_comp_run(importState, exportState, next_ymd, next_tod, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! write_restart if alarm is ringing + write_restart = dshr_check_restart_alarm(clock, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (write_restart) then + call ESMF_TraceRegionEnter('dlnd_restart') + call shr_get_rpointer_name(gcomp, 'lnd', next_ymd, next_tod, rpfile, 'write', rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_restart_write(rpfile, case_name, 'dlnd', inst_suffix, next_ymd, next_tod, & + logunit, my_task, sdat, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_TraceRegionExit('dlnd_restart') + endif + + + ! write diagnostics + if (diagnose_data) then + call dshr_state_diagnose(exportState, flds_scalar_name, subname//':ES',rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + end subroutine ModelAdvance + + !=============================================================================== + subroutine ModelFinalize(gcomp, rc) + type(ESMF_GridComp) :: gcomp + integer, intent(out) :: rc + + ! local variables + character(*), parameter :: F00 = "('(dlnd_comp_final) ',8a)" + character(*), parameter :: F91 = "('(dlnd_comp_final) ',73('-'))" + character(len=*),parameter :: subname=trim(modName)//':(ModelFinalize) ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + call ESMF_LogWrite(subname//' called', ESMF_LOGMSG_INFO) + if (my_task == main_task) then + write(logunit,F91) + write(logunit,F00) ' dlnd : end of main integration loop' + write(logunit,F91) + end if + call ESMF_LogWrite(subname//' done', ESMF_LOGMSG_INFO) + + end subroutine ModelFinalize + + !=============================================================================== + subroutine dlnd_comp_advertise(importState, exportState, rc) + + ! determine export and import fields to advertise to mediator + + ! input/output arguments + type(ESMF_State) :: importState + type(ESMF_State) :: exportState + integer , intent(out) :: rc + + ! local variables + type(fldlist_type), pointer :: fldList + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + call glc_elevclass_init(glc_nec) + + !------------------- + ! Advertise export fields + !------------------- + + call dshr_fldList_add(fldsExport, trim(flds_scalar_name)) + call dshr_fldlist_add(fldsExport, "Sl_lfrin") + + ! The following puts all of the elevation class fields as an + ! undidstributed dimension in the export state field - index1 is bare land - and the total number of + ! elevation classes not equal to bare land go from index2 -> glc_nec+1 + if (glc_nec > 0) then + call dshr_fldList_add(fldsExport, 'Sl_tsrf_elev' , ungridded_lbound=1, ungridded_ubound=glc_nec+1) + call dshr_fldList_add(fldsExport, 'Sl_topo_elev' , ungridded_lbound=1, ungridded_ubound=glc_nec+1) + call dshr_fldList_add(fldsExport, 'Flgl_qice_elev', ungridded_lbound=1, ungridded_ubound=glc_nec+1) + end if + + fldlist => fldsExport ! the head of the linked list + do while (associated(fldlist)) + call NUOPC_Advertise(exportState, standardName=fldlist%stdname, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_LogWrite('(dlnd_comp_advertise): Fr_lnd '//trim(fldList%stdname), ESMF_LOGMSG_INFO) + fldList => fldList%next + enddo + + ! TODO: Non snow fields that nead to be added if dlnd is in cplhist mode + ! "Sl_t " "Sl_tref " "Sl_qref " "Sl_avsdr " + ! "Sl_anidr " "Sl_avsdf " "Sl_anidf " "Sl_snowh " + ! "Fall_taux " "Fall_tauy " "Fall_lat " "Fall_sen " + ! "Fall_lwup " "Fall_evap " "Fall_swnet " "Sl_landfrac " + ! "Sl_fv " "Sl_ram1 " + ! "Fall_flxdst1" "Fall_flxdst2" "Fall_flxdst3" "Fall_flxdst4" + + end subroutine dlnd_comp_advertise + + !=============================================================================== + subroutine dlnd_comp_realize(importState, exportState, export_all, rc) + + ! input/output variables + type(ESMF_State) , intent(inout) :: importState + type(ESMF_State) , intent(inout) :: exportState + logical , intent(in) :: export_all + integer , intent(out) :: rc + + ! local variables + character(*), parameter :: subName = "(dlnd_comp_realize) " + ! ---------------------------------------------- + + rc = ESMF_SUCCESS + + ! ------------------------------------- + ! NUOPC_Realize "realizes" a previously advertised field in the importState and exportState + ! by replacing the advertised fields with the newly created fields of the same name. + ! ------------------------------------- + + call dshr_fldlist_realize( exportState, fldsExport, flds_scalar_name, flds_scalar_num, model_mesh, & + subname//':dlndExport', export_all, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + end subroutine dlnd_comp_realize + + !=============================================================================== + subroutine dlnd_comp_run(importState, exportState, target_ymd, target_tod, rc) + + ! -------------------------- + ! advance dlnd + ! -------------------------- + + ! input/output variables: + type(ESMF_State) , intent(inout) :: importState + type(ESMF_State) , intent(inout) :: ExportState + integer , intent(in) :: target_ymd ! model date + integer , intent(in) :: target_tod ! model sec into model date + integer , intent(out) :: rc + + ! local variables + logical :: first_time = .true. + integer :: n + character(len=2) :: nec_str + character(CS), allocatable :: strm_flds(:) + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + call ESMF_TraceRegionEnter('DLND_RUN') + + !-------------------- + ! set module pointers + !-------------------- + + if (first_time) then + + ! Set fractional land pointer in export state + call dshr_state_getfldptr(exportState, fldname='Sl_lfrin', fldptr1=lfrac, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + lfrac(:) = model_frac(:) + + ! Create stream-> export state mapping + ! Note that strm_flds is the model name for the stream field + ! Note that state_fld is the model name for the export field + allocate(strm_flds(0:glc_nec)) + do n = 0,glc_nec + nec_str = glc_elevclass_as_string(n) + strm_flds(n) = 'Sl_tsrf_elev' // trim(nec_str) + end do + call dshr_dfield_add(dfields, sdat, state_fld='Sl_tsrf_elev', strm_flds=strm_flds, state=exportState, & + logunit=logunit, mainproc=mainproc, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + do n = 0,glc_nec + nec_str = glc_elevclass_as_string(n) + strm_flds(n) = 'Sl_topo_elev' // trim(nec_str) + end do + call dshr_dfield_add(dfields, sdat, state_fld='Sl_topo_elev', strm_flds=strm_flds, state=exportState, & + logunit=logunit, mainproc=mainproc, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + do n = 0,glc_nec + nec_str = glc_elevclass_as_string(n) + strm_flds(n) = 'Flgl_qice_elev' // trim(nec_str) + end do + call dshr_dfield_add(dfields, sdat, state_fld='Flgl_qice_elev', strm_flds=strm_flds, state=exportState, & + logunit=logunit, mainproc=mainproc, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + first_time = .false. + end if + + !-------------------- + ! advance dlnd streams + !-------------------- + + ! time and spatially interpolate to model time and grid + call ESMF_TraceRegionEnter('dlnd_strdata_advance') + call shr_strdata_advance(sdat, target_ymd, target_tod, logunit, 'dlnd', rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_TraceRegionExit('dlnd_strdata_advance') + + ! copy all fields from streams to export state as default + ! This automatically will update the fields in the export state + call ESMF_TraceRegionEnter('dlnd_strdata_copy') + call dshr_dfield_copy(dfields, sdat, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_TraceRegionExit('dlnd_strdata_copy') + + ! determine data model behavior based on the mode + call ESMF_TraceRegionEnter('dlnd_datamode') + select case (trim(datamode)) + case('copyall') + ! do nothing extra + end select + + call ESMF_TraceRegionExit('dlnd_datamode') + call ESMF_TraceRegionExit('DLND_RUN') + + end subroutine dlnd_comp_run + +#ifdef CESMCOUPLED +end module lnd_comp_nuopc +#else +end module cdeps_dlnd_comp +#endif diff --git a/CDEPS-interface/CDEPS/doc/Makefile b/CDEPS-interface/CDEPS/doc/Makefile new file mode 100644 index 0000000000..c9ca504c7e --- /dev/null +++ b/CDEPS-interface/CDEPS/doc/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +SPHINXPROJ = CDEPS +SOURCEDIR = source +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/CDEPS-interface/CDEPS/doc/source/_static/pop_ver.js b/CDEPS-interface/CDEPS/doc/source/_static/pop_ver.js new file mode 100644 index 0000000000..b8c58658a8 --- /dev/null +++ b/CDEPS-interface/CDEPS/doc/source/_static/pop_ver.js @@ -0,0 +1,37 @@ +$(document).ready(function() { + /* For a URL that looks like + https://blah.github.io/versions/VERSIONFOO/html/bar/index.html, set cur_version_dir to + 'VERSIONFOO' (i.e., the portion of the path following 'versions'). + */ + var proj_end = document.baseURI.indexOf("versions") + 9; + var end = document.baseURI.indexOf("/", proj_end); + var cur_version_dir = document.baseURI.substring(proj_end, end); + var mylist = $("#version-list"); + mylist.empty(); + $.getJSON(version_json_loc, function(data) { + if (data.hasOwnProperty(cur_version_dir)) { + /* First add the current version so that it appears first in the drop-down + menu and starts as the selected element of the menu. If you click on the + current version, you should stay at the current page. + + The conditional around this block should generally be true, but we check it + just in case the current version is missing from the versions.json file for + some reason. + */ + cur_version_name = data[cur_version_dir]; + mylist.append($("