diff --git a/.circleci/config.yml b/.circleci/config.yml index 2017d80eb250..bbf8acc4ca6d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,301 +1,152 @@ version: 2.1 +# Anchors to prevent forgetting to update a version +baselibs_version: &baselibs_version v7.5.0 +bcs_version: &bcs_version v10.23.0 + orbs: - circleci-tools: geos-esm/circleci-tools@0.11.0 + ci: geos-esm/circleci-tools@1 workflows: build-and-test: jobs: - - build-and-test-MAPL: - name: build-and-test-MAPL-on-<< matrix.compiler >> + + # Builds MAPL in a "default" way - Intel + - ci/build: + name: build-and-test-MAPL-on-<< matrix.compiler >>-using-<< matrix.cmake_generator >> + context: + - docker-hub-creds matrix: parameters: - compiler: [gfortran, ifort] + compiler: [ifort] + cmake_generator: ['Unix Makefiles', 'Ninja'] + baselibs_version: *baselibs_version + repo: MAPL + mepodevelop: false + run_unit_tests: true + ctest_options: "-LE 'PERFORMANCE|EXTDATA1G_BIG_TESTS|EXTDATA2G_BIG_TESTS' --output-on-failure" + persist_workspace: true # Needed for MAPL tutorials + + # Builds MAPL in a "default" way - GNU + # + # NOTE: Currently Open MPI fails on the bundleio with: + # + # The OSC pt2pt component does not support MPI_THREAD_MULTIPLE in this release. + # Workarounds are to run on a single node, or to use a system with an RDMA + # capable network such as Infiniband. + # + # For now, we run GNU/Open MPI without the bundleio tests. Some indications that + # Open MPI 5 will not have this limitation + + - ci/build: + name: build-and-test-MAPL-on-<< matrix.compiler >>-using-<< matrix.cmake_generator >> context: - docker-hub-creds - - build-UFS-MAPL: + matrix: + parameters: + compiler: [gfortran] + cmake_generator: ['Unix Makefiles', 'Ninja'] + baselibs_version: *baselibs_version + repo: MAPL + mepodevelop: false + run_unit_tests: true + ctest_options: "-E bundleio -LE 'PERFORMANCE|EXTDATA1G_BIG_TESTS|EXTDATA2G_BIG_TESTS' --output-on-failure" + persist_workspace: true # Needed for MAPL tutorials + + # Builds MAPL like UFS does (no FLAP and pFlogger, static) + - ci/build: name: build-UFS-MAPL-on-<< matrix.compiler >> + context: + - docker-hub-creds matrix: parameters: compiler: [ifort] + baselibs_version: *baselibs_version + repo: MAPL + mepodevelop: false + extra_cmake_options: "-DBUILD_WITH_FLAP=OFF -DBUILD_WITH_PFLOGGER=OFF -DBUILD_SHARED_MAPL=OFF" + run_unit_tests: true + ctest_options: "-LE 'PERFORMANCE|EXTDATA1G_BIG_TESTS|EXTDATA2G_BIG_TESTS' --output-on-failure" + + # Build GEOSgcm + - ci/build: + name: build-GEOSgcm-on-<< matrix.compiler >> context: - docker-hub-creds - - build-GEOSgcm: - name: build-GEOSgcm-on-<< matrix.compiler >> matrix: parameters: compiler: [gfortran, ifort] + baselibs_version: *baselibs_version + repo: GEOSgcm + checkout_fixture: true + mepodevelop: true + checkout_mapl_branch: true + persist_workspace: true # Needs to be true to run fv3/gcm experiment, costs extra, retained for one day + + # Build GEOSldas + - ci/build: + name: build-GEOSldas-on-<< matrix.compiler >> context: - docker-hub-creds - ################################################### - # - make-FV3-exp: # - # name: make-FV3-exp-on-<< matrix.compiler >> # - # matrix: # - # parameters: # - # compiler: [gfortran, ifort] # - # context: # - # - docker-hub-creds # - # requires: # - # - build-GEOSgcm-on-<< matrix.compiler >> # - # - run-FV3: # - # name: run-FV3-on-<< matrix.compiler >> # - # matrix: # - # parameters: # - # compiler: [gfortran, ifort] # - # context: # - # - docker-hub-creds # - # requires: # - # - make-FV3-exp-on-<< matrix.compiler >> # - ################################################### - - build-GEOSldas: - name: build-GEOSldas-on-<< matrix.compiler >> matrix: parameters: compiler: [gfortran, ifort] + baselibs_version: *baselibs_version + repo: GEOSldas + mepodevelop: false + checkout_fixture: true + fixture_branch: develop + checkout_mapl_branch: true + + # Build GEOSadas (ifort only, needs a couple develop branches) + - ci/build: + name: build-GEOSadas-on-<< matrix.compiler >> context: - docker-hub-creds - - build-GEOSadas: - name: build-GEOSadas-on-<< matrix.compiler >> matrix: parameters: compiler: [ifort] - context: - - docker-hub-creds - -jobs: - build-and-test-MAPL: - parameters: - compiler: - type: string - executor: circleci-tools/<< parameters.compiler >> - working_directory: /root/project - steps: - - checkout: - path: MAPL - - circleci-tools/versions: - compiler: << parameters.compiler >> - - circleci-tools/mepoclone: - repo: MAPL - - circleci-tools/cmake: - repo: MAPL - compiler: << parameters.compiler >> - - circleci-tools/buildinstall: - repo: MAPL - - run: - name: "Build MAPL Unit Tests" - command: | - cd ${CIRCLE_WORKING_DIRECTORY}/workspace/build-MAPL - make -j"$(nproc)" build-tests |& tee /logfiles/build-tests.log - - run: - name: "Run MAPL Unit Tests" - command: | - cd ${CIRCLE_WORKING_DIRECTORY}/workspace/build-MAPL - # skip Performance tests (maybe doable on CircleCI?) - ctest -R MAPL -LE PERFORMANCE --output-on-failure |& tee /logfiles/ctest.log - - circleci-tools/compress_artifacts - - store_artifacts: - path: /logfiles - - build-UFS-MAPL: - parameters: - compiler: - type: string - executor: circleci-tools/<< parameters.compiler >> - working_directory: /root/project - steps: - - checkout: - path: MAPL - - circleci-tools/versions: - compiler: << parameters.compiler >> - - circleci-tools/mepoclone: - repo: MAPL - - circleci-tools/cmake: - repo: MAPL - compiler: << parameters.compiler >> - extra_cmake_options: "-DBUILD_WITH_FLAP=OFF -DBUILD_WITH_PFLOGGER=OFF -DBUILD_SHARED_MAPL=OFF" - - circleci-tools/buildinstall: - repo: MAPL - - run: - name: "Build MAPL Unit Tests" - command: | - cd ${CIRCLE_WORKING_DIRECTORY}/workspace/build-MAPL - make -j"$(nproc)" build-tests |& tee /logfiles/build-tests.log - - run: - name: "Run MAPL Unit Tests" - command: | - cd ${CIRCLE_WORKING_DIRECTORY}/workspace/build-MAPL - # skip Performance tests (maybe doable on CircleCI?) - ctest -R MAPL -LE PERFORMANCE --output-on-failure |& tee /logfiles/ctest.log - - circleci-tools/compress_artifacts - - store_artifacts: - path: /logfiles - - build-GEOSgcm: - parameters: - compiler: - type: string - executor: circleci-tools/<< parameters.compiler >> - working_directory: /root/project - steps: - - circleci-tools/checkout_fixture - - circleci-tools/mepoclone - - circleci-tools/mepodevelop - - circleci-tools/checkout_mapl_branch - - circleci-tools/cmake: - compiler: << parameters.compiler >> - - circleci-tools/buildinstall - - circleci-tools/compress_artifacts - - store_artifacts: - path: /logfiles - - ###################################################### - # # We need to persist the install for the next step # - # # but only if we are running FV3 tests # - # - persist_to_workspace: # - # root: workspace # - # paths: # - # - install-GEOSgcm # - ###################################################### - - build-GEOSldas: - parameters: - compiler: - type: string - executor: circleci-tools/<< parameters.compiler >> - working_directory: /root/project - steps: - - circleci-tools/checkout_fixture: - repo: GEOSldas - - circleci-tools/checkout_branch_on_fixture: - repo: GEOSldas - branch: develop - - circleci-tools/mepoclone: - repo: GEOSldas - - circleci-tools/checkout_mapl_branch: - repo: GEOSldas - - circleci-tools/cmake: - repo: GEOSldas - compiler: << parameters.compiler >> - - circleci-tools/buildinstall: - repo: GEOSldas - - circleci-tools/compress_artifacts - - store_artifacts: - path: /logfiles - - build-GEOSadas: - parameters: - compiler: - type: string - executor: - name: circleci-tools/<< parameters.compiler >> - resource_class: xlarge - working_directory: /root/project - steps: - - circleci-tools/checkout_fixture: - repo: GEOSadas - - circleci-tools/checkout_branch_on_fixture: - repo: GEOSadas - branch: develop - - circleci-tools/mepoclone: - repo: GEOSadas - - circleci-tools/checkout_mapl_branch: - repo: GEOSadas - # Until GEOSadas is closer to modern GEOSgcm, we need to update the ESMA_cmake - - circleci-tools/checkout_branch_on_subrepo: - repo: GEOSadas - branch: develop - subrepo: cmake - # There is currently an issue building GEOSadas with Debug Intel. - - circleci-tools/checkout_branch_on_subrepo: - repo: GEOSadas - branch: develop - subrepo: GEOSana_GridComp - - circleci-tools/cmake: - repo: GEOSadas - compiler: << parameters.compiler >> - - circleci-tools/buildinstall: + resource_class: xlarge + baselibs_version: *baselibs_version repo: GEOSadas + checkout_fixture: true + # This branch on GEOSadas will be used to track subrepos needed + # for GEOSadas + MAPL develop much like how we do with MAPL 3 + fixture_branch: feature/mathomp4/mapldevelop + checkout_mapl_branch: true + mepodevelop: false rebuild_procs: 8 - - circleci-tools/compress_artifacts - - store_artifacts: - path: /logfiles - - make-FV3-exp: - parameters: - compiler: - type: string - executor: circleci-tools/<< parameters.compiler >> - working_directory: /root/project - steps: - - attach_workspace: - at: workspace - - run: - name: "Run fv3_setup" - command: | - cd ${CIRCLE_WORKING_DIRECTORY}/workspace/install-GEOSgcm/bin - - INPUT_FOR_SETUP=$(cat \< /tmp/input.txt - - cat /tmp/input.txt | ./fv3_setup - - run: - name: "Change FV_NX, FV_NY, and RUN_CMD" - command: | - cd ${CIRCLE_WORKING_DIRECTORY}/workspace/test-fv3-c12 - sed -i.bak -e '/set FV_NX/ s/\([0-9]\+\)/1/' -e '/set FV_NY/ s/\([0-9]\+\)/6/' -e '/set RUN_CMD/ c\set RUN_CMD = "mpirun -np "' fv3.j - - run: - name: "Cat fv3.j" - command: | - cd ${CIRCLE_WORKING_DIRECTORY}/workspace/test-fv3-c12 - cat fv3.j - - # We need to persist the install for the next step - - persist_to_workspace: - root: workspace - paths: - - test-fv3-c12 - - run-FV3: - parameters: - compiler: - type: string - executor: circleci-tools/<< parameters.compiler >> - working_directory: /root/project - steps: - - attach_workspace: - at: workspace - - run: - name: "Run fv3.j" - command: | - mkdir -p /logfiles - cd ${CIRCLE_WORKING_DIRECTORY}/workspace/test-fv3-c12 - ./fv3.j |& tee /logfiles/fv3_run.log - - run: - name: "Check for EGRESS" - command: | - cd ${CIRCLE_WORKING_DIRECTORY}/workspace/test-fv3-c12 - - # The scratch directory for fv3 standalone isn't consistent - SCRDIR=$(find . -type d -name 'scratch*') - - if [[ -f $SCRDIR/EGRESS ]] - then - echo "EGRESS found!" - else - echo "EGRESS not found!" - exit 1 - fi - - circleci-tools/compress_artifacts - - store_artifacts: - path: /logfiles + # Run GCM (1 hour, no ExtData) + - ci/run_gcm: + name: run-GCM-on-<< matrix.compiler >> + context: + - docker-hub-creds + matrix: + parameters: + compiler: [gfortran, ifort] + requires: + - build-GEOSgcm-on-<< matrix.compiler >> + repo: GEOSgcm + baselibs_version: *baselibs_version + bcs_version: *bcs_version + + # Run MAPL Tutorials + - ci/run_mapl_tutorial: + name: run-<< matrix.tutorial_name >>-Tutorial-with-<< matrix.compiler >> + context: + - docker-hub-creds + matrix: + parameters: + compiler: [gfortran, ifort] + tutorial_name: + - hello_world + - parent_no_children + - parent_one_child_import_via_extdata + - parent_one_child_no_imports + - parent_two_siblings_connect_import_export + # We will only run the tutorials with GNU make. No need to double up + # as Ninja is a build test only + requires: + - build-and-test-MAPL-on-<< matrix.compiler >>-using-Unix Makefiles + baselibs_version: *baselibs_version diff --git a/.github/workflows/changelog-enforcer.yml b/.github/workflows/changelog-enforcer.yml index 1bebbe2e66e3..69271f96a3f5 100644 --- a/.github/workflows/changelog-enforcer.yml +++ b/.github/workflows/changelog-enforcer.yml @@ -1,21 +1,21 @@ -# name: "Enforce Changelog" -# on: -# pull_request: -# types: [opened, synchronize, reopened, ready_for_review, labeled, unlabeled] +name: "Enforce Changelog" +on: + pull_request: + types: [opened, synchronize, reopened, ready_for_review, labeled, unlabeled] -# jobs: -# # Enforces the update of a changelog file on every pull request -# changelog: -# runs-on: ubuntu-latest -# steps: -# - uses: dangoslen/changelog-enforcer@v3 -# with: -# changeLogPath: 'CHANGELOG.md' -# skipLabels: 'Skip Changelog,0 diff trivial,automatic' -# missingUpdateErrorMessage: > -# No update to CHANGELOG.md found! Please add a changelog -# entry to it describing your change. Please note that the -# keepachangelog (https://keepachangelog.com) format is -# used. If your change is very trivial not applicable for a -# changelog entry, add a 'Skip Changelog' label to the pull -# request to skip the changelog enforcer. +#jobs: +# # Enforces the update of a changelog file on every pull request +# changelog: +# runs-on: ubuntu-latest +# steps: +# - uses: dangoslen/changelog-enforcer@v3 +# with: +# changeLogPath: 'CHANGELOG.md' +# skipLabels: 'Skip Changelog,0 diff trivial,automatic' +# missingUpdateErrorMessage: > +# No update to CHANGELOG.md found! Please add a changelog +# entry to it describing your change. Please note that the +# keepachangelog (https://keepachangelog.com) format is +# used. If your change is very trivial not applicable for a +# changelog entry, add a 'Skip Changelog' label to the pull +# request to skip the changelog enforcer. diff --git a/.github/workflows/validate_yaml_files.yml b/.github/workflows/validate_yaml_files.yml new file mode 100644 index 000000000000..ff19b0d6e695 --- /dev/null +++ b/.github/workflows/validate_yaml_files.yml @@ -0,0 +1,31 @@ +--- + +# Based on code from https://github.com/marketplace/actions/yaml-lint + +name: Yaml Lint + +on: + pull_request: + types: [opened, synchronize, reopened, ready_for_review, labeled, unlabeled] + +# This validation is equivalent to running on the command line: +# yamllint -d relaxed --no-warnings +# and is controlled by the .yamllint.yml file +jobs: + validate-YAML: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - id: yaml-lint + name: yaml-lint + uses: ibiqlik/action-yamllint@v3 + with: + no_warnings: true + format: colored + config_file: .yamllint.yml + + - uses: actions/upload-artifact@v2 + if: always() + with: + name: yamllint-logfile + path: ${{ steps.yaml-lint.outputs.logfile }} diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 59e899eaa892..3414db7a9a34 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -12,171 +12,112 @@ # - ".github/PULL_REQUEST_TEMPLATE.md" # - ".editorconfig" -# jobs: -# build_test_mapl: -# name: Build and Test MAPL -# runs-on: ubuntu-latest -# container: -# image: gmao/ubuntu20-geos-env-mkl:v6.2.8-openmpi_4.0.6-gcc_11.2.0 -# # Per https://github.com/actions/virtual-environments/issues/1445#issuecomment-713861495 -# # It seems like we might not need secrets on GitHub Actions which is good for forked -# # pull requests -# #credentials: -# #username: ${{ secrets.DOCKERHUB_USERNAME }} -# #password: ${{ secrets.DOCKERHUB_TOKEN }} -# env: -# OMPI_ALLOW_RUN_AS_ROOT: 1 -# OMPI_ALLOW_RUN_AS_ROOT_CONFIRM: 1 -# OMPI_MCA_btl_vader_single_copy_mechanism: none -# steps: -# - name: Cancel Previous Runs -# uses: styfle/cancel-workflow-action@0.9.0 -# with: -# access_token: ${{ github.token }} -# - name: Checkout -# uses: actions/checkout@v2 -# with: -# fetch-depth: 1 -# - name: Versions etc. -# run: | -# gfortran --version -# mpirun --version -# echo $BASEDIR -# - name: Mepo clone external repos -# run: | -# mepo init -# mepo clone -# mepo status -# - name: CMake -# run: | -# mkdir build -# cd build -# cmake .. -DBASEDIR=$BASEDIR/Linux -DCMAKE_Fortran_COMPILER=gfortran -DCMAKE_BUILD_TYPE=Debug -DMPIEXEC_PREFLAGS='--oversubscribe' -# - name: Build -# run: | -# cd build -# make -j4 install -# - name: Run MAPL unit tests -# run: | -# cd build -# make -j4 build-tests -# # skip performance tests -# ctest -R MAPL -LE PERFORMANCE --output-on-failure -# ############################################################################################################################################################ -# # build_gcm: # -# # name: Build GEOSgcm # -# # if: "!contains(github.event.pull_request.labels.*.name, '0 diff trivial')" # -# # runs-on: ubuntu-latest # -# # container: # -# # image: gmao/ubuntu20-geos-env-mkl:v6.2.8-openmpi_4.0.6-gcc_11.2.0 # -# # env: # -# # OMPI_ALLOW_RUN_AS_ROOT: 1 # -# # OMPI_ALLOW_RUN_AS_ROOT_CONFIRM: 1 # -# # OMPI_MCA_btl_vader_single_copy_mechanism: none # -# # steps: # -# # - name: Cancel Previous Runs # -# # uses: styfle/cancel-workflow-action@0.9.0 # -# # with: # -# # access_token: ${{ github.token }} # -# # - name: Checkout GCM # -# # uses: actions/checkout@v2 # -# # with: # -# # repository: GEOS-ESM/GEOSgcm # -# # fetch-depth: 1 # -# # - name: Versions etc. # -# # run: | # -# # gfortran --version # -# # mpirun --version # -# # echo $BASEDIR # -# # echo ${GITHUB_HEAD_REF} # -# # echo ${{github.ref}} # -# # echo ${{github.head_ref}} # -# # - name: Mepo clone external repos # -# # run: | # -# # mepo init # -# # mepo clone # -# # mepo status # -# # mepo develop GEOSgcm_GridComp GEOSgcm_App # -# # mepo status # -# # # The next two actions use: # -# # # https://github.uint.cloudmunity/t/is-there-a-way-to-tell-if-a-pr-is-from-a-forked-repository/134186/7?u=mathomp4 # -# # # to test if you are in a fork or not # -# # - name: Git checkout MAPL branch (forks) # -# # if: github.event.pull_request.head.repo.full_name != github.repository # -# # working-directory: ./src/Shared/@MAPL # -# # run: | # -# # # GITHUB_REF will look like 'refs/pull/669/merge' and we want 'pull/669' # -# # GITHUB_REF_STRIP_REFS=${GITHUB_REF##refs/} # -# # GITHUB_REF_STRIP_MERGE=${GITHUB_REF_STRIP_REFS%%/merge} # -# # # This was figured out with looking at CircleCI output # -# # git fetch --force origin "${GITHUB_REF_STRIP_MERGE}/head:remotes/origin/${GITHUB_REF_STRIP_MERGE}" # -# # mepo checkout ${GITHUB_REF_STRIP_MERGE} MAPL # -# # mepo status # -# # # If we are in the same org, this will work # -# # - name: Mepo checkout MAPL branch (same org), MAPL on main/develop # -# # if: github.event.pull_request.head.repo.full_name == github.repository && (github.head_ref == 'main' || github.head_ref == 'develop') # -# # run: | # -# # mepo checkout ${GITHUB_HEAD_REF} MAPL # -# # mepo status # -# # # If we are in the same org, this will work # -# # - name: Mepo checkout MAPL branch (same org), MAPL not on main/develop # -# # if: github.event.pull_request.head.repo.full_name == github.repository && (github.head_ref != 'main' && github.head_ref != 'develop') # -# # run: | # -# # mepo checkout ${GITHUB_HEAD_REF} MAPL # -# # mepo checkout-if-exists ${GITHUB_HEAD_REF} # -# # mepo status # -# # - name: CMake # -# # run: | # -# # mkdir build # -# # cd build # -# # cmake .. -DBASEDIR=$BASEDIR/Linux -DCMAKE_Fortran_COMPILER=gfortran -DCMAKE_BUILD_TYPE=Debug -DMPIEXEC_PREFLAGS='--oversubscribe' -DUSE_F2PY=OFF # -# # - name: Build # -# # run: | # -# # cd build # -# # make -j4 install # -# ############################################################################################################################################################ -# build_test_mapl_intel: -# name: Build and Test MAPL Intel -# runs-on: ubuntu-latest -# container: -# image: gmao/ubuntu20-geos-env:v6.2.8-intelmpi_2021.3.0-intel_2021.3.0 -# # Per https://github.com/actions/virtual-environments/issues/1445#issuecomment-713861495 -# # It seems like we might not need secrets on GitHub Actions which is good for forked -# # pull requests -# #credentials: -# #username: ${{ secrets.DOCKERHUB_USERNAME }} -# #password: ${{ secrets.DOCKERHUB_TOKEN }} -# steps: -# - name: Cancel Previous Runs -# uses: styfle/cancel-workflow-action@0.9.0 -# with: -# access_token: ${{ github.token }} -# - name: Checkout -# uses: actions/checkout@v2 -# with: -# fetch-depth: 1 -# - name: Versions etc. -# run: | -# ifort --version -# mpirun --version -# echo $BASEDIR -# - name: Mepo clone external repos -# run: | -# mepo init -# mepo clone -# mepo status -# - name: CMake -# run: | -# mkdir build -# cd build -# cmake .. -DBASEDIR=$BASEDIR/Linux -DCMAKE_Fortran_COMPILER=ifort -DCMAKE_BUILD_TYPE=Debug -# - name: Build -# run: | -# cd build -# make -j4 install -# - name: Run MAPL unit tests -# run: | -# cd build -# make -j4 build-tests -# # skip performance tests -# ctest -R MAPL -LE PERFORMANCE --output-on-failure +#jobs: +# build_test_mapl: +# name: Build and Test MAPL GNU +# runs-on: ubuntu-latest +# container: +# image: gmao/ubuntu20-geos-env-mkl:v7.5.0-openmpi_4.1.2-gcc_11.2.0 +# # Per https://github.com/actions/virtual-environments/issues/1445#issuecomment-713861495 +# # It seems like we might not need secrets on GitHub Actions which is good for forked +# # pull requests +# #credentials: +# #username: ${{ secrets.DOCKERHUB_USERNAME }} +# #password: ${{ secrets.DOCKERHUB_TOKEN }} +# env: +# OMPI_ALLOW_RUN_AS_ROOT: 1 +# OMPI_ALLOW_RUN_AS_ROOT_CONFIRM: 1 +# OMPI_MCA_btl_vader_single_copy_mechanism: none +# steps: +# - name: Cancel Previous Runs +# uses: styfle/cancel-workflow-action@0.9.1 +# with: +# access_token: ${{ github.token }} +# - name: Checkout +# uses: actions/checkout@v3 +# with: +# fetch-depth: 1 +# - name: Set all directories as git safe +# run: | +# git config --global --add safe.directory '*' +# - name: Versions etc. +# run: | +# gfortran --version +# mpirun --version +# echo $BASEDIR +# - name: Mepo clone external repos +# run: | +# mepo init +# mepo clone +# mepo status +# - name: CMake +# run: | +# mkdir build +# cd build +# cmake .. -DBASEDIR=$BASEDIR/Linux -DCMAKE_Fortran_COMPILER=gfortran -DCMAKE_BUILD_TYPE=Debug -DMPIEXEC_PREFLAGS='--oversubscribe' +# - name: Build +# run: | +# cd build +# make -j4 install +# - name: Run MAPL unit tests +# run: | +# cd build +# make -j4 build-tests +# # skip performance tests +# # NOTE: Currently Open MPI fails on the bundleio with: +# # +# # The OSC pt2pt component does not support MPI_THREAD_MULTIPLE in this release. +# # Workarounds are to run on a single node, or to use a system with an RDMA +# # capable network such as Infiniband. +# # +# # For now, we run GNU/Open MPI without the bundleio tests. Some indications that +# # Open MPI 5 will not have this limitation +# ctest -E bundleio -LE 'PERFORMANCE|EXTDATA1G_BIG_TESTS|EXTDATA2G_BIG_TESTS' --output-on-failure +# build_test_mapl_intel: +# name: Build and Test MAPL Intel +# runs-on: ubuntu-latest +# container: +# image: gmao/ubuntu20-geos-env:v7.5.0-intelmpi_2021.3.0-intel_2021.3.0 +# # Per https://github.com/actions/virtual-environments/issues/1445#issuecomment-713861495 +# # It seems like we might not need secrets on GitHub Actions which is good for forked +# # pull requests +# #credentials: +# #username: ${{ secrets.DOCKERHUB_USERNAME }} +# #password: ${{ secrets.DOCKERHUB_TOKEN }} +# steps: +# - name: Cancel Previous Runs +# uses: styfle/cancel-workflow-action@0.9.1 +# with: +# access_token: ${{ github.token }} +# - name: Checkout +# uses: actions/checkout@v3 +# with: +# fetch-depth: 1 +# - name: Set all directories as git safe +# run: | +# git config --global --add safe.directory '*' +# - name: Versions etc. +# run: | +# ifort --version +# mpirun --version +# echo $BASEDIR +# - name: Mepo clone external repos +# run: | +# mepo init +# mepo clone +# mepo status +# - name: CMake +# run: | +# mkdir build +# cd build +# cmake .. -DBASEDIR=$BASEDIR/Linux -DCMAKE_Fortran_COMPILER=ifort -DCMAKE_BUILD_TYPE=Debug +# - name: Build +# run: | +# cd build +# make -j4 install +# - name: Run MAPL unit tests +# run: | +# cd build +# make -j4 build-tests +# # skip performance tests +# ctest -LE 'PERFORMANCE|EXTDATA1G_BIG_TESTS|EXTDATA2G_BIG_TESTS' --output-on-failure diff --git a/.gitignore b/.gitignore index d51c0ed63e21..86c0ee8b8263 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,10 @@ /.mepo/ *.py.bak CMakeUserPresets.json + +*.swp +*.swo +.DS_Store +*# +.#* +**/CVS/ diff --git a/.yamllint.yml b/.yamllint.yml new file mode 100644 index 000000000000..83f5340c7fdf --- /dev/null +++ b/.yamllint.yml @@ -0,0 +1,29 @@ +--- + +extends: default + +rules: + braces: + level: warning + max-spaces-inside: 1 + brackets: + level: warning + max-spaces-inside: 1 + colons: + level: warning + commas: + level: warning + comments: disable + comments-indentation: disable + document-start: disable + empty-lines: + level: warning + hyphens: + level: warning + indentation: + level: warning + indent-sequences: consistent + line-length: + level: warning + allow-non-breakable-inline-mappings: true + truthy: disable diff --git a/Apps/MAPL_GridCompSpecs_ACG.py b/Apps/MAPL_GridCompSpecs_ACG.py index b65e51d3a808..990e4c63ee2a 100755 --- a/Apps/MAPL_GridCompSpecs_ACG.py +++ b/Apps/MAPL_GridCompSpecs_ACG.py @@ -73,16 +73,11 @@ def get_rank(self): @staticmethod def internal_name(name): - if name[-1] == '*': - return name[:-1] - else: - return name + return name.replace('*','') + @staticmethod def mangled_name(name): - if name[-1] == '*': - return "'" + name[:-1] + "'//trim(comp_name)" - else: - return "'" + name + "'" + return "'" + name.replace("*","'//trim(comp_name)//'") + "'" # Pointers must be declared regardless of COND status. Deactivated # pointers should not be _referenced_ but such sections should still diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c55472112fd..e80d4e505881 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,224 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Deprecated +## [2.26.0] - 2022-09-16 + +### Fixed + +- Change the logic to check if the field is already connected to a valid grid. If yes, we bypass the checks for tilegrid (issue #1654) +- Removed unnecessary DSO extension assert +- Fixed bug that required a /dev/null ExtData entry to still have a file variable name +- Fixed bug with checking for duplicate alias in collection +- Added protection in History to only allow `instantaneous` or `time-averaged` modes + +### Added + +- Added Ninja build of MAPL to CI tests + +### Changed + +- Have `MAPL_AddChildFromDSO` call `MAPL_AddChildFromDSOMeta` (#1598) + +### Removed + +- Removed unused code from History GridComp + +## [2.25.0] - 2022-09-01 + +### Fixed + +- Fix setting stretched grid target latitude and longitude from restart file metadata + +### Added + +- Added member function get_global_var to FileMetadata +- Added option to build source tarfile when building MAPL standalone. By default this is `OFF`, but can be enabled with + `-DINSTALL_SOURCE_TARFILE=ON` +- Added `regrid_method` metadata to History output +- Added an overloaded interface for MAPL_BalanceWork to handle both REAL32 and REAL64 + +### Changed + +- Updated `components.yaml` to match GEOSgcm v10.22.5 (actually a bit beyond) + - ESMA_env v4.2.0 → v4.4.0 (Update to Intel 2022.1, Add TOSS4 Support at NAS) + - ESMA_cmake v3.17.0 → v3.18.0 (Updates to CPack and Provisional M2 Support) + +### Removed + +- Removed `LatLonGridFactory_basic` factory constructor (dead code) +## [2.24.0] - 2022-08-08 + +### Fixed + +- Fix error trapping in bundleio test + +### Added + +- Add tutorials +- Check for duplicate entries in the History.rc file +- Check that a user-provided chunking in the History.rc is compatible with the output grid +- If a user requests CFIOasync in the History.rc, print warning and set to CFIO +- Added option allow writing to pre-existing files with History + +### Changed + +- Replaced deprecated __RC__ macro with _RC and remove unused code in ExtData2G +- Moved to `checkout@v3` action due to git safe directory issue +- Added tutorials to CI + +## [2.23.1] - 2022-07-15 + +### Fixed + +- Fixed the History file existence detection to only run for netCDF output. For still unknown reasons, this detection has an issue + with binary output (see https://github.com/GEOS-ESM/GEOSldas/pull/568) +- Fix GitHub Actions + +## [2.23.0] - 2022-07-06 + +### Added + +- Check return codes for YAML files when parsing in ExtData2G + +### Changed + +- Updated the ESMA_env version to v4.2.0 (Baselibs 7.5.0 → GFE v1.4.0) + - With this update, MAPL now **requires** these versions of GFE libraries + - yaFyaml v1.0.4 (if building with ExtData2G support) + - pFlogger v1.9.1 (if building with pFlogger support) +- Update the CI for Baselibs 7.5.0, BCs version 10.22.3 + +## [2.22.0] - 2022-06-24 + +### Fixed + +- By pass the check of the missing value of Nan +- Update CI to work with latest GEOSadas `develop` (Uses a special branch of GEOSadas) +- Fix bundleio tests +- HistoryGridComp now checks if a file exists already before writing and errors out if so +- Minor updates for FORD documentation testing + - Add `program` statements to some test programs + - Remove `pfio/pfio_io_demo.F90` as dead code + - Fix redefinition of `_RETURN` in `pflogger_stub.F90` + - Removed unused `Test_SimpleClient.pf` +- Update CMake to require NetCDF C components and add `NetCDF::NetCDF_C` to pfio CMake + +### Added + +- Updated MAPL_CapGridComp to mark fields going to ExtData to not be checkpointed by components +- Add debug loggers for start/stop during stages in MAPL_Generic +- Handling for double precision input when retrieving single precision attributes +- Enable GCM run test in CircleCI (1-hour, no ExtData) +- Added monotonic regridding option +- Make availalbe to History and ExtData2G all supported regridding methods +- Add test cases for ExtData +- Add YAML validator GitHub Action + - This action makes sure all YAML files are valid (to a relaxed standard) + +### Changed + +- Modified error messages in FileMetadataUtilities to be unique and print filename +- Updated the ESMA_env version to v3.14.0 +- Updated the ESMA_cmake version to v3.17.0 +- Updated GitHub Actions MAPL build tests +- Added assert for missing file with ExtData2G +- Re-enable bundleio tests in CI +- Updated CircleCI to use latest Baselibs +- Updates for Spack support + - Add `find_package(MPI)` for non-Baselibs builds + - Add explicit interface dependence of `MPI` for `ESMF` target + - Add `esmf` alias library for `ESMF` for compatibility + +## [2.21.3] - 2022-06-07 + +### Fixed + +- Fixed bug in non cubed-sphere grid path in MAPL_GetHorzIJIndex + +## [2.21.2] - 2022-05-31 + +### Fixed + +- Initialize `cap%lperp` in `MAPL_CapGridComp.F90` (see Issue #1530) + +## [2.21.1] - 2022-05-24 + +### Fixed + +- Adding missing _RETURN and _VERIFY macros in GriddedIO.F90 +- Update CircleCI to work with latest GEOSadas + +## [2.21.0] - 2022-05-05 + +### Fixed + +- Fixed incorrect legend when using PRINTSPEC option in MAPL Cap +- Fix ESMF errors exposed by monthly collections + +### Added + +- Added has_variable function to FileMetadata +- Added information about the container type for each item in state when using PRINTSPEC option + +### Changed + +- Change many instances of `_ASSERT(.false.,"msg")` to `_FAIL("msg")` +- Extended format width for exclusive and inclusive times in profiler from `f9.2` to `f10.2` (see #1420) + +## [2.20.0] - 2022-04-19 + +### Fixed + +- Removed one redundant get_file_extension call +- Fix issue where ACG was called when no file had changed +- Add missing `rc=status` in `MAPL_GetResourceFromMAPL_scalar` +- Fixed bugs with next generation ExtData +- Fixed variable PTR40 declaration in GenericCplComp.F90 + +### Added + +- Added support for 4d variables in the coupler. Intentionally decided not to support 4d in the coupler's ReadRestart and WriteRestart to catch errors +- Added ability to use multiple rules for different time periods in next generation ExtData + +### Changed + +- Cleaned up a bit of old CMake +- Updated CircleCI config to use new orb `build` job +- Updated `components.yaml` to match GEOSgcm v10.22.1 + - ESMA_env v3.13.0 + - ESMA_cmake v3.12.0 + +## [2.19.2] - 2022-03-28 + +### Fixed + +- Provided workaround for GNU bug when defining file metadata in cubed-sphere grid factory (similar to Issue #1433 and its solution) + +## [2.19.1] - 2022-03-24 + +### Fixed + +- Fix a bug deallocating a pointer potentially pointing to shared memory allocated by MAPL_Shmem + +## [2.19.0] - 2022-03-18 + +### Fixed + +- Fixed duration of the clock to be the smaller of the user specified duration and (END_DATE - currTime) +- Fixes for compiling on M1 Macs (remove REAL128) +- Fix for CMake when `esmf` is already a target + +### Added + +- New cmake option USE_EXTDATA2G to enable the next generation of ExtData for development, by default uses 1st generation ExtData +- MAPL_ESMFFieldBundleRead/Write modules are now available in when using MAPL + +### Changed + +- Replaced a wild card "*" in any position of a string in MAPL_GridCompSpecs_ACG.py +- Updated `MAPL_SunGetSolarConstantFromNRLFile` to open NRL Solar Table file only on root and broadcast the tables to all processes. Now all processes do interpolation. +- Add voting interpolation method as optional argument to SimpleBundleRead method + ## [2.18.3] - 2022-03-15 ### Fixed @@ -54,6 +272,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Updates to CircleCI - Added GEOSadas CI ifort build test - Add "like-UFS" build to CI. This is no FLAP and pFlogger, and static build +- Added new `_STAT` and `_IOSTAT` macros a la `_RC` ### Changed @@ -66,6 +285,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Updated `components.yaml`. These changes are to support using Spack to build MAPL - ESMA_cmake v3.10.0 (add `FindESMF.cmake` from NOAA-EMC) - ecbuild geos/v1.2.0 (updat `FindNetCDF.cmake` to that from NOAA-EMC) +- Improved file-not-found error handling in ExtData for non-templated filenames ## [2.17.2] - 2022-02-16 diff --git a/CMakeLists.txt b/CMakeLists.txt index 5ac7c74b9679..656a205a50f5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ cmake_policy (SET CMP0054 NEW) project ( MAPL - VERSION 2.18.3 + VERSION 2.26.0 LANGUAGES Fortran CXX C) # Note - CXX is required for ESMF # Set the default build type to release @@ -26,6 +26,7 @@ set (ESMA_CMAKE_DIRS foreach (dir IN LISTS ESMA_CMAKE_DIRS) if (EXISTS ${CMAKE_CURRENT_LIST_DIR}/${dir}) list (APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/${dir}") + set (ESMA_CMAKE_PATH "${CMAKE_CURRENT_LIST_DIR}/${dir}" CACHE PATH "Path to ESMA_cmake code") include (esma) set(MAPL_STANDALONE TRUE) endif () @@ -74,8 +75,9 @@ if(NOT TARGET GFTL::gftl) # MAPL currently requires at least GFTL 1.5.1 find_package(GFTL 1.5.1 REQUIRED) else() + # Remove version check error if using GCHP #if (GFTL_VERSION VERSION_LESS 1.5.1) - # message(FATAL_ERROR "GFTL must be at least 1.5.1 - check baselibs version.") + # message(FATAL_ERROR "GFTL must be at least 1.5.1") #endif () endif() if(NOT TARGET GFTL_SHARED::gftl-shared) @@ -84,14 +86,32 @@ endif() if(NOT TARGET FARGPARSE::fargparse) find_package(FARGPARSE QUIET) endif() -if(NOT TARGET YAFYAML::yafyaml) - find_package(YAFYAML QUIET) + +option(USE_EXTDATA2G "Use ExtData2G" ON) +if(USE_EXTDATA2G) + set (EXTDATA2G_TARGET "MAPL.ExtData2G" CACHE STRING "ExtData2G Target") + if(NOT TARGET YAFYAML::yafyaml) + find_package(YAFYAML 1.0.4 REQUIRED) + else() + # Remove version check error if using GCHP + #if (YAFYAML_VERSION VERSION_LESS 1.0.4) + # message(FATAL_ERROR "yaFyaml must be at least 1.0.4") + #endif () + endif() + message (STATUS "Building with ExtData2G") +else() + set (EXTDATA2G_TARGET "" CACHE STRING "ExtData2G Target") endif() option(BUILD_WITH_PFLOGGER "Build MAPL with pFlogger library support" ON) if (BUILD_WITH_PFLOGGER) if(NOT TARGET PFLOGGER::pflogger) - find_package(PFLOGGER REQUIRED) + find_package(PFLOGGER 1.9.1 REQUIRED) + else() + # Remove version check error if using GCHP + #if (PFLOGGER_VERSION VERSION_LESS 1.9.1) + # message(FATAL_ERROR "pFlogger must be at least 1.9.1") + #endif () endif() endif() @@ -103,7 +123,10 @@ endif () ecbuild_declare_project() if (NOT Baselibs_FOUND) - find_package(NetCDF REQUIRED Fortran) + set(MPI_DETERMINE_LIBRARY_VERSION TRUE) + find_package(MPI) + + find_package(NetCDF REQUIRED C Fortran) add_definitions(-DHAS_NETCDF4) add_definitions(-DHAS_NETCDF3) add_definitions(-DNETCDF_NEED_NF_MPIIO) @@ -114,7 +137,22 @@ if (NOT Baselibs_FOUND) add_definitions(-DH5_HAVE_PARALLEL) endif() - find_package(ESMF MODULE REQUIRED) + if (NOT TARGET esmf) + find_package(ESMF MODULE REQUIRED) + + # ESMF as used in MAPL requires MPI + # NOTE: This looks odd because some versions of FindESMF.cmake out in the + # world provide an "esmf" target while others provide "ESMF". So we + # need this ugliness to support both. + if (TARGET esmf) + target_link_libraries(esmf INTERFACE MPI::MPI_Fortran) + else() + target_link_libraries(ESMF INTERFACE MPI::MPI_Fortran) + # MAPL and GEOS use lowercase target due to historical reasons but + # the latest FindESMF.cmake file from ESMF produces an ESMF target. + add_library(esmf ALIAS ESMF) + endif() + endif () endif () if (BUILD_WITH_PFLOGGER) @@ -137,6 +175,9 @@ add_subdirectory (base) add_subdirectory (MAPL) add_subdirectory (gridcomps) add_subdirectory (griddedio) +if (BUILD_WITH_FLAP) + add_subdirectory (tutorial) +endif() if (PFUNIT_FOUND) include (add_pfunit_ctest) @@ -183,5 +224,18 @@ ecbuild_install_project (NAME MAPL) # This must be after ecbuild_install_project if (MAPL_STANDALONE) - include (esma_cpack OPTIONAL) + # We only care about CPack if MAPL is a standalone + include (esma_cpack OPTIONAL RESULT_VARIABLE esma_cpack_FOUND) + if (esma_cpack_FOUND) + message(STATUS "esma_cpack_FOUND: ${esma_cpack_FOUND}") + + # This installs a tarball of the source code + # in the installation directory. + # MUST BE THE LAST CODE IN THIS FILE + option(INSTALL_SOURCE_TARFILE "Create and install source tarfile" OFF) + if(INSTALL_SOURCE_TARFILE) + install(CODE "set(CMAKE_PROJECT_NAME \"${CMAKE_PROJECT_NAME}\")") + install(SCRIPT "${ESMA_CMAKE_PATH}/esma_postinstall.cmake") + endif() + endif () endif () diff --git a/MAPL/CMakeLists.txt b/MAPL/CMakeLists.txt index 84f4fdc5ae8d..14e6adabd1fe 100644 --- a/MAPL/CMakeLists.txt +++ b/MAPL/CMakeLists.txt @@ -4,11 +4,13 @@ esma_set_this() # GCHP note: customized esma_add_library (${this} SRCS MAPL.F90 - DEPENDENCIES MAPL.base MAPL.generic MAPL.pfio MAPL_cfio_r4 MAPL.gridcomps MAPL.orbit MAPL.griddedio + DEPENDENCIES MAPL.base MAPL.generic MAPL.pfio MAPL_cfio_r4 MAPL.gridcomps MAPL.orbit MAPL.griddedio ${EXTDATA_TARGET} esmf NetCDF::NetCDF_Fortran MPI::MPI_Fortran $<$:FLAP::FLAP> - TYPE ${MAPL_LIBRARY_TYPE} + TYPE ${MAPL_LIBRARY_TYPE} ) +target_compile_definitions (${this} PRIVATE $<$:BUILD_WITH_EXTDATA2G>) + target_include_directories (${this} PUBLIC $) diff --git a/MAPL/MAPL.F90 b/MAPL/MAPL.F90 index 6022c41e7dd3..6751de902c0a 100644 --- a/MAPL/MAPL.F90 +++ b/MAPL/MAPL.F90 @@ -4,11 +4,12 @@ module MAPL use MAPLBase_mod use MAPL_GenericMod use MAPL_VarSpecMiscMod - use MAPL_ExtDataGridCompMod, only: T_EXTDATA_STATE, EXTDATA_WRAP use ESMF_CFIOMod use pFIO use MAPL_GridCompsMod use mapl_StubComponent + use MAPL_ESMFFieldBundleRead + use MAPL_ESMFFieldBundleWrite implicit none end module MAPL diff --git a/MAPL_cfio/CMakeLists.txt b/MAPL_cfio/CMakeLists.txt index 342cdc9e0c75..e6cfd498a7f0 100755 --- a/MAPL_cfio/CMakeLists.txt +++ b/MAPL_cfio/CMakeLists.txt @@ -4,12 +4,12 @@ string (REPLACE MAPL_cfio_ "" precision ${this}) set (srcs ESMF_CFIOBaseMod.f - ESMF_CFIOFileMod.F90 - ESMF_CFIOGridMod.F90 - ESMF_CFIOMod.F90 - ESMF_CFIOSdfMod.F90 - ESMF_CFIOUtilMod.F90 - ESMF_CFIOVarInfoMod.F90 + ESMF_CFIOFileMod.F90 + ESMF_CFIOGridMod.F90 + ESMF_CFIOMod.F90 + ESMF_CFIOSdfMod.F90 + ESMF_CFIOUtilMod.F90 + ESMF_CFIOVarInfoMod.F90 ShaveMantissa.c ) diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index e3e9ae8c9808..216bcf16855f 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -17,6 +17,7 @@ if (BUILD_WITH_FLAP) target_link_libraries(ExtDataDriver.x PRIVATE OpenMP::OpenMP_Fortran) endif () set_target_properties(ExtDataDriver.x PROPERTIES Fortran_MODULE_DIRECTORY ${MODULE_DIRECTORY}) + target_compile_definitions (ExtDataDriver.x PRIVATE $<$:BUILD_WITH_EXTDATA2G>) ecbuild_add_executable (TARGET pfio_MAPL_demo.x SOURCES pfio_MAPL_demo.F90) target_link_libraries (pfio_MAPL_demo.x PRIVATE MAPL FLAP::FLAP esmf) @@ -25,9 +26,6 @@ if (BUILD_WITH_FLAP) target_link_libraries(pfio_MAPL_demo.x PRIVATE OpenMP::OpenMP_Fortran) endif () set_target_properties(pfio_MAPL_demo.x PROPERTIES Fortran_MODULE_DIRECTORY ${MODULE_DIRECTORY}) + add_subdirectory(ExtData_Testing_Framework EXCLUDE_FROM_ALL) endif () - -#install(PROGRAMS ExtDataDriver.x DESTINATION bin) -#install(TARGETS ExtDataDriver.x DESTINATION bin) - diff --git a/Tests/ExtDataDriverGridComp.F90 b/Tests/ExtDataDriverGridComp.F90 index f93681785932..bb2c3be3be05 100644 --- a/Tests/ExtDataDriverGridComp.F90 +++ b/Tests/ExtDataDriverGridComp.F90 @@ -4,7 +4,10 @@ module ExtData_DriverGridCompMod use ESMF use MAPL - use MAPL_ExtDataGridCompMod, only : ExtData_SetServices => SetServices +#if defined(BUILD_WITH_EXTDATA2G) + use MAPL_ExtDataGridComp2G, only : ExtData2G_SetServices => SetServices +#endif + use MAPL_ExtDataGridCompMod, only : ExtData1G_SetServices => SetServices use MAPL_HistoryGridCompMod, only : Hist_SetServices => SetServices use MAPL_Profiler, only : get_global_time_profiler, BaseProfiler @@ -31,6 +34,7 @@ module ExtData_DriverGridCompMod type(ESMF_State), allocatable :: imports(:), exports(:) type(ESMF_VM) :: vm type(ESMF_Time), allocatable :: times(:) + logical :: run_fbf = .false. contains procedure :: set_services procedure :: initialize @@ -140,6 +144,7 @@ subroutine initialize_gc(gc, import_state, export_state, clock, rc) procedure(), pointer :: root_set_services type(ExtData_DriverGridComp), pointer :: cap class(BaseProfiler), pointer :: t_p + logical :: use_extdata2g _UNUSED_DUMMY(import_state) _UNUSED_DUMMY(export_state) @@ -181,6 +186,7 @@ subroutine initialize_gc(gc, import_state, export_state, clock, rc) call MAPL_Set(MAPLOBJ, name = cap%name, cf = cap%config, rc = status) _VERIFY(status) + call ESMF_ConfigGetAttribute(cap%config,cap%run_fbf,label="RUN_FBF:",default=.false.) call ESMF_ConfigGetAttribute(cap%config,cap%run_hist,label="RUN_HISTORY:",default=.true.) call ESMF_ConfigGetAttribute(cap%config,cap%run_extdata,label="RUN_EXTDATA:",default=.true.) @@ -212,6 +218,7 @@ subroutine initialize_gc(gc, import_state, export_state, clock, rc) !EOR enableTimers = ESMF_UtilStringUpperCase(enableTimers, rc = status) _VERIFY(status) + call MAPL_GetResource(maplobj,use_extdata2g,"USE_EXTDATA2G:",default=.false.,_RC) if (enableTimers /= 'YES') then call MAPL_ProfDisable(rc = status) @@ -319,10 +326,16 @@ subroutine initialize_gc(gc, import_state, export_state, clock, rc) call MAPL_Set(MAPLOBJ, CF=CAP%CF_EXT, RC=STATUS) _VERIFY(STATUS) - - cap%extdata_id = MAPL_AddChild (MAPLOBJ, name = 'EXTDATA', SS = ExtData_SetServices, rc = status) - _VERIFY(status) - + if (use_extdata2g) then +#if defined(BUILD_WITH_EXTDATA2G) + cap%extdata_id = MAPL_AddChild (MAPLOBJ, name = 'EXTDATA', SS = ExtData2G_SetServices, _RC) +#else + _FAIL('ExtData2G requested but not built') +#endif + else + cap%extdata_id = MAPL_AddChild (MAPLOBJ, name = 'EXTDATA', SS = ExtData1G_SetServices, _RC) + end if + end if ! Query MAPL for the the children's for GCS, IMPORTS, EXPORTS @@ -400,6 +413,9 @@ subroutine initialize_gc(gc, import_state, export_state, clock, rc) call cap%parseTimes(rc=status) _VERIFY(status) + if (allocated(cap%times) .and. cap%run_fbf ) then + _FAIL("can not run forwards and backwards with specific times") + end if _RETURN(ESMF_SUCCESS) end subroutine initialize_gc @@ -592,6 +608,24 @@ subroutine run_MultipleTimes(gc, rc) call cap%run_one_step(status) _VERIFY(status) enddo + else if (cap%run_fbf) then + do n=1,cap%nsteps + call ESMF_ClockAdvance(cap%clock,rc=status) + _VERIFY(status) + call cap%run_one_step(status) + _VERIFY(status) + enddo + call ESMF_ClockSet(cap%clock,direction=ESMF_DIRECTION_REVERSE,_RC) + do n=1,cap%nsteps + call ESMF_ClockAdvance(cap%clock,rc=status) + enddo + call ESMF_ClockSet(cap%clock,direction=ESMF_DIRECTION_FORWARD,_RC) + do n=1,cap%nsteps + call ESMF_ClockAdvance(cap%clock,rc=status) + _VERIFY(status) + call cap%run_one_step(status) + _VERIFY(status) + enddo else do n=1,cap%nsteps call ESMF_ClockAdvance(cap%clock,rc=status) @@ -709,7 +743,7 @@ subroutine MAPL_ClockInit ( cf, Clock, nsteps, rc) call ESMF_CalendarSetDefault(ESMF_CALKIND_NOLEAP, RC=STATUS) _VERIFY(STATUS) else - _ASSERT(.false.,'needs informative message') + _FAIL('needs informative message') endif call ESMF_ConfigGetAttribute(cf, datetime, label='BEG_DATE:',rc=status) diff --git a/Tests/ExtDataRoot_GridComp.F90 b/Tests/ExtDataRoot_GridComp.F90 index 9f17a4c920da..194e43f7e491 100644 --- a/Tests/ExtDataRoot_GridComp.F90 +++ b/Tests/ExtDataRoot_GridComp.F90 @@ -677,7 +677,7 @@ subroutine CompareState(State1,State2,tol,rc) enddo end if if (foundDiff(ii)) then - _ASSERT(.false.,'found difference when compare state') + _FAIL('found difference when compare state') end if enddo diff --git a/Tests/ExtData_Testing_Framework/CMakeLists.txt b/Tests/ExtData_Testing_Framework/CMakeLists.txt new file mode 100644 index 000000000000..a91051be6019 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/CMakeLists.txt @@ -0,0 +1,51 @@ +# Detect if we are using Open MPI and add oversubscribe +string(REPLACE " " ";" MPI_Fortran_LIBRARY_VERSION_LIST ${MPI_Fortran_LIBRARY_VERSION_STRING}) +list(GET MPI_Fortran_LIBRARY_VERSION_LIST 0 MPI_Fortran_LIBRARY_VERSION_FIRSTWORD) +if(MPI_Fortran_LIBRARY_VERSION_FIRSTWORD MATCHES "Open") + list(APPEND MPIEXEC_PREFLAGS "-oversubscribe") +endif() + +file(STRINGS "test_cases/cases.txt" TEST_CASES) + +set(cutoff "7") + +foreach(TEST_CASE ${TEST_CASES}) + if (EXISTS ${CMAKE_CURRENT_LIST_DIR}/test_cases/${TEST_CASE}/nproc.rc) + file(READ ${CMAKE_CURRENT_LIST_DIR}/test_cases/${TEST_CASE}/nproc.rc num_procs) + else() + set(num_procs "1") + endif() + add_test( + NAME "ExtData1G_${TEST_CASE}" + COMMAND ${CMAKE_COMMAND} + -DTEST_CASE=${TEST_CASE} + -DMPIEXEC_EXECUTABLE=${MPIEXEC_EXECUTABLE} + -DMPIEXEC_NUMPROC_FLAG=${MPIEXEC_NUMPROC_FLAG} + -DMY_BINARY_DIR=${CMAKE_BINARY_DIR}/bin + -DMPIEXEC_PREFLAGS=${MPIEXEC_PREFLAGS} + -DIS_EXTDATA2G=NO + -P ${CMAKE_CURRENT_SOURCE_DIR}/run_extdata.cmake + ) + if (${num_procs} LESS ${cutoff}) + set_tests_properties ("ExtData1G_${TEST_CASE}" PROPERTIES LABELS "EXTDATA1G_SMALL_TESTS") + else() + set_tests_properties ("ExtData1G_${TEST_CASE}" PROPERTIES LABELS "EXTDATA1G_BIG_TESTS") + endif() + + add_test( + NAME "ExtData2G_${TEST_CASE}" + COMMAND ${CMAKE_COMMAND} + -DTEST_CASE=${TEST_CASE} + -DMPIEXEC_EXECUTABLE=${MPIEXEC_EXECUTABLE} + -DMPIEXEC_NUMPROC_FLAG=${MPIEXEC_NUMPROC_FLAG} + -DMY_BINARY_DIR=${CMAKE_BINARY_DIR}/bin + -DMPIEXEC_PREFLAGS=${MPIEXEC_PREFLAGS} + -DIS_EXTDATA2G=YES + -P ${CMAKE_CURRENT_SOURCE_DIR}/run_extdata.cmake + ) + if (${num_procs} LESS ${cutoff}) + set_tests_properties ("ExtData2G_${TEST_CASE}" PROPERTIES LABELS "EXTDATA2G_SMALL_TESTS") + else() + set_tests_properties ("ExtData2G_${TEST_CASE}" PROPERTIES LABELS "EXTDATA2G_BIG_TESTS") + endif() +endforeach() diff --git a/Tests/ExtData_Testing_Framework/run_extdata.cmake b/Tests/ExtData_Testing_Framework/run_extdata.cmake new file mode 100644 index 000000000000..48986e47d042 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/run_extdata.cmake @@ -0,0 +1,30 @@ +macro(run_case CASE) + string(RANDOM LENGTH 24 tempdir) + execute_process( + COMMAND ${CMAKE_COMMAND} -E make_directory ${tempdir} + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_LIST_DIR}/test_cases/${CASE} ${tempdir} + ) + if (EXISTS "${tempdir}/nproc.rc") + file(READ "${tempdir}/nproc.rc" num_procs_temp) + string(STRIP ${num_procs_temp} num_procs) + else() + set(num_procs "1") + endif() + if (${IS_EXTDATA2G} STREQUAL "YES") + file(APPEND "${tempdir}/CAP1.rc" "USE_EXTDATA2G: .true.") + file(APPEND "${tempdir}/CAP2.rc" "USE_EXTDATA2G: .true.") + endif() + execute_process( + COMMAND ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} ${num_procs} ${MPIEXEC_PREFLAGS} ${MY_BINARY_DIR}/ExtDataDriver.x + RESULT_VARIABLE CMD_RESULT + WORKING_DIRECTORY ${tempdir} + #COMMAND_ECHO STDOUT + ) + execute_process( + COMMAND ${CMAKE_COMMAND} -E rm -rf ${tempdir} + ) + if(CMD_RESULT) + message(FATAL_ERROR "Error running ${CASE}") + endif() +endmacro() +run_case(${TEST_CASE}) diff --git a/Tests/ExtData_Testing_Framework/test_cases/case1/AGCM1.rc b/Tests/ExtData_Testing_Framework/test_cases/case1/AGCM1.rc new file mode 100644 index 000000000000..83ad27a2c551 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case1/AGCM1.rc @@ -0,0 +1,24 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC90x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: GenerateExports + +EXPORT_STATE:: +VAR2D , time , days , xy , c +VAR3D , time , days , xyz , c +:: + +FILL_DEF:: +VAR2D time +VAR3D time +:: + +REF_TIME: 20040701 000000 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case1/AGCM2.rc b/Tests/ExtData_Testing_Framework/test_cases/case1/AGCM2.rc new file mode 100644 index 000000000000..2e79954523bd --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case1/AGCM2.rc @@ -0,0 +1,29 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC90x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: CompareImports + +IMPORT_STATE:: +VAR2D , time , days , xy , c +VAR3D , time , days , xyz , c +:: + +EXPORT_STATE:: +VAR2D , time , days , xy , c +VAR3D , time , days , xyz , c +:: + +FILL_DEF:: +VAR2D time +VAR3D time +:: + +REF_TIME: 20040701 000000 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case1/CAP.rc b/Tests/ExtData_Testing_Framework/test_cases/case1/CAP.rc new file mode 100644 index 000000000000..680d0ffa9c5b --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case1/CAP.rc @@ -0,0 +1,4 @@ +CASES:: +CAP1.rc +CAP2.rc +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case1/CAP1.rc b/Tests/ExtData_Testing_Framework/test_cases/case1/CAP1.rc new file mode 100644 index 000000000000..ce2690d6937b --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case1/CAP1.rc @@ -0,0 +1,25 @@ +ROOT_NAME: Root +ROOT_CF: AGCM1.rc +HIST_CF: HISTORY1.rc + +BEG_DATE: 20040101 210000 + +JOB_SGMT: 00001200 000000 +HEARTBEAT_DT: 3600 + +#RUN_EXTDATA: .false. +RUN_TIMES:: +20040115 210000 +20040215 210000 +20040315 210000 +20040415 210000 +20040515 210000 +20040615 210000 +20040715 210000 +20040815 210000 +20040915 210000 +20041015 210000 +20041115 210000 +20041215 210000 +:: + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case1/CAP2.rc b/Tests/ExtData_Testing_Framework/test_cases/case1/CAP2.rc new file mode 100644 index 000000000000..4e9e1bb95026 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case1/CAP2.rc @@ -0,0 +1,15 @@ +ROOT_NAME: Root +ROOT_CF: AGCM2.rc +HIST_CF: HISTORY2.rc + +BEG_DATE: 20040101 210000 + +JOB_SGMT: 00001200 000000 +HEARTBEAT_DT: 3600 + +#RUN_EXTDATA: .false. +RUN_TIMES:: +20041125 210000 +20041126 210000 +:: + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case1/ExtData.rc b/Tests/ExtData_Testing_Framework/test_cases/case1/ExtData.rc new file mode 100644 index 000000000000..a45d1dd13f7f --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case1/ExtData.rc @@ -0,0 +1,13 @@ +#CASE_SENSITIVE_VARIABLE_NAMES: .false. +Ext_AllowExtrap: .false. +Prefetch: .true. +#DEBUG_LEVEL: 20 + +PrimaryExports%% +VAR2D NA N N 0 none none VAR2D case1.%y4.nc4 +VAR3D NA N N 0 none none VAR3D case1.%y4.nc4 +%% + + +DerivedExports%% +%% diff --git a/Tests/ExtData_Testing_Framework/test_cases/case1/HISTORY1.rc b/Tests/ExtData_Testing_Framework/test_cases/case1/HISTORY1.rc new file mode 100644 index 000000000000..51d004d9660c --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case1/HISTORY1.rc @@ -0,0 +1,13 @@ +GRID_LABELS: +:: + +COLLECTIONS: case1 +:: + + case1.template: '%y4.nc4', + case1.format: 'CFIO', + case1.frequency: 010000, + case1.duration: 000000 + case1.fields: 'VAR2D', 'Root', + 'VAR3D', 'Root', + :: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case1/HISTORY2.rc b/Tests/ExtData_Testing_Framework/test_cases/case1/HISTORY2.rc new file mode 100644 index 000000000000..2895432e995a --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case1/HISTORY2.rc @@ -0,0 +1,5 @@ +GRID_LABELS: +:: + +COLLECTIONS: +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case1/README b/Tests/ExtData_Testing_Framework/test_cases/case1/README new file mode 100644 index 000000000000..9a6d7597262d --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case1/README @@ -0,0 +1 @@ +Case, 12-month/12 time 2004 file with 2 updates, non-climatology diff --git a/Tests/ExtData_Testing_Framework/test_cases/case1/extdata.yaml b/Tests/ExtData_Testing_Framework/test_cases/case1/extdata.yaml new file mode 100644 index 000000000000..e2ddb90675ab --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case1/extdata.yaml @@ -0,0 +1,5 @@ +Collections: + fstream1: {template: case1.%y4.nc4, valid_range: "2004-01-01/2005-01-01" } +Exports: + VAR2D: {variable: VAR2D, collection: fstream1} + VAR3D: {variable: VAR3D, collection: fstream1} diff --git a/Tests/ExtData_Testing_Framework/test_cases/case10/AGCM1.rc b/Tests/ExtData_Testing_Framework/test_cases/case10/AGCM1.rc new file mode 100644 index 000000000000..302766bebfab --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case10/AGCM1.rc @@ -0,0 +1,22 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC90x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: GenerateExports + +EXPORT_STATE:: +VAR2D , time , days , xy , c +:: + +FILL_DEF:: +VAR2D time +:: + +REF_TIME: 20040701 000000 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case10/AGCM2.rc b/Tests/ExtData_Testing_Framework/test_cases/case10/AGCM2.rc new file mode 100644 index 000000000000..58616c46abc8 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case10/AGCM2.rc @@ -0,0 +1,27 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC900x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: CompareImports + +IMPORT_STATE:: +VAR2D , time , days , xy , c +:: + +EXPORT_STATE:: +VAR2D , time , days , xy , c +:: + +FILL_DEF:: +VAR2D time +:: + +CLIM_YEAR: 2005 +REF_TIME: 20040701 000000 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case10/CAP.rc b/Tests/ExtData_Testing_Framework/test_cases/case10/CAP.rc new file mode 100644 index 000000000000..680d0ffa9c5b --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case10/CAP.rc @@ -0,0 +1,4 @@ +CASES:: +CAP1.rc +CAP2.rc +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case10/CAP1.rc b/Tests/ExtData_Testing_Framework/test_cases/case10/CAP1.rc new file mode 100644 index 000000000000..7ad5b6f1a378 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case10/CAP1.rc @@ -0,0 +1,36 @@ +ROOT_NAME: Root +ROOT_CF: AGCM1.rc +HIST_CF: HISTORY1.rc + +BEG_DATE: 20040101 210000 + +JOB_SGMT: 00002400 000000 +HEARTBEAT_DT: 3600 + +RUN_TIMES:: +20040115 210000 +20040215 210000 +20040315 210000 +20040415 210000 +20040515 210000 +20040615 210000 +20040715 210000 +20040815 210000 +20040915 210000 +20041015 210000 +20041115 210000 +20041215 210000 +20050115 210000 +20050215 210000 +20050315 210000 +20050415 210000 +20050515 210000 +20050615 210000 +20050715 210000 +20050815 210000 +20050915 210000 +20051015 210000 +20051115 210000 +20051215 210000 +:: + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case10/CAP2.rc b/Tests/ExtData_Testing_Framework/test_cases/case10/CAP2.rc new file mode 100644 index 000000000000..af18ab35fe0d --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case10/CAP2.rc @@ -0,0 +1,14 @@ +ROOT_NAME: Root +ROOT_CF: AGCM2.rc +HIST_CF: HISTORY2.rc + +BEG_DATE: 20060101 210000 + +JOB_SGMT: 00001200 000000 +HEARTBEAT_DT: 3600 + +#RUN_EXTDATA: .false. +RUN_TIMES:: +20060225 210000 +:: + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case10/ExtData.rc b/Tests/ExtData_Testing_Framework/test_cases/case10/ExtData.rc new file mode 100644 index 000000000000..92697fa916f0 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case10/ExtData.rc @@ -0,0 +1,12 @@ +#CASE_SENSITIVE_VARIABLE_NAMES: .false. +Ext_AllowExtrap: .true. +Prefetch: .true. +#DEBUG_LEVEL: 20 + +PrimaryExports%% +VAR2D NA N N 0 none none VAR2D case1.%y4%m2.nc4 +%% + + +DerivedExports%% +%% diff --git a/Tests/ExtData_Testing_Framework/test_cases/case10/HISTORY1.rc b/Tests/ExtData_Testing_Framework/test_cases/case10/HISTORY1.rc new file mode 100644 index 000000000000..0b54db8e8f25 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case10/HISTORY1.rc @@ -0,0 +1,11 @@ +GRID_LABELS: +:: + +COLLECTIONS: case1 +:: + + case1.template: '%y4%m2.nc4', + case1.format: 'CFIO', + case1.frequency: 010000, + case1.fields: 'VAR2D', 'Root', + :: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case10/HISTORY2.rc b/Tests/ExtData_Testing_Framework/test_cases/case10/HISTORY2.rc new file mode 100644 index 000000000000..2895432e995a --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case10/HISTORY2.rc @@ -0,0 +1,5 @@ +GRID_LABELS: +:: + +COLLECTIONS: +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case10/README b/Tests/ExtData_Testing_Framework/test_cases/case10/README new file mode 100644 index 000000000000..d2069c0d94d4 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case10/README @@ -0,0 +1,2 @@ +Interpolation outside of data set (Harvard mode), make a multi year dataset. +Define as not a climatology and ask for data after dataset time range diff --git a/Tests/ExtData_Testing_Framework/test_cases/case10/extdata.yaml b/Tests/ExtData_Testing_Framework/test_cases/case10/extdata.yaml new file mode 100644 index 000000000000..4e9e3ccb39fb --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case10/extdata.yaml @@ -0,0 +1,6 @@ +Samplings: + extrap_clim: {extrapolation: clim} +Collections: + fstream1: {template: "case1.%y4%m2.nc4", valid_range: "2004-01-01/2005-12-31" } +Exports: + VAR2D: {variable: VAR2D, collection: fstream1, sample: extrap_clim} diff --git a/Tests/ExtData_Testing_Framework/test_cases/case11/AGCM1.rc b/Tests/ExtData_Testing_Framework/test_cases/case11/AGCM1.rc new file mode 100644 index 000000000000..302766bebfab --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case11/AGCM1.rc @@ -0,0 +1,22 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC90x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: GenerateExports + +EXPORT_STATE:: +VAR2D , time , days , xy , c +:: + +FILL_DEF:: +VAR2D time +:: + +REF_TIME: 20040701 000000 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case11/AGCM2.rc b/Tests/ExtData_Testing_Framework/test_cases/case11/AGCM2.rc new file mode 100644 index 000000000000..48eb8ed1b8d3 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case11/AGCM2.rc @@ -0,0 +1,27 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC900x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: CompareImports + +IMPORT_STATE:: +VAR2D , time , days , xy , c +:: + +EXPORT_STATE:: +VAR2D , time , days , xy , c +:: + +FILL_DEF:: +VAR2D time +:: + +CLIM_YEAR: 2006 +REF_TIME: 20040701 000000 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case11/CAP.rc b/Tests/ExtData_Testing_Framework/test_cases/case11/CAP.rc new file mode 100644 index 000000000000..680d0ffa9c5b --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case11/CAP.rc @@ -0,0 +1,4 @@ +CASES:: +CAP1.rc +CAP2.rc +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case11/CAP1.rc b/Tests/ExtData_Testing_Framework/test_cases/case11/CAP1.rc new file mode 100644 index 000000000000..e800400d918a --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case11/CAP1.rc @@ -0,0 +1,36 @@ +ROOT_NAME: Root +ROOT_CF: AGCM1.rc +HIST_CF: HISTORY1.rc + +BEG_DATE: 20060101 210000 + +JOB_SGMT: 00002400 000000 +HEARTBEAT_DT: 3600 + +RUN_TIMES:: +20060115 210000 +20060215 210000 +20060315 210000 +20060415 210000 +20060515 210000 +20060615 210000 +20060715 210000 +20060815 210000 +20060915 210000 +20061015 210000 +20061115 210000 +20061215 210000 +20070115 210000 +20070215 210000 +20070315 210000 +20070415 210000 +20070515 210000 +20070615 210000 +20070715 210000 +20070815 210000 +20070915 210000 +20071015 210000 +20071115 210000 +20071215 210000 +:: + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case11/CAP2.rc b/Tests/ExtData_Testing_Framework/test_cases/case11/CAP2.rc new file mode 100644 index 000000000000..68f902819dd8 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case11/CAP2.rc @@ -0,0 +1,14 @@ +ROOT_NAME: Root +ROOT_CF: AGCM2.rc +HIST_CF: HISTORY2.rc + +BEG_DATE: 20050101 210000 + +JOB_SGMT: 00001200 000000 +HEARTBEAT_DT: 3600 + +#RUN_EXTDATA: .false. +RUN_TIMES:: +20050225 210000 +:: + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case11/ExtData.rc b/Tests/ExtData_Testing_Framework/test_cases/case11/ExtData.rc new file mode 100644 index 000000000000..92697fa916f0 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case11/ExtData.rc @@ -0,0 +1,12 @@ +#CASE_SENSITIVE_VARIABLE_NAMES: .false. +Ext_AllowExtrap: .true. +Prefetch: .true. +#DEBUG_LEVEL: 20 + +PrimaryExports%% +VAR2D NA N N 0 none none VAR2D case1.%y4%m2.nc4 +%% + + +DerivedExports%% +%% diff --git a/Tests/ExtData_Testing_Framework/test_cases/case11/HISTORY1.rc b/Tests/ExtData_Testing_Framework/test_cases/case11/HISTORY1.rc new file mode 100644 index 000000000000..0b54db8e8f25 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case11/HISTORY1.rc @@ -0,0 +1,11 @@ +GRID_LABELS: +:: + +COLLECTIONS: case1 +:: + + case1.template: '%y4%m2.nc4', + case1.format: 'CFIO', + case1.frequency: 010000, + case1.fields: 'VAR2D', 'Root', + :: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case11/HISTORY2.rc b/Tests/ExtData_Testing_Framework/test_cases/case11/HISTORY2.rc new file mode 100644 index 000000000000..2895432e995a --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case11/HISTORY2.rc @@ -0,0 +1,5 @@ +GRID_LABELS: +:: + +COLLECTIONS: +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case11/README b/Tests/ExtData_Testing_Framework/test_cases/case11/README new file mode 100644 index 000000000000..52a3f7e59bfa --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case11/README @@ -0,0 +1 @@ +Interpolation outside of data set (Harvard mode), make a multi year dataset. Define as not a climatology and ask for data before datset time range diff --git a/Tests/ExtData_Testing_Framework/test_cases/case11/extdata.yaml b/Tests/ExtData_Testing_Framework/test_cases/case11/extdata.yaml new file mode 100644 index 000000000000..6738280d70a4 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case11/extdata.yaml @@ -0,0 +1,4 @@ +Collections: + fstream1: {template: "case1.%y4%m2.nc4", valid_range: "2006-01-01/2007-12-31" } +Exports: + VAR2D: {variable: VAR2D, collection: fstream1, sample: {extrapolation: clim}} diff --git a/Tests/ExtData_Testing_Framework/test_cases/case12/AGCM1.rc b/Tests/ExtData_Testing_Framework/test_cases/case12/AGCM1.rc new file mode 100644 index 000000000000..5d1b0f452725 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case12/AGCM1.rc @@ -0,0 +1,22 @@ +NX: 6 +NY: 36 + +Root.GRID_TYPE: Cubed-Sphere +Root.GRIDNAME: PE24x144-CF +Root.LM: 3 +Root.NF 6 +Root.IM_WORLD: 24 + +RUN_MODE: GenerateExports + +EXPORT_STATE:: +VAR2D , time , days , xy , c +VAR3D , time , days , xyz , c +:: + +FILL_DEF:: +VAR2D time +VAR3D time +:: + +REF_TIME: 20040701 000000 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case12/AGCM2.rc b/Tests/ExtData_Testing_Framework/test_cases/case12/AGCM2.rc new file mode 100644 index 000000000000..fe9b76e9ab6b --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case12/AGCM2.rc @@ -0,0 +1,27 @@ +NX: 6 +NY: 36 + +Root.GRID_TYPE: Cubed-Sphere +Root.GRIDNAME: PE24x144-CF +Root.LM: 3 +Root.NF 6 +Root.IM_WORLD: 24 + +RUN_MODE: CompareImports + +IMPORT_STATE:: +VAR2D , time , days , xy , c +VAR3D , time , days , xyz , c +:: + +EXPORT_STATE:: +VAR2D , time , days , xy , c +VAR3D , time , days , xyz , c +:: + +FILL_DEF:: +VAR2D time +VAR3D time +:: + +REF_TIME: 20040701 000000 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case12/CAP.rc b/Tests/ExtData_Testing_Framework/test_cases/case12/CAP.rc new file mode 100644 index 000000000000..680d0ffa9c5b --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case12/CAP.rc @@ -0,0 +1,4 @@ +CASES:: +CAP1.rc +CAP2.rc +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case12/CAP1.rc b/Tests/ExtData_Testing_Framework/test_cases/case12/CAP1.rc new file mode 100644 index 000000000000..bed0725f4039 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case12/CAP1.rc @@ -0,0 +1,16 @@ +ROOT_NAME: Root +ROOT_CF: AGCM1.rc +HIST_CF: HISTORY1.rc + +BEG_DATE: 20040101 210000 + +JOB_SGMT: 00001200 000000 +HEARTBEAT_DT: 3600 + +RUN_TIMES:: +20040702 000000 +20040703 000000 +20040704 000000 +20040705 000000 +:: + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case12/CAP2.rc b/Tests/ExtData_Testing_Framework/test_cases/case12/CAP2.rc new file mode 100644 index 000000000000..f4182daac2ca --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case12/CAP2.rc @@ -0,0 +1,13 @@ +ROOT_NAME: Root +ROOT_CF: AGCM2.rc +HIST_CF: HISTORY2.rc + +BEG_DATE: 20040101 210000 + +JOB_SGMT: 00001200 000000 +HEARTBEAT_DT: 3600 + +RUN_TIMES:: +20040703 120000 +:: + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case12/ExtData.rc b/Tests/ExtData_Testing_Framework/test_cases/case12/ExtData.rc new file mode 100644 index 000000000000..19bc2d0132f6 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case12/ExtData.rc @@ -0,0 +1,13 @@ +#CASE_SENSITIVE_VARIABLE_NAMES: .false. +Ext_AllowExtrap: .false. +Prefetch: .true. +#DEBUG_LEVEL: 20 + +PrimaryExports%% +VAR2D NA N N - none none VAR2D vars2d.nc4 +VAR3D NA N N - none none VAR3D vars3d.nc4 +%% + + +DerivedExports%% +%% diff --git a/Tests/ExtData_Testing_Framework/test_cases/case12/HISTORY1.rc b/Tests/ExtData_Testing_Framework/test_cases/case12/HISTORY1.rc new file mode 100644 index 000000000000..bdc7875e13f3 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case12/HISTORY1.rc @@ -0,0 +1,30 @@ +VERSION: 1 +GRID_LABELS: PC20x11-DC +:: + +PC20x11-DC.GRID_TYPE: LatLon +PC20x11-DC.IM_WORLD: 20 +PC20x11-DC.JM_WORLD: 11 +PC20x11-DC.POLE: PC +PC20x11-DC.DATELINE: DC +PC20x11-DC.LM: 3 + +COLLECTIONS: vars2d + vars3d +:: + + + vars2d.template: 'nc4', + vars2d.format: 'CFIO', + vars2d.frequency: 010000, + vars2d.duration: 000000 + vars2d.grid_label: PC20x11-DC + vars2d.fields: 'VAR2D', 'Root', + :: + vars3d.template: 'nc4', + vars3d.format: 'CFIO', + vars3d.frequency: 010000, + vars3d.duration: 000000 + vars3d.grid_label: PC20x11-DC + vars3d.fields: 'VAR3D', 'Root', + :: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case12/HISTORY2.rc b/Tests/ExtData_Testing_Framework/test_cases/case12/HISTORY2.rc new file mode 100644 index 000000000000..2895432e995a --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case12/HISTORY2.rc @@ -0,0 +1,5 @@ +GRID_LABELS: +:: + +COLLECTIONS: +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case12/README b/Tests/ExtData_Testing_Framework/test_cases/case12/README new file mode 100644 index 000000000000..faaab2c64256 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case12/README @@ -0,0 +1 @@ +Test of case where you want to make a really coarse file in History that can not be decomposed on the default layout in the rc file. Be able to output such a file, then read back in on same grid in ExtData diff --git a/Tests/ExtData_Testing_Framework/test_cases/case12/extdata.yaml b/Tests/ExtData_Testing_Framework/test_cases/case12/extdata.yaml new file mode 100644 index 000000000000..e7eeef4a6e16 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case12/extdata.yaml @@ -0,0 +1,6 @@ +Collections: + fstream1: {template: "vars2d.nc4"} + fstream2: {template: "vars3d.nc4"} +Exports: + VAR2D: {variable: VAR2D, collection: fstream1, sample: {update_frequency: "-"}} + VAR3D: {variable: VAR3D, collection: fstream2, sample: {update_frequency: "-"}} diff --git a/Tests/ExtData_Testing_Framework/test_cases/case12/nproc.rc b/Tests/ExtData_Testing_Framework/test_cases/case12/nproc.rc new file mode 100644 index 000000000000..a817176f4a68 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case12/nproc.rc @@ -0,0 +1 @@ +216 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case13/AGCM1.rc b/Tests/ExtData_Testing_Framework/test_cases/case13/AGCM1.rc new file mode 100644 index 000000000000..1199f8335bc6 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case13/AGCM1.rc @@ -0,0 +1,22 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC900x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: GenerateExports + +EXPORT_STATE:: +VAR2D , time , days , xy , c +:: + +FILL_DEF:: +VAR2D time +:: + +REF_TIME: 20070101 000000 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case13/AGCM2.rc b/Tests/ExtData_Testing_Framework/test_cases/case13/AGCM2.rc new file mode 100644 index 000000000000..814c1dfd5e43 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case13/AGCM2.rc @@ -0,0 +1,25 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC90x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: CompareImports + +IMPORT_STATE:: +VAR2D , time , days , xy , c +:: + +EXPORT_STATE:: +VAR2D , time , days , xy , c +:: + +FILL_DEF:: +VAR2D 45.0+(73.0-45.0)*0.5 +:: + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case13/CAP.rc b/Tests/ExtData_Testing_Framework/test_cases/case13/CAP.rc new file mode 100644 index 000000000000..680d0ffa9c5b --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case13/CAP.rc @@ -0,0 +1,4 @@ +CASES:: +CAP1.rc +CAP2.rc +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case13/CAP1.rc b/Tests/ExtData_Testing_Framework/test_cases/case13/CAP1.rc new file mode 100644 index 000000000000..b40edc56fda7 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case13/CAP1.rc @@ -0,0 +1,25 @@ +ROOT_NAME: Root +ROOT_CF: AGCM1.rc +HIST_CF: HISTORY1.rc + +BEG_DATE: 20070101 000000 + +JOB_SGMT: 00001200 000000 +HEARTBEAT_DT: 3600 + +#RUN_EXTDATA: .false. +RUN_TIMES:: +20070115 000000 +20070215 000000 +20070315 000000 +20070415 000000 +20070515 000000 +20070615 000000 +20070715 000000 +20070815 000000 +20070915 000000 +20071015 000000 +20071115 000000 +20071215 000000 +:: + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case13/CAP2.rc b/Tests/ExtData_Testing_Framework/test_cases/case13/CAP2.rc new file mode 100644 index 000000000000..ad9fdbaa59ef --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case13/CAP2.rc @@ -0,0 +1,13 @@ +ROOT_NAME: Root +ROOT_CF: AGCM2.rc +HIST_CF: HISTORY2.rc + +BEG_DATE: 20080101 210000 + +JOB_SGMT: 00001200 000000 +HEARTBEAT_DT: 3600 + +RUN_TIMES:: +20080229 120000 +:: + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case13/ExtData.rc b/Tests/ExtData_Testing_Framework/test_cases/case13/ExtData.rc new file mode 100644 index 000000000000..e535516c3bdf --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case13/ExtData.rc @@ -0,0 +1,12 @@ +#CASE_SENSITIVE_VARIABLE_NAMES: .false. +Ext_AllowExtrap: .false. +Prefetch: .true. +DEBUG_LEVEL: 20 + +PrimaryExports%% +VAR2D NA Y N 0 none none VAR2D case1.2007%m2.nc4 +%% + + +DerivedExports%% +%% diff --git a/Tests/ExtData_Testing_Framework/test_cases/case13/HISTORY1.rc b/Tests/ExtData_Testing_Framework/test_cases/case13/HISTORY1.rc new file mode 100644 index 000000000000..1e9dd9d44599 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case13/HISTORY1.rc @@ -0,0 +1,12 @@ +GRID_LABELS: +:: + +COLLECTIONS: case1 +:: + + case1.template: '%y4%m2.nc4', + case1.format: 'CFIO', + case1.frequency: 010000, + #case1.duration: 000000 + case1.fields: 'VAR2D', 'Root', + :: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case13/HISTORY2.rc b/Tests/ExtData_Testing_Framework/test_cases/case13/HISTORY2.rc new file mode 100644 index 000000000000..2895432e995a --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case13/HISTORY2.rc @@ -0,0 +1,5 @@ +GRID_LABELS: +:: + +COLLECTIONS: +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case13/README b/Tests/ExtData_Testing_Framework/test_cases/case13/README new file mode 100644 index 000000000000..8a66da41fbc9 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case13/README @@ -0,0 +1 @@ +Testing that we can take a climatology for a non-leap year and interpolate to a leap year. 12 files each with the midmonth value for 2007 (non-leap year). Interpolate to 02/29/2008 (leap year) diff --git a/Tests/ExtData_Testing_Framework/test_cases/case13/extdata.yaml b/Tests/ExtData_Testing_Framework/test_cases/case13/extdata.yaml new file mode 100644 index 000000000000..1dc456d831f9 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case13/extdata.yaml @@ -0,0 +1,4 @@ +Collections: + fstream1: {template: "case1.2007%m2.nc4", valid_range: "2007-01-01/2007-12-31" } +Exports: + VAR2D: {variable: VAR2D, collection: fstream1, sample: {extrapolation: clim, source_time: "2007-01-01/2007-12-31"}} diff --git a/Tests/ExtData_Testing_Framework/test_cases/case14/AGCM1.rc b/Tests/ExtData_Testing_Framework/test_cases/case14/AGCM1.rc new file mode 100644 index 000000000000..58c95c0fd941 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case14/AGCM1.rc @@ -0,0 +1,22 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC90x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: GenerateExports + +EXPORT_STATE:: +VAR2D , time , days , xy , c +:: + +FILL_DEF:: +VAR2D time +:: + +REF_TIME: 20070101 000000 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case14/AGCM2.rc b/Tests/ExtData_Testing_Framework/test_cases/case14/AGCM2.rc new file mode 100644 index 000000000000..0858aa614d31 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case14/AGCM2.rc @@ -0,0 +1,24 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC900x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: CompareImports + +IMPORT_STATE:: +VAR2D , time , days , xy , c +:: + +EXPORT_STATE:: +VAR2D , time , days , xy , c +:: + +FILL_DEF:: +VAR2D 58.0+(59.0-58.0)*0.75 +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case14/CAP.rc b/Tests/ExtData_Testing_Framework/test_cases/case14/CAP.rc new file mode 100644 index 000000000000..680d0ffa9c5b --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case14/CAP.rc @@ -0,0 +1,4 @@ +CASES:: +CAP1.rc +CAP2.rc +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case14/CAP1.rc b/Tests/ExtData_Testing_Framework/test_cases/case14/CAP1.rc new file mode 100644 index 000000000000..e725586cac99 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case14/CAP1.rc @@ -0,0 +1,10 @@ +ROOT_NAME: Root +ROOT_CF: AGCM1.rc +HIST_CF: HISTORY1.rc + +BEG_DATE: 20061231 000000 + +JOB_SGMT: 00001200 000000 +HEARTBEAT_DT: 3600 + + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case14/CAP2.rc b/Tests/ExtData_Testing_Framework/test_cases/case14/CAP2.rc new file mode 100644 index 000000000000..36aafef783fe --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case14/CAP2.rc @@ -0,0 +1,14 @@ +ROOT_NAME: Root +ROOT_CF: AGCM2.rc +HIST_CF: HISTORY2.rc + +BEG_DATE: 20040101 210000 + +JOB_SGMT: 00001200 000000 +HEARTBEAT_DT: 3600 + +#RUN_EXTDATA: .false. +RUN_TIMES:: +20080229 120000 +:: + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case14/ExtData.rc b/Tests/ExtData_Testing_Framework/test_cases/case14/ExtData.rc new file mode 100644 index 000000000000..00b82c0f4f77 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case14/ExtData.rc @@ -0,0 +1,12 @@ +#CASE_SENSITIVE_VARIABLE_NAMES: .false. +Ext_AllowExtrap: .false. +Prefetch: .true. +DEBUG_LEVEL: 20 + +PrimaryExports%% +VAR2D NA 2007 N 0 none none VAR2D case1.%y4%m2%d2.nc4 +%% + + +DerivedExports%% +%% diff --git a/Tests/ExtData_Testing_Framework/test_cases/case14/HISTORY1.rc b/Tests/ExtData_Testing_Framework/test_cases/case14/HISTORY1.rc new file mode 100644 index 000000000000..7f1045a27232 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case14/HISTORY1.rc @@ -0,0 +1,12 @@ +GRID_LABELS: +:: + +COLLECTIONS: case1 +:: + + case1.template: '%y4%m2%d2.nc4', + case1.format: 'CFIO', + case1.frequency: 240000, + case1.ref_time: 000000, + case1.fields: 'VAR2D', 'Root', + :: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case14/HISTORY2.rc b/Tests/ExtData_Testing_Framework/test_cases/case14/HISTORY2.rc new file mode 100644 index 000000000000..2895432e995a --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case14/HISTORY2.rc @@ -0,0 +1,5 @@ +GRID_LABELS: +:: + +COLLECTIONS: +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case14/README b/Tests/ExtData_Testing_Framework/test_cases/case14/README new file mode 100644 index 000000000000..712f8869bac4 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case14/README @@ -0,0 +1 @@ +Testing that we can take a climatology for a non-leap year and interpolate to a leap year. Daily files each with 1 value for 2007 (non-leap year). Interpolate to 02/29/2008 (leap year) diff --git a/Tests/ExtData_Testing_Framework/test_cases/case14/extdata.yaml b/Tests/ExtData_Testing_Framework/test_cases/case14/extdata.yaml new file mode 100644 index 000000000000..11c4ed30a938 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case14/extdata.yaml @@ -0,0 +1,6 @@ +Samplings: + sample_clim: {extrapolation: clim} +Collections: + fstream1: {template: "case1.%y4%m2%d2.nc4", valid_range: "2007-01-01/2007-12-31" } +Exports: + VAR2D: {variable: VAR2D, collection: fstream1, source_time: "2007-01-01/2007-12-31", sample: sample_clim} diff --git a/Tests/ExtData_Testing_Framework/test_cases/case15/AGCM1.rc b/Tests/ExtData_Testing_Framework/test_cases/case15/AGCM1.rc new file mode 100644 index 000000000000..58c95c0fd941 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case15/AGCM1.rc @@ -0,0 +1,22 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC90x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: GenerateExports + +EXPORT_STATE:: +VAR2D , time , days , xy , c +:: + +FILL_DEF:: +VAR2D time +:: + +REF_TIME: 20070101 000000 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case15/AGCM2.rc b/Tests/ExtData_Testing_Framework/test_cases/case15/AGCM2.rc new file mode 100644 index 000000000000..58fc61c57d55 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case15/AGCM2.rc @@ -0,0 +1,27 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC900x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: CompareImports + +IMPORT_STATE:: +VAR2D , time , days , xy , c +:: + +EXPORT_STATE:: +VAR2D , time , days , xy , c +:: + +FILL_DEF:: +VAR2D time +:: + +CLIM_YEAR: 2007 +REF_TIME: 20070101 000000 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case15/CAP.rc b/Tests/ExtData_Testing_Framework/test_cases/case15/CAP.rc new file mode 100644 index 000000000000..680d0ffa9c5b --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case15/CAP.rc @@ -0,0 +1,4 @@ +CASES:: +CAP1.rc +CAP2.rc +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case15/CAP1.rc b/Tests/ExtData_Testing_Framework/test_cases/case15/CAP1.rc new file mode 100644 index 000000000000..957ef31d3145 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case15/CAP1.rc @@ -0,0 +1,10 @@ +ROOT_NAME: Root +ROOT_CF: AGCM1.rc +HIST_CF: HISTORY1.rc + +BEG_DATE: 20061231 230000 + +JOB_SGMT: 00001200 000000 +HEARTBEAT_DT: 3600 + + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case15/CAP2.rc b/Tests/ExtData_Testing_Framework/test_cases/case15/CAP2.rc new file mode 100644 index 000000000000..7e31eadc76a6 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case15/CAP2.rc @@ -0,0 +1,14 @@ +ROOT_NAME: Root +ROOT_CF: AGCM2.rc +HIST_CF: HISTORY2.rc + +BEG_DATE: 20040101 210000 + +JOB_SGMT: 00001200 000000 +HEARTBEAT_DT: 3600 + +#RUN_EXTDATA: .false. +RUN_TIMES:: +20060329 120000 +:: + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case15/ExtData.rc b/Tests/ExtData_Testing_Framework/test_cases/case15/ExtData.rc new file mode 100644 index 000000000000..7032d5b44348 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case15/ExtData.rc @@ -0,0 +1,12 @@ +#CASE_SENSITIVE_VARIABLE_NAMES: .false. +Ext_AllowExtrap: .false. +Prefetch: .true. +DEBUG_LEVEL: 20 + +PrimaryExports%% +VAR2D NA 2007 N 0 none none VAR2D case1.nc4 +%% + + +DerivedExports%% +%% diff --git a/Tests/ExtData_Testing_Framework/test_cases/case15/HISTORY1.rc b/Tests/ExtData_Testing_Framework/test_cases/case15/HISTORY1.rc new file mode 100644 index 000000000000..0f000be68631 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case15/HISTORY1.rc @@ -0,0 +1,13 @@ +GRID_LABELS: +:: + +COLLECTIONS: case1 +:: + + case1.template: 'nc4', + case1.format: 'CFIO', + case1.frequency: 60000, + case1.duration: 000000, + case1.ref_time: 000000, + case1.fields: 'VAR2D', 'Root', + :: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case15/HISTORY2.rc b/Tests/ExtData_Testing_Framework/test_cases/case15/HISTORY2.rc new file mode 100644 index 000000000000..2895432e995a --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case15/HISTORY2.rc @@ -0,0 +1,5 @@ +GRID_LABELS: +:: + +COLLECTIONS: +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case15/README b/Tests/ExtData_Testing_Framework/test_cases/case15/README new file mode 100644 index 000000000000..c8303c9f308c --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case15/README @@ -0,0 +1 @@ +Testing that we can take a climatology for a non-leap year and interpolate to a non-leap year. Daily files each with 1 value for 2007 (non-leap year). Interpolate to 03/29/2006 (leap year) diff --git a/Tests/ExtData_Testing_Framework/test_cases/case15/extdata.yaml b/Tests/ExtData_Testing_Framework/test_cases/case15/extdata.yaml new file mode 100644 index 000000000000..a64fe328c5bd --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case15/extdata.yaml @@ -0,0 +1,6 @@ +Samplings: + sample_clim: {extrapolation: clim, source_time: "2007-01-01/2007-12-31"} +Collections: + fstream1: {template: "case1.nc4", valid_range: "2007-01-01/2007-12-31" } +Exports: + VAR2D: {variable: VAR2D, collection: fstream1, sample: sample_clim} diff --git a/Tests/ExtData_Testing_Framework/test_cases/case16/AGCM1.rc b/Tests/ExtData_Testing_Framework/test_cases/case16/AGCM1.rc new file mode 100644 index 000000000000..81bb07dcdcbd --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case16/AGCM1.rc @@ -0,0 +1,22 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC90x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: GenerateExports + +EXPORT_STATE:: +VAR2D , time , days , xy , c +:: + +FILL_DEF:: +VAR2D time +:: + +REF_TIME: 20080101 000000 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case16/AGCM2.rc b/Tests/ExtData_Testing_Framework/test_cases/case16/AGCM2.rc new file mode 100644 index 000000000000..040b724d894e --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case16/AGCM2.rc @@ -0,0 +1,27 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC900x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: CompareImports + +IMPORT_STATE:: +VAR2D , time , days , xy , c +:: + +EXPORT_STATE:: +VAR2D , time , days , xy , c +:: + +FILL_DEF:: +VAR2D time +:: + +CLIM_YEAR: 2008 +REF_TIME: 20080101 000000 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case16/CAP.rc b/Tests/ExtData_Testing_Framework/test_cases/case16/CAP.rc new file mode 100644 index 000000000000..680d0ffa9c5b --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case16/CAP.rc @@ -0,0 +1,4 @@ +CASES:: +CAP1.rc +CAP2.rc +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case16/CAP1.rc b/Tests/ExtData_Testing_Framework/test_cases/case16/CAP1.rc new file mode 100644 index 000000000000..2840fe1b50ce --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case16/CAP1.rc @@ -0,0 +1,10 @@ +ROOT_NAME: Root +ROOT_CF: AGCM1.rc +HIST_CF: HISTORY1.rc + +BEG_DATE: 20071231 230000 + +JOB_SGMT: 00001200 000000 +HEARTBEAT_DT: 3600 + + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case16/CAP2.rc b/Tests/ExtData_Testing_Framework/test_cases/case16/CAP2.rc new file mode 100644 index 000000000000..8ed72d5aabe6 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case16/CAP2.rc @@ -0,0 +1,14 @@ +ROOT_NAME: Root +ROOT_CF: AGCM2.rc +HIST_CF: HISTORY2.rc + +BEG_DATE: 20040101 210000 + +JOB_SGMT: 00001200 000000 +HEARTBEAT_DT: 3600 + +#RUN_EXTDATA: .false. +RUN_TIMES:: +20060329 150000 +:: + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case16/ExtData.rc b/Tests/ExtData_Testing_Framework/test_cases/case16/ExtData.rc new file mode 100644 index 000000000000..1b98d7c432b9 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case16/ExtData.rc @@ -0,0 +1,12 @@ +#CASE_SENSITIVE_VARIABLE_NAMES: .false. +Ext_AllowExtrap: .false. +Prefetch: .true. +DEBUG_LEVEL: 20 + +PrimaryExports%% +VAR2D NA 2008 N 0 none none VAR2D case1.nc4 +%% + + +DerivedExports%% +%% diff --git a/Tests/ExtData_Testing_Framework/test_cases/case16/HISTORY1.rc b/Tests/ExtData_Testing_Framework/test_cases/case16/HISTORY1.rc new file mode 100644 index 000000000000..0f000be68631 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case16/HISTORY1.rc @@ -0,0 +1,13 @@ +GRID_LABELS: +:: + +COLLECTIONS: case1 +:: + + case1.template: 'nc4', + case1.format: 'CFIO', + case1.frequency: 60000, + case1.duration: 000000, + case1.ref_time: 000000, + case1.fields: 'VAR2D', 'Root', + :: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case16/HISTORY2.rc b/Tests/ExtData_Testing_Framework/test_cases/case16/HISTORY2.rc new file mode 100644 index 000000000000..2895432e995a --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case16/HISTORY2.rc @@ -0,0 +1,5 @@ +GRID_LABELS: +:: + +COLLECTIONS: +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case16/README b/Tests/ExtData_Testing_Framework/test_cases/case16/README new file mode 100644 index 000000000000..2b112ffe7b9c --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case16/README @@ -0,0 +1 @@ +Testing that we can take a climatology for a leap year and interpolate to a non-leap year. Daily files each with 1 value for 2008 (leap year). Interpolate to 03/29/2006 15z (leap year) diff --git a/Tests/ExtData_Testing_Framework/test_cases/case16/extdata.yaml b/Tests/ExtData_Testing_Framework/test_cases/case16/extdata.yaml new file mode 100644 index 000000000000..89a527a980e2 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case16/extdata.yaml @@ -0,0 +1,6 @@ +Collections: + fstream1: {template: "case1.nc4", valid_range: "2008-01-01/2008-12-31" } +Samplings: + s1: {source_time: "2008-01-01/2008-12-31", extrapolation: clim} +Exports: + VAR2D: {variable: VAR2D, collection: fstream1, sample: s1} diff --git a/Tests/ExtData_Testing_Framework/test_cases/case18/AGCM1.rc b/Tests/ExtData_Testing_Framework/test_cases/case18/AGCM1.rc new file mode 100644 index 000000000000..7787931e9777 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case18/AGCM1.rc @@ -0,0 +1,24 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC90x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: GenerateExports + +EXPORT_STATE:: +U2D , time , days , xy , c +V2D , time , days , xy , c +:: + +FILL_DEF:: +U2D 0.0 +V2D 5.0 +:: + +REF_TIME: 20040701 000000 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case18/AGCM2.rc b/Tests/ExtData_Testing_Framework/test_cases/case18/AGCM2.rc new file mode 100644 index 000000000000..13bea40d79d3 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case18/AGCM2.rc @@ -0,0 +1,33 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC90x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: FillExportsFromImports + +IMPORT_STATE:: +U2D , time , days , xy , c +#U3D , time , days , xyz , c +V2D , time , days , xy , c +#V3D , time , days , xyz , c +:: + +EXPORT_STATE:: +U2D , time , days , xy , c +#U3D , time , days , xyz , c +V2D , time , days , xy , c +#V3D , time , days , xyz , c +:: + +#FILL_DEF:: +#VAR2D time +#VAR3D time +#:: + +REF_TIME: 20040701 000000 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case18/CAP.rc b/Tests/ExtData_Testing_Framework/test_cases/case18/CAP.rc new file mode 100644 index 000000000000..680d0ffa9c5b --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case18/CAP.rc @@ -0,0 +1,4 @@ +CASES:: +CAP1.rc +CAP2.rc +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case18/CAP1.rc b/Tests/ExtData_Testing_Framework/test_cases/case18/CAP1.rc new file mode 100644 index 000000000000..11e0e36bd675 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case18/CAP1.rc @@ -0,0 +1,26 @@ +ROOT_NAME: Root +ROOT_CF: AGCM1.rc +HIST_CF: HISTORY1.rc + +BEG_DATE: 20040101 210000 + +JOB_SGMT: 00001200 000000 +HEARTBEAT_DT: 3600 + +#RUN_EXTDATA: .false. +RUN_TIMES:: +20040115 210000 +20040215 210000 +20040315 210000 +20040415 210000 +20040515 210000 +20040615 210000 +20040715 210000 +20040815 210000 +20040915 210000 +20041015 210000 +20041115 210000 +20041215 210000 +:: + +USE_EXTDATA2G: .true. diff --git a/Tests/ExtData_Testing_Framework/test_cases/case18/CAP2.rc b/Tests/ExtData_Testing_Framework/test_cases/case18/CAP2.rc new file mode 100644 index 000000000000..4a0f45af02e4 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case18/CAP2.rc @@ -0,0 +1,15 @@ +ROOT_NAME: Root +ROOT_CF: AGCM2.rc +HIST_CF: HISTORY2.rc + +BEG_DATE: 20040101 210000 + +JOB_SGMT: 00001200 000000 +HEARTBEAT_DT: 3600 + +#RUN_EXTDATA: .false. +RUN_TIMES:: +20041126 210000 +:: + +USE_EXTDATA2G: .true. diff --git a/Tests/ExtData_Testing_Framework/test_cases/case18/ExtData.rc b/Tests/ExtData_Testing_Framework/test_cases/case18/ExtData.rc new file mode 100644 index 000000000000..79cf7c1399ab --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case18/ExtData.rc @@ -0,0 +1,15 @@ +#CASE_SENSITIVE_VARIABLE_NAMES: .false. +Ext_AllowExtrap: .false. +Prefetch: .true. +DEBUG_LEVEL: 20 + +PrimaryExports%% +U2D;V2D NA N N 0 none none U2D;V2D case1.%y4.nc4 +#U3D;V3D NA N N 0 none none U3D;V3D case1.%y4.nc4 +#U2D NA N N 0 none none U2D case1.%y4.nc4 +#V2D NA N N 0 none none V2D case1.%y4.nc4 +%% + + +DerivedExports%% +%% diff --git a/Tests/ExtData_Testing_Framework/test_cases/case18/HISTORY1.rc b/Tests/ExtData_Testing_Framework/test_cases/case18/HISTORY1.rc new file mode 100644 index 000000000000..e19d49760185 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case18/HISTORY1.rc @@ -0,0 +1,15 @@ +GRID_LABELS: +:: + +COLLECTIONS: case1 +:: + + case1.template: '%y4.nc4', + case1.format: 'CFIO', + case1.frequency: 010000, + case1.duration: 000000 + case1.fields: 'U2D', 'Root', + #'U3D', 'Root', + 'V2D', 'Root', + #'V3D', 'Root', + :: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case18/HISTORY2.rc b/Tests/ExtData_Testing_Framework/test_cases/case18/HISTORY2.rc new file mode 100644 index 000000000000..6091a4c984bd --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case18/HISTORY2.rc @@ -0,0 +1,13 @@ +GRID_LABELS: +:: + +COLLECTIONS: +:: + + case18_2.template: '%y4.nc4', + case18_2.format: 'CFIO', + case18_2.frequency: 010000, + case18_2.duration: 000000 + case18_2.fields: 'U2D', 'Root', + 'V2D', 'Root', + :: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case18/README b/Tests/ExtData_Testing_Framework/test_cases/case18/README new file mode 100644 index 000000000000..60994edbc151 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case18/README @@ -0,0 +1 @@ +Test vector regridding diff --git a/Tests/ExtData_Testing_Framework/test_cases/case18/extdata.yaml b/Tests/ExtData_Testing_Framework/test_cases/case18/extdata.yaml new file mode 100644 index 000000000000..c69f0f79bf8a --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case18/extdata.yaml @@ -0,0 +1,4 @@ +Collections: + fstream1: {template: "case1.%y4.nc4"} +Exports: + U2D;V2D: {variable: U2D;V2D, collection: fstream1} diff --git a/Tests/ExtData_Testing_Framework/test_cases/case19/AGCM1.rc b/Tests/ExtData_Testing_Framework/test_cases/case19/AGCM1.rc new file mode 100644 index 000000000000..4ebd5b1a73fa --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case19/AGCM1.rc @@ -0,0 +1,24 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC900x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: CompareImports + +IMPORT_STATE:: +VAR2D , time , days , xy , c +:: + +EXPORT_STATE:: +VAR2D , time , days , xy , c +:: + +FILL_DEF:: +VAR2D 17.0 +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case19/CAP.rc b/Tests/ExtData_Testing_Framework/test_cases/case19/CAP.rc new file mode 100644 index 000000000000..4f5328064bab --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case19/CAP.rc @@ -0,0 +1,3 @@ +CASES:: +CAP1.rc +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case19/CAP1.rc b/Tests/ExtData_Testing_Framework/test_cases/case19/CAP1.rc new file mode 100644 index 000000000000..ce2690d6937b --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case19/CAP1.rc @@ -0,0 +1,25 @@ +ROOT_NAME: Root +ROOT_CF: AGCM1.rc +HIST_CF: HISTORY1.rc + +BEG_DATE: 20040101 210000 + +JOB_SGMT: 00001200 000000 +HEARTBEAT_DT: 3600 + +#RUN_EXTDATA: .false. +RUN_TIMES:: +20040115 210000 +20040215 210000 +20040315 210000 +20040415 210000 +20040515 210000 +20040615 210000 +20040715 210000 +20040815 210000 +20040915 210000 +20041015 210000 +20041115 210000 +20041215 210000 +:: + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case19/ExtData.rc b/Tests/ExtData_Testing_Framework/test_cases/case19/ExtData.rc new file mode 100644 index 000000000000..45b2e1653d38 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case19/ExtData.rc @@ -0,0 +1,12 @@ +#CASE_SENSITIVE_VARIABLE_NAMES: .false. +Ext_AllowExtrap: .false. +Prefetch: .true. +#DEBUG_LEVEL: 20 + +PrimaryExports%% +VAR2D NA N N 0 none none VAR2D /dev/null:17.0 +%% + + +DerivedExports%% +%% diff --git a/Tests/ExtData_Testing_Framework/test_cases/case19/HISTORY1.rc b/Tests/ExtData_Testing_Framework/test_cases/case19/HISTORY1.rc new file mode 100644 index 000000000000..d3a6677416e1 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case19/HISTORY1.rc @@ -0,0 +1,5 @@ +GRID_LABELS: +:: + +COLLECTIONS: +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case19/README b/Tests/ExtData_Testing_Framework/test_cases/case19/README new file mode 100644 index 000000000000..23052d595d01 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case19/README @@ -0,0 +1 @@ +test /dev/null diff --git a/Tests/ExtData_Testing_Framework/test_cases/case19/extdata.yaml b/Tests/ExtData_Testing_Framework/test_cases/case19/extdata.yaml new file mode 100644 index 000000000000..e8f03193e4a7 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case19/extdata.yaml @@ -0,0 +1,2 @@ +Exports: + VAR2D: {collection: "/dev/null", linear_transformation: [17.0,0.0]} diff --git a/Tests/ExtData_Testing_Framework/test_cases/case2/AGCM1.rc b/Tests/ExtData_Testing_Framework/test_cases/case2/AGCM1.rc new file mode 100644 index 000000000000..ada4fab64746 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case2/AGCM1.rc @@ -0,0 +1,24 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC900x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: GenerateExports + +EXPORT_STATE:: +VAR2D , time , days , xy , c +VAR3D , time , days , xyz , c +:: + +FILL_DEF:: +VAR2D time +VAR3D time +:: + +REF_TIME: 20040701 000000 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case2/AGCM2.rc b/Tests/ExtData_Testing_Framework/test_cases/case2/AGCM2.rc new file mode 100644 index 000000000000..6fb58c19aba5 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case2/AGCM2.rc @@ -0,0 +1,30 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC90x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: CompareImports + +IMPORT_STATE:: +VAR2D , time , days , xy , c +VAR3D , time , days , xyz , c +:: + +EXPORT_STATE:: +VAR2D , time , days , xy , c +VAR3D , time , days , xyz , c +:: + +FILL_DEF:: +VAR2D time +VAR3D time +:: + +CLIM_YEAR: 2004 +REF_TIME: 20040701 000000 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case2/CAP.rc b/Tests/ExtData_Testing_Framework/test_cases/case2/CAP.rc new file mode 100644 index 000000000000..680d0ffa9c5b --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case2/CAP.rc @@ -0,0 +1,4 @@ +CASES:: +CAP1.rc +CAP2.rc +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case2/CAP1.rc b/Tests/ExtData_Testing_Framework/test_cases/case2/CAP1.rc new file mode 100644 index 000000000000..ce2690d6937b --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case2/CAP1.rc @@ -0,0 +1,25 @@ +ROOT_NAME: Root +ROOT_CF: AGCM1.rc +HIST_CF: HISTORY1.rc + +BEG_DATE: 20040101 210000 + +JOB_SGMT: 00001200 000000 +HEARTBEAT_DT: 3600 + +#RUN_EXTDATA: .false. +RUN_TIMES:: +20040115 210000 +20040215 210000 +20040315 210000 +20040415 210000 +20040515 210000 +20040615 210000 +20040715 210000 +20040815 210000 +20040915 210000 +20041015 210000 +20041115 210000 +20041215 210000 +:: + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case2/CAP2.rc b/Tests/ExtData_Testing_Framework/test_cases/case2/CAP2.rc new file mode 100644 index 000000000000..4dc521f63044 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case2/CAP2.rc @@ -0,0 +1,15 @@ +ROOT_NAME: Root +ROOT_CF: AGCM2.rc +HIST_CF: HISTORY2.rc + +BEG_DATE: 20040101 210000 + +JOB_SGMT: 00001200 000000 +HEARTBEAT_DT: 3600 + +#RUN_EXTDATA: .false. +RUN_TIMES:: +20071125 210000 +20071126 210000 +:: + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case2/ExtData.rc b/Tests/ExtData_Testing_Framework/test_cases/case2/ExtData.rc new file mode 100644 index 000000000000..9a1d56d1f370 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case2/ExtData.rc @@ -0,0 +1,13 @@ +#CASE_SENSITIVE_VARIABLE_NAMES: .false. +Ext_AllowExtrap: .false. +Prefetch: .true. +#DEBUG_LEVEL: 20 + +PrimaryExports%% +VAR2D NA Y N 0 none none VAR2D case1.2004.nc4 +VAR3D NA Y N 0 none none VAR3D case1.2004.nc4 +%% + + +DerivedExports%% +%% diff --git a/Tests/ExtData_Testing_Framework/test_cases/case2/HISTORY1.rc b/Tests/ExtData_Testing_Framework/test_cases/case2/HISTORY1.rc new file mode 100644 index 000000000000..51d004d9660c --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case2/HISTORY1.rc @@ -0,0 +1,13 @@ +GRID_LABELS: +:: + +COLLECTIONS: case1 +:: + + case1.template: '%y4.nc4', + case1.format: 'CFIO', + case1.frequency: 010000, + case1.duration: 000000 + case1.fields: 'VAR2D', 'Root', + 'VAR3D', 'Root', + :: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case2/HISTORY2.rc b/Tests/ExtData_Testing_Framework/test_cases/case2/HISTORY2.rc new file mode 100644 index 000000000000..2895432e995a --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case2/HISTORY2.rc @@ -0,0 +1,5 @@ +GRID_LABELS: +:: + +COLLECTIONS: +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case2/README b/Tests/ExtData_Testing_Framework/test_cases/case2/README new file mode 100644 index 000000000000..a022d98f1113 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case2/README @@ -0,0 +1 @@ +Case, 12-month/12 time 2004 file with 2 updates, climatology diff --git a/Tests/ExtData_Testing_Framework/test_cases/case2/extdata.yaml b/Tests/ExtData_Testing_Framework/test_cases/case2/extdata.yaml new file mode 100644 index 000000000000..739a9e22c98c --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case2/extdata.yaml @@ -0,0 +1,7 @@ +Samplings: + sample_clim: {extrapolation: clim} +Collections: + fstream1: {template: "case1.2004.nc4"} +Exports: + VAR2D: {variable: VAR2D, collection: fstream1, sample: sample_clim} + VAR3D: {variable: VAR3D, collection: fstream1, sample: sample_clim} diff --git a/Tests/ExtData_Testing_Framework/test_cases/case20/AGCM1.rc b/Tests/ExtData_Testing_Framework/test_cases/case20/AGCM1.rc new file mode 100644 index 000000000000..3583e9d12516 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case20/AGCM1.rc @@ -0,0 +1,22 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC90x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: GenerateExports + +EXPORT_STATE:: +VAR2D , time , days , xy , c +:: + +FILL_DEF:: +VAR2D time +:: + +REF_TIME: 20160101 000000 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case20/AGCM2.rc b/Tests/ExtData_Testing_Framework/test_cases/case20/AGCM2.rc new file mode 100644 index 000000000000..fb783b442edd --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case20/AGCM2.rc @@ -0,0 +1,24 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC900x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: CompareImports + +IMPORT_STATE:: +VAR2D , time , days , xy , c +:: + +EXPORT_STATE:: +VAR2D , time , days , xy , c +:: + +FILL_DEF:: +VAR2D 59.0+(58.0-57.0)*0.5 +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case20/CAP.rc b/Tests/ExtData_Testing_Framework/test_cases/case20/CAP.rc new file mode 100644 index 000000000000..680d0ffa9c5b --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case20/CAP.rc @@ -0,0 +1,4 @@ +CASES:: +CAP1.rc +CAP2.rc +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case20/CAP1.rc b/Tests/ExtData_Testing_Framework/test_cases/case20/CAP1.rc new file mode 100644 index 000000000000..397c91b0abe3 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case20/CAP1.rc @@ -0,0 +1,10 @@ +ROOT_NAME: Root +ROOT_CF: AGCM1.rc +HIST_CF: HISTORY1.rc + +BEG_DATE: 20151231 000000 + +JOB_SGMT: 00001200 000000 +HEARTBEAT_DT: 3600 + + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case20/CAP2.rc b/Tests/ExtData_Testing_Framework/test_cases/case20/CAP2.rc new file mode 100644 index 000000000000..0f06f66198de --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case20/CAP2.rc @@ -0,0 +1,14 @@ +ROOT_NAME: Root +ROOT_CF: AGCM2.rc +HIST_CF: HISTORY2.rc + +BEG_DATE: 20200101 210000 + +JOB_SGMT: 00001200 000000 +HEARTBEAT_DT: 3600 + +#RUN_EXTDATA: .false. +RUN_TIMES:: +20200229 120000 +:: + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case20/ExtData.rc b/Tests/ExtData_Testing_Framework/test_cases/case20/ExtData.rc new file mode 100644 index 000000000000..67ef7b54a4a8 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case20/ExtData.rc @@ -0,0 +1,12 @@ +#CASE_SENSITIVE_VARIABLE_NAMES: .false. +Ext_AllowExtrap: .true. +Prefetch: .true. +DEBUG_LEVEL: 20 + +PrimaryExports%% +VAR2D NA N N 0 none none VAR2D case1.%y4%m2%d2.nc4 +%% + + +DerivedExports%% +%% diff --git a/Tests/ExtData_Testing_Framework/test_cases/case20/HISTORY1.rc b/Tests/ExtData_Testing_Framework/test_cases/case20/HISTORY1.rc new file mode 100644 index 000000000000..7f1045a27232 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case20/HISTORY1.rc @@ -0,0 +1,12 @@ +GRID_LABELS: +:: + +COLLECTIONS: case1 +:: + + case1.template: '%y4%m2%d2.nc4', + case1.format: 'CFIO', + case1.frequency: 240000, + case1.ref_time: 000000, + case1.fields: 'VAR2D', 'Root', + :: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case20/HISTORY2.rc b/Tests/ExtData_Testing_Framework/test_cases/case20/HISTORY2.rc new file mode 100644 index 000000000000..2895432e995a --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case20/HISTORY2.rc @@ -0,0 +1,5 @@ +GRID_LABELS: +:: + +COLLECTIONS: +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case20/README b/Tests/ExtData_Testing_Framework/test_cases/case20/README new file mode 100644 index 000000000000..5e7fa8803054 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case20/README @@ -0,0 +1 @@ +Make daily files for 2016. Then start on February 29th in 2020 and allow extrapolation outside of dataset a climatology diff --git a/Tests/ExtData_Testing_Framework/test_cases/case20/extdata.yaml b/Tests/ExtData_Testing_Framework/test_cases/case20/extdata.yaml new file mode 100644 index 000000000000..01db6d85f976 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case20/extdata.yaml @@ -0,0 +1,8 @@ +Collections: + fstream1: {template: "case1.%y4%m2%d2.nc4", valid_range: "2016-01-01/2016-12-31" } +Samplings: + S1: + extrapolation: clim + source_time: "2016-01-01/2016-12-31" +Exports: + VAR2D: {variable: VAR2D, collection: fstream1, sample: S1} diff --git a/Tests/ExtData_Testing_Framework/test_cases/case21/AGCM1.rc b/Tests/ExtData_Testing_Framework/test_cases/case21/AGCM1.rc new file mode 100644 index 000000000000..1f672143e749 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case21/AGCM1.rc @@ -0,0 +1,24 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC90x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: GenerateExports + +EXPORT_STATE:: +VAR1 , time , days , xy , c +VAR2 , time , days , xy , c +:: + +FILL_DEF:: +VAR1 time +VAR2 time +:: + +REF_TIME: 20040701 000000 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case21/AGCM2.rc b/Tests/ExtData_Testing_Framework/test_cases/case21/AGCM2.rc new file mode 100644 index 000000000000..14b0d586bdfb --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case21/AGCM2.rc @@ -0,0 +1,33 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC90x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: CompareImports + +IMPORT_STATE:: +VAR2D , time , days , xy , c +VAR1 , time , days , xy , c +VAR2 , time , days , xy , c +:: + +EXPORT_STATE:: +VAR2D , time , days , xy , c +VAR1 , time , days , xy , c +VAR2 , time , days , xy , c +:: + + +FILL_DEF:: +VAR2D time+time +VAR1 time +VAR2 time +:: + +REF_TIME: 20040701 000000 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case21/CAP.rc b/Tests/ExtData_Testing_Framework/test_cases/case21/CAP.rc new file mode 100644 index 000000000000..680d0ffa9c5b --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case21/CAP.rc @@ -0,0 +1,4 @@ +CASES:: +CAP1.rc +CAP2.rc +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case21/CAP1.rc b/Tests/ExtData_Testing_Framework/test_cases/case21/CAP1.rc new file mode 100644 index 000000000000..ce2690d6937b --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case21/CAP1.rc @@ -0,0 +1,25 @@ +ROOT_NAME: Root +ROOT_CF: AGCM1.rc +HIST_CF: HISTORY1.rc + +BEG_DATE: 20040101 210000 + +JOB_SGMT: 00001200 000000 +HEARTBEAT_DT: 3600 + +#RUN_EXTDATA: .false. +RUN_TIMES:: +20040115 210000 +20040215 210000 +20040315 210000 +20040415 210000 +20040515 210000 +20040615 210000 +20040715 210000 +20040815 210000 +20040915 210000 +20041015 210000 +20041115 210000 +20041215 210000 +:: + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case21/CAP2.rc b/Tests/ExtData_Testing_Framework/test_cases/case21/CAP2.rc new file mode 100644 index 000000000000..4e9e1bb95026 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case21/CAP2.rc @@ -0,0 +1,15 @@ +ROOT_NAME: Root +ROOT_CF: AGCM2.rc +HIST_CF: HISTORY2.rc + +BEG_DATE: 20040101 210000 + +JOB_SGMT: 00001200 000000 +HEARTBEAT_DT: 3600 + +#RUN_EXTDATA: .false. +RUN_TIMES:: +20041125 210000 +20041126 210000 +:: + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case21/ExtData.rc b/Tests/ExtData_Testing_Framework/test_cases/case21/ExtData.rc new file mode 100644 index 000000000000..57736ed30bef --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case21/ExtData.rc @@ -0,0 +1,14 @@ +#CASE_SENSITIVE_VARIABLE_NAMES: .false. +Ext_AllowExtrap: .false. +Prefetch: .true. +#DEBUG_LEVEL: 20 + +PrimaryExports%% +VAR1 NA N N 0 none none VAR1 case1.%y4.nc4 +VAR2 NA N N 0 none none VAR2 case1.%y4.nc4 +%% + + +DerivedExports%% +VAR2D VAR1+VAR2 0 +%% diff --git a/Tests/ExtData_Testing_Framework/test_cases/case21/HISTORY1.rc b/Tests/ExtData_Testing_Framework/test_cases/case21/HISTORY1.rc new file mode 100644 index 000000000000..bb5ee8a77ef6 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case21/HISTORY1.rc @@ -0,0 +1,13 @@ +GRID_LABELS: +:: + +COLLECTIONS: case1 +:: + + case1.template: '%y4.nc4', + case1.format: 'CFIO', + case1.frequency: 010000, + case1.duration: 000000 + case1.fields: 'VAR1', 'Root', + 'VAR2', 'Root', + :: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case21/HISTORY2.rc b/Tests/ExtData_Testing_Framework/test_cases/case21/HISTORY2.rc new file mode 100644 index 000000000000..2895432e995a --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case21/HISTORY2.rc @@ -0,0 +1,5 @@ +GRID_LABELS: +:: + +COLLECTIONS: +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case21/README b/Tests/ExtData_Testing_Framework/test_cases/case21/README new file mode 100644 index 000000000000..df7cb0f82872 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case21/README @@ -0,0 +1 @@ +test derived export to create sum of 2 variables diff --git a/Tests/ExtData_Testing_Framework/test_cases/case21/extdata.yaml b/Tests/ExtData_Testing_Framework/test_cases/case21/extdata.yaml new file mode 100644 index 000000000000..c1f9b4354434 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case21/extdata.yaml @@ -0,0 +1,8 @@ +Collections: + fstream1: {template: case1.%y4.nc4, valid_range: "2004-01-01/2005-01-01" } +Exports: + VAR1: {variable: VAR1, collection: fstream1} + VAR2: {variable: VAR2, collection: fstream1} + +Derived: + VAR2D: {function: VAR1+VAR2} diff --git a/Tests/ExtData_Testing_Framework/test_cases/case22/AGCM1.rc b/Tests/ExtData_Testing_Framework/test_cases/case22/AGCM1.rc new file mode 100644 index 000000000000..81bb07dcdcbd --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case22/AGCM1.rc @@ -0,0 +1,22 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC90x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: GenerateExports + +EXPORT_STATE:: +VAR2D , time , days , xy , c +:: + +FILL_DEF:: +VAR2D time +:: + +REF_TIME: 20080101 000000 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case22/AGCM2.rc b/Tests/ExtData_Testing_Framework/test_cases/case22/AGCM2.rc new file mode 100644 index 000000000000..0a1f70b7456c --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case22/AGCM2.rc @@ -0,0 +1,22 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC90x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 90 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: GenerateExports + +EXPORT_STATE:: +VAR2D , time , days , xy , c +:: + +FILL_DEF:: +VAR2D time +:: + +REF_TIME: 20080101 000000 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case22/AGCM3.rc b/Tests/ExtData_Testing_Framework/test_cases/case22/AGCM3.rc new file mode 100644 index 000000000000..dc81ef15d2da --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case22/AGCM3.rc @@ -0,0 +1,26 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC900x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: CompareImports + +IMPORT_STATE:: +VAR2D , time , days , xy , c +:: + +EXPORT_STATE:: +VAR2D , time , days , xy , c +:: + +FILL_DEF:: +VAR2D time +:: + +REF_TIME: 20080101 000000 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case22/CAP.rc b/Tests/ExtData_Testing_Framework/test_cases/case22/CAP.rc new file mode 100644 index 000000000000..7cbd02ce9493 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case22/CAP.rc @@ -0,0 +1,5 @@ +CASES:: +CAP1.rc +CAP2.rc +CAP3.rc +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case22/CAP1.rc b/Tests/ExtData_Testing_Framework/test_cases/case22/CAP1.rc new file mode 100644 index 000000000000..2dd970d08f1b --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case22/CAP1.rc @@ -0,0 +1,12 @@ +ROOT_NAME: Root +ROOT_CF: AGCM1.rc +HIST_CF: HISTORY1.rc + +BEG_DATE: 20071231 230000 + +JOB_SGMT: 00001201 000000 +HEARTBEAT_DT: 3600 + + +USE_EXTDATA2G: .true. +USE_EXTDATA2G: .true. diff --git a/Tests/ExtData_Testing_Framework/test_cases/case22/CAP2.rc b/Tests/ExtData_Testing_Framework/test_cases/case22/CAP2.rc new file mode 100644 index 000000000000..18c901f66ed9 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case22/CAP2.rc @@ -0,0 +1,12 @@ +ROOT_NAME: Root +ROOT_CF: AGCM2.rc +HIST_CF: HISTORY2.rc + +BEG_DATE: 20081231 230000 + +JOB_SGMT: 00001200 000000 +HEARTBEAT_DT: 3600 + + +USE_EXTDATA2G: .true. +USE_EXTDATA2G: .true. diff --git a/Tests/ExtData_Testing_Framework/test_cases/case22/CAP3.rc b/Tests/ExtData_Testing_Framework/test_cases/case22/CAP3.rc new file mode 100644 index 000000000000..cbb7b325f460 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case22/CAP3.rc @@ -0,0 +1,11 @@ +ROOT_NAME: Root +ROOT_CF: AGCM3.rc +HIST_CF: HISTORY3.rc + +BEG_DATE: 20081229 000000 + +JOB_SGMT: 00000010 000000 +HEARTBEAT_DT: 3600 + + +USE_EXTDATA2G: .true. diff --git a/Tests/ExtData_Testing_Framework/test_cases/case22/ExtData.rc b/Tests/ExtData_Testing_Framework/test_cases/case22/ExtData.rc new file mode 100644 index 000000000000..1b98d7c432b9 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case22/ExtData.rc @@ -0,0 +1,12 @@ +#CASE_SENSITIVE_VARIABLE_NAMES: .false. +Ext_AllowExtrap: .false. +Prefetch: .true. +DEBUG_LEVEL: 20 + +PrimaryExports%% +VAR2D NA 2008 N 0 none none VAR2D case1.nc4 +%% + + +DerivedExports%% +%% diff --git a/Tests/ExtData_Testing_Framework/test_cases/case22/HISTORY1.rc b/Tests/ExtData_Testing_Framework/test_cases/case22/HISTORY1.rc new file mode 100644 index 000000000000..fe45450680fd --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case22/HISTORY1.rc @@ -0,0 +1,13 @@ +GRID_LABELS: +:: + +COLLECTIONS: case1 +:: + + case1.template: 'nc4', + case1.format: 'CFIO', + case1.frequency: 240000, + case1.duration: 000000, + case1.ref_time: 000000, + case1.fields: 'VAR2D', 'Root', + :: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case22/HISTORY2.rc b/Tests/ExtData_Testing_Framework/test_cases/case22/HISTORY2.rc new file mode 100644 index 000000000000..e75f98424508 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case22/HISTORY2.rc @@ -0,0 +1,13 @@ +GRID_LABELS: +:: + +COLLECTIONS: case2 +:: + + case2.template: 'nc4', + case2.format: 'CFIO', + case2.frequency: 240000, + case2.duration: 000000, + case2.ref_time: 000000, + case2.fields: 'VAR2D', 'Root', + :: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case22/HISTORY3.rc b/Tests/ExtData_Testing_Framework/test_cases/case22/HISTORY3.rc new file mode 100644 index 000000000000..720dd45ecd3d --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case22/HISTORY3.rc @@ -0,0 +1,13 @@ +GRID_LABELS: +:: + +COLLECTIONS: +:: + + case2.template: 'nc4', + case2.format: 'CFIO', + case2.frequency: 240000, + case2.duration: 000000, + case2.ref_time: 000000, + case2.fields: 'VAR2D', 'Root', + :: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case22/README b/Tests/ExtData_Testing_Framework/test_cases/case22/README new file mode 100644 index 000000000000..6ea1c769dbad --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case22/README @@ -0,0 +1 @@ +test multiple datasets where an export uses both with with no extrapolation outside and crosses transition date diff --git a/Tests/ExtData_Testing_Framework/test_cases/case22/case1.rcx b/Tests/ExtData_Testing_Framework/test_cases/case22/case1.rcx new file mode 100644 index 000000000000..1a19553ea86f --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case22/case1.rcx @@ -0,0 +1,7 @@ + case1.template: 'nc4', + case1.format: 'CFIO', + case1.frequency: 240000, + case1.duration: 000000, + case1.ref_time: 000000, + case1.fields: 'VAR2D', 'Root', + :: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case22/case2.rcx b/Tests/ExtData_Testing_Framework/test_cases/case22/case2.rcx new file mode 100644 index 000000000000..4ba51fb14b9b --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case22/case2.rcx @@ -0,0 +1,7 @@ + case2.template: 'nc4', + case2.format: 'CFIO', + case2.frequency: 240000, + case2.duration: 000000, + case2.ref_time: 000000, + case2.fields: 'VAR2D', 'Root', + :: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case22/egress b/Tests/ExtData_Testing_Framework/test_cases/case22/egress new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case22/extdata.yaml b/Tests/ExtData_Testing_Framework/test_cases/case22/extdata.yaml new file mode 100644 index 000000000000..34ce04867e7b --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case22/extdata.yaml @@ -0,0 +1,7 @@ +Collections: + fstream1: {template: "case1.nc4", valid_range: "2008-01-01/2008-12-31"} + fstream2: {template: "case2.nc4", valid_range: "2009-01-01/2009-12-31"} +Exports: + VAR2D: + - {starting: "2008-01-01", variable: VAR2D, collection: fstream1} + - {starting: "2009-01-01", variable: VAR2D, collection: fstream2} diff --git a/Tests/ExtData_Testing_Framework/test_cases/case22/warnings_and_errors.log b/Tests/ExtData_Testing_Framework/test_cases/case22/warnings_and_errors.log new file mode 100644 index 000000000000..9144b2f54291 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case22/warnings_and_errors.log @@ -0,0 +1,60 @@ +pe=00000: MAPL: No configure file specified for logging layer. Using defaults. +pe=00000: MAPL: No configure file specified for logging layer. Using defaults. +pe=00000: MAPL: No configure file specified for logging layer. Using defaults. +pe=00000: MAPL: No configure file specified for logging layer. Using defaults. +pe=00000: EXTDATA: Using ExtData2G, note this is still in BETA stage +pe=00000: MAPL: No configure file specified for logging layer. Using defaults. +pe=00000: MAPL: No configure file specified for logging layer. Using defaults. +pe=00000: MAPL: No configure file specified for logging layer. Using defaults. +pe=00000: MAPL: No configure file specified for logging layer. Using defaults. +pe=00000: MAPL: No configure file specified for logging layer. Using defaults. +pe=00000: EXTDATA: Using ExtData2G, note this is still in BETA stage +pe=00000: MAPL: No configure file specified for logging layer. Using defaults. +pe=00000: MAPL: No configure file specified for logging layer. Using defaults. +pe=00000: MAPL: No configure file specified for logging layer. Using defaults. +pe=00000: MAPL: No configure file specified for logging layer. Using defaults. +pe=00000: MAPL: No configure file specified for logging layer. Using defaults. +pe=00000: MAPL: No configure file specified for logging layer. Using defaults. +pe=00000: MAPL: No configure file specified for logging layer. Using defaults. +pe=00000: EXTDATA: Using ExtData2G, note this is still in BETA stage +pe=00000: EXTDATA: In ExtData resource file, could not find: VAR2D +pe=00000: MAPL: No configure file specified for logging layer. Using defaults. +pe=00000: EXTDATA: Using ExtData2G, note this is still in BETA stage +pe=00000: EXTDATA: In ExtData resource file, could not find: VAR2D +pe=00000: MAPL: No configure file specified for logging layer. Using defaults. +pe=00000: EXTDATA: Using ExtData2G, note this is still in BETA stage +pe=00000: EXTDATA: In ExtData resource file, could not find: VAR2D +pe=00000: MAPL: No configure file specified for logging layer. Using defaults. +pe=00000: EXTDATA: Using ExtData2G, note this is still in BETA stage +pe=00000: MAPL: No configure file specified for logging layer. Using defaults. +pe=00000: EXTDATA: Using ExtData2G, note this is still in BETA stage +pe=00000: MAPL: No configure file specified for logging layer. Using defaults. +pe=00000: EXTDATA: Using ExtData2G, note this is still in BETA stage +pe=00000: MAPL: No configure file specified for logging layer. Using defaults. +pe=00000: EXTDATA: Using ExtData2G, note this is still in BETA stage +pe=00000: MAPL: No configure file specified for logging layer. Using defaults. +pe=00000: EXTDATA: Using ExtData2G, note this is still in BETA stage +pe=00000: MAPL: No configure file specified for logging layer. Using defaults. +pe=00000: EXTDATA: Using ExtData2G, note this is still in BETA stage +pe=00000: MAPL: No configure file specified for logging layer. Using defaults. +pe=00000: EXTDATA: Using ExtData2G, note this is still in BETA stage +pe=00000: MAPL: No configure file specified for logging layer. Using defaults. +pe=00000: EXTDATA: Using ExtData2G, note this is still in BETA stage +pe=00000: MAPL: No configure file specified for logging layer. Using defaults. +pe=00000: EXTDATA: Using ExtData2G, note this is still in BETA stage +pe=00000: MAPL: No configure file specified for logging layer. Using defaults. +pe=00000: EXTDATA: Using ExtData2G, note this is still in BETA stage +pe=00000: MAPL: No configure file specified for logging layer. Using defaults. +pe=00000: EXTDATA: Using ExtData2G, note this is still in BETA stage +pe=00000: MAPL: No configure file specified for logging layer. Using defaults. +pe=00000: EXTDATA: Using ExtData2G, note this is still in BETA stage +pe=00000: MAPL: No configure file specified for logging layer. Using defaults. +pe=00000: EXTDATA: Using ExtData2G, note this is still in BETA stage +pe=00000: MAPL: No configure file specified for logging layer. Using defaults. +pe=00000: EXTDATA: Using ExtData2G, note this is still in BETA stage +pe=00000: MAPL: No configure file specified for logging layer. Using defaults. +pe=00000: EXTDATA: Using ExtData2G, note this is still in BETA stage +pe=00000: MAPL: No configure file specified for logging layer. Using defaults. +pe=00000: EXTDATA: Using ExtData2G, note this is still in BETA stage +pe=00000: MAPL: No configure file specified for logging layer. Using defaults. +pe=00000: EXTDATA: Using ExtData2G, note this is still in BETA stage diff --git a/Tests/ExtData_Testing_Framework/test_cases/case23/AGCM1.rc b/Tests/ExtData_Testing_Framework/test_cases/case23/AGCM1.rc new file mode 100644 index 000000000000..3583e9d12516 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case23/AGCM1.rc @@ -0,0 +1,22 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC90x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: GenerateExports + +EXPORT_STATE:: +VAR2D , time , days , xy , c +:: + +FILL_DEF:: +VAR2D time +:: + +REF_TIME: 20160101 000000 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case23/AGCM2.rc b/Tests/ExtData_Testing_Framework/test_cases/case23/AGCM2.rc new file mode 100644 index 000000000000..3583e9d12516 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case23/AGCM2.rc @@ -0,0 +1,22 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC90x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: GenerateExports + +EXPORT_STATE:: +VAR2D , time , days , xy , c +:: + +FILL_DEF:: +VAR2D time +:: + +REF_TIME: 20160101 000000 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case23/AGCM3.rc b/Tests/ExtData_Testing_Framework/test_cases/case23/AGCM3.rc new file mode 100644 index 000000000000..fa066d52daf6 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case23/AGCM3.rc @@ -0,0 +1,26 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC90x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: FillImports + +IMPORT_STATE:: +VAR2D , time , days , xy , c +:: + +EXPORT_STATE:: +VAR2D , time , days , xy , c +:: + +FILL_DEF:: +VAR2D time +:: + +REF_TIME: 20160101 000000 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case23/CAP.rc b/Tests/ExtData_Testing_Framework/test_cases/case23/CAP.rc new file mode 100644 index 000000000000..7cbd02ce9493 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case23/CAP.rc @@ -0,0 +1,5 @@ +CASES:: +CAP1.rc +CAP2.rc +CAP3.rc +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case23/CAP1.rc b/Tests/ExtData_Testing_Framework/test_cases/case23/CAP1.rc new file mode 100644 index 000000000000..cd699d9b294a --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case23/CAP1.rc @@ -0,0 +1,11 @@ +ROOT_NAME: Root +ROOT_CF: AGCM1.rc +HIST_CF: HISTORY1.rc + +BEG_DATE: 20151231 000000 + +JOB_SGMT: 00001200 000000 +HEARTBEAT_DT: 3600 + + +USE_EXTDATA2G: .true. diff --git a/Tests/ExtData_Testing_Framework/test_cases/case23/CAP2.rc b/Tests/ExtData_Testing_Framework/test_cases/case23/CAP2.rc new file mode 100644 index 000000000000..70bafc168604 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case23/CAP2.rc @@ -0,0 +1,11 @@ +ROOT_NAME: Root +ROOT_CF: AGCM2.rc +HIST_CF: HISTORY2.rc + +BEG_DATE: 20191225 000000 + +JOB_SGMT: 00000020 000000 +HEARTBEAT_DT: 3600 + + +USE_EXTDATA2G: .true. diff --git a/Tests/ExtData_Testing_Framework/test_cases/case23/CAP3.rc b/Tests/ExtData_Testing_Framework/test_cases/case23/CAP3.rc new file mode 100644 index 000000000000..177c24b23153 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case23/CAP3.rc @@ -0,0 +1,11 @@ +ROOT_NAME: Root +ROOT_CF: AGCM3.rc +HIST_CF: HISTORY3.rc + +BEG_DATE: 20191227 000000 + +JOB_SGMT: 00000011 000000 +HEARTBEAT_DT: 3600 + + +USE_EXTDATA2G: .true. diff --git a/Tests/ExtData_Testing_Framework/test_cases/case23/ExtData.rc b/Tests/ExtData_Testing_Framework/test_cases/case23/ExtData.rc new file mode 100644 index 000000000000..67ef7b54a4a8 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case23/ExtData.rc @@ -0,0 +1,12 @@ +#CASE_SENSITIVE_VARIABLE_NAMES: .false. +Ext_AllowExtrap: .true. +Prefetch: .true. +DEBUG_LEVEL: 20 + +PrimaryExports%% +VAR2D NA N N 0 none none VAR2D case1.%y4%m2%d2.nc4 +%% + + +DerivedExports%% +%% diff --git a/Tests/ExtData_Testing_Framework/test_cases/case23/HISTORY1.rc b/Tests/ExtData_Testing_Framework/test_cases/case23/HISTORY1.rc new file mode 100644 index 000000000000..7f1045a27232 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case23/HISTORY1.rc @@ -0,0 +1,12 @@ +GRID_LABELS: +:: + +COLLECTIONS: case1 +:: + + case1.template: '%y4%m2%d2.nc4', + case1.format: 'CFIO', + case1.frequency: 240000, + case1.ref_time: 000000, + case1.fields: 'VAR2D', 'Root', + :: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case23/HISTORY2.rc b/Tests/ExtData_Testing_Framework/test_cases/case23/HISTORY2.rc new file mode 100644 index 000000000000..cddbea20dd5e --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case23/HISTORY2.rc @@ -0,0 +1,12 @@ +GRID_LABELS: +:: + +COLLECTIONS: case2 +:: + + case2.template: '%y4%m2%d2.nc4', + case2.format: 'CFIO', + case2.frequency: 240000, + case2.ref_time: 000000, + case2.fields: 'VAR2D', 'Root', + :: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case23/HISTORY3.rc b/Tests/ExtData_Testing_Framework/test_cases/case23/HISTORY3.rc new file mode 100644 index 000000000000..31702240896d --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case23/HISTORY3.rc @@ -0,0 +1,12 @@ +GRID_LABELS: +:: + +COLLECTIONS: +:: + + case1.template: '%y4%m2%d2.nc4', + case1.format: 'CFIO', + case1.frequency: 240000, + case1.ref_time: 000000, + case1.fields: 'VAR2D', 'Root', + :: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case23/README b/Tests/ExtData_Testing_Framework/test_cases/case23/README new file mode 100644 index 000000000000..8f1c29fb1967 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case23/README @@ -0,0 +1 @@ +Test multiple datasets and treat Climatology in the first and a real-time in the 2nd diff --git a/Tests/ExtData_Testing_Framework/test_cases/case23/extdata.yaml b/Tests/ExtData_Testing_Framework/test_cases/case23/extdata.yaml new file mode 100644 index 000000000000..49fa281346d1 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case23/extdata.yaml @@ -0,0 +1,11 @@ +Collections: + fstream1: {template: "case1.%y4%m2%d2.nc4", valid_range: "2016-01-01/2016-12-31" } + fstream2: {template: "case2.%y4%m2%d2.nc4", valid_range: "2019-12-31/2020-01-10" } +Samplings: + S1: + extrapolation: clim + source_time: "2016-01-01/2016-12-31" +Exports: + VAR2D: + - {starting: 1970-01-01, variable: VAR2D, collection: fstream1, sample: S1} + - {starting: 2020-01-01, variable: VAR2D, collection: fstream2} diff --git a/Tests/ExtData_Testing_Framework/test_cases/case24/AGCM1.rc b/Tests/ExtData_Testing_Framework/test_cases/case24/AGCM1.rc new file mode 100644 index 000000000000..2ef970737fb7 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case24/AGCM1.rc @@ -0,0 +1,22 @@ +NX: 1 +NY: 6 + +Root.GRID_TYPE: Cubed-Sphere +Root.GRIDNAME: PE24x144-CF +Root.LM: 3 +Root.IM_WORLD: 24 +Root.NF: 6 + +RUN_MODE: GenerateExports + +EXPORT_STATE:: +VAR2D , time , days , xy , c +VAR3D , time , days , xyz , c +:: + +FILL_DEF:: +VAR2D time +VAR3D time +:: + +REF_TIME: 20040701 000000 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case24/AGCM2.rc b/Tests/ExtData_Testing_Framework/test_cases/case24/AGCM2.rc new file mode 100644 index 000000000000..c49217bcec3c --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case24/AGCM2.rc @@ -0,0 +1,27 @@ +NX: 1 +NY: 6 + +Root.GRID_TYPE: Cubed-Sphere +Root.GRIDNAME: PE24x144-CF +Root.LM: 3 +Root.IM_WORLD: 24 +Root.NF: 6 + +RUN_MODE: CompareImports + +IMPORT_STATE:: +VAR2D , time , days , xy , c +VAR3D , time , days , xyz , c +:: + +EXPORT_STATE:: +VAR2D , time , days , xy , c +VAR3D , time , days , xyz , c +:: + +FILL_DEF:: +VAR2D time +VAR3D time +:: + +REF_TIME: 20040701 000000 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case24/CAP.rc b/Tests/ExtData_Testing_Framework/test_cases/case24/CAP.rc new file mode 100644 index 000000000000..680d0ffa9c5b --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case24/CAP.rc @@ -0,0 +1,4 @@ +CASES:: +CAP1.rc +CAP2.rc +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case24/CAP1.rc b/Tests/ExtData_Testing_Framework/test_cases/case24/CAP1.rc new file mode 100644 index 000000000000..ce2690d6937b --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case24/CAP1.rc @@ -0,0 +1,25 @@ +ROOT_NAME: Root +ROOT_CF: AGCM1.rc +HIST_CF: HISTORY1.rc + +BEG_DATE: 20040101 210000 + +JOB_SGMT: 00001200 000000 +HEARTBEAT_DT: 3600 + +#RUN_EXTDATA: .false. +RUN_TIMES:: +20040115 210000 +20040215 210000 +20040315 210000 +20040415 210000 +20040515 210000 +20040615 210000 +20040715 210000 +20040815 210000 +20040915 210000 +20041015 210000 +20041115 210000 +20041215 210000 +:: + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case24/CAP2.rc b/Tests/ExtData_Testing_Framework/test_cases/case24/CAP2.rc new file mode 100644 index 000000000000..4e9e1bb95026 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case24/CAP2.rc @@ -0,0 +1,15 @@ +ROOT_NAME: Root +ROOT_CF: AGCM2.rc +HIST_CF: HISTORY2.rc + +BEG_DATE: 20040101 210000 + +JOB_SGMT: 00001200 000000 +HEARTBEAT_DT: 3600 + +#RUN_EXTDATA: .false. +RUN_TIMES:: +20041125 210000 +20041126 210000 +:: + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case24/ExtData.rc b/Tests/ExtData_Testing_Framework/test_cases/case24/ExtData.rc new file mode 100644 index 000000000000..0e50d21b5b84 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case24/ExtData.rc @@ -0,0 +1,13 @@ +#CASE_SENSITIVE_VARIABLE_NAMES: .false. +Ext_AllowExtrap: .false. +Prefetch: .true. +#DEBUG_LEVEL: 20 + +PrimaryExports%% +VAR2D NA N N 0 none none VAR2D case1.%y4.nc4 +VAR3D NA N N 0 none none VAR3D case2.%y4.nc4 +%% + + +DerivedExports%% +%% diff --git a/Tests/ExtData_Testing_Framework/test_cases/case24/HISTORY1.rc b/Tests/ExtData_Testing_Framework/test_cases/case24/HISTORY1.rc new file mode 100644 index 000000000000..15d036f1bc9f --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case24/HISTORY1.rc @@ -0,0 +1,19 @@ +GRID_LABELS: +:: + +COLLECTIONS: case1 + case2 +:: + + case1.template: '%y4.nc4', + case1.format: 'CFIO', + case1.frequency: 010000, + case1.duration: 000000 + case1.fields: 'VAR2D', 'Root', + :: + case2.template: '%y4.nc4', + case2.format: 'CFIO', + case2.frequency: 010000, + case2.duration: 000000 + case2.fields: 'VAR3D', 'Root', + :: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case24/HISTORY2.rc b/Tests/ExtData_Testing_Framework/test_cases/case24/HISTORY2.rc new file mode 100644 index 000000000000..2895432e995a --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case24/HISTORY2.rc @@ -0,0 +1,5 @@ +GRID_LABELS: +:: + +COLLECTIONS: +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case24/README b/Tests/ExtData_Testing_Framework/test_cases/case24/README new file mode 100644 index 000000000000..39f44190eea4 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case24/README @@ -0,0 +1 @@ +Case, 12-month/12 time 2004 file with 2 updates, non-climatology, cubed-sphere diff --git a/Tests/ExtData_Testing_Framework/test_cases/case24/extdata.yaml b/Tests/ExtData_Testing_Framework/test_cases/case24/extdata.yaml new file mode 100644 index 000000000000..ade3dd293935 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case24/extdata.yaml @@ -0,0 +1,6 @@ +Collections: + fstream1: {template: case1.%y4.nc4, valid_range: "2004-01-01/2005-01-01" } + fstream2: {template: case2.%y4.nc4, valid_range: "2004-01-01/2005-01-01" } +Exports: + VAR2D: {variable: VAR2D, collection: fstream1} + VAR3D: {variable: VAR3D, collection: fstream2} diff --git a/Tests/ExtData_Testing_Framework/test_cases/case24/nproc.rc b/Tests/ExtData_Testing_Framework/test_cases/case24/nproc.rc new file mode 100644 index 000000000000..1e8b31496214 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case24/nproc.rc @@ -0,0 +1 @@ +6 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case25/AGCM1.rc b/Tests/ExtData_Testing_Framework/test_cases/case25/AGCM1.rc new file mode 100644 index 000000000000..9772fa73fa05 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case25/AGCM1.rc @@ -0,0 +1,22 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC90x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: GenerateExports + +EXPORT_STATE:: +VAR3D , time , days , xyz , e +:: + +FILL_DEF:: +VAR3D time +:: + +REF_TIME: 20040701 000000 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case25/AGCM2.rc b/Tests/ExtData_Testing_Framework/test_cases/case25/AGCM2.rc new file mode 100644 index 000000000000..25468d893da6 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case25/AGCM2.rc @@ -0,0 +1,26 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC90x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: CompareImports + +IMPORT_STATE:: +VAR3D , time , days , xyz , e +:: + +EXPORT_STATE:: +VAR3D , time , days , xyz , e +:: + +FILL_DEF:: +VAR3D time +:: + +REF_TIME: 20040701 000000 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case25/CAP.rc b/Tests/ExtData_Testing_Framework/test_cases/case25/CAP.rc new file mode 100644 index 000000000000..680d0ffa9c5b --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case25/CAP.rc @@ -0,0 +1,4 @@ +CASES:: +CAP1.rc +CAP2.rc +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case25/CAP1.rc b/Tests/ExtData_Testing_Framework/test_cases/case25/CAP1.rc new file mode 100644 index 000000000000..ce2690d6937b --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case25/CAP1.rc @@ -0,0 +1,25 @@ +ROOT_NAME: Root +ROOT_CF: AGCM1.rc +HIST_CF: HISTORY1.rc + +BEG_DATE: 20040101 210000 + +JOB_SGMT: 00001200 000000 +HEARTBEAT_DT: 3600 + +#RUN_EXTDATA: .false. +RUN_TIMES:: +20040115 210000 +20040215 210000 +20040315 210000 +20040415 210000 +20040515 210000 +20040615 210000 +20040715 210000 +20040815 210000 +20040915 210000 +20041015 210000 +20041115 210000 +20041215 210000 +:: + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case25/CAP2.rc b/Tests/ExtData_Testing_Framework/test_cases/case25/CAP2.rc new file mode 100644 index 000000000000..4e9e1bb95026 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case25/CAP2.rc @@ -0,0 +1,15 @@ +ROOT_NAME: Root +ROOT_CF: AGCM2.rc +HIST_CF: HISTORY2.rc + +BEG_DATE: 20040101 210000 + +JOB_SGMT: 00001200 000000 +HEARTBEAT_DT: 3600 + +#RUN_EXTDATA: .false. +RUN_TIMES:: +20041125 210000 +20041126 210000 +:: + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case25/ExtData.rc b/Tests/ExtData_Testing_Framework/test_cases/case25/ExtData.rc new file mode 100644 index 000000000000..a45d1dd13f7f --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case25/ExtData.rc @@ -0,0 +1,13 @@ +#CASE_SENSITIVE_VARIABLE_NAMES: .false. +Ext_AllowExtrap: .false. +Prefetch: .true. +#DEBUG_LEVEL: 20 + +PrimaryExports%% +VAR2D NA N N 0 none none VAR2D case1.%y4.nc4 +VAR3D NA N N 0 none none VAR3D case1.%y4.nc4 +%% + + +DerivedExports%% +%% diff --git a/Tests/ExtData_Testing_Framework/test_cases/case25/HISTORY1.rc b/Tests/ExtData_Testing_Framework/test_cases/case25/HISTORY1.rc new file mode 100644 index 000000000000..1b6e816089a7 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case25/HISTORY1.rc @@ -0,0 +1,23 @@ +GRID_LABELS: PC45x21-DC +:: + +PC45x21-DC.GRID_TYPE: LatLon +PC45x21-DC.IM_WORLD: 45 +PC45x21-DC.JM_WORLD: 21 +PC45x21-DC.POLE: PC +PC45x21-DC.DATELINE: DC +PC45x21-DC.LM: 3 + +#GRID_LABELS: +#:: + +COLLECTIONS: case1 +:: + + case1.template: '%y4.nc4', + case1.format: 'CFIO', + case1.frequency: 010000, + case1.duration: 000000 + case1.grid_label: PC45x21-DC + case1.fields: 'VAR3D', 'Root', + :: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case25/HISTORY2.rc b/Tests/ExtData_Testing_Framework/test_cases/case25/HISTORY2.rc new file mode 100644 index 000000000000..2895432e995a --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case25/HISTORY2.rc @@ -0,0 +1,5 @@ +GRID_LABELS: +:: + +COLLECTIONS: +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case25/README b/Tests/ExtData_Testing_Framework/test_cases/case25/README new file mode 100644 index 000000000000..318986102ca4 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case25/README @@ -0,0 +1 @@ +test reading edge variables diff --git a/Tests/ExtData_Testing_Framework/test_cases/case25/extdata.yaml b/Tests/ExtData_Testing_Framework/test_cases/case25/extdata.yaml new file mode 100644 index 000000000000..e2ddb90675ab --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case25/extdata.yaml @@ -0,0 +1,5 @@ +Collections: + fstream1: {template: case1.%y4.nc4, valid_range: "2004-01-01/2005-01-01" } +Exports: + VAR2D: {variable: VAR2D, collection: fstream1} + VAR3D: {variable: VAR3D, collection: fstream1} diff --git a/Tests/ExtData_Testing_Framework/test_cases/case26/AGCM1.rc b/Tests/ExtData_Testing_Framework/test_cases/case26/AGCM1.rc new file mode 100644 index 000000000000..214bbb31e7bf --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case26/AGCM1.rc @@ -0,0 +1,24 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC90x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: GenerateExports + +EXPORT_STATE:: +VAR3Dc , time , days , xyz , c +VAR3De , time , days , xyz , e +:: + +FILL_DEF:: +VAR3Dc time +VAR3De time +:: + +REF_TIME: 20040701 000000 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case26/AGCM2.rc b/Tests/ExtData_Testing_Framework/test_cases/case26/AGCM2.rc new file mode 100644 index 000000000000..defaa0643ab7 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case26/AGCM2.rc @@ -0,0 +1,29 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC90x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: CompareImports + +IMPORT_STATE:: +VAR3Dc , time , days , xyz , c +VAR3De , time , days , xyz , e +:: + +EXPORT_STATE:: +VAR3Dc , time , days , xyz , c +VAR3De , time , days , xyz , e +:: + +FILL_DEF:: +VAR3Dc time +VAR3De time +:: + +REF_TIME: 20040701 000000 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case26/CAP.rc b/Tests/ExtData_Testing_Framework/test_cases/case26/CAP.rc new file mode 100644 index 000000000000..680d0ffa9c5b --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case26/CAP.rc @@ -0,0 +1,4 @@ +CASES:: +CAP1.rc +CAP2.rc +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case26/CAP1.rc b/Tests/ExtData_Testing_Framework/test_cases/case26/CAP1.rc new file mode 100644 index 000000000000..ce2690d6937b --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case26/CAP1.rc @@ -0,0 +1,25 @@ +ROOT_NAME: Root +ROOT_CF: AGCM1.rc +HIST_CF: HISTORY1.rc + +BEG_DATE: 20040101 210000 + +JOB_SGMT: 00001200 000000 +HEARTBEAT_DT: 3600 + +#RUN_EXTDATA: .false. +RUN_TIMES:: +20040115 210000 +20040215 210000 +20040315 210000 +20040415 210000 +20040515 210000 +20040615 210000 +20040715 210000 +20040815 210000 +20040915 210000 +20041015 210000 +20041115 210000 +20041215 210000 +:: + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case26/CAP2.rc b/Tests/ExtData_Testing_Framework/test_cases/case26/CAP2.rc new file mode 100644 index 000000000000..4e9e1bb95026 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case26/CAP2.rc @@ -0,0 +1,15 @@ +ROOT_NAME: Root +ROOT_CF: AGCM2.rc +HIST_CF: HISTORY2.rc + +BEG_DATE: 20040101 210000 + +JOB_SGMT: 00001200 000000 +HEARTBEAT_DT: 3600 + +#RUN_EXTDATA: .false. +RUN_TIMES:: +20041125 210000 +20041126 210000 +:: + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case26/ExtData.rc b/Tests/ExtData_Testing_Framework/test_cases/case26/ExtData.rc new file mode 100644 index 000000000000..10b7735216ec --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case26/ExtData.rc @@ -0,0 +1,13 @@ +#CASE_SENSITIVE_VARIABLE_NAMES: .false. +Ext_AllowExtrap: .false. +Prefetch: .true. +#DEBUG_LEVEL: 20 + +PrimaryExports%% +VAR3Dc NA N N 0 none none VAR3Dc casec.%y4.nc4 +VAR3De NA N N 0 none none VAR3De casee.%y4.nc4 +%% + + +DerivedExports%% +%% diff --git a/Tests/ExtData_Testing_Framework/test_cases/case26/HISTORY1.rc b/Tests/ExtData_Testing_Framework/test_cases/case26/HISTORY1.rc new file mode 100644 index 000000000000..d0936b060353 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case26/HISTORY1.rc @@ -0,0 +1,31 @@ +GRID_LABELS: PC45x21-DC +:: + +PC45x21-DC.GRID_TYPE: LatLon +PC45x21-DC.IM_WORLD: 45 +PC45x21-DC.JM_WORLD: 21 +PC45x21-DC.POLE: PC +PC45x21-DC.DATELINE: DC +PC45x21-DC.LM: 3 + +#GRID_LABELS: +#:: + +COLLECTIONS: casec + casee +:: + + casec.template: '%y4.nc4', + casec.format: 'CFIO', + casec.frequency: 010000, + casec.duration: 000000 + casec.grid_label: PC45x21-DC + casec.fields: 'VAR3Dc', 'Root', + :: + casee.template: '%y4.nc4', + casee.format: 'CFIO', + casee.frequency: 010000, + casee.duration: 000000 + casee.grid_label: PC45x21-DC + casee.fields: 'VAR3De', 'Root', + :: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case26/HISTORY2.rc b/Tests/ExtData_Testing_Framework/test_cases/case26/HISTORY2.rc new file mode 100644 index 000000000000..2895432e995a --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case26/HISTORY2.rc @@ -0,0 +1,5 @@ +GRID_LABELS: +:: + +COLLECTIONS: +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case26/README b/Tests/ExtData_Testing_Framework/test_cases/case26/README new file mode 100644 index 000000000000..cec787fe0882 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case26/README @@ -0,0 +1 @@ +Read edge + center diff --git a/Tests/ExtData_Testing_Framework/test_cases/case26/extdata.yaml b/Tests/ExtData_Testing_Framework/test_cases/case26/extdata.yaml new file mode 100644 index 000000000000..75ab030466dd --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case26/extdata.yaml @@ -0,0 +1,6 @@ +Collections: + fstreamc: {template: casec.%y4.nc4, valid_range: "2004-01-01/2005-01-01" } + fstreame: {template: casee.%y4.nc4, valid_range: "2004-01-01/2005-01-01" } +Exports: + VAR3Dc: {variable: VAR3Dc, collection: fstreamc} + VAR3De: {variable: VAR3De, collection: fstreame} diff --git a/Tests/ExtData_Testing_Framework/test_cases/case3/AGCM1.rc b/Tests/ExtData_Testing_Framework/test_cases/case3/AGCM1.rc new file mode 100644 index 000000000000..302766bebfab --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case3/AGCM1.rc @@ -0,0 +1,22 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC90x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: GenerateExports + +EXPORT_STATE:: +VAR2D , time , days , xy , c +:: + +FILL_DEF:: +VAR2D time +:: + +REF_TIME: 20040701 000000 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case3/AGCM2.rc b/Tests/ExtData_Testing_Framework/test_cases/case3/AGCM2.rc new file mode 100644 index 000000000000..63df38ae71a5 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case3/AGCM2.rc @@ -0,0 +1,27 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC900x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: CompareImports + +IMPORT_STATE:: +VAR2D , time , days , xy , c +:: + +EXPORT_STATE:: +VAR2D , time , days , xy , c +:: + +FILL_DEF:: +VAR2D time +:: + +CLIM_YEAR: 2004 +REF_TIME: 20040701 000000 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case3/CAP.rc b/Tests/ExtData_Testing_Framework/test_cases/case3/CAP.rc new file mode 100644 index 000000000000..680d0ffa9c5b --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case3/CAP.rc @@ -0,0 +1,4 @@ +CASES:: +CAP1.rc +CAP2.rc +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case3/CAP1.rc b/Tests/ExtData_Testing_Framework/test_cases/case3/CAP1.rc new file mode 100644 index 000000000000..a75a8c48bd1e --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case3/CAP1.rc @@ -0,0 +1,24 @@ +ROOT_NAME: Root +ROOT_CF: AGCM1.rc +HIST_CF: HISTORY1.rc + +BEG_DATE: 20040101 210000 + +JOB_SGMT: 00001200 000000 +HEARTBEAT_DT: 3600 + +RUN_TIMES:: +20040115 210000 +20040215 210000 +20040315 210000 +20040415 210000 +20040515 210000 +20040615 210000 +20040715 210000 +20040815 210000 +20040915 210000 +20041015 210000 +20041115 210000 +20041215 210000 +:: + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case3/CAP2.rc b/Tests/ExtData_Testing_Framework/test_cases/case3/CAP2.rc new file mode 100644 index 000000000000..4dc521f63044 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case3/CAP2.rc @@ -0,0 +1,15 @@ +ROOT_NAME: Root +ROOT_CF: AGCM2.rc +HIST_CF: HISTORY2.rc + +BEG_DATE: 20040101 210000 + +JOB_SGMT: 00001200 000000 +HEARTBEAT_DT: 3600 + +#RUN_EXTDATA: .false. +RUN_TIMES:: +20071125 210000 +20071126 210000 +:: + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case3/ExtData.rc b/Tests/ExtData_Testing_Framework/test_cases/case3/ExtData.rc new file mode 100644 index 000000000000..523802edf5f1 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case3/ExtData.rc @@ -0,0 +1,12 @@ +#CASE_SENSITIVE_VARIABLE_NAMES: .false. +Ext_AllowExtrap: .false. +Prefetch: .true. +#DEBUG_LEVEL: 20 + +PrimaryExports%% +VAR2D NA 2004 N 0 none none VAR2D case1.%y4%m2.nc4 +%% + + +DerivedExports%% +%% diff --git a/Tests/ExtData_Testing_Framework/test_cases/case3/HISTORY1.rc b/Tests/ExtData_Testing_Framework/test_cases/case3/HISTORY1.rc new file mode 100644 index 000000000000..0b54db8e8f25 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case3/HISTORY1.rc @@ -0,0 +1,11 @@ +GRID_LABELS: +:: + +COLLECTIONS: case1 +:: + + case1.template: '%y4%m2.nc4', + case1.format: 'CFIO', + case1.frequency: 010000, + case1.fields: 'VAR2D', 'Root', + :: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case3/HISTORY2.rc b/Tests/ExtData_Testing_Framework/test_cases/case3/HISTORY2.rc new file mode 100644 index 000000000000..2895432e995a --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case3/HISTORY2.rc @@ -0,0 +1,5 @@ +GRID_LABELS: +:: + +COLLECTIONS: +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case3/README b/Tests/ExtData_Testing_Framework/test_cases/case3/README new file mode 100644 index 000000000000..f47e12688ffc --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case3/README @@ -0,0 +1 @@ +Case 3, monthly files for 2004 file with 1 updates, climatology for 2007 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case3/extdata.yaml b/Tests/ExtData_Testing_Framework/test_cases/case3/extdata.yaml new file mode 100644 index 000000000000..1f70929226a8 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case3/extdata.yaml @@ -0,0 +1,6 @@ +Samplings: + sample_clim: {extrapolation: clim} +Collections: + fstream1: {template: "case1.%y4%m2.nc4", valid_range: "2004-01-01/2004-12-31" } +Exports: + VAR2D: {variable: VAR2D, collection: fstream1, source_time: "2004-01-01/2004-12-31", sample: sample_clim} diff --git a/Tests/ExtData_Testing_Framework/test_cases/case4/AGCM1.rc b/Tests/ExtData_Testing_Framework/test_cases/case4/AGCM1.rc new file mode 100644 index 000000000000..93585c3bfdd2 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case4/AGCM1.rc @@ -0,0 +1,22 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC90x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: GenerateExports + +EXPORT_STATE:: +VAR2D , time , days , xy , c +:: + +FILL_DEF:: +VAR2D time +:: + +REF_TIME: 20040415 210000 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case4/AGCM2.rc b/Tests/ExtData_Testing_Framework/test_cases/case4/AGCM2.rc new file mode 100644 index 000000000000..2271a4a04fe9 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case4/AGCM2.rc @@ -0,0 +1,26 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC90x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: CompareImports + +IMPORT_STATE:: +VAR2D , time , days , xy , c +:: + +EXPORT_STATE:: +VAR2D , time , days , xy , c +:: + +FILL_DEF:: +VAR2D time +:: + +REF_TIME: 20040416 090000 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case4/CAP.rc b/Tests/ExtData_Testing_Framework/test_cases/case4/CAP.rc new file mode 100644 index 000000000000..680d0ffa9c5b --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case4/CAP.rc @@ -0,0 +1,4 @@ +CASES:: +CAP1.rc +CAP2.rc +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case4/CAP1.rc b/Tests/ExtData_Testing_Framework/test_cases/case4/CAP1.rc new file mode 100644 index 000000000000..8bc0e5df5306 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case4/CAP1.rc @@ -0,0 +1,16 @@ +ROOT_NAME: Root +ROOT_CF: AGCM1.rc +HIST_CF: HISTORY1.rc + +BEG_DATE: 20040101 210000 + +JOB_SGMT: 00001200 000000 +HEARTBEAT_DT: 3600 + +RUN_TIMES:: +20040415 210000 +20040416 210000 +20040417 210000 +20040418 210000 +:: + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case4/CAP2.rc b/Tests/ExtData_Testing_Framework/test_cases/case4/CAP2.rc new file mode 100644 index 000000000000..0209bfea0d8b --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case4/CAP2.rc @@ -0,0 +1,13 @@ +ROOT_NAME: Root +ROOT_CF: AGCM2.rc +HIST_CF: HISTORY2.rc + +BEG_DATE: 20040415 210000 + +JOB_SGMT: 00000001 000000 +HEARTBEAT_DT: 3600 + +RUN_TIMES:: +20040416 090000 +:: + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case4/ExtData.rc b/Tests/ExtData_Testing_Framework/test_cases/case4/ExtData.rc new file mode 100644 index 000000000000..782b2e1947b9 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case4/ExtData.rc @@ -0,0 +1,12 @@ +#CASE_SENSITIVE_VARIABLE_NAMES: .false. +Ext_AllowExtrap: .false. +Prefetch: .true. +#DEBUG_LEVEL: 20 + +PrimaryExports%% +VAR2D NA N N F0 none none VAR2D case1.%y4%m2%d2.nc4 +%% + + +DerivedExports%% +%% diff --git a/Tests/ExtData_Testing_Framework/test_cases/case4/HISTORY1.rc b/Tests/ExtData_Testing_Framework/test_cases/case4/HISTORY1.rc new file mode 100644 index 000000000000..295240a18188 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case4/HISTORY1.rc @@ -0,0 +1,11 @@ +GRID_LABELS: +:: + +COLLECTIONS: case1 +:: + + case1.template: '%y4%m2%d2.nc4', + case1.format: 'CFIO', + case1.frequency: 010000, + case1.fields: 'VAR2D', 'Root', + :: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case4/HISTORY2.rc b/Tests/ExtData_Testing_Framework/test_cases/case4/HISTORY2.rc new file mode 100644 index 000000000000..2895432e995a --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case4/HISTORY2.rc @@ -0,0 +1,5 @@ +GRID_LABELS: +:: + +COLLECTIONS: +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case4/README b/Tests/ExtData_Testing_Framework/test_cases/case4/README new file mode 100644 index 000000000000..04a0216fbe17 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case4/README @@ -0,0 +1 @@ +Case 4, simple everytime update with daily files and last value fixed diff --git a/Tests/ExtData_Testing_Framework/test_cases/case4/extdata.yaml b/Tests/ExtData_Testing_Framework/test_cases/case4/extdata.yaml new file mode 100644 index 000000000000..191e5e0e8ca5 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case4/extdata.yaml @@ -0,0 +1,6 @@ +Samplings: + sample_fixed: {time_interpolation: false} +Collections: + fstream1: {template: case1.%y4%m2%d2.nc4} +Exports: + VAR2D: {variable: VAR2D, collection: fstream1, sample: sample_fixed} diff --git a/Tests/ExtData_Testing_Framework/test_cases/case5/AGCM1.rc b/Tests/ExtData_Testing_Framework/test_cases/case5/AGCM1.rc new file mode 100644 index 000000000000..93585c3bfdd2 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case5/AGCM1.rc @@ -0,0 +1,22 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC90x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: GenerateExports + +EXPORT_STATE:: +VAR2D , time , days , xy , c +:: + +FILL_DEF:: +VAR2D time +:: + +REF_TIME: 20040415 210000 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case5/AGCM2.rc b/Tests/ExtData_Testing_Framework/test_cases/case5/AGCM2.rc new file mode 100644 index 000000000000..6241b66ae49c --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case5/AGCM2.rc @@ -0,0 +1,26 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC90x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: CompareImports + +IMPORT_STATE:: +VAR2D , time , days , xy , c +:: + +EXPORT_STATE:: +VAR2D , time , days , xy , c +:: + +FILL_DEF:: +VAR2D time +:: + +REF_TIME: 20040415 210000 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case5/CAP.rc b/Tests/ExtData_Testing_Framework/test_cases/case5/CAP.rc new file mode 100644 index 000000000000..680d0ffa9c5b --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case5/CAP.rc @@ -0,0 +1,4 @@ +CASES:: +CAP1.rc +CAP2.rc +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case5/CAP1.rc b/Tests/ExtData_Testing_Framework/test_cases/case5/CAP1.rc new file mode 100644 index 000000000000..8bc0e5df5306 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case5/CAP1.rc @@ -0,0 +1,16 @@ +ROOT_NAME: Root +ROOT_CF: AGCM1.rc +HIST_CF: HISTORY1.rc + +BEG_DATE: 20040101 210000 + +JOB_SGMT: 00001200 000000 +HEARTBEAT_DT: 3600 + +RUN_TIMES:: +20040415 210000 +20040416 210000 +20040417 210000 +20040418 210000 +:: + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case5/CAP2.rc b/Tests/ExtData_Testing_Framework/test_cases/case5/CAP2.rc new file mode 100644 index 000000000000..0209bfea0d8b --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case5/CAP2.rc @@ -0,0 +1,13 @@ +ROOT_NAME: Root +ROOT_CF: AGCM2.rc +HIST_CF: HISTORY2.rc + +BEG_DATE: 20040415 210000 + +JOB_SGMT: 00000001 000000 +HEARTBEAT_DT: 3600 + +RUN_TIMES:: +20040416 090000 +:: + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case5/ExtData.rc b/Tests/ExtData_Testing_Framework/test_cases/case5/ExtData.rc new file mode 100644 index 000000000000..1c81c28b2b97 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case5/ExtData.rc @@ -0,0 +1,12 @@ +#CASE_SENSITIVE_VARIABLE_NAMES: .false. +Ext_AllowExtrap: .false. +Prefetch: .true. +#DEBUG_LEVEL: 20 + +PrimaryExports%% +VAR2D NA N N 0 none none VAR2D case1.%y4%m2%d2.nc4 +%% + + +DerivedExports%% +%% diff --git a/Tests/ExtData_Testing_Framework/test_cases/case5/HISTORY1.rc b/Tests/ExtData_Testing_Framework/test_cases/case5/HISTORY1.rc new file mode 100644 index 000000000000..295240a18188 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case5/HISTORY1.rc @@ -0,0 +1,11 @@ +GRID_LABELS: +:: + +COLLECTIONS: case1 +:: + + case1.template: '%y4%m2%d2.nc4', + case1.format: 'CFIO', + case1.frequency: 010000, + case1.fields: 'VAR2D', 'Root', + :: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case5/HISTORY2.rc b/Tests/ExtData_Testing_Framework/test_cases/case5/HISTORY2.rc new file mode 100644 index 000000000000..2895432e995a --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case5/HISTORY2.rc @@ -0,0 +1,5 @@ +GRID_LABELS: +:: + +COLLECTIONS: +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case5/README b/Tests/ExtData_Testing_Framework/test_cases/case5/README new file mode 100644 index 000000000000..728af50ea7e9 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case5/README @@ -0,0 +1 @@ +Case 5, simple everytime update with daily files and time interpolation diff --git a/Tests/ExtData_Testing_Framework/test_cases/case5/extdata.yaml b/Tests/ExtData_Testing_Framework/test_cases/case5/extdata.yaml new file mode 100644 index 000000000000..a126e4e0ebf9 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case5/extdata.yaml @@ -0,0 +1,4 @@ +Collections: + fstream1: {template: case1.%y4%m2%d2.nc4} +Exports: + VAR2D: {variable: VAR2D, collection: fstream1} diff --git a/Tests/ExtData_Testing_Framework/test_cases/case6/AGCM1.rc b/Tests/ExtData_Testing_Framework/test_cases/case6/AGCM1.rc new file mode 100644 index 000000000000..302766bebfab --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case6/AGCM1.rc @@ -0,0 +1,22 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC90x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: GenerateExports + +EXPORT_STATE:: +VAR2D , time , days , xy , c +:: + +FILL_DEF:: +VAR2D time +:: + +REF_TIME: 20040701 000000 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case6/AGCM2.rc b/Tests/ExtData_Testing_Framework/test_cases/case6/AGCM2.rc new file mode 100644 index 000000000000..7c517e6969e4 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case6/AGCM2.rc @@ -0,0 +1,24 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC900x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: CompareImports + +IMPORT_STATE:: +VAR2D , time , days , xy , c +:: + +EXPORT_STATE:: +VAR2D , time , days , xy , c +:: + +FILL_DEF:: +VAR2D 183+0.5*(-182.0-183.0) +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case6/CAP.rc b/Tests/ExtData_Testing_Framework/test_cases/case6/CAP.rc new file mode 100644 index 000000000000..680d0ffa9c5b --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case6/CAP.rc @@ -0,0 +1,4 @@ +CASES:: +CAP1.rc +CAP2.rc +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case6/CAP1.rc b/Tests/ExtData_Testing_Framework/test_cases/case6/CAP1.rc new file mode 100644 index 000000000000..b9c2d90f9891 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case6/CAP1.rc @@ -0,0 +1,10 @@ +ROOT_NAME: Root +ROOT_CF: AGCM1.rc +HIST_CF: HISTORY1.rc + +BEG_DATE: 20031231 000000 + +JOB_SGMT: 00001202 000000 +HEARTBEAT_DT: 3600 + + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case6/CAP2.rc b/Tests/ExtData_Testing_Framework/test_cases/case6/CAP2.rc new file mode 100644 index 000000000000..845a49be478b --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case6/CAP2.rc @@ -0,0 +1,14 @@ +ROOT_NAME: Root +ROOT_CF: AGCM2.rc +HIST_CF: HISTORY2.rc + +BEG_DATE: 20040101 210000 + +JOB_SGMT: 00001200 000000 +HEARTBEAT_DT: 3600 + +#RUN_EXTDATA: .false. +RUN_TIMES:: +20061231 120000 +:: + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case6/ExtData.rc b/Tests/ExtData_Testing_Framework/test_cases/case6/ExtData.rc new file mode 100644 index 000000000000..13d1376b6cf3 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case6/ExtData.rc @@ -0,0 +1,12 @@ +#CASE_SENSITIVE_VARIABLE_NAMES: .false. +Ext_AllowExtrap: .false. +Prefetch: .true. +DEBUG_LEVEL: 20 + +PrimaryExports%% +VAR2D NA 2004 N 0 none none VAR2D case1.%y4%m2%d2.nc4 +%% + + +DerivedExports%% +%% diff --git a/Tests/ExtData_Testing_Framework/test_cases/case6/HISTORY1.rc b/Tests/ExtData_Testing_Framework/test_cases/case6/HISTORY1.rc new file mode 100644 index 000000000000..7f1045a27232 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case6/HISTORY1.rc @@ -0,0 +1,12 @@ +GRID_LABELS: +:: + +COLLECTIONS: case1 +:: + + case1.template: '%y4%m2%d2.nc4', + case1.format: 'CFIO', + case1.frequency: 240000, + case1.ref_time: 000000, + case1.fields: 'VAR2D', 'Root', + :: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case6/HISTORY2.rc b/Tests/ExtData_Testing_Framework/test_cases/case6/HISTORY2.rc new file mode 100644 index 000000000000..2895432e995a --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case6/HISTORY2.rc @@ -0,0 +1,5 @@ +GRID_LABELS: +:: + +COLLECTIONS: +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case6/README b/Tests/ExtData_Testing_Framework/test_cases/case6/README new file mode 100644 index 000000000000..585f98aab2ca --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case6/README @@ -0,0 +1 @@ +Case 6, daily files for 0z for a year, fill a time at 12z on the 31st of december 2006 as a climatology diff --git a/Tests/ExtData_Testing_Framework/test_cases/case6/extdata.yaml b/Tests/ExtData_Testing_Framework/test_cases/case6/extdata.yaml new file mode 100644 index 000000000000..67a7a29a9b0d --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case6/extdata.yaml @@ -0,0 +1,6 @@ +Samplings: + sample_clim: {extrapolation: clim, source_time: "2004-01-01/2004-12-31"} +Collections: + fstream1: {template: "case1.%y4%m2%d2.nc4", valid_range: "2004-01-01/2004-12-31" } +Exports: + VAR2D: {variable: VAR2D, collection: fstream1, sample: sample_clim} diff --git a/Tests/ExtData_Testing_Framework/test_cases/case7/AGCM1.rc b/Tests/ExtData_Testing_Framework/test_cases/case7/AGCM1.rc new file mode 100644 index 000000000000..1a52adfe187d --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case7/AGCM1.rc @@ -0,0 +1,22 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC900x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: GenerateExports + +EXPORT_STATE:: +VAR2D , time , days , xy , c +:: + +FILL_DEF:: +VAR2D time +:: + +REF_TIME: 20040701 000000 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case7/AGCM2.rc b/Tests/ExtData_Testing_Framework/test_cases/case7/AGCM2.rc new file mode 100644 index 000000000000..7bc84048f88f --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case7/AGCM2.rc @@ -0,0 +1,25 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC90x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: CompareImports + +IMPORT_STATE:: +VAR2D , time , days , xy , c +:: + +EXPORT_STATE:: +VAR2D , time , days , xy , c +:: + +FILL_DEF:: +VAR2D 167.0+(2.0/31.0)*(-168.0-167.0) +:: + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case7/CAP.rc b/Tests/ExtData_Testing_Framework/test_cases/case7/CAP.rc new file mode 100644 index 000000000000..680d0ffa9c5b --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case7/CAP.rc @@ -0,0 +1,4 @@ +CASES:: +CAP1.rc +CAP2.rc +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case7/CAP1.rc b/Tests/ExtData_Testing_Framework/test_cases/case7/CAP1.rc new file mode 100644 index 000000000000..77bd783ddb2e --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case7/CAP1.rc @@ -0,0 +1,25 @@ +ROOT_NAME: Root +ROOT_CF: AGCM1.rc +HIST_CF: HISTORY1.rc + +BEG_DATE: 20040101 210000 + +JOB_SGMT: 00001200 000000 +HEARTBEAT_DT: 3600 + +#RUN_EXTDATA: .false. +RUN_TIMES:: +20040115 000000 +20040215 000000 +20040315 000000 +20040415 000000 +20040515 000000 +20040615 000000 +20040715 000000 +20040815 000000 +20040915 000000 +20041015 000000 +20041115 000000 +20041215 000000 +:: + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case7/CAP2.rc b/Tests/ExtData_Testing_Framework/test_cases/case7/CAP2.rc new file mode 100644 index 000000000000..af401118d4fa --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case7/CAP2.rc @@ -0,0 +1,14 @@ +ROOT_NAME: Root +ROOT_CF: AGCM2.rc +HIST_CF: HISTORY2.rc + +BEG_DATE: 20040101 210000 + +JOB_SGMT: 00001200 000000 +HEARTBEAT_DT: 3600 + +#RUN_EXTDATA: .false. +RUN_TIMES:: +20061217 000000 +:: + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case7/ExtData.rc b/Tests/ExtData_Testing_Framework/test_cases/case7/ExtData.rc new file mode 100644 index 000000000000..ca41e8d3a0ec --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case7/ExtData.rc @@ -0,0 +1,11 @@ +#CASE_SENSITIVE_VARIABLE_NAMES: .false. +Ext_AllowExtrap: .false. +Prefetch: .true. + +PrimaryExports%% +VAR2D NA Y N 0 none none VAR2D case1.2004.nc4 +%% + + +DerivedExports%% +%% diff --git a/Tests/ExtData_Testing_Framework/test_cases/case7/HISTORY1.rc b/Tests/ExtData_Testing_Framework/test_cases/case7/HISTORY1.rc new file mode 100644 index 000000000000..a2ad110c3fde --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case7/HISTORY1.rc @@ -0,0 +1,12 @@ +GRID_LABELS: +:: + +COLLECTIONS: case1 +:: + + case1.template: '%y4.nc4', + case1.format: 'CFIO', + case1.frequency: 010000, + case1.duration: 000000 + case1.fields: 'VAR2D', 'Root', + :: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case7/HISTORY2.rc b/Tests/ExtData_Testing_Framework/test_cases/case7/HISTORY2.rc new file mode 100644 index 000000000000..2895432e995a --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case7/HISTORY2.rc @@ -0,0 +1,5 @@ +GRID_LABELS: +:: + +COLLECTIONS: +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case7/README b/Tests/ExtData_Testing_Framework/test_cases/case7/README new file mode 100644 index 000000000000..fdfb854902d9 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case7/README @@ -0,0 +1 @@ +Case, 12-month/12 time 2004 file with an update that will wrap around the year diff --git a/Tests/ExtData_Testing_Framework/test_cases/case7/extdata.yaml b/Tests/ExtData_Testing_Framework/test_cases/case7/extdata.yaml new file mode 100644 index 000000000000..23fba59ae3ba --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case7/extdata.yaml @@ -0,0 +1,6 @@ +Samplings: + sample_clim: {source_time: "2004-01-01/2004-12-31", extrapolation: clim} +Collections: + fstream1: {template: "case1.2004.nc4", valid_range: "2004-01-01/2004-12-31" } +Exports: + VAR2D: {variable: VAR2D, collection: fstream1, sample: sample_clim} diff --git a/Tests/ExtData_Testing_Framework/test_cases/case8/AGCM1.rc b/Tests/ExtData_Testing_Framework/test_cases/case8/AGCM1.rc new file mode 100644 index 000000000000..93585c3bfdd2 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case8/AGCM1.rc @@ -0,0 +1,22 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC90x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: GenerateExports + +EXPORT_STATE:: +VAR2D , time , days , xy , c +:: + +FILL_DEF:: +VAR2D time +:: + +REF_TIME: 20040415 210000 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case8/AGCM2.rc b/Tests/ExtData_Testing_Framework/test_cases/case8/AGCM2.rc new file mode 100644 index 000000000000..6241b66ae49c --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case8/AGCM2.rc @@ -0,0 +1,26 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC90x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: CompareImports + +IMPORT_STATE:: +VAR2D , time , days , xy , c +:: + +EXPORT_STATE:: +VAR2D , time , days , xy , c +:: + +FILL_DEF:: +VAR2D time +:: + +REF_TIME: 20040415 210000 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case8/CAP.rc b/Tests/ExtData_Testing_Framework/test_cases/case8/CAP.rc new file mode 100644 index 000000000000..680d0ffa9c5b --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case8/CAP.rc @@ -0,0 +1,4 @@ +CASES:: +CAP1.rc +CAP2.rc +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case8/CAP1.rc b/Tests/ExtData_Testing_Framework/test_cases/case8/CAP1.rc new file mode 100644 index 000000000000..72cccef1f8b8 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case8/CAP1.rc @@ -0,0 +1,9 @@ +ROOT_NAME: Root +ROOT_CF: AGCM1.rc +HIST_CF: HISTORY1.rc + +BEG_DATE: 20040201 210000 + +JOB_SGMT: 00000002 000000 +HEARTBEAT_DT: 1800 + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case8/CAP2.rc b/Tests/ExtData_Testing_Framework/test_cases/case8/CAP2.rc new file mode 100644 index 000000000000..e820872c1e5b --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case8/CAP2.rc @@ -0,0 +1,14 @@ +ROOT_NAME: Root +ROOT_CF: AGCM2.rc +HIST_CF: HISTORY2.rc + +BEG_DATE: 20040201 213000 + +JOB_SGMT: 00000002 000000 +HEARTBEAT_DT: 1800 + +RUN_TIMES:: +20040202 150000 +20040202 230000 +:: + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case8/ExtData.rc b/Tests/ExtData_Testing_Framework/test_cases/case8/ExtData.rc new file mode 100644 index 000000000000..706353827d51 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case8/ExtData.rc @@ -0,0 +1,12 @@ +#CASE_SENSITIVE_VARIABLE_NAMES: .false. +Ext_AllowExtrap: .false. +Prefetch: .true. +#DEBUG_LEVEL: 20 + +PrimaryExports%% +VAR2D NA N N 0 none none VAR2D case1.%y4%m2%d2_%h2%n2.nc4 2004-02-01T21:30:00P0000-00-00T03:00:00 +%% + + +DerivedExports%% +%% diff --git a/Tests/ExtData_Testing_Framework/test_cases/case8/HISTORY1.rc b/Tests/ExtData_Testing_Framework/test_cases/case8/HISTORY1.rc new file mode 100644 index 000000000000..ce09c7e5290b --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case8/HISTORY1.rc @@ -0,0 +1,12 @@ +GRID_LABELS: +:: + +COLLECTIONS: case1 +:: + + case1.template: '%y4%m2%d2_%h2%n2.nc4', + case1.format: 'CFIO', + case1.frequency: 030000, + case1.ref_time: 213000 + case1.fields: 'VAR2D', 'Root', + :: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case8/HISTORY2.rc b/Tests/ExtData_Testing_Framework/test_cases/case8/HISTORY2.rc new file mode 100644 index 000000000000..2895432e995a --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case8/HISTORY2.rc @@ -0,0 +1,5 @@ +GRID_LABELS: +:: + +COLLECTIONS: +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case8/README b/Tests/ExtData_Testing_Framework/test_cases/case8/README new file mode 100644 index 000000000000..ef8f3c8089fb --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case8/README @@ -0,0 +1 @@ +Case 8, simple everytime update with a new file every 3 hours relative to 003000z diff --git a/Tests/ExtData_Testing_Framework/test_cases/case8/extdata.yaml b/Tests/ExtData_Testing_Framework/test_cases/case8/extdata.yaml new file mode 100644 index 000000000000..f7fbd8500570 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case8/extdata.yaml @@ -0,0 +1,4 @@ +Collections: + fstream1: {template: case1.%y4%m2%d2_%h2%n2.nc4, ref_time: "2004-02-01T21:30:00", freq: PT3H} +Exports: + VAR2D: {variable: VAR2D, collection: fstream1} diff --git a/Tests/ExtData_Testing_Framework/test_cases/case9/AGCM1.rc b/Tests/ExtData_Testing_Framework/test_cases/case9/AGCM1.rc new file mode 100644 index 000000000000..e7caf16aa2d0 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case9/AGCM1.rc @@ -0,0 +1,22 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC90x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: GenerateExports + +EXPORT_STATE:: +VAR2D , time , days , xy , c +:: + +FILL_DEF:: +VAR2D 17.0 +:: + +REF_TIME: 20040701 000000 diff --git a/Tests/ExtData_Testing_Framework/test_cases/case9/AGCM2.rc b/Tests/ExtData_Testing_Framework/test_cases/case9/AGCM2.rc new file mode 100644 index 000000000000..8560c27aecc7 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case9/AGCM2.rc @@ -0,0 +1,25 @@ +NX: 1 +NY: 1 + +Root.GRID_TYPE: LatLon +Root.GRIDNAME: DC90x45-PC +Root.LM: 3 +Root.IM_WORLD: 90 +Root.JM_WORLD: 45 +Root.POLE: 'PC' +Root.DATELINE: 'DC' + +RUN_MODE: CompareImports + +IMPORT_STATE:: +VAR2D , time , days , xy , c +:: + +EXPORT_STATE:: +VAR2D , time , days , xy , c +:: + +FILL_DEF:: +VAR2D 17.0 +:: + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case9/CAP.rc b/Tests/ExtData_Testing_Framework/test_cases/case9/CAP.rc new file mode 100644 index 000000000000..680d0ffa9c5b --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case9/CAP.rc @@ -0,0 +1,4 @@ +CASES:: +CAP1.rc +CAP2.rc +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case9/CAP1.rc b/Tests/ExtData_Testing_Framework/test_cases/case9/CAP1.rc new file mode 100644 index 000000000000..db6a1b1fa205 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case9/CAP1.rc @@ -0,0 +1,14 @@ +ROOT_NAME: Root +ROOT_CF: AGCM1.rc +HIST_CF: HISTORY1.rc + +BEG_DATE: 20040101 210000 + +JOB_SGMT: 00001200 000000 +HEARTBEAT_DT: 3600 + +#RUN_EXTDATA: .false. +RUN_TIMES:: +20040701 000000 +:: + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case9/CAP2.rc b/Tests/ExtData_Testing_Framework/test_cases/case9/CAP2.rc new file mode 100644 index 000000000000..31ad1a874601 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case9/CAP2.rc @@ -0,0 +1,17 @@ +ROOT_NAME: Root +ROOT_CF: AGCM2.rc +HIST_CF: HISTORY2.rc + +BEG_DATE: 20000101 210000 + +JOB_SGMT: 00009600 000000 +HEARTBEAT_DT: 3600 + +#RUN_EXTDATA: .false. +RUN_TIMES:: +20020703 000000 +:: +#RUN_TIMES:: +#20041125 210000 +#:: + diff --git a/Tests/ExtData_Testing_Framework/test_cases/case9/ExtData.rc b/Tests/ExtData_Testing_Framework/test_cases/case9/ExtData.rc new file mode 100644 index 000000000000..b5f2a303a22e --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case9/ExtData.rc @@ -0,0 +1,12 @@ +#CASE_SENSITIVE_VARIABLE_NAMES: .false. +Ext_AllowExtrap: .false. +Prefetch: .true. +#DEBUG_LEVEL: 20 + +PrimaryExports%% +VAR2D NA N N - none none VAR2D case1.nc4 +%% + + +DerivedExports%% +%% diff --git a/Tests/ExtData_Testing_Framework/test_cases/case9/HISTORY1.rc b/Tests/ExtData_Testing_Framework/test_cases/case9/HISTORY1.rc new file mode 100644 index 000000000000..490301aee5ea --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case9/HISTORY1.rc @@ -0,0 +1,12 @@ +GRID_LABELS: +:: + +COLLECTIONS: case1 +:: + + case1.template: 'nc4', + case1.format: 'CFIO', + case1.frequency: 010000, + case1.duration: 000000 + case1.fields: 'VAR2D', 'Root', + :: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case9/HISTORY2.rc b/Tests/ExtData_Testing_Framework/test_cases/case9/HISTORY2.rc new file mode 100644 index 000000000000..2895432e995a --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case9/HISTORY2.rc @@ -0,0 +1,5 @@ +GRID_LABELS: +:: + +COLLECTIONS: +:: diff --git a/Tests/ExtData_Testing_Framework/test_cases/case9/README b/Tests/ExtData_Testing_Framework/test_cases/case9/README new file mode 100644 index 000000000000..ffb8734bc0e7 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case9/README @@ -0,0 +1 @@ +Case 9 Single time file, persisted at all times diff --git a/Tests/ExtData_Testing_Framework/test_cases/case9/extdata.yaml b/Tests/ExtData_Testing_Framework/test_cases/case9/extdata.yaml new file mode 100644 index 000000000000..79f977377386 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/case9/extdata.yaml @@ -0,0 +1,6 @@ +Samplings: + sample_closest: {extrapolation: persist_closest} +Collections: + fstream1: {template: case1.nc4} +Exports: + VAR2D: {variable: VAR2D, collection: fstream1, sample: sample_closest} diff --git a/Tests/ExtData_Testing_Framework/test_cases/cases.txt b/Tests/ExtData_Testing_Framework/test_cases/cases.txt new file mode 100644 index 000000000000..9753d563eb9a --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/cases.txt @@ -0,0 +1,25 @@ +case1 +case2 +case3 +case4 +case5 +case6 +case7 +case8 +case9 +case10 +case11 +case12 +case13 +case14 +case15 +case16 +case18 +case19 +case20 +case21 +case22 +case23 +case24 +case25 +case26 diff --git a/Tests/ExtData_Testing_Framework/test_cases/test_case_descriptions.md b/Tests/ExtData_Testing_Framework/test_cases/test_case_descriptions.md new file mode 100644 index 000000000000..2b8b02b42681 --- /dev/null +++ b/Tests/ExtData_Testing_Framework/test_cases/test_case_descriptions.md @@ -0,0 +1,33 @@ +# Test Case Descriptions + +Note all test cases are in a numbered directory caseX, where a X is an integer and each case is described in the following list where the list number X is for folder caseX + +To run the test cases you can use the provided script and run the command: +path_to_script/run_extdatadriver_cases.py --builddir path_to_geos_install/bin --casedir path_to_cases --cases cases.txt --savelog TRUE + +1. 12-month/12 time 2004 file with 2 updates, non-climatology +2. 12-month/12 time 2004 file with 2 updates, climatology +3. monthly files for 2004 file with 1 updates, climatology for 2007 +4. simple everytime update with daily files and no time interpolation +5. simple everytime update with daily files and time interpolation +6. daily files for 0z for a year, fill a time at 12z on the 31st of december 2006 as a climatology +7. 12-month/12 time 2004 file with an update that will wrap around the year +8. simple everytime update with a new file every 3 hours relative to 003000z +9. Single time file, persisted at all times +10. Interpolation outside of data set (Harvard mode), make a multi year dataset. Define as not a climatology and ask for data after dataset time range +11. Interpolation outside of data set (Harvard mode), make a multi year dataset. Define as not a climatology and ask for data before datset time range +12. Test of case where you want to make a really coarse file in History that can not be decomposed on the default layout in the rc file. Be able to output such a file, then read back in on same grid in ExtData +13. Testing that we can take a climatology for a non-leap year and interpolate to a leap year. 12 files each with the midmonth value for 2007 (non-leap year). Interpolate to 02/29/2008 (leap year) +14. Testing that we can take a climatology for a non-leap year and interpolate to a leap year. Daily files each with 1 value for 2007 (non-leap year). Interpolate to 02/29/2008 (leap year) +15. Testing that we can take a climatology for a non-leap year and interpolate to a non-leap year. Daily files each with 1 value for 2007 (non-leap year). Interpolate to 03/29/2006 (leap year) +16. Testing that we can take a climatology for a leap year and interpolate to a non-leap year. Daily files each with 1 value for 2008 (leap year). Interpolate to 03/29/2006 15z (leap year) +17. Not used +18. Test vector regridding +19. Test set file to /dev/null +20. Make daily files for 2016. Then start on February 29th in 2020 and allow extrapolation outside of dataset a climatology +21. Test derived export to create sum of 2 variables +22. Test multiple datasets where an export uses both with with no extrapolation outside and crosses transition date +23. Test multiple datasets and treat Climatology in the first and a real-time in the 2nd +24. Test reading cubed-sphere input +25. Test reading edge variable +26. Test reading edge + cetner variables diff --git a/base/Base/Base_Base_implementation.F90 b/base/Base/Base_Base_implementation.F90 index e886bf5dae45..d415ca1f00b7 100644 --- a/base/Base/Base_Base_implementation.F90 +++ b/base/Base/Base_Base_implementation.F90 @@ -183,7 +183,7 @@ module subroutine MAPL_FieldAllocCommit(field, dims, location, typekind, & gridToFieldMap=gridToFieldMap, & rc = status) case default - _ASSERT(.false., 'unsupported rank > 1') + _FAIL( 'unsupported rank > 1') end select else @@ -197,7 +197,7 @@ module subroutine MAPL_FieldAllocCommit(field, dims, location, typekind, & gridToFieldMap=gridToFieldMap, & rc = status) case default - _ASSERT(.false., 'unsupported rank > 1') + _FAIL( 'unsupported rank > 1') end select endif @@ -290,7 +290,7 @@ module subroutine MAPL_FieldAllocCommit(field, dims, location, typekind, & totalUWidth=haloWidth(1:griddedDims), & rc = status) case default - _ASSERT(.false., 'only up to 4D are supported') + _FAIL( 'only up to 4D are supported') end select RankCase2d else select case (rank) @@ -325,7 +325,7 @@ module subroutine MAPL_FieldAllocCommit(field, dims, location, typekind, & totalUWidth=haloWidth(1:griddedDims), & rc = status) case default - _ASSERT(.false., 'only up to 4D are supported') + _FAIL( 'only up to 4D are supported') end select end if _VERIFY(STATUS) @@ -444,7 +444,7 @@ module subroutine MAPL_FieldAllocCommit(field, dims, location, typekind, & datacopyFlag = ESMF_DATACOPY_REFERENCE, & rc = status) case default - _ASSERT(.false., 'only 2D and 3D are supported') + _FAIL( 'only 2D and 3D are supported') end select else @@ -474,7 +474,7 @@ module subroutine MAPL_FieldAllocCommit(field, dims, location, typekind, & datacopyFlag = ESMF_DATACOPY_REFERENCE, & rc = status) case default - _ASSERT(.false., 'only 2D and 3D are supported') + _FAIL( 'only 2D and 3D are supported') end select endif @@ -1385,7 +1385,7 @@ module function MAPL_FieldCreateRename(FIELD, NAME, DoCopy, RC) RESULT(F) rc = status) _VERIFY(STATUS) case default - _ASSERT(.false., 'only upto 4D are supported') + _FAIL( 'only upto 4D are supported') end select else if (tk == ESMF_TypeKind_R8) then select case (fieldRank) @@ -1422,10 +1422,10 @@ module function MAPL_FieldCreateRename(FIELD, NAME, DoCopy, RC) RESULT(F) rc = status) _VERIFY(STATUS) case default - _ASSERT(.false., 'only 2D and 3D are supported') + _FAIL( 'only 2D and 3D are supported') end select else - _ASSERT(.false., 'unsupported typekind') + _FAIL( 'unsupported typekind') endif deallocate(gridToFieldMap) @@ -1560,7 +1560,7 @@ module function MAPL_FieldCreateNewgrid(FIELD, GRID, LM, NEWNAME, RC) RESULT(F) DIMS = MAPL_DimsHorzVert end if else - _ASSERT(.false., 'rank > 4 not supported') + _FAIL( 'rank > 4 not supported') end if deallocate(gridToFieldMap) @@ -1660,7 +1660,7 @@ module function MAPL_FieldCreateR4(FIELD, RC) RESULT(F) rc = status) _VERIFY(STATUS) case default - _ASSERT(.false., 'only 2D and 3D are supported') + _FAIL( 'only 2D and 3D are supported') end select deallocate(gridToFieldMap) @@ -1762,7 +1762,7 @@ module subroutine MAPL_FieldCopy(from, to, RC) _VERIFY(STATUS) var_3d = vr8_3d case default - _ASSERT(.false., 'unsupported fieldRank (> 3)') + _FAIL( 'unsupported fieldRank (> 3)') end select _RETURN(ESMF_SUCCESS) @@ -2701,7 +2701,7 @@ module subroutine MAPL_FieldDestroy(Field,RC) deallocate(VR8_3d,stat=status) _VERIFY(STATUS) else - _ASSERT(.false., 'unsupported typekind+rank') + _FAIL( 'unsupported typekind+rank') end if call ESMF_FieldDestroy(Field,rc=status) _VERIFY(STATUS) @@ -3011,10 +3011,8 @@ module subroutine MAPL_GetHorzIJIndex(npts,II,JJ,lon,lat,lonR8,latR8,Grid, rc) integer :: IM_World, JM_World, dims(3) integer :: IM, JM, counts(3) - real(ESMF_KIND_R8), pointer :: lons(:,:) => null() - real(ESMF_KIND_R8), pointer :: lats(:,:) => null() - real(ESMF_KIND_R8), allocatable :: lons_1d(:) - real(ESMF_KIND_R8), allocatable :: lats_1d(:) + real(ESMF_KIND_R8), pointer :: lons(:,:) + real(ESMF_KIND_R8), pointer :: lats(:,:) real(ESMF_KIND_R8), allocatable :: elons(:) real(ESMF_KIND_R8), allocatable :: elats(:) integer :: i,iiloc,jjloc @@ -3082,26 +3080,26 @@ module subroutine MAPL_GetHorzIJIndex(npts,II,JJ,lon,lat,lonR8,latR8,Grid, rc) else if (localSearch) then call ESMF_GridGetCoord(grid,coordDim=1, localDe=0, & - staggerloc=ESMF_STAGGERLOC_CENTER, fArrayPtr = lons, rc=status) - _VERIFY(STATUS) + staggerloc=ESMF_STAGGERLOC_CORNER, fArrayPtr = lons, _RC) call ESMF_GridGetCoord(grid,coordDim=2, localDe=0, & - staggerloc=ESMF_STAGGERLOC_CENTER, fArrayPtr = lats, rc=status) - _VERIFY(STATUS) + staggerloc=ESMF_STAGGERLOC_CORNER, fArrayPtr = lats, _RC) else - _ASSERT(.false.,'if not isCubed, localSearch must be .true.') + _FAIL('if not isCubed, localSearch must be .true.') end if - allocate(lons_1d(im),stat=status) - _VERIFY(STATUS) - allocate(lats_1d(jm),stat=status) - _VERIFY(STATUS) allocate(elons(im+1),stat=status) _VERIFY(STATUS) allocate(elats(jm+1),stat=status) _VERIFY(STATUS) - lons_1d = lons(:,1) - lats_1d = lats(1,:) - call calc_edges_1d(elons,lons_1d,IM) - call calc_edges_1d(elats,lats_1d,JM) + call ESMF_GridGet(grid,coordSys=coordSys,rc=status) + _VERIFY(STATUS) + elons = lons(:,1) + elats = lats(1,:) + if (coordSys==ESMF_COORDSYS_SPH_DEG) then + elons=elons*MAPL_DEGREES_TO_RADIANS_R8 + elats=elats*MAPL_DEGREES_TO_RADIANS_R8 + else if (coordSys==ESMF_COORDSYS_CART) then + _FAIL('Unsupported coordinate system: ESMF_COORDSYS_CART') + end if ! lat-lon grid goes from -180 to 180 shift if we must ! BMA this -180 to 180 might change at some point do i=1,npts @@ -3113,7 +3111,7 @@ module subroutine MAPL_GetHorzIJIndex(npts,II,JJ,lon,lat,lonR8,latR8,Grid, rc) II(i) = IIloc JJ(i) = JJloc end do - deallocate(lons_1d,lats_1d,elons,elats) + deallocate(elons,elats) end if _RETURN(ESMF_SUCCESS) @@ -3167,16 +3165,6 @@ integer function ijsearch(coords,idim,valueIn,periodic) ! fast bisection version endif end function ijsearch - subroutine calc_edges_1d(ecoords,coords,idim) - integer, intent(in) :: idim - real(ESMF_KIND_R8), intent(in) :: coords(idim) - real(ESMF_KIND_R8), intent(out) :: ecoords(idim+1) - ecoords(1) = coords(1) - 0.5 * ( coords(2) - coords(1) ) - ecoords(2:idim) = 0.5 * ( coords(1:idim-1)+coords(2:idim) ) - ecoords(idim+1) = coords(idim) + 0.5 * (coords(idim) - coords(idim-1)) - return - end subroutine calc_edges_1d - end subroutine MAPL_GetHorzIJIndex module subroutine MAPL_GenGridName(im, jm, lon, lat, xyoffset, gridname, geos_style) @@ -3645,7 +3633,7 @@ module subroutine MAPL_FieldSplit(field, fields, aliasName, rc) end do end if else if (tk == ESMF_TYPEKIND_R8) then - _ASSERT(.false., "R8 overload not implemented yet") + _FAIL( "R8 overload not implemented yet") end if deallocate(gridToFieldMap) diff --git a/base/BinIO.F90 b/base/BinIO.F90 index 2f2dd9735abb..5b3aaf769914 100644 --- a/base/BinIO.F90 +++ b/base/BinIO.F90 @@ -453,7 +453,7 @@ subroutine MAPL_StateVarRead(UNIT, STATE, NAME, arrdes, bootstrapable, RC) _VERIFY(STATUS) !ALT else -!ALT _ASSERT(.false.,'failed mapl_statevarread') +!ALT _FAIL('failed mapl_statevarread') end if @@ -739,7 +739,7 @@ subroutine MAPL_FieldRead(UNIT,FIELD, ARRDES, HomePE, ignoreEOF, RC) call MAPL_VarRead(unit, grid, vr8_4d, rc=status) end if else - _ASSERT(.false., "ERROR: unsupported RANK") + _FAIL( "ERROR: unsupported RANK") endif _VERIFY(STATUS) diff --git a/base/CMakeLists.txt b/base/CMakeLists.txt index b7d1e6992576..7e28e574e445 100644 --- a/base/CMakeLists.txt +++ b/base/CMakeLists.txt @@ -19,10 +19,10 @@ set (srcs ESMF_CFIOPtrVectorMod.F90 MAPL_RegridderVector.F90 ESMFL_Mod.F90 MAPL_SatVapor.F90 FileMetadataUtilities.F90 MAPL_GetLatLonCoord.F90 MAPL_SimpleAlarm.F90 - FileMetadataUtilitiesVector.F90 MAPL_GridManager.F90 MAPL_SimpleBundleMod.F90 + FileMetadataUtilitiesVector.F90 MAPL_GridManager.F90 MAPL_SimpleBundleMod.F90 MAPL_AbstractGridFactory.F90 MAPL_GridSpec.F90 MAPL_StringGridFactoryMap.F90 MAPL_GridType.F90 MAPL_StringGridMap.F90 MaplGrid.F90 - MAPL_AbstractRegridder.F90 + MAPL_AbstractRegridder.F90 MAPL_StringRouteHandleMap.F90 MAPL_IdentityRegridder.F90 MAPL_stubs.F90 MAPL_Integer64GridFactoryMap.F90 MAPL_sun_uc.F90 @@ -37,16 +37,16 @@ set (srcs MAPL_ConservativeRegridder.F90 MAPL_MaxMinMod.F90 MAPL_VerticalInterpMod.F90 MAPL_CubedSphereGridFactory.F90 MAPL_MemUtils.F90 MAPL_VerticalMethods.F90 MAPL_DefGridName.F90 Base.F90 MAPL_VotingRegridder.F90 - MAPL_EsmfRegridder.F90 MAPL_NewArthParser.F90 + MAPL_EsmfRegridder.F90 MAPL_NewArthParser.F90 MAPL_ESMFTimeVectorMod.F90 Regrid_Functions_Mod.F90 - MAPL_EtaHybridVerticalCoordinate.F90 - MAPL_NominalOrbitsMod.F90 + MAPL_EtaHybridVerticalCoordinate.F90 + MAPL_NominalOrbitsMod.F90 MAPL_LocStreamFactoryMod.F90 MAPL_LocstreamRegridder.F90 MAPL_ExternalGridFactory.F90 ServerManager.F90 ApplicationSupport.F90 - ESMF_CFIOPtrVectorMod.F90 + ESMF_CFIOPtrVectorMod.F90 CFIOCollection.F90 MAPL_CFIO.F90 - regex_module.F90 StringTemplate.F90 MAPL_SphericalGeometry.F90 + regex_module.F90 StringTemplate.F90 MAPL_SphericalGeometry.F90 regex_F.c c_mapl_locstream_F.c getrss.c memuse.c Base/Base_Base.F90 Base/Base_Base_implementation.F90 @@ -92,7 +92,7 @@ if (EXTENDED_SOURCE) esma_fortran_generator_list (${this} ${EXTENDED_SOURCE}) endif() -# Users guide +# Users guide if (LATEX_FOUND) add_subdirectory (TeX) endif () diff --git a/base/ESMFL_Mod.F90 b/base/ESMFL_Mod.F90 index e3b7de1e38bd..4d0ef998ccec 100644 --- a/base/ESMFL_Mod.F90 +++ b/base/ESMFL_Mod.F90 @@ -3735,7 +3735,7 @@ subroutine Bundle2State (BUN, STA, rc) _VERIFY(STATUS) dst_pr83d = src_pr83d case default - _ASSERT(.false., 'unsupported rank (>= 4)') + _FAIL( 'unsupported rank (>= 4)') end select end if end if @@ -3936,7 +3936,7 @@ SUBROUTINE ESMFL_HALO_R4_2D(GRID, INPUT, RC) if (.not.found) then print *, "Error: need bigger MAX_HALOTYPES value" - _ASSERT(.false., 'no unused slot for halo types') + _FAIL( 'no unused slot for halo types') end if call ESMF_GridGet(GRID, distGrid=distGrid, dimCount=dimCount, RC=STATUS) diff --git a/base/FileIOShared.F90 b/base/FileIOShared.F90 index 4a7adcad26e8..5e6211798dc4 100644 --- a/base/FileIOShared.F90 +++ b/base/FileIOShared.F90 @@ -208,7 +208,7 @@ subroutine alloc_(A,type,im,jm,rc) _ASSERT(present(jm), 'jm not present for 2d') allocate(A%I4_2(IM,JM)) case default - _ASSERT(.false., 'unsupported tkr') + _FAIL( 'unsupported tkr') end select a%allocated=type @@ -254,7 +254,7 @@ subroutine dealloc_(A,RC) nullify(A%i4_2) end if case default - _ASSERT(.false., 'unsupported tkr') + _FAIL( 'unsupported tkr') end select a%allocated=not_allocated end if @@ -367,7 +367,7 @@ subroutine MAPL_TileMaskGet(grid, mask, rc) enddo #ifdef NEW - _ASSERT(.false., 'unsupported code block') !ALT this section is questionable + _FAIL( 'unsupported code block') !ALT this section is questionable do I = 0,nDEs-1 de = I I1 = AL(1,I) diff --git a/base/FileMetadataUtilities.F90 b/base/FileMetadataUtilities.F90 index e08429ee8965..695bffe89e5b 100644 --- a/base/FileMetadataUtilities.F90 +++ b/base/FileMetadataUtilities.F90 @@ -138,7 +138,7 @@ function get_var_attr_real32(this,var_name,attr_name,rc) result(attr_real32) tmpd = attr_val attr_real32 = REAL(tmpd(1)) class default - _ASSERT(.false.,'unsupported subclass for units of attribute named '//attr_name//' in '//var_name//' in '//fname) + _FAIL('unsupported subclass (not real32) for units of attribute named '//attr_name//' in '//var_name//' in '//fname) end select _RETURN(_SUCCESS) @@ -169,7 +169,7 @@ function get_var_attr_real64(this,var_name,attr_name,rc) result(attr_real64) tmp = attr_val attr_real64 = tmp(1) class default - _ASSERT(.false.,'unsupported subclass for units of attribute named '//attr_name//' in '//var_name//' in '//fname) + _FAIL('unsupported subclass (not real64) for units of attribute named '//attr_name//' in '//var_name//' in '//fname) end select _RETURN(_SUCCESS) @@ -200,7 +200,7 @@ function get_var_attr_int32(this,var_name,attr_name,rc) result(attr_int32) tmp = attr_val attr_int32 = tmp(1) class default - _ASSERT(.false.,'unsupported subclass for units of attribute named '//attr_name//' in '//var_name//' in '//fname) + _FAIL('unsupported subclass (not int32) for units of attribute named '//attr_name//' in '//var_name//' in '//fname) end select _RETURN(_SUCCESS) @@ -231,7 +231,7 @@ function get_var_attr_int64(this,var_name,attr_name,rc) result(attr_int64) tmp = attr_val attr_int64 = tmp(1) class default - _ASSERT(.false.,'unsupported subclass for units of attribute named '//attr_name//' in '//var_name//' in '//fname) + _FAIL('unsupported subclass (not int64) for units of attribute named '//attr_name//' in '//var_name//' in '//fname) end select _RETURN(_SUCCESS) @@ -260,7 +260,7 @@ function get_var_attr_string(this,var_name,attr_name,rc) result(attr_string) type is(character(*)) attr_string = attr_val class default - _ASSERT(.false.,'unsupported subclass for units of attribute named '//attr_name//' in '//var_name//' in '//fname) + _FAIL('unsupported subclass (not string) for units of attribute named '//attr_name//' in '//var_name//' in '//fname) end select _RETURN(_SUCCESS) @@ -378,7 +378,7 @@ subroutine get_time_info(this,startTime,startyear,startmonth,startday,starthour, endif endif class default - _ASSERT(.false.,"Time unit must be character in "//fname) + _FAIL("Time unit must be character in "//fname) end select call ESMF_TimeSet(unmodStartTime,yy=year,mm=month,dd=day,h=hour,m=min,s=sec,rc=status) _VERIFY(status) @@ -399,7 +399,7 @@ subroutine get_time_info(this,startTime,startyear,startmonth,startday,starthour, type is (integer(kind=INT32)) tr_r64=ptr class default - _ASSERT(.false.,"unsupported time variable type in "//fname) + _FAIL("unsupported time variable type in "//fname) end select do i=1,tsize select case (trim(tUnits)) @@ -420,7 +420,7 @@ subroutine get_time_info(this,startTime,startyear,startmonth,startday,starthour, _VERIFY(status) tvec(i)=unmodStartTime+tint case default - _ASSERT(.false.,"unsupported time unit in "//fname) + _FAIL("unsupported time unit in "//fname) end select enddo @@ -439,6 +439,7 @@ subroutine get_time_info(this,startTime,startyear,startmonth,startday,starthour, allocate(timeVector,source=tVec,stat=status) _VERIFY(status) end if + _RETURN(_SUCCESS) end subroutine get_time_info @@ -461,7 +462,6 @@ function get_variable_attribute(this,var_name,attr_name,rc) result(units) character(len=*), intent(in) :: var_name character(len=*), intent(in) :: attr_name integer, optional, intent(out) :: rc - character(:), allocatable :: fname character(len=:), pointer :: units type(Attribute), pointer :: attr => null() @@ -481,7 +481,7 @@ function get_variable_attribute(this,var_name,attr_name,rc) result(units) type is (character(*)) units => vunits class default - _ASSERT(.false.,'units must be string for '//var_name//' in '//fname) + _FAIL('units must be string for '//var_name//' in '//fname) end select else units => null() @@ -522,7 +522,7 @@ subroutine get_coordinate_info(this,coordinate_name,coordSize,coordUnits,coords, type is (character(*)) coordUnits = trim(coordUnitPtr) class default - _ASSERT(.false.,'coordinate units must be string in '//fname) + _FAIL('coordinate units must be string in '//fname) end select end if @@ -539,9 +539,10 @@ subroutine get_coordinate_info(this,coordinate_name,coordSize,coordUnits,coords, type is (integer(kind=INT32)) coords=ptr class default - _ASSERT(.false.,"unsupported coordel variable type in "//fname) + _FAIL("unsupported coordinate variable type in "//fname) end select end if + _RETURN(_SUCCESS) end subroutine get_coordinate_info diff --git a/base/MAPL_AbstractRegridder.F90 b/base/MAPL_AbstractRegridder.F90 index 3b7a1c55acb2..30ffeb83017e 100644 --- a/base/MAPL_AbstractRegridder.F90 +++ b/base/MAPL_AbstractRegridder.F90 @@ -120,7 +120,7 @@ subroutine regrid_scalar_2d_real32(this, q_in, q_out, rc) integer, optional, intent(out) :: rc character(len=*), parameter :: Iam = MOD_NAME//'regrid_scalar_2d_real32' - _ASSERT(.false., 'unimplemented - must override in subclass') + _FAIL( 'unimplemented - must override in subclass') _UNUSED_DUMMY(this) _UNUSED_DUMMY(q_in) q_out = 0 @@ -136,7 +136,7 @@ subroutine regrid_scalar_2d_real64(this, q_in, q_out, rc) integer, optional, intent(out) :: rc character(len=*), parameter :: Iam = MOD_NAME//'regrid_scalar_2d_real64' - _ASSERT(.false., 'unimplemented - must override in subclass') + _FAIL( 'unimplemented - must override in subclass') _UNUSED_DUMMY(this) _UNUSED_DUMMY(q_in) q_out = 0 @@ -152,7 +152,7 @@ subroutine regrid_scalar_3d_real32(this, q_in, q_out, rc) integer, optional, intent(out) :: rc character(len=*), parameter :: Iam = MOD_NAME//'regrid_scalar_3d_real32' - _ASSERT(.false., 'unimplemented - must override in subclass') + _FAIL( 'unimplemented - must override in subclass') _UNUSED_DUMMY(this) _UNUSED_DUMMY(q_in) q_out = 0 @@ -168,7 +168,7 @@ subroutine regrid_scalar_3d_real64(this, q_in, q_out, rc) integer, optional, intent(out) :: rc character(len=*), parameter :: Iam = MOD_NAME//'regrid_scalar_3d_real64' - _ASSERT(.false., 'unimplemented - must override in subclass') + _FAIL( 'unimplemented - must override in subclass') _UNUSED_DUMMY(this) _UNUSED_DUMMY(q_in) q_out = 0 @@ -187,7 +187,7 @@ subroutine regrid_vector_2d_real32(this, u_in, v_in, u_out, v_out, rotate, rc) integer, optional, intent(out) :: rc character(len=*), parameter :: Iam = MOD_NAME//'regrid_vector_2d_real32' - _ASSERT(.false., 'unimplemented - must override in subclass') + _FAIL( 'unimplemented - must override in subclass') _UNUSED_DUMMY(this) _UNUSED_DUMMY(u_in) _UNUSED_DUMMY(v_in) @@ -209,7 +209,7 @@ subroutine regrid_vector_2d_real64(this, u_in, v_in, u_out, v_out, rotate, rc) integer, optional, intent(out) :: rc character(len=*), parameter :: Iam = MOD_NAME//'regrid_vector_2d_real64' - _ASSERT(.false., 'unimplemented - must override in subclass') + _FAIL( 'unimplemented - must override in subclass') _UNUSED_DUMMY(this) _UNUSED_DUMMY(u_in) _UNUSED_DUMMY(v_in) @@ -230,7 +230,7 @@ subroutine regrid_vector_3d_real32(this, u_in, v_in, u_out, v_out, rotate, rc) integer, optional, intent(out) :: rc character(len=*), parameter :: Iam = MOD_NAME//'regrid_vector_3d_real32' - _ASSERT(.false., 'unimplemented - must override in subclass') + _FAIL( 'unimplemented - must override in subclass') _UNUSED_DUMMY(this) _UNUSED_DUMMY(u_in) _UNUSED_DUMMY(v_in) @@ -251,7 +251,7 @@ subroutine regrid_vector_3d_real64(this, u_in, v_in, u_out, v_out, rc) integer, optional, intent(out) :: rc character(len=*), parameter :: Iam = MOD_NAME//'regrid_vector_3d_real64' - _ASSERT(.false., 'unimplemented - must override in subclass') + _FAIL( 'unimplemented - must override in subclass') _UNUSED_DUMMY(this) _UNUSED_DUMMY(u_in) _UNUSED_DUMMY(v_in) @@ -321,7 +321,7 @@ subroutine regrid_esmf_fields_scalar(this, f_in, f_out, rc) end block case default - _ASSERT(.false., 'unsupported typekind') + _FAIL( 'unsupported typekind') end select case (3) @@ -354,11 +354,11 @@ subroutine regrid_esmf_fields_scalar(this, f_in, f_out, rc) _VERIFY(status) end block case default ! unsupported type/kind - _ASSERT(.false., 'unsupported type kind') + _FAIL( 'unsupported type kind') end select case default ! unsupported rank - _ASSERT(.false., 'unsupported rank') + _FAIL( 'unsupported rank') end select _RETURN(_SUCCESS) @@ -445,7 +445,7 @@ subroutine regrid_esmf_fields_vector(this, f_in, f_out, rc) end block case default ! unsupported typekind - _ASSERT(.false., 'unsupported typekind') + _FAIL( 'unsupported typekind') end select case (3) @@ -487,11 +487,11 @@ subroutine regrid_esmf_fields_vector(this, f_in, f_out, rc) end block case default ! unsupported type/kind - _ASSERT(.false., 'unsupported type-kind') + _FAIL( 'unsupported type-kind') end select case default ! unsupported rank - _ASSERT(.false., 'unsupported rank') + _FAIL( 'unsupported rank') end select _RETURN(_SUCCESS) @@ -509,7 +509,7 @@ subroutine transpose_regrid_scalar_2d_real32(this, q_in, q_out, rc) integer, optional, intent(out) :: rc character(len=*), parameter :: Iam = MOD_NAME//'transpose_regrid_scalar_2d_real32' - _ASSERT(.false., 'unimplemented - must override in subclass') + _FAIL( 'unimplemented - must override in subclass') _UNUSED_DUMMY(this) _UNUSED_DUMMY(q_in) q_out = 0 @@ -524,7 +524,7 @@ subroutine transpose_regrid_scalar_2d_real64(this, q_in, q_out, rc) integer, optional, intent(out) :: rc character(len=*), parameter :: Iam = MOD_NAME//'transpose_regrid_scalar_2d_real64' - _ASSERT(.false., 'unimplemented - must override in subclass') + _FAIL( 'unimplemented - must override in subclass') _UNUSED_DUMMY(this) _UNUSED_DUMMY(q_in) q_out = 0 @@ -539,7 +539,7 @@ subroutine transpose_regrid_scalar_3d_real32(this, q_in, q_out, rc) integer, optional, intent(out) :: rc character(len=*), parameter :: Iam = MOD_NAME//'transpose_regrid_scalar_3d_real32' - _ASSERT(.false., 'unimplemented - must override in subclass') + _FAIL( 'unimplemented - must override in subclass') _UNUSED_DUMMY(this) _UNUSED_DUMMY(q_in) q_out = 0 @@ -555,7 +555,7 @@ subroutine transpose_regrid_scalar_3d_real64(this, q_in, q_out, rc) integer, optional, intent(out) :: rc character(len=*), parameter :: Iam = MOD_NAME//'transpose_regrid_scalar_3d_real64' - _ASSERT(.false., 'unimplemented - must override in subclass') + _FAIL( 'unimplemented - must override in subclass') _UNUSED_DUMMY(this) _UNUSED_DUMMY(q_in) q_out = 0 @@ -575,7 +575,7 @@ subroutine transpose_regrid_vector_2d_real32(this, u_in, v_in, u_out, v_out, rot character(len=*), parameter :: Iam = MOD_NAME//'transpose_regrid_vector_2d_real32' - _ASSERT(.false., 'unimplemented - must override in subclass') + _FAIL( 'unimplemented - must override in subclass') _UNUSED_DUMMY(this) _UNUSED_DUMMY(u_in) _UNUSED_DUMMY(v_in) @@ -600,7 +600,7 @@ subroutine transpose_regrid_vector_2d_real64(this, u_in, v_in, u_out, v_out, rot character(len=*), parameter :: Iam = MOD_NAME//'transpose_regrid_vector_2d_real64' - _ASSERT(.false., 'unimplemented - must override in subclass') + _FAIL( 'unimplemented - must override in subclass') _UNUSED_DUMMY(this) _UNUSED_DUMMY(u_in) _UNUSED_DUMMY(v_in) @@ -625,7 +625,7 @@ subroutine transpose_regrid_vector_3d_real32(this, u_in, v_in, u_out, v_out, rot character(len=*), parameter :: Iam = MOD_NAME//'transpose_regrid_vector_3d_real32' - _ASSERT(.false., 'unimplemented - must override in subclass') + _FAIL( 'unimplemented - must override in subclass') _UNUSED_DUMMY(this) _UNUSED_DUMMY(u_in) _UNUSED_DUMMY(v_in) @@ -649,7 +649,7 @@ subroutine transpose_regrid_vector_3d_real64(this, u_in, v_in, u_out, v_out, rc) character(len=*), parameter :: Iam = MOD_NAME//'transpose_regrid_vector_3d_real64' - _ASSERT(.false., 'unimplemented - must override in subclass') + _FAIL( 'unimplemented - must override in subclass') _UNUSED_DUMMY(this) _UNUSED_DUMMY(u_in) _UNUSED_DUMMY(v_in) @@ -721,7 +721,7 @@ subroutine transpose_regrid_esmf_fields_scalar(this, f_in, f_out, rc) end block case default ! unsupported typekind - _ASSERT(.false., 'unsupported typekind') + _FAIL( 'unsupported typekind') end select case (3) @@ -754,11 +754,11 @@ subroutine transpose_regrid_esmf_fields_scalar(this, f_in, f_out, rc) _VERIFY(status) end block case default ! unsupported type/kind - _ASSERT(.false., 'unsupported typekind') + _FAIL( 'unsupported typekind') end select case default ! unsupported rank - _ASSERT(.false., 'unsupported rank') + _FAIL( 'unsupported rank') end select _RETURN(_SUCCESS) @@ -845,7 +845,7 @@ subroutine transpose_regrid_esmf_fields_vector(this, f_in, f_out, rc) end block case default ! unsupported typekind - _ASSERT(.false., 'unsupported typekind') + _FAIL( 'unsupported typekind') end select case (3) @@ -887,11 +887,11 @@ subroutine transpose_regrid_esmf_fields_vector(this, f_in, f_out, rc) end block case default ! unsupported type/kind - _ASSERT(.false., 'unsupported typekind') + _FAIL( 'unsupported typekind') end select case default ! unsupported rank - _ASSERT(.false., 'unsupported rank') + _FAIL( 'unsupported rank') end select _RETURN(_SUCCESS) diff --git a/base/MAPL_CFIO.F90 b/base/MAPL_CFIO.F90 index 0093464f5536..2032536719b1 100644 --- a/base/MAPL_CFIO.F90 +++ b/base/MAPL_CFIO.F90 @@ -475,7 +475,7 @@ subroutine MAPL_CFIOCreateFromBundle ( MCFIO, NAME, CLOCK, BUNDLE, OFFSET, print*,'WARNING: CFIO parameter "order" is no longer used.' print*,' The new regrid facility uses ESMF parameters to' print*,' specify the type of regridding to perform.' - _ASSERT(.false., 'Order must be present') + _FAIL( 'Order must be present') MCFIO%Order = Order else MCFIO%Order = -1 @@ -739,7 +739,7 @@ subroutine MAPL_CFIOCreateFromBundle ( MCFIO, NAME, CLOCK, BUNDLE, OFFSET, unGrdCoordCheck = .false. end if if ( unGrdUnitCheck .or. unGrdNameCheck .or. unGrdCoordCheck) then - _ASSERT(.false., 'Ungridded attributes for variables in collection do not match') + _FAIL( 'Ungridded attributes for variables in collection do not match') end if end if end do @@ -807,7 +807,7 @@ subroutine MAPL_CFIOCreateFromBundle ( MCFIO, NAME, CLOCK, BUNDLE, OFFSET, LM = size(ULEVELS) HAVE_edge = .false. if (HAVE_ungrd) then - _ASSERT(.false., 'ERROR: Specifying LEVELS is not allowed for UNGRIDDED vars') + _FAIL( 'ERROR: Specifying LEVELS is not allowed for UNGRIDDED vars') end if else @@ -817,17 +817,17 @@ subroutine MAPL_CFIOCreateFromBundle ( MCFIO, NAME, CLOCK, BUNDLE, OFFSET, DO I = 1, NumVars IF (LOCATION(I)==MAPL_VLocationEdge) print*, mCFIO%VarName(I) ENDDO - _ASSERT(.false., 'ERROR: Mixed Vlocation in CFIO not allowed unless LEVELS is specified') + _FAIL( 'ERROR: Mixed Vlocation in CFIO not allowed unless LEVELS is specified') endif if( all(MCFIO%VarDims==2)) then LM = 1 else if (HAVE_ungrd) then if (HAVE_center .or. HAVE_edge) then - _ASSERT(.false., 'ERROR: Mixed 3d and UNGRIDDED in CFIO not allowed') + _FAIL( 'ERROR: Mixed 3d and UNGRIDDED in CFIO not allowed') end if if (minval(vsize) /= maxval(vsize)) then - _ASSERT(.false., 'ERROR: Outputting variables with different ungridded sizes in one collection') + _FAIL( 'ERROR: Outputting variables with different ungridded sizes in one collection') end if LM = maxval(vsize) else @@ -958,7 +958,7 @@ subroutine MAPL_CFIOCreateFromBundle ( MCFIO, NAME, CLOCK, BUNDLE, OFFSET, exit end do if (.not.foundEmpty) then - _ASSERT(.false., 'ERROR: Need bigger table with storedCoords') + _FAIL( 'ERROR: Need bigger table with storedCoords') end if end if endif @@ -995,7 +995,7 @@ subroutine MAPL_CFIOCreateFromBundle ( MCFIO, NAME, CLOCK, BUNDLE, OFFSET, lons1d = MAPL_Range(-180.+(180./IMO), 180.-(180./IMO), IMO) lats1d = MAPL_Range(-90.+(90./JMO), +90.-(90./JMO), JMO) case default - _ASSERT(.false.,'needs informative message') + _FAIL('needs informative message') end select mcfio%xyoffset = xyoffset else @@ -5257,13 +5257,13 @@ subroutine MAPL_CFIOCreateFromFile(MCFIO,bundlein,RegridMethod,hw,only_vars,rc) end if else if (gridStagger == MAPL_DGrid) then if (rotation /= MAPL_RotateCube) then - _ASSERT(.false.,'must rotate LL') + _FAIL('must rotate LL') else mCFIO%doRotate = .false. end if else if (gridStagger == MAPL_CGrid) then if (rotation /= MAPL_RotateCube) then - _ASSERT(.false.,'must rotate LL') + _FAIL('must rotate LL') else mCFIO%doRotate = .false. end if diff --git a/base/MAPL_Comms.F90 b/base/MAPL_Comms.F90 index 9496479311bd..51d86ae8c747 100644 --- a/base/MAPL_Comms.F90 +++ b/base/MAPL_Comms.F90 @@ -464,7 +464,7 @@ subroutine MAPL_CreateRequest(grid, Root, request, tag, RequestType, & _VERIFY(STATUS) end if else - _ASSERT(.false., 'unsupported action') + _FAIL( 'unsupported action') end if ! Allocate a contiguous buffer for communication diff --git a/base/MAPL_CubedSphereGridFactory.F90 b/base/MAPL_CubedSphereGridFactory.F90 index eef03c9fb63a..abd24727098d 100644 --- a/base/MAPL_CubedSphereGridFactory.F90 +++ b/base/MAPL_CubedSphereGridFactory.F90 @@ -33,7 +33,7 @@ module MAPL_CubedSphereGridFactoryMod type, extends(AbstractGridFactory) :: CubedSphereGridFactory private - + character(len=:), allocatable :: grid_name integer :: grid_type = MAPL_UNDEFINED_INTEGER @@ -90,9 +90,9 @@ module MAPL_CubedSphereGridFactoryMod procedure :: decomps_are_equal procedure :: physical_params_are_equal end type CubedSphereGridFactory - + character(len=*), parameter :: MOD_NAME = 'CubedSphereGridFactory::' - + interface CubedSphereGridFactory module procedure CubedSphereGridFactory_from_parameters end interface CubedSphereGridFactory @@ -128,7 +128,7 @@ function CubedSphereGridFactory_from_parameters(unusable, grid_name, grid_type, integer, optional, intent(in) :: jms(:) ! stretched grid - real(REAL32), optional, intent(in) :: stretch_factor, target_lon, target_lat + real(REAL32), optional, intent(in) :: stretch_factor, target_lon, target_lat integer, optional, intent(out) :: rc @@ -182,7 +182,7 @@ function make_new_grid(this, unusable, rc) result(grid) end function make_new_grid - + function create_basic_grid(this, unusable, rc) result(grid) type (ESMF_Grid) :: grid class (CubedSphereGridFactory), intent(in) :: this @@ -210,7 +210,7 @@ function create_basic_grid(this, unusable, rc) result(grid) enddo if(allocated(this%jms_2d)) then - _ASSERT(size(this%jms_2d,2) == 6,'incompatible shape') + _ASSERT(size(this%jms_2d,2) == 6,'incompatible shape') allocate(jms, source = this%jms_2d) else allocate(jms(this%ny,nTile)) @@ -226,7 +226,7 @@ function create_basic_grid(this, unusable, rc) result(grid) transformArgument%target_lat=this%target_lat grid = ESMF_GridCreateCubedSPhere(this%im_world,countsPerDEDim1PTile=ims, & countsPerDEDim2PTile=jms ,name=this%grid_name, & - staggerLocList=[ESMF_STAGGERLOC_CENTER,ESMF_STAGGERLOC_CORNER], coordSys=ESMF_COORDSYS_SPH_RAD, & + staggerLocList=[ESMF_STAGGERLOC_CENTER,ESMF_STAGGERLOC_CORNER], coordSys=ESMF_COORDSYS_SPH_RAD, & transformArgs=transformArgument,rc=status) _VERIFY(status) if (this%stretch_factor/=MAPL_UNDEFINED_REAL .and. this%target_lon/=MAPL_UNDEFINED_REAL .and. & @@ -287,7 +287,7 @@ function create_basic_grid(this, unusable, rc) result(grid) _RETURN(_SUCCESS) end function create_basic_grid - + subroutine initialize_from_file_metadata(this, file_metadata, unusable, force_file_coordinates, rc) use MAPL_KeywordEnforcerMod use MAPL_BaseMod, only: MAPL_DecomposeDim @@ -316,7 +316,7 @@ subroutine initialize_from_file_metadata(this, file_metadata, unusable, force_fi im = file_metadata%get_dimension('lon',rc=status) _VERIFY(status) else - _ASSERT(.false.,"can not identify dimenions of cubed-sphere file") + _FAIL("can not identify dimenions of cubed-sphere file") end if end associate call this%make_arbitrary_decomposition(this%nx, this%ny, reduceFactor=6, rc=status) @@ -332,7 +332,7 @@ subroutine initialize_from_file_metadata(this, file_metadata, unusable, force_fi type is (real(kind=REAL32)) this%stretch_factor = q(1) class default - _ASSERT(.false.,'unsupport subclass for stretch params') + _FAIL('unsupport subclass for stretch params') end select attr => file_metadata%get_attribute('TARGET_LAT') attr_val => attr%get_values() @@ -340,7 +340,7 @@ subroutine initialize_from_file_metadata(this, file_metadata, unusable, force_fi type is (real(kind=REAL32)) this%target_lat = q(1) class default - _ASSERT(.false.,'unsupport subclass for stretch params') + _FAIL('unsupport subclass for stretch params') end select attr => file_metadata%get_attribute('TARGET_LON') attr_val => attr%get_values() @@ -348,10 +348,10 @@ subroutine initialize_from_file_metadata(this, file_metadata, unusable, force_fi type is (real(kind=REAL32)) this%target_lon = q(1) class default - _ASSERT(.false.,'unsupport subclass for stretch params') + _FAIL('unsupport subclass for stretch params') end select end if - + hasLev=.false. hasLevel=.false. @@ -432,7 +432,7 @@ subroutine initialize_from_config_with_prefix(this, config, prefix, unusable, rc _VERIFY(status) ! halo initialization - + call ESMF_VmGet(VM, mpicommunicator=vmcomm, petCount=ndes, rc=status) _VERIFY(status) @@ -440,7 +440,7 @@ subroutine initialize_from_config_with_prefix(this, config, prefix, unusable, rc _RETURN(_SUCCESS) contains - + subroutine get_multi_integer(values, label, rc) integer, allocatable, intent(out) :: values(:) character(len=*) :: label @@ -451,7 +451,7 @@ subroutine get_multi_integer(values, label, rc) integer :: tmp integer :: status logical :: isPresent - + call ESMF_ConfigFindLabel(config, label=prefix//label,isPresent=isPresent,rc=status) _VERIFY(status) if (.not. isPresent) then @@ -494,7 +494,7 @@ subroutine get_jms_from_file(values, file_name, n, rc) integer :: status, N_proc,NF integer, allocatable :: values_tmp(:), values_(:,:) - + N_proc = n*6 ! it has been devided by 6. get back the original NY allocate(values_tmp(N_proc), stat=status) ! no point in checking status _VERIFY(status) @@ -534,7 +534,7 @@ subroutine get_jms_from_file(values, file_name, n, rc) face = face + values_tmp(k) k = k+1 if (face == this%im_world) exit - enddo + enddo enddo values = values_ @@ -551,7 +551,7 @@ subroutine get_bounds(bounds, label, rc) integer :: n integer :: status logical :: isPresent - + call ESMF_ConfigFindLabel(config, label=prefix//label,isPresent=isPresent,rc=status) _VERIFY(status) if (.not. isPresent) then @@ -568,9 +568,9 @@ subroutine get_bounds(bounds, label, rc) end subroutine get_bounds - + end subroutine initialize_from_config_with_prefix - + subroutine halo_init(this, halo_width,rc) class (CubedSphereGridFactory), intent(inout) :: this integer, optional, intent(in) :: halo_width @@ -602,7 +602,7 @@ subroutine halo_init(this, halo_width,rc) _VERIFY(status) call ESMF_FieldDestroy(field,rc=status) _VERIFY(status) - + end subroutine halo_init function to_string(this) result(string) @@ -649,14 +649,14 @@ subroutine check_and_fill_consistency(this, unusable, rc) !_ASSERT(allocated(this%ims) .eqv. allocated(this%jms),'inconsistent options') call verify(this%nx, this%im_world, this%ims, rc=status) if (allocated(this%jms_2d)) then - _ASSERT(size(this%jms_2d,2)==6, 'incompatible shape') + _ASSERT(size(this%jms_2d,2)==6, 'incompatible shape') _ASSERT(sum(this%jms_2d) == 6*this%im_world, 'incompatible shape') else call verify(this%ny, this%im_world, this%jms, rc=status) endif - + _RETURN(_SUCCESS) - + contains subroutine verify(n, m_world, ms, rc) @@ -704,52 +704,52 @@ elemental subroutine set_with_default_integer(to, from, default) integer, intent(out) :: to integer, optional, intent(in) :: from integer, intent(in) :: default - + if (present(from)) then to = from else to = default end if - + end subroutine set_with_default_integer - + elemental subroutine set_with_default_real64(to, from, default) real(REAL64), intent(out) :: to real(REAL64), optional, intent(in) :: from real(REAL64), intent(in) :: default - + if (present(from)) then to = from else to = default end if - + end subroutine set_with_default_real64 - + elemental subroutine set_with_default_real(to, from, default) real, intent(out) :: to real, optional, intent(in) :: from real, intent(in) :: default - + if (present(from)) then to = from else to = default end if - + end subroutine set_with_default_real - + subroutine set_with_default_character(to, from, default) character(len=:), allocatable, intent(out) :: to character(len=*), optional, intent(in) :: from character(len=*), intent(in) :: default - + if (present(from)) then to = from else to = default end if - + end subroutine set_with_default_character @@ -757,15 +757,15 @@ elemental subroutine set_with_default_bounds(to, from, default) type (RealMinMax), intent(out) :: to type (RealMinMax), optional, intent(in) :: from type (RealMinMax), intent(in) :: default - + if (present(from)) then to = from else to = default end if - + end subroutine set_with_default_bounds - + function decomps_are_equal(this, a) result(equal) class (CubedSphereGridFactory), intent(in) :: this class (AbstractGridFactory), intent(in) :: a @@ -781,7 +781,7 @@ function decomps_are_equal(this, a) result(equal) if (.not. equal) return equal = size(a%jms) == size(this%jms) if (.not. equal) return - equal = all(a%ims == this%ims) + equal = all(a%ims == this%ims) if (.not. equal) return if ( allocated(a%jms) .and. allocated(this%jms)) then @@ -795,7 +795,7 @@ function decomps_are_equal(this, a) result(equal) equal = all(a%jms_2d == this%jms_2d) if (.not. equal) return endif - end select + end select end function decomps_are_equal @@ -813,18 +813,18 @@ function physical_params_are_equal(this, a) result(equal) equal = (a%im_world == this%im_world) if (.not. equal) return - + equal = (a%stretch_factor == this%stretch_factor) if (.not. equal) return - + equal = (a%target_lon == this%target_lon) if (.not. equal) return - + equal = (a%target_lat == this%target_lat) if (.not. equal) return - + end select - + end function physical_params_are_equal logical function equals(a, b) @@ -843,12 +843,12 @@ logical function equals(a, b) equals = a%decomps_are_equal(b) if (.not. equals) return - + equals = a%physical_params_are_equal(b) if (.not. equals) return - + end select - + end function equals subroutine initialize_from_esmf_distGrid(this, dist_grid, lon_array, lat_array, unusable, rc) @@ -866,7 +866,7 @@ subroutine initialize_from_esmf_distGrid(this, dist_grid, lon_array, lat_array, _UNUSED_DUMMY(lon_array) _UNUSED_DUMMY(lat_array) _UNUSED_DUMMY(unusable) - + _FAIL('not implemented') end subroutine initialize_from_esmf_distGrid @@ -887,7 +887,7 @@ subroutine halo(this, array, unusable, halo_width, rc) integer :: useableHalo_width _UNUSED_DUMMY(unusable) - + if (.not. this%halo_initialized) then call this%halo_init(halo_width = halo_width) this%halo_initialized = .true. @@ -912,7 +912,7 @@ subroutine halo(this, array, unusable, halo_width, rc) array = ptr call ESMF_FieldDestroy(field,rc=status) _VERIFY(status) - + _RETURN(_SUCCESS) end subroutine halo @@ -943,6 +943,8 @@ subroutine append_metadata(this, metadata)!, unusable, rc) integer, allocatable :: ivar(:,:) integer, allocatable :: ivar2(:,:,:) + real(REAL64), allocatable :: temp_coords(:) + integer :: status integer, parameter :: ncontact = 4 integer, parameter :: nf = 6 @@ -960,12 +962,16 @@ subroutine append_metadata(this, metadata)!, unusable, rc) v = Variable(type=PFIO_REAL64, dimensions='Xdim') call v%add_attribute('long_name', 'Fake Longitude for GrADS Compatibility') call v%add_attribute('units', 'degrees_east') - call metadata%add_variable('Xdim', CoordinateVariable(v, this%get_fake_longitudes())) + temp_coords = this%get_fake_longitudes() + call metadata%add_variable('Xdim', CoordinateVariable(v, temp_coords)) + deallocate(temp_coords) v = Variable(type=PFIO_REAL64, dimensions='Ydim') call v%add_attribute('long_name', 'Fake Latitude for GrADS Compatibility') call v%add_attribute('units', 'degrees_north') - call metadata%add_variable('Ydim', CoordinateVariable(v, this%get_fake_latitudes())) + temp_coords = this%get_fake_latitudes() + call metadata%add_variable('Ydim', CoordinateVariable(v, temp_coords)) + deallocate(temp_coords) v = Variable(type=PFIO_INT32, dimensions='nf') call v%add_attribute('long_name','cubed-sphere face') @@ -1007,7 +1013,7 @@ subroutine append_metadata(this, metadata)!, unusable, rc) im = this%im_world allocate(ivar2(4,4,6)) - ivar2 = reshape( & + ivar2 = reshape( & [[im, im, 1, im, & 1, im, 1, 1, & 1, im, 1, 1, & @@ -1125,11 +1131,11 @@ function get_fake_longitudes(this, unusable, rc) result(longitudes) integer :: j_mid integer :: tile integer :: status - + character(len=*), parameter :: Iam = MOD_NAME // 'get_fake_longitudes()' - + _UNUSED_DUMMY(unusable) - + grid = this%make_grid() call ESMF_GridGetCoord(grid, coordDim=1, localDE=0, & @@ -1142,7 +1148,7 @@ function get_fake_longitudes(this, unusable, rc) result(longitudes) call ESMF_VMGet(vm, mpiCommunicator=comm_grid, petcount=npes, localpet=pet, rc=status) _VERIFY(status) - + call MAPL_grid_interior(grid, i_1, i_n, j_1, j_n) j_mid = 1 + this%im_world/2 @@ -1159,7 +1165,7 @@ function get_fake_longitudes(this, unusable, rc) result(longitudes) end if allocate(counts(0:npes-1), displs(0:npes-1)) - + call MPI_Allgather(n_loc, 1, MPI_INTEGER, counts, 1, MPI_INTEGER, comm_grid, ierror) _VERIFY(ierror) @@ -1173,7 +1179,7 @@ function get_fake_longitudes(this, unusable, rc) result(longitudes) _VERIFY(ierror) longitudes = longitudes * MAPL_RADIANS_TO_DEGREES - + end function get_fake_longitudes function get_fake_latitudes(this, unusable, rc) result(latitudes) @@ -1197,11 +1203,11 @@ function get_fake_latitudes(this, unusable, rc) result(latitudes) integer :: j_mid integer :: tile integer :: status - + character(len=*), parameter :: Iam = MOD_NAME // 'get_fake_latitudes()' _UNUSED_DUMMY(unusable) - + grid = this%make_grid() call ESMF_GridGetCoord(grid, coordDim=2, localDE=0, & @@ -1214,7 +1220,7 @@ function get_fake_latitudes(this, unusable, rc) result(latitudes) call ESMF_VMGet(vm, mpiCommunicator=comm_grid, petcount=npes, localpet=pet, rc=status) _VERIFY(status) - + call MAPL_grid_interior(grid, i_1, i_n, j_1, j_n) j_mid = 1 + this%im_world/2 @@ -1231,7 +1237,7 @@ function get_fake_latitudes(this, unusable, rc) result(latitudes) end if allocate(counts(0:npes-1), displs(0:npes-1)) - + call MPI_Allgather(n_loc, 1, MPI_INTEGER, counts, 1, MPI_INTEGER, comm_grid, ierror) _VERIFY(ierror) @@ -1245,7 +1251,7 @@ function get_fake_latitudes(this, unusable, rc) result(latitudes) _VERIFY(ierror) latitudes = latitudes * MAPL_RADIANS_TO_DEGREES - + end function get_fake_latitudes subroutine generate_file_bounds(this,grid,local_start,global_start,global_count,metaData,rc) diff --git a/base/MAPL_EsmfRegridder.F90 b/base/MAPL_EsmfRegridder.F90 index 9749a184acdc..519f216ef6f9 100644 --- a/base/MAPL_EsmfRegridder.F90 +++ b/base/MAPL_EsmfRegridder.F90 @@ -83,8 +83,10 @@ logical function supports(spec, unusable, rc) supports = any(spec%regrid_method == & [ & REGRID_METHOD_BILINEAR, & + REGRID_METHOD_BILINEAR_MONOTONIC, & REGRID_METHOD_BILINEAR_ROTATE, & REGRID_METHOD_CONSERVE, & + REGRID_METHOD_CONSERVE_MONOTONIC, & REGRID_METHOD_VOTE, & REGRID_METHOD_FRACTION, & REGRID_METHOD_CONSERVE_2ND, & @@ -1172,7 +1174,56 @@ subroutine simpleDynMaskProcV(dynamicMaskList, dynamicSrcMaskValue, & rc = ESMF_SUCCESS end subroutine simpleDynMaskProcV + subroutine monotonicDynMaskProcV(dynamicMaskList, dynamicSrcMaskValue, & + dynamicDstMaskValue, rc) + type(ESMF_DynamicMaskElementR4R8R4V), pointer :: dynamicMaskList(:) + real(ESMF_KIND_R4), intent(in), optional :: dynamicSrcMaskValue + real(ESMF_KIND_R4), intent(in), optional :: dynamicDstMaskValue + integer, intent(out) :: rc + integer :: i, j, k, n + real(ESMF_KIND_R4), allocatable :: renorm(:),max_input(:),min_input(:) + _UNUSED_DUMMY(dynamicDstMaskValue) + + if (associated(dynamicMaskList)) then + n = size(dynamicMaskList(1)%srcElement(1)%ptr) + allocate(renorm(n),max_input(n),min_input(n)) + + do i=1, size(dynamicMaskList) + dynamicMaskList(i)%dstElement = 0.0 ! set to zero + + renorm = 0.d0 ! reset + max_input = -huge(0.0) + min_input = huge(0.0) + do j=1, size(dynamicMaskList(i)%factor) + do k = 1, size(dynamicMaskList(i)%srcElement(j)%ptr) + if (.not. & + match(dynamicSrcMaskValue,dynamicMaskList(i)%srcElement(j)%ptr(k))) then + dynamicMaskList(i)%dstElement(k) = dynamicMaskList(i)%dstElement(k) & + + dynamicMaskList(i)%factor(j) & + * dynamicMaskList(i)%srcElement(j)%ptr(k) + renorm(k) = renorm(k) + dynamicMaskList(i)%factor(j) + if (dynamicMaskList(i)%srcElement(j)%ptr(k) > max_input(k)) max_input(k) = dynamicMaskList(i)%srcElement(j)%ptr(k) + if (dynamicMaskList(i)%srcElement(j)%ptr(k) < min_input(k)) min_input(k) = dynamicMaskList(i)%srcElement(j)%ptr(k) + endif + end do + end do + where (renorm > 0.d0) + dynamicMaskList(i)%dstElement = dynamicMaskList(i)%dstElement / renorm + elsewhere + dynamicMaskList(i)%dstElement = dynamicSrcMaskValue + end where + where (renorm > 0.d0 .and. dynamicMaskList(i)%dstElement > max_input) + dynamicMaskList(i)%dstElement = max_input + end where + where (renorm > 0.d0 .and. dynamicMaskList(i)%dstElement < min_input) + dynamicMaskList(i)%dstElement = min_input + end where + enddo + endif + ! return successfully + rc = ESMF_SUCCESS + end subroutine monotonicDynMaskProcV logical function match(missing,b) @@ -1337,6 +1388,13 @@ subroutine initialize_subclass(this, unusable, rc) & dynamicMaskRoutine=simpleDynMaskProcV, & & rc=rc) _VERIFY(rc) + case (REGRID_METHOD_BILINEAR_MONOTONIC, REGRID_METHOD_CONSERVE_MONOTONIC) + call ESMF_DynamicMaskSetR4R8R4V(this%dynamic_mask, & + & dynamicSrcMaskValue=MAPL_undef, & + & dynamicMaskRoutine=monotonicDynMaskProcV, & + & handleAllElements=.true., & + & rc=rc) + _VERIFY(rc) case (REGRID_METHOD_VOTE) call ESMF_DynamicMaskSetR4R8R4V(this%dynamic_mask, & & dynamicSrcMaskValue=MAPL_undef, & @@ -1435,7 +1493,7 @@ subroutine create_route_handle(this, kind, rc) if (.not.global) unmappedaction=ESMF_UNMAPPEDACTION_IGNORE end if select case (spec%regrid_method) - case (REGRID_METHOD_BILINEAR) + case (REGRID_METHOD_BILINEAR, REGRID_METHOD_BILINEAR_MONOTONIC) call ESMF_FieldRegridStore(src_field, dst_field, & & regridmethod=ESMF_REGRIDMETHOD_BILINEAR, & @@ -1462,7 +1520,7 @@ subroutine create_route_handle(this, kind, rc) & factorList=factorList, factorIndexList=factorIndexList, & & routehandle=route_handle, unmappedaction=unmappedaction, rc=status) _VERIFY(status) - case (REGRID_METHOD_CONSERVE, REGRID_METHOD_VOTE, REGRID_METHOD_FRACTION) + case (REGRID_METHOD_CONSERVE, REGRID_METHOD_CONSERVE_MONOTONIC, REGRID_METHOD_VOTE, REGRID_METHOD_FRACTION) call ESMF_FieldRegridStore(src_field, dst_field, & & regridmethod=ESMF_REGRIDMETHOD_CONSERVE, & & srcTermProcessing = srcTermProcessing, & diff --git a/base/MAPL_LatLonGridFactory.F90 b/base/MAPL_LatLonGridFactory.F90 index 9cf017f3784c..f4df37d7cade 100644 --- a/base/MAPL_LatLonGridFactory.F90 +++ b/base/MAPL_LatLonGridFactory.F90 @@ -39,7 +39,7 @@ module MAPL_LatLonGridFactoryMod real(kind=REAL64), allocatable :: lon_corners(:) real(kind=REAL64), allocatable :: lat_corners(:) logical :: force_decomposition = .false. - + ! Domain decomposition: integer :: nx = MAPL_UNDEFINED_INTEGER integer :: ny = MAPL_UNDEFINED_INTEGER @@ -101,7 +101,6 @@ module MAPL_LatLonGridFactoryMod character(len=*), parameter :: MOD_NAME = 'MAPL_LatLonGridFactory::' interface LatLonGridFactory - module procedure LatLonGridFactory_basic module procedure LatLonGridFactory_from_parameters end interface LatLonGridFactory @@ -116,67 +115,6 @@ module MAPL_LatLonGridFactoryMod contains - ! Note: lats and lons must be in _radians_, as the ESMF_Grid - ! constructor is currently assuming that choice. - function Latlongridfactory_basic(grid_name, & - & lon_centers, lat_centers, lon_corners, lat_corners, & - & ims, jms, lm, unusable, rc) result(factory) - type (LatLonGridFactory) :: factory - character(len=*), intent(in) :: grid_name - real(kind=REAL64), intent(in) :: lon_centers(:) - real(kind=REAL64), intent(in) :: lat_centers(:) - real(kind=REAL64), intent(in) :: lon_corners(:) - real(kind=REAL64), intent(in) :: lat_corners(:) - integer, intent(in) :: ims(:) - integer, intent(in) :: jms(:) - integer, intent(in) :: lm - class (KeywordEnforcer), optional, intent(in) :: unusable - integer, optional, intent(out) :: rc - - type (ESMF_VM) :: vm - integer :: nPet - - integer :: status - character(*), parameter :: IAM = __FILE__ - - _UNUSED_DUMMY(unusable) - - factory%is_regular = .false. - - factory%grid_name = grid_name - factory%lon_centers = lon_centers - factory%lat_centers = lat_centers - factory%lon_corners = lon_corners - factory%lat_corners = lat_corners - - factory%im_world = size(lon_centers) - factory%jm_world = size(lon_centers) - factory%lm = lm - - ! Decomposition - factory%ims = ims - factory%jms = jms - factory%nx = size(ims) - factory%ny = size(jms) - - ! Check consistency - - _ASSERT(size(lon_corners) == size(lon_centers)+1, 'inconsistent shape') - _ASSERT(size(lat_corners) == size(lat_centers)+1, 'inconsistent shape') - - _ASSERT(sum(ims) == size(lon_centers),'inconcistent decomposition') - _ASSERT(sum(jms) == size(lat_centers),'inconcistent decomposition') - - call ESMF_VMGetCurrent(vm, rc=status) - _VERIFY(status) - call ESMF_VMGet(vm, PETcount=nPet, rc=status) - _VERIFY(status) - _ASSERT(factory%nx*factory%ny == nPet,'inconsistent process topology') - - _RETURN(_SUCCESS) - - end function LatLonGridFactory_basic - function LatLonGridFactory_from_parameters(unusable, grid_name, & & im_world, jm_world, lm, nx, ny, ims, jms, & @@ -199,7 +137,7 @@ function LatLonGridFactory_from_parameters(unusable, grid_name, & integer, optional, intent(in) :: ny integer, optional, intent(in) :: ims(:) integer, optional, intent(in) :: jms(:) - logical, optional, intent(in) :: force_decomposition + logical, optional, intent(in) :: force_decomposition integer, optional, intent(out) :: rc @@ -467,7 +405,7 @@ function compute_lon_corners(this, dateline, unusable, rc) result(lon_corners) regional = (dateline == 'XY') if (regional) then delta = (this%lon_range%max - this%lon_range%min) / this%im_world - min_coord = this%lon_range%min + min_coord = this%lon_range%min max_coord = this%lon_range%max else delta = 360.d0 / this%im_world @@ -732,11 +670,11 @@ subroutine initialize_from_file_metadata(this, file_metadata, unusable, force_fi integer :: i logical :: hasLon, hasLat, hasLongitude, hasLatitude, hasLev,hasLevel,regLat,regLon real(kind=REAL64) :: del12,delij - + integer :: i_min, i_max real(kind=REAL64) :: d_lat, d_lat_temp, extrap_lat logical :: is_valid, use_file_coords, compute_lons, compute_lats - + _UNUSED_DUMMY(unusable) if (present(force_file_coordinates)) then @@ -747,7 +685,7 @@ subroutine initialize_from_file_metadata(this, file_metadata, unusable, force_fi ! Cannot assume that lats and lons are evenly spaced this%is_regular = .false. - + associate (im => this%im_world, jm => this%jm_world, lm => this%lm) lon_name = 'lon' hasLon = file_metadata%has_dimension(lon_name) @@ -757,7 +695,7 @@ subroutine initialize_from_file_metadata(this, file_metadata, unusable, force_fi else lon_name = 'longitude' hasLongitude = file_metadata%has_dimension(lon_name) - if (hasLongitude) then + if (hasLongitude) then im = file_metadata%get_dimension(lon_name, rc=status) _VERIFY(status) else @@ -772,7 +710,7 @@ subroutine initialize_from_file_metadata(this, file_metadata, unusable, force_fi else lat_name = 'latitude' hasLatitude = file_metadata%has_dimension(lat_name) - if (hasLatitude) then + if (hasLatitude) then jm = file_metadata%get_dimension(lat_name, rc=status) _VERIFY(status) else @@ -793,11 +731,11 @@ subroutine initialize_from_file_metadata(this, file_metadata, unusable, force_fi lm = file_metadata%get_dimension(lev_name,rc=status) _VERIFY(status) end if - end if - + end if + ! TODO: if 'lat' and 'lon' are not present then ! assume ... pole/dateline are ? - + ! TODO: check radians vs degrees. Assume degrees for now. @@ -865,12 +803,12 @@ subroutine initialize_from_file_metadata(this, file_metadata, unusable, force_fi end if end if end if - + ! Corners are the midpoints of centers (and extrapolated at the ! poles for lats.) allocate(this%lon_corners(im+1), this%lat_corners(jm+1)) - + this%lon_corners(1) = (this%lon_centers(im) + this%lon_centers(1))/2 - 180 this%lon_corners(2:im) = (this%lon_centers(1:im-1) + this%lon_centers(2:im))/2 this%lon_corners(im+1) = (this%lon_centers(im) + this%lon_centers(1))/2 + 180 @@ -892,7 +830,7 @@ subroutine initialize_from_file_metadata(this, file_metadata, unusable, force_fi this%lat_corners(1) = this%lat_centers(1) - (this%lat_centers(2)-this%lat_centers(1))/2 this%lat_corners(2:jm) = (this%lat_centers(1:jm-1) + this%lat_centers(2:jm))/2 this%lat_corners(jm+1) = this%lat_centers(jm) - (this%lat_centers(jm-1)-this%lat_centers(jm))/2 - + if (abs(this%lat_centers(1) + 90) < 1000*epsilon(1.0)) then this%pole = 'PC' else if (abs(this%lat_corners(1) + 90) < 1000*epsilon(1.0)) then @@ -928,10 +866,10 @@ subroutine initialize_from_file_metadata(this, file_metadata, unusable, force_fi else compute_lons=.false. compute_lats=.false. - if (regLon .and. (this%dateline.ne.'XY')) then + if (regLon .and. (this%dateline.ne.'XY')) then compute_lons=.true. end if - if (regLat .and. (this%pole.ne.'XY')) then + if (regLat .and. (this%pole.ne.'XY')) then compute_lats=.true. end if if (compute_lons .and. compute_lats) then @@ -959,7 +897,7 @@ subroutine initialize_from_file_metadata(this, file_metadata, unusable, force_fi end if end associate - + call this%make_arbitrary_decomposition(this%nx, this%ny, rc=status) _VERIFY(status) @@ -969,7 +907,7 @@ subroutine initialize_from_file_metadata(this, file_metadata, unusable, force_fi allocate(this%jms(0:this%ny-1)) call MAPL_DecomposeDim(this%im_world, this%ims, this%nx, min_DE_extent=2) call MAPL_DecomposeDim(this%jm_world, this%jms, this%ny, min_DE_extent=2) - + call this%check_and_fill_consistency(rc=status) _VERIFY(status) @@ -995,7 +933,7 @@ subroutine initialize_from_config_with_prefix(this, config, prefix, unusable, rc call ESMF_VmGetCurrent(VM, rc=status) _VERIFY(status) - + this%is_regular = .true. call ESMF_ConfigGetAttribute(config, tmp, label=prefix//'GRIDNAME:', default=MAPL_GRID_NAME_DEFAULT) this%grid_name = trim(tmp) @@ -1404,7 +1342,7 @@ subroutine initialize_from_esmf_distGrid(this, dist_grid, lon_array, lat_array, ! the code below is kluge to return DE/DC wheither or not the file lons are -180 to 180 or 0 360 ! it detects whether the first longitudes which are cell centers - ! If first longitude is 0 or -180 (DC) it is dateline center in that 0 or -180 is + ! If first longitude is 0 or -180 (DC) it is dateline center in that 0 or -180 is ! in the center of a grid cell. ! or shifted by half a grid box (DE) so 0 or -180 is the edge of a cell ! really should have 4 options dateline edge (DE), dateline center(DC) @@ -1439,7 +1377,7 @@ subroutine initialize_from_esmf_distGrid(this, dist_grid, lon_array, lat_array, nx_guess = nint(sqrt(real(nPet))) do nx = nx_guess,1,-1 - ny=nPet/nx + ny=nPet/nx if (nx*ny==nPet) then call MAPL_ConfigSetAttribute(config, nx, 'NX:') call MAPL_ConfigSetAttribute(config, ny, 'NY:') @@ -1514,7 +1452,7 @@ function physical_params_are_equal(this, a) result(equal) end if else equal = & - & all(a%lon_centers == this%lon_centers) .and. & + & all(a%lon_centers == this%lon_centers) .and. & & all(a%lon_corners == this%lon_corners) .and. & & all(a%lat_centers == this%lat_centers) .and. & & all(a%lat_corners == this%lat_corners) @@ -1612,7 +1550,7 @@ function generate_new_decomp(im,nd) result(n) integer, intent(in) :: im, nd integer :: n logical :: canNotDecomp - + canNotDecomp = .true. n = nd do while(canNotDecomp) @@ -1623,7 +1561,7 @@ function generate_new_decomp(im,nd) result(n) end if enddo end function generate_new_decomp - + subroutine init_halo(this, unusable, rc) class (LatLonGridFactory), target, intent(inout) :: this class (KeywordEnforcer), optional, intent(in) :: unusable @@ -1659,7 +1597,7 @@ subroutine init_halo(this, unusable, rc) this%py = pet / this%nx this%is_halo_initialized = .true. - + _RETURN(_SUCCESS) end subroutine init_halo @@ -1688,7 +1626,7 @@ subroutine halo(this, array, unusable, halo_width, rc) call this%init_halo(rc=status) _VERIFY(status) end if - + associate (nx => this%nx, ny => this% ny, px => this%px, py => this%py) ! Nearest neighbors processor' ids pet_north = get_pet(px, py+1, nx, ny) @@ -1729,7 +1667,7 @@ subroutine fill_north(array, rc) integer :: len, last - last = size(array,2)-1 + last = size(array,2)-1 len = size(array,1) call MAPL_CommsSendRecv(this%layout, & @@ -1754,7 +1692,7 @@ subroutine fill_south(array, rc) integer :: len, last - last = size(array,2)-1 + last = size(array,2)-1 len = size(array,1) call MAPL_CommsSendRecv(this%layout, & @@ -1780,7 +1718,7 @@ subroutine fill_east(array, rc) integer :: len, last - last = size(array,2)-1 + last = size(array,2)-1 len = size(array,1) call MAPL_CommsSendRecv(this%layout, & @@ -1826,7 +1764,7 @@ subroutine append_metadata(this, metadata) type (Variable) :: v real(kind=REAL64), allocatable :: temp_coords(:) - + ! Horizontal grid dimensions call metadata%add_dimension('lon', this%im_world) call metadata%add_dimension('lat', this%jm_world) @@ -1897,8 +1835,8 @@ subroutine generate_file_bounds(this,grid,local_start,global_start,global_count, allocate(local_start,source=[i1,j1]) allocate(global_start,source=[1,1]) allocate(global_count,source=[global_dim(1),global_dim(2)]) - - _RETURN(_SUCCESS) + + _RETURN(_SUCCESS) end subroutine generate_file_bounds @@ -1929,7 +1867,7 @@ function generate_file_reference2D(this,fpointer) result(ref) _UNUSED_DUMMY(this) ref = ArrayReference(fpointer) end function generate_file_reference2D - + function generate_file_reference3D(this,fpointer,metaData) result(ref) use pFIO type(ArrayReference) :: ref @@ -1939,6 +1877,6 @@ function generate_file_reference3D(this,fpointer,metaData) result(ref) _UNUSED_DUMMY(this) ref = ArrayReference(fpointer) end function generate_file_reference3D - + end module MAPL_LatLonGridFactoryMod diff --git a/base/MAPL_LocStreamMod.F90 b/base/MAPL_LocStreamMod.F90 index 4d9ecc14ede2..220eef8a748b 100644 --- a/base/MAPL_LocStreamMod.F90 +++ b/base/MAPL_LocStreamMod.F90 @@ -233,7 +233,7 @@ subroutine MAPL_LocStreamGet(LocStream, NT_LOCAL, nt_global, TILETYPE, TILEKIND, if (present(tilekind)) then PRINT *, 'IN LocStreamGet TILEKIND NO LONGER VALID ARGUMENT' - _ASSERT(.false.,'needs informative message') + _FAIL('needs informative message') ! tilekind => locstream%Ptr%Local_GeoLocation(:)%u end if @@ -1912,11 +1912,11 @@ subroutine MAPL_LocStreamTransformT2G (LocStream, OUTPUT, INPUT, MASK, SAMPLE, T end if if (computeVariance .and. usableTranspose) then - _ASSERT(.false.,"Can not compute variance and transpose in LocStream!") + _FAIL("Can not compute variance and transpose in LocStream!") end if if (computeVariance .and. uSample) then - _ASSERT(.false.,"Can not compute variance and sample in LocStream!") + _FAIL("Can not compute variance and sample in LocStream!") end if ! Compute weighted average over masked locations @@ -2123,7 +2123,7 @@ subroutine MAPL_LocStreamTransformG2T ( LocStream, OUTPUT, INPUT, & if (usableGLOBAL) then PRINT *, 'IN G2T GLOBAL NO LONGER VALID ARGUMENT' - _ASSERT(.FALSE.,'needs informative message') + _FAIL('needs informative message') else do N = 1, size(OUTPUT) if(usableMASK(N)) then diff --git a/base/MAPL_NewArthParser.F90 b/base/MAPL_NewArthParser.F90 index 9b7a8e13a054..d714397803f5 100755 --- a/base/MAPL_NewArthParser.F90 +++ b/base/MAPL_NewArthParser.F90 @@ -55,11 +55,13 @@ MODULE MAPL_NewArthParserMod use MAPL_BaseMod use MAPL_CommsMod use MAPL_ExceptionHandling + use gFTL_StringVector IMPLICIT NONE !------- -------- --------- --------- --------- --------- --------- --------- ------- PRIVATE + public :: parser_variables_in_expression PUBLIC :: MAPL_StateEval PUBLIC :: CheckSyntax PUBLIC :: RealNum @@ -182,7 +184,7 @@ subroutine MAPL_StateEval(state,expression,field,rc) isConformal = CheckIfConformal(field,state_field,rc=status) _VERIFY(STATUS) if (.not.isConformal) then - _ASSERT(.FALSE.,'needs informative message') + _FAIL('needs informative message') end if end if end do @@ -742,6 +744,125 @@ SUBROUTINE CopyScalarToField(ptrs,rn,rc) END SUBROUTINE CopyScalarToField ! + function parser_variables_in_expression (FuncStr,rc) result(variables_in_expression) + !----- -------- --------- --------- --------- --------- --------- --------- ------- + ! Check syntax of function string, returns 0 if syntax is ok + !----- -------- --------- --------- --------- --------- --------- --------- ------- + IMPLICIT NONE + type(StringVector) :: variables_in_expression + CHARACTER (LEN=*), INTENT(in) :: FuncStr ! Original function string + INTEGER, OPTIONAL :: rc + INTEGER :: n + CHARACTER (LEN=1) :: c + REAL :: r + LOGICAL :: err + INTEGER :: ParCnt, & ! Parenthesis counter + j,ib,in,lFunc + LOGICAL :: isUndef + character(len=ESMF_MAXPATHLEN) :: func + integer, allocatable :: ipos(:) + character(len=ESMF_MAXSTR), parameter :: IAm="CheckSyntax" + !----- -------- --------- --------- --------- --------- --------- --------- ------- + Func = FuncStr ! Local copy of function string + ALLOCATE (ipos(LEN_TRIM(FuncStr))) + CALL Replace ('**','^ ',Func) ! Exponent into 1-Char. format + CALL RemoveSpaces (Func,ipos) + j = 1 + ParCnt = 0 + lFunc = LEN_TRIM(Func) + step: DO + IF (j > lFunc) CALL ParseErrMsg (j, FuncStr, ipos) + c = Func(j:j) + !-- -------- --------- --------- --------- --------- --------- --------- ------- + ! Check for valid operand (must appear) + !-- -------- --------- --------- --------- --------- --------- --------- ------- + IF (c == '-' .OR. c == '+') THEN ! Check for leading - or + + j = j+1 + IF (j > lFunc) THEN + _FAIL('Missing operand in '//trim(funcstr)) + END IF + c = Func(j:j) + IF (ANY(c == Ops)) THEN + _FAIL('Multiple operators in '//trim(funcstr)) + END IF + END IF + n = MathFunctionIndex (Func(j:)) + IF (n > 0) THEN ! Check for math function + j = j+LEN_TRIM(Funcs(n)) + IF (j > lFunc) THEN + _FAIL('Missing function argument in '//trim(funcstr)) + END IF + c = Func(j:j) + IF (c /= '(') THEN + _FAIL('Missing opening parenthesis in '//trim(funcstr)) + END IF + END IF + IF (c == '(') THEN ! Check for opening parenthesis + ParCnt = ParCnt+1 + j = j+1 + CYCLE step + END IF + IF (SCAN(c,'0123456789.') > 0) THEN ! Check for number + r = RealNum (Func(j:),ib,in,err) + IF (err) THEN + _FAIL('Invalid number format: '//Func(j+ib-1:j+in-2)) + END IF + j = j+in-1 + IF (j > lFunc) EXIT + c = Func(j:j) + ELSE ! Check for variable + isUndef = checkUndef(Func(j:),ib,in) + if (isUndef) then + j = j+in-1 + IF (j> lFunc) EXIT + c = Func(j:j) + else + call GetVariables (Func(j:),ib,in) + call variables_in_expression%push_back(Func(j+ib-1:j+in-2)) + j = j+in-1 + IF (j > lFunc) EXIT + c = Func(j:j) + end if + END IF + DO WHILE (c == ')') ! Check for closing parenthesis + ParCnt = ParCnt-1 + IF (ParCnt < 0) THEN + _FAIL('Mismatched parenthesis in '//trim(funcstr)) + END IF + IF (Func(j-1:j-1) == '(') THEN + _FAIL('Empty parentheses in '//trim(funcstr)) + END IF + j = j+1 + IF (j > lFunc) EXIT + c = Func(j:j) + END DO + !-- -------- --------- --------- --------- --------- --------- --------- ------- + ! Now, we have a legal operand: A legal operator or end of string must follow + !-- -------- --------- --------- --------- --------- --------- --------- ------- + IF (j > lFunc) EXIT + IF (ANY(c == Ops)) THEN ! Check for multiple operators + IF (j+1 > lFunc) THEN + _FAIL('needs informative message') + END IF + IF (ANY(Func(j+1:j+1) == Ops)) THEN + _FAIL('Multiple operators in '//trim(funcstr)) + END IF + ELSE ! Check for next operand + _FAIL('Missing operator in '//trim(funcstr)) + END IF + !-- -------- --------- --------- --------- --------- --------- --------- ------- + ! Now, we have an operand and an operator: the next loop will check for another + ! operand (must appear) + !-- -------- --------- --------- --------- --------- --------- --------- ------- + j = j+1 + END DO step + IF (ParCnt > 0) THEN + _FAIL('Missing ) '//trim(funcstr)) + END IF + DEALLOCATE(ipos) + _RETURN(ESMF_SUCCESS) + end function + SUBROUTINE CheckSyntax (FuncStr,Var,needed,ExtVar,rc) !----- -------- --------- --------- --------- --------- --------- --------- ------- ! Check syntax of function string, returns 0 if syntax is ok @@ -780,26 +901,22 @@ SUBROUTINE CheckSyntax (FuncStr,Var,needed,ExtVar,rc) IF (c == '-' .OR. c == '+') THEN ! Check for leading - or + j = j+1 IF (j > lFunc) THEN - CALL ParseErrMsg (j, FuncStr, ipos, 'Missing operand') - _ASSERT(.FALSE.,'needs informative message') + _FAIL('Missing operand in '//trim(funcstr)) END IF c = Func(j:j) IF (ANY(c == Ops)) THEN - CALL ParseErrMsg (j, FuncStr, ipos, 'Multiple operators') - _ASSERT(.FALSE.,'needs informative message') + _FAIL('Multiple operators in '//trim(funcstr)) END IF END IF n = MathFunctionIndex (Func(j:)) IF (n > 0) THEN ! Check for math function j = j+LEN_TRIM(Funcs(n)) IF (j > lFunc) THEN - CALL ParseErrMsg (j, FuncStr, ipos, 'Missing function argument') - _ASSERT(.FALSE.,'needs informative message') + _FAIL('Missing function argument in '//trim(funcStr)) END IF c = Func(j:j) IF (c /= '(') THEN - CALL ParseErrMsg (j, FuncStr, ipos, 'Missing opening parenthesis') - _ASSERT(.FALSE.,'needs informative message') + _FAIL('Missing opening parenthesis in '//trim(funcstr)) END IF END IF IF (c == '(') THEN ! Check for opening parenthesis @@ -810,8 +927,7 @@ SUBROUTINE CheckSyntax (FuncStr,Var,needed,ExtVar,rc) IF (SCAN(c,'0123456789.') > 0) THEN ! Check for number r = RealNum (Func(j:),ib,in,err) IF (err) THEN - CALL ParseErrMsg (j, FuncStr, ipos, 'Invalid number format: '//Func(j+ib-1:j+in-2)) - _ASSERT(.FALSE.,'needs informative message') + _FAIL('Invalid number format: '//Func(j+ib-1:j+in-2)) END IF j = j+in-1 IF (j > lFunc) EXIT @@ -829,8 +945,7 @@ SUBROUTINE CheckSyntax (FuncStr,Var,needed,ExtVar,rc) IF (present(ExtVar)) then ExtVar = trim(ExtVar)//Func(j+ib-1:j+in-2)//"," ELSE - CALL ParseErrMsg (j, FuncStr, ipos, 'Invalid element: '//Func(j+ib-1:j+in-2)) - _ASSERT(.FALSE.,'needs informative message') + _FAIL('Invalid element: '//Func(j+ib-1:j+in-2)) ENDIF END IF j = j+in-1 @@ -841,12 +956,10 @@ SUBROUTINE CheckSyntax (FuncStr,Var,needed,ExtVar,rc) DO WHILE (c == ')') ! Check for closing parenthesis ParCnt = ParCnt-1 IF (ParCnt < 0) THEN - CALL ParseErrMsg (j, FuncStr, ipos, 'Mismatched parenthesis') - _ASSERT(.FALSE.,'needs informative message') + _FAIL('Mismatched parenthesis in '//trim(funcStr)) END IF IF (Func(j-1:j-1) == '(') THEN - CALL ParseErrMsg (j-1, FuncStr, ipos, 'Empty parentheses') - _ASSERT(.FALSE.,'needs informative message') + _FAIL('Empty paraentheses '//trim(funcstr)) END IF j = j+1 IF (j > lFunc) EXIT @@ -858,16 +971,13 @@ SUBROUTINE CheckSyntax (FuncStr,Var,needed,ExtVar,rc) IF (j > lFunc) EXIT IF (ANY(c == Ops)) THEN ! Check for multiple operators IF (j+1 > lFunc) THEN - CALL ParseErrMsg (j, FuncStr, ipos) - _ASSERT(.FALSE.,'needs informative message') + _FAIL('needs informative message') END IF IF (ANY(Func(j+1:j+1) == Ops)) THEN - CALL ParseErrMsg (j+1, FuncStr, ipos, 'Multiple operators') - _ASSERT(.FALSE.,'needs informative message') + _FAIL('Multiple operatos in '//trim(Funcstr)) END IF ELSE ! Check for next operand - CALL ParseErrMsg (j, FuncStr, ipos, 'Missing operator') - _ASSERT(.FALSE.,'needs informative message') + _FAIL('Missing operator in '//trim(funcstr)) END IF !-- -------- --------- --------- --------- --------- --------- --------- ------- ! Now, we have an operand and an operator: the next loop will check for another @@ -876,8 +986,7 @@ SUBROUTINE CheckSyntax (FuncStr,Var,needed,ExtVar,rc) j = j+1 END DO step IF (ParCnt > 0) THEN - CALL ParseErrMsg (j, FuncStr, ipos, 'Missing )') - _ASSERT(.FALSE.,'needs informative message') + _FAIL('Missing ) in '//trim(funcstr)) END IF DEALLOCATE(ipos) _RETURN(ESMF_SUCCESS) @@ -945,6 +1054,29 @@ FUNCTION MathFunctionIndex (str) RESULT (n) END DO END FUNCTION MathFunctionIndex ! + subroutine GetVariables (str, ibegin, inext) + !----- -------- --------- --------- --------- --------- --------- --------- ------- + ! Return index of variable at begin of string str (returns 0 if no variable found) + !----- -------- --------- --------- --------- --------- --------- --------- ------- + IMPLICIT NONE + CHARACTER (LEN=*), INTENT(in) :: str ! String + INTEGER, INTENT(out) :: ibegin, & ! Start position of variable name + inext ! Position of character after name + INTEGER :: j,ib,in,lstr + !----- -------- --------- --------- --------- --------- --------- --------- ------- + lstr = LEN_TRIM(str) + IF (lstr > 0) THEN + DO ib=1,lstr ! Search for first character in str + IF (str(ib:ib) /= ' ') EXIT ! When lstr>0 at least 1 char in str + END DO + DO in=ib,lstr ! Search for name terminators + IF (SCAN(str(in:in),'+-*/^) ') > 0) EXIT + END DO + END IF + ibegin = ib + inext = in + end subroutine GetVariables + FUNCTION VariableIndex (str, Var, ibegin, inext) RESULT (n) !----- -------- --------- --------- --------- --------- --------- --------- ------- ! Return index of variable at begin of string str (returns 0 if no variable found) diff --git a/base/MAPL_SimpleBundleMod.F90 b/base/MAPL_SimpleBundleMod.F90 index 0c27e5ad715c..3e9ab23b9ad2 100644 --- a/base/MAPL_SimpleBundleMod.F90 +++ b/base/MAPL_SimpleBundleMod.F90 @@ -749,7 +749,8 @@ end subroutine MAPL_SimpleBundleDestroy ! Function MAPL_SimpleBundleRead (filename, bundle_name, grid, time, verbose, & - only_vars, expid, rc ) result (self) + only_vars, expid, voting, unusable, rc ) result (self) + use mapl_KeywordEnforcerMod ! !ARGUMENTS: @@ -762,6 +763,8 @@ Function MAPL_SimpleBundleRead (filename, bundle_name, grid, time, verbose, & logical, OPTIONAL, intent(in) :: verbose character(len=*), optional, intent(IN) :: only_vars character(len=*), optional, intent(IN) :: expid + class(KeywordEnforcer), optional, intent(in) :: unusable + logical, optional, intent(in) :: voting integer, OPTIONAL, intent(out) :: rc ! !DESCRIPTION: @@ -781,7 +784,7 @@ Function MAPL_SimpleBundleRead (filename, bundle_name, grid, time, verbose, & Bundle = ESMF_FieldBundleCreate ( name=bundle_name, __RC__ ) call ESMF_FieldBundleSet ( bundle, grid=Grid, __RC__ ) call MAPL_CFIORead ( filename, Time, Bundle, verbose=verbose, & - ONLY_VARS=only_vars, expid=expid, __RC__ ) + ONLY_VARS=only_vars, expid=expid, voting=voting, __RC__ ) self = MAPL_SimpleBundleCreate ( Bundle, __RC__ ) self%bundleAlloc = .true. diff --git a/base/MAPL_TimeMethods.F90 b/base/MAPL_TimeMethods.F90 index c14719ea67b5..4dd8f5a2c832 100644 --- a/base/MAPL_TimeMethods.F90 +++ b/base/MAPL_TimeMethods.F90 @@ -145,7 +145,7 @@ function define_time_variable(this,rc) result(v) end if time_increment = this%frequency/86400 case default - _ASSERT(.false., 'Not supported yet') + _FAIL( 'Not supported yet') end select call this%tvec%clear() @@ -265,7 +265,7 @@ function get_start_time(this,metadata,rc) result(startTime) startTime = parse_time_string(units,rc=status) _VERIFY(status) class default - _ASSERT(.false.,'unsupported subclass for units') + _FAIL('unsupported subclass for units') end select @@ -296,7 +296,7 @@ function parse_time_string(timeUnits,rc) result(time) lastdash = index(TimeUnits, '-', BACK=.TRUE.) if (firstdash .LE. 0 .OR. lastdash .LE. 0) then - _ASSERT(.false.,'time string is not a valid format') + _FAIL('time string is not a valid format') endif ypos(2) = firstdash - 1 mpos(1) = firstdash + 1 diff --git a/base/MAPL_VerticalMethods.F90 b/base/MAPL_VerticalMethods.F90 index c15ffd466fb2..51568980250b 100644 --- a/base/MAPL_VerticalMethods.F90 +++ b/base/MAPL_VerticalMethods.F90 @@ -36,7 +36,7 @@ module MAPL_VerticalDataMod real, allocatable :: surface_level(:,:) real, allocatable :: ple3d(:,:,:) real, allocatable :: pl3d(:,:,:) - integer :: lm + integer :: lm = 0 integer :: regrid_type type(ESMF_Field) :: interp_var logical :: ascending @@ -402,7 +402,7 @@ subroutine append_vertical_metadata(this,metadata,bundle,posDown,rc) unGrdCoordCheck = .false. end if if ( unGrdUnitCheck .or. unGrdNameCheck .or. unGrdCoordCheck) then - _ASSERT(.false.,'Ungridded attributes for variables in collection do not match') + _FAIL('Ungridded attributes for variables in collection do not match') end if end if end do diff --git a/base/MAPL_sun_uc.F90 b/base/MAPL_sun_uc.F90 index 0773fe2cede3..f964b7d7f348 100644 --- a/base/MAPL_sun_uc.F90 +++ b/base/MAPL_sun_uc.F90 @@ -1047,7 +1047,7 @@ subroutine SOLAR_ARR_INT(LONS, LATS, ORBIT, ZTH, SLR, INTV, CLOCK, & ! Begin - _ASSERT(.FALSE.," pmn: this routine is not up to date, is it even used anywhere?") + _FAIL(" pmn: this routine is not up to date, is it even used anywhere?") call ESMF_ArrayGet(LONS, RANK=RANK, RC=STATUS) _VERIFY(STATUS) @@ -1998,7 +1998,7 @@ subroutine MAPL_SunGetSolarConstantByYearDoY(year,dayofyear,SC,HK, rc) HK(8) = ChouBand8(i1)*(1.-F) + ChouBand8(i2)*F _ASSERT(abs(1.0-sum(HK))<1.e-4,'Chou Solar band weightings do not sum to unity!') else - _ASSERT(.false.,'HK: Solar band weightings only available for Chou') + _FAIL('HK: Solar band weightings only available for Chou') endif end if @@ -2080,7 +2080,7 @@ subroutine MAPL_SunGetSolarConstantFromNetcdfFile(CLOCK,fileName,SC,HK,MESOPHOT, if (STATUS /= NF90_NOERR) then write (*,*) trim(Iam)//': Error opening file ', trim(fileName), status write (*,*) nf90_strerror(status) - _ASSERT(.false.,'needs informative message') + _FAIL('needs informative message') end if ! Read in dimensions @@ -2090,14 +2090,14 @@ subroutine MAPL_SunGetSolarConstantFromNetcdfFile(CLOCK,fileName,SC,HK,MESOPHOT, if (STATUS /= NF90_NOERR) then write (*,*) trim(Iam)//': Error getting ndate dimid', status write (*,*) nf90_strerror(status) - _ASSERT(.false.,'needs informative message') + _FAIL('needs informative message') end if status = nf90_inquire_dimension(ncid, dimid_ndate, len = ndate) if (STATUS /= NF90_NOERR) then write (*,*) trim(Iam)//': Error getting ndate length', status write (*,*) nf90_strerror(status) - _ASSERT(.false.,'needs informative message') + _FAIL('needs informative message') end if if (present(HK)) then @@ -2105,14 +2105,14 @@ subroutine MAPL_SunGetSolarConstantFromNetcdfFile(CLOCK,fileName,SC,HK,MESOPHOT, if (STATUS /= NF90_NOERR) then write (*,*) trim(Iam)//': Error getting nbin_sorad dimid', status write (*,*) nf90_strerror(status) - _ASSERT(.false.,'needs informative message') + _FAIL('needs informative message') end if status = nf90_inquire_dimension(ncid, dimid_nbin_sorad, len = nbin_sorad) if (STATUS /= NF90_NOERR) then write (*,*) trim(Iam)//': Error getting nbin_sorad length', status write (*,*) nf90_strerror(status) - _ASSERT(.false.,'needs informative message') + _FAIL('needs informative message') end if end if @@ -2121,14 +2121,14 @@ subroutine MAPL_SunGetSolarConstantFromNetcdfFile(CLOCK,fileName,SC,HK,MESOPHOT, if (STATUS /= NF90_NOERR) then write (*,*) trim(Iam)//': Error getting nbin_meso_phot dimid', status write (*,*) nf90_strerror(status) - _ASSERT(.false.,'needs informative message') + _FAIL('needs informative message') end if status = nf90_inquire_dimension(ncid, dimid_nbin_meso_phot, len = nbin_meso_phot) if (STATUS /= NF90_NOERR) then write (*,*) trim(Iam)//': Error getting nbin_meso_phot length', status write (*,*) nf90_strerror(status) - _ASSERT(.false.,'needs informative message') + _FAIL('needs informative message') end if end if @@ -2137,14 +2137,14 @@ subroutine MAPL_SunGetSolarConstantFromNetcdfFile(CLOCK,fileName,SC,HK,MESOPHOT, if (STATUS /= NF90_NOERR) then write (*,*) trim(Iam)//': Error getting nbin_jcalc4 dimid', status write (*,*) nf90_strerror(status) - _ASSERT(.false.,'needs informative message') + _FAIL('needs informative message') end if status = nf90_inquire_dimension(ncid, dimid_nbin_jcalc4, len = nbin_jcalc4) if (STATUS /= NF90_NOERR) then write (*,*) trim(Iam)//': Error getting nbin_jcalc4 length', status write (*,*) nf90_strerror(status) - _ASSERT(.false.,'needs informative message') + _FAIL('needs informative message') end if end if @@ -2182,14 +2182,14 @@ subroutine MAPL_SunGetSolarConstantFromNetcdfFile(CLOCK,fileName,SC,HK,MESOPHOT, if (STATUS /= NF90_NOERR) then write (*,*) trim(Iam)//': Error getting date_year varid', status write (*,*) nf90_strerror(status) - _ASSERT(.false.,'needs informative message') + _FAIL('needs informative message') end if status = nf90_get_var(ncid, varid_date_year, date_year) if (STATUS /= NF90_NOERR) then write (*,*) trim(Iam)//': Error getting date_year variable', status write (*,*) nf90_strerror(status) - _ASSERT(.false.,'needs informative message') + _FAIL('needs informative message') end if ! Read in date_month @@ -2199,14 +2199,14 @@ subroutine MAPL_SunGetSolarConstantFromNetcdfFile(CLOCK,fileName,SC,HK,MESOPHOT, if (STATUS /= NF90_NOERR) then write (*,*) trim(Iam)//': Error getting date_month varid', status write (*,*) nf90_strerror(status) - _ASSERT(.false.,'needs informative message') + _FAIL('needs informative message') end if status = nf90_get_var(ncid, varid_date_month, date_month) if (STATUS /= NF90_NOERR) then write (*,*) trim(Iam)//': Error getting date_month variable', status write (*,*) nf90_strerror(status) - _ASSERT(.false.,'needs informative message') + _FAIL('needs informative message') end if ! Read in tsi @@ -2216,14 +2216,14 @@ subroutine MAPL_SunGetSolarConstantFromNetcdfFile(CLOCK,fileName,SC,HK,MESOPHOT, if (STATUS /= NF90_NOERR) then write (*,*) trim(Iam)//': Error getting tsi varid', status write (*,*) nf90_strerror(status) - _ASSERT(.false.,'needs informative message') + _FAIL('needs informative message') end if status = nf90_get_var(ncid, varid_tsi, tsi) if (STATUS /= NF90_NOERR) then write (*,*) trim(Iam)//': Error getting tsi variable', status write (*,*) nf90_strerror(status) - _ASSERT(.false.,'needs informative message') + _FAIL('needs informative message') end if ! Read in coef_sorad @@ -2235,14 +2235,14 @@ subroutine MAPL_SunGetSolarConstantFromNetcdfFile(CLOCK,fileName,SC,HK,MESOPHOT, if (STATUS /= NF90_NOERR) then write (*,*) trim(Iam)//': Error getting coef_sorad varid', status write (*,*) nf90_strerror(status) - _ASSERT(.false.,'needs informative message') + _FAIL('needs informative message') end if status = nf90_get_var(ncid, varid_coef_sorad, coef_sorad) if (STATUS /= NF90_NOERR) then write (*,*) trim(Iam)//': Error getting coef_sorad variable', status write (*,*) nf90_strerror(status) - _ASSERT(.false.,'needs informative message') + _FAIL('needs informative message') end if end if @@ -2256,14 +2256,14 @@ subroutine MAPL_SunGetSolarConstantFromNetcdfFile(CLOCK,fileName,SC,HK,MESOPHOT, if (STATUS /= NF90_NOERR) then write (*,*) trim(Iam)//': Error getting coef_meso_phot varid', status write (*,*) nf90_strerror(status) - _ASSERT(.false.,'needs informative message') + _FAIL('needs informative message') end if status = nf90_get_var(ncid, varid_coef_meso_phot, coef_meso_phot) if (STATUS /= NF90_NOERR) then write (*,*) trim(Iam)//': Error getting coef_meso_phot variable', status write (*,*) nf90_strerror(status) - _ASSERT(.false.,'needs informative message') + _FAIL('needs informative message') end if end if @@ -2277,14 +2277,14 @@ subroutine MAPL_SunGetSolarConstantFromNetcdfFile(CLOCK,fileName,SC,HK,MESOPHOT, if (STATUS /= NF90_NOERR) then write (*,*) trim(Iam)//': Error getting coef_jcalc4 varid', status write (*,*) nf90_strerror(status) - _ASSERT(.false.,'needs informative message') + _FAIL('needs informative message') end if status = nf90_get_var(ncid, varid_coef_jcalc4, coef_jcalc4) if (STATUS /= NF90_NOERR) then write (*,*) trim(Iam)//': Error getting coef_jcalc4 variable', status write (*,*) nf90_strerror(status) - _ASSERT(.false.,'needs informative message') + _FAIL('needs informative message') end if end if @@ -2475,54 +2475,45 @@ subroutine MAPL_SunGetSolarConstantFromNRLFile(CLOCK,filename_in,SC,MG,SB,Persis CREATE_TABLE: if (.not. TableCreated) then - ! Open the file - ! ------------- - - filename = trim(filename_in) - - ! Does the file exist? - inquire( FILE=filename, EXIST=found ) - _ASSERT( found ,'Could not find NRL data file '//trim(filename) ) - - UNIT = GETFILE(filename, DO_OPEN=0, form="formatted", rc=status) - _VERIFY(STATUS) - - open(unit=unit, file=filename) + ! First we open the file on root to get the + ! number of lines so we can allocate our tables + ! --------------------------------------------- if (amIRoot) then + ! Open the file + ! ------------- + filename = trim(filename_in) + open(newunit=unit, file=filename, form="formatted", status="old", iostat=status) + _ASSERT(status==0,'Could not find NRL data file '// trim(filename )) + ! Determine length of file ! ------------------------ - call lgr%debug("Scanning the Solar Table to determine number of data points") - numlines = num_lines_in_file(UNIT) - call lgr%debug("Solar Table Data Points: %i0", numlines) - ! Allocate our arrays - ! ------------------- + end if - allocate(yearTable(numlines), source=0, stat=status) - _VERIFY(STATUS) + ! Broadcast the number of lines + ! ----------------------------- + call MAPL_CommsBcast(vm, DATA=numlines, N=1, ROOT=0, _RC) - allocate(doyTable(numlines), source=0, stat=status) - _VERIFY(STATUS) + ! Allocate our arrays on all processes + ! ------------------------------------ - allocate(tsi(numlines), source=0.0, stat=status) - _VERIFY(STATUS) + allocate(yearTable(numlines), source=0, _STAT) + allocate(doyTable(numlines), source=0, _STAT) + allocate(tsi(numlines), source=0.0, _STAT) + allocate(mgindex(numlines), source=0.0, _STAT) + allocate(sbindex(numlines), source=0.0, _STAT) - allocate(mgindex(numlines), source=0.0, stat=status) - _VERIFY(STATUS) + ! Back to root to read in the values + ! ---------------------------------- - allocate(sbindex(numlines), source=0.0, stat=status) - _VERIFY(STATUS) - - ! Read in arrays - ! -------------- + if (amIRoot) then call lgr%debug("Reading the Solar Table") - i = 1 do read(unit,'(A)',iostat=stat) line @@ -2536,51 +2527,75 @@ subroutine MAPL_SunGetSolarConstantFromNRLFile(CLOCK,filename_in,SC,MG,SB,Persis ! Belt and suspenders check that all data was read _ASSERT(size(yearTable) == numlines,"Inconsistency in NRL number of lines") + close(unit, _IOSTAT) + end if - ! Close the file - ! -------------- + ! Broadcast the tables + ! -------------------- - call FREE_FILE(UNIT) + call MAPL_CommsBcast(vm, DATA=yearTable, N=numlines, ROOT=0, _RC) + call MAPL_CommsBcast(vm, DATA=doyTable, N=numlines, ROOT=0, _RC) + call MAPL_CommsBcast(vm, DATA=tsi, N=numlines, ROOT=0, _RC) + call MAPL_CommsBcast(vm, DATA=mgindex, N=numlines, ROOT=0, _RC) + call MAPL_CommsBcast(vm, DATA=sbindex, N=numlines, ROOT=0, _RC) TableCreated = .TRUE. end if CREATE_TABLE - ON_ROOT: if (amIRoot) then + ! Now we need to find the two bracketing days + ! ------------------------------------------- - ! Now we need to find the two bracketing days - ! ------------------------------------------- + ! Get current time + ! ---------------- + call ESMF_ClockGet(CLOCK, CURRTIME=currentTime, _RC) - ! Get current time - ! ---------------- - call ESMF_ClockGet(CLOCK, CURRTIME=currentTime, RC=STATUS) - _VERIFY(STATUS) + call ESMF_TimeGet( currentTime, YY = currentYear, & + MM = currentMon, & + DD = currentDay, & + dayOfYear = currentDOY, _RC) - call ESMF_TimeGet( currentTime, YY = currentYear, & - MM = currentMon, & - DD = currentDay, & - dayOfYear = currentDOY, & - RC = STATUS ) - _VERIFY(STATUS) + ! Test if current time is outside our file + ! ---------------------------------------- - ! Test if current time is outside our file - ! ---------------------------------------- + outOfTable = .FALSE. - outOfTable = .FALSE. + ! First is current year higher than last in file... + if ( currentYear > yearTable(numlines) ) then + outOfTable = .TRUE. + ! ...or if a partial year, are we near the end + else if ( currentYear == yearTable(numlines) .and. currentDOY >= doyTable(numlines)) then + outOfTable = .TRUE. + end if - ! First is current year higher than last in file... - if ( currentYear > yearTable(numlines) ) then - outOfTable = .TRUE. - ! ...or if a partial year, are we near the end - else if ( currentYear == yearTable(numlines) .and. currentDOY >= doyTable(numlines)) then - outOfTable = .TRUE. - end if + ! If we are out of the table... + ! ----------------------------- + + OUT_OF_TABLE: if ( outOfTable ) then + + PERSIST_SOLAR: if ( PersistSolar_ ) then + + ! If we are outOfTable and we have the PersistSolar + ! option we just use the last value in the table... + ! ------------------------------------------------- + + SC = tsi(numlines) + MG = mgindex(numlines) + SB = sbindex(numlines) + + call lgr%debug('Off the end of table, persisting last values') + call lgr%debug(' tsi at end of table: %F8.3', tsi(numlines)) + call lgr%debug(' mgindex at end of table: %F8.6', mgindex(numlines)) + call lgr%debug(' sbindex at end of table: %F9.4', sbindex(numlines)) - ! If we are out of the table and not persisting, we must - ! recenter our day to be based on the last complete Solar Cycle - ! ------------------------------------------------------------- - OUT_OF_TABLE_AND_CYCLE: if ( outOfTable .and. (.not. PersistSolar_) ) then + _RETURN(ESMF_SUCCESS) + + else + + ! If we are out of the table and not persisting, we must + ! recenter our day to be based on the last complete Solar Cycle + ! ------------------------------------------------------------- ! Create an ESMF_Time at start of Cycle 24 ! ---------------------------------------- @@ -2589,9 +2604,7 @@ subroutine MAPL_SunGetSolarConstantFromNRLFile(CLOCK,filename_in,SC,MG,SB,Persis DD = 1, & H = 12, & M = 00, & - S = 00, & - RC = STATUS ) - _VERIFY(STATUS) + S = 00, _RC) ! Create an ESMF_Time at start of Cycle 25 ! ---------------------------------------- @@ -2600,9 +2613,7 @@ subroutine MAPL_SunGetSolarConstantFromNRLFile(CLOCK,filename_in,SC,MG,SB,Persis DD = 1, & H = 12, & M = 00, & - S = 00, & - RC = STATUS ) - _VERIFY(STATUS) + S = 00, _RC) ! Create TimeInterval based on interval ! from start of latest Cycle 25 @@ -2631,126 +2642,86 @@ subroutine MAPL_SunGetSolarConstantFromNRLFile(CLOCK,filename_in,SC,MG,SB,Persis ! Get new currentYear, currentMon, currentDay ! ------------------------------------------- - call ESMF_TimeGet( currentTime, YY = currentYear, & - MM = currentMon, & - DD = currentDay, & - dayOfYear = currentDOY, & - RC = STATUS ) - _VERIFY(STATUS) - + call ESMF_TimeGet( currentTime, YY = currentYear, & + MM = currentMon, & + DD = currentDay, & + dayOfYear = currentDOY, _RC) - ! Debugging Prints - ! ---------------- call lgr%debug('Off the end of table, moving into last complete cycle') call lgr%debug(' Original Year-Mon-Day to Find: %i0.4~-%i0.2~-%i0.2', originalYear,originalMon,originalDay) call lgr%debug(' Original Day of Year: %i0', origDOY) call lgr%debug(' New Year-Mon-Day to Find: %i0.4~-%i0.2~-%i0.2', currentYear,currentMon,currentDay) call lgr%debug(' New Day of Year: %i0', currentDOY) - end if OUT_OF_TABLE_AND_CYCLE - - ! Create an ESMF_Time on noon of current day - ! ------------------------------------------ - call ESMF_TimeSet( noonCurrentDay, YY = currentYear, & - MM = currentMon, & - DD = currentDay, & - H = 12, & - M = 00, & - S = 00, & - RC = STATUS ) - _VERIFY(STATUS) - - ! Figure out bracketing days for interpolation - ! NOTE: nextNoon is mainly for debugging purposes - ! ----------------------------------------------- - call ESMF_TimeIntervalSet(oneDayInterval, D=1, rc=status) - if (currentTime <= noonCurrentDay) then - prevNoon = noonCurrentDay - oneDayInterval - nextNoon = noonCurrentDay - else - prevNoon = noonCurrentDay - nextNoon = noonCurrentDay + oneDayInterval - end if + end if PERSIST_SOLAR - ! Get the DOYs - ! ------------ - call ESMF_TimeGet( prevNoon, YY = prevNoonYear, dayOfYear = prevDOY, rc = status ) - call ESMF_TimeGet( nextNoon, YY = nextNoonYear, dayOfYear = nextDOY, rc = status ) + end if OUT_OF_TABLE - ! Our interpolation factor is based of when we are compared to the next noon - ! -------------------------------------------------------------------------- - intToNextNoon = nextNoon-currentTime - - ! The FAC for interpolating is just the real version - ! of the size of the timeinterval to the next noon - ! -------------------------------------------------- - call ESMF_TimeIntervalGet(intToNextNoon, d_r8=days_r8, rc=STATUS) - _VERIFY(STATUS) - FAC = real(days_r8) - - ! Use our find_file_index function to get the index for previous noon - ! ------------------------------------------------------------------- - INDX1 = find_file_index(numlines, yearTable, prevNoonYear, prevDOY) - INDX2 = INDX1 + 1 + ! Create an ESMF_Time on noon of current day + ! ------------------------------------------ + call ESMF_TimeSet( noonCurrentDay, YY = currentYear, & + MM = currentMon, & + DD = currentDay, & + H = 12, & + M = 00, & + S = 00, _RC) + + ! Figure out bracketing days for interpolation + ! NOTE: nextNoon is mainly for debugging purposes + ! ----------------------------------------------- + call ESMF_TimeIntervalSet(oneDayInterval, D=1, _RC) + if (currentTime <= noonCurrentDay) then + prevNoon = noonCurrentDay - oneDayInterval + nextNoon = noonCurrentDay + else + prevNoon = noonCurrentDay + nextNoon = noonCurrentDay + oneDayInterval + end if - ! If we are outOfTable and we have the PersistSolar - ! option we just use the last value in the table... - ! ------------------------------------------------- - OUT_OF_TABLE_AND_PERSIST: if ( outOfTable .and. PersistSolar_) then + ! Get the DOYs + ! ------------ + call ESMF_TimeGet( prevNoon, YY = prevNoonYear, dayOfYear = prevDOY, _RC) + call ESMF_TimeGet( nextNoon, YY = nextNoonYear, dayOfYear = nextDOY, _RC) - SC = tsi(numlines) - MG = mgindex(numlines) - SB = sbindex(numlines) + ! Our interpolation factor is based of when we are compared to the next noon + ! -------------------------------------------------------------------------- + intToNextNoon = nextNoon-currentTime - ! Debugging Prints - ! ---------------- - call lgr%debug('Off the end of table, persisting last values') - call lgr%debug(' tsi at end of table: %F8.3', tsi(numlines)) - call lgr%debug(' mgindex at end of table: %F8.6', mgindex(numlines)) - call lgr%debug(' sbindex at end of table: %F9.4', sbindex(numlines)) + ! The FAC for interpolating is just the real version + ! of the size of the timeinterval to the next noon + ! -------------------------------------------------- + call ESMF_TimeIntervalGet(intToNextNoon, d_r8=days_r8, _RC) + FAC = real(days_r8) - ! Otherwise we interpolate to the table - ! ------------------------------------- - else + ! Use our find_file_index function to get the index for previous noon + ! ------------------------------------------------------------------- + INDX1 = find_file_index(numlines, yearTable, prevNoonYear, prevDOY) + INDX2 = INDX1 + 1 - ! Linear Interpolation to the given day-of-month - ! ---------------------------------------------- - - SC = tsi(INDX1)*FAC + tsi(INDX2)*(1.0-FAC) - MG = mgindex(INDX1)*FAC + mgindex(INDX2)*(1.0-FAC) - SB = sbindex(INDX1)*FAC + sbindex(INDX2)*(1.0-FAC) - - ! Debugging Prints - ! ---------------- - call lgr%debug(' First DOY to Find: %i3', prevDOY) - call lgr%debug(' file_index for date: %i6', INDX1) - call lgr%debug(' yearTable(date): %i4', yearTable(INDX1)) - call lgr%debug(' doyTable(date): %i3', doyTable(INDX1)) - call lgr%debug(' tsi(date): %f8.3', tsi(INDX1)) - call lgr%debug(' mgindex(date): %f8.6', mgindex(INDX1)) - call lgr%debug(' sbindex(date): %f9.4', sbindex(INDX1)) - - call lgr%debug(' Second DOY to Find: %i3', nextDOY) - call lgr%debug(' file_index for date: %i6', INDX2) - call lgr%debug(' yearTable(date): %i4', yearTable(INDX2)) - call lgr%debug(' doyTable(date): %i3', doyTable(INDX2)) - call lgr%debug(' tsi(date): %f8.3', tsi(INDX2)) - call lgr%debug(' mgindex(date): %f8.6', mgindex(INDX2)) - call lgr%debug(' sbindex(date): %f9.4', sbindex(INDX2)) - - call lgr%debug(' Interpolation Factor: %f8.6', FAC) - end if OUT_OF_TABLE_AND_PERSIST - end if ON_ROOT - - ! Broadcast the values - ! -------------------- + ! Linear Interpolation to the given day-of-month + ! ---------------------------------------------- - call MAPL_CommsBcast(vm, DATA=SC, N=1, ROOT=0, RC=status) - _VERIFY(STATUS) - call MAPL_CommsBcast(vm, DATA=MG, N=1, ROOT=0, RC=status) - _VERIFY(STATUS) - call MAPL_CommsBcast(vm, DATA=SB, N=1, ROOT=0, RC=status) - _VERIFY(STATUS) + SC = tsi(INDX1)*FAC + tsi(INDX2)*(1.0-FAC) + MG = mgindex(INDX1)*FAC + mgindex(INDX2)*(1.0-FAC) + SB = sbindex(INDX1)*FAC + sbindex(INDX2)*(1.0-FAC) + + call lgr%debug(' First DOY to Find: %i3', prevDOY) + call lgr%debug(' file_index for date: %i6', INDX1) + call lgr%debug(' yearTable(date): %i4', yearTable(INDX1)) + call lgr%debug(' doyTable(date): %i3', doyTable(INDX1)) + call lgr%debug(' tsi(date): %f8.3', tsi(INDX1)) + call lgr%debug(' mgindex(date): %f8.6', mgindex(INDX1)) + call lgr%debug(' sbindex(date): %f9.4', sbindex(INDX1)) + + call lgr%debug(' Second DOY to Find: %i3', nextDOY) + call lgr%debug(' file_index for date: %i6', INDX2) + call lgr%debug(' yearTable(date): %i4', yearTable(INDX2)) + call lgr%debug(' doyTable(date): %i3', doyTable(INDX2)) + call lgr%debug(' tsi(date): %f8.3', tsi(INDX2)) + call lgr%debug(' mgindex(date): %f8.6', mgindex(INDX2)) + call lgr%debug(' sbindex(date): %f9.4', sbindex(INDX2)) + + call lgr%debug(' Interpolation Factor: %f8.6', FAC) _RETURN(ESMF_SUCCESS) diff --git a/base/NCIO.F90 b/base/NCIO.F90 index 0480974a09e3..5868690ae01f 100644 --- a/base/NCIO.F90 +++ b/base/NCIO.F90 @@ -242,7 +242,7 @@ subroutine MAPL_FieldReadNCPar(formatter,name,FIELD, ARRDES, HomePE, RC) call ESMF_ArrayGet(array, localDE=0, farrayptr=var_4d, rc=status) _VERIFY(STATUS) if (.not.associated(var_4d)) then - _ASSERT(.false., "Cannot read unassociated variable") + _FAIL( "Cannot read unassociated variable") end if do L = 1,size(var_4d,3) @@ -254,10 +254,10 @@ subroutine MAPL_FieldReadNCPar(formatter,name,FIELD, ARRDES, HomePE, RC) end do end do else - _ASSERT(.false., "ERROR: unsupported RANK/KIND") + _FAIL( "ERROR: unsupported RANK/KIND") endif else - _ASSERT(.false., "ERROR: unsupported RANK") + _FAIL( "ERROR: unsupported RANK") endif _VERIFY(STATUS) @@ -381,7 +381,7 @@ subroutine MAPL_FieldWriteNCPar(formatter, name, FIELD, ARRDES, HomePE, oClients endif else - _ASSERT(.false., "Cannot write unassociated var-1d") + _FAIL( "Cannot write unassociated var-1d") end if else call ESMF_ArrayGet(array, localDE=0, farrayptr=vr8_1d, rc=status) @@ -422,7 +422,7 @@ subroutine MAPL_FieldWriteNCPar(formatter, name, FIELD, ARRDES, HomePE, oClients endif else - _ASSERT(.false., "Cannot write unassociated var8-1d") + _FAIL( "Cannot write unassociated var8-1d") end if endif else if (rank == 2) then @@ -458,7 +458,7 @@ subroutine MAPL_FieldWriteNCPar(formatter, name, FIELD, ARRDES, HomePE, oClients call MAPL_VarWrite(formatter, name, var_2d, arrdes=arrdes, oClients=oClients, rc=status) endif ! dims else - _ASSERT(.false., "Cannot write unassociated var-2d") + _FAIL( "Cannot write unassociated var-2d") endif ! associated else call ESMF_ArrayGet(array, localDE=0, farrayptr=vr8_2d, rc=status) @@ -491,7 +491,7 @@ subroutine MAPL_FieldWriteNCPar(formatter, name, FIELD, ARRDES, HomePE, oClients call MAPL_VarWrite(formatter, name, vr8_2d, arrdes=arrdes, oClients=oClients, rc=status) end if else - _ASSERT(.false., "Cannot write unassociated var8-2d") + _FAIL( "Cannot write unassociated var8-2d") end if endif else if (rank == 3) then @@ -532,7 +532,7 @@ subroutine MAPL_FieldWriteNCPar(formatter, name, FIELD, ARRDES, HomePE, oClients call MAPL_VarWrite(formatter, name, var_3d, arrdes=arrdes, oClients=oClients, rc=status) endif else - _ASSERT(.false., "Cannot write unassociated var-3d") + _FAIL( "Cannot write unassociated var-3d") end if else call ESMF_ArrayGet(array, localDE=0, farrayptr=vr8_3d, rc=status) @@ -570,25 +570,25 @@ subroutine MAPL_FieldWriteNCPar(formatter, name, FIELD, ARRDES, HomePE, oClients call MAPL_VarWrite(formatter, name, vr8_3d, arrdes=arrdes, oClients=oClients, rc=status) end if else - _ASSERT(.false., "Cannot write unassociated var8-3d") + _FAIL( "Cannot write unassociated var8-3d") end if endif else if (rank == 4) then if (DIMS == MAPL_DimsTileOnly .or. DIMS == MAPL_DimsTileTile) then - _ASSERT(.false., "Unsupported tile/ungrid variable") + _FAIL( "Unsupported tile/ungrid variable") end if if (tk == ESMF_TYPEKIND_R4) then call ESMF_ArrayGet(array, localDE=0, farrayptr=var_4d, rc=status) _VERIFY(STATUS) if (.not.associated(var_4d)) then - _ASSERT(.false., "Cannot write unassociated vars") + _FAIL( "Cannot write unassociated vars") end if call MAPL_VarWrite(formatter, name, var_4d, arrdes=arrdes, oClients=oClients, rc=status) else call ESMF_ArrayGet(array, localDE=0, farrayptr=vr8_4d, rc=status) _VERIFY(STATUS) if (.not.associated(vr8_4d)) then - _ASSERT(.false., "Cannot write unassociated vars") + _FAIL( "Cannot write unassociated vars") end if call MAPL_VarWrite(formatter, name, vr8_4d, arrdes=arrdes, oClients=oClients, rc=status) endif @@ -2999,7 +2999,7 @@ subroutine MAPL_StateVarReadNCPar(filename, STATE, arrdes, bootstrapable, NAME, value=MAPL_RestartBootstrap, rc=status) else - _ASSERT(.false., " Could not find field "//trim(FieldName)//" in "//trim(filename)) + _FAIL( " Could not find field "//trim(FieldName)//" in "//trim(filename)) end if end if @@ -3053,7 +3053,7 @@ subroutine MAPL_StateVarReadNCPar(filename, STATE, arrdes, bootstrapable, NAME, call ESMF_AttributeSet ( field, name='RESTART', & value=MAPL_RestartBootstrap, rc=status) else - _ASSERT(.false., " Could not find field "//trim(Fieldname)//" in "//trim(filename)) + _FAIL( " Could not find field "//trim(Fieldname)//" in "//trim(filename)) end if end if @@ -3283,7 +3283,7 @@ subroutine MAPL_BundleWriteNCPar(Bundle, arrdes, CLOCK, filename, oClients, rc) ! verify that file is compatible with fields in bundle we are reading if (nVars == 0) then - _ASSERT(.false., "The bundle you are trying to write is empty") + _FAIL( "The bundle you are trying to write is empty") endif ! first we need to prep the netcdf file for writing @@ -3374,7 +3374,7 @@ subroutine MAPL_BundleWriteNCPar(Bundle, arrdes, CLOCK, filename, oClients, rc) UNGRID_DIMS(I,1) = size(var_4d,3) UNGRID_DIMS(I,2) = size(var_4d,4) else - _ASSERT(.false., "Unsupported DIMS type") + _FAIL( "Unsupported DIMS type") end if elseif (tk == ESMF_TYPEKIND_R8) then call ESMF_ArrayGet(array, localDE=0, farrayptr=var8_4d, rc=status) @@ -3385,10 +3385,10 @@ subroutine MAPL_BundleWriteNCPar(Bundle, arrdes, CLOCK, filename, oClients, rc) UNGRID_DIMS(I,1) = size(var8_4d,3) UNGRID_DIMS(I,2) = size(var8_4d,4) else - _ASSERT(.false., "Unsupported DIMS type") + _FAIL( "Unsupported DIMS type") end if else - _ASSERT(.false., "Unsupported type/rank") + _FAIL( "Unsupported type/rank") endif endif @@ -3661,7 +3661,7 @@ subroutine MAPL_BundleWriteNCPar(Bundle, arrdes, CLOCK, filename, oClients, rc) call add_fvar(cf,trim(fieldname),pfDataType,'edge',units,long_name,rc=status) _VERIFY(status) else - _ASSERT(.false., 'ERROR: LOCATION not recognized for rank 1') + _FAIL( 'ERROR: LOCATION not recognized for rank 1') endif elseif(DIMS(1)==MAPL_DimsTileOnly) then call add_fvar(cf,trim(fieldname),pfDataType,'tile',units,long_name,rc=status) @@ -3680,7 +3680,7 @@ subroutine MAPL_BundleWriteNCPar(Bundle, arrdes, CLOCK, filename, oClients, rc) call add_fvar(cf,trim(fieldname),pfDataType,myUngridDimName1,units,long_name,rc=status) _VERIFY(status) else - _ASSERT(.false., 'unsupported Dims case') + _FAIL( 'unsupported Dims case') endif else if(arrayRank == 2) then if (DIMS(1)==MAPL_DimsHorzOnly) then @@ -3701,7 +3701,7 @@ subroutine MAPL_BundleWriteNCPar(Bundle, arrdes, CLOCK, filename, oClients, rc) _VERIFY(status) else write(buffer,*)'ERROR: DIMS not recognized for rank 2 variable ',trim(FieldName), DIMS(1) - _ASSERT(.false., trim(buffer)) + _FAIL( trim(buffer)) endif else if(arrayRank == 3) then @@ -3715,7 +3715,7 @@ subroutine MAPL_BundleWriteNCPar(Bundle, arrdes, CLOCK, filename, oClients, rc) call add_fvar(cf,trim(fieldname),pfDataType,'lon,lat,edge',units,long_name,rc=status) _VERIFY(status) else - _ASSERT(.false., 'ERROR: LOCATION not recognized for rank 3') + _FAIL( 'ERROR: LOCATION not recognized for rank 3') endif else if(DIMS(1)==MAPL_DimsHorzOnly) then do j=1,n_unique_ungrid_dims @@ -3745,7 +3745,7 @@ subroutine MAPL_BundleWriteNCPar(Bundle, arrdes, CLOCK, filename, oClients, rc) call add_fvar(cf,trim(fieldname),pfDataType,'tile,'//myUngridDimName1//','//myUngridDimName2,units,long_name,rc=status) _VERIFY(status) else if(DIMS(1)/=MAPL_DimsHorzVert .and. DIMS(1)/=MAPL_DimsHorzOnly) then - _ASSERT(.false., 'ERROR: What else could it be') + _FAIL( 'ERROR: What else could it be') endif else if(arrayRank == 4) then if (DIMS(1)==MAPL_DimsHorzVert) then @@ -3763,7 +3763,7 @@ subroutine MAPL_BundleWriteNCPar(Bundle, arrdes, CLOCK, filename, oClients, rc) call add_fvar(cf,trim(fieldname),pfDataType,'lon,lat,edge,'//myUngridDimName1,units,long_name,rc=status) _VERIFY(status) else - _ASSERT(.false., 'ERROR: LOCATION not recognized for rank 4') + _FAIL( 'ERROR: LOCATION not recognized for rank 4') endif else if(DIMS(1)==MAPL_DimsHorzOnly) then do j=1,n_unique_ungrid_dims @@ -3784,13 +3784,13 @@ subroutine MAPL_BundleWriteNCPar(Bundle, arrdes, CLOCK, filename, oClients, rc) _VERIFY(status) else if (DIMS(1)==MAPL_DimsTileOnly .or. & DIMS(1)==MAPL_DimsTileTile) then - _ASSERT(.false., 'ERROR: tiles with 2 or more UNGRIDDED dims not supported') + _FAIL( 'ERROR: tiles with 2 or more UNGRIDDED dims not supported') else - _ASSERT(.false., 'ERROR: What else could it be') + _FAIL( 'ERROR: What else could it be') endif else write(buffer,*) 'ERROR: arrayRank ',arrayRank, ' not supported' - _ASSERT(.false., trim(buffer)) + _FAIL( trim(buffer)) endif enddo @@ -4379,7 +4379,7 @@ subroutine MAPL_IOGetTime(cf,nymd,nhms,rc) type is (character(*)) call MAPL_NCIOParseTimeUnits(units,year,month,day,hour,min,sec,status) class default - _ASSERT(.false., 'unsupported subclass for units') + _FAIL( 'unsupported subclass for units') end select nymd = year*10000 + month*100 + day nhms = hour*10000 + min*100 + sec @@ -4536,7 +4536,7 @@ function check_flip(metadata,rc) result(flip) type is (character(*)) positive => vpos class default - _ASSERT(.false.,'units must be string') + _FAIL('units must be string') end select else positive => null() diff --git a/base/RegridMethods.F90 b/base/RegridMethods.F90 index dfdc698a2c48..0253ab893057 100644 --- a/base/RegridMethods.F90 +++ b/base/RegridMethods.F90 @@ -1,12 +1,15 @@ module mapl_RegridMethods + use ESMF implicit none private public :: REGRID_HINT_LOCAL public :: REGRID_METHOD_IDENTITY public :: REGRID_METHOD_BILINEAR + public :: REGRID_METHOD_BILINEAR_MONOTONIC public :: REGRID_METHOD_BILINEAR_ROTATE public :: REGRID_METHOD_CONSERVE + public :: REGRID_METHOD_CONSERVE_MONOTONIC public :: REGRID_METHOD_VOTE public :: REGRID_METHOD_FRACTION public :: REGRID_METHOD_CONSERVE_2ND @@ -15,6 +18,8 @@ module mapl_RegridMethods public :: REGRID_METHOD_CONSERVE_HFLUX public :: UNSPECIFIED_REGRID_METHOD public :: TILING_METHODS + public :: get_regrid_method + public :: translate_regrid_method enum, bind(c) enumerator :: REGRID_METHOD_IDENTITY @@ -27,10 +32,83 @@ module mapl_RegridMethods enumerator :: REGRID_METHOD_PATCH enumerator :: REGRID_METHOD_NEAREST_STOD enumerator :: REGRID_METHOD_CONSERVE_HFLUX + enumerator :: REGRID_METHOD_BILINEAR_MONOTONIC + enumerator :: REGRID_METHOD_CONSERVE_MONOTONIC enumerator :: UNSPECIFIED_REGRID_METHOD = -1 end enum integer, parameter :: TILING_METHODS(3) = [REGRID_METHOD_CONSERVE,REGRID_METHOD_VOTE,REGRID_METHOD_FRACTION] integer, parameter :: REGRID_HINT_LOCAL = 1 + contains + function get_regrid_method(string_regrid_method) result(int_regrid_method) + integer :: int_regrid_method + character(len=*), intent(in) :: string_regrid_method + + character(len=:), allocatable :: temp_str + temp_str = ESMF_UtilStringUpperCase(trim(string_regrid_method)) + + select case (temp_str) + case ("IDENTITY") + int_regrid_method = REGRID_METHOD_IDENTITY + case ("BILINEAR") + int_regrid_method = REGRID_METHOD_BILINEAR + case ("BILINEAR_ROTATE") + int_regrid_method = REGRID_METHOD_BILINEAR_ROTATE + case ("CONSERVE") + int_regrid_method = REGRID_METHOD_CONSERVE + case ("VOTE") + int_regrid_method = REGRID_METHOD_VOTE + case ("FRACTION") + int_regrid_method = REGRID_METHOD_FRACTION + case ("CONSERVE_2ND") + int_regrid_method = REGRID_METHOD_CONSERVE_2ND + case ("PATCH") + int_regrid_method = REGRID_METHOD_PATCH + case ("CONSERVE_HFLUX") + int_regrid_method = REGRID_METHOD_CONSERVE_HFLUX + case ("CONSERVE_MONOTONIC") + int_regrid_method = REGRID_METHOD_CONSERVE_MONOTONIC + case ("BILINEAR_MONOTONIC") + int_regrid_method = REGRID_METHOD_BILINEAR_MONOTONIC + case ("NEAREST_STOD") + int_regrid_method = REGRID_METHOD_NEAREST_STOD + case default + int_regrid_method = UNSPECIFIED_REGRID_METHOD + end select + end function + + function translate_regrid_method(int_regrid_method) result(string_regrid_method) + integer, intent(in) :: int_regrid_method + character(len=:), allocatable :: string_regrid_method + + select case (int_regrid_method) + case (REGRID_METHOD_IDENTITY) + string_regrid_method = "identity" + case (REGRID_METHOD_BILINEAR) + string_regrid_method = "bilinear" + case (REGRID_METHOD_BILINEAR_ROTATE) + string_regrid_method = "bilinear_rotate" + case (REGRID_METHOD_CONSERVE) + string_regrid_method = "conserve" + case (REGRID_METHOD_VOTE) + string_regrid_method = "vote" + case (REGRID_METHOD_FRACTION) + string_regrid_method = "fraction" + case (REGRID_METHOD_CONSERVE_2ND) + string_regrid_method = "conserve_2nd" + case (REGRID_METHOD_PATCH) + string_regrid_method = "patch" + case (REGRID_METHOD_CONSERVE_HFLUX) + string_regrid_method = "conserve_hflux" + case (REGRID_METHOD_CONSERVE_MONOTONIC) + string_regrid_method = "conserve_monotonic" + case (REGRID_METHOD_BILINEAR_MONOTONIC) + string_regrid_method = "bilinear_monotonic" + case (REGRID_METHOD_NEAREST_STOD) + string_regrid_method = "nearest_stod" + case default + string_regrid_method = "unspecified_regrid_method" + end select + end function end module mapl_RegridMethods diff --git a/base/StringTemplate.F90 b/base/StringTemplate.F90 index 03ad68fe0f10..1b13af15edfa 100644 --- a/base/StringTemplate.F90 +++ b/base/StringTemplate.F90 @@ -110,7 +110,7 @@ subroutine fill_grads_template(output_string,template,unusable,experiment_id,nym output_string(k:k+1)="%s" k=k+1 else - _ASSERT(.false.,"Using %s token with no experiment id") + _FAIL("Using %s token with no experiment id") end if case("%") istp=2 @@ -133,7 +133,7 @@ subroutine fill_grads_template(output_string,template,unusable,experiment_id,nym output_string(k:m)=sbuf k=m+1 else - _ASSERT(.false.,"Invalid token in file template: "//c1//c2) + _FAIL("Invalid token in file template: "//c1//c2) end if end select else diff --git a/base/mapl_tree.py b/base/mapl_tree.py index e55a43e89f04..aabd7003c3de 100755 --- a/base/mapl_tree.py +++ b/base/mapl_tree.py @@ -421,7 +421,7 @@ def main(): if ( REPO ): FULL_TREE = True TRIM = False - + MT = MAPL_Tree(OUT_FORM, OUT_COLOR, ADD_LINK, FULL_TREE, TRIM, REPO) if OUT_TYPE=='chname': @@ -452,7 +452,7 @@ def parse_args(): choices=['txt','mm'], default='txt') p.add_argument('-F','--full', help='display full tree', action='store_true') p.add_argument('-l','--link', help='add external link to nodes (edit MAPL_Tree::get_link)', action='store_true') - p.add_argument('-t','--trim', help='skip non GridComps, shorten names, use bult-in aliases',action='store_true') + p.add_argument('-t','--trim', help='skip non GridComps, shorten names, use built-in aliases',action='store_true') p.add_argument('-r','--repo', help='shows only the repository hierarchy',action='store_true') # Do not document this, it should be removed diff --git a/base/read_parallel.H b/base/read_parallel.H index 83e15b177188..79ba0ad55953 100644 --- a/base/read_parallel.H +++ b/base/read_parallel.H @@ -91,7 +91,7 @@ subroutine SUB_ ( layout, DATA, UNIT, FORMAT, arrdes, RC) #if (RANK_ > 2 || VARTYPE_ <= 0) - _ASSERT(.FALSE.,'needs informative message') + _FAIL('needs informative message') #else diff --git a/base/sun.H b/base/sun.H index c3ccbc246dc0..988b0697a431 100644 --- a/base/sun.H +++ b/base/sun.H @@ -108,7 +108,7 @@ ! pmn: EOT will just displace sunlit period wrt mean noon, ! but the daily mean values will not change - _ASSERT(.FALSE.,'pmn: MAPL_SunDailyMean probably in error!') + _FAIL('pmn: MAPL_SunDailyMean probably in error!') _ASSERT(.NOT.ORBIT%ANAL2B,'not implemented for analytic two-body orbit') SLR = sin(LATS)*ORBIT%ZS(IDAY) @@ -149,7 +149,7 @@ ! its a mean over the whole currently fixed 4-year cycle. ! see above - _ASSERT(.FALSE.,'pmn: MAPL_SunAnnualMean probably in error!') + _FAIL('pmn: MAPL_SunAnnualMean probably in error!') _ASSERT(.NOT.ORBIT%ANAL2B,'not implemented for analytic two-body orbit') SLR = 0.0 diff --git a/base/tests/CMakeLists.txt b/base/tests/CMakeLists.txt index 9e300e6d8357..83ac2cf7e2eb 100644 --- a/base/tests/CMakeLists.txt +++ b/base/tests/CMakeLists.txt @@ -53,10 +53,10 @@ ecbuild_add_executable ( set_target_properties(${TESTIO} PROPERTIES Fortran_MODULE_DIRECTORY ${MODULE_DIRECTORY}) add_test(NAME bundleio_tests_latlon - COMMAND ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} 2 ${MPIEXEC_PREFLAGS} ${CMAKE_CURRENT_BINARY_DIR}/${TESTIO} -nx 2 -ny 1 -ogrid PC90x47-DE) + COMMAND ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} 2 ${MPIEXEC_PREFLAGS} ${CMAKE_CURRENT_BINARY_DIR}/${TESTIO} -nx 2 -ny 1 -ogrid PC90x47-DE -o file1_ll.nc4) add_test(NAME bundleio_tests_cube - COMMAND ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} 6 ${MPIEXEC_PREFLAGS} ${CMAKE_CURRENT_BINARY_DIR}/${TESTIO} -nx 1 -ny 6 -ogrid PE12x72-CF) + COMMAND ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} 6 ${MPIEXEC_PREFLAGS} ${CMAKE_CURRENT_BINARY_DIR}/${TESTIO} -nx 1 -ny 6 -ogrid PE12x72-CF -o file_cs.nc4) add_dependencies(build-tests ${TESTIO}) diff --git a/base/tests/mapl_bundleio_test.F90 b/base/tests/mapl_bundleio_test.F90 index b7006fa3c884..9e77d3b52b64 100644 --- a/base/tests/mapl_bundleio_test.F90 +++ b/base/tests/mapl_bundleio_test.F90 @@ -1,6 +1,6 @@ #include "MAPL_Generic.h" - Program ut_ReGridding + module BundleTestSupport use mpi use ESMF @@ -18,166 +18,12 @@ Program ut_ReGridding use MAPL_ESMFFieldBundleRead use MAPL_ServerManager use MAPL_FileMetadataUtilsMod - + implicit NONE real, parameter :: cs_stretch_uninit = -1.0 - call main() - CONTAINS - - subroutine main() - -!CONTAINS - -! Basic ESMF objects being used in this example -! --------------------------------------------- - type(ESMF_Grid) :: grid_new - type(ESMF_VM) :: vm ! ESMF Virtual Machine - -! Basic information about the parallel environment -! PET = Persistent Execution Threads -! In the current implementation, a PET is equivalent -! to an MPI process -! ------------------------------------------------ - integer :: myPET ! The local PET number - integer :: nPET ! The total number of PETs you are running on - - integer :: status, rc - integer :: Nx,Ny,nargs - integer :: IM_World_new, JM_World_new, lm_world - - type(ESMF_FieldBundle) :: bundle,bundle_new - type(ESMF_Field) :: field - type(ESMF_Time) :: time - type(ESMF_TimeInterval) :: timeInterval - type(ESMF_Clock) :: clock - - character(len=ESMF_MAXSTR) :: Iam - character(len=ESMF_MAXSTR) :: filename - - integer :: i - - character(len=2) :: pole_new,dateline_new - character(len=ESMF_MAXSTR) :: gridname - character(len=ESMF_MAXPATHLEN) :: str,astr - type(ESMF_CONFIG) :: cfoutput - - type(FieldBundleWriter) :: newWriter - type(ServerManager) :: io_server - real, pointer :: ptr2d(:,:),ptr3d(:,:,:) - real :: cs_stretch_param(3) - integer :: exit_code - - Iam = "ut_ReGridding" - -! Initialize the ESMF. For performance reasons, it is important -! to turn OFF ESMF's automatic logging feature -! ------------------------------------------------------------- - call ESMF_Initialize (LogKindFlag=ESMF_LOGKIND_NONE, vm=vm, rc=STATUS) - _VERIFY(STATUS) - call ESMF_VMGet(vm, localPET=myPET, petCount=nPet) - call MAPL_Initialize(__RC__) - - call io_server%initialize(mpi_comm_world) - - nx=1 - ny=6 - cs_stretch_param=cs_stretch_uninit - nargs = command_argument_count() - do i=1,nargs - call get_command_argument(i,str) - select case(trim(str)) - case('-ogrid') - call get_command_argument(i+1,Gridname) - case('-nx') - call get_command_argument(i+1,astr) - read(astr,*)nx - case('-ny') - call get_command_argument(i+1,astr) - read(astr,*)ny - end select - enddo - - call MAPL_GetNodeInfo (comm=MPI_COMM_WORLD, rc=status) - _VERIFY(STATUS) - - call ESMF_CalendarSetDefault ( ESMF_CALKIND_GREGORIAN, rc=status ) - _VERIFY(STATUS) - - call ESMF_TimeSet(time, yy=2000, mm=3, dd=15, h=21, m=0, s=0,__RC__) - call ESMF_TimeIntervalSet( TimeInterval, h=6, m=0, s=0, rc=status ) - _VERIFY(STATUS) - Clock = ESMF_ClockCreate ( name="Eric", timeStep=TimeInterval, & - startTime=time, rc=status ) - _VERIFY(STATUS) - - call UnpackGridName(Gridname,im_world_new,jm_world_new,dateline_new,pole_new) - - lm_world=3 - cfoutput = create_cf(gridname,im_world_new,jm_world_new,nx,ny,lm_world,cs_stretch_param,__RC__) - grid_new=grid_manager%make_grid(cfoutput,prefix=trim(gridname)//".",__RC__) - bundle=ESMF_FieldBundleCreate(name="cfio_bundle",rc=status) - call ESMF_FieldBundleSet(bundle,grid=grid_new,rc=status) - _VERIFY(STATUS) - bundle_new=ESMF_FieldBundleCreate(name="cfio_bundle",rc=status) - call ESMF_FieldBundleSet(bundle_new,grid=grid_new,rc=status) - _VERIFY(STATUS) - - field=ESMF_FieldCreate(grid=grid_new,typekind=ESMF_TYPEKIND_R4,name="f2d",rc=status) - _VERIFY(status) - call ESMF_AttributeSet(FIELD, NAME='LONG_NAME', VALUE="what_am_i", RC=STATUS) - _VERIFY(STATUS) - call ESMF_AttributeSet(FIELD, NAME='UNITS', VALUE="NA", RC=STATUS) - _VERIFY(STATUS) - call ESMF_AttributeSet(FIELD, NAME='DIMS', VALUE=MAPL_DimsHorzOnly, RC=STATUS) - _VERIFY(STATUS) - call ESMF_AttributeSet(FIELD, NAME='VLOCATION', & - VALUE=MAPL_VLocationNone, RC=STATUS) - _VERIFY(STATUS) - call ESMF_FieldGet(field,farrayPtr=ptr2d,__RC__) - ptr2d=17.0 - call MAPL_FieldBundleAdd(bundle,field,__RC__) - - field=ESMF_FieldCreate(grid=grid_new,typekind=ESMF_TYPEKIND_R4,name="f3d", & - ungriddedLBound=[1],ungriddedUBound=[lm_world],rc=status) - _VERIFY(status) - call ESMF_AttributeSet(FIELD, NAME='LONG_NAME', VALUE="what_am_i", RC=STATUS) - _VERIFY(STATUS) - call ESMF_AttributeSet(FIELD, NAME='UNITS', VALUE="NA", RC=STATUS) - _VERIFY(STATUS) - call ESMF_AttributeSet(FIELD, NAME='DIMS', VALUE=MAPL_DimsHorzVert, RC=STATUS) - _VERIFY(STATUS) - call ESMF_AttributeSet(FIELD, NAME='VLOCATION', & - VALUE=MAPL_VLocationCenter, RC=STATUS) - _VERIFY(STATUS) - call ESMF_FieldGet(field,farrayPtr=ptr3d,__RC__) - ptr3d=17.0 - call MAPL_FieldBundleAdd(bundle,field,__RC__) - - - filename="temp_file.nc4" - call newWriter%create_from_bundle(bundle,clock,filename,rc=status) - _VERIFY(status) - call newWriter%write_to_file(rc=status) - _VERIFY(status) - call MAPL_Read_bundle(bundle_new,trim(filename),time=time,rc=status) - _VERIFY(status) - - call Compare_Bundle(bundle,bundle_new,1.0e6,rc=exit_code) - - call io_server%finalize() - call MAPL_Finalize(__RC__) - call ESMF_Finalize ( rc=status ) - _VERIFY(STATUS) - if (exit_code ==0) then - stop 0 - else - stop 1 - end if - - end subroutine main subroutine compare_bundle(State1,State2,tol,rc) type(ESMF_FieldBundle), intent(inout) :: State1 @@ -196,22 +42,20 @@ subroutine compare_bundle(State1,State2,tol,rc) logical, allocatable :: foundDiff(:) type(ESMF_Field) :: Field1,Field2 - call ESMF_FieldBundleGet(State1,fieldcount=itemCount,__RC__) - allocate(NameList(itemCount),stat=status) - _VERIFY(status) - allocate(foundDiff(itemCount),stat=status) - _VERIFY(status) - call ESMF_FieldBundleGet(State1,fieldNameList=NameList,__RC__) + call ESMF_FieldBundleGet(State1,fieldcount=itemCount,_RC) + allocate(NameList(itemCount),_STAT) + allocate(foundDiff(itemCount),_STAT) + call ESMF_FieldBundleGet(State1,fieldNameList=NameList,_RC) do ii=1,itemCount - call ESMF_FieldBundleGet(State1,trim(nameList(ii)),field=field1,__RC__) - call ESMF_FieldBundleGet(State2,trim(nameList(ii)),field=field2,__RC__) - call ESMF_FieldGet(field1,rank=rank1,__RC__) - call ESMF_FieldGet(field1,rank=rank2,__RC__) + call ESMF_FieldBundleGet(State1,trim(nameList(ii)),field=field1,_RC) + call ESMF_FieldBundleGet(State2,trim(nameList(ii)),field=field2,_RC) + call ESMF_FieldGet(field1,rank=rank1,_RC) + call ESMF_FieldGet(field1,rank=rank2,_RC) _ASSERT(rank1==rank2,'needs informative message') foundDiff(ii)=.false. if (rank1==2) then - call ESMF_FieldGet(field1,farrayPtr=ptr2_1,__RC__) - call ESMF_FieldGet(field2,farrayPtr=ptr2_2,__RC__) + call ESMF_FieldGet(field1,farrayPtr=ptr2_1,_RC) + call ESMF_FieldGet(field2,farrayPtr=ptr2_2,_RC) do i=1,size(ptr2_1,1) do j=1,size(ptr2_1,2) if (abs(ptr2_1(i,j)-ptr2_2(i,j)) .gt. tol) then @@ -221,8 +65,8 @@ subroutine compare_bundle(State1,State2,tol,rc) enddo enddo else if (rank1==3) then - call ESMF_FieldGet(field1,farrayPtr=ptr3_1,__RC__) - call ESMF_FieldGet(field2,farrayPtr=ptr3_2,__RC__) + call ESMF_FieldGet(field1,farrayPtr=ptr3_1,_RC) + call ESMF_FieldGet(field2,farrayPtr=ptr3_2,_RC) lb=lbound(ptr3_1) ub=ubound(ptr3_1) do i=1,size(ptr3_1,1) @@ -237,7 +81,7 @@ subroutine compare_bundle(State1,State2,tol,rc) enddo end if if (foundDiff(ii)) then - _ASSERT(.false.,'found difference when compare state') + _FAIL('found difference when compare state') end if enddo @@ -275,7 +119,6 @@ function create_cf(grid_name,im_world,jm_world,nx,ny,lm,cs_stretch_param,rc) res real, intent(in) :: cs_stretch_param(3) integer, optional, intent(out) :: rc - character(len=ESMF_MAXSTR),parameter :: Iam = "create_cf" integer :: status character(len=2) :: pole,dateline integer :: nn @@ -284,44 +127,31 @@ function create_cf(grid_name,im_world,jm_world,nx,ny,lm,cs_stretch_param,rc) res dateline=grid_name(nn-1:nn) pole=grid_name(1:2) - cf = MAPL_ConfigCreate(__RC__) - call MAPL_ConfigSetAttribute(cf,value=NX, label=trim(grid_name)//".NX:",rc=status) - VERIFY_(status) - call MAPL_ConfigSetAttribute(cf,value=lm, label=trim(grid_name)//".LM:",rc=status) - VERIFY_(status) + cf = MAPL_ConfigCreate(_RC) + call MAPL_ConfigSetAttribute(cf,value=NX, label=trim(grid_name)//".NX:",_RC) + call MAPL_ConfigSetAttribute(cf,value=lm, label=trim(grid_name)//".LM:",_RC) if (jm_world==6*im_world) then - call MAPL_ConfigSetAttribute(cf,value="Cubed-Sphere", label=trim(grid_name)//".GRID_TYPE:",rc=status) - VERIFY_(status) - call MAPL_ConfigSetAttribute(cf,value=6, label=trim(grid_name)//".NF:",rc=status) - VERIFY_(status) - call MAPL_ConfigSetAttribute(cf,value=im_world,label=trim(grid_name)//".IM_WORLD:",rc=status) - VERIFY_(status) - call MAPL_ConfigSetAttribute(cf,value=ny/6, label=trim(grid_name)//".NY:",rc=status) - VERIFY_(status) + call MAPL_ConfigSetAttribute(cf,value="Cubed-Sphere", label=trim(grid_name)//".GRID_TYPE:",_RC) + call MAPL_ConfigSetAttribute(cf,value=6, label=trim(grid_name)//".NF:",_RC) + call MAPL_ConfigSetAttribute(cf,value=im_world,label=trim(grid_name)//".IM_WORLD:",_RC) + call MAPL_ConfigSetAttribute(cf,value=ny/6, label=trim(grid_name)//".NY:",_RC) if (any(cs_stretch_param/=cs_stretch_uninit)) then - call MAPL_ConfigSetAttribute(cf,value=cs_stretch_param(1),label=trim(grid_name)//".STRETCH_FACTOR:",rc=status) - VERIFY_(status) - call MAPL_ConfigSetAttribute(cf,value=cs_stretch_param(2),label=trim(grid_name)//".TARGET_LON:",rc=status) - call MAPL_ConfigSetAttribute(cf,value=cs_stretch_param(3),label=trim(grid_name)//".TARGET_LAT:",rc=status) + call MAPL_ConfigSetAttribute(cf,value=cs_stretch_param(1),label=trim(grid_name)//".STRETCH_FACTOR:",_RC) + call MAPL_ConfigSetAttribute(cf,value=cs_stretch_param(2),label=trim(grid_name)//".TARGET_LON:",_RC) + call MAPL_ConfigSetAttribute(cf,value=cs_stretch_param(3),label=trim(grid_name)//".TARGET_LAT:",_RC) end if - + else - call MAPL_ConfigSetAttribute(cf,value="LatLon", label=trim(grid_name)//".GRID_TYPE:",rc=status) - VERIFY_(status) - call MAPL_ConfigSetAttribute(cf,value=im_world,label=trim(grid_name)//".IM_WORLD:",rc=status) - VERIFY_(status) - call MAPL_ConfigSetAttribute(cf,value=jm_world,label=trim(grid_name)//".JM_WORLD:",rc=status) - VERIFY_(status) - call MAPL_ConfigSetAttribute(cf,value=ny, label=trim(grid_name)//".NY:",rc=status) - VERIFY_(status) - call MAPL_ConfigSetAttribute(cf,value=pole, label=trim(grid_name)//".POLE:",rc=status) - VERIFY_(status) - call MAPL_ConfigSetAttribute(cf,value=dateline, label=trim(grid_name)//".DATELINE:",rc=status) - VERIFY_(status) + call MAPL_ConfigSetAttribute(cf,value="LatLon", label=trim(grid_name)//".GRID_TYPE:",_RC) + call MAPL_ConfigSetAttribute(cf,value=im_world,label=trim(grid_name)//".IM_WORLD:",_RC) + call MAPL_ConfigSetAttribute(cf,value=jm_world,label=trim(grid_name)//".JM_WORLD:",_RC) + call MAPL_ConfigSetAttribute(cf,value=ny, label=trim(grid_name)//".NY:",_RC) + call MAPL_ConfigSetAttribute(cf,value=pole, label=trim(grid_name)//".POLE:",_RC) + call MAPL_ConfigSetAttribute(cf,value=dateline, label=trim(grid_name)//".DATELINE:",_RC) end if - end function create_cf + end function create_cf function create_gridname(im,jm,date,pole) result(gridname) integer, intent(in) :: im @@ -337,4 +167,135 @@ function create_gridname(im,jm,date,pole) result(gridname) end function create_gridname - end program ut_ReGridding + end module BundleTestSupport + +! This is how you can "reset" the MAPL_Generic.h verify bits for a program. +! Program must be at the end of the file to do this and everything else in a module + +#undef MAPL_ErrLog_DONE +#define I_AM_MAIN +#include "MAPL_Generic.h" + + program ut_ReGridding + + use BundleTestSupport + implicit none + +!CONTAINS + +! Basic ESMF objects being used in this example +! --------------------------------------------- + type(ESMF_Grid) :: grid_new + type(ESMF_VM) :: vm ! ESMF Virtual Machine + +! Basic information about the parallel environment +! PET = Persistent Execution Threads +! In the current implementation, a PET is equivalent +! to an MPI process +! ------------------------------------------------ + integer :: myPET ! The local PET number + integer :: nPET ! The total number of PETs you are running on + + integer :: status + integer :: Nx,Ny,nargs + integer :: IM_World_new, JM_World_new, lm_world + + type(ESMF_FieldBundle) :: bundle,bundle_new + type(ESMF_Field) :: field + type(ESMF_Time) :: time + type(ESMF_TimeInterval) :: timeInterval + type(ESMF_Clock) :: clock + + character(len=ESMF_MAXSTR) :: filename + + integer :: i + + character(len=2) :: pole_new,dateline_new + character(len=ESMF_MAXSTR) :: gridname + character(len=ESMF_MAXPATHLEN) :: str,astr + type(ESMF_CONFIG) :: cfoutput + + type(FieldBundleWriter) :: newWriter + type(ServerManager) :: io_server + real, pointer :: ptr2d(:,:),ptr3d(:,:,:) + real :: cs_stretch_param(3) + +! Initialize the ESMF. For performance reasons, it is important +! to turn OFF ESMF's automatic logging feature +! ------------------------------------------------------------- + call ESMF_Initialize (LogKindFlag=ESMF_LOGKIND_NONE, vm=vm, _RC) + call ESMF_VMGet(vm, localPET=myPET, petCount=nPet, _RC) + call MAPL_Initialize(_RC) + + call io_server%initialize(mpi_comm_world) + + nx=1 + ny=6 + cs_stretch_param=cs_stretch_uninit + nargs = command_argument_count() + do i=1,nargs + call get_command_argument(i,str) + select case(trim(str)) + case('-ogrid') + call get_command_argument(i+1,Gridname) + case('-nx') + call get_command_argument(i+1,astr) + read(astr,*)nx + case('-ny') + call get_command_argument(i+1,astr) + read(astr,*)ny + case('-o') + call get_command_argument(i+1,filename) + end select + enddo + + call MAPL_GetNodeInfo (comm=MPI_COMM_WORLD, _RC) + + call ESMF_CalendarSetDefault ( ESMF_CALKIND_GREGORIAN, _RC ) + + call ESMF_TimeSet(time, yy=2000, mm=3, dd=15, h=21, m=0, s=0,_RC) + call ESMF_TimeIntervalSet( TimeInterval, h=6, m=0, s=0, _RC ) + Clock = ESMF_ClockCreate ( name="Eric", timeStep=TimeInterval, & + startTime=time, _RC ) + + call UnpackGridName(Gridname,im_world_new,jm_world_new,dateline_new,pole_new) + + lm_world=3 + cfoutput = create_cf(gridname,im_world_new,jm_world_new,nx,ny,lm_world,cs_stretch_param,_RC) + grid_new=grid_manager%make_grid(cfoutput,prefix=trim(gridname)//".",_RC) + bundle=ESMF_FieldBundleCreate(name="cfio_bundle",_RC) + call ESMF_FieldBundleSet(bundle,grid=grid_new,_RC) + bundle_new=ESMF_FieldBundleCreate(name="cfio_bundle",_RC) + call ESMF_FieldBundleSet(bundle_new,grid=grid_new,_RC) + + field=ESMF_FieldCreate(grid=grid_new,typekind=ESMF_TYPEKIND_R4,name="f2d",_RC) + call ESMF_AttributeSet(FIELD,'LONG_NAME','what_am_i',_RC) + call ESMF_AttributeSet(FIELD,'UNITS','NA',_RC) + call ESMF_AttributeSet(FIELD,'DIMS',MAPL_DimsHorzOnly,_RC) + call ESMF_AttributeSet(FIELD,'VLOCATION',MAPL_VLocationNone,_RC) + call ESMF_FieldGet(field,farrayPtr=ptr2d,_RC) + ptr2d=17.0 + call MAPL_FieldBundleAdd(bundle,field,_RC) + + field=ESMF_FieldCreate(grid=grid_new,typekind=ESMF_TYPEKIND_R4,name="f3d", & + ungriddedLBound=[1],ungriddedUBound=[lm_world],_RC) + call ESMF_AttributeSet(FIELD,'LONG_NAME','what_am_i',_RC) + call ESMF_AttributeSet(FIELD,'UNITS','NA',_RC) + call ESMF_AttributeSet(FIELD,'DIMS',MAPL_DimsHorzVert,_RC) + call ESMF_AttributeSet(FIELD,'VLOCATION',MAPL_VLocationCenter,_RC) + call ESMF_FieldGet(field,farrayPtr=ptr3d,_RC) + ptr3d=17.0 + call MAPL_FieldBundleAdd(bundle,field,_RC) + + + call newWriter%create_from_bundle(bundle,clock,filename,_RC) + call newWriter%write_to_file(_RC) + call MAPL_Read_bundle(bundle_new,trim(filename),time=time,_RC) + + call Compare_Bundle(bundle,bundle_new,1.0e6,_RC) + + call io_server%finalize() + call MAPL_Finalize(_RC) + call ESMF_Finalize(_RC) + + end program ut_ReGridding diff --git a/base/tests/testbin.F90 b/base/tests/testbin.F90 index 8e7c03c9c0c5..cf9d69a843c5 100644 --- a/base/tests/testbin.F90 +++ b/base/tests/testbin.F90 @@ -1,4 +1,4 @@ - +program testbin use HorzBinMod type (HorzBinTransform) :: T diff --git a/base/tests/testhorz.F90 b/base/tests/testhorz.F90 index 67277d6c7ed2..0f0314a39334 100644 --- a/base/tests/testhorz.F90 +++ b/base/tests/testhorz.F90 @@ -1,3 +1,5 @@ +program testhorz + use MAPL_HorzTransformMod implicit none diff --git a/base/tstqsat.F90 b/base/tstqsat.F90 index b8cb4e5d1b01..871c0f895a53 100644 --- a/base/tstqsat.F90 +++ b/base/tstqsat.F90 @@ -1,4 +1,4 @@ - +program tstqsat use MAPLBase_Mod diff --git a/base/write_parallel.H b/base/write_parallel.H index 5f2e8f343bca..823ce1c74a52 100644 --- a/base/write_parallel.H +++ b/base/write_parallel.H @@ -87,7 +87,7 @@ subroutine SUB_ ( data, UNIT, ARRDES, format, RC) #if (RANK_ > 2 || VARTYPE_ <= 0) - _ASSERT(.FALSE.,'needs informative message') + _FAIL('needs informative message') #else diff --git a/cmake/mapl_acg.cmake b/cmake/mapl_acg.cmake index b55364233a70..d37f08eafc59 100644 --- a/cmake/mapl_acg.cmake +++ b/cmake/mapl_acg.cmake @@ -28,12 +28,12 @@ function (mapl_acg target specs_file) string (REPLACE "_GridComp" "" component_name ${target}) if (ARGS_UNPARSED_ARGUMENTS) - ecbuild_error ("maple_acg() - unparsed arguments: ${ARGS_UNPARSED_ARGUMENTS}") + ecbuild_error ("mapl_acg() - unparsed arguments: ${ARGS_UNPARSED_ARGUMENTS}") endif () set (generated) # empty unless set (options "") - + set (suffix_for_generated_include_files "___.h") # Handle oneValueArgs with no value (Python provides default) foreach (opt flag default IN ZIP_LISTS oneValueArgs flags defaults) @@ -44,7 +44,7 @@ function (mapl_acg target specs_file) list (APPEND options ${flag} ${ARGS_${opt}}) elseif (${opt} IN_LIST ARGS_KEYWORDS_MISSING_VALUES) string (REPLACE "{component}" component_name fname ${default}) - list (APPEND generated ${fname}) + list (APPEND generated "${component_name}_${fname}${suffix_for_generated_include_files}") list (APPEND options ${flag}) endif () @@ -60,7 +60,7 @@ function (mapl_acg target specs_file) add_custom_command ( OUTPUT ${generated} COMMAND ${generator} ${CMAKE_CURRENT_SOURCE_DIR}/${specs_file} ${options} - MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/${specs_file} + MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/${specs_file} DEPENDS ${generator} ${specs_file} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMENT "Generating automatic code for ${specs_file}" diff --git a/components.yaml b/components.yaml index 6f9e8e70c545..d4ae66224621 100644 --- a/components.yaml +++ b/components.yaml @@ -5,13 +5,13 @@ MAPL: ESMA_env: local: ./ESMA_env remote: ../ESMA_env.git - tag: v3.11.0 + tag: v4.4.0 develop: main ESMA_cmake: local: ./ESMA_cmake remote: ../ESMA_cmake.git - tag: v3.10.0 + tag: v3.18.0 develop: develop ecbuild: diff --git a/generic/GenericCplComp.F90 b/generic/GenericCplComp.F90 index aa1cb263343b..12cde4206720 100644 --- a/generic/GenericCplComp.F90 +++ b/generic/GenericCplComp.F90 @@ -1,4 +1,14 @@ - +#define _DEALLOC(A) \ + if(associated(A))then; \ + if(MAPL_ShmInitialized)then; \ + call MAPL_SyncSharedMemory(rc=STATUS); \ + call MAPL_DeAllocNodeArray(A,rc=STATUS); \ + else; \ + deallocate(A,stat=STATUS); \ + endif; \ + _VERIFY(STATUS); \ + NULLIFY(A); \ + endif #include "MAPL_Generic.h" #include "unused_dummy.H" @@ -21,6 +31,7 @@ module MAPL_GenericCplCompMod use ESMF use ESMFL_Mod + use MAPL_ShmemMod use MAPL_BaseMod use MAPL_Constants use MAPL_IOMod @@ -42,9 +53,10 @@ module MAPL_GenericCplCompMod !EOP type MAPL_CplCnt - integer, pointer :: PTR1C(:) => null() - integer, pointer :: PTR2C(:,:) => null() - integer, pointer :: PTR3C(:,:,:) => null() + integer, pointer :: PTR1C(:) => null() + integer, pointer :: PTR2C(:,:) => null() + integer, pointer :: PTR3C(:,:,:) => null() + integer, pointer :: PTR4C(:,:,:,:) => null() end type MAPL_CplCnt type MAPL_GenericCplState @@ -272,9 +284,11 @@ subroutine Initialize(CC, SRC, DST, CLOCK, RC) real, pointer :: PTR1 (: ) real, pointer :: PTR2 (:,: ) real, pointer :: PTR3 (:,:,:) + real, pointer :: PTR4 (:,:,:,:) real, pointer :: PTR10(: ) real, pointer :: PTR20(:,: ) real, pointer :: PTR30(:,:,:) + real, pointer :: PTR40(:,:,:,:) integer :: OFFSET integer, pointer :: ungrd(:) logical :: has_ungrd @@ -476,7 +490,7 @@ subroutine Initialize(CC, SRC, DST, CLOCK, RC) if (has_ungrd) then DIMS = DIMS + size(UNGRD) end if - _ASSERT(DIMS < 4,'needs informative message') ! ALT: due to laziness we are supporting only 3 dims + _ASSERT(DIMS < 5,'needs informative message') ! ALT: due to laziness we are supporting only 4 dims STATE%ACCUM_RANK(J) = DIMS @@ -497,6 +511,25 @@ subroutine Initialize(CC, SRC, DST, CLOCK, RC) select case(DIMS) + case(4) +! Get SRC pointer, making sure it is allocated. + call MAPL_GetPointer(SRC, PTR4, NAME, ALLOC=.TRUE., RC=STATUS) + _VERIFY(STATUS) +! Allocate space for accumulator + L1 = LBOUND(PTR4,3) + LN = UBOUND(PTR4,3) + allocate(PTR40(size(PTR4,1),size(PTR4,2),L1:LN,size(PTR4,4)), STAT=STATUS) + _VERIFY(STATUS) + if (STATE%couplerType(J) /= MAPL_CplAverage .and. STATE%couplerType(J) /= MAPL_CplAccumulate) then + PTR40 = MAPL_UNDEF + else +! Set accumulator values to zero + PTR40 = 0.0 + endif +! Put pointer in accumulator + STATE%ACCUMULATORS(J)=ESMF_LocalArrayCreate( PTR40, RC=STATUS) + _VERIFY(STATUS) + case(3) ! Get SRC pointer, making sure it is allocated. call MAPL_GetPointer(SRC, PTR3, NAME, ALLOC=.TRUE., RC=STATUS) @@ -646,19 +679,22 @@ subroutine ACCUMULATE(SRC, STATE, RC) ! local vars integer :: J - integer :: I1, I2, I3 + integer :: I1, I2, I3, I4 integer :: couplerType character (len=ESMF_MAXSTR) :: NAME integer :: DIMS real, pointer :: PTR1 (:) real, pointer :: PTR2 (:,:) real, pointer :: PTR3 (:,:,:) + real, pointer :: PTR4 (:,:,:,:) real, pointer :: PTR10(:) real, pointer :: PTR20(:,:) real, pointer :: PTR30(:,:,:) + real, pointer :: PTR40(:,:,:,:) integer, pointer :: PTR1c(:) => NULL() integer, pointer :: PTR2c(:,:) => NULL() integer, pointer :: PTR3c(:,:,:) => NULL() + integer, pointer :: PTR4c(:,:,:,:) => NULL() character(*), parameter :: IAm="ACCUMULATE" integer :: STATUS @@ -683,6 +719,53 @@ subroutine ACCUMULATE(SRC, STATE, RC) select case(DIMS) + case(4) + call MAPL_GetPointer (SRC, PTR4, NAME, RC=STATUS) + _VERIFY(STATUS) + call ESMF_LocalArrayGet(STATE%ACCUMULATORS(J),farrayPtr=PTR40,RC=STATUS) + _VERIFY(STATUS) + PTR4c => STATE%ARRAY_COUNT(J)%PTR4C + + if(.not.associated(PTR4C)) then + if( any( PTR4==MAPL_UNDEF ) ) then + allocate(PTR4C(size(PTR4,1), size(PTR4,2), size(PTR4,3), size(PTR4,4)),STAT=STATUS) + _VERIFY(STATUS) + PTR4C = STATE%ACCUM_COUNT(J) +! put it back into array + STATE%ARRAY_COUNT(J)%PTR4C => PTR4c + _VERIFY(STATUS) + end if + end if + + if (couplerType == MAPL_CplAverage .or. couplerType == MAPL_CplAccumulate) then + if(associated(PTR3C)) then + where (PTR4 /= MAPL_Undef) + PTR40 = PTR40 + PTR4 + PTR4c = PTR4c + 1 + end where + else + PTR40 = PTR40 + PTR4 + end if + else + DO I1=1,size(PTR4,1) + DO I2=1,size(PTR4,2) + DO I3=1,size(PTR4,3) + DO I4=1,size(PTR4,4) + if (PTR40(I1,I2,I3,I4)== MAPL_Undef) then + PTR40(I1,I2,I3,I4) = PTR4(I1,I2,I3,I4) + else + if (couplerType == MAPL_CplMax) then + PTR40(I1,I2,I3,I4) = max(PTR40(I1,I2,I3,I4),PTR4(I1,I2,I3,I4)) + else if (couplerType == MAPL_CplMin) then + PTR40(I1,I2,I3,I4) = min(PTR40(I1,I2,I3,I4),PTR4(I1,I2,I3,I4)) + end if + end if + end DO + end DO + end DO + end DO + end if + case(3) call MAPL_GetPointer (SRC, PTR3, NAME, RC=STATUS) _VERIFY(STATUS) @@ -838,12 +921,10 @@ subroutine ZERO_CLEAR_COUNT(STATE, RC) integer :: J integer :: DIMS logical :: RINGING - real, pointer :: PTR1 (:) - real, pointer :: PTR2 (:,:) - real, pointer :: PTR3 (:,:,:) real, pointer :: PTR10(:) real, pointer :: PTR20(:,:) real, pointer :: PTR30(:,:,:) + real, pointer :: PTR40(:,:,:,:) character(*), parameter :: IAm="ZERO_CLEAR_COUNT" integer :: STATUS @@ -861,11 +942,21 @@ subroutine ZERO_CLEAR_COUNT(STATE, RC) DIMS = STATE%ACCUM_RANK(J) -! Process the 3 dimension possibilities +! Process the 4 dimension possibilities !-------------------------------------- select case(DIMS) + case(4) + call ESMF_LocalArrayGet(STATE%ACCUMULATORS(J),farrayPtr=PTR40,RC=STATUS) + _VERIFY(STATUS) + if (STATE%couplerType(J) /= MAPL_CplAverage .and. STATE%couplerType(J) /= MAPL_CplAccumulate) then + PTR40 = MAPL_UNDEF + else + PTR40 = 0.0 + endif + if (associated(STATE%ARRAY_COUNT(J)%PTR4C)) STATE%ARRAY_COUNT(J)%PTR4C = 0 + case(3) call ESMF_LocalArrayGet(STATE%ACCUMULATORS(J),farrayPtr=PTR30,RC=STATUS) _VERIFY(STATUS) @@ -914,6 +1005,10 @@ subroutine ZERO_CLEAR_COUNT(STATE, RC) deallocate(STATE%ARRAY_COUNT(J)%PTR3C) nullify(STATE%ARRAY_COUNT(J)%PTR3C) end if + if (associated(STATE%ARRAY_COUNT(J)%PTR4C)) then + deallocate(STATE%ARRAY_COUNT(J)%PTR4C) + nullify(STATE%ARRAY_COUNT(J)%PTR4C) + end if end if end do @@ -935,12 +1030,15 @@ subroutine COUPLE(SRC, STATE, RC) real, pointer :: PTR1 (:) real, pointer :: PTR2 (:,:) real, pointer :: PTR3 (:,:,:) + real, pointer :: PTR4 (:,:,:,:) real, pointer :: PTR10(:) real, pointer :: PTR20(:,:) real, pointer :: PTR30(:,:,:) + real, pointer :: PTR40(:,:,:,:) integer, pointer :: PTR1c(:) integer, pointer :: PTR2c(:,:) integer, pointer :: PTR3c(:,:,:) + integer, pointer :: PTR4c(:,:,:,:) logical :: RINGING integer :: couplerType @@ -964,11 +1062,45 @@ subroutine COUPLE(SRC, STATE, RC) DIMS = STATE%ACCUM_RANK(J) -! Process the three dimension possibilities +! Process the four dimension possibilities !------------------------------------------ select case(DIMS) + case(4) + call ESMF_LocalArrayGet(STATE%ACCUMULATORS(J),farrayPtr=PTR40,RC=STATUS) + _VERIFY(STATUS) + call MAPL_GetPointer (DST, PTR4, NAME, RC=STATUS) + _VERIFY(STATUS) + PTR4c => STATE%ARRAY_COUNT(J)%PTR4C + if(associated(PTR4C)) then + if (couplerType /= MAPL_CplAccumulate) then + where (PTR4C /= 0) + PTR40 = PTR40 / PTR4C + elsewhere + PTR40 = MAPL_Undef + end where + else + where (PTR4C /= 0) + PTR40 = PTR40 + elsewhere + PTR40 = MAPL_Undef + end where + end if + elseif(STATE%ACCUM_COUNT(J)>0) then + if (couplerType /= MAPL_CplAccumulate) then + PTR40 = PTR40 / STATE%ACCUM_COUNT(J) + else + PTR40 = PTR40 + end if + else + PTR40 = MAPL_Undef + end if + +! Regrid stubbed + + PTR4 = PTR40 + case(3) call ESMF_LocalArrayGet(STATE%ACCUMULATORS(J),farrayPtr=PTR30,RC=STATUS) _VERIFY(STATUS) @@ -1336,9 +1468,9 @@ subroutine ReadRestart(CC, SRC, DST, CLOCK, RC) deallocate(buf1) end if case default - _ASSERT(.false., "Unsupported rank") + _FAIL( "Unsupported rank") end select - if(associated(mask)) deallocate(mask) + _DEALLOC(mask) end do if (am_i_root) call Free_File(unit = UNIT, rc=STATUS) @@ -1459,7 +1591,7 @@ subroutine WriteRestart(CC, SRC, DST, CLOCK, RC) case(3) local_undefs = associated(state%array_count(i)%ptr3c) case default - _ASSERT(.false., "Unsupported rank") + _FAIL( "Unsupported rank") end select have_undefs = 0 n_undefs = 0 @@ -1530,9 +1662,9 @@ subroutine WriteRestart(CC, SRC, DST, CLOCK, RC) deallocate(buf1) end if case default - _ASSERT(.false.," Unsupported rank") + _FAIL(" Unsupported rank") end select - if(associated(mask)) deallocate(mask) + _DEALLOC(mask) end do if(am_i_root) call Free_File(unit = UNIT, rc=STATUS) @@ -1578,7 +1710,7 @@ subroutine MAPL_CplCompSetAlarm ( CC, ALARM, RC ) if (.not.associated(STATE%TIME2CPL_ALARM)) then STATE%TIME2CPL_ALARM => ALARM else - _ASSERT(.false., "Alarm is already associated! Cannot set it again!") + _FAIL( "Alarm is already associated! Cannot set it again!") end if _RETURN(ESMF_SUCCESS) end subroutine MAPL_CplCompSetAlarm diff --git a/generic/MAPL_Generic.F90 b/generic/MAPL_Generic.F90 index 7e90152a8922..5f770fa4818e 100644 --- a/generic/MAPL_Generic.F90 +++ b/generic/MAPL_Generic.F90 @@ -222,6 +222,7 @@ module MAPL_GenericMod public MAPL_GenericStateSave public MAPL_GenericStateRestore public MAPL_RootGcRetrieve + public MAPL_AddAttributeToFields !BOP ! !PUBLIC TYPES: @@ -242,6 +243,7 @@ module MAPL_GenericMod module procedure AddChildFromMeta module procedure AddChildFromDSO_old module procedure AddChildFromDSO + module procedure AddChildFromDSOMeta end interface MAPL_AddChild interface MAPL_AddImportSpec @@ -341,6 +343,10 @@ module MAPL_GenericMod module procedure MAPL_GetLogger_meta end interface MAPL_GetLogger + interface MAPL_AddAttributeToFields + module procedure MAPL_AddAttributeToFields_I4 + end interface + ! ======================================================================= @@ -1707,7 +1713,10 @@ recursive subroutine MAPL_GenericWrapper ( GC, IMPORT, EXPORT, CLOCK, RC) procedure(ESMF_GridCompRun), pointer :: func_ptr => NULL() character(len=12), target :: timers_run(1) = & [character(len=12):: 'GenRunMine'] - character(len=12) :: sbrtn + character(len=:), allocatable :: sbrtn + + character(:), allocatable :: stage_description + class(Logger), pointer :: lgr !============================================================================= @@ -1726,6 +1735,8 @@ recursive subroutine MAPL_GenericWrapper ( GC, IMPORT, EXPORT, CLOCK, RC) _VERIFY(status) Iam = trim(comp_name) // trim(Iam) + lgr => logging%get_logger('MAPL.GENERIC') + call ESMF_VmGetCurrent(VM) ! Retrieve the pointer to the internal state. It comes in a wrapper. ! ------------------------------------------------------------------ @@ -1735,7 +1746,7 @@ recursive subroutine MAPL_GenericWrapper ( GC, IMPORT, EXPORT, CLOCK, RC) ! TIMERS on t_p => get_global_time_profiler() - call t_p%start(trim(state%compname),__RC__) + call t_p%start(trim(state%compname),_RC) phase_ = MAPL_MAX_PHASES+phase ! this is the "actual" phase, i.e. the one user registered @@ -1770,10 +1781,12 @@ recursive subroutine MAPL_GenericWrapper ( GC, IMPORT, EXPORT, CLOCK, RC) sbrtn = 'WriteRestart' endif MethodBlock + stage_description = sbrtn//' stage of the gridded component <'//trim(COMP_NAME)//'>' + ! TIMERS on if (method /= ESMF_METHOD_READRESTART .and. method /= ESMF_METHOD_WRITERESTART) then - call state%t_profiler%start(__RC__) - call state%t_profiler%start(trim(sbrtn),__RC__) + call state%t_profiler%start(_RC) + call state%t_profiler%start(trim(sbrtn),_RC) end if if (associated(timers)) then @@ -1784,34 +1797,32 @@ recursive subroutine MAPL_GenericWrapper ( GC, IMPORT, EXPORT, CLOCK, RC) ! Method itself ! ---------- -#ifdef DEBUG - IF (mapl_am_i_root(vm)) then - print *,'DBG: running ', sbrtn, ' phase ',phase,' of ',trim(comp_name) - end IF -#endif - + call lgr%debug('Started %a', stage_description) call func_ptr (GC, & importState=IMPORT, & exportState=EXPORT, & clock=CLOCK, PHASE=PHASE_, & - userRC=userRC, __RC__ ) + userRC=userRC, _RC ) _VERIFY(userRC) + _ASSERT(userRC==ESMF_SUCCESS .and. STATUS==ESMF_SUCCESS,'Error during '//stage_description//' for <'//trim(COMP_NAME)//'>') + call lgr%debug('Finished %a', stage_description) + ! TIMERS off if (associated(timers)) then do i = size(timers),1,-1 - call MAPL_TimerOff (STATE,timers(i),__RC__) + call MAPL_TimerOff (STATE,timers(i),_RC) end do end if if (method /= ESMF_METHOD_FINALIZE) then if (method /= ESMF_METHOD_WRITERESTART .and. & method /= ESMF_METHOD_READRESTART) then - call state%t_profiler%stop(trim(sbrtn),__RC__) - call state%t_profiler%stop(__RC__) + call state%t_profiler%stop(trim(sbrtn),_RC) + call state%t_profiler%stop(_RC) end if - call t_p%stop(trim(state%compname),__RC__) + call t_p%stop(trim(state%compname),_RC) endif @@ -2099,7 +2110,7 @@ recursive subroutine MAPL_GenericFinalize ( GC, IMPORT, EXPORT, CLOCK, RC ) nwrgt1 = ((state%grid%num_readers > 1) .or. (state%grid%num_writers > 1)) if(FILETYPE=='pnc4' .and. nwrgt1) then print*,trim(Iam),': num_readers and number_writers must be 1 with pnc4 unless HDF5 was built with -enable-parallel' - _ASSERT(.false.,'needs informative message') + _FAIL('needs informative message') endif #endif call MAPL_GetResource( STATE , hdr, & @@ -2129,7 +2140,7 @@ recursive subroutine MAPL_GenericFinalize ( GC, IMPORT, EXPORT, CLOCK, RC ) nwrgt1 = ((state%grid%num_readers > 1) .or. (state%grid%num_writers > 1)) if(FILETYPE=='pnc4' .and. nwrgt1) then print*,trim(Iam),': num_readers and number_writers must be 1 with pnc4 unless HDF5 was built with -enable-parallel' - _ASSERT(.false.,'needs informative message') + _FAIL('needs informative message') endif #endif call MAPL_ESMFStateWriteToFile(IMPORT,CLOCK,FILENAME, & @@ -2184,18 +2195,18 @@ subroutine report_generic_profile( rc ) min_multi = MultiColumn(['Min'], separator='=') call min_multi%add_column(FormattedTextColumn(' % ','(f6.2)', 6, PercentageColumn(ExclusiveColumn('MIN')), separator='-')) - call min_multi%add_column(FormattedTextColumn('inclusive', '(f9.2)', 9, InclusiveColumn('MIN'), separator='-')) - call min_multi%add_column(FormattedTextColumn('exclusive', '(f9.2)',9, ExclusiveColumn('MIN'), separator='-')) + call min_multi%add_column(FormattedTextColumn('inclusive', '(f10.2)', 10, InclusiveColumn('MIN'), separator='-')) + call min_multi%add_column(FormattedTextColumn('exclusive', '(f10.2)',10, ExclusiveColumn('MIN'), separator='-')) mean_multi = MultiColumn(['Mean'], separator='=') call mean_multi%add_column(FormattedTextColumn(' % ','(f6.2)', 6, PercentageColumn(ExclusiveColumn('MEAN')), separator='-')) - call mean_multi%add_column(FormattedTextColumn('inclusive', '(f9.2)', 9, InclusiveColumn('MEAN'), separator='-')) - call mean_multi%add_column(FormattedTextColumn('exclusive', '(f9.2)', 9, ExclusiveColumn('MEAN'), separator='-')) + call mean_multi%add_column(FormattedTextColumn('inclusive', '(f10.2)', 10, InclusiveColumn('MEAN'), separator='-')) + call mean_multi%add_column(FormattedTextColumn('exclusive', '(f10.2)', 10, ExclusiveColumn('MEAN'), separator='-')) max_multi = MultiColumn(['Max'], separator='=') call max_multi%add_column(FormattedTextColumn(' % ','(f6.2)', 6, PercentageColumn(ExclusiveColumn('MAX')), separator='-')) - call max_multi%add_column(FormattedTextColumn('inclusive', '(f9.2)', 9, InclusiveColumn('MAX'), separator='-')) - call max_multi%add_column(FormattedTextColumn('exclusive', '(f9.2)', 9, ExclusiveColumn('MAX'), separator='-')) + call max_multi%add_column(FormattedTextColumn('inclusive', '(f10.2)', 10, InclusiveColumn('MAX'), separator='-')) + call max_multi%add_column(FormattedTextColumn('exclusive', '(f10.2)', 10, ExclusiveColumn('MAX'), separator='-')) pe_multi = MultiColumn(['PE'], separator='=') call pe_multi%add_column(FormattedTextColumn('max','(1x,i5.5)', 6, ExclusiveColumn('MAX_PE'), separator='-')) @@ -4439,6 +4450,7 @@ recursive subroutine MAPL_StatePrintSpecCSV(GC, printSpec, RC) type (MAPL_VarSpec), pointer :: IMPORT_SPEC(:) type (MAPL_VarSpec), pointer :: EXPORT_SPEC(:) + type (MAPL_VarSpec), pointer :: INTERNAL_SPEC(:) integer :: I type(ESMF_GridComp), pointer :: gridcomp @@ -4459,11 +4471,12 @@ recursive subroutine MAPL_StatePrintSpecCSV(GC, printSpec, RC) IMPORT_SPEC => MAPLOBJ%COMPONENT_SPEC%IMPORT%OLD_VAR_SPECS EXPORT_SPEC => MAPLOBJ%COMPONENT_SPEC%EXPORT%OLD_VAR_SPECS + INTERNAL_SPEC => MAPLOBJ%COMPONENT_SPEC%INTERNAL%OLD_VAR_SPECS if (printSpec == 1) then if (associated(IMPORT_SPEC)) then call WRITE_PARALLEL("#IMPORT spec for " // trim(comp_name)) - call WRITE_PARALLEL("#COMPONENT, SHORT_NAME, LONG_NAME, UNIT, DIMS") + call WRITE_PARALLEL("#COMPONENT, SHORT_NAME, LONG_NAME, UNIT, DIMS, CONTAINER_TYPE") if (associated(IMPORT_SPEC)) then call MAPL_VarSpecPrintCSV(IMPORT_SPEC, comp_name, RC=status) _VERIFY(status) @@ -4471,16 +4484,24 @@ recursive subroutine MAPL_StatePrintSpecCSV(GC, printSpec, RC) end if if (associated(EXPORT_SPEC)) then call WRITE_PARALLEL("#EXPORT spec for " // trim(comp_name)) - call WRITE_PARALLEL("#COMPONENT, SHORT_NAME, LONG_NAME, UNIT, DIMS") + call WRITE_PARALLEL("#COMPONENT, SHORT_NAME, LONG_NAME, UNIT, DIMS, CONTAINER_TYPE") if (associated(EXPORT_SPEC)) then call MAPL_VarSpecPrintCSV(EXPORT_SPEC, comp_name, RC=status) _VERIFY(status) end if end if + if (associated(INTERNAL_SPEC)) then + call WRITE_PARALLEL("#INTERNAL spec for " // trim(comp_name)) + call WRITE_PARALLEL("#COMPONENT, SHORT_NAME, LONG_NAME, UNIT, DIMS, CONTAINER_TYPE") + if (associated(INTERNAL_SPEC)) then + call MAPL_VarSpecPrintCSV(INTERNAL_SPEC, comp_name, RC=status) + _VERIFY(status) + end if + end if else if (printSpec == 2) then if (associated(IMPORT_SPEC)) then call WRITE_PARALLEL("#IMPORT spec for " // trim(comp_name)) - call WRITE_PARALLEL("#COMPONENT, SHORT_NAME, LONG_NAME, UNIT, DIMS") + call WRITE_PARALLEL("#COMPONENT, SHORT_NAME, LONG_NAME, UNIT, DIMS, CONTAINER_TYPE") if (associated(IMPORT_SPEC)) then call MAPL_VarSpecPrintCSV(IMPORT_SPEC, comp_name, RC=status) _VERIFY(status) @@ -4489,12 +4510,21 @@ recursive subroutine MAPL_StatePrintSpecCSV(GC, printSpec, RC) else if (printSpec == 3) then if (associated(EXPORT_SPEC)) then call WRITE_PARALLEL("#EXPORT spec for " // trim(comp_name)) - call WRITE_PARALLEL("#COMPONENT, SHORT_NAME, LONG_NAME, UNIT, DIMS") + call WRITE_PARALLEL("#COMPONENT, SHORT_NAME, LONG_NAME, UNIT, DIMS, CONTAINER_TYPE") if (associated(EXPORT_SPEC)) then call MAPL_VarSpecPrintCSV(EXPORT_SPEC, comp_name, RC=status) _VERIFY(status) end if end if + else if (printSpec == 4) then + if (associated(INTERNAL_SPEC)) then + call WRITE_PARALLEL("#INTERNAL spec for " // trim(comp_name)) + call WRITE_PARALLEL("#COMPONENT, SHORT_NAME, LONG_NAME, UNIT, DIMS, CONTAINER_TYPE") + if (associated(INTERNAL_SPEC)) then + call MAPL_VarSpecPrintCSV(INTERNAL_SPEC, comp_name, RC=status) + _VERIFY(status) + end if + end if end if do I = 1, MAPLOBJ%get_num_children() @@ -4534,6 +4564,9 @@ recursive integer function AddChildFromMeta(META, NAME, GRID, & class(BaseProfiler), pointer :: t_p integer :: userRC + character(:), allocatable :: stage_description + class(Logger), pointer :: lgr + if (.not.allocated(META%GCNameList)) then ! this is the first child to be added allocate(META%GCNameList(0), __STAT__) @@ -4542,27 +4575,30 @@ recursive integer function AddChildFromMeta(META, NAME, GRID, & I = META%get_num_children() + 1 AddChildFromMeta = I - call AddChild_preamble(meta, I, name, grid=grid, configfile=configfile, parentGC=parentgc, petList=petlist, child_meta=child_meta, __RC__) + call AddChild_preamble(meta, I, name, grid=grid, configfile=configfile, parentGC=parentgc, petList=petlist, child_meta=child_meta, _RC) + + stage_description = 'setServices() of the gridded component <'//trim(name)//'>' + lgr => logging%get_logger('MAPL.GENERIC') + t_p => get_global_time_profiler() - call t_p%start(trim(NAME),__RC__) - call child_meta%t_profiler%start(__RC__) - call child_meta%t_profiler%start('SetService',__RC__) + call t_p%start(trim(NAME),_RC) + call child_meta%t_profiler%start(_RC) + call child_meta%t_profiler%start('SetService',_RC) !!$ gridcomp => META%GET_CHILD_GRIDCOMP(I) - call ESMF_GridCompSetServices ( child_meta%gridcomp, SS, userRC=userRC, __RC__ ) + call lgr%debug("Started %a", stage_description) + call ESMF_GridCompSetServices ( child_meta%gridcomp, SS, userRC=userRC, _RC ) _VERIFY(userRC) + call lgr%debug("Finished %a", stage_description) - call child_meta%t_profiler%stop('SetService',__RC__) - call child_meta%t_profiler%stop(__RC__) - call t_p%stop(trim(NAME),__RC__) + call child_meta%t_profiler%stop('SetService',_RC) + call child_meta%t_profiler%stop(_RC) + call t_p%stop(trim(NAME),_RC) _VERIFY(status) _RETURN(ESMF_SUCCESS) - - contains - end function AddChildFromMeta recursive subroutine AddChild_preamble(meta, I, name, grid, configfile, parentGC, petlist, child_meta, unusable, rc) @@ -4591,10 +4627,10 @@ recursive subroutine AddChild_preamble(meta, I, name, grid, configfile, parentGC type(ESMF_VM) :: vm integer :: comm - call make_full_name(name, child_name, parentGC, __RC__) - call grow_children_names(meta%GCNamelist, child_name, __RC__) + call make_full_name(name, child_name, parentGC, _RC) + call grow_children_names(meta%GCNamelist, child_name, _RC) - allocate(tmp_meta, __STAT__) + allocate(tmp_meta, _STAT) tmp_framework => META%add_child(child_name, tmp_meta) deallocate(tmp_meta) _ASSERT(associated(tmp_framework),'add_child() failed') @@ -4611,38 +4647,38 @@ recursive subroutine AddChild_preamble(meta, I, name, grid, configfile, parentGC end if if (present(configfile)) then - child_meta%cf = ESMF_ConfigCreate(__RC__) - call ESMF_ConfigLoadFile(child_meta%cf, configfile, __RC__) + child_meta%cf = ESMF_ConfigCreate(_RC) + call ESMF_ConfigLoadFile(child_meta%cf, configfile, _RC) else ! use parents config child_meta%cf = meta%cf end if child_meta%gridcomp = ESMF_GridCompCreate ( & name = child_name, & - CONFIG = child_meta%cf, & + CONFIG = child_meta%cf, & grid = grid, & petList = petList, & contextFlag = contextFlag, & - __RC__) + _RC) ! Create each child's import/export state ! ---------------------------------- child_import_state => META%get_child_import_state(i) child_import_state = ESMF_StateCreate ( & name = trim(META%GCNameList(I)) // '_Imports', & - stateIntent = ESMF_STATEINTENT_IMPORT, __RC__) + stateIntent = ESMF_STATEINTENT_IMPORT, _RC) child_export_state => META%get_child_export_state(i) child_export_state = ESMF_StateCreate ( & name = trim(META%GCNameList(I)) // '_Exports', & - stateIntent = ESMF_STATEINTENT_EXPORT, __RC__) + stateIntent = ESMF_STATEINTENT_EXPORT, _RC) ! create MAPL_Meta - call MAPL_InternalStateCreate ( child_meta%gridcomp, child_meta, __RC__) + call MAPL_InternalStateCreate ( child_meta%gridcomp, child_meta, _RC) ! Create child components time profiler - call ESMF_VMGetCurrent(vm, __RC__) - call ESMF_VMGet(vm, mpiCommunicator=comm, __RC__) + call ESMF_VMGetCurrent(vm, _RC) + call ESMF_VMGet(vm, mpiCommunicator=comm, _RC) CHILD_META%t_profiler = DistributedProfiler(trim(name), MpiTimerGauge(), comm=comm) end select @@ -4737,64 +4773,56 @@ recursive integer function AddChildFromGC(GC, name, SS, petList, configFile, RC) type(MAPL_MetaComp), pointer :: META - call MAPL_InternalStateRetrieve(GC, META, RC=status) - _VERIFY(status) + call MAPL_InternalStateRetrieve(GC, META, _RC) - AddChildFromGC = AddChildFromMeta(Meta, name, SS=SS, PARENTGC=GC, petList=petList, configFile=configFile, RC=status) - _VERIFY(status) + AddChildFromGC = AddChildFromMeta(Meta, name, SS=SS, PARENTGC=GC, petList=petList, configFile=configFile, _RC) _RETURN(ESMF_SUCCESS) end function AddChildFromGC - !INTERFACE: - recursive integer function AddChildFromDSO(gc, name, userRoutine, grid, sharedObj, petList, configFile, RC) + recursive integer function AddChildFromDSOMeta(meta, name, userRoutine, grid, sharedObj, petList, configFile, parentGC, RC) !ARGUMENTS: - type(ESMF_GridComp), intent(INOUT) :: gc - character(len=*), intent(IN) :: name - character(len=*), intent(in) :: userRoutine - type(ESMF_Grid), optional, intent(INout) :: grid - character(len=*), optional, intent(in) :: sharedObj - - integer, optional , intent(IN ) :: petList(:) - character(len=*), optional, intent(IN ) :: configFile - integer, optional , intent( OUT) :: rc + type(MAPL_MetaComp), target, intent(INOUT) :: META + character(len=*), intent(IN) :: name + character(len=*), intent(in) :: userRoutine + type(ESMF_Grid), optional, intent(INOUT) :: grid + character(len=*), optional, intent(IN) :: sharedObj + + integer, optional, intent(IN) :: petList(:) + character(len=*), optional, intent(IN) :: configFile + type(ESMF_GridComp), optional, intent(IN) :: parentGC + integer, optional, intent(OUT) :: rc !EOP - integer :: status - integer :: userRC - - type(MAPL_MetaComp), pointer :: META + integer :: status + integer :: userRC - integer :: I - type(MAPL_MetaComp), pointer :: child_meta - class(BaseProfiler), pointer :: t_p + integer :: I + type(MAPL_MetaComp), pointer :: child_meta + class(BaseProfiler), pointer :: t_p class(Logger), pointer :: lgr character(len=:), allocatable :: shared_object_library_to_load character(len=:), allocatable :: extension - call MAPL_InternalStateRetrieve(gc, meta, __RC__) - if (.not.allocated(meta%GCNameList)) then ! this is the first child to be added - allocate(meta%GCNameList(0), __STAT__) + allocate(meta%GCNameList(0), _STAT) end if I = meta%get_num_children() + 1 - AddChildFromDSO = I + AddChildFromDSOMeta = I - call AddChild_preamble(meta, I, name, grid=grid, configfile=configfile, parentGC=gc, petList=petlist, child_meta=child_meta, __RC__) + call AddChild_preamble(meta, I, name, grid=grid, configfile=configfile, parentGC=parentGC, petList=petlist, child_meta=child_meta, _RC) t_p => get_global_time_profiler() - call t_p%start(trim(name),__RC__) - call child_meta%t_profiler%start(__RC__) - call child_meta%t_profiler%start('SetService',__RC__) - - extension = get_file_extension(SharedObj) - _ASSERT(is_supported_dso_name(SharedObj), "AddChildFromDSO: Unsupported shared library extension '"//extension//",.") + call t_p%start(trim(name),_RC) + call child_meta%t_profiler%start(_RC) + call child_meta%t_profiler%start('SetService',_RC) if (.not. is_valid_dso_name(SharedObj)) then + extension = get_file_extension(SharedObj) lgr => logging%get_logger('MAPL.GENERIC') call lgr%warning("AddChildFromDSO: changing shared library extension from %a~ to system specific extension %a~", & "'"//extension//"'", "'"//SYSTEM_DSO_EXTENSION//"'") @@ -4802,12 +4830,39 @@ recursive integer function AddChildFromDSO(gc, name, userRoutine, grid, sharedOb shared_object_library_to_load = adjust_dso_name(sharedObj) call ESMF_GridCompSetServices ( child_meta%gridcomp, userRoutine, & - sharedObj=shared_object_library_to_load,userRC=userRC,__RC__) + sharedObj=shared_object_library_to_load,userRC=userRC,_RC) _VERIFY(userRC) - call child_meta%t_profiler%stop('SetService',__RC__) - call child_meta%t_profiler%stop(__RC__) - call t_p%stop(trim(name),__RC__) + call child_meta%t_profiler%stop('SetService',_RC) + call child_meta%t_profiler%stop(_RC) + call t_p%stop(trim(name),_RC) + + _RETURN(ESMF_SUCCESS) + end function AddChildFromDSOMeta + + + !INTERFACE: + recursive integer function AddChildFromDSO(gc, name, userRoutine, grid, sharedObj, petList, configFile, RC) + + !ARGUMENTS: + type(ESMF_GridComp), intent(INOUT) :: gc + character(len=*), intent(IN) :: name + character(len=*), intent(in) :: userRoutine + type(ESMF_Grid), optional, intent(INout) :: grid + character(len=*), optional, intent(in) :: sharedObj + + integer, optional , intent(IN ) :: petList(:) + character(len=*), optional, intent(IN ) :: configFile + integer, optional , intent( OUT) :: rc + !EOP + + integer :: status + + type(MAPL_MetaComp), pointer :: META + + call MAPL_InternalStateRetrieve(gc, meta, _RC) + + AddChildFromDSO = AddChildFromDSOMeta(meta, name, userRoutine, grid=grid, sharedObj=sharedObj, petList=petList, configFile=configFile, _RC) _RETURN(ESMF_SUCCESS) end function AddChildFromDSO @@ -4831,7 +4886,7 @@ recursive integer function AddChildFromDSO_old(name, userRoutine, grid, ParentGC integer :: status _ASSERT(present(ParentGC),'must have a parent to use this interface') - addchildfromdso_old = addChildFromDSO(parentGC, name, userRoutine, grid=grid, sharedObj=sharedObj, petList=petList, configFile=configFile, __RC__) + addchildfromdso_old = addChildFromDSO(parentGC, name, userRoutine, grid=grid, sharedObj=sharedObj, petList=petList, configFile=configFile, _RC) _RETURN(ESMF_SUCCESS) end function AddChildFromDSO_Old @@ -5655,7 +5710,7 @@ subroutine MAPL_ESMFStateWriteToFile(STATE,CLOCK,FILENAME,FILETYPE,MPL,HDR, oCli #ifndef H5_HAVE_PARALLEL if (nwrgt1) then print*,trim(Iam),': num_readers and number_writers must be 1 with pnc4 unless HDF5 was built with -enable-parallel' - _ASSERT(.false.,'needs informative message') + _FAIL('needs informative message') end if #endif AmWriter = mpl%grid%writers_comm/=MPI_COMM_NULL @@ -6043,7 +6098,7 @@ subroutine MAPL_ESMFStateReadFromFile(STATE,CLOCK,FILENAME,MPL,HDR,RC) #ifndef H5_HAVE_PARALLEL if (nwrgt1) then print*,trim(Iam),': num_readers and number_writers must be 1 with pnc4 unless HDF5 was built with -enable-parallel' - _ASSERT(.false.,'needs informative message') + _FAIL('needs informative message') end if #endif AmReader = mpl%grid%readers_comm/=MPI_COMM_NULL @@ -6158,6 +6213,8 @@ subroutine MAPL_StateCreateFromVarSpecNew(STATE,SPEC,GRID,TILEGRID,DEFER,range,R integer :: range_(2) type(MAPL_VarSpec), pointer :: varspec + logical :: is_created + type(ESMF_Field) :: SPEC_FIELD if (present(range)) then range_ = range @@ -6176,37 +6233,45 @@ subroutine MAPL_StateCreateFromVarSpecNew(STATE,SPEC,GRID,TILEGRID,DEFER,range,R GRD = GRID else ! choose the grid - Dimensionality: select case(DIMS) + call MAPL_VarSpecGet(SPEC%var_specs%of(L), FIELD=SPEC_FIELD, _RC) + is_created = ESMF_FieldIsCreated(SPEC_FIELD, _RC) + if (is_created) then + call ESMF_FieldGet(SPEC_FIELD, GRID=GRD, _RC) + else + + + Dimensionality: select case(DIMS) - case(MAPL_DimsHorzVert) - select case(LOCATION) - case(MAPL_VLocationCenter) + case(MAPL_DimsHorzVert) + select case(LOCATION) + case(MAPL_VLocationCenter) + GRD = GRID + case(MAPL_VLocationEdge ) + GRD = GRID + case default + _RETURN(ESMF_FAILURE) + end select + case(MAPL_DimsHorzOnly) + GRD = GRID + case(MAPL_DimsVertOnly) GRD = GRID - case(MAPL_VLocationEdge ) + case(MAPL_DimsNone) GRD = GRID + case(MAPL_DimsTileOnly) + if (.not. present(TILEGRID)) then + _RETURN(ESMF_FAILURE) + endif + GRD = TILEGRID + case(MAPL_DimsTileTile) + if (.not. present(TILEGRID)) then + _RETURN(ESMF_FAILURE) + endif + GRD = TILEGRID case default _RETURN(ESMF_FAILURE) - end select - case(MAPL_DimsHorzOnly) - GRD = GRID - case(MAPL_DimsVertOnly) - GRD = GRID - case(MAPL_DimsNone) - GRD = GRID - case(MAPL_DimsTileOnly) - if (.not. present(TILEGRID)) then - _RETURN(ESMF_FAILURE) - endif - GRD = TILEGRID - case(MAPL_DimsTileTile) - if (.not. present(TILEGRID)) then - _RETURN(ESMF_FAILURE) - endif - GRD = TILEGRID - case default - _RETURN(ESMF_FAILURE) - end select Dimensionality - end if + end select Dimensionality + end if ! if created + end if ! if ISTAT varspec => SPEC%var_specs%of(L) call MAPL_VarSpecSet(varspec, GRID=GRD, RC=status ) @@ -8265,10 +8330,10 @@ subroutine MAPL_GetResourceFromMAPL_scalar(state, val, label, default, rc) end if if (label_is_present) then - call MAPL_GetResourceFromConfig_Scalar(state%cf,val,label_to_use,default,rc) + call MAPL_GetResourceFromConfig_Scalar(state%cf,val,label_to_use,default,rc = status) _VERIFY(status) else - call MAPL_GetResourceFromConfig_Scalar(state%cf,val,label,default,rc) + call MAPL_GetResourceFromConfig_Scalar(state%cf,val,label,default,rc = status) _VERIFY(status) end if @@ -8357,7 +8422,7 @@ subroutine MAPL_GetResourceFromConfig_scalar(config, val, label, default, rc) _VERIFY(status) end if class default - _ASSERT(.false., "Unupported type") + _FAIL( "Unupported type") end select call ESMF_ConfigGetAttribute(config, printrc, label = 'PRINTRC:', default = 0, rc = status) @@ -8482,7 +8547,7 @@ subroutine MAPL_GetResource_array(state, vals, label, default, rc) _VERIFY(status) end if class default - _ASSERT(.false., "Unsupported type") + _FAIL( "Unsupported type") end select _RETURN(ESMF_SUCCESS) @@ -8554,7 +8619,7 @@ subroutine print_resource(printrc, label, val, default, rc) default_str = intrinsic_to_string(default, 'a') end if class default - _ASSERT(.false.,"Unsupported type") + _FAIL("Unsupported type") end select output_format = "(1x, " // type_str // ", 'Resource Parameter: '" // ", a"// ", a)" @@ -8615,7 +8680,7 @@ function intrinsic_to_string(val, str_format, rc) result(formatted_str) type is(character(len=*)) formatted_str = trim(val) class default - _ASSERT(.false., "Unsupported type in intrinsic_to_string") + _FAIL( "Unsupported type in intrinsic_to_string") end select end function intrinsic_to_string @@ -9315,7 +9380,7 @@ subroutine MAPL_ReadForcingX(MPL,NAME,DATAFILE,CURRTIME, & elseif(present(FORCING2)) then ONED = .FALSE. else - _ASSERT(.FALSE.,'needs informative message') + _FAIL('needs informative message') end if ! Get parameters from generic state. @@ -9945,7 +10010,7 @@ subroutine READIT(WHICH) if(TRANSFORM) then if (PRF /= 0) then - _ASSERT(.false.,'needs informative message') ! for now + _FAIL('needs informative message') ! for now else ! ALT this LOOKS WRONG. MAPL_VarRead needs a mask for tiles!!! call MAPL_VarRead(UNIT, GRID, VAR2, RC=status ) @@ -10135,7 +10200,7 @@ subroutine MAPL_GridCreate(GC, MAPLOBJ, ESMFGRID, srcGC, rc) elseif(present(MAPLOBJ)) then STATE => MAPLOBJ else - _ASSERT(.false.,'needs informative message') + _FAIL('needs informative message') endif call MAPL_ConfigPrepend(state%cf,trim(comp_name),MAPL_CF_COMPONENT_SEPARATOR,'NX:',rc=status) @@ -11301,4 +11366,41 @@ subroutine warn_empty(string, MPL, rc) _RETURN(ESMF_SUCCESS) end subroutine warn_empty + recursive subroutine MAPL_AddAttributeToFields_I4(gc,field_name,att_name,att_val,rc) + type(ESMF_GridComp), pointer, intent(inout) :: gc + character(len=*), intent(in) :: field_name + character(len=*), intent(in) :: att_name + integer(int32), intent(in) :: att_val + integer, optional, intent(out) :: rc + + integer :: nc,i,status + type(MAPL_MetaComp), pointer :: state + type(ESMF_GridComp), pointer :: child_gc + type(ESMF_Field) :: field + type(ESMF_StateItem_Flag) :: item_type + type(ESMF_TypeKind_Flag) :: item_kind + integer :: item_count + logical :: is_present + + call MAPL_GetObjectFromGC(gc,state,_RC) + call ESMF_StateGet(state%import_state,field_name,item_type,_RC) + if (item_type == ESMF_STATEITEM_FIELD) then + call ESMF_StateGet(state%import_state,field_name,field,_RC) + call ESMF_AttributeGet(field,name=att_name,isPresent=is_Present,_RC) + if (is_present) then + call ESMF_AttributeGet(field,name=att_name,typekind=item_kind,itemCount=item_count,_RC) + _ASSERT(item_kind == ESMF_TYPEKIND_I4,"attribute "//att_name//" in "//field_name//" is not I4") + _ASSERT(item_count==1,"attribute "//att_name//" in "//field_name//" is not a scalar") + end if + call ESMF_AttributeSet(field,name=att_name,value=att_val,_RC) + end if + nc = state%get_num_children() + do i=1,nc + child_gc => state%get_child_gridcomp(i) + call MAPL_AddAttributeToFields_I4(child_gc,field_name,att_name,att_val,_RC) + enddo + + _RETURN(_SUCCESS) + end subroutine MAPL_AddAttributeToFields_I4 + end module MAPL_GenericMod diff --git a/generic/VarSpec.F90 b/generic/VarSpec.F90 index 080cce7fff9f..71a7d5e1666b 100644 --- a/generic/VarSpec.F90 +++ b/generic/VarSpec.F90 @@ -1450,15 +1450,24 @@ subroutine MAPL_VarSpecPrint1CSV(spec, compName, rc ) integer , optional , intent(out) :: RC class(Logger), pointer :: lgr + character(len=:), allocatable :: item_type if(.not.associated(SPEC%SPECPtr)) then _RETURN(ESMF_FAILURE) endif + if (iand(spec%specptr%stat,MAPL_BundleItem) /= 0) then + item_type = "esmf_bundle" + else if (iand(spec%specptr%stat,MAPL_StateItem) /=0) then + item_type = "esmf_state" + else + item_type = "esmf_field" + end if + lgr => logging%get_logger('MAPL.GENERIC') - call lgr%info('%a~, %a~, %a~, %i3', & + call lgr%info('%a~, %a~, %a~, %a~, %i3~, %a~ ', & trim(compName), trim(spec%specptr%short_name), trim(spec%specptr%long_name), & - spec%specptr%dims) + trim(spec%specptr%units),spec%specptr%dims,item_type) _RETURN(ESMF_SUCCESS) end subroutine MAPL_VarSpecPrint1CSV diff --git a/gridcomps/CMakeLists.txt b/gridcomps/CMakeLists.txt index 3a29088ffec6..6493a3ad2de6 100644 --- a/gridcomps/CMakeLists.txt +++ b/gridcomps/CMakeLists.txt @@ -17,3 +17,6 @@ add_subdirectory(Cap) add_subdirectory(History) add_subdirectory(Orbit) add_subdirectory(ExtData) +if(USE_EXTDATA2G) + add_subdirectory(ExtData2G) +endif() diff --git a/gridcomps/Cap/CMakeLists.txt b/gridcomps/Cap/CMakeLists.txt index 65af8fbe678e..1800e81928a7 100644 --- a/gridcomps/Cap/CMakeLists.txt +++ b/gridcomps/Cap/CMakeLists.txt @@ -4,6 +4,7 @@ set (srcs MAPL_CapGridComp.F90 MAPL_NUOPCWrapperMod.F90 CapOptions.F90 + ExternalGCStorage.F90 ) if (BUILD_WITH_FLAP) list (APPEND srcs FlapCLI.F90) @@ -11,10 +12,12 @@ endif() esma_add_library (${this} SRCS ${srcs} DEPENDENCIES MAPL.shared MAPL.constants MAPL.base MAPL.profiler MAPL.history - MAPL.ExtData TYPE ${MAPL_LIBRARY_TYPE}) + MAPL.ExtData ${EXTDATA2G_TARGET} TYPE ${MAPL_LIBRARY_TYPE}) target_link_libraries (${this} PUBLIC GFTL::gftl GFTL_SHARED::gftl-shared esmf NetCDF::NetCDF_Fortran PRIVATE MPI::MPI_Fortran $<$:FLAP::FLAP>) +target_compile_definitions (${this} PRIVATE $<$:BUILD_WITH_EXTDATA2G>) + # CMake has an OpenMP issue with NAG Fortran: https://gitlab.kitware.com/cmake/cmake/-/issues/21280 if (NOT CMAKE_Fortran_COMPILER_ID MATCHES "NAG") target_link_libraries(${this} PRIVATE OpenMP::OpenMP_Fortran) diff --git a/gridcomps/Cap/CapOptions.F90 b/gridcomps/Cap/CapOptions.F90 index 104136cf2553..661dedc5593e 100644 --- a/gridcomps/Cap/CapOptions.F90 +++ b/gridcomps/Cap/CapOptions.F90 @@ -16,6 +16,7 @@ module mapl_CapOptionsMod logical :: use_comm_world = .true. character(:), allocatable :: egress_file character(:), allocatable :: cap_rc_file + character(:), allocatable :: root_dso type (ESMF_LogKind_Flag) :: esmf_logging_mode = ESMF_LOGKIND_NONE integer :: npes_model = -1 ! only one of the next two options can have nonzero values diff --git a/gridcomps/Cap/ExternalGCStorage.F90 b/gridcomps/Cap/ExternalGCStorage.F90 new file mode 100644 index 000000000000..8711c21b8126 --- /dev/null +++ b/gridcomps/Cap/ExternalGCStorage.F90 @@ -0,0 +1,14 @@ +module MAPL_ExternalGCStorage +use esmf +implicit none + +type t_extdata_state + type(ESMF_State) :: expState + type(ESMF_GridComp) :: gc +end type t_extdata_state + +type extdata_wrap + type (t_extdata_state), pointer :: PTR +end type extdata_wrap + +end module MAPL_ExternalGCStorage diff --git a/gridcomps/Cap/FlapCLI.F90 b/gridcomps/Cap/FlapCLI.F90 index 32ef0c687ac6..6c81e1e702a4 100644 --- a/gridcomps/Cap/FlapCLI.F90 +++ b/gridcomps/Cap/FlapCLI.F90 @@ -92,6 +92,13 @@ subroutine add_command_line_options(options, unusable, rc) integer :: status _UNUSED_DUMMY(unusable) + call options%add(switch='--root_dso', & + help='name of root dso to use', & + required=.false., & + def='none', & + act='store', & + error=status) + _VERIFY(status) call options%add(switch='--esmf_logtype', & help='ESMF Logging type', & required=.false., & @@ -275,6 +282,9 @@ subroutine fill_cap_options(flapCLI, cap_options, unusable, rc) integer, allocatable :: nodes_output_server(:) + call flapCLI%cli_options%get(val=buffer, switch='--root_dso', error=status); _VERIFY(status) + cap_options%root_dso = trim(buffer) + call flapCLI%cli_options%get(val=buffer, switch='--egress_file', error=status); _VERIFY(status) cap_options%egress_file = trim(buffer) @@ -357,6 +367,8 @@ function old_CapOptions_from_Flap( flapCLI, unusable, rc) result (cap_options) integer, allocatable :: nodes_output_server(:) + call flapCLI%cli_options%get(val=buffer, switch='--root_dso', error=status); _VERIFY(status) + cap_options%root_dso = trim(buffer) call flapCLI%cli_options%get(val=buffer, switch='--egress_file', error=status); _VERIFY(status) cap_options%egress_file = trim(buffer) diff --git a/gridcomps/Cap/MAPL_Cap.F90 b/gridcomps/Cap/MAPL_Cap.F90 index 5feeeeb6eb21..624257ffdb58 100755 --- a/gridcomps/Cap/MAPL_Cap.F90 +++ b/gridcomps/Cap/MAPL_Cap.F90 @@ -25,9 +25,11 @@ module MAPL_CapMod private character(:), allocatable :: name procedure(), nopass, pointer :: set_services => null() + logical :: non_dso = .false. integer :: comm_world integer :: rank integer :: npes_member + character(:), allocatable :: root_dso type (MAPL_CapOptions), allocatable :: cap_options ! misc @@ -62,7 +64,8 @@ module MAPL_CapMod end type MAPL_Cap interface MAPL_Cap - module procedure new_MAPL_Cap + module procedure new_MAPL_Cap_from_set_services + module procedure new_MAPL_Cap_from_dso end interface MAPL_Cap @@ -74,18 +77,55 @@ end function c_chdir end interface contains - - function new_MAPL_Cap(name, set_services, unusable, cap_options, rc) result(cap) + + function new_MAPL_Cap_from_set_services(name, set_services, unusable, cap_options, rc) result(cap) type (MAPL_Cap) :: cap character(*), intent(in) :: name procedure() :: set_services class (KeywordEnforcer), optional, intent(in) :: unusable type ( MAPL_CapOptions), optional, intent(in) :: cap_options integer, optional, intent(out) :: rc - integer :: status + integer :: status cap%name = name cap%set_services => set_services + cap%non_dso = .true. + + if (present(cap_options)) then + allocate(cap%cap_options, source = cap_options) + else + allocate(cap%cap_options, source = MAPL_CapOptions()) + endif + + if (cap%cap_options%use_comm_world) then + cap%comm_world = MPI_COMM_WORLD + cap%cap_options%comm = MPI_COMM_WORLD + else + cap%comm_world = cap%cap_options%comm + endif + + call cap%initialize_mpi(rc=status) + _VERIFY(status) + + call MAPL_Initialize(comm=cap%comm_world, & + logging_config=cap%cap_options%logging_config, & + rc=status) + _VERIFY(status) + + _RETURN(_SUCCESS) + _UNUSED_DUMMY(unusable) + + end function new_MAPL_Cap_from_set_services + + function new_MAPL_Cap_from_dso(name, unusable, cap_options, rc) result(cap) + type (MAPL_Cap) :: cap + character(*), intent(in) :: name + class (KeywordEnforcer), optional, intent(in) :: unusable + type ( MAPL_CapOptions), optional, intent(in) :: cap_options + integer, optional, intent(out) :: rc + integer :: status + + cap%name = name if (present(cap_options)) then allocate(cap%cap_options, source = cap_options) @@ -111,7 +151,7 @@ function new_MAPL_Cap(name, set_services, unusable, cap_options, rc) result(cap) _RETURN(_SUCCESS) _UNUSED_DUMMY(unusable) - end function new_MAPL_Cap + end function new_MAPL_Cap_from_dso ! 3. Run the ensemble (default is 1 member) @@ -314,8 +354,14 @@ subroutine initialize_cap_gc(this, unusable, n_run_phases, rc) _UNUSED_DUMMY(unusable) - call MAPL_CapGridCompCreate(this%cap_gc, this%set_services, this%get_cap_rc_file(), & - this%name, this%get_egress_file(), n_run_phases=n_run_phases, rc=status) + if (this%non_dso) then + call MAPL_CapGridCompCreate(this%cap_gc, this%get_cap_rc_file(), & + this%name, this%get_egress_file(), n_run_phases=n_run_phases, root_set_services = this%set_services,rc=status) + else + _ASSERT(this%cap_options%root_dso /= 'none',"No set services specified, must pass a dso") + call MAPL_CapGridCompCreate(this%cap_gc, this%get_cap_rc_file(), & + this%name, this%get_egress_file(), n_run_phases=n_run_phases, root_dso = this%cap_options%root_dso,rc=status) + end if _VERIFY(status) _RETURN(_SUCCESS) end subroutine initialize_cap_gc diff --git a/gridcomps/Cap/MAPL_CapGridComp.F90 b/gridcomps/Cap/MAPL_CapGridComp.F90 index b8a72a922abb..7a53f9d5a610 100644 --- a/gridcomps/Cap/MAPL_CapGridComp.F90 +++ b/gridcomps/Cap/MAPL_CapGridComp.F90 @@ -17,8 +17,10 @@ module MAPL_CapGridCompMod use MAPL_ShmemMod use MAPL_HistoryGridCompMod, only : Hist_SetServices => SetServices use MAPL_HistoryGridCompMod, only : HISTORY_ExchangeListWrap - use MAPL_ExtDataGridCompMod, only : ExtData_SetServices => SetServices - use MAPL_ExtDataGridCompMod, only : T_EXTDATA_STATE, EXTDATA_WRAP +#if defined(BUILD_WITH_EXTDATA2G) + use MAPL_ExtDataGridComp2G, only : ExtData2G_SetServices => SetServices +#endif + use MAPL_ExtDataGridCompMod, only : ExtData1G_SetServices => SetServices use MAPL_ConfigMod use MAPL_DirPathMod use MAPL_KeywordEnforcerMod @@ -28,9 +30,10 @@ module MAPL_CapGridCompMod use gFTL_StringVector use pflogger, only: logging, Logger use MAPL_TimeUtilsMod, only: is_valid_time, is_valid_date + use MAPL_ExternalGCStorage use iso_fortran_env - + implicit none private @@ -48,9 +51,11 @@ module MAPL_CapGridCompMod private type (ESMF_GridComp) :: gc procedure(), pointer, nopass :: root_set_services => null() + character(len=:), allocatable :: root_dso character(len=:), allocatable :: final_file, name, cap_rc_file integer :: nsteps, heartbeat_dt, perpetual_year, perpetual_month, perpetual_day - logical :: amiroot, lperp, started_loop_timer + logical :: amiroot, started_loop_timer + logical :: lperp = .false. integer :: extdata_id, history_id, root_id, printspec type(ESMF_Clock) :: clock, clock_hist type(ESMF_Config) :: cf_ext, cf_root, cf_hist, config @@ -103,27 +108,32 @@ module MAPL_CapGridCompMod contains - - subroutine MAPL_CapGridCompCreate(cap, root_set_services, cap_rc, name, final_file, unusable, n_run_phases, rc) + + subroutine MAPL_CapGridCompCreate(cap, cap_rc, name, final_file, unusable, n_run_phases, root_set_services, root_dso, rc) use mapl_StubComponent type(MAPL_CapGridComp), intent(out), target :: cap - procedure() :: root_set_services character(*), intent(in) :: cap_rc, name character(len=*), optional, intent(in) :: final_file class(KeywordEnforcer), optional, intent(in) :: unusable + procedure(), optional :: root_set_services + character(len=*), optional, intent(in) :: root_dso integer, optional, intent(in) :: n_run_phases integer, optional, intent(out) :: rc type(MAPL_CapGridComp_Wrapper) :: cap_wrapper type(MAPL_MetaComp), pointer :: meta => null() - integer :: status + integer :: status character(*), parameter :: cap_name = "CAP" type(StubComponent) :: stub_component - + _UNUSED_DUMMY(unusable) cap%cap_rc_file = cap_rc - cap%root_set_services => root_set_services + if (present(root_set_services)) cap%root_set_services => root_set_services + if (present(root_dso)) cap%root_dso = root_dso + if (present(root_dso) .and. present(root_set_services)) then + _FAIL("can only specify a setservice pointer or a dso to use") + end if if (present(final_file)) then allocate(cap%final_file, source=final_file) end if @@ -174,8 +184,8 @@ subroutine initialize_gc(gc, import_state, export_state, clock, rc) integer :: status - type (T_ExtData_STATE), pointer :: ExtData_internal_state => null() - type (ExtData_wrap) :: wrap + type (t_extdata_state), pointer :: ExtData_internal_state => null() + type (extdata_wrap) :: wrap character(len=ESMF_MAXSTR ) :: timerModeStr @@ -206,12 +216,14 @@ subroutine initialize_gc(gc, import_state, export_state, clock, rc) type (MAPL_MetaComp), pointer :: maplobj, root_obj + character(len=ESMF_MAXSTR) :: sharedObj type (ESMF_GridComp), pointer :: root_gc procedure(), pointer :: root_set_services type(MAPL_CapGridComp), pointer :: cap class(BaseProfiler), pointer :: t_p class(Logger), pointer :: lgr type(ESMF_Clock) :: cap_clock + logical :: use_extdata2g _UNUSED_DUMMY(import_state) _UNUSED_DUMMY(export_state) @@ -273,7 +285,7 @@ subroutine initialize_gc(gc, import_state, export_state, clock, rc) cap%nsteps = 1 cap%compute_throughput = .false. else - ! Create Clock. This is a private routine that sets the start and + ! Create Clock. This is a private routine that sets the start and ! end times and the time interval of the clock from the configuration. ! The start time is temporarily set to 1 interval before the time in the ! configuration. Once the Alarms are set in intialize, the clock will @@ -367,33 +379,33 @@ subroutine initialize_gc(gc, import_state, export_state, clock, rc) endif endif - ! Get configurable info to create HIST + ! Get configurable info to create HIST ! and the ROOT of the computational hierarchy !--------------------------------------------- !BOR ! !RESOURCE_ITEM: string :: Name of ROOT's config file - call MAPL_GetResource(MAPLOBJ, ROOT_CF, "ROOT_CF:", default = "ROOT.rc", rc = status) + call MAPL_GetResource(MAPLOBJ, ROOT_CF, "ROOT_CF:", default = "ROOT.rc", rc = status) _VERIFY(status) ! !RESOURCE_ITEM: string :: Name to assign to the ROOT component - call MAPL_GetResource(MAPLOBJ, ROOT_NAME, "ROOT_NAME:", default = "ROOT", rc = status) + call MAPL_GetResource(MAPLOBJ, ROOT_NAME, "ROOT_NAME:", default = "ROOT", rc = status) _VERIFY(status) - ! !RESOURCE_ITEM: string :: Name of HISTORY's config file - call MAPL_GetResource(MAPLOBJ, HIST_CF, "HIST_CF:", default = "HIST.rc", rc = status) + ! !RESOURCE_ITEM: string :: Name of HISTORY's config file + call MAPL_GetResource(MAPLOBJ, HIST_CF, "HIST_CF:", default = "HIST.rc", rc = status) _VERIFY(status) ! !RESOURCE_ITEM: string :: Name of ExtData's config file call MAPL_GetResource(MAPLOBJ, EXTDATA_CF, "EXTDATA_CF:", default = 'ExtData.rc', rc = status) _VERIFY(status) - ! !RESOURCE_ITEM: string :: Control Timers + ! !RESOURCE_ITEM: string :: Control Timers call MAPL_GetResource(MAPLOBJ, enableTimers, "MAPL_ENABLE_TIMERS:", default = 'NO', rc = status) _VERIFY(status) - ! !RESOURCE_ITEM: string :: Control Memory Diagnostic Utility + ! !RESOURCE_ITEM: string :: Control Memory Diagnostic Utility call MAPL_GetResource(MAPLOBJ, enableMemUtils, "MAPL_ENABLE_MEMUTILS:", default='NO', rc = status) _VERIFY(status) call MAPL_GetResource(MAPLOBJ, MemUtilsMode, "MAPL_MEMUTILS_MODE:", default = MAPL_MemUtilsModeBase, rc = status) @@ -401,6 +413,7 @@ subroutine initialize_gc(gc, import_state, export_state, clock, rc) !EOR enableTimers = ESMF_UtilStringUpperCase(enableTimers, rc = status) _VERIFY(status) + call MAPL_GetResource(maplobj,use_extdata2g,"USE_EXTDATA2G:",default=.false.,_RC) if (enableTimers /= 'YES') then call MAPL_ProfDisable(rc = status) @@ -411,7 +424,7 @@ subroutine initialize_gc(gc, import_state, export_state, clock, rc) _VERIFY(STATUS) timerModeStr = ESMF_UtilStringUpperCase(timerModeStr, rc=STATUS) - _VERIFY(STATUS) + _VERIFY(STATUS) end if cap%started_loop_timer=.false. @@ -506,7 +519,7 @@ subroutine initialize_gc(gc, import_state, export_state, clock, rc) ! Add a SINGLE_COLUMN flag in HISTORY.rc based on DYCORE value(from AGCM.rc) !--------------------------------------------------------------------------- - call ESMF_ConfigGetAttribute(cap%cf_root, value=DYCORE, Label="DYCORE:", rc=status) + call ESMF_ConfigGetAttribute(cap%cf_root, value=DYCORE, Label="DYCORE:", default = 'FV3', rc=status) _VERIFY(STATUS) if (DYCORE == 'DATMO') then snglcol = 1 @@ -541,11 +554,17 @@ subroutine initialize_gc(gc, import_state, export_state, clock, rc) root_set_services => cap%root_set_services call t_p%start('SetService') - cap%root_id = MAPL_AddChild(MAPLOBJ, name = root_name, SS = root_set_services, rc = status) - _VERIFY(status) + if (.not.allocated(cap%root_dso)) then + cap%root_id = MAPL_AddChild(MAPLOBJ, name = root_name, SS = root_set_services, rc = status) + _VERIFY(status) + else + sharedObj = trim(cap%root_dso) + cap%root_id = MAPL_AddChild(MAPLOBJ, root_name, 'setservices_', sharedObj=sharedObj, rc=status) + _VERIFY(status) + end if root_gc => maplobj%get_child_gridcomp(cap%root_id) - call MAPL_GetObjectFromGC(root_gc, root_obj, rc=status) - _ASSERT(cap%n_run_phases <= SIZE(root_obj%phase_run),"n_run_phases in cap_gc should not exceed n_run_phases in root") + call MAPL_GetObjectFromGC(root_gc, root_obj, rc=status) + _ASSERT(cap%n_run_phases <= SIZE(root_obj%phase_run),"n_run_phases in cap_gc should not exceed n_run_phases in root") ! Create History child !---------------------- @@ -553,7 +572,7 @@ subroutine initialize_gc(gc, import_state, export_state, clock, rc) call MAPL_Set(MAPLOBJ, CF=CAP%CF_HIST, RC=STATUS) _VERIFY(STATUS) - cap%history_id = MAPL_AddChild( MAPLOBJ, name = 'HIST', SS = HIST_SetServices, rc = status) + cap%history_id = MAPL_AddChild( MAPLOBJ, name = 'HIST', SS = HIST_SetServices, rc = status) _VERIFY(status) @@ -578,8 +597,16 @@ subroutine initialize_gc(gc, import_state, export_state, clock, rc) call MAPL_Set(MAPLOBJ, CF=CAP%CF_EXT, RC=STATUS) _VERIFY(STATUS) - cap%extdata_id = MAPL_AddChild (MAPLOBJ, name = 'EXTDATA', SS = ExtData_SetServices, rc = status) - _VERIFY(status) + if (use_extdata2g) then +#if defined(BUILD_WITH_EXTDATA2G) + cap%extdata_id = MAPL_AddChild (MAPLOBJ, name = 'EXTDATA', SS = ExtData2G_SetServices, _RC) +#else + call lgr%error('ExtData2G requested but not built') + _FAIL('ExtData2G requested but not built') +#endif + else + cap%extdata_id = MAPL_AddChild (MAPLOBJ, name = 'EXTDATA', SS = ExtData1G_SetServices, _RC) + end if call t_p%stop('SetService') ! Add NX and NY from AGCM.rc to ExtData.rc as well as name of ExtData rc file @@ -630,7 +657,7 @@ subroutine initialize_gc(gc, import_state, export_state, clock, rc) call cap%initialize_history(rc=status) _VERIFY(status) - call cap%initialize_extdata(rc=status) + call cap%initialize_extdata(root_gc,rc=status) _VERIFY(status) ! Finally check is this is a regular replay @@ -646,7 +673,7 @@ subroutine initialize_gc(gc, import_state, export_state, clock, rc) _VERIFY(STATUS) ExtData_internal_state => wrap%ptr ExtData_internal_state%gc = CAP%GCS(cap%extdata_id) - ExtData_internal_state%expState = CAP%CHILD_EXPORTS(cap%extdata_id) + ExtData_internal_state%expState = CAP%CHILD_EXPORTS(cap%extdata_id) end if call t_p%stop('Initialize') end if @@ -655,7 +682,7 @@ subroutine initialize_gc(gc, import_state, export_state, clock, rc) _RETURN(ESMF_SUCCESS) end subroutine initialize_gc - + subroutine initialize_history(cap, rc) class(MAPL_CapGridComp), intent(inout) :: cap integer, optional, intent(out) :: rc @@ -689,8 +716,9 @@ subroutine initialize_history(cap, rc) end subroutine initialize_history - subroutine initialize_extdata(cap , rc) + subroutine initialize_extdata(cap , root_gc, rc) class(MAPL_CapGridComp), intent(inout) :: cap + type (ESMF_GridComp), intent(inout), pointer :: root_gc integer, optional, intent(out) :: rc integer :: item_count, status type (ESMF_StateItem_Flag), pointer :: item_types(:) @@ -757,6 +785,7 @@ subroutine initialize_extdata(cap , rc) if (item_types(i) == ESMF_StateItem_Field) then call ESMF_StateGet(root_imports, item_names(i), field, rc = status) _VERIFY(status) + call MAPL_AddAttributeToFields(root_gc,trim(item_names(i)),'RESTART',MAPL_RestartSkip,_RC) call MAPL_StateAdd(state, field, rc = status) _VERIFY(status) else if (item_types(i) == ESMF_StateItem_FieldBundle) then @@ -774,18 +803,18 @@ subroutine initialize_extdata(cap , rc) !------------------------ call ESMF_GridCompInitialize (cap%gcs(cap%extdata_id), importState = cap%child_imports(cap%extdata_id), & - exportState = cap%child_exports(cap%extdata_id), & + exportState = cap%child_exports(cap%extdata_id), & clock = cap%clock, userRc = status) _VERIFY(status) _RETURN(ESMF_SUCCESS) end subroutine initialize_extdata - - + + subroutine run_gc(gc, import, export, clock, rc) !ARGUMENTS: - type(ESMF_GridComp) :: GC ! Gridded component + type(ESMF_GridComp) :: GC ! Gridded component type(ESMF_State) :: import ! Import state type(ESMF_State) :: export ! Export state type(ESMF_Clock) :: clock ! The clock @@ -829,7 +858,7 @@ subroutine finalize_gc(gc, import_state, export_state, clock, rc) _UNUSED_DUMMY(import_state) _UNUSED_DUMMY(export_state) _UNUSED_DUMMY(clock) - + cap => get_CapGridComp_from_gc(gc) call MAPL_GetObjectFromGC(gc, maplobj, rc=status) _VERIFY(status) @@ -923,7 +952,7 @@ end subroutine set_services subroutine initialize(this, rc) class(MAPL_CapGridComp), intent(inout) :: this integer, optional, intent(out) :: rc - + integer :: status call ESMF_GridCompInitialize(this%gc, userRC=status) @@ -953,9 +982,9 @@ end subroutine run subroutine finalize(this, rc) class(MAPL_CapGridComp), intent(inout) :: this integer, optional, intent(out) :: rc - - integer :: status - + + integer :: status + call ESMF_GridCompFinalize(this%gc, rc = status) _VERIFY(status) _RETURN(ESMF_SUCCESS) @@ -974,7 +1003,7 @@ function get_model_duration(this, rc) result (duration) end function get_model_duration - + function get_am_i_root(this, rc) result (amiroot) class (MAPL_CapGridComp) :: this integer, optional, intent(out) :: rc @@ -1041,8 +1070,8 @@ function get_CapGridComp_from_gc(gc) result(cap) cap => cap_wrapper%ptr end function get_CapGridComp_from_gc - - + + function get_vec_from_config(config, key) result(vec) type(ESMF_Config), intent(inout) :: config character(len=*), intent(in) :: key @@ -1050,13 +1079,13 @@ function get_vec_from_config(config, key) result(vec) integer :: status, rc character(len=ESMF_MAXSTR) :: cap_import type(StringVector) :: vec - + call ESMF_ConfigFindLabel(config, key//":", isPresent = present, rc = status) _VERIFY(status) cap_import = "" if (present) then - + do while(trim(cap_import) /= "::") call ESMF_ConfigNextLine(config, rc = status) _VERIFY(status) @@ -1065,10 +1094,10 @@ function get_vec_from_config(config, key) result(vec) if (trim(cap_import) /= "::") call vec%push_back(trim(cap_import)) end do end if - + end function get_vec_from_config - + logical function vector_contains_str(vector, string) type(StringVector), intent(in) :: vector character(len=*), intent(in) :: string @@ -1090,7 +1119,7 @@ logical function vector_contains_str(vector, string) end function vector_contains_str - + subroutine run_MAPL_GridComp(gc, phase, rc) type (ESMF_Gridcomp) :: gc integer, optional, intent(in) :: phase @@ -1098,7 +1127,6 @@ subroutine run_MAPL_GridComp(gc, phase, rc) integer :: reverse_time ! GCHP only -! ewl: phase_ was added between 2.6.3 and 2.16 integer :: n, status, phase_ logical :: done @@ -1338,19 +1366,19 @@ subroutine last_phase(rc) _VERIFY(status) end_run_timer = MPI_WTime(status) end if - + call ESMF_ClockAdvance(this%clock, rc = status) _VERIFY(STATUS) call ESMF_ClockAdvance(this%clock_hist, rc = status) _VERIFY(STATUS) - + ! Update Perpetual Clock ! ---------------------- if (this%lperp) then call Perpetual_Clock(this, status) _VERIFY(status) end if - + call ESMF_GridCompRun(this%gcs(this%history_id), importstate=this%child_imports(this%history_id), & exportstate = this%child_exports(this%history_id), & clock = this%clock_hist, userrc = status) @@ -1381,7 +1409,7 @@ subroutine print_throughput(rc) integer :: AGCM_YY, AGCM_MM, AGCM_DD, AGCM_H, AGCM_M, AGCM_S integer :: HRS_R, MIN_R, SEC_R - + call ESMF_ClockGet(this%clock, CurrTime = currTime, rc = status) _VERIFY(status) call ESMF_TimeGet(CurrTime, YY = AGCM_YY, & @@ -1421,11 +1449,11 @@ subroutine print_throughput(rc) LOOP_THROUGHPUT,INST_THROUGHPUT,RUN_THROUGHPUT,HRS_R,MIN_R,SEC_R,& mem_committed_percent,mem_used_percent 1000 format(1x,'AGCM Date: ',i4.4,'/',i2.2,'/',i2.2,2x,'Time: ',i2.2,':',i2.2,':',i2.2, & - 2x,'Throughput(days/day)[Avg Tot Run]: ',f8.1,1x,f8.1,1x,f8.1,2x,'TimeRemaining(Est) ',i3.3,':'i2.2,':',i2.2,2x, & + 2x,'Throughput(days/day)[Avg Tot Run]: ',f12.1,1x,f12.1,1x,f12.1,2x,'TimeRemaining(Est) ',i3.3,':'i2.2,':',i2.2,2x, & f5.1,'% : ',f5.1,'% Mem Comm:Used') _RETURN(_SUCCESS) - + end subroutine end subroutine step @@ -1465,7 +1493,7 @@ subroutine refresh_state(this, rc) integer, intent(out) :: rc integer :: status - integer :: i + integer :: i call MAPL_GenericStateRestore(this%gcs(this%root_id),this%child_imports(this%root_id), & this%child_exports(this%root_id),this%clock,rc=status) _VERIFY(status) @@ -1592,7 +1620,7 @@ subroutine destroy_state(this, rc) call MAPL_DestroyStateSave(this%gcs(this%root_id),rc=status) _VERIFY(status) - + if (allocated(this%alarm_list)) deallocate(this%alarm_list) if (allocated(this%AlarmRingTime)) deallocate(this%alarmRingTime) if (allocated(this%ringingState)) deallocate(this%ringingState) @@ -1613,7 +1641,7 @@ subroutine rewind_clock(this, time, rc) if (current_time > time) then call ESMF_ClockSet(this%clock,direction=ESMF_DIRECTION_REVERSE,rc=status) _VERIFY(status) - do + do call ESMF_ClockAdvance(this%clock,rc=status) _VERIFY(status) call ESMF_ClockGet(this%clock,currTime=ct,rc=status) @@ -1623,13 +1651,13 @@ subroutine rewind_clock(this, time, rc) call ESMF_ClockSet(this%clock,direction=ESMF_DIRECTION_FORWARD,rc=status) _VERIFY(status) end if - + call ESMF_ClockGet(this%clock_hist,currTime=current_time,rc=status) _VERIFY(status) if (current_time > time) then call ESMF_ClockSet(this%clock_hist,direction=ESMF_DIRECTION_REVERSE,rc=status) _VERIFY(status) - do + do call ESMF_ClockAdvance(this%clock_hist,rc=status) _VERIFY(status) call ESMF_ClockGet(this%clock_hist,currTime=ct,rc=status) @@ -1639,8 +1667,8 @@ subroutine rewind_clock(this, time, rc) call ESMF_ClockSet(this%clock_hist,direction=ESMF_DIRECTION_FORWARD,rc=status) _VERIFY(status) end if - - + + _RETURN(_SUCCESS) end subroutine rewind_clock @@ -1722,7 +1750,7 @@ end subroutine step_reverse ! !IROUTINE: MAPL_ClockInit -- Sets the clock - ! !INTERFACE: + ! !INTERFACE: subroutine MAPL_ClockInit ( MAPLOBJ, Clock, nsteps, rc) @@ -1735,10 +1763,10 @@ subroutine MAPL_ClockInit ( MAPLOBJ, Clock, nsteps, rc) ! !DESCRIPTION: - ! This is a private routine that sets the start and + ! This is a private routine that sets the start and ! end times and the time interval of the application clock from the configuration. ! This time interal is the ``heartbeat'' of the application. - ! The Calendar is set to Gregorian by default. + ! The Calendar is set to Gregorian by default. ! The start time is temporarily set to 1 interval before the time in the ! configuration. Once the Alarms are set in intialize, the clock will ! be advanced to guarantee it and its alarms are in the same state as they @@ -1752,6 +1780,7 @@ subroutine MAPL_ClockInit ( MAPLOBJ, Clock, nsteps, rc) type(ESMF_Time) :: CurrTime ! Current Current Time of Experiment type(ESMF_TimeInterval) :: timeStep ! HEARTBEAT type(ESMF_TimeInterval) :: duration + type(ESMF_TimeInterval) :: maxDuration type(ESMF_Calendar) :: cal character(ESMF_MAXSTR) :: calendar @@ -1946,7 +1975,7 @@ subroutine MAPL_ClockInit ( MAPLOBJ, Clock, nsteps, rc) M = END_M , & S = END_S , & calendar=cal, rc = STATUS ) - _VERIFY(STATUS) + _VERIFY(STATUS) ! Read CAP Restart File for Current Time ! -------------------------------------- @@ -1988,7 +2017,7 @@ subroutine MAPL_ClockInit ( MAPLOBJ, Clock, nsteps, rc) S = CUR_S , & calendar=cal, rc = STATUS ) _VERIFY(STATUS) - + ! initialize final stop time ! -------------------------- @@ -2003,7 +2032,10 @@ subroutine MAPL_ClockInit ( MAPLOBJ, Clock, nsteps, rc) rc = STATUS ) _VERIFY(STATUS) - if (endTime < startTime) duration = -duration + if (endTime < startTime) duration = -duration ! GCHP + + maxDuration = EndTime - currTime + if (duration > maxDuration) duration = maxDuration stopTime = currTime + duration @@ -2146,7 +2178,7 @@ subroutine Perpetual_Clock (this, rc) (PERPETUAL_DAY == -999) ) then AGCM_YY = PERPETUAL_YEAR AGCM_MM = PERPETUAL_MONTH - if( HIST_MM /= PERPETUAL_MONTH ) then + if( HIST_MM /= PERPETUAL_MONTH ) then HIST_MM = PERPETUAL_MONTH if( PERPETUAL_MONTH /= 12) HIST_YY = HIST_YY + 1 call ESMF_AlarmRingerOn( PERPETUAL, rc=status ) @@ -2162,7 +2194,7 @@ subroutine Perpetual_Clock (this, rc) (PERPETUAL_MONTH /= -999) .and. & (PERPETUAL_DAY == -999) ) then AGCM_MM = PERPETUAL_MONTH - if( HIST_MM /= PERPETUAL_MONTH ) then + if( HIST_MM /= PERPETUAL_MONTH ) then HIST_MM = PERPETUAL_MONTH if( PERPETUAL_MONTH /= 12) HIST_YY = HIST_YY + 1 AGCM_YY = HIST_YY @@ -2177,7 +2209,7 @@ subroutine Perpetual_Clock (this, rc) AGCM_YY = PERPETUAL_YEAR AGCM_MM = PERPETUAL_MONTH AGCM_DD = PERPETUAL_DAY - if( HIST_MM /= PERPETUAL_MONTH ) then + if( HIST_MM /= PERPETUAL_MONTH ) then HIST_MM = PERPETUAL_MONTH if( PERPETUAL_MONTH /= 12) HIST_YY = HIST_YY + 1 call ESMF_AlarmRingerOn( PERPETUAL, rc=status ) @@ -2219,7 +2251,7 @@ subroutine ESMFL_ClockSet(clock, currTime, rc) ! ErrLog vars integer :: status - ! Local Vars + ! Local Vars type(ESMF_Time) :: targetTime type(ESMF_Time) :: cTime type(ESMF_TimeInterval) :: zero diff --git a/gridcomps/ExtData/ExtDataGridCompMod.F90 b/gridcomps/ExtData/ExtDataGridCompMod.F90 index 9c48fe1e38eb..694d07c4585f 100644 --- a/gridcomps/ExtData/ExtDataGridCompMod.F90 +++ b/gridcomps/ExtData/ExtDataGridCompMod.F90 @@ -11,7 +11,7 @@ MODULE MAPL_ExtDataGridCompMod !BOP ! !MODULE: MAPL_ExtDataGridCompMod - Implements Interface to External Data ! -! !DESCRIPTION: +! !DESCRIPTION: ! ! {\tt MAPL\_ExtDataGridComp} is an ESMF gridded component implementing ! an interface to boundary conditions and other types of external data @@ -64,8 +64,6 @@ MODULE MAPL_ExtDataGridCompMod ! !PUBLIC MEMBER FUNCTIONS: PUBLIC SetServices - public T_EXTDATA_STATE - public EXTDATA_WRAP !EOP ! ! !REVISION HISTORY: @@ -136,12 +134,12 @@ MODULE MAPL_ExtDataGridCompMod ! the corresponding names of the two vector components on file character(len=ESMF_MAXSTR) :: fcomp1, fcomp2 type(GriddedIOitem) :: fileVars - type(SimpleAlarm) :: update_alarm + type(SimpleAlarm) :: update_alarm integer :: collection_id integer :: pfioCollection_id integer :: iclient_collection_id - + logical :: ExtDataAlloc ! time shifting during continuous update type(ESMF_TimeInterval) :: tshift @@ -162,7 +160,7 @@ MODULE MAPL_ExtDataGridCompMod PRIVATE integer :: nItems = 0 logical :: have_phis - type(PrimaryExport), pointer :: item(:) => null() + type(PrimaryExport), pointer :: item(:) => null() end type PrimaryExports type DerivedExport @@ -215,17 +213,6 @@ MODULE MAPL_ExtDataGridCompMod type (MAPL_ExtData_State), pointer :: PTR => null() end type MAPL_ExtData_WRAP - type T_EXTDATA_STATE - type(ESMF_State) :: expState - type(ESMF_GridComp) :: gc - end type T_EXTDATA_STATE - - ! Wrapper for extracting internal state - ! ------------------------------------- - type EXTDATA_WRAP - type (T_EXTDATA_STATE), pointer :: PTR - end type EXTDATA_WRAP - class(Logger), pointer :: lgr @@ -248,7 +235,7 @@ SUBROUTINE SetServices ( GC, RC ) type(ESMF_GridComp), intent(INOUT) :: GC ! gridded component integer, optional :: RC ! return code -! !DESCRIPTION: Sets Initialize, Run and Finalize services. +! !DESCRIPTION: Sets Initialize, Run and Finalize services. ! ! !REVISION HISTORY: ! @@ -279,7 +266,7 @@ SUBROUTINE SetServices ( GC, RC ) allocate ( self, stat=STATUS ) _VERIFY(STATUS) wrap%ptr => self - + ! ------------------------ ! ESMF Functional Services ! ------------------------ @@ -289,12 +276,12 @@ SUBROUTINE SetServices ( GC, RC ) call MAPL_GridCompSetEntryPoint ( GC, ESMF_METHOD_INITIALIZE, Initialize_, __RC__ ) call MAPL_GridCompSetEntryPoint ( GC, ESMF_METHOD_RUN, Run_, __RC__ ) call MAPL_GridCompSetEntryPoint ( GC, ESMF_METHOD_FINALIZE, Finalize_, __RC__ ) - + ! Store internal state in GC ! -------------------------- call ESMF_UserCompSetInternalState ( GC, 'MAPL_ExtData_state', wrap, STATUS ) _VERIFY(STATUS) - + ! Generic Set Services ! -------------------- @@ -335,7 +322,7 @@ SUBROUTINE Initialize_ ( GC, IMPORT, EXPORT, CLOCK, rc ) type(ESMF_State), intent(inout) :: EXPORT ! Export State integer, intent(out) :: rc ! Error return code: ! 0 - all is well - ! 1 - + ! 1 - ! !DESCRIPTION: This is a simple ESMF wrapper. ! @@ -348,7 +335,7 @@ SUBROUTINE Initialize_ ( GC, IMPORT, EXPORT, CLOCK, rc ) type(MAPL_ExtData_state), pointer :: self ! Legacy state type(ESMF_Grid) :: GRID ! Grid - type(ESMF_Config) :: CF_main ! Universal Config + type(ESMF_Config) :: CF_main ! Universal Config character(len=ESMF_MAXSTR) :: comp_name character(len=ESMF_MAXSTR) :: Iam @@ -358,7 +345,7 @@ SUBROUTINE Initialize_ ( GC, IMPORT, EXPORT, CLOCK, rc ) type(PrimaryExports) :: Primary type(PrimaryExport), pointer :: item type(DerivedExports) :: Derived - type(DerivedExport), pointer :: derivedItem + type(DerivedExport), pointer :: derivedItem integer :: nLines integer :: i integer :: ItemCount, itemCounter, j @@ -427,7 +414,7 @@ SUBROUTINE Initialize_ ( GC, IMPORT, EXPORT, CLOCK, rc ) ! Start Some Timers ! ----------------- call MAPL_GetObjectFromGC ( gc, MAPLSTATE, RC=STATUS) - _VERIFY(STATUS) + _VERIFY(STATUS) call MAPL_TimerOn(MAPLSTATE,"Initialize") ! Get information from export state @@ -495,9 +482,9 @@ SUBROUTINE Initialize_ ( GC, IMPORT, EXPORT, CLOCK, rc ) totalPrimaryEntries=0 totalDerivedEntries=0 call ESMF_ConfigNextLine(CFtemp,__RC__) - do while (status == ESMF_SUCCESS) + do while (status == ESMF_SUCCESS) call ESMF_ConfigNextLine(CFtemp,rc=status) - if (status == ESMF_SUCCESS) then + if (status == ESMF_SUCCESS) then call ESMF_ConfigGetAttribute(CFtemp,thisLine,rc=status) _VERIFY(STATUS) if (trim(thisLine) == "PrimaryExports%%" .or. trim(thisLine) == "DerivedExports%%" ) then @@ -528,14 +515,14 @@ SUBROUTINE Initialize_ ( GC, IMPORT, EXPORT, CLOCK, rc ) allocate(primary%item(totalPrimaryEntries), stat=STATUS) _VERIFY(STATUS) end if - + derived%nItems = totalDerivedEntries - if (totalDerivedEntries > 0) then + if (totalDerivedEntries > 0) then Allocate(DerivedVarNeeded(totalDerivedEntries),stat=status) _VERIFY(STATUS) DerivedVarNeeded = .false. allocate(derived%item(totalDerivedEntries),stat=status) - _VERIFY(STATUS) + _VERIFY(STATUS) end if ! Primary Exports @@ -549,7 +536,7 @@ SUBROUTINE Initialize_ ( GC, IMPORT, EXPORT, CLOCK, rc ) call ESMF_ConfigLoadFile(CFtemp,EXTDATA_CF,rc=status) _VERIFY(STATUS) call ESMF_ConfigNextLine(CFtemp,__RC__) - do while(status == ESMF_SUCCESS) + do while(status == ESMF_SUCCESS) call ESMF_ConfigNextLine(CFtemp,rc=status) if (status == ESMF_SUCCESS) then @@ -647,7 +634,7 @@ SUBROUTINE Initialize_ ( GC, IMPORT, EXPORT, CLOCK, rc ) primary%item(totalPrimaryEntries)%do_scale = .true. read(c_scale,*,iostat=ios) primary%item(totalPrimaryEntries)%scale end if - + ! variable name on file entry call ESMF_ConfigGetAttribute(CFtemp, primary%item(totalPrimaryEntries)%var, __RC__) ! file template entry @@ -662,8 +649,8 @@ SUBROUTINE Initialize_ ( GC, IMPORT, EXPORT, CLOCK, rc ) primary%item(totalPrimaryEntries)%hasFileReffTime = .false. else primary%item(totalPrimaryEntries)%hasFileReffTime = .true. - end if - + end if + ! assume we will allocate primary%item(totalPrimaryEntries)%ExtDataAlloc = .true. ! check if this is going to be a constant @@ -681,10 +668,6 @@ SUBROUTINE Initialize_ ( GC, IMPORT, EXPORT, CLOCK, rc ) primary%item(totalPrimaryEntries)%cyclic='n' end if - - if ( primary%item(totalPrimaryEntries)%isConst .eqv. .false. ) then - call CreateTimeInterval(primary%item(totalPrimaryEntries),clock,__RC__) - end if end if enddo ! Derived Exports @@ -708,7 +691,7 @@ SUBROUTINE Initialize_ ( GC, IMPORT, EXPORT, CLOCK, rc ) end if end if end do - !Done parsing resource file + !Done parsing resource file PrimaryItemCount = 0 DerivedItemCount = 0 @@ -764,14 +747,14 @@ SUBROUTINE Initialize_ ( GC, IMPORT, EXPORT, CLOCK, rc ) itemCounter = itemCounter + 1 found = .true. if (primary%item(j)%isConst .and. ITEMTYPES(I) == ESMF_StateItem_FieldBundle) then - _ASSERT(.false., 'Can not have constant bundle in ExtData.rc file') + _FAIL( 'Can not have constant bundle in ExtData.rc file') end if PrimaryItemCount = PrimaryItemCount + 1 PrimaryVarNeeded(j) = .true. primary%item(j)%ExtDataAlloc = .false. VarName=trim(primary%item(J)%name) primary%item(j)%fileVars%xname=trim(primary%item(J)%var) - + if (ITEMTYPES(I) == ESMF_StateItem_Field) then primary%item(J)%vartype = MAPL_FieldItem call ESMF_StateGet(Export,VarName,field,__RC__) @@ -791,7 +774,7 @@ SUBROUTINE Initialize_ ( GC, IMPORT, EXPORT, CLOCK, rc ) if (ItemNames(I) == derived%item(J)%name) then if (ITEMTYPES(I) == ESMF_StateItem_FieldBundle) then - _ASSERT(.false.,'Derived items cannot be field bundle') + _FAIL('Derived items cannot be field bundle') end if found = .true. DerivedVarNeeded(j) = .true. @@ -811,15 +794,15 @@ SUBROUTINE Initialize_ ( GC, IMPORT, EXPORT, CLOCK, rc ) end if end do - call ESMF_VMGetCurrent(VM) + call ESMF_VMGetCurrent(VM) call ESMF_VMBarrier(VM) - + ! we have better found all the items in the export in either a primary or derived item if (itemCounter /= ItemCount) then write(error_msg_str, '(A6,I3,A31)') 'Found ', ItemCount-itemCounter,' unfulfilled imports in extdata' - _ASSERT(.false., error_msg_str) + _FAIL( error_msg_str) end if - + NumVarNames=primary%nItems allocate(VarNames(NumVarNames)) allocate(LocalVarNeeded(NumVarNames)) @@ -866,7 +849,7 @@ SUBROUTINE Initialize_ ( GC, IMPORT, EXPORT, CLOCK, rc ) call ESMF_StateGet(self%ExtDataState,VarName,field,__RC__) VarName=trim(primary%item(j)%name) fieldnew = MAPL_FieldCreate(field,varname,doCopy=.true.,__RC__) - primary%item(j)%fileVars%xname=trim(primary%item(j)%var) + primary%item(j)%fileVars%xname=trim(primary%item(j)%var) call MAPL_StateAdd(self%ExtDataState,fieldnew,__RC__) PrimaryVarNeeded(j) = .true. primary%item(j)%ExtDataAlloc = .true. @@ -917,6 +900,10 @@ SUBROUTINE Initialize_ ( GC, IMPORT, EXPORT, CLOCK, rc ) call lgr%debug('ExtData Initialize_(): PrimaryLoop: ') + if ( .not. item%isConst ) then + call CreateTimeInterval(item,clock,__RC__) + end if + item%pfioCollection_id = MAPL_DataAddCollection(item%file,use_file_coords=self%use_file_coords) ! parse refresh template to see if we have a time shift during constant updating @@ -968,30 +955,30 @@ SUBROUTINE Initialize_ ( GC, IMPORT, EXPORT, CLOCK, rc ) ptr3d = item%const endif else if (item%vartype == MAPL_BundleItem) then - _ASSERT(.false.,'Cannot assign constant to field bundle') + _FAIL('Cannot assign constant to field bundle') else if (item%vartype == MAPL_ExtDataVectorItem) then call ESMF_StateGet(self%ExtDataState,trim(item%vcomp1),field,__RC__) call ESMF_FieldGet(field,dimCount=fieldRank,__RC__) - if (fieldRank == 2) then + if (fieldRank == 2) then call MAPL_GetPointer(self%ExtDataState, ptr2d, trim(item%vcomp1),__RC__) ptr2d = item%const - else if (fieldRank == 3) then + else if (fieldRank == 3) then call MAPL_GetPointer(self%ExtDataState, ptr3d, trim(item%vcomp1), __RC__) ptr3d = item%const endif call ESMF_StateGet(self%ExtDataState,trim(item%vcomp2),field,__RC__) call ESMF_FieldGet(field,dimCount=fieldRank,__RC__) - if (fieldRank == 2) then + if (fieldRank == 2) then call MAPL_GetPointer(self%ExtDataState, ptr2d, trim(item%vcomp2),__RC__) ptr2d = item%const - else if (fieldRank == 3) then + else if (fieldRank == 3) then call MAPL_GetPointer(self%ExtDataState, ptr3d, trim(item%vcomp2), __RC__) ptr3d = item%const endif end if cycle end if - + ! check if this is a single piece of data if user put - for refresh template ! by that it is an untemplated file with one time that could not possibly be time interpolated if (PrimaryExportIsConstant_(item)) then @@ -1022,7 +1009,7 @@ SUBROUTINE Initialize_ ( GC, IMPORT, EXPORT, CLOCK, rc ) if (fieldRank==3) then call ESMF_FieldGet(field,0,farrayPtr=ptr3d,__RC__) lm = size(ptr3d,3) - end if + end if if (item%lm /= lm .and. lm /= 0 .and. item%havePressure) then item%do_VertInterp = .true. else if (item%lm /= lm .and. lm /= 0) then @@ -1045,9 +1032,9 @@ SUBROUTINE Initialize_ ( GC, IMPORT, EXPORT, CLOCK, rc ) call ESMF_FieldBundleSet(item%binterp2, GRID=GRID, __RC__) call MAPL_CFIORead(item%file,time,item%binterp1,noread=.true.,ignorecase=self%ignorecase,only_vars=item%var,__RC__) call MAPL_CFIORead(item%file,time,item%binterp2,noread=.true.,ignorecase=self%ignorecase,only_vars=item%var,__RC__) - + else if (item%vartype == MAPL_ExtDataVectorItem) then - + ! Only some methods are supported for vector regridding _ASSERT(any(item%Trans /= [REGRID_METHOD_BILINEAR,REGRID_METHOD_CONSERVE_HFLUX]), 'Regrid method unsupported for vectors.') @@ -1063,7 +1050,7 @@ SUBROUTINE Initialize_ ( GC, IMPORT, EXPORT, CLOCK, rc ) call ESMF_StateGet(self%ExtDataState, trim(item%vcomp1), field,__RC__) call ESMF_FieldGet(field,grid=grid,rank=fieldRank,__RC__) - lm = 0 + lm = 0 if (fieldRank==3) then call ESMF_FieldGet(field,0,farrayPtr=ptr3d,__RC__) lm = size(ptr3d,3) @@ -1126,7 +1113,7 @@ SUBROUTINE Initialize_ ( GC, IMPORT, EXPORT, CLOCK, rc ) print *, trim(Iam)//': IMPORT State during Initialize():' call ESMF_StatePrint ( IMPORT ) print * - print *, trim(Iam)//': EXPORT State during Initialize():' + print *, trim(Iam)//': EXPORT State during Initialize():' call ESMF_StatePrint ( EXPORT ) end if #endif @@ -1145,7 +1132,7 @@ SUBROUTINE Initialize_ ( GC, IMPORT, EXPORT, CLOCK, rc ) idx =i end if if (self%primary%item(i)%vartype==MAPL_BundleItem) then - _ASSERT(.false.,'Cannot perform vertical interpolation on field bundle') + _FAIL('Cannot perform vertical interpolation on field bundle') end if enddo _ASSERT(idx/=-1,'Surface pressure not present for vertical interpolation') @@ -1162,7 +1149,7 @@ SUBROUTINE Initialize_ ( GC, IMPORT, EXPORT, CLOCK, rc ) idx =i end if if (self%primary%item(i)%vartype==MAPL_BundleItem) then - _ASSERT(.false.,'Cannot perform vertical interpolation on field bundle') + _FAIL('Cannot perform vertical interpolation on field bundle') end if enddo if (idx/=-1) then @@ -1184,7 +1171,7 @@ SUBROUTINE Initialize_ ( GC, IMPORT, EXPORT, CLOCK, rc ) if (allocated(DerivedVarNeeded)) deallocate(DerivedVarNeeded) if (allocated(LocalVarNeeded)) deallocate(LocalVarNeeded) - !Done parsing resource file + !Done parsing resource file ! Set has run to false to we know when we first go to run method it is first call hasRun = .false. @@ -1227,7 +1214,7 @@ SUBROUTINE Run_ ( GC, IMPORT, EXPORT, CLOCK, rc ) type(ESMF_State), intent(inout) :: EXPORT ! Export State integer, intent(out) :: rc ! Error return code: ! 0 - all is well - ! 1 - + ! 1 - ! !DESCRIPTION: This is a simple ESMF wrapper. ! @@ -1241,7 +1228,7 @@ SUBROUTINE Run_ ( GC, IMPORT, EXPORT, CLOCK, rc ) type(MAPL_ExtData_state), pointer :: self ! Legacy state type(ESMF_Field) :: field ! Field type(ESMF_FieldBundle) :: bundle - type(ESMF_Config) :: CF ! Universal Config + type(ESMF_Config) :: CF ! Universal Config character(len=ESMF_MAXSTR) :: comp_name character(len=ESMF_MAXSTR) :: Iam @@ -1272,10 +1259,10 @@ SUBROUTINE Run_ ( GC, IMPORT, EXPORT, CLOCK, rc ) _UNUSED_DUMMY(IMPORT) _UNUSED_DUMMY(EXPORT) -! Declare pointers to IMPORT/EXPORT/INTERNAL states +! Declare pointers to IMPORT/EXPORT/INTERNAL states ! ------------------------------------------------- ! #include "MAPL_ExtData_DeclarePointer___.h" - + ! Get my name and set-up traceback handle ! --------------------------------------- Iam = 'Run_' @@ -1297,13 +1284,13 @@ SUBROUTINE Run_ ( GC, IMPORT, EXPORT, CLOCK, rc ) end if call MAPL_GetObjectFromGC ( gc, MAPLSTATE, RC=STATUS) - _VERIFY(STATUS) + _VERIFY(STATUS) call MAPL_TimerOn(MAPLSTATE,"Run") call ESMF_ClockGet(CLOCK, currTIME=time0, __RC__) -! Fill in the internal state with data from the files +! Fill in the internal state with data from the files ! --------------------------------------------------- allocate(doUpdate(self%primary%nitems),stat=status) @@ -1313,7 +1300,7 @@ SUBROUTINE Run_ ( GC, IMPORT, EXPORT, CLOCK, rc ) _VERIFY(STATUS) call MAPL_TimerOn(MAPLSTATE,"-Read_Loop") - + call lgr%debug('ExtData Rune_(): Start') call lgr%debug('ExtData Run_(): READ_LOOP: Start') @@ -1354,7 +1341,7 @@ SUBROUTINE Run_ ( GC, IMPORT, EXPORT, CLOCK, rc ) ! update left time call lgr%debug(' ExtData Run_: HAS_RUN: NotSingle is true. Update left time (bracket L)') - call UpdateBracketTime(item,time,"L",item%interp_time1, & + call UpdateBracketTime(item,time,"L",item%interp_time1, & item%time1,file_processed1,self%allowExtrap,rc=status) _VERIFY(status) call IOBundle_Add_Entry(IOBundles,item,self%primaryOrder(i),file_processed1,MAPL_ExtDataLeft,item%tindex1,__RC__) @@ -1381,7 +1368,7 @@ SUBROUTINE Run_ ( GC, IMPORT, EXPORT, CLOCK, rc ) call lgr%debug(' ExtData Run_: HAS_RUN: End') endif HAS_RUN - + ! now update bracketing times if neccessary NOT_SINGLE: if (NotSingle) then @@ -1512,13 +1499,13 @@ SUBROUTINE Run_ ( GC, IMPORT, EXPORT, CLOCK, rc ) call MAPL_TimerOff(MAPLSTATE,"---IclientDone") _VERIFY(STATUS) - + call MAPL_TimerOn(MAPLSTATE,"---read-prefetch") ! GCHP: extra prints call lgr%debug('ExtData Run_: ---read-prefetch') - call MAPL_ExtDataReadPrefetch(IOBundles,rc=status) + call MAPL_ExtDataReadPrefetch(IOBundles,rc=status) _VERIFY(status) call MAPL_TimerOff(MAPLSTATE,"---read-prefetch") call MAPL_TimerOff(MAPLSTATE,"--PRead") @@ -1542,7 +1529,7 @@ SUBROUTINE Run_ ( GC, IMPORT, EXPORT, CLOCK, rc ) call MAPL_TimerOff(MAPLSTATE,"-Read_Loop") call MAPL_TimerOn(MAPLSTATE,"-Interpolate") - + call lgr%debug('ExtData Run_: INTERP_LOOP: Start') INTERP_LOOP: do i = 1, self%primary%nItems @@ -1551,15 +1538,15 @@ SUBROUTINE Run_ ( GC, IMPORT, EXPORT, CLOCK, rc ) if (doUpdate(i)) then - call lgr%debug('ExtData Run_: INTERP_LOOP: interpolating between bracket times, variable: %a10, file: %a', & + call lgr%debug('ExtData Run_: INTERP_LOOP: interpolating between bracket times, variable: %a, file: %a', & & trim(item%var), trim(item%file)) - + ! finally interpolate between bracketing times if (item%vartype == MAPL_FieldItem) then call ESMF_StateGet(self%ExtDataState, item%name, field, __RC__) - call MAPL_ExtDataInterpField(item,useTime(i),field,__RC__) + call MAPL_ExtDataInterpField(item,useTime(i),field,__RC__) else if (item%vartype == MAPL_BundleItem) then @@ -1579,12 +1566,12 @@ SUBROUTINE Run_ ( GC, IMPORT, EXPORT, CLOCK, rc ) call MAPL_ExtDataInterpField(item,useTime(i),field,vector_comp=1,__RC__) call ESMF_StateGet(self%ExtDataState, item%vcomp2, field, __RC__) call MAPL_ExtDataInterpField(item,useTime(i),field,vector_comp=2,__RC__) - + end if endif - nullify(item) + nullify(item) end do INTERP_LOOP @@ -1658,7 +1645,7 @@ SUBROUTINE Finalize_ ( GC, IMPORT, EXPORT, CLOCK, rc ) type(ESMF_State), intent(inout) :: EXPORT ! Export State integer, intent(out) :: rc ! Error return code: ! 0 - all is well - ! 1 - + ! 1 - ! !DESCRIPTION: This is a simple ESMF wrapper. ! @@ -1670,7 +1657,7 @@ SUBROUTINE Finalize_ ( GC, IMPORT, EXPORT, CLOCK, rc ) !------------------------------------------------------------------------- type(MAPL_ExtData_state), pointer :: self ! Legacy state - type(ESMF_Config) :: CF ! Universal Config + type(ESMF_Config) :: CF ! Universal Config character(len=ESMF_MAXSTR) :: comp_name character(len=ESMF_MAXSTR) :: Iam @@ -1728,7 +1715,7 @@ subroutine extract_ ( GC, self, CF, rc) type(ESMF_GridComp), intent(INout) :: GC ! Grid Comp object type(MAPL_ExtData_state), pointer :: self ! Legacy state - type(ESMF_Config), intent(out) :: CF ! Universal Config + type(ESMF_Config), intent(out) :: CF ! Universal Config integer, intent(out), optional :: rc @@ -1758,20 +1745,20 @@ subroutine extract_ ( GC, self, CF, rc) ! --------------------- call ESMF_GridCompGet ( GC, config=CF, __RC__ ) - + _RETURN(ESMF_SUCCESS) end subroutine extract_ - + ! ............................................................................ logical function PrimaryExportIsConstant_(item) - + type(PrimaryExport), intent(in) :: item if ( trim(item%refresh_template) == '-' .or. & trim(item%file) == '/dev/null' ) then - PrimaryExportIsConstant_ = .true. + PrimaryExportIsConstant_ = .true. else PrimaryExportIsConstant_ = .false. end if @@ -1781,11 +1768,11 @@ end function PrimaryExportIsConstant_ ! ............................................................................ logical function DerivedExportIsConstant_(item) - + type(DerivedExport), intent(in) :: item if ( trim(item%refresh_template) == '-') then - DerivedExportIsConstant_ = .true. + DerivedExportIsConstant_ = .true. else DerivedExportIsConstant_ = .false. end if @@ -1833,7 +1820,7 @@ end subroutine scale_field_ type (ESMF_Time) function timestamp_(time, template, rc) type(ESMF_Time), intent(inout) :: time character(len=ESMF_MAXSTR), intent(in) :: template - integer, optional, intent(inout) :: rc + integer, optional, intent(inout) :: rc ! locals integer, parameter :: DATETIME_MAXSTR_ = 32 @@ -1844,23 +1831,23 @@ type (ESMF_Time) function timestamp_(time, template, rc) integer :: i, il, ir integer :: status - + ! test the length of the timestamp template _ASSERT(len_trim(template) < DATETIME_MAXSTR_,'Timestamp template is greater than Maximum allowed len') buff = trim(template) buff = ESMF_UtilStringLowerCase(buff, __RC__) - + ! test if the template is empty and return the current time as result if (buff == '-' .or. buff == '--' .or. buff == '---' .or. & buff == 'na' .or. buff == 'none' .or. buff == 'n/a') then timestamp_ = time - else + else ! split the time stamp template into a date and time strings i = scan(buff, 't') If (.not.(i > 3)) Then - _ASSERT(.False.,'ERROR: Time stamp ' // trim(template) // ' uses the fixed format, and must therefore contain a T') + _FAIL('ERROR: Time stamp ' // trim(template) // ' uses the fixed format, and must therefore contain a T') End If buff_date = buff(1:i-1) @@ -1879,7 +1866,7 @@ type (ESMF_Time) function timestamp_(time, template, rc) str_hs = trim(buff_time(1:il-1)) str_ms = trim(buff_time(il+1:ir-1)) str_ss = trim(buff_time(ir+1:)) - + ! remove the trailing 'Z' from the seconds string i = scan(str_ss, 'z') if (i > 0) then @@ -1902,7 +1889,7 @@ type (ESMF_Time) function timestamp_(time, template, rc) _RETURN(ESMF_SUCCESS) end function timestamp_ - + subroutine CreateTimeInterval(item,clock,rc) type(PrimaryExport) , intent(inout) :: item type(ESMF_Clock) , intent(in ) :: clock @@ -1914,15 +1901,16 @@ subroutine CreateTimeInterval(item,clock,rc) type(ESMF_Time) :: time,start_time integer :: cindex,pindex character(len=ESMF_MAXSTR) :: creffTime, ctInt - + integer :: status - + logical :: found + creffTime = '' ctInt = '' call ESMF_ClockGet (CLOCK, currTIME=time, startTime=start_time, __RC__) if (.not.item%hasFileReffTime) then ! if int_frequency is less than zero than try to guess it from the file template - ! if that fails then it must be a single file or a climatology + ! if that fails then it must be a single file or a climatology call ESMF_TimeGet(time, yy=iyy, mm=imm, dd=idd,h=ihh, m=imn, s=isc ,__RC__) !======================================================================= @@ -1965,6 +1953,10 @@ subroutine CreateTimeInterval(item,clock,rc) else ! couldn't find any tokens so all the data must be on one file call ESMF_TimeIntervalSet(item%frequency,__RC__) + + ! check if non-token file exists + inquire(file=trim(item%file),EXIST=found) + _ASSERT(found,'File ' // trim(item%file) // ' not found') end if else ! Reference time should look like: @@ -1976,10 +1968,10 @@ subroutine CreateTimeInterval(item,clock,rc) ! 1985-01-01T00:00:00P0001-00-00T00:00:00 ! Get refference time, if not provided use current model date pindex=index(item%FileReffTime,'P') - if (pindex==0) then - _ASSERT(.false., 'ERROR: File template ' // item%file // ' has invalid reference date format') + if (pindex==0) then + _FAIL( 'ERROR: File template ' // item%file // ' has invalid reference date format') end if - cReffTime = item%FileReffTime(1:pindex-1) + cReffTime = item%FileReffTime(1:pindex-1) if (trim(cReffTime) == '') then item%reff_time = Time else @@ -1995,7 +1987,7 @@ subroutine CreateTimeInterval(item,clock,rc) call MAPL_NCIOParseTimeUnits(ctInt,iyy,imm,idd,ihh,imn,isc,status) _VERIFY(STATUS) call ESMF_TimeIntervalSet(item%frequency,yy=iyy,mm=imm,d=idd,h=ihh,m=imn,s=isc,rc=status) - _VERIFY(STATUS) + _VERIFY(STATUS) end if if (lgr%isEnabledFor(DEBUG)) then @@ -2005,7 +1997,7 @@ subroutine CreateTimeInterval(item,clock,rc) call ESMF_TimeIntervalGet(item%frequency,yy=iyy,mm=imm,d=idd,h=ihh,m=imn,s=isc,rc=status) call lgr%debug(' >> Frequency : %i0.4~-%i0.2~-%i0.2 %i0.2~:%i0.2~:%i0.2', iYy, iMm, iDd, iHh, iMn, iSc) endif - _RETURN(ESMF_SUCCESS) + _RETURN(ESMF_SUCCESS) end subroutine CreateTimeInterval @@ -2071,7 +2063,7 @@ subroutine GetClimYear(item, rc) item%climYear = climYear _RETURN(ESMF_SUCCESS) else - _ASSERT(.false., 'cyclic keyword was not y, n, or a valid year (0 < year < 3000)') + _FAIL( 'cyclic keyword was not y, n, or a valid year (0 < year < 3000)') end if end if @@ -2092,13 +2084,13 @@ subroutine GetLevs(item, time, state, allowExtrap, rc) integer :: nymd, nhms, rank type(ESMF_Time) :: fTime type(ESMF_Field) :: field - real, allocatable :: levFile(:) + real, allocatable :: levFile(:) character(len=ESMF_MAXSTR) :: buff,levunits,tlevunits,temp_name logical :: found,lFound,intOK integer :: maxOffset character(len=:), allocatable :: levname - character(len=:), pointer :: positive character(len=64) :: posStr ! GCHP + character(len=:), pointer :: positive type(FileMetadataUtils), pointer :: metadata type(Variable), pointer :: var type(ESMF_TimeInterval) :: zero @@ -2122,7 +2114,7 @@ subroutine GetLevs(item, time, state, allowExtrap, rc) end if if (item%frequency == zero) then - + file = item%file Inquire(file=trim(file),EXIST=found) _ASSERT(found,'File ' // trim(item%file) // ' not found') @@ -2178,10 +2170,10 @@ subroutine GetLevs(item, time, state, allowExtrap, rc) enddo if (.not.lfound) then - _ASSERT(.false., 'From ' // trim(item%file) // ' could not find file with extrapolation') + _FAIL( 'From ' // trim(item%file) // ' could not find file with extrapolation') end if else - _ASSERT(.false.,'From ' // trim(item%file) // ' could not find time no extrapolation') + _FAIL('From ' // trim(item%file) // ' could not find time no extrapolation') end if end if @@ -2197,7 +2189,7 @@ subroutine GetLevs(item, time, state, allowExtrap, rc) var=>metadata%get_variable(trim(item%var)) _ASSERT(associated(var),"Variable "//TRIM(item%var)//" not found in file "//TRIM(item%file)) end if - + levName = metadata%get_level_name(rc=status) _VERIFY(status) if (trim(levName) /='') then @@ -2300,7 +2292,7 @@ subroutine UpdateBracketTime(item,cTime,bSide,interpTime,fileTime,file_processed UniFileClim = .false. ! if the file is constant, i.e. no tokens in in the template - ! but it was marked as cyclic we must have a year long climatology + ! but it was marked as cyclic we must have a year long climatology ! on one file, set UniFileClim to true if (trim(item%cyclic)=='y') UniFileClim = .true. @@ -2322,7 +2314,7 @@ subroutine UpdateBracketTime(item,cTime,bSide,interpTime,fileTime,file_processed call lgr%error('Bracket timing request failed on fixed file %a for side %a', trim(item%file), bSide) _RETURN(ESMF_FAILURE) end if - else + else if (lgr%isEnabledFor(DEBUG)) then call lgr%debug(' UpdateBracketTime: Scanning template %a for side %a1',trim(item%file), bSide) @@ -2347,10 +2339,10 @@ subroutine UpdateBracketTime(item,cTime,bSide,interpTime,fileTime,file_processed else yrOffset = 0 if (item%reff_time > cTime) then - _ASSERT(.False.,'Reference time for file ' // trim(item%file) // ' is too late') + _FAIL('Reference time for file ' // trim(item%file) // ' is too late') end if ! This approach causes a problem if cTime and item%reff_time are too far - ! apart - do it the hard way instead... + ! apart - do it the hard way instead... ftime = item%reff_time n = 0 ! LRB: If frequency is variable, we can't skip ahead by n intervals. @@ -2361,6 +2353,11 @@ subroutine UpdateBracketTime(item,cTime,bSide,interpTime,fileTime,file_processed n = max(0,floor((cTime-item%reff_time)/item%frequency)) if (n>0) fTime = fTime + (n*item%frequency) end if + !!!! SDE DEBUG: This caused problems in the past but the + !!!! alternative is far too slow... need to keep an eye + !!!! on this but the Max(0,...) should help. + !!!n = max(0,floor((cTime-item%reff_time)/item%frequency)) + !!!if (n>0) fTime = fTime + (n*item%frequency) do while (.not.found) ! SDE: This needs to be ">" found = ((ftime + item%frequency) > ctime) @@ -2391,7 +2388,7 @@ subroutine UpdateBracketTime(item,cTime,bSide,interpTime,fileTime,file_processed if (found) then call lgr%debug(' Target file for %a found and is %a', trim(item%file), trim(file_processed)) !yrOffset = 0 - Else if (allowExtrap) then + Else if (allowExtrap) then if (lgr%isEnabledFor(DEBUG)) then call lgr%debug(' UpdateBracketTime: Target file not found: %a', trim(item%file)) @@ -2505,7 +2502,7 @@ subroutine UpdateBracketTime(item,cTime,bSide,interpTime,fileTime,file_processed do while (ftime > newTime) fTime = fTime - item%frequency n = n - 1 - end do + end do ! untemplate file call ESMF_TimeGet(fTime,yy=iyr,mm=imm,dd=idd,h=ihr,m=imn,s=isc,__RC__) call MAPL_PackTime(curDate,iyr,imm,idd) @@ -2535,7 +2532,7 @@ subroutine UpdateBracketTime(item,cTime,bSide,interpTime,fileTime,file_processed ! question could actually be for a different year. We therefore feed the file time ! into the refresh template and see if the result has the same year. If it doesn't, ! then we can assume that the year is actually fixed, and the times in the file will - ! correspond to the year in the refresh template. In this case, an additional year + ! correspond to the year in the refresh template. In this case, an additional year ! offset must be applied. yrOffsetStamp = 0 buff = trim(item%refresh_template) @@ -2556,7 +2553,7 @@ subroutine UpdateBracketTime(item,cTime,bSide,interpTime,fileTime,file_processed call lgr%debug(' UpdateBracketTime: Found status of %a~: %l1', trim(file_processed), found) ! if we didn't find the bracketing time look forwards or backwards depending on - ! whether it is the right or left time + ! whether it is the right or left time if (.not.found) then call lgr%debug(' UpdateBracketTime: Scanning for bracket %a1 of %a~. RSide: %l1', bSide, trim(file_processed), (bSide=="R")) @@ -2661,7 +2658,7 @@ subroutine UpdateBracketTime(item,cTime,bSide,interpTime,fileTime,file_processed buff = ESMF_UtilStringLowerCase(buff, __RC__) If (buff /= "0" .and. index(buff,"p")==0 ) Then newTime = timestamp_(fTime,item%refresh_template,__RC__) - + if (lgr%isEnabledFor(DEBUG)) then call ESMF_TimeGet(fTime,yy=iyr,mm=imm,dd=idd,h=ihr,m=imn,s=isc,__RC__) call ESMF_TimeGet(newTime,yy=fyr,mm=fmm,dd=fdd,h=fhr,m=fmn,s=fsc,__RC__) @@ -2713,9 +2710,9 @@ subroutine UpdateBracketTime(item,cTime,bSide,interpTime,fileTime,file_processed call lgr%info(' ... file processed: %a', trim(file_processed)) _RETURN(ESMF_SUCCESS) - + end subroutine UpdateBracketTime - + subroutine swapBracketInformation(item,rc) type(PrimaryExport), intent(inout) :: item integer, optional, intent(out) :: rc @@ -2752,7 +2749,7 @@ subroutine swapBracketInformation(item,rc) do j = 1,fieldCount call ESMF_FieldBundleGet(item%binterp1, names(j), field=field1, __RC__) call ESMF_FieldBundleGet(item%binterp2, names(j), field=field2, __RC__) - call ESMF_FieldGet(field1, dimCount=fieldRank, __RC__) + call ESMF_FieldGet(field1, dimCount=fieldRank, __RC__) if (fieldRank == 2) then call ESMF_FieldGet(field1, localDE=0, farrayPtr=var2d_prev, __RC__) call ESMF_FieldGet(field2, localDE=0, farrayPtr=var2d_next, __RC__) @@ -2820,7 +2817,7 @@ subroutine GetTimesOnFile(cfio,tSeries,rc) allocate(tSeriesInt(cfio%tSteps)) call getDateTimeVec(cfio%fid,begDate,begTime,tSeriesInt,__RC__) - + ! Assume success If (present(rc)) rc=ESMF_SUCCESS @@ -2834,7 +2831,7 @@ subroutine GetTimesOnFile(cfio,tSeries,rc) call MAPL_UnpackTime(nymdB,iyr,imm,idd) call MAPL_UnpackTime(nhmsB,ihr,imn,isc) - + if (lgr%isEnabledFor(DEBUG) .and. any(i == [1,cfio%tsteps])) then call lgr%debug(' ==> STD Sample %i~: %i0.4~-%i0.2~-%i0.2 %i0.2~:%i0.2~:%i0.2', i, iYr, iMm, iDd, iHr, iMn, iSc) end if @@ -2847,7 +2844,7 @@ subroutine GetTimesOnFile(cfio,tSeries,rc) end subroutine GetTimesOnFile subroutine OffsetTimeYear(inTime,yrOffset,outTime,rc) - + type(ESMF_Time), intent(in ) :: inTime integer :: yrOffset type(ESMF_Time), intent(out ) :: outTime @@ -2969,7 +2966,7 @@ subroutine GetBracketTimeOnSingleFile(fdata,tSeries,cTime,bSide,UniFileClim,UniF rc = esmf_success return end if - + if (lgr%isEnabledFor(DEBUG)) then call lgr%debug(' GetBracketTimeOnSingleFile called for %a', trim(fdata%get_file_name())) call lgr%debug(' GetBracketTimeOnSingleFile: Reading times from fixed (%l1) file %a', UniFileClim, trim(fdata%get_file_name())) @@ -3003,7 +3000,7 @@ subroutine GetBracketTimeOnSingleFile(fdata,tSeries,cTime,bSide,UniFileClim,UniF end if end do - + allocate(tSeriesC(tsteps),__STAT__) do i=1,tsteps tSeriesC(i)=tSeries(iEntry+i-1) @@ -3062,7 +3059,7 @@ subroutine GetBracketTimeOnSingleFile(fdata,tSeries,cTime,bSide,UniFileClim,UniF end if end do end if - end if + end if else @@ -3074,7 +3071,7 @@ subroutine GetBracketTimeOnSingleFile(fdata,tSeries,cTime,bSide,UniFileClim,UniF RSide = (.not.LSide) LExact = (cLimTime == tSeries(1)) RExact = (cLimTime == tSeries(nsteps)) - LExtrap = (cLimTime < tSeries(1)) + LExtrap = (cLimTime < tSeries(1)) RExtrap = (cLimTime > tSeries(nsteps)) found = .false. @@ -3232,7 +3229,7 @@ subroutine GetBracketTimeOnFile(fdata,tSeries,cTime,bSide,UniFileClim,interpTime call OffsetTimeYear(cTime,yrOffset,cLimTime,rc) else climTime = cTime - end if + end if climSize = 1 ! Debug output @@ -3308,15 +3305,15 @@ subroutine GetBracketTimeOnFile(fdata,tSeries,cTime,bSide,UniFileClim,interpTime call lgr%error('Requested sample not found in file %a ', trim(fdata%get_file_name())) _RETURN(ESMF_FAILURE) endif - !end if + !end if end subroutine GetBracketTimeOnFile subroutine CalcDerivedField(state,exportName,exportExpr,masking,rc) type(ESMF_State), intent(inout) :: state - character(len=*), intent(in ) :: exportName + character(len=*), intent(in ) :: exportName character(len=*), intent(in ) :: exportExpr - logical, intent(in ) :: masking + logical, intent(in ) :: masking integer, optional, intent(out ) :: rc integer :: status @@ -3346,7 +3343,7 @@ subroutine MAPL_ExtDataInterpField(item,time,field,vector_comp,rc) real :: alpha real, pointer :: var2d(:,:) => null() real, pointer :: var3d(:,:,:) => null() - real, pointer :: var2d_prev(:,:) => null() + real, pointer :: var2d_prev(:,:) => null() real, pointer :: var2d_next(:,:) => null() real, pointer :: var3d_prev(:,:,:) => null() real, pointer :: var3d_next(:,:,:) => null() @@ -3363,7 +3360,7 @@ subroutine MAPL_ExtDataInterpField(item,time,field,vector_comp,rc) alpha = tinv1/tinv2 end if call ESMF_FieldGet(FIELD, dimCount=fieldRank,name=name,__RC__) - + if (lgr%isEnabledFor(DEBUG)) then call ESMF_TimeGet(item%interp_time1,yy=yr,mm=mm,dd=dd,h=hr,m=mn,s=sc,__RC__) call MAPL_PackTime(nhms1,hr,mn,sc) @@ -3381,7 +3378,7 @@ subroutine MAPL_ExtDataInterpField(item,time,field,vector_comp,rc) nhms2=0 nymd2=0 end if - + if (lgr%isEnabledFor(DEBUG) .and. .not. item%doInterpolate) then call lgr%debug(' MAPL_ExtDataInterpField: Uninterpolated field %a set to sample L %i0.8 %i0.6', trim(item%name), nymd1, nhms1) else if (time == item%interp_time1) then @@ -3492,7 +3489,7 @@ subroutine MAPL_ExtDataInterpField(item,time,field,vector_comp,rc) end if enddo enddo - enddo + enddo endif _RETURN(ESMF_SUCCESS) @@ -3515,7 +3512,7 @@ subroutine MAPL_ExtDataVerticalInterpolate(ExtState,item,filec,rc) if (trim(item%importVDir)/=trim(item%fileVDir)) then call MAPL_ExtDataFlipVertical(item,filec,rc=status) _VERIFY(status) - end if + end if if (item%vartype == MAPL_fieldItem) then call MAPL_ExtDataGetBracket(item,filec,newField,getRL=.true.,rc=status) _VERIFY(STATUS) @@ -3526,7 +3523,7 @@ subroutine MAPL_ExtDataVerticalInterpolate(ExtState,item,filec,rc) _VERIFY(STATUS) call vertInterpolation_pressKappa(field,newfield,psF,item%levs,MAPL_UNDEF,rc=status) _VERIFY(STATUS) - + else if (item%vartype == MAPL_ExtDataVectorItem) then id_ps = ExtState%primaryOrder(1) @@ -3575,7 +3572,7 @@ subroutine MAPL_ExtDataVerticalInterpolate(ExtState,item,filec,rc) _VERIFY(status) end if end if - + _RETURN(ESMF_SUCCESS) end subroutine MAPL_ExtDataVerticalInterpolate @@ -3692,7 +3689,7 @@ subroutine MAPL_ExtDataEvaluateMask(state,exportName,exportExpr,rc) call MAPL_GetPointer(state,rvar3d,vartomask,__RC__) call MAPL_GetPointer(state,var3d,exportName,__RC__) else - _ASSERT(.false.,'Rank must be 2 or 3') + _FAIL('Rank must be 2 or 3') end if k=32 @@ -3707,7 +3704,7 @@ subroutine MAPL_ExtDataEvaluateMask(state,exportName,exportExpr,rc) deallocate(flag,stat=status) _VERIFY(STATUS) - ! Set local mask to 1 where gridMask matches each integer (within precision!) + ! Set local mask to 1 where gridMask matches each integer (within precision!) ! --------------------------------------------------------------------------- allocate(mask(size(rmask,1),size(rmask,2)),stat=status) _VERIFY(STATUS) @@ -3755,7 +3752,7 @@ subroutine MAPL_ExtDataEvaluateMask(state,exportName,exportExpr,rc) call MAPL_GetPointer(state,rvar3d,vartomask,__RC__) call MAPL_GetPointer(state,var3d,exportName,__RC__) else - _ASSERT(.false.,'Rank must be 2 or 3') + _FAIL('Rank must be 2 or 3') end if if (rank == 2) then @@ -3869,7 +3866,7 @@ subroutine MAPL_ExtDataEvaluateMask(state,exportName,exportExpr,rc) call MAPL_GetPointer(state,rvar3d,vartomask,__RC__) call MAPL_GetPointer(state,var3d,exportName,__RC__) else - _ASSERT(.false.,'Rank must be 2 or 3') + _FAIL('Rank must be 2 or 3') end if if (rank == 2) then @@ -3917,15 +3914,15 @@ SUBROUTINE MAPL_ExtDataExtractIntegers(string,iSize,iValues,delimiter,verbose,rc INTEGER, INTENT(IN) :: iSize INTEGER, INTENT(INOUT) :: iValues(iSize)! Space allocated for extracted integers CHARACTER(LEN=*), OPTIONAL :: delimiter ! 1-character delimiter - LOGICAL, OPTIONAL, INTENT(IN) :: verbose ! Let me know iValues as they are found. - ! DEBUG directive turns on the message even - ! if verbose is not present or if + LOGICAL, OPTIONAL, INTENT(IN) :: verbose ! Let me know iValues as they are found. + ! DEBUG directive turns on the message even + ! if verbose is not present or if ! verbose = .FALSE. INTEGER, OPTIONAL, INTENT(OUT) :: rc ! Return code -! !DESCRIPTION: +! !DESCRIPTION: ! ! Extract integers from a character-delimited string, for example, "-1,45,256,7,10". In the context -! of Chem_Util, this is provided for determining the numerically indexed regions over which an +! of Chem_Util, this is provided for determining the numerically indexed regions over which an ! emission might be applied. ! ! In multiple passes, the string is parsed for the delimiter, and the characters up to, but not @@ -3936,7 +3933,7 @@ SUBROUTINE MAPL_ExtDataExtractIntegers(string,iSize,iValues,delimiter,verbose,rc ! The default delimiter is a comma (","). ! ! "Unfilled" iValues are zero. -! +! ! Return codes: ! 1 Zero-length string. ! 2 iSize needs to be increased. @@ -3967,7 +3964,7 @@ SUBROUTINE MAPL_ExtDataExtractIntegers(string,iSize,iValues,delimiter,verbose,rc ! "+1" ! "1 3 6" ! -! !REVISION HISTORY: +! !REVISION HISTORY: ! ! Taken from chem utilities. ! @@ -3990,7 +3987,7 @@ SUBROUTINE MAPL_ExtDataExtractIntegers(string,iSize,iValues,delimiter,verbose,rc base = ICHAR("0") iDash = ICHAR("-") -! Determine verbosity, letting the DEBUG +! Determine verbosity, letting the DEBUG ! directive override local specification ! -------------------------------------- tellMe = .FALSE. @@ -4142,9 +4139,9 @@ subroutine AdvanceAndCount(CF,nLines,rc) _VERIFY(STATUS) call ESMF_ConfigGetAttribute(CF,thisLine,rc=status) _VERIFY(STATUS) - if (trim(thisLine) == "%%") then + if (trim(thisLine) == "%%") then inBlock = .false. - else + else iCnt = iCnt + 1 end if end do @@ -4154,7 +4151,7 @@ subroutine AdvanceAndCount(CF,nLines,rc) end subroutine advanceAndCount - subroutine CheckUpdate(doUpdate,updateTime,currTime,hasRun,primaryItem,derivedItem,rc) + subroutine CheckUpdate(doUpdate,updateTime,currTime,hasRun,primaryItem,derivedItem,rc) logical, intent(out ) :: doUpdate type(ESMF_Time), intent(inout) :: updateTime type(ESMF_Time), intent(inout) :: currTime @@ -4171,7 +4168,7 @@ subroutine CheckUpdate(doUpdate,updateTime,currTime,hasRun,primaryItem,derivedIt time0 = currTime time = currTime if (present(primaryItem)) then - + if (primaryItem%AlarmIsEnabled) then doUpdate = primaryItem%update_alarm%is_ringing(currTime,__RC__) if (hasRun .eqv. .false.) doUpdate = .true. @@ -4223,11 +4220,11 @@ subroutine CheckUpdate(doUpdate,updateTime,currTime,hasRun,primaryItem,derivedIt end if end if end if - + _RETURN(ESMF_SUCCESS) end subroutine CheckUpdate - subroutine SetRefreshAlarms(clock,primaryItem,derivedItem,rc) + subroutine SetRefreshAlarms(clock,primaryItem,derivedItem,rc) type(ESMF_Clock), intent(inout) :: Clock type(PrimaryExport), optional, intent(inout) :: primaryItem type(DerivedExport), optional, intent(inout) :: derivedItem @@ -4257,7 +4254,7 @@ subroutine SetRefreshAlarms(clock,primaryItem,derivedItem,rc) call MAPL_NCIOParseTimeUnits(ctInt,iyy,imm,idd,ihh,imn,isc,status) _VERIFY(STATUS) call ESMF_TimeIntervalSet(tInterval,yy=iyy,mm=imm,d=idd,h=ihh,m=imn,s=isc,rc=status) - _VERIFY(STATUS) + _VERIFY(STATUS) if (present(primaryItem)) then primaryItem%update_alarm = simpleAlarm(current_time,tInterval,rc=status) _VERIFY(status) @@ -4373,7 +4370,7 @@ subroutine MAPL_ExtDataGetBracket(item,Bside,field,bundle,getRL,vcomp,rc) character(len=ESMF_MAXSTR) :: Iam logical :: getRL_ - + Iam = "MAPL_ExtDataGetBracket" if (present(getRL)) then @@ -4386,7 +4383,7 @@ subroutine MAPL_ExtDataGetBracket(item,Bside,field,bundle,getRL,vcomp,rc) if (present(field)) then - if (Bside == MAPL_ExtDataLeft .and. vcomp == 1) then + if (Bside == MAPL_ExtDataLeft .and. vcomp == 1) then if (getRL_) then field = item%modelGridFields%v1_faux1 _RETURN(ESMF_SUCCESS) @@ -4394,7 +4391,7 @@ subroutine MAPL_ExtDataGetBracket(item,Bside,field,bundle,getRL,vcomp,rc) field = item%modelGridFields%v1_finterp1 _RETURN(ESMF_SUCCESS) end if - else if (Bside == MAPL_ExtDataLeft .and. vcomp == 2) then + else if (Bside == MAPL_ExtDataLeft .and. vcomp == 2) then if (getRL_) then field = item%modelGridFields%v2_faux1 _RETURN(ESMF_SUCCESS) @@ -4402,7 +4399,7 @@ subroutine MAPL_ExtDataGetBracket(item,Bside,field,bundle,getRL,vcomp,rc) field = item%modelGridFields%v2_finterp1 _RETURN(ESMF_SUCCESS) end if - else if (Bside == MAPL_ExtDataRight .and. vcomp == 1) then + else if (Bside == MAPL_ExtDataRight .and. vcomp == 1) then if (getRL_) then field = item%modelGridFields%v1_faux2 _RETURN(ESMF_SUCCESS) @@ -4410,7 +4407,7 @@ subroutine MAPL_ExtDataGetBracket(item,Bside,field,bundle,getRL,vcomp,rc) field = item%modelGridFields%v1_finterp2 _RETURN(ESMF_SUCCESS) end if - else if (Bside == MAPL_ExtDataRight .and. vcomp == 2) then + else if (Bside == MAPL_ExtDataRight .and. vcomp == 2) then if (getRL_) then field = item%modelGridFields%v2_faux2 _RETURN(ESMF_SUCCESS) @@ -4432,7 +4429,7 @@ subroutine MAPL_ExtDataGetBracket(item,Bside,field,bundle,getRL,vcomp,rc) if (getRL_) then field = item%modelGridFields%v1_faux1 _RETURN(ESMF_SUCCESS) - else + else field = item%modelGridFields%v1_finterp1 _RETURN(ESMF_SUCCESS) end if @@ -4440,16 +4437,16 @@ subroutine MAPL_ExtDataGetBracket(item,Bside,field,bundle,getRL,vcomp,rc) if (getRL_) then field = item%modelGridFields%v1_faux2 _RETURN(ESMF_SUCCESS) - else + else field = item%modelGridFields%v1_finterp2 _RETURN(ESMF_SUCCESS) end if end if else if (present(bundle)) then - if (Bside == MAPL_ExtDataLeft) then + if (Bside == MAPL_ExtDataLeft) then bundle = item%binterp1 _RETURN(ESMF_SUCCESS) - else if (Bside == MAPL_ExtDataRight) then + else if (Bside == MAPL_ExtDataRight) then bundle = item%binterp2 _RETURN(ESMF_SUCCESS) end if @@ -4516,16 +4513,16 @@ subroutine MAPL_ExtDataFillField(item,FieldF,FieldR,rc) call lgr%debug(' --> MAPL_ExtDataFillField: filling %i3 level input to %i3 levels for %a', lm_in, lm_out, trim(item%name)) _RETURN(ESMF_SUCCESS) - + end subroutine MAPL_ExtDataFillField subroutine MAPL_ExtDataFlipVertical(item,filec,rc) type(PrimaryExport), intent(inout) :: item integer, intent(in) :: filec integer, optional, intent(out) :: rc - + integer :: status - + type(ESMF_Field) :: Field,field1,field2 real, pointer :: ptr(:,:,:) real, allocatable :: ptemp(:,:,:) @@ -4585,9 +4582,9 @@ subroutine MAPL_ExtDataPopulateBundle(item,filec,pbundle,rc) integer, intent(in) :: filec type(ESMF_FieldBundle), intent(inout) :: pbundle integer, optional, intent(out) :: rc - + integer :: status - + type(ESMF_Field) :: Field,field1,field2 type(ESMF_Grid) :: grid @@ -4647,7 +4644,7 @@ subroutine MAPL_ExtDataCreateCFIO(IOBundles, rc) type (IoBundleVectorIterator) :: bundle_iter type (ExtData_IoBundle), pointer :: io_bundle integer :: status - + bundle_iter = IOBundles%begin() do while (bundle_iter /= IOBundles%end()) io_bundle => bundle_iter%get() @@ -4750,7 +4747,7 @@ end subroutine createFileLevBracket subroutine IOBundle_Add_Entry(IOBundles,item,entry_num,file,bside,time_index,rc) type(Iobundlevector), intent(inout) :: IOBundles - type(primaryExport), intent(in) :: item + type(primaryExport), intent(in) :: item integer, intent(in) :: entry_num character(len=*), intent(in) :: file integer, intent(in) :: bside diff --git a/gridcomps/ExtData2G/CMakeLists.txt b/gridcomps/ExtData2G/CMakeLists.txt new file mode 100644 index 000000000000..3e1a749be1be --- /dev/null +++ b/gridcomps/ExtData2G/CMakeLists.txt @@ -0,0 +1,34 @@ +esma_set_this (OVERRIDE MAPL.ExtData2G) + +set (srcs + ExtDataFileStream.F90 + ExtDataRule.F90 + ExtDataDerived.F90 + ExtDataConfig.F90 + ExtDataGridCompNG.F90 + TimeStringConversion.F90 + ExtDataTypeDef.F90 + ExtDataOldTypesCreator.F90 + ExtDataBracket.F90 + ExtDataUpdatePointer.F90 + ExtDataAbstractFileHandler.F90 + ExtDataClimFileHandler.F90 + ExtDataSimpleFileHandler.F90 + ExtDataNode.F90 + ExtDataLgr.F90 + ExtDataConstants.F90 + ExtDataSample.F90 + ExtData_IOBundleMod.F90 + ExtData_IOBundleVectorMod.F90 + ExtDataMasking.F90 + ) + + +# Replace SHARED with ${MAPL_LIBRARY_TYPE} if using GCHP +#esma_add_library (${this} SRCS ${srcs} DEPENDENCIES MAPL.shared MAPL.base MAPL.generic MAPL.griddedio TYPE SHARED) +esma_add_library (${this} SRCS ${srcs} DEPENDENCIES MAPL.shared MAPL.base MAPL.generic MAPL.griddedio TYPE ${MAPL_LIBRARY_TYPE}) +target_link_libraries (${this} PUBLIC GFTL::gftl GFTL_SHARED::gftl-shared YAFYAML::yafyaml esmf NetCDF::NetCDF_Fortran + PRIVATE MPI::MPI_Fortran) +target_include_directories (${this} PUBLIC $) + +set_target_properties (${this} PROPERTIES Fortran_MODULE_DIRECTORY ${include_${this}}) diff --git a/gridcomps/ExtData2G/ExtDataAbstractFileHandler.F90 b/gridcomps/ExtData2G/ExtDataAbstractFileHandler.F90 new file mode 100644 index 000000000000..afa0ccffcb76 --- /dev/null +++ b/gridcomps/ExtData2G/ExtDataAbstractFileHandler.F90 @@ -0,0 +1,168 @@ +#include "MAPL_Exceptions.h" +#include "MAPL_ErrLog.h" +#include "unused_dummy.H" +module MAPL_ExtdataAbstractFileHandler + use ESMF + use yafYaml + use MAPL_KeywordEnforcerMod + use MAPL_ExceptionHandling + use MAPL_ExtDataBracket + use MAPL_ExtDataFileStream + use MAPL_ExtDataFileStreamMap + use MAPL_DataCollectionMod + use MAPL_CollectionVectorMod + use MAPL_ExtDataConstants + use MAPL_DataCollectionManagerMod + use MAPL_FileMetadataUtilsMod + use MAPL_TimeStringConversion + use MAPL_StringTemplate + implicit none + private + public :: ExtDataAbstractFileHandler + + type, abstract :: ExtDataAbstractFileHandler + character(:), allocatable :: file_template + type(ESMF_TimeInterval) :: frequency + type(ESMF_Time) :: reff_time + integer :: collection_id + type(ESMF_Time), allocatable :: valid_range(:) + logical :: persist_closest + contains + procedure :: initialize + procedure :: make_metadata + procedure :: get_time_on_file + procedure(get_file_bracket), deferred :: get_file_bracket + end type + + abstract interface + subroutine get_file_bracket(this, input_time, source_time, bracket, rc) + use ESMF + use MAPL_ExtDataBracket + import ExtDataAbstractFileHandler + class(ExtDataAbstractFileHandler), intent(inout) :: this + type(ESMF_Time), intent(in) :: input_time + type(ESMF_Time), intent(in) :: source_time(:) + type(ExtDataBracket), intent(inout) :: bracket + integer, optional, intent(out) :: rc + end subroutine get_file_bracket + + end interface + +contains + + subroutine initialize(this,file_series,persist_closest,unusable,rc) + class(ExtDataAbstractFileHandler), intent(inout) :: this + type(ExtDataFileStream), intent(in) :: file_series + class(KeywordEnforcer), optional, intent(in) :: unusable + logical, optional, intent(in) :: persist_closest + integer, optional, intent(out) :: rc + + integer :: status + + _UNUSED_DUMMY(unusable) + + this%file_template = file_series%file_template + this%frequency = file_series%frequency + this%reff_time = file_series%reff_time + if (allocated(file_series%valid_range)) then + allocate(this%valid_range,source=file_series%valid_range) + end if + this%collection_id = file_series%collection_id + if (present(persist_closest)) then + this%persist_closest = persist_closest + else + this%persist_closest = .false. + end if + + end subroutine initialize + + subroutine get_time_on_file(this,filename,target_time,bracketside,time_index,output_time,unusable,wrap,rc) + class(ExtdataAbstractFileHandler), intent(inout) :: this + character(len=*), intent(inout) :: filename + type(ESMF_Time), intent(in) :: target_time + character(len=*), intent(in) :: bracketside + integer, intent(Out) :: time_index + type(ESMF_Time), intent(out) :: output_time + class (KeywordEnforcer), optional, intent(out) :: unusable + integer, optional, intent(inout) :: wrap + integer, optional, intent(out) :: rc + integer :: status + + type(FileMetadataUtils), pointer :: file_metadata + type(ESMF_Time), allocatable :: time_series(:) + logical :: in_bounds, found_time, wrap_ + integer :: i,num_times + + _UNUSED_DUMMY(unusable) + if (present(wrap)) then + wrap_= .true. + else + wrap_=.false. + end if + time_index=time_not_found + + call this%make_metadata(filename,file_metadata,__RC__) + call file_metadata%get_time_info(timeVector=time_series,__RC__) + num_times = size(time_series) + found_time = .false. + if (bracketside == 'L') then + in_bounds = .not.(target_time < time_series(1)) + if (in_bounds) then + do i=num_times,1,-1 + if (target_time >= time_series(i)) then + output_time = time_series(i) + time_index = i + found_time = .true. + exit + end if + enddo + else + if (wrap_) then + output_time=time_series(num_times) + time_index = num_times + found_time = .true. + wrap = -1 + end if + end if + else if (bracketside == 'R') then + in_bounds = .not.(target_time >= time_series(num_times)) + if (in_bounds) then + do i=1,num_times + if (target_time < time_series(i)) then + output_time = time_series(i) + time_index = i + found_time = .true. + exit + end if + enddo + else + if (wrap_) then + output_time=time_series(1) + time_index = 1 + found_time = .true. + wrap = 1 + end if + end if + else + _FAIL("unknown bracket side") + end if + + _RETURN(_SUCCESS) + + end subroutine get_time_on_file + + subroutine make_metadata(this,file,metadata,rc) + class(ExtdataAbstractFileHandler), intent(inout) :: this + character(len=*), intent(in ) :: file + type(FileMetadataUtils), pointer, intent(inout) :: metadata + integer, optional, intent(out ) :: rc + type(MAPLDataCollection), pointer :: collection => null() + + Collection => DataCollections%at(this%collection_id) + metadata => collection%find(file) + _RETURN(_SUCCESS) + + end subroutine make_metadata + + +end module MAPL_ExtdataAbstractFileHandler diff --git a/gridcomps/ExtData2G/ExtDataBracket.F90 b/gridcomps/ExtData2G/ExtDataBracket.F90 new file mode 100644 index 000000000000..393eef062377 --- /dev/null +++ b/gridcomps/ExtData2G/ExtDataBracket.F90 @@ -0,0 +1,270 @@ +#include "MAPL_Exceptions.h" +#include "MAPL_ErrLog.h" +module MAPL_ExtDataBracket + use ESMF + use MAPL_KeywordEnforcerMod + use MAPL_ExceptionHandling + use MAPL_BaseMod, only: MAPL_UNDEF + use MAPL_ExtDataNode + implicit none + private + + public :: ExtDataBracket + + type ExtDataBracket + type(ExtDataNode) :: left_node + type(ExtDataNode) :: right_node + real :: scale_factor = 0.0 + real :: offset = 0.0 + logical :: disable_interpolation = .false. + logical :: intermittent_disable = .false. + logical :: new_file_right + logical :: new_file_left + contains + procedure :: interpolate_to_time + procedure :: time_in_bracket + procedure :: set_parameters + procedure :: get_parameters + procedure :: set_node + procedure :: get_node + procedure :: swap_node_fields + procedure :: reset + end type ExtDataBracket + +contains + + subroutine reset(this) + class(ExtDataBracket), intent(inout) :: this + this%new_file_right=.false. + this%new_file_left =.false. + end subroutine reset + + function time_in_bracket(this,time) result(in_bracket) + class(ExtDataBracket), intent(in) :: this + logical :: in_bracket + type(ESMF_Time), intent(in) :: time + + in_bracket = (this%left_node%time <=time) .and. (time < this%right_node%time) + + end function time_in_bracket + + subroutine set_node(this, bracketside, unusable, field, file, time, time_index, was_set, rc) + class(ExtDataBracket), intent(inout) :: this + character(len=*), intent(in) :: bracketside + class(KeywordEnforcer), optional, intent(in) :: unusable + type(ESMF_Field), optional, intent(in) :: field + character(len=*), optional, intent(in) :: file + integer, optional, intent(in) :: time_index + type(ESMF_Time), optional, intent(in) :: time + logical, optional, intent(in) :: was_set + integer, optional, intent(out) :: rc + + _UNUSED_DUMMY(unusable) + if (bracketside=='L') then + if (present(field)) this%left_node%field=field + if (present(time)) this%left_node%time=time + if (present(time_index)) this%left_node%time_index=time_index + if (present(file)) this%left_node%file=file + if (present(was_set)) this%left_node%was_set=was_set + else if (bracketside=='R') then + if (present(field)) this%right_node%field=field + if (present(time)) this%right_node%time=time + if (present(time_index)) this%right_node%time_index=time_index + if (present(file)) this%right_node%file=file + if (present(was_set)) this%right_node%was_set=was_set + else + _FAIL('wrong bracket side') + end if + _RETURN(_SUCCESS) + + end subroutine set_node + + subroutine get_node(this, bracketside, unusable, field, file, time, time_index, was_set, rc) + class(ExtDataBracket), intent(inout) :: this + character(len=*), intent(in) :: bracketside + class(KeywordEnforcer), optional, intent(in) :: unusable + type(ESMF_Field), optional, intent(out) :: field + character(len=*), optional, intent(out) :: file + integer, optional, intent(out) :: time_index + type(ESMF_Time), optional, intent(out) :: time + logical, optional, intent(out) :: was_set + integer, optional, intent(out) :: rc + + _UNUSED_DUMMY(unusable) + if (bracketside=='L') then + if (present(field)) field=this%left_node%field + if (present(time)) time=this%left_node%time + if (present(time_index)) time_index=this%left_node%time_index + if (present(file)) file=this%left_node%file + if (present(was_set)) was_set=this%left_node%was_set + else if (bracketside=='R') then + if (present(field)) field=this%right_node%field + if (present(time)) time=this%right_node%time + if (present(time_index)) time_index=this%right_node%time_index + if (present(file)) file=this%right_node%file + if (present(was_set)) was_set=this%right_node%was_set + else + _FAIL('wrong bracket side') + end if + _RETURN(_SUCCESS) + + end subroutine get_node + + + subroutine set_parameters(this, unusable, linear_trans, disable_interpolation, left_field, right_field, intermittent_disable, rc) + class(ExtDataBracket), intent(inout) :: this + class(KeywordEnforcer), optional, intent(in) :: unusable + real, optional, intent(in) :: linear_trans(2) + logical, optional, intent(in) :: disable_interpolation + type(ESMF_Field), optional, intent(in) :: left_field + type(ESMF_Field), optional, intent(in) :: right_field + logical, optional, intent(in) :: intermittent_disable + integer, optional, intent(out) :: rc + + _UNUSED_DUMMY(unusable) + if (present(linear_trans)) then + this%offset=linear_trans(1) + this%scale_factor=linear_trans(2) + end if + if (present(disable_interpolation)) this%disable_interpolation = disable_interpolation + if (present(left_field)) this%left_node%field=left_field + if (present(right_field)) this%right_node%field=right_field + if (present(intermittent_disable)) this%intermittent_disable = intermittent_disable + _RETURN(_SUCCESS) + + end subroutine set_parameters + + subroutine get_parameters(this, bracket_side, unusable, field, file, time, time_index, update, rc) + class(ExtDataBracket), intent(inout) :: this + character(len=*), intent(in) :: bracket_side + class(KeywordEnforcer), optional, intent(in) :: unusable + type(ESMF_Field), optional, intent(out) :: field + character(len=*), optional, intent(out) :: file + type(ESMF_Time), optional, intent(out) :: time + integer, optional, intent(out) :: time_index + logical, optional, intent(out) :: update + integer, optional, intent(out) :: rc + + _UNUSED_DUMMY(unusable) + if (bracket_side == 'L') then + if (present(field)) field = this%left_node%field + if (present(file)) file = trim(this%left_node%file) + if (present(time)) time = this%left_node%time + if (present(time_index)) time_index = this%left_node%time_index + if (present(update)) update = this%new_file_left + else if (bracket_side == 'R') then + if (present(field)) field = this%right_node%field + if (present(file)) file = trim(this%right_node%file) + if (present(time)) time = this%right_node%time + if (present(time_index)) time_index = this%right_node%time_index + if (present(update)) update = this%new_file_right + else + _FAIL('invalid bracket side!') + end if + _RETURN(_SUCCESS) + + end subroutine get_parameters + + subroutine interpolate_to_time(this,field,time,rc) + class(ExtDataBracket), intent(inout) :: this + type(ESMF_Field), intent(inout) :: field + type(ESMF_Time), intent(in) :: time + integer, optional, intent(out) :: rc + + type(ESMF_TimeInterval) :: tinv1, tinv2 + real :: alpha + real, pointer :: var2d(:,:) => null() + real, pointer :: var3d(:,:,:) => null() + real, pointer :: var2d_left(:,:) => null() + real, pointer :: var2d_right(:,:) => null() + real, pointer :: var3d_left(:,:,:) => null() + real, pointer :: var3d_right(:,:,:) => null() + integer :: field_rank + integer :: status + + call ESMF_FieldGet(field,dimCount=field_rank,__RC__) + alpha = 0.0 + if ( (.not.this%disable_interpolation) .and. (.not.this%intermittent_disable)) then + tinv1 = time - this%left_node%time + tinv2 = this%right_node%time - this%left_node%time + alpha = tinv1/tinv2 + end if + if (field_rank==2) then + call ESMF_FieldGet(field,localDE=0,farrayPtr=var2d,__RC__) + call ESMF_FieldGet(this%right_node%field,localDE=0,farrayPtr=var2d_right,__RC__) + call ESMF_FieldGet(this%left_node%field,localDE=0,farrayPtr=var2d_left,__RC__) + if (time == this%left_node%time .or. this%disable_interpolation) then + var2d = var2d_left + else if (time == this%right_node%time) then + var2d = var2d_right + else + where( (var2d_left /= MAPL_UNDEF) .and. (var2d_right /= MAPL_UNDEF)) + var2d = var2d_left + alpha*(var2d_right-var2d_left) + elsewhere + var2d = MAPL_UNDEF + endwhere + end if + + if (this%scale_factor == 0.0 .and. this%offset /= 0.0) then + where(var2d /= MAPL_UNDEF) var2d=var2d+this%offset + end if + if (this%scale_factor /= 0.0 .and. this%offset == 0.0) then + where(var2d /= MAPL_UNDEF) var2d=var2d*this%scale_factor + end if + if (this%scale_factor /= 0.0 .and. this%offset /= 0.0) then + where(var2d /= MAPL_UNDEF) var2d=var2d*this%scale_factor+this%offset + end if + + else if (field_rank==3) then + call ESMF_FieldGet(field,localDE=0,farrayPtr=var3d,__RC__) + call ESMF_FieldGet(this%right_node%field,localDE=0,farrayPtr=var3d_right,__RC__) + call ESMF_FieldGet(this%left_node%field,localDE=0,farrayPtr=var3d_left,__RC__) + if (time == this%left_node%time .or. this%disable_interpolation) then + var3d = var3d_left + else if (time == this%right_node%time) then + var3d = var3d_right + else + where( (var3d_left /= MAPL_UNDEF) .and. (var3d_right /= MAPL_UNDEF)) + var3d = var3d_left + alpha*(var3d_right-var3d_left) + elsewhere + var3d = MAPL_UNDEF + endwhere + end if + + if (this%scale_factor == 0.0 .and. this%offset /= 0.0) then + where(var3d /= MAPL_UNDEF) var3d=var3d+this%offset + end if + if (this%scale_factor /= 0.0 .and. this%offset == 0.0) then + where(var3d /= MAPL_UNDEF) var3d=var3d*this%scale_factor + end if + if (this%scale_factor /= 0.0 .and. this%offset /= 0.0) then + where(var3d /= MAPL_UNDEF) var3d=var3d*this%scale_factor+this%offset + end if + + end if + _RETURN(_SUCCESS) + + end subroutine interpolate_to_time + + subroutine swap_node_fields(this,rc) + class(ExtDataBracket), intent(inout) :: this + integer, optional, intent(out) :: rc + integer :: status + integer :: field_rank + real, pointer :: var3d_left(:,:,:),var3d_right(:,:,:) + real, pointer :: var2d_left(:,:),var2d_right(:,:) + + call ESMF_FieldGet(this%left_node%field,dimCount=field_rank,__RC__) + if (field_rank == 2) then + call ESMF_FieldGet(this%right_node%field,localDE=0,farrayPtr=var2d_right,__RC__) + call ESMF_FieldGet(this%left_node%field,localDE=0,farrayPtr=var2d_left,__RC__) + var2d_left = var2d_right + else if (field_rank ==3) then + call ESMF_FieldGet(this%right_node%field,localDE=0,farrayPtr=var3d_right,__RC__) + call ESMF_FieldGet(this%left_node%field,localDE=0,farrayPtr=var3d_left,__RC__) + var3d_left = var3d_right + end if + _RETURN(_SUCCESS) + end subroutine swap_node_fields + +end module MAPL_ExtDataBracket diff --git a/gridcomps/ExtData2G/ExtDataClimFileHandler.F90 b/gridcomps/ExtData2G/ExtDataClimFileHandler.F90 new file mode 100644 index 000000000000..0e4fdbd75f93 --- /dev/null +++ b/gridcomps/ExtData2G/ExtDataClimFileHandler.F90 @@ -0,0 +1,280 @@ +#include "MAPL_Exceptions.h" +#include "MAPL_ErrLog.h" +module MAPL_ExtdataClimFileHandler + use ESMF + use MAPL_ExtDataAbstractFileHandler + use MAPL_KeywordEnforcerMod + use MAPL_ExceptionHandling + use MAPL_DataCollectionMod + use MAPL_CollectionVectorMod + use MAPL_DataCollectionManagerMod + use MAPL_FileMetadataUtilsMod + use MAPL_TimeStringConversion + use MAPL_StringTemplate + use MAPL_ExtDataBracket + use MAPL_ExtDataConstants + implicit none + private + public ExtDataClimFileHandler + + integer, parameter :: CLIM_NULL = -1 + type, extends(ExtDataAbstractFileHandler) :: ExtDataClimFileHandler + integer :: clim_year = CLIM_NULL + contains + procedure :: get_file_bracket + procedure :: get_file + end type + +contains + + subroutine get_file_bracket(this, input_time, source_time, bracket, rc) + class(ExtdataClimFileHandler), intent(inout) :: this + type(ESMF_Time), intent(in) :: input_time + type(ESMF_Time), intent(in) :: source_time(:) + type(ExtDataBracket), intent(inout) :: bracket + integer, optional, intent(out) :: rc + + type(ESMF_Time) :: time + integer :: time_index + character(len=ESMF_MAXPATHLEN) :: current_file + integer :: status + type(ESMF_TimeInterval) :: zero + type(ESMF_Time) :: target_time + + integer :: target_year, original_year,clim_shift,valid_years(2) + integer, allocatable :: source_years(:) + + + if (bracket%time_in_bracket(input_time)) then + _RETURN(_SUCCESS) + end if + + target_time=input_time + _ASSERT(size(this%valid_range) == 2, 'Valid time is not defined so can not do any extrapolation or climatology') + call ESMF_TimeGet(this%valid_range(1),yy=valid_years(1),__RC__) + call ESMF_TimeGet(this%valid_range(2),yy=valid_years(2),__RC__) + if (size(source_time)==2) then + allocate(source_years(2)) + call ESMF_TimeGet(source_time(1),yy=source_years(1),__RC__) + call ESMF_TimeGet(source_time(2),yy=source_years(2),__RC__) + _ASSERT(source_years(1) >= valid_years(1),'source time outide valid range') + _ASSERT(source_years(1) <= valid_years(2),'source time outide valid range') + _ASSERT(source_years(2) >= valid_years(1),'source time outide valid range') + _ASSERT(source_years(2) <= valid_years(2),'source time outide valid range') + end if + + ! shift target year to request source time if specified + ! is TS1 < TM < TS2, if not then extrapolate beyond that + call ESMF_TimeGet(target_time,yy=target_year,__RC__) + original_year=target_year + + !if (size(source_years)>0) then + if (allocated(source_years)) then + if (target_year < source_years(1)) then + target_year = source_years(1) + this%clim_year = target_year + else if (target_year >= source_years(2)) then + target_year = source_years(2) + this%clim_year = target_year + end if + call swap_year(target_time,target_year,__RC__) + else + if (target_year < valid_years(1)) then + target_year = valid_years(1) + this%clim_year = target_year + call swap_year(target_time,target_year,__RC__) + else if (target_year >= valid_years(2)) then + target_year = valid_years(2) + this%clim_year = target_year + call swap_year(target_time,target_year,__RC__) + end if + end if + + ! the target time is contained in the dataset and we are not extrapolating outside of source time selection based on available data + if (this%clim_year == CLIM_NULL) then + + call ESMF_TimeIntervalSet(zero,__RC__) + if (this%frequency == zero) then + current_file = this%file_template + call this%get_time_on_file(current_file,input_time,'L',time_index,time,__RC__) + _ASSERT(time_index/=time_not_found,"Time not found on file") + call bracket%set_node('L',file=current_file,time_index=time_index,time=time,__RC__) + if (bracket%left_node == bracket%right_node) then + call bracket%swap_node_fields(rc=status) + _VERIFY(status) + else + bracket%new_file_left=.true. + end if + call this%get_time_on_file(current_file,input_time,'R',time_index,time,__RC__) + _ASSERT(time_index/=time_not_found,"Time not found on file") + call bracket%set_node('R',file=current_file,time_index=time_index,time=time,__RC__) + bracket%new_file_right=.true. + else + call this%get_file(current_file,target_time,0,__RC__) + call this%get_time_on_file(current_file,target_time,'L',time_index,time,rc=status) + if (time_index == time_not_found) then + call this%get_file(current_file,target_time,-1,__RC__) + call this%get_time_on_file(current_file,target_time,'L',time_index,time,__RC__) + _ASSERT(time_index/=time_not_found,"Time not found on file") + end if + call bracket%set_node('L',file=current_file,time_index=time_index,time=time,__RC__) + if (bracket%left_node == bracket%right_node) then + call bracket%swap_node_fields(rc=status) + _VERIFY(status) + else + bracket%new_file_left=.true. + end if + + call this%get_file(current_file,target_time,0,__RC__) + call this%get_time_on_file(current_file,target_time,'R',time_index,time,rc=status) + if (time_index == time_not_found) then + call this%get_file(current_file,target_time,1,__RC__) + call this%get_time_on_file(current_file,target_time,'R',time_index,time,__RC__) + _ASSERT(time_index/=time_not_found,"Time not found on file") + end if + call bracket%set_node('R',file=current_file,time_index=time_index,time=time,__RC__) + bracket%new_file_right=.true. + end if + + ! the target time has been specified to be a climatology for the year; either we + ! are outside the dataset or we have requested a source time range and are on + ! or outside either end + else + + call ESMF_TimeIntervalSet(zero,__RC__) + if (this%frequency == zero) then + current_file = this%file_template + clim_shift=0 + call this%get_time_on_file(current_file,target_time,'L',time_index,time,wrap=clim_shift,__RC__) + _ASSERT(time_index/=time_not_found,"Time not found on file") + call swap_year(time,original_year+clim_shift,__RC__) + call bracket%set_node('L',file=current_file,time_index=time_index,time=time,__RC__) + if (bracket%left_node == bracket%right_node) then + call bracket%swap_node_fields(rc=status) + _VERIFY(status) + else + bracket%new_file_left=.true. + end if + + clim_shift=0 + call this%get_time_on_file(current_file,target_time,'R',time_index,time,wrap=clim_shift,__RC__) + _ASSERT(time_index/=time_not_found,"Time not found on file") + call swap_year(time,original_year+clim_shift,__RC__) + call bracket%set_node('R',file=current_file,time_index=time_index,time=time,__RC__) + bracket%new_file_right=.true. + + else + + call this%get_file(current_file,target_time,0,__RC__) + call this%get_time_on_file(current_file,target_time,'L',time_index,time,rc=status) + if (time_index == time_not_found) then + call this%get_file(current_file,target_time,-1,__RC__) + call this%get_time_on_file(current_file,target_time,'L',time_index,time,__RC__) + _ASSERT(time_index/=time_not_found,"Time not found on file") + call ESMF_TimeGet(target_time,yy=target_year,__RC__) + if (target_year > this%clim_year) then + call swap_year(time,original_year-1,__RC__) + else + call swap_year(time,original_year,__RC__) + end if + else + call swap_year(time,original_year,__RC__) + end if + if (bracket%left_node == bracket%right_node) then + call bracket%swap_node_fields(rc=status) + _VERIFY(status) + else + bracket%new_file_left=.true. + end if + call bracket%set_node('L',file=current_file,time_index=time_index,time=time,__RC__) + + call this%get_file(current_file,target_time,0,__RC__) + call this%get_time_on_file(current_file,target_time,'R',time_index,time,rc=status) + if (time_index == time_not_found) then + call this%get_file(current_file,target_time,1,__RC__) + call this%get_time_on_file(current_file,target_time,'R',time_index,time,__RC__) + _ASSERT(time_index/=time_not_found,"Time not found on file") + call ESMF_TimeGet(target_time,yy=target_year,__RC__) + if (target_year < this%clim_year) then + call swap_year(time,original_year+1,__RC__) + else + call swap_year(time,original_year,__RC__) + end if + else + call swap_year(time,original_year,__RC__) + end if + call bracket%set_node('R',file=current_file,time_index=time_index,time=time,__RC__) + bracket%new_file_right=.true. + + end if + + end if + + _RETURN(_SUCCESS) + + end subroutine get_file_bracket + + subroutine get_file(this,filename,target_time,shift,rc) + class(ExtdataClimFileHandler), intent(inout) :: this + character(len=*), intent(out) :: filename + type(ESMF_Time) :: target_time + integer, intent(in) :: shift + integer, intent(out), optional :: rc + + type(ESMF_Time) :: ftime + integer :: n,status + logical :: file_found + integer :: new_year + integer(ESMF_KIND_I8) :: interval_seconds + + + call ESMF_TimeIntervalGet(this%frequency,s_i8=interval_seconds) + if (interval_seconds==0) then + ! time is not representable as absolute time interval (month, year etc...) do this + ! brute force way. Not good but ESMF leaves no choice + ftime=this%reff_time + do while (ftime <= target_time) + ftime = ftime + this%frequency + enddo + ftime=ftime -this%frequency + shift*this%frequency + else + n = (target_time-this%reff_time)/this%frequency + ftime = this%reff_time+(n+shift)*this%frequency + end if + if (this%clim_year /= CLIM_NULL) then + call ESMF_TimeGet(ftime,yy=new_year,__RC__) + if (new_year/=this%clim_year) then + call swap_year(ftime,this%clim_year,__RC__) + if (shift > 0) then + call swap_year(target_time,this%clim_year-shift) + else if (shift < 0) then + call swap_year(target_time,this%clim_year+shift) + end if + end if + end if + call fill_grads_template(filename,this%file_template,time=ftime,__RC__) + inquire(file=trim(filename),exist=file_found) + _ASSERT(file_found,"get_file did not file a file using: "//trim(this%file_template)) + _RETURN(_SUCCESS) + + end subroutine get_file + + subroutine swap_year(time,year,rc) + type(ESMF_Time), intent(inout) :: time + integer, intent(in) :: year + integer, optional, intent(out) :: rc + logical :: is_leap_year + type(ESMF_Calendar) :: calendar + integer :: status, month, day, hour, minute, second + + is_leap_year=.false. + call ESMF_TimeGet(time,mm=month,dd=day,h=hour,m=minute,s=second,calendar=calendar,__RC__) + if (day==29 .and. month==2) then + is_leap_year = ESMF_CalendarIsLeapYear(calendar,year,__RC__) + if (.not.is_leap_year) day=28 + end if + call ESMF_TimeSet(time,yy=year,mm=month,dd=day,h=hour,m=minute,s=second,__RC__) + _RETURN(_SUCCESS) + end subroutine + +end module MAPL_ExtdataClimFileHandler diff --git a/gridcomps/ExtData2G/ExtDataConfig.F90 b/gridcomps/ExtData2G/ExtDataConfig.F90 new file mode 100644 index 000000000000..a6b29845364c --- /dev/null +++ b/gridcomps/ExtData2G/ExtDataConfig.F90 @@ -0,0 +1,420 @@ +#include "MAPL_ErrLog.h" +module MAPL_ExtDataConfig + use ESMF + use yaFyaml + use gFTL_StringVector + use MAPL_KeywordEnforcerMod + use MAPL_ExceptionHandling + use MAPL_ExtDataFileStream + use MAPL_ExtDataFileStreamMap + use MAPL_ExtDataRule + use MAPL_ExtDataRuleMap + use MAPL_ExtDataDerived + use MAPL_ExtDataDerivedMap + use MAPL_ExtDataConstants + use MAPL_ExtDataTimeSample + use MAPL_ExtDataTimeSampleMap + use MAPL_TimeStringConversion + use MAPL_ExtDataMask + implicit none + private + + character(len=1), parameter :: rule_sep = "+" + + type, public :: ExtDataConfig + integer :: debug + type(ExtDataRuleMap) :: rule_map + type(ExtDataDerivedMap) :: derived_map + type(ExtDataFileStreamMap) :: file_stream_map + type(ExtDataTimeSampleMap) :: sample_map + + contains + procedure :: add_new_rule + procedure :: get_item_type + procedure :: new_ExtDataConfig_from_yaml + procedure :: count_rules_for_item + procedure :: get_time_range + procedure :: get_extra_derived_items + end type + +contains + + recursive subroutine new_ExtDataConfig_from_yaml(ext_config,config_file,current_time,unusable,rc) + class(ExtDataConfig), intent(inout), target :: ext_config + character(len=*), intent(in) :: config_file + type(ESMF_Time), intent(in) :: current_time + class(KeywordEnforcer), optional, intent(in) :: unusable + integer, optional, intent(out) :: rc + + type(Parser) :: p + class(YAML_Node), allocatable :: config + class(YAML_Node), pointer :: subcfg, ds_config, rule_config, derived_config, sample_config, subconfigs, rule_map + class(NodeIterator), allocatable :: iter + character(len=:), pointer :: key + character(len=:), allocatable :: new_key + type(ExtDataFileStream) :: ds + type(ExtDataDerived) :: derived + type(ExtDataTimeSample) :: ts + integer :: status + + type(ExtDataFileStream), pointer :: temp_ds + type(ExtDataTimeSample), pointer :: temp_ts + type(ExtDataDerived), pointer :: temp_derived + + character(len=:), pointer :: sub_file + integer :: i,num_rules + integer, allocatable :: sorted_rules(:) + character(len=1) :: i_char + logical :: file_found + + _UNUSED_DUMMY(unusable) + + inquire(file=trim(config_file),exist=file_found) + _ASSERT(file_found,"could not find: "//trim(config_file)) + + p = Parser('core') + config = p%load(config_file,rc=status) + if (status/=_SUCCESS) then + _FAIL("Error parsing "//trim(config_file)) + end if + + if (config%has("subconfigs")) then + subconfigs => config%at("subconfigs") + _ASSERT(subconfigs%is_sequence(),'subconfigs is not a sequence') + do i=1,subconfigs%size() + sub_file => to_string(subconfigs%at(i)) + call new_ExtDataConfig_from_yaml(ext_config,sub_file,current_time,rc=status) + _VERIFY(status) + end do + end if + + if (config%has("Samplings")) then + sample_config => config%of("Samplings") + iter = sample_config%begin() + do while (iter /= sample_config%end()) + key => to_string(iter%first(),_RC) + temp_ts => ext_config%sample_map%at(key) + _ASSERT(.not.associated(temp_ts),"defined duplicate named sample key") + subcfg => iter%second() + ts = ExtDataTimeSample(subcfg,_RC) + _VERIFY(status) + call ext_config%sample_map%insert(trim(key),ts) + call iter%next() + enddo + end if + + if (config%has("Collections")) then + ds_config => config%of("Collections") + iter = ds_config%begin() + do while (iter /= ds_config%end()) + key => to_string(iter%first(),_RC) + temp_ds => ext_config%file_stream_map%at(key) + _ASSERT(.not.associated(temp_ds),"defined duplicate named collection") + subcfg => iter%second() + ds = ExtDataFileStream(subcfg,current_time,_RC) + call ext_config%file_stream_map%insert(trim(key),ds) + call iter%next() + enddo + end if + + if (config%has("Exports")) then + rule_config => config%of("Exports") + iter = rule_config%begin() + do while (iter /= rule_config%end()) + key => to_string(iter%first(),_RC) + subcfg => iter%second() + if (subcfg%is_mapping()) then + call ext_config%add_new_rule(key,subcfg,_RC) + else if (subcfg%is_sequence()) then + sorted_rules = sort_rules_by_start(subcfg,_RC) + num_rules = subcfg%size() + do i=1,num_rules + rule_map => subcfg%of(sorted_rules(i)) + write(i_char,'(I1)')i + new_key = key//rule_sep//i_char + call ext_config%add_new_rule(new_key,rule_map,multi_rule=.true.,_RC) + enddo + else + _FAIL("Exports must be sequence or map") + end if + call iter%next() + enddo + end if + + if (config%has("Derived")) then + derived_config => config%at("Derived") + iter = derived_config%begin() + do while (iter /= derived_config%end()) + call derived%set_defaults(rc=status) + _VERIFY(status) + key => to_string(iter%first(),_RC) + subcfg => iter%second() + derived = ExtDataDerived(subcfg,_RC) + temp_derived => ext_config%derived_map%at(trim(key)) + _ASSERT(.not.associated(temp_derived),"duplicated derived entry key") + call ext_config%derived_map%insert(trim(key),derived) + call iter%next() + enddo + end if + + if (config%has("debug")) then + call config%get(ext_config%debug,"debug",rc=status) + _VERIFY(status) + end if + + _RETURN(_SUCCESS) + end subroutine new_ExtDataConfig_from_yaml + + function count_rules_for_item(this,item_name,rc) result(number_of_rules) + integer :: number_of_rules + class(ExtDataConfig), intent(in) :: this + character(len=*), intent(in) :: item_name + integer, optional, intent(out) :: rc + + type(ExtDataRuleMapIterator) :: rule_iterator + character(len=:), pointer :: key + integer :: idx + rule_iterator = this%rule_map%begin() + number_of_rules = 0 + do while(rule_iterator /= this%rule_map%end()) + key => rule_iterator%key() + idx = index(key,rule_sep) + if (idx > 0) then + if (trim(item_name)==key(1:idx-1)) number_of_rules = number_of_rules + 1 + else + if (trim(item_name) == trim(key)) number_of_rules = number_of_rules + 1 + end if + call rule_iterator%next() + enddo + + _RETURN(_SUCCESS) + end function count_rules_for_item + + function get_time_range(this,item_name,rc) result(time_range) + type(ESMF_Time), allocatable :: time_range(:) + class(ExtDataConfig), intent(in) :: this + character(len=*), intent(in) :: item_name + integer, optional, intent(out) :: rc + + type(ExtDataRuleMapIterator) :: rule_iterator + character(len=:), pointer :: key + type(StringVector) :: start_times + integer :: num_rules + type(ExtDataRule), pointer :: rule + integer :: i,status,idx + type(ESMF_Time) :: very_future_time + + rule_iterator = this%rule_map%begin() + do while(rule_iterator /= this%rule_map%end()) + key => rule_iterator%key() + idx = index(key,rule_sep) + if (idx > 0) then + if (key(1:idx-1) == trim(item_name)) then + rule => rule_iterator%value() + call start_times%push_back(rule%start_time) + end if + end if + call rule_iterator%next() + enddo + + num_rules = start_times%size() + allocate(time_range(num_rules+1)) + do i=1,num_rules + time_range(i) = string_to_esmf_time(start_times%at(i)) + enddo + call ESMF_TimeSet(very_future_time,yy=2365,mm=1,dd=1,_RC) + time_range(num_rules+1) = very_future_time + + _RETURN(_SUCCESS) + end function get_time_range + + function sort_rules_by_start(yaml_sequence,rc) result(sorted_index) + integer, allocatable :: sorted_index(:) + class(YAML_Node), intent(inout) :: yaml_sequence + integer, optional, intent(out) :: rc + + integer :: num_rules,i,j,i_temp,imin + logical :: found_start + class(YAML_Node), pointer :: yaml_dict + character(len=:), allocatable :: start_time + type(ESMF_Time), allocatable :: start_times(:) + type(ESMF_Time) :: temp_time + + num_rules = yaml_sequence%size() + allocate(start_times(num_rules)) + allocate(sorted_index(num_rules),source=[(i,i=1,num_rules)]) + + do i=1,num_rules + yaml_dict => yaml_sequence%of(i) + found_start = yaml_dict%has("starting") + _ASSERT(found_start,"no start key in multirule export of extdata") + start_time = yaml_dict%of("starting") + start_times(i) = string_to_esmf_time(start_time) + enddo + + do i=1,num_rules-1 + imin = i + do j=i+1,num_rules + if (start_times(j) < start_times(imin)) then + temp_time = start_times(imin) + start_times(imin) = start_times(i) + start_times(i) = temp_time + i_temp = sorted_index(imin) + sorted_index(imin) = sorted_index(i) + sorted_index(i) = i_temp + end if + enddo + enddo + _RETURN(_SUCCESS) + end function sort_rules_by_start + + function get_item_type(this,item_name,unusable,rc) result(item_type) + class(ExtDataConfig), intent(inout) :: this + character(len=*), intent(in) :: item_name + class(KeywordEnforcer), optional, intent(in) :: unusable + integer, optional, intent(out) :: rc + integer :: item_type + type(ExtDataRule), pointer :: rule + type(ExtDataDerived), pointer :: derived + + type(ExtDataRuleMapIterator) :: rule_iterator + character(len=:), pointer :: key + character(len=:), allocatable :: found_key + logical :: found_rule + + _UNUSED_DUMMY(unusable) + item_type=ExtData_not_found + + found_rule = .false. + rule_iterator = this%rule_map%begin() + do while(rule_iterator /= this%rule_map%end()) + key => rule_iterator%key() + if (index(key,trim(item_name))/=0) then + found_rule = .true. + found_key = key + exit + end if + call rule_iterator%next() + enddo + + if (found_rule) then + rule => this%rule_map%at(found_key) + if (associated(rule)) then + if (allocated(rule%vector_component)) then + if (rule%vector_component=='EW') then + item_type=Primary_Type_Vector_comp1 + else if (rule%vector_component=='NS') then + item_type=Primary_Type_Vector_comp2 + end if + else + item_type=Primary_Type_scalar + end if + end if + end if + derived => this%derived_map%at(trim(item_name)) + if (associated(derived)) then + item_type=derived_type + found_rule = .true. + end if + _RETURN(_SUCCESS) + end function get_item_type + + subroutine add_new_rule(this,key,export_rule,multi_rule,rc) + class(ExtDataConfig), intent(inout) :: this + character(len=*), intent(in) :: key + class(YAML_Node), intent(in) :: export_rule + logical, optional, intent(in) :: multi_rule + integer, intent(out), optional :: rc + + integer :: semi_pos,status + type(ExtDataRule) :: rule,ucomp,vcomp + type(ExtDataRule), pointer :: temp_rule + character(len=:), allocatable :: uname,vname + logical :: usable_multi_rule + + if (present(multi_rule)) then + usable_multi_rule = multi_rule + else + usable_multi_rule = .false. + end if + + call rule%set_defaults(rc=status) + _VERIFY(status) + rule = ExtDataRule(export_rule,this%sample_map,key,multi_rule=usable_multi_rule,_RC) + semi_pos = index(key,";") + if (semi_pos > 0) then + call rule%split_vector(key,ucomp,vcomp,rc=status) + uname = key(1:semi_pos-1) + vname = key(semi_pos+1:len_trim(key)) + temp_rule => this%rule_map%at(trim(uname)) + _ASSERT(.not.associated(temp_rule),"duplicated export entry key: "//trim(key)) + call this%rule_map%insert(trim(uname),ucomp) + temp_rule => this%rule_map%at(trim(vname)) + _ASSERT(.not.associated(temp_rule),"duplicated export entry key: "//trim(key)) + call this%rule_map%insert(trim(vname),vcomp) + else + temp_rule => this%rule_map%at(trim(key)) + _ASSERT(.not.associated(temp_rule),"duplicated export entry key: "//trim(key)) + call this%rule_map%insert(trim(key),rule) + end if + _RETURN(_SUCCESS) + end subroutine add_new_rule + + function get_extra_derived_items(this,primary_items,derived_items,rc) result(needed_vars) + type(StringVector) :: needed_vars + class(ExtDataConfig), intent(inout) :: this + type(StringVector), intent(in) :: primary_items + type(StringVector), intent(in) :: derived_items + integer, intent(out), optional :: rc + + integer :: status + type(StringVectorIterator) :: string_iter + type(ExtDataDerived), pointer :: derived_item + type(StringVector) :: variables_in_expression + character(len=:), pointer :: sval,derived_name + type(ExtDataRule), pointer :: rule + integer :: i + + if (derived_items%size() ==0) then + _RETURN(_SUCCESS) + end if + + string_iter = derived_items%begin() + do while(string_iter /= derived_items%end() ) + derived_name => string_iter%get() + derived_item => this%derived_map%at(derived_name) + variables_in_expression = derived_item%get_variables_in_expression(_RC) + ! now we have a stringvector of the variables involved in the expression + ! check which of this are already in primary_items list, if any are not + ! then we need to createa new list of needed variables and the "derived field" + ! wence to coppy them + do i=1,variables_in_expression%size() + sval => variables_in_expression%at(i) + if (.not.string_in_string_vector(sval,primary_items)) then + rule => this%rule_map%at(sval) + _ASSERT(associated(rule),"no rule for "//trim(sval)//" needed by "//trim(derived_name)) + call needed_vars%push_back(sval//","//derived_name) + end if + enddo + call string_iter%next() + enddo + + _RETURN(_SUCCESS) + end function get_extra_derived_items + + function string_in_string_vector(target_string,string_vector) result(in_vector) + logical :: in_vector + character(len=*), intent(in) :: target_string + type(StringVector), intent(in) :: string_vector + + type(StringVectorIterator) :: iter + + in_vector = .false. + iter = string_vector%begin() + do while(iter /= string_vector%end()) + if (trim(target_string) == iter%get()) in_vector = .true. + call iter%next() + enddo + end function string_in_string_vector + +end module MAPL_ExtDataConfig diff --git a/gridcomps/ExtData2G/ExtDataConstants.F90 b/gridcomps/ExtData2G/ExtDataConstants.F90 new file mode 100644 index 000000000000..dd711bf12b74 --- /dev/null +++ b/gridcomps/ExtData2G/ExtDataConstants.F90 @@ -0,0 +1,12 @@ +module MAPL_ExtDataConstants +implicit none +private + + integer, parameter, public :: ExtData_Not_Found = 0 + integer, parameter, public :: Primary_Type_Scalar = 1 + integer, parameter, public :: Primary_Type_Vector_comp1 = 2 + integer, parameter, public :: Primary_Type_Vector_comp2 = 3 + integer, parameter, public :: Derived_TYpe = 4 + integer, parameter, public :: time_not_found = -1 + +end module MAPL_ExtDataConstants diff --git a/gridcomps/ExtData2G/ExtDataDerived.F90 b/gridcomps/ExtData2G/ExtDataDerived.F90 new file mode 100644 index 000000000000..f036898ce6b0 --- /dev/null +++ b/gridcomps/ExtData2G/ExtDataDerived.F90 @@ -0,0 +1,114 @@ +#include "MAPL_Exceptions.h" +#include "MAPL_ErrLog.h" +module MAPL_ExtDataDerived + use ESMF + use yaFyaml + use MAPL_KeywordEnforcerMod + use MAPL_ExceptionHandling + use gFTL_StringVector + use MAPL_NewArthParserMod + use MAPL_ExtDataMask + implicit none + private + + type, public :: ExtDataDerived + character(:), allocatable :: expression + character(:), allocatable :: sample_key + contains + procedure :: display + procedure :: set_defaults + procedure :: get_variables_in_expression + end type + + interface ExtDataDerived + module procedure new_ExtDataDerived + end interface + +contains + + function new_ExtDataDerived(config,unusable,rc) result(rule) + class(YAML_Node), intent(in) :: config + class(KeywordEnforcer), optional, intent(in) :: unusable + integer, optional, intent(out) :: rc + + type(ExtDataDerived) :: rule + logical :: is_present + integer :: status + character(len=:), allocatable :: tempc + _UNUSED_DUMMY(unusable) + + + if (allocated(tempc)) deallocate(tempc) + is_present = config%has("function") + _ASSERT(is_present,"no expression found in derived entry") + call config%get(tempc,"function",rc=status) + _VERIFY(status) + rule%expression=tempc + + if (allocated(tempc)) deallocate(tempc) + is_present = config%has("sample") + if (is_present) then + call config%get(tempc,"sample",rc=status) + _VERIFY(status) + rule%sample_key=tempc + end if + + _RETURN(_SUCCESS) + end function new_ExtDataDerived + + function get_variables_in_expression(this,rc) result(variables_in_expression) + type(StringVector) :: variables_in_expression + class(ExtDataDerived), intent(inout), target :: this + integer, intent(out), optional :: rc + + integer :: status + type(ExtDataMask), allocatable :: temp_mask + + if (index(this%expression,"mask")/=0) then + allocate(temp_mask) + temp_mask = ExtDataMask(this%expression) + variables_in_expression = temp_mask%get_mask_variables(_RC) + else + variables_in_expression = parser_variables_in_expression(this%expression,_RC) + end if + _RETURN(_SUCCESS) + + end function + + + subroutine set_defaults(this,unusable,rc) + class(ExtDataDerived), intent(inout), target :: this + class(KeywordEnforcer), optional, intent(in) :: unusable + integer, optional, intent(out) :: rc + + this%expression='' + _RETURN(_SUCCESS) + _UNUSED_DUMMY(unusable) + end subroutine set_defaults + + subroutine display(this) + class(ExtDataDerived) :: this + write(*,*)"function: ",trim(this%expression) + end subroutine display + +end module MAPL_ExtDataDerived + +module MAPL_ExtDataDerivedMap + use MAPL_ExtDataDerived + +#include "types/key_deferredLengthString.inc" +#define _value type(ExtDataDerived) +#define _alt + +#define _map ExtDataDerivedMap +#define _iterator ExtDataDerivedMapIterator + +#include "templates/map.inc" + +#undef _iterator +#undef _map + +#undef _alt +#undef _value + +end module MAPL_ExtDataDerivedMap diff --git a/gridcomps/ExtData2G/ExtDataFileStream.F90 b/gridcomps/ExtData2G/ExtDataFileStream.F90 new file mode 100644 index 000000000000..68ddddc22270 --- /dev/null +++ b/gridcomps/ExtData2G/ExtDataFileStream.F90 @@ -0,0 +1,209 @@ +#include "MAPL_Exceptions.h" +#include "MAPL_ErrLog.h" +module MAPL_ExtDataFileStream + use ESMF + use yaFyaml + use MAPL_KeywordEnforcerMod + use MAPL_ExceptionHandling + use MAPL_TimeStringConversion + use MAPL_DataCollectionMod + use MAPL_CollectionVectorMod + use MAPL_DataCollectionManagerMod + use MAPL_FileMetadataUtilsMod + use MAPL_StringTemplate + implicit none + private + + type, public :: ExtDataFileStream + character(:), allocatable :: file_template + type(ESMF_TimeInterval) :: frequency + type(ESMF_Time) :: reff_time + integer :: collection_id + type(ESMF_Time), allocatable :: valid_range(:) + type(FileMetaData) :: metadata + contains + procedure :: detect_metadata + end type + + interface ExtDataFileStream + module procedure new_ExtDataFileStream + end interface ExtDataFileStream +contains + + function new_ExtDataFileStream(config,current_time,unusable,rc) result(data_set) + class(Yaml_node), intent(in) :: config + type(ESMF_Time), intent(in) :: current_time + class(KeywordEnforcer), optional, intent(in) :: unusable + integer, optional, intent(out) :: rc + + type(ExtDataFileStream) :: data_set + integer :: status + integer :: last_token + integer :: iyy,imm,idd,ihh,imn,isc,idx + character(len=2) :: token + character(len=:), allocatable :: file_frequency, file_reff_time,range_str + logical :: is_present + + _UNUSED_DUMMY(unusable) + + if (config%is_scalar()) then + + else if (config%is_mapping()) then + is_present = config%has("template") + _ASSERT(is_present,"no file template in the collection") + if (is_present) then + call config%get(data_set%file_template,"template",rc=status) + _VERIFY(status) + file_frequency = get_string_with_default(config,"freq") + file_reff_time = get_string_with_default(config,"ref_time") + range_str = get_string_with_default(config,"valid_range") + end if + end if + + if (file_frequency /= '') then + data_set%frequency = string_to_esmf_timeinterval(file_frequency) + else + last_token = index(data_set%file_template,'%',back=.true.) + if (last_token.gt.0) then + token = data_set%file_template(last_token+1:last_token+2) + select case(token) + case("y4") + call ESMF_TimeIntervalSet(data_set%frequency,yy=1,__RC__) + case("m2") + call ESMF_TimeIntervalSet(data_set%frequency,mm=1,__RC__) + case("d2") + call ESMF_TimeIntervalSet(data_set%frequency,d=1,__RC__) + case("h2") + call ESMF_TimeIntervalSet(data_set%frequency,h=1,__RC__) + case("n2") + call ESMF_TimeIntervalSet(data_set%frequency,m=1,__RC__) + end select + else + ! couldn't find any tokens so all the data must be on one file + call ESMF_TimeIntervalSet(data_set%frequency,__RC__) + end if + end if + + if (file_reff_time /= '') then + data_set%reff_time = string_to_esmf_time(file_reff_time) + else + last_token = index(data_set%file_template,'%',back=.true.) + if (last_token.gt.0) then + call ESMF_TimeGet(current_time, yy=iyy, mm=imm, dd=idd,h=ihh, m=imn, s=isc ,__RC__) + token = data_set%file_template(last_token+1:last_token+2) + select case(token) + case("y4") + call ESMF_TimeSet(data_set%reff_time,yy=iyy,mm=1,dd=1,h=0,m=0,s=0,__RC__) + case("m2") + call ESMF_TimeSet(data_set%reff_time,yy=iyy,mm=imm,dd=1,h=0,m=0,s=0,__RC__) + case("d2") + call ESMF_TimeSet(data_set%reff_time,yy=iyy,mm=imm,dd=idd,h=0,m=0,s=0,__RC__) + case("h2") + call ESMF_TimeSet(data_set%reff_time,yy=iyy,mm=imm,dd=idd,h=ihh,m=0,s=0,__RC__) + case("n2") + call ESMF_TimeSet(data_set%reff_time,yy=iyy,mm=imm,dd=idd,h=ihh,m=imn,s=0,__RC__) + end select + else + data_set%reff_time = current_time + end if + end if + + if (range_str /= '') then + idx = index(range_str,'/') + _ASSERT(idx/=0,'invalid specification of time range') + if (allocated(data_set%valid_range)) deallocate(data_set%valid_range) + allocate(data_set%valid_range(2)) + data_set%valid_range(1)=string_to_esmf_time(range_str(:idx-1)) + data_set%valid_range(2)=string_to_esmf_time(range_str(idx+1:)) + call ESMF_TimeGet(data_set%reff_time,yy=iyy,mm=imm,dd=idd,h=ihh,m=imn,__RC__) + call ESMF_TimeGet(data_set%valid_range(1),yy=iyy,__RC__) + call ESMF_TimeSet(data_set%reff_time,yy=iyy,mm=imm,dd=idd,h=ihh,m=imn,__RC__) + end if + data_set%collection_id = MAPL_DataAddCollection(data_set%file_template) + + _RETURN(_SUCCESS) + + contains + + function get_string_with_default(config,selector) result(string) + class(Yaml_Node), intent(in) :: config + character(len=*), intent(In) :: selector + character(len=:), allocatable :: string + + if (config%has(selector)) then + string=config%of(selector) + else + string='' + end if + end function + + end function new_ExtDataFileStream + + subroutine detect_metadata(this,metadata_out,time,multi_rule,get_range,rc) + class(ExtDataFileStream), intent(inout) :: this + type(FileMetadataUtils), intent(inout) :: metadata_out + type(ESMF_Time), intent(in) :: time + logical, intent(in) :: multi_rule + logical, optional, intent(in) :: get_range + integer, optional, intent(out) :: rc + + logical :: get_range_ + type(MAPLDataCollection), pointer :: collection + type(FileMetadataUtils), pointer :: metadata + type(ESMF_Time), allocatable :: time_series(:) + integer :: status + character(len=ESMF_MAXPATHLEN) :: filename + + if (multi_rule) then + _ASSERT(allocated(this%valid_range),"must use a collection with valid range") + end if + + if (present(get_range)) then + get_range_ = get_range + else + get_range_ = .false. + end if + + collection => DataCollections%at(this%collection_id) + if (get_range_ .and. (.not.allocated(this%valid_range))) then + if (index('%',this%file_template) == 0) then + metadata => collection%find(this%file_template) + call metadata%get_time_info(timeVector=time_series,__RC__) + allocate(this%valid_range(2)) + this%valid_range(1)=time_series(1) + this%valid_range(2)=time_series(size(time_series)) + end if + end if + + if (get_range_ .or. multi_rule) then + call fill_grads_template(filename,this%file_template,time=this%valid_range(1),__RC__) + else + call fill_grads_template(filename,this%file_template,time=time,__RC__) + end if + metadata => collection%find(filename,__RC__) + metadata_out = metadata + _RETURN(_SUCCESS) + + end subroutine detect_metadata + +end module MAPL_ExtDataFileStream + +module MAPL_ExtDataFileStreamMap + use MAPL_ExtDataFileStream + +#include "types/key_deferredLengthString.inc" +#define _value type(ExtDataFileStream) +#define _alt + +#define _map ExtDataFileStreamMap +#define _iterator ExtDataFileStreamMapIterator + +#include "templates/map.inc" + +#undef _iterator +#undef _map + +#undef _alt +#undef _value + +end module MAPL_ExtDataFileStreamMap diff --git a/gridcomps/ExtData2G/ExtDataGridCompNG.F90 b/gridcomps/ExtData2G/ExtDataGridCompNG.F90 new file mode 100644 index 000000000000..c1984c538e4c --- /dev/null +++ b/gridcomps/ExtData2G/ExtDataGridCompNG.F90 @@ -0,0 +1,1748 @@ +#include "MAPL_Exceptions.h" +#include "MAPL_Generic.h" +#include "unused_dummy.H" + +!------------------------------------------------------------------------- +! NASA/GSFC, Global Modeling and Assimilation Office, Code 910.1 ! +!------------------------------------------------------------------------- + + MODULE MAPL_ExtDataGridComp2G + +!BOP +! !MODULE: MAPL_ExtDataGridCompMod - Implements Interface to External Data +! +! !DESCRIPTION: +! +! {\tt MAPL\_ExtDataGridComp} is an ESMF gridded component implementing +! an interface to boundary conditions and other types of external data +! files. +! +! Developed for GEOS-5 release Fortuna 2.0 and later. +! +! !USES: +! + USE ESMF + use gFTL_StringVector + use gFTL_IntegerVector + use MAPL_BaseMod + use MAPL_CommsMod + use MAPL_ShmemMod + use ESMFL_Mod + use MAPL_GenericMod + use MAPL_VarSpecMod + use MAPL_CFIOMod + use MAPL_NewArthParserMod + use MAPL_ConstantsMod, only: MAPL_PI,MAPL_PI_R8,MAPL_RADIANS_TO_DEGREES + use MAPL_IOMod, only: MAPL_NCIOParseTimeUnits + use, intrinsic :: iso_fortran_env, only: REAL64 + use linearVerticalInterpolation_mod + use ESMF_CFIOCollectionVectorMod + use ESMF_CFIOCollectionMod + use MAPL_ConfigMod + use MAPL_GridManagerMod + use MAPL_ExtDataNG_IOBundleMod + use MAPL_ExtDataNG_IOBundleVectorMod + use MAPL_ExceptionHandling + use MAPL_DataCollectionMod + use MAPL_CollectionVectorMod + use MAPL_DataCollectionManagerMod + use MAPL_FileMetadataUtilsMod + use pFIO_ClientManagerMod, only : i_Clients + use MAPL_GriddedIOItemMod + use MAPL_GriddedIOItemVectorMod + use MAPL_ExtDataConfig + use MAPL_ExtDataTypeDef + use MAPL_ExtDataOldTypesCreator + use MAPL_StringTemplate + use pflogger, only: logging, Logger + use MAPL_ExtDataLogger + use MAPL_ExtDataConstants + + IMPLICIT NONE + PRIVATE +! +! !PUBLIC MEMBER FUNCTIONS: + + PUBLIC SetServices +!EOP +! +! !REVISION HISTORY: +! +! 12Dec2009 da Silva Design and first implementation. +! +!------------------------------------------------------------------------- + + integer, parameter :: MAPL_ExtDataLeft = 1 + integer, parameter :: MAPL_ExtDataRight = 2 + logical :: hasRun + character(len=ESMF_MAXSTR) :: error_msg_str + + type PrimaryExports + PRIVATE + integer :: nItems = 0 + type(integerVector) :: export_id_start + type(integerVector) :: number_of_rules + type(stringVector) :: import_names + type(PrimaryExport), pointer :: item(:) => null() + contains + procedure :: get_item_index + end type PrimaryExports + + type DerivedExports + PRIVATE + integer :: nItems = 0 + type(stringVector) :: import_names + type(DerivedExport), pointer :: item(:) => null() + end type DerivedExports + +! Legacy state +! ------------ + type MAPL_ExtData_State + PRIVATE + type(PrimaryExports) :: Primary + type(DerivedExports) :: Derived + ! will add fields from export state to this state + ! will also add new fields that could be mask + ! or primary exports that were not in the export + ! state recieved by ExtData, i.e. fields that are + ! needed by a derived field where the primary fields + ! are not actually required + type(ESMF_State) :: ExtDataState + type(ESMF_Config) :: CF + logical :: active + end type MAPL_ExtData_State + +! Hook for the ESMF +! ----------------- + type MAPL_ExtData_Wrap + type (MAPL_ExtData_State), pointer :: PTR => null() + end type MAPL_ExtData_WRAP + +CONTAINS + + +!------------------------------------------------------------------------- +! NASA/GSFC, Global Modeling and Assimilation Office, Code 910.1 ! +!------------------------------------------------------------------------- +!BOP +! +! !IROUTINE: SetServices --- Sets IRF services for the MAPL_ExtData +! +! !INTERFACE: + + SUBROUTINE SetServices ( GC, RC ) + +! !ARGUMENTS: + + type(ESMF_GridComp), intent(INOUT) :: GC ! gridded component + integer, optional :: RC ! return code + +! !DESCRIPTION: Sets Initialize, Run and Finalize services. +! +! !REVISION HISTORY: +! +! 12Dec2009 da Silva Design and first implementation. +! +!EOP +!------------------------------------------------------------------------- + +! Local derived type aliases +! -------------------------- + type (MAPL_ExtData_State), pointer :: self ! internal, that is + type (MAPL_ExtData_wrap) :: wrap + + character(len=ESMF_MAXSTR) :: comp_name + integer :: status + +! ------------ + +! Get my name and set-up traceback handle +! --------------------------------------- + call ESMF_GridCompGet( GC, name=comp_name, _RC ) + +! Wrap internal state for storing in GC; rename legacyState +! ------------------------------------- + allocate ( self, stat=STATUS ) + _VERIFY(STATUS) + wrap%ptr => self + +! ------------------------ +! ESMF Functional Services +! ------------------------ + +! Set the Initialize, Run, Finalize entry points +! ---------------------------------------------- + call MAPL_GridCompSetEntryPoint ( GC, ESMF_METHOD_INITIALIZE, Initialize_, _RC ) + call MAPL_GridCompSetEntryPoint ( GC, ESMF_METHOD_RUN, Run_, _RC ) + call MAPL_GridCompSetEntryPoint ( GC, ESMF_METHOD_FINALIZE, Finalize_, _RC ) + +! Store internal state in GC +! -------------------------- + call ESMF_UserCompSetInternalState ( GC, 'MAPL_ExtData_state', wrap, STATUS ) + _VERIFY(STATUS) + + call MAPL_TimerAdd(gc,name="Initialize", rc=status) + _VERIFY(STATUS) + call MAPL_TimerAdd(gc,name="Run", rc=status) + _VERIFY(STATUS) + call MAPL_TimerAdd(gc,name="-Read_Loop", rc=status) + _VERIFY(STATUS) + call MAPL_TimerAdd(gc,name="--CheckUpd", rc=status) + _VERIFY(STATUS) + call MAPL_TimerAdd(gc,name="--Read", rc=status) + _VERIFY(STATUS) + call MAPL_TimerAdd(gc,name="--GridCreate", rc=status) + _VERIFY(STATUS) + call MAPL_TimerAdd(gc,name="--IclientWait", rc=status) + _VERIFY(STATUS) + call MAPL_TimerAdd(gc,name="--PRead", rc=status) + _VERIFY(STATUS) + call MAPL_TimerAdd(gc,name="---CreateCFIO", rc=status) + _VERIFY(STATUS) + call MAPL_TimerAdd(gc,name="---prefetch", rc=status) + _VERIFY(STATUS) + call MAPL_TimerAdd(gc,name="----add-collection", rc=status) + _VERIFY(STATUS) + call MAPL_TimerAdd(gc,name="----make-reference", rc=status) + _VERIFY(STATUS) + call MAPL_TimerAdd(gc,name="----RegridStore", rc=status) + _VERIFY(STATUS) + call MAPL_TimerAdd(gc,name="----request", rc=status) + _VERIFY(STATUS) + call MAPL_TimerAdd(gc,name="---IclientDone", rc=status) + _VERIFY(STATUS) + call MAPL_TimerAdd(gc,name="----RegridApply", rc=status) + _VERIFY(STATUS) + call MAPL_TimerAdd(gc,name="---read-prefetch", rc=status) + _VERIFY(STATUS) + call MAPL_TimerAdd(gc,name="--Swap", rc=status) + _VERIFY(STATUS) + call MAPL_TimerAdd(gc,name="--Bracket", rc=status) + _VERIFY(STATUS) + call MAPL_TimerAdd(gc,name="-Interpolate", rc=status) + _VERIFY(STATUS) +! Generic Set Services +! -------------------- + call MAPL_GenericSetServices ( GC, _RC ) + +! All done +! -------- + + _RETURN(ESMF_SUCCESS) + + END SUBROUTINE SetServices + + +!------------------------------------------------------------------------- +! NASA/GSFC, Global Modeling and Assimilation Office, Code 610.1 ! +!------------------------------------------------------------------------- +!BOP +! +! !IROUTINE: Initialize_ --- Initialize MAPL_ExtData +! +! !INTERFACE: +! + + SUBROUTINE Initialize_ ( GC, IMPORT, EXPORT, CLOCK, rc ) + +! !USES: + + implicit NONE + +! !INPUT PARAMETERS: + + type(ESMF_Clock), intent(inout) :: CLOCK ! The clock + +! !OUTPUT PARAMETERS: + + type(ESMF_GridComp), intent(inout) :: GC ! Grid Component + type(ESMF_State), intent(inout) :: IMPORT ! Import State + type(ESMF_State), intent(inout) :: EXPORT ! Export State + integer, intent(out) :: rc ! Error return code: + ! 0 - all is well + ! 1 - + +! !DESCRIPTION: This is a simple ESMF wrapper. +! +! !REVISION HISTORY: +! +! 12Dec2009 da Silva Design and first implementation. +! +!EOP +!------------------------------------------------------------------------- + + type(MAPL_ExtData_state), pointer :: self ! Legacy state + type(ESMF_Config) :: CF_master ! Universal Config + + character(len=ESMF_MAXSTR) :: comp_name + integer :: Status + + type(PrimaryExport), pointer :: item + integer :: i,j + integer :: ItemCount + integer :: PrimaryItemCount, DerivedItemCount + + type(ESMF_Time) :: time + + type (ESMF_Field) :: field + type (ESMF_StateItem_Flag), pointer :: ITEMTYPES(:) + character(len=ESMF_MAXSTR), allocatable :: ITEMNAMES(:) + + integer :: idx + type(MAPL_MetaComp),pointer :: MAPLSTATE + + type(ExtDataOldTypesCreator),target :: config_yaml + character(len=ESMF_MAXSTR) :: new_rc_file + logical :: found_in_config + integer :: num_primary,num_derived,num_rules + integer :: item_type + type(StringVector) :: unsatisfied_imports,extra_variables_needed + type(StringVectorIterator) :: siter + character(len=:), pointer :: current_base_name,extra_var + character(len=:), allocatable :: primary_var_name,derived_var_name + type(ESMF_Time), allocatable :: time_ranges(:) + character(len=1) :: sidx + type(ESMF_VM) :: vm + type(ESMF_Field) :: new_field,existing_field + type(ESMF_StateItem_Flag) :: state_item_type + !class(logger), pointer :: lgr + +! Get my name and set-up traceback handle +! --------------------------------------- + call ESMF_GridCompGet( GC, name=comp_name, config=CF_master, vm=vm, _RC ) + call MAPL_GetLogger(gc, extdata_lgr, _RC) + +! Extract relevant runtime information +! ------------------------------------ + call extract_ ( GC, self, CF_master, _RC) + self%CF = CF_master + +! Start Some Timers +! ----------------- + call MAPL_GetObjectFromGC ( gc, MAPLSTATE, RC=STATUS) + _VERIFY(STATUS) + call MAPL_TimerOn(MAPLSTATE,"TOTAL") + call MAPL_TimerOn(MAPLSTATE,"Initialize") + + call ESMF_ConfigGetAttribute(cf_master,new_rc_file,label="EXTDATA_YAML_FILE:",default="extdata.yaml",_RC) + self%active = am_i_running(new_rc_file,_RC) + + call ESMF_ClockGet(CLOCK, currTIME=time, _RC) +! Get information from export state +!---------------------------------- + call ESMF_StateGet(EXPORT, ITEMCOUNT=ItemCount, RC=STATUS) + _VERIFY(STATUS) + + ! no need to run ExtData if there are no imports to fill + if (ItemCount == 0) then + self%active = .false. + end if + + if (.not.self%active) then + call MAPL_TimerOff(MAPLSTATE,"Initialize") + call MAPL_TimerOff(MAPLSTATE,"TOTAL") + _RETURN(ESMF_SUCCESS) + end if + + config_yaml = ExtDataOldTypesCreator(new_rc_file,time,_RC) + + allocate(ITEMNAMES(ITEMCOUNT), STAT=STATUS) + _VERIFY(STATUS) + allocate(ITEMTYPES(ITEMCOUNT), STAT=STATUS) + _VERIFY(STATUS) + + call ESMF_StateGet(EXPORT, ITEMNAMELIST=ITEMNAMES, & + ITEMTYPELIST=ITEMTYPES, RC=STATUS) + _VERIFY(STATUS) + +! -------- +! Initialize MAPL Generic +! ----------------------- + call MAPL_GenericInitialize ( GC, IMPORT, EXPORT, clock, _RC ) + + call extdata_lgr%info("Using ExtData2G, note this is still in BETA stage") + +! --------------------------- +! Parse ExtData Resource File +! --------------------------- + self%ExtDataState = ESMF_StateCreate(Name="ExtDataNameSpace",_RC) + num_primary=0 + num_derived=0 + primaryitemcount=0 + deriveditemcount=0 + do i=1,size(itemnames) + item_type = config_yaml%get_item_type(trim(itemnames(i)),rc=status) + _VERIFY(status) + found_in_config = (item_type/= ExtData_not_found) + if (.not.found_in_config) call unsatisfied_imports%push_back(itemnames(i)) + if (item_type == derived_type) then + call self%derived%import_names%push_back(trim(itemnames(i))) + deriveditemcount=deriveditemcount+1 + else if (item_type==Primary_Type_Scalar .or. item_type==Primary_Type_Vector_comp1) then + call self%primary%import_names%push_back(trim(itemnames(i))) + primaryitemcount=primaryitemcount+config_yaml%count_rules_for_item(trim(itemnames(i)),_RC) + end if + enddo + extra_variables_needed = config_yaml%get_extra_derived_items(self%primary%import_names,self%derived%import_names,_RC) + siter = extra_variables_needed%begin() + do while(siter/=extra_variables_needed%end()) + extra_var => siter%get() + idx = index(extra_var,",") + primary_var_name = extra_var(:idx-1) + derived_var_name = extra_var(idx+1:) + call self%primary%import_names%push_back(primary_var_name) + primaryItemCount=primaryItemCount+config_yaml%count_rules_for_item(primary_var_name,_RC) + call ESMF_StateGet(self%ExtDataState,primary_var_name,state_item_type,_RC) + if (state_item_type == ESMF_STATEITEM_NOTFOUND) then + call ESMF_StateGet(export,derived_var_name,existing_field,_RC) + new_field = MAPL_FieldCreate(existing_field,primary_var_name,doCOpy=.true.,_RC) + call MAPL_StateAdd(self%ExtDataState,new_field,_RC) + end if + call siter%next() + enddo + call ESMF_VMBarrier(vm,_RC) + if (unsatisfied_imports%size() > 0) then + do i=1,unsatisfied_imports%size() + call extdata_lgr%error("In ExtData resource file, could not find: "//trim(unsatisfied_imports%at(i))) + enddo + _FAIL("Unsatisfied imports in ExtData") + end if + + allocate(self%primary%item(PrimaryItemCount),__STAT__) + allocate(self%derived%item(DerivedItemCount),__STAT__) + self%primary%nitems = PrimaryItemCount + self%derived%nitems = DerivedItemCount + + num_primary=0 + num_derived=0 + do i=1,self%primary%import_names%size() + current_base_name => self%primary%import_names%at(i) + num_rules = config_yaml%count_rules_for_item(current_base_name) + _ASSERT(num_rules > 0,"no rule found for "//trim(current_base_name)) + call self%primary%number_of_rules%push_back(num_rules) + call self%primary%export_id_start%push_back(num_primary+1) + if (num_rules > 1) then + if (allocated(time_ranges)) deallocate(time_ranges) + allocate(time_ranges(num_rules)) + time_ranges = config_yaml%get_time_range(current_base_name,_RC) + do j=1,num_rules + num_primary=num_primary+1 + write(sidx,'(I1)')j + call config_yaml%fillin_primary(current_base_name//"+"//sidx,current_base_name,self%primary%item(num_primary),time,clock,_RC) + allocate(self%primary%item(num_primary)%start_end_time(2)) + self%primary%item(num_primary)%start_end_time(1)=time_ranges(j) + self%primary%item(num_primary)%start_end_time(2)=time_ranges(j+1) + enddo + else + num_primary=num_primary+1 + call config_yaml%fillin_primary(current_base_name,current_base_name,self%primary%item(num_primary),time,clock,_RC) + end if + call ESMF_StateGet(Export,current_base_name,state_item_type,_RC) + if (state_item_type /= ESMF_STATEITEM_NOTFOUND) then + call ESMF_StateGet(Export,current_base_name,field,_RC) + call MAPL_StateAdd(self%ExtDataState,field,_RC) + item_type = config_yaml%get_item_type(current_base_name) + if (item_type == Primary_Type_Vector_comp1) then + call ESMF_StateGet(Export,self%primary%item(num_primary)%vcomp2,field,_RC) + call MAPL_StateAdd(self%ExtDataState,field,_RC) + end if + end if + enddo + do i=1,self%derived%import_names%size() + current_base_name => self%derived%import_names%at(i) + num_derived=num_derived+1 + call config_yaml%fillin_derived(current_base_name,self%derived%item(num_derived),time,clock,_RC) + call ESMF_StateGet(Export,current_base_name,field,_RC) + call MAPL_StateAdd(self%ExtDataState,field,_RC) + enddo + + PrimaryLoop: do i=1,self%primary%import_names%size() + + current_base_name => self%primary%import_names%at(i) + idx = self%primary%get_item_index(current_base_name,time,_RC) + item => self%primary%item(idx) + item%initialized = .true. + + item%pfioCollection_id = MAPL_DataAddCollection(item%file_template) + if (item%isConst) then + call set_constant_field(item,self%extDataState,_RC) + cycle + end if + call create_bracketing_fields(item,self%ExtDataState,cf_master,_RC) + + end do PrimaryLoop + +! Check if we have any files that would need to be vertically interpolated +! if so ensure that PS is done first +!! check for PS + !idx = -1 + !if (any(self%primary%item%do_VertInterp .eqv. .true.)) then + !do i=1,size(self%primary%item) + !if (self%primary%item(i)%name=='PS') then + !idx =i + !end if + !enddo + !_ASSERT(idx/=-1,'Surface pressure not present for vertical interpolation') + !self%primary%item(idx)%units = ESMF_UtilStringUppercase(self%primary%item(idx)%units,rc=status) + !_ASSERT(trim(self%primary%item(idx)%units)=="PA",'PS must be in units of PA') + !end if + + call extdata_lgr%info('*******************************************************') + call extdata_lgr%info('** Variables to be provided by the ExtData Component **') + call extdata_lgr%info('*******************************************************') + do i = 1, ItemCount + call extdata_lgr%info('---- %i0.5~: %a', i, trim(ItemNames(i))) + end do + call extdata_lgr%info('*******************************************************\n') + +! Clean up +! -------- + deallocate(ItemTypes) + deallocate(ItemNames) + +! Set has run to false to we know when we first go to run method it is first call + hasRun = .false. + + call MAPL_TimerOff(MAPLSTATE,"Initialize") + call MAPL_TimerOff(MAPLSTATE,"TOTAL") +! All done +! -------- + + call extdata_lgr%debug('ExtData Initialize_(): End') + + _RETURN(ESMF_SUCCESS) + + END SUBROUTINE Initialize_ + + +!------------------------------------------------------------------------- +! NASA/GSFC, Global Modeling and Assimilation Office, Code 610.1 ! +!------------------------------------------------------------------------- +!BOP +! +! !IROUTINE: Run_ --- Runs MAPL_ExtData +! +! !INTERFACE: +! + + SUBROUTINE Run_ ( GC, IMPORT, EXPORT, CLOCK, rc ) + +! !USES: + + implicit NONE + +! !INPUT PARAMETERS: + + type(ESMF_Clock), intent(inout) :: CLOCK ! The clock + +! !OUTPUT PARAMETERS: + + type(ESMF_GridComp), intent(inout) :: GC ! Grid Component + type(ESMF_State), intent(inout) :: IMPORT ! Import State + type(ESMF_State), intent(inout) :: EXPORT ! Export State + integer, intent(out) :: rc ! Error return code: + ! 0 - all is well + ! 1 - + +! !DESCRIPTION: This is a simple ESMF wrapper. +! +! !REVISION HISTORY: +! +! 12Dec2009 da Silva Design and first implementation. +! +!EOP +!------------------------------------------------------------------------- + + type(MAPL_ExtData_state), pointer :: self ! Legacy state + type(ESMF_Config) :: CF ! Universal Config + + character(len=ESMF_MAXSTR) :: comp_name + integer :: status + + type(PrimaryExport), pointer :: item + type(DerivedExport), pointer :: derivedItem + integer :: i + + type(ESMF_Time) :: time, time0 + type(MAPL_MetaComp), pointer :: MAPLSTATE + + logical :: doUpdate_ + character(len=ESMF_MAXPATHLEN) :: file_processed + logical, allocatable :: doUpdate(:) + type(ESMF_Time), allocatable :: useTime(:) + + integer :: bracket_side + integer :: entry_num + type(IOBundleNGVector), target :: IOBundles + type(IOBundleNGVectorIterator) :: bundle_iter + type(ExtDataNG_IOBundle), pointer :: io_bundle + character(len=:), pointer :: current_base_name + integer :: idx,nitems + type(ESMF_Config) :: cf_master + + _UNUSED_DUMMY(IMPORT) + _UNUSED_DUMMY(EXPORT) + +! Get my name and set-up traceback handle +! --------------------------------------- + call ESMF_GridCompGet( GC, name=comp_name, config=CF_master, _RC ) + +! Extract relevant runtime information +! ------------------------------------ + call extract_ ( GC, self, CF, _RC ) + + if (.not. self%active) then + _RETURN(ESMF_SUCCESS) + end if + + call MAPL_GetObjectFromGC ( gc, MAPLSTATE, RC=STATUS) + _VERIFY(STATUS) + call MAPL_TimerOn(MAPLSTATE,"TOTAL") + call MAPL_TimerOn(MAPLSTATE,"Run") + + call ESMF_ClockGet(CLOCK, currTIME=time0, _RC) + +! Fill in the internal state with data from the files +! --------------------------------------------------- + + allocate(doUpdate(self%primary%nitems),stat=status) + _VERIFY(STATUS) + doUpdate = .false. + allocate(useTime(self%primary%nitems),stat=status) + _VERIFY(STATUS) + + call MAPL_TimerOn(MAPLSTATE,"-Read_Loop") + + call extdata_lgr%debug('ExtData Rune_(): Start') + call extdata_lgr%debug('ExtData Run_(): READ_LOOP: Start') + + READ_LOOP: do i=1,self%primary%import_names%size() + + current_base_name => self%primary%import_names%at(i) + idx = self%primary%get_item_index(current_base_name,time0,_RC) + item => self%primary%item(idx) + + if (.not.item%initialized) then + item%pfioCollection_id = MAPL_DataAddCollection(item%file_template) + if (item%isConst) then + call set_constant_field(item,self%extDataState,_RC) + cycle + end if + call create_bracketing_fields(item,self%ExtDataState,cf_master, _RC) + item%initialized=.true. + end if + + nitems = self%primary%import_names%size() + !call extdata_lgr%debug('ExtData Run_(): READ_LOOP: variable %i0 of %i0~: %a', i, nitems, trim(current_base_name)) + !call extdata_lgr%debug(' ==> file: %a', trim(item%file_template)) + !call extdata_lgr%debug(' ==> isConst:: %l1', item%isConst) + + if (item%isConst) then + call extdata_lgr%debug(' ==> Break loop since isConst is true') + cycle + endif + + call MAPL_TimerOn(MAPLSTATE,"--CheckUpd") + + call item%update_freq%check_update(doUpdate(i),time,time0,.not.hasRun,_RC) + call MAPL_TimerOff(MAPLSTATE,"--CheckUpd") + + DO_UPDATE: if (doUpdate(i)) then + + !call extdata_lgr%info('Going to update %a with file template: %a ',current_base_name, item%file_template) + call item%modelGridFields%comp1%reset() + call item%filestream%get_file_bracket(time,item%source_time, item%modelGridFields%comp1,_RC) + if (item%vartype == MAPL_VectorField) then + call item%filestream%get_file_bracket(time,item%source_time, item%modelGridFields%comp2,_RC) + end if + call IOBundle_Add_Entry(IOBundles,item,idx) + useTime(i)=time + + end if DO_UPDATE + + end do READ_LOOP + + call extdata_lgr%debug('ExtData Run_: READ_LOOP: Done') + + bundle_iter = IOBundles%begin() + do while (bundle_iter /= IoBundles%end()) + io_bundle => bundle_iter%get() + bracket_side = io_bundle%bracket_side + entry_num = io_bundle%entry_index + file_Processed = io_bundle%file_name + item => self%primary%item(entry_num) + + io_bundle%pbundle = ESMF_FieldBundleCreate(rc=status) + _VERIFY(STATUS) + + call MAPL_ExtDataPopulateBundle(item,bracket_side,io_bundle%pbundle,rc=status) + _VERIFY(status) + call bundle_iter%next() + enddo + + call MAPL_TimerOn(MAPLSTATE,"--PRead") + call MAPL_TimerOn(MAPLSTATE,"---CreateCFIO") + call MAPL_ExtDataCreateCFIO(IOBundles, rc=status) + _VERIFY(status) + call MAPL_TimerOff(MAPLSTATE,"---CreateCFIO") + + call MAPL_TimerOn(MAPLSTATE,"---prefetch") + call MAPL_ExtDataPrefetch(IOBundles, rc=status) + _VERIFY(status) + call MAPL_TimerOff(MAPLSTATE,"---prefetch") + _VERIFY(STATUS) + call MAPL_TimerOn(MAPLSTATE,"---IclientDone") + + call i_Clients%done_collective_prefetch() + call i_Clients%wait() + + call MAPL_TimerOff(MAPLSTATE,"---IclientDone") + _VERIFY(STATUS) + + call MAPL_TimerOn(MAPLSTATE,"---read-prefetch") + call MAPL_ExtDataReadPrefetch(IOBundles,rc=status) + _VERIFY(status) + call MAPL_TimerOff(MAPLSTATE,"---read-prefetch") + call MAPL_TimerOff(MAPLSTATE,"--PRead") + + bundle_iter = IOBundles%begin() + do while (bundle_iter /= IOBundles%end()) + io_bundle => bundle_iter%get() + bracket_side = io_bundle%bracket_side + entry_num = io_bundle%entry_index + item => self%primary%item(entry_num) + call MAPL_ExtDataVerticalInterpolate(self,item,bracket_side,time0,rc=status) + _VERIFY(status) + call bundle_iter%next() + enddo + call MAPL_ExtDataDestroyCFIO(IOBundles,rc=status) + _VERIFY(status) + + call MAPL_TimerOff(MAPLSTATE,"-Read_Loop") + + call MAPL_TimerOn(MAPLSTATE,"-Interpolate") + + call extdata_lgr%debug('ExtData Run_: INTERP_LOOP: Start') + + INTERP_LOOP: do i=1,self%primary%import_names%size() + + current_base_name => self%primary%import_names%at(i) + idx = self%primary%get_item_index(current_base_name,time0,_RC) + item => self%primary%item(idx) + + if (doUpdate(i)) then + + call extdata_lgr%debug('ExtData Run_: INTERP_LOOP: interpolating between bracket times, variable: %a, file: %a', & + & trim(current_base_name), trim(item%file_template)) + + call MAPL_ExtDataInterpField(item,self%ExtDataState,useTime(i),_RC) + + endif + + nullify(item) + + end do INTERP_LOOP + + call extdata_lgr%debug('ExtData Run_: INTERP_LOOP: Done') + + call MAPL_TimerOff(MAPLSTATE,"-Interpolate") + + ! now take care of derived fields + do i=1,self%derived%nItems + + derivedItem => self%derived%item(i) + + call derivedItem%update_freq%check_update(doUpdate_,time,time0,.not.hasRun,_RC) + + if (doUpdate_) then + + call derivedItem%evaluate_derived_field(self%ExtDataState,_RC) + + end if + + end do + + call extdata_lgr%debug('ExtData Run_: End') + +! All done +! -------- + deallocate(doUpdate) + deallocate(useTime) + + if (hasRun .eqv. .false.) hasRun = .true. + call MAPL_TimerOff(MAPLSTATE,"Run") + call MAPL_TimerOff(MAPLSTATE,"TOTAL") + + _RETURN(ESMF_SUCCESS) + + END SUBROUTINE Run_ + +!------------------------------------------------------------------------- +! NASA/GSFC, Global Modeling and Assimilation Office, Code 610.1 ! +!------------------------------------------------------------------------- +!BOP +! +! !IROUTINE: Finalize_ --- Finalize MAPL_ExtData +! +! !INTERFACE: +! + + SUBROUTINE Finalize_ ( GC, IMPORT, EXPORT, CLOCK, rc ) + +! !USES: + + implicit NONE + +! !INPUT PARAMETERS: + + type(ESMF_Clock), intent(inout) :: CLOCK ! The clock + +! !OUTPUT PARAMETERS: + + type(ESMF_GridComp), intent(inout) :: GC ! Grid Component + type(ESMF_State), intent(inout) :: IMPORT ! Import State + type(ESMF_State), intent(inout) :: EXPORT ! Export State + integer, intent(out) :: rc ! Error return code: + ! 0 - all is well + ! 1 - + +! !DESCRIPTION: This is a simple ESMF wrapper. +! +! !REVISION HISTORY: +! +! 12Dec2009 da Silva Design and first implementation. +! +!EOP +!------------------------------------------------------------------------- + + type(MAPL_ExtData_state), pointer :: self ! Legacy state + type(ESMF_Config) :: CF ! Universal Config + + character(len=ESMF_MAXSTR) :: comp_name + integer :: status + + +! Get my name and set-up traceback handle +! --------------------------------------- + call ESMF_GridCompGet( GC, name=comp_name, _RC ) + +! Finalize MAPL Generic +! --------------------- + call MAPL_GenericFinalize ( GC, IMPORT, EXPORT, CLOCK, _RC ) + +! Extract relevant runtime information +! ------------------------------------ + call extract_ ( GC, self, CF, _RC) + +! Free the memory used to hold the primary export items +! ----------------------------------------------------- + if (associated(self%primary%item)) then + deallocate(self%primary%item) + end if + + +! All done +! -------- + _RETURN(ESMF_SUCCESS) + + end SUBROUTINE Finalize_ + +!....................................................................... + + subroutine extract_ ( GC, self, CF, rc) + + type(ESMF_GridComp), intent(INout) :: GC ! Grid Comp object + + type(MAPL_ExtData_state), pointer :: self ! Legacy state + type(ESMF_Config), intent(out) :: CF ! Universal Config + + integer, intent(out), optional :: rc + +! --- + + character(len=ESMF_MAXSTR) :: comp_name + integer :: status + + type(MAPL_ExtData_Wrap) :: wrap + +! Get my name and set-up traceback handle +! --------------------------------------- + call ESMF_GridCompGet( GC, NAME=comp_name, _RC ) + + If (present(rc)) rc=ESMF_SUCCESS + +! Get my internal state +! --------------------- + call ESMF_UserCompGetInternalState(gc, 'MAPL_ExtData_state', WRAP, STATUS) + _VERIFY(STATUS) + self => wrap%ptr + +! Get the configuration +! --------------------- + call ESMF_GridCompGet ( GC, config=CF, _RC ) + + + _RETURN(ESMF_SUCCESS) + + end subroutine extract_ + +! ............................................................................ + + logical function PrimaryExportIsConstant_(item) + + type(PrimaryExport), intent(in) :: item + + if ( item%update_freq%is_single_shot() .or. & + trim(item%file_template) == '/dev/null' ) then + PrimaryExportIsConstant_ = .true. + else + PrimaryExportIsConstant_ = .false. + end if + + end function PrimaryExportIsConstant_ + +! ............................................................................ + + logical function DerivedExportIsConstant_(item) + + type(DerivedExport), intent(in) :: item + + if ( item%update_freq%is_disabled() ) then + DerivedExportIsConstant_ = .true. + else + DerivedExportIsConstant_ = .false. + end if + + end function DerivedExportIsConstant_ + + subroutine GetLevs(item, rc) + + type(PrimaryExport) , intent(inout) :: item + integer, optional , intent(out ) :: rc + + integer :: status + + real, allocatable :: levFile(:) + character(len=ESMF_MAXSTR) :: levunits,tlevunits + character(len=:), allocatable :: levname + character(len=:), pointer :: positive + type(Variable), pointer :: var + integer :: i + + positive=>null() + var => null() + if (item%isVector) then + var=>item%file_metadata%get_variable(trim(item%fcomp1)) + _ASSERT(associated(var),"Variable "//TRIM(item%fcomp1)//" not found in file "//TRIM(item%file_template)) + var => null() + var=>item%file_metadata%get_variable(trim(item%fcomp2)) + _ASSERT(associated(var),"Variable "//TRIM(item%fcomp2)//" not found in file "//TRIM(item%file_template)) + else + var=>item%file_metadata%get_variable(trim(item%var)) + _ASSERT(associated(var),"Variable "//TRIM(item%var)//" not found in file "//TRIM(item%file_template)) + end if + + levName = item%file_metadata%get_level_name(rc=status) + _VERIFY(status) + if (trim(levName) /='') then + call item%file_metadata%get_coordinate_info(levName,coordSize=item%lm,coordUnits=tLevUnits,coords=levFile,_RC) + levUnits=MAPL_TrimString(tlevUnits) + ! check if pressure + item%levUnit = ESMF_UtilStringLowerCase(levUnits) + if (trim(item%levUnit) == 'hpa' .or. trim(item%levUnit)=='pa') then + item%havePressure = .true. + end if + if (item%havePressure) then + if (levFile(1)>levFile(size(levFile))) item%fileVDir="up" + else + positive => item%file_metadata%get_variable_attribute(levName,'positive',_RC) + if (associated(positive)) then + if (MAPL_TrimString(positive)=='up') item%fileVDir="up" + end if + end if + + allocate(item%levs(item%lm),__STAT__) + item%levs=levFile + if (trim(item%fileVDir)/=trim(item%importVDir)) then + do i=1,size(levFile) + item%levs(i)=levFile(size(levFile)-i+1) + enddo + end if + if (trim(item%levunit)=='hpa') item%levs=item%levs*100.0 + if (item%isVector) then + item%units = item%file_metadata%get_variable_attribute(trim(item%fcomp1),"units",rc=status) + _VERIFY(status) + else + item%units = item%file_metadata%get_variable_attribute(trim(item%var),"units",rc=status) + _VERIFY(status) + end if + + else + item%LM=0 + end if + + _RETURN(ESMF_SUCCESS) + + end subroutine GetLevs + + subroutine MAPL_ExtDataInterpField(item,state,time,rc) + type(PrimaryExport), intent(inout) :: item + type(ESMF_State), intent(in) :: state + type(ESMF_Time), intent(in ) :: time + integer, optional, intent(out ) :: rc + + integer :: status + type(ESMF_Field) :: field + + call ESMF_StateGet(state,item%vcomp1,field,_RC) + call item%modelGridFields%comp1%interpolate_to_time(field,time,_RC) + if (item%vartype == MAPL_VectorField) then + call ESMF_StateGet(state,item%vcomp2,field,_RC) + call item%modelGridFields%comp2%interpolate_to_time(field,time,_RC) + end if + _RETURN(ESMF_SUCCESS) + end subroutine MAPL_ExtDataInterpField + + subroutine MAPL_ExtDataVerticalInterpolate(ExtState,item,filec,current_time,rc) + type(MAPL_ExtData_State), intent(inout) :: ExtState + type(PrimaryExport), intent(inout) :: item + integer, intent(in ) :: filec + type(ESMF_Time), intent(in ) :: current_time + integer, optional, intent(out ) :: rc + + integer :: status + integer :: id_ps + type(ESMF_Field) :: field, newfield,psF + + if (item%do_VertInterp) then + if (trim(item%importVDir)/=trim(item%fileVDir)) then + call MAPL_ExtDataFlipVertical(item,filec,rc=status) + _VERIFY(status) + end if + if (item%vartype == MAPL_fieldItem) then + call MAPL_ExtDataGetBracket(item,filec,newField,getRL=.true.,rc=status) + _VERIFY(STATUS) + call MAPL_ExtDataGetBracket(item,filec,Field,rc=status) + _VERIFY(STATUS) + id_ps = ExtState%primary%get_item_index("PS",current_time,_RC) + call MAPL_ExtDataGetBracket(ExtState%primary%item(id_ps),filec,field=psF,rc=status) + _VERIFY(STATUS) + call vertInterpolation_pressKappa(field,newfield,psF,item%levs,MAPL_UNDEF,rc=status) + _VERIFY(STATUS) + + else if (item%vartype == MAPL_VectorField) then + + id_ps = ExtState%primary%get_item_index("PS",current_time,_RC) + call MAPL_ExtDataGetBracket(ExtState%primary%item(id_ps),filec,field=psF,rc=status) + _VERIFY(STATUS) + call MAPL_ExtDataGetBracket(item,filec,newField,getRL=.true.,vcomp=1,rc=status) + _VERIFY(STATUS) + call MAPL_ExtDataGetBracket(item,filec,Field,vcomp=1,rc=status) + _VERIFY(STATUS) + call vertInterpolation_pressKappa(field,newfield,psF,item%levs,MAPL_UNDEF,rc=status) + _VERIFY(STATUS) + call MAPL_ExtDataGetBracket(item,filec,newField,getRL=.true.,vcomp=2,rc=status) + _VERIFY(STATUS) + call MAPL_ExtDataGetBracket(item,filec,Field,vcomp=2,rc=status) + _VERIFY(STATUS) + call vertInterpolation_pressKappa(field,newfield,psF,item%levs,MAPL_UNDEF,rc=status) + _VERIFY(STATUS) + + end if + + else if (item%do_Fill) then + if (item%vartype == MAPL_fieldItem) then + call MAPL_ExtDataGetBracket(item,filec,newField,getRL=.true.,rc=status) + _VERIFY(STATUS) + call MAPL_ExtDataGetBracket(item,filec,Field,rc=status) + _VERIFY(STATUS) + call MAPL_ExtDataFillField(item,field,newfield,rc=status) + _VERIFY(STATUS) + else if (item%vartype == MAPL_VectorField) then + call MAPL_ExtDataGetBracket(item,filec,newField,getRL=.true.,vcomp=1,rc=status) + _VERIFY(STATUS) + call MAPL_ExtDataGetBracket(item,filec,Field,vcomp=1,rc=status) + _VERIFY(STATUS) + call MAPL_ExtDataFillField(item,field,newfield,rc=status) + _VERIFY(STATUS) + call MAPL_ExtDataGetBracket(item,filec,newField,getRL=.true.,vcomp=2,rc=status) + _VERIFY(STATUS) + call MAPL_ExtDataGetBracket(item,filec,Field,vcomp=2,rc=status) + _VERIFY(STATUS) + call MAPL_ExtDataFillField(item,field,newfield,rc=status) + _VERIFY(STATUS) + end if + else + if (trim(item%importVDir)/=trim(item%fileVDir)) then + call MAPL_ExtDataFlipVertical(item,filec,rc=status) + _VERIFY(status) + end if + end if + + _RETURN(ESMF_SUCCESS) + end subroutine MAPL_ExtDataVerticalInterpolate + + function MAPL_ExtDataGridChangeLev(Grid,CF,lm,rc) result(NewGrid) + + type(ESMF_Grid), intent(inout) :: Grid + type(ESMF_Config), intent(inout) :: CF + integer, intent(in) :: lm + integer, optional, intent(out) :: rc + + integer :: status + + character(len=ESMF_MAXSTR) :: gname, comp_name + integer :: counts(3) + integer :: NX,NY + type(ESMF_Grid) :: newGrid + type(ESMF_Config) :: cflocal + character(len=*), parameter :: CF_COMPONENT_SEPARATOR = '.' + real :: temp_real + logical :: isPresent + type(ESMF_Info) :: infoh + + call MAPL_GridGet(grid,globalCellCountPerDim=counts,_RC) + call ESMF_GridGet(grid,name=gName,_RC) + call ESMF_ConfigGetAttribute(CF, value = NX, Label="NX:", _RC) + call ESMF_ConfigGetAttribute(CF, value = NY, Label="NY:", _RC) + + comp_name = "ExtData" + cflocal = MAPL_ConfigCreate(rc=status) + _VERIFY(status) + call MAPL_ConfigSetAttribute(cflocal,value=NX, label=trim(COMP_Name)//CF_COMPONENT_SEPARATOR//"NX:",rc=status) + _VERIFY(status) + call MAPL_ConfigSetAttribute(cflocal,value=lm, label=trim(COMP_Name)//CF_COMPONENT_SEPARATOR//"LM:",rc=status) + _VERIFY(status) + + if (counts(2) == 6*counts(1)) then + call MAPL_ConfigSetAttribute(cflocal,value="Cubed-Sphere", label=trim(COMP_Name)//CF_COMPONENT_SEPARATOR//"GRID_TYPE:",rc=status) + _VERIFY(status) + call MAPL_ConfigSetAttribute(cflocal,value=6, label=trim(COMP_Name)//CF_COMPONENT_SEPARATOR//"NF:",rc=status) + _VERIFY(status) + call MAPL_ConfigSetAttribute(cflocal,value=counts(1), label=trim(COMP_Name)//CF_COMPONENT_SEPARATOR//"IM_WORLD:",rc=status) + _VERIFY(status) + call MAPL_ConfigSetAttribute(cflocal,value=ny/6, label=trim(COMP_Name)//CF_COMPONENT_SEPARATOR//"NY:",rc=status) + _VERIFY(status) + call MAPL_ConfigSetAttribute(cflocal,value=trim(gname), label=trim(COMP_Name)//CF_COMPONENT_SEPARATOR//"GRIDNAME:",rc=status) + _VERIFY(status) + + call ESMF_InfoGetFromHost(grid,infoh,rc=status) + _VERIFY(status) + isPresent = ESMF_InfoIsPresent(infoh,'STRETCH_FACTOR',rc=status) + _VERIFY(status) + if (isPresent) then + call ESMF_InfoGet(infoh,'STRETCH_FACTOR',temp_real,rc=status) + _VERIFY(status) + call MAPL_ConfigSetAttribute(cflocal,value=temp_real, label=trim(COMP_Name)//MAPL_CF_COMPONENT_SEPARATOR//"STRETCH_FACTOR:",rc=status) + _VERIFY(status) + endif + + isPresent = ESMF_InfoIsPresent(infoh,'TARGET_LON',rc=status) + _VERIFY(status) + if (isPresent) then + call ESMF_InfoGet(infoh,'TARGET_LON',temp_real,rc=status) + _VERIFY(status) + call MAPL_ConfigSetAttribute(cflocal,value=temp_real*MAPL_RADIANS_TO_DEGREES, label=trim(COMP_Name)//MAPL_CF_COMPONENT_SEPARATOR//"TARGET_LON:",rc=status) + _VERIFY(status) + endif + + isPresent = ESMF_InfoIsPresent(infoh,'TARGET_LAT',rc=status) + _VERIFY(status) + if (isPresent) then + call ESMF_InfoGet(infoh,'TARGET_LAT',temp_real,rc=status) + _VERIFY(status) + call MAPL_ConfigSetAttribute(cflocal,value=temp_real*MAPL_RADIANS_TO_DEGREES, label=trim(COMP_Name)//MAPL_CF_COMPONENT_SEPARATOR//"TARGET_LAT:",rc=status) + _VERIFY(status) + endif + else + call MAPL_ConfigSetAttribute(cflocal,value=counts(1), label=trim(COMP_Name)//CF_COMPONENT_SEPARATOR//"IM_WORLD:",rc=status) + _VERIFY(status) + call MAPL_ConfigSetAttribute(cflocal,value=counts(2), label=trim(COMP_Name)//CF_COMPONENT_SEPARATOR//"JM_WORLD:",rc=status) + _VERIFY(status) + call MAPL_ConfigSetAttribute(cflocal,value=ny, label=trim(COMP_Name)//CF_COMPONENT_SEPARATOR//"NY:",rc=status) + _VERIFY(status) + call MAPL_ConfigSetAttribute(cflocal,value=trim(gname), label=trim(COMP_Name)//CF_COMPONENT_SEPARATOR//"GRIDNAME:",rc=status) + _VERIFY(status) + end if + newgrid = grid_manager%make_grid(cflocal, prefix=trim(COMP_Name)//".", rc=status) + _VERIFY(status) + + _RETURN(ESMF_SUCCESS) + + end function MAPL_ExtDataGridChangeLev + + subroutine MAPL_ExtDataGetBracket(item,Bside,field,bundle,getRL,vcomp,rc) + + type(PrimaryExport), intent(inout) :: item + integer, intent(in ) :: bside + type(ESMF_Field), optional, intent(inout) :: field + type(ESMF_FieldBundle), optional, intent(inout) :: bundle + logical, optional, intent(in ) :: getRL + integer, optional, intent(in ) :: vcomp + integer, optional, intent(out ) :: rc + + integer :: status + + logical :: getRL_ + + if (present(getRL)) then + getRL_=getRL + else + getRL_=.false. + end if + + if (present(vcomp)) then + + if (present(field)) then + + if (Bside == MAPL_ExtDataLeft .and. vcomp == 1) then + if (getRL_) then + call item%modelGridFields%auxiliary1%get_parameters('L',field=field,_RC) + _RETURN(ESMF_SUCCESS) + else + call item%modelGridFields%comp1%get_parameters('L',field=field,_RC) + _RETURN(ESMF_SUCCESS) + end if + else if (Bside == MAPL_ExtDataLeft .and. vcomp == 2) then + if (getRL_) then + call item%modelGridFields%auxiliary2%get_parameters('L',field=field,_RC) + _RETURN(ESMF_SUCCESS) + else + call item%modelGridFields%comp2%get_parameters('L',field=field,_RC) + _RETURN(ESMF_SUCCESS) + end if + else if (Bside == MAPL_ExtDataRight .and. vcomp == 1) then + if (getRL_) then + call item%modelGridFields%auxiliary1%get_parameters('R',field=field,_RC) + _RETURN(ESMF_SUCCESS) + else + call item%modelGridFields%comp1%get_parameters('R',field=field,_RC) + _RETURN(ESMF_SUCCESS) + end if + else if (Bside == MAPL_ExtDataRight .and. vcomp == 2) then + if (getRL_) then + call item%modelGridFields%auxiliary2%get_parameters('R',field=field,_RC) + _RETURN(ESMF_SUCCESS) + else + call item%modelGridFields%comp2%get_parameters('R',field=field,_RC) + _RETURN(ESMF_SUCCESS) + end if + end if + + else if (present(bundle)) then + _RETURN(ESMF_FAILURE) + end if + + else + + if (present(field)) then + if (Bside == MAPL_ExtDataLeft) then + if (getRL_) then + call item%modelGridFields%auxiliary1%get_parameters('L',field=field,_RC) + _RETURN(ESMF_SUCCESS) + else + call item%modelGridFields%comp1%get_parameters('L',field=field,_RC) + _RETURN(ESMF_SUCCESS) + end if + else if (Bside == MAPL_ExtDataRight) then + if (getRL_) then + call item%modelGridFields%auxiliary1%get_parameters('R',field=field,_RC) + _RETURN(ESMF_SUCCESS) + else + call item%modelGridFields%comp1%get_parameters('R',field=field,_RC) + _RETURN(ESMF_SUCCESS) + end if + end if + else if (present(bundle)) then + !if (Bside == MAPL_ExtDataLeft) then + !bundle = item%binterp1 + !_RETURN(ESMF_SUCCESS) + !else if (Bside == MAPL_ExtDataRight) then + !bundle = item%binterp2 + !_RETURN(ESMF_SUCCESS) + !end if + + end if + + end if + _RETURN(ESMF_FAILURE) + + end subroutine MAPL_ExtDataGetBracket + + subroutine MAPL_ExtDataFillField(item,FieldF,FieldR,rc) + + type(PrimaryExport), intent(inout) :: item + type(ESMF_Field), intent(inout) :: FieldF + type(ESMF_Field), intent(inout) :: FieldR + integer, optional, intent(out) :: rc + + integer :: status + + real, pointer :: ptrF(:,:,:),ptrR(:,:,:) + integer :: lm_in,lm_out,i + + call ESMF_FieldGet(FieldF,0,farrayPtr=ptrF,rc=status) + _VERIFY(STATUS) + call ESMF_FieldGet(FieldR,0,farrayPtr=ptrR,rc=status) + _VERIFY(STATUS) + ptrF = 0.0 + lm_in= size(ptrR,3) + lm_out = size(ptrF,3) + if (trim(item%importVDir)=="down") then + + if (trim(item%fileVDir)=="down") then + do i=1,lm_in + ptrF(:,:,lm_out-lm_in+i)=ptrR(:,:,i) + enddo + else if (trim(item%fileVDir)=="up") then + do i=1,lm_in + ptrF(:,:,lm_out-i+1)=ptrR(:,:,i) + enddo + end if + else if (trim(item%importVDir)=="up") then + if (trim(item%fileVDir)=="down") then + do i=1,lm_in + ptrF(:,:,lm_in-i+1)=ptrR(:,:,i) + enddo + else if (trim(item%fileVDir)=="up") then + do i=1,lm_in + ptrF(:,:,i)=ptrR(:,:,i) + enddo + end if + end if + + _RETURN(ESMF_SUCCESS) + + end subroutine MAPL_ExtDataFillField + + subroutine MAPL_ExtDataFlipVertical(item,filec,rc) + type(PrimaryExport), intent(inout) :: item + integer, intent(in) :: filec + integer, optional, intent(out) :: rc + + integer :: status + + type(ESMF_Field) :: Field,field1,field2 + real, pointer :: ptr(:,:,:) + real, allocatable :: ptemp(:,:,:) + integer :: ls, le + + if (item%isVector) then + + if (item%do_Fill .or. item%do_VertInterp) then + call MAPL_ExtDataGetBracket(item,filec,field=Field1,vcomp=1,getRL=.true.,_RC) + call MAPL_ExtDataGetBracket(item,filec,field=Field2,vcomp=2,getRL=.true.,_RC) + else + call MAPL_ExtDataGetBracket(item,filec,field=Field1,vcomp=1,_RC) + call MAPL_ExtDataGetBracket(item,filec,field=Field2,vcomp=2,_RC) + end if + + call ESMF_FieldGet(Field1,0,farrayPtr=ptr,rc=status) + _VERIFY(STATUS) + allocate(ptemp,source=ptr,stat=status) + _VERIFY(status) + ls = lbound(ptr,3) + le = ubound(ptr,3) + ptr(:,:,le:ls:-1) = ptemp(:,:,ls:le:+1) + + call ESMF_FieldGet(Field2,0,farrayPtr=ptr,rc=status) + _VERIFY(STATUS) + ptemp=ptr + ptr(:,:,le:ls:-1) = ptemp(:,:,ls:le:+1) + + deallocate(ptemp) + + else + + if (item%do_Fill .or. item%do_VertInterp) then + call MAPL_ExtDataGetBracket(item,filec,field=Field,getRL=.true.,_RC) + else + call MAPL_ExtDataGetBracket(item,filec,field=Field,_RC) + end if + + call ESMF_FieldGet(Field,0,farrayPtr=ptr,rc=status) + _VERIFY(STATUS) + allocate(ptemp,source=ptr,stat=status) + _VERIFY(status) + ls = lbound(ptr,3) + le = ubound(ptr,3) + ptr(:,:,le:ls:-1) = ptemp(:,:,ls:le:+1) + deallocate(ptemp) + end if + + _RETURN(ESMF_SUCCESS) + + end subroutine MAPL_ExtDataFlipVertical + subroutine MAPL_ExtDataPopulateBundle(item,filec,pbundle,rc) + type(PrimaryExport), intent(inout) :: item + integer, intent(in) :: filec + type(ESMF_FieldBundle), intent(inout) :: pbundle + integer, optional, intent(out) :: rc + + integer :: status + + type(ESMF_Field) :: Field,field1,field2 + type(ESMF_Grid) :: grid + + if (item%isVector) then + + if (item%do_Fill .or. item%do_VertInterp) then + call MAPL_ExtDataGetBracket(item,filec,field=Field1,vcomp=1,getRL=.true.,_RC) + call MAPL_ExtDataGetBracket(item,filec,field=Field2,vcomp=2,getRL=.true.,_RC) + else + call MAPL_ExtDataGetBracket(item,filec,field=Field1,vcomp=1,_RC) + call MAPL_ExtDataGetBracket(item,filec,field=Field2,vcomp=2,_RC) + end if + + call ESMF_FieldGet(Field1,grid=grid,rc=status) + _VERIFY(STATUS) + call ESMF_FieldBundleSet(pbundle,grid=grid,rc=status) + _VERIFY(STATUS) + call MAPL_FieldBundleAdd(pbundle,Field1,rc=status) + _VERIFY(STATUS) + call MAPL_FieldBundleAdd(pbundle,Field2,rc=status) + _VERIFY(STATUS) + + else + + if (item%do_Fill .or. item%do_VertInterp) then + call MAPL_ExtDataGetBracket(item,filec,field=Field,getRL=.true.,_RC) + else + call MAPL_ExtDataGetBracket(item,filec,field=Field,_RC) + end if + + call ESMF_FieldGet(Field,grid=grid,rc=status) + _VERIFY(STATUS) + call ESMF_FieldBundleSet(pbundle,grid=grid,rc=status) + _VERIFY(STATUS) + call MAPL_FieldBundleAdd(pbundle,Field,rc=status) + _VERIFY(STATUS) + + end if + + _RETURN(ESMF_SUCCESS) + + end subroutine MAPL_ExtDataPopulateBundle + + subroutine MAPL_ExtDataCreateCFIO(IOBundles, rc) + type(IOBundleNGVector), target, intent(inout) :: IOBundles + integer, optional, intent(out ) :: rc + + type (IOBundleNGVectorIterator) :: bundle_iter + type (ExtDataNG_IOBundle), pointer :: io_bundle + integer :: status + + bundle_iter = IOBundles%begin() + do while (bundle_iter /= IOBundles%end()) + io_bundle => bundle_iter%get() + call io_bundle%make_cfio(_RC) + call bundle_iter%next() + enddo + + _RETURN(ESMF_SUCCESS) + + end subroutine MAPL_ExtDataCreateCFIO + + subroutine MAPL_ExtDataDestroyCFIO(IOBundles,rc) + type(IOBundleNGVector), target, intent(inout) :: IOBundles + integer, optional, intent(out ) :: rc + + type(IOBundleNGVectorIterator) :: bundle_iter + type (ExtDataNG_IOBundle), pointer :: io_bundle + integer :: status + + bundle_iter = IOBundles%begin() + do while (bundle_iter /= IOBundles%end()) + io_bundle => bundle_iter%get() + call io_bundle%clean(_RC) + call bundle_iter%next + enddo + call IOBundles%clear() + + _RETURN(ESMF_SUCCESS) + + end subroutine MAPL_ExtDataDestroyCFIO + + subroutine MAPL_ExtDataPrefetch(IOBundles,rc) + type(IOBundleNGVector), target, intent(inout) :: IOBundles + integer, optional, intent(out ) :: rc + + integer :: n,nfiles + type(ExtDataNG_IOBundle), pointer :: io_bundle => null() + integer :: status + + nfiles = IOBundles%size() + + do n = 1, nfiles + io_bundle => IOBundles%at(n) + call io_bundle%cfio%request_data_from_file(io_bundle%file_name,io_bundle%time_index,rc=status) + _VERIFY(status) + enddo + + _RETURN(ESMF_SUCCESS) + + end subroutine MAPL_ExtDataPrefetch + + subroutine MAPL_ExtDataReadPrefetch(IOBundles,rc) + type(IOBundleNGVector), target, intent(inout) :: IOBundles + integer, optional, intent(out ) :: rc + + integer :: nfiles, n + type (ExtDataNG_IOBundle), pointer :: io_bundle + integer :: status + + + nfiles = IOBundles%size() + do n=1, nfiles + io_bundle => IOBundles%at(n) + call io_bundle%cfio%process_data_from_file(rc=status) + _VERIFY(status) + enddo + + _RETURN(ESMF_SUCCESS) + + end subroutine MAPL_ExtDataReadPrefetch + + subroutine createFileLevBracket(item,cf,rc) + type(PrimaryExport), intent(inout) :: item + type(ESMF_Config), intent(inout) :: cf + integer, optional, intent(out) :: rc + + integer :: status + type (ESMF_Grid) :: grid, newgrid + type(ESMF_Field) :: field,new_field + + call item%modelGridFields%comp1%get_parameters('L',field=field,_RC) + newGrid = MAPL_ExtDataGridChangeLev(grid,cf,item%lm,_RC) + new_field = MAPL_FieldCreate(field,newGrid,lm=item%lm,newName=trim(item%fcomp1),_RC) + call item%modelGridFields%auxiliary1%set_parameters(left_field=new_field,_RC) + new_field = MAPL_FieldCreate(field,newGrid,lm=item%lm,newName=trim(item%fcomp1),_RC) + call item%modelGridFields%auxiliary1%set_parameters(right_field=new_field,_RC) + if (item%vartype==MAPL_VectorField) then + new_field = MAPL_FieldCreate(field,newGrid,lm=item%lm,newName=trim(item%fcomp2),_RC) + call item%modelGridFields%auxiliary2%set_parameters(left_field=new_field,_RC) + new_field = MAPL_FieldCreate(field,newGrid,lm=item%lm,newName=trim(item%fcomp2),_RC) + call item%modelGridFields%auxiliary2%set_parameters(right_field=new_field,_RC) + end if + _RETURN(_SUCCESS) + + end subroutine createFileLevBracket + + + subroutine IOBundle_Add_Entry(IOBundles,item,entry_num,rc) + type(IOBundleNGVector), intent(inout) :: IOBundles + type(primaryExport), intent(inout) :: item + integer, intent(in) :: entry_num + integer, intent(out), optional :: rc + + integer :: status + + type (ExtDataNG_IOBundle) :: io_bundle + type (GriddedIOItemVector) :: itemsL, itemsR + logical :: update + character(len=ESMF_MAXPATHLEN) :: current_file + integer :: time_index + + call item%modelGridFields%comp1%get_parameters('L',update=update,file=current_file,time_index=time_index) + if (update) then + call itemsL%push_back(item%fileVars) + io_bundle = ExtDataNG_IOBundle(MAPL_ExtDataLeft, entry_num, current_file, time_index, item%trans, item%fracval, item%file_template, & + item%pfioCollection_id,item%iclient_collection_id,itemsL,rc=status) + _VERIFY(status) + call IOBundles%push_back(io_bundle) + call extdata_lgr%info('%a updated L bracket with: %a at time index %i2 ',item%name, current_file, time_index) + end if + call item%modelGridFields%comp1%get_parameters('R',update=update,file=current_file,time_index=time_index) + if (update) then + call itemsR%push_back(item%fileVars) + io_bundle = ExtDataNG_IOBundle(MAPL_ExtDataRight, entry_num, current_file, time_index, item%trans, item%fracval, item%file_template, & + item%pfioCollection_id,item%iclient_collection_id,itemsR,rc=status) + _VERIFY(status) + call IOBundles%push_back(io_bundle) + call extdata_lgr%info('%a updated R bracket with: %a at time index %i2 ',item%name,current_file, time_index) + end if + + _RETURN(ESMF_SUCCESS) + + end subroutine IOBundle_Add_Entry + + subroutine set_constant_field(item,ExtDataState,rc) + type(PrimaryExport), intent(inout) :: item + type(ESMF_State), intent(inout) :: extDataState + integer, intent(out), optional :: rc + + integer :: status,fieldRank + real(kind=REAL32), pointer :: ptr2d(:,:),ptr3d(:,:,:) + type(ESMF_Field) :: field + + if (item%vartype == MAPL_FieldItem) then + call ESMF_StateGet(ExtDataState,trim(item%name),field,_RC) + call ESMF_FieldGet(field,dimCount=fieldRank,_RC) + if (fieldRank == 2) then + call MAPL_GetPointer(ExtDataState, ptr2d, trim(item%name),_RC) + ptr2d = item%const + else if (fieldRank == 3) then + call MAPL_GetPointer(ExtDataState, ptr3d, trim(item%name), _RC) + ptr3d = item%const + endif + else if (item%vartype == MAPL_VectorField) then + call ESMF_StateGet(ExtDataState,trim(item%vcomp1),field,_RC) + call ESMF_FieldGet(field,dimCount=fieldRank,_RC) + if (fieldRank == 2) then + call MAPL_GetPointer(ExtDataState, ptr2d, trim(item%vcomp1),_RC) + ptr2d = item%const + else if (fieldRank == 3) then + call MAPL_GetPointer(ExtDataState, ptr3d, trim(item%vcomp1), _RC) + ptr3d = item%const + endif + call ESMF_StateGet(ExtDataState,trim(item%vcomp2),field,_RC) + call ESMF_FieldGet(field,dimCount=fieldRank,_RC) + if (fieldRank == 2) then + call MAPL_GetPointer(ExtDataState, ptr2d, trim(item%vcomp2),_RC) + ptr2d = item%const + else if (fieldRank == 3) then + call MAPL_GetPointer(ExtDataState, ptr3d, trim(item%vcomp2), _RC) + ptr3d = item%const + endif + end if + + _RETURN(_SUCCESS) + end subroutine set_constant_field + + subroutine create_bracketing_fields(item,ExtDataState,cf,rc) + type(PrimaryExport), intent(inout) :: item + type(ESMF_State), intent(inout) :: extDataState + type(ESMF_Config), intent(inout) :: cf + integer, intent(out), optional :: rc + + integer :: status,lm,fieldRank + type(ESMF_Field) :: field,left_field,right_field + type(ESMF_Grid) :: grid + real(kind=REAL32), pointer :: ptr3d(:,:,:) + + call GetLevs(item,_RC) + item%iclient_collection_id=i_clients%add_ext_collection(trim(item%file_template)) + if (item%vartype == MAPL_FieldItem) then + + call ESMF_StateGet(ExtDataState, trim(item%name), field,_RC) + call ESMF_FieldGet(field,grid=grid,rank=fieldRank,_RC) + + lm=0 + if (fieldRank==3) then + call ESMF_FieldGet(field,0,farrayPtr=ptr3d,_RC) + lm = size(ptr3d,3) + end if + if (item%lm /= lm .and. lm /= 0 .and. item%havePressure) then + item%do_VertInterp = .true. + else if (item%lm /= lm .and. lm /= 0) then + item%do_Fill = .true. + end if + left_field = MAPL_FieldCreate(field,item%var,doCopy=.true.,_RC) + right_field = MAPL_FieldCreate(field,item%var,doCopy=.true.,_RC) + call item%modelGridFields%comp1%set_parameters(left_field=left_field,right_field=right_field, _RC) + if (item%do_fill .or. item%do_vertInterp) then + call createFileLevBracket(item,cf,_RC) + end if + + else if (item%vartype == MAPL_VectorField) then + + if (item%Trans /= REGRID_METHOD_BILINEAR) then + _FAIL('No conservative re-gridding with vectors') + end if + + call ESMF_StateGet(ExtDataState, trim(item%vcomp1), field,_RC) + call ESMF_FieldGet(field,grid=grid,rank=fieldRank,_RC) + + lm = 0 + if (fieldRank==3) then + call ESMF_FieldGet(field,0,farrayPtr=ptr3d,_RC) + lm = size(ptr3d,3) + end if + if (item%lm /= lm .and. item%havePressure) then + item%do_VertInterp = .true. + else if (item%lm /= lm .and. lm /= 0) then + item%do_Fill = .true. + end if + + left_field = MAPL_FieldCreate(field,item%fcomp1,doCopy=.true.,_RC) + right_field = MAPL_FieldCreate(field,item%fcomp1,doCopy=.true.,_RC) + call item%modelGridFields%comp1%set_parameters(left_field=left_field,right_field=right_field, _RC) + call ESMF_StateGet(ExtDataState, trim(item%vcomp2), field,_RC) + left_field = MAPL_FieldCreate(field,item%fcomp2,doCopy=.true.,_RC) + right_field = MAPL_FieldCreate(field,item%fcomp2,doCopy=.true.,_RC) + call item%modelGridFields%comp2%set_parameters(left_field=left_field,right_field=right_field, _RC) + + if (item%do_fill .or. item%do_vertInterp) then + call createFileLevBracket(item,cf,_RC) + end if + + end if + + _RETURN(_SUCCESS) + end subroutine create_bracketing_fields + + function get_item_index(this,base_name,current_time,rc) result(item_index) + integer :: item_index + class(primaryExports), intent(in) :: this + type(ESMF_Time) :: current_time + character(len=*),intent(in) :: base_name + integer, optional, intent(out) :: rc + + integer :: status + character(len=:), pointer :: cname + integer :: i + integer, pointer :: num_rules,i_start + logical :: found + + found = .false. + do i=1,this%import_names%size() + cname => this%import_names%at(i) + if (cname == base_name) then + found = .true. + i_start => this%export_id_start%at(i) + num_rules => this%number_of_rules%at(i) + exit + end if + enddo + _ASSERT(found,"no item with that basename found") + + item_index = -1 + if (num_rules == 1) then + item_index = i_start + else if (num_rules > 1) then + do i=1,num_rules + if (current_time >= this%item(i_start+i-1)%start_end_time(1) .and. & + current_time < this%item(i_start+i-1)%start_end_time(2)) then + item_index = i_start + i -1 + exit + endif + enddo + end if + _ASSERT(item_index/=-1,"did not find item") + _RETURN(_SUCCESS) + end function get_item_index + + function am_i_running(yaml_file,rc) result(am_running) + logical :: am_running + character(len=*), intent(in) :: yaml_file + integer, intent(out), optional :: rc + + type(Parser) :: p + class(YAML_Node), allocatable :: config + integer :: status + + am_running=.true. + p = Parser('core') + config = p%load(yaml_file,rc=status) + if (status/=_SUCCESS) then + _FAIL("Error parsing: "//trim(yaml_file)) + end if + + if (config%has("USE_EXTDATA")) then + am_running = config%of("USE_EXTDATA") + end if + _RETURN(_SUCCESS) + + end function am_i_running + + END MODULE MAPL_ExtDataGridComp2G diff --git a/gridcomps/ExtData2G/ExtDataLgr.F90 b/gridcomps/ExtData2G/ExtDataLgr.F90 new file mode 100644 index 000000000000..48654ffa982c --- /dev/null +++ b/gridcomps/ExtData2G/ExtDataLgr.F90 @@ -0,0 +1,8 @@ +module MAPL_ExtDataLogger + use pFlogger + + public :: extdata_lgr + class(Logger), pointer :: extdata_lgr + +end module MAPL_ExtDataLogger + diff --git a/gridcomps/ExtData2G/ExtDataMasking.F90 b/gridcomps/ExtData2G/ExtDataMasking.F90 new file mode 100644 index 000000000000..b9fb0d609807 --- /dev/null +++ b/gridcomps/ExtData2G/ExtDataMasking.F90 @@ -0,0 +1,597 @@ +#include "MAPL_Exceptions.h" +#include "MAPL_ErrLog.h" +#include "MAPL_Generic.h" +module MAPL_ExtDataMask + use ESMF + use MAPL_KeywordEnforcerMod + use ESMFL_Mod + use MAPL_BaseMod + use MAPL_ExceptionHandling + use gFTL_StringVector + use MAPL_NewArthParserMod + use MAPL_Constants + implicit none + private + + type, public :: ExtDataMask + character(len=:), allocatable :: mask_type + character(len=:), allocatable :: mask_arguments + contains + procedure :: get_mask_variables + procedure :: evaluate_mask + procedure :: evaluate_region_mask + procedure :: evaluate_zone_mask + procedure :: evaluate_box_mask + end type ExtDataMask + + interface ExtDataMask + module procedure new_ExtDataMask + end interface ExtDataMask + + contains + + function new_ExtDataMask(mask_expression,rc) result(new_mask) + type(ExtDataMask) :: new_mask + character(len=*), intent(in) :: mask_expression + integer, optional, intent(out) :: rc + + integer :: status + character(len=:), allocatable :: function_name + character(len=:), allocatable :: arguments + integer :: i1,len + + i1 = index(mask_expression,"(") + _ASSERT(i1 > 0,'Incorrect format for function expression: missing "("') + function_name = adjustl(mask_expression(:i1-1)) + function_name = ESMF_UtilStringLowerCase(function_name, __RC__) + + if (index(function_name,"regionmask") /= 0) then + new_mask%mask_type = "regionmask" + else if (index(function_name,"zonemask") /= 0) then + new_mask%mask_type = "zonemask" + else if (index(function_name,"boxmask") /= 0) then + new_mask%mask_type = "boxmask" + else + _FAIL("Invalid mask type") + end if + + len = len_trim(mask_expression) + arguments = adjustl(mask_expression(i1+1:len-1)) + i1 = index(arguments,",") + _ASSERT(i1 > 0,'Incorrect format for function expression: missing ","') + new_mask%mask_arguments = arguments + _RETURN(_SUCCESS) + end function + + function get_mask_variables(this,rc) result(variables_in_mask) + class(ExtDataMask), intent(inout) :: this + type(StringVector) :: variables_in_mask + integer, intent(out), optional :: rc + + integer :: status + integer :: i1,i2 + logical :: twovar + character(len=:), allocatable :: tmpstring1,tmpstring2 + + if (this%mask_type == "regionmask") twovar = .true. + if (this%mask_type == "zonemask") twovar = .false. + if (this%mask_type == "boxmask") twovar = .false. + i1 = index(this%mask_arguments,",") + i2 = index(this%mask_arguments,";") + if (twovar) then + tmpstring1 = this%mask_arguments(1:i1-1) + tmpstring2 = this%mask_arguments(i1+1:i2-1) + call variables_in_mask%push_back(trim(tmpstring1)) + call variables_in_mask%push_back(trim(tmpstring2)) + else + tmpstring1 = this%mask_arguments(1:i1-1) + call variables_in_mask%push_back(trim(tmpstring1)) + end if + _RETURN(_SUCCESS) + + end function + + subroutine evaluate_mask(this,state,var_name,rc) + class(ExtDataMask), intent(inout) :: this + type(ESMF_State), intent(inout) :: state + character(len=*), intent(in) :: var_name + integer, optional, intent(out) :: rc + + integer :: status + select case(this%mask_type) + case("regionmask") + call this%evaluate_region_mask(state,var_name,_RC) + case("zonemask") + call this%evaluate_zone_mask(state,var_name,_RC) + case("boxmask") + call this%evaluate_box_mask(state,var_name,_RC) + end select + _RETURN(_SUCCESS) + end subroutine evaluate_mask + + subroutine evaluate_region_mask(this,state,var_name,rc) + class(ExtDataMask), intent(inout) :: this + type(ESMF_State), intent(inout) :: state + character(len=*), intent(in) :: var_name + integer, optional, intent(out) :: rc + + integer :: status + integer :: k,i + character(len=:), allocatable :: maskString,maskname,vartomask + integer, allocatable :: regionNumbers(:), flag(:) + integer, allocatable :: mask(:,:) + real, pointer :: rmask(:,:) + real, pointer :: rvar2d(:,:) + real, pointer :: rvar3d(:,:,:) + real, pointer :: var2d(:,:) + real, pointer :: var3d(:,:,:) + integer :: rank,ib,ie + type(ESMF_Field) :: field + + call ESMF_StateGet(state,var_name,field,__RC__) + call ESMF_FieldGet(field,rank=rank,__RC__) + + ! get mask string + ib = index(this%mask_arguments,";") + maskString = this%mask_arguments(ib+1:) + ! get mask name + ie = index(this%mask_arguments,";") + ib = index(this%mask_arguments,",") + vartomask = this%mask_arguments(:ib-1) + maskname = this%mask_arguments(ib+1:ie-1) + + call MAPL_GetPointer(state,rmask,maskName,__RC__) + if (rank == 2) then + call MAPL_GetPointer(state,rvar2d,vartomask,__RC__) + call MAPL_GetPointer(state,var2d,var_name,__RC__) + else if (rank == 3) then + call MAPL_GetPointer(state,rvar3d,vartomask,__RC__) + call MAPL_GetPointer(state,var3d,var_name,__RC__) + else + _FAIL('Rank must be 2 or 3') + end if + + k=32 + allocate(regionNumbers(k), flag(k), stat=status) + _VERIFY(STATUS) + regionNumbers = 0 + call ExtDataExtractIntegers(maskString,k,regionNumbers,rc=status) + _VERIFY(STATUS) + flag(:) = 1 + WHERE(regionNumbers(:) == 0) flag(:) = 0 + k = SUM(flag) + deallocate(flag,stat=status) + _VERIFY(STATUS) + + ! Set local mask to 1 where gridMask matches each integer (within precision!) + ! --------------------------------------------------------------------------- + allocate(mask(size(rmask,1),size(rmask,2)),stat=status) + _VERIFY(STATUS) + mask = 0 + DO i=1,k + WHERE(regionNumbers(i)-0.01 <= rmask .AND. & + rmask <= regionNumbers(i)+0.01) mask = 1 + END DO + + if (rank == 2) then + var2d = rvar2d + where(mask == 0) var2d = 0.0 + else if (rank == 3) then + var3d = rvar3d + do i=1,size(var3d,3) + where(mask == 0) var3d(:,:,i) = 0.0 + enddo + end if + deallocate( mask) + + _RETURN(_SUCCESS) + end subroutine evaluate_region_mask + + subroutine evaluate_zone_mask(this,state,var_name,rc) + class(ExtDataMask), intent(inout) :: this + type(ESMF_State), intent(inout) :: state + character(len=*), intent(in) :: var_name + integer, optional, intent(out) :: rc + + integer :: status + + integer :: i + character(len=:), allocatable :: vartomask,clatS,clatN + real, pointer :: rvar2d(:,:) + real, pointer :: rvar3d(:,:,:) + real, pointer :: var2d(:,:) + real, pointer :: var3d(:,:,:) + real(REAL64), pointer :: lats(:,:) + real(REAL64) :: limitS, limitN + type(ESMF_Field) :: field + type(ESMF_Grid) :: grid + integer :: rank,ib,is + type(ESMF_CoordSys_Flag) :: coordSys + + call ESMF_StateGet(state,var_name,field,__RC__) + call ESMF_FieldGet(field,rank=rank,grid=grid,__RC__) + + ib = index(this%mask_arguments,",") + vartomask = this%mask_arguments(:ib-1) + is = index(this%mask_arguments,",",back=.true.) + clatS = this%mask_arguments(ib+1:is-1) + clatN = this%mask_arguments(is+1:) + READ(clatS,*,IOSTAT=status) limitS + _VERIFY(status) + READ(clatN,*,IOSTAT=status) limitN + _VERIFY(status) + + call ESMF_GridGetCoord(grid, coordDim=2, localDE=0, & + staggerloc=ESMF_STAGGERLOC_CENTER, farrayPtr=lats, rc=status) + _VERIFY(status) + call ESMF_GridGet(grid,coordsys=coordsys,_RC) + if (coordsys == ESMF_COORDSYS_SPH_RAD) then + limitN=limitN*MAPL_PI_R8/180.0d0 + limitS=limitS*MAPL_PI_R8/180.0d0 + end if + + if (rank == 2) then + call MAPL_GetPointer(state,rvar2d,vartomask,__RC__) + call MAPL_GetPointer(state,var2d,var_name,__RC__) + else if (rank == 3) then + call MAPL_GetPointer(state,rvar3d,vartomask,__RC__) + call MAPL_GetPointer(state,var3d,var_name,__RC__) + else + _FAIL('Rank must be 2 or 3') + end if + + if (rank == 2) then + var2d = 0.0 + where(limitS <= lats .and. lats <=limitN) var2d = rvar2d + else if (rank == 3) then + var3d = 0.0 + do i=1,size(var3d,3) + where(limitS <= lats .and. lats <=limitN) var3d(:,:,i) = rvar3d(:,:,i) + enddo + end if + + _RETURN(_SUCCESS) + end subroutine evaluate_zone_mask + + subroutine evaluate_box_mask(this,state,var_name,rc) + class(ExtDataMask), intent(inout) :: this + type(ESMF_State), intent(inout) :: state + character(len=*), intent(in) :: var_name + integer, optional, intent(out) :: rc + + integer :: status + + integer :: i + character(len=:), allocatable :: vartomask,strtmp + real, pointer :: rvar2d(:,:) + real, pointer :: rvar3d(:,:,:) + real, pointer :: var2d(:,:) + real, pointer :: var3d(:,:,:) + real(REAL64), pointer :: lats(:,:) + real(REAL64), pointer :: lons(:,:) + real(REAL64) :: limitS, limitN, limitE, limitW + real(REAL64) :: limitE1, limitW1 + real(REAL64) :: limitE2, limitW2 + type(ESMF_Field) :: field + type(ESMF_Grid) :: grid + integer :: rank,is,nargs + integer :: counts(3) + logical :: isCube, twoBox + real, allocatable :: temp2d(:,:) + character(len=ESMF_MAXSTR) :: args(5) + type(ESMF_CoordSys_Flag) :: coordSys + + call ESMF_StateGet(state,var_name,field,__RC__) + call ESMF_FieldGet(field,rank=rank,grid=grid,__RC__) + call ESMF_GridGet(grid,coordsys=coordsys,_RC) + + strtmp = this%mask_arguments + do nargs=1,5 + is = index(strtmp,',') + if (is >0) then + args(nargs) = strtmp(:is-1) + else + args(nargs) = strtmp + end if + strtmp = strtmp(is+1:) + end do + + varToMask=args(1) + + READ(args(2),*,IOSTAT=status) limitS + _VERIFY(status) + READ(args(3),*,IOSTAT=status) limitN + _VERIFY(status) + READ(args(4),*,IOSTAT=status) limitW + _VERIFY(status) + READ(args(5),*,IOSTAT=status) limitE + _VERIFY(status) + _ASSERT(limitE > limitW,'LimitE must be greater than limitW') + _ASSERT(limitE /= limitW,'LimitE cannot equal limitW') + _ASSERT(limitN /= limitS,'LimitN cannot equal LimitS') + _ASSERT((limitE-limitW)<=360.0d0,'(LimitE - LimitW) must be less than or equal to 360') + + call ESMF_GridGetCoord(grid, coordDim=1, localDE=0, & + staggerloc=ESMF_STAGGERLOC_CENTER, farrayPtr=lons, rc=status) + _VERIFY(status) + call ESMF_GridGetCoord(grid, coordDim=2, localDE=0, & + staggerloc=ESMF_STAGGERLOC_CENTER, farrayPtr=lats, rc=status) + _VERIFY(status) + + ! do some tests if cube goes from 0 to 360, lat-lon -180 to 180 + call MAPL_GridGet(grid, globalCellCountPerDim=COUNTS,rc=status) + _VERIFY(STATUS) + if (counts(2)==6*counts(1)) then + isCube=.true. + else + isCube=.false. + end if + twoBox = .false. + if (isCube) then + if (limitW < 0.0d0 .and. limitE >=0.0d0) then + ! need two boxes + twoBox=.true. + limitW1=0.0d0 + limitE1=limitE + limitW2=limitW+360.0d0 + limitE2=360.0d0 + + else if (limitW <0.0d0 .and. limitE <0.0d0) then + ! just shift + limitW1=limitW+360.d0 + limitE1=limitE+360.d0 + + else + ! normal case + limitW1=limitW + limitE1=limitE + end if + + else + + if (limitW <= 180.0d0 .and. limitE > 180.0d0) then + ! need two boxes + twoBox=.true. + limitW1=limitW + limitE1=180.0d0 + limitW2=-180.d0 + limitE2=limitE-360.0d0 + else if (limitW > 180.0d0 .and. limitE > 180.0d0) then + ! just shift + limitW1=limitW-360.d0 + limitE1=limitE-360.d0 + else + ! normal case + limitW1=limitW + limitE1=limitE + end if + + end if + if (coordSys == ESMF_COORDSYS_SPH_RAD) then + limitE1=limitE1*MAPL_PI_R8/180.0d0 + limitW1=limitW1*MAPL_PI_R8/180.0d0 + if (twoBox) then + limitE2=limitE2*MAPL_PI_R8/180.0d0 + limitW2=limitW2*MAPL_PI_R8/180.0d0 + end if + + limitN=limitN*MAPL_PI_R8/180.0d0 + limitS=limitS*MAPL_PI_R8/180.0d0 + end if + if (rank == 2) then + call MAPL_GetPointer(state,rvar2d,vartomask,__RC__) + call MAPL_GetPointer(state,var2d,var_name,__RC__) + else if (rank == 3) then + call MAPL_GetPointer(state,rvar3d,vartomask,__RC__) + call MAPL_GetPointer(state,var3d,var_name,__RC__) + else + _FAIL('Rank must be 2 or 3') + end if + + if (rank == 2) then + var2d = 0.0 + where(limitS <= lats .and. lats <=limitN .and. limitW1 <= lons .and. lons <= limitE1 ) var2d = rvar2d + else if (rank == 3) then + var3d = 0.0 + do i=1,size(var3d,3) + where(limitS <= lats .and. lats <=limitN .and. limitW1 <= lons .and. lons <= limitE1 ) var3d(:,:,i) = rvar3d(:,:,i) + enddo + end if + + if (twoBox) then + allocate(temp2d(size(var2d,1),size(var2d,2)),stat=status) + _VERIFY(STATUS) + if (rank == 2) then + temp2d = 0.0 + where(limitS <= lats .and. lats <=limitN .and. limitW2 <= lons .and. lons <= limitE2 ) temp2d = rvar2d + var2d=var2d+temp2d + else if (rank == 3) then + do i=1,size(var3d,3) + temp2d = 0.0 + where(limitS <= lats .and. lats <=limitN .and. limitW2 <= lons .and. lons <= limitE2 ) temp2d = rvar3d(:,:,i) + var3d(:,:,i)=var3d(:,:,i)+temp2d + enddo + end if + deallocate(temp2d) + end if + + _RETURN(_SUCCESS) + end subroutine evaluate_box_mask + + SUBROUTINE ExtDataExtractIntegers(string,iSize,iValues,delimiter,verbose,rc) + +! !USES: + + IMPLICIT NONE + +! !INPUT/OUTPUT PARAMETERS: + + CHARACTER(LEN=*), INTENT(IN) :: string ! Character-delimited string of integers + INTEGER, INTENT(IN) :: iSize + INTEGER, INTENT(INOUT) :: iValues(iSize)! Space allocated for extracted integers + CHARACTER(LEN=*), OPTIONAL :: delimiter ! 1-character delimiter + LOGICAL, OPTIONAL, INTENT(IN) :: verbose ! Let me know iValues as they are found. + ! DEBUG directive turns on the message even + ! if verbose is not present or if + ! verbose = .FALSE. + INTEGER, OPTIONAL, INTENT(OUT) :: rc ! Return code +! !DESCRIPTION: +! +! Extract integers from a character-delimited string, for example, "-1,45,256,7,10". In the context +! of Chem_Util, this is provided for determining the numerically indexed regions over which an +! emission might be applied. +! +! In multiple passes, the string is parsed for the delimiter, and the characters up to, but not +! including the delimiter are taken as consecutive digits of an integer. A negative sign ("-") is +! allowed. After the first pass, each integer and its trailing delimiter are lopped of the head of +! the (local copy of the) string, and the process is started over. +! +! The default delimiter is a comma (","). +! +! "Unfilled" iValues are zero. +! +! Return codes: +! 1 Zero-length string. +! 2 iSize needs to be increased. +! +! Assumptions/bugs: +! +! A non-zero return code does not stop execution. +! Allowed numerals are: 0,1,2,3,4,5,6,7,8,9. +! A delimiter must be separated from another delimiter by at least one numeral. +! The delimiter cannot be a numeral or a negative sign. +! The character following a negative sign must be an allowed numeral. +! The first character must be an allowed numeral or a negative sign. +! The last character must be an allowed numeral. +! The blank character (" ") cannot serve as a delimiter. +! +! Examples of strings that will work: +! "1" +! "-1" +! "-1,2004,-3" +! "1+-2+3" +! "-1A100A5" +! Examples of strings that will not work: +! "1,--2,3" +! "1,,2,3" +! "1,A,3" +! "1,-,2" +! "1,2,3,4," +! "+1" +! "1 3 6" + + INTEGER :: base,count,i,iDash,last,lenStr + INTEGER :: multiplier,pos,posDelim,sign + CHARACTER(LEN=255) :: str + CHARACTER(LEN=1) :: char,delimChar + LOGICAL :: Done + LOGICAL :: tellMe + +! Initializations +! --------------- + count = 1 + Done = .FALSE. + iValues(:) = 0 + base = ICHAR("0") + iDash = ICHAR("-") + +! Determine verbosity, letting the DEBUG +! directive override local specification +! -------------------------------------- + tellMe = .FALSE. + IF(PRESENT(verbose)) THEN + IF(verbose) tellMe = .TRUE. + END IF +#ifdef DEBUG + tellMe = .TRUE. +#endif +! Check for zero-length string +! ---------------------------- + lenStr = LEN_TRIM(string) + IF(lenStr == 0) THEN + _FAIL("ERROR - Found zero-length string.") + END IF + +! Default delimiter is a comma +! ---------------------------- + delimChar = "," + IF(PRESENT(delimiter)) delimChar(1:1) = delimiter(1:1) + +! Work on a local copy +! -------------------- + str = TRIM(string) + +! One pass for each delimited integer +! ----------------------------------- + Parse: DO + + lenStr = LEN_TRIM(str) + +! Parse the string for the delimiter +! ---------------------------------- + posDelim = INDEX(TRIM(str),TRIM(delimChar)) + +! If the delimiter does not exist, +! one integer remains to be extracted. +! ------------------------------------ + IF(posDelim == 0) THEN + Done = .TRUE. + last = lenStr + ELSE + last = posDelim-1 + END IF + multiplier = 10**last + +! Examine the characters of this integer +! -------------------------------------- + Extract: DO pos=1,last + + char = str(pos:pos) + i = ICHAR(char) + +! Account for a leading "-" +! ------------------------- + IF(pos == 1) THEN + IF(i == iDash) THEN + sign = -1 + ELSE + sign = 1 + END IF + END IF + +! "Power" of 10 for this character +! -------------------------------- + multiplier = multiplier/10 + + IF(pos == 1 .AND. sign == -1) CYCLE Extract + +! Integer comes from remaining characters +! --------------------------------------- + i = (i-base)*multiplier + iValues(count) = iValues(count)+i + IF(pos == last) THEN + iValues(count) = iValues(count)*sign + END IF + + END DO Extract + IF(Done) EXIT + +! Lop off the leading integer and try again +! ----------------------------------------- + str(1:lenStr-posDelim) = str(posDelim+1:lenStr) + str(lenStr-posDelim+1:255) = " " + count = count+1 + +! Check size +! ---------- + IF(count > iSize) THEN + _FAIL("ERROR - iValues does not have enough elements.") + END IF + + END DO Parse + + _RETURN(ESMF_SUCCESS) + + END SUBROUTINE ExtDataExtractIntegers + +end module MAPL_ExtDataMask diff --git a/gridcomps/ExtData2G/ExtDataNode.F90 b/gridcomps/ExtData2G/ExtDataNode.F90 new file mode 100644 index 000000000000..3270f9868f9c --- /dev/null +++ b/gridcomps/ExtData2G/ExtDataNode.F90 @@ -0,0 +1,73 @@ +#include "MAPL_Exceptions.h" +#include "MAPL_ErrLog.h" +module MAPL_ExtDataNode + use ESMF + use MAPL_KeywordEnforcerMod + use MAPL_ExceptionHandling + use MAPL_BaseMod, only: MAPL_UNDEF + implicit none + private + + type, public :: ExtDataNode + type(ESMF_Field) :: field + type(ESMF_Time) :: time + character(len=ESMF_MAXPATHLEN) :: file + integer :: time_index + logical :: was_set = .false. + contains + procedure :: set + procedure :: get + procedure :: equals + generic :: operator(==) => equals + end type + +contains + + subroutine set(this, unusable, field, time, file, time_index, was_set, rc) + class(ExtDataNode), intent(inout) :: this + class(KeywordEnforcer), optional, intent(in) :: unusable + type(ESMF_Time), optional, intent(in) :: time + type(ESMF_Field), optional, intent(in) :: field + character(len=*), optional, intent(in) :: file + integer, optional, intent(in) :: time_index + logical, optional, intent(in) :: was_set + integer, optional, intent(out) :: rc + + _UNUSED_DUMMY(unusable) + if (present(time)) this%time = time + if (present(field)) this%field = field + if (present(file)) this%file = trim(file) + if (present(time_index)) this%time_index = time_index + if (present(was_set)) this%was_set = was_set + _RETURN(_SUCCESS) + + end subroutine set + + subroutine get(this, unusable, field, time, file, time_index, was_set, rc) + class(ExtDataNode), intent(inout) :: this + class(KeywordEnforcer), optional, intent(in) :: unusable + type(ESMF_Time), optional, intent(out) :: time + type(ESMF_Field), optional, intent(out) :: field + character(len=*), optional, intent(out) :: file + integer, optional, intent(out) :: time_index + logical, optional, intent(out) :: was_set + integer, optional, intent(out) :: rc + + _UNUSED_DUMMY(unusable) + if (present(time)) time = this%time + if (present(field)) field = this%field + if (present(file)) file = trim(this%file) + if (present(time_index)) time_index = this%time_index + if (present(was_set)) was_set = this%was_set + _RETURN(_SUCCESS) + + end subroutine get + + logical function equals(a,b) + class(ExtDataNode), intent(in) :: a + class(ExtDataNode), intent(in) :: b + + equals = (trim(a%file)==trim(b%file)) .and. (a%time==b%time) .and. (a%time_index==b%time_index) + end function equals + +end module MAPL_ExtDataNode diff --git a/gridcomps/ExtData2G/ExtDataOldTypesCreator.F90 b/gridcomps/ExtData2G/ExtDataOldTypesCreator.F90 new file mode 100644 index 000000000000..305c93d6727c --- /dev/null +++ b/gridcomps/ExtData2G/ExtDataOldTypesCreator.F90 @@ -0,0 +1,207 @@ +#include "MAPL_Exceptions.h" +#include "MAPL_ErrLog.h" + +module MAPL_ExtDataOldTypesCreator + use ESMF + use MAPL_BaseMod + use yafYaml + use MAPL_KeywordEnforcerMod + use MAPL_ExceptionHandling + use MAPL_ExtDataTypeDef + use MAPL_ExtDataConfig + use MAPL_ExtDataFileStream + use MAPL_ExtDataFileStreamMap + use MAPL_ExtDataRule + use MAPL_ExtDataRuleMap + use MAPL_ExtDataDerived + use MAPL_ExtDataDerivedMap + use MAPL_RegridMethods + use MAPL_ExtDataAbstractFileHandler + use MAPL_ExtDataSimpleFileHandler + use MAPL_ExtDataClimFileHandler + use MAPL_ExtDataTimeSample + use MAPL_ExtDataTimeSampleMap + implicit none + public :: ExtDataOldTypesCreator + + type, extends(ExtDataConfig) :: ExtDataOldTypesCreator + private + contains + procedure :: fillin_primary + procedure :: fillin_derived + end type ExtDataOldTypesCreator + + interface ExtDataOldTypesCreator + module procedure :: new_ExtDataOldTypesCreator + end interface + + contains + + function new_ExtDataOldTypesCreator(config_file,current_time,unusable,rc ) result(ExtDataObj) + character(len=*), intent(in) :: config_file + type(ESMF_Time), intent(in) :: current_time + class(KeywordEnforcer), optional, intent(in) :: unusable + integer, optional, intent(out) :: rc + + type(ExtDataOldTypesCreator) :: ExtDataObj + + integer :: status + + _UNUSED_DUMMY(unusable) + call ExtDataObj%ExtDataConfig%new_ExtDataConfig_from_yaml(config_file,current_time,rc=status) + _VERIFY(status) + + _RETURN(_SUCCESS) + end function new_ExtDataOldTypesCreator + + + subroutine fillin_primary(this,item_name,base_name,primary_item,time,clock,unusable,rc) + class(ExtDataOldTypesCreator), intent(inout) :: this + character(len=*), intent(in) :: item_name + character(len=*), intent(in) :: base_name + type(PrimaryExport), intent(inout) :: primary_item + type(ESMF_Time), intent(inout) :: time + type(ESMF_Clock), intent(inout) :: clock + class(KeywordEnforcer), optional, intent(in) :: unusable + integer, optional, intent(out) :: rc + + type(ExtDataRule), pointer :: rule + type(ExtDataFileStream), pointer :: dataset + type(ExtDataTimeSample), pointer :: time_sample + type(ExtDataTimeSample), target :: default_time_sample + type(ExtDataSimpleFileHandler) :: simple_handler + type(ExtDataClimFileHandler) :: clim_handler + integer :: status, semi_pos + logical :: disable_interpolation, get_range + + _UNUSED_DUMMY(unusable) + rule => this%rule_map%at(trim(item_name)) + time_sample => this%sample_map%at(rule%sample_key) + + if(.not.associated(time_sample)) then + call default_time_sample%set_defaults() + time_sample=>default_time_sample + end if + primary_item%isVector = allocated(rule%vector_partner) + ! name and file var + !primary_item%name = trim(item_name) + primary_item%name = trim(base_name) + if (primary_item%isVector) then + primary_item%vartype = MAPL_VectorField + !primary_item%vcomp1 = trim(item_name) + primary_item%vcomp1 = trim(base_name) + primary_item%vcomp2 = trim(rule%vector_partner) + primary_item%var = rule%file_var + primary_item%fcomp1 = rule%file_var + primary_item%fcomp2 = rule%vector_file_partner + primary_item%fileVars%itemType = ItemTypeVector + primary_item%fileVars%xname = trim(rule%file_var) + primary_item%fileVars%yname = trim(rule%vector_file_partner) + else + primary_item%vartype = MAPL_FieldItem + !primary_item%vcomp1 = trim(item_name) + primary_item%vcomp1 = trim(base_name) + primary_item%var = rule%file_var + primary_item%fcomp1 = rule%file_var + primary_item%fileVars%itemType = ItemTypeScalar + primary_item%fileVars%xname = trim(rule%file_var) + end if + + ! regrid method + if (index(rule%regrid_method,"FRACTION;")>0) then + semi_pos = index(rule%regrid_method,";") + read(rule%regrid_method(semi_pos+1:),*) primary_item%fracVal + primary_item%trans = REGRID_METHOD_FRACTION + else + primary_item%trans = get_regrid_method(rule%regrid_method) + end if + _ASSERT(primary_item%trans/=UNSPECIFIED_REGRID_METHOD,"improper regrid method chosen") + + if (trim(time_sample%extrap_outside) =="clim") then + primary_item%cycling=.true. + else if (trim(time_sample%extrap_outside) == "persist_closest") then + primary_item%persist_closest=.true. + else if (trim(time_sample%extrap_outside) == "none") then + primary_item%cycling=.false. + primary_item%persist_closest=.false. + end if + + allocate(primary_item%source_time,source=time_sample%source_time) + ! new refresh + call primary_item%update_freq%create_from_parameters(time_sample%refresh_time, & + time_sample%refresh_frequency, time_sample%refresh_offset, time, clock, __RC__) + + disable_interpolation = .not.time_sample%time_interpolation + + call primary_item%modelGridFields%comp1%set_parameters(linear_trans=rule%linear_trans,disable_interpolation=disable_interpolation) + call primary_item%modelGridFields%comp2%set_parameters(linear_trans=rule%linear_trans,disable_interpolation=disable_interpolation) + call primary_item%modelGridFields%auxiliary1%set_parameters(linear_trans=rule%linear_trans, disable_interpolation=disable_interpolation) + call primary_item%modelGridFields%auxiliary2%set_parameters(linear_trans=rule%linear_trans, disable_interpolation=disable_interpolation) + + ! file_template + primary_item%isConst = .false. + if (index(rule%collection,"/dev/null")==0) then + dataset => this%file_stream_map%at(trim(rule%collection)) + primary_item%file_template = dataset%file_template + get_range = trim(time_sample%extrap_outside) /= "none" + call dataset%detect_metadata(primary_item%file_metadata,time,rule%multi_rule,get_range=get_range,__RC__) + else + primary_item%file_template = rule%collection + end if + + if (index(rule%collection,'/dev/null') /= 0) then + primary_item%isConst = .true. + primary_item%const=rule%linear_trans(1) + else + if (primary_item%cycling) then + call clim_handler%initialize(dataset,__RC__) + allocate(primary_item%filestream,source=clim_handler) + else + call simple_handler%initialize(dataset,persist_closest=primary_item%persist_closest,__RC__) + allocate(primary_item%filestream,source=simple_handler) + end if + end if + + _RETURN(_SUCCESS) + + end subroutine fillin_primary + + subroutine fillin_derived(this,item_name,derived_item,time,clock,unusable,rc) + class(ExtDataOldTypesCreator), intent(inout) :: this + character(len=*), intent(in) :: item_name + type(DerivedExport), intent(inout) :: derived_item + type(ESMF_Time), intent(inout) :: time + type(ESMF_Clock), intent(inout) :: clock + class(KeywordEnforcer), optional, intent(in) :: unusable + integer, optional, intent(out) :: rc + + type(ExtDataDerived), pointer :: rule + integer :: status + type(ExtDataTimeSample), pointer :: time_sample + type(ExtDataTimeSample), target :: default_time_sample + + _UNUSED_DUMMY(unusable) + rule => this%derived_map%at(trim(item_name)) + + derived_item%name = trim(item_name) + derived_item%expression = rule%expression + if (allocated(rule%sample_key)) then + time_sample => this%sample_map%at(rule%sample_key) + else + call default_time_sample%set_defaults() + time_sample=>default_time_sample + end if + call derived_item%update_freq%create_from_parameters(time_sample%refresh_time, & + time_sample%refresh_frequency, time_sample%refresh_offset, time, clock, __RC__) + derived_item%masking=.false. + if (index(derived_item%expression,"mask") /= 0 ) then + derived_item%masking=.true. + allocate(derived_item%mask_definition) + derived_item%mask_definition = ExtDataMask(derived_item%expression,_RC) + end if + + _RETURN(_SUCCESS) + + end subroutine fillin_derived + +end module MAPL_ExtDataOldTypesCreator diff --git a/gridcomps/ExtData2G/ExtDataRule.F90 b/gridcomps/ExtData2G/ExtDataRule.F90 new file mode 100644 index 000000000000..720a81f32d50 --- /dev/null +++ b/gridcomps/ExtData2G/ExtDataRule.F90 @@ -0,0 +1,177 @@ +#include "MAPL_ErrLog.h" +module MAPL_ExtDataRule + use yaFyaml + use ESMF + use MAPL_KeywordEnforcerMod + use MAPL_ExceptionHandling + use MAPL_TimeStringConversion + use MAPL_ExtDataTimeSample + use MAPL_ExtDataTimeSampleMap + implicit none + private + + type, public :: ExtDataRule + character(:), allocatable :: start_time + character(:), allocatable :: collection + character(:), allocatable :: file_var + character(:), allocatable :: sample_key + real, allocatable :: linear_trans(:) + character(:), allocatable :: regrid_method + character(:), allocatable :: vector_partner + character(:), allocatable :: vector_component + character(:), allocatable :: vector_file_partner + logical :: multi_rule + contains + procedure :: set_defaults + procedure :: split_vector + end type + + interface ExtDataRule + module procedure new_ExtDataRule + end interface + +contains + + function new_ExtDataRule(config,sample_map,key,unusable,multi_rule,rc) result(rule) + class(YAML_Node), intent(in) :: config + character(len=*), intent(in) :: key + type(ExtDataTimeSampleMap) :: sample_map + class(KeywordEnforcer), optional, intent(in) :: unusable + logical, optional, intent(in) :: multi_rule + integer, optional, intent(out) :: rc + + type(ExtDataRule) :: rule + logical :: collection_present, variable_present + integer :: status + class(YAML_Node), pointer ::config1 + character(len=:), allocatable :: tempc + type(ExtDataTimeSample) :: ts + logical :: usable_multi_rule + _UNUSED_DUMMY(unusable) + + if (present(multi_rule)) then + usable_multi_rule = multi_rule + else + usable_multi_rule = .false. + end if + + if (allocated(tempc)) deallocate(tempc) + collection_present = config%has("collection") + _ASSERT(collection_present,"no collection present in ExtData export") + rule%collection = config%of("collection") + + if (allocated(tempc)) deallocate(tempc) + variable_present = config%has("variable") + if (index(rule%collection,"/dev/null")==0) then + _ASSERT(variable_present,"no variable present in ExtData export") + end if + if (variable_present) then + tempc = config%of("variable") + rule%file_var=tempc + else + rule%file_var='null' + end if + + if (config%has("sample")) then + config1=>config%at("sample") + if (config1%is_mapping()) then + ts = ExtDataTimeSample(config1,_RC) + call sample_map%insert(trim(key)//"_sample",ts) + rule%sample_key=trim(key)//"_sample" + else if (config1%is_string()) then + rule%sample_key=config1 + else + _FAIL("sample entry unsupported") + end if + else + rule%sample_key = "" + end if + + if (allocated(rule%linear_trans)) deallocate(rule%linear_trans) + if (config%has("linear_transformation")) then + call config%get(rule%linear_trans,"linear_transformation") + else + allocate(rule%linear_trans,source=[0.0,0.0]) + end if + + if (allocated(tempc)) deallocate(tempc) + if (config%has("regrid")) then + tempc = config%of("regrid") + rule%regrid_method=tempc + else + rule%regrid_method="BILINEAR" + end if + + if (config%has("starting")) then + tempc = config%of("starting") + rule%start_time = tempc + end if + + rule%multi_rule=usable_multi_rule + + _RETURN(_SUCCESS) + end function new_ExtDataRule + + subroutine set_defaults(this,unusable,rc) + class(ExtDataRule), intent(inout), target :: this + class(KeywordEnforcer), optional, intent(in) :: unusable + integer, optional, intent(out) :: rc + + _UNUSED_DUMMY(unusable) + this%collection='' + this%file_var='missing_variable' + this%regrid_method='BILINEAR' + _RETURN(_SUCCESS) + end subroutine set_defaults + + subroutine split_vector(this,original_key,ucomp,vcomp,unusable,rc) + class(ExtDataRule), intent(in) :: this + character(len=*), intent(in) :: original_key + type(ExtDataRule), intent(inout) :: ucomp,vcomp + class(KeywordEnforcer), optional, intent(in) :: unusable + integer, optional, intent(out) :: rc + integer :: semi_pos + character(len=:),allocatable :: uname,vname + + _UNUSED_DUMMY(unusable) + + semi_pos = index(this%file_var,";") + _ASSERT(semi_pos > 0,"vector rule does not have 2 variables in the file_var") + uname = this%file_var(1:semi_pos-1) + vname = this%file_var(semi_pos+1:len_trim(this%file_var)) + ucomp = this + vcomp = this + semi_pos = index(original_key,";") + ucomp%vector_partner = original_key(semi_pos+1:len_trim(original_key)) + vcomp%vector_partner = original_key(1:semi_pos-1) + ucomp%file_var = uname + vcomp%file_var = vname + ucomp%vector_file_partner = vname + vcomp%vector_file_partner = uname + ucomp%vector_component = "EW" + vcomp%vector_component = "NS" + _RETURN(_SUCCESS) + + end subroutine split_vector + +end module MAPL_ExtDataRule + +module MAPL_ExtDataRuleMap + use MAPL_ExtDataRule + +#include "types/key_deferredLengthString.inc" +#define _value type(ExtDataRule) +#define _alt + +#define _map ExtDataRuleMap +#define _iterator ExtDataRuleMapIterator + +#include "templates/map.inc" + +#undef _iterator +#undef _map + +#undef _alt +#undef _value + +end module MAPL_ExtDataRuleMap diff --git a/gridcomps/ExtData2G/ExtDataSample.F90 b/gridcomps/ExtData2G/ExtDataSample.F90 new file mode 100644 index 000000000000..8a7629e235c4 --- /dev/null +++ b/gridcomps/ExtData2G/ExtDataSample.F90 @@ -0,0 +1,114 @@ +#include "MAPL_ErrLog.h" +module MAPL_ExtDataTimeSample + use yaFyaml + use ESMF + use MAPL_KeywordEnforcerMod + use MAPL_ExceptionHandling + use MAPL_TimeStringConversion + implicit none + private + + type, public :: ExtDataTimeSample + logical :: time_interpolation + type(ESMF_Time), allocatable :: source_time(:) + character(:), allocatable :: extrap_outside + character(:), allocatable :: refresh_time + character(:), allocatable :: refresh_frequency + character(:), allocatable :: refresh_offset + contains + procedure :: set_defaults + end type + + interface ExtDataTimeSample + module procedure new_ExtDataTimeSample + end interface + +contains + + function new_ExtDataTimeSample(config,unusable,rc) result(TimeSample) + class(YAML_Node), intent(in) :: config + class(KeywordEnforcer), optional, intent(in) :: unusable + integer, optional, intent(out) :: rc + + type(ExtDataTimeSample) :: TimeSample + integer :: status + character(len=:), allocatable :: source_str + integer :: idx + _UNUSED_DUMMY(unusable) + + call TimeSample%set_defaults() + + if (config%has("extrapolation")) TimeSample%extrap_outside=config%of("extrapolation") + + if (config%has("time_interpolation")) then + TimeSample%time_interpolation = config%of("time_interpolation") + else + TimeSample%time_interpolation = .true. + end if + + if (config%has("update_reference_time")) TimeSample%refresh_time=config%of("update_reference_time") + + if (config%has("update_reference_time")) TimeSample%refresh_frequency=config%of("update_frequency") + + if (config%has("update_offset")) TimeSample%refresh_offset=config%of("update_offset") + + if (config%has("source_time")) then + call config%get(source_str,"source_time",rc=status) + _VERIFY(status) + if (allocated(TimeSample%source_time)) deallocate(TimeSample%source_time) + idx = index(source_str,'/') + _ASSERT(idx/=0,'invalid specification of source_time') + allocate(TimeSample%source_time(2)) + TimeSample%source_time(1)=string_to_esmf_time(source_str(:idx-1)) + TimeSample%source_time(2)=string_to_esmf_time(source_str(idx+1:)) + else + if (.not.allocated(TimeSample%source_time)) allocate(TimeSample%source_time(0)) + end if + + _RETURN(_SUCCESS) + + end function new_ExtDataTimeSample + + + subroutine set_defaults(this,unusable,rc) + class(ExtDataTimeSample), intent(inout), target :: this + class(KeywordEnforcer), optional, intent(in) :: unusable + integer, optional, intent(out) :: rc + + integer :: status + _UNUSED_DUMMY(unusable) + this%time_interpolation=.true. + this%extrap_outside='none' + this%refresh_time="00" + this%refresh_frequency="PT0S" + this%refresh_offset="PT0S" + if (allocated(this%source_time)) then + deallocate(this%source_time,stat=status) + _VERIFY(status) + end if + allocate(this%source_time(0),stat=status) + _VERIFY(status) + _RETURN(_SUCCESS) + end subroutine set_defaults + +end module MAPL_ExtDataTimeSample + +module MAPL_ExtDataTimeSampleMap + use MAPL_ExtDataTimeSample + +#include "types/key_deferredLengthString.inc" +#define _value type(ExtDataTimeSample) +#define _alt + +#define _map ExtDataTimeSampleMap +#define _iterator ExtDataTimeSampleMapIterator + +#include "templates/map.inc" + +#undef _iterator +#undef _map + +#undef _alt +#undef _value + +end module MAPL_ExtDataTimeSampleMap diff --git a/gridcomps/ExtData2G/ExtDataSimpleFileHandler.F90 b/gridcomps/ExtData2G/ExtDataSimpleFileHandler.F90 new file mode 100644 index 000000000000..6a1da3d14e8c --- /dev/null +++ b/gridcomps/ExtData2G/ExtDataSimpleFileHandler.F90 @@ -0,0 +1,158 @@ +#include "MAPL_Exceptions.h" +#include "MAPL_ErrLog.h" +module MAPL_ExtdataSimpleFileHandler + use ESMF + use MAPL_ExtDataAbstractFileHandler + use MAPL_KeywordEnforcerMod + use MAPL_ExceptionHandling + use MAPL_DataCollectionMod + use MAPL_CollectionVectorMod + use MAPL_DataCollectionManagerMod + use MAPL_FileMetadataUtilsMod + use MAPL_TimeStringConversion + use MAPL_StringTemplate + use MAPL_ExtDataBracket + use MAPL_ExtDataConstants + + implicit none + private + public ExtDataSimpleFileHandler + + type, extends(ExtDataAbstractFileHandler) :: ExtDataSimpleFileHandler + contains + procedure :: get_file_bracket + procedure :: get_file + end type + +contains + + subroutine get_file_bracket(this, input_time, source_time, bracket, rc) + class(ExtdataSimpleFileHandler), intent(inout) :: this + type(ESMF_Time), intent(in) :: input_time + type(ESMF_Time), intent(in) :: source_time(:) + type(ExtDataBracket), intent(inout) :: bracket + integer, optional, intent(out) :: rc + integer :: status + type(ESMF_TimeInterval) :: zero + + type(ESMF_Time) :: time + integer :: time_index + character(len=ESMF_MAXPATHLEN) :: current_file + logical :: get_left, get_right,in_range,was_set + type(ESMF_Time) :: target_time + + get_left=.true. + get_right=.true. + in_range=.true. + target_time=input_time + call bracket%set_parameters(intermittent_disable=.false.) + if (this%persist_closest) then + if (input_time <= this%valid_range(1)) then + target_time = this%valid_range(1) + get_right = .false. + in_range = .false. + call bracket%get_node('L',was_set=was_set) + if (was_set) get_left=.false. + call bracket%set_parameters(intermittent_disable=.true.) + else if (input_time >= this%valid_range(2)) then + target_time = this%valid_range(2) + get_right = .false. + in_range = .false. + call bracket%get_node('L',was_set=was_set) + if (was_set) get_left=.false. + call bracket%set_parameters(intermittent_disable=.true.) + end if + end if + if (bracket%time_in_bracket(target_time) .and. in_range) then + _RETURN(_SUCCESS) + end if + call ESMF_TimeIntervalSet(zero,__RC__) + if (this%frequency == zero) then + current_file = this%file_template + if (get_left) then + call this%get_time_on_file(current_file,target_time,'L',time_index,time,__RC__) + _ASSERT(time_index/=time_not_found,"Time not found in file") + call bracket%set_node('L',file=current_file,time_index=time_index,time=time,__RC__) + if (in_range .and. (bracket%left_node == bracket%right_node)) then + call bracket%swap_node_fields(rc=status) + _VERIFY(status) + else + bracket%new_file_left=.true. + call bracket%set_node('L',was_set=.true.) + end if + end if + if (get_right) then + call this%get_time_on_file(current_file,target_time,'R',time_index,time,__RC__) + _ASSERT(time_index/=time_not_found,"Time not found in file") + call bracket%set_node('R',file=current_file,time_index=time_index,time=time,__RC__) + bracket%new_file_right=.true. + end if + else + if (get_left) then + call this%get_file(current_file,target_time,0,__RC__) + call this%get_time_on_file(current_file,target_time,'L',time_index,time,__RC__) + if (time_index == time_not_found) then + call this%get_file(current_file,target_time,-1,__RC__) + call this%get_time_on_file(current_file,target_time,'L',time_index,time,__RC__) + _ASSERT(time_index/=time_not_found,"Time not found in file") + end if + call bracket%set_node('L',file=current_file,time_index=time_index,time=time,__RC__) + if (in_range .and. (bracket%left_node == bracket%right_node)) then + call bracket%swap_node_fields(rc=status) + _VERIFY(status) + else + bracket%new_file_left=.true. + call bracket%set_node('L',was_set=.true.) + end if + end if + + if (get_right) then + call this%get_file(current_file,target_time,0,__RC__) + call this%get_time_on_file(current_file,target_time,'R',time_index,time,__RC__) + if (time_index == time_not_found) then + call this%get_file(current_file,target_time,1,__RC__) + call this%get_time_on_file(current_file,target_time,'R',time_index,time,__RC__) + _ASSERT(time_index /= time_not_found,"Time not found in file") + end if + call bracket%set_node('R',file=current_file,time_index=time_index,time=time,__RC__) + bracket%new_file_right=.true. + end if + + end if + _RETURN(_SUCCESS) + + end subroutine get_file_bracket + + subroutine get_file(this,filename,input_time,shift,rc) + class(ExtdataSimpleFileHandler), intent(inout) :: this + character(len=*), intent(out) :: filename + type(ESMF_Time) :: input_time + integer, intent(in) :: shift + integer, intent(out), optional :: rc + + type(ESMF_Time) :: ftime + integer :: n,status + logical :: file_found + integer(ESMF_KIND_I8) :: interval_seconds + + call ESMF_TimeIntervalGet(this%frequency,s_i8=interval_seconds) + if (interval_seconds==0) then + ! time is not representable as absolute time interval (month, year etc...) do this + ! brute force way. Not good but ESMF leaves no choice + ftime=this%reff_time + do while (ftime <= input_time) + ftime = ftime + this%frequency + enddo + ftime=ftime -this%frequency + shift*this%frequency + else + n = (input_time-this%reff_time)/this%frequency + ftime = this%reff_time+(n+shift)*this%frequency + end if + call fill_grads_template(filename,this%file_template,time=ftime,__RC__) + inquire(file=trim(filename),exist=file_found) + _ASSERT(file_found,"get_file did not file a file using: "//trim(this%file_template)) + _RETURN(_SUCCESS) + + end subroutine get_file + +end module MAPL_ExtdataSimpleFileHandler diff --git a/gridcomps/ExtData2G/ExtDataTypeDef.F90 b/gridcomps/ExtData2G/ExtDataTypeDef.F90 new file mode 100644 index 000000000000..f7f7ec75ded3 --- /dev/null +++ b/gridcomps/ExtData2G/ExtDataTypeDef.F90 @@ -0,0 +1,107 @@ +#include "MAPL_Exceptions.h" +module MAPL_ExtDataTypeDef + use ESMF + use MAPL_GriddedIOItemMod + use MAPL_ExtDataBracket + use MAPL_ExtDataPointerUpdate + use MAPL_ExtDataAbstractFileHandler + use MAPL_FileMetadataUtilsMod + use MAPL_NewArthParserMod + use MAPL_ExtDataMask + implicit none + + public PrimaryExport + public DerivedExport + public BracketingFields + + integer, parameter :: MAPL_ExtDataNullFrac = -9999 + + type BracketingFields + ! fields to store endpoints for interpolation of a vector pair + type(ExtDataBracket) :: comp1 + type(ExtDataBracket) :: comp2 + ! if vertically interpolating vector fields + type(ExtDataBracket) :: auxiliary1 + type(ExtDataBracket) :: auxiliary2 + end type BracketingFields + + type PrimaryExport + character(len=ESMF_MAXSTR) :: name + character(len=ESMF_MAXSTR) :: units='' + integer :: Trans + character(len=ESMF_MAXSTR) :: var + character(len=ESMF_MAXPATHLEN) :: file_template ! remove + + logical :: isConst + real :: Const !remove + integer :: vartype ! MAPL_FieldItem or MAPL_BundleItem + + class(ExtDataAbstractFileHandler), allocatable :: filestream + + ! if primary export represents a pair of vector fields + logical :: isVector + type(BracketingFields) :: modelGridFields + + ! names of the two vector components in the gridded component where import is declared + character(len=ESMF_MAXSTR) :: vcomp1, vcomp2 + ! the corresponding names of the two vector components on file + character(len=ESMF_MAXSTR) :: fcomp1, fcomp2 + type(GriddedIOitem) :: fileVars + + integer :: pfioCollection_id + integer :: iclient_collection_id + + logical :: ExtDataAlloc + integer :: FracVal = MAPL_ExtDataNullFrac + ! do we have to do vertical interpolation + logical :: do_VertInterp = .false. + logical :: do_Fill = .false. + type(FileMetadataUtils) :: file_metadata + integer :: LM + real, allocatable :: levs(:) + character(len=4) :: importVDir = "down" + character(len=4) :: fileVDir = "down" + character(len=ESMF_MAXSTR) :: levUnit + logical :: havePressure = .false. + type(ExtDataPointerUpdate) :: update_freq + + ! new stuff + logical :: cycling + logical :: persist_closest + type(ESMF_Time), allocatable :: source_time(:) + + ! for multiple collections + type(ESMF_Time), allocatable :: start_end_time(:) + logical :: initialized = .false. + end type PrimaryExport + + type DerivedExport + character(len=ESMF_MAXSTR) :: name + character(len=ESMF_MAXPATHLEN) :: expression + logical :: masking + type(ExtDataMask), allocatable :: mask_definition + type(ExtDataPointerUpdate) :: update_freq + contains + procedure :: evaluate_derived_field + end type DerivedExport + + contains + + subroutine evaluate_derived_field(this,state,rc) + class(DerivedExport), intent(inout) :: this + type(ESMF_State), intent(inout) :: state + integer, optional, intent(out) :: rc + + integer :: status + type(ESMF_Field) :: field + + if (this%masking) then + call this%mask_definition%evaluate_mask(state,trim(this%name),_RC) + else + call ESMF_StateGet(state,trim(this%name),field,_RC) + call MAPL_StateEval(state,trim(this%expression),field,_RC) + end if + _RETURN(_SUCCESS) + end subroutine + +end module MAPL_ExtDataTypeDef diff --git a/gridcomps/ExtData2G/ExtDataUpdatePointer.F90 b/gridcomps/ExtData2G/ExtDataUpdatePointer.F90 new file mode 100644 index 000000000000..0847e067bf35 --- /dev/null +++ b/gridcomps/ExtData2G/ExtDataUpdatePointer.F90 @@ -0,0 +1,150 @@ +#include "MAPL_Exceptions.h" +#include "MAPL_ErrLog.h" + +module MAPL_ExtDataPointerUpdate + use ESMF + use MAPL_KeywordEnforcerMod + use MAPL_ExceptionHandling + use MAPL_TimeStringConversion + use MAPL_CommsMod + implicit none + private + + public :: ExtDataPointerUpdate + + type :: ExtDataPointerUpdate + private + logical :: disabled = .false. + logical :: first_time_updated = .true. + type(ESMF_TimeInterval) :: offset + logical :: single_shot = .false. + type(ESMF_TimeInterval) :: update_freq + type(ESMF_Time) :: last_ring + type(ESMF_Time) :: reference_time + logical :: simple_alarm_created = .false. + type(ESMF_TIme) :: last_checked + contains + procedure :: create_from_parameters + procedure :: check_update + procedure :: is_disabled + procedure :: is_single_shot + procedure :: disable + end type + + contains + + subroutine create_from_parameters(this,update_time,update_freq,update_offset,time,clock,rc) + class(ExtDataPointerUpdate), intent(inout) :: this + character(len=*), intent(in) :: update_time + character(len=*), intent(in) :: update_freq + character(len=*), intent(in) :: update_offset + type(ESMF_Time), intent(inout) :: time + type(ESMF_Clock), intent(inout) :: clock + integer, optional, intent(out) :: rc + + integer :: status,int_time,year,month,day,hour,minute,second + + this%last_checked = time + if (update_freq == "-") then + this%single_shot = .true. + else if (update_freq /= "PT0S") then + this%simple_alarm_created = .true. + int_time = string_to_integer_time(update_time) + hour=int_time/10000 + minute=mod(int_time/100,100) + second=mod(int_time,100) + call ESMF_TimeGet(time,yy=year,mm=month,dd=day,__RC__) + call ESMF_TimeSet(this%reference_time,yy=year,mm=month,dd=day,h=hour,m=minute,s=second,__RC__) + this%last_ring = this%reference_time + this%update_freq = string_to_esmf_timeinterval(update_freq,__RC__) + end if + this%offset=string_to_esmf_timeinterval(update_offset,__RC__) + _RETURN(_SUCCESS) + + end subroutine create_from_parameters + + subroutine check_update(this,do_update,use_time,current_time,first_time,rc) + class(ExtDataPointerUpdate), intent(inout) :: this + logical, intent(out) :: do_update + type(ESMF_Time), intent(inout) :: use_time + type(ESMF_Time), intent(inout) :: current_time + logical, intent(in) :: first_time + integer, optional, intent(out) :: rc + type(ESMF_Time) :: next_ring + + integer :: status + + if (this%disabled) then + do_update = .false. + _RETURN(_SUCCESS) + end if + if (this%simple_alarm_created) then + use_time = current_time+this%offset + if (first_time) then + do_update = .true. + this%first_time_updated = .true. + use_time = this%last_ring + this%offset + else + ! normal flow + next_ring = this%last_ring + if (current_time > this%last_checked) then + do while (next_ring < current_time) + next_ring=next_ring+this%update_freq + enddo + if (current_time == next_ring) then + do_update = .true. + this%last_ring = next_ring + this%first_time_updated = .false. + end if + ! if clock went backwards, so we must update, set ringtime to previous ring from working time + else if (current_time < this%last_checked) then + next_ring = this%last_ring + ! the clock must have rewound past last ring + if (this%last_ring > current_time) then + do while(next_ring <= current_time) + next_ring=next_ring-this%update_freq + enddo + use_time = next_ring+this%offset + this%last_ring = next_ring + ! alarm never rang during the previous advance, only update the previous update was the first time + else if (this%last_ring < current_time) then + if (this%first_time_updated) then + do_update=.true. + this%first_time_updated = .false. + use_time = this%last_ring + this%offset + end if + ! otherwise we land on a time when the alarm would ring and we would update + else if (this%last_ring == current_time) then + do_update =.true. + this%first_time_updated = .false. + use_time = current_time+this%offset + end if + end if + end if + else + do_update = .true. + if (this%single_shot) this%disabled = .true. + use_time = current_time+this%offset + end if + this%last_checked = current_time + + end subroutine check_update + + function is_disabled(this) result(disabled) + class(ExtDataPointerUpdate), intent(in) :: this + logical :: disabled + disabled = this%disabled + end function is_disabled + + function is_single_shot(this) result(single_shot) + class(ExtDataPointerUpdate), intent(in) :: this + logical :: single_shot + single_shot = this%single_shot + end function is_single_shot + + subroutine disable(this) + class(ExtDataPointerUpdate), intent(inout) :: this + this%disabled = .true. + end subroutine + +end module MAPL_ExtDataPointerUpdate diff --git a/gridcomps/ExtData2G/ExtData_IOBundleMod.F90 b/gridcomps/ExtData2G/ExtData_IOBundleMod.F90 new file mode 100644 index 000000000000..1e116ee47a8d --- /dev/null +++ b/gridcomps/ExtData2G/ExtData_IOBundleMod.F90 @@ -0,0 +1,127 @@ +!#include "MAPL_Exceptions.h" +#include "MAPL_Generic.h" +#include "unused_dummy.H" + +!------------------------------------------------------------------------- +! NASA/GSFC, Global Modeling and Assimilation Office, Code 610.1 ! +!------------------------------------------------------------------------- + +module MAPL_ExtDataNG_IOBundleMod + use ESMF + use MAPL_BaseMod + use MAPL_GriddedIOMod + use MAPL_ExceptionHandling + use MAPL_GriddedIOItemMod + use MAPL_GriddedIOItemVectorMod + + public :: ExtDataNG_IOBundle + + type ExtDataNG_IOBundle + type (MAPL_GriddedIO) :: cfio + type (ESMF_FieldBundle) :: pbundle + character(:), allocatable :: template + integer :: regrid_method + + integer :: bracket_side + integer :: entry_index + character(:), allocatable :: file_name + integer :: time_index + integer :: fraction + integer :: metadata_coll_id + integer :: server_coll_id + type(GriddedIOItemVector) :: items + + contains + + procedure :: clean + procedure :: make_cfio + procedure :: assign + generic :: assignment(=) => assign + end type ExtDataNG_IOBundle + + + interface ExtDataNG_IOBundle + module procedure new_ExtDataNG_IOBundle + end interface ExtDataNG_IOBundle + +contains + + function new_ExtDataNG_IOBundle(bracket_side, entry_index, file_name, time_index, regrid_method, fraction, template, metadata_coll_id,server_coll_id,items,rc) result(io_bundle) + type (ExtDataNG_IOBundle) :: io_bundle + + integer, intent(in) :: bracket_side + integer, intent(in) :: entry_index + character(len=*), intent(in) :: file_name + integer, intent(in) :: time_index + integer, intent(in) :: regrid_method + integer, intent(in) :: fraction + character(len=*), intent(in) :: template + integer, intent(in) :: metadata_coll_id + integer, intent(in) :: server_coll_id + type(GriddedIOItemVector) :: items + integer, optional, intent(out) :: rc + + io_bundle%bracket_side = bracket_side + io_bundle%entry_index = entry_index + io_bundle%file_name = file_name + io_bundle%time_index = time_index + io_bundle%regrid_method = regrid_method + io_bundle%fraction = fraction + io_bundle%template = trim(template) + + io_bundle%metadata_coll_id=metadata_coll_id + io_bundle%server_coll_id=server_coll_id + io_bundle%items=items + + _RETURN(ESMF_SUCCESS) + end function new_ExtDataNG_IOBundle + + + subroutine clean(this, rc) + class (ExtDataNG_IOBundle), intent(inout) :: this + integer, optional, intent(out) :: rc + + integer :: status + call ESMF_FieldBundleDestroy(this%pbundle, noGarbage=.true.,rc=status) + _VERIFY(status) + + _RETURN(ESMF_SUCCESS) + + end subroutine clean + + + subroutine make_cfio(this, rc) + class (ExtDataNG_IOBundle), intent(inout) :: this + integer, optional, intent(out) :: rc + + this%cfio = MAPL_GriddedIO(output_bundle=this%pbundle,regrid_method=this%regrid_method, & + read_collection_id=this%server_coll_id, & + metadata_collection_id = this%metadata_coll_id, fraction = this%fraction, & + items=this%items) + + _RETURN(ESMF_SUCCESS) + + end subroutine make_cfio + + subroutine assign(to,from) + class(ExtDataNG_IOBundle), intent(out) :: to + type(ExtDataNG_IOBundle), intent(in) :: from + + to%bracket_side = from%bracket_side + to%entry_index = from%entry_index + to%file_name = from%file_name + to%time_index = from%time_index + to%regrid_method = from%regrid_method + to%fraction = from%fraction + to%template = from%template + + to%metadata_coll_id=from%metadata_coll_id + to%server_coll_id=from%server_coll_id + to%items=from%items + to%pbundle=from%pbundle + to%CFIO=from%CFIO + + end subroutine assign + +end module MAPL_ExtDataNG_IOBundleMod + diff --git a/gridcomps/ExtData2G/ExtData_IOBundleVectorMod.F90 b/gridcomps/ExtData2G/ExtData_IOBundleVectorMod.F90 new file mode 100644 index 000000000000..cdfc72c49b06 --- /dev/null +++ b/gridcomps/ExtData2G/ExtData_IOBundleVectorMod.F90 @@ -0,0 +1,10 @@ +module MAPL_ExtDataNG_IOBundleVectorMod + use MAPL_ExtDataNG_IOBundleMod + +#define _type type(ExtDataNG_IoBundle) +#define _vector IoBundleNGVector +#define _iterator IoBundleNGVectorIterator + +#include "templates/vector.inc" + +end module MAPL_ExtDataNG_IOBundleVectorMod diff --git a/gridcomps/ExtData2G/TimeStringConversion.F90 b/gridcomps/ExtData2G/TimeStringConversion.F90 new file mode 100644 index 000000000000..b7f5017ff001 --- /dev/null +++ b/gridcomps/ExtData2G/TimeStringConversion.F90 @@ -0,0 +1,242 @@ +#include "MAPL_Exceptions.h" +#include "MAPL_ErrLog.h" +module MAPL_TimeStringConversion + use ESMF + use MAPL_KeywordEnforcerMod + use MAPL_ExceptionHandling + implicit none + private + + public :: string_to_integer_time + public :: string_to_integer_date + public :: string_to_esmf_time + public :: string_to_esmf_timeinterval + +contains + + function string_to_integer_time(time_string,unusable,rc) result(time) + character(len=*), intent(in) :: time_string + class(KeywordEnforcer), optional, intent(in) :: unusable + integer, optional, intent(out) :: rc + + integer :: time + integer mpos(2), hpos(2), spos(2) + integer strlen + integer firstcolon, lastcolon + integer lastspace + integer hour,min,sec + + _UNUSED_DUMMY(unusable) + + strlen = LEN_TRIM (time_string) + + firstcolon = index(time_string, ':') + if (firstcolon .LE. 0) then + + ! If no colons, check for hour. + + ! Logic below assumes a null character or something else is after the hour + ! if we do not find a null character add one so that it correctly parses time + !if (time_string(strlen:strlen) /= char(0)) then + !time_string = trim(time_string)//char(0) + !strlen=len_trim(time_string) + !endif + lastspace = index(TRIM(time_string), ' ', BACK=.TRUE.) + if ((strlen-lastspace).eq.2 .or. (strlen-lastspace).eq.3) then + hpos(1) = lastspace+1 + hpos(2) = strlen-1 + read (time_string(hpos(1):hpos(2)), * ) hour + min = 0 + sec = 0 + else + hour = 0 + min = 0 + sec = 0 + endif + + else + hpos(1) = firstcolon - 2 + hpos(2) = firstcolon - 1 + lastcolon = index(time_string, ':', BACK=.TRUE.) + if ( lastcolon .EQ. firstcolon ) then + mpos(1) = firstcolon + 1 + mpos(2) = firstcolon + 2 + read (time_string(hpos(1):hpos(2)), * ) hour + read (time_string(mpos(1):mpos(2)), * ) min + sec = 0 + else + mpos(1) = firstcolon + 1 + mpos(2) = lastcolon - 1 + spos(1) = lastcolon + 1 + spos(2) = lastcolon + 2 + read (time_string(hpos(1):hpos(2)), * ) hour + read (time_string(mpos(1):mpos(2)), * ) min + read (time_string(spos(1):spos(2)), * ) sec + endif + endif + + time = hour*10000+min*100+sec + _RETURN(_SUCCESS) + + end function string_to_integer_time + + function string_to_integer_date(time_string,unusable,rc) result(date) + character(len=*), intent(in) :: time_string + class(KeywordEnforcer), optional, intent(in) :: unusable + integer, optional, intent(out) :: rc + + integer :: date + integer ypos(2), mpos(2), dpos(2) + integer strlen + integer firstdash, lastdash + integer year,month,day + + _UNUSED_DUMMY(unusable) + + strlen = LEN_TRIM (time_string) + + firstdash = index(time_string, '-') + lastdash = index(time_string, '-', BACK=.TRUE.) + + if (firstdash .LE. 0 .OR. lastdash .LE. 0) then + _RETURN(_FAILURE) + endif + + ypos(2) = firstdash - 1 + mpos(1) = firstdash + 1 + ypos(1) = ypos(2) - 3 + + mpos(2) = lastdash - 1 + dpos(1) = lastdash + 1 + dpos(2) = dpos(1) + 1 + + read ( time_string(ypos(1):ypos(2)), * ) year + read ( time_string(mpos(1):mpos(2)), * ) month + read ( time_string(dpos(1):dpos(2)), * ) day + + date = year*10000+month*100+day + _RETURN(_SUCCESS) + + end function string_to_integer_date + + function string_to_esmf_time(input_string,unusable,rc) result(time) + character(len=*), intent(in) :: input_string + class(KeywordEnforcer), optional, intent(in) :: unusable + integer, optional, intent(out) :: rc + + type(ESMF_Time) :: time + integer :: status + integer :: tpos + integer year,month,day,hour,min,sec + integer :: int_time, int_date + character(len=:), allocatable :: date_string,time_string + logical :: have_time + + _UNUSED_DUMMY(unusable) + + tpos = index(input_string,'T') + if (tpos<=0) then + have_time = .false. + else + have_time = .true. + end if + + if (have_time) then + time_string = input_string(tpos+1:) + date_string = input_string(:tpos-1) + int_time = string_to_integer_time(time_string,__RC__) + else + date_string = trim(input_string) + int_time = 0 + end if + int_date = string_to_integer_date(date_string,__RC__) + + year=int_date/10000 + month=mod(int_date/100,100) + day=mod(int_date,100) + hour=int_time/10000 + min=mod(int_time/100,100) + sec=mod(int_time,100) + call ESMF_TimeSet(time,yy=year,mm=month,dd=day,h=hour,m=min,s=sec,__RC__) + _RETURN(_SUCCESS) + + end function string_to_esmf_time + + function string_to_esmf_timeinterval(time_interval_string,unusable,rc) result(time_interval) + character(len=*), intent(in) :: time_interval_string + class(KeywordEnforcer), optional, intent(in) :: unusable + integer, optional, intent(out) :: rc + + type(ESMF_TimeInterval) :: time_interval + integer :: status + + integer :: strlen,ppos,cpos,lpos,tpos + integer year,month,day,hour,min,sec + character(len=:), allocatable :: date_string,time_string + _UNUSED_DUMMY(unusable) + + year=0 + month=0 + day=0 + hour=0 + min=0 + sec=0 + strlen = len_trim(time_interval_string) + tpos = index(time_interval_string,'T') + ppos = index(time_interval_string,'P') + _ASSERT(time_interval_string(1:1) == 'P','Not valid time duration') + + if (tpos /= 0) then + if (tpos /= ppos+1) then + date_string = time_interval_string(ppos+1:tpos-1) + end if + time_string = time_interval_string(tpos+1:strlen) + else + date_string = time_interval_string(ppos+1:strlen) + end if + + if (allocated(date_string)) then + strlen = len_trim(date_string) + lpos = 0 + cpos = index(date_string,'Y') + if (cpos /= 0) then + read(date_string(lpos+1:cpos-1),*)year + lpos = cpos + end if + cpos = index(date_string,'M') + if (cpos /= 0) then + read(date_string(lpos+1:cpos-1),*)month + lpos = cpos + end if + cpos = index(date_string,'D') + if (cpos /= 0) then + read(date_string(lpos+1:cpos-1),*)day + lpos = cpos + end if + end if + if (allocated(time_string)) then + strlen = len_trim(time_string) + lpos = 0 + cpos = index(time_string,'H') + if (cpos /= 0) then + read(time_string(lpos+1:cpos-1),*)hour + lpos = cpos + end if + cpos = index(time_string,'M') + if (cpos /= 0) then + read(time_string(lpos+1:cpos-1),*)min + lpos = cpos + end if + cpos = index(time_string,'S') + if (cpos /= 0) then + read(time_string(lpos+1:cpos-1),*)sec + lpos = cpos + end if + end if + + call ESMF_TimeIntervalSet(time_interval,yy=year,mm=month,d=day,h=hour,m=min,s=sec,__RC__) + _RETURN(_SUCCESS) + + end function string_to_esmf_timeinterval + +end module MAPL_TimeStringConversion diff --git a/gridcomps/History/MAPL_HistoryCollection.F90 b/gridcomps/History/MAPL_HistoryCollection.F90 index 1655a760a7b4..ae367ae7e1b2 100644 --- a/gridcomps/History/MAPL_HistoryCollection.F90 +++ b/gridcomps/History/MAPL_HistoryCollection.F90 @@ -70,7 +70,7 @@ module MAPL_HistoryCollectionMod real :: vscale character(len=ESMF_MAXSTR) :: vunit character(len=ESMF_MAXSTR) :: vvars(2) - integer :: conservative + integer :: regrid_method integer :: voting integer :: nbits integer :: deflate diff --git a/gridcomps/History/MAPL_HistoryGridComp.F90 b/gridcomps/History/MAPL_HistoryGridComp.F90 index 3068b7da9e37..3e4694635d3d 100644 --- a/gridcomps/History/MAPL_HistoryGridComp.F90 +++ b/gridcomps/History/MAPL_HistoryGridComp.F90 @@ -40,6 +40,7 @@ module MAPL_HistoryGridCompMod use MAPL_GriddedIOitemMod use pFIO_ClientManagerMod, only: o_Clients use pFIO_DownbitMod, only: pFIO_DownBit + use pFIO_ConstantsMod use HistoryTrajectoryMod use MAPL_StringTemplate use regex_module @@ -108,14 +109,12 @@ module MAPL_HistoryGridCompMod type(HistoryCollectionGlobalAttributes) :: global_atts integer :: CoresPerNode, mype, npes integer :: AvoidRootNodeThreshold - integer :: blocksize - integer :: MarkDone - integer :: PrePost integer :: version logical :: fileOrderAlphabetical logical :: integer_time integer :: collectionWriteSplit integer :: serverSizeSplit + logical :: allow_overwrite end type HISTORY_STATE type HISTORY_wrap @@ -428,7 +427,9 @@ subroutine Initialize ( gc, import, dumexport, clock, rc ) type(ESMF_Field), allocatable :: fldList(:) character(len=ESMF_MAXSTR), allocatable :: regexList(:) type(StringStringMap) :: global_attributes - character(len=ESMF_MAXSTR) :: name + character(len=ESMF_MAXSTR) :: name,regrid_method + logical :: has_conservative_keyword, has_regrid_keyword + integer :: create_mode ! ewl: gchp merge conflict. The following are only in GCHP. ! debug variables @@ -505,7 +506,7 @@ subroutine Initialize ( gc, import, dumexport, clock, rc ) ! set up few variables to deal with monthly startOfThisMonth = currTime call ESMF_TimeSet(startOfThisMonth,dd=1,h=0,m=0,s=0,__RC__) - call ESMF_TimeIntervalSet( oneMonth, MM=1, __RC__) + call ESMF_TimeIntervalSet( oneMonth, MM=1, StartTime=StartTime, __RC__) ! Read User-Supplied History Lists from Config File @@ -544,19 +545,20 @@ subroutine Initialize ( gc, import, dumexport, clock, rc ) label ='AvoidRootNodeThreshold:', default=1024, rc=status ) _VERIFY(STATUS) - call ESMF_ConfigGetAttribute(config, value=INTSTATE%blocksize, & - label='BlockSize:', default=10, rc=status) - _VERIFY(STATUS) - call ESMF_ConfigGetAttribute(config, value=cFileOrder, & label='FileOrder:', default='ABC', rc=status) _VERIFY(STATUS) + call ESMF_ConfigGetAttribute(config, value=intState%allow_overwrite, & + label='Allow_Overwrite:', default=.false., _RC) + create_mode = PFIO_NOCLOBBER ! defaut no overwrite + if (intState%allow_overwrite) create_mode = PFIO_CLOBBER + if (trim(cFileOrder) == 'ABC') then intstate%fileOrderAlphabetical = .true. else if (trim(cFileOrder) == 'AddOrder') then intstate%fileOrderAlphabetical = .false. else - _ASSERT(.false.,'needs informative message') + _FAIL('needs informative message') end if call ESMF_ConfigGetAttribute(config, value=intstate%integer_time,label="IntegerTime:", default=.false.,_RC) @@ -571,14 +573,6 @@ subroutine Initialize ( gc, import, dumexport, clock, rc ) n_hist_split = IntState%collectionWriteSplit,rc=status) _VERIFY(status) - call ESMF_ConfigGetAttribute(config, value=INTSTATE%MarkDone, & - label='MarkDone:', default=0, rc=status) - _VERIFY(STATUS) - call ESMF_ConfigGetAttribute(config, value=INTSTATE%PrePost, & - label='PrePost:', default=1, rc=status) - _VERIFY(STATUS) - - call ESMF_ConfigGetAttribute(config, value=snglcol, & label='SINGLE_COLUMN:', default=0, rc=status) _VERIFY(STATUS) @@ -598,9 +592,6 @@ subroutine Initialize ( gc, import, dumexport, clock, rc ) print *, 'EXPID: ',trim(INTSTATE%expid) print *, 'Descr: ',trim(INTSTATE%expdsc) print *, 'DisableSubVmChecks:', disableSubVmChecks - print *, 'BlockSize: ' , INTSTATE%blocksize - print *, 'MarkDone: ' , INTSTATE%MarkDone - print *, 'PrePost: ' , INTSTATE%PrePost print * if (reverseTime .eq. 1) THEN print *, 'REVERSE_TIME = "', reverseTime, '"' @@ -905,13 +896,27 @@ subroutine Initialize ( gc, import, dumexport, clock, rc ) call ESMF_ConfigGetAttribute ( cfg, list(n)%tm, default=tm_default, & label=trim(string) // 'tm:', rc=status ) _VERIFY(STATUS) - call ESMF_ConfigGetAttribute ( cfg, list(n)%conservative, default=0, & - label=trim(string) // 'conservative:' ,rc=status ) - _VERIFY(STATUS) - if (list(n)%conservative==0) then - list(n)%conservative=REGRID_METHOD_BILINEAR - else if (list(n)%conservative==1) then - list(n)%conservative=REGRID_METHOD_CONSERVE + + call ESMF_ConfigFindLabel ( cfg, label=trim(string) // 'conservative:',isPresent=has_conservative_keyword,_RC) + call ESMF_ConfigFindLabel ( cfg, label=trim(string) // 'regrid_method:',isPresent=has_regrid_keyword,_RC) + _ASSERT(.not.(has_conservative_keyword .and. has_regrid_keyword),trim(string)//" specified both conservative and regrid_method") + + list(n)%regrid_method = REGRID_METHOD_BILINEAR + if (has_conservative_keyword) then + call ESMF_ConfigGetAttribute ( cfg, list(n)%regrid_method, default=0, & + label=trim(string) // 'conservative:' ,rc=status ) + _VERIFY(STATUS) + if (list(n)%regrid_method==0) then + list(n)%regrid_method=REGRID_METHOD_BILINEAR + else if (list(n)%regrid_method==1) then + list(n)%regrid_method=REGRID_METHOD_CONSERVE + end if + end if + if (has_regrid_keyword) then + call ESMF_ConfigGetAttribute ( cfg, regrid_method, default="REGRID_METHOD_BILINEAR", & + label=trim(string) // 'regrid_method:' ,rc=status ) + _VERIFY(STATUS) + list(n)%regrid_method = get_regrid_method(trim(regrid_method)) end if ! Get an optional file containing a 1-D track for the output @@ -950,7 +955,7 @@ subroutine Initialize ( gc, import, dumexport, clock, rc ) if (old_fields_style) then field_set_name = trim(string) // 'fields' allocate(field_set) - call parse_fields(cfg, trim(field_set_name), field_set, list(n)%items, rc=status) + call parse_fields(cfg, trim(field_set_name), field_set, collection_name = list(n)%collection, items = list(n)%items, _RC) end if list(n)%field_set => field_set @@ -1280,7 +1285,7 @@ subroutine Initialize ( gc, import, dumexport, clock, rc ) RingTime = startOfThisMonth else sec = MAPL_nsecf( list(n)%frequency ) - call ESMF_TimeIntervalSet( Frequency, S=sec, calendar=cal, rc=status ) ; _VERIFY(STATUS) + call ESMF_TimeIntervalSet( Frequency, S=sec, StartTime=StartTime, rc=status ) ; _VERIFY(STATUS) RingTime = RefTime end if @@ -1370,7 +1375,7 @@ subroutine Initialize ( gc, import, dumexport, clock, rc ) if( list(n)%duration.ne.0 ) then if (.not.list(n)%monthly) then sec = MAPL_nsecf( list(n)%duration ) - call ESMF_TimeIntervalSet( Frequency, S=sec, calendar=cal, rc=status ) ; _VERIFY(STATUS) + call ESMF_TimeIntervalSet( Frequency, S=sec, StartTime=StartTime, rc=status ) ; _VERIFY(STATUS) else Frequency = oneMonth !ALT keep the values from above @@ -1524,7 +1529,7 @@ subroutine Initialize ( gc, import, dumexport, clock, rc ) else if (index(list(n)%field_set%fields(1,m),'%') /= 0) then call WRITE_PARALLEL('Can not do arithmetic expression with bundle item') - _ASSERT(.false.,'needs informative message') + _FAIL('needs informative message') end if end if enddo @@ -1862,17 +1867,19 @@ subroutine Initialize ( gc, import, dumexport, clock, rc ) stateIntent = ESMF_STATEINTENT_IMPORT, & rc=status ) _VERIFY(STATUS) - if(list(n)%mode == "instantaneous") then + + select case (list(n)%mode) + case ("instantaneous") IntState%average(n) = .false. - else + case ("time-averaged") IntState%average(n) = .true. IntState%CIM(n) = ESMF_StateCreate ( name=trim(list(n)%filename), & - stateIntent = ESMF_STATEINTENT_IMPORT, & - rc=status ) - _VERIFY(STATUS) + stateIntent = ESMF_STATEINTENT_IMPORT, _RC) NULLIFY(INTSTATE%SRCS(n)%SPEC) NULLIFY(INTSTATE%DSTS(n)%SPEC) - endif + case default + _FAIL("Invalid mode ["//trim(list(n)%mode)//"] for collection ["//trim(list(n)%collection)//"]. Only 'instantaneous' and 'time-averaged' are supported") + end select if (associated(IntState%Regrid(n)%PTR)) then _ASSERT(.not. list(n)%subVm,'needs informative message') ! ALT: currently we are not supporting regridding on subVM @@ -2587,6 +2594,10 @@ subroutine Initialize ( gc, import, dumexport, clock, rc ) do n=1,nlist if (list(n)%disabled) cycle + if (list(n)%format == 'CFIOasync') then + list(n)%format = 'CFIO' + if (mapl_am_i_root()) write(*,*)'Chose CFIOasync setting to CFIO, update your History.rc file' + end if if (list(n)%format == 'CFIO') then call Get_Tdim (list(n), clock, tm) if (associated(list(n)%levels) .and. list(n)%vvars(1) /= "") then @@ -2605,7 +2616,7 @@ subroutine Initialize ( gc, import, dumexport, clock, rc ) _VERIFY(status) call list(n)%mGriddedIO%set_param(nbits=list(n)%nbits,rc=status) _VERIFY(status) - call list(n)%mGriddedIO%set_param(regrid_method=list(n)%conservative,rc=status) + call list(n)%mGriddedIO%set_param(regrid_method=list(n)%regrid_method,rc=status) _VERIFY(status) call list(n)%mGriddedIO%set_param(itemOrder=intState%fileOrderAlphabetical,rc=status) _VERIFY(status) @@ -2641,7 +2652,7 @@ subroutine Initialize ( gc, import, dumexport, clock, rc ) ! ewl end _VERIFY(status) end if - collection_id = o_Clients%add_hist_collection(list(n)%mGriddedIO%metadata) + collection_id = o_Clients%add_hist_collection(list(n)%mGriddedIO%metadata, mode = create_mode) call list(n)%mGriddedIO%set_param(write_collection_id=collection_id) end if end if @@ -2711,7 +2722,7 @@ subroutine Initialize ( gc, import, dumexport, clock, rc ) case (3) print *, ' XY-offset: ',list(n)%xyoffset,' (DePe: Dateline Edge, Pole Edge)' case default - _ASSERT(.false.,'needs informative message') + _FAIL('needs informative message') end select !print *, ' Fields: ',((trim(list(n)%field_set%fields(3,m)),' '),m=1,list(n)%field_set%nfields) @@ -3141,7 +3152,7 @@ function hasSplitableField(fldName, rc) result(okToSplit) exp_state = export(k) call MAPL_StateGet(exp_state,baseName,fld,__RC__) - + okToSplit = hasSplitField(fld, __RC__) if (okToSplit) then @@ -3288,20 +3299,27 @@ function extract_unquoted_item(string_list) result(item) end function extract_unquoted_item - subroutine parse_fields(cfg, label, field_set, items, rc) + subroutine parse_fields(cfg, label, field_set, collection_name, items, rc) type(ESMF_Config), intent(inout) :: cfg character(*), intent(in) :: label type (FieldSet), intent(inout) :: field_set + character(*), intent(in), optional :: collection_name type(GriddedIOitemVector), intent(inout), optional :: items integer, optional, intent(out) :: rc logical :: table_end - logical :: vectorDone - integer :: m + logical :: vectorDone,match_alias + integer :: m,i,j character(ESMF_MAXSTR), pointer:: fields (:,:) type(GriddedIOitem) :: item integer :: status + character(len=:), allocatable :: usable_collection_name + if (present(collection_name)) then + usable_collection_name = trim(collection_name) + else + usable_collection_name = "unknown" + end if call ESMF_ConfigFindLabel ( cfg, label=label//':', rc=status) _VERIFY(status) @@ -3440,6 +3458,17 @@ subroutine parse_fields(cfg, label, field_set, items, rc) if(present(items)) call items%push_back(item) enddo field_set%nfields = m +! check for duplicates + do i=1,field_set%nfields-1 + do j=i+1,field_set%nfields + + match_alias = field_set%fields(3,i) == field_set%fields(3,j) + if (match_alias) then + _FAIL("Caught collection "//usable_collection_name//" with this duplicate alias or shortname if no alias provided: "//trim(field_set%fields(3,i))) + end if + + enddo + enddo end subroutine parse_fields @@ -3475,7 +3504,6 @@ subroutine Run ( gc, import, export, clock, rc ) type(ESMF_State) :: state_out integer :: nymd, nhms character(len=ESMF_MAXSTR) :: DateStamp - integer :: CollBlock type(ESMF_Time) :: current_time type(ESMF_Time) :: lastMonth type(ESMF_TimeInterval) :: dur, oneMonth @@ -3487,6 +3515,7 @@ subroutine Run ( gc, import, export, clock, rc ) ! ErrLog vars integer :: status + logical :: file_exists ! Debug variables type(ESMF_Time) :: CurrTime @@ -3517,7 +3546,6 @@ subroutine Run ( gc, import, export, clock, rc ) list => IntState%list nlist = size(list) - CollBlock = IntState%blocksize ! Retrieve the pointer to the generic state !------------------------------------------ @@ -3774,6 +3802,10 @@ subroutine Run ( gc, import, export, clock, rc ) else if( list(n)%unit.eq.0 ) then if (list(n)%format == 'CFIO') then + if (.not.intState%allow_overwrite) then + inquire (file=trim(filename(n)),exist=file_exists) + _ASSERT(.not.file_exists,trim(filename(n))//" being created for History output already exists") + end if call list(n)%mGriddedIO%modifyTime(oClients=o_Clients,rc=status) _VERIFY(status) list(n)%currentFile = filename(n) @@ -4046,6 +4078,7 @@ subroutine MAPL_GradsCtlWrite ( clock, state,list,fname,expid,expdsc,output_grid type(ESMF_Grid) :: grid type(ESMF_Time) :: CurrTime type(ESMF_Time) :: StopTime + type(ESMF_Time) :: StartTime type(ESMF_Calendar) :: cal type(ESMF_TimeInterval) :: ti, Frequency integer :: nsteps @@ -4081,9 +4114,10 @@ subroutine MAPL_GradsCtlWrite ( clock, state,list,fname,expid,expdsc,output_grid 'DTDT' , 'PHYSICS' , & 'DTDT' , 'GWD' / - call ESMF_ClockGet ( clock, currTime=CurrTime ,rc=STATUS ) ; _VERIFY(STATUS) - call ESMF_ClockGet ( clock, StopTime=StopTime ,rc=STATUS ) ; _VERIFY(STATUS) - call ESMF_ClockGet ( clock, Calendar=cal ,rc=STATUS ) ; _VERIFY(STATUS) + call ESMF_ClockGet ( clock, currTime=CurrTime, rc=STATUS ) ; _VERIFY(STATUS) + call ESMF_ClockGet ( clock, StopTime=StopTime, rc=STATUS ) ; _VERIFY(STATUS) + call ESMF_ClockGet ( clock, StartTime=StartTime, rc=STATUS ) ; _VERIFY(STATUS) + call ESMF_ClockGet ( clock, Calendar=cal, rc=STATUS ) ; _VERIFY(STATUS) call ESMF_TimeGet ( CurrTime, timeString=TimeString, rc=status ) ; _VERIFY(STATUS) @@ -4095,7 +4129,7 @@ subroutine MAPL_GradsCtlWrite ( clock, state,list,fname,expid,expdsc,output_grid ti = StopTime-CurrTime freq = MAPL_nsecf( list%frequency ) - call ESMF_TimeIntervalSet( Frequency, S=freq, calendar=cal, rc=status ) ; _VERIFY(STATUS) + call ESMF_TimeIntervalSet( Frequency, S=freq, StartTime=StartTime, rc=status ) ; _VERIFY(STATUS) nsteps = ti/Frequency + 1 @@ -5268,7 +5302,7 @@ subroutine MAPL_SetExpression(nfield,fields,tmpfields,rewrite,nPExtraFields, & if (ifound_vloc) then if (ivLoc /= Totloc(i) .and. totloc(i) /= MAPL_VLocationNone) then - _ASSERT(.false.,'arithmetic expression has two different vlocations') + _FAIL('arithmetic expression has two different vlocations') end if else if (totloc(i) /= MAPL_VLocationNone) then @@ -5564,7 +5598,7 @@ subroutine shavebits( state, list, rc) call pFIO_DownBit(ptr3d,ptr3d,list%nbits,undef=MAPL_undef,rc=status) _VERIFY(STATUS) else - _ASSERT(.false. ,'The field rank is not implmented') + _FAIL('The field rank is not implmented') endif enddo diff --git a/gridcomps/History/MAPL_HistoryTrajectoryMod.F90 b/gridcomps/History/MAPL_HistoryTrajectoryMod.F90 index 00812e736fd3..94e0d1c3d3a8 100644 --- a/gridcomps/History/MAPL_HistoryTrajectoryMod.F90 +++ b/gridcomps/History/MAPL_HistoryTrajectoryMod.F90 @@ -596,7 +596,7 @@ subroutine get_file_start_time(this,start_time,time_units,rc) endif endif class default - _ASSERT(.false.,"Time unit must be character") + _FAIL("Time unit must be character") end select call ESMF_TimeSet(start_time,yy=year,mm=month,dd=day,h=hour,m=min,s=sec,rc=status) _VERIFY(status) diff --git a/gridcomps/MAPL_GridComps.F90 b/gridcomps/MAPL_GridComps.F90 index fea600aa200a..daedebb7f624 100644 --- a/gridcomps/MAPL_GridComps.F90 +++ b/gridcomps/MAPL_GridComps.F90 @@ -1,6 +1,7 @@ module MAPL_GridCompsMod use mapl_CapMod use mapl_CapOptionsMod + use mapl_externalGCStorage #ifdef USE_FLAP use mapl_FlapCLIMod #endif diff --git a/griddedio/GriddedIO.F90 b/griddedio/GriddedIO.F90 index ecf61f854630..c4942cbcf933 100644 --- a/griddedio/GriddedIO.F90 +++ b/griddedio/GriddedIO.F90 @@ -24,14 +24,14 @@ module MAPL_GriddedIOMod use MAPL_FileMetadataUtilsMod use, intrinsic :: ISO_C_BINDING use, intrinsic :: iso_fortran_env, only: REAL64 + use ieee_arithmetic, only: isnan => ieee_is_nan implicit none - - private - character(len=20), parameter :: fill_value_label = "GriddedIO_Fill_Value" + private type, public :: MAPL_GriddedIO type(FileMetaData) :: metadata + type(fileMetadataUtils), pointer :: current_file_metadata integer :: write_collection_id integer :: read_collection_id integer :: metadata_collection_id @@ -65,6 +65,7 @@ module MAPL_GriddedIOMod procedure :: regridVector procedure :: set_param procedure :: set_default_chunking + procedure :: check_chunking procedure :: alphabatize_variables procedure :: request_data_from_file procedure :: process_data_from_file @@ -91,7 +92,7 @@ function new_MAPL_GriddedIO(metadata,input_bundle,output_bundle,write_collection type(GriddedIOitemVector), intent(in), optional :: items integer, intent(out), optional :: rc - if (present(metadata)) GriddedIO%metadata=metadata + if (present(metadata)) GriddedIO%metadata=metadata if (present(input_bundle)) GriddedIO%input_bundle=input_bundle if (present(output_bundle)) GriddedIO%output_bundle=output_bundle if (present(regrid_method)) GriddedIO%regrid_method=regrid_method @@ -172,15 +173,17 @@ subroutine CreateFileMetaData(this,items,bundle,timeInfo,vdata,ogrid,global_attr if (.not.allocated(this%chunking)) then call this%set_default_chunking(rc=status) _VERIFY(status) + else + call this%check_chunking(this%vdata%lm,_RC) end if order = this%metadata%get_order(rc=status) _VERIFY(status) metadataVarsSize = order%size() - + do while (iter /= this%items%end()) item => iter%get() - if (item%itemType == ItemTypeScalar) then + if (item%itemType == ItemTypeScalar) then call this%CreateVariable(item%xname,rc=status) _VERIFY(status) else if (item%itemType == ItemTypeVector) then @@ -191,7 +194,7 @@ subroutine CreateFileMetaData(this,items,bundle,timeInfo,vdata,ogrid,global_attr end if call iter%next() enddo - + if (this%itemOrderAlphabetical) then call this%alphabatize_variables(metadataVarsSize,rc=status) _VERIFY(status) @@ -200,12 +203,13 @@ subroutine CreateFileMetaData(this,items,bundle,timeInfo,vdata,ogrid,global_attr if (present(global_attributes)) then s_iter = global_attributes%begin() do while(s_iter /= global_attributes%end()) - attr_name => s_iter%key() + attr_name => s_iter%key() attr_val => s_iter%value() - call this%metadata%add_attribute(attr_name,attr_val,_RC) + call this%metadata%add_attribute(attr_name,attr_val,_RC) call s_iter%next() enddo end if + _RETURN(_SUCCESS) end subroutine CreateFileMetaData @@ -261,12 +265,53 @@ subroutine set_default_chunking(this,rc) end subroutine set_default_chunking + subroutine check_chunking(this,lev_size,rc) + class (MAPL_GriddedIO), intent(inout) :: this + integer, intent(in) :: lev_size + integer, optional, intent(out) :: rc + + integer :: global_dim(3) + integer :: status + character(len=5) :: c1,c2 + + call MAPL_GridGet(this%output_grid,globalCellCountPerDim=global_dim,rc=status) + _VERIFY(status) + if (global_dim(1)*6 == global_dim(2)) then + write(c2,'(I5)')global_dim(1) + write(c1,'(I5)')this%chunking(1) + _ASSERT(this%chunking(1) <= global_dim(1), "Chunk for Xdim "//c1//" must be less than or equal to "//c2) + write(c1,'(I5)')this%chunking(2) + _ASSERT(this%chunking(2) <= global_dim(1), "Chunk for Ydim "//c1//" must be less than or equal to "//c2) + _ASSERT(this%chunking(3) <= 6, "Chunksize for face dimension must be 6 or less") + if (lev_size > 0) then + write(c2,'(I5)')lev_size + write(c1,'(I5)')this%chunking(4) + _ASSERT(this%chunking(4) <= lev_size, "Chunk for level size "//c1//" must be less than or equal to "//c2) + end if + _ASSERT(this%chunking(5) == 1, "Time must have chunk size of 1") + else + write(c2,'(I5)')global_dim(1) + write(c1,'(I5)')this%chunking(1) + _ASSERT(this%chunking(1) <= global_dim(1), "Chunk for lon "//c1//" must be less than or equal to "//c2) + write(c2,'(I5)')global_dim(2) + write(c1,'(I5)')this%chunking(2) + _ASSERT(this%chunking(2) <= global_dim(2), "Chunk for lat "//c1//" must be less than or equal to "//c2) + if (lev_size > 0) then + write(c2,'(I5)')lev_size + write(c1,'(I5)')this%chunking(3) + _ASSERT(this%chunking(3) <= lev_size, "Chunk for level size "//c1//" must be less than or equal to "//c2) + end if + _ASSERT(this%chunking(4) == 1, "Time must have chunk size of 1") + endif + _RETURN(ESMF_SUCCESS) + + end subroutine check_chunking subroutine CreateVariable(this,itemName,rc) class (MAPL_GriddedIO), intent(inout) :: this character(len=*), intent(in) :: itemName integer, optional, intent(out) :: rc - + integer :: status type(ESMF_Field) :: field,newField @@ -308,8 +353,8 @@ subroutine CreateVariable(this,itemName,rc) vdims=grid_dims//",time" else if (fieldRank==3) then vdims=grid_dims//",lev,time" - else - _ASSERT(.false., 'Unsupported field rank') + else + _FAIL( 'Unsupported field rank') end if v = Variable(type=PFIO_REAL32,dimensions=vdims,chunksizes=this%chunking,deflation=this%deflateLevel) call v%add_attribute('units',trim(units)) @@ -323,6 +368,7 @@ subroutine CreateVariable(this,itemName,rc) call v%add_attribute('add_offset',0.0) call v%add_attribute('_FillValue',MAPL_UNDEF) call v%add_attribute('valid_range',(/-MAPL_UNDEF,MAPL_UNDEF/)) + call v%add_attribute('regrid_method', translate_regrid_method(this%regrid_method)) call factory%append_variable_metadata(v) call this%metadata%add_variable(trim(varName),v,rc=status) _VERIFY(status) @@ -331,20 +377,22 @@ subroutine CreateVariable(this,itemName,rc) newField = MAPL_FieldCreate(field,this%output_grid,lm=this%vData%lm,rc=status) _VERIFY(status) call MAPL_FieldBundleAdd(this%output_bundle,newField,rc=status) + _VERIFY(status) else newField = MAPL_FieldCreate(field,this%output_grid,rc=status) _VERIFY(status) call MAPL_FieldBundleAdd(this%output_bundle,newField,rc=status) + _VERIFY(status) end if - + _RETURN(_SUCCESS) end subroutine CreateVariable - subroutine modifyTime(this, oClients, rc) + subroutine modifyTime(this, oClients, rc) class(MAPL_GriddedIO), intent(inout) :: this type (ClientManager), optional, intent(inout) :: oClients integer, optional, intent(out) :: rc - + type(Variable) :: v type(StringVariableMap) :: var_map integer :: status @@ -362,11 +410,11 @@ subroutine modifyTime(this, oClients, rc) end subroutine modifyTime - subroutine modifyTimeIncrement(this, frequency, rc) + subroutine modifyTimeIncrement(this, frequency, rc) class(MAPL_GriddedIO), intent(inout) :: this integer, intent(in) :: frequency integer, optional, intent(out) :: rc - + integer :: status call this%timeInfo%setFrequency(frequency, rc=status) @@ -393,11 +441,11 @@ subroutine bundlepost(this,filename,oClients,rc) this%times = this%timeInfo%compute_time_vector(this%metadata,rc=status) _VERIFY(status) ref = ArrayReference(this%times) - call oClients%stage_nondistributed_data(this%write_collection_id,trim(filename),'time',ref) + call oClients%stage_nondistributed_data(this%write_collection_id,trim(filename),'time',ref) tindex = size(this%times) if (tindex==1) then - call this%stage2DLatLon(filename,oClients=oClients,rc=status) + call this%stage2DLatLon(filename,oClients=oClients,_RC) end if if (this%vdata%regrid_type==VERTICAL_METHOD_ETA2LEV) then @@ -539,7 +587,7 @@ subroutine RegridScalar(this,itemName,rc) call MAPL_FieldGetPointer(OutField,outptr3d,rc=status) _VERIFY(status) else - allocate(outptr3d(0,0,0)) + allocate(outptr3d(0,0,0)) end if if (gridIn==gridOut) then outPtr3d=Ptr3d @@ -549,10 +597,11 @@ subroutine RegridScalar(this,itemName,rc) _VERIFY(status) end if else - _ASSERT(.false.,'rank not supported') + _FAIL('rank not supported') end if if (allocated(ptr3d_inter)) deallocate(ptr3d_inter) + _RETURN(_SUCCESS) end subroutine RegridScalar @@ -719,6 +768,7 @@ subroutine RegridVector(this,xName,yName,rc) if (allocated(xptr3d_inter)) deallocate(xptr3d_inter) if (allocated(yptr3d_inter)) deallocate(yptr3d_inter) + _RETURN(_SUCCESS) end subroutine RegridVector @@ -735,10 +785,10 @@ subroutine stage2DLatLon(this, fileName, oClients, rc) integer, allocatable :: localStart(:),globalStart(:),globalCount(:) logical :: hasll class(Variable), pointer :: var_lat,var_lon - + var_lon => this%metadata%get_variable('lons') var_lat => this%metadata%get_variable('lats') - + hasll = associated(var_lon) .and. associated(var_lat) if (hasll) then factory => get_factory(this%output_grid,rc=status) @@ -768,7 +818,7 @@ subroutine stage2DLatLon(this, fileName, oClients, rc) var_lon => this%metadata%get_variable('corner_lons') var_lat => this%metadata%get_variable('corner_lats') - + hasll = associated(var_lon) .and. associated(var_lat) if (hasll) then factory => get_factory(this%output_grid,rc=status) @@ -794,11 +844,11 @@ subroutine stage2DLatLon(this, fileName, oClients, rc) call oClients%collective_stage_data(this%write_collection_id,trim(filename),'corner_lats', & ref,start=localStart, global_start=GlobalStart, global_count=GlobalCount) end if - + _RETURN(_SUCCESS) end subroutine stage2DLatLon - - subroutine stageData(this, field, fileName, tIndex, oClients, rc) + + subroutine stageData(this, field, fileName, tIndex, oClients, rc) class (MAPL_GriddedIO), intent(inout) :: this type(ESMF_Field), intent(inout) :: field character(len=*), intent(in) :: fileName @@ -859,10 +909,11 @@ subroutine stageData(this, field, fileName, tIndex, oClients, rc) allocate(globalStart,source=[gridGlobalStart,1,tindex]) allocate(globalCount,source=[gridGlobalCount,lm,1]) else - _ASSERT(.false., "Rank not supported") + _FAIL( "Rank not supported") end if call oClients%collective_stage_data(this%write_collection_id,trim(filename),trim(fieldName), & ref,start=localStart, global_start=GlobalStart, global_count=GlobalCount) + _RETURN(_SUCCESS) end subroutine stageData @@ -870,7 +921,7 @@ subroutine alphabatize_variables(this,nfixedVars,rc) class (MAPL_GriddedIO), intent(inout) :: this integer, intent(in) :: nFixedVars integer, optional, intent(out) :: rc - + type(StringVector) :: order type(StringVector) :: newOrder character(len=:), pointer :: v1 @@ -888,7 +939,7 @@ subroutine alphabatize_variables(this,nfixedVars,rc) v1 => order%at(i) if ( i > nFixedVars) temp(i)=trim(v1) enddo - + swapped = .true. do while(swapped) swapped = .false. @@ -915,7 +966,7 @@ subroutine alphabatize_variables(this,nfixedVars,rc) deallocate(temp) _RETURN(_SUCCESS) - + end subroutine alphabatize_variables subroutine request_data_from_file(this,filename,timeindex,rc) @@ -940,12 +991,10 @@ subroutine request_data_from_file(this,filename,timeindex,rc) type(ESMF_Grid) :: output_grid logical :: hasDE class(AbstractGridFactory), pointer :: factory - type(fileMetadataUtils), pointer :: metadata real(REAL32) :: missing_value collection => Datacollections%at(this%metadata_collection_id) - metadata => collection%find(filename, __RC__) - + this%current_file_metadata => collection%find(filename, __RC__) filegrid = collection%src_grid factory => get_factory(filegrid) hasDE=MAPL_GridHasDE(filegrid,rc=status) @@ -958,7 +1007,7 @@ subroutine request_data_from_file(this,filename,timeindex,rc) end if call MAPL_GridGet(filegrid,globalCellCountPerdim=dims,rc=status) _VERIFY(status) - call factory%generate_file_bounds(fileGrid,gridLocalStart,gridGlobalStart,gridGlobalCount,metadata=metadata%fileMetadata,rc=status) + call factory%generate_file_bounds(fileGrid,gridLocalStart,gridGlobalStart,gridGlobalCount,metadata=this%current_file_metadata%fileMetadata,rc=status) _VERIFY(status) ! create input bundle call ESMF_FieldBundleGet(this%output_bundle,fieldCount=numVars,rc=status) @@ -974,10 +1023,6 @@ subroutine request_data_from_file(this,filename,timeindex,rc) _VERIFY(status) call ESMF_FieldGet(output_field,rank=rank,rc=status) _VERIFY(status) - missing_value = MAPL_UNDEF - if (metadata%var_has_missing_value(trim(names(i)))) then - missing_value = metadata%var_get_missing_value(trim(names(i)),_RC) - end if if (rank==2) then input_fields(i) = ESMF_FieldCreate(filegrid,typekind=ESMF_TYPEKIND_R4,gridToFieldMap=[1,2],name=trim(names(i)),rc=status) _VERIFY(status) @@ -1006,18 +1051,15 @@ subroutine request_data_from_file(this,filename,timeindex,rc) allocate(ptr3d(0,0,0),stat=status) _VERIFY(status) end if - ref=factory%generate_file_reference3D(ptr3d,metadata=metadata%filemetadata) + ref=factory%generate_file_reference3D(ptr3d,metadata=this%current_file_metadata%filemetadata) allocate(localStart,source=[gridLocalStart,1,timeIndex]) allocate(globalStart,source=[gridGlobalStart,1,timeIndex]) - allocate(globalCount,source=[gridGlobalCount,lm,1]) + allocate(globalCount,source=[gridGlobalCount,lm,1]) end if call i_Clients%collective_prefetch_data( & this%read_collection_id, fileName, trim(names(i)), & & ref, start=localStart, global_start=globalStart, global_count=globalCount) deallocate(localStart,globalStart,globalCount) - if (missing_value /= MAPL_UNDEF) then - call ESMF_AttributeSet(input_fields(i),name=fill_value_label,value=missing_value,_RC) - end if enddo deallocate(gridLocalStart,gridGlobalStart,gridGlobalCount) this%input_bundle = ESMF_FieldBundleCreate(fieldList=input_fields,rc=status) @@ -1030,7 +1072,7 @@ subroutine process_data_from_file(this,rc) class(mapl_GriddedIO), intent(inout) :: this integer, intent(out), optional :: rc - integer :: status + integer :: status integer :: i,numVars character(len=ESMF_MAXSTR), allocatable :: names(:) type(ESMF_Field) :: field @@ -1083,38 +1125,50 @@ subroutine swap_undef_value(this,fname,rc) real, pointer :: ptr3d(:,:,:) real, pointer :: ptr2d(:,:) type(ESMF_Grid) :: gridIn - logical :: hasDE_in,has_custom_fill_val + logical :: hasDE_in real(REAL32) :: fill_value - call ESMF_FieldBundleGet(this%input_bundle,fname,field=field,_RC) - call ESMF_AttributeGet(field,name=fill_value_label,isPresent=has_custom_fill_val,_RC) + if ( .not. this%current_file_metadata%var_has_missing_value(fname) ) then + _RETURN(_SUCCESS) + endif - if (has_custom_fill_val) then + fill_value = this%current_file_metadata%var_get_missing_value(fname,_RC) - call ESMF_AttributeGet(field,name=fill_value_label,value=fill_value,_RC) - call ESMF_FieldGet(field,rank=fieldRank,_RC) - _VERIFY(status) - call ESMF_FieldBundleGet(this%input_bundle,grid=gridIn,_RC) - hasDE_in = MAPL_GridHasDE(gridIn,_RC) + call ESMF_FieldBundleGet(this%input_bundle,fname,field=field,_RC) + call ESMF_FieldBundleGet(this%input_bundle,grid=gridIn,_RC) + call ESMF_FieldGet(field,rank=fieldRank,_RC) + hasDE_in = MAPL_GridHasDE(gridIn,_RC) - if (fieldRank==2) then - if (hasDE_in) then - call MAPL_FieldGetPointer(field,ptr2d,_RC) - else - allocate(ptr2d(0,0)) - end if + if (fieldRank==2) then + if (hasDE_in) then + call MAPL_FieldGetPointer(field,ptr2d,_RC) + else + allocate(ptr2d(0,0)) + end if + + if (isnan(fill_value)) then + where(isnan(ptr2d)) ptr2d=MAPL_UNDEF + else where(ptr2d==fill_value) ptr2d=MAPL_UNDEF - else if (fieldRank==3) then - if (hasDE_in) then - call ESMF_FieldGet(field,farrayPtr=ptr3d,_RC) - else - allocate(ptr3d(0,0,0)) - end if - where(ptr3d==fill_value) ptr3d=MAPL_UNDEF + endif + + else if (fieldRank==3) then + if (hasDE_in) then + call ESMF_FieldGet(field,farrayPtr=ptr3d,_RC) else - _ASSERT(.false.,'rank not supported') + allocate(ptr3d(0,0,0)) end if + + if (isnan(fill_value)) then + where(isnan(ptr3d)) ptr3d=MAPL_UNDEF + else + where(ptr3d==fill_value) ptr3d=MAPL_UNDEF + endif + + else + _FAIL('rank not supported') end if + _RETURN(_SUCCESS) end subroutine swap_undef_value diff --git a/griddedio/Regrid_Util.F90 b/griddedio/Regrid_Util.F90 index f5affdc4d7d2..574aa15058ba 100644 --- a/griddedio/Regrid_Util.F90 +++ b/griddedio/Regrid_Util.F90 @@ -182,23 +182,8 @@ subroutine process_command_line(this,rc) end select enddo - if (trim(regridMth) .ne. 'bilinear' .and. trim(regridMth ) .ne. 'conservative' .and. trim(regridMth ) .ne. 'conservative2' .and. & - trim(regridMth).ne.'patch') then - if (MAPL_AM_I_Root()) write(*,*)'invalid regrid method choose bilinear or conservative' - _ASSERT(.false.,'needs informative message') - end if - if (trim(regridMth) == 'bilinear') then - this%regridMethod = REGRID_METHOD_BILINEAR - end if - if (trim(regridMth) == 'patch') then - this%regridMethod = REGRID_METHOD_PATCH - end if - if (trim(regridMth) == 'conservative') then - this%regridMethod = REGRID_METHOD_CONSERVE - end if - if (trim(regridMth) == 'conservative2') then - this%regridMethod = REGRID_METHOD_CONSERVE_2ND - end if + this%regridMethod = get_regrid_method(regridMth) + _ASSERT(this%regridMethod/=UNSPECIFIED_REGRID_METHOD,"improper regrid method chosen") this%filenames = split_string(cfilenames,',') this%outputfiles = split_string(coutputfiles,',') diff --git a/include/MAPL_ErrLog.h b/include/MAPL_ErrLog.h index 36e8bb9a69fe..6c5dacb8a597 100644 --- a/include/MAPL_ErrLog.h +++ b/include/MAPL_ErrLog.h @@ -2,7 +2,7 @@ ! The error logging may eventually evolve into a module based ! on the ESMF logger. For now these macros provide simple -! traceback capability. +! traceback capability. #ifndef MAPL_ErrLog_DONE @@ -44,6 +44,12 @@ # ifdef _RC # undef _RC # endif +# ifdef _STAT +# undef _STAT +# endif +# ifdef _IOSTAT +# undef _IOSTAT +# endif # ifdef __return # undef __return # endif @@ -55,7 +61,7 @@ # ifdef I_AM_MAIN # define __return call MAPL_abort() -# define __rc(rc) +# define __rc(rc) # else # define __return return # define __rc(rc) ,rc @@ -92,6 +98,8 @@ # define _RC_(rc,status) rc=status);_VERIFY(status # define _RC _RC_(rc,status) +# define _STAT _RC_(stat,status) +# define _IOSTAT _RC_(iostat,status) # define _ASSERT_MSG_AND_LOC_AND_RC(A,msg,stat,file,line,rc) if(MAPL_Assert(A,msg,stat,file,line __rc(rc))) __return diff --git a/pfio/AbstractDataReference.F90 b/pfio/AbstractDataReference.F90 index bfe9704b1f34..2a31225eb722 100644 --- a/pfio/AbstractDataReference.F90 +++ b/pfio/AbstractDataReference.F90 @@ -140,7 +140,7 @@ subroutine fetch_data(this,offset_address,global_shape,offset_start, rc) full_rank = size(global_shape) if(size(this%shape) > full_rank) then - _ASSERT(.false.,"ranks do not agree (probably fixable)") + _FAIL("ranks do not agree (probably fixable)") endif allocate(count(full_rank)) @@ -176,7 +176,7 @@ subroutine fetch_data(this,offset_address,global_shape,offset_start, rc) call c_f_pointer(offset_address, all_real64_0d) values_real64_0d=all_real64_0d case default - _ASSERT(.false.,"type not supported yet") + _FAIL("type not supported yet") end select case(1) s1=start(1) @@ -199,7 +199,7 @@ subroutine fetch_data(this,offset_address,global_shape,offset_start, rc) call c_f_pointer(offset_address, all_real64_1d, global_shape) values_real64_1d=all_real64_1d(s1:e1) case default - _ASSERT(.false.,"type not supported yet") + _FAIL("type not supported yet") end select case(2) s1=start(1) @@ -224,7 +224,7 @@ subroutine fetch_data(this,offset_address,global_shape,offset_start, rc) call c_f_pointer(offset_address, all_real64_2d, global_shape) values_real64_2d=all_real64_2d(s1:e1,s2:e2) case default - _ASSERT(.false.,"type not supported yet") + _FAIL("type not supported yet") end select case (3) s1=start(1) @@ -251,7 +251,7 @@ subroutine fetch_data(this,offset_address,global_shape,offset_start, rc) call c_f_pointer(offset_address, all_real64_3d, global_shape) values_real64_3d=all_real64_3d(s1:e1,s2:e2,s3:e3) case default - _ASSERT(.false.,"type not supported yet") + _FAIL("type not supported yet") end select case (4) s1=start(1) @@ -280,7 +280,7 @@ subroutine fetch_data(this,offset_address,global_shape,offset_start, rc) call c_f_pointer(offset_address, all_real64_4d, global_shape) values_real64_4d=all_real64_4d(s1:e1,s2:e2,s3:e3,s4:e4) case default - _ASSERT(.false.,"type not supported yet") + _FAIL("type not supported yet") end select case (5) @@ -312,11 +312,11 @@ subroutine fetch_data(this,offset_address,global_shape,offset_start, rc) call c_f_pointer(offset_address, all_real64_5d, global_shape) values_real64_5d=all_real64_5d(s1:e1,s2:e2,s3:e3,s4:e4,s5:e5) case default - _ASSERT(.false.,"type not supported yet") + _FAIL("type not supported yet") end select case default - _ASSERT(.false.,"dimension not supported yet") + _FAIL("dimension not supported yet") end select end subroutine fetch_data diff --git a/pfio/AbstractServer.F90 b/pfio/AbstractServer.F90 index 3793a237309f..232a145d1aa8 100644 --- a/pfio/AbstractServer.F90 +++ b/pfio/AbstractServer.F90 @@ -315,20 +315,20 @@ subroutine receive_output_data(this, rc) class (AbstractServer),target, intent(inout) :: this integer, optional, intent(out) :: rc - _ASSERT(.false.," no action of receive_output_data") + _FAIL(" no action of receive_output_data") end subroutine receive_output_data subroutine put_DataToFile(this, rc) class (AbstractServer),target, intent(inout) :: this integer, optional, intent(out) :: rc - _ASSERT(.false.," no action of server_put_DataToFile") + _FAIL(" no action of server_put_DataToFile") end subroutine put_DataToFile subroutine get_DataFromMem(this,multi, rc) class (AbstractServer),target, intent(inout) :: this logical, intent(in) :: multi integer, optional, intent(out) :: rc - _ASSERT(.false.," no action of server_get_DataFromMem") + _FAIL(" no action of server_get_DataFromMem") _UNUSED_DUMMY(multi) end subroutine get_DataFromMem @@ -434,12 +434,12 @@ subroutine report_profile(this, rc ) reporter = ProfileReporter(empty) call reporter%add_column(NameColumn(20)) - call reporter%add_column(FormattedTextColumn('Inclusive','(f9.2)', 9, InclusiveColumn('MEAN'))) + call reporter%add_column(FormattedTextColumn('Inclusive','(f10.2)', 10, InclusiveColumn('MEAN'))) call reporter%add_column(FormattedTextColumn('% Incl','(f6.2)', 6, PercentageColumn(InclusiveColumn('MEAN'),'MAX'))) - call reporter%add_column(FormattedTextColumn('Exclusive','(f9.2)', 9, ExclusiveColumn('MEAN'))) + call reporter%add_column(FormattedTextColumn('Exclusive','(f10.2)', 10, ExclusiveColumn('MEAN'))) call reporter%add_column(FormattedTextColumn('% Excl','(f6.2)', 6, PercentageColumn(ExclusiveColumn('MEAN')))) - call reporter%add_column(FormattedTextColumn(' Max Excl)','(f9.2)', 9, ExclusiveColumn('MAX'))) - call reporter%add_column(FormattedTextColumn(' Min Excl)','(f9.2)', 9, ExclusiveColumn('MIN'))) + call reporter%add_column(FormattedTextColumn(' Max Excl)','(f10.2)', 10, ExclusiveColumn('MAX'))) + call reporter%add_column(FormattedTextColumn(' Min Excl)','(f10.2)', 10, ExclusiveColumn('MIN'))) call reporter%add_column(FormattedTextColumn('Max PE)','(1x,i4.4,1x)', 6, ExclusiveColumn('MAX_PE'))) call reporter%add_column(FormattedTextColumn('Min PE)','(1x,i4.4,1x)', 6, ExclusiveColumn('MIN_PE'))) report_lines = reporter%generate_report(ioserver_profiler) diff --git a/pfio/AddHistCollectionMessage.F90 b/pfio/AddHistCollectionMessage.F90 index 1511958c2862..d4f813ac4465 100644 --- a/pfio/AddHistCollectionMessage.F90 +++ b/pfio/AddHistCollectionMessage.F90 @@ -6,6 +6,7 @@ module pFIO_AddHistCollectionMessageMod use pFIO_UtilitiesMod use pFIO_AbstractMessageMod use pFIO_FileMetadataMod + use pFIO_ConstantsMod implicit none private @@ -13,9 +14,7 @@ module pFIO_AddHistCollectionMessageMod type, extends(AbstractMessage) :: AddHistCollectionMessage type(FileMetadata) :: fmd - ! WY node: -1 : add ( default ) - ! other : replace - integer :: collection_id = -1 + integer :: create_mode contains procedure, nopass :: get_type_id procedure :: get_length @@ -29,12 +28,13 @@ module pFIO_AddHistCollectionMessageMod contains - function new_AddHistCollectionMessage(fmd, collection_id) result(message) + function new_AddHistCollectionMessage(fmd, mode) result(message) type (AddHistCollectionMessage) :: message type(FileMetadata), intent(in) :: fmd - integer, optional, intent(in) :: collection_id + integer, optional, intent(in) :: mode message%fmd = fmd - if( present(collection_id)) message%collection_id = collection_id + message%create_mode = PFIO_NOCLOBBER + if( present(mode)) message%create_mode = mode end function new_AddHistCollectionMessage @@ -47,7 +47,7 @@ integer function get_length(this) result(length) class (AddHistCollectionMessage), intent(in) :: this integer,allocatable :: buffer(:) ! no-op call this%fmd%serialize(buffer) - length = size(buffer) + 1 ! 1 is the collection_id + length = size(buffer) + 1 ! 1 is the create_mode end function get_length @@ -60,7 +60,7 @@ subroutine serialize(this, buffer, rc) integer :: status call this%fmd%serialize(tmp_buffer, status) _VERIFY(status) - buffer = [tmp_buffer,serialize_intrinsic(this%collection_id)] + buffer = [tmp_buffer,serialize_intrinsic(this%create_mode)] _RETURN(_SUCCESS) end subroutine serialize @@ -76,7 +76,7 @@ subroutine deserialize(this, buffer,rc) _VERIFY(status) call deserialize_intrinsic(buffer(n:), length) n = n + length - call deserialize_intrinsic(buffer(n:), this%collection_id) + call deserialize_intrinsic(buffer(n:), this%create_mode) _RETURN(_SUCCESS) end subroutine deserialize diff --git a/pfio/ArrayReference.F90 b/pfio/ArrayReference.F90 index 716faaa5cd80..c821a7ee6d3b 100644 --- a/pfio/ArrayReference.F90 +++ b/pfio/ArrayReference.F90 @@ -55,7 +55,7 @@ function new_ArrayReference_0d(scalar, rc) result(reference) type is (integer(kind=INT64)) reference%base_address = c_loc(scalar) class default - _ASSERT(.false., "ArrayRef does not support this type") + _FAIL( "ArrayRef does not support this type") end select reference%shape = shape(scalar) reference%type_kind = type_kind(scalar) @@ -81,7 +81,7 @@ function new_ArrayReference_1d(array, rc) result(reference) reference%base_address = c_loc(array) reference%type_kind = pFIO_INT64 class default - _ASSERT(.false., "ArrayRef does not support this type") + _FAIL( "ArrayRef does not support this type") end select reference%shape = shape(array) @@ -108,7 +108,7 @@ function new_ArrayReference_2d(array, rc) result(reference) reference%base_address = c_loc(array) reference%type_kind = pFIO_INT64 class default - _ASSERT(.false., "ArrayRef does not support this type") + _FAIL( "ArrayRef does not support this type") end select reference%shape = shape(array) @@ -135,7 +135,7 @@ function new_ArrayReference_3d(array, rc) result(reference) reference%base_address = c_loc(array) reference%type_kind = pFIO_INT64 class default - _ASSERT(.false., "ArrayRef does not support this type") + _FAIL( "ArrayRef does not support this type") end select reference%shape = shape(array) @@ -163,7 +163,7 @@ function new_ArrayReference_4d(array, rc) result(reference) reference%base_address = c_loc(array) reference%type_kind = pFIO_INT64 class default - _ASSERT(.false., "ArrayRef does not support this type") + _FAIL( "ArrayRef does not support this type") end select reference%shape = shape(array) @@ -190,7 +190,7 @@ function new_ArrayReference_5d(array, rc) result(reference) reference%base_address = c_loc(array) reference%type_kind = pFIO_INT64 class default - _ASSERT(.false., "ArrayRef does not support this type") + _FAIL( "ArrayRef does not support this type") end select reference%shape = shape(array) @@ -213,7 +213,7 @@ integer function type_kind(element, rc) type is (real(kind=REAL64)) type_kind = pFIO_REAL64 class default - _ASSERT(.false.,'kind error') + _FAIL('kind error') end select _RETURN(_SUCCESS) end function type_kind diff --git a/pfio/BaseServer.F90 b/pfio/BaseServer.F90 index 472df508f2f5..4ec1c741859b 100644 --- a/pfio/BaseServer.F90 +++ b/pfio/BaseServer.F90 @@ -125,7 +125,7 @@ subroutine put_DataToFile(this, rc) type is (RDMAReference) remotePtr=>dataRefPtr class default - _ASSERT(.false., "remote is a must") + _FAIL( "remote is a must") end select request_iter = this%stage_offset%find(i_to_string(q%request_id)//'done') @@ -219,7 +219,7 @@ function get_dmessage(this, rc) result(dmessage) type is (MpiSocket) allocate(dmessage,source = DummyMessage()) class default - _ASSERT(.false., "wrong socket type") + _FAIL( "wrong socket type") end select _RETURN(_SUCCESS) diff --git a/pfio/CMakeLists.txt b/pfio/CMakeLists.txt index 86bb25c70aee..335620f4f11a 100644 --- a/pfio/CMakeLists.txt +++ b/pfio/CMakeLists.txt @@ -91,7 +91,9 @@ set (srcs StringVectorUtil.F90 ) +# Exclude NetCDF_C dependency since only needed for demos which are not used in GCHP esma_add_library (${this} SRCS ${srcs} DEPENDENCIES MAPL.shared MAPL.profiler NetCDF::NetCDF_Fortran TYPE ${MAPL_LIBRARY_TYPE}) +#esma_add_library (${this} SRCS ${srcs} DEPENDENCIES MAPL.shared MAPL.profiler NetCDF::NetCDF_Fortran NetCDF::NetCDF_C TYPE ${MAPL_LIBRARY_TYPE}) target_link_libraries (${this} PUBLIC GFTL_SHARED::gftl-shared PRIVATE MPI::MPI_Fortran) # CMake has an OpenMP issue with NAG Fortran: https://gitlab.kitware.com/cmake/cmake/-/issues/21280 if (NOT CMAKE_Fortran_COMPILER_ID MATCHES "NAG") @@ -114,33 +116,34 @@ ecbuild_add_executable ( LIBS ${this} ) set_target_properties (pfio_open_close.x PROPERTIES Fortran_MODULE_DIRECTORY ${include_${this}}) -ecbuild_add_executable ( - TARGET pfio_server_demo.x - SOURCES pfio_server_demo.F90 - LIBS ${this} ${NETCDF_LIBRARIES} $<$:OpenMP::OpenMP_Fortran> MPI::MPI_Fortran) - #LIBS ${this} MPI::MPI_Fortran) -set_target_properties (pfio_server_demo.x PROPERTIES Fortran_MODULE_DIRECTORY ${include_${this}}) -# CMake has an OpenMP issue with NAG Fortran: https://gitlab.kitware.com/cmake/cmake/-/issues/21280 -if (NOT CMAKE_Fortran_COMPILER_ID MATCHES "NAG") - target_link_libraries(pfio_server_demo.x OpenMP::OpenMP_Fortran) -endif () - -ecbuild_add_executable ( - TARGET pfio_collective_demo.x - SOURCES pfio_collective_demo.F90 - LIBS ${this} ${NETCDF_LIBRARIES} $<$:OpenMP::OpenMP_Fortran> MPI::MPI_Fortran) -set_target_properties (pfio_collective_demo.x PROPERTIES Fortran_MODULE_DIRECTORY ${include_${this}}) -# CMake has an OpenMP issue with NAG Fortran: https://gitlab.kitware.com/cmake/cmake/-/issues/21280 -if (NOT CMAKE_Fortran_COMPILER_ID MATCHES "NAG") - target_link_libraries(pfio_collective_demo.x OpenMP::OpenMP_Fortran) -endif () +# Do not add demo executables if using GCHP +#ecbuild_add_executable ( +# TARGET pfio_server_demo.x +# SOURCES pfio_server_demo.F90 +# LIBS ${this} ${NETCDF_LIBRARIES} $<$:OpenMP::OpenMP_Fortran> MPI::MPI_Fortran) +# #LIBS ${this} MPI::MPI_Fortran) +#set_target_properties (pfio_server_demo.x PROPERTIES Fortran_MODULE_DIRECTORY ${include_${this}}) +## CMake has an OpenMP issue with NAG Fortran: https://gitlab.kitware.com/cmake/cmake/-/issues/21280 +#if (NOT CMAKE_Fortran_COMPILER_ID MATCHES "NAG") +# target_link_libraries(pfio_server_demo.x OpenMP::OpenMP_Fortran) +#endif () +# +#ecbuild_add_executable ( +# TARGET pfio_collective_demo.x +# SOURCES pfio_collective_demo.F90 +# LIBS ${this} ${NETCDF_LIBRARIES} $<$:OpenMP::OpenMP_Fortran> MPI::MPI_Fortran) +#set_target_properties (pfio_collective_demo.x PROPERTIES Fortran_MODULE_DIRECTORY ${include_${this}}) +## CMake has an OpenMP issue with NAG Fortran: https://gitlab.kitware.com/cmake/cmake/-/issues/21280 +#if (NOT CMAKE_Fortran_COMPILER_ID MATCHES "NAG") +# target_link_libraries(pfio_collective_demo.x OpenMP::OpenMP_Fortran) +#endif () # GCHP note: customize ecbuild_add_executable ( - TARGET pfio_writer.x - SOURCES pfio_writer.F90 - LIBS ${this} ${NETCDF_LIBRARIES} $<$:OpenMP::OpenMP_Fortran> MPI::MPI_Fortran) - #LIBS ${this} NetCDF::NetCDF_Fortran MPI::MPI_Fortran) + TARGET pfio_writer.x + SOURCES pfio_writer.F90 + LIBS ${this} ${NETCDF_LIBRARIES} $<$:OpenMP::OpenMP_Fortran> MPI::MPI_Fortran) + #LIBS ${this} NetCDF::NetCDF_Fortran NetCDF::NetCDF_C MPI::MPI_Fortran) set_target_properties (pfio_writer.x PROPERTIES Fortran_MODULE_DIRECTORY ${include_${this}}) # GCHP note: added next line diff --git a/pfio/ClientManager.F90 b/pfio/ClientManager.F90 index 6439a5ed91d2..fc19ebadb6b6 100644 --- a/pfio/ClientManager.F90 +++ b/pfio/ClientManager.F90 @@ -38,7 +38,6 @@ module pFIO_ClientManagerMod contains procedure :: add_ext_collection procedure :: add_hist_collection - procedure :: replace_hist_collection procedure :: modify_metadata procedure :: modify_metadata_all procedure :: prefetch_data @@ -130,43 +129,25 @@ function add_ext_collection(this, template, unusable, rc) result(collection_id) _UNUSED_DUMMY(unusable) end function add_ext_collection - function add_hist_collection(this, fmd, unusable, rc) result(hist_collection_id) + function add_hist_collection(this, fmd, unusable,mode, rc) result(hist_collection_id) integer :: hist_collection_id class (ClientManager), intent(inout) :: this type(FileMetadata),intent(in) :: fmd class (KeywordEnforcer), optional, intent(out) :: unusable + integer, optional, intent(in) :: mode integer, optional, intent(out) :: rc class (ClientThread), pointer :: clientPtr integer :: i do i = 1, this%size() ClientPtr => this%clients%at(i) - hist_collection_id = clientPtr%add_hist_collection(fmd) + hist_collection_id = clientPtr%add_hist_collection(fmd, mode=mode) enddo _RETURN(_SUCCESS) _UNUSED_DUMMY(unusable) end function add_hist_collection - subroutine replace_hist_collection(this, hist_collection_id, fmd, unusable, rc) - class (ClientManager), intent(inout) :: this - integer, intent(in) :: hist_collection_id - type(FileMetadata),intent(in) :: fmd - class (KeywordEnforcer), optional, intent(out) :: unusable - integer, optional, intent(out) :: rc - - class (ClientThread), pointer :: clientPtr - integer :: i - - do i = 1, this%size() - ClientPtr => this%clients%at(i) - call clientPtr%replace_hist_collection(hist_collection_id, fmd) - enddo - - _RETURN(_SUCCESS) - _UNUSED_DUMMY(unusable) - end subroutine replace_hist_collection - subroutine prefetch_data(this, collection_id, file_name, var_name, data_reference, & & unusable, start, rc) class (ClientManager), intent(inout) :: this diff --git a/pfio/ClientThread.F90 b/pfio/ClientThread.F90 index 1706c66c97ec..0a302bb552e1 100644 --- a/pfio/ClientThread.F90 +++ b/pfio/ClientThread.F90 @@ -56,7 +56,6 @@ module pFIO_ClientThreadMod contains procedure :: add_ext_collection procedure :: add_hist_collection - procedure :: replace_hist_collection procedure :: modify_metadata procedure :: prefetch_data procedure :: stage_data @@ -123,15 +122,17 @@ function add_ext_collection(this, template, rc) result(collection_id) type is(IDMessage) collection_id = message%id class default - _ASSERT(.false., " should get id message") + _FAIL( " should get id message") end select _RETURN(_SUCCESS) end function add_ext_collection - function add_hist_collection(this, fmd, rc) result(hist_collection_id) + function add_hist_collection(this, fmd, unusable, mode, rc) result(hist_collection_id) integer :: hist_collection_id class (ClientThread), intent(inout) :: this type(FileMetadata),intent(in) :: fmd + class (KeywordEnforcer), optional, intent(out) :: unusable + integer, optional, intent(in) :: mode integer, optional, intent(out) :: rc class (AbstractMessage), pointer :: message @@ -139,46 +140,19 @@ function add_hist_collection(this, fmd, rc) result(hist_collection_id) integer :: status connection=>this%get_connection() - call connection%send(AddHistCollectionMessage(fmd)) + call connection%send(AddHistCollectionMessage(fmd, mode=mode)) message => connection%receive() select type(message) type is(IDMessage) hist_collection_id = message%id class default - _ASSERT(.false., " should get id message") + _FAIL( " should get id message") end select _RETURN(_SUCCESS) end function add_hist_collection - subroutine replace_hist_collection(this,hist_collection_id,fmd, rc) - class (ClientThread), intent(inout) :: this - integer, intent(in) :: hist_collection_id - type(FileMetadata),intent(in) :: fmd - integer, optional, intent(out) :: rc - - integer :: return_id - - class (AbstractMessage), pointer :: message - class(AbstractSocket),pointer :: connection - integer :: status - - connection=>this%get_connection() - call connection%send(AddHistCollectionMessage(fmd,hist_collection_id),_RC) - - message => connection%receive() - select type(message) - type is(IDMessage) - return_id = message%id - class default - _ASSERT(.false., " should get id message") - end select - - _ASSERT( return_id == hist_collection_id, "return id should be the same as the collection_id") - _RETURN(_SUCCESS) - end subroutine replace_hist_collection - function prefetch_data(this, collection_id, file_name, var_name, data_reference, & & unusable, start, rc) result(request_id) class (ClientThread), intent(inout) :: this diff --git a/pfio/CoordinateVariable.F90 b/pfio/CoordinateVariable.F90 index e692e4a59f00..9ae8cade769a 100644 --- a/pfio/CoordinateVariable.F90 +++ b/pfio/CoordinateVariable.F90 @@ -119,7 +119,7 @@ subroutine get_real32(this, coordinate_data, unusable, rc) type is (real(kind=REAL32)) coordinate_data => q class default ! wrong type - _ASSERT(.false., "wrong type") + _FAIL( "wrong type") end select _RETURN(_SUCCESS) @@ -138,7 +138,7 @@ subroutine get_real64(this, coordinate_data, unusable, rc) type is (real(kind=REAL64)) coordinate_data => q class default ! wrong type - _ASSERT(.false., 'wrong type') + _FAIL( 'wrong type') end select _RETURN(_SUCCESS) @@ -156,7 +156,7 @@ subroutine get_int32(this, coordinate_data, unusable, rc) type is (integer(kind=INT32)) coordinate_data => q class default ! wrong type - _ASSERT(.false., 'wrong type') + _FAIL( 'wrong type') end select _RETURN(_SUCCESS) @@ -174,7 +174,7 @@ subroutine get_int64(this, coordinate_data, unusable, rc) type is (integer(kind=INT64)) coordinate_data => q class default ! wrong type - _ASSERT(.false., 'wrong type') + _FAIL( 'wrong type') end select _RETURN(_SUCCESS) @@ -209,7 +209,7 @@ subroutine serialize(this, buffer, rc) type_kind = pFIO_REAL64 buffer =[tmp_buffer, serialize_intrinsic(type_kind),serialize_intrinsic(coord)] class default - _ASSERT(.false.,"not support coord type") + _FAIL("not support coord type") end select length = serialize_buffer_length(length)+ serialize_buffer_length(Coord_SERIALIZE_TYPE) + size(buffer) buffer = [serialize_intrinsic(length), serialize_intrinsic(Coord_SERIALIZE_TYPE), buffer] @@ -273,7 +273,7 @@ subroutine deserialize(this, buffer, rc) call deserialize_intrinsic(buffer(n:),values_REAL64) allocate(this%coordinate_data, source = values_real64) case default - _ASSERT(.false., "not supportted type") + _FAIL( "not supportted type") end select _RETURN(_SUCCESS) end subroutine deserialize diff --git a/pfio/FileMetadata.F90 b/pfio/FileMetadata.F90 index 7db3a79ab68c..c2cc01873782 100644 --- a/pfio/FileMetadata.F90 +++ b/pfio/FileMetadata.F90 @@ -26,12 +26,13 @@ module pFIO_FileMetadataMod type :: FileMetadata private type (StringIntegerMap) :: dimensions - type (Variable) :: global + type (Variable) :: global_var type (StringVariableMap) :: variables type (StringVector) :: order contains procedure :: get_dimensions + procedure :: get_global_var procedure :: add_dimension procedure :: get_dimension procedure :: modify_dimension @@ -51,6 +52,7 @@ module pFIO_FileMetadataMod procedure :: set_order procedure :: modify_variable procedure :: has_dimension + procedure :: has_variable generic :: operator(==) => equal generic :: operator(/=) => not_equal @@ -81,8 +83,8 @@ function new_FileMetadata(unusable, dimensions, global, variables, order) result fmd%dimensions = StringIntegerMap() if (present(dimensions)) fmd%dimensions = dimensions - fmd%global = Variable() - if (present(global)) fmd%global = global + fmd%global_var = Variable() + if (present(global)) fmd%global_var = global fmd%variables = StringVariableMap() if (present(variables)) fmd%variables = variables @@ -100,6 +102,14 @@ function get_dimensions(this) result(dimensions) end function get_dimensions + function get_global_var(this) result(global_var) + type (Variable), pointer :: global_var + class (FileMetadata), target, intent(in) :: this + + global_var => this%global_var + + end function get_global_var + subroutine add_dimension(this, dim_name, extent, unusable, rc) class (FileMetadata), target, intent(inout) :: this @@ -160,7 +170,7 @@ integer function get_dimension(this, dim_name, unusable, rc) result(extent) else extent = 0 if (present(rc)) rc=pFIO_DIMENSION_NOT_FOUND - !_ASSERT(.false., 'FileMetadata::get_dimension() - no such dimension <'//dim_name//'>.') + !_FAIL( 'FileMetadata::get_dimension() - no such dimension <'//dim_name//'>.') end if _UNUSED_DUMMY(unusable) @@ -174,7 +184,7 @@ subroutine add_attribute_0d(this, attr_name, attr_value, unusable, rc) class (KeywordEnforcer), optional, intent(in) :: unusable integer, optional, intent(out) :: rc - call this%global%add_attribute(attr_name, attr_value) + call this%global_var%add_attribute(attr_name, attr_value) _RETURN(_SUCCESS) _UNUSED_DUMMY(unusable) end subroutine add_attribute_0d @@ -187,7 +197,7 @@ subroutine add_attribute_1d(this, attr_name, values, unusable, rc) class (KeywordEnforcer), optional, intent(in) :: unusable integer, optional, intent(out) :: rc - call this%global%add_attribute(attr_name, values) + call this%global_var%add_attribute(attr_name, values) _RETURN(_SUCCESS) _UNUSED_DUMMY(unusable) end subroutine add_attribute_1d @@ -200,7 +210,7 @@ function get_attribute(this, attr_name, unusable, rc) result(ref) class (KeywordEnforcer), optional, intent(in) :: unusable integer, optional, intent(out) :: rc - ref => this%global%get_attribute(attr_name) + ref => this%global_var%get_attribute(attr_name) _ASSERT(associated(ref),'FileMetadata::get_attribute() - no such attribute <'//attr_name//'>.') _RETURN(_SUCCESS) _UNUSED_DUMMY(unusable) @@ -212,7 +222,7 @@ logical function has_attribute(this, attr_name) class (FileMetadata), target, intent(in) :: this character(len=*), intent(in) :: attr_name - has_attribute = this%global%is_attribute_present(attr_name) + has_attribute = this%global_var%is_attribute_present(attr_name) end function has_attribute @@ -222,7 +232,7 @@ function get_attributes(this, rc ) result(attributes) class (FileMetadata), target, intent(in) :: this integer, optional, intent(out) :: rc - attributes => this%global%get_attributes() + attributes => this%global_var%get_attributes() _RETURN(_SUCCESS) end function get_attributes @@ -239,6 +249,20 @@ function get_variable(this, var_name, unusable, rc) result(var) _UNUSED_DUMMY(unusable) end function get_variable + logical function has_variable(this, var_name, unusable, rc) result(has) + class (FileMetadata), target, intent(in) :: this + character(len=*), intent(in) :: var_name + class (KeywordEnforcer), optional, intent(in) :: unusable + integer, optional, intent(out) :: rc + class (Variable), pointer :: var + + has = .false. + var => this%variables%at(var_name) + if (associated(var)) has = .true. + _RETURN(_SUCCESS) + _UNUSED_DUMMY(unusable) + end function has_variable + ! Returns null pointer unless var_name is a key corresponding to ! a CoordinateVariable value. ! rc returns _SUCCESS unless the var_name is not found at all. @@ -378,7 +402,7 @@ subroutine add_variable(this, var_name, var, unusable, rc) _UNUSED_DUMMY(unusable) end subroutine add_variable - + subroutine modify_variable(this, var_name, var, unusable, rc) class (FileMetadata), target, intent(inout) :: this character(len=*), intent(in) :: var_name @@ -496,7 +520,7 @@ logical function same_attributes(a, b) result(equal) type (Attribute), pointer :: attr_a, attr_b character(len=:), pointer :: attr_name - equal = (a%global == b%global) + equal = (a%global_var == b%global_var) end function same_attributes @@ -549,7 +573,7 @@ subroutine serialize(this, buffer, rc) call StringIntegerMap_serialize(this%dimensions, tmp_buffer) buffer = [tmp_buffer] - call this%global%serialize(tmp_buffer) + call this%global_var%serialize(tmp_buffer) buffer = [buffer,tmp_buffer] call StringVariableMap_serialize(this%variables, tmp_buffer) buffer = [buffer,tmp_buffer] @@ -591,7 +615,7 @@ subroutine deserialize(this, buffer, rc) call deserialize_intrinsic(buffer(n:),length) n = n + length call deserialize_intrinsic(buffer(n:),length) - call Variable_deserialize(buffer(n:n+length-1),this%global, status) + call Variable_deserialize(buffer(n:n+length-1),this%global_var, status) _VERIFY(status) n = n + length call StringVariableMap_deserialize(buffer(n:), this%variables, status) diff --git a/pfio/LocalMemReference.F90 b/pfio/LocalMemReference.F90 index 23d74414fa53..bae5ebfb3b0a 100644 --- a/pfio/LocalMemReference.F90 +++ b/pfio/LocalMemReference.F90 @@ -90,7 +90,7 @@ function new_LocalMemReference_0d(scalar, rc) result(reference) call c_f_pointer(reference%base_address, real64Ptr) real64Ptr = scalar class default - _ASSERT(.false., "LocalMemRef does not support this type") + _FAIL( "LocalMemRef does not support this type") end select _RETURN(_SUCCESS) @@ -140,7 +140,7 @@ function new_LocalMemReference_1d(array, rc) result(reference) call c_f_pointer(reference%base_address, real64Ptr, shape=shape(array)) real64Ptr = array class default - _ASSERT(.false., "LocalMemRef does not support this type") + _FAIL( "LocalMemRef does not support this type") end select _RETURN(_SUCCESS) @@ -191,7 +191,7 @@ function new_LocalMemReference_2d(array, rc) result(reference) call c_f_pointer(reference%base_address, real64Ptr, shape=shape(array)) real64Ptr = array class default - _ASSERT(.false., "LocalMemRef does not support this type") + _FAIL( "LocalMemRef does not support this type") end select _RETURN(_SUCCESS) @@ -242,7 +242,7 @@ function new_LocalMemReference_3d(array, rc) result(reference) call c_f_pointer(reference%base_address, real64Ptr, shape=shape(array)) real64Ptr = array class default - _ASSERT(.false., "LocalMemRef does not support this type") + _FAIL( "LocalMemRef does not support this type") end select _RETURN(_SUCCESS) @@ -293,7 +293,7 @@ function new_LocalMemReference_4d(array, rc) result(reference) call c_f_pointer(reference%base_address, real64Ptr, shape=shape(array)) real64Ptr = array class default - _ASSERT(.false., "LocalMemRef does not support this type") + _FAIL( "LocalMemRef does not support this type") end select _RETURN(_SUCCESS) @@ -344,7 +344,7 @@ function new_LocalMemReference_5d(array, rc) result(reference) call c_f_pointer(reference%base_address, real64Ptr, shape=shape(array)) real64Ptr = array class default - _ASSERT(.false., "LocalMemRef does not support this type") + _FAIL( "LocalMemRef does not support this type") end select _RETURN(_SUCCESS) diff --git a/pfio/MessageVisitor.F90 b/pfio/MessageVisitor.F90 index c1a1805545b2..e2134c940693 100644 --- a/pfio/MessageVisitor.F90 +++ b/pfio/MessageVisitor.F90 @@ -126,7 +126,7 @@ recursive subroutine handle(this, message, rc) ! if the serverthread sends the dummy directly to clientthread, it will not go through here. _VERIFY(0) class default - _ASSERT(.false., 'unsupported subclass') + _FAIL( 'unsupported subclass') end select _RETURN(_SUCCESS) end subroutine handle @@ -135,7 +135,7 @@ subroutine handle_CollectivePrefetchData(this, message, rc) class (MessageVisitor), intent(inout) :: this type (CollectivePrefetchDataMessage), intent(in) :: message integer, optional, intent(out) :: rc - _ASSERT(.false., "Warning : dummy handle_CollectivePrefetchData should not be called") + _FAIL( "Warning : dummy handle_CollectivePrefetchData should not be called") _UNUSED_DUMMY(this) _UNUSED_DUMMY(message) end subroutine handle_CollectivePrefetchData @@ -144,7 +144,7 @@ subroutine handle_CollectiveStageData(this, message, rc) class (MessageVisitor), intent(inout) :: this type (CollectiveStageDataMessage), intent(in) :: message integer, optional, intent(out) :: rc - _ASSERT(.false., "Warning : dummy handle_CollectiveStageData should not be called") + _FAIL( "Warning : dummy handle_CollectiveStageData should not be called") _UNUSED_DUMMY(this) _UNUSED_DUMMY(message) end subroutine handle_CollectiveStageData @@ -153,7 +153,7 @@ subroutine handle_Terminate(this, message, rc) class (MessageVisitor), intent(inout) :: this type (TerminateMessage), intent(in) :: message integer, optional, intent(out) :: rc - _ASSERT(.false., "Warning : dummy handle_Terminate should not be called") + _FAIL( "Warning : dummy handle_Terminate should not be called") _UNUSED_DUMMY(this) _UNUSED_DUMMY(message) end subroutine handle_Terminate @@ -162,7 +162,7 @@ subroutine handle_Done(this, message, rc) class (MessageVisitor), target, intent(inout) :: this type (DoneMessage), intent(in) :: message integer, optional, intent(out) :: rc - _ASSERT(.false., "Warning : dummy handle_Done should not be called") + _FAIL( "Warning : dummy handle_Done should not be called") _UNUSED_DUMMY(this) _UNUSED_DUMMY(message) end subroutine handle_Done @@ -171,7 +171,7 @@ subroutine handle_Done_prefetch(this, message, rc) class (MessageVisitor), target, intent(inout) :: this type (PrefetchDoneMessage), intent(in) :: message integer, optional, intent(out) :: rc - _ASSERT(.false., "Warning : dummy handle_Done_prefetch should not be called") + _FAIL( "Warning : dummy handle_Done_prefetch should not be called") _UNUSED_DUMMY(this) _UNUSED_DUMMY(message) end subroutine handle_Done_prefetch @@ -180,7 +180,7 @@ subroutine handle_Done_collective_prefetch(this, message, rc) class (MessageVisitor), target, intent(inout) :: this type (CollectivePrefetchDoneMessage), intent(in) :: message integer, optional, intent(out) :: rc - _ASSERT(.false., "Warning : dummy handle_Done_collective_prefetch should not be called") + _FAIL( "Warning : dummy handle_Done_collective_prefetch should not be called") _UNUSED_DUMMY(this) _UNUSED_DUMMY(message) end subroutine handle_Done_collective_prefetch @@ -189,7 +189,7 @@ subroutine handle_Done_stage(this, message, rc) class (MessageVisitor), target, intent(inout) :: this type (StageDoneMessage), intent(in) :: message integer, optional, intent(out) :: rc - _ASSERT(.false., "Warning : dummy handle_Done_stage should not be called") + _FAIL( "Warning : dummy handle_Done_stage should not be called") _UNUSED_DUMMY(this) _UNUSED_DUMMY(message) end subroutine handle_Done_stage @@ -198,7 +198,7 @@ subroutine handle_Done_collective_stage(this, message, rc) class (MessageVisitor), target, intent(inout) :: this type (CollectiveStageDoneMessage), intent(in) :: message integer, optional, intent(out) :: rc - _ASSERT(.false., "Warning : dummy handle_Done_collective_stage should not be called") + _FAIL( "Warning : dummy handle_Done_collective_stage should not be called") _UNUSED_DUMMY(this) _UNUSED_DUMMY(message) end subroutine handle_Done_collective_stage @@ -207,7 +207,7 @@ subroutine handle_AddExtCollection(this, message, rc) class (MessageVisitor), target, intent(inout) :: this type (AddExtCollectionMessage), intent(in) :: message integer, optional, intent(out) :: rc - _ASSERT(.false., "Warning : dummy handle_AddExtCollection should not be called") + _FAIL( "Warning : dummy handle_AddExtCollection should not be called") _UNUSED_DUMMY(this) _UNUSED_DUMMY(message) end subroutine handle_AddExtCollection @@ -216,7 +216,7 @@ subroutine handle_AddHistCollection(this, message, rc) class (MessageVisitor), target, intent(inout) :: this type (AddHistCollectionMessage), intent(in) :: message integer, optional, intent(out) :: rc - _ASSERT(.false., "Warning : dummy handle_AddHistCollection should not be called") + _FAIL( "Warning : dummy handle_AddHistCollection should not be called") _UNUSED_DUMMY(this) _UNUSED_DUMMY(message) end subroutine handle_AddHistCollection @@ -225,7 +225,7 @@ subroutine handle_Id(this, message, rc) class (MessageVisitor), intent(inout) :: this type (IdMessage), intent(in) :: message integer, optional, intent(out) :: rc - _ASSERT(.false., "Warning : dummy handle_ID should not be called. hint: maybe server and app are the same?") + _FAIL( "Warning : dummy handle_ID should not be called. hint: maybe server and app are the same?") _UNUSED_DUMMY(this) _UNUSED_DUMMY(message) end subroutine handle_Id @@ -234,7 +234,7 @@ subroutine handle_PrefetchData(this, message, rc) class (MessageVisitor), intent(inout) :: this type (PrefetchDataMessage), intent(in) :: message integer, optional, intent(out) :: rc - _ASSERT(.false., "Warning : dummy handle_PrefetchData should not be called") + _FAIL( "Warning : dummy handle_PrefetchData should not be called") _UNUSED_DUMMY(this) _UNUSED_DUMMY(message) end subroutine handle_PrefetchData @@ -243,7 +243,7 @@ subroutine handle_StageData(this, message, rc) class (MessageVisitor), intent(inout) :: this type (StageDataMessage), intent(in) :: message integer, optional, intent(out) :: rc - _ASSERT(.false., "Warning : dummy handle_StageData should not be called") + _FAIL( "Warning : dummy handle_StageData should not be called") _UNUSED_DUMMY(this) _UNUSED_DUMMY(message) end subroutine handle_StageData @@ -252,7 +252,7 @@ subroutine handle_ModifyMetadata(this, message, rc) class (MessageVisitor), intent(inout) :: this type (ModifyMetadataMessage), intent(in) :: message integer, optional, intent(out) :: rc - _ASSERT(.false., "Warning : dummy handle_ModifyMetadata should not be called") + _FAIL( "Warning : dummy handle_ModifyMetadata should not be called") _UNUSED_DUMMY(this) _UNUSED_DUMMY(message) end subroutine handle_ModifyMetadata @@ -261,7 +261,7 @@ subroutine handle_HandShake(this, message, rc) class (MessageVisitor), target, intent(inout) :: this type (HandShakeMessage), intent(in) :: message integer, optional, intent(out) :: rc - _ASSERT(.false., "Warning : dummy handle_HandShake should not be called") + _FAIL( "Warning : dummy handle_HandShake should not be called") _UNUSED_DUMMY(this) _UNUSED_DUMMY(message) end subroutine handle_HandShake diff --git a/pfio/MultiCommServer.F90 b/pfio/MultiCommServer.F90 index 5d1f2246e167..99cd49a4c034 100644 --- a/pfio/MultiCommServer.F90 +++ b/pfio/MultiCommServer.F90 @@ -482,7 +482,7 @@ subroutine clean_up(this, rc) type is (LocalMemReference) i_ptr =>dataRefPtr%i_ptr class default - _ASSERT(.false., "I expect localmemReference") + _FAIL( "I expect localmemReference") end select iter = this%stage_offset%find(i_to_string(q%request_id)//'done') @@ -497,7 +497,7 @@ subroutine clean_up(this, rc) call this%stage_offset%insert(i_to_string(q%request_id)//'done',0_MPI_ADDRESS_KIND) endif class default - _ASSERT(.false., "I expect CollectiveStageDataMessage") + _FAIL( "I expect CollectiveStageDataMessage") end select call msg_iter%next() enddo diff --git a/pfio/MultiGroupServer.F90 b/pfio/MultiGroupServer.F90 index ec7d9a4901e3..ec8ef6ab7b27 100644 --- a/pfio/MultiGroupServer.F90 +++ b/pfio/MultiGroupServer.F90 @@ -264,7 +264,7 @@ subroutine put_DataToFile(this, rc) class (MultiGroupServer),target, intent(inout) :: this integer, optional, intent(out) :: rc if (this%front_Comm == MPI_COMM_NULL) then - _ASSERT(.false. , "hey backend does not call this") + _FAIL("hey backend does not call this") else _RETURN(_SUCCESS) endif @@ -383,7 +383,7 @@ subroutine receive_output_data(this, rc) endif if (associated(ioserver_profiler)) call ioserver_profiler%stop("collection_"//i_to_string(q%collection_id)) class default - _ASSERT(.false., "yet to implemented") + _FAIL( "yet to implemented") end select call iter%next() end do ! iter @@ -684,7 +684,7 @@ subroutine start_back_writers(rc) q%start(1) = word_size(q%type_kind)*(q%start(1)-1)+1 select case (d_rank) case (0) - _ASSERT(.false., "scalar ?? ") + _FAIL( "scalar ?? ") case (1) call c_f_pointer(address, g_1d, shape=q%global_count) msize_word = product(q%count) diff --git a/pfio/MultiLayerServer.F90 b/pfio/MultiLayerServer.F90 index 6857e179029f..48a96b8be76f 100644 --- a/pfio/MultiLayerServer.F90 +++ b/pfio/MultiLayerServer.F90 @@ -180,7 +180,7 @@ subroutine put_DataToFile(this, rc) type is (RDMAReference) remotePtr=>dataRefPtr class default - _ASSERT(.false., "remote is a must") + _FAIL( "remote is a must") end select request_iter = this%stage_offset%find(i_to_string(q%request_id)//'done') diff --git a/pfio/NetCDF4_FileFormatter.F90 b/pfio/NetCDF4_FileFormatter.F90 index ffadf77f9d53..740081c517e7 100644 --- a/pfio/NetCDF4_FileFormatter.F90 +++ b/pfio/NetCDF4_FileFormatter.F90 @@ -150,12 +150,21 @@ subroutine create(this, file, unusable, mode, rc) integer :: status integer :: mode_ + integer :: pfio_mode if (present(mode)) then - mode_=mode + pfio_mode=mode else - mode_=NF90_CLOBBER + pfio_mode=PFIO_NOCLOBBER end if + + select case (pfio_mode) + case (pFIO_CLOBBER) + mode_ = NF90_CLOBBER + case (pFIO_NOCLOBBER) + mode_ = NF90_NOCLOBBER + end select + !$omp critical status = nf90_create(file, IOR(mode_, NF90_NETCDF4), this%ncid) !$omp end critical @@ -179,13 +188,21 @@ subroutine create_par(this, file, unusable, mode, comm, info, rc) integer :: info_ integer :: status integer :: mode_ + integer :: pfio_mode if (present(mode)) then - mode_=mode + pfio_mode=mode else - mode_=NF90_CLOBBER + pfio_mode=PFIO_NOCLOBBER end if + select case (pfio_mode) + case (pFIO_CLOBBER) + mode_ = NF90_CLOBBER + case (pFIO_NOCLOBBER) + mode_ = NF90_NOCLOBBER + end select + if (present(comm)) then comm_ = comm else @@ -234,7 +251,7 @@ subroutine open(this, file, mode, unusable, comm, info, rc) case (pFIO_WRITE) omode = NF90_WRITE case default - _ASSERT(.false.,"read or write mode") + _FAIL("read or write mode") end select if (present(comm)) then diff --git a/pfio/NetCDF4_get_var.H b/pfio/NetCDF4_get_var.H index d6bd62a76984..8cc776edb692 100644 --- a/pfio/NetCDF4_get_var.H +++ b/pfio/NetCDF4_get_var.H @@ -26,7 +26,7 @@ status = nf90_inq_varid(this%ncid, name=var_name, varid=varid) !$omp end critical - _VERIFY(status) + _ASSERT(status==0,"Variable not found: "//trim(var_name)) !$omp critical #if (_RANK == 0) status = nf90_get_var(this%ncid, varid, values) diff --git a/pfio/ServerThread.F90 b/pfio/ServerThread.F90 index 832394bf368c..e09e8a944229 100644 --- a/pfio/ServerThread.F90 +++ b/pfio/ServerThread.F90 @@ -255,19 +255,19 @@ recursive subroutine handle_Done(this, message, rc) select type (q=>msg) type is (PrefetchDataMessage) - _ASSERT(.false., "please use done_prefetch") + _FAIL( "please use done_prefetch") _RETURN(_SUCCESS) type is (CollectivePrefetchDataMessage) - _ASSERT(.false., "please use done_collective_prefetch") + _FAIL( "please use done_collective_prefetch") _RETURN(_SUCCESS) type is (StageDataMessage) - _ASSERT(.false., "please use done_stage") + _FAIL( "please use done_stage") _RETURN(_SUCCESS) type is (CollectiveStageDataMessage) - _ASSERT(.false., "please use done_collective_stage") + _FAIL( "please use done_collective_stage") _RETURN(_SUCCESS) class default - _ASSERT(.false., "Wrong message type") + _FAIL( "Wrong message type") end select @@ -531,18 +531,10 @@ subroutine handle_AddHistCollection(this, message, rc) class(AbstractSocket),pointer :: connection if (associated(ioserver_profiler)) call ioserver_profiler%start("add_Histcollection") - if ( message%collection_id == -1 ) then - n = this%hist_collections%size()+1 - else - n = message%collection_id - endif + n = this%hist_collections%size()+1 hist_collection = HistoryCollection(message%fmd) - if ( message%collection_id == -1) then - call this%hist_collections%push_back(hist_collection) - else - call this%hist_collections%set(n,hist_collection) - endif + call this%hist_collections%push_back(hist_collection) connection=>this%get_connection() call connection%send(IdMessage(n),_RC) @@ -681,7 +673,7 @@ subroutine get_DataFromFile(this,message,address, rc) start = message%global_start count = message%global_count class default - _ASSERT(.false., "wrong PrefetchDataMessage type") + _FAIL( "wrong PrefetchDataMessage type") end select ! if (product(count) /= product(file_data_reference%shape)) stop "memory size not match" @@ -701,7 +693,7 @@ subroutine get_DataFromFile(this,message,address, rc) call c_f_pointer(address, values_real64_0d) call formatter%get_var(message%var_name, values_real64_0d, _RC) case default - _ASSERT(.false., "Not supported type") + _FAIL( "Not supported type") end select case (1:) select case (message%type_kind) @@ -718,7 +710,7 @@ subroutine get_DataFromFile(this,message,address, rc) call c_f_pointer(address, values_real64_1d, [product(count)]) call formatter%get_var(message%var_name, values_real64_1d, start=start, count=count, _RC) case default - _ASSERT(.false., "Not supported type") + _FAIL( "Not supported type") end select end select @@ -808,7 +800,7 @@ subroutine put_DataToFile(this, message, address, rc) count = message%global_count class default - _ASSERT(.false., "wrong StageDataMessage type") + _FAIL( "wrong StageDataMessage type") end select ! if (product(count) /= product(file_data_reference%shape)) stop "memory size not match" select case (size(count)) ! rank @@ -827,7 +819,7 @@ subroutine put_DataToFile(this, message, address, rc) call c_f_pointer(address, values_real64_0d) call formatter%put_var(message%var_name, values_real64_0d, _RC) case default - _ASSERT(.false., "not supported type") + _FAIL( "not supported type") end select case (1:) select case (message%type_kind) @@ -844,7 +836,7 @@ subroutine put_DataToFile(this, message, address, rc) call c_f_pointer(address, values_real64_1d, [product(count)]) call formatter%put_var(message%var_name, values_real64_1d, start=start, count=count, _RC) case default - _ASSERT(.false., "not supported type") + _FAIL( "not supported type") end select end select @@ -904,7 +896,7 @@ subroutine receive_output_data(this, rc) type is (RDMAReference) remotePtr=>dataRefPtr class default - _ASSERT(.false., " need a remote pointer") + _FAIL( " need a remote pointer") end select rank = remotePtr%mem_rank @@ -916,7 +908,7 @@ subroutine receive_output_data(this, rc) endif ! local_size > 0 class default - _ASSERT(.false., "receive_output_data") + _FAIL( "receive_output_data") end select call iter%next() enddo @@ -1028,7 +1020,7 @@ recursive subroutine handle_Done_stage(this, message, rc) call this%request_backlog%erase(iter) class default - _ASSERT(.false., "Wrong message type") + _FAIL( "Wrong message type") end select iter = this%request_backlog%begin() enddo @@ -1067,7 +1059,7 @@ recursive subroutine handle_Done_prefetch(this, message, rc) call this%request_backlog%erase(iter) class default - _ASSERT(.false., "Wrong message type") + _FAIL( "Wrong message type") end select iter = this%request_backlog%begin() enddo @@ -1164,7 +1156,7 @@ subroutine get_DataFromMem( this, multi_data_read, rc) call this%request_backlog%erase(iter) class default - _ASSERT(.false., "Message type should be CollectivePrefetchDataMessage ") + _FAIL( "Message type should be CollectivePrefetchDataMessage ") end select iter = this%request_backlog%begin() enddo diff --git a/pfio/SimpleSocket.F90 b/pfio/SimpleSocket.F90 index 195ae6655914..65344ab9d9d9 100644 --- a/pfio/SimpleSocket.F90 +++ b/pfio/SimpleSocket.F90 @@ -106,7 +106,7 @@ recursive subroutine send(this, message, rc) allocate(connection%msg , source = message) call connection%msg%dispatch(this%visitor, _RC) class default - _ASSERT(.false.,"Simple should connect Simple") + _FAIL("Simple should connect Simple") end select _RETURN(_SUCCESS) ! call message%dispatch(this%visitor,_RC) diff --git a/pfio/UnlimitedEntity.F90 b/pfio/UnlimitedEntity.F90 index 4b21aa8a1b72..a8f3c706c27e 100644 --- a/pfio/UnlimitedEntity.F90 +++ b/pfio/UnlimitedEntity.F90 @@ -110,7 +110,7 @@ function new_UnlimitedEntity_1d(values, rc) result(attr) select type (values) type is (character(len=*)) - _ASSERT(.false., 'unsupported unless shape is [1]') + _FAIL( 'unsupported unless shape is [1]') class default allocate(attr%values, source=values) attr%shape = shape(values) @@ -137,7 +137,7 @@ function new_UnlimitedEntity_2d(values, rc) result(attr) type is (logical) allocate(values1d, source = reshape(values, [product(shape(values))])) class default - _ASSERT(.false., 'not support type') + _FAIL( 'not support type') end select attr = UnlimitedEntity(values1d) @@ -165,7 +165,7 @@ function new_UnlimitedEntity_3d(values, rc) result(attr) type is (logical) allocate(values1d, source = reshape(values, [product(shape(values))])) class default - _ASSERT(.false., 'not support type') + _FAIL( 'not support type') end select attr = UnlimitedEntity(values1d) @@ -193,7 +193,7 @@ function new_UnlimitedEntity_4d(values, rc) result(attr) type is (logical) allocate(values1d, source = reshape(values, [product(shape(values))])) class default - _ASSERT(.false., 'not support type') + _FAIL( 'not support type') end select attr = UnlimitedEntity(values1d) @@ -221,7 +221,7 @@ function new_UnlimitedEntity_5d(values, rc) result(attr) type is (logical) allocate(values1d, source = reshape(values, [product(shape(values))])) class default - _ASSERT(.false., 'not support type') + _FAIL( 'not support type') end select attr = UnlimitedEntity(values1d) @@ -544,7 +544,7 @@ subroutine serialize( this, buffer, rc) serialize_intrinsic(type_kind), & serialize_intrinsic(value%value)] class default - _ASSERT(.false.," type is not supported") + _FAIL(" type is not supported") end select endif case (1:) @@ -581,7 +581,7 @@ subroutine serialize( this, buffer, rc) ! serialize_intrinsic(type_kind), & ! serialize_intrinsic(values)] class default - _ASSERT(.false.," type is not supported") + _FAIL(" type is not supported") end select end select length = serialize_buffer_length(length) + size(buffer) @@ -658,7 +658,7 @@ subroutine deserialize( this, buffer, rc) ! this is uninitialized case, make sure shape is not allocated even it is empty if (allocated(this%shape))deallocate(this%shape) case default - _ASSERT(.false., "UnlimitedEntity deserialize not support") + _FAIL( "UnlimitedEntity deserialize not support") end select case (1:) select case (type_kind) @@ -678,7 +678,7 @@ subroutine deserialize( this, buffer, rc) call deserialize_intrinsic(buffer(n:),values_logical) allocate(this%values, source =values_logical) case default - _ASSERT(.false., "UnlimitedEntity deserialize not support") + _FAIL( "UnlimitedEntity deserialize not support") end select end select diff --git a/pfio/pFIO_Constants.F90 b/pfio/pFIO_Constants.F90 index 1edb709377e5..ce3b8a1eaa9e 100644 --- a/pfio/pFIO_Constants.F90 +++ b/pfio/pFIO_Constants.F90 @@ -24,6 +24,8 @@ module pFIO_ConstantsMod ! IO modes public :: pFIO_WRITE public :: pFIO_READ + public :: pFIO_CLOBBER + public :: pFIO_NOCLOBBER public :: pFIO_s_tag public :: pFIO_m_w_tag public :: pFIO_w_m_tag @@ -58,6 +60,11 @@ module pFIO_ConstantsMod enumerator :: pFIO_WRITE end enum + enum, bind(C) + enumerator :: pFIO_CLOBBER + enumerator :: pFIO_NOCLOBBER + end enum + integer, parameter :: pFIO_s_tag = 9999 integer, parameter :: pFIO_m_w_tag = 8888 integer, parameter :: pFIO_w_m_tag = 7777 diff --git a/pfio/pFIO_Utilities.F90 b/pfio/pFIO_Utilities.F90 index d9152252321c..e94d903b831e 100644 --- a/pfio/pFIO_Utilities.F90 +++ b/pfio/pFIO_Utilities.F90 @@ -514,7 +514,7 @@ integer function word_size(type_kind,rc) case (pFIO_INT64) word_size = c_sizeof(i64)/c_sizeof(i32) case default - _ASSERT(.false., "unsupported type kind") + _FAIL( "unsupported type kind") end select _RETURN(_SUCCESS) diff --git a/pfio/pfio_io_demo.F90 b/pfio/pfio_io_demo.F90 deleted file mode 100644 index bddd1ffe4943..000000000000 --- a/pfio/pfio_io_demo.F90 +++ /dev/null @@ -1,514 +0,0 @@ -!usage -!mpirun -np 8 ./pfio_collective_demo.x -nc 4 -nsi 2 -nso 2 -f1 xxx1.nc4 -f2 xxx2.nc4 -v T -s mpi -!The variable should be 4d with lavel>=20 -#include "MAPL_ErrLog.h" -#include "unused_dummy.H" - -module io_demo_CLI - use MAPL_ExceptionHandling - use pFIO_StringVectorMod - implicit none - private - - public :: CommandLineOptions - public :: process_command_line - - type CommandLineOptions - character(len=:), allocatable :: file_1, file_2 - type (StringVector) :: requested_variables - - integer :: npes_client - integer :: npes_iserver - integer :: npes_oserver - logical :: debug - character(len=:),allocatable :: server_type ! 'mpi' or 'openmp' - end type CommandLineOptions - - -contains - - ! The following procedure parses the command line to find various - ! arguments for file names, target grid resolution, etc. - subroutine process_command_line(options, rc) - type (CommandLineOptions), intent(inout) :: options - integer, optional, intent(out) :: rc - - integer :: n_args - integer :: i_arg - character(len=:), allocatable :: argument - character(len=:), allocatable :: buffer - - n_args = command_argument_count() - - i_arg = 0 - do - if (i_arg > n_args) exit - - argument = get_next_argument() - - select case (argument) - case ('-nc', '--npes_client') - buffer = get_next_argument() - _ASSERT(buffer /= '-') - read(buffer,*) options%npes_client - case ('-nsi', '--npes_iserver') - buffer = get_next_argument() - _ASSERT(buffer /= '-') - read(buffer,*) options%npes_iserver - case ('-nso', '--npes_oserver') - buffer = get_next_argument() - _ASSERT(buffer /= '-') - read(buffer,*) options%npes_oserver - case ('-f1', '--file_1') - options%file_1 = get_next_argument() - _ASSERT(options%file_1(1:1) /= '-') - case ('-f2', '--file_2') - options%file_2 = get_next_argument() - _ASSERT(options%file_2(1:1) /= '-') - case ('-v', '--var') - buffer = get_next_argument() - _ASSERT(buffer(1:1) /= '-') - options%requested_variables = parse_vars(buffer) - case ('-s', '--server_type') - options%server_type = get_next_argument() - _ASSERT(options%server_type /= '-') - case ('-d', '--debug') - options%debug = .true. - case default - ! ignore - end select - - end do - - contains - - function get_next_argument() result(argument) - character(len=:), allocatable :: argument - - integer :: length - - i_arg = i_arg + 1 - - call get_command_argument(i_arg, length=length) - allocate(character(len=length) :: argument) - call get_command_argument(i_arg, value=argument) - - end function get_next_argument - - function parse_vars(buffer) result(vars) - type (StringVector) :: vars - character(len=*), intent(in) :: buffer - - integer :: idx - character(len=1), parameter :: COMMA = ',' - character(len=:), allocatable :: string - - string = buffer // COMMA - do - if (len(string) == 0) exit - idx = index(string,COMMA) - call vars%push_back(string(1:idx-1)) - string = string(idx+1:) - end do - - end function parse_vars - - - end subroutine process_command_line - - -end module io_demo_CLI - -module FakeExtDataMod - use io_demo_CLI - use pFIO - use pFIO_StringVectorMod - use, intrinsic :: iso_fortran_env, only: REAL32 - implicit none - private - - public :: FakeExtData - - type FakeBundle - real(kind=REAL32), allocatable :: x(:,:,:,:) - integer :: request_id - end type FakeBundle - - type FakeExtData - type (ClientThread) :: i_c - type (ClientThread) :: o_c - integer, allocatable :: hist_collection_ids(:) - - character(len=:), allocatable :: file_1 - character(len=:), allocatable :: file_2 - - type (StringVector) :: vars - type (FakeBundle), allocatable :: bundle(:) - - integer :: comm - integer :: rank - integer :: npes - - integer :: nlat - integer :: nlon - - contains - procedure :: init - procedure :: run - procedure :: finalize - - end type FakeExtData - -contains - - - subroutine init(this, options, comm, d_s) - use pFIO_StringIntegerMapMod - class (FakeExtData),target, intent(inout) :: this - type (CommandLineOptions), intent(in) :: options - integer, intent(in) :: comm - class (AbstractDirectoryService), target,intent(inout) :: d_s - - integer :: ierror - type (FileMetadata) :: file_metadata - type (NetCDF4_FileFormatter) :: formatter - type (StringIntegerMap) :: dims - - this%i_c = ClientThread() - call d_s%connect_to_server('i_server', this%i_c, comm) - - this%o_c = ClientThread() - call d_s%connect_to_server('o_server', this%o_c, comm) - - - this%file_1 = options%file_1 - this%file_2 = options%file_2 - this%vars = options%requested_variables - !call this%vars%push_back('T') - !call this%vars%push_back('U') - !call this%vars%push_back('V') - - - this%comm = comm - call MPI_Comm_rank(comm,this%rank,ierror) - call MPI_Comm_size(comm,this%npes,ierror) - - allocate(this%bundle(this%vars%size())) - - call formatter%open(this%file_1, pFIO_READ) - file_metadata = formatter%read() - call formatter%close() - - dims = file_metadata%get_dimensions() - this%nlat = dims%at('lat') - this%nlon = dims%at('lon') - - allocate(this%hist_collection_ids(10)) - - end subroutine init - - subroutine run(this, step) - class (FakeExtData), target, intent(inout) :: this - integer, intent(in) :: step - - type(ArrayReference) :: ref - type(FileMetadata) :: fmd,fmd2 - Type(Variable) :: T1,T2 - - integer :: i_var,i - integer :: lat0, lat1, nlats - integer :: collection_id, file_md_id - character(len=3) :: tmp - integer :: c1,c2,num_request - integer,allocatable :: pull_ids(:,:) - integer,allocatable :: push_ids(:,:) - - lat0 = 1 + (this%rank*this%nlat)/this%npes - lat1 = (this%rank+1)*this%nlat/this%npes - nlats = (lat1 - lat0 + 1) - - ! Establish the collection - ! In a real use case the collection name would be the ExtData template. - ! But the actual name does not matter - it is just used to identify - ! a group of files that have identical metadata (except for time) - !num_request = 1000 - num_request = 3 - call system_clock(c1) - - do i = 1,num_request - tmp= '' - write(tmp,'(I3.3)') i - collection_id = this%i_c%add_ext_collection('collection-i'//tmp) - collection_id = this%o_c%add_ext_collection('collection-o'//tmp) - enddo - call system_clock(c2) - - allocate(pull_ids(this%vars%size(),num_request)) - allocate(push_ids(this%vars%size(),num_request)) - - select case (step) - case (1) ! read 1st file; prefetch 2nd - - ! call system_clock(c1) - do i_var = 1, this%vars%size() - allocate(this%bundle(i_var)%x(this%nlon,lat0:lat1,1,1)) - this%bundle(i_var)%x = -1 - ref = ArrayReference(this%bundle(i_var)%x) - - do i =1, num_request - pull_ids(i_var,i) = & - & this%i_c%collective_prefetch_data(collection_id, this%file_1, this%vars%at(i_var), ref,& - & start=[1,lat0,20,1], & - & global_start=[1,1,20,1],global_count=[this%nlon,this%nlat,1,1]) - enddo - - end do - !call system_clock(c2) - call this%i_c%done_collective_prefetch() - - do i_var = 1, this%vars%size() - do i = 1, num_request - call this%i_c%wait(pull_ids(i_var,i)) - enddo - end do - - do i_var = 1, this%vars%size() - this%bundle(i_var)%x = -1 - ref = ArrayReference(this%bundle(i_var)%x) - this%bundle(i_var)%request_id = & - & this%i_c%collective_prefetch_data(collection_id, this%file_1, this%vars%at(i_var), ref,& - & start=[1,lat0,20,1], & - & global_start=[1,1,20,1],global_count=[this%nlon,this%nlat,1,1]) - end do - call this%i_c%done_collective_prefetch() - - - case (2) ! wait for 2nd file to complete - - do i_var = 1, this%vars%size() - call this%i_c%wait(this%bundle(i_var)%request_id) - end do - -!!!!!!!!!!!!!!!!! -! individual write - call fmd%add_dimension('lon',this%nlon) - call fmd%add_dimension('lat',nlats) - call fmd%add_dimension('level',1) - call fmd%add_dimension('time',1) - T1 = Variable(type=pFIO_REAL32, dimensions='lon,lat,level,time') - call fmd%add_variable('T',T1) - this%hist_collection_ids(1) = this%o_c%add_hist_collection(fmd) - - call fmd2%add_dimension('lon',this%nlon) - call fmd2%add_dimension('lat',this%nlat) - call fmd2%add_dimension('level',1) - call fmd2%add_dimension('time',1) - T2 = Variable(type=pFIO_REAL32, dimensions='lon,lat,level,time') - call fmd2%add_variable('T',T2) - this%hist_collection_ids(2) = this%o_c%add_hist_collection(fmd2) - - file_md_id = this%hist_collection_ids(1) - write(tmp,'(I3.3)') this%rank - - do i_var = 1, this%vars%size() - - ref = ArrayReference(this%bundle(i_var)%x) - - do i =1, 1 - push_ids(i_var,i) = & - & this%o_c%stage_data(file_md_id,trim(this%file_1)//'.rank_'//tmp//'.nc4', this%vars%at(i_var), ref,& - & start=[1,lat0,20,1]) - - enddo - - end do - !call system_clock(c2) - call this%o_c%done_stage() - do i_var = 1, this%vars%size() - do i = 1, 1 - call this%o_c%wait(push_ids(i_var,i)) - enddo - end do - -! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - ! writing - file_md_id = this%hist_collection_ids(2) - - do i_var = 1, this%vars%size() - - ref = ArrayReference(this%bundle(i_var)%x) - do i =1, 1 - push_ids(i_var,i) = & - & this%o_c%collective_stage_data(file_md_id, trim(this%file_1)//'.new.nc4', this%vars%at(i_var), ref,& - & start=[1,lat0,1,1], & - & global_start=[1,1,1,1],global_count=[this%nlon,this%nlat,1,1]) - - enddo - - end do - !call system_clock(c2) - call this%o_c%done_collective_stage() - do i_var = 1, this%vars%size() - do i = 1, 1 - call this%o_c%wait(push_ids(i_var,i)) - enddo - end do - -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1 - end select - - end subroutine run - - - subroutine finalize(this) - class (FakeExtData), intent(inout) :: this - integer :: ierror - deallocate(this%bundle) - call Mpi_Barrier(this%comm,ierror) - print*,"iclient sent terminate signal" - call this%i_c%terminate() - call Mpi_Barrier(this%comm,ierror) - print*,"oclient sent terminate signal" - call this%o_c%terminate() - end subroutine finalize - -end module FakeExtDataMod - -program main - use, intrinsic :: iso_fortran_env, only: REAL32 - use mpi - use pFIO - use io_demo_CLI - use FakeExtDataMod - use MAPL_ExceptionHandling - implicit none - - integer :: rank, npes, ierror, provided,required - integer :: status, color, key - - class(AbstractServer),pointer :: iserver,oserver - class(AbstractDirectoryService), pointer :: d_s => null() - - type (CommandLineOptions) :: options - integer, parameter :: NO_COLOR = 0 - integer, parameter :: iSERVER_COLOR = 1 - integer, parameter :: oSERVER_COLOR = 4 - integer, parameter :: CLIENT_COLOR = 2 - integer, parameter :: BOTH_COLOR = 3 - - integer :: comm,num_threads - type (FakeExtData), target :: extData - - - required = MPI_THREAD_MULTIPLE - call MPI_init_thread(required, provided, ierror) - call MPI_Comm_rank(MPI_COMM_WORLD, rank, ierror) - call MPI_Comm_size(MPI_COMM_WORLD, npes, ierror) - - call process_command_line(options, rc=status) - -!! sanity check - - if(options%server_type == 'openmp') then - if (required > provided) stop "provided thread is not enough for openmp" - num_threads = 10 - call omp_set_num_threads(num_threads) - endif - - d_s => get_directory_service(options%server_type) - - color = split_color(options%server_type,options%npes_iserver,options%npes_oserver) - key = 0 - - call MPI_Comm_split(MPI_COMM_WORLD, color, key, comm, ierror) - - if (color == iSERVER_COLOR .or. color == BOTH_COLOR ) then ! i_server - - iserver=>get_server(options%server_type,comm, d_s,'i_server') - print*,"start i_server" - if (color == iSERVER_COLOR ) call iserver%start() - - endif - - if (color == oSERVER_COLOR .or. color == BOTH_COLOR ) then ! o_server - - oserver=>get_server(options%server_type,comm,d_s,'o_server') - - print*,"start o_server" - if (color == oSERVER_COLOR ) call oserver%start() - - endif - - if (color == CLIENT_COLOR .or. color == BOTH_COLOR) then ! client - - call extData%init(options, comm, d_s) - call extData%run(step=1) - call extData%run(step=2) - call extData%finalize() - - end if - - call Mpi_Barrier(MPI_COMM_WORLD,ierror) - - call MPI_finalize(ierror) - -contains - - function get_directory_service(stype) result(d_s) - character(*),intent(in) :: stype - class(AbstractDirectoryService),pointer :: d_s - - allocate(d_s, source = DirectoryService(MPI_COMM_WORLD)) - - end function - - function split_color(stype,split_irank,split_orank) result(color) - character(*),intent(in) :: stype - integer,intent(in) :: split_irank - integer,intent(in) :: split_orank - integer :: color - - select case (stype) - case ('openmp','mpi') - if (rank < split_irank) then - color = iSERVER_COLOR - elseif (rank < split_orank+split_irank ) then - color = oSERVER_COLOR - else - color = CLIENT_COLOR - end if - case ('simple') - color = BOTH_COLOR - case default - stop "not known server type" - end select - - end function - - function get_server(stype,comm,d_s,port_name) result(server) - character(*),intent(in) :: stype - integer,intent(in) :: comm - class (AbstractDirectoryService), target,intent(inout) :: d_s - character(*), intent(in) :: port_name - - class(BaseServer),pointer :: server - - select case (stype) - case('mpi') - allocate(server,source=MpiServer(comm, port_name)) - call d_s%publish(PortInfo(port_name, server),server) - call d_s%connect_to_client(port_name, server) - print*,"using MpiServer" - case('openmp') -!!$ allocate(server,source=OpenmpServer(comm,d_s)) -!!$ print*,"using OpenMpServer" - case('simple') - allocate(server,source=MpiServer(comm, port_name)) - call d_s%publish(PortInfo(port_name, server), server) -! call d_s%connect_to_client(port_name, server) - print*,"using simple server" - end select - - end function - -end program main diff --git a/pfio/pfio_writer.F90 b/pfio/pfio_writer.F90 index 3e3410749e2f..d567be3afb02 100644 --- a/pfio/pfio_writer.F90 +++ b/pfio/pfio_writer.F90 @@ -232,7 +232,7 @@ subroutine write_data(message, formatter, attr, rc) call c_f_pointer(address, values_real64_0d) call formatter%put_var(message%var_name, values_real64_0d) case default - _ASSERT(.false., "not supported type") + _FAIL( "not supported type") end select case (1:) select case (message%type_kind) @@ -249,7 +249,7 @@ subroutine write_data(message, formatter, attr, rc) call c_f_pointer(address, values_real64_1d, [product(count)]) call formatter%put_var(message%var_name, values_real64_1d, start=start, count=count) case default - _ASSERT(.false., "not supported type") + _FAIL( "not supported type") end select end select end subroutine diff --git a/pfio/tests/Test_SimpleClient.pf b/pfio/tests/Test_SimpleClient.pf deleted file mode 100644 index fe526bea29cb..000000000000 --- a/pfio/tests/Test_SimpleClient.pf +++ /dev/null @@ -1,15 +0,0 @@ -module Test_SimpleClient - use pFIO_SimpleClient - use pfunit - implicit none - -contains - - @test - subroutine test_ - - - call client%send(array) - - -end module Test_SimpleClient diff --git a/pflogger_stub/pflogger_stub.F90 b/pflogger_stub/pflogger_stub.F90 index dcf56379bdf9..f35cc62bf69d 100644 --- a/pflogger_stub/pflogger_stub.F90 +++ b/pflogger_stub/pflogger_stub.F90 @@ -1,5 +1,8 @@ #include "MAPL_ErrLog.h" #define _SUCCESS 0 +#ifdef _RETURN +#undef _RETURN +#endif #define _RETURN(status) if(present(rc))rc=status; return module PFL_SeverityLevels @@ -22,7 +25,7 @@ module PFL_SeverityLevels end enum end module PFL_SeverityLevels - + module PFL_Logger use PFL_SeverityLevels, only: NOTSET use PFL_SeverityLevels, only: DEBUG_LEVEL => DEBUG @@ -60,7 +63,7 @@ end subroutine free subroutine debug(this, message, ARG_LIST, unusable, extra, line, file, rc) class (Logger), target, intent(inout) :: this character(len=*), intent(in) :: message - include 'recordOptArgs.inc' + include 'recordOptArgs.inc' class (KeywordEnforcer), optional, intent(in) :: unusable type (StringUnlimitedMap), optional, target, intent(in) :: extra integer, optional, intent(in) :: line @@ -89,7 +92,7 @@ end subroutine debug subroutine info(this, message, ARG_LIST, unusable, extra, line, file, rc) class (Logger), target, intent(inout) :: this character(len=*), intent(in) :: message - include 'recordOptArgs.inc' + include 'recordOptArgs.inc' class (KeywordEnforcer), optional, intent(in) :: unusable type (StringUnlimitedMap), optional, target, intent(in) :: extra integer, optional, intent(in) :: line @@ -118,13 +121,13 @@ end subroutine info subroutine warning(this, message, ARG_LIST, unusable, extra, line, file, rc) class (Logger), target, intent(inout) :: this character(len=*), intent(in) :: message - include 'recordOptArgs.inc' + include 'recordOptArgs.inc' class (KeywordEnforcer), optional, intent(in) :: unusable type (StringUnlimitedMap), optional, target, intent(in) :: extra integer, optional, intent(in) :: line character(*), optional, intent(in) :: file integer, optional, intent(out) :: rc - + _UNUSED_DUMMY(this) _UNUSED_DUMMY(message) _UNUSED_DUMMY(arg1) @@ -148,7 +151,7 @@ subroutine error(this, message, ARG_LIST, unusable, extra, line, file, rc) ! Log message with the integer severity 'DEBUG'. class (Logger), target, intent(inout) :: this character(len=*), intent(in) :: message - include 'recordOptArgs.inc' + include 'recordOptArgs.inc' class (KeywordEnforcer), optional, intent(in) :: unusable type (StringUnlimitedMap), optional, target, intent(in) :: extra integer, optional, intent(in) :: line @@ -177,7 +180,7 @@ end subroutine error subroutine critical(this, message, ARG_LIST, unusable, extra, line, file, rc) class (Logger), target, intent(inout) :: this character(len=*), intent(in) :: message - include 'recordOptArgs.inc' + include 'recordOptArgs.inc' class (KeywordEnforcer), optional, intent(in) :: unusable type (StringUnlimitedMap), optional, target, intent(in) :: extra integer, optional, intent(in) :: line @@ -208,7 +211,7 @@ logical function isEnabledFor(this, level) integer, intent(in) :: level isEnabledFor = .false. end function isEnabledFor - + end module PFL_Logger module PFL_LoggerManager @@ -228,7 +231,7 @@ module PFL_LoggerManager generic :: get_logger => get_logger_root procedure :: free end type LoggerManager - + type (LoggerManager), target, save :: logging contains diff --git a/pfunit/CMakeLists.txt b/pfunit/CMakeLists.txt index e23222eba6be..2cb3a2a44654 100644 --- a/pfunit/CMakeLists.txt +++ b/pfunit/CMakeLists.txt @@ -6,7 +6,7 @@ set (srcs ESMF_TestParameter.F90 MAPL_pFUnit_Throw.F90 MAPL_Initialize.F90 -) +) esma_add_library (${this} EXCLUDE_FROM_ALL SRCS ${srcs} NOINSTALL TYPE ${MAPL_LIBRARY_TYPE}) diff --git a/profiler/MeterNode.F90 b/profiler/MeterNode.F90 index b5fd5d0a360d..043b14340671 100644 --- a/profiler/MeterNode.F90 +++ b/profiler/MeterNode.F90 @@ -1,5 +1,5 @@ module MAPL_MeterNode - use, intrinsic :: iso_fortran_env, only: REAL64, REAL128 + use, intrinsic :: iso_fortran_env, only: REAL64 use MAPL_AbstractMeter use MAPL_AbstractMeterNode use MAPL_MeterNodeVector @@ -67,10 +67,10 @@ module MAPL_MeterNode interface MeterNodeIterator module procedure new_MeterNodeIterator end interface MeterNodeIterator - + integer, parameter :: NOT_FOUND = -1 - + contains @@ -79,7 +79,7 @@ function new_MeterNode(name, meter, depth) result(tree) character(*), intent(in) :: name class(AbstractMeter), intent(in) :: meter integer, optional, intent(in) :: depth - + tree%name = name tree%meter = meter @@ -99,14 +99,14 @@ function get_meter(this) result(meter) class (MeterNode), target, intent(in) :: this meter => this%meter end function get_meter - + function get_name(this) result(name) character(:), pointer :: name class (MeterNode), target, intent(in) :: this name => this%name end function get_name - + function get_inclusive(this) result(inclusive) real(kind=REAL64) :: inclusive @@ -121,11 +121,14 @@ function get_exclusive(this) result(exclusive) type (MeterNodevectorIterator) :: iter class (AbstractMeterNode), pointer :: child - real(kind=REAL128) :: tmp + real(kind=REAL64) :: tmp + + ! Subtract time of submeters from time of node meter. + ! Previously, this used 128-bit precision to avoid negative + ! exclusive times due to roundoff. But the GNU on M1 and NVHPC do + ! not allow REAL128. So tmp is now 64-bit and we use a max(tmp,0) + ! below to try and cap negatives - ! Subtract time of submeters from time of node meter. Note the - ! use of 128-bit precision to avoid negative exclusive times due - ! to roundoff. tmp = this%get_inclusive() iter = this%children%begin() @@ -135,7 +138,7 @@ function get_exclusive(this) result(exclusive) call iter%next() end do - exclusive = tmp + exclusive = max(tmp, 0.0_REAL64) end function get_exclusive @@ -178,7 +181,7 @@ function get_child(this, name) result(child) character(*), intent(in) :: name integer :: idx - + idx = this%find_child(name) if (idx /= NOT_FOUND) then child => this%children%at(idx) @@ -232,7 +235,7 @@ recursive integer function get_num_nodes(this) result(num_nodes) type (MeterNodeVectorIterator) :: iter class (AbstractMeterNode), pointer :: child - + num_nodes = 1 iter = this%children%begin() do while (iter /= this%children%end()) @@ -271,7 +274,7 @@ function begin(this) result(iterator) allocate(iterator, source=MeterNodeIterator(this)) end function begin - + function end(this) result(iterator) @@ -293,7 +296,7 @@ function end(this) result(iterator) end function end - + recursive subroutine next(this) class (MeterNodeIterator), intent(inout) :: this class (AbstractMeterNode), pointer :: current_child @@ -318,7 +321,7 @@ recursive subroutine next(this) deallocate(this%iterator_of_current_child) call this%iterator_over_children%next() if (this%iterator_over_children == this%reference%children%end()) then ! done - deallocate(this%iterator_over_children) + deallocate(this%iterator_over_children) else current_child => this%iterator_over_children%get() this%iterator_of_current_child = current_child%begin() ! always at least one node @@ -326,7 +329,7 @@ recursive subroutine next(this) end if end if end if - + end subroutine next @@ -360,7 +363,7 @@ logical function equals(a, b) type is (MeterNodeIterator) equals = associated(a%reference, b%reference) if (.not. equals) return - + equals = associated(a%current) .eqv. associated(b%current) if (.not. equals) return @@ -423,7 +426,7 @@ recursive subroutine accumulate(this, other) call t%reset() end if call t%accumulate(other%get_meter()) - + ! recurse over children of other iter = other%begin() call iter%next() ! skip top node (already handled) @@ -434,5 +437,5 @@ recursive subroutine accumulate(this, other) end subroutine accumulate - + end module MAPL_MeterNode diff --git a/shared/DSO_Utilities.F90 b/shared/DSO_Utilities.F90 index 7f720edaf7cf..0eefd9e27455 100644 --- a/shared/DSO_Utilities.F90 +++ b/shared/DSO_Utilities.F90 @@ -31,7 +31,7 @@ end function is_valid_dso_extension ! puts a Linux DSO in a resource file. pure logical function is_supported_dso_name(name) character(len=*), intent(in) :: name - is_supported_dso_name = is_supported_dso_extension(get_file_extension(get_file_extension(name))) + is_supported_dso_name = is_supported_dso_extension(get_file_extension(name)) end function is_supported_dso_name ! We allow users to specify a DSO extensions that is only valid on diff --git a/shared/MAPL_HeapMod.F90 b/shared/MAPL_HeapMod.F90 index 4259394d93ae..ffab5917c1aa 100644 --- a/shared/MAPL_HeapMod.F90 +++ b/shared/MAPL_HeapMod.F90 @@ -139,7 +139,7 @@ end function loadr2d if(I>=NumSegments) then print *, 'MAPL_Alloc: Out of Segments. Need: ', I - _ASSERT(.false.,'needs informative message') + _FAIL('needs informative message') end if ! If we are filling a gap, move trailing segments down @@ -174,7 +174,7 @@ end function loadr2d do i=1,NumSegments print *, i, heap%HP_start(i), heap%HP_end(i) end do - _ASSERT(.false.,'needs informative message') + _FAIL('needs informative message') end if heap%ptrs(i)%a => heap%buffer(heap%HP_start(i):heap%HP_end(i)) @@ -216,7 +216,7 @@ end function ival1 i = i+1 if(i==NumSegments) then print *, 'MAPL_DeAlloc: Bad Pointer' - _ASSERT(.false.,'needs informative message') + _FAIL('needs informative message') end if end do @@ -230,7 +230,7 @@ end function ival1 i = i+1 if(i==NumSegments-1) then print *, 'MAPL_DeAlloc: Something wrong. Missed bottom mark' - _ASSERT(.false.,'needs informative message') + _FAIL('needs informative message') end if end do diff --git a/shared/MAPL_LoadBalance.F90 b/shared/MAPL_LoadBalance.F90 index 817b906318ba..57e8b6203101 100644 --- a/shared/MAPL_LoadBalance.F90 +++ b/shared/MAPL_LoadBalance.F90 @@ -5,6 +5,7 @@ module MAPL_LoadBalanceMod + use MAPL_Constants, only : MAPL_R8 use MAPL_SortMod use MAPL_ExceptionHandling use mpi @@ -16,6 +17,10 @@ module MAPL_LoadBalanceMod public MAPL_BalanceDestroy public MAPL_BalanceGet + interface MAPL_BalanceWork + module procedure MAPL_BalanceWork4 + module procedure MAPL_BalanceWork8 + end interface MAPL_BalanceWork integer, public, parameter :: MAPL_Distribute = 1 integer, public, parameter :: MAPL_Retrieve = 2 @@ -78,7 +83,7 @@ module MAPL_LoadBalanceMod contains - subroutine MAPL_BalanceWork(A, Idim, Direction, Handle, rc) + subroutine MAPL_BalanceWork4(A, Idim, Direction, Handle, rc) real, intent(INOUT) :: A(:) integer, intent(IN ) :: Idim, Direction integer, optional, intent(IN ) :: Handle @@ -178,7 +183,111 @@ subroutine MAPL_BalanceWork(A, Idim, Direction, Handle, rc) end if _RETURN(LDB_SUCCESS) - end subroutine MAPL_BalanceWork + end subroutine MAPL_BalanceWork4 + +!!!=============================================================== + + subroutine MAPL_BalanceWork8(A, Idim, Direction, Handle, rc) + real(kind=MAPL_R8), intent(INOUT) :: A(:) + integer, intent(IN ) :: Idim, Direction + integer, optional, intent(IN ) :: Handle + integer, optional, intent( OUT) :: rc + + integer :: PASS, LENGTH, PROCESSOR, CURSOR, ISTRAT + integer :: COMM, Vtype, VLength, STATUS, K1, K2, K3, Jdim + logical :: SEND, RECV + integer, pointer :: NOP(:,:) + +! Depending on the argument "Direction", this performs the actual distribution +! of work or the gathering of results for a given strategy. The strategy has to +! have been predefined by a call to MAPL_BalanceCreate. A strategy "Handle" +! obtained from that call can be optionally used to specify the strategy. Otherwise, +! a default strategy is assumed (see MAPL_BalanceCreate for details). +! Work (Results) is distributed (retrieved) using the buffer A, which is assumed +! to consist of Jdim contiguous blocks of size Idim. Of course, Jdim can be 1. +! The blocksize of A (Idim) must be at least as large as the BufLen associated +! with the strategy. This size can be obtained by quering the strategy using +! its handle or be saving it from the MAPL_BalanceCreate call. Again, see +! MAPL_BalanceCreate for details. + + Jdim = size(A)/Idim + + if(present(Handle)) then + ISTRAT = Handle + else + ISTRAT = 0 + endif + + if(THE_STRATEGIES(ISTRAT)%PASSES>0) then ! We have a defined strategy + _ASSERT(associated(THE_STRATEGIES(ISTRAT)%NOP),'needs informative message') + +! Initialize CURSOR, which is the location in the first block of A where +! the next read or write is to occur. K1 and K2 are the limits + + if (Direction==MAPL_Distribute) then + CURSOR = THE_STRATEGIES(ISTRAT)%UnBALANCED_LENGTH + 1 + k1=1 + k2=THE_STRATEGIES(ISTRAT)%PASSES + k3=1 + else + CURSOR = THE_STRATEGIES(ISTRAT)% BALANCED_LENGTH + 1 + k1=THE_STRATEGIES(ISTRAT)%PASSES + k2=1 + k3=-1 + end if + +! NOP contains the communication pattern for the strategy, i.e,, +! who passes what to whom within COMM. + + NOP => THE_STRATEGIES(ISTRAT)%NOP + COMM = THE_STRATEGIES(ISTRAT)%COMM + + do PASS=K1,K2,K3 + if(Direction==MAPL_Distribute) then + SEND = NOP(1,PASS)>0 + RECV = NOP(1,PASS)<0 + else + SEND = NOP(1,PASS)<0 + RECV = NOP(1,PASS)>0 + end if + + LENGTH = abs(NOP(1,PASS)) + PROCESSOR = NOP(2,PASS) + + if(Jdim==1) then + Vtype = MPI_DOUBLE_PRECISION + VLength = LENGTH + else + call MPI_Type_VECTOR(Jdim, Length, Idim, MPI_DOUBLE_PRECISION, Vtype, STATUS) + _ASSERT(STATUS==MPI_SUCCESS,'needs informative message') + call MPI_TYPE_COMMIT(Vtype,STATUS) + _ASSERT(STATUS==MPI_SUCCESS,'needs informative message') + VLength = 1 + end if + + if(SEND) then ! -- SENDER + CURSOR = CURSOR - LENGTH + call MPI_SEND(A(CURSOR), VLength, Vtype, PROCESSOR, PASS, COMM, STATUS) + _ASSERT(STATUS==MPI_SUCCESS,'needs informative message') + endif + + + if(RECV) then ! -- RECEIVER + call MPI_RECV(A(CURSOR), VLength, Vtype, PROCESSOR, PASS, COMM, & + MPI_STATUS_IGNORE, STATUS) + _ASSERT(STATUS==MPI_SUCCESS,'needs informative message') + CURSOR = CURSOR + LENGTH + endif + + if(Jdim>1) then + call MPI_TYPE_FREE(Vtype,STATUS) + _ASSERT(STATUS==MPI_SUCCESS,'needs informative message') + end if + enddo + end if + + _RETURN(LDB_SUCCESS) + end subroutine MAPL_BalanceWork8 !!!=============================================================== diff --git a/shared/Shmem/Shmem_implementation.F90 b/shared/Shmem/Shmem_implementation.F90 index 4de51b02915e..0c1c60851f9f 100644 --- a/shared/Shmem/Shmem_implementation.F90 +++ b/shared/Shmem/Shmem_implementation.F90 @@ -929,7 +929,7 @@ Segs(pos)%shmid = shmget(key, numBytes, shmflg) if (Segs(pos)%shmid < 0) then call perror('server shmget():'//C_NULL_CHAR) - _ASSERT(.false.,'needs informative message') + _FAIL('needs informative message') end if call MPI_Barrier(MAPL_NodeComm, STATUS) _ASSERT(STATUS==MPI_SUCCESS,'needs informative message') diff --git a/tutorial/CMakeLists.txt b/tutorial/CMakeLists.txt new file mode 100644 index 000000000000..8de0b740c189 --- /dev/null +++ b/tutorial/CMakeLists.txt @@ -0,0 +1,10 @@ +install (PROGRAMS run_tutorial_case.sh DESTINATION bin) + +add_subdirectory (driver_app) +add_subdirectory (grid_comps) + +file (GLOB_RECURSE tutorial_files CONFIGURE_DEPENDS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} mapl_tutorials/*) +foreach ( file ${tutorial_files} ) + get_filename_component( dir ${file} DIRECTORY ) + install( FILES ${file} DESTINATION etc/${dir} ) +endforeach() diff --git a/tutorial/README.md b/tutorial/README.md new file mode 100644 index 000000000000..e31e9b3254e3 --- /dev/null +++ b/tutorial/README.md @@ -0,0 +1,41 @@ +# MAPL Tutorials Overview + +For user education we have provided some simple tutorials. These demonstrate how to create simple gridded componnts and hierachies of components and drive them via the MAPL_Cap just like the real GEOSgcm model. Each "tutorial" will consist of a set of input files that can be run with our the Example_Driver.x and will itself contain a REAMDE file with explanation about what that particular tutorial is demonstrating. In addition, each will suggest exercises that you can do to extend them. + +Before embarking on these tutorials the new users should review the MAPL/ESMF powerpoint presentation here to get a general sense of what these frameworks are about and become familiar with the terminology. + +In addition, to use these tutorials you will have to have either built MAPL as a standalone fixture or as part of another fixture like the GEOSgcm. If you are reading this and have not built either, see the instructions for how to build MAPL [here](https://github.com/GEOS-ESM/MAPL/wiki/Building-and-Testing-MAPL-as-a-standalone). For these exercises we highly recommend building MAPL by itself as your build will be much faster, expecially when you change the code. The build itself takes a short time. We also recommend using the "debug" build rather than the "release" build. This will turn off optimzations and add extra error checking. The build will be faster in this case. Details on how to do this is in the aformentioned wiki page. + +Once you have installed either MAPL or the full GEOSgcm, you will have an installation directory whose full path I will refer to as INSTALL_DIR. + +Once you have this, you will find a script run_tutorial_case.sh that is in INSTALL_DIR/bin we have created for your convinience. + +This script takes two arguments, the path to INSTALL_DIR and the directory name of the test case you wish to run. To run this, go to a tempoary directory then run the script with the arguments. It will copy the input files to that directory and run the Example_Driver.x for that set of input files. Note that if you are at NCCS or NAS you will need to be on an interactive job with a single node. If you are at NCCS you will be using slurm and instructions can be found [here](https://www.nccs.nasa.gov/nccs-users/instructional/using-slurm). At NAS you would use PBS and instructions can be found [here](https://www.nas.nasa.gov/hecc/support/kb/portable-batch-system-(pbs)-overview_126.html). + +The following tutorials are available in the recommended order and represent the tutorial name you would use in the run script. +- hello_world +- parent_no_children +- parent_one_child_no_imports +- parent_two_siblings_connect_import_export +- parent_one_child_import_via_extdata + + +As a concrete example, suppose you have installed MAPL here at `discover/nobackup/auser/MAPL/install` and want to run the hello_world tutorial you run this on the command line: + +``` +/discover/nobackup/auser/MAPL/install/bin/run_tutorial_case.sh /discover/nobackup/auser/MAPL/install hello_world +``` + + +# Note for the Curious +The astute user might ask, how is it each tutorial is running the same executable yet using different gridded components? The answer is that each gridded component is compiled as a shared object library. Each time you run Example_Driver.x, you pass in the actual name of the shared object library that will be used as the top level gridded component. This was done to make the life of the humble developer writing this tutorial easier. + +Note that this technology, while used at places in the full GEOSgcm model to handle mom5 and mom6, it is not ubiquitous. You might notice that a few calls in these tutorails, particularly MAPL_AddChild calls in most gridded components and the "program" itself, aka where you have something like this: +``` +program Example_Driver.x + +! we have some source code + +end program Example_Driver.x +``` +may look a little different if you look at the corresponding program file for GEOSgcm.x. Do not worry. Please come ask your nearest SI team member. diff --git a/tutorial/driver_app/CMakeLists.txt b/tutorial/driver_app/CMakeLists.txt new file mode 100644 index 000000000000..35a100098073 --- /dev/null +++ b/tutorial/driver_app/CMakeLists.txt @@ -0,0 +1,8 @@ +set (srcs + Example_Driver.F90 + ) + +ecbuild_add_executable (TARGET Example_Driver.x SOURCES ${srcs}) +target_link_libraries (Example_Driver.x PRIVATE MAPL OpenMP::OpenMP_Fortran FLAP::FLAP esmf) +target_compile_definitions (Example_Driver.x PRIVATE $<$:BUILD_WITH_EXTDATA2G>) + diff --git a/tutorial/driver_app/Example_Driver.F90 b/tutorial/driver_app/Example_Driver.F90 new file mode 100644 index 000000000000..f489f358637f --- /dev/null +++ b/tutorial/driver_app/Example_Driver.F90 @@ -0,0 +1,22 @@ +#define I_AM_MAIN + +#include "MAPL_Generic.h" + +program Example_Driver + use MPI + use MAPL + implicit none + + type (MAPL_Cap) :: cap + type (MAPL_FlapCLI) :: cli + type (MAPL_CapOptions) :: cap_options + integer :: status + + cli = MAPL_FlapCLI(description = 'GEOS AGCM', & + authors = 'GMAO') + cap_options = MAPL_CapOptions(cli) + cap = MAPL_Cap('example', cap_options = cap_options) + call cap%run(_RC) + +end program Example_Driver + diff --git a/tutorial/grid_comps/CMakeLists.txt b/tutorial/grid_comps/CMakeLists.txt new file mode 100644 index 000000000000..2a006d2e4feb --- /dev/null +++ b/tutorial/grid_comps/CMakeLists.txt @@ -0,0 +1,6 @@ +add_subdirectory (hello_world_gridcomp) +add_subdirectory (parent_with_no_children) +add_subdirectory (leaf_comp_a) +add_subdirectory (leaf_comp_b) +add_subdirectory (parent_with_one_child) +add_subdirectory (parent_with_two_children) diff --git a/tutorial/grid_comps/hello_world_gridcomp/CMakeLists.txt b/tutorial/grid_comps/hello_world_gridcomp/CMakeLists.txt new file mode 100644 index 000000000000..e73d833a3992 --- /dev/null +++ b/tutorial/grid_comps/hello_world_gridcomp/CMakeLists.txt @@ -0,0 +1,10 @@ +esma_set_this (OVERRIDE MAPL.hello_world_gridcomp) +set (srcs + HelloWorld_GridComp.F90 + ) + +esma_add_library (${this} SRCS ${srcs} DEPENDENCIES MAPL.shared MAPL TYPE ${MAPL_LIBRARY_TYPE}) +target_link_libraries (${this} PRIVATE esmf OpenMP::OpenMP_Fortran) +target_include_directories (${this} PUBLIC $) +set_target_properties (${this} PROPERTIES Fortran_MODULE_DIRECTORY ${include_${this}}) +#target_compile_definitions(${this} PRIVATE SYSTEM_DSO_SUFFIX="${CMAKE_SHARED_LIBRARY_SUFFIX}") diff --git a/tutorial/grid_comps/hello_world_gridcomp/HelloWorld_GridComp.F90 b/tutorial/grid_comps/hello_world_gridcomp/HelloWorld_GridComp.F90 new file mode 100644 index 000000000000..94ec32261eb8 --- /dev/null +++ b/tutorial/grid_comps/hello_world_gridcomp/HelloWorld_GridComp.F90 @@ -0,0 +1,75 @@ +#include "MAPL_Generic.h" +#include "MAPL_Exceptions.h" +module HelloWorld_GridComp + + use ESMF + use MAPL + + implicit none + private + + public setservices + + contains + + subroutine setservices(gc,rc) + + type(ESMF_GridComp), intent(inout) :: gc + integer, optional :: rc + + integer :: status + + call MAPL_GridCompSetEntryPoint ( gc, ESMF_METHOD_INITIALIZE, my_initialize, _RC) + call MAPL_GridCompSetEntryPoint ( gc, ESMF_METHOD_RUN, my_run, _RC) + call MAPL_GenericSetServices(gc, _RC) + _RETURN(_SUCCESS) + + end subroutine setservices + + + subroutine my_initialize(gc, import, export, clock, rc) + type(ESMF_GridComp), intent(inout) :: gc + type(ESMF_State), intent(inout) :: import + type(ESMF_State), intent(inout) :: export + type(ESMF_Clock), intent(inout) :: clock + integer, intent(out), optional :: rc + + integer :: status + + call MAPL_GridCreate(gc, _RC) + call MAPL_GenericInitialize(gc, import, export, clock, _RC) + + _RETURN(_SUCCESS) + + end subroutine my_initialize + + + subroutine my_run(gc, import, export, clock, rc) + type(ESMF_GridComp), intent(inout) :: gc + type(ESMF_State), intent(inout) :: import + type(ESMF_State), intent(inout) :: export + type(ESMF_Clock), intent(inout) :: clock + integer, intent(out), optional :: rc + + type(ESMF_Time) :: current_time + integer :: status + + call ESMF_ClockGet(clock,currTime=current_time,_RC) + write(*,*) + write(*,*) + write(*,*)"Hello World, I say the time is:" + call ESMF_TimePrint(current_time,options='string',_RC) + + _RETURN(_SUCCESS) + + end subroutine my_run + +end module HelloWorld_GridComp + +subroutine SetServices(gc, rc) + use ESMF + use HelloWorld_GridComp, only : mySetservices=>SetServices + type(ESMF_GridComp) :: gc + integer, intent(out) :: rc + call mySetServices(gc, rc=rc) +end subroutine diff --git a/tutorial/grid_comps/leaf_comp_a/AAA_GridComp.F90 b/tutorial/grid_comps/leaf_comp_a/AAA_GridComp.F90 new file mode 100644 index 000000000000..444666f066cc --- /dev/null +++ b/tutorial/grid_comps/leaf_comp_a/AAA_GridComp.F90 @@ -0,0 +1,83 @@ +#include "MAPL_Generic.h" +#include "MAPL_Exceptions.h" +module AAA_GridComp + + use ESMF + use MAPL + + implicit none + private + + public setservices + + contains + + subroutine setservices(gc,rc) + + type(ESMF_GridComp), intent(inout) :: gc + integer, optional :: rc + + integer :: status + + call MAPL_GridCompSetEntryPoint ( gc, ESMF_METHOD_INITIALIZE, my_initialize, _RC) + call MAPL_GridCompSetEntryPoint ( gc, ESMF_METHOD_RUN, my_run, _RC) + + call MAPL_AddExportSpec(gc,short_name='field1', long_name='NA',units='NA', & + dims = MAPL_DimsHorzOnly, & + vlocation = MAPL_VLocationNone, _RC) + + + call MAPL_GenericSetServices(gc, _RC) + _RETURN(_SUCCESS) + + end subroutine setservices + + + subroutine my_initialize(gc, import, export, clock, rc) + type(ESMF_GridComp), intent(inout) :: gc + type(ESMF_State), intent(inout) :: import + type(ESMF_State), intent(inout) :: export + type(ESMF_Clock), intent(inout) :: clock + integer, intent(out), optional :: rc + + integer :: status + + call MAPL_GenericInitialize(gc, import, export, clock, _RC) + + _RETURN(_SUCCESS) + + end subroutine my_initialize + + + subroutine my_run(gc, import, export, clock, rc) + type(ESMF_GridComp), intent(inout) :: gc + type(ESMF_State), intent(inout) :: import + type(ESMF_State), intent(inout) :: export + type(ESMF_Clock), intent(inout) :: clock + integer, intent(out), optional :: rc + + real, pointer :: ptr_2d(:,:) + type(ESMF_Time) :: current_time, start_time + type(ESMF_TimeInterval) :: time_interval + real(ESMF_KIND_R8) :: relative_time + integer :: status + + call MAPL_GetPointer(export,ptr_2d,'field1',_RC) + call ESMF_ClockGet(clock,currTime=current_time,startTime=start_time,_RC) + time_interval = current_time - start_time + call ESMF_TimeIntervalGet(time_interval,h_r8=relative_time,_RC) + if (associated(ptr_2d)) ptr_2d = relative_time + + _RETURN(_SUCCESS) + + end subroutine my_run + +end module AAA_GridComp + +subroutine SetServices(gc, rc) + use ESMF + use AAA_GridComp, only : mySetservices=>SetServices + type(ESMF_GridComp) :: gc + integer, intent(out) :: rc + call mySetServices(gc, rc=rc) +end subroutine diff --git a/tutorial/grid_comps/leaf_comp_a/CMakeLists.txt b/tutorial/grid_comps/leaf_comp_a/CMakeLists.txt new file mode 100644 index 000000000000..01e9e9b6df6d --- /dev/null +++ b/tutorial/grid_comps/leaf_comp_a/CMakeLists.txt @@ -0,0 +1,10 @@ +esma_set_this (OVERRIDE MAPL.aaa) +set (srcs + AAA_GridComp.F90 + ) + +esma_add_library (${this} SRCS ${srcs} DEPENDENCIES MAPL.shared MAPL TYPE ${MAPL_LIBRARY_TYPE}) +target_link_libraries (${this} PRIVATE esmf OpenMP::OpenMP_Fortran) +target_include_directories (${this} PUBLIC $) +set_target_properties (${this} PROPERTIES Fortran_MODULE_DIRECTORY ${include_${this}}) +#target_compile_definitions(${this} PRIVATE SYSTEM_DSO_SUFFIX="${CMAKE_SHARED_LIBRARY_SUFFIX}") diff --git a/tutorial/grid_comps/leaf_comp_b/BBB_GridComp.F90 b/tutorial/grid_comps/leaf_comp_b/BBB_GridComp.F90 new file mode 100644 index 000000000000..ef8eb94d565d --- /dev/null +++ b/tutorial/grid_comps/leaf_comp_b/BBB_GridComp.F90 @@ -0,0 +1,77 @@ +#include "MAPL_Generic.h" +#include "MAPL_Exceptions.h" +module BBB_GridComp + + use ESMF + use MAPL + + implicit none + private + + public setservices + + contains + + subroutine setservices(gc,rc) + + type(ESMF_GridComp), intent(inout) :: gc + integer, optional :: rc + + integer :: status + + call MAPL_GridCompSetEntryPoint ( gc, ESMF_METHOD_INITIALIZE, my_initialize, _RC) + call MAPL_GridCompSetEntryPoint ( gc, ESMF_METHOD_RUN, my_run, _RC) + + call MAPL_AddImportSpec(gc,short_name='field1', long_name='NA',units='NA', & + dims = MAPL_DimsHorzOnly, & + vlocation = MAPL_VLocationNone, _RC) + + + call MAPL_GenericSetServices(gc, _RC) + _RETURN(_SUCCESS) + + end subroutine setservices + + + subroutine my_initialize(gc, import, export, clock, rc) + type(ESMF_GridComp), intent(inout) :: gc + type(ESMF_State), intent(inout) :: import + type(ESMF_State), intent(inout) :: export + type(ESMF_Clock), intent(inout) :: clock + integer, intent(out), optional :: rc + + integer :: status + + call MAPL_GenericInitialize(gc, import, export, clock, _RC) + + _RETURN(_SUCCESS) + + end subroutine my_initialize + + + subroutine my_run(gc, import, export, clock, rc) + type(ESMF_GridComp), intent(inout) :: gc + type(ESMF_State), intent(inout) :: import + type(ESMF_State), intent(inout) :: export + type(ESMF_Clock), intent(inout) :: clock + integer, intent(out), optional :: rc + + real, pointer :: ptr_2d(:,:) + integer :: status + + call MAPL_GetPointer(import,ptr_2d,'field1',_RC) + write(*,*)"BBB import 1 maxval: ",maxval(ptr_2d) + + _RETURN(_SUCCESS) + + end subroutine my_run + +end module BBB_GridComp + +subroutine SetServices(gc, rc) + use ESMF + use BBB_GridComp, only : mySetservices=>SetServices + type(ESMF_GridComp) :: gc + integer, intent(out) :: rc + call mySetServices(gc, rc=rc) +end subroutine diff --git a/tutorial/grid_comps/leaf_comp_b/CMakeLists.txt b/tutorial/grid_comps/leaf_comp_b/CMakeLists.txt new file mode 100644 index 000000000000..7c272521d5c7 --- /dev/null +++ b/tutorial/grid_comps/leaf_comp_b/CMakeLists.txt @@ -0,0 +1,10 @@ +esma_set_this (OVERRIDE MAPL.bbb) +set (srcs + BBB_GridComp.F90 + ) + +esma_add_library (${this} SRCS ${srcs} DEPENDENCIES MAPL.shared MAPL TYPE ${MAPL_LIBRARY_TYPE}) +target_link_libraries (${this} PRIVATE esmf OpenMP::OpenMP_Fortran) +target_include_directories (${this} PUBLIC $) +set_target_properties (${this} PROPERTIES Fortran_MODULE_DIRECTORY ${include_${this}}) +#target_compile_definitions(${this} PRIVATE SYSTEM_DSO_SUFFIX="${CMAKE_SHARED_LIBRARY_SUFFIX}") diff --git a/tutorial/grid_comps/parent_with_no_children/CMakeLists.txt b/tutorial/grid_comps/parent_with_no_children/CMakeLists.txt new file mode 100644 index 000000000000..e370ad84e3ed --- /dev/null +++ b/tutorial/grid_comps/parent_with_no_children/CMakeLists.txt @@ -0,0 +1,10 @@ +esma_set_this (OVERRIDE MAPL.parent_no_children) +set (srcs + ParentNoChildren_GridComp.F90 + ) + +esma_add_library (${this} SRCS ${srcs} DEPENDENCIES MAPL.shared MAPL TYPE ${MAPL_LIBRARY_TYPE}) +target_link_libraries (${this} PRIVATE esmf OpenMP::OpenMP_Fortran) +target_include_directories (${this} PUBLIC $) +set_target_properties (${this} PROPERTIES Fortran_MODULE_DIRECTORY ${include_${this}}) +#target_compile_definitions(${this} PRIVATE SYSTEM_DSO_SUFFIX="${CMAKE_SHARED_LIBRARY_SUFFIX}") diff --git a/tutorial/grid_comps/parent_with_no_children/ParentNoChildren_GridComp.F90 b/tutorial/grid_comps/parent_with_no_children/ParentNoChildren_GridComp.F90 new file mode 100644 index 000000000000..80c37872ae84 --- /dev/null +++ b/tutorial/grid_comps/parent_with_no_children/ParentNoChildren_GridComp.F90 @@ -0,0 +1,88 @@ +#include "MAPL_Generic.h" +#include "MAPL_Exceptions.h" +module ParentNoChild_GridComp + + use ESMF + use MAPL + + implicit none + private + + public setservices + + contains + + subroutine setservices(gc,rc) + + type(ESMF_GridComp), intent(inout) :: gc + integer, optional :: rc + + integer :: status + + call MAPL_GridCompSetEntryPoint ( gc, ESMF_METHOD_INITIALIZE, my_initialize, _RC) + call MAPL_GridCompSetEntryPoint ( gc, ESMF_METHOD_RUN, my_run, _RC) + + call MAPL_AddExportSpec(gc,short_name='output1', long_name='NA',units='NA', & + dims = MAPL_DimsHorzOnly, & + vlocation = MAPL_VLocationNone, _RC) + call MAPL_AddExportSpec(gc,short_name='output2', long_name='NA',units='NA', & + dims = MAPL_DimsHorzVert, & + vlocation = MAPL_VLocationCenter, _RC) + + + + call MAPL_GenericSetServices(gc, _RC) + _RETURN(_SUCCESS) + + end subroutine setservices + + + subroutine my_initialize(gc, import, export, clock, rc) + type(ESMF_GridComp), intent(inout) :: gc + type(ESMF_State), intent(inout) :: import + type(ESMF_State), intent(inout) :: export + type(ESMF_Clock), intent(inout) :: clock + integer, intent(out), optional :: rc + + integer :: status + + call MAPL_GridCreate(gc, _RC) + call MAPL_GenericInitialize(gc, import, export, clock, _RC) + + _RETURN(_SUCCESS) + + end subroutine my_initialize + + + subroutine my_run(gc, import, export, clock, rc) + type(ESMF_GridComp), intent(inout) :: gc + type(ESMF_State), intent(inout) :: import + type(ESMF_State), intent(inout) :: export + type(ESMF_Clock), intent(inout) :: clock + integer, intent(out), optional :: rc + + real, pointer :: ptr_2d(:,:), ptr_3d(:,:) + type (MAPL_MetaComp), pointer :: MAPL + real :: my_constant + integer :: status + + call MAPL_GetObjectFromGC ( GC, MAPL, _RC) + call MAPL_GetResource(MAPL, my_constant, Label="my_value:", default=17.0,_RC) + call MAPL_GetPointer(export,ptr_2d,'output1',_RC) + if (associated(ptr_2d)) ptr_2d = my_constant + call MAPL_GetPointer(export,ptr_3d,'output2',_RC) + if (associated(ptr_3d)) ptr_3d = my_constant + + _RETURN(_SUCCESS) + + end subroutine my_run + +end module ParentNoChild_GridComp + +subroutine SetServices(gc, rc) + use ESMF + use ParentNoChild_GridComp, only : mySetservices=>SetServices + type(ESMF_GridComp) :: gc + integer, intent(out) :: rc + call mySetServices(gc, rc=rc) +end subroutine diff --git a/tutorial/grid_comps/parent_with_one_child/CMakeLists.txt b/tutorial/grid_comps/parent_with_one_child/CMakeLists.txt new file mode 100644 index 000000000000..c0ca68ae25ac --- /dev/null +++ b/tutorial/grid_comps/parent_with_one_child/CMakeLists.txt @@ -0,0 +1,10 @@ +esma_set_this (OVERRIDE MAPL.parent_one_child) +set (srcs + ParentOneChild_GridComp.F90 + ) + +esma_add_library (${this} SRCS ${srcs} DEPENDENCIES MAPL.shared MAPL TYPE ${MAPL_LIBRARY_TYPE}) +target_link_libraries (${this} PRIVATE esmf OpenMP::OpenMP_Fortran) +target_include_directories (${this} PUBLIC $) +set_target_properties (${this} PROPERTIES Fortran_MODULE_DIRECTORY ${include_${this}}) +#target_compile_definitions(${this} PRIVATE SYSTEM_DSO_SUFFIX="${CMAKE_SHARED_LIBRARY_SUFFIX}") diff --git a/tutorial/grid_comps/parent_with_one_child/ParentOneChild_GridComp.F90 b/tutorial/grid_comps/parent_with_one_child/ParentOneChild_GridComp.F90 new file mode 100644 index 000000000000..1b61b22c4a87 --- /dev/null +++ b/tutorial/grid_comps/parent_with_one_child/ParentOneChild_GridComp.F90 @@ -0,0 +1,93 @@ +#include "MAPL_Generic.h" +#include "MAPL_Exceptions.h" +module ParentOneChild_GridComp + + use ESMF + use MAPL + + implicit none + private + + public setservices + + integer :: child1 + + contains + + subroutine setservices(gc,rc) + + type(ESMF_GridComp), intent(inout) :: gc + integer, optional :: rc + + integer :: status + type(MAPL_MetaComp), pointer :: MAPL + character(len=80) :: my_child_name, my_child_so + + call MAPL_GetObjectFromGC ( GC, MAPL, _RC) + call MAPL_GetResource(MAPL, my_child_name, Label="my_child_name:",_RC) + call MAPL_GetResource(MAPL, my_child_so, Label="my_child_so:",_RC) + + call MAPL_GridCompSetEntryPoint ( gc, ESMF_METHOD_INITIALIZE, my_initialize, _RC) + call MAPL_GridCompSetEntryPoint ( gc, ESMF_METHOD_RUN, my_run, _RC) + + call MAPL_AddExportSpec(gc,short_name='output1', long_name='NA',units='NA', & + dims = MAPL_DimsHorzOnly, & + vlocation = MAPL_VLocationNone, _RC) + + child1 = MAPL_AddChild(gc, my_child_name, "setservices_", sharedObj=my_child_so, _RC) + + call MAPL_GenericSetServices(gc, _RC) + _RETURN(_SUCCESS) + + end subroutine setservices + + + subroutine my_initialize(gc, import, export, clock, rc) + type(ESMF_GridComp), intent(inout) :: gc + type(ESMF_State), intent(inout) :: import + type(ESMF_State), intent(inout) :: export + type(ESMF_Clock), intent(inout) :: clock + integer, intent(out), optional :: rc + + integer :: status + + call MAPL_GridCreate(gc, _RC) + call MAPL_GenericInitialize(gc, import, export, clock, _RC) + + _RETURN(_SUCCESS) + + end subroutine my_initialize + + + subroutine my_run(gc, import, export, clock, rc) + type(ESMF_GridComp), intent(inout) :: gc + type(ESMF_State), intent(inout) :: import + type(ESMF_State), intent(inout) :: export + type(ESMF_Clock), intent(inout) :: clock + integer, intent(out), optional :: rc + + type(MAPL_MetaComp), pointer :: MAPL + real, pointer :: ptr_2d(:,:) + real :: my_constant + integer :: status + + call MAPL_GetObjectFromGC ( GC, MAPL, _RC) + call MAPL_GetResource(MAPL, my_constant, Label="my_value:", default=17.0,_RC) + call MAPL_GetPointer(export,ptr_2d,'output1',_RC) + if (associated(ptr_2d)) ptr_2d = my_constant + + call MAPL_GenericRunChildren(gc, import, export, clock, _RC) + + _RETURN(_SUCCESS) + + end subroutine my_run + +end module ParentOneChild_GridComp + +subroutine SetServices(gc, rc) + use ESMF + use ParentOneChild_GridComp, only : mySetservices=>SetServices + type(ESMF_GridComp) :: gc + integer, intent(out) :: rc + call mySetServices(gc, rc=rc) +end subroutine diff --git a/tutorial/grid_comps/parent_with_two_children/CMakeLists.txt b/tutorial/grid_comps/parent_with_two_children/CMakeLists.txt new file mode 100644 index 000000000000..e79ece0e2b32 --- /dev/null +++ b/tutorial/grid_comps/parent_with_two_children/CMakeLists.txt @@ -0,0 +1,10 @@ +esma_set_this (OVERRIDE MAPL.parent_two_siblings) +set (srcs + ParentTwoSiblings_GridComp.F90 + ) + +esma_add_library (${this} SRCS ${srcs} DEPENDENCIES MAPL.shared MAPL TYPE ${MAPL_LIBRARY_TYPE}) +target_link_libraries (${this} PRIVATE esmf OpenMP::OpenMP_Fortran) +target_include_directories (${this} PUBLIC $) +set_target_properties (${this} PROPERTIES Fortran_MODULE_DIRECTORY ${include_${this}}) +#target_compile_definitions(${this} PRIVATE SYSTEM_DSO_SUFFIX="${CMAKE_SHARED_LIBRARY_SUFFIX}") diff --git a/tutorial/grid_comps/parent_with_two_children/ParentTwoSiblings_GridComp.F90 b/tutorial/grid_comps/parent_with_two_children/ParentTwoSiblings_GridComp.F90 new file mode 100644 index 000000000000..be0a3257234c --- /dev/null +++ b/tutorial/grid_comps/parent_with_two_children/ParentTwoSiblings_GridComp.F90 @@ -0,0 +1,103 @@ +#include "MAPL_Generic.h" +#include "MAPL_Exceptions.h" +module ParentTwoSiblings_GridComp + + use ESMF + use MAPL + + implicit none + private + + public setservices + + integer :: child1 + integer :: child2 + + contains + + subroutine setservices(gc,rc) + + type(ESMF_GridComp), intent(inout) :: gc + integer, optional :: rc + + integer :: status + type(MAPL_MetaComp), pointer :: MAPL + character(len=80) :: my_child1_name, my_child1_so + character(len=80) :: my_child2_name, my_child2_so + + call MAPL_GetObjectFromGC ( GC, MAPL, _RC) + call MAPL_GetResource(MAPL, my_child1_name, Label="my_child1_name:",_RC) + call MAPL_GetResource(MAPL, my_child1_so, Label="my_child1_so:",_RC) + call MAPL_GetResource(MAPL, my_child2_name, Label="my_child2_name:",_RC) + call MAPL_GetResource(MAPL, my_child2_so, Label="my_child2_so:",_RC) + + call MAPL_GridCompSetEntryPoint ( gc, ESMF_METHOD_INITIALIZE, my_initialize, _RC) + call MAPL_GridCompSetEntryPoint ( gc, ESMF_METHOD_RUN, my_run, _RC) + + call MAPL_AddExportSpec(gc,short_name='output1', long_name='NA',units='NA', & + dims = MAPL_DimsHorzOnly, & + vlocation = MAPL_VLocationNone, _RC) + + child1 = MAPL_AddChild(gc, my_child1_name, "setservices_", sharedObj=my_child1_so, _RC) + child2 = MAPL_AddChild(gc, my_child2_name, "setservices_", sharedObj=my_child2_so, _RC) + call MAPL_AddConnectivity(gc, & + short_name = ["field1"], & + src_id = child1, & + dst_id = child2, & + _RC) + + call MAPL_GenericSetServices(gc, _RC) + _RETURN(_SUCCESS) + + end subroutine setservices + + + subroutine my_initialize(gc, import, export, clock, rc) + type(ESMF_GridComp), intent(inout) :: gc + type(ESMF_State), intent(inout) :: import + type(ESMF_State), intent(inout) :: export + type(ESMF_Clock), intent(inout) :: clock + integer, intent(out), optional :: rc + + integer :: status + + call MAPL_GridCreate(gc, _RC) + call MAPL_GenericInitialize(gc, import, export, clock, _RC) + + _RETURN(_SUCCESS) + + end subroutine my_initialize + + + subroutine my_run(gc, import, export, clock, rc) + type(ESMF_GridComp), intent(inout) :: gc + type(ESMF_State), intent(inout) :: import + type(ESMF_State), intent(inout) :: export + type(ESMF_Clock), intent(inout) :: clock + integer, intent(out), optional :: rc + + type(MAPL_MetaComp), pointer :: MAPL + real, pointer :: ptr_2d(:,:) + real :: my_constant + integer :: status + + call MAPL_GetObjectFromGC ( GC, MAPL, _RC) + call MAPL_GetResource(MAPL, my_constant, Label="my_value:", default=17.0,_RC) + call MAPL_GetPointer(export,ptr_2d,'output1',_RC) + if (associated(ptr_2d)) ptr_2d = my_constant + + call MAPL_GenericRunChildren(gc, import, export, clock, _RC) + + _RETURN(_SUCCESS) + + end subroutine my_run + +end module ParentTwoSiblings_GridComp + +subroutine SetServices(gc, rc) + use ESMF + use ParentTwoSiblings_GridComp, only : mySetservices=>SetServices + type(ESMF_GridComp) :: gc + integer, intent(out) :: rc + call mySetServices(gc, rc=rc) +end subroutine diff --git a/tutorial/mapl_tutorials/hello_world/CAP.rc b/tutorial/mapl_tutorials/hello_world/CAP.rc new file mode 100644 index 000000000000..da07b2afa230 --- /dev/null +++ b/tutorial/mapl_tutorials/hello_world/CAP.rc @@ -0,0 +1,10 @@ +ROOT_NAME: hello_world +HIST_CF: HISTORY.rc + + +ROOT_CF: hello_world.rc + +BEG_DATE: 20070801 000000 +END_DATE: 29990302 210000 +JOB_SGMT: 00000001 000000 +HEARTBEAT_DT: 3600 diff --git a/tutorial/mapl_tutorials/hello_world/ExtData.rc b/tutorial/mapl_tutorials/hello_world/ExtData.rc new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tutorial/mapl_tutorials/hello_world/HISTORY.rc b/tutorial/mapl_tutorials/hello_world/HISTORY.rc new file mode 100644 index 000000000000..d3a6677416e1 --- /dev/null +++ b/tutorial/mapl_tutorials/hello_world/HISTORY.rc @@ -0,0 +1,5 @@ +GRID_LABELS: +:: + +COLLECTIONS: +:: diff --git a/tutorial/mapl_tutorials/hello_world/README.md b/tutorial/mapl_tutorials/hello_world/README.md new file mode 100644 index 000000000000..59b1075b196d --- /dev/null +++ b/tutorial/mapl_tutorials/hello_world/README.md @@ -0,0 +1,140 @@ +# Tutorial 1 - Hello World +Note the code for the gridded component used by this tutorial can be found here: + +tutorial/grid_comps/hello_world_gridcomp/HelloWorld_GridComp.F90 + +For this tutorial we will make the simplest possible gridded component we can and have it print hello in its run method. + +The gridded component itself is run from the MAPL "CAP". This is a layer that the user should never have to touch. Its main function, as far as the user is concerned, is to perform the time stepping controlled via the CAP.rc and run the "root" gridded component (in this example HelloWorld_GridComp.F90) the user or program specified, as well as two other special gridded components, "History" and "ExtData", that provide services that we will talk about in later tutorials. + +# HelloWorld_GridComp.F90 Explanation + +If you look in the gridded component you will see that it is quite simple and is just about the minumum lines needed to create a gridded component, a grid for the component, and a run method that does something. + +The first routine is the setServices. This is the ONLY routine in the module that should be public. Everything else should be private. In addition the SetServices interface must match the interface defined by ESMF> The main function of the SetServies is to let the user registers the actual methods to be used during the initialize and run phases of the gridded component. These specifed via the SetEntryPoint calls and methods defined in the same module. They also must be defined with the interface prescribed by ESMF. In addition, the MAPL_GenericSetServices is called in this routine and every MAPL component must call this before ending the subroutine. The MAPL_GenericSetServices handles all the extra services provided by MAPL beyond EMSF. + +Next we see that a custom initialization routine "my_initialize" is created. Notice the subroutine interface. This is the interface all initialize, run, and finalize methods registered my ESMF SetEntryPoint methods must follow. The import state contains all the fields (as well as possibly other types) that will be needed to run the component. The component should not modify the import state. Likewise the export state is what the gridded component produces for use by other components. Finally the clock is just that, a clock that defines the current temporal situation. + +In this exmaple, the initialize routine only has two calls. The first tells it how to create the grid that is will be used by the gridded component. + +MAPL_GridCreate actually examines the components RC file which in this case is "hello_world.rc". The user will notice these lines: +``` +hello_world.GRID_TYPE: LatLon +hello_world.GRIDNAME: DC90x45-PC +hello_world.LM: 72 +hello_world.IM_WORLD: 90 +hello_world.JM_WORLD: 45 +hello_world.POLE: 'PC' +hello_world.DATELINE: 'DC' +``` +Generally the user will not have to modify these are the setup scripts when running the model would define this for you. In this case it is saying the grid will be a 90x45 lat-lon grid with LM vertical levels. + +After this call MAPL_GenericInitialize is called. This is again a MAPL call that handles all the MAPL specify functionality. It also calls the initialize methods of any child, which will be discussed subsequent tutorials. Once again every custom initialize routine must call this. If no custom initialize routine is defined this will be called automatically. + +Finally we get to the run method my_run. Notice it has the same interface the initialize method. This was registered and will be executed each time step. As you can see if does very little in this example. It gets the current time from the ESMF clock (this literally a clock that is advanced by the MAPL "CAP"). The time is stored in a variable of `type(ESMF_Time)` declared in the subroutine. It then prints the obligatory "Hello World" and finally uses an ESMF cal which takes an ESMF time and prints it as a string. + +# A Note on Error Handling +You will notice that the setServices, initialize, and run subroutines all have an optional rc return variable. This is represents a return code that the calling routine can check to see if the subroutine executed successfully or produced an error. All ESMF and MAPL subroutines and functions have an optional rc value that can be checked when making a call. To check the return status you would do something like this. +``` +integer :: status + + +call ESMF_Foo(arg1,arg2,rc=status) +if (status/=ESMF_SUCCESS) then + if present(rc)) then + rc =status + write(*,*)"Error ",rc," in ",__FILE," on ",__LINE__ + return + end if +end +``` + +This would get very tedious, not to mention make the code hard to read if the user had to do this after every subroutine or function call. To assist the developer MAPL defines a collection of preprocessor macros for error checking . + +You will notice that all subroutine calls in this example end with `_RC`. This is a preprocessor macro that expands to `rc=status); _VERIFY(status`. + +`_VERIFY` itself is another macro that essentially implements the lines after the call to `ESMF_Foo` in the previous example. It will check the status and if there is an error report the file and line and return. + +At the end of each subroutine you will notice another macro, `_RETURN(_SUCCESS)`. This macro ensures that if the optional rc code is passed, it will be set to the "succes" value if the caller is checking the return code. It general placed at the very end of a subroutine. + +All new functions and subroutines should have an optional rc code and use these macros. It will make debugging and crash analysis much easier. + +# Running the code +When you run the code the first few lines will look like this: +``` +srun: cluster configuration lacks support for cpu binding + MAPL: No configure file specified for logging layer. Using defaults. + Starting pFIO input server on Clients + Starting pFIO output server on Clients + MAPL: Running with MOAB library for ESMF Mesh: F + SHMEM: NumCores per Node = 1 + SHMEM: NumNodes in use = 1 + SHMEM: Total PEs = 1 + SHMEM: NumNodes in use = 1 + Integer*4 Resource Parameter: HEARTBEAT_DT:3600 + NOT using buffer I/O for file: cap_restart + CAP: Read CAP restart properly, Current Date = 2007/08/01 + CAP: Current Time = 00/00/00 + Character Resource Parameter: ROOT_CF:hello_world.rc + Character Resource Parameter: ROOT_NAME:hello_world + Character Resource Parameter: HIST_CF:HISTORY.rc + oserver is not split + + EXPSRC: + EXPID: + Descr: + DisableSubVmChecks: F + BlockSize: 10 + MarkDone: 0 + PrePost: 1 + + Reading HISTORY RC Files: + ------------------------- + + + Hello World, I say the time is: +Time ----------------------------------- +2007-08-01T00:00:00 +end Time ------------------------------- + + AGCM Date: 2007/08/01 Time: 01:00:00 Throughput(days/day)[Avg Tot Run]: 407962.2 410922.5 18590964.7 TimeRemaining(Est) 000:00:00 2.7% : 13.3% Mem Comm:Used + + + Hello World, I say the time is: +Time ----------------------------------- +2007-08-01T01:00:00 +end Time ------------------------------- + + AGCM Date: 2007/08/01 Time: 02:00:00 Throughput(days/day)[Avg Tot Run]: 21061906.1 10684057.3 25508595.8 TimeRemaining(Est) 000:00:00 2.7% : 13.3% Mem Comm:Used + ``` + Lets see how this corresponds to what is in the input files. + + First lets discuss the CAP.rc, the relevant lines are + ``` + JOB_SGMT: 00000001 000000 +HEARTBEAT_DT: 3600 +``` +which tell the MAPL "CAP" to run 1 day via the JOB_SGMT line and with a timestep of 3600s. In addition the +``` +ROOT_CF: hello_world.rc +``` +tells "CAP" that the root component will use hello_world.rc. +Finally you will notice that hello_world.rc has these lines: +``` +NX: 1 +NY: 1 +``` +This says we will be using decomposing each dimension of the grid by 1 (so no decomposition at all!). A rule of thumb, the number of MPI tasks must be equal to NX*NY. + +Finally in you should see a "cap_restart" file in the run directory. This is the time the application will actually start at. It must be equal or later than the BEG_DATE in the CAP.rc and before the END_DATE. Note that generally these are only needed when running real experiments with the model. One final note about the "cap_restart". When the application finishes it overwrites the cap_restart with the final application time. + +Now to connect this to the output. We see the that it reports +``` +SHMEM: Total PEs = 1 +``` +which says we are using 1 MPI task. +Then later you the tell works and quick glance should confirm it is stepping the clock by 1 hour each time. Finally you see lines like this: +``` +AGCM Date: 2007/08/01 Time: 02:00:00 Throughput(days/day)[Avg Tot Run]: 21061906.1 10684057.3 25508595.8 TimeRemaining(Est) 000:00:00 2.7% : 13.3% Mem Comm:Used +``` +This is actually reported by the "CAP" itself. and prints the current time as well as some statistics about memroy use and throughput. The astute user will notice that the time reported here is 1 hour after the time printed in the gridded component. This is because the clock is advanced at the end of each iteration in the "CAP", after the component is run and this reporting is at the very end of each iteration. diff --git a/tutorial/mapl_tutorials/hello_world/cap_restart b/tutorial/mapl_tutorials/hello_world/cap_restart new file mode 100644 index 000000000000..d61015bfaab6 --- /dev/null +++ b/tutorial/mapl_tutorials/hello_world/cap_restart @@ -0,0 +1 @@ +20070801 000000 diff --git a/tutorial/mapl_tutorials/hello_world/hello_world.rc b/tutorial/mapl_tutorials/hello_world/hello_world.rc new file mode 100644 index 000000000000..4eb08053f1f6 --- /dev/null +++ b/tutorial/mapl_tutorials/hello_world/hello_world.rc @@ -0,0 +1,10 @@ +NX: 1 +NY: 1 + +hello_world.GRID_TYPE: LatLon +hello_world.GRIDNAME: DC90x45-PC +hello_world.LM: 72 +hello_world.IM_WORLD: 90 +hello_world.JM_WORLD: 45 +hello_world.POLE: 'PC' +hello_world.DATELINE: 'DC' diff --git a/tutorial/mapl_tutorials/hello_world/root_lib b/tutorial/mapl_tutorials/hello_world/root_lib new file mode 100644 index 000000000000..7956352b0320 --- /dev/null +++ b/tutorial/mapl_tutorials/hello_world/root_lib @@ -0,0 +1 @@ +libMAPL.hello_world_gridcomp.so diff --git a/tutorial/mapl_tutorials/parent_no_children/CAP.rc b/tutorial/mapl_tutorials/parent_no_children/CAP.rc new file mode 100644 index 000000000000..b613b5f5ceb6 --- /dev/null +++ b/tutorial/mapl_tutorials/parent_no_children/CAP.rc @@ -0,0 +1,9 @@ +ROOT_NAME: root +HIST_CF: HISTORY.rc + +ROOT_CF: root.rc + +BEG_DATE: 20070801 000000 +END_DATE: 29990302 210000 +JOB_SGMT: 00000001 000000 +HEARTBEAT_DT: 3600 diff --git a/tutorial/mapl_tutorials/parent_no_children/ExtData.rc b/tutorial/mapl_tutorials/parent_no_children/ExtData.rc new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tutorial/mapl_tutorials/parent_no_children/HISTORY.rc b/tutorial/mapl_tutorials/parent_no_children/HISTORY.rc new file mode 100644 index 000000000000..28cfb9eaf6bf --- /dev/null +++ b/tutorial/mapl_tutorials/parent_no_children/HISTORY.rc @@ -0,0 +1,12 @@ +GRID_LABELS: +:: + +COLLECTIONS: my_collection +:: + +my_collection.template: "%y4%m2%d2_%h2%n2z.nc4" +my_collection.format: 'CFIO' +my_collection.frequency: 060000 +my_collection.fields: 'output1', 'root' + :: + diff --git a/tutorial/mapl_tutorials/parent_no_children/README.md b/tutorial/mapl_tutorials/parent_no_children/README.md new file mode 100644 index 000000000000..d09b4cd59914 --- /dev/null +++ b/tutorial/mapl_tutorials/parent_no_children/README.md @@ -0,0 +1,56 @@ +# Tutorial 2 - Gridded Component: Create a Field and Write Out Via History +In this tutorial we will take the Hello World example a step further and demonstrate more features. I will only focus on what is added here so make sure you understand the Hello World example first. + +Note the code for the gridded component used by this tutorial can be found here: + +tutorial/grid_comps/parent_with_no_children/ParentNoChildren_GridComp.F90 + + + + +# ParentNoChildren_GridComp.F90 + +The user will notice several new things in this example. First look at the setServices routine. Notice the two MAPL_AddExportSpec calls. Each call tells the component to create an ESMF_Field in the components Export state and information about the dimensionality of the field. In this example output1 is a 2D field with no vertical levels and output2 is a 3D field. This call merely tells MAPL to create the field but does not actually create it until the components MAPL_GenericInitialize is run. + +The my_initialize routine looks the same as the Hello World example. + +Finally the my_run call now has some new stuff. First the user will notice some new declarations, a couple of real pointers as well as a MAPL_MetaComp object. +The MAPL_MetaComp is an internal derived type stored in the gridded component that stores MAPL specific information beyond what ESMF stores. +Past the declarations, we see we first retrieve the MAPL_MetaComp from the gridded component. Next, we call MAPL_GetResource which is a shorthand way to retrieve information from the components rc file which in this case is "root.rc". The call is looking for a key name "my_value:" and if the user examines the rc file they indeed will see this line: +``` +my_value: 11.0 +``` +Finally there are two calls to MAPL_GetPointer which is a shorthand way to obtain a Fortran pointer to the data in an ESMF_Field, contained in an ESMF_State. Through the magic of MAPL, the user will find that there are indeed two fields in the state named ouput1 and output2! All this was handled by MAPL and ESMF!. Notice that a check is mde to determine if the pointer is associated before using it. Only if the pointer is actually associated can it be used. If it is associated, in this case all the values of the array are set to the constant my_constat. Why do we check the associated status? Because exports might not have been allocated. Imports always are, so the rule is for any pointer from an Export state, always check the associated status before using it. + +$ HISTORY.rc + +If one looks in the tutorial directory for this example you will see the History.rc contains these lines: +``` +GRID_LABELS: +:: + +COLLECTIONS: my_collection +:: + +my_collection.template: "%y4%m2%d2_%h2%n2z.nc4" +my_collection.format: 'CFIO' +my_collection.frequency: 060000 +my_collection.fields: 'output1', 'root' + :: +``` +The HISTORY.rc drives the MAPL_HistoryGridComp which is a special service provided by MAPL to allow users to write fields from any component's export state to a file. Documentation for the input file can be found [here](https://github.com/GEOS-ESM/MAPL/wiki/MAPL-History-Component). In this example we are saying every 6 hours write the field 'output1' from the component root. You should see that in your run directory you have 4 files named starting with my_collection. If you ncdump them you will see that the variable output1 should be identically 11 in each one. If you examine the output from the run, you will see message when History writes a file, for example: +``` + AGCM Date: 2007/08/01 Time: 01:00:00 Throughput(days/day)[Avg Tot Run]: 998447.8 1017616.9 22162362.2 TimeRemaining(Est) 000:00:00 2.8% : 13.5% Mem Comm:Used + AGCM Date: 2007/08/01 Time: 02:00:00 Throughput(days/day)[Avg Tot Run]: 24850021.6 12648460.0 51528614.8 TimeRemaining(Est) 000:00:00 2.8% : 13.5% Mem Comm:Used + AGCM Date: 2007/08/01 Time: 03:00:00 Throughput(days/day)[Avg Tot Run]: 16222750.9 14134794.7 55756268.3 TimeRemaining(Est) 000:00:00 2.8% : 13.5% Mem Comm:Used + AGCM Date: 2007/08/01 Time: 04:00:00 Throughput(days/day)[Avg Tot Run]: 13864970.4 13973735.3 49224105.6 TimeRemaining(Est) 000:00:00 2.8% : 13.5% Mem Comm:Used + AGCM Date: 2007/08/01 Time: 05:00:00 Throughput(days/day)[Avg Tot Run]: 12915278.6 14773101.2 58278111.3 TimeRemaining(Est) 000:00:00 2.8% : 13.5% Mem Comm:Used + + Writing: 1 Slices to File: my_collection.20070801_0600z.nc4 +``` + + +# Exercise for the User + +The user may want to print the size of the ptr_2d and ptr_3d array to confirm that they match the size of the grid. +The user may also notice that in the files only the output1 field was written. Try adding output2 to the HISTORY.rc and see what happens. diff --git a/tutorial/mapl_tutorials/parent_no_children/cap_restart b/tutorial/mapl_tutorials/parent_no_children/cap_restart new file mode 100644 index 000000000000..d61015bfaab6 --- /dev/null +++ b/tutorial/mapl_tutorials/parent_no_children/cap_restart @@ -0,0 +1 @@ +20070801 000000 diff --git a/tutorial/mapl_tutorials/parent_no_children/root.rc b/tutorial/mapl_tutorials/parent_no_children/root.rc new file mode 100644 index 000000000000..a9db4182618a --- /dev/null +++ b/tutorial/mapl_tutorials/parent_no_children/root.rc @@ -0,0 +1,12 @@ +NX: 1 +NY: 1 + +root.GRID_TYPE: LatLon +root.GRIDNAME: DC90x45-PC +root.LM: 72 +root.IM_WORLD: 90 +root.JM_WORLD: 45 +root.POLE: 'PC' +root.DATELINE: 'DC' + +my_value: 11.0 diff --git a/tutorial/mapl_tutorials/parent_no_children/root_lib b/tutorial/mapl_tutorials/parent_no_children/root_lib new file mode 100644 index 000000000000..36c8061079f3 --- /dev/null +++ b/tutorial/mapl_tutorials/parent_no_children/root_lib @@ -0,0 +1 @@ +libMAPL.parent_no_children.so diff --git a/tutorial/mapl_tutorials/parent_one_child_import_via_extdata/CAP.rc b/tutorial/mapl_tutorials/parent_one_child_import_via_extdata/CAP.rc new file mode 100644 index 000000000000..de00498d9711 --- /dev/null +++ b/tutorial/mapl_tutorials/parent_one_child_import_via_extdata/CAP.rc @@ -0,0 +1,10 @@ +ROOT_NAME: root +HIST_CF: HISTORY.rc + + +ROOT_CF: root.rc + +BEG_DATE: 20070801 000000 +END_DATE: 29990302 210000 +JOB_SGMT: 00000001 000000 +HEARTBEAT_DT: 3600 diff --git a/tutorial/mapl_tutorials/parent_one_child_import_via_extdata/ExtData.rc b/tutorial/mapl_tutorials/parent_one_child_import_via_extdata/ExtData.rc new file mode 100644 index 000000000000..99c82e227446 --- /dev/null +++ b/tutorial/mapl_tutorials/parent_one_child_import_via_extdata/ExtData.rc @@ -0,0 +1,3 @@ +PrimaryExports%% +field1 NA N N 0 none none field1 extdata_input.%y4%m2.nc4 +%% diff --git a/tutorial/mapl_tutorials/parent_one_child_import_via_extdata/HISTORY.rc b/tutorial/mapl_tutorials/parent_one_child_import_via_extdata/HISTORY.rc new file mode 100644 index 000000000000..d3a6677416e1 --- /dev/null +++ b/tutorial/mapl_tutorials/parent_one_child_import_via_extdata/HISTORY.rc @@ -0,0 +1,5 @@ +GRID_LABELS: +:: + +COLLECTIONS: +:: diff --git a/tutorial/mapl_tutorials/parent_one_child_import_via_extdata/README.md b/tutorial/mapl_tutorials/parent_one_child_import_via_extdata/README.md new file mode 100644 index 000000000000..7523e41bdfe3 --- /dev/null +++ b/tutorial/mapl_tutorials/parent_one_child_import_via_extdata/README.md @@ -0,0 +1,27 @@ +# Tutorial 5 - Simple Hierarchy with one child and using ExtData +In this tutorial we take things a step further and now create a MAPL hierarchy of a parent and one child. This time we use component BBB as the child. Please be sure you understand everything in the previous tutorial before moving on to this one. + +Note the code for the gridded component used by this tutorial can be found here: + +tutorial/grid_comps/leaf_comp_b/BBB_GridComp.F90 +tutorial/grid_comps/parent_with_one_child/ParentOneChild_GridComp.F90 + +# ParentOneChild_GridComp.F90 + +This is the same as the earlier tutorial and the "root" component. + +# BBB_GridComp.F90 +This is the same as the previous tutorial + +# Running +In this example we use the same components you have seen before. But now our child has an import but there is no other child to make a connectivity with to fill it!. But you will see that the print from BBB has a value that is changing on each step. How is that possible? The answer is the other special MAPL gridded component, ExtData. During the run you will see lines like this: +``` + EXTDATA: Updating L bracket for field1 + EXTDATA: ... file processed: extdata_input.200708.nc4 + EXTDATA: Updating R bracket for field1 + EXTDATA: ... file processed: extdata_input.200708.nc4 +``` +In the tutorial with two childrun under root we discussed how import "bubble up" to their parents. In this case since there is no connectivity here here, the import bubbles up to the MAPL_Cap. At this point any imports that have reached the MAPL_Cap are handed off to a special component named ExtData. This is a special component that is delivered ESMF fields and uses "rules" from an input file to fill these fields with data from NetCDF files on the disk. It is used for time varying quantities like emissions and forcing data. If you look in your input files you will see that ExtData.rc has an entry that starts with "field1". This is a "rule" that tell it how to fill a variable named "field1" from a datafile. More imformation about ExtData [here](https://github.com/GEOS-ESM/MAPL/wiki/MAPL-ExtData-Component). + +Also note that ExtData is currently undergoing a transition to use a new input format which will use YAML rather than the `ESMF_Config` format. Information about that format can be found [here](https://github.com/GEOS-ESM/MAPL/wiki/ExtData-Next-Generation---User-Guide). + diff --git a/tutorial/mapl_tutorials/parent_one_child_import_via_extdata/cap_restart b/tutorial/mapl_tutorials/parent_one_child_import_via_extdata/cap_restart new file mode 100644 index 000000000000..d61015bfaab6 --- /dev/null +++ b/tutorial/mapl_tutorials/parent_one_child_import_via_extdata/cap_restart @@ -0,0 +1 @@ +20070801 000000 diff --git a/tutorial/mapl_tutorials/parent_one_child_import_via_extdata/extdata.yaml b/tutorial/mapl_tutorials/parent_one_child_import_via_extdata/extdata.yaml new file mode 100644 index 000000000000..162048cd8d0c --- /dev/null +++ b/tutorial/mapl_tutorials/parent_one_child_import_via_extdata/extdata.yaml @@ -0,0 +1,5 @@ +Collections: + collection_1: {template: extdata_input.%y4%m2.nc4} + +Exports: + field1: {collection: collection_1, variable: field1} diff --git a/tutorial/mapl_tutorials/parent_one_child_import_via_extdata/extdata_input.200708.nc4 b/tutorial/mapl_tutorials/parent_one_child_import_via_extdata/extdata_input.200708.nc4 new file mode 100644 index 000000000000..febb4492617c Binary files /dev/null and b/tutorial/mapl_tutorials/parent_one_child_import_via_extdata/extdata_input.200708.nc4 differ diff --git a/tutorial/mapl_tutorials/parent_one_child_import_via_extdata/root.rc b/tutorial/mapl_tutorials/parent_one_child_import_via_extdata/root.rc new file mode 100644 index 000000000000..a6773f784a08 --- /dev/null +++ b/tutorial/mapl_tutorials/parent_one_child_import_via_extdata/root.rc @@ -0,0 +1,14 @@ +NX: 1 +NY: 1 + +root.GRID_TYPE: LatLon +root.GRIDNAME: DC90x45-PC +root.LM: 72 +root.IM_WORLD: 90 +root.JM_WORLD: 45 +root.POLE: 'PC' +root.DATELINE: 'DC' + +my_value: 11.0 +my_child_so: libMAPL.bbb.so +my_child_name: BBB diff --git a/tutorial/mapl_tutorials/parent_one_child_import_via_extdata/root_lib b/tutorial/mapl_tutorials/parent_one_child_import_via_extdata/root_lib new file mode 100644 index 000000000000..af62f457c3b0 --- /dev/null +++ b/tutorial/mapl_tutorials/parent_one_child_import_via_extdata/root_lib @@ -0,0 +1 @@ +libMAPL.parent_one_child.so diff --git a/tutorial/mapl_tutorials/parent_one_child_no_imports/CAP.rc b/tutorial/mapl_tutorials/parent_one_child_no_imports/CAP.rc new file mode 100644 index 000000000000..de00498d9711 --- /dev/null +++ b/tutorial/mapl_tutorials/parent_one_child_no_imports/CAP.rc @@ -0,0 +1,10 @@ +ROOT_NAME: root +HIST_CF: HISTORY.rc + + +ROOT_CF: root.rc + +BEG_DATE: 20070801 000000 +END_DATE: 29990302 210000 +JOB_SGMT: 00000001 000000 +HEARTBEAT_DT: 3600 diff --git a/tutorial/mapl_tutorials/parent_one_child_no_imports/ExtData.rc b/tutorial/mapl_tutorials/parent_one_child_no_imports/ExtData.rc new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tutorial/mapl_tutorials/parent_one_child_no_imports/HISTORY.rc b/tutorial/mapl_tutorials/parent_one_child_no_imports/HISTORY.rc new file mode 100644 index 000000000000..32ae97d5a103 --- /dev/null +++ b/tutorial/mapl_tutorials/parent_one_child_no_imports/HISTORY.rc @@ -0,0 +1,13 @@ +GRID_LABELS: +:: + +COLLECTIONS: my_collection +:: + +my_collection.template: "%y4%m2%d2_%h2%n2z.nc4" +my_collection.format: 'CFIO' +my_collection.frequency: 060000 +my_collection.fields: 'output1', 'root' , 'root_output_field' + 'field1', 'AAA', + :: + diff --git a/tutorial/mapl_tutorials/parent_one_child_no_imports/README.md b/tutorial/mapl_tutorials/parent_one_child_no_imports/README.md new file mode 100644 index 000000000000..81df9b46349f --- /dev/null +++ b/tutorial/mapl_tutorials/parent_one_child_no_imports/README.md @@ -0,0 +1,33 @@ +# Tutorial 3 - Simple Hierarchy +In this tutorial we take things a step further and now create a MAPL hierarchy. Please be sure you understand everything in the previous tutorialbefore moving on to this one. + +Note the code for the gridded component used by this tutorial can be found here: + +tutorial/grid_comps/leaf_comp_a/AAA_GridComp.F90 +tutorial/grid_comps/parent_with_one_child/ParentOneChild_GridComp.F90 + +# ParentOneChild_GridComp.F90 + +In this tutorial this is the "root" gridded component. Let's go over what's new. First notice that the setservices has a MAPL_AddChild call. We are telling it that we will add a child in the MAPL hierarchy. In this example the name of the child is obtained from the rc file which is again "root.rc" and we tell it the name of the library that will contain the code for the gridded component, also from the rc file. + +Note that other than a few places in the full GEOSgcm model you will see MAPL_AddChild being done slightly differently (the exception is the Ocean gridded components). Usually we explicit "use" a module and pass a pointer to the setservices to MAPL_AddChild but this requires knowing what module you will use at compile time. For the tutorial this is not desirable. Do not get hung up on this. + +Finally in the my_initialize and my_run there are no new wrinkles other than that my_run now calls MAPL_GenericRunChildren. If this call is not made the run method of any children, grandchildren etc will not be executed. + +# AAA_GridComp.F90 + +Now we have our first child component. It should look very familiar. It registers an initialize and run as well as adding an export spec. + +One important point is that its my-initialize does not call MAPL_GridCreate. This is because the component will use the same grid as its parent. In fact you could delete my_initialize and the SetEntryPoint call in this module since if no user initialize is registered, MAPL_GenericInitialize is called automatically! Try it and see. + +Now we get to the run method. Most of this should look the same but now it is adding something slightly more interesting filling the export field with time varying data. In this case I get the start time and current time from the clock and get the difference between the two in hours. I set the field to this value. + +# HISTORY.rc + +Now notice the HISTORY.rc has an extra line in the "fields" definition. +``` +my_collection.fields: 'output1', 'root' , 'root_output_field' + 'field1', 'AAA', + :: +``` +Here it says write out field1 from the component "AAA". The AAA component was added with the name "AAA". If you examine these output files you should notice that output1 is constant where as field1 varies in time. diff --git a/tutorial/mapl_tutorials/parent_one_child_no_imports/cap_restart b/tutorial/mapl_tutorials/parent_one_child_no_imports/cap_restart new file mode 100644 index 000000000000..d61015bfaab6 --- /dev/null +++ b/tutorial/mapl_tutorials/parent_one_child_no_imports/cap_restart @@ -0,0 +1 @@ +20070801 000000 diff --git a/tutorial/mapl_tutorials/parent_one_child_no_imports/root.rc b/tutorial/mapl_tutorials/parent_one_child_no_imports/root.rc new file mode 100644 index 000000000000..650c0f8b75ca --- /dev/null +++ b/tutorial/mapl_tutorials/parent_one_child_no_imports/root.rc @@ -0,0 +1,14 @@ +NX: 1 +NY: 1 + +root.GRID_TYPE: LatLon +root.GRIDNAME: DC90x45-PC +root.LM: 72 +root.IM_WORLD: 90 +root.JM_WORLD: 45 +root.POLE: 'PC' +root.DATELINE: 'DC' + +my_value: 11.0 +my_child_so: libMAPL.aaa.so +my_child_name: AAA diff --git a/tutorial/mapl_tutorials/parent_one_child_no_imports/root_lib b/tutorial/mapl_tutorials/parent_one_child_no_imports/root_lib new file mode 100644 index 000000000000..af62f457c3b0 --- /dev/null +++ b/tutorial/mapl_tutorials/parent_one_child_no_imports/root_lib @@ -0,0 +1 @@ +libMAPL.parent_one_child.so diff --git a/tutorial/mapl_tutorials/parent_two_siblings_connect_import_export/CAP.rc b/tutorial/mapl_tutorials/parent_two_siblings_connect_import_export/CAP.rc new file mode 100644 index 000000000000..de00498d9711 --- /dev/null +++ b/tutorial/mapl_tutorials/parent_two_siblings_connect_import_export/CAP.rc @@ -0,0 +1,10 @@ +ROOT_NAME: root +HIST_CF: HISTORY.rc + + +ROOT_CF: root.rc + +BEG_DATE: 20070801 000000 +END_DATE: 29990302 210000 +JOB_SGMT: 00000001 000000 +HEARTBEAT_DT: 3600 diff --git a/tutorial/mapl_tutorials/parent_two_siblings_connect_import_export/ExtData.rc b/tutorial/mapl_tutorials/parent_two_siblings_connect_import_export/ExtData.rc new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tutorial/mapl_tutorials/parent_two_siblings_connect_import_export/HISTORY.rc b/tutorial/mapl_tutorials/parent_two_siblings_connect_import_export/HISTORY.rc new file mode 100644 index 000000000000..28cfb9eaf6bf --- /dev/null +++ b/tutorial/mapl_tutorials/parent_two_siblings_connect_import_export/HISTORY.rc @@ -0,0 +1,12 @@ +GRID_LABELS: +:: + +COLLECTIONS: my_collection +:: + +my_collection.template: "%y4%m2%d2_%h2%n2z.nc4" +my_collection.format: 'CFIO' +my_collection.frequency: 060000 +my_collection.fields: 'output1', 'root' + :: + diff --git a/tutorial/mapl_tutorials/parent_two_siblings_connect_import_export/README.md b/tutorial/mapl_tutorials/parent_two_siblings_connect_import_export/README.md new file mode 100644 index 000000000000..371075d9e99d --- /dev/null +++ b/tutorial/mapl_tutorials/parent_two_siblings_connect_import_export/README.md @@ -0,0 +1,27 @@ +# Tutorial 4- Simple Hierarchy with Siblings +In this tutorial we take things a step further and now create a MAPL hierarchy of a parent with two Siblings. Please be sure you understand everything in the previous before moving on to this one. + +Note the code for the gridded component used by this tutorial can be found here: + +tutorial/grid_comps/leaf_comp_a/AAA_GridComp.F90 +tutorial/grid_comps/leaf_comp_b/BBB_GridComp.F90 +tutorial/grid_comps/parent_with_two_children/ParentTwoSiblings_GridComp.F90 + +# ParentTwoSiblings_GridComp.F90 + +In this tutorial this is "root" gridded component. Lets go over what's new. First notice that the setservices has two MAPL_AddChild calls now and adds two child components defined in `AAA_GridComp.F90` and `BBB_GridComp.F90`. Also notice the MAPL_AddConnectivity call. This says that a field named "field1" from the export state of child1 (AAA) will be "connected" to a field named "field1" in the import state of child2 (BBB). In practice what happens behind the scenes is that field1 the respective states actually a pointer to the same memory, so any time AAA touches field1 in its export state this is reflected in field1 in the import state of BBB. + +# AAA_GridComp.F90 + +This is the same as the previous tutorial so nothing more needs to be said. + +# BBB_GridComp.F90 +This looks similar to the AAA gridcomp but now it does a MAPL_AddImportSpec call instead of a MAPL_AddExport Spec call. This adds a field named field1 to its import state. In the run method we get a pointer to field1 and write the maximum value. Since this is an import field we do not need to protect the pointer with an if (associated) check. + +# How Imports are Handled in a MAPL Hierachy +This section will discuss how imports are handled in a MAPL hierarchy. As stated BBB creates a field in the import state. In fitting with the ESMF symantics and conventions the component should not touch or modify the contents of the import state so something else will nee to fill it with data. The general rule is that a parent "inherits" all the imports of its children. In practice what this means is that if the child has an field in its import state named foo, the parent will also get a field in its import state named foo. Moreover both fields will point to the same underlying pointer so are literally referencing the same memory. If the parent contains a` MAPL_AddConnectivity` call as in this exmaple the import field of the child is connected a field in the export state of another child. In MAPL when we say connected what is actually happening is that both the field in the import state and export state of the components shared the same pointer to the physical memory. The `MAPL_AddConnectivity` call also has another effect. It prevents the parent or grandparent etc of the referenced import field from being added to to those gridded component's import states. + +What would happen in this example if we did not have the `MAPL_AddConnectivity`? That is an important question and will be discussed in a later tutorial. + +# Running +When running this example you will notice the print from BBB each timestep and this should be increasing by 1. That's because it is "connected" to the export from AAA in this example. diff --git a/tutorial/mapl_tutorials/parent_two_siblings_connect_import_export/cap_restart b/tutorial/mapl_tutorials/parent_two_siblings_connect_import_export/cap_restart new file mode 100644 index 000000000000..d61015bfaab6 --- /dev/null +++ b/tutorial/mapl_tutorials/parent_two_siblings_connect_import_export/cap_restart @@ -0,0 +1 @@ +20070801 000000 diff --git a/tutorial/mapl_tutorials/parent_two_siblings_connect_import_export/root.rc b/tutorial/mapl_tutorials/parent_two_siblings_connect_import_export/root.rc new file mode 100644 index 000000000000..0b01c46cfb13 --- /dev/null +++ b/tutorial/mapl_tutorials/parent_two_siblings_connect_import_export/root.rc @@ -0,0 +1,16 @@ +NX: 1 +NY: 1 + +root.GRID_TYPE: LatLon +root.GRIDNAME: DC90x45-PC +root.LM: 72 +root.IM_WORLD: 90 +root.JM_WORLD: 45 +root.POLE: 'PC' +root.DATELINE: 'DC' + +my_value: 11.0 +my_child1_so: libMAPL.aaa.so +my_child1_name: AAA +my_child2_so: libMAPL.bbb.so +my_child2_name: BBB diff --git a/tutorial/mapl_tutorials/parent_two_siblings_connect_import_export/root_lib b/tutorial/mapl_tutorials/parent_two_siblings_connect_import_export/root_lib new file mode 100644 index 000000000000..1af902f1b72f --- /dev/null +++ b/tutorial/mapl_tutorials/parent_two_siblings_connect_import_export/root_lib @@ -0,0 +1 @@ +libMAPL.parent_two_siblings.so diff --git a/tutorial/run_tutorial_case.sh b/tutorial/run_tutorial_case.sh new file mode 100755 index 000000000000..5f99b9648bfe --- /dev/null +++ b/tutorial/run_tutorial_case.sh @@ -0,0 +1,35 @@ +#!/bin/bash -f + +####################################################################### +# Batch Parameters for Run Job +####################################################################### + +umask 022 + +ulimit -s unlimited + +####################################################################### +# Architecture Specific Environment Variables +####################################################################### + +export site=NCCS + +export INSTALL_DIR=$1 +export TUTORIAL_CASE=$2 +source $INSTALL_DIR/bin/g5_modules.sh +export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${BASEDIR}/${ARCH}/lib:${INSTALL_DIR}/lib +export TUTORIAL_PATH=${INSTALL_DIR}/etc/mapl_tutorials/${TUTORIAL_CASE} + +for file in `ls ${TUTORIAL_PATH}`; do + cp "${TUTORIAL_PATH}/${file}" . +done + +ROOT_LIB=`cat root_lib` + +export ROOT_RC=`grep '^\s*ROOT_CF:' CAP.rc | cut -d: -f2` +export NX=`grep '^\s*NX:' ${ROOT_RC} | cut -d: -f2` +export NY=`grep '^\s*NY:' ${ROOT_RC} | cut -d: -f2` + +export NPES=`expr ${NY} \* ${NX}` + +mpirun -np ${NPES} ${INSTALL_DIR}/bin/Example_Driver.x --root_dso ${ROOT_LIB}