diff --git a/.github/workflows/Intel.yml b/.github/workflows/Intel.yml index 4feb8acb7..3f39c7484 100644 --- a/.github/workflows/Intel.yml +++ b/.github/workflows/Intel.yml @@ -17,124 +17,44 @@ concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true -# Use custom shell with -l so .bash_profile is sourced which loads intel/oneapi/setvars.sh -# without having to do it in manually every step -defaults: - run: - shell: bash -leo pipefail {0} - jobs: Intel: runs-on: ubuntu-latest - env: - CC: icc - FC: ifort - CXX: icpc strategy: fail-fast: true matrix: - compilers: ["CC=icc FC=ifort", "CC=icx FC=ifx"] + compilers: ["oneapi", "classic"] steps: - # See https://software.intel.com/content/www/us/en/develop/articles/oneapi-repo-instructions.html - - name: install-intel - run: | - set -x - cd /tmp - wget https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB - sudo apt-key add GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB - rm GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB - echo "deb https://apt.repos.intel.com/oneapi all main" | sudo tee /etc/apt/sources.list.d/oneAPI.list - sudo apt-get update - sudo apt-get install intel-oneapi-dev-utilities intel-oneapi-mpi-devel intel-oneapi-compiler-fortran-2023.2.1 intel-oneapi-compiler-dpcpp-cpp-and-cpp-classic-2023.2.1 intel-oneapi-openmp - echo "source /opt/intel/oneapi/setvars.sh" >> ~/.bash_profile - - - name: checkout-bacio - uses: actions/checkout@v3 - with: - repository: NOAA-EMC/NCEPLIBS-bacio - path: bacio - ref: develop - - - name: build-bacio - run: | - cd bacio - mkdir build - cd build - which ifort || which ifx - ${{ matrix.compilers }} cmake .. -DCMAKE_INSTALL_PREFIX=~/bacio - make -j2 - make install - - - name: checkout-w3emc - uses: actions/checkout@v3 + - name: "Install Intel" + uses: NOAA-EMC/ci-install-intel-toolkit@develop with: - repository: NOAA-EMC/NCEPLIBS-w3emc - path: w3emc - ref: develop + compiler-setup: ${{ matrix.compilers }} - - name: build-w3emc - run: | - cd w3emc - mkdir build - cd build - ${{ matrix.compilers }} cmake -DCMAKE_PREFIX_PATH=~/bacio -DCMAKE_INSTALL_PREFIX=~/w3emc -DBUILD_WITH_BUFR=OFF .. - make -j2 - make install - - - name: checkout-jasper - uses: actions/checkout@v3 + - name: "Build dependencies" + uses: NOAA-EMC/ci-build-nceplibs@develop with: - repository: jasper-software/jasper - path: jasper - ref: version-4.0.0 - - - name: cache-jasper - id: cache-jasper - uses: actions/cache@v3 - with: - path: ~/Jasper - key: jasper-intel-${{ matrix.compilers }}-${{ runner.os }}-4.0.0 - - - name: build-jasper - if: steps.cache-jasper.outputs.cache-hit != 'true' - run: | - cd jasper - mkdir build-jasper && cd build-jasper - ${{ matrix.compilers }} cmake .. -DCMAKE_INSTALL_PREFIX=~/Jasper - make -j2 - make install - - - name: checkout-ip - uses: actions/checkout@v3 - with: - repository: NOAA-EMC/NCEPLIBS-ip - path: ip - ref: develop - - - name: build-ip - run: | - cd ip - mkdir build - cd build - cmake -DCMAKE_INSTALL_PREFIX=~/ip .. - make -j2 - make install + bacio-version: develop + jasper-version: version-4.0.0 + w3emc-version: develop + w3emc-cmake-args: -DBUILD_WITH_BUFR=OFF + ip-version: develop + key-prefix: Intel- - name: checkout - uses: actions/checkout@v3 - with: + uses: actions/checkout@v4 + with: path: g2 - name: build run: | cd g2 - mkdir build + mkdir build cd build - ${{ matrix.compilers }} cmake -DCMAKE_PREFIX_PATH="~/Jasper;~/bacio;~/w3emc;~/ip" -DBUILD_UTILS=ON .. + cmake -DCMAKE_PREFIX_PATH="$GITHUB_WORKSPACE/nceplibs/jasper;$GITHUB_WORKSPACE/nceplibs/NCEPLIBS-bacio;$GITHUB_WORKSPACE/nceplibs/NCEPLIBS-w3emc;$GITHUB_WORKSPACE/nceplibs/NCEPLIBS-ip" -DBUILD_UTILS=ON .. make -j2 - + - name: test run: | cd $GITHUB_WORKSPACE/g2/build diff --git a/.github/workflows/Linux_options.yml b/.github/workflows/Linux_options.yml index 74ccdb20e..b1c410b5d 100644 --- a/.github/workflows/Linux_options.yml +++ b/.github/workflows/Linux_options.yml @@ -39,7 +39,7 @@ jobs: - { options: "-DBUILD_WITH_W3EMC=OFF" } - - { + - { options: "-DBUILD_UTILS=ON -DBUILD_WITH_W3EMC=OFF" } @@ -50,120 +50,24 @@ jobs: sudo apt-get update sudo apt-get install libpng-dev zlib1g-dev libjpeg-dev - - name: cache-bacio - id: cache-bacio - uses: actions/cache@v3 - with: - path: ~/bacio - key: bacio-${{ runner.os }}-${{ matrix.bacio-version }} - - - name: checkout-bacio - if: steps.cache-bacio.outputs.cache-hit != 'true' - uses: actions/checkout@v3 - with: - repository: NOAA-EMC/NCEPLIBS-bacio - path: bacio - ref: v${{ matrix.bacio-version }} - - - name: build-bacio - if: steps.cache-bacio.outputs.cache-hit != 'true' - run: | - cd bacio - mkdir build - cd build - cmake .. -DCMAKE_INSTALL_PREFIX=~/bacio - make -j2 - make install - - - name: cache-w3emc - id: cache-w3emc - uses: actions/cache@v3 - with: - path: ~/w3emc - key: w3emc-${{ runner.os }}-${{ matrix.w3emc-version }}-${{ matrix.bacio-version }} - - - name: checkout-w3emc - if: steps.cache-w3emc.outputs.cache-hit != 'true' - uses: actions/checkout@v3 - with: - repository: NOAA-EMC/NCEPLIBS-w3emc - path: w3emc - ref: v${{ matrix.w3emc-version }}-1 - - - name: build-w3emc - if: steps.cache-w3emc.outputs.cache-hit != 'true' - run: | - cd w3emc - mkdir build - cd build - cmake -DCMAKE_PREFIX_PATH=~/bacio -DCMAKE_INSTALL_PREFIX=~/w3emc -DBUILD_WITH_BUFR=OFF -DBUILD_WITH_EXTRA_DEPS=ON -DBUILD_DEPRECATED=ON .. - make -j2 - make install - - - name: cache-jasper - id: cache-jasper - uses: actions/cache@v3 - with: - path: ~/jasper - key: jasper-${{ runner.os }}-4.0.0 - - - name: checkout-jasper - if: steps.cache-jasper.outputs.cache-hit != 'true' - uses: actions/checkout@v3 + - name: "Build dependencies" + uses: NOAA-EMC/ci-build-nceplibs@develop with: - repository: jasper-software/jasper - path: jasper - ref: version-4.0.0 + bacio-version: v${{ matrix.bacio-version }} + g2c-version: develop + jasper-version: version-4.0.0 + w3emc-version: v${{ matrix.w3emc-version }} + w3emc-cmake-args: -DBUILD_WITH_BUFR=OFF -DBUILD_WITH_EXTRA_DEPS=ON + ip-version: develop - - name: build-jasper - if: steps.cache-jasper.outputs.cache-hit != 'true' - run: | - cd jasper - mkdir build-jasper && cd build-jasper - cmake .. -DCMAKE_INSTALL_PREFIX=~/jasper - make -j2 - make install - - - name: checkout-ip - uses: actions/checkout@v3 - with: - repository: NOAA-EMC/NCEPLIBS-ip - path: ip - ref: develop - - - name: build-ip - run: | - cd ip - mkdir build - cd build - cmake -DCMAKE_INSTALL_PREFIX=~/ip .. - make -j2 - make install - - - name: checkout-g2c - uses: actions/checkout@v3 - with: - repository: NOAA-EMC/NCEPLIBS-g2c - path: g2c - ref: develop - - - name: build-g2c - run: | - cd g2c - mkdir build - cd build - cmake .. -DCMAKE_INSTALL_PREFIX=~/g2c -DJasper_ROOT=~/jasper - make -j2 - make install - - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: path: g2 - name: cache-data id: cache-data - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/data key: data-5 @@ -174,7 +78,7 @@ jobs: cd g2 mkdir build cd build - cmake ${{ matrix.config.options }} -DCMAKE_PREFIX_PATH="~/jasper;~/g2c;~/bacio;~/w3emc;~/ip" -DFTP_TEST_FILES=ON -DTEST_FILE_DIR=/home/runner/data .. + cmake ${{ matrix.config.options }} -DCMAKE_PREFIX_PATH="$GITHUB_WORKSPACE/nceplibs/jasper;$GITHUB_WORKSPACE/nceplibs/NCEPLIBS-g2c;$GITHUB_WORKSPACE/nceplibs/NCEPLIBS-bacio;$GITHUB_WORKSPACE/nceplibs/NCEPLIBS-w3emc;$GITHUB_WORKSPACE/nceplibs/NCEPLIBS-ip" -DFTP_TEST_FILES=ON -DTEST_FILE_DIR=/home/runner/data .. make -j2 VERBOSE=1 - name: cache-data @@ -182,10 +86,8 @@ jobs: run: | mkdir ~/data cp $GITHUB_WORKSPACE/g2/build/tests/data/* ~/data - + - name: test run: | cd $GITHUB_WORKSPACE/g2/build ctest --verbose --rerun-failed --output-on-failure - - diff --git a/.github/workflows/Linux_shared.yml b/.github/workflows/Linux_shared.yml index 086562e1f..9c907cf93 100644 --- a/.github/workflows/Linux_shared.yml +++ b/.github/workflows/Linux_shared.yml @@ -47,120 +47,27 @@ jobs: sudo apt-get update sudo apt-get install libpng-dev zlib1g-dev libjpeg-dev - - name: cache-bacio - id: cache-bacio - uses: actions/cache@v3 + - name: "Build dependencies" + uses: NOAA-EMC/ci-build-nceplibs@develop with: - path: ~/bacio - key: bacio-${{ runner.os }}-${{ matrix.bacio-version }}-shared - - - name: checkout-bacio - if: steps.cache-bacio.outputs.cache-hit != 'true' - uses: actions/checkout@v3 - with: - repository: NOAA-EMC/NCEPLIBS-bacio - path: bacio - ref: v${{ matrix.bacio-version }} - - - name: build-bacio - if: steps.cache-bacio.outputs.cache-hit != 'true' - run: | - cd bacio - mkdir build - cd build - cmake -DCMAKE_INSTALL_PREFIX=~/bacio -DBUILD_SHARED_LIBS=ON .. - make -j2 - make install - - - name: cache-w3emc - id: cache-w3emc - uses: actions/cache@v3 - with: - path: ~/w3emc - key: w3emc-${{ runner.os }}-${{ matrix.w3emc-version }}-${{ matrix.bacio-version }}-shared - - - name: checkout-w3emc - if: steps.cache-w3emc.outputs.cache-hit != 'true' - uses: actions/checkout@v3 - with: - repository: NOAA-EMC/NCEPLIBS-w3emc - path: w3emc - ref: v${{ matrix.w3emc-version }} - - - name: build-w3emc - if: steps.cache-w3emc.outputs.cache-hit != 'true' - run: | - cd w3emc - mkdir build - cd build - cmake -DCMAKE_PREFIX_PATH=~/bacio -DCMAKE_INSTALL_PREFIX=~/w3emc -DBUILD_WITH_BUFR=OFF -DENABLE_SHARED=ON -DBUILD_WITH_EXTRA_DEPS=OFF .. - make -j2 - make install - - - name: cache-jasper - id: cache-jasper - uses: actions/cache@v3 - with: - path: ~/jasper - key: jasper-${{ runner.os }}-4.0.0-shared - - - name: checkout-jasper - if: steps.cache-jasper.outputs.cache-hit != 'true' - uses: actions/checkout@v3 - with: - repository: jasper-software/jasper - path: jasper - ref: version-4.0.0 - - - name: build-jasper - if: steps.cache-jasper.outputs.cache-hit != 'true' - run: | - cd jasper - mkdir build-jasper && cd build-jasper - cmake -DCMAKE_INSTALL_PREFIX=~/jasper -DENABLE_SHARED=ON .. - make -j2 - make install + bacio-version: v${{ matrix.bacio-version }} + bacio-cmake-args: -DBUILD_SHARED_LIBS=ON + g2c-version: develop + g2c-cmake-args: -DENABLE_SHARED=ON + jasper-version: version-4.0.0 + jasper-cmake-args: -DENABLE_SHARED=ON + w3emc-version: v${{ matrix.w3emc-version }} + w3emc-cmake-args: -DBUILD_WITH_BUFR=OFF -DENABLE_SHARED=ON -DBUILD_WITH_EXTRA_DEPS=OFF + ip-version: develop - - name: checkout-g2c - uses: actions/checkout@v3 - with: - repository: NOAA-EMC/NCEPLIBS-g2c - path: g2c - ref: develop - - - name: checkout-ip - uses: actions/checkout@v3 - with: - repository: NOAA-EMC/NCEPLIBS-ip - path: ip - ref: develop - - - name: build-ip - run: | - cd ip - mkdir build - cd build - cmake -DCMAKE_INSTALL_PREFIX=~/ip .. - make -j2 - make install - - - name: build-g2c - run: | - cd g2c - mkdir build - cd build - cmake -DCMAKE_INSTALL_PREFIX=~/g2c -DJasper_ROOT=~/jasper -DENABLE_SHARED=ON .. - make -j2 - make install - - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: path: g2 - name: cache-data id: cache-data - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/data key: data-5 @@ -171,7 +78,7 @@ jobs: cd g2 mkdir build cd build - cmake ${{ matrix.config.options }} -DCMAKE_PREFIX_PATH="~/jasper;~/g2c;~/bacio;~/w3emc;~/ip" -DCMAKE_INSTALL_PREFIX="~/g2/install" -DFTP_TEST_FILES=ON -DTEST_FILE_DIR=/home/runner/data -DBUILD_SHARED_LIBS=ON .. + cmake ${{ matrix.config.options }} -DCMAKE_PREFIX_PATH="$GITHUB_WORKSPACE/nceplibs/jasper;$GITHUB_WORKSPACE/nceplibs/NCEPLIBS-g2c;$GITHUB_WORKSPACE/nceplibs/NCEPLIBS-bacio;$GITHUB_WORKSPACE/nceplibs/NCEPLIBS-w3emc;$GITHUB_WORKSPACE/nceplibs/NCEPLIBS-bacio;$GITHUB_WORKSPACE/nceplibs/NCEPLIBS-ip" -DCMAKE_INSTALL_PREFIX="~/g2/install" -DFTP_TEST_FILES=ON -DTEST_FILE_DIR=/home/runner/data -DBUILD_SHARED_LIBS=ON .. make -j2 VERBOSE=1 - name: cache-data @@ -179,7 +86,7 @@ jobs: run: | mkdir ~/data cp $GITHUB_WORKSPACE/g2/build/tests/data/* ~/data - + - name: test run: | cd $GITHUB_WORKSPACE/g2/build @@ -190,7 +97,3 @@ jobs: cd $GITHUB_WORKSPACE/g2/build make install ls -l ~/g2/install/lib/lib*.so || exit 1 - - - - diff --git a/.github/workflows/Linux_versions.yml b/.github/workflows/Linux_versions.yml index 3b2dfbdfe..0b47ddd4b 100644 --- a/.github/workflows/Linux_versions.yml +++ b/.github/workflows/Linux_versions.yml @@ -39,120 +39,24 @@ jobs: sudo apt-get update sudo apt-get install libpng-dev zlib1g-dev libjpeg-dev - - name: cache-bacio - id: cache-bacio - uses: actions/cache@v3 + - name: "Build dependencies" + uses: NOAA-EMC/ci-build-nceplibs@develop with: - path: ~/bacio - key: bacio-${{ runner.os }}-${{ matrix.bacio-version }} - - - name: checkout-bacio - if: steps.cache-bacio.outputs.cache-hit != 'true' - uses: actions/checkout@v3 - with: - repository: NOAA-EMC/NCEPLIBS-bacio - path: bacio - ref: v${{ matrix.bacio-version }} - - - name: build-bacio - if: steps.cache-bacio.outputs.cache-hit != 'true' - run: | - cd bacio - mkdir build - cd build - cmake .. -DCMAKE_INSTALL_PREFIX=~/bacio - make -j2 - make install - - - name: cache-w3emc - id: cache-w3emc - uses: actions/cache@v3 - with: - path: ~/w3emc - key: w3emc-${{ runner.os }}-${{ matrix.w3emc-version }}-${{ matrix.bacio-version }}-1 - - - name: checkout-w3emc - if: steps.cache-w3emc.outputs.cache-hit != 'true' - uses: actions/checkout@v3 - with: - repository: NOAA-EMC/NCEPLIBS-w3emc - path: w3emc - ref: v${{ matrix.w3emc-version }} - - - name: build-w3emc - if: steps.cache-w3emc.outputs.cache-hit != 'true' - run: | - cd w3emc - mkdir build - cd build - cmake -DCMAKE_PREFIX_PATH=~/bacio -DCMAKE_INSTALL_PREFIX=~/w3emc -DBUILD_WITH_BUFR=OFF .. - make -j2 - make install - - - name: cache-jasper - id: cache-jasper - uses: actions/cache@v3 - with: - path: ~/jasper - key: jasper-${{ runner.os }}-${{ matrix.jasper-version }} + bacio-version: v${{ matrix.bacio-version }} + g2c-version: develop + jasper-version: version-${{ matrix.jasper-version }} + w3emc-version: v${{ matrix.w3emc-version }} + w3emc-cmake-args: -DBUILD_WITH_BUFR=OFF + ip-version: develop - - name: checkout-jasper - if: steps.cache-jasper.outputs.cache-hit != 'true' - uses: actions/checkout@v3 - with: - repository: jasper-software/jasper - path: jasper - ref: version-${{ matrix.jasper-version }} - - - name: build-jasper - if: steps.cache-jasper.outputs.cache-hit != 'true' - run: | - cd jasper - mkdir build-jasper && cd build-jasper - cmake .. -DCMAKE_INSTALL_PREFIX=~/jasper - make -j2 - make install - - - name: checkout-ip - uses: actions/checkout@v3 - with: - repository: NOAA-EMC/NCEPLIBS-ip - path: ip - ref: develop - - - name: build-ip - run: | - cd ip - mkdir build - cd build - cmake -DCMAKE_INSTALL_PREFIX=~/ip .. - make -j2 - make install - - - name: checkout-g2c - uses: actions/checkout@v3 - with: - repository: NOAA-EMC/NCEPLIBS-g2c - path: g2c - ref: develop - - - name: build-g2c - run: | - cd g2c - mkdir build - cd build - cmake .. -DCMAKE_INSTALL_PREFIX=~/g2c -DJasper_ROOT=~/jasper - make -j2 - make install - - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: path: g2 - name: cache-data id: cache-data - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/data key: data-5 @@ -163,7 +67,7 @@ jobs: cd g2 mkdir build cd build - cmake -DCMAKE_PREFIX_PATH="~/jasper;~/g2c;~/bacio;~/w3emc;~/ip" -DLOGGING=ON -DFTP_TEST_FILES=ON -DTEST_FILE_DIR=/home/runner/data .. + cmake -DCMAKE_PREFIX_PATH="$GITHUB_WORKSPACE/nceplibs/jasper;$GITHUB_WORKSPACE/nceplibs/NCEPLIBS-g2c;$GITHUB_WORKSPACE/nceplibs/NCEPLIBS-bacio;$GITHUB_WORKSPACE/nceplibs/NCEPLIBS-w3emc;$GITHUB_WORKSPACE/nceplibs/NCEPLIBS-ip" -DLOGGING=ON -DFTP_TEST_FILES=ON -DTEST_FILE_DIR=/home/runner/data .. make -j2 VERBOSE=1 - name: cache-data diff --git a/.github/workflows/MacOS.yml b/.github/workflows/MacOS.yml index c115f7e15..2de7f9884 100644 --- a/.github/workflows/MacOS.yml +++ b/.github/workflows/MacOS.yml @@ -39,114 +39,18 @@ jobs: brew install libpng brew install jpeg-turbo - - name: cache-bacio - id: cache-bacio - uses: actions/cache@v3 + - name: "Build dependencies" + uses: NOAA-EMC/ci-build-nceplibs@develop with: - path: ~/bacio - key: bacio-${{ runner.os }}-${{ matrix.bacio-version }} - - - name: checkout-bacio - if: steps.cache-bacio.outputs.cache-hit != 'true' - uses: actions/checkout@v3 - with: - repository: NOAA-EMC/NCEPLIBS-bacio - path: bacio - ref: v${{ matrix.bacio-version }} - - - name: build-bacio - if: steps.cache-bacio.outputs.cache-hit != 'true' - run: | - cd bacio - mkdir build - cd build - cmake .. -DCMAKE_INSTALL_PREFIX=~/bacio - make -j2 - make install - - - name: cache-w3emc - id: cache-w3emc - uses: actions/cache@v3 - with: - path: ~/w3emc - key: w3emc-${{ runner.os }}-2.10.0-bacio-${{ matrix.bacio-version }} - - - name: checkout-w3emc - if: steps.cache-w3emc.outputs.cache-hit != 'true' - uses: actions/checkout@v3 - with: - repository: NOAA-EMC/NCEPLIBS-w3emc - path: w3emc - ref: v2.10.0 - - - name: build-w3emc - if: steps.cache-w3emc.outputs.cache-hit != 'true' - run: | - cd w3emc - mkdir build - cd build - cmake .. -DCMAKE_PREFIX_PATH=~/bacio -DCMAKE_INSTALL_PREFIX=~/w3emc -DBUILD_WITH_BUFR=OFF - make -j2 - make install - - - name: cache-jasper - id: cache-jasper - uses: actions/cache@v3 - with: - path: ~/jasper - key: jasper-${{ runner.os }}-${{ matrix.jasper-version }} - - - name: checkout-jasper - if: steps.cache-jasper.outputs.cache-hit != 'true' - uses: actions/checkout@v3 - with: - repository: jasper-software/jasper - path: jasper - ref: version-${{ matrix.jasper-version }} - - - name: build-jasper - if: steps.cache-jasper.outputs.cache-hit != 'true' - run: | - cd jasper - mkdir build-jasper && cd build-jasper - cmake .. -DCMAKE_INSTALL_PREFIX=~/jasper - make -j2 - make install - - - name: checkout-ip - uses: actions/checkout@v3 - with: - repository: NOAA-EMC/NCEPLIBS-ip - path: ip - ref: develop - - - name: build-ip - run: | - cd ip - mkdir build - cd build - cmake -DCMAKE_INSTALL_PREFIX=~/ip .. - make -j2 - make install - - - name: checkout-g2c - uses: actions/checkout@v3 - with: - repository: NOAA-EMC/NCEPLIBS-g2c - path: g2c - ref: develop - - - name: build-g2c - run: | - cd g2c - mkdir build - cd build - cmake .. -DCMAKE_PREFIX_PATH=~/jasper -DCMAKE_INSTALL_PREFIX=~/g2c - make -j2 - make install + bacio-version: v${{ matrix.bacio-version }} + g2c-version: develop + jasper-version: version-${{ matrix.jasper-version }} + w3emc-version: v2.10.0 + w3emc-cmake-args: -DBUILD_WITH_BUFR=OFF + ip-version: develop - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: path: g2 @@ -155,7 +59,7 @@ jobs: cd g2 mkdir build cd build - cmake -DCMAKE_PREFIX_PATH="~/jasper;~/bacio;~/w3emc;~/g2c;~/ip" -DCMAKE_BUILD_TYPE=Debug -DBUILD_UTILS=ON .. + cmake -DCMAKE_PREFIX_PATH="$GITHUB_WORKSPACE/nceplibs/jasper;$GITHUB_WORKSPACE/nceplibs/NCEPLIBS-g2c;$GITHUB_WORKSPACE/nceplibs/NCEPLIBS-bacio;$GITHUB_WORKSPACE/nceplibs/NCEPLIBS-w3emc;$GITHUB_WORKSPACE/nceplibs/NCEPLIBS-ip" -DCMAKE_BUILD_TYPE=Debug -DBUILD_UTILS=ON .. make -j2 VERBOSE=1 - name: test diff --git a/.github/workflows/Spack.yml b/.github/workflows/Spack.yml index 0be57ff56..0f0d37011 100644 --- a/.github/workflows/Spack.yml +++ b/.github/workflows/Spack.yml @@ -26,42 +26,20 @@ jobs: strategy: matrix: os: ["ubuntu-latest"] - pic: ["+pic", "~pic"] - precision: ["precision=d", "precision=4"] - w3emc: ["+w3emc", "~w3emc"] - utils: ["+utils", "~utils"] + variants: ["+shared +pic precision=d +w3emc +utils", "~shared ~pic precision=4 ~w3emc ~utils"] runs-on: ${{ matrix.os }} steps: - - name: checkout-g2 - uses: actions/checkout@v4 + - name: "Build Spack package" + uses: NOAA-EMC/ci-test-spack-package@develop with: - path: g2 - - - name: spack-build-and-test - run: | - git clone -c feature.manyFiles=true https://github.com/spack/spack - . spack/share/spack/setup-env.sh - spack env create g2-env - spack env activate g2-env - cp $GITHUB_WORKSPACE/g2/spack/package.py $SPACK_ROOT/var/spack/repos/builtin/packages/g2/package.py - spack develop --no-clone --path $GITHUB_WORKSPACE/g2 g2@develop - spack add g2@develop%gcc@11 ${{ matrix.pic }} ${{ matrix.precision }} ${{ matrix.w3emc }} ${{ matrix.utils }} - spack external find cmake gmake - spack concretize - # Run installation and run CTest suite - spack install --verbose --fail-fast --test root - # Run 'spack load' to check for obvious errors in setup_run_environment - spack load g2 - - - name: Upload test results - uses: actions/upload-artifact@v3 - if: ${{ failure() }} - with: - name: spackci-ctest-output-${{ matrix.os }}-${{ matrix.pic }}-${{ matrix.precision }}-${{ matrix.w3emc }}-${{ matrix.utils }} - path: ${{ github.workspace }}/g2/spack-build-*/Testing/Temporary/LastTest.log - + package-name: g2 + package-variants: ${{ matrix.variants }} + custom-recipe: spack/package.py + use-repo-cache: true + spack-compiler: gcc + repo-cache-key-suffix: ${{ matrix.os }}-${{ matrix.variants }}-1 # This job validates the Spack recipe by making sure each cmake build option is represented recipe-check: @@ -69,15 +47,9 @@ jobs: steps: - - name: checkout-g2 - uses: actions/checkout@v4 - with: - path: g2 - - name: recipe-check - run: | - echo "If this jobs fails, look at the most recently output CMake option below and make sure that option appears in spack/package.py" - for opt in $(grep -ioP '^option\(\K(?!(ENABLE_DOCS|FTP_TEST_FILES|FTP_LARGE_TEST_FILES|FTP_EXTRA_TEST_FILES|LOGGING|BUILD_SHARED_LIBS))[^ ]+' $GITHUB_WORKSPACE/g2/CMakeLists.txt) ; do - echo "Checking for presence of '$opt' CMake option in package.py" - grep -cP "define.+\b${opt}\b" $GITHUB_WORKSPACE/g2/spack/package.py - done + uses: NOAA-EMC/ci-check-spack-recipe@develop + with: + recipe-file: package/spack/package.py + cmakelists-txt: package/CMakeLists.txt + ignore-list: ENABLE_DOCS,FTP_TEST_FILES,FTP_LARGE_TEST_FILES,FTP_EXTRA_TEST_FILES,LOGGING diff --git a/.github/workflows/developer.yml b/.github/workflows/developer.yml index cf4fb398d..dad6c23ee 100644 --- a/.github/workflows/developer.yml +++ b/.github/workflows/developer.yml @@ -27,94 +27,17 @@ jobs: sudo apt-get update sudo apt-get install libpng-dev zlib1g-dev libjpeg-dev doxygen gcovr valgrind - - name: checkout-bacio - uses: actions/checkout@v4 - with: - repository: NOAA-EMC/NCEPLIBS-bacio - path: bacio - ref: develop - - - name: build-bacio - run: | - cd bacio - mkdir build - cd build - cmake .. -DCMAKE_INSTALL_PREFIX=~/bacio - make -j2 - make install - - - name: checkout-w3emc - uses: actions/checkout@v4 - with: - repository: NOAA-EMC/NCEPLIBS-w3emc - path: w3emc - ref: develop - - - name: build-w3emc - run: | - cd w3emc - mkdir build - cd build - cmake -DCMAKE_PREFIX_PATH=~/bacio -DCMAKE_INSTALL_PREFIX=~/w3emc -DBUILD_WITH_BUFR=OFF .. - make -j2 - make install - - - name: cache-jasper - id: cache-jasper - uses: actions/cache@v4 - with: - path: ~/Jasper - key: jasper-${{ runner.os }}-4.0.0 - - - name: checkout-jasper - if: steps.cache-jasper.outputs.cache-hit != 'true' - uses: actions/checkout@v4 - with: - repository: jasper-software/jasper - path: jasper - ref: version-4.0.0 - - - name: build-jasper - if: steps.cache-jasper.outputs.cache-hit != 'true' - run: | - cd jasper - mkdir build-jasper && cd build-jasper - cmake .. -DCMAKE_INSTALL_PREFIX=~/Jasper - make -j2 - make install - - - name: checkout-ip - uses: actions/checkout@v4 - with: - repository: NOAA-EMC/NCEPLIBS-ip - path: ip - ref: develop - - - name: build-ip - run: | - cd ip - mkdir build - cd build - cmake -DCMAKE_INSTALL_PREFIX=~/ip .. - make -j2 - make install - - - name: checkout-g2c - uses: actions/checkout@v4 + - name: "Build dependencies" + uses: NOAA-EMC/ci-build-nceplibs@develop with: - repository: NOAA-EMC/NCEPLIBS-g2c - path: g2c - ref: develop + bacio-version: develop + w3emc-version: develop + jasper-version: version-4.0.0 + w3emc-cmake-args: -DBUILD_WITH_BUFR=OFF + ip-version: develop + g2c-version: develop + g2c-cmake-args: -DBUILD_G2C=ON - - name: build-g2c - run: | - cd g2c - mkdir build - cd build - cmake -DCMAKE_INSTALL_PREFIX=~/g2c -DCMAKE_PREFIX_PATH="~/Jasper" -DBUILD_G2C=ON .. - make -j2 - make install - - name: checkout uses: actions/checkout@v4 with: @@ -134,7 +57,7 @@ jobs: mkdir build doxygen --version cd build - cmake -DBUILD_UTILS=OFF -DG2C_COMPARE=ON -DFTP_LARGE_TEST_FILES=ON -DENABLE_DOCS=On -DJasper_ROOT=~/Jasper -DCMAKE_PREFIX_PATH="~/bacio;~/ip;~/w3emc;~/g2c" -DCMAKE_Fortran_FLAGS="-g -fprofile-abs-path -fprofile-arcs -ftest-coverage -O0 -Wall -fno-omit-frame-pointer -fsanitize=address" -DCMAKE_C_FLAGS="-g -fprofile-abs-path -fprofile-arcs -ftest-coverage -O0 -Wall -fno-omit-frame-pointer -fsanitize=address" -DFTP_TEST_FILES=ON -DTEST_FILE_DIR=/home/runner/data -DCMAKE_BUILD_TYPE=Debug .. + cmake -DBUILD_UTILS=OFF -DG2C_COMPARE=ON -DFTP_LARGE_TEST_FILES=ON -DENABLE_DOCS=ON -DCMAKE_PREFIX_PATH="$GITHUB_WORKSPACE/nceplibs/jasper;$GITHUB_WORKSPACE/nceplibs/NCEPLIBS-bacio;$GITHUB_WORKSPACE/nceplibs/NCEPLIBS-w3emc;$GITHUB_WORKSPACE/nceplibs/NCEPLIBS-ip;$GITHUB_WORKSPACE/nceplibs/NCEPLIBS-g2c" -DCMAKE_Fortran_FLAGS="-g -fprofile-abs-path -fprofile-arcs -ftest-coverage -O0 -Wall -fno-omit-frame-pointer -fsanitize=address" -DCMAKE_C_FLAGS="-g -fprofile-abs-path -fprofile-arcs -ftest-coverage -O0 -Wall -fno-omit-frame-pointer -fsanitize=address" -DFTP_TEST_FILES=ON -DTEST_FILE_DIR=/home/runner/data -DCMAKE_BUILD_TYPE=Debug .. make -j2 VERBOSE=1 - name: test_asan @@ -156,4 +79,3 @@ jobs: path: | g2/build/*.html g2/build/*.css - diff --git a/.github/workflows/memcheck.yml b/.github/workflows/memcheck.yml index 176f8f145..a9d36edfb 100644 --- a/.github/workflows/memcheck.yml +++ b/.github/workflows/memcheck.yml @@ -31,61 +31,13 @@ jobs: sudo apt-get update sudo apt-get install libpng-dev zlib1g-dev libjpeg-dev doxygen gcovr valgrind - - name: checkout-bacio - uses: actions/checkout@v4 - with: - repository: NOAA-EMC/NCEPLIBS-bacio - path: bacio - ref: develop - - - name: build-bacio - run: | - cd bacio - mkdir build - cd build - cmake .. -DCMAKE_INSTALL_PREFIX=~/bacio - make -j2 - make install - - - name: checkout-w3emc - uses: actions/checkout@v4 - with: - repository: NOAA-EMC/NCEPLIBS-w3emc - path: w3emc - ref: develop - - - name: build-w3emc - run: | - cd w3emc - mkdir build - cd build - cmake -DCMAKE_PREFIX_PATH=~/bacio -DCMAKE_INSTALL_PREFIX=~/w3emc -DBUILD_WITH_BUFR=OFF .. - make -j2 - make install - - - name: cache-jasper - id: cache-jasper - uses: actions/cache@v4 - with: - path: ~/Jasper - key: jasper-${{ runner.os }}-4.0.0 - - - name: checkout-jasper - if: steps.cache-jasper.outputs.cache-hit != 'true' - uses: actions/checkout@v4 + - name: "Build dependencies" + uses: NOAA-EMC/ci-build-nceplibs@develop with: - repository: jasper-software/jasper - path: jasper - ref: version-4.0.0 - - - name: build-jasper - if: steps.cache-jasper.outputs.cache-hit != 'true' - run: | - cd jasper - mkdir build-jasper && cd build-jasper - cmake .. -DCMAKE_INSTALL_PREFIX=~/Jasper - make -j2 - make install + bacio-version: develop + w3emc-version: develop + jasper-version: version-4.0.0 + w3emc-cmake-args: -DBUILD_WITH_BUFR=OFF - name: checkout-ip uses: actions/checkout@v3 @@ -93,7 +45,7 @@ jobs: repository: NOAA-EMC/NCEPLIBS-ip path: ip ref: develop - + - name: build-ip run: | cd ip @@ -101,7 +53,7 @@ jobs: cd build cmake -DCMAKE_INSTALL_PREFIX=~/ip .. make -j2 - make install + make install - name: checkout uses: actions/checkout@v4 @@ -120,12 +72,12 @@ jobs: cd g2 mkdir build cd build - cmake -DJasper_ROOT=~/Jasper -DCMAKE_PREFIX_PATH="~/bacio;~/w3emc;~/ip" -DCMAKE_Fortran_FLAGS="-g -O0" -DCMAKE_C_FLAGS="-g -O0" -DFTP_TEST_FILES=ON -DTEST_FILE_DIR=/home/runner/data -DCMAKE_BUILD_TYPE=Debug .. + cmake -DJasper_ROOT=~/Jasper -DCMAKE_PREFIX_PATH="$GITHUB_WORKSPACE/nceplibs/NCEPLIBS-bacio;$GITHUB_WORKSPACE/nceplibs/NCEPLIBS-w3emc;$GITHUB_WORKSPACE/nceplibs/jasper;$GITHUB_WORKSPACE/nceplibs/NCEPLIBS-ip" -DCMAKE_Fortran_FLAGS="-g -O0" -DCMAKE_C_FLAGS="-g -O0" -DFTP_TEST_FILES=ON -DTEST_FILE_DIR=/home/runner/data -DCMAKE_BUILD_TYPE=Debug .. make -j2 VERBOSE=1 - name: test_memcheck run: | - cd $GITHUB_WORKSPACE/g2/build + cd $GITHUB_WORKSPACE/g2/build ctest -LE "^noMemcheck$" -T memcheck - name: cache-data @@ -133,5 +85,3 @@ jobs: run: | mkdir ~/data cp $GITHUB_WORKSPACE/g2/build/tests/data/* ~/data - - diff --git a/docs/user_guide.md b/docs/user_guide.md index 412985282..a005e51cd 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -29,6 +29,69 @@ Unrepeated sections remain in effect until redefined. The above overview was taken from WMO's FM 92-XII GRIB description of the experimental GRIB Edition 2 form. +# Building NCEPLIBS-g2 + +The NCEPLIBS-g2 library is built with CMake. Starting with +NCEPLIBS-g2-4.0.0, the +[NCEPLIBS-g2c](https://github.com/NOAA-EMC/NCEPLIBS-g2c) library is +required for the build. + +The [NCEPLIBS-w3emc](https://github.com/NOAA-EMC/NCEPLIBS-w3emc) +library provides GRIB1 support. It's required for some NCEPLIBS-g2 +subroutines and some utilities. If built without NCEPLIBS-w3emc, then +NCEPLIBS-g2 will not contain any GRIB1 functionality and utilities +which need GRIB1 subroutines will not be built. + +# Utilities + +The NCEPLIBS-g2 project contains a collection of NCEP grib +related utilities. + +The utilities: +- cnvgrib.F90 - Convert between GRIB1 and GRIB2. +- copygb.F90 - Copy all or part of a GRIB1 file. +- copygb2.F90 - Copy all or part of a GRIB2 file. +- degrib2.F90 - Inventory a GRIB2 file. +- grbindex.F90 - Create an index from a GRIB1 file. +- grb2index.F90 - Create an index from a GRIB2 file. +- tocgrib.F90 - Copy some GRIB2 fields to a new GRIB1 file. +- tocgrib2.F90 - Copy some GRIB2 fields to a new GRIB2 file. +- tocgrib2super.F90 - Copy some GRIB2 fields to a new GRIB2 file with super WMO header. + +# File-Based API + +NCEPLIBS-g2-4.0.0 introduces a new file-based API. This API adds the +capability of handling GRIB2 files, keeping track of the locations of +messages for the user. + +To open a file with the new API, call g2cf_open(). This will return a +file ID which can be used in other subroutines. + +Subroutines in the new API include: + +* g2cf_open() - Open a GRIB2 file. +* g2cf_open_index() - Open a file using an index file for better performance. +* g2cf_inq() - Learn about a GRIB2 file. +* g2cf_inq_msg() - Learn about a GRIB2 message in the file. +* g2cf_close() - Close an opened GRIB2 file. + +Release all resources for the file by calling g2cf_close(). + +# Index Files + +The NCEPLIBS-g2 library uses index files to help quickly navigate a +GRIB2 file. These index files can result in significant performance +improvement for large GRIB2 files. + +There are two versions of the index file. The original version +(version 1) was used until NCEPLIBS-g2-4.0.0. This version of the +index file does not handle files larger than 2 GB. + +The second version of the index file (version 2) handles GRIB2 files +which are larger than 2 GB. + +Create an index file with the grb2index utility. + # GRIB2 Encoding Routines To start a new GRIB2 message, call subroutine gribcreate(). It @@ -144,6 +207,7 @@ http://www.nws.noaa.gov/tdl/iwt/grib2/frameset_grib2.htm. ## Documentation for Previous Versions of NCEPLIBS-g2 +* [NCEPLIBS-g2 Version 3.5.0](ver-3.5.0/index.html) * [NCEPLIBS-g2 Version 3.4.9](ver-3.4.9/index.html) * [NCEPLIBS-g2 Version 3.4.8](ver-3.4.8/index.html) * [NCEPLIBS-g2 Version 3.4.7](ver-3.4.7/index.html) diff --git a/spack/package.py b/spack/package.py index 8c160d5f1..7db7f9e99 100644 --- a/spack/package.py +++ b/spack/package.py @@ -37,6 +37,7 @@ class G2(CMakePackage): when="@3.4.6:", ) variant("w3emc", default=True, description="Enable GRIB1 through w3emc", when="@3.4.6:") + variant("shared", default="False", when="@3.4.7:") variant("openmp", default=False, description="Use OpenMP multithreading") variant("utils", default=False, description="Build grib utilities") variant("g2c_compare", default=False, description="Enable copygb2 tests using g2c_compare") @@ -63,6 +64,7 @@ def cmake_args(self): self.define_from_variant("OPENMP", "openmp"), self.define_from_variant("CMAKE_POSITION_INDEPENDENT_CODE", "pic"), self.define_from_variant("BUILD_WITH_W3EMC", "w3emc"), + self.define_from_variant("BUILD_SHARED_LIBS", "shared"), self.define("BUILD_4", self.spec.satisfies("precision=4")), self.define("BUILD_D", self.spec.satisfies("precision=d")), self.define_from_variant("G2C_COMPARE", "g2c_compare"), @@ -76,11 +78,10 @@ def setup_run_environment(self, env): self.spec.variants["precision"].value if self.spec.satisfies("@3.4.6:") else ("4", "d") ) for suffix in precisions: - lib = find_libraries("libg2_" + suffix, root=self.prefix, shared=False, recursive=True) + lib = find_libraries("libg2_" + suffix, root=self.prefix, shared=self.spec.satisfies("+shared"), recursive=True) env.set("G2_LIB" + suffix, lib[0]) env.set("G2_INC" + suffix, join_path(self.prefix, "include_" + suffix)) def check(self): with working_dir(self.builder.build_directory): make("test") - diff --git a/test_utils/CMakeLists.txt b/test_utils/CMakeLists.txt index 168e5fa83..2f35ca9b1 100644 --- a/test_utils/CMakeLists.txt +++ b/test_utils/CMakeLists.txt @@ -5,8 +5,7 @@ if(BUILD_4) # This fortran test is for the internals of degrib2. - add_executable(test_degrib2_int test_degrib2_int.F90 ${CMAKE_SOURCE_DIR}/utils/prlevel.F90 - ${CMAKE_SOURCE_DIR}/utils/prvtime.F90) + add_executable(test_degrib2_int test_degrib2_int.F90 ${CMAKE_SOURCE_DIR}/utils/prgrib2.F90) target_link_libraries(test_degrib2_int PUBLIC ${PROJECT_NAME}_4) add_test(NAME test_degrib2_int COMMAND test_degrib2_int) endif() diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt index 3f54070fc..c68d607ae 100644 --- a/utils/CMakeLists.txt +++ b/utils/CMakeLists.txt @@ -31,14 +31,12 @@ if (BUILD_D) endif() if (BUILD_4) - add_executable(cnvgrib cnv12.F90 cnv22.F90 gds2gdt.F90 makepdsens.F90 - pds2pdtens.F90 putgbexn.F90 cnv21.F90 cnvgrib.F90 gdt2gds.F90 - makepds.F90 pds2pdt.F90 setbit.F90) + add_executable(cnvgrib cnv12.F90 cnv22.F90 cnv21.F90 cnvgrib.F90) target_link_libraries(cnvgrib PUBLIC ${PROJECT_NAME}_4) target_link_libraries(cnvgrib PRIVATE bacio::bacio w3emc::w3emc_4 ${JASPER_LIBRARIES} PNG::PNG ${ZLIB_LIBRARY}) - add_executable(degrib2 degrib2.F90 prlevel.F90 prvtime.F90) + add_executable(degrib2 prgrib2.F90 degrib2.F90) target_link_libraries(degrib2 PUBLIC ${PROJECT_NAME}_4) target_link_libraries(degrib2 PRIVATE bacio::bacio w3emc::w3emc_4 ${JASPER_LIBRARIES} PNG::PNG ${ZLIB_LIBRARY}) @@ -82,7 +80,7 @@ target_link_libraries(copygb PRIVATE bacio::bacio w3emc::w3emc_d ip::ip_d) add_executable(grbindex grbindex.f) target_link_libraries(grbindex PRIVATE bacio::bacio w3emc::w3emc_4) -add_executable(tocgrib makwmo.F90 mkfldsep.F90 tocgrib.F90) +add_executable(tocgrib makwmo.F90 tocgrib.F90) target_link_libraries(tocgrib PRIVATE bacio::bacio w3emc::w3emc_4) if(ip_VERSION LESS 5.0) diff --git a/utils/cnv12.F90 b/utils/cnv12.F90 index 80dd8304d..69302e41e 100644 --- a/utils/cnv12.F90 +++ b/utils/cnv12.F90 @@ -367,3 +367,1512 @@ subroutine cnv12(ifl1, ifl2, ipack, usemiss, imiss, uvvect, table_ver) return end subroutine cnv12 + +!> This routine converts a GRIB1 GDS (in format specfied in +!> w3fi63.f) to necessary info for a GRIB2 Grid Definition Section. +!> +!> ### Program History Log +!> Date | Programmer | Comments +!> -----|------------|--------- +!> 2003-06-17 | Gilbert | Initial. +!> 2004-04-27 | Gilbert | Added support for Gaussian grids. +!> 2007-04-16 | Vuong | Added Curvilinear Orthogonal grids. +!> 2007-05-29 | Vuong | Added Rotate Lat/Lon E-grid (203) +!> 2010-05-10 | Vuong | Added Rotate Lat/Lon for Non-E Stagger grid (205) +!> 2011-05-04 | Vuong | Corrected Arakawa Lat/Lon of grid points for Non-E Stagger grid (205) +!> +!> @param[in] kgds GRIB1 GDS info as returned by w3fi63.f. +!> @param[out] igds Contains information read from the appropriate GRIB +!> Grid Definition Section 3 for the field being returned. Must be +!> dimensioned >= 5. +!> - igds(1) Source of grid definition (see Code Table 3.0) +!> - igds(2) Number of grid points in the defined grid. +!> - igds(3) Number of octets needed for each additional grid points +!> definition. Used to define number of points in each row (or column) +!> for non-regular grids. = 0, if using regular grid. +!> - igds(4) Interpretation of list for optional points definition. (Code Table 3.11) +!> - igds(5) Grid Definition Template Number (Code Table 3.1) +!> @param[out] igdstmpl Grid Definition Template values for GDT 3.igds(5) +!> @param[out] idefnum The number of entries in array +!> ideflist. i.e. number of rows (or columns) for which optional grid +!> points are defined. +!> @param[out] ideflist Optional integer array containing the number of +!> grid points contained in each row (or column). +!> @param[out] iret Error return value: +!> - 0 Successful +!> - 1 Unrecognized GRIB1 grid data representation type +!> +!> @author Stephen Gilbert @date 2003-06-17 +subroutine gds2gdt(kgds,igds,igdstmpl,idefnum,ideflist,iret) + + integer,intent(in) :: kgds(*) + integer,intent(out) :: igds(*),igdstmpl(*),ideflist(*) + integer,intent(out) :: idefnum,iret + + iret=0 + if (kgds(1).eq.0) then ! Lat/Lon grid + idefnum=0 + igds(1)=0 ! grid def specfied in template + igds(2)=kgds(2)*kgds(3) ! num of grid points + igds(3)=0 ! octets for further grid definition + igds(4)=0 ! interpretation of optional list + igds(5)=0 ! Grid Definition Template number + if (btest(kgds(6),6)) then ! shape of Earth + igdstmpl(1)=2 + else + igdstmpl(1)=0 + endif + igdstmpl(2)=0 + igdstmpl(3)=0 + igdstmpl(4)=0 + igdstmpl(5)=0 + igdstmpl(6)=0 + igdstmpl(7)=0 + igdstmpl(8)=kgds(2) !Ni + igdstmpl(9)=kgds(3) !Nj + igdstmpl(10)=0 + igdstmpl(11)=0 + igdstmpl(12)=kgds(4)*1000 ! Lat of 1st grid point + if (kgds(5).lt.0) then ! Lon of 1st grid point + igdstmpl(13)=(360000+kgds(5))*1000 ! convert W to E + else + igdstmpl(13)=kgds(5)*1000 + endif + igdstmpl(14)=0 ! Resolution and Component flags + if (btest(kgds(6),7)) igdstmpl(14)=48 + if (btest(kgds(6),3)) igdstmpl(14)=igdstmpl(14)+8 + igdstmpl(15)=kgds(7)*1000 ! Lat of last grid point + if (kgds(8).lt.0) then ! Lon of last grid point + igdstmpl(16)=(360000+kgds(8))*1000 ! convert W to E + else + igdstmpl(16)=kgds(8)*1000 + endif + igdstmpl(17)=kgds(9)*1000 ! Di + igdstmpl(18)=kgds(10)*1000 ! Dj + igdstmpl(19)=kgds(11) ! Scanning mode + if (kgds(20).ne.255) then ! irregular grid (eg WAFS) + igds(2)=kgds(21) ! num of grid points + !idefnum=kgds(19) + if (kgds(2).eq.65535) idefnum=kgds(3) + if (kgds(3).eq.65535) idefnum=kgds(2) + imax=0 + do j=1,idefnum + ideflist(j)=kgds(21+j) + if (ideflist(j).gt.imax) imax=ideflist(j) + enddo + igds(3)=1 ! octets for further grid definition + if (imax.gt.255) igds(3)=2 + if (imax.gt.65535) igds(3)=3 + if (imax.gt.16777215) igds(3)=4 + igds(4)=1 ! interpretation of optional list + igdstmpl(8)=-1 + igdstmpl(17)=-1 + endif + elseif (kgds(1).eq.1) then ! Mercator grid + idefnum=0 + igds(1)=0 ! grid def specfied in template + igds(2)=kgds(2)*kgds(3) ! num of grid points + igds(3)=0 ! octets for further grid definition + igds(4)=0 ! interpretation of optional list + igds(5)=10 ! Grid Definition Template number + if (btest(kgds(6),6)) then ! shape of Earth + igdstmpl(1)=2 + else + igdstmpl(1)=0 + endif + igdstmpl(2)=0 + igdstmpl(3)=0 + igdstmpl(4)=0 + igdstmpl(5)=0 + igdstmpl(6)=0 + igdstmpl(7)=0 + igdstmpl(8)=kgds(2) ! Ni + igdstmpl(9)=kgds(3) ! Nj + igdstmpl(10)=kgds(4)*1000 ! Lat of 1st grid point + if (kgds(5).lt.0) then ! Lon of 1st grid point + igdstmpl(11)=(360000+kgds(5))*1000 ! convert W to E + else + igdstmpl(11)=kgds(5)*1000 + endif + igdstmpl(12)=0 ! Resolution and Component flags + if (btest(kgds(6),7)) igdstmpl(12)=48 + if (btest(kgds(6),3)) igdstmpl(12)=igdstmpl(12)+8 + igdstmpl(13)=kgds(9)*1000 ! Lat intersects earth + igdstmpl(14)=kgds(7)*1000 ! Lat of last grid point + if (kgds(8).lt.0) then ! Lon of last grid point + igdstmpl(15)=(360000+kgds(8))*1000 ! convert W to E + else + igdstmpl(15)=kgds(8)*1000 + endif + igdstmpl(16)=kgds(11) ! Scanning mode + igdstmpl(17)=0 ! Orientation of grid + igdstmpl(18)=kgds(12)*1000 ! Di + igdstmpl(19)=kgds(13)*1000 ! Dj + elseif (kgds(1).eq.3) then ! Lambert Conformal Grid + idefnum=0 + igds(1)=0 ! grid def specfied in template + igds(2)=kgds(2)*kgds(3) ! num of grid points + igds(3)=0 ! octets for further grid definition + igds(4)=0 ! interpretation of optional list + igds(5)=30 ! Grid Definition Template number + if (btest(kgds(6),6)) then ! shape of Earth + igdstmpl(1)=2 + else + igdstmpl(1)=0 + endif + igdstmpl(2)=0 + igdstmpl(3)=0 + igdstmpl(4)=0 + igdstmpl(5)=0 + igdstmpl(6)=0 + igdstmpl(7)=0 + igdstmpl(8)=kgds(2) ! Nx + igdstmpl(9)=kgds(3) ! Ny + igdstmpl(10)=kgds(4)*1000 ! Lat of 1st grid point + if (kgds(5).lt.0) then ! Lon of 1st grid point + igdstmpl(11)=(360000+kgds(5))*1000 ! convert W to E + else + igdstmpl(11)=kgds(5)*1000 + endif + igdstmpl(12)=0 ! Resolution and Component flags + if (btest(kgds(6),7)) igdstmpl(12)=48 + if (btest(kgds(6),3)) igdstmpl(12)=igdstmpl(12)+8 + igdstmpl(13)=kgds(12)*1000 ! Lat where Dx and Dy specified + if (kgds(7).lt.0) then ! Lon of orientation + igdstmpl(14)=(360000+kgds(7))*1000 ! convert W to E + else + igdstmpl(14)=kgds(7)*1000 + endif + igdstmpl(15)=kgds(8)*1000 ! Dx + igdstmpl(16)=kgds(9)*1000 ! Dy + igdstmpl(17)=kgds(10) ! Projection Center Flag + igdstmpl(18)=kgds(11) ! Scanning mode + igdstmpl(19)=kgds(12)*1000 ! Latin 1 + igdstmpl(20)=kgds(13)*1000 ! Latin 2 + igdstmpl(21)=kgds(14)*1000 ! Lat of S. Pole of projection + if (kgds(15).lt.0) then ! Lon of S. Pole of projection + igdstmpl(22)=(360000+kgds(15))*1000 ! convert W to E + else + igdstmpl(22)=kgds(15)*1000 + endif + elseif (kgds(1).eq.4) then ! Gaussian Lat/Lon grid + idefnum=0 + igds(1)=0 ! grid def specfied in template + igds(2)=kgds(2)*kgds(3) ! num of grid points + igds(3)=0 ! octets for further grid definition + igds(4)=0 ! interpretation of optional list + igds(5)=40 ! Grid Definition Template number + if (btest(kgds(6),6)) then ! shape of Earth + igdstmpl(1)=2 + else + igdstmpl(1)=0 + endif + igdstmpl(2)=0 + igdstmpl(3)=0 + igdstmpl(4)=0 + igdstmpl(5)=0 + igdstmpl(6)=0 + igdstmpl(7)=0 + igdstmpl(8)=kgds(2) !Ni + igdstmpl(9)=kgds(3) !Nj + igdstmpl(10)=0 + igdstmpl(11)=0 + igdstmpl(12)=kgds(4)*1000 ! Lat of 1st grid point + if (kgds(5).lt.0) then ! Lon of 1st grid point + igdstmpl(13)=(360000+kgds(5))*1000 ! convert W to E + else + igdstmpl(13)=kgds(5)*1000 + endif + igdstmpl(14)=0 ! Resolution and Component flags + if (btest(kgds(6),7)) igdstmpl(14)=48 + if (btest(kgds(6),3)) igdstmpl(14)=igdstmpl(14)+8 + igdstmpl(15)=kgds(7)*1000 ! Lat of last grid point + if (kgds(8).lt.0) then ! Lon of last grid point + igdstmpl(16)=(360000+kgds(8))*1000 ! convert W to E + else + igdstmpl(16)=kgds(8)*1000 + endif + igdstmpl(17)=kgds(9)*1000 ! Di + igdstmpl(18)=kgds(10) ! D - Number of parallels + igdstmpl(19)=kgds(11) ! Scanning mode + elseif (kgds(1).eq.5) then ! Polar Stereographic Grid + idefnum=0 + igds(1)=0 ! grid def specfied in template + igds(2)=kgds(2)*kgds(3) ! num of grid points + igds(3)=0 ! octets for further grid definition + igds(4)=0 ! interpretation of optional list + igds(5)=20 ! Grid Definition Template number + if (btest(kgds(6),6)) then ! shape of Earth + igdstmpl(1)=2 + else + igdstmpl(1)=0 + endif + igdstmpl(2)=0 + igdstmpl(3)=0 + igdstmpl(4)=0 + igdstmpl(5)=0 + igdstmpl(6)=0 + igdstmpl(7)=0 + igdstmpl(8)=kgds(2) ! Nx + igdstmpl(9)=kgds(3) ! Ny + igdstmpl(10)=kgds(4)*1000 ! Lat of 1st grid point + if (kgds(5).lt.0) then ! Lon of 1st grid point + igdstmpl(11)=(360000+kgds(5))*1000 ! convert W to E + else + igdstmpl(11)=kgds(5)*1000 + endif + igdstmpl(12)=0 ! Resolution and Component flags + if (btest(kgds(6),7)) igdstmpl(12)=48 + if (btest(kgds(6),3)) igdstmpl(12)=igdstmpl(12)+8 + igdstmpl(13)=60000000 ! Lat where Dx and Dy specified + if (btest(kgds(10),7)) igdstmpl(13)=-60000000 + if (kgds(7).lt.0) then ! Lon of orientation + igdstmpl(14)=(360000+kgds(7))*1000 ! convert W to E + else + igdstmpl(14)=kgds(7)*1000 + endif + igdstmpl(15)=kgds(8)*1000 ! Dx + igdstmpl(16)=kgds(9)*1000 ! Dy + igdstmpl(17)=kgds(10) ! Projection Center Flag + igdstmpl(18)=kgds(11) ! Scanning mode + elseif (kgds(1).eq.204) then ! Curivilinear Orthogonal Grid (Used by RTOFS) + idefnum=0 + igds(1)=0 ! grid def specfied in template + igds(2)=kgds(2)*kgds(3) ! num of grid points + igds(3)=0 ! octets for further grid definition + igds(4)=0 ! interpretation of optional list + igds(5)=204 ! Grid Definition Template number + if (btest(kgds(6),6)) then ! shape of Earth + igdstmpl(1)=2 + else + igdstmpl(1)=0 + endif + igdstmpl(2)=0 + igdstmpl(3)=0 + igdstmpl(4)=0 + igdstmpl(5)=0 + igdstmpl(6)=0 + igdstmpl(7)=0 + igdstmpl(8)=kgds(2) !Ni - No of points along x-grid direction + igdstmpl(9)=kgds(3) !Nj - No of points along y-grid direction + igdstmpl(10)=0 + igdstmpl(11)=0 + igdstmpl(12)=0 + igdstmpl(13)=0 + igdstmpl(14)=0 ! Resolution and Component flags + if (btest(kgds(6),7)) igdstmpl(14)=48 + if (btest(kgds(6),3)) igdstmpl(14)=igdstmpl(14)+8 + igdstmpl(15)=0 + igdstmpl(16)=0 + igdstmpl(17)=0 + igdstmpl(18)=0 + igdstmpl(19)=kgds(11) ! Scanning mode + elseif (kgds(1).eq.203) then ! Rot Lat/Lon grid (Arakawa) + idefnum=0 + igds(1)=0 ! grid def specfied in template + igds(2)=kgds(2)*kgds(3) ! num of grid points + igds(3)=0 ! octets for further grid definition + igds(4)=0 ! interpretation of optional list + igds(5)=32768 ! Grid Definition Template number + if (btest(kgds(6),6)) then ! shape of Earth + igdstmpl(1)=2 + else + igdstmpl(1)=0 + endif + igdstmpl(2)=0 + igdstmpl(3)=0 + igdstmpl(4)=0 + igdstmpl(5)=0 + igdstmpl(6)=0 + igdstmpl(7)=0 + igdstmpl(8)=kgds(2) !Ni + igdstmpl(9)=kgds(3) !Nj + igdstmpl(10)=0 + igdstmpl(11)=0 + igdstmpl(12)=kgds(4)*1000 ! Lat of 1st grid point + if (kgds(5).lt.0) then ! Lon of 1st grid point + igdstmpl(13)=(360000+kgds(5))*1000 ! convert W to E + else + igdstmpl(13)=kgds(5)*1000 + endif + igdstmpl(14)=0 ! Resolution and Component flags + if (btest(kgds(6),7)) igdstmpl(14)=48 + if (btest(kgds(6),3)) igdstmpl(14)=igdstmpl(14)+8 + igdstmpl(15)=kgds(7)*1000 ! Lat of last grid point + if (kgds(8).lt.0) then ! Lon of last grid point + igdstmpl(16)=(360000+kgds(8))*1000 ! convert W to E + else + igdstmpl(16)=kgds(8)*1000 + endif + igdstmpl(17)=kgds(9)*1000 ! Di + igdstmpl(18)=kgds(10)*1000 ! Dj + igdstmpl(19)=kgds(11) ! Scanning mode + elseif (kgds(1).eq.205) then ! Rot Lat/Lon for Non-E Stagger grid (Arakawa) + idefnum=0 + igds(1)=0 ! grid def specfied in template + igds(2)=kgds(2)*kgds(3) ! num of grid points + igds(3)=0 ! octets for further grid definition + igds(4)=0 ! interpretation of optional list + igds(5)=32769 ! Grid Definition Template number + if (btest(kgds(6),6)) then ! shape of Earth + igdstmpl(1)=2 + else + igdstmpl(1)=0 + endif + igdstmpl(2)=0 + igdstmpl(3)=0 + igdstmpl(4)=0 + igdstmpl(5)=0 + igdstmpl(6)=0 + igdstmpl(7)=0 + igdstmpl(8)=kgds(2) !Ni + igdstmpl(9)=kgds(3) !Nj + igdstmpl(10)=0 + igdstmpl(11)=0 + igdstmpl(12)=kgds(4)*1000 ! Lat of 1st grid point + if (kgds(5).lt.0) then ! Lon of 1st grid point + igdstmpl(13)=(360000+kgds(5))*1000 ! convert W to E + else + igdstmpl(13)=kgds(5)*1000 + endif + igdstmpl(14)=0 ! Resolution and Component flags + if (btest(kgds(6),7)) igdstmpl(14)=48 + if (btest(kgds(6),3)) igdstmpl(14)=igdstmpl(14)+8 + igdstmpl(15)=kgds(7)*1000 ! Lat of last grid point + if (kgds(8).lt.0) then ! Lon of last grid point + igdstmpl(16)=(360000+kgds(8))*1000 ! convert W to E + else + igdstmpl(16)=kgds(8)*1000 + endif + igdstmpl(17)=kgds(9)*1000 ! Di + igdstmpl(18)=kgds(10)*1000 ! Dj + igdstmpl(19)=kgds(11) ! Scanning mode + igdstmpl(20)=kgds(12)*1000 + igdstmpl(21)=kgds(13)*1000 + else + Print *,'gds2gdt: Unrecognized GRIB1 Grid type = ',kgds(1) + iret=1 + endif + return +end subroutine gds2gdt + +!> This routine converts a GRIB1 PDS (Section 1) info to a GRIB2 PDS +!> (Section 4) info with appropriate Product Definition Template. +!> +!> @note Use pds2pdtens for ensemble related PDS. +!> +!> ### Program History Log +!> Date | Programmer | Comments +!> -----|------------|--------- +!> 2003-06-12 | Gilbert | Initial. +!> 2005-04-19 | Gilbert | Changed scaling factor used with potential vorticity surfaces. +!> 2007-02-07 | Gilbert | fixed end date calculation +!> 2007-03-26 | Gordon | Added check for ECMWF data to reference ECMWF Conversion tables. +!> 2007-05-14 | Boi Vuong | Added Time Range Indicator 51 (Climatological Mean Value) +!> 2009-05-20 | Boi Vuong | Added check for WAFS to use PDT 4.8 for Max Wind +!> 2009-12-14 | Boi Vuong | Added check for WAFS to use PDT 4.15 for Icing, Turbulence and Cumulonimbus +!> 2010-02-18 | Boi Vuong | Added Time Range Indicator 7 +!> 2010-08-10 | Boi Vuong | Removed check for WAFS to use PDT 4.8 for Max Wind +!> 2011-10-24 | Boi Vuong | Added check for parameters (MAXUW, MAXVW, to set type of statistical processing (MIN and MAX) +!> +!> @param[in] kpds GRIB1 PDS info as specified in W3FI63. +!> @param[out] ipdsnum GRIB2 Product Definition Template Number +!> @param[out] ipdstmpl GRIB2 Product Definition Template entries for PDT 4.ipdsnum +!> @param[out] numcoord number of vertical discretisation values (not implemented) +!> @param[out] coordlist rtical discretisation values (not implemented) +!> @param[out] iret Error return value: +!> - 0 Successful +!> - 1 Unrecognized GRIB1 Time Range Indicator +!> +!> @author Stephen Gilbert @date 2003-06-12 +subroutine pds2pdt(kpds,ipdsnum,ipdstmpl,numcoord,coordlist, & + iret) + + use params + use params_ecmwf + + integer,intent(in) :: kpds(*) + integer,intent(out) :: ipdstmpl(*) + real,intent(out) :: coordlist(*) + integer,intent(out) :: ipdsnum,numcoord,iret + + integer :: idat(8),jdat(8) + real :: rinc(5) + logical :: ecmwf + + iret=0 + numcoord=0 + ecmwf=.false. + + if (kpds(1).eq.98) ecmwf=.true. + ! + ! Special check for WAFS products for parameters (Max Icing, TP and CAT) + ! to PDT 4.15 + ! + if ((kpds(2).eq.96 .AND. kpds(3).eq.45 .AND. & + kpds(16).eq.10) .AND. & + (kpds(19).eq.140 .AND. (kpds(5).ge.168 .AND. & + kpds(5).le.173))) then + ipdsnum=15 + ! get GRIB2 parameter category and number from GRIB1 + ! parameter number + if (ecmwf) then ! treat ecmwf data conversion seperately + call param_ecmwf_g1_to_g2(kpds(5),kpds(19),idum, & + ipdstmpl(1),ipdstmpl(2)) + else + call param_g1_to_g2(kpds(5),kpds(19),idum,ipdstmpl(1), & + ipdstmpl(2)) + endif + ipdstmpl(3)=2 + ipdstmpl(4)=0 + ipdstmpl(5)=kpds(2) + ipdstmpl(6)=0 + ipdstmpl(7)=0 + ipdstmpl(8)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(8)=13 + ipdstmpl(9)=kpds(14) + call cnvlevel(kpds(6),kpds(7),ipdstmpl) + if (kpds(5).eq.168.or.kpds(5).eq.170.or. & ! statistical process WAFS-ICAO + kpds(5).eq.172) ipdstmpl(16)=0 ! for Mean Icing, CT, CAT + if (kpds(5).eq.169.or.kpds(5).eq.171.or. & ! statistical process WAFS-ICAO + kpds(5).eq.173) ipdstmpl(16)=2 ! for MAX Icing, CT, CAT + ipdstmpl(17)=3 ! Neighbor interpolation + ! Output values is set to nearest input values + ipdstmpl(18)=1 ! Number of data point (grid 45) + elseif (kpds(16).eq.0.or.kpds(16).eq.1.or.kpds(16).eq.10) then + ipdsnum=0 + ! get GRIB2 parameter category and number from GRIB1 + ! parameter number + if (ecmwf) then ! treat ecmwf data conversion seperately + call param_ecmwf_g1_to_g2(kpds(5),kpds(19),idum, & + ipdstmpl(1),ipdstmpl(2)) + else + call param_g1_to_g2(kpds(5),kpds(19),idum,ipdstmpl(1), & + ipdstmpl(2)) + endif + if (kpds(16).eq.1) then + ipdstmpl(3)=0 + else + ipdstmpl(3)=2 + endif + ipdstmpl(4)=0 + ipdstmpl(5)=kpds(2) + ipdstmpl(6)=0 + ipdstmpl(7)=0 + ipdstmpl(8)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(8)=13 + !if (kpds(16).eq.10) then + ! ipdstmpl(9)=(kpds(14)*256)+kpds(15) + !else + ipdstmpl(9)=kpds(14) + !endif + call cnvlevel(kpds(6),kpds(7),ipdstmpl) + if (kpds(2).eq.96 .AND. kpds(3).eq.45 .AND. & + kpds(16).eq.10) then + if (kpds(5).eq.174) ipdstmpl(10) = 10 + if (kpds(5).eq.179) ipdstmpl(10) = 11 + if (kpds(5).eq.180) ipdstmpl(10) = 12 + end if + elseif (kpds(16).ge.2.AND.kpds(16).le.5) then + ipdsnum=8 + ! get GRIB2 parameter category and number from GRIB1 + ! parameter number + if (ecmwf) then ! treat ecmwf data conversion seperately + call param_ecmwf_g1_to_g2(kpds(5),kpds(19),idum, & + ipdstmpl(1),ipdstmpl(2)) + else + call param_g1_to_g2(kpds(5),kpds(19),idum,ipdstmpl(1), & + ipdstmpl(2)) + endif + ipdstmpl(3)=2 + ipdstmpl(4)=0 + ipdstmpl(5)=kpds(2) + ipdstmpl(6)=0 + ipdstmpl(7)=0 + ipdstmpl(8)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(8)=13 + ipdstmpl(9)=kpds(14) + call cnvlevel(kpds(6),kpds(7),ipdstmpl) + ! calculate ending time using initial ref-time, idat, + ! and increment rinc. + idat=0 + idat(1)=((kpds(21)-1)*100)+kpds(8) + idat(2)=kpds(9) + idat(3)=kpds(10) + idat(4)=-500 ! EST + idat(5)=kpds(11) + idat(6)=kpds(12) + rinc=0.0 + if ( ipdstmpl(8).eq.0 ) then + rinc(3)=kpds(15) + elseif ( ipdstmpl(8).eq.1 ) then + rinc(2)=kpds(15) + elseif ( ipdstmpl(8).eq.2 ) then + rinc(1)=kpds(15) + elseif ( ipdstmpl(8).eq.10 ) then + rinc(2)=kpds(15) * 3 + elseif ( ipdstmpl(8).eq.11 ) then + rinc(2)=kpds(15) * 6 + elseif ( ipdstmpl(8).eq.12 ) then + rinc(2)=kpds(15) * 12 + elseif ( ipdstmpl(8).eq.13 ) then + rinc(4)=kpds(15) + endif + call w3movdat(rinc,idat,jdat) ! calculate end date/time + ipdstmpl(16)=jdat(1) ! year of end time + ipdstmpl(17)=jdat(2) ! month of end time + ipdstmpl(18)=jdat(3) ! day of end time + ipdstmpl(19)=jdat(5) ! hour of end time + ipdstmpl(20)=jdat(6) ! minute of end time + ipdstmpl(21)=jdat(7) ! second of end time + ipdstmpl(22)=1 ! # of time ranges + ipdstmpl(23)=kpds(20) ! # of values missing + if (kpds(16).eq.2) then ! statistical process + ipdstmpl(24)=255 + elseif (kpds(16).eq.3) then + ipdstmpl(24)=0 + elseif (kpds(16).eq.4) then + ipdstmpl(24)=1 + elseif (kpds(16).eq.5) then + ipdstmpl(24)=4 + endif + ipdstmpl(25)=2 + if (kpds(19).eq.129 .AND. & + (kpds(5).eq.235 .or. kpds(5).eq.236 .or. & + kpds(5).eq.237 .or. kpds(5).eq.238 .or. & + kpds(5).eq.239 .or. kpds(5).eq.253 .or. & + kpds(5).eq.254 )) then + ipdstmpl(24)=2 + endif + ipdstmpl(26)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(26)=13 + ipdstmpl(27)=kpds(15)-kpds(14) + ipdstmpl(28)=255 + ipdstmpl(29)=0 + elseif (kpds(16).eq.7) then + ipdsnum=8 + ! get GRIB2 parameter category and number from GRIB1 + ! parameter number + if (ecmwf) then ! treat ecmwf data conversion seperately + call param_ecmwf_g1_to_g2(kpds(5),kpds(19),idum, & + ipdstmpl(1),ipdstmpl(2)) + else + call param_g1_to_g2(kpds(5),kpds(19),idum,ipdstmpl(1), & + ipdstmpl(2)) + endif + ipdstmpl(3)=2 + ipdstmpl(4)=0 + ipdstmpl(5)=kpds(2) + ipdstmpl(6)=0 + ipdstmpl(7)=0 + ipdstmpl(8)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(8)=13 + ipdstmpl(9)= - kpds(14) + call cnvlevel(kpds(6),kpds(7),ipdstmpl) + ! calculate ending time using initial ref-time, idat, + ! and increment rinc. + idat=0 + idat(1)=((kpds(21)-1)*100)+kpds(8) + idat(2)=kpds(9) + idat(3)=kpds(10) + idat(4)=-500 ! EST + idat(5)=kpds(11) + idat(6)=kpds(12) + rinc=0.0 + if ( ipdstmpl(8).eq.0 ) then + rinc(3)=kpds(15) + elseif ( ipdstmpl(8).eq.1 ) then + rinc(2)=kpds(15) + elseif ( ipdstmpl(8).eq.2 ) then + rinc(1)=kpds(15) + elseif ( ipdstmpl(8).eq.10 ) then + rinc(2)=kpds(15) * 3 + elseif ( ipdstmpl(8).eq.11 ) then + rinc(2)=kpds(15) * 6 + elseif ( ipdstmpl(8).eq.12 ) then + rinc(2)=kpds(15) * 12 + elseif ( ipdstmpl(8).eq.13 ) then + rinc(4)=kpds(15) + endif + call w3movdat(rinc,idat,jdat) ! calculate end date/time + ipdstmpl(16)=jdat(1) ! year of end time + ipdstmpl(17)=jdat(2) ! month of end time + ipdstmpl(18)=jdat(3) ! day of end time + ipdstmpl(19)=jdat(5) ! hour of end time + ipdstmpl(20)=jdat(6) ! minute of end time + ipdstmpl(21)=jdat(7) ! second of end time + ipdstmpl(22)=1 ! # of time ranges + ipdstmpl(23)=kpds(20) ! # of values missing + ipdstmpl(24)=0 + ipdstmpl(25)=2 + ipdstmpl(26)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(26)=13 + ipdstmpl(27)=kpds(15) + kpds(14) + ipdstmpl(28)=255 + ipdstmpl(29)=0 + elseif (kpds(16).eq.51) then + ipdsnum=8 + ! get GRIB2 parameter category and number from GRIB1 + ! parameter number + if (ecmwf) then ! treat ecmwf data conversion seperately + call param_ecmwf_g1_to_g2(kpds(5),kpds(19),idum, & + ipdstmpl(1),ipdstmpl(2)) + else + call param_g1_to_g2(kpds(5),kpds(19),idum,ipdstmpl(1), & + ipdstmpl(2)) + endif + ipdstmpl(3)=2 + ipdstmpl(4)=0 + ipdstmpl(5)=kpds(2) + ipdstmpl(6)=0 + ipdstmpl(7)=0 + ipdstmpl(8)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(8)=13 + ipdstmpl(9)=kpds(14) + call cnvlevel(kpds(6),kpds(7),ipdstmpl) + ! calculate ending time using initial ref-time, idat, + ! and increment rinc. + idat=0 + idat(1)=((kpds(21)-1)*100)+kpds(8) + idat(2)=kpds(9) + idat(3)=kpds(10) + idat(4)=-500 ! EST + idat(5)=kpds(11) + idat(6)=kpds(12) + rinc=0.0 + if ( ipdstmpl(8).eq.0 ) then + rinc(3)=kpds(15) + elseif ( ipdstmpl(8).eq.1 ) then + rinc(2)=kpds(15) + elseif ( ipdstmpl(8).eq.2 ) then + rinc(1)=kpds(15) + elseif ( ipdstmpl(8).eq.10 ) then + rinc(2)=kpds(15) * 3 + elseif ( ipdstmpl(8).eq.11 ) then + rinc(2)=kpds(15) * 6 + elseif ( ipdstmpl(8).eq.12 ) then + rinc(2)=kpds(15) * 12 + elseif ( ipdstmpl(8).eq.13 ) then + rinc(4)=kpds(15) + endif + call w3movdat(rinc,idat,jdat) ! calculate end date/time + ipdstmpl(16)=jdat(1) ! year of end time + ipdstmpl(17)=jdat(2) ! month of end time + ipdstmpl(18)=jdat(3) ! day of end time + ipdstmpl(19)=jdat(5) ! hour of end time + ipdstmpl(20)=jdat(6) ! minute of end time + ipdstmpl(21)=jdat(7) ! second of end time + ipdstmpl(22)=1 ! # of time ranges + ipdstmpl(23)=kpds(20) ! # of values missing + ipdstmpl(24)=51 ! Climatological Mean + ipdstmpl(25)=2 + ipdstmpl(26)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(26)=13 + ipdstmpl(27)=kpds(15)-kpds(14) + ipdstmpl(28)=255 + ipdstmpl(29)=0 + else + Print *,' Unrecognized Time Range Indicator = ',kpds(16) + Print *,'pds2pdt: Couldn:t construct PDS Template ' + iret=1 + endif + + return +end subroutine pds2pdt + +!> This routine converts a GRIB1 Level type and Level value to GRIB2 +!> values and fills in the appropriate PDT values for the level/layer +!> information. +!> +!> ### Program History Log +!> Date | Programmer | Comments +!> -----|------------|--------- +!> 2003-06-12 | Gilbert | Initial. +!> 2011-01-13 | Boi Vuong | Added level/layer values from 235 to 239 +!> +!> @param[in] ltype GRIB1 level type (PDS octet 10) +!> @param[in] lval GRIB1 level/layer value(s) (PDS octets 11 and 12) +!> @param[out] ipdstmpl GRIB2 Product Definition Template values. +!> +!> @author Stephen Gilbert @date 2003-06-12 +subroutine cnvlevel(ltype,lval,ipdstmpl) + + integer,intent(in) :: ltype,lval + integer,intent(inout) :: ipdstmpl(*) + + ipdstmpl(10)=ltype + ipdstmpl(11)=0 + ipdstmpl(12)=0 + ipdstmpl(13)=255 + ipdstmpl(14)=0 + ipdstmpl(15)=0 + + if (ltype.eq.100) then + ipdstmpl(12)=lval*100 + elseif (ltype.eq.101) then + ipdstmpl(10)=100 + ipdstmpl(12)=(lval/256)*1000 + ipdstmpl(13)=100 + ipdstmpl(15)=mod(lval,256)*1000 + elseif (ltype.eq.102) then + ipdstmpl(10)=101 + elseif (ltype.eq.103) then + ipdstmpl(10)=102 + ipdstmpl(12)=lval + elseif (ltype.eq.104) then + ipdstmpl(10)=102 + ipdstmpl(12)=lval/256 + ipdstmpl(13)=102 + ipdstmpl(15)=mod(lval,256) + elseif (ltype.eq.105) then + ipdstmpl(10)=103 + ipdstmpl(12)=lval + elseif (ltype.eq.106) then + ipdstmpl(10)=103 + ipdstmpl(12)=(lval/256)*100 + ipdstmpl(13)=103 + ipdstmpl(15)=mod(lval,256)*100 + elseif (ltype.eq.107) then + ipdstmpl(10)=104 + ipdstmpl(11)=4 + ipdstmpl(12)=lval + elseif (ltype.eq.108) then + ipdstmpl(10)=104 + ipdstmpl(11)=2 + ipdstmpl(12)=lval/256 + ipdstmpl(13)=104 + ipdstmpl(14)=2 + ipdstmpl(15)=mod(lval,256) + elseif (ltype.eq.109) then + ipdstmpl(10)=105 + ipdstmpl(12)=lval + elseif (ltype.eq.110) then + ipdstmpl(10)=105 + ipdstmpl(12)=lval/256 + ipdstmpl(13)=105 + ipdstmpl(15)=mod(lval,256) + elseif (ltype.eq.111) then + ipdstmpl(10)=106 + ipdstmpl(11)=2 + ipdstmpl(12)=lval + elseif (ltype.eq.112) then + ipdstmpl(10)=106 + ipdstmpl(11)=2 + ipdstmpl(12)=lval/256 + ipdstmpl(13)=106 + ipdstmpl(14)=2 + ipdstmpl(15)=mod(lval,256) + elseif (ltype.eq.113) then + ipdstmpl(10)=107 + ipdstmpl(12)=lval + elseif (ltype.eq.114) then + ipdstmpl(10)=107 + ipdstmpl(12)=475+(lval/256) + ipdstmpl(13)=107 + ipdstmpl(15)=475+mod(lval,256) + elseif (ltype.eq.115) then + ipdstmpl(10)=108 + ipdstmpl(12)=lval*100 + elseif (ltype.eq.116) then + ipdstmpl(10)=108 + ipdstmpl(12)=(lval/256)*100 + ipdstmpl(13)=108 + ipdstmpl(15)=mod(lval,256)*100 + elseif (ltype.eq.117) then + ipdstmpl(10)=109 + ipdstmpl(11)=9 + ipdstmpl(12)=lval + if ( btest(lval,15) ) then + ipdstmpl(12)=-1*mod(lval,32768) + endif + elseif (ltype.eq.119) then + ipdstmpl(10)=111 + ipdstmpl(11)=4 + ipdstmpl(12)=lval + elseif (ltype.eq.120) then + ipdstmpl(10)=111 + ipdstmpl(11)=2 + ipdstmpl(12)=lval/256 + ipdstmpl(13)=111 + ipdstmpl(14)=2 + ipdstmpl(15)=mod(lval,256) + elseif (ltype.eq.121) then + ipdstmpl(10)=100 + ipdstmpl(12)=(1100+(lval/256))*100 + ipdstmpl(13)=100 + ipdstmpl(15)=(1100+mod(lval,256))*100 + elseif (ltype.eq.125) then + ipdstmpl(10)=103 + ipdstmpl(11)=2 + ipdstmpl(12)=lval + elseif (ltype.eq.126) then + ipdstmpl(10)=100 + ipdstmpl(12)=lval + elseif (ltype.eq.128) then + ipdstmpl(10)=104 + ipdstmpl(11)=3 + ipdstmpl(12)=1100+(lval/256) + ipdstmpl(13)=104 + ipdstmpl(14)=3 + ipdstmpl(15)=1100+mod(lval,256) + elseif (ltype.eq.141) then + ipdstmpl(10)=100 + ipdstmpl(12)=(lval/256)*100 + ipdstmpl(13)=100 + ipdstmpl(15)=(1100+mod(lval,256))*100 + elseif (ltype.eq.160) then + ipdstmpl(10)=160 + ipdstmpl(12)=lval + elseif (ltype.gt.99.AND.ltype.lt.200) then + print *,'cnvlevel: GRIB1 Level ',ltype,' not recognized.' + ipdstmpl(10)=255 + elseif (ltype.eq.235) then + ipdstmpl(10)=ltype + ipdstmpl(12)=lval + elseif (ltype.eq.236) then + ipdstmpl(10)=ltype + ipdstmpl(12)=lval/256 + ipdstmpl(13)=ltype + ipdstmpl(15)=mod(lval,256) + elseif (ltype.ge.237.AND.ltype.le.239) then + ipdstmpl(10)=ltype + ipdstmpl(12)=lval + endif + + return +end subroutine cnvlevel + +!> This routine converts a GRIB1 PDS (Section 1) that includes NCEP +!> ensemble PDS extensions to a GRIB2 PDS (Section 4) info with +!> appropriate Product Definition Template. +!> +!> @note Use routine pds2pdt for non ensemble related PDS. +!> +!> ### Program History Log +!> Date | Programmer | Comments +!> -----|------------|--------- +!> 2003-06-12 | Gilbert | Initial. +!> 2007-02-07 | Gilbert | fixed end date calculation +!> 2007-05-14 | Boi Vuong | Added Time Range Indicator 51 (Climatological Mean Value) +!> +!> @param[in] kpds GRIB1 PDS info as specified in W3FI63. +!> @param[in] kens Ensemble identification from PDS octets 41-45. +!> @param[in] kprob Ensemble probability info from PDS octets 46 & 47. +!> @param[in] xprob Ensemble probability info from PDS octets 48-55. +!> @param[in] kclust Ensemble cluster info from PDS octets 61-76. +!> @param[in] kmember- semble membership info from PDS octest 77-86. +!> @param[out] ipdsnum GRIB2 Product Definition Template Number. +!> @param[out] ipdstmpl GRIB2 Product Definition Template entries for PDT 4.ipdsnum. +!> @param[out] numcoord number of vertical discretisation values (not implemented). +!> @param[out] coordlist- rtical discretisation values (not implemented). +!> @param[out] iret Error return value: +!> - 0 = Successful +!> - 1 = Unrecognized GRIB1 Time Range Indicator for ensembles +!> - 2 = Unrecognized GRIB1 Ensemble type +!> - 10 = Unrecognized GRIB1 Time Range Indicator for probabilities +!> +!> @author Stephen Gilbert @date 2003-06-12 +subroutine pds2pdtens(kpds,kens,kprob,xprob,kclust,kmember, & + ipdsnum,ipdstmpl,numcoord,coordlist, & + iret) + + use params + + integer,intent(in) :: kpds(*),kens(*),kprob(*),kclust(*) + integer,intent(in) :: kmember(*) + real,intent(in) :: xprob(*) + integer,intent(out) :: ipdstmpl(*) + real,intent(out) :: coordlist(*) + integer,intent(out) :: ipdsnum,numcoord,iret + + integer :: idat(8),jdat(8) + real :: rinc(5) + + iret=0 + numcoord=0 + if (kens(2).eq.1.or.kens(2).eq.2.or.kens(2).eq.3) then + ! individual ensemble fcst... + if (kpds(16).eq.0.or.kpds(16).eq.1.or.kpds(16).eq.10) then + ! At specific point in time... + ipdsnum=1 + ! get GRIB2 parameter category and number from GRIB1 + ! parameter number + call param_g1_to_g2(kpds(5),kpds(19),idum,ipdstmpl(1), & + ipdstmpl(2)) + ipdstmpl(3)=4 + ipdstmpl(4)=0 + ipdstmpl(5)=kpds(2) + ipdstmpl(6)=0 + ipdstmpl(7)=0 + ipdstmpl(8)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(8)=13 + !if (kpds(16).eq.10) then + ! ipdstmpl(9)=(kpds(14)*256)+kpds(15) + !else + ipdstmpl(9)=kpds(14) + !endif + call cnvlevel(kpds(6),kpds(7),ipdstmpl) + if (kens(2).eq.1) then + ! if (kens(3).eq.1) ipdstmpl(16)=0 + ! if (kens(3).eq.2) ipdstmpl(16)=1 + ipdstmpl(16)=kens(3)-1 + ipdstmpl(17)=0 + elseif (kens(2).eq.2) then + ipdstmpl(16)=2 + ipdstmpl(17)=kens(3) + elseif (kens(2).eq.3) then + ipdstmpl(16)=3 + ipdstmpl(17)=kens(3) + endif + ipdstmpl(18)=10 + elseif (kpds(16).ge.2.AND.kpds(16).le.5) then + ! over time range... + ipdsnum=11 + ! get GRIB2 parameter category and number from GRIB1 + ! parameter number + call param_g1_to_g2(kpds(5),kpds(19),idum,ipdstmpl(1), & + ipdstmpl(2)) + ipdstmpl(3)=4 + ipdstmpl(4)=0 + ipdstmpl(5)=kpds(2) + ipdstmpl(6)=0 + ipdstmpl(7)=0 + ipdstmpl(8)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(8)=13 + ipdstmpl(9)=kpds(14) + call cnvlevel(kpds(6),kpds(7),ipdstmpl) + !ipdstmpl(9)=kpds(15) + if (kens(2).eq.1) then + ! if (kens(3).eq.1) ipdstmpl(16)=0 + ! if (kens(3).eq.2) ipdstmpl(16)=1 + ipdstmpl(16)=kens(3)-1 + ipdstmpl(17)=0 + elseif (kens(2).eq.2) then + ipdstmpl(16)=2 + ipdstmpl(17)=kens(3) + elseif (kens(2).eq.3) then + ipdstmpl(16)=3 + ipdstmpl(17)=kens(3) + endif + ipdstmpl(18)=10 + ! calculate ending time using initial ref-time, idat, + ! and increment rinc. + idat=0 + idat(1)=((kpds(21)-1)*100)+kpds(8) + idat(2)=kpds(9) + idat(3)=kpds(10) + idat(4)=-500 ! EST + idat(5)=kpds(11) + idat(6)=kpds(12) + rinc=0 + if ( ipdstmpl(8).eq.0 ) then + rinc(3)=kpds(15) + elseif ( ipdstmpl(8).eq.1 ) then + rinc(2)=kpds(15) + elseif ( ipdstmpl(8).eq.2 ) then + rinc(1)=kpds(15) + elseif ( ipdstmpl(8).eq.10 ) then + rinc(2)=kpds(15) * 3 + elseif ( ipdstmpl(8).eq.11 ) then + rinc(2)=kpds(15) * 6 + elseif ( ipdstmpl(8).eq.12 ) then + rinc(2)=kpds(15) * 12 + elseif ( ipdstmpl(8).eq.13 ) then + rinc(4)=kpds(15) + endif + call w3movdat(rinc,idat,jdat) ! calculate end date/time + ipdstmpl(19)=jdat(1) ! year of end time + ipdstmpl(20)=jdat(2) ! month of end time + ipdstmpl(21)=jdat(3) ! day of end time + ipdstmpl(22)=jdat(5) ! hour of end time + ipdstmpl(23)=jdat(6) ! minute of end time + ipdstmpl(24)=jdat(7) ! second of end time + ipdstmpl(25)=1 + ipdstmpl(26)=0 + if (kpds(16).eq.2) then + ipdstmpl(27)=255 + if (kpds(5).eq.15) ipdstmpl(27)=2 + if (kpds(5).eq.16) ipdstmpl(27)=3 + elseif (kpds(16).eq.3) then + ipdstmpl(27)=0 + elseif (kpds(16).eq.4) then + ipdstmpl(27)=1 + elseif (kpds(16).eq.5) then + ipdstmpl(27)=4 + endif + ipdstmpl(28)=2 + ipdstmpl(29)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(29)=13 + ipdstmpl(30)=kpds(15)-kpds(14) + ipdstmpl(31)=255 + ipdstmpl(32)=0 + elseif (kpds(16).eq.51) then + ! over time range... + ipdsnum=11 + ! get GRIB2 parameter category and number from GRIB1 + ! parameter number + call param_g1_to_g2(kpds(5),kpds(19),idum,ipdstmpl(1), & + ipdstmpl(2)) + ipdstmpl(3)=4 + ipdstmpl(4)=0 + ipdstmpl(5)=kpds(2) + ipdstmpl(6)=0 + ipdstmpl(7)=0 + ipdstmpl(8)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(8)=13 + ipdstmpl(9)=kpds(14) + call cnvlevel(kpds(6),kpds(7),ipdstmpl) + !ipdstmpl(9)=kpds(15) + if (kens(2).eq.1) then + ! if (kens(3).eq.1) ipdstmpl(16)=0 + ! if (kens(3).eq.2) ipdstmpl(16)=1 + ipdstmpl(16)=kens(3)-1 + ipdstmpl(17)=0 + elseif (kens(2).eq.2) then + ipdstmpl(16)=2 + ipdstmpl(17)=kens(3) + elseif (kens(2).eq.3) then + ipdstmpl(16)=3 + ipdstmpl(17)=kens(3) + endif + ipdstmpl(18)=10 + ! calculate ending time using initial ref-time, idat, + ! and increment rinc. + idat=0 + idat(1)=((kpds(21)-1)*100)+kpds(8) + idat(2)=kpds(9) + idat(3)=kpds(10) + idat(4)=-500 ! EST + idat(5)=kpds(11) + idat(6)=kpds(12) + rinc=0 + if ( ipdstmpl(8).eq.0 ) then + rinc(3)=kpds(15) + elseif ( ipdstmpl(8).eq.1 ) then + rinc(2)=kpds(15) + elseif ( ipdstmpl(8).eq.2 ) then + rinc(1)=kpds(15) + elseif ( ipdstmpl(8).eq.10 ) then + rinc(2)=kpds(15) * 3 + elseif ( ipdstmpl(8).eq.11 ) then + rinc(2)=kpds(15) * 6 + elseif ( ipdstmpl(8).eq.12 ) then + rinc(2)=kpds(15) * 12 + elseif ( ipdstmpl(8).eq.13 ) then + rinc(4)=kpds(15) + endif + call w3movdat(rinc,idat,jdat) ! calculate end date/time + ipdstmpl(19)=jdat(1) ! year of end time + ipdstmpl(20)=jdat(2) ! month of end time + ipdstmpl(21)=jdat(3) ! day of end time + ipdstmpl(22)=jdat(5) ! hour of end time + ipdstmpl(23)=jdat(6) ! minute of end time + ipdstmpl(24)=jdat(7) ! second of end time + ipdstmpl(25)=1 + ipdstmpl(26)=0 + ipdstmpl(27)=51 + ipdstmpl(28)=2 + ipdstmpl(29)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(29)=13 + ipdstmpl(30)=kpds(15)-kpds(14) + ipdstmpl(31)=255 + ipdstmpl(32)=0 + else + Print *,' Unrecognized Time Range Ind for ensembles = ', & + kpds(16),kens(2) + Print *,'pds2pdtens: Couldn:t construct PDS Template ' + iret=1 + endif + + elseif (kens(2).eq.5) then ! WHOLE or CLUSTERENSEMBLE type + if (kpds(5).eq.191.OR.kpds(5).eq.192) then ! probs + if (kpds(16).eq.0.or.kpds(16).eq.1.or.kpds(16).eq.10) then + ! At specific point in time... + ipdsnum=5 + ! get GRIB2 parameter category and number from GRIB1 + ! parameter number + call param_g1_to_g2(kprob(1),kpds(19),idum,ipdstmpl(1), & + ipdstmpl(2)) + ipdstmpl(3)=5 + ipdstmpl(4)=0 + ipdstmpl(5)=kpds(2) + ipdstmpl(6)=0 + ipdstmpl(7)=0 + ipdstmpl(8)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(8)=13 + !if (kpds(16).eq.10) then + ! ipdstmpl(9)=(kpds(14)*256)+kpds(15) + !else + ipdstmpl(9)=kpds(14) + !endif + call cnvlevel(kpds(6),kpds(7),ipdstmpl) + ipdstmpl(16)=0 !? + ipdstmpl(17)=kclust(1) !? + ipdstmpl(18)=kprob(2)-1 + if (ipdstmpl(18).eq.0.OR.ipdstmpl(18).eq.2) then + ipdstmpl(19)=3 + ipdstmpl(20)=nint(xprob(1)*1000.0) + else + ipdstmpl(19)=0 + ipdstmpl(20)=0 + endif + if (ipdstmpl(18).eq.1.OR.ipdstmpl(18).eq.2) then + ipdstmpl(21)=3 + ipdstmpl(22)=nint(xprob(2)*1000.0) + else + ipdstmpl(21)=0 + ipdstmpl(22)=0 + endif + elseif (kpds(16).ge.2.AND.kpds(16).le.5) then + ! over time range... + ipdsnum=9 + ! get GRIB2 parameter category and number from GRIB1 + ! parameter number + call param_g1_to_g2(kprob(1),kpds(19),idum,ipdstmpl(1), & + ipdstmpl(2)) + ipdstmpl(3)=5 + ipdstmpl(4)=0 + ipdstmpl(5)=kpds(2) + ipdstmpl(6)=0 + ipdstmpl(7)=0 + ipdstmpl(8)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(8)=13 + ipdstmpl(9)=kpds(14) + call cnvlevel(kpds(6),kpds(7),ipdstmpl) + !ipdstmpl(9)=kpds(15) + ipdstmpl(16)=0 !? + ipdstmpl(17)=kclust(1) !? + ipdstmpl(18)=kprob(2)-1 + if (ipdstmpl(18).eq.0.OR.ipdstmpl(18).eq.2) then + ipdstmpl(19)=3 + ipdstmpl(20)=nint(xprob(1)*1000.0) + else + ipdstmpl(19)=0 + ipdstmpl(20)=0 + endif + if (ipdstmpl(18).eq.1.OR.ipdstmpl(18).eq.2) then + ipdstmpl(21)=3 + ipdstmpl(22)=nint(xprob(2)*1000.0) + else + ipdstmpl(21)=0 + ipdstmpl(22)=0 + endif + ! calculate ending time using initial ref-time, idat, + ! and increment rinc. + idat=0 + idat(1)=((kpds(21)-1)*100)+kpds(8) + idat(2)=kpds(9) + idat(3)=kpds(10) + idat(4)=-500 ! EST + idat(5)=kpds(11) + idat(6)=kpds(12) + rinc=0 + if ( ipdstmpl(8).eq.0 ) then + rinc(3)=kpds(15) + elseif ( ipdstmpl(8).eq.1 ) then + rinc(2)=kpds(15) + elseif ( ipdstmpl(8).eq.2 ) then + rinc(1)=kpds(15) + elseif ( ipdstmpl(8).eq.10 ) then + rinc(2)=kpds(15) * 3 + elseif ( ipdstmpl(8).eq.11 ) then + rinc(2)=kpds(15) * 6 + elseif ( ipdstmpl(8).eq.12 ) then + rinc(2)=kpds(15) * 12 + elseif ( ipdstmpl(8).eq.13 ) then + rinc(4)=kpds(15) + endif + call w3movdat(rinc,idat,jdat) ! calculate end date/time + ipdstmpl(23)=jdat(1) ! year of end time + ipdstmpl(24)=jdat(2) ! month of end time + ipdstmpl(25)=jdat(3) ! day of end time + ipdstmpl(26)=jdat(5) ! hour of end time + ipdstmpl(27)=jdat(6) ! minute of end time + ipdstmpl(28)=jdat(7) ! second of end time + ipdstmpl(29)=1 + ipdstmpl(30)=0 + if (kpds(16).eq.2) then + ipdstmpl(31)=255 + if (kpds(5).eq.15) ipdstmpl(31)=2 + if (kpds(5).eq.16) ipdstmpl(31)=3 + elseif (kpds(16).eq.3) then + ipdstmpl(31)=0 + elseif (kpds(16).eq.4) then + ipdstmpl(31)=1 + elseif (kpds(16).eq.5) then + ipdstmpl(31)=4 + endif + ipdstmpl(32)=2 + ipdstmpl(33)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(33)=13 + ipdstmpl(34)=kpds(15)-kpds(14) + ipdstmpl(35)=255 + ipdstmpl(36)=0 + elseif (kpds(16).eq.51) then + ! over time range... + ipdsnum=9 + ! get GRIB2 parameter category and number from GRIB1 + ! parameter number + call param_g1_to_g2(kprob(1),kpds(19),idum,ipdstmpl(1), & + ipdstmpl(2)) + ipdstmpl(3)=5 + ipdstmpl(4)=0 + ipdstmpl(5)=kpds(2) + ipdstmpl(6)=0 + ipdstmpl(7)=0 + ipdstmpl(8)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(8)=13 + ipdstmpl(9)=kpds(14) + call cnvlevel(kpds(6),kpds(7),ipdstmpl) + !ipdstmpl(9)=kpds(15) + ipdstmpl(16)=0 !? + ipdstmpl(17)=kclust(1) !? + ipdstmpl(18)=kprob(2)-1 + if (ipdstmpl(18).eq.0.OR.ipdstmpl(18).eq.2) then + ipdstmpl(19)=3 + ipdstmpl(20)=nint(xprob(1)*1000.0) + else + ipdstmpl(19)=0 + ipdstmpl(20)=0 + endif + if (ipdstmpl(18).eq.1.OR.ipdstmpl(18).eq.2) then + ipdstmpl(21)=3 + ipdstmpl(22)=nint(xprob(2)*1000.0) + else + ipdstmpl(21)=0 + ipdstmpl(22)=0 + endif + ! calculate ending time using initial ref-time, idat, + ! and increment rinc. + idat=0 + idat(1)=((kpds(21)-1)*100)+kpds(8) + idat(2)=kpds(9) + idat(3)=kpds(10) + idat(4)=-500 ! EST + idat(5)=kpds(11) + idat(6)=kpds(12) + rinc=0 + if ( ipdstmpl(8).eq.0 ) then + rinc(3)=kpds(15) + elseif ( ipdstmpl(8).eq.1 ) then + rinc(2)=kpds(15) + elseif ( ipdstmpl(8).eq.2 ) then + rinc(1)=kpds(15) + elseif ( ipdstmpl(8).eq.10 ) then + rinc(2)=kpds(15) * 3 + elseif ( ipdstmpl(8).eq.11 ) then + rinc(2)=kpds(15) * 6 + elseif ( ipdstmpl(8).eq.12 ) then + rinc(2)=kpds(15) * 12 + elseif ( ipdstmpl(8).eq.13 ) then + rinc(4)=kpds(15) + endif + call w3movdat(rinc,idat,jdat) ! calculate end date/time + ipdstmpl(23)=jdat(1) ! year of end time + ipdstmpl(24)=jdat(2) ! month of end time + ipdstmpl(25)=jdat(3) ! day of end time + ipdstmpl(26)=jdat(5) ! hour of end time + ipdstmpl(27)=jdat(6) ! minute of end time + ipdstmpl(28)=jdat(7) ! second of end time + ipdstmpl(29)=1 + ipdstmpl(30)=0 + ipdstmpl(31)=51 + ipdstmpl(32)=2 + ipdstmpl(33)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(33)=13 + ipdstmpl(34)=kpds(15)-kpds(14) + ipdstmpl(35)=255 + ipdstmpl(36)=0 + else + Print *,' Unrecognized Time Range Ind for Probs = ', & + kpds(16),kens(2) + Print *,'pds2pdtens: Couldn:t construct PDS Template ' + iret=10 + endif + else ! Non-probablility Whole Ens Fcst + if (kpds(16).eq.0.or.kpds(16).eq.1.or.kpds(16).eq.10) then + ! At specific point in time... + ipdsnum=2 + ! get GRIB2 parameter category and number from GRIB1 + ! parameter number + call param_g1_to_g2(kpds(5),kpds(19),idum,ipdstmpl(1), & + ipdstmpl(2)) + ipdstmpl(3)=4 + ipdstmpl(4)=0 + ipdstmpl(5)=kpds(2) + ipdstmpl(6)=0 + ipdstmpl(7)=0 + ipdstmpl(8)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(8)=13 + !if (kpds(16).eq.10) then + ! ipdstmpl(9)=(kpds(14)*256)+kpds(15) + !else + ipdstmpl(9)=kpds(14) + !endif + call cnvlevel(kpds(6),kpds(7),ipdstmpl) + if (kens(4).eq.1) then + ipdstmpl(16)=0 + elseif (kens(4).eq.2) then + ipdstmpl(16)=1 + elseif (kens(4).eq.11) then + ipdstmpl(16)=2 + elseif (kens(4).eq.12) then + ipdstmpl(16)=3 + endif + ipdstmpl(17)=kclust(1) + elseif (kpds(16).ge.2.AND.kpds(16).le.5) then + ! over time range... + ipdsnum=12 + ! get GRIB2 parameter category and number from GRIB1 + ! parameter number + call param_g1_to_g2(kpds(5),kpds(19),idum,ipdstmpl(1), & + ipdstmpl(2)) + ipdstmpl(3)=4 + ipdstmpl(4)=0 + ipdstmpl(5)=kpds(2) + ipdstmpl(6)=0 + ipdstmpl(7)=0 + ipdstmpl(8)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(8)=13 + ipdstmpl(9)=kpds(14) + call cnvlevel(kpds(6),kpds(7),ipdstmpl) + !ipdstmpl(9)=kpds(15) + if (kens(4).eq.1) then + ipdstmpl(16)=0 + elseif (kens(4).eq.2) then + ipdstmpl(16)=1 + elseif (kens(4).eq.11) then + ipdstmpl(16)=2 + elseif (kens(4).eq.12) then + ipdstmpl(16)=3 + endif + ipdstmpl(17)=kclust(1) + ! calculate ending time using initial ref-time, idat, + ! and increment rinc. + idat=0 + idat(1)=((kpds(21)-1)*100)+kpds(8) + idat(2)=kpds(9) + idat(3)=kpds(10) + idat(4)=-500 ! EST + idat(5)=kpds(11) + idat(6)=kpds(12) + rinc=0 + if ( ipdstmpl(8).eq.0 ) then + rinc(3)=kpds(15) + elseif ( ipdstmpl(8).eq.1 ) then + rinc(2)=kpds(15) + elseif ( ipdstmpl(8).eq.2 ) then + rinc(1)=kpds(15) + elseif ( ipdstmpl(8).eq.10 ) then + rinc(2)=kpds(15) * 3 + elseif ( ipdstmpl(8).eq.11 ) then + rinc(2)=kpds(15) * 6 + elseif ( ipdstmpl(8).eq.12 ) then + rinc(2)=kpds(15) * 12 + elseif ( ipdstmpl(8).eq.13 ) then + rinc(4)=kpds(15) + endif + call w3movdat(rinc,idat,jdat) ! calculate end date/time + ipdstmpl(18)=jdat(1) ! year of end time + ipdstmpl(19)=jdat(2) ! month of end time + ipdstmpl(20)=jdat(3) ! day of end time + ipdstmpl(21)=jdat(5) ! hour of end time + ipdstmpl(22)=jdat(6) ! minute of end time + ipdstmpl(23)=jdat(7) ! second of end time + ipdstmpl(24)=1 + ipdstmpl(25)=0 + if (kpds(16).eq.2) then + ipdstmpl(26)=255 + if (kpds(5).eq.15) ipdstmpl(26)=2 + if (kpds(5).eq.16) ipdstmpl(26)=3 + elseif (kpds(16).eq.3) then + ipdstmpl(26)=0 + elseif (kpds(16).eq.4) then + ipdstmpl(26)=1 + elseif (kpds(16).eq.5) then + ipdstmpl(26)=4 + endif + ipdstmpl(27)=2 + ipdstmpl(28)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(28)=13 + ipdstmpl(29)=kpds(15)-kpds(14) + ipdstmpl(30)=255 + ipdstmpl(31)=0 + elseif (kpds(16).eq.51) then + ! over time range... + ipdsnum=12 + ! get GRIB2 parameter category and number from GRIB1 + ! parameter number + call param_g1_to_g2(kpds(5),kpds(19),idum,ipdstmpl(1), & + ipdstmpl(2)) + ipdstmpl(3)=4 + ipdstmpl(4)=0 + ipdstmpl(5)=kpds(2) + ipdstmpl(6)=0 + ipdstmpl(7)=0 + ipdstmpl(8)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(8)=13 + ipdstmpl(9)=kpds(14) + call cnvlevel(kpds(6),kpds(7),ipdstmpl) + !ipdstmpl(9)=kpds(15) + if (kens(4).eq.1) then + ipdstmpl(16)=0 + elseif (kens(4).eq.2) then + ipdstmpl(16)=1 + elseif (kens(4).eq.11) then + ipdstmpl(16)=2 + elseif (kens(4).eq.12) then + ipdstmpl(16)=3 + endif + ipdstmpl(17)=kclust(1) + ! calculate ending time using initial ref-time, idat, + ! and increment rinc. + idat=0 + idat(1)=((kpds(21)-1)*100)+kpds(8) + idat(2)=kpds(9) + idat(3)=kpds(10) + idat(4)=-500 ! EST + idat(5)=kpds(11) + idat(6)=kpds(12) + rinc=0 + if ( ipdstmpl(8).eq.0 ) then + rinc(3)=kpds(15) + elseif ( ipdstmpl(8).eq.1 ) then + rinc(2)=kpds(15) + elseif ( ipdstmpl(8).eq.2 ) then + rinc(1)=kpds(15) + elseif ( ipdstmpl(8).eq.10 ) then + rinc(2)=kpds(15) * 3 + elseif ( ipdstmpl(8).eq.11 ) then + rinc(2)=kpds(15) * 6 + elseif ( ipdstmpl(8).eq.12 ) then + rinc(2)=kpds(15) * 12 + elseif ( ipdstmpl(8).eq.13 ) then + rinc(4)=kpds(15) + endif + call w3movdat(rinc,idat,jdat) ! calculate end date/time + ipdstmpl(18)=jdat(1) ! year of end time + ipdstmpl(19)=jdat(2) ! month of end time + ipdstmpl(20)=jdat(3) ! day of end time + ipdstmpl(21)=jdat(5) ! hour of end time + ipdstmpl(22)=jdat(6) ! minute of end time + ipdstmpl(23)=jdat(7) ! second of end time + ipdstmpl(24)=1 + ipdstmpl(25)=0 + ipdstmpl(26)=51 + ipdstmpl(27)=2 + ipdstmpl(28)=kpds(13) + if (kpds(13).eq.254) ipdstmpl(28)=13 + ipdstmpl(29)=kpds(15)-kpds(14) + ipdstmpl(30)=255 + ipdstmpl(31)=0 + endif + endif + else + Print *,' Unrecognized Ensemble type = ',kens(2) + Print *,'pds2pdtens: Couldn:t construct PDS Template ' + iret=2 + endif + + return +end subroutine pds2pdtens diff --git a/utils/cnv21.F90 b/utils/cnv21.F90 index 96653ad74..ce2a811fc 100644 --- a/utils/cnv21.F90 +++ b/utils/cnv21.F90 @@ -190,3 +190,1338 @@ subroutine cnv21(ifl1,ifl2) return end subroutine cnv21 + +!> This routine creates a GRIB1 PDS (Section 1) from appropriate +!> information from a GRIB2 Product Definition Template. +!> +!> @note Use pds2pdtens for ensemble related PDS. +!> +!> ### Program History Log +!> Date | Programmer | Comments +!> -----|------------|--------- +!> 2003-06-12 | Gilbert | Initial. +!> 2005-04-19 | Gilbert | Changed scaling factor used with potential vorticity surfaces. +!> 2007-05-08 | VUONG | Add Product Definition Template entries 120-124, 131, 88, 45, 47. +!> 2007-05-14 | Boi Vuong | Added Time Range Indicator 51 (Climatological Mean Value) +!> 2007-10-24 | Boi Vuong | Added level 8 (Nominal top of atmosphere) +!> 2009-05-19 | Boi Vuong | Added levels 10(Entire Atmosphere), 11(Cumulonimbus Base),12(Cumulonimbus Top) and level 126(Isobaric Pa) +!> 2009-12-14 | Boi Vuong | Added check for WAFS to use PDT 4.15 for Icing, Turbulence and Cumulonimbus +!> 2010-08-10 | Boi Vuong | Added check for FNMOC to use TMP as TMAX and TMIN - Removed check WAFS MAX wind level +!> 2011-10-24 | Boi Vuong | Added check for NAM (NMM-B) parameters to set statistical processing as MAX and MIN +!> 2012-03-29 | Boi Vuong | Added check Time Range for APCP in FNMOC +!> 2014-05-20 | Boi Vuong | Added check Time Range after F252 +!> 2014-11-14 | Boi Vuong | Added check Time Range for 15-hr or 18-hr or 21-hr or 24-hr Accumulation for APCP after F240 +!> 2018-07-26 | Boi Vuong | Added check Time Range for continuous accumulated APCP after F252 when convert from grib2 to grib1 +!> +!> @param[in] idisc GRIB2 discipline from Section 0. +!> @param[in] idsect GRIB2 Section 1 info. +!> - idsect(1) Id of orginating centre (Common Code Table C-1) +!> - idsect(2) Id of orginating sub-centre (local table) +!> - idsect(3) GRIB Master Tables Version Number (Code Table 1.0) +!> - idsect(4) GRIB Local Tables Version Number (Code Table 1.1) +!> - idsect(5) Significance of Reference Time (Code Table 1.2) +!> - idsect(6) Reference Time - Year (4 digits) +!> - idsect(7) Reference Time - Month +!> - idsect(8) Reference Time - Day +!> - idsect(9) Reference Time - Hour +!> - idsect(10) Reference Time - Minute +!> - idsect(11) Reference Time - Second +!> - idsect(12) Production status of data (Code Table 1.3) +!> - idsect(13) Type of processed data (Code Table 1.4) +!> @param[in] ipdsnum GRIB2 Product Definition Template Number +!> @param[in] ipdstmpl GRIB2 Product Definition Template entries for PDT 4.ipdsnum +!> @param[in] ibmap GRIB2 bitmap indicator from octet 6, Section 6. +!> @param[in] idrsnum GRIB2 Data Representation Template Number +!> @param[in] idrstmpl GRIB2 Data Representation Template entries +!> @param[out] kpds GRIB1 PDS info as specified in W3FI63. +!> - 1 id of center +!> - 2 generating process id number +!> - 3 grid definition +!> - 4 gds/bms flag (right adj copy of octet 8) +!> - 5 indicator of parameter +!> - 6 type of level +!> - 7 height/pressure , etc of level +!> - 8 year including (century-1) +!> - 9 month of year +!> - 10 day of month +!> - 11 hour of day +!> - 12 minute of hour +!> - 13 indicator of forecast time unit +!> - 14 time range 1 +!> - 15 time range 2 +!> - 16 time range flag +!> - 17 number included in average +!> - 18 version nr of grib specification +!> - 19 version nr of parameter table +!> - 20 nr missing from average/accumulation +!> - 21 century of reference time of data +!> - 22 units decimal scale factor +!> - 23 subcenter number +!> @param[out] iret Error return value: +!> - 0 Successful +!> - 1 Don't know what to do with pre-defined bitmap. +!> - 2 Unrecognized GRIB2 PDT 4.ipdsnum +!> +!> @author Stephen Gilbert @date 2003-06-12 +subroutine makepds(idisc,idsect,ipdsnum,ipdstmpl,ibmap, & + idrsnum,idrstmpl,kpds,iret) + + use params + + integer,intent(in) :: idsect(*),ipdstmpl(*),idrstmpl(*) + integer,intent(in) :: ipdsnum,idisc,idrsnum,ibmap + integer,intent(out) :: kpds(*) + integer,intent(out) :: iret + + iret=0 + ipos=0 + kpds(1:24)=0 + if ( (ipdsnum.lt.0).OR.(ipdsnum.gt.15) ) then + print *,'makepds: Don:t know GRIB2 PDT 4.',ipdsnum + iret=2 + return + endif + + kpds(1)=idsect(1) + kpds(2)=ipdstmpl(5) + kpds(3)=255 + kpds(4)=128 + if ( ibmap.ne.255 ) kpds(4)=kpds(4)+64 + if ( ibmap.ge.1.AND.ibmap.le.253 ) then + print *,'makepds: Don:t know about predefined bit-map ',ibmap + iret=1 + return + endif + call param_g2_to_g1(idisc,ipdstmpl(1),ipdstmpl(2),kpds(5), & + kpds(19)) + ! + ! Special parameters for ICAO WAFS (Max Icing, TP and CAT) + ! + If (ipdstmpl(16).eq.2.and.ipdstmpl(1).eq.19.and. & + ipdstmpl(2).eq.20) kpds(5) = 169 + If (ipdstmpl(16).eq.2.and.ipdstmpl(1).eq.19.and. & + ipdstmpl(2).eq.21) kpds(5) = 171 + If (ipdstmpl(16).eq.2.and.ipdstmpl(1).eq.19.and. & + ipdstmpl(2).eq.22) kpds(5) = 173 + ! + ! Special parameters for NAM (NMMB) + ! + If (idisc.eq.0.and.ipdstmpl(1).eq.2) then + if (ipdstmpl(2).eq.220) then + kpds(5) = 237 + kpds(19) = 129 + end if + if (ipdstmpl(2).eq.221) then + kpds(5) = 238 + kpds(19) = 129 + end if + if (ipdstmpl(2).eq.222) then + kpds(5) = 253 + kpds(19) = 129 + end if + if (ipdstmpl(2).eq.223) then + kpds(5) = 254 + kpds(19) = 129 + end if + endif + ! + If (idisc.eq.0.and.ipdstmpl(2).eq.16 & + .and.ipdstmpl(3).eq.198) then + kpds(5) = 235 + kpds(19) = 129 + endif + ! + If (idisc.eq.0.and.ipdstmpl(2).eq.7 & + .and.ipdstmpl(3).eq.199) then + kpds(5) = 236 + kpds(19) = 129 + endif + ! + ! Special parameters for ICAO Height at CB Base and Top + ! in GRIB1 Table 140 + ! + If (ipdstmpl(1).eq.3.and.ipdstmpl(2).eq.3) then + If (ipdstmpl(10).eq.11) then + kpds(19) = 140 + kpds(5) = 179 + end if + If (ipdstmpl(10).eq.12) then + kpds(19) = 140 + kpds(5) = 180 + end if + end if + ! + call levelcnv(ipdstmpl,kpds(6),kpds(7)) ! level + kpds(8)=mod(idsect(6),100) + if ( kpds(8).eq.0 ) kpds(8)=100 + kpds(9)=idsect(7) ! Year + kpds(10)=idsect(8) ! Month + kpds(11)=idsect(9) ! Day + kpds(12)=idsect(10) ! Hour + if ( ipdstmpl(8).ne.13 ) then + kpds(13)=ipdstmpl(8) ! Time Unit + else + kpds(13)=254 + endif + kpds(14)=ipdstmpl(9) ! P1 + if ( ipdsnum.le.7 ) then ! P2 + kpds(15)=0 + kpds(16)=0 + kpds(20)=0 + if ( kpds(14).eq.0 ) kpds(16)=1 + if ( kpds(14).gt.255 ) kpds(16)=10 + if ( ipdstmpl(5).eq.77.OR.ipdstmpl(5).eq.81.OR. & + ipdstmpl(5).eq.96.OR.ipdstmpl(5).eq.80.OR. & + ipdstmpl(5).eq.82.OR.ipdstmpl(5).eq.120.OR. & + ipdstmpl(5).eq.47.OR.ipdstmpl(5).eq.11 ) then + kpds(16)=10 + end if + if (ipdstmpl(5).eq.84.AND.kpds(5).eq.154)kpds(16) = 10 + ! + ! NOAA Wave Watch III and Coastal Ocean Circulation + ! and Alaska Waters Regional Wave Model + ! + if ( ipdstmpl(5).eq.88.OR.ipdstmpl(5).eq.121 & + .OR.ipdstmpl(5).eq.122.OR.ipdstmpl(5).eq.123 & + .OR.ipdstmpl(5).eq.124.OR.ipdstmpl(5).eq.125 & + .OR.ipdstmpl(5).eq.131.OR.ipdstmpl(5).eq.45 & + .OR.ipdstmpl(5).eq.11 ) then + kpds(16) = 0 + ! + ! Level Surface set to 1 + ! + if (kpds(5).eq.80.OR.kpds(5).eq.82.OR. & + kpds(5).eq.88.OR.kpds(5).eq.49.OR. & + kpds(5).eq.50) kpds(7)=1 ! Level Surface + if (ipdstmpl(5).eq.122.OR.ipdstmpl(5).eq.124.OR. & + ipdstmpl(5).eq.131.OR.ipdstmpl(5).eq.123.OR. & + ipdstmpl(5).eq.125.OR.ipdstmpl(5).eq.88.OR. & + ipdstmpl(5).eq.121) kpds(7)=1 + if (idsect(1).eq.54.AND.ipdstmpl(5).eq.45) kpds(16) = 10 + endif + else + selectcase (ipdsnum) + case(8) + ipos=24 + case(9) + ipos=31 + case(10) + ipos=25 + case(11) + ipos=27 + case(12) + ipos=26 + case(13) + ipos=40 + case(14) + ipos=39 + end select + kpds(15)=ipdstmpl(ipos+3)+kpds(14) ! P2 + selectcase (ipdstmpl(ipos)) + case (255) + kpds(16)=2 + case (0) + kpds(16)=3 + case (1) + kpds(16)=4 + case (2) + kpds(16)=2 + case (3) + kpds(16)=2 + case (4) + kpds(16)=5 + case (51) + kpds(16)=51 + end select + kpds(20)=ipdstmpl(ipos-1) + endif + if (ipdstmpl(9) .ge. 252) then + if (ipdstmpl(ipos+3).eq.3) then + kpds(13)= 10 ! Forecast time unit is 3-hour + kpds(14)=ipdstmpl(9)/3 ! Time range P1 + kpds(15)=ipdstmpl(ipos+3)/3+kpds(14) ! Time range P2 + else if (ipdstmpl(ipos+3).eq.6) then + kpds(13)= 11 ! Forecast time unit is 6-hour + kpds(14)=ipdstmpl(9)/6 ! Time range P1 + kpds(15)=ipdstmpl(ipos+3)/6+kpds(14) ! Time range P2 + else if (ipdstmpl(ipos+3).eq.12) then + kpds(13)= 12 ! Forecast time unit is 12-hour + kpds(14)=ipdstmpl(9)/12 ! Time range P1 + kpds(15)=ipdstmpl(ipos+3)/12+kpds(14) ! Time range P2 + end if + end if + if (ipdsnum .eq. 8 .AND. ipdstmpl(9) .eq. 0) then + if (ipdstmpl(ipos+3).ge.252) then + kpds(13)= 10 ! Forecast time unit is hour + kpds(14)=ipdstmpl(9)/3 ! Time range P1 + kpds(15)=ipdstmpl(ipos+3)/3+kpds(14) ! Time range P2 + end if + end if + ! + ! Checking total preciptation for 15-hr or 18-hr or 21-hr or 24-hr accumulation + ! after forecast hour F240 + ! + if (ipdstmpl(9) .ge. 240 )then + if ( ipdstmpl(ipos+3).eq.15 .OR. ipdstmpl(ipos+3).eq.18 & + .OR. ipdstmpl(ipos+3).eq.21 .OR. & + ipdstmpl(ipos+3).eq.24 ) then + kpds(13)= 10 ! Forecast time unit is 3-hour + kpds(14)=ipdstmpl(9)/3 ! Time range P1 + kpds(15)=ipdstmpl(ipos+3)/3+kpds(14) ! Time range P2 + end if + end if + ! + ! Checking Unit of Time Range for FNMOC (APCP) + ! + if (ipdstmpl(4).eq.58 .AND. ipdsnum.eq.11 .AND. & + (ipdstmpl(1).eq.1 .AND.ipdstmpl(2).eq.8) & + .AND. (ipdstmpl(10).eq.1)) then + if (ipdstmpl(9) .ge. 252) then + kpds(13)= 11 ! Forecast time unit is 6-hour + kpds(14)=ipdstmpl(9)/6 ! Time range P1 + kpds(15)=ipdstmpl(ipos+3)/6+kpds(14) ! Time range P2 + else + kpds(13)= 1 ! Forecast time unit is 1-hour + kpds(14)=ipdstmpl(9) ! Time range P1 + end if + end if + ! + ! Special case for FNMOC (TMAX and TMIN) + ! + if (ipdstmpl(4).eq.58 .AND. ipdsnum.eq.11 .AND. & + (ipdstmpl(1).eq.0 & + .AND.ipdstmpl(2).eq.0).AND.(ipdstmpl(10).eq.103)) then + kpds(16) = 2 + ! For Maximum Temperature + If (ipdstmpl(27).eq.2 .AND. ipdstmpl(1).eq.0 .AND. & + ipdstmpl(2).eq.0) kpds(5) = 15 + ! For Minimum Temperature + If (ipdstmpl(27).eq.3 .AND. ipdstmpl(1).eq.0 .AND. & + ipdstmpl(2).eq.0) kpds(5) = 16 + end if + ! + ! Special case for WAFS (Mean/MAx IP,CTP and CAT) + ! + if (ipdstmpl(5).eq.96.AND.((ipdstmpl(1).eq.19) & + .AND.(ipdstmpl(2).eq.20.or.ipdstmpl(2).eq.21.or. & + ipdstmpl(2).eq.22)).AND.(ipdstmpl(10).eq.100)) then + kpds(16) = 10 + end if + ! + kpds(17)=0 + kpds(18)=1 ! GRIB edition + kpds(21)=(idsect(6)/100)+1 ! Century + if ( kpds(8).eq.100 ) kpds(21)=idsect(6)/100 + kpds(22)=idrstmpl(3) ! Decimal scale factor + kpds(23)=idsect(2) ! Sub-center + return +end subroutine makepds + +!> This routine converts Level/layer information from a GRIB2 Product +!> Definition Template to GRIB1 Level type and Level value. +!> +!> ### Program History Log +!> Date | Programmer | Comments +!> -----|------------|--------- +!> 2003-06-12 | Gilbert | Initial +!> 2007-10-24 | Boi Vuong | Added level 8 (Nominal top of atmosphere) +!> 2011-01-13 | Boi Vuong | Added level/layer values from 235 to 239 +!> +!> @param[in] ipdstmpl GRIB2 Product Definition Template values +!> @param[out] ltype GRIB1 level type (PDS octet 10) +!> @param[out] lval GRIB1 level/layer value(s) (PDS octets 11 and 12) +!> +!> @author Stephen Gilbert @date 2003-06-12 +subroutine levelcnv(ipdstmpl,ltype,lval) + integer,intent(in) :: ipdstmpl(*) + integer,intent(out) :: ltype,lval + + ltype=255 + lval=0 + ltype1=ipdstmpl(10) + ltype2=ipdstmpl(13) + + if ( ltype1.eq.10.AND.ltype2.eq.255 ) then + ltype=200 + lval=0 + elseif ( ltype1.eq.11.AND.ltype2.eq.255 ) then + ltype=216 + lval=0 + elseif ( ltype1.eq.12.AND.ltype2.eq.255 ) then + ltype=217 + lval=0 + elseif ( ltype1.lt.100.AND.ltype2.eq.255 ) then + ltype=ltype1 + lval=0 + elseif ( ltype1.eq.1.AND.ltype2.eq.8 ) then + ltype=ltype1 + lval=0 + elseif ( ltype1.eq.10.AND.ltype2.eq.255 ) then + ltype=200 + lval=0 + elseif ( ltype1.eq.235.AND.ltype2.eq.255 ) then + ltype=235 + rscal1=10.**(-ipdstmpl(11)) + lval=nint(real(ipdstmpl(12))*rscal1) + elseif ( ltype1.ge.200.AND.ltype2.eq.255 ) then + ltype=ltype1 + lval=0 + elseif (ltype1.eq.100.AND.ltype2.eq.255 ) then + ltype=100 + rscal1=10.**(-ipdstmpl(11)) + lval=nint(real(ipdstmpl(12))*rscal1/100.) + elseif (ltype1.eq.100.AND.ltype2.eq.100 ) then + ltype=101 + rscal1=10.**(-ipdstmpl(11)) + lval1=nint(real(ipdstmpl(12))*rscal1/1000.) + rscal2=10.**(-ipdstmpl(14)) + lval2=nint(real(ipdstmpl(15))*rscal2/1000.) + lval=(lval1*256)+lval2 + elseif (ltype1.eq.101.AND.ltype2.eq.255 ) then + ltype=102 + lval=0 + elseif (ltype1.eq.102.AND.ltype2.eq.255 ) then + ltype=103 + rscal1=10.**(-ipdstmpl(11)) + lval=nint(real(ipdstmpl(12))*rscal1) + elseif (ltype1.eq.102.AND.ltype2.eq.102 ) then + ltype=104 + rscal1=10.**(-ipdstmpl(11)) + lval1=nint(real(ipdstmpl(12))*rscal1) + rscal2=10.**(-ipdstmpl(14)) + lval2=nint(real(ipdstmpl(15))*rscal2) + lval=(lval1*256)+lval2 + elseif (ltype1.eq.103.AND.ltype2.eq.255 ) then + ltype=105 + rscal1=10.**(-ipdstmpl(11)) + lval=nint(real(ipdstmpl(12))*rscal1) + elseif (ltype1.eq.103.AND.ltype2.eq.103 ) then + ltype=106 + rscal1=10.**(-ipdstmpl(11)) + lval1=nint(real(ipdstmpl(12))*rscal1/100.) + rscal2=10.**(-ipdstmpl(14)) + lval2=nint(real(ipdstmpl(15))*rscal2/100.) + lval=(lval1*256)+lval2 + elseif (ltype1.eq.104.AND.ltype2.eq.255 ) then + ltype=107 + rscal1=10.**(-ipdstmpl(11)) + lval=nint(real(ipdstmpl(12))*rscal1*10000.) + elseif (ltype1.eq.104.AND.ltype2.eq.104 ) then + ltype=108 + rscal1=10.**(-ipdstmpl(11)) + lval1=nint(real(ipdstmpl(12))*rscal1*100.) + rscal2=10.**(-ipdstmpl(14)) + lval2=nint(real(ipdstmpl(15))*rscal2*100.) + lval=(lval1*256)+lval2 + elseif (ltype1.eq.105.AND.ltype2.eq.255 ) then + ltype=109 + lval=ipdstmpl(12) + elseif (ltype1.eq.105.AND.ltype2.eq.105 ) then + ltype=110 + rscal1=10.**(-ipdstmpl(11)) + lval1=nint(real(ipdstmpl(12))*rscal1) + rscal2=10.**(-ipdstmpl(14)) + lval2=nint(real(ipdstmpl(15))*rscal2) + lval=(lval1*256)+lval2 + elseif (ltype1.eq.106.AND.ltype2.eq.255 ) then + ltype=111 + rscal1=10.**(-ipdstmpl(11)) + lval=nint(real(ipdstmpl(12))*rscal1*100.) + elseif (ltype1.eq.106.AND.ltype2.eq.106 ) then + ltype=112 + rscal1=10.**(-ipdstmpl(11)) + lval1=nint(real(ipdstmpl(12))*rscal1*100.) + rscal2=10.**(-ipdstmpl(14)) + lval2=nint(real(ipdstmpl(15))*rscal2*100.) + lval=(lval1*256)+lval2 + elseif (ltype1.eq.107.AND.ltype2.eq.255 ) then + ltype=113 + rscal1=10.**(-ipdstmpl(11)) + lval=nint(real(ipdstmpl(12))*rscal1) + elseif (ltype1.eq.107.AND.ltype2.eq.107 ) then + ltype=114 + rscal1=10.**(-ipdstmpl(11)) + lval1=475-nint(real(ipdstmpl(12))*rscal1) + rscal2=10.**(-ipdstmpl(14)) + lval2=475-nint(real(ipdstmpl(15))*rscal2) + lval=(lval1*256)+lval2 + elseif (ltype1.eq.108.AND.ltype2.eq.255 ) then + ltype=115 + rscal1=10.**(-ipdstmpl(11)) + lval=nint(real(ipdstmpl(12))*rscal1/100.) + elseif (ltype1.eq.108.AND.ltype2.eq.108 ) then + ltype=116 + rscal1=10.**(-ipdstmpl(11)) + lval1=nint(real(ipdstmpl(12))*rscal1/100.) + rscal2=10.**(-ipdstmpl(14)) + lval2=nint(real(ipdstmpl(15))*rscal2/100.) + lval=(lval1*256)+lval2 + elseif (ltype1.eq.109.AND.ltype2.eq.255 ) then + ltype=117 + rscal1=10.**(-ipdstmpl(11)) + lval=nint(real(ipdstmpl(12))*rscal1*1000000000.) + elseif (ltype1.eq.111.AND.ltype2.eq.255 ) then + ltype=119 + rscal1=10.**(-ipdstmpl(11)) + lval=nint(real(ipdstmpl(12))*rscal1*10000.) + elseif (ltype1.eq.111.AND.ltype2.eq.111 ) then + ltype=120 + rscal1=10.**(-ipdstmpl(11)) + lval1=nint(real(ipdstmpl(12))*rscal1*100.) + rscal2=10.**(-ipdstmpl(14)) + lval2=nint(real(ipdstmpl(15))*rscal2*100.) + lval=(lval1*256)+lval2 + elseif (ltype1.eq.160.AND.ltype2.eq.255 ) then + ltype=160 + rscal1=10.**(-ipdstmpl(11)) + lval=nint(real(ipdstmpl(12))*rscal1) + elseif ((ltype1.ge.236.AND.ltype1.le.239).AND. & + (ltype2.ge.236.AND.ltype2.le.239)) then + ltype=ltype1 + rscal1=10.**(-ipdstmpl(11)) + lval1=nint(real(ipdstmpl(12))*rscal1) + rscal2=10.**(-ipdstmpl(14)) + lval2=nint(real(ipdstmpl(15))*rscal2) + lval=(lval1*256)+lval2 + else + print *,'levelcnv: GRIB2 Levels ',ltype1,ltype2, & + ' not recognized.' + ltype=255 + endif + + ! High resolution stuff + ! elseif (ltype.eq.121) then + ! ipdstmpl(10)=100 + ! ipdstmpl(12)=(1100+(lval/256))*100 + ! ipdstmpl(13)=100 + ! ipdstmpl(15)=(1100+mod(lval,256))*100 + ! elseif (ltype.eq.125) then + ! ipdstmpl(10)=103 + ! ipdstmpl(11)=-2 + ! ipdstmpl(12)=lval + ! elseif (ltype.eq.128) then + ! ipdstmpl(10)=104 + ! ipdstmpl(11)=-3 + ! ipdstmpl(12)=1100+(lval/256) + ! ipdstmpl(13)=104 + ! ipdstmpl(14)=-3 + ! ipdstmpl(15)=1100+mod(lval,256) + ! elseif (ltype.eq.141) then + ! ipdstmpl(10)=100 + ! ipdstmpl(12)=(lval/256)*100 + ! ipdstmpl(13)=100 + ! ipdstmpl(15)=(1100+mod(lval,256))*100 + + return +end subroutine levelcnv + +!> This routine creates the GRIB1 NCEP Ensemble PDS extension +!> information from appropriate information from a GRIB2 Product +!> Definition Template. +!> +!> @note Use pds2pdtens for ensemble related PDS. +!> +!> ### Program History Log +!> Date | Programmer | Comments +!> -----|------------|--------- +!> 2003-06-12 | Gilbert | Initial +!> 2007-05-14 | Boi Vuong | Corrected scale factor probabilities +!> 2010-07-26 | Boi Vuong | Added two type of ensemblers (4 and 192) +!> +!> @param[in] ipdsnum GRIB2 Product Definition Template Number +!> @param[in] ipdstmpl GRIB2 Product Definition Template entries for +!> PDT 4.ipdsnum +!> @param[inout] kpds GRIB1 PDS info as specified in W3FI63. +!> - 1 id of center +!> - 2 generating process id number +!> - 3 grid definition +!> - 4 gds/bms flag (right adj copy of octet 8) +!> - 5 indicator of parameter +!> - 6 type of level +!> - 7 height/pressure , etc of level +!> - 8 year including (century-1) +!> - 9 month of year +!> - 10 day of month +!> - 11 hour of day +!> - 12 minute of hour +!> - 13 indicator of forecast time unit +!> - 14 time range 1 +!> - 15 time range 2 +!> - 16 time range flag +!> - 17 number included in average +!> - 18 version nr of grib specification +!> - 19 version nr of parameter table +!> - 20 nr missing from average/accumulation +!> - 21 century of reference time of data +!> - 22 units decimal scale factor +!> - 23 subcenter number +!> @param[out] kens Ensemble identification for PDS octets 41-45 +!> @param[out] kprob Ensemble probability info for PDS octets 46 47 +!> @param[out] xprob Ensemble probability info for PDS octets 48-55 +!> @param[out] kclust Ensemble cluster info for PDS octets 61-76 +!> @param[out] kmembr Ensemble membership info for PDS octest 77-86 +!> @param[out] iret Error return value: +!> - 0 Successful +!> - 2 Unrecognized GRIB2 PDT 4.ipdsnum +!> +!> @author Stephen Gilbert @date 2003-06-12 +subroutine makepdsens(ipdsnum,ipdstmpl,kpds,kens,kprob, & + xprob,kclust,kmembr,iret) + use params + + integer,intent(in) :: ipdstmpl(*) + integer,intent(in) :: ipdsnum + integer,intent(inout) :: kpds(*) + integer,intent(out) :: kens(5),kprob(2) + integer,intent(out) :: kclust(16),kmembr(80) + real,intent(out) :: xprob(2) + integer,intent(out) :: iret + + iret=0 + kpds(23)=2 ! subcenter = ensemble + + kens(1:5)=0 + kprob(1:2)=0 + xprob(1:2)=0. + kclust(1:16)=0 + kmembr(1:80)=0 + ! + ! Individual Ensemble Fcst + ! + if (ipdsnum.eq.1.OR.ipdsnum.eq.11) then + kens(1)=1 + selectcase (ipdstmpl(16)) + case(0) + kens(2)=1 + kens(3)=1 + case(1) + kens(2)=1 + kens(3)=2 + case(2) + kens(2)=2 + kens(3)=ipdstmpl(17) + case(3) + kens(2)=3 + kens(3)=ipdstmpl(17) + case(4) + kens(2)=3 + kens(3)=ipdstmpl(17) + case(192) + kens(2)=3 + kens(3)=ipdstmpl(17) + end select + kens(4)=1 + kens(5)=255 + ! + ! Probability Fcst + ! + elseif (ipdsnum.eq.5.OR.ipdsnum.eq.9) then + kens(1)=1 + kens(2)=5 + kens(3)=0 + kens(4)=0 + kens(5)=255 + kprob(1)=kpds(5) + kpds(5)=191 + kprob(2)=ipdstmpl(18)+1 + if (kprob(2).eq.1) then + rscale=10.**ipdstmpl(19) + xprob(1)=real(ipdstmpl(20))/rscale + xprob(2)=0.0 + elseif (kprob(2).eq.2) then + xprob(1)=0.0 + rscale=10.**ipdstmpl(21) + xprob(2)=real(ipdstmpl(22))/rscale + elseif (kprob(2).eq.3) then + rscale=10.**ipdstmpl(19) + xprob(1)=real(ipdstmpl(20))/rscale + rscale=10.**ipdstmpl(21) + xprob(2)=real(ipdstmpl(22))/rscale + endif + kclust(1)=ipdstmpl(17) + ! + ! Derived Ensemble Fcst + ! + elseif (ipdsnum.eq.2.OR.ipdsnum.eq.12) then + kens(1)=1 + kens(2)=5 + kens(3)=0 + selectcase (ipdstmpl(16)) + case(0) + kens(4)=1 + case(1) + kens(4)=2 + case(2) + kens(4)=11 + case(3) + kens(4)=12 + end select + !kens(5)=89 + kens(5)=0 + kclust(1)=ipdstmpl(17) + else + print *,'makepdsens: Don:t know GRIB2 PDT 4.',ipdsnum + iret=2 + endif + + return +end subroutine makepdsens + +!> This routine converts grid information from a GRIB2 Grid Description +!> Section as well as its Grid Definition Template to GRIB1 GDS info. In +!> addition, a check is made to determine if the grid is an NCEP +!> predefined grid. +!> +!> ### Program History Log +!> Date | Programmer | Comments +!> -----|------------|--------- +!> 2003-06-17 | Gilbert | Initial. +!> 2004-04-27 | Gilbert | Added support for gaussian grids. +!> 2007-04-16 | Vuong | Added Curvilinear Orthogonal grids. +!> 2007-05-29 | Vuong | Added Rotate Lat/Lon E-grid (203) +!> +!> @param[in] igds Contains information read from the appropriate GRIB +!> Grid Definition Section 3 for the field being returned. Must be +!> dimensioned >= 5. +!> - igds(1) Source of grid definition (see Code Table 3.0) +!> - igds(2) Number of grid points in the defined grid. +!> - igds(3) Number of octets needed for each additional grid points +!> definition. Used to define number of points in each row (or column) +!> for non-regular grids. = 0, if using regular grid. +!> - igds(4) Interpretation of list for optional points +!> definition. (Code Table 3.11). +!> - igds(5) Grid Definition Template Number (Code Table 3.1) +!> @param[in] igdstmpl Grid Definition Template values for GDT 3.igds(5) +!> @param[in] idefnum The number of entries in array +!> ideflist. i.e. number of rows (or columns) for which optional grid +!> points are defined. +!> @param[in] ideflist Optional integer array containing the number of +!> grid points contained in each row (or column). +!> @param[out] kgds GRIB1 GDS as described in w3fi63 format. +!> @param[out] igrid NCEP predefined GRIB1 grid number +!> set to 255, if not NCEP grid +!> @param[out] iret Error return value: +!> - 0 Successful +!> - 1 Unrecognized GRIB2 GDT number 3.igds(5). +!> +!> @author Stephen Gilbert @date 2003-06-17 & +subroutine gdt2gds(igds,igdstmpl,idefnum,ideflist,kgds, & + igrid,iret) + + ! + integer,intent(in) :: idefnum + integer,intent(in) :: igds(*),igdstmpl(*),ideflist(*) + integer,intent(out) :: kgds(*),igrid,iret + + integer :: kgds72(200),kgds71(200),idum(200),jdum(200) + + iret=0 + if (igds(5).eq.0) then ! Lat/Lon grid + kgds(1)=0 + kgds(2)=igdstmpl(8) ! Ni + kgds(3)=igdstmpl(9) ! Nj + kgds(4)=igdstmpl(12)/1000 ! Lat of 1st grid point + kgds(5)=igdstmpl(13)/1000 ! Long of 1st grid point + kgds(6)=0 ! resolution and component flags + if (igdstmpl(1)==2) kgds(6)=64 + if (btest(igdstmpl(14),4).OR.btest(igdstmpl(14),5)) & + kgds(6)=kgds(6)+128 + if (btest(igdstmpl(14),3)) kgds(6)=kgds(6)+8 + kgds(7)=igdstmpl(15)/1000 ! Lat of last grid point + kgds(8)=igdstmpl(16)/1000 ! Long of last grid point + kgds(9)=igdstmpl(17)/1000 ! Di + kgds(10)=igdstmpl(18)/1000 ! Dj + kgds(11)=igdstmpl(19) ! Scanning mode + kgds(12)=0 + kgds(13)=0 + kgds(14)=0 + kgds(15)=0 + kgds(16)=0 + kgds(17)=0 + kgds(18)=0 + kgds(19)=0 + kgds(20)=255 + kgds(21)=0 + kgds(22)=0 + ! + ! Process irreg grid stuff, if necessary + ! + if (idefnum.ne.0) then + if (igdstmpl(8).eq.-1) then + kgds(2)=65535 + kgds(9)=65535 + endif + if (igdstmpl(9).eq.-1) then + kgds(3)=65535 + kgds(10)=65535 + endif + kgds(19)=0 + kgds(20)=33 + if (kgds(1).eq.1.OR.kgds(1).eq.3) kgds(20)=43 + kgds(21)=igds(2) ! num of grid points + do j=1,idefnum + kgds(21+j)=ideflist(j) + enddo + endif + elseif (igds(5).eq.10) then ! Mercator grid + kgds(1)=1 ! Grid Definition Template number + kgds(2)=igdstmpl(8) ! Ni + kgds(3)=igdstmpl(9) ! Nj + kgds(4)=igdstmpl(10)/1000 ! Lat of 1st grid point + kgds(5)=igdstmpl(11)/1000 ! Long of 1st grid point + kgds(6)=0 ! resolution and component flags + if (igdstmpl(1)==2) kgds(6)=64 + if (btest(igdstmpl(12),4).OR.btest(igdstmpl(12),5)) & + kgds(6)=kgds(6)+128 + if (btest(igdstmpl(12),3)) kgds(6)=kgds(6)+8 + kgds(7)=igdstmpl(14)/1000 ! Lat of last grid point + kgds(8)=igdstmpl(15)/1000 ! Long of last grid point + kgds(9)=igdstmpl(13)/1000 ! Lat intersects earth + kgds(10)=0 + kgds(11)=igdstmpl(16) ! Scanning mode + kgds(12)=igdstmpl(18)/1000 ! Di + kgds(13)=igdstmpl(19)/1000 ! Dj + kgds(14)=0 + kgds(15)=0 + kgds(16)=0 + kgds(17)=0 + kgds(18)=0 + kgds(19)=0 + kgds(20)=255 + kgds(21)=0 + kgds(22)=0 + elseif (igds(5).eq.30) then ! Lambert Conformal Grid + kgds(1)=3 + kgds(2)=igdstmpl(8) ! Nx + kgds(3)=igdstmpl(9) ! Ny + kgds(4)=igdstmpl(10)/1000 ! Lat of 1st grid point + kgds(5)=igdstmpl(11)/1000 ! Long of 1st grid point + kgds(6)=0 ! resolution and component flags + if (igdstmpl(1)==2) kgds(6)=64 + if (btest(igdstmpl(12),4).OR.btest(igdstmpl(12),5)) & + kgds(6)=kgds(6)+128 + if (btest(igdstmpl(12),3)) kgds(6)=kgds(6)+8 + kgds(7)=igdstmpl(14)/1000 ! Lon of orientation + kgds(8)=igdstmpl(15)/1000 ! Dx + kgds(9)=igdstmpl(16)/1000 ! Dy + kgds(10)=igdstmpl(17) ! Projection Center Flag + kgds(11)=igdstmpl(18) ! Scanning mode + kgds(12)=igdstmpl(19)/1000 ! Lat in 1 + kgds(13)=igdstmpl(20)/1000 ! Lat in 2 + kgds(14)=igdstmpl(21)/1000 ! Lat of S. Pole of projection + kgds(15)=igdstmpl(22)/1000 ! Lon of S. Pole of projection + kgds(16)=0 + kgds(17)=0 + kgds(18)=0 + kgds(19)=0 + kgds(20)=255 + kgds(21)=0 + kgds(22)=0 + elseif (igds(5).eq.40) then ! Gaussian Lat/Lon grid + kgds(1)=4 + kgds(2)=igdstmpl(8) ! Ni + kgds(3)=igdstmpl(9) ! Nj + kgds(4)=igdstmpl(12)/1000 ! Lat of 1st grid point + kgds(5)=igdstmpl(13)/1000 ! Long of 1st grid point + kgds(6)=0 ! resolution and component flags + if (igdstmpl(1)==2) kgds(6)=64 + if (btest(igdstmpl(14),4).OR.btest(igdstmpl(14),5)) & + kgds(6)=kgds(6)+128 + if (btest(igdstmpl(14),3)) kgds(6)=kgds(6)+8 + kgds(7)=igdstmpl(15)/1000 ! Lat of last grid point + kgds(8)=igdstmpl(16)/1000 ! Long of last grid point + kgds(9)=igdstmpl(17)/1000 ! Di + kgds(10)=igdstmpl(18) ! N - Number of parallels + kgds(11)=igdstmpl(19) ! Scanning mode + kgds(12)=0 + kgds(13)=0 + kgds(14)=0 + kgds(15)=0 + kgds(16)=0 + kgds(17)=0 + kgds(18)=0 + kgds(19)=0 + kgds(20)=255 + kgds(21)=0 + kgds(22)=0 + elseif (igds(5).eq.20) then ! Polar Stereographic Grid + kgds(1)=5 + kgds(2)=igdstmpl(8) ! Nx + kgds(3)=igdstmpl(9) ! Ny + kgds(4)=igdstmpl(10)/1000 ! Lat of 1st grid point + kgds(5)=igdstmpl(11)/1000 ! Long of 1st grid point + kgds(6)=0 ! resolution and component flags + if (igdstmpl(1)==2) kgds(6)=64 + if (btest(igdstmpl(12),4).OR.btest(igdstmpl(12),5)) & + kgds(6)=kgds(6)+128 + if (btest(igdstmpl(12),3)) kgds(6)=kgds(6)+8 + kgds(7)=igdstmpl(14)/1000 ! Lon of orientation + kgds(8)=igdstmpl(15)/1000 ! Dx + kgds(9)=igdstmpl(16)/1000 ! Dy + kgds(10)=igdstmpl(17) ! Projection Center Flag + kgds(11)=igdstmpl(18) ! Scanning mode + kgds(12)=0 + kgds(13)=0 + kgds(14)=0 + kgds(15)=0 + kgds(16)=0 + kgds(17)=0 + kgds(18)=0 + kgds(19)=0 + kgds(20)=255 + kgds(21)=0 + kgds(22)=0 + elseif (igds(5).eq.204) then ! Curvilinear Orthogonal + kgds(1)=204 + kgds(2)=igdstmpl(8) ! Ni + kgds(3)=igdstmpl(9) ! Nj + kgds(4)=0 + kgds(5)=0 + kgds(6)=0 ! resolution and component flags + if (igdstmpl(1)==2) kgds(6)=64 + if (btest(igdstmpl(14),4).OR.btest(igdstmpl(14),5)) & + kgds(6)=kgds(6)+128 + if (btest(igdstmpl(14),3)) kgds(6)=kgds(6)+8 + kgds(7)=0 + kgds(8)=0 + kgds(9)=0 + kgds(10)=0 + kgds(11)=igdstmpl(19) ! Scanning mode + kgds(12)=0 + kgds(13)=0 + kgds(14)=0 + kgds(15)=0 + kgds(16)=0 + kgds(17)=0 + kgds(18)=0 + kgds(19)=0 + kgds(20)=255 + kgds(21)=0 + kgds(22)=0 + ! + ! Process irreg grid stuff, if necessary + ! + if (idefnum.ne.0) then + if (igdstmpl(8).eq.-1) then + kgds(2)=65535 + kgds(9)=65535 + endif + if (igdstmpl(9).eq.-1) then + kgds(3)=65535 + kgds(10)=65535 + endif + kgds(19)=0 + kgds(20)=33 + if (kgds(1).eq.1.OR.kgds(1).eq.3) kgds(20)=43 + kgds(21)=igds(2) ! num of grid points + do j=1,idefnum + kgds(21+j)=ideflist(j) + enddo + endif + elseif (igds(5).eq.32768) then ! Rotate Lat/Lon grid + kgds(1)=203 ! Arakawa Staggerred E/B grid + kgds(2)=igdstmpl(8) ! Ni + kgds(3)=igdstmpl(9) ! Nj + kgds(4)=igdstmpl(12)/1000 ! Lat of 1st grid point + kgds(5)=igdstmpl(13)/1000 ! Lon of 1st grid point + kgds(6)=0 ! resolution and component flags + if (igdstmpl(1)==2) kgds(6)=64 + if (btest(igdstmpl(14),4).OR.btest(igdstmpl(14),5)) & + kgds(6)=kgds(6)+128 + if (btest(igdstmpl(14),3)) kgds(6)=kgds(6)+8 + kgds(7)=igdstmpl(15)/1000 ! Lat of last grid point + kgds(8)=igdstmpl(16)/1000 ! Lon of last grid point + kgds(9)=igdstmpl(17)/1000 ! Di + kgds(10)=igdstmpl(18)/1000 ! Dj + kgds(11)=igdstmpl(19) ! Scanning mode + kgds(12)=0 + kgds(13)=0 + kgds(14)=0 + kgds(15)=0 + kgds(16)=0 + kgds(17)=0 + kgds(18)=0 + kgds(19)=0 + kgds(20)=255 + kgds(21)=0 + kgds(22)=0 + ! + ! Process irreg grid stuff, if necessary + ! + if (idefnum.ne.0) then + if (igdstmpl(8).eq.-1) then + kgds(2)=65535 + kgds(9)=65535 + endif + if (igdstmpl(9).eq.-1) then + kgds(3)=65535 + kgds(10)=65535 + endif + kgds(19)=0 + kgds(20)=33 + if (kgds(1).eq.1.OR.kgds(1).eq.3) kgds(20)=43 + kgds(21)=igds(2) ! num of grid points + do j=1,idefnum + kgds(21+j)=ideflist(j) + enddo + endif + elseif (igds(5).eq.32769) then ! Rotate Lat/Lon grid + kgds(1)=205 ! Arakawa Staggerred for Non-E Stagger grid + kgds(2)=igdstmpl(8) ! Ni + kgds(3)=igdstmpl(9) ! Nj + kgds(4)=igdstmpl(12)/1000 ! Lat of 1st grid point + kgds(5)=igdstmpl(13)/1000 ! Lon of 1st grid point + kgds(6)=0 ! resolution and component flags + if (igdstmpl(1)==2) kgds(6)=64 + if (btest(igdstmpl(14),4).OR.btest(igdstmpl(14),5)) & + kgds(6)=kgds(6)+128 + if (btest(igdstmpl(14),3)) kgds(6)=kgds(6)+8 + kgds(7)=igdstmpl(15)/1000 ! Lat of last grid point + kgds(8)=igdstmpl(16)/1000 ! Lon of last grid point + kgds(9)=igdstmpl(17)/1000 ! Di + kgds(10)=igdstmpl(18)/1000 ! Dj + kgds(11)=igdstmpl(19) ! Scanning mode + kgds(12)=igdstmpl(20)/1000 + kgds(13)=igdstmpl(21)/1000 + kgds(14)=0 + kgds(15)=0 + kgds(16)=0 + kgds(17)=0 + kgds(18)=0 + kgds(19)=0 + kgds(20)=255 + kgds(21)=0 + kgds(22)=0 + else + Print *,'gdt2gds: Unrecognized GRIB2 GDT = 3.',igds(5) + iret=1 + kgds(1:22)=0 + return + endif + ! + ! Can we determine NCEP grid number ? + ! + igrid=255 + do j=254,1,-1 + !do j=225,225 + kgds71=0 + kgds72=0 + call w3fi71(j,kgds71,ierr) + if (ierr.ne.0) cycle + ! convert W to E for longitudes + if (kgds71(3).eq.0) then ! lat/lon + if (kgds71(7).lt.0) kgds71(7)=360000+kgds71(7) + if (kgds71(10).lt.0) kgds71(10)=360000+kgds71(10) + elseif (kgds71(3).eq.1) then ! mercator + if (kgds71(7).lt.0) kgds71(7)=360000+kgds71(7) + if (kgds71(10).lt.0) kgds71(10)=360000+kgds71(10) + elseif (kgds71(3).eq.3) then ! lambert conformal + if (kgds71(7).lt.0) kgds71(7)=360000+kgds71(7) + if (kgds71(9).lt.0) kgds71(9)=360000+kgds71(9) + if (kgds71(18).lt.0) kgds71(18)=360000+kgds71(18) + elseif (kgds71(3).eq.4) then ! Guassian lat/lon + if (kgds71(7).lt.0) kgds71(7)=360000+kgds71(7) + if (kgds71(10).lt.0) kgds71(10)=360000+kgds71(10) + elseif (kgds71(3).eq.5) then ! polar stereographic + if (kgds71(7).lt.0) kgds71(7)=360000+kgds71(7) + if (kgds71(9).lt.0) kgds71(9)=360000+kgds71(9) + endif + call r63w72(idum,kgds,jdum,kgds72) + if (kgds72(3).eq.3) kgds72(14)=0 ! lambert conformal fix + if (kgds72(3).eq.1) kgds72(15:18)=0 ! mercator fix + if (kgds72(3).eq.5) kgds72(14:18)=0 ! polar str fix + ! print *,' kgds71(',j,')= ', kgds71(1:30) + ! print *,' kgds72 = ', kgds72(1:30) + if (all(kgds71.eq.kgds72)) then + igrid=j + return + endif + enddo + + return +end subroutine gdt2gds + +!> Pack and write a grib message. This subprogram is nearly the inverse +!> of getgbe. +!> +!> @note Subprogram can be called from a multiprocessing environment. +!> Do not engage the same logical unit from more than one processor. +!> +!> ### Program History Log +!> Date | Programmer | Comments +!> -----|------------|--------- +!> 94-04-01 | Iredell | Initial. +!> 95-10-31 | Iredell | Removed saves and prints +!> 97-02-11 | Y. Zhu | Included probability and cluster arguments +!> 2002-03-18 | Gilbert | Modified from putgbex to account for binary scale factors. +!> +!> @param[in] lugb teger unit of the unblocked grib data file +!> @param[in] kf teger number of data points +!> @param[in] kpds teger (200) pds parameters +!> - 1 id of center +!> - 2 generating process id number +!> - 3 grid definition +!> - 4 gds/bms flag (right adj copy of octet 8) +!> - 5 indicator of parameter +!> - 6 type of level +!> - 7 height/pressure , etc of level +!> - 8 year including (century-1) +!> - 9 month of year +!> - 10 day of month +!> - 11 hour of day +!> - 12 minute of hour +!> - 13 indicator of forecast time unit +!> - 14 time range 1 +!> - 15 time range 2 +!> - 16 time range flag +!> - 17 number included in average +!> - 18 version nr of grib specification +!> - 19 version nr of parameter table +!> - 20 nr missing from average/accumulation +!> - 21 century of reference time of data +!> - 22 units decimal scale factor +!> - 23 subcenter number +!> - 24 pds byte 29, for nmc ensemble products, 128 if forecast field +!> error, 64 if bias corrected fcst field, 32 if smoothed field, +!> warning: can be combination of more than 1. +!> - 25 pds byte 30, not used +!> @param[in] kgds teger (200) gds parameters +!> - 1 data representation type +!> - 19 number of vertical coordinate parameters +!> - 20 octet number of the list of vertical coordinate parameters or +!> octet number of the list of numbers of points in each row or 255 if +!> neither are present. +!> - 21 for grids with pl, number of points in grid +!> - 22 number of words in each row latitude/longitude grids +!> - 2 n(i) nr points on latitude circle +!> - 3 n(j) nr points on longitude meridian +!> - 4 la(1) latitude of origin +!> - 5 lo(1) longitude of origin +!> - 6 resolution flag (right adj copy of octet 17) +!> - 7 la(2) latitude of extreme point +!> - 8 lo(2) longitude of extreme point +!> - 9 di longitudinal direction of increment +!> - 10 dj latitudinal direction increment +!> - 11 scanning mode flag (right adj copy of octet 28) +!> Gaussian grids: +!> - 2 n(i) nr points on latitude circle +!> - 3 n(j) nr points on longitude meridian +!> - 4 la(1) latitude of origin +!> - 5 lo(1) longitude of origin +!> - 6 resolution flag (right adj copy of octet 17) +!> - 7 la(2) latitude of extreme point +!> - 8 lo(2) longitude of extreme point +!> - 9 di longitudinal direction of increment +!> - 10 n - nr of circles pole to equator +!> - 11 scanning mode flag (right adj copy of octet 28) +!> - 12 nv - nr of vert coord parameters +!> - 13 pv - octet nr of list of vert coord parameters or pl - location +!> of the list of numbers of points in each row (if no vert coord +!> parameters are present or 255 if neither are present +!> Polar Stereographic grids: +!> - 2 n(i) nr points along lat circle +!> - 3 n(j) nr points along lon circle +!> - 4 la(1) latitude of origin +!> - 5 lo(1) longitude of origin +!> - 6 resolution flag (right adj copy of octet 17) +!> - 7 lov grid orientation +!> - 8 dx - x direction increment +!> - 9 dy - y direction increment +!> - 10 projection center flag +!> - 11 scanning mode (right adj copy of octet 28) +!> Spherical Harmonic Coefficients: +!> - 2 j pentagonal resolution parameter +!> - 3 k pentagonal resolution parameter +!> - 4 m pentagonal resolution parameter +!> - 5 representation type +!> - 6 coefficient storage mode +!> Mercator grids: +!> - 2 n(i) nr points on latitude circle +!> - 3 n(j) nr points on longitude meridian +!> - 4 la(1) latitude of origin +!> - 5 lo(1) longitude of origin +!> - 6 resolution flag (right adj copy of octet 17) +!> - 7 la(2) latitude of last grid point +!> - 8 lo(2) longitude of last grid point +!> - 9 latit - latitude of projection intersection +!> - 10 reserved +!> - 11 scanning mode flag (right adj copy of octet 28) +!> - 12 longitudinal dir grid length +!> - 13 latitudinal dir grid length +!> Lambert Conformal Grids: +!> - 2 nx nr points along x-axis +!> - 3 ny nr points along y-axis +!> - 4 la1 lat of origin (lower left) +!> - 5 lo1 lon of origin (lower left) +!> - 6 resolution (right adj copy of octet 17) +!> - 7 lov - orientation of grid +!> - 8 dx - x-dir increment +!> - 9 dy - y-dir increment +!> - 10 projection center flag +!> - 11 scanning mode flag (right adj copy of octet 28) +!> - 12 latin 1 - first lat from pole of secant cone inter +!> - 13 latin 2 - second lat from pole of secant cone inter +!> @param[in] kens teger (200) ensemble pds parms +!> - 1 application identifier +!> - 2 ensemble type +!> - 3 ensemble identifier +!> - 4 product identifier +!> - 5 smoothing flag +!> @param[in] kprob teger (2) probability ensemble parms +!> @param[in] xprob al (2) probability ensemble parms +!> @param[in] kclust teger (16) cluster ensemble parms +!> @param[in] kmembr teger (8) cluster ensemble parms +!> @param[in] ibs teger binary scale factor (0 to ignore) +!> @param[in] nbits teger number of bits in which to pack (0 to ignore) +!> @param[in] lb gical*1 (kf) bitmap if present +!> @param[in] f al (kf) data +!> @param[out] iret teger return code +!> - 0 Success +!> - Other W3FI72 GRIB packer return code +!> +!> @author Mark Iredell @date 94-04-01 +SUBROUTINE PUTGBEXN(LUGB,KF,KPDS,KGDS,KENS, & + KPROB,XPROB,KCLUST,KMEMBR,IBS,NBITS,LB,F,IRET) + + INTEGER KPDS(200),KGDS(200),KENS(200) + INTEGER KPROB(2),KCLUST(16),KMEMBR(80) + REAL XPROB(2) + LOGICAL*1 LB(KF) + REAL F(KF) + ! PARAMETER(MAXBIT=16) + PARAMETER(MAXBIT=24) + INTEGER IBM(KF),IPDS(200),IGDS(200),IBDS(200) + CHARACTER PDS(400),GRIB(1000+KF*(MAXBIT+1)/8) + + ! GET W3FI72 PARAMETERS + !print *,'SAGT: start putgbexn' + CALL R63W72(KPDS,KGDS,IPDS,IGDS) + IBDS=0 + + ! COUNT VALID DATA + KBM=KF + IF(IPDS(7).NE.0) THEN + KBM=0 + DO I=1,KF + IF(LB(I)) THEN + IBM(I)=1 + KBM=KBM+1 + ELSE + IBM(I)=0 + ENDIF + ENDDO + IF(KBM.EQ.KF) IPDS(7)=0 + ENDIF + + ! GET NUMBER OF BITS AND ROUND DATA + IF(NBITS.GT.0) THEN + NBIT=NBITS + ELSE + IF(KBM.EQ.0) THEN + DO I=1,KF + F(I)=0. + ENDDO + NBIT=0 + ELSE + !print *,'SAGT:',IPDS(7),IBS,IPDS(25),KF + !print *,'SAGT:',count(ibm.eq.0),count(ibm.eq.1) + CALL SETBIT(IPDS(7),-IBS,IPDS(25),KF,IBM,F,FMIN,FMAX,NBIT) + NBIT=MIN(NBIT,MAXBIT) + ENDIF + ENDIF + + ! CREATE PRODUCT DEFINITION SECTION + CALL W3FI68(IPDS,PDS) + IF(IPDS(24).EQ.2) THEN + ILAST=45 + IF (IPDS(8).EQ.191.OR.IPDS(8).EQ.192) ILAST=55 + IF (KENS(2).EQ.5) ILAST=76 + IF (KENS(2).EQ.5) ILAST=86 + IF (KENS(2).EQ.4) ILAST=86 + CALL PDSENS(KENS,KPROB,XPROB,KCLUST,KMEMBR,ILAST,PDS) + ENDIF + + ! PACK AND WRITE GRIB DATA + igflag=1 + igrid=kpds(3) + if (igrid.ne.255) igflag=0 + !print *,minval(f(1:kf)),maxval(f(1:kf)) + !print *,nbit,kf + !print *,(ipds(j),j=1,28) + !write(6,fmt='(28z2)') (pds(j),j=1,28) + !print *,(kgds(j),j=1,28) + !print *,(igds(j),j=1,28) + icomp=0 + CALL W3FI72(0,F,0,NBIT,1,IPDS,PDS, & + igflag,igrid,IGDS,ICOMP,0,IBM,KF,IBDS, & + KFO,GRIB,LGRIB,IRET) + IF(IRET.EQ.0) CALL WRYTE(LUGB,LGRIB,GRIB) + + RETURN +END SUBROUTINE PUTGBEXN + +!> The number of bits required to pack a given field for particular +!> binary and decimal scalings is computed. The minimum and maximum +!> rounded field values are also returned. GRIB bitmap masking for +!> valid data is optionally used. +!> +!> @param[in] ibm integer bitmap flag (=0 for no bitmap). +!> @param[in] ibs integer binary scaling (e.g. ibs=3 to round field to +!> nearest eighth value). +!> @param[in] ids integer decimal scaling (e.g. ids=3 to round field to +!> nearest milli-value) (note that ids and ibs can both be nonzero, +!> e.g. ids=1 and ibs=1 rounds to the nearest twentieth). +!> @param[in] len integer length of the field and bitmap. +!> @param[in] mg integer (len) bitmap if ibm=1 (0 to skip, 1 to keep). +!> @param[in] g real (len) field. +!> @param[out] gmin real minimum valid rounded field value. +!> @param[out] gmax real maximum valid rounded field value. +!> @param[out] nbit integer number of bits to pack. +!> +!> @author Mark Iredell @date 92-10-31 +SUBROUTINE SETBIT(IBM,IBS,IDS,LEN,MG,G,GMIN,GMAX,NBIT) + + DIMENSION MG(LEN),G(LEN) + + ! ROUND FIELD AND DETERMINE EXTREMES WHERE BITMAP IS ON + S=2.**IBS*10.**IDS + IF(IBM.EQ.0) THEN + GMAX=G(1) + GMIN=G(1) + DO I=2,LEN + GMAX=MAX(GMAX,G(I)) + GMIN=MIN(GMIN,G(I)) + ENDDO + ELSE + I1=1 + DO WHILE(I1.LE.LEN.AND.MG(I1).EQ.0) + I1=I1+1 + ENDDO + IF(I1.LE.LEN) THEN + DO I=1,I1-1 + G(I)=0. + ENDDO + GMAX=G(I1) + GMIN=G(I1) + DO I=I1+1,LEN + IF(MG(I).NE.0) THEN + GMAX=MAX(GMAX,G(I)) + GMIN=MIN(GMIN,G(I)) + ELSE + G(I)=0. + ENDIF + ENDDO + ELSE + DO I=1,LEN + G(I)=0. + ENDDO + GMAX=0. + GMIN=0. + ENDIF + ENDIF + + ! COMPUTE NUMBER OF BITS + NBIT=LOG((GMAX-GMIN)*S+0.9)/LOG(2.)+1. + + RETURN +END SUBROUTINE SETBIT diff --git a/utils/gds2gdt.F90 b/utils/gds2gdt.F90 deleted file mode 100644 index 773e64cd3..000000000 --- a/utils/gds2gdt.F90 +++ /dev/null @@ -1,392 +0,0 @@ -!> @file -!> @brief Convert a GRIB1 GDS to necessary info for a GRIB2 Grid -!> Definition Section. -!> @author Stephen Gilbert @date 2003-06-17 - -!> This routine converts a GRIB1 GDS (in format specfied in -!> w3fi63.f) to necessary info for a GRIB2 Grid Definition Section. -!> -!> ### Program History Log -!> Date | Programmer | Comments -!> -----|------------|--------- -!> 2003-06-17 | Gilbert | Initial. -!> 2004-04-27 | Gilbert | Added support for Gaussian grids. -!> 2007-04-16 | Vuong | Added Curvilinear Orthogonal grids. -!> 2007-05-29 | Vuong | Added Rotate Lat/Lon E-grid (203) -!> 2010-05-10 | Vuong | Added Rotate Lat/Lon for Non-E Stagger grid (205) -!> 2011-05-04 | Vuong | Corrected Arakawa Lat/Lon of grid points for Non-E Stagger grid (205) -!> -!> @param[in] kgds GRIB1 GDS info as returned by w3fi63.f. -!> @param[out] igds Contains information read from the appropriate GRIB -!> Grid Definition Section 3 for the field being returned. Must be -!> dimensioned >= 5. -!> - igds(1) Source of grid definition (see Code Table 3.0) -!> - igds(2) Number of grid points in the defined grid. -!> - igds(3) Number of octets needed for each additional grid points -!> definition. Used to define number of points in each row (or column) -!> for non-regular grids. = 0, if using regular grid. -!> - igds(4) Interpretation of list for optional points definition. (Code Table 3.11) -!> - igds(5) Grid Definition Template Number (Code Table 3.1) -!> @param[out] igdstmpl Grid Definition Template values for GDT 3.igds(5) -!> @param[out] idefnum The number of entries in array -!> ideflist. i.e. number of rows (or columns) for which optional grid -!> points are defined. -!> @param[out] ideflist Optional integer array containing the number of -!> grid points contained in each row (or column). -!> @param[out] iret Error return value: -!> - 0 Successful -!> - 1 Unrecognized GRIB1 grid data representation type -!> -!> @author Stephen Gilbert @date 2003-06-17 -subroutine gds2gdt(kgds,igds,igdstmpl,idefnum,ideflist,iret) - - integer,intent(in) :: kgds(*) - integer,intent(out) :: igds(*),igdstmpl(*),ideflist(*) - integer,intent(out) :: idefnum,iret - - iret=0 - if (kgds(1).eq.0) then ! Lat/Lon grid - idefnum=0 - igds(1)=0 ! grid def specfied in template - igds(2)=kgds(2)*kgds(3) ! num of grid points - igds(3)=0 ! octets for further grid definition - igds(4)=0 ! interpretation of optional list - igds(5)=0 ! Grid Definition Template number - if (btest(kgds(6),6)) then ! shape of Earth - igdstmpl(1)=2 - else - igdstmpl(1)=0 - endif - igdstmpl(2)=0 - igdstmpl(3)=0 - igdstmpl(4)=0 - igdstmpl(5)=0 - igdstmpl(6)=0 - igdstmpl(7)=0 - igdstmpl(8)=kgds(2) !Ni - igdstmpl(9)=kgds(3) !Nj - igdstmpl(10)=0 - igdstmpl(11)=0 - igdstmpl(12)=kgds(4)*1000 ! Lat of 1st grid point - if (kgds(5).lt.0) then ! Lon of 1st grid point - igdstmpl(13)=(360000+kgds(5))*1000 ! convert W to E - else - igdstmpl(13)=kgds(5)*1000 - endif - igdstmpl(14)=0 ! Resolution and Component flags - if (btest(kgds(6),7)) igdstmpl(14)=48 - if (btest(kgds(6),3)) igdstmpl(14)=igdstmpl(14)+8 - igdstmpl(15)=kgds(7)*1000 ! Lat of last grid point - if (kgds(8).lt.0) then ! Lon of last grid point - igdstmpl(16)=(360000+kgds(8))*1000 ! convert W to E - else - igdstmpl(16)=kgds(8)*1000 - endif - igdstmpl(17)=kgds(9)*1000 ! Di - igdstmpl(18)=kgds(10)*1000 ! Dj - igdstmpl(19)=kgds(11) ! Scanning mode - if (kgds(20).ne.255) then ! irregular grid (eg WAFS) - igds(2)=kgds(21) ! num of grid points - !idefnum=kgds(19) - if (kgds(2).eq.65535) idefnum=kgds(3) - if (kgds(3).eq.65535) idefnum=kgds(2) - imax=0 - do j=1,idefnum - ideflist(j)=kgds(21+j) - if (ideflist(j).gt.imax) imax=ideflist(j) - enddo - igds(3)=1 ! octets for further grid definition - if (imax.gt.255) igds(3)=2 - if (imax.gt.65535) igds(3)=3 - if (imax.gt.16777215) igds(3)=4 - igds(4)=1 ! interpretation of optional list - igdstmpl(8)=-1 - igdstmpl(17)=-1 - endif - elseif (kgds(1).eq.1) then ! Mercator grid - idefnum=0 - igds(1)=0 ! grid def specfied in template - igds(2)=kgds(2)*kgds(3) ! num of grid points - igds(3)=0 ! octets for further grid definition - igds(4)=0 ! interpretation of optional list - igds(5)=10 ! Grid Definition Template number - if (btest(kgds(6),6)) then ! shape of Earth - igdstmpl(1)=2 - else - igdstmpl(1)=0 - endif - igdstmpl(2)=0 - igdstmpl(3)=0 - igdstmpl(4)=0 - igdstmpl(5)=0 - igdstmpl(6)=0 - igdstmpl(7)=0 - igdstmpl(8)=kgds(2) ! Ni - igdstmpl(9)=kgds(3) ! Nj - igdstmpl(10)=kgds(4)*1000 ! Lat of 1st grid point - if (kgds(5).lt.0) then ! Lon of 1st grid point - igdstmpl(11)=(360000+kgds(5))*1000 ! convert W to E - else - igdstmpl(11)=kgds(5)*1000 - endif - igdstmpl(12)=0 ! Resolution and Component flags - if (btest(kgds(6),7)) igdstmpl(12)=48 - if (btest(kgds(6),3)) igdstmpl(12)=igdstmpl(12)+8 - igdstmpl(13)=kgds(9)*1000 ! Lat intersects earth - igdstmpl(14)=kgds(7)*1000 ! Lat of last grid point - if (kgds(8).lt.0) then ! Lon of last grid point - igdstmpl(15)=(360000+kgds(8))*1000 ! convert W to E - else - igdstmpl(15)=kgds(8)*1000 - endif - igdstmpl(16)=kgds(11) ! Scanning mode - igdstmpl(17)=0 ! Orientation of grid - igdstmpl(18)=kgds(12)*1000 ! Di - igdstmpl(19)=kgds(13)*1000 ! Dj - elseif (kgds(1).eq.3) then ! Lambert Conformal Grid - idefnum=0 - igds(1)=0 ! grid def specfied in template - igds(2)=kgds(2)*kgds(3) ! num of grid points - igds(3)=0 ! octets for further grid definition - igds(4)=0 ! interpretation of optional list - igds(5)=30 ! Grid Definition Template number - if (btest(kgds(6),6)) then ! shape of Earth - igdstmpl(1)=2 - else - igdstmpl(1)=0 - endif - igdstmpl(2)=0 - igdstmpl(3)=0 - igdstmpl(4)=0 - igdstmpl(5)=0 - igdstmpl(6)=0 - igdstmpl(7)=0 - igdstmpl(8)=kgds(2) ! Nx - igdstmpl(9)=kgds(3) ! Ny - igdstmpl(10)=kgds(4)*1000 ! Lat of 1st grid point - if (kgds(5).lt.0) then ! Lon of 1st grid point - igdstmpl(11)=(360000+kgds(5))*1000 ! convert W to E - else - igdstmpl(11)=kgds(5)*1000 - endif - igdstmpl(12)=0 ! Resolution and Component flags - if (btest(kgds(6),7)) igdstmpl(12)=48 - if (btest(kgds(6),3)) igdstmpl(12)=igdstmpl(12)+8 - igdstmpl(13)=kgds(12)*1000 ! Lat where Dx and Dy specified - if (kgds(7).lt.0) then ! Lon of orientation - igdstmpl(14)=(360000+kgds(7))*1000 ! convert W to E - else - igdstmpl(14)=kgds(7)*1000 - endif - igdstmpl(15)=kgds(8)*1000 ! Dx - igdstmpl(16)=kgds(9)*1000 ! Dy - igdstmpl(17)=kgds(10) ! Projection Center Flag - igdstmpl(18)=kgds(11) ! Scanning mode - igdstmpl(19)=kgds(12)*1000 ! Latin 1 - igdstmpl(20)=kgds(13)*1000 ! Latin 2 - igdstmpl(21)=kgds(14)*1000 ! Lat of S. Pole of projection - if (kgds(15).lt.0) then ! Lon of S. Pole of projection - igdstmpl(22)=(360000+kgds(15))*1000 ! convert W to E - else - igdstmpl(22)=kgds(15)*1000 - endif - elseif (kgds(1).eq.4) then ! Gaussian Lat/Lon grid - idefnum=0 - igds(1)=0 ! grid def specfied in template - igds(2)=kgds(2)*kgds(3) ! num of grid points - igds(3)=0 ! octets for further grid definition - igds(4)=0 ! interpretation of optional list - igds(5)=40 ! Grid Definition Template number - if (btest(kgds(6),6)) then ! shape of Earth - igdstmpl(1)=2 - else - igdstmpl(1)=0 - endif - igdstmpl(2)=0 - igdstmpl(3)=0 - igdstmpl(4)=0 - igdstmpl(5)=0 - igdstmpl(6)=0 - igdstmpl(7)=0 - igdstmpl(8)=kgds(2) !Ni - igdstmpl(9)=kgds(3) !Nj - igdstmpl(10)=0 - igdstmpl(11)=0 - igdstmpl(12)=kgds(4)*1000 ! Lat of 1st grid point - if (kgds(5).lt.0) then ! Lon of 1st grid point - igdstmpl(13)=(360000+kgds(5))*1000 ! convert W to E - else - igdstmpl(13)=kgds(5)*1000 - endif - igdstmpl(14)=0 ! Resolution and Component flags - if (btest(kgds(6),7)) igdstmpl(14)=48 - if (btest(kgds(6),3)) igdstmpl(14)=igdstmpl(14)+8 - igdstmpl(15)=kgds(7)*1000 ! Lat of last grid point - if (kgds(8).lt.0) then ! Lon of last grid point - igdstmpl(16)=(360000+kgds(8))*1000 ! convert W to E - else - igdstmpl(16)=kgds(8)*1000 - endif - igdstmpl(17)=kgds(9)*1000 ! Di - igdstmpl(18)=kgds(10) ! D - Number of parallels - igdstmpl(19)=kgds(11) ! Scanning mode - elseif (kgds(1).eq.5) then ! Polar Stereographic Grid - idefnum=0 - igds(1)=0 ! grid def specfied in template - igds(2)=kgds(2)*kgds(3) ! num of grid points - igds(3)=0 ! octets for further grid definition - igds(4)=0 ! interpretation of optional list - igds(5)=20 ! Grid Definition Template number - if (btest(kgds(6),6)) then ! shape of Earth - igdstmpl(1)=2 - else - igdstmpl(1)=0 - endif - igdstmpl(2)=0 - igdstmpl(3)=0 - igdstmpl(4)=0 - igdstmpl(5)=0 - igdstmpl(6)=0 - igdstmpl(7)=0 - igdstmpl(8)=kgds(2) ! Nx - igdstmpl(9)=kgds(3) ! Ny - igdstmpl(10)=kgds(4)*1000 ! Lat of 1st grid point - if (kgds(5).lt.0) then ! Lon of 1st grid point - igdstmpl(11)=(360000+kgds(5))*1000 ! convert W to E - else - igdstmpl(11)=kgds(5)*1000 - endif - igdstmpl(12)=0 ! Resolution and Component flags - if (btest(kgds(6),7)) igdstmpl(12)=48 - if (btest(kgds(6),3)) igdstmpl(12)=igdstmpl(12)+8 - igdstmpl(13)=60000000 ! Lat where Dx and Dy specified - if (btest(kgds(10),7)) igdstmpl(13)=-60000000 - if (kgds(7).lt.0) then ! Lon of orientation - igdstmpl(14)=(360000+kgds(7))*1000 ! convert W to E - else - igdstmpl(14)=kgds(7)*1000 - endif - igdstmpl(15)=kgds(8)*1000 ! Dx - igdstmpl(16)=kgds(9)*1000 ! Dy - igdstmpl(17)=kgds(10) ! Projection Center Flag - igdstmpl(18)=kgds(11) ! Scanning mode - elseif (kgds(1).eq.204) then ! Curivilinear Orthogonal Grid (Used by RTOFS) - idefnum=0 - igds(1)=0 ! grid def specfied in template - igds(2)=kgds(2)*kgds(3) ! num of grid points - igds(3)=0 ! octets for further grid definition - igds(4)=0 ! interpretation of optional list - igds(5)=204 ! Grid Definition Template number - if (btest(kgds(6),6)) then ! shape of Earth - igdstmpl(1)=2 - else - igdstmpl(1)=0 - endif - igdstmpl(2)=0 - igdstmpl(3)=0 - igdstmpl(4)=0 - igdstmpl(5)=0 - igdstmpl(6)=0 - igdstmpl(7)=0 - igdstmpl(8)=kgds(2) !Ni - No of points along x-grid direction - igdstmpl(9)=kgds(3) !Nj - No of points along y-grid direction - igdstmpl(10)=0 - igdstmpl(11)=0 - igdstmpl(12)=0 - igdstmpl(13)=0 - igdstmpl(14)=0 ! Resolution and Component flags - if (btest(kgds(6),7)) igdstmpl(14)=48 - if (btest(kgds(6),3)) igdstmpl(14)=igdstmpl(14)+8 - igdstmpl(15)=0 - igdstmpl(16)=0 - igdstmpl(17)=0 - igdstmpl(18)=0 - igdstmpl(19)=kgds(11) ! Scanning mode - elseif (kgds(1).eq.203) then ! Rot Lat/Lon grid (Arakawa) - idefnum=0 - igds(1)=0 ! grid def specfied in template - igds(2)=kgds(2)*kgds(3) ! num of grid points - igds(3)=0 ! octets for further grid definition - igds(4)=0 ! interpretation of optional list - igds(5)=32768 ! Grid Definition Template number - if (btest(kgds(6),6)) then ! shape of Earth - igdstmpl(1)=2 - else - igdstmpl(1)=0 - endif - igdstmpl(2)=0 - igdstmpl(3)=0 - igdstmpl(4)=0 - igdstmpl(5)=0 - igdstmpl(6)=0 - igdstmpl(7)=0 - igdstmpl(8)=kgds(2) !Ni - igdstmpl(9)=kgds(3) !Nj - igdstmpl(10)=0 - igdstmpl(11)=0 - igdstmpl(12)=kgds(4)*1000 ! Lat of 1st grid point - if (kgds(5).lt.0) then ! Lon of 1st grid point - igdstmpl(13)=(360000+kgds(5))*1000 ! convert W to E - else - igdstmpl(13)=kgds(5)*1000 - endif - igdstmpl(14)=0 ! Resolution and Component flags - if (btest(kgds(6),7)) igdstmpl(14)=48 - if (btest(kgds(6),3)) igdstmpl(14)=igdstmpl(14)+8 - igdstmpl(15)=kgds(7)*1000 ! Lat of last grid point - if (kgds(8).lt.0) then ! Lon of last grid point - igdstmpl(16)=(360000+kgds(8))*1000 ! convert W to E - else - igdstmpl(16)=kgds(8)*1000 - endif - igdstmpl(17)=kgds(9)*1000 ! Di - igdstmpl(18)=kgds(10)*1000 ! Dj - igdstmpl(19)=kgds(11) ! Scanning mode - elseif (kgds(1).eq.205) then ! Rot Lat/Lon for Non-E Stagger grid (Arakawa) - idefnum=0 - igds(1)=0 ! grid def specfied in template - igds(2)=kgds(2)*kgds(3) ! num of grid points - igds(3)=0 ! octets for further grid definition - igds(4)=0 ! interpretation of optional list - igds(5)=32769 ! Grid Definition Template number - if (btest(kgds(6),6)) then ! shape of Earth - igdstmpl(1)=2 - else - igdstmpl(1)=0 - endif - igdstmpl(2)=0 - igdstmpl(3)=0 - igdstmpl(4)=0 - igdstmpl(5)=0 - igdstmpl(6)=0 - igdstmpl(7)=0 - igdstmpl(8)=kgds(2) !Ni - igdstmpl(9)=kgds(3) !Nj - igdstmpl(10)=0 - igdstmpl(11)=0 - igdstmpl(12)=kgds(4)*1000 ! Lat of 1st grid point - if (kgds(5).lt.0) then ! Lon of 1st grid point - igdstmpl(13)=(360000+kgds(5))*1000 ! convert W to E - else - igdstmpl(13)=kgds(5)*1000 - endif - igdstmpl(14)=0 ! Resolution and Component flags - if (btest(kgds(6),7)) igdstmpl(14)=48 - if (btest(kgds(6),3)) igdstmpl(14)=igdstmpl(14)+8 - igdstmpl(15)=kgds(7)*1000 ! Lat of last grid point - if (kgds(8).lt.0) then ! Lon of last grid point - igdstmpl(16)=(360000+kgds(8))*1000 ! convert W to E - else - igdstmpl(16)=kgds(8)*1000 - endif - igdstmpl(17)=kgds(9)*1000 ! Di - igdstmpl(18)=kgds(10)*1000 ! Dj - igdstmpl(19)=kgds(11) ! Scanning mode - igdstmpl(20)=kgds(12)*1000 - igdstmpl(21)=kgds(13)*1000 - else - Print *,'gds2gdt: Unrecognized GRIB1 Grid type = ',kgds(1) - iret=1 - endif - return -end subroutine gds2gdt diff --git a/utils/gdt2gds.F90 b/utils/gdt2gds.F90 deleted file mode 100644 index 0513ba15d..000000000 --- a/utils/gdt2gds.F90 +++ /dev/null @@ -1,378 +0,0 @@ -!> @file -!> @brief Convert grid information from a GRIB2 Grid Description -!> Section to GRIB1 GDS info. -!> @author Stephen Gilbert @date 2003-06-17 - -!> This routine converts grid information from a GRIB2 Grid Description -!> Section as well as its Grid Definition Template to GRIB1 GDS info. In -!> addition, a check is made to determine if the grid is an NCEP -!> predefined grid. -!> -!> ### Program History Log -!> Date | Programmer | Comments -!> -----|------------|--------- -!> 2003-06-17 | Gilbert | Initial. -!> 2004-04-27 | Gilbert | Added support for gaussian grids. -!> 2007-04-16 | Vuong | Added Curvilinear Orthogonal grids. -!> 2007-05-29 | Vuong | Added Rotate Lat/Lon E-grid (203) -!> -!> @param[in] igds Contains information read from the appropriate GRIB -!> Grid Definition Section 3 for the field being returned. Must be -!> dimensioned >= 5. -!> - igds(1) Source of grid definition (see Code Table 3.0) -!> - igds(2) Number of grid points in the defined grid. -!> - igds(3) Number of octets needed for each additional grid points -!> definition. Used to define number of points in each row (or column) -!> for non-regular grids. = 0, if using regular grid. -!> - igds(4) Interpretation of list for optional points -!> definition. (Code Table 3.11). -!> - igds(5) Grid Definition Template Number (Code Table 3.1) -!> @param[in] igdstmpl Grid Definition Template values for GDT 3.igds(5) -!> @param[in] idefnum The number of entries in array -!> ideflist. i.e. number of rows (or columns) for which optional grid -!> points are defined. -!> @param[in] ideflist Optional integer array containing the number of -!> grid points contained in each row (or column). -!> @param[out] kgds GRIB1 GDS as described in w3fi63 format. -!> @param[out] igrid NCEP predefined GRIB1 grid number -!> set to 255, if not NCEP grid -!> @param[out] iret Error return value: -!> - 0 Successful -!> - 1 Unrecognized GRIB2 GDT number 3.igds(5). -!> -!> @author Stephen Gilbert @date 2003-06-17 & -subroutine gdt2gds(igds,igdstmpl,idefnum,ideflist,kgds, & - igrid,iret) - - ! - integer,intent(in) :: idefnum - integer,intent(in) :: igds(*),igdstmpl(*),ideflist(*) - integer,intent(out) :: kgds(*),igrid,iret - - integer :: kgds72(200),kgds71(200),idum(200),jdum(200) - - iret=0 - if (igds(5).eq.0) then ! Lat/Lon grid - kgds(1)=0 - kgds(2)=igdstmpl(8) ! Ni - kgds(3)=igdstmpl(9) ! Nj - kgds(4)=igdstmpl(12)/1000 ! Lat of 1st grid point - kgds(5)=igdstmpl(13)/1000 ! Long of 1st grid point - kgds(6)=0 ! resolution and component flags - if (igdstmpl(1)==2) kgds(6)=64 - if (btest(igdstmpl(14),4).OR.btest(igdstmpl(14),5)) & - kgds(6)=kgds(6)+128 - if (btest(igdstmpl(14),3)) kgds(6)=kgds(6)+8 - kgds(7)=igdstmpl(15)/1000 ! Lat of last grid point - kgds(8)=igdstmpl(16)/1000 ! Long of last grid point - kgds(9)=igdstmpl(17)/1000 ! Di - kgds(10)=igdstmpl(18)/1000 ! Dj - kgds(11)=igdstmpl(19) ! Scanning mode - kgds(12)=0 - kgds(13)=0 - kgds(14)=0 - kgds(15)=0 - kgds(16)=0 - kgds(17)=0 - kgds(18)=0 - kgds(19)=0 - kgds(20)=255 - kgds(21)=0 - kgds(22)=0 - ! - ! Process irreg grid stuff, if necessary - ! - if (idefnum.ne.0) then - if (igdstmpl(8).eq.-1) then - kgds(2)=65535 - kgds(9)=65535 - endif - if (igdstmpl(9).eq.-1) then - kgds(3)=65535 - kgds(10)=65535 - endif - kgds(19)=0 - kgds(20)=33 - if (kgds(1).eq.1.OR.kgds(1).eq.3) kgds(20)=43 - kgds(21)=igds(2) ! num of grid points - do j=1,idefnum - kgds(21+j)=ideflist(j) - enddo - endif - elseif (igds(5).eq.10) then ! Mercator grid - kgds(1)=1 ! Grid Definition Template number - kgds(2)=igdstmpl(8) ! Ni - kgds(3)=igdstmpl(9) ! Nj - kgds(4)=igdstmpl(10)/1000 ! Lat of 1st grid point - kgds(5)=igdstmpl(11)/1000 ! Long of 1st grid point - kgds(6)=0 ! resolution and component flags - if (igdstmpl(1)==2) kgds(6)=64 - if (btest(igdstmpl(12),4).OR.btest(igdstmpl(12),5)) & - kgds(6)=kgds(6)+128 - if (btest(igdstmpl(12),3)) kgds(6)=kgds(6)+8 - kgds(7)=igdstmpl(14)/1000 ! Lat of last grid point - kgds(8)=igdstmpl(15)/1000 ! Long of last grid point - kgds(9)=igdstmpl(13)/1000 ! Lat intersects earth - kgds(10)=0 - kgds(11)=igdstmpl(16) ! Scanning mode - kgds(12)=igdstmpl(18)/1000 ! Di - kgds(13)=igdstmpl(19)/1000 ! Dj - kgds(14)=0 - kgds(15)=0 - kgds(16)=0 - kgds(17)=0 - kgds(18)=0 - kgds(19)=0 - kgds(20)=255 - kgds(21)=0 - kgds(22)=0 - elseif (igds(5).eq.30) then ! Lambert Conformal Grid - kgds(1)=3 - kgds(2)=igdstmpl(8) ! Nx - kgds(3)=igdstmpl(9) ! Ny - kgds(4)=igdstmpl(10)/1000 ! Lat of 1st grid point - kgds(5)=igdstmpl(11)/1000 ! Long of 1st grid point - kgds(6)=0 ! resolution and component flags - if (igdstmpl(1)==2) kgds(6)=64 - if (btest(igdstmpl(12),4).OR.btest(igdstmpl(12),5)) & - kgds(6)=kgds(6)+128 - if (btest(igdstmpl(12),3)) kgds(6)=kgds(6)+8 - kgds(7)=igdstmpl(14)/1000 ! Lon of orientation - kgds(8)=igdstmpl(15)/1000 ! Dx - kgds(9)=igdstmpl(16)/1000 ! Dy - kgds(10)=igdstmpl(17) ! Projection Center Flag - kgds(11)=igdstmpl(18) ! Scanning mode - kgds(12)=igdstmpl(19)/1000 ! Lat in 1 - kgds(13)=igdstmpl(20)/1000 ! Lat in 2 - kgds(14)=igdstmpl(21)/1000 ! Lat of S. Pole of projection - kgds(15)=igdstmpl(22)/1000 ! Lon of S. Pole of projection - kgds(16)=0 - kgds(17)=0 - kgds(18)=0 - kgds(19)=0 - kgds(20)=255 - kgds(21)=0 - kgds(22)=0 - elseif (igds(5).eq.40) then ! Gaussian Lat/Lon grid - kgds(1)=4 - kgds(2)=igdstmpl(8) ! Ni - kgds(3)=igdstmpl(9) ! Nj - kgds(4)=igdstmpl(12)/1000 ! Lat of 1st grid point - kgds(5)=igdstmpl(13)/1000 ! Long of 1st grid point - kgds(6)=0 ! resolution and component flags - if (igdstmpl(1)==2) kgds(6)=64 - if (btest(igdstmpl(14),4).OR.btest(igdstmpl(14),5)) & - kgds(6)=kgds(6)+128 - if (btest(igdstmpl(14),3)) kgds(6)=kgds(6)+8 - kgds(7)=igdstmpl(15)/1000 ! Lat of last grid point - kgds(8)=igdstmpl(16)/1000 ! Long of last grid point - kgds(9)=igdstmpl(17)/1000 ! Di - kgds(10)=igdstmpl(18) ! N - Number of parallels - kgds(11)=igdstmpl(19) ! Scanning mode - kgds(12)=0 - kgds(13)=0 - kgds(14)=0 - kgds(15)=0 - kgds(16)=0 - kgds(17)=0 - kgds(18)=0 - kgds(19)=0 - kgds(20)=255 - kgds(21)=0 - kgds(22)=0 - elseif (igds(5).eq.20) then ! Polar Stereographic Grid - kgds(1)=5 - kgds(2)=igdstmpl(8) ! Nx - kgds(3)=igdstmpl(9) ! Ny - kgds(4)=igdstmpl(10)/1000 ! Lat of 1st grid point - kgds(5)=igdstmpl(11)/1000 ! Long of 1st grid point - kgds(6)=0 ! resolution and component flags - if (igdstmpl(1)==2) kgds(6)=64 - if (btest(igdstmpl(12),4).OR.btest(igdstmpl(12),5)) & - kgds(6)=kgds(6)+128 - if (btest(igdstmpl(12),3)) kgds(6)=kgds(6)+8 - kgds(7)=igdstmpl(14)/1000 ! Lon of orientation - kgds(8)=igdstmpl(15)/1000 ! Dx - kgds(9)=igdstmpl(16)/1000 ! Dy - kgds(10)=igdstmpl(17) ! Projection Center Flag - kgds(11)=igdstmpl(18) ! Scanning mode - kgds(12)=0 - kgds(13)=0 - kgds(14)=0 - kgds(15)=0 - kgds(16)=0 - kgds(17)=0 - kgds(18)=0 - kgds(19)=0 - kgds(20)=255 - kgds(21)=0 - kgds(22)=0 - elseif (igds(5).eq.204) then ! Curvilinear Orthogonal - kgds(1)=204 - kgds(2)=igdstmpl(8) ! Ni - kgds(3)=igdstmpl(9) ! Nj - kgds(4)=0 - kgds(5)=0 - kgds(6)=0 ! resolution and component flags - if (igdstmpl(1)==2) kgds(6)=64 - if (btest(igdstmpl(14),4).OR.btest(igdstmpl(14),5)) & - kgds(6)=kgds(6)+128 - if (btest(igdstmpl(14),3)) kgds(6)=kgds(6)+8 - kgds(7)=0 - kgds(8)=0 - kgds(9)=0 - kgds(10)=0 - kgds(11)=igdstmpl(19) ! Scanning mode - kgds(12)=0 - kgds(13)=0 - kgds(14)=0 - kgds(15)=0 - kgds(16)=0 - kgds(17)=0 - kgds(18)=0 - kgds(19)=0 - kgds(20)=255 - kgds(21)=0 - kgds(22)=0 - ! - ! Process irreg grid stuff, if necessary - ! - if (idefnum.ne.0) then - if (igdstmpl(8).eq.-1) then - kgds(2)=65535 - kgds(9)=65535 - endif - if (igdstmpl(9).eq.-1) then - kgds(3)=65535 - kgds(10)=65535 - endif - kgds(19)=0 - kgds(20)=33 - if (kgds(1).eq.1.OR.kgds(1).eq.3) kgds(20)=43 - kgds(21)=igds(2) ! num of grid points - do j=1,idefnum - kgds(21+j)=ideflist(j) - enddo - endif - elseif (igds(5).eq.32768) then ! Rotate Lat/Lon grid - kgds(1)=203 ! Arakawa Staggerred E/B grid - kgds(2)=igdstmpl(8) ! Ni - kgds(3)=igdstmpl(9) ! Nj - kgds(4)=igdstmpl(12)/1000 ! Lat of 1st grid point - kgds(5)=igdstmpl(13)/1000 ! Lon of 1st grid point - kgds(6)=0 ! resolution and component flags - if (igdstmpl(1)==2) kgds(6)=64 - if (btest(igdstmpl(14),4).OR.btest(igdstmpl(14),5)) & - kgds(6)=kgds(6)+128 - if (btest(igdstmpl(14),3)) kgds(6)=kgds(6)+8 - kgds(7)=igdstmpl(15)/1000 ! Lat of last grid point - kgds(8)=igdstmpl(16)/1000 ! Lon of last grid point - kgds(9)=igdstmpl(17)/1000 ! Di - kgds(10)=igdstmpl(18)/1000 ! Dj - kgds(11)=igdstmpl(19) ! Scanning mode - kgds(12)=0 - kgds(13)=0 - kgds(14)=0 - kgds(15)=0 - kgds(16)=0 - kgds(17)=0 - kgds(18)=0 - kgds(19)=0 - kgds(20)=255 - kgds(21)=0 - kgds(22)=0 - ! - ! Process irreg grid stuff, if necessary - ! - if (idefnum.ne.0) then - if (igdstmpl(8).eq.-1) then - kgds(2)=65535 - kgds(9)=65535 - endif - if (igdstmpl(9).eq.-1) then - kgds(3)=65535 - kgds(10)=65535 - endif - kgds(19)=0 - kgds(20)=33 - if (kgds(1).eq.1.OR.kgds(1).eq.3) kgds(20)=43 - kgds(21)=igds(2) ! num of grid points - do j=1,idefnum - kgds(21+j)=ideflist(j) - enddo - endif - elseif (igds(5).eq.32769) then ! Rotate Lat/Lon grid - kgds(1)=205 ! Arakawa Staggerred for Non-E Stagger grid - kgds(2)=igdstmpl(8) ! Ni - kgds(3)=igdstmpl(9) ! Nj - kgds(4)=igdstmpl(12)/1000 ! Lat of 1st grid point - kgds(5)=igdstmpl(13)/1000 ! Lon of 1st grid point - kgds(6)=0 ! resolution and component flags - if (igdstmpl(1)==2) kgds(6)=64 - if (btest(igdstmpl(14),4).OR.btest(igdstmpl(14),5)) & - kgds(6)=kgds(6)+128 - if (btest(igdstmpl(14),3)) kgds(6)=kgds(6)+8 - kgds(7)=igdstmpl(15)/1000 ! Lat of last grid point - kgds(8)=igdstmpl(16)/1000 ! Lon of last grid point - kgds(9)=igdstmpl(17)/1000 ! Di - kgds(10)=igdstmpl(18)/1000 ! Dj - kgds(11)=igdstmpl(19) ! Scanning mode - kgds(12)=igdstmpl(20)/1000 - kgds(13)=igdstmpl(21)/1000 - kgds(14)=0 - kgds(15)=0 - kgds(16)=0 - kgds(17)=0 - kgds(18)=0 - kgds(19)=0 - kgds(20)=255 - kgds(21)=0 - kgds(22)=0 - else - Print *,'gdt2gds: Unrecognized GRIB2 GDT = 3.',igds(5) - iret=1 - kgds(1:22)=0 - return - endif - ! - ! Can we determine NCEP grid number ? - ! - igrid=255 - do j=254,1,-1 - !do j=225,225 - kgds71=0 - kgds72=0 - call w3fi71(j,kgds71,ierr) - if (ierr.ne.0) cycle - ! convert W to E for longitudes - if (kgds71(3).eq.0) then ! lat/lon - if (kgds71(7).lt.0) kgds71(7)=360000+kgds71(7) - if (kgds71(10).lt.0) kgds71(10)=360000+kgds71(10) - elseif (kgds71(3).eq.1) then ! mercator - if (kgds71(7).lt.0) kgds71(7)=360000+kgds71(7) - if (kgds71(10).lt.0) kgds71(10)=360000+kgds71(10) - elseif (kgds71(3).eq.3) then ! lambert conformal - if (kgds71(7).lt.0) kgds71(7)=360000+kgds71(7) - if (kgds71(9).lt.0) kgds71(9)=360000+kgds71(9) - if (kgds71(18).lt.0) kgds71(18)=360000+kgds71(18) - elseif (kgds71(3).eq.4) then ! Guassian lat/lon - if (kgds71(7).lt.0) kgds71(7)=360000+kgds71(7) - if (kgds71(10).lt.0) kgds71(10)=360000+kgds71(10) - elseif (kgds71(3).eq.5) then ! polar stereographic - if (kgds71(7).lt.0) kgds71(7)=360000+kgds71(7) - if (kgds71(9).lt.0) kgds71(9)=360000+kgds71(9) - endif - call r63w72(idum,kgds,jdum,kgds72) - if (kgds72(3).eq.3) kgds72(14)=0 ! lambert conformal fix - if (kgds72(3).eq.1) kgds72(15:18)=0 ! mercator fix - if (kgds72(3).eq.5) kgds72(14:18)=0 ! polar str fix - ! print *,' kgds71(',j,')= ', kgds71(1:30) - ! print *,' kgds72 = ', kgds72(1:30) - if (all(kgds71.eq.kgds72)) then - igrid=j - return - endif - enddo - - return -end subroutine gdt2gds diff --git a/utils/makepds.F90 b/utils/makepds.F90 deleted file mode 100644 index ca82c3502..000000000 --- a/utils/makepds.F90 +++ /dev/null @@ -1,528 +0,0 @@ -!> @file -!> @brief Create a GRIB1 PDS (Section 1). -!> @author Stephen Gilbert @date 2003-06-12 - -!> This routine creates a GRIB1 PDS (Section 1) from appropriate -!> information from a GRIB2 Product Definition Template. -!> -!> @note Use pds2pdtens for ensemble related PDS. -!> -!> ### Program History Log -!> Date | Programmer | Comments -!> -----|------------|--------- -!> 2003-06-12 | Gilbert | Initial. -!> 2005-04-19 | Gilbert | Changed scaling factor used with potential vorticity surfaces. -!> 2007-05-08 | VUONG | Add Product Definition Template entries 120-124, 131, 88, 45, 47. -!> 2007-05-14 | Boi Vuong | Added Time Range Indicator 51 (Climatological Mean Value) -!> 2007-10-24 | Boi Vuong | Added level 8 (Nominal top of atmosphere) -!> 2009-05-19 | Boi Vuong | Added levels 10(Entire Atmosphere), 11(Cumulonimbus Base),12(Cumulonimbus Top) and level 126(Isobaric Pa) -!> 2009-12-14 | Boi Vuong | Added check for WAFS to use PDT 4.15 for Icing, Turbulence and Cumulonimbus -!> 2010-08-10 | Boi Vuong | Added check for FNMOC to use TMP as TMAX and TMIN - Removed check WAFS MAX wind level -!> 2011-10-24 | Boi Vuong | Added check for NAM (NMM-B) parameters to set statistical processing as MAX and MIN -!> 2012-03-29 | Boi Vuong | Added check Time Range for APCP in FNMOC -!> 2014-05-20 | Boi Vuong | Added check Time Range after F252 -!> 2014-11-14 | Boi Vuong | Added check Time Range for 15-hr or 18-hr or 21-hr or 24-hr Accumulation for APCP after F240 -!> 2018-07-26 | Boi Vuong | Added check Time Range for continuous accumulated APCP after F252 when convert from grib2 to grib1 -!> -!> @param[in] idisc GRIB2 discipline from Section 0. -!> @param[in] idsect GRIB2 Section 1 info. -!> - idsect(1) Id of orginating centre (Common Code Table C-1) -!> - idsect(2) Id of orginating sub-centre (local table) -!> - idsect(3) GRIB Master Tables Version Number (Code Table 1.0) -!> - idsect(4) GRIB Local Tables Version Number (Code Table 1.1) -!> - idsect(5) Significance of Reference Time (Code Table 1.2) -!> - idsect(6) Reference Time - Year (4 digits) -!> - idsect(7) Reference Time - Month -!> - idsect(8) Reference Time - Day -!> - idsect(9) Reference Time - Hour -!> - idsect(10) Reference Time - Minute -!> - idsect(11) Reference Time - Second -!> - idsect(12) Production status of data (Code Table 1.3) -!> - idsect(13) Type of processed data (Code Table 1.4) -!> @param[in] ipdsnum GRIB2 Product Definition Template Number -!> @param[in] ipdstmpl GRIB2 Product Definition Template entries for PDT 4.ipdsnum -!> @param[in] ibmap GRIB2 bitmap indicator from octet 6, Section 6. -!> @param[in] idrsnum GRIB2 Data Representation Template Number -!> @param[in] idrstmpl GRIB2 Data Representation Template entries -!> @param[out] kpds GRIB1 PDS info as specified in W3FI63. -!> - 1 id of center -!> - 2 generating process id number -!> - 3 grid definition -!> - 4 gds/bms flag (right adj copy of octet 8) -!> - 5 indicator of parameter -!> - 6 type of level -!> - 7 height/pressure , etc of level -!> - 8 year including (century-1) -!> - 9 month of year -!> - 10 day of month -!> - 11 hour of day -!> - 12 minute of hour -!> - 13 indicator of forecast time unit -!> - 14 time range 1 -!> - 15 time range 2 -!> - 16 time range flag -!> - 17 number included in average -!> - 18 version nr of grib specification -!> - 19 version nr of parameter table -!> - 20 nr missing from average/accumulation -!> - 21 century of reference time of data -!> - 22 units decimal scale factor -!> - 23 subcenter number -!> @param[out] iret Error return value: -!> - 0 Successful -!> - 1 Don't know what to do with pre-defined bitmap. -!> - 2 Unrecognized GRIB2 PDT 4.ipdsnum -!> -!> @author Stephen Gilbert @date 2003-06-12 -subroutine makepds(idisc,idsect,ipdsnum,ipdstmpl,ibmap, & - idrsnum,idrstmpl,kpds,iret) - - use params - - integer,intent(in) :: idsect(*),ipdstmpl(*),idrstmpl(*) - integer,intent(in) :: ipdsnum,idisc,idrsnum,ibmap - integer,intent(out) :: kpds(*) - integer,intent(out) :: iret - - iret=0 - ipos=0 - kpds(1:24)=0 - if ( (ipdsnum.lt.0).OR.(ipdsnum.gt.15) ) then - print *,'makepds: Don:t know GRIB2 PDT 4.',ipdsnum - iret=2 - return - endif - - kpds(1)=idsect(1) - kpds(2)=ipdstmpl(5) - kpds(3)=255 - kpds(4)=128 - if ( ibmap.ne.255 ) kpds(4)=kpds(4)+64 - if ( ibmap.ge.1.AND.ibmap.le.253 ) then - print *,'makepds: Don:t know about predefined bit-map ',ibmap - iret=1 - return - endif - call param_g2_to_g1(idisc,ipdstmpl(1),ipdstmpl(2),kpds(5), & - kpds(19)) - ! - ! Special parameters for ICAO WAFS (Max Icing, TP and CAT) - ! - If (ipdstmpl(16).eq.2.and.ipdstmpl(1).eq.19.and. & - ipdstmpl(2).eq.20) kpds(5) = 169 - If (ipdstmpl(16).eq.2.and.ipdstmpl(1).eq.19.and. & - ipdstmpl(2).eq.21) kpds(5) = 171 - If (ipdstmpl(16).eq.2.and.ipdstmpl(1).eq.19.and. & - ipdstmpl(2).eq.22) kpds(5) = 173 - ! - ! Special parameters for NAM (NMMB) - ! - If (idisc.eq.0.and.ipdstmpl(1).eq.2) then - if (ipdstmpl(2).eq.220) then - kpds(5) = 237 - kpds(19) = 129 - end if - if (ipdstmpl(2).eq.221) then - kpds(5) = 238 - kpds(19) = 129 - end if - if (ipdstmpl(2).eq.222) then - kpds(5) = 253 - kpds(19) = 129 - end if - if (ipdstmpl(2).eq.223) then - kpds(5) = 254 - kpds(19) = 129 - end if - endif - ! - If (idisc.eq.0.and.ipdstmpl(2).eq.16 & - .and.ipdstmpl(3).eq.198) then - kpds(5) = 235 - kpds(19) = 129 - endif - ! - If (idisc.eq.0.and.ipdstmpl(2).eq.7 & - .and.ipdstmpl(3).eq.199) then - kpds(5) = 236 - kpds(19) = 129 - endif - ! - ! Special parameters for ICAO Height at CB Base and Top - ! in GRIB1 Table 140 - ! - If (ipdstmpl(1).eq.3.and.ipdstmpl(2).eq.3) then - If (ipdstmpl(10).eq.11) then - kpds(19) = 140 - kpds(5) = 179 - end if - If (ipdstmpl(10).eq.12) then - kpds(19) = 140 - kpds(5) = 180 - end if - end if - ! - call levelcnv(ipdstmpl,kpds(6),kpds(7)) ! level - kpds(8)=mod(idsect(6),100) - if ( kpds(8).eq.0 ) kpds(8)=100 - kpds(9)=idsect(7) ! Year - kpds(10)=idsect(8) ! Month - kpds(11)=idsect(9) ! Day - kpds(12)=idsect(10) ! Hour - if ( ipdstmpl(8).ne.13 ) then - kpds(13)=ipdstmpl(8) ! Time Unit - else - kpds(13)=254 - endif - kpds(14)=ipdstmpl(9) ! P1 - if ( ipdsnum.le.7 ) then ! P2 - kpds(15)=0 - kpds(16)=0 - kpds(20)=0 - if ( kpds(14).eq.0 ) kpds(16)=1 - if ( kpds(14).gt.255 ) kpds(16)=10 - if ( ipdstmpl(5).eq.77.OR.ipdstmpl(5).eq.81.OR. & - ipdstmpl(5).eq.96.OR.ipdstmpl(5).eq.80.OR. & - ipdstmpl(5).eq.82.OR.ipdstmpl(5).eq.120.OR. & - ipdstmpl(5).eq.47.OR.ipdstmpl(5).eq.11 ) then - kpds(16)=10 - end if - if (ipdstmpl(5).eq.84.AND.kpds(5).eq.154)kpds(16) = 10 - ! - ! NOAA Wave Watch III and Coastal Ocean Circulation - ! and Alaska Waters Regional Wave Model - ! - if ( ipdstmpl(5).eq.88.OR.ipdstmpl(5).eq.121 & - .OR.ipdstmpl(5).eq.122.OR.ipdstmpl(5).eq.123 & - .OR.ipdstmpl(5).eq.124.OR.ipdstmpl(5).eq.125 & - .OR.ipdstmpl(5).eq.131.OR.ipdstmpl(5).eq.45 & - .OR.ipdstmpl(5).eq.11 ) then - kpds(16) = 0 - ! - ! Level Surface set to 1 - ! - if (kpds(5).eq.80.OR.kpds(5).eq.82.OR. & - kpds(5).eq.88.OR.kpds(5).eq.49.OR. & - kpds(5).eq.50) kpds(7)=1 ! Level Surface - if (ipdstmpl(5).eq.122.OR.ipdstmpl(5).eq.124.OR. & - ipdstmpl(5).eq.131.OR.ipdstmpl(5).eq.123.OR. & - ipdstmpl(5).eq.125.OR.ipdstmpl(5).eq.88.OR. & - ipdstmpl(5).eq.121) kpds(7)=1 - if (idsect(1).eq.54.AND.ipdstmpl(5).eq.45) kpds(16) = 10 - endif - else - selectcase (ipdsnum) - case(8) - ipos=24 - case(9) - ipos=31 - case(10) - ipos=25 - case(11) - ipos=27 - case(12) - ipos=26 - case(13) - ipos=40 - case(14) - ipos=39 - end select - kpds(15)=ipdstmpl(ipos+3)+kpds(14) ! P2 - selectcase (ipdstmpl(ipos)) - case (255) - kpds(16)=2 - case (0) - kpds(16)=3 - case (1) - kpds(16)=4 - case (2) - kpds(16)=2 - case (3) - kpds(16)=2 - case (4) - kpds(16)=5 - case (51) - kpds(16)=51 - end select - kpds(20)=ipdstmpl(ipos-1) - endif - if (ipdstmpl(9) .ge. 252) then - if (ipdstmpl(ipos+3).eq.3) then - kpds(13)= 10 ! Forecast time unit is 3-hour - kpds(14)=ipdstmpl(9)/3 ! Time range P1 - kpds(15)=ipdstmpl(ipos+3)/3+kpds(14) ! Time range P2 - else if (ipdstmpl(ipos+3).eq.6) then - kpds(13)= 11 ! Forecast time unit is 6-hour - kpds(14)=ipdstmpl(9)/6 ! Time range P1 - kpds(15)=ipdstmpl(ipos+3)/6+kpds(14) ! Time range P2 - else if (ipdstmpl(ipos+3).eq.12) then - kpds(13)= 12 ! Forecast time unit is 12-hour - kpds(14)=ipdstmpl(9)/12 ! Time range P1 - kpds(15)=ipdstmpl(ipos+3)/12+kpds(14) ! Time range P2 - end if - end if - if (ipdsnum .eq. 8 .AND. ipdstmpl(9) .eq. 0) then - if (ipdstmpl(ipos+3).ge.252) then - kpds(13)= 10 ! Forecast time unit is hour - kpds(14)=ipdstmpl(9)/3 ! Time range P1 - kpds(15)=ipdstmpl(ipos+3)/3+kpds(14) ! Time range P2 - end if - end if - ! - ! Checking total preciptation for 15-hr or 18-hr or 21-hr or 24-hr accumulation - ! after forecast hour F240 - ! - if (ipdstmpl(9) .ge. 240 )then - if ( ipdstmpl(ipos+3).eq.15 .OR. ipdstmpl(ipos+3).eq.18 & - .OR. ipdstmpl(ipos+3).eq.21 .OR. & - ipdstmpl(ipos+3).eq.24 ) then - kpds(13)= 10 ! Forecast time unit is 3-hour - kpds(14)=ipdstmpl(9)/3 ! Time range P1 - kpds(15)=ipdstmpl(ipos+3)/3+kpds(14) ! Time range P2 - end if - end if - ! - ! Checking Unit of Time Range for FNMOC (APCP) - ! - if (ipdstmpl(4).eq.58 .AND. ipdsnum.eq.11 .AND. & - (ipdstmpl(1).eq.1 .AND.ipdstmpl(2).eq.8) & - .AND. (ipdstmpl(10).eq.1)) then - if (ipdstmpl(9) .ge. 252) then - kpds(13)= 11 ! Forecast time unit is 6-hour - kpds(14)=ipdstmpl(9)/6 ! Time range P1 - kpds(15)=ipdstmpl(ipos+3)/6+kpds(14) ! Time range P2 - else - kpds(13)= 1 ! Forecast time unit is 1-hour - kpds(14)=ipdstmpl(9) ! Time range P1 - end if - end if - ! - ! Special case for FNMOC (TMAX and TMIN) - ! - if (ipdstmpl(4).eq.58 .AND. ipdsnum.eq.11 .AND. & - (ipdstmpl(1).eq.0 & - .AND.ipdstmpl(2).eq.0).AND.(ipdstmpl(10).eq.103)) then - kpds(16) = 2 - ! For Maximum Temperature - If (ipdstmpl(27).eq.2 .AND. ipdstmpl(1).eq.0 .AND. & - ipdstmpl(2).eq.0) kpds(5) = 15 - ! For Minimum Temperature - If (ipdstmpl(27).eq.3 .AND. ipdstmpl(1).eq.0 .AND. & - ipdstmpl(2).eq.0) kpds(5) = 16 - end if - ! - ! Special case for WAFS (Mean/MAx IP,CTP and CAT) - ! - if (ipdstmpl(5).eq.96.AND.((ipdstmpl(1).eq.19) & - .AND.(ipdstmpl(2).eq.20.or.ipdstmpl(2).eq.21.or. & - ipdstmpl(2).eq.22)).AND.(ipdstmpl(10).eq.100)) then - kpds(16) = 10 - end if - ! - kpds(17)=0 - kpds(18)=1 ! GRIB edition - kpds(21)=(idsect(6)/100)+1 ! Century - if ( kpds(8).eq.100 ) kpds(21)=idsect(6)/100 - kpds(22)=idrstmpl(3) ! Decimal scale factor - kpds(23)=idsect(2) ! Sub-center - return -end subroutine makepds - - -!> This routine converts Level/layer information from a GRIB2 Product -!> Definition Template to GRIB1 Level type and Level value. -!> -!> ### Program History Log -!> Date | Programmer | Comments -!> -----|------------|--------- -!> 2003-06-12 | Gilbert | Initial -!> 2007-10-24 | Boi Vuong | Added level 8 (Nominal top of atmosphere) -!> 2011-01-13 | Boi Vuong | Added level/layer values from 235 to 239 -!> -!> @param[in] ipdstmpl GRIB2 Product Definition Template values -!> @param[out] ltype GRIB1 level type (PDS octet 10) -!> @param[out] lval GRIB1 level/layer value(s) (PDS octets 11 and 12) -!> -!> @author Stephen Gilbert @date 2003-06-12 -subroutine levelcnv(ipdstmpl,ltype,lval) - integer,intent(in) :: ipdstmpl(*) - integer,intent(out) :: ltype,lval - - ltype=255 - lval=0 - ltype1=ipdstmpl(10) - ltype2=ipdstmpl(13) - - if ( ltype1.eq.10.AND.ltype2.eq.255 ) then - ltype=200 - lval=0 - elseif ( ltype1.eq.11.AND.ltype2.eq.255 ) then - ltype=216 - lval=0 - elseif ( ltype1.eq.12.AND.ltype2.eq.255 ) then - ltype=217 - lval=0 - elseif ( ltype1.lt.100.AND.ltype2.eq.255 ) then - ltype=ltype1 - lval=0 - elseif ( ltype1.eq.1.AND.ltype2.eq.8 ) then - ltype=ltype1 - lval=0 - elseif ( ltype1.eq.10.AND.ltype2.eq.255 ) then - ltype=200 - lval=0 - elseif ( ltype1.eq.235.AND.ltype2.eq.255 ) then - ltype=235 - rscal1=10.**(-ipdstmpl(11)) - lval=nint(real(ipdstmpl(12))*rscal1) - elseif ( ltype1.ge.200.AND.ltype2.eq.255 ) then - ltype=ltype1 - lval=0 - elseif (ltype1.eq.100.AND.ltype2.eq.255 ) then - ltype=100 - rscal1=10.**(-ipdstmpl(11)) - lval=nint(real(ipdstmpl(12))*rscal1/100.) - elseif (ltype1.eq.100.AND.ltype2.eq.100 ) then - ltype=101 - rscal1=10.**(-ipdstmpl(11)) - lval1=nint(real(ipdstmpl(12))*rscal1/1000.) - rscal2=10.**(-ipdstmpl(14)) - lval2=nint(real(ipdstmpl(15))*rscal2/1000.) - lval=(lval1*256)+lval2 - elseif (ltype1.eq.101.AND.ltype2.eq.255 ) then - ltype=102 - lval=0 - elseif (ltype1.eq.102.AND.ltype2.eq.255 ) then - ltype=103 - rscal1=10.**(-ipdstmpl(11)) - lval=nint(real(ipdstmpl(12))*rscal1) - elseif (ltype1.eq.102.AND.ltype2.eq.102 ) then - ltype=104 - rscal1=10.**(-ipdstmpl(11)) - lval1=nint(real(ipdstmpl(12))*rscal1) - rscal2=10.**(-ipdstmpl(14)) - lval2=nint(real(ipdstmpl(15))*rscal2) - lval=(lval1*256)+lval2 - elseif (ltype1.eq.103.AND.ltype2.eq.255 ) then - ltype=105 - rscal1=10.**(-ipdstmpl(11)) - lval=nint(real(ipdstmpl(12))*rscal1) - elseif (ltype1.eq.103.AND.ltype2.eq.103 ) then - ltype=106 - rscal1=10.**(-ipdstmpl(11)) - lval1=nint(real(ipdstmpl(12))*rscal1/100.) - rscal2=10.**(-ipdstmpl(14)) - lval2=nint(real(ipdstmpl(15))*rscal2/100.) - lval=(lval1*256)+lval2 - elseif (ltype1.eq.104.AND.ltype2.eq.255 ) then - ltype=107 - rscal1=10.**(-ipdstmpl(11)) - lval=nint(real(ipdstmpl(12))*rscal1*10000.) - elseif (ltype1.eq.104.AND.ltype2.eq.104 ) then - ltype=108 - rscal1=10.**(-ipdstmpl(11)) - lval1=nint(real(ipdstmpl(12))*rscal1*100.) - rscal2=10.**(-ipdstmpl(14)) - lval2=nint(real(ipdstmpl(15))*rscal2*100.) - lval=(lval1*256)+lval2 - elseif (ltype1.eq.105.AND.ltype2.eq.255 ) then - ltype=109 - lval=ipdstmpl(12) - elseif (ltype1.eq.105.AND.ltype2.eq.105 ) then - ltype=110 - rscal1=10.**(-ipdstmpl(11)) - lval1=nint(real(ipdstmpl(12))*rscal1) - rscal2=10.**(-ipdstmpl(14)) - lval2=nint(real(ipdstmpl(15))*rscal2) - lval=(lval1*256)+lval2 - elseif (ltype1.eq.106.AND.ltype2.eq.255 ) then - ltype=111 - rscal1=10.**(-ipdstmpl(11)) - lval=nint(real(ipdstmpl(12))*rscal1*100.) - elseif (ltype1.eq.106.AND.ltype2.eq.106 ) then - ltype=112 - rscal1=10.**(-ipdstmpl(11)) - lval1=nint(real(ipdstmpl(12))*rscal1*100.) - rscal2=10.**(-ipdstmpl(14)) - lval2=nint(real(ipdstmpl(15))*rscal2*100.) - lval=(lval1*256)+lval2 - elseif (ltype1.eq.107.AND.ltype2.eq.255 ) then - ltype=113 - rscal1=10.**(-ipdstmpl(11)) - lval=nint(real(ipdstmpl(12))*rscal1) - elseif (ltype1.eq.107.AND.ltype2.eq.107 ) then - ltype=114 - rscal1=10.**(-ipdstmpl(11)) - lval1=475-nint(real(ipdstmpl(12))*rscal1) - rscal2=10.**(-ipdstmpl(14)) - lval2=475-nint(real(ipdstmpl(15))*rscal2) - lval=(lval1*256)+lval2 - elseif (ltype1.eq.108.AND.ltype2.eq.255 ) then - ltype=115 - rscal1=10.**(-ipdstmpl(11)) - lval=nint(real(ipdstmpl(12))*rscal1/100.) - elseif (ltype1.eq.108.AND.ltype2.eq.108 ) then - ltype=116 - rscal1=10.**(-ipdstmpl(11)) - lval1=nint(real(ipdstmpl(12))*rscal1/100.) - rscal2=10.**(-ipdstmpl(14)) - lval2=nint(real(ipdstmpl(15))*rscal2/100.) - lval=(lval1*256)+lval2 - elseif (ltype1.eq.109.AND.ltype2.eq.255 ) then - ltype=117 - rscal1=10.**(-ipdstmpl(11)) - lval=nint(real(ipdstmpl(12))*rscal1*1000000000.) - elseif (ltype1.eq.111.AND.ltype2.eq.255 ) then - ltype=119 - rscal1=10.**(-ipdstmpl(11)) - lval=nint(real(ipdstmpl(12))*rscal1*10000.) - elseif (ltype1.eq.111.AND.ltype2.eq.111 ) then - ltype=120 - rscal1=10.**(-ipdstmpl(11)) - lval1=nint(real(ipdstmpl(12))*rscal1*100.) - rscal2=10.**(-ipdstmpl(14)) - lval2=nint(real(ipdstmpl(15))*rscal2*100.) - lval=(lval1*256)+lval2 - elseif (ltype1.eq.160.AND.ltype2.eq.255 ) then - ltype=160 - rscal1=10.**(-ipdstmpl(11)) - lval=nint(real(ipdstmpl(12))*rscal1) - elseif ((ltype1.ge.236.AND.ltype1.le.239).AND. & - (ltype2.ge.236.AND.ltype2.le.239)) then - ltype=ltype1 - rscal1=10.**(-ipdstmpl(11)) - lval1=nint(real(ipdstmpl(12))*rscal1) - rscal2=10.**(-ipdstmpl(14)) - lval2=nint(real(ipdstmpl(15))*rscal2) - lval=(lval1*256)+lval2 - else - print *,'levelcnv: GRIB2 Levels ',ltype1,ltype2, & - ' not recognized.' - ltype=255 - endif - - ! High resolution stuff - ! elseif (ltype.eq.121) then - ! ipdstmpl(10)=100 - ! ipdstmpl(12)=(1100+(lval/256))*100 - ! ipdstmpl(13)=100 - ! ipdstmpl(15)=(1100+mod(lval,256))*100 - ! elseif (ltype.eq.125) then - ! ipdstmpl(10)=103 - ! ipdstmpl(11)=-2 - ! ipdstmpl(12)=lval - ! elseif (ltype.eq.128) then - ! ipdstmpl(10)=104 - ! ipdstmpl(11)=-3 - ! ipdstmpl(12)=1100+(lval/256) - ! ipdstmpl(13)=104 - ! ipdstmpl(14)=-3 - ! ipdstmpl(15)=1100+mod(lval,256) - ! elseif (ltype.eq.141) then - ! ipdstmpl(10)=100 - ! ipdstmpl(12)=(lval/256)*100 - ! ipdstmpl(13)=100 - ! ipdstmpl(15)=(1100+mod(lval,256))*100 - - return -end subroutine levelcnv diff --git a/utils/makepdsens.F90 b/utils/makepdsens.F90 deleted file mode 100644 index 7767afc45..000000000 --- a/utils/makepdsens.F90 +++ /dev/null @@ -1,156 +0,0 @@ -!> @file -!> @brief Create GRIB1 NCEP Ensemble PDS extension information from a -!> GRIB2 Product Definition Template. -!> @author Stephen Gilbert @date 2003-06-12 - -!> This routine creates the GRIB1 NCEP Ensemble PDS extension -!> information from appropriate information from a GRIB2 Product -!> Definition Template. -!> -!> @note Use pds2pdtens for ensemble related PDS. -!> -!> ### Program History Log -!> Date | Programmer | Comments -!> -----|------------|--------- -!> 2003-06-12 | Gilbert | Initial -!> 2007-05-14 | Boi Vuong | Corrected scale factor probabilities -!> 2010-07-26 | Boi Vuong | Added two type of ensemblers (4 and 192) -!> -!> @param[in] ipdsnum GRIB2 Product Definition Template Number -!> @param[in] ipdstmpl GRIB2 Product Definition Template entries for -!> PDT 4.ipdsnum -!> @param[inout] kpds GRIB1 PDS info as specified in W3FI63. -!> - 1 id of center -!> - 2 generating process id number -!> - 3 grid definition -!> - 4 gds/bms flag (right adj copy of octet 8) -!> - 5 indicator of parameter -!> - 6 type of level -!> - 7 height/pressure , etc of level -!> - 8 year including (century-1) -!> - 9 month of year -!> - 10 day of month -!> - 11 hour of day -!> - 12 minute of hour -!> - 13 indicator of forecast time unit -!> - 14 time range 1 -!> - 15 time range 2 -!> - 16 time range flag -!> - 17 number included in average -!> - 18 version nr of grib specification -!> - 19 version nr of parameter table -!> - 20 nr missing from average/accumulation -!> - 21 century of reference time of data -!> - 22 units decimal scale factor -!> - 23 subcenter number -!> @param[out] kens Ensemble identification for PDS octets 41-45 -!> @param[out] kprob Ensemble probability info for PDS octets 46 47 -!> @param[out] xprob Ensemble probability info for PDS octets 48-55 -!> @param[out] kclust Ensemble cluster info for PDS octets 61-76 -!> @param[out] kmembr Ensemble membership info for PDS octest 77-86 -!> @param[out] iret Error return value: -!> - 0 Successful -!> - 2 Unrecognized GRIB2 PDT 4.ipdsnum -!> -!> @author Stephen Gilbert @date 2003-06-12 -subroutine makepdsens(ipdsnum,ipdstmpl,kpds,kens,kprob, & - xprob,kclust,kmembr,iret) - use params - - integer,intent(in) :: ipdstmpl(*) - integer,intent(in) :: ipdsnum - integer,intent(inout) :: kpds(*) - integer,intent(out) :: kens(5),kprob(2) - integer,intent(out) :: kclust(16),kmembr(80) - real,intent(out) :: xprob(2) - integer,intent(out) :: iret - - iret=0 - kpds(23)=2 ! subcenter = ensemble - - kens(1:5)=0 - kprob(1:2)=0 - xprob(1:2)=0. - kclust(1:16)=0 - kmembr(1:80)=0 - ! - ! Individual Ensemble Fcst - ! - if (ipdsnum.eq.1.OR.ipdsnum.eq.11) then - kens(1)=1 - selectcase (ipdstmpl(16)) - case(0) - kens(2)=1 - kens(3)=1 - case(1) - kens(2)=1 - kens(3)=2 - case(2) - kens(2)=2 - kens(3)=ipdstmpl(17) - case(3) - kens(2)=3 - kens(3)=ipdstmpl(17) - case(4) - kens(2)=3 - kens(3)=ipdstmpl(17) - case(192) - kens(2)=3 - kens(3)=ipdstmpl(17) - end select - kens(4)=1 - kens(5)=255 - ! - ! Probability Fcst - ! - elseif (ipdsnum.eq.5.OR.ipdsnum.eq.9) then - kens(1)=1 - kens(2)=5 - kens(3)=0 - kens(4)=0 - kens(5)=255 - kprob(1)=kpds(5) - kpds(5)=191 - kprob(2)=ipdstmpl(18)+1 - if (kprob(2).eq.1) then - rscale=10.**ipdstmpl(19) - xprob(1)=real(ipdstmpl(20))/rscale - xprob(2)=0.0 - elseif (kprob(2).eq.2) then - xprob(1)=0.0 - rscale=10.**ipdstmpl(21) - xprob(2)=real(ipdstmpl(22))/rscale - elseif (kprob(2).eq.3) then - rscale=10.**ipdstmpl(19) - xprob(1)=real(ipdstmpl(20))/rscale - rscale=10.**ipdstmpl(21) - xprob(2)=real(ipdstmpl(22))/rscale - endif - kclust(1)=ipdstmpl(17) - ! - ! Derived Ensemble Fcst - ! - elseif (ipdsnum.eq.2.OR.ipdsnum.eq.12) then - kens(1)=1 - kens(2)=5 - kens(3)=0 - selectcase (ipdstmpl(16)) - case(0) - kens(4)=1 - case(1) - kens(4)=2 - case(2) - kens(4)=11 - case(3) - kens(4)=12 - end select - !kens(5)=89 - kens(5)=0 - kclust(1)=ipdstmpl(17) - else - print *,'makepdsens: Don:t know GRIB2 PDT 4.',ipdsnum - iret=2 - endif - - return -end subroutine makepdsens diff --git a/utils/mkfldsep.F90 b/utils/mkfldsep.F90 deleted file mode 100644 index e0f5353ec..000000000 --- a/utils/mkfldsep.F90 +++ /dev/null @@ -1,96 +0,0 @@ -!> @file -!> @brief Makes TOC Flag Field Separator Block. -!> @author Gilbert @date 2002-09-16 - -!> Generates a TOC Flag Field Separator Block used to separate WMO -!> Bulletins within a transmission file to be ingested in TOC's FTP -!> Input Service, which can be used to disseminate WMO buletins (see -!> http://weather.gov/tg/ftpingest.html). -!> -!> This routine can generate different flag field separator blocks -!> depending on the value of variable iopt. -!> -!> Bulletin "Flag Field Separator" block - OPTION 1 (old) -!> -!> Bytes | Description -!> ------|------------ -!> 1 - 4 | marker string (####) -!> 5 - 7 | block length [018 fixed value] -!> 8 - 13 | total length of bulletin in bytes [octets] (not including the flag field block) -!> 14 - 17 | marker string (####) -!> 18 | line Feed (ASCII "0A") -!> -!> Bulletin "Flag Field Separator" block - OPTION 1a (new) -!> -!> Bytes | Description -!> ------|------------ -!> 1 - 4 | marker string (####) -!> 5 - 7 | block length (nnn) - value always greater than 018 -!> 8 - 18 | total length of bulletin in bytes [octets] (not including the flag field block) -!> 19 - nnn-5 | reserved for future use -!> nnn-4 - nnn-1 | marker string (####) -!> nnn | line Feed (ASCII "0A") -!> -!> Bulletin "Flag Field Separator" block - OPTION 2 (limited) -!> -!> Bytes | Description -!> ------|------------ -!> 1 - 4 | marker string (****) -!> 5 - 14 | total length of bulletin in bytes [octets] (not including the flag field block) -!> 15 - 18 | marker string (****) -!> 19 | line Feed (ASCII "0A") -!> -!> @param[out] csep*(*) Character array containing the flag field separator. -!> @param[in] iopt Flag Field Separator block option: -!> - 1 Separator block for use with alphanumeric bulletins. -!> - if lenin <= 18 and lenbull <= 999999, OPTION 1 block will be generated. -!> - if lenin > 18 or lenbull > 999999, OPTION 1a block will be generated. -!> - 2 Separator block for use with GRIB/BUFR bulletins. -!> @param[in] lenin Desired length of the flag field separator -!> block. ignored, if iopt=2. -!> @param[in] lenbull Integer length of the bulletin (in bytes) that -!> will follow this separator block. -!> @param[out] lenout Integer length of the flag field separator block. -!> -!> @author Gilbert @date 2002-09-16 -subroutine mkfldsep(csep,iopt,lenin,lenbull,lenout) - ! - character*(*),intent(out) :: csep - integer,intent(in) :: iopt,lenin,lenbull - integer,intent(out) :: lenout - ! - character(len=4),parameter :: cstar='****',clb='####' - ! - if (iopt.eq.1) then - if ( lenin .le. 18 .and. lenbull .le. 999999 ) then - ! Create OPTION 1 separator block - csep(1:4)=clb - csep(5:7)='018' - write(csep(8:13),fmt='(I6.6)') lenbull - csep(14:17)=clb - csep(18:18)=char(10) - lenout=18 - else ! Create OPTION 1a separator block - nnn=lenin - if ( nnn.lt.23 ) nnn=23 - csep(1:4)=clb - write(csep(5:7),fmt='(I3.3)') nnn - write(csep(8:18),fmt='(I11.11)') lenbull - csep(19:nnn-5)='0' - csep(nnn-4:nnn-1)=clb - csep(nnn:nnn)=char(10) - lenout=nnn - endif - elseif (iopt.eq.2) then ! Create OPTION 2 separator block - csep(1:4)=cstar - write(csep(5:14),fmt='(I10.10)') lenbull - csep(15:18)=cstar - csep(19:19)=char(10) - lenout=19 - else - print *,"mkfldsep: Option ",iopt," not recognized." - csep(1:lenin)=' ' - endif - ! - return -end subroutine mkfldsep diff --git a/utils/pds2pdt.F90 b/utils/pds2pdt.F90 deleted file mode 100644 index df59351ea..000000000 --- a/utils/pds2pdt.F90 +++ /dev/null @@ -1,490 +0,0 @@ -!> @file -!> @brief Convert a GRIB1 PDS (Section 1) info to a GRIB2 PDS (Section -!> 4) info. -!> @author Stephen Gilbert @date 2003-06-12 - -!> This routine converts a GRIB1 PDS (Section 1) info to a GRIB2 PDS -!> (Section 4) info with appropriate Product Definition Template. -!> -!> @note Use pds2pdtens for ensemble related PDS. -!> -!> ### Program History Log -!> Date | Programmer | Comments -!> -----|------------|--------- -!> 2003-06-12 | Gilbert | Initial. -!> 2005-04-19 | Gilbert | Changed scaling factor used with potential vorticity surfaces. -!> 2007-02-07 | Gilbert | fixed end date calculation -!> 2007-03-26 | Gordon | Added check for ECMWF data to reference ECMWF Conversion tables. -!> 2007-05-14 | Boi Vuong | Added Time Range Indicator 51 (Climatological Mean Value) -!> 2009-05-20 | Boi Vuong | Added check for WAFS to use PDT 4.8 for Max Wind -!> 2009-12-14 | Boi Vuong | Added check for WAFS to use PDT 4.15 for Icing, Turbulence and Cumulonimbus -!> 2010-02-18 | Boi Vuong | Added Time Range Indicator 7 -!> 2010-08-10 | Boi Vuong | Removed check for WAFS to use PDT 4.8 for Max Wind -!> 2011-10-24 | Boi Vuong | Added check for parameters (MAXUW, MAXVW, to set type of statistical processing (MIN and MAX) -!> -!> @param[in] kpds GRIB1 PDS info as specified in W3FI63. -!> @param[out] ipdsnum GRIB2 Product Definition Template Number -!> @param[out] ipdstmpl GRIB2 Product Definition Template entries for PDT 4.ipdsnum -!> @param[out] numcoord number of vertical discretisation values (not implemented) -!> @param[out] coordlist rtical discretisation values (not implemented) -!> @param[out] iret Error return value: -!> - 0 Successful -!> - 1 Unrecognized GRIB1 Time Range Indicator -!> -!> @author Stephen Gilbert @date 2003-06-12 -subroutine pds2pdt(kpds,ipdsnum,ipdstmpl,numcoord,coordlist, & - iret) - - use params - use params_ecmwf - - integer,intent(in) :: kpds(*) - integer,intent(out) :: ipdstmpl(*) - real,intent(out) :: coordlist(*) - integer,intent(out) :: ipdsnum,numcoord,iret - - integer :: idat(8),jdat(8) - real :: rinc(5) - logical :: ecmwf - - iret=0 - numcoord=0 - ecmwf=.false. - - if (kpds(1).eq.98) ecmwf=.true. - ! - ! Special check for WAFS products for parameters (Max Icing, TP and CAT) - ! to PDT 4.15 - ! - if ((kpds(2).eq.96 .AND. kpds(3).eq.45 .AND. & - kpds(16).eq.10) .AND. & - (kpds(19).eq.140 .AND. (kpds(5).ge.168 .AND. & - kpds(5).le.173))) then - ipdsnum=15 - ! get GRIB2 parameter category and number from GRIB1 - ! parameter number - if (ecmwf) then ! treat ecmwf data conversion seperately - call param_ecmwf_g1_to_g2(kpds(5),kpds(19),idum, & - ipdstmpl(1),ipdstmpl(2)) - else - call param_g1_to_g2(kpds(5),kpds(19),idum,ipdstmpl(1), & - ipdstmpl(2)) - endif - ipdstmpl(3)=2 - ipdstmpl(4)=0 - ipdstmpl(5)=kpds(2) - ipdstmpl(6)=0 - ipdstmpl(7)=0 - ipdstmpl(8)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(8)=13 - ipdstmpl(9)=kpds(14) - call cnvlevel(kpds(6),kpds(7),ipdstmpl) - if (kpds(5).eq.168.or.kpds(5).eq.170.or. & ! statistical process WAFS-ICAO - kpds(5).eq.172) ipdstmpl(16)=0 ! for Mean Icing, CT, CAT - if (kpds(5).eq.169.or.kpds(5).eq.171.or. & ! statistical process WAFS-ICAO - kpds(5).eq.173) ipdstmpl(16)=2 ! for MAX Icing, CT, CAT - ipdstmpl(17)=3 ! Neighbor interpolation - ! Output values is set to nearest input values - ipdstmpl(18)=1 ! Number of data point (grid 45) - elseif (kpds(16).eq.0.or.kpds(16).eq.1.or.kpds(16).eq.10) then - ipdsnum=0 - ! get GRIB2 parameter category and number from GRIB1 - ! parameter number - if (ecmwf) then ! treat ecmwf data conversion seperately - call param_ecmwf_g1_to_g2(kpds(5),kpds(19),idum, & - ipdstmpl(1),ipdstmpl(2)) - else - call param_g1_to_g2(kpds(5),kpds(19),idum,ipdstmpl(1), & - ipdstmpl(2)) - endif - if (kpds(16).eq.1) then - ipdstmpl(3)=0 - else - ipdstmpl(3)=2 - endif - ipdstmpl(4)=0 - ipdstmpl(5)=kpds(2) - ipdstmpl(6)=0 - ipdstmpl(7)=0 - ipdstmpl(8)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(8)=13 - !if (kpds(16).eq.10) then - ! ipdstmpl(9)=(kpds(14)*256)+kpds(15) - !else - ipdstmpl(9)=kpds(14) - !endif - call cnvlevel(kpds(6),kpds(7),ipdstmpl) - if (kpds(2).eq.96 .AND. kpds(3).eq.45 .AND. & - kpds(16).eq.10) then - if (kpds(5).eq.174) ipdstmpl(10) = 10 - if (kpds(5).eq.179) ipdstmpl(10) = 11 - if (kpds(5).eq.180) ipdstmpl(10) = 12 - end if - elseif (kpds(16).ge.2.AND.kpds(16).le.5) then - ipdsnum=8 - ! get GRIB2 parameter category and number from GRIB1 - ! parameter number - if (ecmwf) then ! treat ecmwf data conversion seperately - call param_ecmwf_g1_to_g2(kpds(5),kpds(19),idum, & - ipdstmpl(1),ipdstmpl(2)) - else - call param_g1_to_g2(kpds(5),kpds(19),idum,ipdstmpl(1), & - ipdstmpl(2)) - endif - ipdstmpl(3)=2 - ipdstmpl(4)=0 - ipdstmpl(5)=kpds(2) - ipdstmpl(6)=0 - ipdstmpl(7)=0 - ipdstmpl(8)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(8)=13 - ipdstmpl(9)=kpds(14) - call cnvlevel(kpds(6),kpds(7),ipdstmpl) - ! calculate ending time using initial ref-time, idat, - ! and increment rinc. - idat=0 - idat(1)=((kpds(21)-1)*100)+kpds(8) - idat(2)=kpds(9) - idat(3)=kpds(10) - idat(4)=-500 ! EST - idat(5)=kpds(11) - idat(6)=kpds(12) - rinc=0.0 - if ( ipdstmpl(8).eq.0 ) then - rinc(3)=kpds(15) - elseif ( ipdstmpl(8).eq.1 ) then - rinc(2)=kpds(15) - elseif ( ipdstmpl(8).eq.2 ) then - rinc(1)=kpds(15) - elseif ( ipdstmpl(8).eq.10 ) then - rinc(2)=kpds(15) * 3 - elseif ( ipdstmpl(8).eq.11 ) then - rinc(2)=kpds(15) * 6 - elseif ( ipdstmpl(8).eq.12 ) then - rinc(2)=kpds(15) * 12 - elseif ( ipdstmpl(8).eq.13 ) then - rinc(4)=kpds(15) - endif - call w3movdat(rinc,idat,jdat) ! calculate end date/time - ipdstmpl(16)=jdat(1) ! year of end time - ipdstmpl(17)=jdat(2) ! month of end time - ipdstmpl(18)=jdat(3) ! day of end time - ipdstmpl(19)=jdat(5) ! hour of end time - ipdstmpl(20)=jdat(6) ! minute of end time - ipdstmpl(21)=jdat(7) ! second of end time - ipdstmpl(22)=1 ! # of time ranges - ipdstmpl(23)=kpds(20) ! # of values missing - if (kpds(16).eq.2) then ! statistical process - ipdstmpl(24)=255 - elseif (kpds(16).eq.3) then - ipdstmpl(24)=0 - elseif (kpds(16).eq.4) then - ipdstmpl(24)=1 - elseif (kpds(16).eq.5) then - ipdstmpl(24)=4 - endif - ipdstmpl(25)=2 - if (kpds(19).eq.129 .AND. & - (kpds(5).eq.235 .or. kpds(5).eq.236 .or. & - kpds(5).eq.237 .or. kpds(5).eq.238 .or. & - kpds(5).eq.239 .or. kpds(5).eq.253 .or. & - kpds(5).eq.254 )) then - ipdstmpl(24)=2 - endif - ipdstmpl(26)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(26)=13 - ipdstmpl(27)=kpds(15)-kpds(14) - ipdstmpl(28)=255 - ipdstmpl(29)=0 - elseif (kpds(16).eq.7) then - ipdsnum=8 - ! get GRIB2 parameter category and number from GRIB1 - ! parameter number - if (ecmwf) then ! treat ecmwf data conversion seperately - call param_ecmwf_g1_to_g2(kpds(5),kpds(19),idum, & - ipdstmpl(1),ipdstmpl(2)) - else - call param_g1_to_g2(kpds(5),kpds(19),idum,ipdstmpl(1), & - ipdstmpl(2)) - endif - ipdstmpl(3)=2 - ipdstmpl(4)=0 - ipdstmpl(5)=kpds(2) - ipdstmpl(6)=0 - ipdstmpl(7)=0 - ipdstmpl(8)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(8)=13 - ipdstmpl(9)= - kpds(14) - call cnvlevel(kpds(6),kpds(7),ipdstmpl) - ! calculate ending time using initial ref-time, idat, - ! and increment rinc. - idat=0 - idat(1)=((kpds(21)-1)*100)+kpds(8) - idat(2)=kpds(9) - idat(3)=kpds(10) - idat(4)=-500 ! EST - idat(5)=kpds(11) - idat(6)=kpds(12) - rinc=0.0 - if ( ipdstmpl(8).eq.0 ) then - rinc(3)=kpds(15) - elseif ( ipdstmpl(8).eq.1 ) then - rinc(2)=kpds(15) - elseif ( ipdstmpl(8).eq.2 ) then - rinc(1)=kpds(15) - elseif ( ipdstmpl(8).eq.10 ) then - rinc(2)=kpds(15) * 3 - elseif ( ipdstmpl(8).eq.11 ) then - rinc(2)=kpds(15) * 6 - elseif ( ipdstmpl(8).eq.12 ) then - rinc(2)=kpds(15) * 12 - elseif ( ipdstmpl(8).eq.13 ) then - rinc(4)=kpds(15) - endif - call w3movdat(rinc,idat,jdat) ! calculate end date/time - ipdstmpl(16)=jdat(1) ! year of end time - ipdstmpl(17)=jdat(2) ! month of end time - ipdstmpl(18)=jdat(3) ! day of end time - ipdstmpl(19)=jdat(5) ! hour of end time - ipdstmpl(20)=jdat(6) ! minute of end time - ipdstmpl(21)=jdat(7) ! second of end time - ipdstmpl(22)=1 ! # of time ranges - ipdstmpl(23)=kpds(20) ! # of values missing - ipdstmpl(24)=0 - ipdstmpl(25)=2 - ipdstmpl(26)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(26)=13 - ipdstmpl(27)=kpds(15) + kpds(14) - ipdstmpl(28)=255 - ipdstmpl(29)=0 - elseif (kpds(16).eq.51) then - ipdsnum=8 - ! get GRIB2 parameter category and number from GRIB1 - ! parameter number - if (ecmwf) then ! treat ecmwf data conversion seperately - call param_ecmwf_g1_to_g2(kpds(5),kpds(19),idum, & - ipdstmpl(1),ipdstmpl(2)) - else - call param_g1_to_g2(kpds(5),kpds(19),idum,ipdstmpl(1), & - ipdstmpl(2)) - endif - ipdstmpl(3)=2 - ipdstmpl(4)=0 - ipdstmpl(5)=kpds(2) - ipdstmpl(6)=0 - ipdstmpl(7)=0 - ipdstmpl(8)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(8)=13 - ipdstmpl(9)=kpds(14) - call cnvlevel(kpds(6),kpds(7),ipdstmpl) - ! calculate ending time using initial ref-time, idat, - ! and increment rinc. - idat=0 - idat(1)=((kpds(21)-1)*100)+kpds(8) - idat(2)=kpds(9) - idat(3)=kpds(10) - idat(4)=-500 ! EST - idat(5)=kpds(11) - idat(6)=kpds(12) - rinc=0.0 - if ( ipdstmpl(8).eq.0 ) then - rinc(3)=kpds(15) - elseif ( ipdstmpl(8).eq.1 ) then - rinc(2)=kpds(15) - elseif ( ipdstmpl(8).eq.2 ) then - rinc(1)=kpds(15) - elseif ( ipdstmpl(8).eq.10 ) then - rinc(2)=kpds(15) * 3 - elseif ( ipdstmpl(8).eq.11 ) then - rinc(2)=kpds(15) * 6 - elseif ( ipdstmpl(8).eq.12 ) then - rinc(2)=kpds(15) * 12 - elseif ( ipdstmpl(8).eq.13 ) then - rinc(4)=kpds(15) - endif - call w3movdat(rinc,idat,jdat) ! calculate end date/time - ipdstmpl(16)=jdat(1) ! year of end time - ipdstmpl(17)=jdat(2) ! month of end time - ipdstmpl(18)=jdat(3) ! day of end time - ipdstmpl(19)=jdat(5) ! hour of end time - ipdstmpl(20)=jdat(6) ! minute of end time - ipdstmpl(21)=jdat(7) ! second of end time - ipdstmpl(22)=1 ! # of time ranges - ipdstmpl(23)=kpds(20) ! # of values missing - ipdstmpl(24)=51 ! Climatological Mean - ipdstmpl(25)=2 - ipdstmpl(26)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(26)=13 - ipdstmpl(27)=kpds(15)-kpds(14) - ipdstmpl(28)=255 - ipdstmpl(29)=0 - else - Print *,' Unrecognized Time Range Indicator = ',kpds(16) - Print *,'pds2pdt: Couldn:t construct PDS Template ' - iret=1 - endif - - return -end subroutine pds2pdt - -!> This routine converts a GRIB1 Level type and Level value to GRIB2 -!> values and fills in the appropriate PDT values for the level/layer -!> information. -!> -!> ### Program History Log -!> Date | Programmer | Comments -!> -----|------------|--------- -!> 2003-06-12 | Gilbert | Initial. -!> 2011-01-13 | Boi Vuong | Added level/layer values from 235 to 239 -!> -!> @param[in] ltype GRIB1 level type (PDS octet 10) -!> @param[in] lval GRIB1 level/layer value(s) (PDS octets 11 and 12) -!> @param[out] ipdstmpl GRIB2 Product Definition Template values. -!> -!> @author Stephen Gilbert @date 2003-06-12 -subroutine cnvlevel(ltype,lval,ipdstmpl) - - integer,intent(in) :: ltype,lval - integer,intent(inout) :: ipdstmpl(*) - - ipdstmpl(10)=ltype - ipdstmpl(11)=0 - ipdstmpl(12)=0 - ipdstmpl(13)=255 - ipdstmpl(14)=0 - ipdstmpl(15)=0 - - if (ltype.eq.100) then - ipdstmpl(12)=lval*100 - elseif (ltype.eq.101) then - ipdstmpl(10)=100 - ipdstmpl(12)=(lval/256)*1000 - ipdstmpl(13)=100 - ipdstmpl(15)=mod(lval,256)*1000 - elseif (ltype.eq.102) then - ipdstmpl(10)=101 - elseif (ltype.eq.103) then - ipdstmpl(10)=102 - ipdstmpl(12)=lval - elseif (ltype.eq.104) then - ipdstmpl(10)=102 - ipdstmpl(12)=lval/256 - ipdstmpl(13)=102 - ipdstmpl(15)=mod(lval,256) - elseif (ltype.eq.105) then - ipdstmpl(10)=103 - ipdstmpl(12)=lval - elseif (ltype.eq.106) then - ipdstmpl(10)=103 - ipdstmpl(12)=(lval/256)*100 - ipdstmpl(13)=103 - ipdstmpl(15)=mod(lval,256)*100 - elseif (ltype.eq.107) then - ipdstmpl(10)=104 - ipdstmpl(11)=4 - ipdstmpl(12)=lval - elseif (ltype.eq.108) then - ipdstmpl(10)=104 - ipdstmpl(11)=2 - ipdstmpl(12)=lval/256 - ipdstmpl(13)=104 - ipdstmpl(14)=2 - ipdstmpl(15)=mod(lval,256) - elseif (ltype.eq.109) then - ipdstmpl(10)=105 - ipdstmpl(12)=lval - elseif (ltype.eq.110) then - ipdstmpl(10)=105 - ipdstmpl(12)=lval/256 - ipdstmpl(13)=105 - ipdstmpl(15)=mod(lval,256) - elseif (ltype.eq.111) then - ipdstmpl(10)=106 - ipdstmpl(11)=2 - ipdstmpl(12)=lval - elseif (ltype.eq.112) then - ipdstmpl(10)=106 - ipdstmpl(11)=2 - ipdstmpl(12)=lval/256 - ipdstmpl(13)=106 - ipdstmpl(14)=2 - ipdstmpl(15)=mod(lval,256) - elseif (ltype.eq.113) then - ipdstmpl(10)=107 - ipdstmpl(12)=lval - elseif (ltype.eq.114) then - ipdstmpl(10)=107 - ipdstmpl(12)=475+(lval/256) - ipdstmpl(13)=107 - ipdstmpl(15)=475+mod(lval,256) - elseif (ltype.eq.115) then - ipdstmpl(10)=108 - ipdstmpl(12)=lval*100 - elseif (ltype.eq.116) then - ipdstmpl(10)=108 - ipdstmpl(12)=(lval/256)*100 - ipdstmpl(13)=108 - ipdstmpl(15)=mod(lval,256)*100 - elseif (ltype.eq.117) then - ipdstmpl(10)=109 - ipdstmpl(11)=9 - ipdstmpl(12)=lval - if ( btest(lval,15) ) then - ipdstmpl(12)=-1*mod(lval,32768) - endif - elseif (ltype.eq.119) then - ipdstmpl(10)=111 - ipdstmpl(11)=4 - ipdstmpl(12)=lval - elseif (ltype.eq.120) then - ipdstmpl(10)=111 - ipdstmpl(11)=2 - ipdstmpl(12)=lval/256 - ipdstmpl(13)=111 - ipdstmpl(14)=2 - ipdstmpl(15)=mod(lval,256) - elseif (ltype.eq.121) then - ipdstmpl(10)=100 - ipdstmpl(12)=(1100+(lval/256))*100 - ipdstmpl(13)=100 - ipdstmpl(15)=(1100+mod(lval,256))*100 - elseif (ltype.eq.125) then - ipdstmpl(10)=103 - ipdstmpl(11)=2 - ipdstmpl(12)=lval - elseif (ltype.eq.126) then - ipdstmpl(10)=100 - ipdstmpl(12)=lval - elseif (ltype.eq.128) then - ipdstmpl(10)=104 - ipdstmpl(11)=3 - ipdstmpl(12)=1100+(lval/256) - ipdstmpl(13)=104 - ipdstmpl(14)=3 - ipdstmpl(15)=1100+mod(lval,256) - elseif (ltype.eq.141) then - ipdstmpl(10)=100 - ipdstmpl(12)=(lval/256)*100 - ipdstmpl(13)=100 - ipdstmpl(15)=(1100+mod(lval,256))*100 - elseif (ltype.eq.160) then - ipdstmpl(10)=160 - ipdstmpl(12)=lval - elseif (ltype.gt.99.AND.ltype.lt.200) then - print *,'cnvlevel: GRIB1 Level ',ltype,' not recognized.' - ipdstmpl(10)=255 - elseif (ltype.eq.235) then - ipdstmpl(10)=ltype - ipdstmpl(12)=lval - elseif (ltype.eq.236) then - ipdstmpl(10)=ltype - ipdstmpl(12)=lval/256 - ipdstmpl(13)=ltype - ipdstmpl(15)=mod(lval,256) - elseif (ltype.ge.237.AND.ltype.le.239) then - ipdstmpl(10)=ltype - ipdstmpl(12)=lval - endif - - return -end subroutine cnvlevel diff --git a/utils/pds2pdtens.F90 b/utils/pds2pdtens.F90 deleted file mode 100644 index a7df0a770..000000000 --- a/utils/pds2pdtens.F90 +++ /dev/null @@ -1,640 +0,0 @@ -!> @file -!> @brief Convert a GRIB1 PDS (Section 1) that includes NCEP -!> ensemble PDS extensions to a GRIB2 PDS (Section 4) info. -!> @author Stephen Gilbert @date 2003-06-12 - -!> This routine converts a GRIB1 PDS (Section 1) that includes NCEP -!> ensemble PDS extensions to a GRIB2 PDS (Section 4) info with -!> appropriate Product Definition Template. -!> -!> @note Use routine pds2pdt for non ensemble related PDS. -!> -!> ### Program History Log -!> Date | Programmer | Comments -!> -----|------------|--------- -!> 2003-06-12 | Gilbert | Initial. -!> 2007-02-07 | Gilbert | fixed end date calculation -!> 2007-05-14 | Boi Vuong | Added Time Range Indicator 51 (Climatological Mean Value) -!> -!> @param[in] kpds GRIB1 PDS info as specified in W3FI63. -!> @param[in] kens Ensemble identification from PDS octets 41-45. -!> @param[in] kprob Ensemble probability info from PDS octets 46 & 47. -!> @param[in] xprob Ensemble probability info from PDS octets 48-55. -!> @param[in] kclust Ensemble cluster info from PDS octets 61-76. -!> @param[in] kmember- semble membership info from PDS octest 77-86. -!> @param[out] ipdsnum GRIB2 Product Definition Template Number. -!> @param[out] ipdstmpl GRIB2 Product Definition Template entries for PDT 4.ipdsnum. -!> @param[out] numcoord number of vertical discretisation values (not implemented). -!> @param[out] coordlist- rtical discretisation values (not implemented). -!> @param[out] iret Error return value: -!> - 0 = Successful -!> - 1 = Unrecognized GRIB1 Time Range Indicator for ensembles -!> - 2 = Unrecognized GRIB1 Ensemble type -!> - 10 = Unrecognized GRIB1 Time Range Indicator for probabilities -!> -!> @author Stephen Gilbert @date 2003-06-12 -subroutine pds2pdtens(kpds,kens,kprob,xprob,kclust,kmember, & - ipdsnum,ipdstmpl,numcoord,coordlist, & - iret) - - - use params - - integer,intent(in) :: kpds(*),kens(*),kprob(*),kclust(*) - integer,intent(in) :: kmember(*) - real,intent(in) :: xprob(*) - integer,intent(out) :: ipdstmpl(*) - real,intent(out) :: coordlist(*) - integer,intent(out) :: ipdsnum,numcoord,iret - - integer :: idat(8),jdat(8) - real :: rinc(5) - - iret=0 - numcoord=0 - if (kens(2).eq.1.or.kens(2).eq.2.or.kens(2).eq.3) then - ! individual ensemble fcst... - if (kpds(16).eq.0.or.kpds(16).eq.1.or.kpds(16).eq.10) then - ! At specific point in time... - ipdsnum=1 - ! get GRIB2 parameter category and number from GRIB1 - ! parameter number - call param_g1_to_g2(kpds(5),kpds(19),idum,ipdstmpl(1), & - ipdstmpl(2)) - ipdstmpl(3)=4 - ipdstmpl(4)=0 - ipdstmpl(5)=kpds(2) - ipdstmpl(6)=0 - ipdstmpl(7)=0 - ipdstmpl(8)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(8)=13 - !if (kpds(16).eq.10) then - ! ipdstmpl(9)=(kpds(14)*256)+kpds(15) - !else - ipdstmpl(9)=kpds(14) - !endif - call cnvlevel(kpds(6),kpds(7),ipdstmpl) - if (kens(2).eq.1) then - ! if (kens(3).eq.1) ipdstmpl(16)=0 - ! if (kens(3).eq.2) ipdstmpl(16)=1 - ipdstmpl(16)=kens(3)-1 - ipdstmpl(17)=0 - elseif (kens(2).eq.2) then - ipdstmpl(16)=2 - ipdstmpl(17)=kens(3) - elseif (kens(2).eq.3) then - ipdstmpl(16)=3 - ipdstmpl(17)=kens(3) - endif - ipdstmpl(18)=10 - elseif (kpds(16).ge.2.AND.kpds(16).le.5) then - ! over time range... - ipdsnum=11 - ! get GRIB2 parameter category and number from GRIB1 - ! parameter number - call param_g1_to_g2(kpds(5),kpds(19),idum,ipdstmpl(1), & - ipdstmpl(2)) - ipdstmpl(3)=4 - ipdstmpl(4)=0 - ipdstmpl(5)=kpds(2) - ipdstmpl(6)=0 - ipdstmpl(7)=0 - ipdstmpl(8)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(8)=13 - ipdstmpl(9)=kpds(14) - call cnvlevel(kpds(6),kpds(7),ipdstmpl) - !ipdstmpl(9)=kpds(15) - if (kens(2).eq.1) then - ! if (kens(3).eq.1) ipdstmpl(16)=0 - ! if (kens(3).eq.2) ipdstmpl(16)=1 - ipdstmpl(16)=kens(3)-1 - ipdstmpl(17)=0 - elseif (kens(2).eq.2) then - ipdstmpl(16)=2 - ipdstmpl(17)=kens(3) - elseif (kens(2).eq.3) then - ipdstmpl(16)=3 - ipdstmpl(17)=kens(3) - endif - ipdstmpl(18)=10 - ! calculate ending time using initial ref-time, idat, - ! and increment rinc. - idat=0 - idat(1)=((kpds(21)-1)*100)+kpds(8) - idat(2)=kpds(9) - idat(3)=kpds(10) - idat(4)=-500 ! EST - idat(5)=kpds(11) - idat(6)=kpds(12) - rinc=0 - if ( ipdstmpl(8).eq.0 ) then - rinc(3)=kpds(15) - elseif ( ipdstmpl(8).eq.1 ) then - rinc(2)=kpds(15) - elseif ( ipdstmpl(8).eq.2 ) then - rinc(1)=kpds(15) - elseif ( ipdstmpl(8).eq.10 ) then - rinc(2)=kpds(15) * 3 - elseif ( ipdstmpl(8).eq.11 ) then - rinc(2)=kpds(15) * 6 - elseif ( ipdstmpl(8).eq.12 ) then - rinc(2)=kpds(15) * 12 - elseif ( ipdstmpl(8).eq.13 ) then - rinc(4)=kpds(15) - endif - call w3movdat(rinc,idat,jdat) ! calculate end date/time - ipdstmpl(19)=jdat(1) ! year of end time - ipdstmpl(20)=jdat(2) ! month of end time - ipdstmpl(21)=jdat(3) ! day of end time - ipdstmpl(22)=jdat(5) ! hour of end time - ipdstmpl(23)=jdat(6) ! minute of end time - ipdstmpl(24)=jdat(7) ! second of end time - ipdstmpl(25)=1 - ipdstmpl(26)=0 - if (kpds(16).eq.2) then - ipdstmpl(27)=255 - if (kpds(5).eq.15) ipdstmpl(27)=2 - if (kpds(5).eq.16) ipdstmpl(27)=3 - elseif (kpds(16).eq.3) then - ipdstmpl(27)=0 - elseif (kpds(16).eq.4) then - ipdstmpl(27)=1 - elseif (kpds(16).eq.5) then - ipdstmpl(27)=4 - endif - ipdstmpl(28)=2 - ipdstmpl(29)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(29)=13 - ipdstmpl(30)=kpds(15)-kpds(14) - ipdstmpl(31)=255 - ipdstmpl(32)=0 - elseif (kpds(16).eq.51) then - ! over time range... - ipdsnum=11 - ! get GRIB2 parameter category and number from GRIB1 - ! parameter number - call param_g1_to_g2(kpds(5),kpds(19),idum,ipdstmpl(1), & - ipdstmpl(2)) - ipdstmpl(3)=4 - ipdstmpl(4)=0 - ipdstmpl(5)=kpds(2) - ipdstmpl(6)=0 - ipdstmpl(7)=0 - ipdstmpl(8)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(8)=13 - ipdstmpl(9)=kpds(14) - call cnvlevel(kpds(6),kpds(7),ipdstmpl) - !ipdstmpl(9)=kpds(15) - if (kens(2).eq.1) then - ! if (kens(3).eq.1) ipdstmpl(16)=0 - ! if (kens(3).eq.2) ipdstmpl(16)=1 - ipdstmpl(16)=kens(3)-1 - ipdstmpl(17)=0 - elseif (kens(2).eq.2) then - ipdstmpl(16)=2 - ipdstmpl(17)=kens(3) - elseif (kens(2).eq.3) then - ipdstmpl(16)=3 - ipdstmpl(17)=kens(3) - endif - ipdstmpl(18)=10 - ! calculate ending time using initial ref-time, idat, - ! and increment rinc. - idat=0 - idat(1)=((kpds(21)-1)*100)+kpds(8) - idat(2)=kpds(9) - idat(3)=kpds(10) - idat(4)=-500 ! EST - idat(5)=kpds(11) - idat(6)=kpds(12) - rinc=0 - if ( ipdstmpl(8).eq.0 ) then - rinc(3)=kpds(15) - elseif ( ipdstmpl(8).eq.1 ) then - rinc(2)=kpds(15) - elseif ( ipdstmpl(8).eq.2 ) then - rinc(1)=kpds(15) - elseif ( ipdstmpl(8).eq.10 ) then - rinc(2)=kpds(15) * 3 - elseif ( ipdstmpl(8).eq.11 ) then - rinc(2)=kpds(15) * 6 - elseif ( ipdstmpl(8).eq.12 ) then - rinc(2)=kpds(15) * 12 - elseif ( ipdstmpl(8).eq.13 ) then - rinc(4)=kpds(15) - endif - call w3movdat(rinc,idat,jdat) ! calculate end date/time - ipdstmpl(19)=jdat(1) ! year of end time - ipdstmpl(20)=jdat(2) ! month of end time - ipdstmpl(21)=jdat(3) ! day of end time - ipdstmpl(22)=jdat(5) ! hour of end time - ipdstmpl(23)=jdat(6) ! minute of end time - ipdstmpl(24)=jdat(7) ! second of end time - ipdstmpl(25)=1 - ipdstmpl(26)=0 - ipdstmpl(27)=51 - ipdstmpl(28)=2 - ipdstmpl(29)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(29)=13 - ipdstmpl(30)=kpds(15)-kpds(14) - ipdstmpl(31)=255 - ipdstmpl(32)=0 - else - Print *,' Unrecognized Time Range Ind for ensembles = ', & - kpds(16),kens(2) - Print *,'pds2pdtens: Couldn:t construct PDS Template ' - iret=1 - endif - - elseif (kens(2).eq.5) then ! WHOLE or CLUSTERENSEMBLE type - if (kpds(5).eq.191.OR.kpds(5).eq.192) then ! probs - if (kpds(16).eq.0.or.kpds(16).eq.1.or.kpds(16).eq.10) then - ! At specific point in time... - ipdsnum=5 - ! get GRIB2 parameter category and number from GRIB1 - ! parameter number - call param_g1_to_g2(kprob(1),kpds(19),idum,ipdstmpl(1), & - ipdstmpl(2)) - ipdstmpl(3)=5 - ipdstmpl(4)=0 - ipdstmpl(5)=kpds(2) - ipdstmpl(6)=0 - ipdstmpl(7)=0 - ipdstmpl(8)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(8)=13 - !if (kpds(16).eq.10) then - ! ipdstmpl(9)=(kpds(14)*256)+kpds(15) - !else - ipdstmpl(9)=kpds(14) - !endif - call cnvlevel(kpds(6),kpds(7),ipdstmpl) - ipdstmpl(16)=0 !? - ipdstmpl(17)=kclust(1) !? - ipdstmpl(18)=kprob(2)-1 - if (ipdstmpl(18).eq.0.OR.ipdstmpl(18).eq.2) then - ipdstmpl(19)=3 - ipdstmpl(20)=nint(xprob(1)*1000.0) - else - ipdstmpl(19)=0 - ipdstmpl(20)=0 - endif - if (ipdstmpl(18).eq.1.OR.ipdstmpl(18).eq.2) then - ipdstmpl(21)=3 - ipdstmpl(22)=nint(xprob(2)*1000.0) - else - ipdstmpl(21)=0 - ipdstmpl(22)=0 - endif - elseif (kpds(16).ge.2.AND.kpds(16).le.5) then - ! over time range... - ipdsnum=9 - ! get GRIB2 parameter category and number from GRIB1 - ! parameter number - call param_g1_to_g2(kprob(1),kpds(19),idum,ipdstmpl(1), & - ipdstmpl(2)) - ipdstmpl(3)=5 - ipdstmpl(4)=0 - ipdstmpl(5)=kpds(2) - ipdstmpl(6)=0 - ipdstmpl(7)=0 - ipdstmpl(8)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(8)=13 - ipdstmpl(9)=kpds(14) - call cnvlevel(kpds(6),kpds(7),ipdstmpl) - !ipdstmpl(9)=kpds(15) - ipdstmpl(16)=0 !? - ipdstmpl(17)=kclust(1) !? - ipdstmpl(18)=kprob(2)-1 - if (ipdstmpl(18).eq.0.OR.ipdstmpl(18).eq.2) then - ipdstmpl(19)=3 - ipdstmpl(20)=nint(xprob(1)*1000.0) - else - ipdstmpl(19)=0 - ipdstmpl(20)=0 - endif - if (ipdstmpl(18).eq.1.OR.ipdstmpl(18).eq.2) then - ipdstmpl(21)=3 - ipdstmpl(22)=nint(xprob(2)*1000.0) - else - ipdstmpl(21)=0 - ipdstmpl(22)=0 - endif - ! calculate ending time using initial ref-time, idat, - ! and increment rinc. - idat=0 - idat(1)=((kpds(21)-1)*100)+kpds(8) - idat(2)=kpds(9) - idat(3)=kpds(10) - idat(4)=-500 ! EST - idat(5)=kpds(11) - idat(6)=kpds(12) - rinc=0 - if ( ipdstmpl(8).eq.0 ) then - rinc(3)=kpds(15) - elseif ( ipdstmpl(8).eq.1 ) then - rinc(2)=kpds(15) - elseif ( ipdstmpl(8).eq.2 ) then - rinc(1)=kpds(15) - elseif ( ipdstmpl(8).eq.10 ) then - rinc(2)=kpds(15) * 3 - elseif ( ipdstmpl(8).eq.11 ) then - rinc(2)=kpds(15) * 6 - elseif ( ipdstmpl(8).eq.12 ) then - rinc(2)=kpds(15) * 12 - elseif ( ipdstmpl(8).eq.13 ) then - rinc(4)=kpds(15) - endif - call w3movdat(rinc,idat,jdat) ! calculate end date/time - ipdstmpl(23)=jdat(1) ! year of end time - ipdstmpl(24)=jdat(2) ! month of end time - ipdstmpl(25)=jdat(3) ! day of end time - ipdstmpl(26)=jdat(5) ! hour of end time - ipdstmpl(27)=jdat(6) ! minute of end time - ipdstmpl(28)=jdat(7) ! second of end time - ipdstmpl(29)=1 - ipdstmpl(30)=0 - if (kpds(16).eq.2) then - ipdstmpl(31)=255 - if (kpds(5).eq.15) ipdstmpl(31)=2 - if (kpds(5).eq.16) ipdstmpl(31)=3 - elseif (kpds(16).eq.3) then - ipdstmpl(31)=0 - elseif (kpds(16).eq.4) then - ipdstmpl(31)=1 - elseif (kpds(16).eq.5) then - ipdstmpl(31)=4 - endif - ipdstmpl(32)=2 - ipdstmpl(33)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(33)=13 - ipdstmpl(34)=kpds(15)-kpds(14) - ipdstmpl(35)=255 - ipdstmpl(36)=0 - elseif (kpds(16).eq.51) then - ! over time range... - ipdsnum=9 - ! get GRIB2 parameter category and number from GRIB1 - ! parameter number - call param_g1_to_g2(kprob(1),kpds(19),idum,ipdstmpl(1), & - ipdstmpl(2)) - ipdstmpl(3)=5 - ipdstmpl(4)=0 - ipdstmpl(5)=kpds(2) - ipdstmpl(6)=0 - ipdstmpl(7)=0 - ipdstmpl(8)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(8)=13 - ipdstmpl(9)=kpds(14) - call cnvlevel(kpds(6),kpds(7),ipdstmpl) - !ipdstmpl(9)=kpds(15) - ipdstmpl(16)=0 !? - ipdstmpl(17)=kclust(1) !? - ipdstmpl(18)=kprob(2)-1 - if (ipdstmpl(18).eq.0.OR.ipdstmpl(18).eq.2) then - ipdstmpl(19)=3 - ipdstmpl(20)=nint(xprob(1)*1000.0) - else - ipdstmpl(19)=0 - ipdstmpl(20)=0 - endif - if (ipdstmpl(18).eq.1.OR.ipdstmpl(18).eq.2) then - ipdstmpl(21)=3 - ipdstmpl(22)=nint(xprob(2)*1000.0) - else - ipdstmpl(21)=0 - ipdstmpl(22)=0 - endif - ! calculate ending time using initial ref-time, idat, - ! and increment rinc. - idat=0 - idat(1)=((kpds(21)-1)*100)+kpds(8) - idat(2)=kpds(9) - idat(3)=kpds(10) - idat(4)=-500 ! EST - idat(5)=kpds(11) - idat(6)=kpds(12) - rinc=0 - if ( ipdstmpl(8).eq.0 ) then - rinc(3)=kpds(15) - elseif ( ipdstmpl(8).eq.1 ) then - rinc(2)=kpds(15) - elseif ( ipdstmpl(8).eq.2 ) then - rinc(1)=kpds(15) - elseif ( ipdstmpl(8).eq.10 ) then - rinc(2)=kpds(15) * 3 - elseif ( ipdstmpl(8).eq.11 ) then - rinc(2)=kpds(15) * 6 - elseif ( ipdstmpl(8).eq.12 ) then - rinc(2)=kpds(15) * 12 - elseif ( ipdstmpl(8).eq.13 ) then - rinc(4)=kpds(15) - endif - call w3movdat(rinc,idat,jdat) ! calculate end date/time - ipdstmpl(23)=jdat(1) ! year of end time - ipdstmpl(24)=jdat(2) ! month of end time - ipdstmpl(25)=jdat(3) ! day of end time - ipdstmpl(26)=jdat(5) ! hour of end time - ipdstmpl(27)=jdat(6) ! minute of end time - ipdstmpl(28)=jdat(7) ! second of end time - ipdstmpl(29)=1 - ipdstmpl(30)=0 - ipdstmpl(31)=51 - ipdstmpl(32)=2 - ipdstmpl(33)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(33)=13 - ipdstmpl(34)=kpds(15)-kpds(14) - ipdstmpl(35)=255 - ipdstmpl(36)=0 - else - Print *,' Unrecognized Time Range Ind for Probs = ', & - kpds(16),kens(2) - Print *,'pds2pdtens: Couldn:t construct PDS Template ' - iret=10 - endif - else ! Non-probablility Whole Ens Fcst - if (kpds(16).eq.0.or.kpds(16).eq.1.or.kpds(16).eq.10) then - ! At specific point in time... - ipdsnum=2 - ! get GRIB2 parameter category and number from GRIB1 - ! parameter number - call param_g1_to_g2(kpds(5),kpds(19),idum,ipdstmpl(1), & - ipdstmpl(2)) - ipdstmpl(3)=4 - ipdstmpl(4)=0 - ipdstmpl(5)=kpds(2) - ipdstmpl(6)=0 - ipdstmpl(7)=0 - ipdstmpl(8)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(8)=13 - !if (kpds(16).eq.10) then - ! ipdstmpl(9)=(kpds(14)*256)+kpds(15) - !else - ipdstmpl(9)=kpds(14) - !endif - call cnvlevel(kpds(6),kpds(7),ipdstmpl) - if (kens(4).eq.1) then - ipdstmpl(16)=0 - elseif (kens(4).eq.2) then - ipdstmpl(16)=1 - elseif (kens(4).eq.11) then - ipdstmpl(16)=2 - elseif (kens(4).eq.12) then - ipdstmpl(16)=3 - endif - ipdstmpl(17)=kclust(1) - elseif (kpds(16).ge.2.AND.kpds(16).le.5) then - ! over time range... - ipdsnum=12 - ! get GRIB2 parameter category and number from GRIB1 - ! parameter number - call param_g1_to_g2(kpds(5),kpds(19),idum,ipdstmpl(1), & - ipdstmpl(2)) - ipdstmpl(3)=4 - ipdstmpl(4)=0 - ipdstmpl(5)=kpds(2) - ipdstmpl(6)=0 - ipdstmpl(7)=0 - ipdstmpl(8)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(8)=13 - ipdstmpl(9)=kpds(14) - call cnvlevel(kpds(6),kpds(7),ipdstmpl) - !ipdstmpl(9)=kpds(15) - if (kens(4).eq.1) then - ipdstmpl(16)=0 - elseif (kens(4).eq.2) then - ipdstmpl(16)=1 - elseif (kens(4).eq.11) then - ipdstmpl(16)=2 - elseif (kens(4).eq.12) then - ipdstmpl(16)=3 - endif - ipdstmpl(17)=kclust(1) - ! calculate ending time using initial ref-time, idat, - ! and increment rinc. - idat=0 - idat(1)=((kpds(21)-1)*100)+kpds(8) - idat(2)=kpds(9) - idat(3)=kpds(10) - idat(4)=-500 ! EST - idat(5)=kpds(11) - idat(6)=kpds(12) - rinc=0 - if ( ipdstmpl(8).eq.0 ) then - rinc(3)=kpds(15) - elseif ( ipdstmpl(8).eq.1 ) then - rinc(2)=kpds(15) - elseif ( ipdstmpl(8).eq.2 ) then - rinc(1)=kpds(15) - elseif ( ipdstmpl(8).eq.10 ) then - rinc(2)=kpds(15) * 3 - elseif ( ipdstmpl(8).eq.11 ) then - rinc(2)=kpds(15) * 6 - elseif ( ipdstmpl(8).eq.12 ) then - rinc(2)=kpds(15) * 12 - elseif ( ipdstmpl(8).eq.13 ) then - rinc(4)=kpds(15) - endif - call w3movdat(rinc,idat,jdat) ! calculate end date/time - ipdstmpl(18)=jdat(1) ! year of end time - ipdstmpl(19)=jdat(2) ! month of end time - ipdstmpl(20)=jdat(3) ! day of end time - ipdstmpl(21)=jdat(5) ! hour of end time - ipdstmpl(22)=jdat(6) ! minute of end time - ipdstmpl(23)=jdat(7) ! second of end time - ipdstmpl(24)=1 - ipdstmpl(25)=0 - if (kpds(16).eq.2) then - ipdstmpl(26)=255 - if (kpds(5).eq.15) ipdstmpl(26)=2 - if (kpds(5).eq.16) ipdstmpl(26)=3 - elseif (kpds(16).eq.3) then - ipdstmpl(26)=0 - elseif (kpds(16).eq.4) then - ipdstmpl(26)=1 - elseif (kpds(16).eq.5) then - ipdstmpl(26)=4 - endif - ipdstmpl(27)=2 - ipdstmpl(28)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(28)=13 - ipdstmpl(29)=kpds(15)-kpds(14) - ipdstmpl(30)=255 - ipdstmpl(31)=0 - elseif (kpds(16).eq.51) then - ! over time range... - ipdsnum=12 - ! get GRIB2 parameter category and number from GRIB1 - ! parameter number - call param_g1_to_g2(kpds(5),kpds(19),idum,ipdstmpl(1), & - ipdstmpl(2)) - ipdstmpl(3)=4 - ipdstmpl(4)=0 - ipdstmpl(5)=kpds(2) - ipdstmpl(6)=0 - ipdstmpl(7)=0 - ipdstmpl(8)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(8)=13 - ipdstmpl(9)=kpds(14) - call cnvlevel(kpds(6),kpds(7),ipdstmpl) - !ipdstmpl(9)=kpds(15) - if (kens(4).eq.1) then - ipdstmpl(16)=0 - elseif (kens(4).eq.2) then - ipdstmpl(16)=1 - elseif (kens(4).eq.11) then - ipdstmpl(16)=2 - elseif (kens(4).eq.12) then - ipdstmpl(16)=3 - endif - ipdstmpl(17)=kclust(1) - ! calculate ending time using initial ref-time, idat, - ! and increment rinc. - idat=0 - idat(1)=((kpds(21)-1)*100)+kpds(8) - idat(2)=kpds(9) - idat(3)=kpds(10) - idat(4)=-500 ! EST - idat(5)=kpds(11) - idat(6)=kpds(12) - rinc=0 - if ( ipdstmpl(8).eq.0 ) then - rinc(3)=kpds(15) - elseif ( ipdstmpl(8).eq.1 ) then - rinc(2)=kpds(15) - elseif ( ipdstmpl(8).eq.2 ) then - rinc(1)=kpds(15) - elseif ( ipdstmpl(8).eq.10 ) then - rinc(2)=kpds(15) * 3 - elseif ( ipdstmpl(8).eq.11 ) then - rinc(2)=kpds(15) * 6 - elseif ( ipdstmpl(8).eq.12 ) then - rinc(2)=kpds(15) * 12 - elseif ( ipdstmpl(8).eq.13 ) then - rinc(4)=kpds(15) - endif - call w3movdat(rinc,idat,jdat) ! calculate end date/time - ipdstmpl(18)=jdat(1) ! year of end time - ipdstmpl(19)=jdat(2) ! month of end time - ipdstmpl(20)=jdat(3) ! day of end time - ipdstmpl(21)=jdat(5) ! hour of end time - ipdstmpl(22)=jdat(6) ! minute of end time - ipdstmpl(23)=jdat(7) ! second of end time - ipdstmpl(24)=1 - ipdstmpl(25)=0 - ipdstmpl(26)=51 - ipdstmpl(27)=2 - ipdstmpl(28)=kpds(13) - if (kpds(13).eq.254) ipdstmpl(28)=13 - ipdstmpl(29)=kpds(15)-kpds(14) - ipdstmpl(30)=255 - ipdstmpl(31)=0 - endif - endif - else - Print *,' Unrecognized Ensemble type = ',kens(2) - Print *,'pds2pdtens: Couldn:t construct PDS Template ' - iret=2 - endif - - return -end subroutine pds2pdtens diff --git a/utils/prlevel.F90 b/utils/prgrib2.F90 similarity index 76% rename from utils/prlevel.F90 rename to utils/prgrib2.F90 index 86e5d4221..d5120aa60 100644 --- a/utils/prlevel.F90 +++ b/utils/prgrib2.F90 @@ -1,6 +1,5 @@ !> @file -!> @brief Print level information to a character array, given the -!> GRIB2 Product Definition Template information. +!> @brief Subroutines for converting GRIB2 info to string output. !> @author Stephen Gilbert @date 2010-09-08 !> Print level information to a character array, given the GRIB2 @@ -280,3 +279,147 @@ subroutine frmt(cval, ival, iscal) return end subroutine frmt + +!> Convert date and time from GRIB2 info to string output. +!> +!> @param[in] ipdtn Product Definition Template Number ([Code Table +!> 4.0] +!> (https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_table4-0.shtml)). +!> @param[in] ipdtmpl Array of data values for the Product Definition +!> Template specified by ipdtn. +!> @param[in] listsec1 Contains information read from GRIB +!> Identification Section 1. Must be dimensioned >= 13. +!> @param[out] tabbrev Character array that will get the date and time +!> string. Must be of length 100. +!> +!> @author Stephen Gilbert @date 2010-09-08 +subroutine prvtime(ipdtn, ipdtmpl, listsec1, tabbrev) + implicit none + + integer, intent(in) :: ipdtn + integer, intent(in) :: ipdtmpl(*), listsec1(*) + character(len = 110), intent(out) :: tabbrev + + character(len = 16) :: reftime, endtime + character(len = 12) :: tmpval2 + character(len = 12) :: tmpval + character(len = 10) :: tunit + integer, dimension(200) :: ipos, ipos2 + integer :: is, itemp, itemp2, iunit, iuni2t2, iunit2, iutpos, iutpos2, j + + data ipos /7*0, 16, 23, 17, 19, 18, 32, 31, 27*0, 17, 20, 0, 0, 22, & + 25, 43*0, 23, 109*0/ + + data ipos2 /7*0, 26, 33, 27, 29, 28, 42, 41, 27*0, 22, 30, 0, 0, 32, & + 35, 43*0, 33, 109*0/ + + tabbrev(1:100) = " " + + ! Determine unit of time range. + if ((ipdtn .ge. 0 .and. ipdtn .le. 15) .or. ipdtn .eq. 32 & + .or. ipdtn .eq. 50 .or. ipdtn .eq. 51 & + .or. ipdtn .eq. 91) then + iutpos = 8 + elseif (ipdtn .ge. 40 .and. ipdtn .le. 43) then + iutpos = 9 + elseif (ipdtn .ge. 44 .and. ipdtn .le. 47) then + iutpos = 14 + elseif (ipdtn .eq. 48) then + iutpos = 19 + elseif (ipdtn .eq. 52) then + iutpos = 11 + else + iutpos = 8 + endif + + ! Determine first unit of time range. + selectcase(ipdtmpl(iutpos)) + case (0) + tunit = "minute" + iunit = 1 + case (1) + tunit = "hour" + iunit = 1 + case (2) + tunit = "day" + iunit = 1 + case (3) + tunit = "month" + iunit = 1 + case (4) + tunit = "year" + iunit = 1 + case (10) + tunit = "hour" + iunit = 3 + case (11) + tunit = "hour" + iunit = 6 + case default + tunit = "hour" + iunit = 1 + end select + + ! Determine second unit of time range. + if (ipdtn .eq. 0) then + iunit2 = 1 + iutpos2 = 0 + else + iutpos2 = ipos2(ipdtn) + if (iutpos2 .gt. 0) then + selectcase(ipdtmpl(iutpos2)) + case (0) + iunit2 = 1 + case (1) + iunit2 = 1 + case (2) + iunit2 = 1 + case (3) + iuni2t2 = 1 + case (4) + iunit2 = 1 + case (10) + iunit2 = 3 + case (11) + iunit2 = 6 + case default + iunit2 = 1 + end select + endif + endif + + write(reftime, fmt = '(i4,3i2.2,":",i2.2,":",i2.2)') (listsec1(j), j = 6, 11) + itemp = abs(ipdtmpl(iutpos + 1)) * iunit + write(tmpval, '(I0)') itemp + write(tabbrev, fmt = '("valid at ", i4)') ipdtmpl(iutpos + 1) + + ! Determine Reference Time: Year, Month, Day, Hour, Minute, Second. + if ((ipdtn .ge. 0 .and. ipdtn .le. 7) .or. ipdtn .eq. 15 & + .or. ipdtn .eq. 20 .or. (ipdtn .ge. 30 .and. ipdtn .le. 32) & + .or. ipdtn .eq. 40 .or. ipdtn .eq. 41 .or. ipdtn .eq. 44 & + .or. ipdtn .eq. 45 .or. ipdtn .eq. 48 .or. & + (ipdtn .ge. 50 .and. ipdtn .le. 52)) then ! Point in time + tabbrev = "valid " // trim(tmpval) // " " // trim(tunit) // " after " // reftime + else + is = ipos(ipdtn) ! Continuous time interval + write(endtime, fmt = '(i4,3i2.2,":",i2.2,":",i2.2)') (ipdtmpl(j), j = is, is + 5) + itemp2 = abs(ipdtmpl(iutpos2 + 1)) * iunit2 + itemp2 = itemp + itemp2 + write(tmpval2, '(I0)') itemp2 + if (ipdtn .eq. 8 .and. ipdtmpl(9) .lt. 0) then + tabbrev = "(" // trim(tmpval) // " -" & + // trim(tmpval2) // ") valid " // trim(tmpval) // & + " " // trim(tunit) // " before " & + // reftime // " to " //endtime + elseif ((ipdtn .ge. 8 .and. ipdtn .le. 14) .or. & + (ipdtn .ge. 42 .and. ipdtn .le. 47) .or. & + ipdtn .eq. 91) then ! Continuous time interval + tabbrev = "(" // trim(tmpval) // " -" & + // trim(tmpval2) // " hr) valid " // trim(tmpval) // & + " " // trim(tunit) // " after " & + // reftime // " to " // endtime + endif + endif + + return +end subroutine prvtime \ No newline at end of file diff --git a/utils/prvtime.F90 b/utils/prvtime.F90 deleted file mode 100644 index 93e82e3cd..000000000 --- a/utils/prvtime.F90 +++ /dev/null @@ -1,147 +0,0 @@ -!> @file -!> @brief Convert date and time from GRIB2 info to string output. -!> @author Stephen Gilbert @date 2010-09-08 - -!> Convert date and time from GRIB2 info to string output. -!> -!> @param[in] ipdtn Product Definition Template Number ([Code Table -!> 4.0] -!> (https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_table4-0.shtml)). -!> @param[in] ipdtmpl Array of data values for the Product Definition -!> Template specified by ipdtn. -!> @param[in] listsec1 Contains information read from GRIB -!> Identification Section 1. Must be dimensioned >= 13. -!> @param[out] tabbrev Character array that will get the date and time -!> string. Must be of length 100. -!> -!> @author Stephen Gilbert @date 2010-09-08 -subroutine prvtime(ipdtn, ipdtmpl, listsec1, tabbrev) - implicit none - - integer, intent(in) :: ipdtn - integer, intent(in) :: ipdtmpl(*), listsec1(*) - character(len = 110), intent(out) :: tabbrev - - character(len = 16) :: reftime, endtime - character(len = 12) :: tmpval2 - character(len = 12) :: tmpval - character(len = 10) :: tunit - integer, dimension(200) :: ipos, ipos2 - integer :: is, itemp, itemp2, iunit, iuni2t2, iunit2, iutpos, iutpos2, j - - data ipos /7*0, 16, 23, 17, 19, 18, 32, 31, 27*0, 17, 20, 0, 0, 22, & - 25, 43*0, 23, 109*0/ - - data ipos2 /7*0, 26, 33, 27, 29, 28, 42, 41, 27*0, 22, 30, 0, 0, 32, & - 35, 43*0, 33, 109*0/ - - tabbrev(1:100) = " " - - ! Determine unit of time range. - if ((ipdtn .ge. 0 .and. ipdtn .le. 15) .or. ipdtn .eq. 32 & - .or. ipdtn .eq. 50 .or. ipdtn .eq. 51 & - .or. ipdtn .eq. 91) then - iutpos = 8 - elseif (ipdtn .ge. 40 .and. ipdtn .le. 43) then - iutpos = 9 - elseif (ipdtn .ge. 44 .and. ipdtn .le. 47) then - iutpos = 14 - elseif (ipdtn .eq. 48) then - iutpos = 19 - elseif (ipdtn .eq. 52) then - iutpos = 11 - else - iutpos = 8 - endif - - ! Determine first unit of time range. - selectcase(ipdtmpl(iutpos)) - case (0) - tunit = "minute" - iunit = 1 - case (1) - tunit = "hour" - iunit = 1 - case (2) - tunit = "day" - iunit = 1 - case (3) - tunit = "month" - iunit = 1 - case (4) - tunit = "year" - iunit = 1 - case (10) - tunit = "hour" - iunit = 3 - case (11) - tunit = "hour" - iunit = 6 - case default - tunit = "hour" - iunit = 1 - end select - - ! Determine second unit of time range. - if (ipdtn .eq. 0) then - iunit2 = 1 - iutpos2 = 0 - else - iutpos2 = ipos2(ipdtn) - if (iutpos2 .gt. 0) then - selectcase(ipdtmpl(iutpos2)) - case (0) - iunit2 = 1 - case (1) - iunit2 = 1 - case (2) - iunit2 = 1 - case (3) - iuni2t2 = 1 - case (4) - iunit2 = 1 - case (10) - iunit2 = 3 - case (11) - iunit2 = 6 - case default - iunit2 = 1 - end select - endif - endif - - write(reftime, fmt = '(i4,3i2.2,":",i2.2,":",i2.2)') (listsec1(j), j = 6, 11) - itemp = abs(ipdtmpl(iutpos + 1)) * iunit - write(tmpval, '(I0)') itemp - write(tabbrev, fmt = '("valid at ", i4)') ipdtmpl(iutpos + 1) - - ! Determine Reference Time: Year, Month, Day, Hour, Minute, Second. - if ((ipdtn .ge. 0 .and. ipdtn .le. 7) .or. ipdtn .eq. 15 & - .or. ipdtn .eq. 20 .or. (ipdtn .ge. 30 .and. ipdtn .le. 32) & - .or. ipdtn .eq. 40 .or. ipdtn .eq. 41 .or. ipdtn .eq. 44 & - .or. ipdtn .eq. 45 .or. ipdtn .eq. 48 .or. & - (ipdtn .ge. 50 .and. ipdtn .le. 52)) then ! Point in time - tabbrev = "valid " // trim(tmpval) // " " // trim(tunit) // " after " // reftime - else - is = ipos(ipdtn) ! Continuous time interval - write(endtime, fmt = '(i4,3i2.2,":",i2.2,":",i2.2)') (ipdtmpl(j), j = is, is + 5) - itemp2 = abs(ipdtmpl(iutpos2 + 1)) * iunit2 - itemp2 = itemp + itemp2 - write(tmpval2, '(I0)') itemp2 - if (ipdtn .eq. 8 .and. ipdtmpl(9) .lt. 0) then - tabbrev = "(" // trim(tmpval) // " -" & - // trim(tmpval2) // ") valid " // trim(tmpval) // & - " " // trim(tunit) // " before " & - // reftime // " to " //endtime - elseif ((ipdtn .ge. 8 .and. ipdtn .le. 14) .or. & - (ipdtn .ge. 42 .and. ipdtn .le. 47) .or. & - ipdtn .eq. 91) then ! Continuous time interval - tabbrev = "(" // trim(tmpval) // " -" & - // trim(tmpval2) // " hr) valid " // trim(tmpval) // & - " " // trim(tunit) // " after " & - // reftime // " to " // endtime - endif - endif - - return -end subroutine prvtime diff --git a/utils/putgbexn.F90 b/utils/putgbexn.F90 deleted file mode 100644 index fd04cb571..000000000 --- a/utils/putgbexn.F90 +++ /dev/null @@ -1,222 +0,0 @@ -!> @file -!> @brief Pack and write a grib message. -!> @author Mark Iredell @date 94-04-01 - -!> Pack and write a grib message. This subprogram is nearly the inverse -!> of getgbe. -!> -!> @note Subprogram can be called from a multiprocessing environment. -!> Do not engage the same logical unit from more than one processor. -!> -!> ### Program History Log -!> Date | Programmer | Comments -!> -----|------------|--------- -!> 94-04-01 | Iredell | Initial. -!> 95-10-31 | Iredell | Removed saves and prints -!> 97-02-11 | Y. Zhu | Included probability and cluster arguments -!> 2002-03-18 | Gilbert | Modified from putgbex to account for binary scale factors. -!> -!> @param[in] lugb teger unit of the unblocked grib data file -!> @param[in] kf teger number of data points -!> @param[in] kpds teger (200) pds parameters -!> - 1 id of center -!> - 2 generating process id number -!> - 3 grid definition -!> - 4 gds/bms flag (right adj copy of octet 8) -!> - 5 indicator of parameter -!> - 6 type of level -!> - 7 height/pressure , etc of level -!> - 8 year including (century-1) -!> - 9 month of year -!> - 10 day of month -!> - 11 hour of day -!> - 12 minute of hour -!> - 13 indicator of forecast time unit -!> - 14 time range 1 -!> - 15 time range 2 -!> - 16 time range flag -!> - 17 number included in average -!> - 18 version nr of grib specification -!> - 19 version nr of parameter table -!> - 20 nr missing from average/accumulation -!> - 21 century of reference time of data -!> - 22 units decimal scale factor -!> - 23 subcenter number -!> - 24 pds byte 29, for nmc ensemble products, 128 if forecast field -!> error, 64 if bias corrected fcst field, 32 if smoothed field, -!> warning: can be combination of more than 1. -!> - 25 pds byte 30, not used -!> @param[in] kgds teger (200) gds parameters -!> - 1 data representation type -!> - 19 number of vertical coordinate parameters -!> - 20 octet number of the list of vertical coordinate parameters or -!> octet number of the list of numbers of points in each row or 255 if -!> neither are present. -!> - 21 for grids with pl, number of points in grid -!> - 22 number of words in each row latitude/longitude grids -!> - 2 n(i) nr points on latitude circle -!> - 3 n(j) nr points on longitude meridian -!> - 4 la(1) latitude of origin -!> - 5 lo(1) longitude of origin -!> - 6 resolution flag (right adj copy of octet 17) -!> - 7 la(2) latitude of extreme point -!> - 8 lo(2) longitude of extreme point -!> - 9 di longitudinal direction of increment -!> - 10 dj latitudinal direction increment -!> - 11 scanning mode flag (right adj copy of octet 28) -!> Gaussian grids: -!> - 2 n(i) nr points on latitude circle -!> - 3 n(j) nr points on longitude meridian -!> - 4 la(1) latitude of origin -!> - 5 lo(1) longitude of origin -!> - 6 resolution flag (right adj copy of octet 17) -!> - 7 la(2) latitude of extreme point -!> - 8 lo(2) longitude of extreme point -!> - 9 di longitudinal direction of increment -!> - 10 n - nr of circles pole to equator -!> - 11 scanning mode flag (right adj copy of octet 28) -!> - 12 nv - nr of vert coord parameters -!> - 13 pv - octet nr of list of vert coord parameters or pl - location -!> of the list of numbers of points in each row (if no vert coord -!> parameters are present or 255 if neither are present -!> Polar Stereographic grids: -!> - 2 n(i) nr points along lat circle -!> - 3 n(j) nr points along lon circle -!> - 4 la(1) latitude of origin -!> - 5 lo(1) longitude of origin -!> - 6 resolution flag (right adj copy of octet 17) -!> - 7 lov grid orientation -!> - 8 dx - x direction increment -!> - 9 dy - y direction increment -!> - 10 projection center flag -!> - 11 scanning mode (right adj copy of octet 28) -!> Spherical Harmonic Coefficients: -!> - 2 j pentagonal resolution parameter -!> - 3 k pentagonal resolution parameter -!> - 4 m pentagonal resolution parameter -!> - 5 representation type -!> - 6 coefficient storage mode -!> Mercator grids: -!> - 2 n(i) nr points on latitude circle -!> - 3 n(j) nr points on longitude meridian -!> - 4 la(1) latitude of origin -!> - 5 lo(1) longitude of origin -!> - 6 resolution flag (right adj copy of octet 17) -!> - 7 la(2) latitude of last grid point -!> - 8 lo(2) longitude of last grid point -!> - 9 latit - latitude of projection intersection -!> - 10 reserved -!> - 11 scanning mode flag (right adj copy of octet 28) -!> - 12 longitudinal dir grid length -!> - 13 latitudinal dir grid length -!> Lambert Conformal Grids: -!> - 2 nx nr points along x-axis -!> - 3 ny nr points along y-axis -!> - 4 la1 lat of origin (lower left) -!> - 5 lo1 lon of origin (lower left) -!> - 6 resolution (right adj copy of octet 17) -!> - 7 lov - orientation of grid -!> - 8 dx - x-dir increment -!> - 9 dy - y-dir increment -!> - 10 projection center flag -!> - 11 scanning mode flag (right adj copy of octet 28) -!> - 12 latin 1 - first lat from pole of secant cone inter -!> - 13 latin 2 - second lat from pole of secant cone inter -!> @param[in] kens teger (200) ensemble pds parms -!> - 1 application identifier -!> - 2 ensemble type -!> - 3 ensemble identifier -!> - 4 product identifier -!> - 5 smoothing flag -!> @param[in] kprob teger (2) probability ensemble parms -!> @param[in] xprob al (2) probability ensemble parms -!> @param[in] kclust teger (16) cluster ensemble parms -!> @param[in] kmembr teger (8) cluster ensemble parms -!> @param[in] ibs teger binary scale factor (0 to ignore) -!> @param[in] nbits teger number of bits in which to pack (0 to ignore) -!> @param[in] lb gical*1 (kf) bitmap if present -!> @param[in] f al (kf) data -!> @param[out] iret teger return code -!> - 0 Success -!> - Other W3FI72 GRIB packer return code -!> -!> @author Mark Iredell @date 94-04-01 -SUBROUTINE PUTGBEXN(LUGB,KF,KPDS,KGDS,KENS, & - KPROB,XPROB,KCLUST,KMEMBR,IBS,NBITS,LB,F,IRET) - - INTEGER KPDS(200),KGDS(200),KENS(200) - INTEGER KPROB(2),KCLUST(16),KMEMBR(80) - REAL XPROB(2) - LOGICAL*1 LB(KF) - REAL F(KF) - ! PARAMETER(MAXBIT=16) - PARAMETER(MAXBIT=24) - INTEGER IBM(KF),IPDS(200),IGDS(200),IBDS(200) - CHARACTER PDS(400),GRIB(1000+KF*(MAXBIT+1)/8) - - ! GET W3FI72 PARAMETERS - !print *,'SAGT: start putgbexn' - CALL R63W72(KPDS,KGDS,IPDS,IGDS) - IBDS=0 - - ! COUNT VALID DATA - KBM=KF - IF(IPDS(7).NE.0) THEN - KBM=0 - DO I=1,KF - IF(LB(I)) THEN - IBM(I)=1 - KBM=KBM+1 - ELSE - IBM(I)=0 - ENDIF - ENDDO - IF(KBM.EQ.KF) IPDS(7)=0 - ENDIF - - ! GET NUMBER OF BITS AND ROUND DATA - IF(NBITS.GT.0) THEN - NBIT=NBITS - ELSE - IF(KBM.EQ.0) THEN - DO I=1,KF - F(I)=0. - ENDDO - NBIT=0 - ELSE - !print *,'SAGT:',IPDS(7),IBS,IPDS(25),KF - !print *,'SAGT:',count(ibm.eq.0),count(ibm.eq.1) - CALL SETBIT(IPDS(7),-IBS,IPDS(25),KF,IBM,F,FMIN,FMAX,NBIT) - NBIT=MIN(NBIT,MAXBIT) - ENDIF - ENDIF - - ! CREATE PRODUCT DEFINITION SECTION - CALL W3FI68(IPDS,PDS) - IF(IPDS(24).EQ.2) THEN - ILAST=45 - IF (IPDS(8).EQ.191.OR.IPDS(8).EQ.192) ILAST=55 - IF (KENS(2).EQ.5) ILAST=76 - IF (KENS(2).EQ.5) ILAST=86 - IF (KENS(2).EQ.4) ILAST=86 - CALL PDSENS(KENS,KPROB,XPROB,KCLUST,KMEMBR,ILAST,PDS) - ENDIF - - ! PACK AND WRITE GRIB DATA - igflag=1 - igrid=kpds(3) - if (igrid.ne.255) igflag=0 - !print *,minval(f(1:kf)),maxval(f(1:kf)) - !print *,nbit,kf - !print *,(ipds(j),j=1,28) - !write(6,fmt='(28z2)') (pds(j),j=1,28) - !print *,(kgds(j),j=1,28) - !print *,(igds(j),j=1,28) - icomp=0 - CALL W3FI72(0,F,0,NBIT,1,IPDS,PDS, & - igflag,igrid,IGDS,ICOMP,0,IBM,KF,IBDS, & - KFO,GRIB,LGRIB,IRET) - IF(IRET.EQ.0) CALL WRYTE(LUGB,LGRIB,GRIB) - - RETURN -END SUBROUTINE PUTGBEXN diff --git a/utils/setbit.F90 b/utils/setbit.F90 deleted file mode 100644 index 8a62d63b0..000000000 --- a/utils/setbit.F90 +++ /dev/null @@ -1,69 +0,0 @@ -!> @file -!> Compute bits required to pack a given field. -!> @author Mark Iredell @date 92-10-31 - -!> The number of bits required to pack a given field for particular -!> binary and decimal scalings is computed. The minimum and maximum -!> rounded field values are also returned. GRIB bitmap masking for -!> valid data is optionally used. -!> -!> @param[in] ibm integer bitmap flag (=0 for no bitmap). -!> @param[in] ibs integer binary scaling (e.g. ibs=3 to round field to -!> nearest eighth value). -!> @param[in] ids integer decimal scaling (e.g. ids=3 to round field to -!> nearest milli-value) (note that ids and ibs can both be nonzero, -!> e.g. ids=1 and ibs=1 rounds to the nearest twentieth). -!> @param[in] len integer length of the field and bitmap. -!> @param[in] mg integer (len) bitmap if ibm=1 (0 to skip, 1 to keep). -!> @param[in] g real (len) field. -!> @param[out] gmin real minimum valid rounded field value. -!> @param[out] gmax real maximum valid rounded field value. -!> @param[out] nbit integer number of bits to pack. -!> -!> @author Mark Iredell @date 92-10-31 -SUBROUTINE SETBIT(IBM,IBS,IDS,LEN,MG,G,GMIN,GMAX,NBIT) - - DIMENSION MG(LEN),G(LEN) - - ! ROUND FIELD AND DETERMINE EXTREMES WHERE BITMAP IS ON - S=2.**IBS*10.**IDS - IF(IBM.EQ.0) THEN - GMAX=G(1) - GMIN=G(1) - DO I=2,LEN - GMAX=MAX(GMAX,G(I)) - GMIN=MIN(GMIN,G(I)) - ENDDO - ELSE - I1=1 - DO WHILE(I1.LE.LEN.AND.MG(I1).EQ.0) - I1=I1+1 - ENDDO - IF(I1.LE.LEN) THEN - DO I=1,I1-1 - G(I)=0. - ENDDO - GMAX=G(I1) - GMIN=G(I1) - DO I=I1+1,LEN - IF(MG(I).NE.0) THEN - GMAX=MAX(GMAX,G(I)) - GMIN=MIN(GMIN,G(I)) - ELSE - G(I)=0. - ENDIF - ENDDO - ELSE - DO I=1,LEN - G(I)=0. - ENDDO - GMAX=0. - GMIN=0. - ENDIF - ENDIF - - ! COMPUTE NUMBER OF BITS - NBIT=LOG((GMAX-GMIN)*S+0.9)/LOG(2.)+1. - - RETURN -END SUBROUTINE SETBIT diff --git a/utils/tocgrib.F90 b/utils/tocgrib.F90 index 937f598e2..0f649d7f4 100644 --- a/utils/tocgrib.F90 +++ b/utils/tocgrib.F90 @@ -242,3 +242,96 @@ PROGRAM tocgrib STOP END PROGRAM tocgrib + +!> Generates a TOC Flag Field Separator Block used to separate WMO +!> Bulletins within a transmission file to be ingested in TOC's FTP +!> Input Service, which can be used to disseminate WMO buletins (see +!> http://weather.gov/tg/ftpingest.html). +!> +!> This routine can generate different flag field separator blocks +!> depending on the value of variable iopt. +!> +!> Bulletin "Flag Field Separator" block - OPTION 1 (old) +!> +!> Bytes | Description +!> ------|------------ +!> 1 - 4 | marker string (####) +!> 5 - 7 | block length [018 fixed value] +!> 8 - 13 | total length of bulletin in bytes [octets] (not including the flag field block) +!> 14 - 17 | marker string (####) +!> 18 | line Feed (ASCII "0A") +!> +!> Bulletin "Flag Field Separator" block - OPTION 1a (new) +!> +!> Bytes | Description +!> ------|------------ +!> 1 - 4 | marker string (####) +!> 5 - 7 | block length (nnn) - value always greater than 018 +!> 8 - 18 | total length of bulletin in bytes [octets] (not including the flag field block) +!> 19 - nnn-5 | reserved for future use +!> nnn-4 - nnn-1 | marker string (####) +!> nnn | line Feed (ASCII "0A") +!> +!> Bulletin "Flag Field Separator" block - OPTION 2 (limited) +!> +!> Bytes | Description +!> ------|------------ +!> 1 - 4 | marker string (****) +!> 5 - 14 | total length of bulletin in bytes [octets] (not including the flag field block) +!> 15 - 18 | marker string (****) +!> 19 | line Feed (ASCII "0A") +!> +!> @param[out] csep*(*) Character array containing the flag field separator. +!> @param[in] iopt Flag Field Separator block option: +!> - 1 Separator block for use with alphanumeric bulletins. +!> - if lenin <= 18 and lenbull <= 999999, OPTION 1 block will be generated. +!> - if lenin > 18 or lenbull > 999999, OPTION 1a block will be generated. +!> - 2 Separator block for use with GRIB/BUFR bulletins. +!> @param[in] lenin Desired length of the flag field separator +!> block. ignored, if iopt=2. +!> @param[in] lenbull Integer length of the bulletin (in bytes) that +!> will follow this separator block. +!> @param[out] lenout Integer length of the flag field separator block. +!> +!> @author Gilbert @date 2002-09-16 +subroutine mkfldsep(csep,iopt,lenin,lenbull,lenout) + ! + character*(*),intent(out) :: csep + integer,intent(in) :: iopt,lenin,lenbull + integer,intent(out) :: lenout + ! + character(len=4),parameter :: cstar='****',clb='####' + ! + if (iopt.eq.1) then + if ( lenin .le. 18 .and. lenbull .le. 999999 ) then + ! Create OPTION 1 separator block + csep(1:4)=clb + csep(5:7)='018' + write(csep(8:13),fmt='(I6.6)') lenbull + csep(14:17)=clb + csep(18:18)=char(10) + lenout=18 + else ! Create OPTION 1a separator block + nnn=lenin + if ( nnn.lt.23 ) nnn=23 + csep(1:4)=clb + write(csep(5:7),fmt='(I3.3)') nnn + write(csep(8:18),fmt='(I11.11)') lenbull + csep(19:nnn-5)='0' + csep(nnn-4:nnn-1)=clb + csep(nnn:nnn)=char(10) + lenout=nnn + endif + elseif (iopt.eq.2) then ! Create OPTION 2 separator block + csep(1:4)=cstar + write(csep(5:14),fmt='(I10.10)') lenbull + csep(15:18)=cstar + csep(19:19)=char(10) + lenout=19 + else + print *,"mkfldsep: Option ",iopt," not recognized." + csep(1:lenin)=' ' + endif + ! + return +end subroutine mkfldsep \ No newline at end of file