diff --git a/.circleci/config.yml b/.circleci/config.yml index 096c8ed0..cb24b2ed 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,14 +1,16 @@ version: 2.1 -# Anchor to prevent forgetting to update a version -baselibs_version: &baselibs_version v7.7.0 +# Anchors in case we need to override the defaults from the orb +#baselibs_version: &baselibs_version v7.17.0 +#bcs_version: &bcs_version v11.4.0 orbs: - ci: geos-esm/circleci-tools@1 + ci: geos-esm/circleci-tools@2 workflows: build-test: jobs: + # Build GEOSldas - ci/build: name: build-GEOSldas-on-<< matrix.compiler >> context: @@ -16,7 +18,7 @@ workflows: matrix: parameters: compiler: [ifort, gfortran] - baselibs_version: *baselibs_version + #baselibs_version: *baselibs_version repo: GEOSldas mepodevelop: false persist_workspace: false # Needs to be true to run fv3/gcm experiment, costs extra diff --git a/.github/workflows/enforce-labels.yml b/.github/workflows/enforce-labels.yml index 3e27600d..86f4bb4e 100644 --- a/.github/workflows/enforce-labels.yml +++ b/.github/workflows/enforce-labels.yml @@ -8,20 +8,20 @@ jobs: require-label: runs-on: ubuntu-latest steps: - - uses: mheap/github-action-required-labels@v3 + - uses: mheap/github-action-required-labels@v5 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: mode: minimum count: 1 - labels: "0 diff,0 diff trivial,Non 0-diff,0 diff structural,0-diff trivial,Not 0-diff,0-diff,automatic,0-diff uncoupled" + labels: "0 diff,0 diff trivial,Non 0-diff,0 diff structural,0-diff trivial,Not 0-diff,0-diff,automatic,0-diff uncoupled,github_actions" add_comment: true message: "This PR is being prevented from merging because you have not added one of our required labels: {{ provided }}. Please add one so that the PR can be merged." blocking-label: runs-on: ubuntu-latest steps: - - uses: mheap/github-action-required-labels@v3 + - uses: mheap/github-action-required-labels@v5 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: @@ -30,4 +30,3 @@ jobs: labels: "Contingent - DNA,Needs Lead Approval,Contingent -- Do Not Approve" add_comment: true message: "This PR is being prevented from merging because you have added one of our blocking labels: {{ provided }}. You'll need to remove it before this PR can be merged." - diff --git a/.github/workflows/push-to-develop.yml b/.github/workflows/push-to-develop.yml index 59424134..ebbd3109 100644 --- a/.github/workflows/push-to-develop.yml +++ b/.github/workflows/push-to-develop.yml @@ -11,11 +11,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repo - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Run the action - uses: devops-infra/action-pull-request@v0.4 + uses: devops-infra/action-pull-request@v0.5.5 with: github_token: ${{ secrets.GITHUB_TOKEN }} source_branch: develop diff --git a/.github/workflows/release-tarball.yml b/.github/workflows/release-tarball.yml index 467370db..3866b8dd 100644 --- a/.github/workflows/release-tarball.yml +++ b/.github/workflows/release-tarball.yml @@ -10,12 +10,12 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: path: ${{ github.event.repository.name }}-${{ github.event.release.tag_name }} - name: Checkout mepo - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: repository: GEOS-ESM/mepo path: mepo diff --git a/README.md b/README.md index 172d3dfd..84ca1cf8 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ This document explains how to build, set up, and run the GEOS land modeling and ## How to Build GEOSldas -### Step 1: Load the Build Modules +### Step 1: Load the Build Modules Load the `GEOSenv` module provided by the GMAO Software Infrastructure team. It contains the latest `git`, `CMake`, and `mepo` modules and must be loaded in any interactive window that is used to check out and build the model. @@ -13,22 +13,24 @@ module use -a (path) module load GEOSenv ``` -where `(path)` depends on the computer and operating system: +where `(path)` depends on the computing system; at NCCS, `(path)` also depends on the operating system (SLES12 on Skylake and Cascade Lake nodes; SLES15 on Milan nodes, as of Jan. 2024): | System | Path | | ------------- |---------------------------------------------------| -| NCCS | `/discover/swdev/gmao_SIteam/modulefiles-SLES12` | +| NCCS Discover | `/discover/swdev/gmao_SIteam/modulefiles-SLES12` | +| | `/discover/swdev/gmao_SIteam/modulefiles-SLES15` | | NAS | `/nobackup/gmao_SIteam/modulefiles` | | GMAO desktops | `/ford1/share/gmao_SIteam/modulefiles` | +Step 1 can be coded into the user's shell configuration file (e.g., `.bashrc` or `.cshrc`). See the [GEOSgcm Wiki](https://github.com/GEOS-ESM/GEOSgcm/wiki/) for sample shell configuration files. ### Step 2: Obtain the Model -For development work, clone the _entire_ repository and use the `develop` branch as your starting point (equivalent to the `UNSTABLE` tag in the old CVS repository): +For development work, clone the _entire_ repository and use the `develop` branch as your starting point: ``` git clone -b develop git@github.com:GEOS-ESM/GEOSldas.git ``` -For science runs, you can also obtain a specific tag or branch _only_ (as opposed to the _entire_ repository), e.g.: +For science runs, you can also obtain a specific tag or branch _only_ (as opposed to the _entire_ repository), e.g.: ``` git clone -b v17.9.1 --single-branch git@github.com:GEOS-ESM/GEOSldas.git ``` @@ -36,28 +38,35 @@ git clone -b v17.9.1 --single-branch git@github.com:GEOS-ESM/GEOSldas.git ### Step 3: Build the Model -To build the model in a single step, do the following: +To build the model in a single step, do the following from a head node: ``` cd ./GEOSldas parallel_build.csh -``` -from a head node. Doing so will check out all the external repositories of the model (albeit only on the first run, [see subsection on mepo below](#mepo)!) and build the model. When done, the resulting model build will be found in `build/` and the installation will be found in `install/`, with setup scripts like `ldas_setup` in `install/bin`. +``` +This checks out all the external repositories of the model (albeit only on the first run, [see subsection on mepo below](#mepo)!) and then builds and installs the model. + +At **NCCS**, the default is to build GEOSldas on SLES12 (Skylake or Cascade Lake nodes); to build GEOSldas on SLES15 (Milan nodes), use `parallel_build.csh -mil`. + +The resulting model build is found in `build[-SLESxx]/`, and the installation is found in `install[-SLESxx]/`, with setup scripts like `ldas_setup` in `install[-SLESxx]/bin`. -To obtain a build that is suitable for debugging, use `parallel_build.csh -debug`, which will build in `build-Debug/` and install in `install-Debug/`. There is also an option for aggressive optimization. For details, see [GEOSldas Wiki](https://github.com/GEOS-ESM/GEOSldas/wiki). +To obtain a build that is suitable for debugging, use `parallel_build.csh -debug`, which builds in `build-Debug[-SLESxx]/` and installs in `install-Debug[-SLESxx]/`. There is also an option for aggressive optimization. For details, see the [GEOSldas Wiki](https://github.com/GEOS-ESM/GEOSldas/wiki). -See below for how to build the model in multiple steps. +Instructions for building the model in multiple steps are provided below. --- ## How to Set Up (Configure) and Run GEOSldas -a) Set up the job as follows: + +a) At **NCCS**, GEOSldas must be built, configured, and run on the same operating system. To run GEOSldas on Milan nodes (SLES15), start with `ssh discover-mil`. + +b) Set up the job as follows: ``` -cd (build_path)/GEOSldas/install/bin +cd (build_path)/GEOSldas/install[-SLESxx]/bin source g5_modules [for bash or zsh: source g5_modules.[z]sh] ./ldas_setup setup [-v] (exp_path) ("exe"_input_filename) ("bat"_input_filename) -``` +``` where @@ -70,19 +79,19 @@ where The three arguments for `ldas_setup` are positional and must be ordered as indicated above. -The latter two files contain essential information about the experiment setup. +The latter two files contain essential information about the experiment setup. Sample files can be generated as follows: -``` +``` ldas_setup sample --exeinp > YOUR_exeinp.txt ldas_setup sample --batinp > YOUR_batinp.txt ``` -Edit these sample files following the examples and comments within the sample files. +Edit these sample files following the examples and comments within the sample files. The ldas_setup script creates a run directory and other directories at: `[exp_path]/[exp_name]` -Configuration input files will be created at: +Configuration input files are created at: `[exp_path]/[exp_name]/run` For more options and documentation, use any of the following: @@ -92,16 +101,19 @@ ldas_setup sample -h ldas_setup setup -h ``` -b) Configure the experiment output by editing the ```./run/HISTORY.rc``` file as needed. +c) Configure the experiment output by editing the ```./run/HISTORY.rc``` file as needed. -c) Run the job: +d) Run the job: ``` cd [exp_path]/[exp_name]/run/ sbatch lenkf.j ``` -For more information, see the files in `./doc/`. -Moreover, descriptions of the configuration (resource) parameters are included in the sample "exeinp" and "batinp" files that can be generated using `ldas_setup`. +At **NCCS**, the appropriate SLURM directive `#SBATCH --constraint=[xxx]` is automatically added into `lenkf.j` depending on the operating system. + +For more information, see the files in `./doc/`. Moreover, descriptions of the configuration (resource) parameters are included in the sample "exeinp" and "batinp" files that can be generated using `ldas_setup`. + + ----------------------------------------------------------------------------------- @@ -138,7 +150,6 @@ We currently do not allow in-source builds of GEOSldas. So we must make a direct ``` mkdir build ``` -The advantages of this is that you can build both a Debug and Release version with the same clone if desired. #### Run CMake CMake generates the Makefiles needed to build the model. @@ -146,7 +157,7 @@ CMake generates the Makefiles needed to build the model. cd build cmake .. -DBASEDIR=$BASEDIR/Linux -DCMAKE_Fortran_COMPILER=ifort -DCMAKE_INSTALL_PREFIX=../install ``` -This will install to a directory parallel to your `build` directory. If you prefer to install elsewhere change the path in: +This installs into a directory parallel to your `build` directory. If you prefer to install elsewhere change the path in: ``` -DCMAKE_INSTALL_PREFIX= ``` @@ -156,7 +167,7 @@ and CMake will install there. ``` make -j6 install ``` -If you are at NCCS, you **should** run `make -j6 install` on an interactive _compute_ node. +If you are at NCCS, you **should** run `make -j6 install` on an interactive _compute_ node. ## Contributing diff --git a/components.yaml b/components.yaml index 4a394bb8..c041aafc 100644 --- a/components.yaml +++ b/components.yaml @@ -4,37 +4,44 @@ GEOSldas: env: local: ./@env remote: ../ESMA_env.git - tag: v4.9.1 + tag: v4.23.0 cmake: local: ./@cmake remote: ../ESMA_cmake.git - tag: v3.28.0 + tag: v3.41.0 ecbuild: local: ./@cmake/@ecbuild remote: ../ecbuild.git tag: geos/v1.3.0 +NCEP_Shared: + local: ./src/Shared/@NCEP_Shared + remote: ../NCEP_Shared.git + tag: v1.3.0 + sparse: ./config/NCEP_Shared.sparse + GMAO_Shared: local: ./src/Shared/@GMAO_Shared remote: ../GMAO_Shared.git + tag: v1.9.7 sparse: ./config/GMAO_Shared.sparse - tag: v1.9.0 GEOS_Util: local: ./src/Shared/@GMAO_Shared/@GEOS_Util remote: ../GEOS_Util.git - tag: v2.0.1 + tag: v2.0.7 + sparse: ./config/GEOS_Util.sparse MAPL: local: ./src/Shared/@MAPL remote: ../MAPL.git - tag: v2.39.1 + tag: v2.44.1 GEOSgcm_GridComp: local: ./src/Components/GEOSldas_GridComp/@GEOSgcm_GridComp remote: ../GEOSgcm_GridComp.git + tag: v2.5.2 sparse: ./config/GEOSgcm_GridComp_ldas.sparse - tag: v2.1.1 diff --git a/config/GEOS_Util.sparse b/config/GEOS_Util.sparse new file mode 100644 index 00000000..44ea2be3 --- /dev/null +++ b/config/GEOS_Util.sparse @@ -0,0 +1,3 @@ +/CMakeLists.txt +/pre/remap_restart +/pre/CMakeLists.txt diff --git a/config/NCEP_Shared.sparse b/config/NCEP_Shared.sparse new file mode 100644 index 00000000..b0801a63 --- /dev/null +++ b/config/NCEP_Shared.sparse @@ -0,0 +1,8 @@ +!/* +/NCEP_sp +/NCEP_w3 +/NCEP_bufr +/NCEP_bacio +/NCEP_sfcio +/NCEP_sigio +/CMakeLists.txt diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index 54b2545d..5626d2ef 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -27,12 +27,85 @@ this period, LDASsa and GEOSldas development continued in parallel. In 2019, GEOS LDAS version control transferred from CVS to Git. -This README file contains the history of stable GEOSldas versions ("tags") in Git, followed by older, CVS LDASsa and GEOSldas versions and change logs. +This README file contains the history of stable GEOSldas Releases in Git, followed by older, CVS LDASsa tags and GEOSldas versions and change logs. Overview of Git Releases: ============================ +[v18.0.0](https://github.com/GEOS-ESM/GEOSldas/releases/tag/v18.0.0) - 2024-03-22 +------------------------------ + +- 0-diff vs. v17.13.1 except for MAPL bug fix ([PR #734](https://github.com/GEOS-ESM/GEOSldas/pull/734)). + +- Notes: + - Release uses original GEOSldas repository structure. Next release is expected to use a revised repository structure. + +- Science changes: + - Added MODIS snow cover fraction assimilation ([PR #512](https://github.com/GEOS-ESM/GEOSldas/pull/512)). + - Added ASCAT soil moisture assimilation ([PR #656](https://github.com/GEOS-ESM/GEOSldas/pull/656), [PR #703](https://github.com/GEOS-ESM/GEOSldas/pull/703), [PR #723](https://github.com/GEOS-ESM/GEOSldas/pull/723), [PR #729](https://github.com/GEOS-ESM/GEOSldas/pull/729)). + - New update_type=13 for ASCAT soil moisture and SMAP brightness temperature assimilation ([PR #703](https://github.com/GEOS-ESM/GEOSldas/pull/703)). + - New update_type=13 replaces update_type=[1,2], which has been disabled. + - Requires ASCAT mask file ([PR #723](https://github.com/GEOS-ESM/GEOSldas/pull/723), [PR #729](https://github.com/GEOS-ESM/GEOSldas/pull/729)). + - Disabled CatchmentCNCLM45 model option (LSM_CHOICE=3) ([PR #707](https://github.com/GEOS-ESM/GEOSldas/pull/707), [GEOSgcm_GridComp PR #900](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/900)). + - Added support for GEOS-IT surface met forcing ([PR #688](https://github.com/GEOS-ESM/GEOSldas/pull/688)). + - Added CATCHMENT_SPINUP mode ([PR #647](https://github.com/GEOS-ESM/GEOSldas/pull/647), [GEOSgcm_GridComp PR #751](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/751)). + +- GEOSgcm_GridComp v2.5.2: + - Improved MODIS-based snow albedo (v2) in make_bcs package ([GEOSgcm_GridComp PR #687](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/687)). + - Major source code cleanup: + - Stieglitz snow model ([GEOSgcm_GridComp PR #834](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/834)). + - make_bcs package ([GEOSgcm_GridComp PR #763](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/763), [GEOSgcm_GridComp PR #786](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/786), [GEOSgcm_GridComp PR #846](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/846)). + - coeffsib ([GEOSgcm_GridComp PR #845](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/845)). + - Fixed CDCR2 long_name ([GEOSgcm_GridComp PR #818](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/818)). + - Optional checks of snow states after application of LDAS increments ([GEOSgcm_GridComp PR #834](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/834)). + - Refined check for allowable bcs versions for CatchCN ([GEOSgcm_GridComp PR #882](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/882)). + - Fixed treatment of atmospheric CO2 input file for CatchCN ([PR #663](https://github.com/GEOS-ESM/GEOSldas/pull/663), [GEOSgcm_GridComp PR #771](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/771)). + - Fixed bug when reading vegetation type ity from restart ([GEOSgcm_GridComp PR #757](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/757)). + - Fixed bug to correct vegetation fraction assessment in GetIds_carbon (getids.F90) for CatchCN ([GEOSgcm_GridComp PR #770](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/770)). + +- Interface: + - Use boundary conditions inputs in revised directory layout and naming convention ([PR #680](https://github.com/GEOS-ESM/GEOSldas/pull/680)). + +- Utilities: + - GMAO_Shared v1.9.7 ([PR #725](https://github.com/GEOS-ESM/GEOSldas/pull/725)). + - GEOS_Util v2.0.7 ([PR #725](https://github.com/GEOS-ESM/GEOSldas/pull/725)). + - Sparse checkout of GEOS_Util ([PR #711](https://github.com/GEOS-ESM/GEOSldas/pull/711)). + - Improved remap_restarts package ([GEOS_Util PR #43](https://github.com/GEOS-ESM/GEOS_Util/pull/19), [GEOS_Util PR #43](https://github.com/GEOS-ESM/GEOS_Util/pull/43), [GEOS_Util PR #53](https://github.com/GEOS-ESM/GEOS_Util/pull/53)) + - Added NCEP_Shared v1.3.0 ([PR #656](https://github.com/GEOS-ESM/GEOSldas/pull/656)). + +- Infrastructure: + - Updated for NCCS/Discover hardware: + - Added support for SLES15/Milan nodes ([PR #693](https://github.com/GEOS-ESM/GEOSldas/pull/693)). + - Removed support for Haswell nodes ([PR #681](https://github.com/GEOS-ESM/GEOSldas/pull/681)). + - Support for running GEOSldas at the NASA Advanced Supercomputing (NAS) facility ([PR #706](https://github.com/GEOS-ESM/GEOSldas/pull/706)). + - Allow experiment setup from another user's build ([PR #733](https://github.com/GEOS-ESM/GEOSldas/pull/733), [PR #740](https://github.com/GEOS-ESM/GEOSldas/pull/740)). + - ESMA_env v4.23.0, Baselibs v7.16.0 ([PR #681](https://github.com/GEOS-ESM/GEOSldas/pull/681)). + - ESMA_cmake v3.41.0 ([PR #725](https://github.com/GEOS-ESM/GEOSldas/pull/725)). + - MAPL v2.44.1 ([PR #734](https://github.com/GEOS-ESM/GEOSldas/pull/734)). + - CircleCI Orb v2 ([PR #694](https://github.com/GEOS-ESM/GEOSldas/pull/694)). + - Replaced FLAP with fArgParse ([PR #669](https://github.com/GEOS-ESM/GEOSldas/pull/669)). + - Updated versions of GitHub Actions ([PR #739](https://github.com/GEOS-ESM/GEOSldas/pull/739)). + + +- Documentation: + - Updates and corrections ([PR #728](https://github.com/GEOS-ESM/GEOSldas/pull/728)). + +- Bug fixes and other minor changes: + - Fixed bug that degraded simulation when writing (MAPL-binary) instantaneous output with bit shaving ([PR #734](https://github.com/GEOS-ESM/GEOSldas/pull/734)). + - Removed requirement for mwRTM parameter input files ([PR #685](https://github.com/GEOS-ESM/GEOSldas/pull/685)). + - Support for reading corrected precipitation from aggregated daily netcdf files ([PR #718](https://github.com/GEOS-ESM/GEOSldas/pull/718)). + - Updated generate_catchincr_hist.py and sample documents for coupled land-atmosphere data assimilation ([PR #698](https://github.com/GEOS-ESM/GEOSldas/pull/698)). + - Bug fix to avoid NaN for ens std-dev in debug mode ([PR #679](https://github.com/GEOS-ESM/GEOSldas/pull/679)). + - Implementation changes for FFT used in perturbations ([PR #679](https://github.com/GEOS-ESM/GEOSldas/pull/679)). + - Some cleanup of unused variables ([PR #679](https://github.com/GEOS-ESM/GEOSldas/pull/679)). + - Updated met forcing path when coupled with ADAS ([PR #682](https://github.com/GEOS-ESM/GEOSldas/pull/682)). + - Added more export variable definitions to tile_bin2nc4.F90 ([PR #676](https://github.com/GEOS-ESM/GEOSldas/pull/676)). + - Fixed LONG_NAME for longwave radiation variables ([PR #674](https://github.com/GEOS-ESM/GEOSldas/pull/674), [GEOSgcm_GridComp PR #764](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/764)). + - Fixed bug in matlab reader MAPL_ReadForcing_fullfile.m ([PR #665](https://github.com/GEOS-ESM/GEOSldas/pull/665)). + - Renamed GEOSldas_GridComp/Shared to GEOSldas_GridComp/LDAS_Shared ([PR #714](https://github.com/GEOS-ESM/GEOSldas/pull/714)). + +------------------------------ [v17.13.1](https://github.com/GEOS-ESM/GEOSldas/releases/tag/v17.13.1) - 2023-06-26 ------------------------------ diff --git a/doc/README.MetForcing_and_BCS.md b/doc/README.MetForcing_and_BCS.md index 5ed10ab3..fa0dd307 100644 --- a/doc/README.MetForcing_and_BCS.md +++ b/doc/README.MetForcing_and_BCS.md @@ -4,7 +4,7 @@ README.metforcing_and_bcs Description: --------------- -Information about met forcing and boundary conditions for GEOSldas. +Information about surface meteorological forcing and boundary conditions for GEOSldas. Author: --------------- @@ -12,29 +12,26 @@ Author: - jperket (10 Dec 2019) - converted to markdown -Met Forcing -========= - -Surface meteorological forcing data +Surface Meteorological Forcing +================================================================================ The forcing time step is controlled with the configurable resource variable __FORCE_DTSTEP__ and __must match the frequency of the input forcing files__. -Specify FORCE_DTSTEP=3600 [seconds] for GEOS products, incl. MERRA, MERRA-2, FP, and FP-IT/RP-IT, which are 1-hourly datasets. +Specify FORCE_DTSTEP=3600 [seconds] for most GEOS products, incl. MERRA, MERRA-2, FP, FP-IT/RP-IT, and GEOS-IT, which are 1-hourly datasets. The spatial (horizontal) interpolation method for the met forcing is controlled by `MET_HINTERP` (see optional parameters in `exeinp` input file to ldas_setup). `MET_PATH` and `MET_TAG` must be consistent: - - `MET_PATH` is the full path to the forcing data set + - `MET_PATH` is the full path to the forcing data set. - - `MET_TAG` is an identifier for the forcing data set + - `MET_TAG` is an identifier for the forcing data set. - - Available non-MERRA and non-GEOS forcing data sets are pre-defined - in subroutine get_forcing() + - Available non-GEOS forcing data sets are pre-defined in subroutine get_forcing(). - - For MERRA and other GEOS forcing datasets, see special `MET_TAG` + - For GEOS forcing datasets, see special `MET_TAG` parsing conventions in subroutines parse_MERRA_met_tag(), parse_MERRA2_met_tag() - and parse_G5DAS_met_tag() + and parse_G5DAS_met_tag(). - For details on corrected precipitation data see also (https://gmao.gsfc.nasa.gov/pubs/): - Reichle and Liu (2014), @@ -64,49 +61,44 @@ COMMONLY USED values for `MET_PATH`: MET_PATH : /discover/nobackup/projects/lis/MET_FORCING/ERA5/ ``` -### GEOS-based datasets +### GEOS datasets #### MERRA forcing (including precip-corrected MERRA forcing) ``` MET_PATH : /discover/nobackup/projects/gmao/merra/iau/merra_land/MERRA_land_forcing/ ``` -#### MERRA2 forcing (including precip-corrected MERRA forcing) +#### MERRA2 forcing (including precip-corrected MERRA2 forcing) ``` MET_PATH : /discover/nobackup/projects/gmao/merra/iau/merra_land/MERRA2_land_forcing/ ``` -#### SMAP_Nature_v03 -``` - MET_PATH : /discover/nobackup/projects/gmao/merra/iau/merra_land/GEOS5_land_forcing/ -``` - -#### SMAP_Nature_v04, SMAP_Nature_v04.1 -``` - MET_PATH : /discover/nobackup/projects/gmao/merra/iau/merra_land/GEOS5_land_forcing/ -``` - -#### SMAP_Nature_v05, v7.2, v8.1, v8.3; SMAP L4_SM Version 4 -``` - MET_PATH : /discover/nobackup/projects/gmao/merra/iau/merra_land/MERRA2_land_forcing/ ! before 1/1/2015 - MET_PATH : /discover/nobackup/projects/gmao/merra/iau/merra_land/GEOS5_land_forcing/ ! after 1/1/2015 -``` +Note: Used for SMAP Nature Run v05, v7.2, v8.1, v8.3, v9.1, v10.0 (before 1/1/2015). #### GEOS FP forcing with "seamless" file names, for use with MET_TAG=GEOS.fp.asm[__prec*] (__PREFERRED__) ``` MET_PATH : /discover/nobackup/projects/gmao/smap/SMAP_L4/GEOS/FP/ ``` +Note: Used for SMAP Nature Run v8.1, v8.3, v9.1, v10.0 (after 1/1/2015); SMAP L4_SM Version 5, 6, 7. + #### GEOS forcing with experiment-specific file names, incl. FP (__DEPRECATED__), FP-IT/RP-IT, and precip-corrected GEOS forcing ``` MET_PATH : /discover/nobackup/projects/gmao/merra/iau/merra_land/GEOS5_land_forcing/ ``` +Note: Used for SMAP Nature Run v03, v04, v04.1, v05, v7.2 (after 1/1/2015); SMAP L4_SM Version 4. + +#### GEOS-IT forcing (including precip-corrected GEOS-IT forcing) +``` + MET_PATH : /discover/nobackup/projects/gmao/merra/iau/merra_land/GEOSIT_land_forcing/ +``` + #### Forcing from post-processed output of the GEOS S2S system (FCST, AODAS) -``` +``` MET_PATH : [check with GMAO S2S group] -``` +``` @@ -126,7 +118,7 @@ COMMONLY USED values for `MET_TAG`: MET_TAG : ERA5_LIS ``` -### GEOS-based datasets +### GEOS datasets #### MERRA ``` @@ -140,32 +132,32 @@ COMMONLY USED values for `MET_TAG`: #### MERRA-2 - - All MERRA-2 options use native MERRA-2 "lfo" files for all surface met forcing fields - *except* precipitation. + - All MERRA-2 options use native MERRA-2 "lfo" files for all surface met forcing fields *except* precipitation. - Option 1a: Use corrected precip seen by the land w/in the MERRA-2 system (i.e., native MERRA-2 "lfo" files). Precip is as corrected within the MERRA-2 system. Closest to land-only MERRA-2 replay. ``` - MET_TAG : M2COR_cross - MET_TAG : M2COR_100 - MET_TAG : M2COR_200 - MET_TAG : M2COR_300 - MET_TAG : M2COR_400 - ``` + MET_TAG : M2COR_cross ! all streams + MET_TAG : M2COR_100 ! stream 1 only + MET_TAG : M2COR_200 ! stream 2 only + MET_TAG : M2COR_300 ! stream 3 only + MET_TAG : M2COR_400 ! stream 4 only + ``` + - Option 1b: - Use corrected precip forcing constructed in post-processing using MERRA-2 as background. + Use corrected precip forcing constructed in post-processing using MERRA-2 as background. Background precip is typically from MERRA-2 "int" data, but corrected precip is stored in files that look like MERRA-2 "lfo" files. For example, select corrected precip version "CPCUGPCP22clim_MERRA2_BMTXS" as follows: ``` - MET_TAG : M2COR_cross__precCPCUGPCP22clim_MERRA2_BMTXS - MET_TAG : M2COR_100__precCPCUGPCP22clim_MERRA2_BMTXS - MET_TAG : M2COR_200__precCPCUGPCP22clim_MERRA2_BMTXS - MET_TAG : M2COR_300__precCPCUGPCP22clim_MERRA2_BMTXS - MET_TAG : M2COR_400__precCPCUGPCP22clim_MERRA2_BMTXS + MET_TAG : M2COR_cross__precCPCUGPCP22clim_MERRA2_BMTXS ! all streams + MET_TAG : M2COR_100__precCPCUGPCP22clim_MERRA2_BMTXS ! stream 1 only + MET_TAG : M2COR_200__precCPCUGPCP22clim_MERRA2_BMTXS ! stream 2 only + MET_TAG : M2COR_300__precCPCUGPCP22clim_MERRA2_BMTXS ! stream 3 only + MET_TAG : M2COR_400__precCPCUGPCP22clim_MERRA2_BMTXS ! stream 4 only ``` This particular version uses as background the MERRA-2 model ("int") precip, rescaled to @@ -178,32 +170,35 @@ COMMONLY USED values for `MET_TAG`: Use uncorrected precip generated by the AGCM w/in the MERRA-2 system (i.e., native MERRA-2 "int" files). ``` - MET_TAG : M2INT_cross - MET_TAG : M2INT_100 - MET_TAG : M2INT_200 - MET_TAG : M2INT_300 - MET_TAG : M2INT_400 - ``` + MET_TAG : M2INT_cross ! all streams + MET_TAG : M2INT_100 ! stream 1 only + MET_TAG : M2INT_200 ! stream 2 only + MET_TAG : M2INT_300 ! stream 3 only + MET_TAG : M2INT_400 ! stream 4 only + ``` #### RP-IT/FP-IT (d591) -``` - MET_TAG : d591_rpit1_jan00 - MET_TAG : d591_rpit2_jun06 - MET_TAG : d591_rpit3_jan11 - MET_TAG : d591_fpit - MET_TAG : cross_d591_RPFPIT -``` + ``` + MET_TAG : cross_d591_RPFPIT ! all streams + MET_TAG : d591_rpit1_jan00 ! stream 1 only + MET_TAG : d591_rpit2_jun06 ! stream 2 only + MET_TAG : d591_rpit3_jan11 ! stream 3 only + MET_TAG : d591_fpit ! stream 4 only + ``` #### RP-IT/FP-IT (d5124) -``` - MET_TAG : d5124_rpit1_jan00 - MET_TAG : d5124_rpit2_jun04 - MET_TAG : d5124_rpit3_jan12 ! updated through present - MET_TAG : cross_d5124_RPFPIT ! uses "late-look" through present -``` + ``` + MET_TAG : cross_d5124_RPFPIT ! all streams - uses "late-look" through present + MET_TAG : d5124_rpit1_jan00 ! stream 1 only + MET_TAG : d5124_rpit2_jun04 ! stream 2 only + MET_TAG : d5124_rpit3_jan12 ! stream 3 only - updated through present + ``` #### GEOS FP -``` + ``` + MET_TAG : GEOS.fp.asm ! PREFERRED: "seamless" FP files (published/generic file names, ~same result as cross_FP) + + MET_TAG : cross_FP ! DEPRECATED: stitch FP experiment names across years MET_TAG : e5110_fp ! starting 11 Jun 2013 MET_TAG : e5130_fp ! starting 20 Aug 2014 MET_TAG : e5131_fp ! starting 1 May 2015 @@ -214,38 +209,70 @@ COMMONLY USED values for `MET_TAG`: MET_TAG : f525_fp ! starting 30 Jan 2020 MET_TAG : f525_p5_fp ! starting 7 Apr 2020 ... + ``` - MET_TAG : cross_FP ! stitch FP experiment names across years (DEPRECATED) +#### GEOS-IT + ``` + MET_TAG : cross_d5294_GEOSIT + ``` - MET_TAG : GEOS.fp.asm ! "seamless" FP files (published/generic file names, ~same result as cross_FP, PREFERRED) -``` +#### Forcing from post-processed output of the GEOS S2S system + + - Forcing derived through post-processing of daily average output from the GEOS S2S system, + including S2S hindcasts/forecasts ("FCST") and the "AODAS" used for S2S initialization. + + S2S output is from the geosgcm_vis2d and geosgcm_surf Collections for FCST and from the + geosgcm_rad and geosgcm_surf Collections for AODAS (see GMAO Office Note No. 16). + + For FCST, post-processing includes a monthly bias correction to the MERRA-2 climatology. + + Daily data are disaggregated to 6-hourly (FCST) or 1-hourly (AODAS) using the MERRA-2 + climatological diurnal cycle. -#### With precip corrections: + For FCST, MET_TAG must specify S2S ensemble member ('ensX'; currently: 'ens1', 'ens2', + 'ens3', or 'ens4') and month/day of forecast initialization ('MMMDD'; e.g., 'jan01'), + separated by double underscores. + + As of 14 Jun 2021: + - Preparation of S2S forcing data ignores the 3-hour offset between S2S daily averages + (21z-21z) and the MERRA-2 daily averages (0z-0z) used for the temporal disaggregration. + - The processing of the S2S output incorrectly partitioned total precipitation into snowfall + and convective precipitation. Therefore, rainfall and snowfall are determined in the + S2S forcing reader from total precipitation and air temperature. Convective rainfall is + set to 0. (As of now, only total rainfall is used by Catchment.) + + ``` + MET_TAG : GEOSs2sFCST__[ensX]__[MMMDD] + MET_TAG : GEOSs2sAODAS + ``` + + +#### SMAP L4_SM #### Pre-beta SMAP L4_SM ``` MET_TAG : cross_FP__precCPCUG5FPv2 ``` -#### SMAP_Nature_v03 +#### SMAP Nature Run v03 ``` MET_TAG : cross_RPFPIT__precCPCUG5RPFPITv1 ! before 1/1/2014 - MET_TAG : cross_FP__precCPCUG5FPv1 ! after 1/1/2014 + MET_TAG : cross_FP__precCPCUG5FPv1 ! after 1/1/2014 ``` -#### SMAP_Nature_v04 +#### SMAP Nature Run v04 ``` MET_TAG : cross_d591_RPFPIT__precCPCUG5RPFPITv2 ! before 1/1/2014 MET_TAG : cross_FP__precCPCUG5FPv2 ! after 1/1/2014 ``` -#### SMAP_Nature_v04.1 +#### SMAP Nature Run v04.1 ``` MET_TAG : cross_d5124_RPFPIT__precCPCUG5RPFPITv2.1 ! before 1/1/2015 MET_TAG : cross_FP__precCPCUG5FPv2 ! after 1/1/2015 ``` -#### SMAP_Nature_v05, v7.2, v8.1, v8.3; SMAP L4_SM Version 4 +#### SMAP Nature Run v05, v7.2, v8.1, v8.3; SMAP L4_SM Version 4 ``` MET_TAG : M2COR_cross__precCPCUGPCP22clim_MERRA2_BMTXS ! before 1/1/2015 MET_TAG : cross_FP__precCPCUG5FPv3 ! after 1/1/2015 @@ -257,48 +284,33 @@ COMMONLY USED values for `MET_TAG`: MET_TAG : GEOS.fp.asm__precCPCUFLKG5FPv3 ! (precip corr with first-look CPCU) ``` -#### SMAP L4_SM Version 6 +#### SMAP Nature Run v9.1; SMAP L4_SM Version 6 ``` - MET_TAG : GEOS.fp.asm__precCPCU_IMGFinal_IMGFclim_G5FP ! (precip corr with IMERG-Final and late-look CPCU) - MET_TAG : GEOS.fp.asm__precCPCULLK_IMERGLateV06b_fp_v1 ! (precip corr with IMERG-Late and late-look CPCU) - MET_TAG : GEOS.fp.asm__precCPCUFLK_IMERGLateV06b_fp_v1 ! (precip corr with IMERG-Late and first-look CPCU) + MET_TAG : M2COR_cross__precSMAPv6_CGIM2 ! before 01/01/2015 + MET_TAG : GEOS.fp.asm__precCPCU_IMGFinal_IMGFclim_G5FP ! before 06/30/2021 (precip corr with IMERG-Final and late-look CPCU) + MET_TAG : GEOS.fp.asm__precCPCULLK_IMERGLateV06b_fp_v1 ! before 10/27/2021 (precip corr with IMERG-Late and late-look CPCU) + MET_TAG : GEOS.fp.asm__precCPCUFLK_IMERGLateV06b_fp_v1 ! before 05/09/2022 (precip corr with IMERG-Late and first-look CPCU) + MET_TAG : GEOS.fp.asm__precCPCUFLK_IMERGLateV06c_fp_v1 ! (precip corr with IMERG-Late and first-look CPCU) ``` -#### Forcing from post-processed output of the GEOS S2S system - - - Forcing derived through post-processing of daily average output from the GEOS S2S system, - including S2S hindcasts/forecasts ("FCST") and the "AODAS" used for S2S initialization. - - S2S output is from the geosgcm_vis2d and geosgcm_surf Collections for FCST and from the - geosgcm_rad and geosgcm_surf Collections for AODAS (see GMAO Office Note No. 16). - - For FCST, post-processing includes a monthly bias correction to the MERRA-2 climatology. - - Daily data are disaggregated to 6-hourly (FCST) or 1-hourly (AODAS) using the MERRA-2 - climatological diurnal cycle. - - For FCST, MET_TAG must specify S2S ensemble member ('ensX'; currently: 'ens1', 'ens2', - 'ens3', or 'ens4') and month/day of forecast initialization ('MMMDD'; e.g., 'jan01'), - separated by double underscores. - - As of 14 Jun 2021: - - Preparation of S2S forcing data ignores the 3-hour offset between S2S daily averages - (21z-21z) and the MERRA-2 daily averages (0z-0z) used for the temporal disaggregration. - - The processing of the S2S output incorrectly partitioned total precipitation into snowfall - and convective precipitation. Therefore, rainfall and snowfall are determined in the - S2S forcing reader from total precipitation and air temperature. Convective rainfall is - set to 0. (As of now, only total rainfall is used by Catchment.) - +#### SMAP Nature Run v10.0*; SMAP L4_SM Version 7 ``` - MET_TAG : GEOSs2sFCST__[ensX]__[MMMDD] - MET_TAG : GEOSs2sAODAS + MET_TAG : M2COR_cross__precSMAPv6_CGIM2 ! before 01/01/2015 + MET_TAG : GEOS.fp.asm__precCPCU_IMGFinal_IMGFclim_G5FP ! before 09/30/2021 (precip corr with IMERG-Final and late-look CPCU) + MET_TAG : GEOS.fp.asm__precCPCUFLK_IMERGLateV06b_fp_v1 ! before 05/09/2022 (precip corr with IMERG-Late and first-look CPCU) + MET_TAG : GEOS.fp.asm__precCPCUFLK_IMERGLateV06c_fp_v1 ! before 07/02/2023 (precip corr with IMERG-Late and first-look CPCU) + MET_TAG : GEOS.fp.asm__precCPCUFLK_IMERGLateV06d_fp_v1 ! before 11/07/2023 (precip corr with IMERG-Late and first-look CPCU) + MET_TAG : GEOS.fp.asm__precCPCUFLK_IMERGLateV06e_fp_v1 ! (precip corr with IMERG-Late and first-look CPCU) + ``` +*Transitions dates are for L4_SM Version 7. Transition dates for NRv10.0 may differ somewhat. + -Boundary Conditions +Boundary Conditions ================================================================================ Boundary conditions (bcs) are tile-space model parameters that are provided in a - set of files located in `BCS_PATH/BCS_RESOLUTION`. + set of files located in `BCS_PATH` for a given `BCS_RESOLUTION`. For "land" tiles, the discretization (tile-space) is constructed in one of two different ways: @@ -310,13 +322,15 @@ For "land" tiles, the discretization (tile-space) is constructed in one of two 0.5-degree ("c180") cube-sphere grid used by the atmospheric model in the MERRA-2 reanalysis: `CF0180x6C_DE1440xPE0720`. - 2. Directly on a regular grid, e.g., `SMAP_EASEv2_M09`. + 2. Directly on a regular grid, e.g., `EASEv2_M09`. -Note: GEOSldas can be run with older bcs. Note, however, that GEOSldas requires some bcs - files (NDVI and vegdyn) that did not exist in earlier bcs versions. Upon request, - older bcs directories can be patched up to work with GEOSldas (and still work with - LDASsa). +**IMPORTANT**: Beginning with GEOSldas release v18.0.0, bcs must be provided in a revised + directory layout and naming convention. On NCCS/Discover, use: +``` + BCS_PATH : /discover/nobackup/projects/gmao/bcs_shared/fvInput/ExtData/esm/tiles/ +``` + COMMONLY USED boundary conditions (bcs): @@ -327,7 +341,7 @@ COMMONLY USED boundary conditions (bcs): BCS_PATH : /discover/nobackup/projects/gmao/ssd/land/l_data/geos5/bcs/SiB2_V2_bad_lon_onDL/DC/ ``` -#### MERRA2 +#### Ganymed-4_0 (GM4): MERRA2 ``` BCS_PATH : /discover/nobackup/projects/gmao/bcs_shared/legacy_bcs/Ganymed-4_0/Ganymed-4_0_MERRA-2/ ``` @@ -349,26 +363,25 @@ COMMONLY USED boundary conditions (bcs): BCS_PATH : /discover/nobackup/projects/gmao/ssd/land/l_data/geos5/bcs/CLSM_params/mkCatchParam_SMAP_L4SM_v002/ ``` -#### Icarus-NL ("New Land"), SMAP_Nature_v7.2 +#### Icarus-NL ("New Land"): SMAP Nature Run v7.2 ``` BCS_PATH : /discover/nobackup/projects/gmao/bcs_shared/legacy_bcs/Icarus-NL/Icarus-NL_[XXXX]/ ``` Notes: -- _DON'T USE_ unless to replicate previous experiments. There is "missing" data in green*.data, nirdf*.dat, and visdf*.dat files. +- _DO NOT USE_ unless replicating previous experiments. There is "missing" data in green*.data, nirdf*.dat, and visdf*.dat files. - This path remains in place to permit recreating experiments that have used this path. - The sub-directory "Icarus-NL_MERRA-2/" contains the "new land" bcs. The string "MERRA-2" in this sub-directory name refers to ocean bcs that are not relevant for GEOSldas. -#### Icarus-NLv2, SMAP L4_SM Version 4 +#### Icarus-NLv2: SMAP L4_SM Version 4 ``` BCS_PATH : /discover/nobackup/projects/gmao/bcs_shared/legacy_bcs/Icarus-NLv2/Icarus-NLv2_[XXXX]/ ``` Notes: - Icarus-NLv2 is a update to Icarus-NL bcs. A patch has been applied to files green*.data, nirdf*.dat, and visdf*.dat. -- DEFAULT for GEOSldas v17.8.0 -#### Icarus-NLv3, SMAP_Nature_v8.1 +#### Icarus-NLv3 (NL3): SMAP Nature Run v8.1, GEOS-FP 5.25, 5.27, 5.29, GEOS-IT ``` BCS_PATH : /discover/nobackup/projects/gmao/bcs_shared/legacy_bcs/Icarus-NLv3/Icarus-NLv3_[XXXX]/ ``` @@ -376,15 +389,13 @@ Notes: Notes: - Soil parameters for a small fraction (< 0.05%) of tiles changed to correct "Mali" bug. - Vegdyn.data now netcdf4; reverts to using Dorman/Sellers veg heights (abandons JPL/Simard et al. 2011 Lidar data). -- Some underlying ASCII data files are now grouped to netcdf4. I.e., data in ar.new, bf.dat, ts.dat, etc are now in: - - clsm/catch_params.nc4 (for Catch) - - clsm/catchcn_params.nc4 (for CatchCN) +- Some underlying ASCII data files are now grouped into a netcdf4 file. I.e., data in ar.new, bf.dat, ts.dat, etc are now in: + - clsm/catch_params.nc4 + - clsm/catchcn_params.nc4 (additional parameters for CatchCN) - Generated with cvs tag Jason-3_0_LANDBCS -- DEFAULT for GEOSldas AFTER v17.8.0 -- Used in GEOS FP 5.25, 5.27, 5.29 -#### Icarus-NLv4, SMAP_Nature_v8.3, SMAP L4_SM Version 5, SMAP_Nature_v9.1, SMAP L4_SM Version 6 +#### Icarus-NLv4 (NL4): SMAP Nature Run v8.3, v9.1, SMAP L4_SM Version 5, 6 ``` BCS_PATH : /discover/nobackup/projects/gmao/smap/SMAP_L4/L4_SM/bcs/CLSM_params/Icarus-NLv4_EASE/ ``` @@ -393,7 +404,27 @@ Notes: - Icarus-NLv4 is identical to Icarus-NLv3 except that NLv4 reinstates veg heights from JPL/Simard et al. 2011 Lidar data. - Generated with GEOSldas tag v17.9.0-beta.7 under SLES11 O/S. - + +#### Icarus-NLv5 (NL5): SMAP Nature Run v10.0, SMAP L4_SM Version 7 +``` + BCS_PATH : /discover/nobackup/projects/gmao/smap/SMAP_L4/L4_SM/bcs/CLSM_params/Icarus-NLv5_EASE/ +``` + +Notes: +- Icarus-NLv5 is identical to Icarus-NLv4 except for parameters associated with PEATCLSM. + + +#### v11 +``` + BCS_PATH : /discover/nobackup/projects/gmao/bcs_shared/fvInput/ExtData/esm/tiles/v11/ +``` + +Notes: +- v11 is identical to Icarus-NLv5 (within roundoff) except for new MODIS-based snow albedo v2 parameters. + + + + diff --git a/src/Applications/LDAS_App/CMakeLists.txt b/src/Applications/LDAS_App/CMakeLists.txt index f2f5ed36..1075229e 100644 --- a/src/Applications/LDAS_App/CMakeLists.txt +++ b/src/Applications/LDAS_App/CMakeLists.txt @@ -13,16 +13,15 @@ ecbuild_add_executable ( TARGET tile_bin2nc4.x SOURCES tile_bin2nc4.F90 LIBS MAPL) - + ecbuild_add_executable ( TARGET mwrtm_bin2nc4.x SOURCES util/inputs/mwRTM_params/mwrtm_bin2nc4.F90 LIBS GEOSlandassim_GridComp) set (scripts - ldas_setup process_hist.csh - process_rst.py + remap_config_ldas.py ens_forcing/average_ensemble_forcing.py ens_forcing/ensemble_forc.py ens_forcing/regrid_forc.csh @@ -35,6 +34,10 @@ install ( DESTINATION bin ) +set(file ldas_setup) +configure_file(${file} ${file} @ONLY) +install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/${file} DESTINATION bin) + file(GLOB rc_files GEOSldas_*rc) file(GLOB nml_files LDASsa_DEFAULT*nml) @@ -42,3 +45,5 @@ install( FILES ${rc_files} ${nml_files} lenkf.j.template DESTINATION etc ) + +esma_add_subdirectories(util/inputs/ASCAT_sm_mask) diff --git a/src/Applications/LDAS_App/GEOSldas.F90 b/src/Applications/LDAS_App/GEOSldas.F90 index 4605aaad..5a09b3bc 100644 --- a/src/Applications/LDAS_App/GEOSldas.F90 +++ b/src/Applications/LDAS_App/GEOSldas.F90 @@ -4,7 +4,7 @@ program LDAS_Main - + ! !USES: use MAPL use GEOS_LDASGridCompMod, only: ROOT_SetServices => SetServices @@ -13,16 +13,15 @@ program LDAS_Main character(len=*), parameter :: Iam = "LDAS_Main" type (MAPL_Cap) :: cap - type (MAPL_FlapCLI) :: cli + type (MAPL_FargparseCLI) :: cli type (MAPL_CapOptions) :: cap_options integer :: status !EOP !---------------------------------------------------------------------- !BOC - - cli = MAPL_FlapCLI(description = 'GEOS LDAS', & - authors = 'GMAO') + + cli = MAPL_FargparseCLI() cap_options = MAPL_CapOptions(cli) cap_options%egress_file = 'EGRESS.ldas' @@ -31,5 +30,5 @@ program LDAS_Main !call MAPL_CAP(ROOT_SetServices, FinalFile='EGRESS.ldas', rc=status) !VERIFY_(status) - + end program LDAS_Main diff --git a/src/Applications/LDAS_App/GEOSldas_LDAS.rc b/src/Applications/LDAS_App/GEOSldas_LDAS.rc index 8e35303b..df92fdb0 100644 --- a/src/Applications/LDAS_App/GEOSldas_LDAS.rc +++ b/src/Applications/LDAS_App/GEOSldas_LDAS.rc @@ -11,7 +11,7 @@ #################################################################################### -# ---- Using Catchment/CatchmentCN offline? +# ---- Using Catchment[CN] offline? # # 0: DEFAULT for GCM, (WW,CH,CM,CQ,FR) are required in Catchment restart file # 1: DEFAULT for GEOSldas, (WW,CH,CM,CQ,FR) are optional @@ -20,12 +20,20 @@ # CATCHMENT_OFFLINE: 1 + +# ---- Catchment[CN] spinup mode +# +# 0 : No spinup (default) +# 1 : remove snow every Aug 1 in N. Hemisphere and every Feb 1 in S. Hemisphere +# +CATCHMENT_SPINUP: 0 + + # ---- Choice of land surface model # # 1 : Catchment model (default) # 2 : CatchmentCN-CLM4.0 -# 3 : CatchmentCN-CLM4.5 - +# LSM_CHOICE: 1 diff --git a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml index 259eeb52..ece206c4 100644 --- a/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml +++ b/src/Applications/LDAS_App/LDASsa_DEFAULT_inputs_ensupd.nml @@ -19,19 +19,22 @@ ! update type - for details see subroutine cat_enkf_update() ! (note: all 3d updates use compact support) ! -! local = "1d", regional = "3d" -! -! update_type = 0: NO assimilation, NO bias correction -! update_type = 1: 1d soil moisture analysis; sfmc obs -! update_type = 2: 3d soil moisture analysis; sfmc obs -! update_type = 3: 1d Tskin (assim incr NOT applied, use w/ bias corr) analysis; Tskin obs -! update_type = 4: 1d Tskin/ght1 (assim incr applied, use w/ or w/o bias corr) analysis; Tskin obs -! update_type = 5: 1d Tskin/ght1 (assim incr NOT applied, use w/ bias corr) analysis; Tskin obs -! update_type = 6: 1d soil moisture/Tskin/ght(1); TB obs -! update_type = 7: 3d Tskin/ght1 update; Tskin obs -! update_type = 8: 3d soil moisture/Tskin/ght(1); TB obs -! update_type = 9: 1d Tskin/ght1 update; FT obs -! update_type = 10: 3d soil moisture/Tskin/ght(1) excl. catdef unless PEATCLSM tile; TB obs +! local = "1d", regional = "3d" +! +! # = no longer supported +! +! update_type = 0: NO assimilation, NO bias correction +! # update_type = 1: 1d soil moisture analysis; sfmc obs +! # update_type = 2: 3d soil moisture analysis; sfmc obs +! update_type = 3: 1d Tskin (assim incr NOT applied, use w/ bias corr) analysis; Tskin obs +! update_type = 4: 1d Tskin/ght1 (assim incr applied, use w/ or w/o bias corr) analysis; Tskin obs +! update_type = 5: 1d Tskin/ght1 (assim incr NOT applied, use w/ bias corr) analysis; Tskin obs +! update_type = 6: 1d soil moisture/Tskin/ght(1); TB obs +! update_type = 7: 3d Tskin/ght1 update; Tskin obs +! update_type = 8: 3d soil moisture/Tskin/ght(1); TB obs +! update_type = 9: 1d Tskin/ght1 update; FT obs +! update_type = 10: 3d soil moisture/Tskin/ght(1) excl. catdef unless PEATCLSM tile; TB obs +! update_type = 13: 3d soil moisture/Tskin/ght(1) excl. catdef unless PEATCLSM tile; sfmc and TB obs update_type = 0 @@ -83,15 +86,15 @@ fcsterr_inflation_fac = -9999. ! 0 = n/a [eg., in situ obs] ! 1 = ascending ! 2 = descending -! 3 = ascending and descending +! 3 = ascending or descending ! 4 = geostationary ! %pol = polarization ! 0 = n/a [eg., multi-pol. retrieval] ! 1 = horizontal ! 2 = vertical ! 3 = ... -! %N_ang = # angles in species -! %ang = vector of angles +! %N_ang = # satellite viewing angles in species (radiance obs only) +! %ang = vector of satellite viewing angles ! %freq = frequency [Hz] ! %FOV = field-of-view *radius*, see NOTES below ! (if FOV==0. equate obs footprint w/ tile) @@ -115,6 +118,8 @@ fcsterr_inflation_fac = -9999. ! %units = units (eg., 'K' or 'm3/m3') ! %path = path to measurement files ! %name = name identifier for file containing measurements +! %maskpath = path to obs mask file +! %maskname = filename for obs mask ! %scalepath = path to file(s) with scaling parameters ! %scalename = filename for scaling parameters ! %flistpath = path to file with list of obs file names @@ -234,8 +239,7 @@ fcsterr_inflation_fac = -9999. obs_param_nml( 1)%descr = 'ae_l2_sm_a' obs_param_nml( 1)%orbit = 1 obs_param_nml( 1)%pol = 0 -obs_param_nml( 1)%N_ang = 1 -obs_param_nml( 1)%ang(1) = 55. +obs_param_nml( 1)%N_ang = 0 obs_param_nml( 1)%freq = 10.65e9 obs_param_nml( 1)%FOV = 20. obs_param_nml( 1)%FOV_units = 'km' @@ -251,6 +255,8 @@ obs_param_nml( 1)%varname = 'sfmc' obs_param_nml( 1)%units = 'm3/m3' obs_param_nml( 1)%path = '/land/l_data/AMSR/data/AMSR_E_L2_Land_V001/' obs_param_nml( 1)%name = 'AMSR_E_L2_Land_' +obs_param_nml( 1)%maskpath = '' +obs_param_nml( 1)%maskname = '' obs_param_nml( 1)%scalepath = '' obs_param_nml( 1)%scalename = '' obs_param_nml( 1)%flistpath = '' @@ -270,8 +276,7 @@ obs_param_nml( 1)%adapt = 0 obs_param_nml( 2)%descr = 'ae_l2_sm_d' obs_param_nml( 2)%orbit = 2 obs_param_nml( 2)%pol = 0 -obs_param_nml( 2)%N_ang = 1 -obs_param_nml( 2)%ang(1) = 55. +obs_param_nml( 2)%N_ang = 0 obs_param_nml( 2)%freq = 10.65e9 obs_param_nml( 2)%FOV = 20. obs_param_nml( 2)%FOV_units = 'km' @@ -287,6 +292,8 @@ obs_param_nml( 2)%varname = 'sfmc' obs_param_nml( 2)%units = 'm3/m3' obs_param_nml( 2)%path = '/land/l_data/AMSR/data/AMSR_E_L2_Land_V001/' obs_param_nml( 2)%name = 'AMSR_E_L2_Land_' +obs_param_nml( 2)%maskpath = '' +obs_param_nml( 2)%maskname = '' obs_param_nml( 2)%scalepath = '' obs_param_nml( 2)%scalename = '' obs_param_nml( 2)%flistpath = '' @@ -322,6 +329,8 @@ obs_param_nml( 3)%varname = 'tsurf' obs_param_nml( 3)%units = 'K' obs_param_nml( 3)%path = '/land/l_data/ISCCP/GSWP2_1by1_V1/' obs_param_nml( 3)%name = 'isccpdx_tskin.' +obs_param_nml( 3)%maskpath = '' +obs_param_nml( 3)%maskname = '' obs_param_nml( 3)%scalepath = '' obs_param_nml( 3)%scalename = '' obs_param_nml( 3)%flistpath = '' @@ -357,6 +366,8 @@ obs_param_nml( 4)%varname = 'sfmc' obs_param_nml( 4)%units = 'm3/m3' obs_param_nml( 4)%path = '/land/l_data/RedArk/Retrievals_36km/retrievals_20060508/' obs_param_nml( 4)%name = 'SM_retrieval.' +obs_param_nml( 4)%maskpath = '' +obs_param_nml( 4)%maskname = '' obs_param_nml( 4)%scalepath = '.' obs_param_nml( 4)%scalename = '.' obs_param_nml( 4)%flistpath = '' @@ -392,6 +403,8 @@ obs_param_nml( 5)%varname = 'sfmc' obs_param_nml( 5)%units = 'm3/m3' obs_param_nml( 5)%path = '/land/l_data/RedArk/Truth/50mm_Soil_Moisture_Truth/' obs_param_nml( 5)%name = 'red_ark_50mm.sm.' +obs_param_nml( 5)%maskpath = '' +obs_param_nml( 5)%maskname = '' obs_param_nml( 5)%scalepath = '.' obs_param_nml( 5)%scalename = '.' obs_param_nml( 5)%flistpath = '' @@ -427,6 +440,8 @@ obs_param_nml( 6)%varname = 'rzmc' obs_param_nml( 6)%units = 'm3/m3' obs_param_nml( 6)%path = '/land/l_data/RedArk/Truth/400mm_Soil_Moisture_Truth/' obs_param_nml( 6)%name = 'red_ark_400mm.sm.' +obs_param_nml( 6)%maskpath = '' +obs_param_nml( 6)%maskname = '' obs_param_nml( 6)%scalepath = '.' obs_param_nml( 6)%scalename = '.' obs_param_nml( 6)%flistpath = '' @@ -462,6 +477,8 @@ obs_param_nml( 7)%varname = 'sfmc' obs_param_nml( 7)%units = 'm3/m3' obs_param_nml( 7)%path = '/land/l_data/RedArk_OSSE/data/Retrievals_CLSM_synth/M0001_P0001_R0001_URI/std_synth_obs_0.020/' obs_param_nml( 7)%name = 'CLSM_synth_sm.' +obs_param_nml( 7)%maskpath = '' +obs_param_nml( 7)%maskname = '' obs_param_nml( 7)%scalepath = '.' obs_param_nml( 7)%scalename = '.' obs_param_nml( 7)%flistpath = '' @@ -497,6 +514,8 @@ obs_param_nml( 8)%varname = 'sfmc' obs_param_nml( 8)%units = 'm3/m3' obs_param_nml( 8)%path = '/discover/nobackup/vmaggion/Synth_sfmc/radar_sim/std_synth_sfmc_0.040/' obs_param_nml( 8)%name = 'synth_sfmc_VivianaOK_' +obs_param_nml( 8)%maskpath = '' +obs_param_nml( 8)%maskname = '' obs_param_nml( 8)%scalepath = '.' obs_param_nml( 8)%scalename = '.' obs_param_nml( 8)%flistpath = '' @@ -516,8 +535,7 @@ obs_param_nml( 8)%adapt = 0 obs_param_nml( 9)%descr = 'ae_sm_LPRM_a_C' obs_param_nml( 9)%orbit = 1 obs_param_nml( 9)%pol = 0 -obs_param_nml( 9)%N_ang = 1 -obs_param_nml( 9)%ang(1) = 55. +obs_param_nml( 9)%N_ang = 0 obs_param_nml( 9)%freq = 6.925e9 obs_param_nml( 9)%FOV = 20. obs_param_nml( 9)%FOV_units = 'km' @@ -533,6 +551,8 @@ obs_param_nml( 9)%varname = 'sfmc' obs_param_nml( 9)%units = 'm3/m3' obs_param_nml( 9)%path = '/land/l_data/AMSR/data/AMSR_E_sm_LPRM/L2_EASE/bin/' obs_param_nml( 9)%name = 'AMSRsmUVA.EASE.v03.' +obs_param_nml( 9)%maskpath = '' +obs_param_nml( 9)%maskname = '' obs_param_nml( 9)%scalepath = '' obs_param_nml( 9)%scalename = '' obs_param_nml( 9)%flistpath = '' @@ -552,8 +572,7 @@ obs_param_nml( 9)%adapt = 0 obs_param_nml(10)%descr = 'ae_sm_LPRM_d_C' obs_param_nml(10)%orbit = 2 obs_param_nml(10)%pol = 0 -obs_param_nml(10)%N_ang = 1 -obs_param_nml(10)%ang(1) = 55. +obs_param_nml(10)%N_ang = 0 obs_param_nml(10)%freq = 6.925e9 obs_param_nml(10)%FOV = 20. obs_param_nml(10)%FOV_units = 'km' @@ -569,6 +588,8 @@ obs_param_nml(10)%varname = 'sfmc' obs_param_nml(10)%units = 'm3/m3' obs_param_nml(10)%path = '/land/l_data/AMSR/data/AMSR_E_sm_LPRM/L2_EASE/bin/' obs_param_nml(10)%name = 'AMSRsmUVA.EASE.v03.' +obs_param_nml(10)%maskpath = '' +obs_param_nml(10)%maskname = '' obs_param_nml(10)%scalepath = '' obs_param_nml(10)%scalename = '' obs_param_nml(10)%flistpath = '' @@ -588,8 +609,7 @@ obs_param_nml(10)%adapt = 0 obs_param_nml(11)%descr = 'ae_sm_LPRM_a_X' obs_param_nml(11)%orbit = 1 obs_param_nml(11)%pol = 0 -obs_param_nml(11)%N_ang = 1 -obs_param_nml(11)%ang(1) = 55. +obs_param_nml(11)%N_ang = 0 obs_param_nml(11)%freq = 10.65e9 obs_param_nml(11)%FOV = 20. obs_param_nml(11)%FOV_units = 'km' @@ -605,6 +625,8 @@ obs_param_nml(11)%varname = 'sfmc' obs_param_nml(11)%units = 'm3/m3' obs_param_nml(11)%path = '/land/l_data/AMSR/data/AMSR_E_sm_LPRM/L2_EASE/bin/' obs_param_nml(11)%name = 'AMSRsmUVA.EASE.v03.' +obs_param_nml(11)%maskpath = '' +obs_param_nml(11)%maskname = '' obs_param_nml(11)%scalepath = '' obs_param_nml(11)%scalename = '' obs_param_nml(11)%flistpath = '' @@ -624,8 +646,7 @@ obs_param_nml(11)%adapt = 0 obs_param_nml(12)%descr = 'ae_sm_LPRM_d_X' obs_param_nml(12)%orbit = 2 obs_param_nml(12)%pol = 0 -obs_param_nml(12)%N_ang = 1 -obs_param_nml(12)%ang(1) = 55. +obs_param_nml(12)%N_ang = 0 obs_param_nml(12)%freq = 10.65e9 obs_param_nml(12)%FOV = 20. obs_param_nml(12)%FOV_units = 'km' @@ -641,6 +662,8 @@ obs_param_nml(12)%varname = 'sfmc' obs_param_nml(12)%units = 'm3/m3' obs_param_nml(12)%path = '/land/l_data/AMSR/data/AMSR_E_sm_LPRM/L2_EASE/bin/' obs_param_nml(12)%name = 'AMSRsmUVA.EASE.v03.' +obs_param_nml(12)%maskpath = '' +obs_param_nml(12)%maskname = '' obs_param_nml(12)%scalepath = '' obs_param_nml(12)%scalename = '' obs_param_nml(12)%flistpath = '' @@ -680,6 +703,8 @@ obs_param_nml(13)%varname = 'sfmc' obs_param_nml(13)%units = 'm3/m3' obs_param_nml(13)%path = '/discover/nobackup/rreichle/l_data/ASCAT/TUW_W5.4/EASE/CONUS/bin/' obs_param_nml(13)%name = 'SDS_' +obs_param_nml(13)%maskpath = '' +obs_param_nml(13)%maskname = '' obs_param_nml(13)%scalepath = '' obs_param_nml(13)%scalename = '' obs_param_nml(13)%flistpath = '' @@ -719,6 +744,8 @@ obs_param_nml(14)%varname = 'sfmc' obs_param_nml(14)%units = 'm3/m3' obs_param_nml(14)%path = '/discover/nobackup/rreichle/l_data/ASCAT/TUW_W5.4/EASE/CONUS/bin/' obs_param_nml(14)%name = 'SDS_' +obs_param_nml(14)%maskpath = '' +obs_param_nml(14)%maskname = '' obs_param_nml(14)%scalepath = '' obs_param_nml(14)%scalename = '' obs_param_nml(14)%flistpath = '' @@ -754,6 +781,8 @@ obs_param_nml(15)%varname = 'sfmc' obs_param_nml(15)%units = 'm3/m3' obs_param_nml(15)%path = '/discover/nobackup/projects/gmao/ssd/land/l_data/SMOS/EASEv2/ESA_REPR/SMOS_M36_SMUDP2/' obs_param_nml(15)%name = '' +obs_param_nml(15)%maskpath = '' +obs_param_nml(15)%maskname = '' obs_param_nml(15)%scalepath = '' obs_param_nml(15)%scalename = '' obs_param_nml(15)%flistpath = '' @@ -789,6 +818,8 @@ obs_param_nml(16)%varname = 'sfmc' obs_param_nml(16)%units = 'm3/m3' obs_param_nml(16)%path = '/discover/nobackup/projects/gmao/ssd/land/l_data/SMOS/EASEv2/ESA_REPR/SMOS_M36_SMUDP2/' obs_param_nml(16)%name = '' +obs_param_nml(16)%maskpath = '' +obs_param_nml(16)%maskname = '' obs_param_nml(16)%scalepath = '' obs_param_nml(16)%scalename = '' obs_param_nml(16)%flistpath = '' @@ -872,6 +903,8 @@ obs_param_nml(17)%varname = 'Tb' obs_param_nml(17)%units = 'K' obs_param_nml(17)%path = '/discover/nobackup/projects/gmao/ssd/land/l_data/SMOS/EASEv2/ESA_REPR/SMOS_M36_SCLF1C_reg_nosky_noatm_v620_ESA_v102/' obs_param_nml(17)%name = '' +obs_param_nml(17)%maskpath = '' +obs_param_nml(17)%maskname = '' obs_param_nml(17)%scalepath = '' obs_param_nml(17)%scalename = '' obs_param_nml(17)%flistpath = '' @@ -914,6 +947,8 @@ obs_param_nml(18)%varname = 'Tb' obs_param_nml(18)%units = 'K' obs_param_nml(18)%path = '/discover/nobackup/projects/gmao/ssd/land/l_data/SMOS/EASEv2/ESA_REPR/SMOS_M36_SCLF1C_reg_nosky_noatm_v620_ESA_v102/' obs_param_nml(18)%name = '' +obs_param_nml(18)%maskpath = '' +obs_param_nml(18)%maskname = '' obs_param_nml(18)%scalepath = '' obs_param_nml(18)%scalename = '' obs_param_nml(18)%flistpath = '' @@ -956,6 +991,8 @@ obs_param_nml(19)%varname = 'Tb' obs_param_nml(19)%units = 'K' obs_param_nml(19)%path = '/discover/nobackup/projects/gmao/ssd/land/l_data/SMOS/EASEv2/ESA_REPR/SMOS_M36_SCLF1C_reg_nosky_noatm_v620_ESA_v102/' obs_param_nml(19)%name = '' +obs_param_nml(19)%maskpath = '' +obs_param_nml(19)%maskname = '' obs_param_nml(19)%scalepath = '' obs_param_nml(19)%scalename = '' obs_param_nml(19)%flistpath = '' @@ -998,6 +1035,8 @@ obs_param_nml(20)%varname = 'Tb' obs_param_nml(20)%units = 'K' obs_param_nml(20)%path = '/discover/nobackup/projects/gmao/ssd/land/l_data/SMOS/EASEv2/ESA_REPR/SMOS_M36_SCLF1C_reg_nosky_noatm_v620_ESA_v102/' obs_param_nml(20)%name = '' +obs_param_nml(20)%maskpath = '' +obs_param_nml(20)%maskname = '' obs_param_nml(20)%scalepath = '' obs_param_nml(20)%scalename = '' obs_param_nml(20)%flistpath = '' @@ -1034,6 +1073,8 @@ obs_param_nml(21)%varname = 'Tb' obs_param_nml(21)%units = 'K' obs_param_nml(21)%path = '/discover/nobackup/projects/gmao/ssd/land/l_data/SMOS/EASEv2/ESA_REPR/SMOS_M36_SCLF1C_fit_nosky_noatm_v620_ESA_v102/SMOS_fit_poly2/' obs_param_nml(21)%name = '' +obs_param_nml(21)%maskpath = '' +obs_param_nml(21)%maskname = '' obs_param_nml(21)%scalepath = '' obs_param_nml(21)%scalename = '' obs_param_nml(21)%flistpath = '' @@ -1070,6 +1111,8 @@ obs_param_nml(22)%varname = 'Tb' obs_param_nml(22)%units = 'K' obs_param_nml(22)%path = '/discover/nobackup/projects/gmao/ssd/land/l_data/SMOS/EASEv2/ESA_REPR/SMOS_M36_SCLF1C_fit_nosky_noatm_v620_ESA_v102/SMOS_fit_poly2/' obs_param_nml(22)%name = '' +obs_param_nml(22)%maskpath = '' +obs_param_nml(22)%maskname = '' obs_param_nml(22)%scalepath = '' obs_param_nml(22)%scalename = '' obs_param_nml(22)%flistpath = '' @@ -1106,6 +1149,8 @@ obs_param_nml(23)%varname = 'Tb' obs_param_nml(23)%units = 'K' obs_param_nml(23)%path = '/discover/nobackup/projects/gmao/ssd/land/l_data/SMOS/EASEv2/ESA_REPR/SMOS_M36_SCLF1C_fit_nosky_noatm_v620_ESA_v102/SMOS_fit_poly2/' obs_param_nml(23)%name = '' +obs_param_nml(23)%maskpath = '' +obs_param_nml(23)%maskname = '' obs_param_nml(23)%scalepath = '' obs_param_nml(23)%scalename = '' obs_param_nml(23)%flistpath = '' @@ -1142,6 +1187,8 @@ obs_param_nml(24)%varname = 'Tb' obs_param_nml(24)%units = 'K' obs_param_nml(24)%path = '/discover/nobackup/projects/gmao/ssd/land/l_data/SMOS/EASEv2/ESA_REPR/SMOS_M36_SCLF1C_fit_nosky_noatm_v620_ESA_v102/SMOS_fit_poly2/' obs_param_nml(24)%name = '' +obs_param_nml(24)%maskpath = '' +obs_param_nml(24)%maskname = '' obs_param_nml(24)%scalepath = '' obs_param_nml(24)%scalename = '' obs_param_nml(24)%flistpath = '' @@ -1157,41 +1204,40 @@ obs_param_nml(24)%adapt = 0 ! -------------------------------------------------------------------- ! -! 21 = MODIS SCF -! -! TO DO: which platform? -! TO DO: figure out orbit (day!) - -obs_param_nml(25)%descr = 'MODIS_SCF' -obs_param_nml(25)%orbit = 0 -obs_param_nml(25)%pol = 0 -obs_param_nml(25)%N_ang = 0 -obs_param_nml(25)%freq = 0. -obs_param_nml(25)%FOV = 0. -obs_param_nml(25)%FOV_units = 'deg' +! 25 = [empty] + +obs_param_nml(25)%descr = 'NULL' +obs_param_nml(25)%orbit = -9999 +obs_param_nml(25)%pol = -9999 +obs_param_nml(25)%N_ang = -9999 +obs_param_nml(25)%freq = -9999. +obs_param_nml(25)%FOV = -9999. +obs_param_nml(25)%FOV_units = 'NULL' obs_param_nml(25)%assim = .false. obs_param_nml(25)%scale = .false. obs_param_nml(25)%getinnov = .false. -obs_param_nml(25)%RTM_ID = 0 -obs_param_nml(25)%bias_Npar = 0 -obs_param_nml(25)%bias_trel = 864000 -obs_param_nml(25)%bias_tcut = 432000 +obs_param_nml(25)%RTM_ID = -9999 +obs_param_nml(25)%bias_Npar = -9999 +obs_param_nml(25)%bias_trel = -9999 +obs_param_nml(25)%bias_tcut = -9999 obs_param_nml(25)%nodata = -9999. -obs_param_nml(25)%varname = 'asnow' -obs_param_nml(25)%units = 'm2/m2' -obs_param_nml(25)%path = '' -obs_param_nml(25)%name = '' -obs_param_nml(25)%scalepath = '' -obs_param_nml(25)%scalename = '' -obs_param_nml(25)%flistpath = '' -obs_param_nml(25)%flistname = '' -obs_param_nml(25)%errstd = .0 -obs_param_nml(25)%std_normal_max = 2.5 -obs_param_nml(25)%zeromean = .true. +obs_param_nml(25)%varname = 'NULL' +obs_param_nml(25)%units = 'NULL' +obs_param_nml(25)%path = 'NULL' +obs_param_nml(25)%name = 'NULL' +obs_param_nml(25)%maskpath = 'NULL' +obs_param_nml(25)%maskname = 'NULL' +obs_param_nml(25)%scalepath = 'NULL' +obs_param_nml(25)%scalename = 'NULL' +obs_param_nml(25)%flistpath = 'NULL' +obs_param_nml(25)%flistname = 'NULL' +obs_param_nml(25)%errstd = -9999. +obs_param_nml(25)%std_normal_max = -9999. +obs_param_nml(25)%zeromean = .false. obs_param_nml(25)%coarsen_pert = .false. -obs_param_nml(25)%xcorr = 0. -obs_param_nml(25)%ycorr = 0. -obs_param_nml(25)%adapt = 0 +obs_param_nml(25)%xcorr = -9999. +obs_param_nml(25)%ycorr = -9999. +obs_param_nml(25)%adapt = -9999 ! -------------------------------------------------------------------- ! @@ -1217,6 +1263,8 @@ obs_param_nml(26)%varname = 'tsurf' obs_param_nml(26)%units = 'K' obs_param_nml(26)%path = '/discover/nobackup/csdraper/LaRC_float/GOES-WEST/' obs_param_nml(26)%name = 'larc-v3.inst3_g15_Nch.' +obs_param_nml(26)%maskpath = '' +obs_param_nml(26)%maskname = '' obs_param_nml(26)%scalepath = '' obs_param_nml(26)%scalename = '' obs_param_nml(26)%flistpath = '' @@ -1253,6 +1301,8 @@ obs_param_nml(27)%varname = 'tsurf' obs_param_nml(27)%units = 'K' obs_param_nml(27)%path = '/discover/nobackup/csdraper/LaRC_float/v4/GOES-EAST/' obs_param_nml(27)%name = 'larc-v3.inst3_g13_Nch.' +obs_param_nml(27)%maskpath = '' +obs_param_nml(27)%maskname = '' obs_param_nml(27)%scalepath = '' obs_param_nml(27)%scalename = '' obs_param_nml(27)%flistpath = '' @@ -1289,6 +1339,8 @@ obs_param_nml(28)%varname = 'tsurf' obs_param_nml(28)%units = 'K' obs_param_nml(28)%path = '/discover/nobackup/csdraper/LaRC_float/MET09/' obs_param_nml(28)%name = 'larc-v3.inst3_mt9_Nch.' +obs_param_nml(28)%maskpath = '' +obs_param_nml(28)%maskname = '' obs_param_nml(28)%scalepath = '' obs_param_nml(28)%scalename = '' obs_param_nml(28)%flistpath = '' @@ -1325,6 +1377,8 @@ obs_param_nml(29)%varname = 'tsurf' obs_param_nml(29)%units = 'K' obs_param_nml(29)%path = '/discover/nobackup/csdraper/LaRC_float/FY2E/' obs_param_nml(29)%name = 'larc-v3.inst3_fye_Nch.' +obs_param_nml(29)%maskpath = '' +obs_param_nml(29)%maskname = '' obs_param_nml(29)%scalepath = '' obs_param_nml(29)%scalename = '' obs_param_nml(29)%flistpath = '' @@ -1361,6 +1415,8 @@ obs_param_nml(30)%varname = 'tsurf' obs_param_nml(30)%units = 'K' obs_param_nml(30)%path = '/discover/nobackup/csdraper/LaRC_float/MTSAT-2/' obs_param_nml(30)%name = 'larc-v3.inst3_mt2_Nch.' +obs_param_nml(30)%maskpath = '' +obs_param_nml(30)%maskname = '' obs_param_nml(30)%scalepath = '' obs_param_nml(30)%scalename = '' obs_param_nml(30)%flistpath = '' @@ -1407,6 +1463,8 @@ obs_param_nml(31)%varname = 'Tb' obs_param_nml(31)%units = 'K' obs_param_nml(31)%path = '/discover/nobackup/projects/gmao/smap/SMAP_L4/SMAP/L1C_TB/' obs_param_nml(31)%name = '' +obs_param_nml(31)%maskpath = '' +obs_param_nml(31)%maskname = '' obs_param_nml(31)%scalepath = '' obs_param_nml(31)%scalename = '' obs_param_nml(31)%flistpath = '' @@ -1443,6 +1501,8 @@ obs_param_nml(32)%varname = 'Tb' obs_param_nml(32)%units = 'K' obs_param_nml(32)%path = '/discover/nobackup/projects/gmao/smap/SMAP_L4/SMAP/L1C_TB/' obs_param_nml(32)%name = '' +obs_param_nml(32)%maskpath = '' +obs_param_nml(32)%maskname = '' obs_param_nml(32)%scalepath = '' obs_param_nml(32)%scalename = '' obs_param_nml(32)%flistpath = '' @@ -1479,6 +1539,8 @@ obs_param_nml(33)%varname = 'Tb' obs_param_nml(33)%units = 'K' obs_param_nml(33)%path = '/discover/nobackup/projects/gmao/smap/SMAP_L4/SMAP/L1C_TB/' obs_param_nml(33)%name = '' +obs_param_nml(33)%maskpath = '' +obs_param_nml(33)%maskname = '' obs_param_nml(33)%scalepath = '' obs_param_nml(33)%scalename = '' obs_param_nml(33)%flistpath = '' @@ -1515,6 +1577,8 @@ obs_param_nml(34)%varname = 'Tb' obs_param_nml(34)%units = 'K' obs_param_nml(34)%path = '/discover/nobackup/projects/gmao/smap/SMAP_L4/SMAP/L1C_TB/' obs_param_nml(34)%name = '' +obs_param_nml(34)%maskpath = '' +obs_param_nml(34)%maskname = '' obs_param_nml(34)%scalepath = '' obs_param_nml(34)%scalename = '' obs_param_nml(34)%flistpath = '' @@ -1562,6 +1626,8 @@ obs_param_nml(35)%varname = 'Tb' obs_param_nml(35)%units = 'K' obs_param_nml(35)%path = '/discover/nobackup/projects/gmao/smap/SMAP_L4/SMAP/L2_SM_AP/' obs_param_nml(35)%name = '' +obs_param_nml(35)%maskpath = '' +obs_param_nml(35)%maskname = '' obs_param_nml(35)%scalepath = '' obs_param_nml(35)%scalename = '' obs_param_nml(35)%flistpath = '' @@ -1598,6 +1664,8 @@ obs_param_nml(36)%varname = 'Tb' obs_param_nml(36)%units = 'K' obs_param_nml(36)%path = '/discover/nobackup/projects/gmao/smap/SMAP_L4/SMAP/L2_SM_AP/' obs_param_nml(36)%name = '' +obs_param_nml(36)%maskpath = '' +obs_param_nml(36)%maskname = '' obs_param_nml(36)%scalepath = '' obs_param_nml(36)%scalename = '' obs_param_nml(36)%flistpath = '' @@ -1634,6 +1702,8 @@ obs_param_nml(37)%varname = 'Tb' obs_param_nml(37)%units = 'K' obs_param_nml(37)%path = '/discover/nobackup/projects/gmao/smap/SMAP_L4/SMAP/L2_SM_AP/' obs_param_nml(37)%name = '' +obs_param_nml(37)%maskpath = '' +obs_param_nml(37)%maskname = '' obs_param_nml(37)%scalepath = '' obs_param_nml(37)%scalename = '' obs_param_nml(37)%flistpath = '' @@ -1670,6 +1740,8 @@ obs_param_nml(38)%varname = 'Tb' obs_param_nml(38)%units = 'K' obs_param_nml(38)%path = '/discover/nobackup/projects/gmao/smap/SMAP_L4/SMAP/L2_SM_AP/' obs_param_nml(38)%name = '' +obs_param_nml(38)%maskpath = '' +obs_param_nml(38)%maskname = '' obs_param_nml(38)%scalepath = '' obs_param_nml(38)%scalename = '' obs_param_nml(38)%flistpath = '' @@ -1689,8 +1761,7 @@ obs_param_nml(38)%adapt = 0 obs_param_nml(39)%descr = 'SMAP_L2AP_FT_A' obs_param_nml(39)%orbit = 1 obs_param_nml(39)%pol = 0 -obs_param_nml(39)%N_ang = 1 -obs_param_nml(39)%ang(1) = 40. +obs_param_nml(39)%N_ang = 0 obs_param_nml(39)%freq = 1.26e9 obs_param_nml(39)%FOV = 5. obs_param_nml(39)%FOV_units = 'km' @@ -1706,6 +1777,8 @@ obs_param_nml(39)%varname = 'FT' obs_param_nml(39)%units = '-' obs_param_nml(39)%path = '/discover/nobackup/projects/gmao/smap/SMAP_L4/SMAP/L2_SM_AP/' obs_param_nml(39)%name = '' +obs_param_nml(39)%maskpath = '' +obs_param_nml(39)%maskname = '' obs_param_nml(39)%scalepath = '' obs_param_nml(39)%scalename = '' obs_param_nml(39)%flistpath = '' @@ -1725,8 +1798,7 @@ obs_param_nml(39)%adapt = 0 obs_param_nml(40)%descr = 'SMAP_L2AP_FT_D' obs_param_nml(40)%orbit = 2 obs_param_nml(40)%pol = 0 -obs_param_nml(40)%N_ang = 1 -obs_param_nml(40)%ang(1) = 40. +obs_param_nml(40)%N_ang = 0 obs_param_nml(40)%freq = 1.26e9 obs_param_nml(40)%FOV = 5. obs_param_nml(40)%FOV_units = 'km' @@ -1742,6 +1814,8 @@ obs_param_nml(40)%varname = 'FT' obs_param_nml(40)%units = '-' obs_param_nml(40)%path = '/discover/nobackup/projects/gmao/smap/SMAP_L4/SMAP/L2_SM_AP/' obs_param_nml(40)%name = '' +obs_param_nml(40)%maskpath = '' +obs_param_nml(40)%maskname = '' obs_param_nml(40)%scalepath = '' obs_param_nml(40)%scalename = '' obs_param_nml(40)%flistpath = '' @@ -1800,6 +1874,8 @@ obs_param_nml(41)%varname = 'Tb' obs_param_nml(41)%units = 'K' obs_param_nml(41)%path = '/discover/nobackup/projects/gmao/smap/SMAP_L4/SMAP/L1C_TB_E/' obs_param_nml(41)%name = '' +obs_param_nml(41)%maskpath = '' +obs_param_nml(41)%maskname = '' obs_param_nml(41)%scalepath = '' obs_param_nml(41)%scalename = '' obs_param_nml(41)%flistpath = '' @@ -1836,6 +1912,8 @@ obs_param_nml(42)%varname = 'Tb' obs_param_nml(42)%units = 'K' obs_param_nml(42)%path = '/discover/nobackup/projects/gmao/smap/SMAP_L4/SMAP/L1C_TB_E/' obs_param_nml(42)%name = '' +obs_param_nml(42)%maskpath = '' +obs_param_nml(42)%maskname = '' obs_param_nml(42)%scalepath = '' obs_param_nml(42)%scalename = '' obs_param_nml(42)%flistpath = '' @@ -1872,6 +1950,8 @@ obs_param_nml(43)%varname = 'Tb' obs_param_nml(43)%units = 'K' obs_param_nml(43)%path = '/discover/nobackup/projects/gmao/smap/SMAP_L4/SMAP/L1C_TB_E/' obs_param_nml(43)%name = '' +obs_param_nml(43)%maskpath = '' +obs_param_nml(43)%maskname = '' obs_param_nml(43)%scalepath = '' obs_param_nml(43)%scalename = '' obs_param_nml(43)%flistpath = '' @@ -1908,6 +1988,8 @@ obs_param_nml(44)%varname = 'Tb' obs_param_nml(44)%units = 'K' obs_param_nml(44)%path = '/discover/nobackup/projects/gmao/smap/SMAP_L4/SMAP/L1C_TB_E/' obs_param_nml(44)%name = '' +obs_param_nml(44)%maskpath = '' +obs_param_nml(44)%maskname = '' obs_param_nml(44)%scalepath = '' obs_param_nml(44)%scalename = '' obs_param_nml(44)%flistpath = '' @@ -1944,6 +2026,8 @@ obs_param_nml(45)%varname = 'Tb' obs_param_nml(45)%units = 'K' obs_param_nml(45)%path = '/discover/nobackup/projects/gmao/smap/SMAP_L4/SMAP/L1C_TB_E/' obs_param_nml(45)%name = '' +obs_param_nml(45)%maskpath = '' +obs_param_nml(45)%maskname = '' obs_param_nml(45)%scalepath = '' obs_param_nml(45)%scalename = '' obs_param_nml(45)%flistpath = '' @@ -1980,6 +2064,8 @@ obs_param_nml(46)%varname = 'Tb' obs_param_nml(46)%units = 'K' obs_param_nml(46)%path = '/discover/nobackup/projects/gmao/smap/SMAP_L4/SMAP/L1C_TB_E/' obs_param_nml(46)%name = '' +obs_param_nml(46)%maskpath = '' +obs_param_nml(46)%maskname = '' obs_param_nml(46)%scalepath = '' obs_param_nml(46)%scalename = '' obs_param_nml(46)%flistpath = '' @@ -2016,6 +2102,8 @@ obs_param_nml(47)%varname = 'Tb' obs_param_nml(47)%units = 'K' obs_param_nml(47)%path = '/discover/nobackup/projects/gmao/smap/SMAP_L4/SMAP/L1C_TB_E/' obs_param_nml(47)%name = '' +obs_param_nml(47)%maskpath = '' +obs_param_nml(47)%maskname = '' obs_param_nml(47)%scalepath = '' obs_param_nml(47)%scalename = '' obs_param_nml(47)%flistpath = '' @@ -2052,6 +2140,8 @@ obs_param_nml(48)%varname = 'Tb' obs_param_nml(48)%units = 'K' obs_param_nml(48)%path = '/discover/nobackup/projects/gmao/smap/SMAP_L4/SMAP/L1C_TB_E/' obs_param_nml(48)%name = '' +obs_param_nml(48)%maskpath = '' +obs_param_nml(48)%maskname = '' obs_param_nml(48)%scalepath = '' obs_param_nml(48)%scalename = '' obs_param_nml(48)%flistpath = '' @@ -2064,6 +2154,206 @@ obs_param_nml(48)%xcorr = 0.1875 obs_param_nml(48)%ycorr = 0.1875 obs_param_nml(48)%adapt = 0 +! -------------------------------------------------------------------- +! +! 49 = ASCAT_META_SM (ASCAT soil moisture ascending and descending orbits) +! +! https://navigator.eumetsat.int/product/EO:EUM:DAT:METOP:SOMO25 + +obs_param_nml(49)%descr = 'ASCAT_META_SM' +obs_param_nml(49)%orbit = 3 +obs_param_nml(49)%pol = 0 +obs_param_nml(49)%N_ang = 0 +obs_param_nml(49)%freq = 0 +obs_param_nml(49)%FOV = 20. +obs_param_nml(49)%FOV_units = 'km' +obs_param_nml(49)%assim = .false. +obs_param_nml(49)%scale = .false. +obs_param_nml(49)%getinnov = .false. +obs_param_nml(49)%RTM_ID = 0 +obs_param_nml(49)%bias_Npar = 0 +obs_param_nml(49)%bias_trel = 864000 +obs_param_nml(49)%bias_tcut = 432000 +obs_param_nml(49)%nodata = -9999. +obs_param_nml(49)%varname = 'sfds' +obs_param_nml(49)%units = '%' +obs_param_nml(49)%path = '/discover/nobackup/projects/gmao/smap/SMAP_Nature/ASCAT_EUMETSAT/Metop_A/' +obs_param_nml(49)%name = 'M02-ASCA-ASCSMO02' +obs_param_nml(49)%maskpath = '' +obs_param_nml(49)%maskname = '' +obs_param_nml(49)%scalepath = '' +obs_param_nml(49)%scalename = '' +obs_param_nml(49)%flistpath = '' +obs_param_nml(49)%flistname = '' +obs_param_nml(49)%errstd = 9. +obs_param_nml(49)%std_normal_max = 2.5 +obs_param_nml(49)%zeromean = .true. +obs_param_nml(49)%coarsen_pert = .false. +obs_param_nml(49)%xcorr = 0.25 +obs_param_nml(49)%ycorr = 0.25 +obs_param_nml(49)%adapt = 0 + +! -------------------------------------------------------------------- +! +! 50 = ASCAT_METB_SM (ASCAT soil moisture ascending and descending orbits) +! +! https://navigator.eumetsat.int/product/EO:EUM:DAT:METOP:SOMO25 + +obs_param_nml(50)%descr = 'ASCAT_METB_SM' +obs_param_nml(50)%orbit = 3 +obs_param_nml(50)%pol = 0 +obs_param_nml(50)%N_ang = 0 +obs_param_nml(50)%freq = 0 +obs_param_nml(50)%FOV = 20. +obs_param_nml(50)%FOV_units = 'km' +obs_param_nml(50)%assim = .false. +obs_param_nml(50)%scale = .false. +obs_param_nml(50)%getinnov = .false. +obs_param_nml(50)%RTM_ID = 0 +obs_param_nml(50)%bias_Npar = 0 +obs_param_nml(50)%bias_trel = 864000 +obs_param_nml(50)%bias_tcut = 432000 +obs_param_nml(50)%nodata = -9999. +obs_param_nml(50)%varname = 'sfds' +obs_param_nml(50)%units = '%' +obs_param_nml(50)%path = '/discover/nobackup/projects/gmao/smap/SMAP_Nature/ASCAT_EUMETSAT/Metop_B/' +obs_param_nml(50)%name = 'M01-ASCA-ASCSMO02' +obs_param_nml(50)%maskpath = '' +obs_param_nml(50)%maskname = '' +obs_param_nml(50)%scalepath = '' +obs_param_nml(50)%scalename = '' +obs_param_nml(50)%flistpath = '' +obs_param_nml(50)%flistname = '' +obs_param_nml(50)%errstd = 9. +obs_param_nml(50)%std_normal_max = 2.5 +obs_param_nml(50)%zeromean = .true. +obs_param_nml(50)%coarsen_pert = .false. +obs_param_nml(50)%xcorr = 0.25 +obs_param_nml(50)%ycorr = 0.25 +obs_param_nml(50)%adapt = 0 + +! -------------------------------------------------------------------- +! +! 51 = ASCAT_METC_SM (ASCAT soil moisture ascending and descending orbits) +! +! https://navigator.eumetsat.int/product/EO:EUM:DAT:METOP:SOMO25 + +obs_param_nml(51)%descr = 'ASCAT_METC_SM' +obs_param_nml(51)%orbit = 3 +obs_param_nml(51)%pol = 0 +obs_param_nml(51)%N_ang = 0 +obs_param_nml(51)%freq = 0 +obs_param_nml(51)%FOV = 20. +obs_param_nml(51)%FOV_units = 'km' +obs_param_nml(51)%assim = .false. +obs_param_nml(51)%scale = .false. +obs_param_nml(51)%getinnov = .false. +obs_param_nml(51)%RTM_ID = 0 +obs_param_nml(51)%bias_Npar = 0 +obs_param_nml(51)%bias_trel = 864000 +obs_param_nml(51)%bias_tcut = 432000 +obs_param_nml(51)%nodata = -9999. +obs_param_nml(51)%varname = 'sfds' +obs_param_nml(51)%units = '%' +obs_param_nml(51)%path = '/discover/nobackup/projects/gmao/smap/SMAP_Nature/ASCAT_EUMETSAT/Metop_C/' +obs_param_nml(51)%name = 'M03-ASCA-ASCSMO02' +obs_param_nml(51)%maskpath = '' +obs_param_nml(51)%maskname = '' +obs_param_nml(51)%scalepath = '' +obs_param_nml(51)%scalename = '' +obs_param_nml(51)%flistpath = '' +obs_param_nml(51)%flistname = '' +obs_param_nml(51)%errstd = 9. +obs_param_nml(51)%std_normal_max = 2.5 +obs_param_nml(51)%zeromean = .true. +obs_param_nml(51)%coarsen_pert = .false. +obs_param_nml(51)%xcorr = 0.25 +obs_param_nml(51)%ycorr = 0.25 +obs_param_nml(51)%adapt = 0 + +! -------------------------------------------------------------------- +! +! 52 = MODIS Aqua snow cover area fraction (SCF) +! +! MOD10C1.*.061: MODIS Aqua SCF, 0.05deg CMG, daytime (01:30pm local) ascending overpass, version V61 +! +! for rule-based snow cover analysis (no obs error/pert specs) + +obs_param_nml(52)%descr = 'MYD10C1' +obs_param_nml(52)%orbit = 1 +obs_param_nml(52)%pol = 0 +obs_param_nml(52)%N_ang = 0 +obs_param_nml(52)%freq = 0. +obs_param_nml(52)%FOV = 0. +obs_param_nml(52)%FOV_units = 'deg' +obs_param_nml(52)%assim = .false. +obs_param_nml(52)%scale = .false. +obs_param_nml(52)%getinnov = .false. +obs_param_nml(52)%RTM_ID = 0 +obs_param_nml(52)%bias_Npar = 0 +obs_param_nml(52)%bias_trel = 864000 +obs_param_nml(52)%bias_tcut = 432000 +obs_param_nml(52)%nodata = -9999. +obs_param_nml(52)%varname = 'asnow' +obs_param_nml(52)%units = 'm2/m2' +obs_param_nml(52)%path = '/discover/nobackup/projects/S2SHMA/MODIS/MYD10C1_V61/' +obs_param_nml(52)%name = 'MYD10C1.Ayyyyddd.061.hdf' +obs_param_nml(52)%maskpath = '' +obs_param_nml(52)%maskname = '' +obs_param_nml(52)%scalepath = '' +obs_param_nml(52)%scalename = '' +obs_param_nml(52)%flistpath = '' +obs_param_nml(52)%flistname = '' +obs_param_nml(52)%errstd = -9999. +obs_param_nml(52)%std_normal_max = -9999. +obs_param_nml(52)%zeromean = .false. +obs_param_nml(52)%coarsen_pert = .false. +obs_param_nml(52)%xcorr = 0. +obs_param_nml(52)%ycorr = 0. +obs_param_nml(52)%adapt = 0 + +! -------------------------------------------------------------------- +! +! 53 = MODIS Terra snow cover area fraction (SCF) +! +! MOD10C1.*.061: MODIS Terra SCF, 0.05deg CMG, daytime (10:30am local) descending overpass, version V61 +! +! for rule-based snow cover analysis (no obs error/pert specs) + +obs_param_nml(53)%descr = 'MOD10C1' +obs_param_nml(53)%orbit = 2 +obs_param_nml(53)%pol = 0 +obs_param_nml(53)%N_ang = 0 +obs_param_nml(53)%freq = 0. +obs_param_nml(53)%FOV = 0. +obs_param_nml(53)%FOV_units = 'deg' +obs_param_nml(53)%assim = .false. +obs_param_nml(53)%scale = .false. +obs_param_nml(53)%getinnov = .false. +obs_param_nml(53)%RTM_ID = 0 +obs_param_nml(53)%bias_Npar = 0 +obs_param_nml(53)%bias_trel = 864000 +obs_param_nml(53)%bias_tcut = 432000 +obs_param_nml(53)%nodata = -9999. +obs_param_nml(53)%varname = 'asnow' +obs_param_nml(53)%units = 'm2/m2' +obs_param_nml(53)%path = '/discover/nobackup/projects/S2SHMA/MODIS/MOD10C1_V61/' +obs_param_nml(53)%name = 'MOD10C1.Ayyyyddd.061.hdf' +obs_param_nml(53)%maskpath = '' +obs_param_nml(53)%maskname = '' +obs_param_nml(53)%scalepath = '' +obs_param_nml(53)%scalename = '' +obs_param_nml(53)%flistpath = '' +obs_param_nml(53)%flistname = '' +obs_param_nml(53)%errstd = -9999. +obs_param_nml(53)%std_normal_max = -9999. +obs_param_nml(53)%zeromean = .false. +obs_param_nml(53)%coarsen_pert = .false. +obs_param_nml(53)%xcorr = 0. +obs_param_nml(53)%ycorr = 0. +obs_param_nml(53)%adapt = 0 + + ! -------------------------------------------------------------------- / diff --git a/src/Applications/LDAS_App/ldas_setup b/src/Applications/LDAS_App/ldas_setup index 54d50070..6c1eada8 100755 --- a/src/Applications/LDAS_App/ldas_setup +++ b/src/Applications/LDAS_App/ldas_setup @@ -12,6 +12,7 @@ import time import resource import subprocess as sp import shlex +import tempfile from dateutil import rrule from datetime import datetime from datetime import timedelta @@ -19,7 +20,7 @@ from collections import OrderedDict from dateutil.relativedelta import relativedelta from remap_utils import * from remap_catchANDcn import * -from process_rst import * +from remap_config_ldas import * """ This script is intended to be run from any installed directory with GEOSldas.x and ldas_setup @@ -36,10 +37,10 @@ class LDASsetup: # Required exe input fields # These fields are needed to pre-compute exp dir structure # ------ - rqdExeInpKeys = ['EXP_ID', 'EXP_DOMAIN', 'NUM_LDAS_ENSEMBLE', + rqdExeInpKeys = ['EXP_ID', 'EXP_DOMAIN', 'NUM_LDAS_ENSEMBLE', 'BEG_DATE', 'END_DATE','RESTART_PATH', 'RESTART_DOMAIN','RESTART_ID','MET_TAG','MET_PATH','FORCE_DTSTEP','BCS_PATH', 'BCS_RESOLUTION'] - rqdExeInpKeys_rst = ['EXP_ID', 'EXP_DOMAIN', 'NUM_LDAS_ENSEMBLE', + rqdExeInpKeys_rst = ['EXP_ID', 'EXP_DOMAIN', 'NUM_LDAS_ENSEMBLE', 'BEG_DATE', 'END_DATE','MET_TAG','MET_PATH','FORCE_DTSTEP','BCS_PATH', 'BCS_RESOLUTION'] # These keywords are excluded from LDAS.rc (i.e., only needed in pre- or post-processing) @@ -51,6 +52,14 @@ class LDASsetup: 'MINLON','MAXLON','MINLAT','MAXLAT','EXCLUDE_FILE','INCLUDE_FILE','MWRTM_PATH','GRIDNAME', 'ADAS_EXPDIR', 'BCS_RESOLUTION' ] + # if built on sles15, BUILT_ON_SLES15 is "TRUE", else empty "" + BUILT_ON_SLES15 = "@BUILT_ON_SLES15@" + if BUILT_ON_SLES15 == "TRUE": + self.BUILT_ON_SLES15 = True + else: + self.BUILT_ON_SLES15 = False + + self.GEOS_SITE = "@GEOS_SITE@" # ------ # Required resource manager input fields @@ -115,6 +124,10 @@ class LDASsetup: self.in_rstfile = None self.in_tilefile = 'None' # default string self.ens_id_width = 6 # _eXXXX + self.bcs_land = '' + self.bcs_geom = '' + self.bcs_landshared = '' + # ------ # Read exe input file which is required to set up the dir # ------ @@ -151,7 +164,7 @@ class LDASsetup: assert self.nens>0, 'NUM_LDAS_ENSEMBLE [%d] <= 0' % self.nens _mydir = self.exphome + '/' + self.rqdExeInp['EXP_ID'] assert not os.path.isdir(_mydir), 'Dir [%s] already exists!' % _mydir - _mydir = None + _mydir = None self.ladas_coupling = int(self.rqdExeInp.get('LADAS_COUPLING',0)) if self.ladas_coupling > 0: assert 'ADAS_EXPDIR' in self.rqdExeInp, " need ADAS_EXPDIR in the input file %s" %(self.exeinpfile) @@ -163,7 +176,7 @@ class LDASsetup: self.ensdirs = ['ens%04d'%iens for iens in range(self.first_ens_id, self.nens + self.first_ens_id)] # if self.ens_id_width = 4, _width = '_e%04d' _width = '_e%0{}d'.format(self.ens_id_width-2) - # self.ensids will be a list of [_e0000, _e0001, ...] + # self.ensids will be a list of [_e0000, _e0001, ...] self.ensids = [ _width%iens for iens in range(self.first_ens_id, self.nens + self.first_ens_id)] if (self.nens == 1) : self.ensdirs_avg = self.ensdirs @@ -244,9 +257,10 @@ class LDASsetup: _d = _d+ _difftime # make sure path is path - if self.rqdExeInp['BCS_PATH'][-1] != '/': - self.rqdExeInp['BCS_PATH'] = self.rqdExeInp['BCS_PATH']+'/' - self.rqdExeInp['BCS_PATH'] = self.rqdExeInp['BCS_PATH']+self.rqdExeInp['BCS_RESOLUTION']+'/' + self.bcs_land = self.rqdExeInp['BCS_PATH']+ '/land/' + self.rqdExeInp['BCS_RESOLUTION']+'/' + self.bcs_geom = self.rqdExeInp['BCS_PATH']+ '/geometry/' + self.rqdExeInp['BCS_RESOLUTION']+'/' + self.bcs_landshared = self.rqdExeInp['BCS_PATH']+ '/land/shared/' + if self.rqdExeInp['MET_PATH'][-1] != '/': self.rqdExeInp['MET_PATH'] = self.rqdExeInp['MET_PATH']+'/' if self.rqdExeInp['RESTART_PATH'][-1] != '/': @@ -254,7 +268,7 @@ class LDASsetup: # make sure catchment and vegdyn restart files ( at least one for each) exist if 'CATCH_DEF_FILE' not in self.rqdExeInp: - self.rqdExeInp['CATCH_DEF_FILE']=self.rqdExeInp['BCS_PATH']+'clsm/catchment.def' + self.rqdExeInp['CATCH_DEF_FILE']= self.bcs_land + 'clsm/catchment.def' assert os.path.isfile(self.rqdExeInp['CATCH_DEF_FILE']),"[%s] file does not exist " % self.rqdExeInp['CATCH_DEF_FILE'] self.rqdExeInp['RST_FROM_GLOBAL'] = 1 @@ -267,27 +281,27 @@ class LDASsetup: '/output/'+self.rqdExeInp['RESTART_DOMAIN']+'/rc_out/'+self.rqdExeInp['RESTART_ID']+'.ldas_domain.txt' if os.path.isfile(ldas_domain) : _numd = int(linecache.getline(ldas_domain, 1).strip()) - - if _numg != _numd : + + if _numg != _numd : self.rqdExeInp['RST_FROM_GLOBAL'] = 0 self.rqdExeInp['LNFM_FILE'] = '' if int(self.rqdExeInp['RST_FROM_GLOBAL']) == 1 : - self.rqdExeInp['TILING_FILE'] =glob.glob(self.rqdExeInp['BCS_PATH']+'*.til')[0] - self.rqdExeInp['GRN_FILE']= glob.glob(self.rqdExeInp['BCS_PATH']+'green_clim_*.data')[0] - self.rqdExeInp['LAI_FILE']= glob.glob(self.rqdExeInp['BCS_PATH']+'lai_clim_*.data')[0] - tmp_ = glob.glob(self.rqdExeInp['BCS_PATH']+'lnfm_clim_*.data') + self.rqdExeInp['TILING_FILE'] =glob.glob(self.bcs_geom + '*.til')[0] + self.rqdExeInp['GRN_FILE']= glob.glob(self.bcs_land + 'green_clim_*.data')[0] + self.rqdExeInp['LAI_FILE']= glob.glob(self.bcs_land + 'lai_clim_*.data')[0] + tmp_ = glob.glob(self.bcs_land + 'lnfm_clim_*.data') if (len(tmp_) ==1) : self.rqdExeInp['LNFM_FILE'] = tmp_[0] - self.rqdExeInp['NDVI_FILE']= glob.glob(self.rqdExeInp['BCS_PATH']+'ndvi_clim_*.data')[0] - self.rqdExeInp['NIRDF_FILE']= glob.glob(self.rqdExeInp['BCS_PATH']+'nirdf_*.dat')[0] - self.rqdExeInp['VISDF_FILE']= glob.glob(self.rqdExeInp['BCS_PATH']+'visdf_*.dat')[0] + self.rqdExeInp['NDVI_FILE'] = glob.glob(self.bcs_land + 'ndvi_clim_*.data')[0] + self.rqdExeInp['NIRDF_FILE']= glob.glob(self.bcs_land + 'nirdf_*.dat')[0] + self.rqdExeInp['VISDF_FILE']= glob.glob(self.bcs_land + 'visdf_*.dat')[0] else : inpdir=self.rqdExeInp['RESTART_PATH']+self.rqdExeInp['RESTART_ID']+'/input/' self.rqdExeInp['TILING_FILE'] =os.path.realpath(glob.glob(inpdir+'*tile.data')[0]) self.rqdExeInp['GRN_FILE']= os.path.realpath(glob.glob(inpdir+'green*data')[0]) self.rqdExeInp['LAI_FILE']= os.path.realpath(glob.glob(inpdir+'lai*data')[0]) - tmp_ = glob.glob(self.rqdExeInp['BCS_PATH']+'lnfm_clim_*.data') + tmp_ = glob.glob(self.bcs_land + 'lnfm_clim_*.data') if (len(tmp_) == 1) : self.rqdExeInp['LNFM_FILE'] = tmp_[0] self.rqdExeInp['NDVI_FILE']= os.path.realpath(glob.glob(inpdir+'ndvi*data')[0]) @@ -308,20 +322,20 @@ class LDASsetup: if len(in_tilefiles_) == 0 : in_tilefiles_ = glob.glob(inpdir+'/*.til') self.in_tilefile =os.path.realpath(in_tilefiles_[0]) - + if os.path.isfile(ldas_domain) : _numd = int(linecache.getline(ldas_domain, 1).strip()) - self.rqdExeInp['TILING_FILE'] =glob.glob(self.rqdExeInp['BCS_PATH']+'*.til')[0] - self.rqdExeInp['GRN_FILE']= glob.glob(self.rqdExeInp['BCS_PATH']+'green_clim_*.data')[0] - self.rqdExeInp['LAI_FILE']= glob.glob(self.rqdExeInp['BCS_PATH']+'lai_clim_*.data')[0] - tmp_ = glob.glob(self.rqdExeInp['BCS_PATH']+'lnfm_clim_*.data') + self.rqdExeInp['TILING_FILE'] =glob.glob(self.bcs_geom + '*.til')[0] + self.rqdExeInp['GRN_FILE']= glob.glob(self.bcs_land + 'green_clim_*.data')[0] + self.rqdExeInp['LAI_FILE']= glob.glob(self.bcs_land + 'lai_clim_*.data')[0] + tmp_ = glob.glob(self.bcs_land + 'lnfm_clim_*.data') if (len(tmp_) == 1) : self.rqdExeInp['LNFM_FILE'] = tmp_[0] - self.rqdExeInp['LNFM_FILE']= glob.glob(self.rqdExeInp['BCS_PATH']+'lnfm_clim_*.data')[0] - self.rqdExeInp['NDVI_FILE']= glob.glob(self.rqdExeInp['BCS_PATH']+'ndvi_clim_*.data')[0] - self.rqdExeInp['NIRDF_FILE']= glob.glob(self.rqdExeInp['BCS_PATH']+'nirdf_*.dat')[0] - self.rqdExeInp['VISDF_FILE']= glob.glob(self.rqdExeInp['BCS_PATH']+'visdf_*.dat')[0] - + self.rqdExeInp['LNFM_FILE'] = glob.glob(self.bcs_land + 'lnfm_clim_*.data')[0] + self.rqdExeInp['NDVI_FILE'] = glob.glob(self.bcs_land + 'ndvi_clim_*.data')[0] + self.rqdExeInp['NIRDF_FILE']= glob.glob(self.bcs_land + 'nirdf_*.dat')[0] + self.rqdExeInp['VISDF_FILE']= glob.glob(self.bcs_land + 'visdf_*.dat')[0] + if 'GRIDNAME' not in self.rqdExeInp : tmptile =self.rqdExeInp['TILING_FILE'] self.rqdExeInp['GRIDNAME'] = linecache.getline(tmptile, 3).strip() @@ -333,8 +347,9 @@ class LDASsetup: self.catch = 'catch' if int(self.rqdExeInp['LSM_CHOICE']) == 2 : self.catch = 'catchcnclm40' - if int(self.rqdExeInp['LSM_CHOICE']) == 3 : - self.catch = 'catchcnclm45' + + assert int(self.rqdExeInp['LSM_CHOICE']) <= 2, "\nLSM_CHOICE=3 (Catchment-CN4.5) is no longer supported. Please set LSM_CHOICE to 1 (Catchment) or 2 (Catchment-CN4.0)" + if 'POSTPROC_HIST' not in self.rqdExeInp: self.rqdExeInp['POSTPROC_HIST'] = 0 @@ -342,7 +357,7 @@ class LDASsetup: self.rqdExeInp['LADAS_COUPLING'] = 0 if 'RUN_IRRIG' not in self.rqdExeInp: - self.rqdExeInp['RUN_IRRIG'] = 0 + self.rqdExeInp['RUN_IRRIG'] = 0 if 'AEROSOL_DEPOSITION' not in self.rqdExeInp: self.rqdExeInp['AEROSOL_DEPOSITION'] = 0 @@ -354,21 +369,22 @@ class LDASsetup: _domain_dic['MAXLAT']= 90. _domain_dic['EXCLUDE_FILE']= "''" _domain_dic['INCLUDE_FILE']= "''" - + for key,val in _domain_dic.items() : if key in self.rqdExeInp : _domain_dic[key]= self.rqdExeInp[key] - fout =open('LDAS_domain_def.nml','w') - fout.write('&domain_inputs\n') + self.domain_def = tempfile.NamedTemporaryFile(mode='w', delete=False) + self.domain_def.write('&domain_inputs\n') for key,val in _domain_dic.items() : keyn=(key+" = ").ljust(16) valn = str(val) if '_FILE' in key: - fout.write(keyn+ "'"+valn+"'"+'\n') + self.domain_def.write(keyn+ "'"+valn+"'"+'\n') else : - fout.write(keyn+ valn +'\n') - fout.write('/\n') - + self.domain_def.write(keyn+ valn +'\n') + self.domain_def.write('/\n') + self.domain_def.close() + # make sure bcs files exist if self.rqdExeInp['RESTART'].isdigit() : if int(self.rqdExeInp['RESTART']) >= 1 : @@ -379,18 +395,18 @@ class LDASsetup: tmpRstDir=self.rqdExeInp['RESTART_PATH']+'/'.join([self.rqdExeInp['RESTART_ID'],'output', self.rqdExeInp['RESTART_DOMAIN'],'rs',self.ensdirs[0],y4m2]) catchRstFile=tmpRstDir+'/'+tmpFile - + assert os.path.isfile(catchRstFile), self.catch+'_internal_rst file [%s] does not exist!' %(catchRstFile) self.in_rstfile = catchRstFile - + if int(self.rqdExeInp['RESTART']) == 1 : tmpFile=self.rqdExeInp['RESTART_ID']+'.vegdyn_internal_rst' tmpRstDir=self.rqdExeInp['RESTART_PATH']+'/'.join([self.rqdExeInp['RESTART_ID'],'output', - self.rqdExeInp['RESTART_DOMAIN'],'rs',self.ensdirs[0]]) + self.rqdExeInp['RESTART_DOMAIN'],'rs',self.ensdirs[0]]) vegdynRstFile=tmpRstDir+'/'+tmpFile if not os.path.isfile(vegdynRstFile): assert int(self.rqdExeInp['RST_FROM_GLOBAL']) == 1, 'restart from LDASsa should be global' - + tmpFile=self.rqdExeInp['RESTART_ID']+'.landpert_internal_rst.'+y4m2d2_h2m2 tmpRstDir=self.rqdExeInp['RESTART_PATH']+'/'.join([self.rqdExeInp['RESTART_ID'],'output', self.rqdExeInp['RESTART_DOMAIN'],'rs',self.ensdirs[0],y4m2]) @@ -398,15 +414,15 @@ class LDASsetup: if ( os.path.isfile(landpertRstFile)) : self.has_geos_pert = True - elif (int(self.rqdExeInp['RESTART']) == 0) : + elif (int(self.rqdExeInp['RESTART']) == 0) : if (self.catch == 'catch'): self.in_rstfile = '/discover/nobackup/projects/gmao/ssd/land/l_data/LandRestarts_for_Regridding' \ - '/Catch/M09/20170101/catch_internal_rst' + '/Catch/M09/20170101/catch_internal_rst' self.in_tilefile = '/discover/nobackup/projects/gmao/ssd/land/l_data/geos5/bcs/CLSM_params' \ '/mkCatchParam_SMAP_L4SM_v002/SMAP_EASEv2_M09/SMAP_EASEv2_M09_3856x1624.til' elif (self.catch == 'catchcnclm40'): self.in_rstfile = '/discover/nobackup/projects/gmao/ssd/land/l_data/LandRestarts_for_Regridding' \ - '/CatchCN/M36/20150301_0000/catchcnclm40_internal_dummy' + '/CatchCN/M36/20150301_0000/catchcnclm40_internal_dummy' self.in_tilefile = '/discover/nobackup/projects/gmao/bcs_shared/legacy_bcs/Heracles-NL/SMAP_EASEv2_M36/SMAP_EASEv2_M36_964x406.til' elif (self.catch == 'catchcnclm45'): self.in_rstfile = '/discover/nobackup/projects/gmao/ssd/land/l_data/LandRestarts_for_Regridding' \ @@ -416,7 +432,7 @@ class LDASsetup: sys.exit('need to provide at least dummy files') self.in_rstfile = None self.in_tilefile = None - + # DEAL WITH mwRTM input from exec self.assim = True if self.rqdExeInp.get('LAND_ASSIM', 'NO').upper() == 'YES' else False # verify mwrtm file @@ -427,15 +443,15 @@ class LDASsetup: if os.path.isfile(mwrtm_param_file_) : self.has_mwrtm = True self.mwrtm_file = mwrtm_param_file_ - else : - assert not mwrtm_param_file_.strip(), ' MWRTM_PATH: %s should contain mwRTM_param.nc4'% self.rqdExeInp['MWRTM_PATH'] + else : + assert not mwrtm_param_file_.strip(), ' MWRTM_PATH: %s should contain mwRTM_param.nc4'% self.rqdExeInp['MWRTM_PATH'] del self.rqdExeInp['MWRTM_PATH'] if os.path.isfile(vegopacity_file_) : self.has_vegopacity = True self.rqdExeInp['VEGOPACITY_FILE'] = vegopacity_file_ - + # DEAL WITH optional input from exec - + # ------ # Read rm input file # Read (and pop from inpfile) the input required fields in to @@ -479,19 +495,18 @@ class LDASsetup: _printdict(self.optRmInp) # ------ - # set top level directories + # set top level directories # rundir, inpdir, outdir, blddir # executable # exefyl # ------ - cwd = os.getcwd() - self.blddir = cwd.rsplit('/',1)[0] + self.bindir = os.path.dirname(os.path.realpath(__file__)) + self.blddir = self.bindir.rsplit('/',1)[0] exefyl = '/bin/GEOSldas.x' tmp_execfyl= self.blddir+exefyl assert os.path.isfile(tmp_execfyl),\ 'Executable [%s] does not exist!' % tmp_execfyl - tmp_expid = self.rqdExeInp['EXP_ID'] tmp_expdir = os.path.abspath(self.exphome + '/' + self.rqdExeInp['EXP_ID']) self.rundir = tmp_expdir + '/run' @@ -517,7 +532,7 @@ class LDASsetup: # default is set to 0 ( no output server) if 'oserver_nodes' not in self.optRmInp : self.optRmInp['oserver_nodes'] = 0 - + self.optRmInp['nodes'] = my_nodes + int(self.optRmInp['oserver_nodes']) if (int(self.optRmInp['oserver_nodes']) >=1) : @@ -527,7 +542,7 @@ class LDASsetup: self.optRmInp['writers-per-node'] = 5 else: self.optRmInp['writers-per-node'] = 0 - + def _parseInputFile(self, inpfile): """ @@ -692,19 +707,20 @@ class LDASsetup: print ('\nCorrect the tile file if it is an old EASE tile format... \n') EASEtile=self.bcsdir+'/MAPL_'+short_tile - cmd = './preprocess_ldas.x correctease '+ tile + ' '+ EASEtile - print ("cmd: " + cmd) + cmd = self.bindir + '/preprocess_ldas.x correctease '+ tile + ' '+ EASEtile + if self.BUILT_ON_SLES15 : + print ("Executables were built on SLES15 and must be run on SLES15: " + cmd) + else: + print ("cmd: " + cmd) + sp.call(shlex.split(cmd)) if os.path.isfile(EASEtile) : #update tile file name short_tile ='MAPL_'+short_tile - tile=EASEtile + tile=EASEtile # setup BC files - if os.path.isfile('f2g.txt'): - os.remove('f2g.txt') - domain_def = 'LDAS_domain_def.nml' catchment_def = self.rqdExeInp['CATCH_DEF_FILE'] exp_id = self.rqdExeInp['EXP_ID'] @@ -717,35 +733,37 @@ class LDASsetup: # These are dummy values for *cold* restart: wemin_in = '13' # WEmin input/output for scale_catch(cn), - wemin_out = '13' # + wemin_out = '13' # if 'WEMIN_IN' in self.rqdExeInp : wemin_in = self.rqdExeInp['WEMIN_IN'] if 'WEMIN_OUT' in self.rqdExeInp : wemin_out = self.rqdExeInp['WEMIN_OUT'] - - cmd = './preprocess_ldas.x c_f2g ' + tile + ' ' + domain_def + ' '+ self.out_path + ' ' + catchment_def + ' ' + exp_id + ' ' + _y4m2d2h2m2 + ' '+ dzsf - print ('Creating f2g.txt....\n') + tmp_f2g_file = tempfile.NamedTemporaryFile(delete=False) + cmd = self.bindir +'/preprocess_ldas.x c_f2g ' + tile + ' ' + self.domain_def.name + ' '+ self.out_path + ' ' + catchment_def + ' ' + exp_id + ' ' + _y4m2d2h2m2 + ' '+ dzsf + ' ' + tmp_f2g_file.name + + print ('Creating f2g file: '+ tmp_f2g_file.name +'....\n') print ("cmd: " + cmd) sp.call(shlex.split(cmd)) # check if it is local or global - with open('f2g.txt') as f2gfile : + with open(tmp_f2g_file.name) as f2gfile : head=[next(f2gfile) for x in range(2)] if(head[0].strip() != head[1].strip()) : self.islocal= True + #os.remove(self.domain_def.name) # update tile domain if self.islocal: newlocalTile = tile+'.domain' print ("\nCreating local tile file :"+ newlocalTile) print ("\n by excluding land type MAPL_Land_ExcludeFromDomain=1100...\n") - cmd = './preprocess_ldas.x c_localtile ' + tile + ' ' + newlocalTile + cmd = self.bindir +'/preprocess_ldas.x c_localtile ' + tile + ' ' + newlocalTile + ' '+ tmp_f2g_file.name print ("cmd: " + cmd) sp.call(shlex.split(cmd)) short_tile=short_tile +'.domain' tile = newlocalTile - + myTile=self.inpdir+'/tile.data' os.symlink(tile,myTile) @@ -769,7 +787,7 @@ class LDASsetup: print ("Creating the boundary files for the simulation domain...\n") bcs_tmp=[] for bcf in bcs : - cmd = './preprocess_ldas.x c_localbc ' + bcf + ' '+ bcf+'.domain' + cmd = self.bindir +'/preprocess_ldas.x c_localbc ' + bcf + ' '+ bcf+'.domain' + ' '+ tmp_f2g_file.name print ("cmd: " + cmd) sp.call(shlex.split(cmd)) bcs_tmp=bcs_tmp+[bcf+'.domain'] @@ -777,7 +795,7 @@ class LDASsetup: # link BC - print ("linking bcs...") + print ("linking bcs...") bcnames=['green','lai','ndvi','nirdf','visdf'] if (self.rqdExeInp['LNFM_FILE'] != ''): bcnames += ['lnfm'] @@ -788,10 +806,10 @@ class LDASsetup: os.symlink(bc,myBC) if ("catchcn" in self.catch): - os.symlink('/discover/nobackup/projects/gmao/bcs_shared/make_bcs_inputs/land/CO2/v1/CO2_MonthlyMean_DiurnalCycle.nc4', \ + os.symlink(self.bcs_landshared + 'CO2_MonthlyMean_DiurnalCycle.nc4', \ self.inpdir+'/CO2_MonthlyMean_DiurnalCycle.nc4') - # create and link restart + # create and link restart print ("Creating and linking restart...") _start = self.begDates[0] @@ -807,7 +825,7 @@ class LDASsetup: self.rqdExeInp['RESTART_ID'] + \ '/output/'+self.rqdExeInp['RESTART_DOMAIN']+'/rc_out/' - # pass into process_rst + # pass into remap_config_ldas sponsorid = self.rqdRmInp['account'] exp_id = self.rqdExeInp['EXP_ID'] exp_dir = self.exphome @@ -819,29 +837,30 @@ class LDASsetup: rstid = self.rqdExeInp['RESTART_ID'] rstdomain = self.rqdExeInp['RESTART_DOMAIN'] rstpath0 = self.rqdExeInp['RESTART_PATH'] - + # just copy the landassim pert seed if it exists for iens in range(self.nens) : _ensdir = self.ensdirs[iens] _ensid = self.ensids[iens] landassim_seeds = rstpath + _ensdir + '/' + y4m2+'/' + rstid + '.landassim_obspertrseed_rst.'+y4m2d2_h2m2 if os.path.isfile(landassim_seeds) and self.assim : - _seeds = self.rstdir + _ensdir + '/' + y4m2+'/' + exp_id + '.landassim_obspertrseed_rst.'+y4m2d2_h2m2 + _seeds = self.rstdir + _ensdir + '/' + y4m2+'/' + exp_id + '.landassim_obspertrseed_rst.'+y4m2d2_h2m2 shutil.copy(landassim_seeds, _seeds) os.symlink(_seeds, myRstDir+ '/landassim_obspertrseed'+ _ensid +'_rst') self.has_landassim_seed = True - mk_outdir = self.exphome+'/'+exp_id+'/mk_restarts/' - cmd= ' '.join(['./process_rst.csh', sponsorid, exp_id, mk_outdir, - out_bcdir, out_tilefile, self.catch, RESTART_str, YYYYMMDDHH, - self.in_rstfile, self.in_tilefile, dzsf, wemin_in, wemin_out]) + mk_outdir = self.exphome+'/'+exp_id+'/mk_restarts/' if (RESTART_str != '1'): + bcs_path = self.rqdExeInp['BCS_PATH'] + while bcs_path[-1] == '/' : bcs_path = bcs_path[0:-1] + bc_base = os.path.dirname(bcs_path) + bc_version = os.path.basename(bcs_path) + remap_tpl = os.path.dirname(os.path.realpath(__file__)) + '/remap_params.tpl' config = yaml_to_config(remap_tpl) - config['slurm']['account'] = self.rqdRmInp['account'] - config['slurm']['qos'] = 'debug' - config['slurm']['qos'] = 'cas' + config['slurm']['account'] = self.rqdRmInp['account'] + config['slurm']['qos'] = 'debug' config['input']['surface']['catch_tilefile'] = self.in_tilefile config['input']['shared']['expid'] = self.rqdExeInp['RESTART_ID'] @@ -853,30 +872,19 @@ class LDASsetup: config['output']['shared']['out_dir'] = mk_outdir config['output']['surface']['catch_remap'] = True config['output']['surface']['catch_tilefile'] = self.rqdExeInp['TILING_FILE'] - config['output']['shared']['bcs_dir'] = self.rqdExeInp['BCS_PATH'] + config['output']['shared']['bc_base'] = bc_base + config['output']['shared']['bc_version'] = bc_version + config['output']['surface']['EASE_grid'] = self.rqdExeInp['BCS_RESOLUTION'] + config['output']['shared']['expid'] = self.rqdExeInp['EXP_ID'] config['output']['surface']['surflay'] = dzsf config['output']['surface']['wemin'] = wemin_out - config = remap_config_ldas( config, RESTART_str, self.rqdExeInp['RESTART_PATH'], self.rqdExeInp['RESTART_ID']) + config = remap_config_ldas( config, RESTART_str, self.rqdExeInp['RESTART_PATH'], self.rqdExeInp['RESTART_ID']) catch_obj = catchANDcn(config_obj = config) catch_obj.remap() - #print "cmd: " + cmd - #os.system(cmd) - - #done_rst=self.exphome+'/'+exp_id+'/mk_restarts/done_rst_file' - #print "Please hold on for a while until the restart file is created ....." - #_animation = "|/-\\" - #_idx = 0 - #while not os.path.isfile(done_rst): - # sys.stdout.write('\r'+_animation[_idx % len(_animation)]) - # sys.stdout.flush() - # _idx += 1 - # time.sleep(1.) - - #for ens in self.ensdirs : catchRstFile0 = '' vegdynRstFile0 = '' @@ -895,16 +903,16 @@ class LDASsetup: if self.rqdExeInp['RESTART'].isdigit() : if int(self.rqdExeInp['RESTART']) == 0 or int(self.rqdExeInp['RESTART']) == 2 : - vegdynRstFile = glob.glob(self.rqdExeInp['BCS_PATH']+'vegdyn_*.dat')[0] + vegdynRstFile = glob.glob(self.bcs_land + 'vegdyn_*.dat')[0] catchRstFile = glob.glob(self.exphome+'/'+exp_id+'/mk_restarts/*'+self.catch+'_internal_rst.'+YYYYMMDD+'*')[0] else : # RESTART == 1 catchRstFile = rstpath+ensdir +'/'+ y4m2+'/'+self.rqdExeInp['RESTART_ID']+'.'+self.catch+'_internal_rst.'+y4m2d2_h2m2 vegdynRstFile= rstpath+ensdir +'/'+self.rqdExeInp['RESTART_ID']+ '.vegdyn_internal_rst' if not os.path.isfile(vegdynRstFile): # no vegdyn restart from LDASsa if not os.path.isfile(vegdynRstFile0): - vegdynRstFile = glob.glob(self.rqdExeInp['BCS_PATH']+'vegdyn_*.dat')[0] + vegdynRstFile = glob.glob(self.bcs_land + 'vegdyn_*.dat')[0] else : - vegdynRstFile = glob.glob(self.rqdExeInp['BCS_PATH']+'vegdyn_*.dat')[0] + vegdynRstFile = glob.glob(self.bcs_land + 'vegdyn_*.dat')[0] catchRstFile = glob.glob(self.exphome+'/'+exp_id+'/mk_restarts/*'+self.catch+'_internal_rst.'+YYYYMMDD+'*')[0] # catchment restart file @@ -912,7 +920,7 @@ class LDASsetup: catchLocal = self.rstdir+ensdir +'/'+ y4m2+'/'+self.rqdExeInp['EXP_ID']+'.'+self.catch+'_internal_rst.'+y4m2d2_h2m2 if self.islocal : print( "Creating local catchment restart file... \n") - cmd='./preprocess_ldas.x c_localcatchrst '+ catchRstFile +' ' + catchLocal + cmd=self.bindir +'/preprocess_ldas.x c_localcatchrst '+ catchRstFile +' ' + catchLocal + ' '+ tmp_f2g_file.name print ("cmd: "+cmd) sp.call(shlex.split(cmd)) else : @@ -922,7 +930,7 @@ class LDASsetup: if '0000' in ensdir : catchRstFile0 = catchRstFile - else : # re-use 0000 catch file + else : # re-use 0000 catch file catchRstFile = catchRstFile0 # vegdyn restart file @@ -930,7 +938,7 @@ class LDASsetup: vegdynLocal = self.rstdir+ensdir +'/'+self.rqdExeInp['EXP_ID']+'.vegdyn_internal_rst' if self.islocal : print ("Creating the local veg restart file... \n") - cmd='./preprocess_ldas.x c_localvegrst '+ vegdynRstFile +' ' + vegdynLocal + cmd=self.bindir + '/preprocess_ldas.x c_localvegrst '+ vegdynRstFile +' ' + vegdynLocal + ' '+ tmp_f2g_file.name print ("cmd: " + cmd) sp.call(shlex.split(cmd)) else : @@ -940,7 +948,7 @@ class LDASsetup: if '0000' in ensdir : vegdynRstFile0 = vegdynRstFile - else : + else : vegdynRstFile = vegdynRstFile0 if (self.has_geos_pert and self.perturb == 1) : @@ -965,7 +973,8 @@ class LDASsetup: mwRTMLocal = self.bcsdir+'/'+ y4m2+'/'+self.rqdExeInp['EXP_ID']+'.ldas_mwRTMparam.'+y4m2d2_h2m2+'z.nc4' if self.islocal : print ("Creating the local mwRTM restart file... \n") - cmd='./preprocess_ldas.x c_localmwrtmrst '+ mwRTMRstFile +' ' + mwRTMLocal + cmd= self.bindir +'/preprocess_ldas.x c_localmwrtmrst '+ mwRTMRstFile +' ' + mwRTMLocal + ' '+ tmp_f2g_file.name + print ("cmd: " + cmd) sp.call(shlex.split(cmd)) else : @@ -978,9 +987,8 @@ class LDASsetup: # update 'restart_path' to use relative path from outdir print ("Updating restart path...") self.rqdExeInp['RESTART_PATH'] = myRstDir - if os.path.isfile('f2g.txt'): - os.remove('f2g.txt') - + #if os.path.isfile(tmp_f2g_file.name): + # os.remove(tmp_f2g_file.name) status = True return status @@ -1034,25 +1042,20 @@ class LDASsetup: shutil.copy2(nmlfile, self.rundir+'/'+shortfile) # get optimzed NX and IMS - if os.path.isfile('optimized_distribution'): - os.remove('optimized_distribution') - + optimized_distribution_file = tempfile.NamedTemporaryFile(delete=False) print ("Optimizing... decomposition of processes.... \n") - cmd = './preprocess_ldas.x optimize '+ self.inpdir+'/tile.data '+ str(self.rqdRmInp['ntasks_model']) + cmd = self.bindir + '/preprocess_ldas.x optimize '+ self.inpdir+'/tile.data '+ str(self.rqdRmInp['ntasks_model']) + ' ' + optimized_distribution_file.name + ' ' + self.rundir print ("cmd: " + cmd) + print ("IMS.rc or JMS.rc would be generated on " + self.rundir) sp.call(shlex.split(cmd)) - optinxny=self._parseInputFile('optimized_distribution') + optinxny=self._parseInputFile(optimized_distribution_file.name) if (int(optinxny['NX']) == 1): if int(optinxny['NY']) != int(self.rqdRmInp['ntasks_model']): self.rqdRmInp['ntasks_model']=optinxny['NY'] print ('adjust ntasks_model %d for cubed-sphere grid' % int(self.rqdRmInp['ntasks_model'])) - - if os.path.isfile('IMS.rc') : - shutil.move('IMS.rc', self.rundir+'/') - if os.path.isfile('JMS.rc') : - shutil.move('JMS.rc', self.rundir+'/') - - os.remove('optimized_distribution') + + + #os.remove(optimized_distribution_file.name) # DEFAULT rc files default_rc = glob.glob(etcdir+'/GEOSldas_*.rc') @@ -1082,21 +1085,21 @@ class LDASsetup: if '-CF' in self.rqdExeInp['GRIDNAME'] : GRID ='CUBE ' + self.rqdExeInp['GRIDNAME'] + ' ' +tmprcfile _assim = '1' if self.assim else '0' - cmd ='./process_hist.csh '+ str(self.rqdExeInp['LSM_CHOICE']) + ' ' + str(self.rqdExeInp['AEROSOL_DEPOSITION']) + \ + cmd =self.bindir +'/process_hist.csh '+ str(self.rqdExeInp['LSM_CHOICE']) + ' ' + str(self.rqdExeInp['AEROSOL_DEPOSITION']) + \ ' ' + GRID + ' ' + str(self.rqdExeInp['RUN_IRRIG']) + ' ' + _assim + ' '+ str(self.nens) print(cmd) #os.system(cmd) - sp.call(shlex.split(cmd)) + sp.call(shlex.split(cmd)) for line in fileinput.input(tmprcfile,inplace=True): print (line.rstrip().replace('GEOSldas_expid',self.rqdExeInp['EXP_ID'])) # just copy an empty ExtData.rc if shortfile=='ExtData.rc' : shutil.copy2(rcfile, self.rundir+'/'+shortfile) - - if shortfile == 'CAP.rc': + + if shortfile == 'CAP.rc': tmprcfile = self.rundir+'/CAP.rc' shutil.copy2(rcfile,tmprcfile) - + _num_sgmt = int(self.rqdExeInp['NUM_SGMT']) for line in fileinput.input(tmprcfile,inplace=True): @@ -1107,15 +1110,15 @@ class LDASsetup: print (line.rstrip().replace('BEG_DATE:',self.begDates[0].strftime('BEG_DATE: %Y%m%d %H%M%S'))) for line in fileinput.input(tmprcfile,inplace=True): print (line.rstrip().replace('END_DATE:',self.endDates[-1].strftime('END_DATE: %Y%m%d %H%M%S'))) - + if shortfile == 'LDAS.rc' : ldasrcInp = OrderedDict() - # land default + # land default default_surfrcInp = self._parseInputFile(etcdir+'/GEOS_SurfaceGridComp.rc') for key,val in default_surfrcInp.items() : ldasrcInp[key] = val - # ldas default, may overwrite land default + # ldas default, may overwrite land default default_ldasrcInp = self._parseInputFile(rcfile) for key,val in default_ldasrcInp.items() : ldasrcInp[key] = val @@ -1132,7 +1135,7 @@ class LDASsetup: # create BC in rc file tmpl_ = '' if self.nens >1 : - tmpl_='%s' + tmpl_='%s' if self.perturb == 1: ldasrcInp['PERTURBATIONS'] ='1' bcval=['../input/green','../input/lai','../input/lnfm','../input/ndvi','../input/nirdf','../input/visdf'] @@ -1156,15 +1159,15 @@ class LDASsetup: if 'VEGDYN_INTERNAL_RESTART_TYPE' in ldasrcInp : # avoid duplicate del ldasrcInp['VEGDYN_INTERNAL_RESTART_TYPE'] - + rstkey=[catch_,'VEGDYN'] rstval=[self.catch,'vegdyn'] - if self.has_mwrtm : + if self.has_mwrtm : keyn='LANDASSIM_INTERNAL_RESTART_FILE' valn='../input/restart/mwrtm_param_rst' ldasrcInp[keyn]= valn - if self.has_vegopacity : + if self.has_vegopacity : keyn='VEGOPACITY_FILE' valn='../input/vegopacity.data' ldasrcInp[keyn]= valn @@ -1179,16 +1182,16 @@ class LDASsetup: valn='../input/restart/landassim_obspertrseed'+tmpl_+'_rst' ldasrcInp[keyn]= valn - if self.assim: + if self.assim: keyn='LANDASSIM_OBSPERTRSEED_CHECKPOINT_FILE' valn='landassim_obspertrseed'+tmpl_+'_checkpoint' ldasrcInp[keyn]= valn - + for key,val in zip(rstkey,rstval) : keyn = key+ '_INTERNAL_RESTART_FILE' valn = '../input/restart/'+val+tmpl_+'_internal_rst' ldasrcInp[keyn]= valn - + # checkpoint file and its type keyn = catch_ + '_INTERNAL_CHECKPOINT_FILE' valn = self.catch+tmpl_+'_internal_checkpoint' @@ -1200,12 +1203,12 @@ class LDASsetup: valn = '../input/restart/landpert'+tmpl_+'_internal_rst' ldasrcInp[keyn]= valn # for lat/lon and EASE tile space, specify LANDPERT checkpoint file here (via MAPL); - # for cube-sphere tile space, Landpert GC will set up LANDPERT checkpoint file + # for cube-sphere tile space, Landpert GC will set up LANDPERT checkpoint file if ('-CF' not in self.rqdExeInp['GRIDNAME']): keyn = 'LANDPERT_INTERNAL_CHECKPOINT_FILE' valn = 'landpert'+tmpl_+'_internal_checkpoint' ldasrcInp[keyn]= valn - + # write LDAS.rc fout =open(self.rundir+'/'+shortfile,'w') # ldasrcInp['NUM_LDAS_ENSEMBLE']=ldasrcInp.pop('NUM_ENSEMBLE') @@ -1219,9 +1222,9 @@ class LDASsetup: fout.write("EXP_ID:".ljust(36)+self.rqdExeInp['EXP_ID']+'\n') fout.write("TILING_FILE:".ljust(36)+"../input/tile.data\n") - fout.close() + fout.close() - fout=open(self.rundir+'/'+'cap_restart','w') + fout=open(self.rundir+'/'+'cap_restart','w') #fout.write(self.rqdExeInp['BEG_DATE']) fout.write(self.begDates[0].strftime('%Y%m%d %H%M%S')) fout.close() @@ -1238,8 +1241,11 @@ class LDASsetup: fout =open(self.rundir+'/ldas_batchrun.j','w') fout.write("#!/bin/bash -f\n") jobid = None + SBATCHQSUB = 'sbatch' expid = self.rqdExeInp['EXP_ID'] - fout.write("\nsed -i 's/if($capdate<$enddate) sbatch /#if($capdate<$enddate) sbatch /g' lenkf.j\n\n") + if self.GEOS_SITE == 'NAS': + SBATCHQSUB = 'qsub' + fout.write("\nsed -i 's/if($capdate<$enddate) "+SBATCHQSUB+"/#if($capdate<$enddate) "+SBATCHQSUB+"/g' lenkf.j\n\n") nSegments = self.nSegments for iseg in range(nSegments): if iseg ==0 : @@ -1273,10 +1279,10 @@ class LDASsetup: #fout.write("jobid%d=$(echo $(sbatch --dependency=afterany:$jobid%d --output=%s --error=%s lenkf.j) | cut -d' ' -f 4)\n"%(iseg,iseg-1,_logfile, _errfile)) fout.write("jobid%d=$(echo $(sbatch --dependency=afterok:$jobid%d lenkf.j) | cut -d' ' -f 4)\n"%(iseg,iseg-1)) fout.write("echo $jobid%d\n"%iseg ) - fout.write("\nsed -i 's/#if($capdate<$enddate) sbatch/if($capdate<$enddate) sbatch /g' lenkf.j") + fout.write("\nsed -i 's/#if($capdate<$enddate) "+SBATCHQSUB+"/if($capdate<$enddate) "+SBATCHQSUB+"/g' lenkf.j\n\n") fout.close() - sp.call(['chmod', '755', self.rundir+'/ldas_batchrun.j']) + sp.call(['chmod', '755', self.rundir+'/ldas_batchrun.j']) status = True return status @@ -1292,6 +1298,7 @@ class LDASsetup: shutil.copy(lenkf,'lenkf.j') my_qos='allnccs' + if self.GEOS_SITE == 'NAS': my_qos = 'normal' if 'qos' in self.optRmInp : my_qos = self.optRmInp['qos'] @@ -1326,23 +1333,40 @@ class LDASsetup: with open(lenkf,'rt') as fin: with open('lenkf.j','wt') as fout : for line in fin : + if self.GEOS_SITE == 'NAS': + if '#SBATCH' in line: + continue + if 'sbatch $HOMDIR/lenkf.j' in line: + continue + + if self.GEOS_SITE == 'NCCS': + if '#PBS' in line: + continue + if 'qsub $HOMDIR/lenkf.j' in line: + continue + if 'MY_ACCOUNT' in line : fout.write(line.replace('MY_ACCOUNT',self.rqdRmInp['account'])) elif 'MY_WALLTIME' in line : fout.write(line.replace('MY_WALLTIME',self.rqdRmInp['walltime'])) elif 'MY_NODES' in line : line_ = line.replace('MY_NODES',str(self.optRmInp['nodes'])) - fout.write(line_.replace('MY_NTASKS_PER_NODE',str(self.rqdRmInp['ntasks-per-node']))) - if int(self.rqdRmInp['ntasks-per-node']) > 40: - fout.write("#SBATCH --constraint=cas\n") - if (28 < int(self.rqdRmInp['ntasks-per-node']) and int(self.rqdRmInp['ntasks-per-node']) <= 40) : - fout.write("#SBATCH --constraint=sky\n") + line_ = line_.replace('MY_NTASKS_PER_NODE',str(self.rqdRmInp['ntasks-per-node'])) + line_ = line_.replace('MY_CONSTRAINT', 'cas_ait') + fout.write(line_) + if self.GEOS_SITE == "NCCS" : + if self.BUILT_ON_SLES15 : + fout.write("#SBATCH --constraint=mil\n") + else: + assert int(self.rqdRmInp['ntasks-per-node']) <= 46, 'ntasks-per-node should be <=46 for cas' + fout.write("#SBATCH --constraint=cas\n") + elif 'MY_OSERVER_NODES' in line : fout.write(line.replace('MY_OSERVER_NODES',str(self.optRmInp['oserver_nodes']))) elif 'MY_WRITERS_NPES' in line : fout.write(line.replace('MY_WRITERS_NPES', str(self.optRmInp['writers-per-node']))) elif 'MY_QOS' in line : - if 'allnccs' not in my_qos: + if 'allnccs' not in my_qos or 'normal' not in my_qos: fout.write(line.replace('MY_QOS',my_qos)) elif 'MY_JOB' in line : fout.write(line.replace('MY_JOB',my_job)) @@ -1357,7 +1381,7 @@ class LDASsetup: elif 'MY_MODEL' in line : fout.write(line.replace('MY_MODEL',self.catch)) elif 'MY_POSTPROC_HIST' in line : - fout.write(line.replace('MY_POSTPROC_HIST',str(self.rqdExeInp['POSTPROC_HIST']))) + fout.write(line.replace('MY_POSTPROC_HIST',str(self.rqdExeInp['POSTPROC_HIST']))) elif 'MY_FIRST_ENS_ID' in line : fout.write(line.replace('MY_FIRST_ENS_ID',str(self.first_ens_id))) elif 'MY_LADAS_COUPLING' in line : @@ -1367,12 +1391,10 @@ class LDASsetup: elif 'MY_ADAS_EXPDIR' in line : if self.ladas_coupling > 0: fout.write(line.replace('MY_ADAS_EXPDIR', self.rqdExeInp['ADAS_EXPDIR'])) - - else : fout.write(line.replace('MY_EXPDIR',self.exphome+'/$EXPID')) - - sp.call(['chmod', '755', 'lenkf.j']) + + sp.call(['chmod', '755', 'lenkf.j']) expdir = '/'.join(self.rundir.rstrip('/').split('/')[:-1]) print ('\nExperiment directory: %s' % expdir) @@ -1393,7 +1415,7 @@ def _printExeInputKeys(rqdExeInpKeys): Private method: print sample exe input """ - print ('####################################################################################') + print ('####################################################################################') print ('# #') print ('# REQUIRED INPUTS #') print ('# #') @@ -1401,7 +1423,7 @@ def _printExeInputKeys(rqdExeInpKeys): print ('# #') print ('####################################################################################') print () - print ('############################################################') + print ('############################################################') print ('# #') print ('# EXPERIMENT INFO #') print ('# #') @@ -1422,14 +1444,14 @@ def _printExeInputKeys(rqdExeInpKeys): print ('# (i) Select "RESTART" option: #') print ('# #') print ('# Use one of the following options if you *have* a #') - print ('# GEOSldas restart file: #') + print ('# GEOSldas restart file: #') print ('# #') print ('# RESTART: 1 #') print ('# YES, have restart file from GEOSldas #') print ('# in SAME tile space (grid) with SAME boundary #') print ('# conditions and SAME snow model parameter (WEMIN). #') print ('# The restart domain can be for the same or #') - print ('# a larger one. #') + print ('# a larger one. #') print ('# #') print ('# RESTART: 2 #') print ('# YES, have restart file from GEOSldas but #') @@ -1439,17 +1461,17 @@ def _printExeInputKeys(rqdExeInpKeys): print ('# Restart *must* be for the GLOBAL domain. #') print ('# #') print ('# Use one of the following options if you DO NOT have a #') - print ('# GEOSldas restart file #') + print ('# GEOSldas restart file #') print ('# (works for global domain ONLY!): #') print ('# #') print ('# RESTART: 0 #') print ('# Cold start from some old restart for Jan 1, 0z. #') print ('# #') print ('# RESTART: M #') - print ('# Re-tile from archived MERRA-2 restart file. #') + print ('# Re-tile from archived MERRA-2 restart file. #') print ('# #') print ('# RESTART: F #') - print ('# Re-tile from FP (Forward Processing) restart file. #') + print ('# Re-tile from FP (Forward Processing) restart file. #') print ('# #') print ('# RESTART: G #') print ('# Re-tile from any AGCM catch[cnclmxx]_internal_rst file.#') @@ -1459,19 +1481,19 @@ def _printExeInputKeys(rqdExeInpKeys): print ('# Except for RESTART=1, SPIN-UP is REQUIRED in almost #') print ('# all cases. #') print ('# -------------------------------------------------------- #') - print ('# #') - print ('# #') + print ('# #') + print ('# #') print ('# (ii) Specify experiment ID/location of restart file: #') print ('# #') print ('# For RESTART=1 or RESTART=2: #') print ('# Specify RESTART_ID, RESTART_PATH, RESTART_DOMAIN with #') print ('# restarts stored as follows: #') print ('# RESTART_PATH/RESTART_ID/output/RESTART_DOMAIN/rs/ #') - print ('# #') + print ('# #') print ('# For RESTART=0 or RESTART=M or RESTART=F: #') print ('# There is no need to specify RESTART_ID, RESTART_PATH, #') print ('# and RESTART_DOMAIN. #') - print ('# #') + print ('# #') print ('# For RESTART=G: #') print ('# RESTART_ID : full_path_to_AGCM_experiment_directory #') print ('# RESTART_PATH : full_path_of_the_AGCM_restart_file #') @@ -1492,7 +1514,7 @@ def _printExeInputKeys(rqdExeInpKeys): print ('# #') print ('# For more information, see: #') print ('# GEOSldas/doc/README.MetForcing_and_BCS.md #') - print ('# #') + print ('# #') print ('############################################################') print () print ('MET_TAG:') @@ -1522,26 +1544,26 @@ def _printExeInputKeys(rqdExeInpKeys): print ('# #') print ('# 0 -- LDAS not coupled with ADAS (default) #') print ('# 1 -- LDAS coupled with central member of ADAS #') - print ('# 2 -- LDAS coupled with ens component of ADAS #') - print ('# #') + print ('# 2 -- LDAS coupled with ens component of ADAS #') + print ('# #') print ('# Requirements for LADAS_COUPLING > 0: #') - print ('# #') + print ('# #') print ('# (0) Specify ADAS_EXPDIR = [full_path]/[ADAS_EXPID] #') print ('# #') print ('# (1) BEG_DATE must be consistent with first cycle date #') print ('# and time of ADAS experiment (time is typically #') print ('# 3z, 9z, 15z, or 21z) #') - print ('# #') + print ('# #') print ('# (2) EXP_DOMAIN must be global CS grid as in ADAS exp #') print ('# #') print ('# (3) MET_TAG must be set to [ADAS_EXPID]__Nx+- #') print ('# MET_PATH must be set as follows for #') - print ('# LADAS_COUPLING = 1: #') - print ('# [full_path]/[LDAS_EXPID]/scratch/ #') - print ('# LADAS_COUPLING = 2: #') + print ('# LADAS_COUPLING = 1: #') + print ('# [full_path]/[LDAS_EXPID]/scratch/ #') + print ('# LADAS_COUPLING = 2: #') print ('# [ADAS_EXPDIR]/atmens/ensdiag/forc #') - print ('# After ldas exp setup, verify the following link: #') - print ('# ../input/met_forcing/forc -> [MET_PATH] #') + print ('# After ldas exp setup, verify the following link: #') + print ('# ../input/met_forcing/forc -> [MET_PATH] #') print ('# #') print ('# (4) BCS_PATH must be consistent with that of #') print ('# [ADAS_EXPDIR][/run/lnbcs #') @@ -1555,7 +1577,7 @@ def _printExeInputKeys(rqdExeInpKeys): print ('# - instantaneous "catch_progn_incr" must be in #') print ('# HISTORY collection #') print ('# - time step must match that of LDAS analysis #') - print ('# - for LADAS_COUPLING=2, HISTORY must include #') + print ('# - for LADAS_COUPLING=2, HISTORY must include #') print ('# "catch_progn_incr[ENS_INDEX]" #') print ('# #') print ('############################################################') @@ -1595,12 +1617,12 @@ def _printExeInputKeys(rqdExeInpKeys): i_ += 1 print () print () - + def _printRmInputKeys(rqdRmInpKeys, optRmInpKeys): """ Private method: print sample resource manager input """ - + print ('#') print ('# REQUIRED inputs') print ('#') @@ -1609,9 +1631,9 @@ def _printRmInputKeys(rqdRmInpKeys, optRmInpKeys): print ('# [At NCCS: Use command "getsponsor" to see available account number(s).]' ) print ('# - walltime = walltime requested; format is HH:MM:SS (hours/minutes/seconds)') print ('# - ntasks_model = number of processors requested for the model (typically 112; output server is not included)') - print ('# - ntasks-per-node = number of tasks per node (typically 46 for cascade lake*, 40 for skylake, and 28 for haswell nodes)') - print ('# [If >40, cascade lake nodes will be allocated, if >28, cascade or skylake, else cascade, skylake or haswell.]') - print ('# [*NCCS recommends <=46 cores per node on SCU16 (cascade lake) due to OS issues (as of 6 Oct 2021).]') + print ('# - ntasks-per-node = number of tasks per node (typically 46 for cascade* and 40 for skylake nodes)') + print ('# [If >40, cascade nodes will be allocated, else cascade or skylake.]') + print ('# [*NCCS recommends <=46 cores per node on SCU16 (cascade) due to OS issues (as of 6 Oct 2021).]') print ('#') for key in rqdRmInpKeys: print (key + ':') @@ -1629,7 +1651,7 @@ def _printRmInputKeys(rqdRmInpKeys, optRmInpKeys): print ('#') for key in optRmInpKeys: print ('#'+key + ':') - + def parseCmdLine(): """ parse command line arguments and return a dict of options @@ -1647,14 +1669,14 @@ def parseCmdLine(): # subparser: sample command p_sample = p_sub.add_parser( - 'sample', + 'sample', help='write sample input files', description='Print sample input files - either for the '\ 'Fortran executable or the resource manager (SLURM)', ) group = p_sample.add_mutually_exclusive_group(required=True) group.add_argument( - '--exeinp', + '--exeinp', help='print sample input file used to generate RC files for GEOSldas App.', action='store_true', ) @@ -1665,25 +1687,25 @@ def parseCmdLine(): ) # subparser: setup command p_setup = p_sub.add_parser( - 'setup', + 'setup', help='setup LDAS experiment', description="The 'setup' sub-command is used to setup a GEOSldas " \ "experiment. The positional argument 'exphome' is used to create " \ "work_path (exphome+/output) and run_path (exphome+/run)." ) p_setup.add_argument( - '-v', - '--verbose', - help='verbose output', + '-v', + '--verbose', + help='verbose output', action='store_true', ) p_setup.add_argument('exphome', help='experiment location') p_setup.add_argument( - 'exeinpfile', + 'exeinpfile', help='input file with arguments used to generate RC files for GEOSldas App', ) p_setup.add_argument( - 'batinpfile', + 'batinpfile', help='input file with arguments for SLURM', ) p_setup.add_argument( @@ -1719,7 +1741,7 @@ if __name__=='__main__': #print "reading params...." args = vars(parseCmdLine()) # vars converts to dict ld = LDASsetup(args) - + print ("creating dir structure") status = ld.createDirStructure() assert(status) diff --git a/src/Applications/LDAS_App/lenkf.j.template b/src/Applications/LDAS_App/lenkf.j.template index 5ec5e2ef..7f6afcb0 100644 --- a/src/Applications/LDAS_App/lenkf.j.template +++ b/src/Applications/LDAS_App/lenkf.j.template @@ -16,6 +16,15 @@ #SBATCH --job-name=MY_JOB #SBATCH --qos=MY_QOS +#PBS -l walltime=MY_WALLTIME +#PBS -l select=MY_NODES:ncpus=40:mpiprocs=40:model=MY_CONSTRAINT +#PBS -N MY_JOB +#PBS -q MY_QOS +#PBS -W group_list=MY_ACCOUNT +#PBS -o ../scratch/GEOSldas_log_txt +#PBS -e ../scratch/GEOSldas_err_txt +#PBS -j oe + ####################################################################### # System Settings and Architecture Specific Environment Variables ####################################################################### @@ -40,7 +49,23 @@ setenv argv source $GEOSBIN/g5_modules -setenv I_MPI_DAPL_UD enable +# OPENMPI flags +# Turn off warning about TMPDIR on NFS +setenv OMPI_MCA_shmem_mmap_enable_nfs_warning 0 +# pre-connect MPI procs on mpi_init +setenv OMPI_MCA_mpi_preconnect_all 1 +setenv OMPI_MCA_coll_tuned_bcast_algorithm 7 +setenv OMPI_MCA_coll_tuned_scatter_algorithm 2 +setenv OMPI_MCA_coll_tuned_reduce_scatter_algorithm 3 +setenv OMPI_MCA_coll_tuned_allreduce_algorithm 3 +setenv OMPI_MCA_coll_tuned_allgather_algorithm 4 +setenv OMPI_MCA_coll_tuned_allgatherv_algorithm 3 +setenv OMPI_MCA_coll_tuned_gather_algorithm 1 +setenv OMPI_MCA_coll_tuned_barrier_algorithm 0 +# required for a tuned flag to be effective +setenv OMPI_MCA_coll_tuned_use_dynamic_rules 1 +# disable file locks +setenv OMPI_MCA_sharedfp "^lockedfile,individual" # By default, ensure 0-diff across processor architecture by limiting MKL's freedom to pick algorithms. # As of June 2021, MKL_CBWR=AVX2 is fastest setting that works for both haswell and skylake at NCCS. @@ -53,11 +78,8 @@ setenv MKL_CBWR "AVX2" # reversed sequence for LADAS_COUPLING (Sep 2020) (needed when coupling with ADAS using different BASEDIR) setenv LD_LIBRARY_PATH ${BASEDIR}/${ARCH}/lib:${ESMADIR}/lib:${LD_LIBRARY_PATH} -if ( -e /etc/os-release ) then - module load nco/4.8.1 -else - module load other/nco-4.6.8-gcc-5.3-sp3 -endif +module load nco + setenv RUN_CMD "$GEOSBIN/esma_mpirun -np " ####################################################################### @@ -130,10 +152,9 @@ if ( $LADAS_COUPLING == 1 ) then cd $SCRDIR else - # copy central-simulation forcing from $FVWORK to scratch dir - - echo "copying lfo_Nx+- met forcing from $FVWORK to $SCRDIR" - /bin/cp -f $FVWORK/*lfo_Nx+-*nc4 $SCRDIR/. + # move central-simulation forcing held in met_forcing to scratch dir + echo "move lfo_Nx+- met forcing from $EXPDIR/input/met_forcing to $SCRDIR" + /bin/mv $EXPDIR/input/met_forcing/*lfo_Nx+-*nc4 $SCRDIR/. endif endif @@ -398,7 +419,11 @@ while ( $counter <= ${NUM_SGMT} ) @ oserver_nodes = MY_OSERVER_NODES @ writers = MY_WRITERS_NPES - set total_npes = $SLURM_NTASKS + if (! $?SLURM_NTASKS) then + set total_npes = `wc -l $PBS_NODEFILE | awk '{print $1}'` + else + set total_npes = $SLURM_NTASKS + endif if ($oserver_nodes == 0) then set oserver_options = "" @@ -819,5 +844,6 @@ else cd $HOMDIR #don't change below line(not even extra space) if($capdate<$enddate) sbatch $HOMDIR/lenkf.j + if($capdate<$enddate) qsub $HOMDIR/lenkf.j endif endif diff --git a/src/Applications/LDAS_App/preprocess_ldas.F90 b/src/Applications/LDAS_App/preprocess_ldas.F90 index 30a68f97..4d5725e6 100644 --- a/src/Applications/LDAS_App/preprocess_ldas.F90 +++ b/src/Applications/LDAS_App/preprocess_ldas.F90 @@ -25,6 +25,7 @@ program main character(len=512) :: arg5 character(len=512) :: arg6 character(len=512) :: arg7 + character(len=512) :: arg8 character(len=512) :: orig_tile character(len=512) :: new_tile @@ -42,6 +43,7 @@ program main character(len=512) :: new_veg character(len=512) :: orig_ease character(len=512) :: new_ease + character(len=512) :: f2g_file character(len=12 ) :: ymdhm character(len=12 ) :: SURFLAY @@ -53,6 +55,7 @@ program main call get_command_argument(6,arg5) call get_command_argument(7,arg6) call get_command_argument(8,arg7) + call get_command_argument(9,arg8) if( trim(option) == "c_f2g") then @@ -66,43 +69,48 @@ program main exp_id = arg5 ymdhm = trim(adjustl(arg6)) SURFLAY = trim(adjustl(arg7)) + f2g_file = arg8 - call createf2g(orig_tile,domain_def_file,trim(out_path),catch_def_file,trim(exp_id),ymdhm, SURFLAY) + call createf2g(orig_tile,domain_def_file,trim(out_path),catch_def_file,trim(exp_id),ymdhm, SURFLAY, f2g_file) else if (trim(option) == "c_localtile") then orig_tile = arg1 new_tile = arg2 - - call createLocalTilefile(orig_tile,new_tile) + f2g_file = arg3 + call createLocalTilefile(f2g_file, orig_tile,new_tile) else if (trim(option) == "c_localbc" ) then - orig_BC = arg1 - new_BC = arg2 + orig_BC = arg1 + new_BC = arg2 + f2g_file = arg3 - call createLocalBC(orig_BC, new_BC) + call createLocalBC(f2g_file, orig_BC, new_BC) else if (trim(option) == "c_localvegrst") then orig_veg = arg1 new_veg = arg2 + f2g_file = arg3 - call createLocalVegRestart(orig_veg, new_veg) + call createLocalVegRestart(f2g_file, orig_veg, new_veg) else if (trim(option) == "c_localmwrtmrst") then orig_rtm = arg1 new_rtm = arg2 + f2g_file = arg3 - call createLocalmwRTMRestart(orig_rtm, new_rtm) + call createLocalmwRTMRestart(f2g_file, orig_rtm, new_rtm) else if (trim(option) == "c_localcatchrst") then orig_catch = arg1 new_catch = arg2 + f2g_file = arg3 - call createLocalCatchRestart(orig_catch, new_catch) + call createLocalCatchRestart(f2g_file, orig_catch, new_catch) else if (trim(option)=="correctease") then @@ -120,7 +128,8 @@ program main else if (trim(option) == "optimize") then - call optimize_latlon(arg1,arg2) + + call optimize_latlon(arg1,arg2, arg3, arg4) else diff --git a/src/Applications/LDAS_App/preprocess_ldas_routines.F90 b/src/Applications/LDAS_App/preprocess_ldas_routines.F90 index 4796b4a9..4a7e9ec1 100644 --- a/src/Applications/LDAS_App/preprocess_ldas_routines.F90 +++ b/src/Applications/LDAS_App/preprocess_ldas_routines.F90 @@ -106,7 +106,7 @@ module preprocess_ldas_routines ! ******************************************************************** - subroutine createf2g(orig_tile,domain_def,out_path,catch_def_file,exp_id,ymdhm, SURFLAY) + subroutine createf2g(orig_tile,domain_def,out_path,catch_def_file,exp_id,ymdhm, SURFLAY, f2g_file) implicit none character(*) :: orig_tile @@ -116,6 +116,7 @@ subroutine createf2g(orig_tile,domain_def,out_path,catch_def_file,exp_id,ymdhm, character(*) :: exp_id character(*) :: ymdhm character(*) :: SURFLAY + character(*) :: f2g_file real :: minlon,maxlon,minlat,maxlat character(len=512):: exclude_file,include_file @@ -211,7 +212,7 @@ subroutine createf2g(orig_tile,domain_def,out_path,catch_def_file,exp_id,ymdhm, else d2f = d2g endif - open(40,file='f2g.txt',form='formatted',action='write') + open(40,file=f2g_file,form='formatted',action='write') write(40,*)N_catf write(40,*)N_catd do n=1,N_catd @@ -1494,17 +1495,18 @@ end subroutine createf2g ! ******************************************************************** - subroutine readsize(N_catg,N_catf) + subroutine readsize(f2g_file, N_catg,N_catf) implicit none + character(*), intent(in):: f2g_file integer,intent(out) :: N_catg integer,intent(out) :: N_catf logical :: file_exist - inquire(file=trim('f2g.txt'),exist=file_exist) + inquire(file=f2g_file,exist=file_exist) if(file_exist) then - open(40,file='f2g.txt',form='formatted',action='read',status='old') + open(40,file= f2g_file,form='formatted',action='read',status='old') read(40,*)N_catg read(40,*)N_catf close(40) @@ -1515,9 +1517,10 @@ end subroutine readsize ! ******************************************************************** - subroutine readf2g(N_catf,f2g) + subroutine readf2g(f2g_file, N_catf,f2g) implicit none + character(*), intent(in):: f2g_file integer,intent(in) :: N_catf integer,dimension(N_catf),intent(inout) :: f2g @@ -1525,9 +1528,9 @@ subroutine readf2g(N_catf,f2g) logical :: file_exist integer :: local_size,n - inquire(file=trim('f2g.txt'),exist=file_exist) + inquire(file=f2g_file,exist=file_exist) if(file_exist) then - open(40,file='f2g.txt',form='formatted',action='read',status='old') + open(40,file= f2g_file,form='formatted',action='read',status='old') read(40,*)N_catg read(40,*)local_size @@ -1551,9 +1554,10 @@ end subroutine readf2g ! ******************************************************************** - subroutine createLocalTilefile(orig_tile,new_tile) + subroutine createLocalTilefile(f2g_file, orig_tile,new_tile) implicit none + character(*), intent(in) :: f2g_file character(*), intent(in) :: orig_tile character(*), intent(in) :: new_tile @@ -1596,13 +1600,13 @@ subroutine createLocalTilefile(orig_tile,new_tile) if( .not. file_exist) stop ("original tile file does not exist") ! Set default local tile file name - call readsize(N_catg,N_catf) + call readsize( f2g_file, N_catg,N_catf) if(N_catg == N_catf) then print*, "It is global domain..." return endif allocate(f2g(N_catf)) - call readf2g(N_catf,f2g) + call readf2g(f2g_file, N_catf,f2g) open(40,file=trim(orig_tile),action="read") open(50,file=trim(new_tile),action="write") @@ -1659,9 +1663,10 @@ end subroutine createLocalTilefile ! ******************************************************************** - subroutine createLocalBC(orig_BC, new_BC) + subroutine createLocalBC(f2g_file, orig_BC, new_BC) implicit none + character(*),intent(in) :: f2g_file character(*),intent(in) :: orig_BC character(*),intent(in) :: new_BC @@ -1670,10 +1675,10 @@ subroutine createLocalBC(orig_BC, new_BC) integer :: istat, N_catg,N_catf integer,dimension(:),allocatable :: f2g - call readsize(N_catg,N_catf) + call readsize(f2g_file, N_catg,N_catf) if(N_catg==N_catf) return allocate(f2g(N_catf)) - call readf2g(N_catf,f2g) + call readf2g(f2g_file, N_catf,f2g) allocate(tmpvec(N_catg)) open(10,file=trim(orig_BC),form='unformatted',action='read',status='old',iostat=istat) @@ -1693,9 +1698,10 @@ end subroutine createLocalBC ! ******************************************************************** - subroutine createLocalCatchRestart(orig_catch, new_catch) + subroutine createLocalCatchRestart(f2g_file, orig_catch, new_catch) implicit none + character(*),intent(in):: f2g_file character(*),intent(in):: orig_catch character(*),intent(in):: new_catch integer,parameter :: subtile=4 @@ -1714,10 +1720,10 @@ subroutine createLocalCatchRestart(orig_catch, new_catch) integer ::n, N_catg,N_catf integer,dimension(:),allocatable :: f2g - call readsize(N_catg,N_catf) + call readsize(f2g_file, N_catg,N_catf) if(N_catg == N_catf) return allocate(f2g(N_catf)) - call readf2g(N_catf,f2g) + call readf2g(f2g_file, N_catf,f2g) allocate(tmp1(N_catg)) allocate(tmp2(N_catg,subtile)) @@ -1824,9 +1830,10 @@ end subroutine createLocalCatchRestart ! ******************************************************************** - subroutine createLocalmwRTMRestart(orig_mwrtm, new_mwrtm) + subroutine createLocalmwRTMRestart(f2g_file, orig_mwrtm, new_mwrtm) implicit none + character(*),intent(in):: f2g_file character(*),intent(in):: orig_mwrtm character(*),intent(in):: new_mwrtm integer,parameter :: subtile=4 @@ -1842,10 +1849,10 @@ subroutine createLocalmwRTMRestart(orig_mwrtm, new_mwrtm) integer :: N_catg,N_catf integer,dimension(:),allocatable :: f2g - call readsize(N_catg,N_catf) + call readsize(f2g_file, N_catg,N_catf) if(N_catg == N_catf) return allocate(f2g(N_catf)) - call readf2g(N_catf,f2g) + call readf2g(f2g_file, N_catf,f2g) allocate(tmp1(N_catg)) @@ -1877,9 +1884,10 @@ end subroutine createLocalmwRTMRestart ! ******************************************************************** - subroutine createLocalVegRestart(orig_veg, new_veg) + subroutine createLocalVegRestart(f2g_file, orig_veg, new_veg) implicit none + character(*),intent(in):: f2g_file character(*),intent(in):: orig_veg character(*),intent(in):: new_veg integer :: istat @@ -1900,10 +1908,10 @@ subroutine createLocalVegRestart(orig_veg, new_veg) character(len=:), pointer :: vname integer :: rc - call readsize(N_catg,N_catf) + call readsize(f2g_file, N_catg,N_catf) if(N_catg == N_catf) return allocate(f2g(N_catf)) - call readf2g(N_catf,f2g) + call readf2g(f2g_file, N_catf,f2g) allocate(rity(N_catg)) allocate(z2(N_catg)) @@ -2034,12 +2042,14 @@ end subroutine correctEase ! NY: N_proc 1 ! JMS.rc IMS.rc - subroutine optimize_latlon(fname_tilefile, N_proc_string) + subroutine optimize_latlon(fname_tilefile, N_proc_string, optimized_file, run_dir) implicit none character(*), intent(in) :: fname_tilefile ! file name (with path) of tile file (*.til) character(*), intent(in) :: N_proc_string ! *string* w/ no. of processors (or tasks), excl. OSERVER tasks + character(*), intent(in) :: optimized_file + character(*), intent(in) :: run_dir ! local variables integer :: N_proc @@ -2059,6 +2069,7 @@ subroutine optimize_latlon(fname_tilefile, N_proc_string) integer :: IMGLOB, JMGLOB integer :: face(6),face_land(6) logical :: forward + character(len=:), allocatable :: IMS_file, JMS_File ! ----------------------------- @@ -2265,8 +2276,8 @@ subroutine optimize_latlon(fname_tilefile, N_proc_string) enddo if( k /=6 ) stop ("one or more processes may accross the face") - - open(10,file="optimized_distribution",action='write') + + open(10,file=optimized_file,action='write') write(10,'(A)') "GEOSldas.GRIDNAME: " // trim(gridname) write(10,'(A)') "GEOSldas.GRID_TYPE: Cubed-Sphere" write(10,'(A)') "GEOSldas.NF: 6" @@ -2277,7 +2288,8 @@ subroutine optimize_latlon(fname_tilefile, N_proc_string) write(10,'(A)') "GEOSldas.JMS_FILE: JMS.rc" close(10) - open(10,file="JMS.rc",action='write') + JMS_file = trim(run_dir)//"/JMS.rc" + open(10,file=JMS_file ,action='write') write(10,'(I5,I5)') N_proc, maxval(face) do n=1,N_proc write(10,'(I8)') JMS(n) @@ -2456,7 +2468,7 @@ subroutine optimize_latlon(fname_tilefile, N_proc_string) enddo if( any(IMS <=1) ) stop ("Each processor must have at least 2 longitude stripes. Request fewer processors.") - open(10,file="optimized_distribution",action='write') + open(10,file=optimized_file, action='write') write(10,'(A)') "GEOSldas.GRID_TYPE: LatLon" write(10,'(A)') "GEOSldas.GRIDNAME: "//trim(gridname) write(10,'(A)') "GEOSldas.LM: 1" @@ -2471,7 +2483,8 @@ subroutine optimize_latlon(fname_tilefile, N_proc_string) write(10,'(A)') "GEOSldas.IMS_FILE: IMS.rc" close(10) - open(10,file="IMS.rc",action='write') + IMS_file = trim(run_dir)//"/IMS.rc" + open(10,file=IMS_file,action='write') write(10,'(I5)') N_proc do n=1,N_proc write(10,'(I8)') IMS(n) diff --git a/src/Applications/LDAS_App/process_rst.py b/src/Applications/LDAS_App/remap_config_ldas.py similarity index 78% rename from src/Applications/LDAS_App/process_rst.py rename to src/Applications/LDAS_App/remap_config_ldas.py index a3ebd194..9848916b 100644 --- a/src/Applications/LDAS_App/process_rst.py +++ b/src/Applications/LDAS_App/remap_config_ldas.py @@ -16,8 +16,12 @@ def remap_config_ldas(config, RESTART_str, RESTART_PATH, RESTART_ID): config['input']['shared'] = merra2_expid(config['input']['shared']) config['input']['shared']['rst_dir'] = out_dir+ '/merra2_tmp_'+ yyyymmddhh config['input']['surface']['wemin'] = 26 - config['input']['shared']['bcs_dir'] = '/discover/nobackup/projects/gmao/bcs_shared/legacy_bcs/Ganymed-4_0/Ganymed-4_0_MERRA-2/CF0180x6C_DE1440xPE0720/' - + config['input']['shared']['bc_base'] = '/discover/nobackup/projects/gmao/bcs_shared/fvInput/ExtData/esm/tiles' + config['input']['shared']['bc_version'] = 'GM4' + config['input']['shared']['agrid'] = 'C180' + config['input']['shared']['ogrid'] = '1440x720' + config['input']['shared']['omodel'] = 'data' + if RESTART_str == "G" : # WY note: it is a bad idea to overload restart_path and restart_id config['input']['surface']['catch_tilefile'] = os.path.realpath(RESTART_ID+'scratch/tile.data') @@ -39,7 +43,11 @@ def remap_config_ldas(config, RESTART_str, RESTART_PATH, RESTART_ID): print( " Please select RESTART: M and use MERRA-2, instead.") sys.exit(1) - config['input']['shared']['bcs_dir'] = '/discover/nobackup/projects/gmao/bcs_shared/legacy_bcs/Icarus/Icarus_Ostia/CF0720x6C_CF0720x6C/' + config['input']['shared']['bc_base'] = '/discover/nobackup/projects/gmao/bcs_shared/fvInput/ExtData/esm/tiles' + config['input']['shared']['bc_version'] = 'ICA' + config['input']['shared']['agrid'] = 'C720' + config['input']['shared']['ogrid'] = 'C720' + config['input']['surface']['wemin'] = 26 config['input']['shared']['rst_dir'] = out_dir+'/InData'+ '/' suffix = '_21z.tar' @@ -47,7 +55,11 @@ def remap_config_ldas(config, RESTART_str, RESTART_PATH, RESTART_ID): if ((date_16 <= expdate) and (expdate < date_17)): fpver = 'GEOS-5.16/GEOSadas-5_16/' fplab = 'f516_fp' - config['input']['shared']['bcs_dir'] = '/discover/nobackup/projects/gmao/bcs_shared/legacy_bcs/Ganymed-4_0/Ganymed-4_0_Ostia/CF0720x6C_DE2880xPE1440/' + config['input']['shared']['bc_base'] = '/discover/nobackup/projects/gmao/bcs_shared/fvInput/ExtData/esm/tiles' + config['input']['shared']['bc_version'] = 'GM4' + config['input']['shared']['agrid'] = 'C720' + config['input']['shared']['ogrid'] = '2880x1440' + suffix = '_21z.bin' if ((date_17 <= expdate) and (expdate < date_21)): diff --git a/src/Applications/LDAS_App/sample_config_files/LADAS/HISTORY.rc.atmens b/src/Applications/LDAS_App/sample_config_files/LADAS/HISTORY.rc.atmens index 8a21db30..0f3e7f1e 100644 --- a/src/Applications/LDAS_App/sample_config_files/LADAS/HISTORY.rc.atmens +++ b/src/Applications/LDAS_App/sample_config_files/LADAS/HISTORY.rc.atmens @@ -1,25 +1,28 @@ + # # Sample GEOSldas HISTORY.rc file for LADAS (atm ensemble) # -# This sample is for the GEOSldas instance that is coupled with the atmospheric -# ensemble component of the Hy4dEnVar ADAS: +# - This sample HISTORY.rc is for the GEOSldas instance that is weakly coupled with the +# atmospheric ensemble component of the Hybrid-4DEnVar ADAS (ADASens). +# +# - The sample file was generated with the utility script +# "GEOSldas/src/Applications/LDAS_App/util/config/generate_catchincr_hist.py". +# +# - The sample file triggers output of the GEOSldas "catch_progn_incr" collection in +# ensemble space, which is needed by ADASens. +# +# - The IDs of the ensemble members and their total number in GEOSldas must match +# those of ADASens. +# +# - The "catch_progn_incr" output is in tile space, which must be the same for +# GEOSldas and ADASens. # -# (1) The definition of the "catch_progn_incr" ensemble collection was generated -# with the utility script "generate_catchincr_hist.py", with the number of -# ensemble members and their indexing matching those of the atmospheric -# ensemble component of the Hy4dEnVar ADAS. -# (2) The "catch_progn_incr" output is in tile space. Its definition is generic -# for any LADAS resolution. -# (3) The resolution of the "lndfcstana" output should be adjusted to match that -# of the LADAS. # ################################################################################## -VERSION: 1 -EXPID: MyGEOSldasAtmEns +EXPID: MyGEOSldasAtmEns COLLECTIONS: -'inst3_2d_lndfcstana_Nx' 'catch_progn_incr0001' 'catch_progn_incr0002' 'catch_progn_incr0003' @@ -54,87 +57,36 @@ COLLECTIONS: 'catch_progn_incr0032' :: -GRID_LABELS: PC720x361-DC - PC576x361-DC - PC288x181-DC -:: - -PC720x361-DC.GRID_TYPE: LatLon -PC720x361-DC.IM_WORLD: 720 -PC720x361-DC.JM_WORLD: 361 -PC720x361-DC.POLE: PC -PC720x361-DC.DATELINE: DC -PC720x361-DC.LM: 1 - -PC576x361-DC.GRID_TYPE: LatLon -PC576x361-DC.IM_WORLD: 576 -PC576x361-DC.JM_WORLD: 361 -PC576x361-DC.POLE: PC -PC576x361-DC.DATELINE: DC -PC576x361-DC.LM: 1 - -PC288x181-DC.GRID_TYPE: LatLon -PC288x181-DC.IM_WORLD: 288 -PC288x181-DC.JM_WORLD: 181 -PC288x181-DC.POLE: PC -PC288x181-DC.DATELINE: DC -PC288x181-DC.LM: 1 - - -inst3_2d_lndfcstana_Nx.descr: '2d,3-Hourly,Instantaneous,Single-Level,Assimilation,Ensemble-average Land Forecast and Analysis Diagnostics', -inst3_2d_lndfcstana_Nx.template: '%y4%m2%d2_%h2%n2z.nc4', -inst3_2d_lndfcstana_Nx.mode: 'instantaneous', -inst3_2d_lndfcstana_Nx.frequency: 030000, -inst3_2d_lndfcstana_Nx.ref_time: 013000, -inst3_2d_lndfcstana_Nx.format: 'CFIO', -inst3_2d_lndfcstana_Nx.regrid_exch: '../input/tile.data', -inst3_2d_lndfcstana_Nx.regrid_name: 'PE90x540-CF', -inst3_2d_lndfcstana_Nx.grid_label: PC288x181-DC, -inst3_2d_lndfcstana_Nx.deflate: 2, -inst3_2d_lndfcstana_Nx.fields: 'WCSF' , 'ENSAVG' , 'SFMC_FCST' , - 'WCRZ' , 'ENSAVG' , 'RZMC_FCST' , - 'WCPR' , 'ENSAVG' , 'PRMC_FCST' , - 'TPSURF' , 'ENSAVG' , 'TSURF_FCST' , - 'TSOIL1TILE' , 'ENSAVG' , 'TSOIL1_FCST' , - 'WCSF_ANA' , 'LANDASSIM' , 'SFMC_ANA' , - 'WCRZ_ANA' , 'LANDASSIM' , 'RZMC_ANA' , - 'WCPR_ANA' , 'LANDASSIM' , 'PRMC_ANA' , - 'TPSURF_ANA' , 'LANDASSIM' , 'TSURF_ANA' , - 'TSOIL1_ANA' , 'LANDASSIM' , 'TSOIL1_ANA' , - :: - - - catch_progn_incr0001.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', catch_progn_incr0001.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0001.mode: 'instantaneous', catch_progn_incr0001.frequency: 030000, catch_progn_incr0001.ref_time: 013000, -catch_progn_incr0001.fields: 'TCFSAT_INCR' , 'CATCHINCR0001' , - 'TCFTRN_INCR' , 'CATCHINCR0001' , - 'TCFWLT_INCR' , 'CATCHINCR0001' , - 'QCFSAT_INCR' , 'CATCHINCR0001' , - 'QCFTRN_INCR' , 'CATCHINCR0001' , - 'QCFWLT_INCR' , 'CATCHINCR0001' , - 'CAPAC_INCR' , 'CATCHINCR0001' , - 'CATDEF_INCR' , 'CATCHINCR0001' , - 'RZEXC_INCR' , 'CATCHINCR0001' , - 'SRFEXC_INCR' , 'CATCHINCR0001' , - 'GHTCNT1_INCR' , 'CATCHINCR0001' , - 'GHTCNT2_INCR' , 'CATCHINCR0001' , - 'GHTCNT3_INCR' , 'CATCHINCR0001' , - 'GHTCNT4_INCR' , 'CATCHINCR0001' , - 'GHTCNT5_INCR' , 'CATCHINCR0001' , - 'GHTCNT6_INCR' , 'CATCHINCR0001' , - 'WESNN1_INCR' , 'CATCHINCR0001' , - 'WESNN2_INCR' , 'CATCHINCR0001' , - 'WESNN3_INCR' , 'CATCHINCR0001' , - 'HTSNNN1_INCR' , 'CATCHINCR0001' , - 'HTSNNN2_INCR' , 'CATCHINCR0001' , - 'HTSNNN3_INCR' , 'CATCHINCR0001' , - 'SNDZN1_INCR' , 'CATCHINCR0001' , - 'SNDZN2_INCR' , 'CATCHINCR0001' , - 'SNDZN3_INCR' , 'CATCHINCR0001' , +catch_progn_incr0001.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0001' , + 'TCFTRN_INCR' , 'CATCHINCR_e0001' , + 'TCFWLT_INCR' , 'CATCHINCR_e0001' , + 'QCFSAT_INCR' , 'CATCHINCR_e0001' , + 'QCFTRN_INCR' , 'CATCHINCR_e0001' , + 'QCFWLT_INCR' , 'CATCHINCR_e0001' , + 'CAPAC_INCR' , 'CATCHINCR_e0001' , + 'CATDEF_INCR' , 'CATCHINCR_e0001' , + 'RZEXC_INCR' , 'CATCHINCR_e0001' , + 'SRFEXC_INCR' , 'CATCHINCR_e0001' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0001' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0001' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0001' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0001' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0001' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0001' , + 'WESNN1_INCR' , 'CATCHINCR_e0001' , + 'WESNN2_INCR' , 'CATCHINCR_e0001' , + 'WESNN3_INCR' , 'CATCHINCR_e0001' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0001' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0001' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0001' , + 'SNDZN1_INCR' , 'CATCHINCR_e0001' , + 'SNDZN2_INCR' , 'CATCHINCR_e0001' , + 'SNDZN3_INCR' , 'CATCHINCR_e0001' , :: catch_progn_incr0002.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -142,31 +94,31 @@ catch_progn_incr0002.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0002.mode: 'instantaneous', catch_progn_incr0002.frequency: 030000, catch_progn_incr0002.ref_time: 013000, -catch_progn_incr0002.fields: 'TCFSAT_INCR' , 'CATCHINCR0002' , - 'TCFTRN_INCR' , 'CATCHINCR0002' , - 'TCFWLT_INCR' , 'CATCHINCR0002' , - 'QCFSAT_INCR' , 'CATCHINCR0002' , - 'QCFTRN_INCR' , 'CATCHINCR0002' , - 'QCFWLT_INCR' , 'CATCHINCR0002' , - 'CAPAC_INCR' , 'CATCHINCR0002' , - 'CATDEF_INCR' , 'CATCHINCR0002' , - 'RZEXC_INCR' , 'CATCHINCR0002' , - 'SRFEXC_INCR' , 'CATCHINCR0002' , - 'GHTCNT1_INCR' , 'CATCHINCR0002' , - 'GHTCNT2_INCR' , 'CATCHINCR0002' , - 'GHTCNT3_INCR' , 'CATCHINCR0002' , - 'GHTCNT4_INCR' , 'CATCHINCR0002' , - 'GHTCNT5_INCR' , 'CATCHINCR0002' , - 'GHTCNT6_INCR' , 'CATCHINCR0002' , - 'WESNN1_INCR' , 'CATCHINCR0002' , - 'WESNN2_INCR' , 'CATCHINCR0002' , - 'WESNN3_INCR' , 'CATCHINCR0002' , - 'HTSNNN1_INCR' , 'CATCHINCR0002' , - 'HTSNNN2_INCR' , 'CATCHINCR0002' , - 'HTSNNN3_INCR' , 'CATCHINCR0002' , - 'SNDZN1_INCR' , 'CATCHINCR0002' , - 'SNDZN2_INCR' , 'CATCHINCR0002' , - 'SNDZN3_INCR' , 'CATCHINCR0002' , +catch_progn_incr0002.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0002' , + 'TCFTRN_INCR' , 'CATCHINCR_e0002' , + 'TCFWLT_INCR' , 'CATCHINCR_e0002' , + 'QCFSAT_INCR' , 'CATCHINCR_e0002' , + 'QCFTRN_INCR' , 'CATCHINCR_e0002' , + 'QCFWLT_INCR' , 'CATCHINCR_e0002' , + 'CAPAC_INCR' , 'CATCHINCR_e0002' , + 'CATDEF_INCR' , 'CATCHINCR_e0002' , + 'RZEXC_INCR' , 'CATCHINCR_e0002' , + 'SRFEXC_INCR' , 'CATCHINCR_e0002' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0002' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0002' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0002' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0002' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0002' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0002' , + 'WESNN1_INCR' , 'CATCHINCR_e0002' , + 'WESNN2_INCR' , 'CATCHINCR_e0002' , + 'WESNN3_INCR' , 'CATCHINCR_e0002' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0002' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0002' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0002' , + 'SNDZN1_INCR' , 'CATCHINCR_e0002' , + 'SNDZN2_INCR' , 'CATCHINCR_e0002' , + 'SNDZN3_INCR' , 'CATCHINCR_e0002' , :: catch_progn_incr0003.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -174,31 +126,31 @@ catch_progn_incr0003.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0003.mode: 'instantaneous', catch_progn_incr0003.frequency: 030000, catch_progn_incr0003.ref_time: 013000, -catch_progn_incr0003.fields: 'TCFSAT_INCR' , 'CATCHINCR0003' , - 'TCFTRN_INCR' , 'CATCHINCR0003' , - 'TCFWLT_INCR' , 'CATCHINCR0003' , - 'QCFSAT_INCR' , 'CATCHINCR0003' , - 'QCFTRN_INCR' , 'CATCHINCR0003' , - 'QCFWLT_INCR' , 'CATCHINCR0003' , - 'CAPAC_INCR' , 'CATCHINCR0003' , - 'CATDEF_INCR' , 'CATCHINCR0003' , - 'RZEXC_INCR' , 'CATCHINCR0003' , - 'SRFEXC_INCR' , 'CATCHINCR0003' , - 'GHTCNT1_INCR' , 'CATCHINCR0003' , - 'GHTCNT2_INCR' , 'CATCHINCR0003' , - 'GHTCNT3_INCR' , 'CATCHINCR0003' , - 'GHTCNT4_INCR' , 'CATCHINCR0003' , - 'GHTCNT5_INCR' , 'CATCHINCR0003' , - 'GHTCNT6_INCR' , 'CATCHINCR0003' , - 'WESNN1_INCR' , 'CATCHINCR0003' , - 'WESNN2_INCR' , 'CATCHINCR0003' , - 'WESNN3_INCR' , 'CATCHINCR0003' , - 'HTSNNN1_INCR' , 'CATCHINCR0003' , - 'HTSNNN2_INCR' , 'CATCHINCR0003' , - 'HTSNNN3_INCR' , 'CATCHINCR0003' , - 'SNDZN1_INCR' , 'CATCHINCR0003' , - 'SNDZN2_INCR' , 'CATCHINCR0003' , - 'SNDZN3_INCR' , 'CATCHINCR0003' , +catch_progn_incr0003.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0003' , + 'TCFTRN_INCR' , 'CATCHINCR_e0003' , + 'TCFWLT_INCR' , 'CATCHINCR_e0003' , + 'QCFSAT_INCR' , 'CATCHINCR_e0003' , + 'QCFTRN_INCR' , 'CATCHINCR_e0003' , + 'QCFWLT_INCR' , 'CATCHINCR_e0003' , + 'CAPAC_INCR' , 'CATCHINCR_e0003' , + 'CATDEF_INCR' , 'CATCHINCR_e0003' , + 'RZEXC_INCR' , 'CATCHINCR_e0003' , + 'SRFEXC_INCR' , 'CATCHINCR_e0003' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0003' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0003' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0003' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0003' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0003' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0003' , + 'WESNN1_INCR' , 'CATCHINCR_e0003' , + 'WESNN2_INCR' , 'CATCHINCR_e0003' , + 'WESNN3_INCR' , 'CATCHINCR_e0003' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0003' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0003' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0003' , + 'SNDZN1_INCR' , 'CATCHINCR_e0003' , + 'SNDZN2_INCR' , 'CATCHINCR_e0003' , + 'SNDZN3_INCR' , 'CATCHINCR_e0003' , :: catch_progn_incr0004.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -206,31 +158,31 @@ catch_progn_incr0004.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0004.mode: 'instantaneous', catch_progn_incr0004.frequency: 030000, catch_progn_incr0004.ref_time: 013000, -catch_progn_incr0004.fields: 'TCFSAT_INCR' , 'CATCHINCR0004' , - 'TCFTRN_INCR' , 'CATCHINCR0004' , - 'TCFWLT_INCR' , 'CATCHINCR0004' , - 'QCFSAT_INCR' , 'CATCHINCR0004' , - 'QCFTRN_INCR' , 'CATCHINCR0004' , - 'QCFWLT_INCR' , 'CATCHINCR0004' , - 'CAPAC_INCR' , 'CATCHINCR0004' , - 'CATDEF_INCR' , 'CATCHINCR0004' , - 'RZEXC_INCR' , 'CATCHINCR0004' , - 'SRFEXC_INCR' , 'CATCHINCR0004' , - 'GHTCNT1_INCR' , 'CATCHINCR0004' , - 'GHTCNT2_INCR' , 'CATCHINCR0004' , - 'GHTCNT3_INCR' , 'CATCHINCR0004' , - 'GHTCNT4_INCR' , 'CATCHINCR0004' , - 'GHTCNT5_INCR' , 'CATCHINCR0004' , - 'GHTCNT6_INCR' , 'CATCHINCR0004' , - 'WESNN1_INCR' , 'CATCHINCR0004' , - 'WESNN2_INCR' , 'CATCHINCR0004' , - 'WESNN3_INCR' , 'CATCHINCR0004' , - 'HTSNNN1_INCR' , 'CATCHINCR0004' , - 'HTSNNN2_INCR' , 'CATCHINCR0004' , - 'HTSNNN3_INCR' , 'CATCHINCR0004' , - 'SNDZN1_INCR' , 'CATCHINCR0004' , - 'SNDZN2_INCR' , 'CATCHINCR0004' , - 'SNDZN3_INCR' , 'CATCHINCR0004' , +catch_progn_incr0004.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0004' , + 'TCFTRN_INCR' , 'CATCHINCR_e0004' , + 'TCFWLT_INCR' , 'CATCHINCR_e0004' , + 'QCFSAT_INCR' , 'CATCHINCR_e0004' , + 'QCFTRN_INCR' , 'CATCHINCR_e0004' , + 'QCFWLT_INCR' , 'CATCHINCR_e0004' , + 'CAPAC_INCR' , 'CATCHINCR_e0004' , + 'CATDEF_INCR' , 'CATCHINCR_e0004' , + 'RZEXC_INCR' , 'CATCHINCR_e0004' , + 'SRFEXC_INCR' , 'CATCHINCR_e0004' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0004' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0004' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0004' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0004' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0004' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0004' , + 'WESNN1_INCR' , 'CATCHINCR_e0004' , + 'WESNN2_INCR' , 'CATCHINCR_e0004' , + 'WESNN3_INCR' , 'CATCHINCR_e0004' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0004' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0004' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0004' , + 'SNDZN1_INCR' , 'CATCHINCR_e0004' , + 'SNDZN2_INCR' , 'CATCHINCR_e0004' , + 'SNDZN3_INCR' , 'CATCHINCR_e0004' , :: catch_progn_incr0005.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -238,31 +190,31 @@ catch_progn_incr0005.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0005.mode: 'instantaneous', catch_progn_incr0005.frequency: 030000, catch_progn_incr0005.ref_time: 013000, -catch_progn_incr0005.fields: 'TCFSAT_INCR' , 'CATCHINCR0005' , - 'TCFTRN_INCR' , 'CATCHINCR0005' , - 'TCFWLT_INCR' , 'CATCHINCR0005' , - 'QCFSAT_INCR' , 'CATCHINCR0005' , - 'QCFTRN_INCR' , 'CATCHINCR0005' , - 'QCFWLT_INCR' , 'CATCHINCR0005' , - 'CAPAC_INCR' , 'CATCHINCR0005' , - 'CATDEF_INCR' , 'CATCHINCR0005' , - 'RZEXC_INCR' , 'CATCHINCR0005' , - 'SRFEXC_INCR' , 'CATCHINCR0005' , - 'GHTCNT1_INCR' , 'CATCHINCR0005' , - 'GHTCNT2_INCR' , 'CATCHINCR0005' , - 'GHTCNT3_INCR' , 'CATCHINCR0005' , - 'GHTCNT4_INCR' , 'CATCHINCR0005' , - 'GHTCNT5_INCR' , 'CATCHINCR0005' , - 'GHTCNT6_INCR' , 'CATCHINCR0005' , - 'WESNN1_INCR' , 'CATCHINCR0005' , - 'WESNN2_INCR' , 'CATCHINCR0005' , - 'WESNN3_INCR' , 'CATCHINCR0005' , - 'HTSNNN1_INCR' , 'CATCHINCR0005' , - 'HTSNNN2_INCR' , 'CATCHINCR0005' , - 'HTSNNN3_INCR' , 'CATCHINCR0005' , - 'SNDZN1_INCR' , 'CATCHINCR0005' , - 'SNDZN2_INCR' , 'CATCHINCR0005' , - 'SNDZN3_INCR' , 'CATCHINCR0005' , +catch_progn_incr0005.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0005' , + 'TCFTRN_INCR' , 'CATCHINCR_e0005' , + 'TCFWLT_INCR' , 'CATCHINCR_e0005' , + 'QCFSAT_INCR' , 'CATCHINCR_e0005' , + 'QCFTRN_INCR' , 'CATCHINCR_e0005' , + 'QCFWLT_INCR' , 'CATCHINCR_e0005' , + 'CAPAC_INCR' , 'CATCHINCR_e0005' , + 'CATDEF_INCR' , 'CATCHINCR_e0005' , + 'RZEXC_INCR' , 'CATCHINCR_e0005' , + 'SRFEXC_INCR' , 'CATCHINCR_e0005' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0005' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0005' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0005' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0005' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0005' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0005' , + 'WESNN1_INCR' , 'CATCHINCR_e0005' , + 'WESNN2_INCR' , 'CATCHINCR_e0005' , + 'WESNN3_INCR' , 'CATCHINCR_e0005' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0005' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0005' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0005' , + 'SNDZN1_INCR' , 'CATCHINCR_e0005' , + 'SNDZN2_INCR' , 'CATCHINCR_e0005' , + 'SNDZN3_INCR' , 'CATCHINCR_e0005' , :: catch_progn_incr0006.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -270,31 +222,31 @@ catch_progn_incr0006.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0006.mode: 'instantaneous', catch_progn_incr0006.frequency: 030000, catch_progn_incr0006.ref_time: 013000, -catch_progn_incr0006.fields: 'TCFSAT_INCR' , 'CATCHINCR0006' , - 'TCFTRN_INCR' , 'CATCHINCR0006' , - 'TCFWLT_INCR' , 'CATCHINCR0006' , - 'QCFSAT_INCR' , 'CATCHINCR0006' , - 'QCFTRN_INCR' , 'CATCHINCR0006' , - 'QCFWLT_INCR' , 'CATCHINCR0006' , - 'CAPAC_INCR' , 'CATCHINCR0006' , - 'CATDEF_INCR' , 'CATCHINCR0006' , - 'RZEXC_INCR' , 'CATCHINCR0006' , - 'SRFEXC_INCR' , 'CATCHINCR0006' , - 'GHTCNT1_INCR' , 'CATCHINCR0006' , - 'GHTCNT2_INCR' , 'CATCHINCR0006' , - 'GHTCNT3_INCR' , 'CATCHINCR0006' , - 'GHTCNT4_INCR' , 'CATCHINCR0006' , - 'GHTCNT5_INCR' , 'CATCHINCR0006' , - 'GHTCNT6_INCR' , 'CATCHINCR0006' , - 'WESNN1_INCR' , 'CATCHINCR0006' , - 'WESNN2_INCR' , 'CATCHINCR0006' , - 'WESNN3_INCR' , 'CATCHINCR0006' , - 'HTSNNN1_INCR' , 'CATCHINCR0006' , - 'HTSNNN2_INCR' , 'CATCHINCR0006' , - 'HTSNNN3_INCR' , 'CATCHINCR0006' , - 'SNDZN1_INCR' , 'CATCHINCR0006' , - 'SNDZN2_INCR' , 'CATCHINCR0006' , - 'SNDZN3_INCR' , 'CATCHINCR0006' , +catch_progn_incr0006.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0006' , + 'TCFTRN_INCR' , 'CATCHINCR_e0006' , + 'TCFWLT_INCR' , 'CATCHINCR_e0006' , + 'QCFSAT_INCR' , 'CATCHINCR_e0006' , + 'QCFTRN_INCR' , 'CATCHINCR_e0006' , + 'QCFWLT_INCR' , 'CATCHINCR_e0006' , + 'CAPAC_INCR' , 'CATCHINCR_e0006' , + 'CATDEF_INCR' , 'CATCHINCR_e0006' , + 'RZEXC_INCR' , 'CATCHINCR_e0006' , + 'SRFEXC_INCR' , 'CATCHINCR_e0006' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0006' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0006' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0006' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0006' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0006' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0006' , + 'WESNN1_INCR' , 'CATCHINCR_e0006' , + 'WESNN2_INCR' , 'CATCHINCR_e0006' , + 'WESNN3_INCR' , 'CATCHINCR_e0006' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0006' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0006' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0006' , + 'SNDZN1_INCR' , 'CATCHINCR_e0006' , + 'SNDZN2_INCR' , 'CATCHINCR_e0006' , + 'SNDZN3_INCR' , 'CATCHINCR_e0006' , :: catch_progn_incr0007.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -302,31 +254,31 @@ catch_progn_incr0007.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0007.mode: 'instantaneous', catch_progn_incr0007.frequency: 030000, catch_progn_incr0007.ref_time: 013000, -catch_progn_incr0007.fields: 'TCFSAT_INCR' , 'CATCHINCR0007' , - 'TCFTRN_INCR' , 'CATCHINCR0007' , - 'TCFWLT_INCR' , 'CATCHINCR0007' , - 'QCFSAT_INCR' , 'CATCHINCR0007' , - 'QCFTRN_INCR' , 'CATCHINCR0007' , - 'QCFWLT_INCR' , 'CATCHINCR0007' , - 'CAPAC_INCR' , 'CATCHINCR0007' , - 'CATDEF_INCR' , 'CATCHINCR0007' , - 'RZEXC_INCR' , 'CATCHINCR0007' , - 'SRFEXC_INCR' , 'CATCHINCR0007' , - 'GHTCNT1_INCR' , 'CATCHINCR0007' , - 'GHTCNT2_INCR' , 'CATCHINCR0007' , - 'GHTCNT3_INCR' , 'CATCHINCR0007' , - 'GHTCNT4_INCR' , 'CATCHINCR0007' , - 'GHTCNT5_INCR' , 'CATCHINCR0007' , - 'GHTCNT6_INCR' , 'CATCHINCR0007' , - 'WESNN1_INCR' , 'CATCHINCR0007' , - 'WESNN2_INCR' , 'CATCHINCR0007' , - 'WESNN3_INCR' , 'CATCHINCR0007' , - 'HTSNNN1_INCR' , 'CATCHINCR0007' , - 'HTSNNN2_INCR' , 'CATCHINCR0007' , - 'HTSNNN3_INCR' , 'CATCHINCR0007' , - 'SNDZN1_INCR' , 'CATCHINCR0007' , - 'SNDZN2_INCR' , 'CATCHINCR0007' , - 'SNDZN3_INCR' , 'CATCHINCR0007' , +catch_progn_incr0007.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0007' , + 'TCFTRN_INCR' , 'CATCHINCR_e0007' , + 'TCFWLT_INCR' , 'CATCHINCR_e0007' , + 'QCFSAT_INCR' , 'CATCHINCR_e0007' , + 'QCFTRN_INCR' , 'CATCHINCR_e0007' , + 'QCFWLT_INCR' , 'CATCHINCR_e0007' , + 'CAPAC_INCR' , 'CATCHINCR_e0007' , + 'CATDEF_INCR' , 'CATCHINCR_e0007' , + 'RZEXC_INCR' , 'CATCHINCR_e0007' , + 'SRFEXC_INCR' , 'CATCHINCR_e0007' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0007' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0007' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0007' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0007' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0007' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0007' , + 'WESNN1_INCR' , 'CATCHINCR_e0007' , + 'WESNN2_INCR' , 'CATCHINCR_e0007' , + 'WESNN3_INCR' , 'CATCHINCR_e0007' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0007' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0007' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0007' , + 'SNDZN1_INCR' , 'CATCHINCR_e0007' , + 'SNDZN2_INCR' , 'CATCHINCR_e0007' , + 'SNDZN3_INCR' , 'CATCHINCR_e0007' , :: catch_progn_incr0008.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -334,31 +286,31 @@ catch_progn_incr0008.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0008.mode: 'instantaneous', catch_progn_incr0008.frequency: 030000, catch_progn_incr0008.ref_time: 013000, -catch_progn_incr0008.fields: 'TCFSAT_INCR' , 'CATCHINCR0008' , - 'TCFTRN_INCR' , 'CATCHINCR0008' , - 'TCFWLT_INCR' , 'CATCHINCR0008' , - 'QCFSAT_INCR' , 'CATCHINCR0008' , - 'QCFTRN_INCR' , 'CATCHINCR0008' , - 'QCFWLT_INCR' , 'CATCHINCR0008' , - 'CAPAC_INCR' , 'CATCHINCR0008' , - 'CATDEF_INCR' , 'CATCHINCR0008' , - 'RZEXC_INCR' , 'CATCHINCR0008' , - 'SRFEXC_INCR' , 'CATCHINCR0008' , - 'GHTCNT1_INCR' , 'CATCHINCR0008' , - 'GHTCNT2_INCR' , 'CATCHINCR0008' , - 'GHTCNT3_INCR' , 'CATCHINCR0008' , - 'GHTCNT4_INCR' , 'CATCHINCR0008' , - 'GHTCNT5_INCR' , 'CATCHINCR0008' , - 'GHTCNT6_INCR' , 'CATCHINCR0008' , - 'WESNN1_INCR' , 'CATCHINCR0008' , - 'WESNN2_INCR' , 'CATCHINCR0008' , - 'WESNN3_INCR' , 'CATCHINCR0008' , - 'HTSNNN1_INCR' , 'CATCHINCR0008' , - 'HTSNNN2_INCR' , 'CATCHINCR0008' , - 'HTSNNN3_INCR' , 'CATCHINCR0008' , - 'SNDZN1_INCR' , 'CATCHINCR0008' , - 'SNDZN2_INCR' , 'CATCHINCR0008' , - 'SNDZN3_INCR' , 'CATCHINCR0008' , +catch_progn_incr0008.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0008' , + 'TCFTRN_INCR' , 'CATCHINCR_e0008' , + 'TCFWLT_INCR' , 'CATCHINCR_e0008' , + 'QCFSAT_INCR' , 'CATCHINCR_e0008' , + 'QCFTRN_INCR' , 'CATCHINCR_e0008' , + 'QCFWLT_INCR' , 'CATCHINCR_e0008' , + 'CAPAC_INCR' , 'CATCHINCR_e0008' , + 'CATDEF_INCR' , 'CATCHINCR_e0008' , + 'RZEXC_INCR' , 'CATCHINCR_e0008' , + 'SRFEXC_INCR' , 'CATCHINCR_e0008' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0008' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0008' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0008' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0008' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0008' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0008' , + 'WESNN1_INCR' , 'CATCHINCR_e0008' , + 'WESNN2_INCR' , 'CATCHINCR_e0008' , + 'WESNN3_INCR' , 'CATCHINCR_e0008' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0008' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0008' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0008' , + 'SNDZN1_INCR' , 'CATCHINCR_e0008' , + 'SNDZN2_INCR' , 'CATCHINCR_e0008' , + 'SNDZN3_INCR' , 'CATCHINCR_e0008' , :: catch_progn_incr0009.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -366,31 +318,31 @@ catch_progn_incr0009.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0009.mode: 'instantaneous', catch_progn_incr0009.frequency: 030000, catch_progn_incr0009.ref_time: 013000, -catch_progn_incr0009.fields: 'TCFSAT_INCR' , 'CATCHINCR0009' , - 'TCFTRN_INCR' , 'CATCHINCR0009' , - 'TCFWLT_INCR' , 'CATCHINCR0009' , - 'QCFSAT_INCR' , 'CATCHINCR0009' , - 'QCFTRN_INCR' , 'CATCHINCR0009' , - 'QCFWLT_INCR' , 'CATCHINCR0009' , - 'CAPAC_INCR' , 'CATCHINCR0009' , - 'CATDEF_INCR' , 'CATCHINCR0009' , - 'RZEXC_INCR' , 'CATCHINCR0009' , - 'SRFEXC_INCR' , 'CATCHINCR0009' , - 'GHTCNT1_INCR' , 'CATCHINCR0009' , - 'GHTCNT2_INCR' , 'CATCHINCR0009' , - 'GHTCNT3_INCR' , 'CATCHINCR0009' , - 'GHTCNT4_INCR' , 'CATCHINCR0009' , - 'GHTCNT5_INCR' , 'CATCHINCR0009' , - 'GHTCNT6_INCR' , 'CATCHINCR0009' , - 'WESNN1_INCR' , 'CATCHINCR0009' , - 'WESNN2_INCR' , 'CATCHINCR0009' , - 'WESNN3_INCR' , 'CATCHINCR0009' , - 'HTSNNN1_INCR' , 'CATCHINCR0009' , - 'HTSNNN2_INCR' , 'CATCHINCR0009' , - 'HTSNNN3_INCR' , 'CATCHINCR0009' , - 'SNDZN1_INCR' , 'CATCHINCR0009' , - 'SNDZN2_INCR' , 'CATCHINCR0009' , - 'SNDZN3_INCR' , 'CATCHINCR0009' , +catch_progn_incr0009.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0009' , + 'TCFTRN_INCR' , 'CATCHINCR_e0009' , + 'TCFWLT_INCR' , 'CATCHINCR_e0009' , + 'QCFSAT_INCR' , 'CATCHINCR_e0009' , + 'QCFTRN_INCR' , 'CATCHINCR_e0009' , + 'QCFWLT_INCR' , 'CATCHINCR_e0009' , + 'CAPAC_INCR' , 'CATCHINCR_e0009' , + 'CATDEF_INCR' , 'CATCHINCR_e0009' , + 'RZEXC_INCR' , 'CATCHINCR_e0009' , + 'SRFEXC_INCR' , 'CATCHINCR_e0009' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0009' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0009' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0009' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0009' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0009' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0009' , + 'WESNN1_INCR' , 'CATCHINCR_e0009' , + 'WESNN2_INCR' , 'CATCHINCR_e0009' , + 'WESNN3_INCR' , 'CATCHINCR_e0009' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0009' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0009' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0009' , + 'SNDZN1_INCR' , 'CATCHINCR_e0009' , + 'SNDZN2_INCR' , 'CATCHINCR_e0009' , + 'SNDZN3_INCR' , 'CATCHINCR_e0009' , :: catch_progn_incr0010.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -398,31 +350,31 @@ catch_progn_incr0010.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0010.mode: 'instantaneous', catch_progn_incr0010.frequency: 030000, catch_progn_incr0010.ref_time: 013000, -catch_progn_incr0010.fields: 'TCFSAT_INCR' , 'CATCHINCR0010' , - 'TCFTRN_INCR' , 'CATCHINCR0010' , - 'TCFWLT_INCR' , 'CATCHINCR0010' , - 'QCFSAT_INCR' , 'CATCHINCR0010' , - 'QCFTRN_INCR' , 'CATCHINCR0010' , - 'QCFWLT_INCR' , 'CATCHINCR0010' , - 'CAPAC_INCR' , 'CATCHINCR0010' , - 'CATDEF_INCR' , 'CATCHINCR0010' , - 'RZEXC_INCR' , 'CATCHINCR0010' , - 'SRFEXC_INCR' , 'CATCHINCR0010' , - 'GHTCNT1_INCR' , 'CATCHINCR0010' , - 'GHTCNT2_INCR' , 'CATCHINCR0010' , - 'GHTCNT3_INCR' , 'CATCHINCR0010' , - 'GHTCNT4_INCR' , 'CATCHINCR0010' , - 'GHTCNT5_INCR' , 'CATCHINCR0010' , - 'GHTCNT6_INCR' , 'CATCHINCR0010' , - 'WESNN1_INCR' , 'CATCHINCR0010' , - 'WESNN2_INCR' , 'CATCHINCR0010' , - 'WESNN3_INCR' , 'CATCHINCR0010' , - 'HTSNNN1_INCR' , 'CATCHINCR0010' , - 'HTSNNN2_INCR' , 'CATCHINCR0010' , - 'HTSNNN3_INCR' , 'CATCHINCR0010' , - 'SNDZN1_INCR' , 'CATCHINCR0010' , - 'SNDZN2_INCR' , 'CATCHINCR0010' , - 'SNDZN3_INCR' , 'CATCHINCR0010' , +catch_progn_incr0010.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0010' , + 'TCFTRN_INCR' , 'CATCHINCR_e0010' , + 'TCFWLT_INCR' , 'CATCHINCR_e0010' , + 'QCFSAT_INCR' , 'CATCHINCR_e0010' , + 'QCFTRN_INCR' , 'CATCHINCR_e0010' , + 'QCFWLT_INCR' , 'CATCHINCR_e0010' , + 'CAPAC_INCR' , 'CATCHINCR_e0010' , + 'CATDEF_INCR' , 'CATCHINCR_e0010' , + 'RZEXC_INCR' , 'CATCHINCR_e0010' , + 'SRFEXC_INCR' , 'CATCHINCR_e0010' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0010' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0010' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0010' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0010' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0010' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0010' , + 'WESNN1_INCR' , 'CATCHINCR_e0010' , + 'WESNN2_INCR' , 'CATCHINCR_e0010' , + 'WESNN3_INCR' , 'CATCHINCR_e0010' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0010' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0010' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0010' , + 'SNDZN1_INCR' , 'CATCHINCR_e0010' , + 'SNDZN2_INCR' , 'CATCHINCR_e0010' , + 'SNDZN3_INCR' , 'CATCHINCR_e0010' , :: catch_progn_incr0011.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -430,31 +382,31 @@ catch_progn_incr0011.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0011.mode: 'instantaneous', catch_progn_incr0011.frequency: 030000, catch_progn_incr0011.ref_time: 013000, -catch_progn_incr0011.fields: 'TCFSAT_INCR' , 'CATCHINCR0011' , - 'TCFTRN_INCR' , 'CATCHINCR0011' , - 'TCFWLT_INCR' , 'CATCHINCR0011' , - 'QCFSAT_INCR' , 'CATCHINCR0011' , - 'QCFTRN_INCR' , 'CATCHINCR0011' , - 'QCFWLT_INCR' , 'CATCHINCR0011' , - 'CAPAC_INCR' , 'CATCHINCR0011' , - 'CATDEF_INCR' , 'CATCHINCR0011' , - 'RZEXC_INCR' , 'CATCHINCR0011' , - 'SRFEXC_INCR' , 'CATCHINCR0011' , - 'GHTCNT1_INCR' , 'CATCHINCR0011' , - 'GHTCNT2_INCR' , 'CATCHINCR0011' , - 'GHTCNT3_INCR' , 'CATCHINCR0011' , - 'GHTCNT4_INCR' , 'CATCHINCR0011' , - 'GHTCNT5_INCR' , 'CATCHINCR0011' , - 'GHTCNT6_INCR' , 'CATCHINCR0011' , - 'WESNN1_INCR' , 'CATCHINCR0011' , - 'WESNN2_INCR' , 'CATCHINCR0011' , - 'WESNN3_INCR' , 'CATCHINCR0011' , - 'HTSNNN1_INCR' , 'CATCHINCR0011' , - 'HTSNNN2_INCR' , 'CATCHINCR0011' , - 'HTSNNN3_INCR' , 'CATCHINCR0011' , - 'SNDZN1_INCR' , 'CATCHINCR0011' , - 'SNDZN2_INCR' , 'CATCHINCR0011' , - 'SNDZN3_INCR' , 'CATCHINCR0011' , +catch_progn_incr0011.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0011' , + 'TCFTRN_INCR' , 'CATCHINCR_e0011' , + 'TCFWLT_INCR' , 'CATCHINCR_e0011' , + 'QCFSAT_INCR' , 'CATCHINCR_e0011' , + 'QCFTRN_INCR' , 'CATCHINCR_e0011' , + 'QCFWLT_INCR' , 'CATCHINCR_e0011' , + 'CAPAC_INCR' , 'CATCHINCR_e0011' , + 'CATDEF_INCR' , 'CATCHINCR_e0011' , + 'RZEXC_INCR' , 'CATCHINCR_e0011' , + 'SRFEXC_INCR' , 'CATCHINCR_e0011' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0011' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0011' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0011' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0011' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0011' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0011' , + 'WESNN1_INCR' , 'CATCHINCR_e0011' , + 'WESNN2_INCR' , 'CATCHINCR_e0011' , + 'WESNN3_INCR' , 'CATCHINCR_e0011' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0011' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0011' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0011' , + 'SNDZN1_INCR' , 'CATCHINCR_e0011' , + 'SNDZN2_INCR' , 'CATCHINCR_e0011' , + 'SNDZN3_INCR' , 'CATCHINCR_e0011' , :: catch_progn_incr0012.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -462,31 +414,31 @@ catch_progn_incr0012.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0012.mode: 'instantaneous', catch_progn_incr0012.frequency: 030000, catch_progn_incr0012.ref_time: 013000, -catch_progn_incr0012.fields: 'TCFSAT_INCR' , 'CATCHINCR0012' , - 'TCFTRN_INCR' , 'CATCHINCR0012' , - 'TCFWLT_INCR' , 'CATCHINCR0012' , - 'QCFSAT_INCR' , 'CATCHINCR0012' , - 'QCFTRN_INCR' , 'CATCHINCR0012' , - 'QCFWLT_INCR' , 'CATCHINCR0012' , - 'CAPAC_INCR' , 'CATCHINCR0012' , - 'CATDEF_INCR' , 'CATCHINCR0012' , - 'RZEXC_INCR' , 'CATCHINCR0012' , - 'SRFEXC_INCR' , 'CATCHINCR0012' , - 'GHTCNT1_INCR' , 'CATCHINCR0012' , - 'GHTCNT2_INCR' , 'CATCHINCR0012' , - 'GHTCNT3_INCR' , 'CATCHINCR0012' , - 'GHTCNT4_INCR' , 'CATCHINCR0012' , - 'GHTCNT5_INCR' , 'CATCHINCR0012' , - 'GHTCNT6_INCR' , 'CATCHINCR0012' , - 'WESNN1_INCR' , 'CATCHINCR0012' , - 'WESNN2_INCR' , 'CATCHINCR0012' , - 'WESNN3_INCR' , 'CATCHINCR0012' , - 'HTSNNN1_INCR' , 'CATCHINCR0012' , - 'HTSNNN2_INCR' , 'CATCHINCR0012' , - 'HTSNNN3_INCR' , 'CATCHINCR0012' , - 'SNDZN1_INCR' , 'CATCHINCR0012' , - 'SNDZN2_INCR' , 'CATCHINCR0012' , - 'SNDZN3_INCR' , 'CATCHINCR0012' , +catch_progn_incr0012.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0012' , + 'TCFTRN_INCR' , 'CATCHINCR_e0012' , + 'TCFWLT_INCR' , 'CATCHINCR_e0012' , + 'QCFSAT_INCR' , 'CATCHINCR_e0012' , + 'QCFTRN_INCR' , 'CATCHINCR_e0012' , + 'QCFWLT_INCR' , 'CATCHINCR_e0012' , + 'CAPAC_INCR' , 'CATCHINCR_e0012' , + 'CATDEF_INCR' , 'CATCHINCR_e0012' , + 'RZEXC_INCR' , 'CATCHINCR_e0012' , + 'SRFEXC_INCR' , 'CATCHINCR_e0012' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0012' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0012' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0012' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0012' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0012' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0012' , + 'WESNN1_INCR' , 'CATCHINCR_e0012' , + 'WESNN2_INCR' , 'CATCHINCR_e0012' , + 'WESNN3_INCR' , 'CATCHINCR_e0012' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0012' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0012' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0012' , + 'SNDZN1_INCR' , 'CATCHINCR_e0012' , + 'SNDZN2_INCR' , 'CATCHINCR_e0012' , + 'SNDZN3_INCR' , 'CATCHINCR_e0012' , :: catch_progn_incr0013.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -494,31 +446,31 @@ catch_progn_incr0013.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0013.mode: 'instantaneous', catch_progn_incr0013.frequency: 030000, catch_progn_incr0013.ref_time: 013000, -catch_progn_incr0013.fields: 'TCFSAT_INCR' , 'CATCHINCR0013' , - 'TCFTRN_INCR' , 'CATCHINCR0013' , - 'TCFWLT_INCR' , 'CATCHINCR0013' , - 'QCFSAT_INCR' , 'CATCHINCR0013' , - 'QCFTRN_INCR' , 'CATCHINCR0013' , - 'QCFWLT_INCR' , 'CATCHINCR0013' , - 'CAPAC_INCR' , 'CATCHINCR0013' , - 'CATDEF_INCR' , 'CATCHINCR0013' , - 'RZEXC_INCR' , 'CATCHINCR0013' , - 'SRFEXC_INCR' , 'CATCHINCR0013' , - 'GHTCNT1_INCR' , 'CATCHINCR0013' , - 'GHTCNT2_INCR' , 'CATCHINCR0013' , - 'GHTCNT3_INCR' , 'CATCHINCR0013' , - 'GHTCNT4_INCR' , 'CATCHINCR0013' , - 'GHTCNT5_INCR' , 'CATCHINCR0013' , - 'GHTCNT6_INCR' , 'CATCHINCR0013' , - 'WESNN1_INCR' , 'CATCHINCR0013' , - 'WESNN2_INCR' , 'CATCHINCR0013' , - 'WESNN3_INCR' , 'CATCHINCR0013' , - 'HTSNNN1_INCR' , 'CATCHINCR0013' , - 'HTSNNN2_INCR' , 'CATCHINCR0013' , - 'HTSNNN3_INCR' , 'CATCHINCR0013' , - 'SNDZN1_INCR' , 'CATCHINCR0013' , - 'SNDZN2_INCR' , 'CATCHINCR0013' , - 'SNDZN3_INCR' , 'CATCHINCR0013' , +catch_progn_incr0013.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0013' , + 'TCFTRN_INCR' , 'CATCHINCR_e0013' , + 'TCFWLT_INCR' , 'CATCHINCR_e0013' , + 'QCFSAT_INCR' , 'CATCHINCR_e0013' , + 'QCFTRN_INCR' , 'CATCHINCR_e0013' , + 'QCFWLT_INCR' , 'CATCHINCR_e0013' , + 'CAPAC_INCR' , 'CATCHINCR_e0013' , + 'CATDEF_INCR' , 'CATCHINCR_e0013' , + 'RZEXC_INCR' , 'CATCHINCR_e0013' , + 'SRFEXC_INCR' , 'CATCHINCR_e0013' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0013' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0013' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0013' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0013' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0013' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0013' , + 'WESNN1_INCR' , 'CATCHINCR_e0013' , + 'WESNN2_INCR' , 'CATCHINCR_e0013' , + 'WESNN3_INCR' , 'CATCHINCR_e0013' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0013' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0013' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0013' , + 'SNDZN1_INCR' , 'CATCHINCR_e0013' , + 'SNDZN2_INCR' , 'CATCHINCR_e0013' , + 'SNDZN3_INCR' , 'CATCHINCR_e0013' , :: catch_progn_incr0014.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -526,31 +478,31 @@ catch_progn_incr0014.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0014.mode: 'instantaneous', catch_progn_incr0014.frequency: 030000, catch_progn_incr0014.ref_time: 013000, -catch_progn_incr0014.fields: 'TCFSAT_INCR' , 'CATCHINCR0014' , - 'TCFTRN_INCR' , 'CATCHINCR0014' , - 'TCFWLT_INCR' , 'CATCHINCR0014' , - 'QCFSAT_INCR' , 'CATCHINCR0014' , - 'QCFTRN_INCR' , 'CATCHINCR0014' , - 'QCFWLT_INCR' , 'CATCHINCR0014' , - 'CAPAC_INCR' , 'CATCHINCR0014' , - 'CATDEF_INCR' , 'CATCHINCR0014' , - 'RZEXC_INCR' , 'CATCHINCR0014' , - 'SRFEXC_INCR' , 'CATCHINCR0014' , - 'GHTCNT1_INCR' , 'CATCHINCR0014' , - 'GHTCNT2_INCR' , 'CATCHINCR0014' , - 'GHTCNT3_INCR' , 'CATCHINCR0014' , - 'GHTCNT4_INCR' , 'CATCHINCR0014' , - 'GHTCNT5_INCR' , 'CATCHINCR0014' , - 'GHTCNT6_INCR' , 'CATCHINCR0014' , - 'WESNN1_INCR' , 'CATCHINCR0014' , - 'WESNN2_INCR' , 'CATCHINCR0014' , - 'WESNN3_INCR' , 'CATCHINCR0014' , - 'HTSNNN1_INCR' , 'CATCHINCR0014' , - 'HTSNNN2_INCR' , 'CATCHINCR0014' , - 'HTSNNN3_INCR' , 'CATCHINCR0014' , - 'SNDZN1_INCR' , 'CATCHINCR0014' , - 'SNDZN2_INCR' , 'CATCHINCR0014' , - 'SNDZN3_INCR' , 'CATCHINCR0014' , +catch_progn_incr0014.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0014' , + 'TCFTRN_INCR' , 'CATCHINCR_e0014' , + 'TCFWLT_INCR' , 'CATCHINCR_e0014' , + 'QCFSAT_INCR' , 'CATCHINCR_e0014' , + 'QCFTRN_INCR' , 'CATCHINCR_e0014' , + 'QCFWLT_INCR' , 'CATCHINCR_e0014' , + 'CAPAC_INCR' , 'CATCHINCR_e0014' , + 'CATDEF_INCR' , 'CATCHINCR_e0014' , + 'RZEXC_INCR' , 'CATCHINCR_e0014' , + 'SRFEXC_INCR' , 'CATCHINCR_e0014' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0014' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0014' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0014' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0014' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0014' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0014' , + 'WESNN1_INCR' , 'CATCHINCR_e0014' , + 'WESNN2_INCR' , 'CATCHINCR_e0014' , + 'WESNN3_INCR' , 'CATCHINCR_e0014' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0014' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0014' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0014' , + 'SNDZN1_INCR' , 'CATCHINCR_e0014' , + 'SNDZN2_INCR' , 'CATCHINCR_e0014' , + 'SNDZN3_INCR' , 'CATCHINCR_e0014' , :: catch_progn_incr0015.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -558,31 +510,31 @@ catch_progn_incr0015.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0015.mode: 'instantaneous', catch_progn_incr0015.frequency: 030000, catch_progn_incr0015.ref_time: 013000, -catch_progn_incr0015.fields: 'TCFSAT_INCR' , 'CATCHINCR0015' , - 'TCFTRN_INCR' , 'CATCHINCR0015' , - 'TCFWLT_INCR' , 'CATCHINCR0015' , - 'QCFSAT_INCR' , 'CATCHINCR0015' , - 'QCFTRN_INCR' , 'CATCHINCR0015' , - 'QCFWLT_INCR' , 'CATCHINCR0015' , - 'CAPAC_INCR' , 'CATCHINCR0015' , - 'CATDEF_INCR' , 'CATCHINCR0015' , - 'RZEXC_INCR' , 'CATCHINCR0015' , - 'SRFEXC_INCR' , 'CATCHINCR0015' , - 'GHTCNT1_INCR' , 'CATCHINCR0015' , - 'GHTCNT2_INCR' , 'CATCHINCR0015' , - 'GHTCNT3_INCR' , 'CATCHINCR0015' , - 'GHTCNT4_INCR' , 'CATCHINCR0015' , - 'GHTCNT5_INCR' , 'CATCHINCR0015' , - 'GHTCNT6_INCR' , 'CATCHINCR0015' , - 'WESNN1_INCR' , 'CATCHINCR0015' , - 'WESNN2_INCR' , 'CATCHINCR0015' , - 'WESNN3_INCR' , 'CATCHINCR0015' , - 'HTSNNN1_INCR' , 'CATCHINCR0015' , - 'HTSNNN2_INCR' , 'CATCHINCR0015' , - 'HTSNNN3_INCR' , 'CATCHINCR0015' , - 'SNDZN1_INCR' , 'CATCHINCR0015' , - 'SNDZN2_INCR' , 'CATCHINCR0015' , - 'SNDZN3_INCR' , 'CATCHINCR0015' , +catch_progn_incr0015.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0015' , + 'TCFTRN_INCR' , 'CATCHINCR_e0015' , + 'TCFWLT_INCR' , 'CATCHINCR_e0015' , + 'QCFSAT_INCR' , 'CATCHINCR_e0015' , + 'QCFTRN_INCR' , 'CATCHINCR_e0015' , + 'QCFWLT_INCR' , 'CATCHINCR_e0015' , + 'CAPAC_INCR' , 'CATCHINCR_e0015' , + 'CATDEF_INCR' , 'CATCHINCR_e0015' , + 'RZEXC_INCR' , 'CATCHINCR_e0015' , + 'SRFEXC_INCR' , 'CATCHINCR_e0015' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0015' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0015' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0015' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0015' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0015' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0015' , + 'WESNN1_INCR' , 'CATCHINCR_e0015' , + 'WESNN2_INCR' , 'CATCHINCR_e0015' , + 'WESNN3_INCR' , 'CATCHINCR_e0015' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0015' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0015' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0015' , + 'SNDZN1_INCR' , 'CATCHINCR_e0015' , + 'SNDZN2_INCR' , 'CATCHINCR_e0015' , + 'SNDZN3_INCR' , 'CATCHINCR_e0015' , :: catch_progn_incr0016.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -590,31 +542,31 @@ catch_progn_incr0016.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0016.mode: 'instantaneous', catch_progn_incr0016.frequency: 030000, catch_progn_incr0016.ref_time: 013000, -catch_progn_incr0016.fields: 'TCFSAT_INCR' , 'CATCHINCR0016' , - 'TCFTRN_INCR' , 'CATCHINCR0016' , - 'TCFWLT_INCR' , 'CATCHINCR0016' , - 'QCFSAT_INCR' , 'CATCHINCR0016' , - 'QCFTRN_INCR' , 'CATCHINCR0016' , - 'QCFWLT_INCR' , 'CATCHINCR0016' , - 'CAPAC_INCR' , 'CATCHINCR0016' , - 'CATDEF_INCR' , 'CATCHINCR0016' , - 'RZEXC_INCR' , 'CATCHINCR0016' , - 'SRFEXC_INCR' , 'CATCHINCR0016' , - 'GHTCNT1_INCR' , 'CATCHINCR0016' , - 'GHTCNT2_INCR' , 'CATCHINCR0016' , - 'GHTCNT3_INCR' , 'CATCHINCR0016' , - 'GHTCNT4_INCR' , 'CATCHINCR0016' , - 'GHTCNT5_INCR' , 'CATCHINCR0016' , - 'GHTCNT6_INCR' , 'CATCHINCR0016' , - 'WESNN1_INCR' , 'CATCHINCR0016' , - 'WESNN2_INCR' , 'CATCHINCR0016' , - 'WESNN3_INCR' , 'CATCHINCR0016' , - 'HTSNNN1_INCR' , 'CATCHINCR0016' , - 'HTSNNN2_INCR' , 'CATCHINCR0016' , - 'HTSNNN3_INCR' , 'CATCHINCR0016' , - 'SNDZN1_INCR' , 'CATCHINCR0016' , - 'SNDZN2_INCR' , 'CATCHINCR0016' , - 'SNDZN3_INCR' , 'CATCHINCR0016' , +catch_progn_incr0016.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0016' , + 'TCFTRN_INCR' , 'CATCHINCR_e0016' , + 'TCFWLT_INCR' , 'CATCHINCR_e0016' , + 'QCFSAT_INCR' , 'CATCHINCR_e0016' , + 'QCFTRN_INCR' , 'CATCHINCR_e0016' , + 'QCFWLT_INCR' , 'CATCHINCR_e0016' , + 'CAPAC_INCR' , 'CATCHINCR_e0016' , + 'CATDEF_INCR' , 'CATCHINCR_e0016' , + 'RZEXC_INCR' , 'CATCHINCR_e0016' , + 'SRFEXC_INCR' , 'CATCHINCR_e0016' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0016' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0016' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0016' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0016' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0016' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0016' , + 'WESNN1_INCR' , 'CATCHINCR_e0016' , + 'WESNN2_INCR' , 'CATCHINCR_e0016' , + 'WESNN3_INCR' , 'CATCHINCR_e0016' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0016' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0016' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0016' , + 'SNDZN1_INCR' , 'CATCHINCR_e0016' , + 'SNDZN2_INCR' , 'CATCHINCR_e0016' , + 'SNDZN3_INCR' , 'CATCHINCR_e0016' , :: catch_progn_incr0017.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -622,31 +574,31 @@ catch_progn_incr0017.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0017.mode: 'instantaneous', catch_progn_incr0017.frequency: 030000, catch_progn_incr0017.ref_time: 013000, -catch_progn_incr0017.fields: 'TCFSAT_INCR' , 'CATCHINCR0017' , - 'TCFTRN_INCR' , 'CATCHINCR0017' , - 'TCFWLT_INCR' , 'CATCHINCR0017' , - 'QCFSAT_INCR' , 'CATCHINCR0017' , - 'QCFTRN_INCR' , 'CATCHINCR0017' , - 'QCFWLT_INCR' , 'CATCHINCR0017' , - 'CAPAC_INCR' , 'CATCHINCR0017' , - 'CATDEF_INCR' , 'CATCHINCR0017' , - 'RZEXC_INCR' , 'CATCHINCR0017' , - 'SRFEXC_INCR' , 'CATCHINCR0017' , - 'GHTCNT1_INCR' , 'CATCHINCR0017' , - 'GHTCNT2_INCR' , 'CATCHINCR0017' , - 'GHTCNT3_INCR' , 'CATCHINCR0017' , - 'GHTCNT4_INCR' , 'CATCHINCR0017' , - 'GHTCNT5_INCR' , 'CATCHINCR0017' , - 'GHTCNT6_INCR' , 'CATCHINCR0017' , - 'WESNN1_INCR' , 'CATCHINCR0017' , - 'WESNN2_INCR' , 'CATCHINCR0017' , - 'WESNN3_INCR' , 'CATCHINCR0017' , - 'HTSNNN1_INCR' , 'CATCHINCR0017' , - 'HTSNNN2_INCR' , 'CATCHINCR0017' , - 'HTSNNN3_INCR' , 'CATCHINCR0017' , - 'SNDZN1_INCR' , 'CATCHINCR0017' , - 'SNDZN2_INCR' , 'CATCHINCR0017' , - 'SNDZN3_INCR' , 'CATCHINCR0017' , +catch_progn_incr0017.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0017' , + 'TCFTRN_INCR' , 'CATCHINCR_e0017' , + 'TCFWLT_INCR' , 'CATCHINCR_e0017' , + 'QCFSAT_INCR' , 'CATCHINCR_e0017' , + 'QCFTRN_INCR' , 'CATCHINCR_e0017' , + 'QCFWLT_INCR' , 'CATCHINCR_e0017' , + 'CAPAC_INCR' , 'CATCHINCR_e0017' , + 'CATDEF_INCR' , 'CATCHINCR_e0017' , + 'RZEXC_INCR' , 'CATCHINCR_e0017' , + 'SRFEXC_INCR' , 'CATCHINCR_e0017' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0017' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0017' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0017' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0017' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0017' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0017' , + 'WESNN1_INCR' , 'CATCHINCR_e0017' , + 'WESNN2_INCR' , 'CATCHINCR_e0017' , + 'WESNN3_INCR' , 'CATCHINCR_e0017' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0017' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0017' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0017' , + 'SNDZN1_INCR' , 'CATCHINCR_e0017' , + 'SNDZN2_INCR' , 'CATCHINCR_e0017' , + 'SNDZN3_INCR' , 'CATCHINCR_e0017' , :: catch_progn_incr0018.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -654,31 +606,31 @@ catch_progn_incr0018.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0018.mode: 'instantaneous', catch_progn_incr0018.frequency: 030000, catch_progn_incr0018.ref_time: 013000, -catch_progn_incr0018.fields: 'TCFSAT_INCR' , 'CATCHINCR0018' , - 'TCFTRN_INCR' , 'CATCHINCR0018' , - 'TCFWLT_INCR' , 'CATCHINCR0018' , - 'QCFSAT_INCR' , 'CATCHINCR0018' , - 'QCFTRN_INCR' , 'CATCHINCR0018' , - 'QCFWLT_INCR' , 'CATCHINCR0018' , - 'CAPAC_INCR' , 'CATCHINCR0018' , - 'CATDEF_INCR' , 'CATCHINCR0018' , - 'RZEXC_INCR' , 'CATCHINCR0018' , - 'SRFEXC_INCR' , 'CATCHINCR0018' , - 'GHTCNT1_INCR' , 'CATCHINCR0018' , - 'GHTCNT2_INCR' , 'CATCHINCR0018' , - 'GHTCNT3_INCR' , 'CATCHINCR0018' , - 'GHTCNT4_INCR' , 'CATCHINCR0018' , - 'GHTCNT5_INCR' , 'CATCHINCR0018' , - 'GHTCNT6_INCR' , 'CATCHINCR0018' , - 'WESNN1_INCR' , 'CATCHINCR0018' , - 'WESNN2_INCR' , 'CATCHINCR0018' , - 'WESNN3_INCR' , 'CATCHINCR0018' , - 'HTSNNN1_INCR' , 'CATCHINCR0018' , - 'HTSNNN2_INCR' , 'CATCHINCR0018' , - 'HTSNNN3_INCR' , 'CATCHINCR0018' , - 'SNDZN1_INCR' , 'CATCHINCR0018' , - 'SNDZN2_INCR' , 'CATCHINCR0018' , - 'SNDZN3_INCR' , 'CATCHINCR0018' , +catch_progn_incr0018.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0018' , + 'TCFTRN_INCR' , 'CATCHINCR_e0018' , + 'TCFWLT_INCR' , 'CATCHINCR_e0018' , + 'QCFSAT_INCR' , 'CATCHINCR_e0018' , + 'QCFTRN_INCR' , 'CATCHINCR_e0018' , + 'QCFWLT_INCR' , 'CATCHINCR_e0018' , + 'CAPAC_INCR' , 'CATCHINCR_e0018' , + 'CATDEF_INCR' , 'CATCHINCR_e0018' , + 'RZEXC_INCR' , 'CATCHINCR_e0018' , + 'SRFEXC_INCR' , 'CATCHINCR_e0018' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0018' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0018' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0018' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0018' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0018' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0018' , + 'WESNN1_INCR' , 'CATCHINCR_e0018' , + 'WESNN2_INCR' , 'CATCHINCR_e0018' , + 'WESNN3_INCR' , 'CATCHINCR_e0018' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0018' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0018' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0018' , + 'SNDZN1_INCR' , 'CATCHINCR_e0018' , + 'SNDZN2_INCR' , 'CATCHINCR_e0018' , + 'SNDZN3_INCR' , 'CATCHINCR_e0018' , :: catch_progn_incr0019.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -686,31 +638,31 @@ catch_progn_incr0019.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0019.mode: 'instantaneous', catch_progn_incr0019.frequency: 030000, catch_progn_incr0019.ref_time: 013000, -catch_progn_incr0019.fields: 'TCFSAT_INCR' , 'CATCHINCR0019' , - 'TCFTRN_INCR' , 'CATCHINCR0019' , - 'TCFWLT_INCR' , 'CATCHINCR0019' , - 'QCFSAT_INCR' , 'CATCHINCR0019' , - 'QCFTRN_INCR' , 'CATCHINCR0019' , - 'QCFWLT_INCR' , 'CATCHINCR0019' , - 'CAPAC_INCR' , 'CATCHINCR0019' , - 'CATDEF_INCR' , 'CATCHINCR0019' , - 'RZEXC_INCR' , 'CATCHINCR0019' , - 'SRFEXC_INCR' , 'CATCHINCR0019' , - 'GHTCNT1_INCR' , 'CATCHINCR0019' , - 'GHTCNT2_INCR' , 'CATCHINCR0019' , - 'GHTCNT3_INCR' , 'CATCHINCR0019' , - 'GHTCNT4_INCR' , 'CATCHINCR0019' , - 'GHTCNT5_INCR' , 'CATCHINCR0019' , - 'GHTCNT6_INCR' , 'CATCHINCR0019' , - 'WESNN1_INCR' , 'CATCHINCR0019' , - 'WESNN2_INCR' , 'CATCHINCR0019' , - 'WESNN3_INCR' , 'CATCHINCR0019' , - 'HTSNNN1_INCR' , 'CATCHINCR0019' , - 'HTSNNN2_INCR' , 'CATCHINCR0019' , - 'HTSNNN3_INCR' , 'CATCHINCR0019' , - 'SNDZN1_INCR' , 'CATCHINCR0019' , - 'SNDZN2_INCR' , 'CATCHINCR0019' , - 'SNDZN3_INCR' , 'CATCHINCR0019' , +catch_progn_incr0019.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0019' , + 'TCFTRN_INCR' , 'CATCHINCR_e0019' , + 'TCFWLT_INCR' , 'CATCHINCR_e0019' , + 'QCFSAT_INCR' , 'CATCHINCR_e0019' , + 'QCFTRN_INCR' , 'CATCHINCR_e0019' , + 'QCFWLT_INCR' , 'CATCHINCR_e0019' , + 'CAPAC_INCR' , 'CATCHINCR_e0019' , + 'CATDEF_INCR' , 'CATCHINCR_e0019' , + 'RZEXC_INCR' , 'CATCHINCR_e0019' , + 'SRFEXC_INCR' , 'CATCHINCR_e0019' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0019' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0019' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0019' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0019' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0019' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0019' , + 'WESNN1_INCR' , 'CATCHINCR_e0019' , + 'WESNN2_INCR' , 'CATCHINCR_e0019' , + 'WESNN3_INCR' , 'CATCHINCR_e0019' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0019' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0019' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0019' , + 'SNDZN1_INCR' , 'CATCHINCR_e0019' , + 'SNDZN2_INCR' , 'CATCHINCR_e0019' , + 'SNDZN3_INCR' , 'CATCHINCR_e0019' , :: catch_progn_incr0020.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -718,31 +670,31 @@ catch_progn_incr0020.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0020.mode: 'instantaneous', catch_progn_incr0020.frequency: 030000, catch_progn_incr0020.ref_time: 013000, -catch_progn_incr0020.fields: 'TCFSAT_INCR' , 'CATCHINCR0020' , - 'TCFTRN_INCR' , 'CATCHINCR0020' , - 'TCFWLT_INCR' , 'CATCHINCR0020' , - 'QCFSAT_INCR' , 'CATCHINCR0020' , - 'QCFTRN_INCR' , 'CATCHINCR0020' , - 'QCFWLT_INCR' , 'CATCHINCR0020' , - 'CAPAC_INCR' , 'CATCHINCR0020' , - 'CATDEF_INCR' , 'CATCHINCR0020' , - 'RZEXC_INCR' , 'CATCHINCR0020' , - 'SRFEXC_INCR' , 'CATCHINCR0020' , - 'GHTCNT1_INCR' , 'CATCHINCR0020' , - 'GHTCNT2_INCR' , 'CATCHINCR0020' , - 'GHTCNT3_INCR' , 'CATCHINCR0020' , - 'GHTCNT4_INCR' , 'CATCHINCR0020' , - 'GHTCNT5_INCR' , 'CATCHINCR0020' , - 'GHTCNT6_INCR' , 'CATCHINCR0020' , - 'WESNN1_INCR' , 'CATCHINCR0020' , - 'WESNN2_INCR' , 'CATCHINCR0020' , - 'WESNN3_INCR' , 'CATCHINCR0020' , - 'HTSNNN1_INCR' , 'CATCHINCR0020' , - 'HTSNNN2_INCR' , 'CATCHINCR0020' , - 'HTSNNN3_INCR' , 'CATCHINCR0020' , - 'SNDZN1_INCR' , 'CATCHINCR0020' , - 'SNDZN2_INCR' , 'CATCHINCR0020' , - 'SNDZN3_INCR' , 'CATCHINCR0020' , +catch_progn_incr0020.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0020' , + 'TCFTRN_INCR' , 'CATCHINCR_e0020' , + 'TCFWLT_INCR' , 'CATCHINCR_e0020' , + 'QCFSAT_INCR' , 'CATCHINCR_e0020' , + 'QCFTRN_INCR' , 'CATCHINCR_e0020' , + 'QCFWLT_INCR' , 'CATCHINCR_e0020' , + 'CAPAC_INCR' , 'CATCHINCR_e0020' , + 'CATDEF_INCR' , 'CATCHINCR_e0020' , + 'RZEXC_INCR' , 'CATCHINCR_e0020' , + 'SRFEXC_INCR' , 'CATCHINCR_e0020' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0020' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0020' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0020' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0020' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0020' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0020' , + 'WESNN1_INCR' , 'CATCHINCR_e0020' , + 'WESNN2_INCR' , 'CATCHINCR_e0020' , + 'WESNN3_INCR' , 'CATCHINCR_e0020' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0020' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0020' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0020' , + 'SNDZN1_INCR' , 'CATCHINCR_e0020' , + 'SNDZN2_INCR' , 'CATCHINCR_e0020' , + 'SNDZN3_INCR' , 'CATCHINCR_e0020' , :: catch_progn_incr0021.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -750,31 +702,31 @@ catch_progn_incr0021.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0021.mode: 'instantaneous', catch_progn_incr0021.frequency: 030000, catch_progn_incr0021.ref_time: 013000, -catch_progn_incr0021.fields: 'TCFSAT_INCR' , 'CATCHINCR0021' , - 'TCFTRN_INCR' , 'CATCHINCR0021' , - 'TCFWLT_INCR' , 'CATCHINCR0021' , - 'QCFSAT_INCR' , 'CATCHINCR0021' , - 'QCFTRN_INCR' , 'CATCHINCR0021' , - 'QCFWLT_INCR' , 'CATCHINCR0021' , - 'CAPAC_INCR' , 'CATCHINCR0021' , - 'CATDEF_INCR' , 'CATCHINCR0021' , - 'RZEXC_INCR' , 'CATCHINCR0021' , - 'SRFEXC_INCR' , 'CATCHINCR0021' , - 'GHTCNT1_INCR' , 'CATCHINCR0021' , - 'GHTCNT2_INCR' , 'CATCHINCR0021' , - 'GHTCNT3_INCR' , 'CATCHINCR0021' , - 'GHTCNT4_INCR' , 'CATCHINCR0021' , - 'GHTCNT5_INCR' , 'CATCHINCR0021' , - 'GHTCNT6_INCR' , 'CATCHINCR0021' , - 'WESNN1_INCR' , 'CATCHINCR0021' , - 'WESNN2_INCR' , 'CATCHINCR0021' , - 'WESNN3_INCR' , 'CATCHINCR0021' , - 'HTSNNN1_INCR' , 'CATCHINCR0021' , - 'HTSNNN2_INCR' , 'CATCHINCR0021' , - 'HTSNNN3_INCR' , 'CATCHINCR0021' , - 'SNDZN1_INCR' , 'CATCHINCR0021' , - 'SNDZN2_INCR' , 'CATCHINCR0021' , - 'SNDZN3_INCR' , 'CATCHINCR0021' , +catch_progn_incr0021.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0021' , + 'TCFTRN_INCR' , 'CATCHINCR_e0021' , + 'TCFWLT_INCR' , 'CATCHINCR_e0021' , + 'QCFSAT_INCR' , 'CATCHINCR_e0021' , + 'QCFTRN_INCR' , 'CATCHINCR_e0021' , + 'QCFWLT_INCR' , 'CATCHINCR_e0021' , + 'CAPAC_INCR' , 'CATCHINCR_e0021' , + 'CATDEF_INCR' , 'CATCHINCR_e0021' , + 'RZEXC_INCR' , 'CATCHINCR_e0021' , + 'SRFEXC_INCR' , 'CATCHINCR_e0021' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0021' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0021' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0021' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0021' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0021' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0021' , + 'WESNN1_INCR' , 'CATCHINCR_e0021' , + 'WESNN2_INCR' , 'CATCHINCR_e0021' , + 'WESNN3_INCR' , 'CATCHINCR_e0021' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0021' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0021' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0021' , + 'SNDZN1_INCR' , 'CATCHINCR_e0021' , + 'SNDZN2_INCR' , 'CATCHINCR_e0021' , + 'SNDZN3_INCR' , 'CATCHINCR_e0021' , :: catch_progn_incr0022.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -782,31 +734,31 @@ catch_progn_incr0022.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0022.mode: 'instantaneous', catch_progn_incr0022.frequency: 030000, catch_progn_incr0022.ref_time: 013000, -catch_progn_incr0022.fields: 'TCFSAT_INCR' , 'CATCHINCR0022' , - 'TCFTRN_INCR' , 'CATCHINCR0022' , - 'TCFWLT_INCR' , 'CATCHINCR0022' , - 'QCFSAT_INCR' , 'CATCHINCR0022' , - 'QCFTRN_INCR' , 'CATCHINCR0022' , - 'QCFWLT_INCR' , 'CATCHINCR0022' , - 'CAPAC_INCR' , 'CATCHINCR0022' , - 'CATDEF_INCR' , 'CATCHINCR0022' , - 'RZEXC_INCR' , 'CATCHINCR0022' , - 'SRFEXC_INCR' , 'CATCHINCR0022' , - 'GHTCNT1_INCR' , 'CATCHINCR0022' , - 'GHTCNT2_INCR' , 'CATCHINCR0022' , - 'GHTCNT3_INCR' , 'CATCHINCR0022' , - 'GHTCNT4_INCR' , 'CATCHINCR0022' , - 'GHTCNT5_INCR' , 'CATCHINCR0022' , - 'GHTCNT6_INCR' , 'CATCHINCR0022' , - 'WESNN1_INCR' , 'CATCHINCR0022' , - 'WESNN2_INCR' , 'CATCHINCR0022' , - 'WESNN3_INCR' , 'CATCHINCR0022' , - 'HTSNNN1_INCR' , 'CATCHINCR0022' , - 'HTSNNN2_INCR' , 'CATCHINCR0022' , - 'HTSNNN3_INCR' , 'CATCHINCR0022' , - 'SNDZN1_INCR' , 'CATCHINCR0022' , - 'SNDZN2_INCR' , 'CATCHINCR0022' , - 'SNDZN3_INCR' , 'CATCHINCR0022' , +catch_progn_incr0022.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0022' , + 'TCFTRN_INCR' , 'CATCHINCR_e0022' , + 'TCFWLT_INCR' , 'CATCHINCR_e0022' , + 'QCFSAT_INCR' , 'CATCHINCR_e0022' , + 'QCFTRN_INCR' , 'CATCHINCR_e0022' , + 'QCFWLT_INCR' , 'CATCHINCR_e0022' , + 'CAPAC_INCR' , 'CATCHINCR_e0022' , + 'CATDEF_INCR' , 'CATCHINCR_e0022' , + 'RZEXC_INCR' , 'CATCHINCR_e0022' , + 'SRFEXC_INCR' , 'CATCHINCR_e0022' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0022' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0022' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0022' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0022' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0022' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0022' , + 'WESNN1_INCR' , 'CATCHINCR_e0022' , + 'WESNN2_INCR' , 'CATCHINCR_e0022' , + 'WESNN3_INCR' , 'CATCHINCR_e0022' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0022' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0022' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0022' , + 'SNDZN1_INCR' , 'CATCHINCR_e0022' , + 'SNDZN2_INCR' , 'CATCHINCR_e0022' , + 'SNDZN3_INCR' , 'CATCHINCR_e0022' , :: catch_progn_incr0023.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -814,31 +766,31 @@ catch_progn_incr0023.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0023.mode: 'instantaneous', catch_progn_incr0023.frequency: 030000, catch_progn_incr0023.ref_time: 013000, -catch_progn_incr0023.fields: 'TCFSAT_INCR' , 'CATCHINCR0023' , - 'TCFTRN_INCR' , 'CATCHINCR0023' , - 'TCFWLT_INCR' , 'CATCHINCR0023' , - 'QCFSAT_INCR' , 'CATCHINCR0023' , - 'QCFTRN_INCR' , 'CATCHINCR0023' , - 'QCFWLT_INCR' , 'CATCHINCR0023' , - 'CAPAC_INCR' , 'CATCHINCR0023' , - 'CATDEF_INCR' , 'CATCHINCR0023' , - 'RZEXC_INCR' , 'CATCHINCR0023' , - 'SRFEXC_INCR' , 'CATCHINCR0023' , - 'GHTCNT1_INCR' , 'CATCHINCR0023' , - 'GHTCNT2_INCR' , 'CATCHINCR0023' , - 'GHTCNT3_INCR' , 'CATCHINCR0023' , - 'GHTCNT4_INCR' , 'CATCHINCR0023' , - 'GHTCNT5_INCR' , 'CATCHINCR0023' , - 'GHTCNT6_INCR' , 'CATCHINCR0023' , - 'WESNN1_INCR' , 'CATCHINCR0023' , - 'WESNN2_INCR' , 'CATCHINCR0023' , - 'WESNN3_INCR' , 'CATCHINCR0023' , - 'HTSNNN1_INCR' , 'CATCHINCR0023' , - 'HTSNNN2_INCR' , 'CATCHINCR0023' , - 'HTSNNN3_INCR' , 'CATCHINCR0023' , - 'SNDZN1_INCR' , 'CATCHINCR0023' , - 'SNDZN2_INCR' , 'CATCHINCR0023' , - 'SNDZN3_INCR' , 'CATCHINCR0023' , +catch_progn_incr0023.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0023' , + 'TCFTRN_INCR' , 'CATCHINCR_e0023' , + 'TCFWLT_INCR' , 'CATCHINCR_e0023' , + 'QCFSAT_INCR' , 'CATCHINCR_e0023' , + 'QCFTRN_INCR' , 'CATCHINCR_e0023' , + 'QCFWLT_INCR' , 'CATCHINCR_e0023' , + 'CAPAC_INCR' , 'CATCHINCR_e0023' , + 'CATDEF_INCR' , 'CATCHINCR_e0023' , + 'RZEXC_INCR' , 'CATCHINCR_e0023' , + 'SRFEXC_INCR' , 'CATCHINCR_e0023' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0023' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0023' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0023' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0023' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0023' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0023' , + 'WESNN1_INCR' , 'CATCHINCR_e0023' , + 'WESNN2_INCR' , 'CATCHINCR_e0023' , + 'WESNN3_INCR' , 'CATCHINCR_e0023' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0023' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0023' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0023' , + 'SNDZN1_INCR' , 'CATCHINCR_e0023' , + 'SNDZN2_INCR' , 'CATCHINCR_e0023' , + 'SNDZN3_INCR' , 'CATCHINCR_e0023' , :: catch_progn_incr0024.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -846,31 +798,31 @@ catch_progn_incr0024.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0024.mode: 'instantaneous', catch_progn_incr0024.frequency: 030000, catch_progn_incr0024.ref_time: 013000, -catch_progn_incr0024.fields: 'TCFSAT_INCR' , 'CATCHINCR0024' , - 'TCFTRN_INCR' , 'CATCHINCR0024' , - 'TCFWLT_INCR' , 'CATCHINCR0024' , - 'QCFSAT_INCR' , 'CATCHINCR0024' , - 'QCFTRN_INCR' , 'CATCHINCR0024' , - 'QCFWLT_INCR' , 'CATCHINCR0024' , - 'CAPAC_INCR' , 'CATCHINCR0024' , - 'CATDEF_INCR' , 'CATCHINCR0024' , - 'RZEXC_INCR' , 'CATCHINCR0024' , - 'SRFEXC_INCR' , 'CATCHINCR0024' , - 'GHTCNT1_INCR' , 'CATCHINCR0024' , - 'GHTCNT2_INCR' , 'CATCHINCR0024' , - 'GHTCNT3_INCR' , 'CATCHINCR0024' , - 'GHTCNT4_INCR' , 'CATCHINCR0024' , - 'GHTCNT5_INCR' , 'CATCHINCR0024' , - 'GHTCNT6_INCR' , 'CATCHINCR0024' , - 'WESNN1_INCR' , 'CATCHINCR0024' , - 'WESNN2_INCR' , 'CATCHINCR0024' , - 'WESNN3_INCR' , 'CATCHINCR0024' , - 'HTSNNN1_INCR' , 'CATCHINCR0024' , - 'HTSNNN2_INCR' , 'CATCHINCR0024' , - 'HTSNNN3_INCR' , 'CATCHINCR0024' , - 'SNDZN1_INCR' , 'CATCHINCR0024' , - 'SNDZN2_INCR' , 'CATCHINCR0024' , - 'SNDZN3_INCR' , 'CATCHINCR0024' , +catch_progn_incr0024.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0024' , + 'TCFTRN_INCR' , 'CATCHINCR_e0024' , + 'TCFWLT_INCR' , 'CATCHINCR_e0024' , + 'QCFSAT_INCR' , 'CATCHINCR_e0024' , + 'QCFTRN_INCR' , 'CATCHINCR_e0024' , + 'QCFWLT_INCR' , 'CATCHINCR_e0024' , + 'CAPAC_INCR' , 'CATCHINCR_e0024' , + 'CATDEF_INCR' , 'CATCHINCR_e0024' , + 'RZEXC_INCR' , 'CATCHINCR_e0024' , + 'SRFEXC_INCR' , 'CATCHINCR_e0024' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0024' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0024' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0024' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0024' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0024' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0024' , + 'WESNN1_INCR' , 'CATCHINCR_e0024' , + 'WESNN2_INCR' , 'CATCHINCR_e0024' , + 'WESNN3_INCR' , 'CATCHINCR_e0024' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0024' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0024' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0024' , + 'SNDZN1_INCR' , 'CATCHINCR_e0024' , + 'SNDZN2_INCR' , 'CATCHINCR_e0024' , + 'SNDZN3_INCR' , 'CATCHINCR_e0024' , :: catch_progn_incr0025.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -878,31 +830,31 @@ catch_progn_incr0025.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0025.mode: 'instantaneous', catch_progn_incr0025.frequency: 030000, catch_progn_incr0025.ref_time: 013000, -catch_progn_incr0025.fields: 'TCFSAT_INCR' , 'CATCHINCR0025' , - 'TCFTRN_INCR' , 'CATCHINCR0025' , - 'TCFWLT_INCR' , 'CATCHINCR0025' , - 'QCFSAT_INCR' , 'CATCHINCR0025' , - 'QCFTRN_INCR' , 'CATCHINCR0025' , - 'QCFWLT_INCR' , 'CATCHINCR0025' , - 'CAPAC_INCR' , 'CATCHINCR0025' , - 'CATDEF_INCR' , 'CATCHINCR0025' , - 'RZEXC_INCR' , 'CATCHINCR0025' , - 'SRFEXC_INCR' , 'CATCHINCR0025' , - 'GHTCNT1_INCR' , 'CATCHINCR0025' , - 'GHTCNT2_INCR' , 'CATCHINCR0025' , - 'GHTCNT3_INCR' , 'CATCHINCR0025' , - 'GHTCNT4_INCR' , 'CATCHINCR0025' , - 'GHTCNT5_INCR' , 'CATCHINCR0025' , - 'GHTCNT6_INCR' , 'CATCHINCR0025' , - 'WESNN1_INCR' , 'CATCHINCR0025' , - 'WESNN2_INCR' , 'CATCHINCR0025' , - 'WESNN3_INCR' , 'CATCHINCR0025' , - 'HTSNNN1_INCR' , 'CATCHINCR0025' , - 'HTSNNN2_INCR' , 'CATCHINCR0025' , - 'HTSNNN3_INCR' , 'CATCHINCR0025' , - 'SNDZN1_INCR' , 'CATCHINCR0025' , - 'SNDZN2_INCR' , 'CATCHINCR0025' , - 'SNDZN3_INCR' , 'CATCHINCR0025' , +catch_progn_incr0025.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0025' , + 'TCFTRN_INCR' , 'CATCHINCR_e0025' , + 'TCFWLT_INCR' , 'CATCHINCR_e0025' , + 'QCFSAT_INCR' , 'CATCHINCR_e0025' , + 'QCFTRN_INCR' , 'CATCHINCR_e0025' , + 'QCFWLT_INCR' , 'CATCHINCR_e0025' , + 'CAPAC_INCR' , 'CATCHINCR_e0025' , + 'CATDEF_INCR' , 'CATCHINCR_e0025' , + 'RZEXC_INCR' , 'CATCHINCR_e0025' , + 'SRFEXC_INCR' , 'CATCHINCR_e0025' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0025' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0025' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0025' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0025' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0025' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0025' , + 'WESNN1_INCR' , 'CATCHINCR_e0025' , + 'WESNN2_INCR' , 'CATCHINCR_e0025' , + 'WESNN3_INCR' , 'CATCHINCR_e0025' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0025' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0025' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0025' , + 'SNDZN1_INCR' , 'CATCHINCR_e0025' , + 'SNDZN2_INCR' , 'CATCHINCR_e0025' , + 'SNDZN3_INCR' , 'CATCHINCR_e0025' , :: catch_progn_incr0026.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -910,31 +862,31 @@ catch_progn_incr0026.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0026.mode: 'instantaneous', catch_progn_incr0026.frequency: 030000, catch_progn_incr0026.ref_time: 013000, -catch_progn_incr0026.fields: 'TCFSAT_INCR' , 'CATCHINCR0026' , - 'TCFTRN_INCR' , 'CATCHINCR0026' , - 'TCFWLT_INCR' , 'CATCHINCR0026' , - 'QCFSAT_INCR' , 'CATCHINCR0026' , - 'QCFTRN_INCR' , 'CATCHINCR0026' , - 'QCFWLT_INCR' , 'CATCHINCR0026' , - 'CAPAC_INCR' , 'CATCHINCR0026' , - 'CATDEF_INCR' , 'CATCHINCR0026' , - 'RZEXC_INCR' , 'CATCHINCR0026' , - 'SRFEXC_INCR' , 'CATCHINCR0026' , - 'GHTCNT1_INCR' , 'CATCHINCR0026' , - 'GHTCNT2_INCR' , 'CATCHINCR0026' , - 'GHTCNT3_INCR' , 'CATCHINCR0026' , - 'GHTCNT4_INCR' , 'CATCHINCR0026' , - 'GHTCNT5_INCR' , 'CATCHINCR0026' , - 'GHTCNT6_INCR' , 'CATCHINCR0026' , - 'WESNN1_INCR' , 'CATCHINCR0026' , - 'WESNN2_INCR' , 'CATCHINCR0026' , - 'WESNN3_INCR' , 'CATCHINCR0026' , - 'HTSNNN1_INCR' , 'CATCHINCR0026' , - 'HTSNNN2_INCR' , 'CATCHINCR0026' , - 'HTSNNN3_INCR' , 'CATCHINCR0026' , - 'SNDZN1_INCR' , 'CATCHINCR0026' , - 'SNDZN2_INCR' , 'CATCHINCR0026' , - 'SNDZN3_INCR' , 'CATCHINCR0026' , +catch_progn_incr0026.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0026' , + 'TCFTRN_INCR' , 'CATCHINCR_e0026' , + 'TCFWLT_INCR' , 'CATCHINCR_e0026' , + 'QCFSAT_INCR' , 'CATCHINCR_e0026' , + 'QCFTRN_INCR' , 'CATCHINCR_e0026' , + 'QCFWLT_INCR' , 'CATCHINCR_e0026' , + 'CAPAC_INCR' , 'CATCHINCR_e0026' , + 'CATDEF_INCR' , 'CATCHINCR_e0026' , + 'RZEXC_INCR' , 'CATCHINCR_e0026' , + 'SRFEXC_INCR' , 'CATCHINCR_e0026' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0026' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0026' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0026' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0026' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0026' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0026' , + 'WESNN1_INCR' , 'CATCHINCR_e0026' , + 'WESNN2_INCR' , 'CATCHINCR_e0026' , + 'WESNN3_INCR' , 'CATCHINCR_e0026' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0026' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0026' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0026' , + 'SNDZN1_INCR' , 'CATCHINCR_e0026' , + 'SNDZN2_INCR' , 'CATCHINCR_e0026' , + 'SNDZN3_INCR' , 'CATCHINCR_e0026' , :: catch_progn_incr0027.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -942,31 +894,31 @@ catch_progn_incr0027.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0027.mode: 'instantaneous', catch_progn_incr0027.frequency: 030000, catch_progn_incr0027.ref_time: 013000, -catch_progn_incr0027.fields: 'TCFSAT_INCR' , 'CATCHINCR0027' , - 'TCFTRN_INCR' , 'CATCHINCR0027' , - 'TCFWLT_INCR' , 'CATCHINCR0027' , - 'QCFSAT_INCR' , 'CATCHINCR0027' , - 'QCFTRN_INCR' , 'CATCHINCR0027' , - 'QCFWLT_INCR' , 'CATCHINCR0027' , - 'CAPAC_INCR' , 'CATCHINCR0027' , - 'CATDEF_INCR' , 'CATCHINCR0027' , - 'RZEXC_INCR' , 'CATCHINCR0027' , - 'SRFEXC_INCR' , 'CATCHINCR0027' , - 'GHTCNT1_INCR' , 'CATCHINCR0027' , - 'GHTCNT2_INCR' , 'CATCHINCR0027' , - 'GHTCNT3_INCR' , 'CATCHINCR0027' , - 'GHTCNT4_INCR' , 'CATCHINCR0027' , - 'GHTCNT5_INCR' , 'CATCHINCR0027' , - 'GHTCNT6_INCR' , 'CATCHINCR0027' , - 'WESNN1_INCR' , 'CATCHINCR0027' , - 'WESNN2_INCR' , 'CATCHINCR0027' , - 'WESNN3_INCR' , 'CATCHINCR0027' , - 'HTSNNN1_INCR' , 'CATCHINCR0027' , - 'HTSNNN2_INCR' , 'CATCHINCR0027' , - 'HTSNNN3_INCR' , 'CATCHINCR0027' , - 'SNDZN1_INCR' , 'CATCHINCR0027' , - 'SNDZN2_INCR' , 'CATCHINCR0027' , - 'SNDZN3_INCR' , 'CATCHINCR0027' , +catch_progn_incr0027.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0027' , + 'TCFTRN_INCR' , 'CATCHINCR_e0027' , + 'TCFWLT_INCR' , 'CATCHINCR_e0027' , + 'QCFSAT_INCR' , 'CATCHINCR_e0027' , + 'QCFTRN_INCR' , 'CATCHINCR_e0027' , + 'QCFWLT_INCR' , 'CATCHINCR_e0027' , + 'CAPAC_INCR' , 'CATCHINCR_e0027' , + 'CATDEF_INCR' , 'CATCHINCR_e0027' , + 'RZEXC_INCR' , 'CATCHINCR_e0027' , + 'SRFEXC_INCR' , 'CATCHINCR_e0027' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0027' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0027' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0027' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0027' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0027' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0027' , + 'WESNN1_INCR' , 'CATCHINCR_e0027' , + 'WESNN2_INCR' , 'CATCHINCR_e0027' , + 'WESNN3_INCR' , 'CATCHINCR_e0027' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0027' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0027' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0027' , + 'SNDZN1_INCR' , 'CATCHINCR_e0027' , + 'SNDZN2_INCR' , 'CATCHINCR_e0027' , + 'SNDZN3_INCR' , 'CATCHINCR_e0027' , :: catch_progn_incr0028.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -974,31 +926,31 @@ catch_progn_incr0028.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0028.mode: 'instantaneous', catch_progn_incr0028.frequency: 030000, catch_progn_incr0028.ref_time: 013000, -catch_progn_incr0028.fields: 'TCFSAT_INCR' , 'CATCHINCR0028' , - 'TCFTRN_INCR' , 'CATCHINCR0028' , - 'TCFWLT_INCR' , 'CATCHINCR0028' , - 'QCFSAT_INCR' , 'CATCHINCR0028' , - 'QCFTRN_INCR' , 'CATCHINCR0028' , - 'QCFWLT_INCR' , 'CATCHINCR0028' , - 'CAPAC_INCR' , 'CATCHINCR0028' , - 'CATDEF_INCR' , 'CATCHINCR0028' , - 'RZEXC_INCR' , 'CATCHINCR0028' , - 'SRFEXC_INCR' , 'CATCHINCR0028' , - 'GHTCNT1_INCR' , 'CATCHINCR0028' , - 'GHTCNT2_INCR' , 'CATCHINCR0028' , - 'GHTCNT3_INCR' , 'CATCHINCR0028' , - 'GHTCNT4_INCR' , 'CATCHINCR0028' , - 'GHTCNT5_INCR' , 'CATCHINCR0028' , - 'GHTCNT6_INCR' , 'CATCHINCR0028' , - 'WESNN1_INCR' , 'CATCHINCR0028' , - 'WESNN2_INCR' , 'CATCHINCR0028' , - 'WESNN3_INCR' , 'CATCHINCR0028' , - 'HTSNNN1_INCR' , 'CATCHINCR0028' , - 'HTSNNN2_INCR' , 'CATCHINCR0028' , - 'HTSNNN3_INCR' , 'CATCHINCR0028' , - 'SNDZN1_INCR' , 'CATCHINCR0028' , - 'SNDZN2_INCR' , 'CATCHINCR0028' , - 'SNDZN3_INCR' , 'CATCHINCR0028' , +catch_progn_incr0028.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0028' , + 'TCFTRN_INCR' , 'CATCHINCR_e0028' , + 'TCFWLT_INCR' , 'CATCHINCR_e0028' , + 'QCFSAT_INCR' , 'CATCHINCR_e0028' , + 'QCFTRN_INCR' , 'CATCHINCR_e0028' , + 'QCFWLT_INCR' , 'CATCHINCR_e0028' , + 'CAPAC_INCR' , 'CATCHINCR_e0028' , + 'CATDEF_INCR' , 'CATCHINCR_e0028' , + 'RZEXC_INCR' , 'CATCHINCR_e0028' , + 'SRFEXC_INCR' , 'CATCHINCR_e0028' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0028' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0028' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0028' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0028' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0028' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0028' , + 'WESNN1_INCR' , 'CATCHINCR_e0028' , + 'WESNN2_INCR' , 'CATCHINCR_e0028' , + 'WESNN3_INCR' , 'CATCHINCR_e0028' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0028' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0028' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0028' , + 'SNDZN1_INCR' , 'CATCHINCR_e0028' , + 'SNDZN2_INCR' , 'CATCHINCR_e0028' , + 'SNDZN3_INCR' , 'CATCHINCR_e0028' , :: catch_progn_incr0029.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -1006,31 +958,31 @@ catch_progn_incr0029.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0029.mode: 'instantaneous', catch_progn_incr0029.frequency: 030000, catch_progn_incr0029.ref_time: 013000, -catch_progn_incr0029.fields: 'TCFSAT_INCR' , 'CATCHINCR0029' , - 'TCFTRN_INCR' , 'CATCHINCR0029' , - 'TCFWLT_INCR' , 'CATCHINCR0029' , - 'QCFSAT_INCR' , 'CATCHINCR0029' , - 'QCFTRN_INCR' , 'CATCHINCR0029' , - 'QCFWLT_INCR' , 'CATCHINCR0029' , - 'CAPAC_INCR' , 'CATCHINCR0029' , - 'CATDEF_INCR' , 'CATCHINCR0029' , - 'RZEXC_INCR' , 'CATCHINCR0029' , - 'SRFEXC_INCR' , 'CATCHINCR0029' , - 'GHTCNT1_INCR' , 'CATCHINCR0029' , - 'GHTCNT2_INCR' , 'CATCHINCR0029' , - 'GHTCNT3_INCR' , 'CATCHINCR0029' , - 'GHTCNT4_INCR' , 'CATCHINCR0029' , - 'GHTCNT5_INCR' , 'CATCHINCR0029' , - 'GHTCNT6_INCR' , 'CATCHINCR0029' , - 'WESNN1_INCR' , 'CATCHINCR0029' , - 'WESNN2_INCR' , 'CATCHINCR0029' , - 'WESNN3_INCR' , 'CATCHINCR0029' , - 'HTSNNN1_INCR' , 'CATCHINCR0029' , - 'HTSNNN2_INCR' , 'CATCHINCR0029' , - 'HTSNNN3_INCR' , 'CATCHINCR0029' , - 'SNDZN1_INCR' , 'CATCHINCR0029' , - 'SNDZN2_INCR' , 'CATCHINCR0029' , - 'SNDZN3_INCR' , 'CATCHINCR0029' , +catch_progn_incr0029.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0029' , + 'TCFTRN_INCR' , 'CATCHINCR_e0029' , + 'TCFWLT_INCR' , 'CATCHINCR_e0029' , + 'QCFSAT_INCR' , 'CATCHINCR_e0029' , + 'QCFTRN_INCR' , 'CATCHINCR_e0029' , + 'QCFWLT_INCR' , 'CATCHINCR_e0029' , + 'CAPAC_INCR' , 'CATCHINCR_e0029' , + 'CATDEF_INCR' , 'CATCHINCR_e0029' , + 'RZEXC_INCR' , 'CATCHINCR_e0029' , + 'SRFEXC_INCR' , 'CATCHINCR_e0029' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0029' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0029' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0029' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0029' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0029' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0029' , + 'WESNN1_INCR' , 'CATCHINCR_e0029' , + 'WESNN2_INCR' , 'CATCHINCR_e0029' , + 'WESNN3_INCR' , 'CATCHINCR_e0029' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0029' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0029' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0029' , + 'SNDZN1_INCR' , 'CATCHINCR_e0029' , + 'SNDZN2_INCR' , 'CATCHINCR_e0029' , + 'SNDZN3_INCR' , 'CATCHINCR_e0029' , :: catch_progn_incr0030.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -1038,31 +990,31 @@ catch_progn_incr0030.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0030.mode: 'instantaneous', catch_progn_incr0030.frequency: 030000, catch_progn_incr0030.ref_time: 013000, -catch_progn_incr0030.fields: 'TCFSAT_INCR' , 'CATCHINCR0030' , - 'TCFTRN_INCR' , 'CATCHINCR0030' , - 'TCFWLT_INCR' , 'CATCHINCR0030' , - 'QCFSAT_INCR' , 'CATCHINCR0030' , - 'QCFTRN_INCR' , 'CATCHINCR0030' , - 'QCFWLT_INCR' , 'CATCHINCR0030' , - 'CAPAC_INCR' , 'CATCHINCR0030' , - 'CATDEF_INCR' , 'CATCHINCR0030' , - 'RZEXC_INCR' , 'CATCHINCR0030' , - 'SRFEXC_INCR' , 'CATCHINCR0030' , - 'GHTCNT1_INCR' , 'CATCHINCR0030' , - 'GHTCNT2_INCR' , 'CATCHINCR0030' , - 'GHTCNT3_INCR' , 'CATCHINCR0030' , - 'GHTCNT4_INCR' , 'CATCHINCR0030' , - 'GHTCNT5_INCR' , 'CATCHINCR0030' , - 'GHTCNT6_INCR' , 'CATCHINCR0030' , - 'WESNN1_INCR' , 'CATCHINCR0030' , - 'WESNN2_INCR' , 'CATCHINCR0030' , - 'WESNN3_INCR' , 'CATCHINCR0030' , - 'HTSNNN1_INCR' , 'CATCHINCR0030' , - 'HTSNNN2_INCR' , 'CATCHINCR0030' , - 'HTSNNN3_INCR' , 'CATCHINCR0030' , - 'SNDZN1_INCR' , 'CATCHINCR0030' , - 'SNDZN2_INCR' , 'CATCHINCR0030' , - 'SNDZN3_INCR' , 'CATCHINCR0030' , +catch_progn_incr0030.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0030' , + 'TCFTRN_INCR' , 'CATCHINCR_e0030' , + 'TCFWLT_INCR' , 'CATCHINCR_e0030' , + 'QCFSAT_INCR' , 'CATCHINCR_e0030' , + 'QCFTRN_INCR' , 'CATCHINCR_e0030' , + 'QCFWLT_INCR' , 'CATCHINCR_e0030' , + 'CAPAC_INCR' , 'CATCHINCR_e0030' , + 'CATDEF_INCR' , 'CATCHINCR_e0030' , + 'RZEXC_INCR' , 'CATCHINCR_e0030' , + 'SRFEXC_INCR' , 'CATCHINCR_e0030' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0030' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0030' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0030' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0030' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0030' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0030' , + 'WESNN1_INCR' , 'CATCHINCR_e0030' , + 'WESNN2_INCR' , 'CATCHINCR_e0030' , + 'WESNN3_INCR' , 'CATCHINCR_e0030' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0030' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0030' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0030' , + 'SNDZN1_INCR' , 'CATCHINCR_e0030' , + 'SNDZN2_INCR' , 'CATCHINCR_e0030' , + 'SNDZN3_INCR' , 'CATCHINCR_e0030' , :: catch_progn_incr0031.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -1070,31 +1022,31 @@ catch_progn_incr0031.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0031.mode: 'instantaneous', catch_progn_incr0031.frequency: 030000, catch_progn_incr0031.ref_time: 013000, -catch_progn_incr0031.fields: 'TCFSAT_INCR' , 'CATCHINCR0031' , - 'TCFTRN_INCR' , 'CATCHINCR0031' , - 'TCFWLT_INCR' , 'CATCHINCR0031' , - 'QCFSAT_INCR' , 'CATCHINCR0031' , - 'QCFTRN_INCR' , 'CATCHINCR0031' , - 'QCFWLT_INCR' , 'CATCHINCR0031' , - 'CAPAC_INCR' , 'CATCHINCR0031' , - 'CATDEF_INCR' , 'CATCHINCR0031' , - 'RZEXC_INCR' , 'CATCHINCR0031' , - 'SRFEXC_INCR' , 'CATCHINCR0031' , - 'GHTCNT1_INCR' , 'CATCHINCR0031' , - 'GHTCNT2_INCR' , 'CATCHINCR0031' , - 'GHTCNT3_INCR' , 'CATCHINCR0031' , - 'GHTCNT4_INCR' , 'CATCHINCR0031' , - 'GHTCNT5_INCR' , 'CATCHINCR0031' , - 'GHTCNT6_INCR' , 'CATCHINCR0031' , - 'WESNN1_INCR' , 'CATCHINCR0031' , - 'WESNN2_INCR' , 'CATCHINCR0031' , - 'WESNN3_INCR' , 'CATCHINCR0031' , - 'HTSNNN1_INCR' , 'CATCHINCR0031' , - 'HTSNNN2_INCR' , 'CATCHINCR0031' , - 'HTSNNN3_INCR' , 'CATCHINCR0031' , - 'SNDZN1_INCR' , 'CATCHINCR0031' , - 'SNDZN2_INCR' , 'CATCHINCR0031' , - 'SNDZN3_INCR' , 'CATCHINCR0031' , +catch_progn_incr0031.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0031' , + 'TCFTRN_INCR' , 'CATCHINCR_e0031' , + 'TCFWLT_INCR' , 'CATCHINCR_e0031' , + 'QCFSAT_INCR' , 'CATCHINCR_e0031' , + 'QCFTRN_INCR' , 'CATCHINCR_e0031' , + 'QCFWLT_INCR' , 'CATCHINCR_e0031' , + 'CAPAC_INCR' , 'CATCHINCR_e0031' , + 'CATDEF_INCR' , 'CATCHINCR_e0031' , + 'RZEXC_INCR' , 'CATCHINCR_e0031' , + 'SRFEXC_INCR' , 'CATCHINCR_e0031' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0031' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0031' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0031' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0031' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0031' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0031' , + 'WESNN1_INCR' , 'CATCHINCR_e0031' , + 'WESNN2_INCR' , 'CATCHINCR_e0031' , + 'WESNN3_INCR' , 'CATCHINCR_e0031' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0031' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0031' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0031' , + 'SNDZN1_INCR' , 'CATCHINCR_e0031' , + 'SNDZN2_INCR' , 'CATCHINCR_e0031' , + 'SNDZN3_INCR' , 'CATCHINCR_e0031' , :: catch_progn_incr0032.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', @@ -1102,31 +1054,30 @@ catch_progn_incr0032.template: '%y4%m2%d2_%h2%n2z.bin', catch_progn_incr0032.mode: 'instantaneous', catch_progn_incr0032.frequency: 030000, catch_progn_incr0032.ref_time: 013000, -catch_progn_incr0032.fields: 'TCFSAT_INCR' , 'CATCHINCR0031' , - 'TCFTRN_INCR' , 'CATCHINCR0032' , - 'TCFWLT_INCR' , 'CATCHINCR0032' , - 'QCFSAT_INCR' , 'CATCHINCR0032' , - 'QCFTRN_INCR' , 'CATCHINCR0032' , - 'QCFWLT_INCR' , 'CATCHINCR0032' , - 'CAPAC_INCR' , 'CATCHINCR0032' , - 'CATDEF_INCR' , 'CATCHINCR0032' , - 'RZEXC_INCR' , 'CATCHINCR0032' , - 'SRFEXC_INCR' , 'CATCHINCR0032' , - 'GHTCNT1_INCR' , 'CATCHINCR0032' , - 'GHTCNT2_INCR' , 'CATCHINCR0032' , - 'GHTCNT3_INCR' , 'CATCHINCR0032' , - 'GHTCNT4_INCR' , 'CATCHINCR0032' , - 'GHTCNT5_INCR' , 'CATCHINCR0032' , - 'GHTCNT6_INCR' , 'CATCHINCR0032' , - 'WESNN1_INCR' , 'CATCHINCR0032' , - 'WESNN2_INCR' , 'CATCHINCR0032' , - 'WESNN3_INCR' , 'CATCHINCR0032' , - 'HTSNNN1_INCR' , 'CATCHINCR0032' , - 'HTSNNN2_INCR' , 'CATCHINCR0032' , - 'HTSNNN3_INCR' , 'CATCHINCR0032' , - 'SNDZN1_INCR' , 'CATCHINCR0032' , - 'SNDZN2_INCR' , 'CATCHINCR0032' , - 'SNDZN3_INCR' , 'CATCHINCR0032' , +catch_progn_incr0032.fields: 'TCFSAT_INCR' , 'CATCHINCR_e0032' , + 'TCFTRN_INCR' , 'CATCHINCR_e0032' , + 'TCFWLT_INCR' , 'CATCHINCR_e0032' , + 'QCFSAT_INCR' , 'CATCHINCR_e0032' , + 'QCFTRN_INCR' , 'CATCHINCR_e0032' , + 'QCFWLT_INCR' , 'CATCHINCR_e0032' , + 'CAPAC_INCR' , 'CATCHINCR_e0032' , + 'CATDEF_INCR' , 'CATCHINCR_e0032' , + 'RZEXC_INCR' , 'CATCHINCR_e0032' , + 'SRFEXC_INCR' , 'CATCHINCR_e0032' , + 'GHTCNT1_INCR' , 'CATCHINCR_e0032' , + 'GHTCNT2_INCR' , 'CATCHINCR_e0032' , + 'GHTCNT3_INCR' , 'CATCHINCR_e0032' , + 'GHTCNT4_INCR' , 'CATCHINCR_e0032' , + 'GHTCNT5_INCR' , 'CATCHINCR_e0032' , + 'GHTCNT6_INCR' , 'CATCHINCR_e0032' , + 'WESNN1_INCR' , 'CATCHINCR_e0032' , + 'WESNN2_INCR' , 'CATCHINCR_e0032' , + 'WESNN3_INCR' , 'CATCHINCR_e0032' , + 'HTSNNN1_INCR' , 'CATCHINCR_e0032' , + 'HTSNNN2_INCR' , 'CATCHINCR_e0032' , + 'HTSNNN3_INCR' , 'CATCHINCR_e0032' , + 'SNDZN1_INCR' , 'CATCHINCR_e0032' , + 'SNDZN2_INCR' , 'CATCHINCR_e0032' , + 'SNDZN3_INCR' , 'CATCHINCR_e0032' , :: - diff --git a/src/Applications/LDAS_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.central b/src/Applications/LDAS_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.central index 34d69d97..c30c880a 100644 --- a/src/Applications/LDAS_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.central +++ b/src/Applications/LDAS_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.central @@ -16,7 +16,7 @@ LADAS_COUPLING: 1 ADAS_EXPDIR: [full_path]/[ADAS_EXPDIR] MET_TAG: [ADAS_EXPID]__Nx+- -MET_PATH: [ADAS_EXPDIR]/lana/forc +MET_PATH: ../../scratch # option to use perturbed forcing created from central simulation and atm ensemble # MET_PATH: [ADAS_EXPDIR]/atmens/rgdlfo diff --git a/src/Applications/LDAS_App/tile_bin2nc4.F90 b/src/Applications/LDAS_App/tile_bin2nc4.F90 index e50a9eb5..df52c8be 100644 --- a/src/Applications/LDAS_App/tile_bin2nc4.F90 +++ b/src/Applications/LDAS_App/tile_bin2nc4.F90 @@ -227,7 +227,7 @@ FUNCTION getAttribute (SHORT_NAME, LNAME, UNT) result (str_atr) case ('net_downward_shortwave_flux'); LONG_NAME = 'Net_shortwave_land'; UNITS = 'W m-2' case ('net_downward_longwave_flux'); LONG_NAME = 'Net_longwave_land'; UNITS = 'W m-2' case ('radiation_shortwave_downward_flux');LONG_NAME = 'Incident_shortwave_land'; UNITS = 'W m-2' - case ('radiation_longwave_absorbed_flux'); LONG_NAME = 'perturbed_surface_downwelling_longwave_flux'; UNITS = 'W m-2' + case ('radiation_longwave_absorbed_flux'); LONG_NAME = 'surface_absorbed_longwave_flux'; UNITS = 'W m-2' case ('precipitation_total_surface_flux'); LONG_NAME = 'RainfSnowf'; UNITS = 'kg m-2 s-1' case ('snowfall_surface_flux'); LONG_NAME = 'snowfall'; UNITS = 'kg m-2 s-1' case ('surface_pressure'); LONG_NAME = 'surface_pressure'; UNITS = 'Pa' @@ -250,13 +250,13 @@ FUNCTION getAttribute (SHORT_NAME, LNAME, UNT) result (str_atr) case ('TB_LAND_1410MHZ_40DEG_VPOL'); LONG_NAME = 'brightness_temperature_land_1410MHz_40deg_Vpol'; UNITS = 'K' ! Done for SM_L4 - + case ('Tair'); LONG_NAME = 'air_temperature_at_RefH'; UNITS = 'K' case ('TA'); LONG_NAME = 'air_temperature_at_RefH'; UNITS = 'K' case ('Qair'); LONG_NAME = 'specific_humidity_at_RefH'; UNITS = 'kg kg-1' case ('QA'); LONG_NAME = 'specific_humidity_at_RefH'; UNITS = 'kg kg-1' - case ('LWdown'); LONG_NAME = 'downward_longwave_radiation"'; UNITS = 'W m-2' - case ('LWDNSRF'); LONG_NAME = 'perturbed_surface_downwelling_longwave_flux'; UNITS = 'W m-2' + case ('LWdown'); LONG_NAME = 'surface_absorbed_longwave_flux'; UNITS = 'W m-2' + case ('LWDNSRF'); LONG_NAME = 'surface_absorbed_longwave_flux'; UNITS = 'W m-2' case ('SWdown'); LONG_NAME = 'downward_shortwave_radiation'; UNITS = 'W m-2' case ('Wind'); LONG_NAME = 'wind_speed_at_RefH'; UNITS = 'm s-1' case ('UU'); LONG_NAME = 'wind_speed_at_RefH'; UNITS = 'm s-1' @@ -275,7 +275,20 @@ FUNCTION getAttribute (SHORT_NAME, LNAME, UNT) result (str_atr) case ('WESNN1'); LONG_NAME = 'snow_mass_layer_1'; UNITS = 'kg m-2' case ('WESNN2'); LONG_NAME = 'snow_mass_layer_2'; UNITS = 'kg m-2' case ('WESNN3'); LONG_NAME = 'snow_mass_layer_3'; UNITS = 'kg m-2' - case ('HLWUP'); LONG_NAME = 'surface_outgoing_longwave_flux'; UNITS = 'W m-2' + case ('HTSNNN1'); LONG_NAME = 'heat_content_snow_layer_1'; UNITS = 'J m-2' + case ('HTSNNN2'); LONG_NAME = 'heat_content_snow_layer_2'; UNITS = 'J m-2' + case ('HTSNNN3'); LONG_NAME = 'heat_content_snow_layer_3'; UNITS = 'J m-2' + case ('SNDZN1'); LONG_NAME = 'snow_depth_layer_1'; UNITS = 'm' + case ('SNDZN2'); LONG_NAME = 'snow_depth_layer_2'; UNITS = 'm' + case ('SNDZN3'); LONG_NAME = 'snow_depth_layer_3'; UNITS = 'm' + case ('FICE1'); LONG_NAME = 'snow_frozen_fraction_layer_1'; UNITS = '1' + case ('FICE2'); LONG_NAME = 'snow_frozen_fraction_layer_2'; UNITS = '1' + case ('FICE3'); LONG_NAME = 'snow_frozen_fraction_layer_3'; UNITS = '1' + case ('ALBVR'); LONG_NAME = 'surface_reflectivity_for_visible_beam'; UNITS = '1' + case ('ALBVF'); LONG_NAME = 'surface_reflectivity_for_visible_diffuse'; UNITS = '1' + case ('ALBNR'); LONG_NAME = 'surface_reflectivity_for_near_infared_beam'; UNITS = '1' + case ('ALBNF'); LONG_NAME = 'surface_reflectivity_for_near_infrared_diffuse'; UNITS = '1' + case ('HLWUP'); LONG_NAME = 'surface_emitted_longwave_flux'; UNITS = 'W m-2' case ('GWETPROF'); LONG_NAME = 'ave_prof_soil_wetness'; UNITS = '1' case ('GWETROOT'); LONG_NAME = 'root_zone_soil_wetness'; UNITS = '1' case ('GWETTOP'); LONG_NAME = 'surface_soil_wetness'; UNITS = '1' diff --git a/src/Applications/LDAS_App/util/config/generate_catchincr_hist.py b/src/Applications/LDAS_App/util/config/generate_catchincr_hist.py old mode 100644 new mode 100755 index 8d6d6d51..ce15d61f --- a/src/Applications/LDAS_App/util/config/generate_catchincr_hist.py +++ b/src/Applications/LDAS_App/util/config/generate_catchincr_hist.py @@ -1,30 +1,55 @@ #!/usr/bin/env python # -# module load python/GEOSpyD/Ana2019.03_py3.7 +# This code works with the python version loaded by g5_modules associated with GEOSldas v17.13.1: +# python/GEOSpyD/Min4.11.0_py3.9_AND_Min4.8.3_py2.7 # +# This script generates a sample HISTORY.rc file for GEOSldas to write Catchment +# model analysis increments in ensemble space, as needed in the weakly-coupled +# Hybrid-4DEnVar land-atm DAS (LADAS). + import os import glob import subprocess as sp +# ------------------------------------------------------------------ +# +# specify number of ensemble members here: + +nens = 32 + +# ------------------------------------------------------------------ +# +# some definitions of text elements in HISTORY.rc file + heads = """ -VERSION: 1 -EXPID: GEOSldas_expid -EXPDSC: GEOSldas_output -EXPSRC: GEOSldas +# +# Sample GEOSldas HISTORY.rc file for LADAS (atm ensemble) +# +# - This sample HISTORY.rc is for the GEOSldas instance that is weakly coupled with the +# atmospheric ensemble component of the Hybrid-4DEnVar ADAS (ADASens). +# +# - The sample file was generated with the utility script +# "GEOSldas/src/Applications/LDAS_App/util/config/generate_catchincr_hist.py". +# +# - The sample file triggers output of the GEOSldas "catch_progn_incr" collection in +# ensemble space, which is needed by ADASens. +# +# - The IDs of the ensemble members and their total number in GEOSldas must match +# those of ADASens. +# +# - The "catch_progn_incr" output is in tile space, which must be the same for +# GEOSldas and ADASens. +# +# +################################################################################## + +EXPID: MyGEOSldasAtmEns COLLECTIONS: """ label = """ :: -GRID_LABELS: PC720x361-DC -:: -PC720x361-DC.GRID_TYPE: LatLon -PC720x361-DC.IM_WORLD: 720 -PC720x361-DC.JM_WORLD: 361 -PC720x361-DC.POLE: PC -PC720x361-DC.DATELINE: DC -PC720x361-DC.LM: 1 """ hist_template = """ @@ -34,51 +59,63 @@ template: '%y4%m2%d2_%h2%n2z.bin', mode: 'instantaneous', frequency: 030000, -ref_time: 000000, -fields: 'TCFSAT_INCR' , 'CATCHINCR' , - 'TCFTRN_INCR' , 'CATCHINCR' , - 'TCFWLT_INCR' , 'CATCHINCR' , - 'QCFSAT_INCR' , 'CATCHINCR' , - 'QCFTRN_INCR' , 'CATCHINCR' , - 'QCFWLT_INCR' , 'CATCHINCR' , - 'CAPAC_INCR' , 'CATCHINCR' , - 'CATDEF_INCR' , 'CATCHINCR' , - 'RZEXC_INCR' , 'CATCHINCR' , - 'SRFEXC_INCR' , 'CATCHINCR' , - 'GHTCNT1_INCR' , 'CATCHINCR' , - 'GHTCNT2_INCR' , 'CATCHINCR' , - 'GHTCNT3_INCR' , 'CATCHINCR' , - 'GHTCNT4_INCR' , 'CATCHINCR' , - 'GHTCNT5_INCR' , 'CATCHINCR' , - 'GHTCNT6_INCR' , 'CATCHINCR' , - 'WESNN1_INCR' , 'CATCHINCR' , - 'WESNN2_INCR' , 'CATCHINCR' , - 'WESNN3_INCR' , 'CATCHINCR' , - 'HTSNNN1_INCR' , 'CATCHINCR' , - 'HTSNNN2_INCR' , 'CATCHINCR' , - 'HTSNNN3_INCR' , 'CATCHINCR' , - 'SNDZN1_INCR' , 'CATCHINCR' , - 'SNDZN2_INCR' , 'CATCHINCR' , - 'SNDZN3_INCR' , 'CATCHINCR' , +ref_time: 013000, +fields: 'TCFSAT_INCR' , 'CATCHINCR_e' , + 'TCFTRN_INCR' , 'CATCHINCR_e' , + 'TCFWLT_INCR' , 'CATCHINCR_e' , + 'QCFSAT_INCR' , 'CATCHINCR_e' , + 'QCFTRN_INCR' , 'CATCHINCR_e' , + 'QCFWLT_INCR' , 'CATCHINCR_e' , + 'CAPAC_INCR' , 'CATCHINCR_e' , + 'CATDEF_INCR' , 'CATCHINCR_e' , + 'RZEXC_INCR' , 'CATCHINCR_e' , + 'SRFEXC_INCR' , 'CATCHINCR_e' , + 'GHTCNT1_INCR' , 'CATCHINCR_e' , + 'GHTCNT2_INCR' , 'CATCHINCR_e' , + 'GHTCNT3_INCR' , 'CATCHINCR_e' , + 'GHTCNT4_INCR' , 'CATCHINCR_e' , + 'GHTCNT5_INCR' , 'CATCHINCR_e' , + 'GHTCNT6_INCR' , 'CATCHINCR_e' , + 'WESNN1_INCR' , 'CATCHINCR_e' , + 'WESNN2_INCR' , 'CATCHINCR_e' , + 'WESNN3_INCR' , 'CATCHINCR_e' , + 'HTSNNN1_INCR' , 'CATCHINCR_e' , + 'HTSNNN2_INCR' , 'CATCHINCR_e' , + 'HTSNNN3_INCR' , 'CATCHINCR_e' , + 'SNDZN1_INCR' , 'CATCHINCR_e' , + 'SNDZN2_INCR' , 'CATCHINCR_e' , + 'SNDZN3_INCR' , 'CATCHINCR_e' , """ -nens = 32 +# ------------------------------------------------------------------ +# +# write file "HISTORY.rc" with nens "catch_progn_incrXXXX" collections, +# one for each ensemble member + with open('HISTORY.rc', 'w') as f: f.write(heads) collection, body = hist_template.split('::\n') collection = collection.strip('\n').strip("'") for i in range(nens): - ids = collection+f'{i:04}' - f.write(f"'{ids}'\n") + i = i +1 + sfx = '%04d'%(i) + ids = "'"+collection+sfx+"'" + f.write(ids+'\n') f.write(label) lines = body.split('\n') for i in range(nens): - collect= collection+f'{i:04}.' + i = i+1 + sfx = '%04d'%(i) + collect= collection+sfx+"." for line in lines: newline = line if ":" in line : newline = collect+line - if "CATCHINCR" in newline: - newline = newline.replace('CATCHINCR',f'CATCHINCR{i:04}') + if "CATCHINCR_e" in newline: + sfx = '%04d'%(i) + frep = 'CATCHINCR_e'+sfx + newline = newline.replace('CATCHINCR_e',frep) f.write(newline+'\n') f.write('::\n') + +# ====================== EOF ===================================== diff --git a/src/Applications/LDAS_App/util/inputs/ASCAT_sm_mask/CMakeLists.txt b/src/Applications/LDAS_App/util/inputs/ASCAT_sm_mask/CMakeLists.txt new file mode 100644 index 00000000..11114b07 --- /dev/null +++ b/src/Applications/LDAS_App/util/inputs/ASCAT_sm_mask/CMakeLists.txt @@ -0,0 +1,4 @@ +# build without installation + +add_executable(ascat_mask_maker.x ascat_mask_maker.F90) +target_link_libraries(ascat_mask_maker.x MAPL) diff --git a/src/Applications/LDAS_App/util/inputs/ASCAT_sm_mask/ascat_mask_maker.F90 b/src/Applications/LDAS_App/util/inputs/ASCAT_sm_mask/ascat_mask_maker.F90 new file mode 100644 index 00000000..e9b4bbd0 --- /dev/null +++ b/src/Applications/LDAS_App/util/inputs/ASCAT_sm_mask/ascat_mask_maker.F90 @@ -0,0 +1,242 @@ +! This program produces a combined mask for use with the assimilation of ASCAT soil moisture retrievals in GEOSldas. +! The combined mask is based on component masks from: +! +! Lindorfer, R., Wagner, W., Hahn, S., Kim, H., Vreugdenhil, M., Gruber, A., Fischer, M., & Trnka, M. (2023). +! Global Scale Maps of Subsurface Scattering Signals Impacting ASCAT Soil Moisture Retrievals (1.0.0) [Data set]. +! TU Wien. https://doi.org/10.48436/9a2y9-e5z14 +! +! The program provides the possibility to combine different masks (default is combination of subsurface and wetland masks) +! and interpolates onto a regular grid with a (hardwired) 0.1 degree lat/lon spacing and -90/-180 degree lower left +! corner used for quick indexing in the ASCAT observation reader QC routine. +! +! Author: AM Fox, March, 2024 + +program ascat_mask_maker + + use netcdf + + implicit none + + integer :: ncid, varid, dimid, ierr, len, N_gpi, dimids(2), N_lon, N_lat + integer :: i, j, closest_index, mask_mode + integer, dimension(:), allocatable :: cold_mask, wet_mask, veg_mask, subsurface_mask, combined_mask + + integer(kind=1), dimension(:,:), allocatable :: mask_out + integer(kind=1) :: missing_value + + real, dimension(:), allocatable :: asc_lon, asc_lat + real, dimension(:), allocatable :: lon, lat, distances + real :: d_lon, d_lat, ll_lon, ll_lat + + character(200) :: fname_in, mask_description, fname_out + + ! -------------------------------------------------------------------------------- + ! + ! hardwired variables + + ! ASCAT soil moisture mask file from Lindorfer et al 2023 + + fname_in = '/discover/nobackup/projects/gmao/smap/SMAP_Nature/ASCAT_EUMETSAT/Mask/subsurface_scattering_ASCAT_ERA5_Land.nc' + + ! Specification of how to combine the masks + ! Mask_mode = 1 (default) combines subsurface and wetland masks + ! Mask_mode = 2 uses only the subsurface mask + ! Mask_mode = 3 uses only the wetland mask + ! Mask_mode = 4 combines subsurface, wetland and vegetation masks + + mask_mode = 1 + + ! Specification of output grid and missing value + + d_lon = 0.1 + d_lat = 0.1 + ll_lon = -180.0 ! longitude of boundary of lower-left grid cell (longitude of lower left corner of grid) + ll_lat = -90.0 ! latitude of boundary of lower-left grid cell (latitude of lower left corner of grid) + + missing_value = -128 + + ! Specify the NetCDF file name for the output mask + + fname_out = 'ascat_combined_mask_p1.nc' + + ! ------------------------------- + + ! Open the NetCDF input file + ierr = nf90_open(fname_in, nf90_nowrite, ncid) + if (ierr /= nf90_noerr) stop 'Error opening file: ' // trim(fname_in) + + ! Data in original mask file are on the 12.5 km fixed Earth grid used for ASCAT (WARP5 grid) and + ! stored in the NetCDF file as 1-dimensional arrays of length N_gpi (over land only). + + ! Get the dimension ID + ierr = nf90_inq_dimid(ncid, 'gpi', dimid) + if (ierr /= nf90_noerr) stop 'Error getting dimension ID' + + ! Get the length of the dimension + ierr = nf90_inquire_dimension(ncid, dimid, len = N_gpi) + if (ierr /= nf90_noerr) stop 'Error inquiring dimension' + + print*, 'N_gpi = ', N_gpi + + ! Allocate the arrays + allocate(asc_lon( N_gpi)) + allocate(asc_lat( N_gpi)) + allocate(cold_mask( N_gpi)) + allocate(wet_mask( N_gpi)) + allocate(veg_mask( N_gpi)) + allocate(subsurface_mask(N_gpi)) + allocate(combined_mask( N_gpi)) + allocate(distances( N_gpi)) + + ! Get the variable IDs and read the variables + ierr = nf90_inq_varid(ncid, 'lon', varid) + ierr = nf90_get_var(ncid, varid, asc_lon) + ierr = nf90_inq_varid(ncid, 'lat', varid) + ierr = nf90_get_var(ncid, varid, asc_lat) + ierr = nf90_inq_varid(ncid, 'cold_mask', varid) + ierr = nf90_get_var(ncid, varid, cold_mask) + ierr = nf90_inq_varid(ncid, 'wet_mask', varid) + ierr = nf90_get_var(ncid, varid, wet_mask) + ierr = nf90_inq_varid(ncid, 'veg_mask', varid) + ierr = nf90_get_var(ncid, varid, veg_mask) + ierr = nf90_inq_varid(ncid, 'subsurface_mask', varid) + ierr = nf90_get_var(ncid, varid, subsurface_mask) + + ! Close the NetCDF file + ierr = nf90_close(ncid) + if (ierr /= nf90_noerr) stop 'Error closing file' + + ! Combine the masks (1-dim arrays) + select case (mask_mode) + case (1) + ! Combine wet_mask and subsurface_mask + mask_description = 'Combined subsurface and wetland mask' + where (wet_mask /= 0) + combined_mask = 1 + elsewhere + combined_mask = subsurface_mask + end where + case (2) + ! Use only subsurface_mask + mask_description = 'Used only subsurface mask' + combined_mask = subsurface_mask + case (3) + ! Use only wet_mask + mask_description = 'Used only wetland mask' + combined_mask = wet_mask + case (4) + ! Combine subsurface_mask, wet_mask, and veg_mask + mask_description = 'Combined subsurface, wetland, and vegetation mask' + where (wet_mask /= 0 .or. veg_mask /= 0) + combined_mask = 1 + elsewhere + combined_mask = subsurface_mask + end where + end select + + ! Re-map "combined_mask" from WARP5 input grid to regular lat/lon output grid (2-dim array) + + N_lon = nint( 360.0 / d_lon ) + N_lat = nint( 180.0 / d_lat ) + + allocate(lon(N_lon)) + allocate(lat(N_lat)) + + lon = [((ll_lon + (d_lon / 2)) + i * d_lon, i = 0, N_lon - 1)] ! NB using grid cell centers for nearest neighbor search + lat = [((ll_lat + (d_lat / 2)) + i * d_lat, i = 0, N_lat - 1)] + + allocate(mask_out( N_lon, N_lat)) + + do i = 1, N_lon + print*, lon(i) + do j = 1, N_lat + distances = (asc_lon - lon(i))**2 + (asc_lat - lat(j))**2 + closest_index = minloc(distances, dim = 1) + if (distances(closest_index) > 0.14**2) then + mask_out(i, j) = missing_value ! Note: ASCAT EUMETSAT reader masks everything .ne. 0 + else + mask_out(i, j) = combined_mask(closest_index) + end if + end do + end do + + ! Write out the mask to netcdf + ierr = nf90_create(fname_out, nf90_clobber, ncid) + if (ierr /= nf90_noerr) stop 'Error creating file: ' // fname_out + + ! Define the dimensions + ierr = nf90_def_dim(ncid, 'lon', N_lon, dimids(1)) + ierr = nf90_def_dim(ncid, 'lat', N_lat, dimids(2)) + + ! Define the global attributes + ierr = nf90_put_att(ncid, nf90_global, 'title', 'ASCAT combined mask') + ierr = nf90_put_att(ncid, nf90_global, 'source', 'Lindorfer et al 2023 doi:10.48436/9a2y9-e5z14') + ierr = nf90_put_att(ncid, nf90_global, 'description', mask_description) + + ! Define the variables + ierr = nf90_def_var(ncid, 'lat', nf90_real, dimids(2), varid) + ierr = nf90_put_att(ncid, varid, 'standard_name', 'latitude') + ierr = nf90_put_att(ncid, varid, 'long_name', 'grid cell center latitude') + ierr = nf90_put_att(ncid, varid, 'units', 'degrees_north') + ierr = nf90_put_att(ncid, varid, 'axis', 'Y') + + ierr = nf90_def_var(ncid, 'lon', nf90_real, dimids(1), varid) + ierr = nf90_put_att(ncid, varid, 'standard_name', 'longitude') + ierr = nf90_put_att(ncid, varid, 'long_name', 'grid cell center longitude') + ierr = nf90_put_att(ncid, varid, 'units', 'degrees_east') + ierr = nf90_put_att(ncid, varid, 'axis', 'X') + + ierr = nf90_def_var(ncid, 'mask', nf90_byte, dimids, varid) + ierr = nf90_put_att(ncid, varid, 'standard_name', 'combined_mask') + ierr = nf90_put_att(ncid, varid, 'long_name', 'combined mask') + ierr = nf90_put_att(ncid, varid, 'units', 'boolean') + ierr = nf90_put_att(ncid, varid, '_FillValue', missing_value) + + ierr = nf90_def_var(ncid, 'll_lon', nf90_real, varid) + ierr = nf90_put_att(ncid, varid, 'standard_name', 'longitude of lower left corner') + ierr = nf90_put_att(ncid, varid, 'long_name', 'longitude of lower left corner') + ierr = nf90_put_att(ncid, varid, 'units', 'degrees_east') + ierr = nf90_put_att(ncid, varid, 'axis', 'X') + + ierr = nf90_def_var(ncid, 'll_lat', nf90_real, varid) + ierr = nf90_put_att(ncid, varid, 'standard_name', 'latitude of lower left corner') + ierr = nf90_put_att(ncid, varid, 'long_name', 'latitude of lower left corner') + ierr = nf90_put_att(ncid, varid, 'units', 'degrees_north') + ierr = nf90_put_att(ncid, varid, 'axis', 'Y') + + ierr = nf90_def_var(ncid, 'd_lon', nf90_real, varid) + ierr = nf90_put_att(ncid, varid, 'standard_name', 'longitude grid spacing') + ierr = nf90_put_att(ncid, varid, 'long_name', 'longitude grid spacing') + ierr = nf90_put_att(ncid, varid, 'units', 'degrees') + ierr = nf90_put_att(ncid, varid, 'axis', 'X') + + ierr = nf90_def_var(ncid, 'd_lat', nf90_real, varid) + ierr = nf90_put_att(ncid, varid, 'long_name', 'latitude grid spacing') + ierr = nf90_put_att(ncid, varid, 'units', 'degrees') + ierr = nf90_put_att(ncid, varid, 'axis', 'Y') + + ! End define mode + ierr = nf90_enddef(ncid) + + ! Write the variables + ierr = nf90_inq_varid(ncid, 'lat', varid) + ierr = nf90_put_var(ncid, varid, lat) + ierr = nf90_inq_varid(ncid, 'lon', varid) + ierr = nf90_put_var(ncid, varid, lon) + ierr = nf90_inq_varid(ncid, 'mask', varid) + ierr = nf90_put_var(ncid, varid, mask_out) + if (ierr /= nf90_noerr) stop 'Error writing variable' + ierr = nf90_inq_varid(ncid, 'll_lon', varid) + ierr = nf90_put_var(ncid, varid, ll_lon) + ierr = nf90_inq_varid(ncid, 'll_lat', varid) + ierr = nf90_put_var(ncid, varid, ll_lat) + ierr = nf90_inq_varid(ncid, 'd_lon', varid) + ierr = nf90_put_var(ncid, varid, d_lon) + ierr = nf90_inq_varid(ncid, 'd_lat', varid) + ierr = nf90_put_var(ncid, varid, d_lat) + + ! Close the NetCDF file + ierr = nf90_close(ncid) + if (ierr /= nf90_noerr) stop 'Error closing file' + +end program ascat_mask_maker diff --git a/src/Applications/LDAS_App/util/inputs/mwRTM_params/Create_vegopacity_8day_clim.m b/src/Applications/LDAS_App/util/inputs/mwRTM_params/Create_vegopacity_8day_clim.m index 3c243b27..13272941 100644 --- a/src/Applications/LDAS_App/util/inputs/mwRTM_params/Create_vegopacity_8day_clim.m +++ b/src/Applications/LDAS_App/util/inputs/mwRTM_params/Create_vegopacity_8day_clim.m @@ -241,7 +241,7 @@ header = [y1 m1 d1 0 0 0 y2 m2 d2 0 0 0 tc.N_tile 1]; - tile_data = nanmean(L2_tau_tile([nidx_pre nidx nidx_nxt],:),1); + tile_data = mean(L2_tau_tile([nidx_pre nidx nidx_nxt],:),1,"omitnan"); tile_data(isnan(tile_data)) = 1.e15; fwrite( ifp, 14*4, int_precision ); % fortran_tag @@ -260,7 +260,7 @@ end % ======================== -% The final vegopacity.bin file contains data averaged (nanmean) of Asc +% The final vegopacity.bin file contains data averaged (mean) of Asc % and Des tau climatology. VOD is climatology,the other 2 parameters are % time constant with maximum spatial coverage data_clim_tile = NaN + ones(48, tc.N_tile,2); @@ -295,7 +295,7 @@ data_clim_tile(data_clim_tile < 0.) = 0.; % set small negative values to 0 % averaging A, D values -tile_data = nanmean(data_clim_tile,3); +tile_data = mean(data_clim_tile,3,"omitnan"); fname_out = strrep(fname, L2_Ascdes,'_AD_'); if fill_small_gaps diff --git a/src/Applications/LDAS_App/util/inputs/mwRTM_params/get_L2_RTM_constants_tile_data.m b/src/Applications/LDAS_App/util/inputs/mwRTM_params/get_L2_RTM_constants_tile_data.m index c717b9be..3125e892 100644 --- a/src/Applications/LDAS_App/util/inputs/mwRTM_params/get_L2_RTM_constants_tile_data.m +++ b/src/Applications/LDAS_App/util/inputs/mwRTM_params/get_L2_RTM_constants_tile_data.m @@ -4,7 +4,7 @@ L2_version,start_time, end_time) % function to compute the 2 RTM constant variables: Albedo and Roughness(H) based on the -% preprocessed data. Constants are taken as the long term temporal nanmean +% preprocessed data. Constants are taken as the long term temporal mean % with maximum coverage across Asc/Desc passes. % Q. Liu 18 Jul 2022 @@ -212,7 +212,7 @@ data_clim_tile(data_clim_tile < 0.) = 0.; % set small negative values to 0 % averaging A, D values - tile_data = nanmean(data_clim_tile,2); + tile_data = mean(data_clim_tile,2,"omitnan"); eval(['out_mwRTM.',out_Para{iPara},'=tile_data;']) end diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_model_and_obs_clim_stats_latlon_grid.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_model_and_obs_clim_stats_latlon_grid.m new file mode 100644 index 00000000..015f6762 --- /dev/null +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_model_and_obs_clim_stats_latlon_grid.m @@ -0,0 +1,115 @@ +clear + +% ------------------------------------------------------------------- +% Begin user-defined inputs +% ------------------------------------------------------------------- + +% addpath('../../shared/matlab/'); +addpath('/discover/nobackup/amfox/current_GEOSldas/GEOSldas/src/Applications/LDAS_App/util/shared/matlab') + +% Define the Open Loop experiment path, run name, domain, and output prefix + +exp_path = '/discover/nobackup/amfox/Experiments/OLv7_M36_ascat'; +exp_run = {'OLv7_M36_ascat'}; +domain = 'SMAP_EASEv2_M36_GLOBAL'; +prefix_out = 'M36_zscore_stats_'; + +% Define the Open Loop experiment start and end dates + +start_month = 4; +start_year = 2015; +end_month = 3; +end_year = 2021; + +% Define the species names + +species_names = {'ASCAT_META_SM','ASCAT_METB_SM','ASCAT_METC_SM'}; + +% Define whether to combine species + +combine_species_stats = 1; % 1 to combine all species into single set of statistics + +% Define the grid resolution (degrees) + +grid_resolution = 0.25; + +% Define moving window size over which statistics are calculated, +% and minimum number of data points required to calculate statistics + +w_days = 75; +Ndata_min = 5; + +% Define the assimilation time step and initial time + +dt_assim = 3*60*60; +t0_assim = 0; + +% Define print intervals + +print_each_DOY = 1; +print_each_pentad = 0; +print_all_pentads = 1; + +% Define output directory (takes form "domain"/stats/"out_dir") +out_dir = 'z_score_clim_quarter_degree'; + +% Define the months to run over, 1:12, plus a number of months required to complete the window +run_months = [1:12 1:ceil(w_days/30)]; + +% ------------------------------------------------------------------- +% End user-defined inputs +% ------------------------------------------------------------------- + +% Calculate the earliest and latest years for each month in the experiment +earliest_year = zeros(length(run_months),1); +latest_year = zeros(length(run_months),1); + +cnt = 0; +for month = run_months + % Initialize the earliest and latest year variables + cnt = cnt + 1; + + % Check if the current year/month combination is earlier than the earliest + if datenum(start_year, month, 1) < datenum(start_year, start_month, 1) + earliest_year(cnt) = start_year+1; + else + earliest_year(cnt) = start_year; + end + + % Check if the current year/month combination is later than the latest + if datenum(end_year, month, 1) > datenum(end_year, end_month,1) + latest_year(cnt) = end_year-1; + else + latest_year(cnt) = end_year; + end +end + +% assume "ldas_obsparam" file is available at 0z on first day of start_month/start_year + +YYYY = num2str( start_year, '%4.4d' ); +MM = num2str( start_month, '%2.2d' ); + +obs_param_fname = [exp_path, '/', exp_run{1}, '/output/', domain, '/rc_out/Y', YYYY, ... + '/M', MM, '/',exp_run{1}, '.ldas_obsparam.', YYYY, MM, '01_0000z.txt']; + +[N_obs_param, obs_param ] = read_obsparam(obs_param_fname); + +species =[]; + +for i = 1:length(species_names) + add_species = obs_param(strcmp(species_names(i),{obs_param.descr})).species; + species = union(species,add_species); +end + +if combine_species_stats + disp('Calculating stats by combining multiple species'); +end + +% Calculate the climatology statistics + +get_model_and_obs_clim_stats_latlon_grid( species_names, run_months, exp_path, exp_run{1}, domain, earliest_year, ... + latest_year, dt_assim, t0_assim, species, combine_species_stats, ... + grid_resolution, w_days, Ndata_min, prefix_out, print_each_DOY, ... + print_each_pentad, print_all_pentads, out_dir ); + +% ================= EOF ========================================================================= diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats.m index 492839a2..8d8b242e 100644 --- a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats.m +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats.m @@ -1,8 +1,8 @@ -function [] = get_model_and_obs_clim_stats( varname, ... +function [] = get_model_and_obs_clim_stats( varname, ... run_months, exp_path, exp_run, domain, start_year, end_year, ... - dt_assim, t0_assim, species, obs_param, ... - hscale, inc_angle, int_Asc, w_days, Ndata_min, prefix, ... + dt_assim, t0_assim, species, obs_param, ... + hscale, inc_angle, int_Asc, w_days, Ndata_min, prefix, ... convert_grid , time_of_day_in_hours ) % @@ -107,19 +107,20 @@ disp('ASSUMING EASEv2 M36 observations'); if ~isempty(strfind(domain,'M36')) && isempty(strfind(obs_param(species(1)).descr, '_E')) - tol = 1E-3; + tol = 1E-3; else - tol = 2; + tol = 2; end % output specs -overwrite = 1; +overwrite = 1; + +Nf = 5; %5 fields per polarization -Nf = 5; %5 fields per polarization N_out_fields = 2*Nf+4; %14; -write_ind_latlon = 'latlon_id'; %'latlon'; +write_ind_latlon = 'latlon_id'; %'latlon'; N_angle = length(inc_angle); N_pol = 2; @@ -159,46 +160,46 @@ D(1) = 1; P(1) = 1; if mi_m > 1 - D(1) = sum(days_in_month( 2014, [1:mi_m-1]))+1; - P(1) = ceil(D(1)/5); + D(1) = sum(days_in_month( 2014, [1:mi_m-1]))+1; + P(1) = ceil(D(1)/5); end if ma_m > 1 - D(2) = sum(days_in_month( 2014, [1:ma_m])); + D(2) = sum(days_in_month( 2014, [1:ma_m])); else - D(2) = 1; + D(2) = 1; end P(2) = floor(D(2)/5); if run_months(1) ~= run_months(end) && run_months(2) ~= run_months(end) - disp('WARNING: incomplete pentad-windows; loop through additional months to get complete pentads'); + disp('WARNING: incomplete pentad-windows; loop through additional months to get complete pentads'); end -fname_out_base = [ outpath, '/', prefix, ... - num2str(min(start_year)),'_doy',num2str(D(1)),'_',... - num2str(max(end_year)), '_doy',num2str(D(2)),... - '_hscale_', num2str(hscale,'%2.2f'), '_', ... - 'W_', num2str(w_days),'d_Nmin_', num2str(Ndata_min)]; +fname_out_base = [ outpath, '/', prefix, ... + num2str(min(start_year)),'_doy',num2str(D(1)),'_', ... + num2str(max(end_year)), '_doy',num2str(D(2)), ... + '_hscale_', num2str(hscale,'%2.2f'), '_', ... + 'W_', num2str(w_days),'d_Nmin_', num2str(Ndata_min)]; -fname_out_base_p = [ outpath, '/', prefix, ... - num2str(min(start_year)),'_p',num2str(P(1)),'_',... - num2str(max(end_year)), '_p',num2str(P(2)),... - '_hscale_', num2str(hscale,'%2.2f'), '_', ... - 'W_', num2str(round(w_days/5)),'p_Nmin_', num2str(Ndata_min)]; +fname_out_base_p = [ outpath, '/', prefix, ... + num2str(min(start_year)),'_p',num2str(P(1)),'_', ... + num2str(max(end_year)), '_p',num2str(P(2)), ... + '_hscale_', num2str(hscale,'%2.2f'), '_', ... + 'W_', num2str(round(w_days/5)),'p_Nmin_', num2str(Ndata_min)]; %fname_out_base = [fname_out_base, spec_tag]; if (int_Asc == 1) - Orbit_tag = '_A'; %'_Asc'; + Orbit_tag = '_A'; %'_Asc'; else - Orbit_tag = '_D'; %'_Desc'; + Orbit_tag = '_D'; %'_Desc'; end -fname_out_base = [fname_out_base, Orbit_tag]; +fname_out_base = [fname_out_base, Orbit_tag]; fname_out_base_p = [fname_out_base_p, Orbit_tag]; - + if exist( 'time_of_day_in_hours', 'var') - fname_out_base = [fname_out_base, '_', num2str(time_of_day_in_hours,'%2.2d'), 'z']; + fname_out_base = [fname_out_base, '_', num2str(time_of_day_in_hours,'%2.2d'), 'z']; fname_out_base_p = [fname_out_base_p, '_', num2str(time_of_day_in_hours,'%2.2d'), 'z']; end @@ -210,7 +211,7 @@ fname = [inpath, '/rc_out/', exp_run, '.ldas_tilecoord.bin']; fnameg= [inpath, '/rc_out/', exp_run, '.ldas_tilegrids.bin']; -[ tile_coord ] = read_tilecoord( fname ); +[ tile_coord ] = read_tilecoord( fname ); [ tile_grid ] = read_tilegrids( fnameg ); N_tile = length(tile_coord.tile_id); @@ -226,101 +227,101 @@ tile_coord_tile_id = tile_coord.tile_id; if (exist('convert_grid')) - - %1) convert to M36 EASE indices - %2) convert back to lat/lon at center of obs - if (~isempty(strfind(convert_grid, 'M36')) && ~isempty(strfind(convert_grid, 'EASEv2'))) - gridid = 'M36'; - [central_row,central_col] = EASEv2_latlon2ind(central_lat,central_lon,gridid,1); - [central_lat,central_lon] = EASEv2_ind2latlon(central_row,central_col,gridid); - elseif (~isempty(strfind(convert_grid, 'M36')) && ~isempty(strfind(convert_grid, 'EASEv1'))) - error('Must provide smapeasev1_latlon2ind() and smapeasev1_ind2latlon()!') - gridid = 'M36'; - [central_row,central_col] = smapeasev1_latlon2ind(central_lat,central_lon,gridid); - [central_lat,central_lon] = smapeasev1_ind2latlon(central_row,central_col,gridid); - else - error(['Unable to convert to ',convert_grid]) - end - - row_col_tmp = [central_row central_col]; - [unique_rc, ia, ic] = unique(row_col_tmp,'rows'); - - max_Hx_c = length(find(mode(ic)==ic)); - - %know which exact M09 tiles are actually administering the obs - %------------------- - tmp_lon = central_lon(ia)+tmp_shift_lon; - tmp_lat = central_lat(ia)+tmp_shift_lat; - - [N_tile_in_cell_ij, tile_num_in_cell_ij] = get_tile_num_in_cell_ij(... - tile_coord, tile_grid); + + %1) convert to M36 EASE indices + %2) convert back to lat/lon at center of obs + if (~isempty(strfind(convert_grid, 'M36')) && ~isempty(strfind(convert_grid, 'EASEv2'))) + gridid = 'M36'; + [central_row,central_col] = EASEv2_latlon2ind(central_lat,central_lon,gridid,1); + [central_lat,central_lon] = EASEv2_ind2latlon(central_row,central_col,gridid); + elseif (~isempty(strfind(convert_grid, 'M36')) && ~isempty(strfind(convert_grid, 'EASEv1'))) + error('Must provide smapeasev1_latlon2ind() and smapeasev1_ind2latlon()!') + gridid = 'M36'; + [central_row,central_col] = smapeasev1_latlon2ind(central_lat,central_lon,gridid); + [central_lat,central_lon] = smapeasev1_ind2latlon(central_row,central_col,gridid); + else + error(['Unable to convert to ',convert_grid]) + end + + row_col_tmp = [central_row central_col]; + [unique_rc, ia, ic] = unique(row_col_tmp,'rows'); + + max_Hx_c = length(find(mode(ic)==ic)); + + %know which exact M09 tiles are actually administering the obs + %------------------- + tmp_lon = central_lon(ia)+tmp_shift_lon; + tmp_lat = central_lat(ia)+tmp_shift_lat; + + [N_tile_in_cell_ij, tile_num_in_cell_ij] = get_tile_num_in_cell_ij( ... + tile_coord, tile_grid); + + this_FOV = 20; + option = 'FOV_in_km'; + %overwrite ia with actual administering tile number + [ia] = get_tile_num_for_obs( tile_coord, tile_grid, ... + N_tile_in_cell_ij, tile_num_in_cell_ij, ... + option, this_FOV, tmp_lat, tmp_lon); + + ia = ia(ia>0 & ~isnan(ia)); + + obsnum = NaN+zeros(length(ic),1); + obsnum(ia) = [1:length(ia)]; + + N_tile_obs = length(ia); + + %------------------- + + if store_all_M09inM36 - this_FOV = 20; - option = 'FOV_in_km'; - %overwrite ia with actual administering tile number - [ia] = get_tile_num_for_obs(tile_coord, tile_grid,... - N_tile_in_cell_ij, tile_num_in_cell_ij,... - option, this_FOV, tmp_lat, tmp_lon); - - ia = ia(ia>0 & ~isnan(ia)); - - obsnum = NaN+zeros(length(ic),1); - obsnum(ia) = [1:length(ia)]; - - N_tile_obs = length(ia); - - %------------------- - - if store_all_M09inM36 - - %Not maintained/elaborated - tile_coord_tile_id = zeros(N_tile_obs,max_Hx_c); - - disp(['centralizing obs on ',convert_grid,' grid before doing stats: max ',num2str(max_Hx_c),'tiles per obs cell']) - - for i=1:N_tile_obs - - tmp_ind = find(row_col_tmp(:,1) == unique_rc(i,1) & row_col_tmp(:,2) == unique_rc(i,2)); - tile_coord_tile_id(i,1:length(tmp_ind)) = tile_coord.tile_id(tmp_ind); - - end - - else - - tile_coord_tile_id = tile_coord.tile_id(ia); - - end - + %Not maintained/elaborated + tile_coord_tile_id = zeros(N_tile_obs,max_Hx_c); + + disp(['centralizing obs on ',convert_grid,' grid before doing stats: max ',num2str(max_Hx_c),'tiles per obs cell']) + + for i=1:N_tile_obs + + tmp_ind = find(row_col_tmp(:,1) == unique_rc(i,1) & row_col_tmp(:,2) == unique_rc(i,2)); + + tile_coord_tile_id(i,1:length(tmp_ind)) = tile_coord.tile_id(tmp_ind); + + end + + else + + tile_coord_tile_id = tile_coord.tile_id(ia); + + end + else - - N_tile_obs = N_tile; - ia = 1:N_tile; - ic = 1:N_tile; - obsnum = 1:N_tile; - + + N_tile_obs = N_tile; + ia = 1:N_tile; + ic = 1:N_tile; + obsnum = 1:N_tile; + end -lon_out = tile_coord.com_lon(ia); %NaN+zeros(N_tile,1); -lat_out = tile_coord.com_lat(ia); %NaN+zeros(N_tile,1); - +lon_out = tile_coord.com_lon(ia); %NaN+zeros(N_tile,1); +lat_out = tile_coord.com_lat(ia); %NaN+zeros(N_tile,1); if hscale>0 - - for i=1:N_tile_obs - - this_lat = lat_out(i); - this_lon = lon_out(i); - - tmp_sq_distance = ... + + for i=1:N_tile_obs + + this_lat = lat_out(i); + this_lon = lon_out(i); + + tmp_sq_distance = ... (central_lon - this_lon).^2 + ... (central_lat - this_lat).^2; - - hscale_ind{i} = find( tmp_sq_distance <= hscale^2 ); - end - + + hscale_ind{i} = find( tmp_sq_distance <= hscale^2 ); + end + else - - hscale_ind = num2cell(ia); + + hscale_ind = num2cell(ia); end @@ -330,13 +331,13 @@ % N_pol and N_angle be specified here. Then subsample specifically % when the files are written out. -o_data = NaN+zeros(N_pol,N_tile_obs,N_angle,w_days); -m_data = NaN+zeros(N_pol,N_tile_obs,N_angle,w_days); -o_data2 = NaN+zeros(N_pol,N_tile_obs,N_angle,w_days); -m_data2 = NaN+zeros(N_pol,N_tile_obs,N_angle,w_days); -N_data = NaN+zeros(N_pol,N_tile_obs,N_angle,w_days); +o_data = NaN+zeros(N_pol,N_tile_obs,N_angle,w_days); +m_data = NaN+zeros(N_pol,N_tile_obs,N_angle,w_days); +o_data2 = NaN+zeros(N_pol,N_tile_obs,N_angle,w_days); +m_data2 = NaN+zeros(N_pol,N_tile_obs,N_angle,w_days); +N_data = NaN+zeros(N_pol,N_tile_obs,N_angle,w_days); -data_out = NaN+zeros(N_out_fields,N_tile_obs,N_angle); +data_out = NaN+zeros(N_out_fields,N_tile_obs,N_angle); % ------------------------------------------------------------- @@ -347,441 +348,381 @@ count = 0; for imonth = 1:length(run_months) - month = run_months(imonth); - -for day = 1:days_in_month( 2014, month) %2014 = random non-leap year + month = run_months(imonth); + + for day = 1:days_in_month( 2014, month) %2014 = random non-leap year + if count < w_days - count = count + 1; - else - count = w_days; - end - - for seconds_in_day = t0_assim:dt_assim:(86400-1) - - hour = floor(seconds_in_day/3600); - - % check if diurnal stats are needed - - if exist('time_of_day_in_hours','var') - tmp_hour = time_of_day_in_hours; + count = count + 1; else - tmp_hour = hour; % all hours of day will be included + count = w_days; end - - if hour==tmp_hour - - minute = floor( (seconds_in_day-hour*3600)/60 ); - - seconds = seconds_in_day-hour*3600-minute*60; - - if (seconds~=0) - input('something is wrong! Ctrl-c now') + + for seconds_in_day = t0_assim:dt_assim:(86400-1) + + hour = floor(seconds_in_day/3600); + + % check if diurnal stats are needed + + if exist('time_of_day_in_hours','var') + tmp_hour = time_of_day_in_hours; + else + tmp_hour = hour; % all hours of day will be included end - - - for year = start_year(imonth):end_year(imonth) - + + if hour==tmp_hour + + minute = floor( (seconds_in_day-hour*3600)/60 ); + + seconds = seconds_in_day-hour*3600-minute*60; + + if (seconds~=0) + input('something is wrong! Ctrl-c now') + end + + for year = start_year(imonth):end_year(imonth) + YYYYMMDD = [ num2str(year, '%4.4d'), ... - num2str(month, '%2.2d'), ... - num2str(day, '%2.2d') ]; - + num2str(month, '%2.2d'), ... + num2str(day, '%2.2d') ]; + HHMM = [ num2str(hour, '%2.2d'), ... - num2str(minute, '%2.2d') ]; - + num2str(minute, '%2.2d') ]; + % read innov files - - fname = [ inpath, '/ana/ens_avg/', ... - 'Y', YYYYMMDD(1:4), '/', ... - 'M', YYYYMMDD(5:6), '/', ... - exp_run, '.ens_avg.ldas_ObsFcstAna.', ... - YYYYMMDD, '_', HHMM, 'z.bin' ]; - - ifp = fopen( fname, 'r', 'l' ); - - if (ifp > 0) %Proceed only if file exists (e.g. irregular SMOS swaths!) - - fclose(ifp); - - [date_time, ... - obs_assim, ... - obs_species, ... - obs_tilenum, ... - obs_lon, ... - obs_lat, ... - obs_obs, ... - obs_obsvar, ... - obs_fcst, ... - obs_fcstvar, ... - obs_ana, ... - obs_anavar ... - ] = ... - read_ObsFcstAna( fname ); - - % remove tiles when there is no obs_fcst (obs_fcst == 0 in innov output when - % missing) - idx = find(obs_fcst == 0); - obs_assim(idx) = []; - obs_species(idx) = []; - obs_tilenum(idx) =[]; - obs_lon(idx) =[]; - obs_lat(idx) = []; - obs_obs(idx) = []; - obs_obsvar(idx) = []; - obs_fcst(idx) = []; - obs_fcstvar(idx) = []; - obs_ana(idx) = []; - obs_anavar(idx) = []; - - % extract species of interest + fname = [ inpath, '/ana/ens_avg/', ... + 'Y', YYYYMMDD(1:4), '/', ... + 'M', YYYYMMDD(5:6), '/', ... + exp_run, '.ens_avg.ldas_ObsFcstAna.', ... + YYYYMMDD, '_', HHMM, 'z.bin' ]; - ind = []; - - for this_species = species - - ind = find( obs_species == this_species); - - if (~isempty(ind)) - + ifp = fopen( fname, 'r', 'l' ); + + if (ifp > 0) % Proceed only if file exists (e.g. irregular SMOS swaths!) + + fclose(ifp); + + [ date_time, ... + obs_assim, ... + obs_species, ... + obs_tilenum, ... + obs_lon, ... + obs_lat, ... + obs_obs, ... + obs_obsvar, ... + obs_fcst, ... + obs_fcstvar, ... + obs_ana, ... + obs_anavar ... + ] = ... + read_ObsFcstAna( fname ); + + % remove tiles where obs_fcst is no-data (note: read_ObsFcstAna() returns NaN) + + idx = isnan(obs_fcst); + + obs_assim( idx) = []; + obs_species(idx) = []; + obs_tilenum(idx) = []; + obs_lon( idx) = []; + obs_lat( idx) = []; + obs_obs( idx) = []; + obs_obsvar( idx) = []; + obs_fcst( idx) = []; + obs_fcstvar(idx) = []; + obs_ana( idx) = []; + obs_anavar( idx) = []; + + % extract species of interest + + ind = []; + + for this_species = species + + ind = find( obs_species == this_species); + + if (~isempty(ind)) + obs_tilenum_i = obs_tilenum(ind); obs_obs_i = obs_obs(ind); obs_fcst_i = obs_fcst(ind); obs_lon_i = obs_lon(ind); obs_lat_i = obs_lat(ind); - + % Check if any location receives more than 1 obs (or 1 species) - + tmp = sort(obs_tilenum_i); same_tile = find(diff(tmp)==0); - + if (~isempty(same_tile)) - error('multiple obs of the same species at one location? - only last one in line is used'); + error('multiple obs of the same species at one location? - only last one in line is used'); end - + % Organize the data in a big matrix - + angle = obs_param(this_species == [obs_param.species]).ang; pol = obs_param(this_species == [obs_param.species]).pol; - - %pol intrinsically gives an index - %now find the index for the angle + + % pol intrinsically gives an index + % now find the index for the angle angle_i = find(angle(1) == inc_angle); - + % Only writes lat-lon at exact obs locations, but with % hscale>0, these obs are spread outside their exact % location. This allows to calculate stats at lan-lons % where no obs are available. - + %lon_out(obs_tilenum_i) = obs_lon_i; %lat_out(obs_tilenum_i) = obs_lat_i; - - %obs_lat/lon are the actual M36 lat/lons, *not* the - %administering tiles, so the lat/lons for the obs and those - %in the tile_coord would not be identical. - %Still, they should be in the - %neighbourhood, so check here if that is true. + + % obs_lat/lon are the actual M36 lat/lons, *not* the + % administering tiles, so the lat/lons for the obs and those + % in the tile_coord would not be identical. + % Still, they should be in the + % neighbourhood, so check here if that is true. if (any(abs(tile_coord.com_lat(obs_tilenum_i)-obs_lat_i) > tol) || ... any(abs(tile_coord.com_lon(obs_tilenum_i)-obs_lon_i) > tol) ) - error('Something wrong with tile_lat/lon') + error('Something wrong with tile_lat/lon') end - - %map model tiles (e.g. all M09) to observation administering - %tiles (could be a reduced subset of all M09) - %-------------------------------------------------------- + + % map model tiles (e.g. all M09) to observation administering + % tiles (could be a reduced subset of all M09) + % -------------------------------------------------------- obs_i = obsnum(obs_tilenum_i); - %-------------------------------------------------------- + % -------------------------------------------------------- if (hscale == 0) - - %11 May 2015: sum the obs and fcst within each day; - %and across years! - %some obs can be found at multiple hours within a day - %e.g. at the poles. - %**nansum of NaN's** result in zero, this need to be - %taken care of - o_data(pol(1),obs_i,angle_i,count) = nansum([o_data(pol(1),obs_i,angle_i,count); obs_obs_i' ]); - m_data(pol(1),obs_i,angle_i,count) = nansum([m_data(pol(1),obs_i,angle_i,count); obs_fcst_i']); - - %X^2 - o_data2(pol(1),obs_i,angle_i,count) = nansum([o_data2(pol(1),obs_i,angle_i,count); obs_obs_i'.^2 ]); - m_data2(pol(1),obs_i,angle_i,count) = nansum([m_data2(pol(1),obs_i,angle_i,count); obs_fcst_i'.^2]); - - %Sum of obs or model elements at each location - N_data(pol(1),obs_i,angle_i,count) = nansum([N_data(pol(1),obs_i,angle_i,count); ~isnan([obs_obs_i])']); - + + % 11 May 2015: sum the obs and fcst within each day; + % and across years! + % some obs can be found at multiple hours within a day + % e.g. at the poles. + % **sum(...,"omitnan") of NaNs** results in zero, this need to be + % taken care of + o_data( pol(1),obs_i,angle_i,count) = sum([o_data( pol(1),obs_i,angle_i,count); obs_obs_i' ], "omitnan"); + m_data( pol(1),obs_i,angle_i,count) = sum([m_data( pol(1),obs_i,angle_i,count); obs_fcst_i' ], "omitnan"); + + % X^2 + o_data2(pol(1),obs_i,angle_i,count) = sum([o_data2(pol(1),obs_i,angle_i,count); obs_obs_i'.^2 ], "omitnan"); + m_data2(pol(1),obs_i,angle_i,count) = sum([m_data2(pol(1),obs_i,angle_i,count); obs_fcst_i'.^2 ], "omitnan"); + + % Sum of obs or model elements at each location + N_data(pol(1), obs_i,angle_i,count) = sum([N_data( pol(1),obs_i,angle_i,count); ~isnan([obs_obs_i])'], "omitnan"); + else - - for i_ind = 1:length(obs_obs_i) - - %introduce a spatial effect of each observation on - %neighbouring statistics (through hscale) - s_eff = unique(hscale_ind{obs_i(i_ind)}); - %hscale_ind =[obs space] % - - %Sum of X - o_data(pol(1),s_eff,angle_i,count) = ... - nansum([o_data(pol(1),s_eff,angle_i,count); repmat(obs_obs_i(i_ind),1,length(s_eff))]); - m_data(pol(1),s_eff,angle_i,count) = ... - nansum([m_data(pol(1),s_eff,angle_i,count); repmat(obs_fcst_i(i_ind),1,length(s_eff))]); - - %Sum of X^2 - o_data2(pol(1),s_eff,angle_i,count) = ... - nansum([o_data2(pol(1),s_eff,angle_i,count); repmat(obs_obs_i(i_ind).^2,1,length(s_eff))]); - m_data2(pol(1),s_eff,angle_i,count) = ... - nansum([m_data2(pol(1),s_eff,angle_i,count); repmat(obs_fcst_i(i_ind).^2,1,length(s_eff))]); - - %Sum of obs or model elements at each location - N_data(pol(1),s_eff,angle_i,count) = ... - nansum([N_data(pol(1),s_eff,angle_i,count); repmat(~isnan([obs_obs_i(i_ind)]),1,length(s_eff)) ]); - - end - - end - - end - - end - + + for i_ind = 1:length(obs_obs_i) + + % introduce a spatial effect of each observation on + % neighbouring statistics (through hscale) + s_eff = unique(hscale_ind{obs_i(i_ind)}); + %hscale_ind =[obs space] % + + % Sum of X + o_data(pol(1),s_eff,angle_i,count) = ... + sum([o_data( pol(1),s_eff,angle_i,count); repmat( obs_obs_i( i_ind), 1,length(s_eff))], "omitnan"); + m_data(pol(1),s_eff,angle_i,count) = ... + sum([m_data( pol(1),s_eff,angle_i,count); repmat( obs_fcst_i(i_ind), 1,length(s_eff))], "omitnan"); + + % Sum of X^2 + o_data2(pol(1),s_eff,angle_i,count) = ... + sum([o_data2(pol(1),s_eff,angle_i,count); repmat( obs_obs_i( i_ind).^2,1,length(s_eff))], "omitnan"); + m_data2(pol(1),s_eff,angle_i,count) = ... + sum([m_data2(pol(1),s_eff,angle_i,count); repmat( obs_fcst_i(i_ind).^2,1,length(s_eff))], "omitnan"); + + % Sum of obs or model elements at each location + N_data(pol(1),s_eff,angle_i,count) = ... + sum([N_data( pol(1),s_eff,angle_i,count); repmat(~isnan([obs_obs_i(i_ind)]), 1,length(s_eff))], "omitnan"); + + end + + end % (hscale == 0) + + end % ~isempty(ind) + + end % species + end % if file present - - end % loop over multiple years - - end % time_of_day_in_hours - - end % seconds_in_day - - %count = count+1; - - if count >= w_days %wait initially until enough data is built up - - end_time.year = 2014; - end_time.month = month; - end_time.day = day; - end_time.hour = hour; - end_time.min = minute; - end_time.sec = seconds; - - start_time = augment_date_time( -floor(w_days*(24*60*60)), end_time ); - - % At the end of each day, collect the obs and fcst of the last - % w_day period, and write out a statistics-file at [w_day - floor(w_day/2)] - - o_data(abs(o_data - nodata) <= nodata_tol) = NaN; - m_data(abs(o_data - nodata) <= nodata_tol) = NaN; - - % data_out = zeros(N_out_fields,1:N_tiles,N_angle); - - for pol=[0 1] - - pp = pol*Nf; - - N_hscale_window = nansum(N_data(1+pol,:,:,1:w_days),4); - - if w_days == 95 - N_hscale_inner_window = nansum(N_data(1+pol,:,:,((w_days+1)/2-15):((w_days+1)/2+15)),4); - end + + end % loop over multiple years + + end % hour == tmp_hour (time_of_day_in_hours) - % OBSERVATIONS - %---------------- - %o_data is a sum over neighbouring obs above; - %here then take a sum over the time steps in the window - data_out(1+pp,:,:) = nansum(o_data(1+pol,:,:,1:w_days),4); - - %then make the average, by dividing over the sum of the number of - %timesteps and influencing obs at each location - data_out(1+pp,:,:) = data_out(1+pp,:,:)./N_hscale_window; - - %stdv_H = sqrt(E[X^2] - E[X]^2) - data_out(2+pp,:,:) = nansum(o_data2(1+pol,:,:,1:w_days),4); - data_out(2+pp,:,:) = data_out(2+pp,:,:)./N_hscale_window; - data_out(2+pp,:,:) = sqrt( data_out(2+pp,:,:) - data_out(1+pp,:,:).^2); - - % MODEL - %---------------- - data_out(3+pp,:,:) = nansum(m_data(1+pol,:,:,1:w_days),4); - data_out(3+pp,:,:) = data_out(3+pp,:,:)./N_hscale_window; - - data_out(4+pp,:,:) = nansum(m_data2(1+pol,:,:,1:w_days),4); - data_out(4+pp,:,:) = data_out(4+pp,:,:)./N_hscale_window; - data_out(4+pp,:,:) = sqrt( data_out(4+pp,:,:) - data_out(3+pp,:,:).^2); - - data_out(5+pp,:,:) = N_hscale_window; - - % Toss out stats that are based on too little data - - data_out([1:5]+pp,N_hscale_window= w_days %wait initially until enough data is built up + + end_time.year = 2014; + end_time.month = month; + end_time.day = day; + end_time.hour = hour; + end_time.min = minute; + end_time.sec = seconds; + + start_time = augment_date_time( -floor(w_days*(24*60*60)), end_time ); + + % At the end of each day, collect the obs and fcst of the last + % w_day period, and write out a statistics-file at [w_day - floor(w_day/2)] - if w_days == 95 + o_data(abs(o_data - nodata) <= nodata_tol) = NaN; + m_data(abs(o_data - nodata) <= nodata_tol) = NaN; + + % data_out = zeros(N_out_fields,1:N_tiles,N_angle); + + for pol=[0 1] + + pp = pol*Nf; + + N_hscale_window = sum(N_data(1+pol,:,:,1:w_days), 4,"omitnan"); + + if w_days == 95 + N_hscale_inner_window = sum(N_data(1+pol,:,:,((w_days+1)/2-15):((w_days+1)/2+15)),4,"omitnan"); + end + + % OBSERVATIONS + %---------------- + % o_data is a sum over neighbouring obs above; + % here then take a sum over the time steps in the window + data_out(1+pp,:,:) = sum( o_data( 1+pol,:,:,1:w_days),4,"omitnan"); + + % then make the average, by dividing over the sum of the number of + % timesteps and influencing obs at each location + data_out(1+pp,:,:) = data_out( 1+pp, :,:)./N_hscale_window; + + %stdv_H = sqrt(E[X^2] - E[X]^2) + data_out(2+pp,:,:) = sum( o_data2( 1+pol,:,:,1:w_days),4,"omitnan"); + data_out(2+pp,:,:) = data_out( 2+pp, :,:)./N_hscale_window; + data_out(2+pp,:,:) = sqrt( data_out( 2+pp, :,:) - data_out(1+pp,:,:).^2); + + % MODEL + %---------------- + data_out(3+pp,:,:) = sum( m_data( 1+pol,:,:,1:w_days),4,"omitnan"); + data_out(3+pp,:,:) = data_out( 3+pp, :,:)./N_hscale_window; + + data_out(4+pp,:,:) = sum( m_data2( 1+pol,:,:,1:w_days),4,"omitnan"); + data_out(4+pp,:,:) = data_out( 4+pp, :,:)./N_hscale_window; + data_out(4+pp,:,:) = sqrt( data_out( 4+pp, :,:) - data_out(3+pp,:,:).^2); + + data_out(5+pp,:,:) = N_hscale_window; + + % Toss out stats that are based on too little data + + data_out( [1:5]+pp,N_hscale_window < Ndata_min ) = NaN; + + if w_days == 95 data_out([1:5]+pp,N_hscale_inner_window < (Ndata_min/2.5)) = NaN; + end + end - end - -% fill_M09basedonM36 = 0; -% %X -% if ~exist('convert_grid') && fill_M09basedonM36 -% -% for kk = 1:size(data_out,1) -% -% idx = find(~isnan(data_out(kk,:))); -% for dd = 1:length(idx) -% -% this_lon = lon_out(idx(dd)); -% this_lat = lat_out(idx(dd)); -% this_data = data_out(kk, idx(dd)); -% -% -% -% [M36_row, M36_col] = smapeasev2_latlon2ind(this_lat,this_lon,'M36'); -% -% M09_row = (M36_row*4):((M36_row+1)*4-1); -% M09_col = (M36_col*4):((M36_col+1)*4-1); -% -% [M09_col, M09_row] = meshgrid(M09_col, M09_row); -% -% [M09_lat, M09_lon] = smapeasev2_ind2latlon(M09_row(:), M09_col(:), 'M09'); -% -% clear s_eff -% for ii = 1:length(M09_lat) -% tmp_sq_distance = ... -% (lon_out - M09_lon(ii)).^2 + ... -% (lat_out - M09_lat(ii)).^2; -% -% [tmp,s_eff(ii)] = min(tmp_sq_distance); -% -% -% %s_eff(ii) = intersect(find(lon_out>M09_lon(ii)-1e-4 & lon_outM09_lat(ii)-1e-4 & lat_out 1) -% disp('something is wrong, M36 might be overwritten') -% pause -% end -% -% data_out(kk,s_eff) = repmat(this_data, 1, length(s_eff)); -% -% end -% end -% end - - - % Get the actual obs/model at the center point (for debugging only!!) - - data_out(11,:,:) = o_data(1,:,:,w_days-floor(w_days/2.0))./N_data(1,:,:,w_days-floor(w_days/2.0)); - data_out(12,:,:) = m_data(1,:,:,w_days-floor(w_days/2.0))./N_data(1,:,:,w_days-floor(w_days/2.0)); - data_out(13,:,:) = o_data(2,:,:,w_days-floor(w_days/2.0))./N_data(2,:,:,w_days-floor(w_days/2.0)); - data_out(14,:,:) = m_data(2,:,:,w_days-floor(w_days/2.0))./N_data(2,:,:,w_days-floor(w_days/2.0)); - - % Get rid of NaN before writing a file - - data_out(isnan(data_out)) = nodata; - %lon_out(isnan(lon_out)) = nodata; - %lat_out(isnan(lat_out)) = nodata; - - % write output file - - date_time = end_time; - date_time = augment_date_time( -floor(w_days*(24*60*60)/2.0), date_time ); - - % always 365 files - - DOY = date_time.dofyr; - - if(is_leap_year(date_time.year) && DOY>=59) - - DOY = DOY-1; - - error('This code should never hit a leap year'); + % Get the actual obs/model at the center point (for debugging only!!) - end - - - fname_out = [fname_out_base, '_DOY', num2str(DOY,'%3.3d'), '.bin']; - - % check whether output file exists - - if (exist(fname_out)==2 && overwrite) - - disp(['output file exists. overwriting', fname_out]) - - elseif (exist(fname_out)==2 && ~overwrite) - - disp(['output file exists. not overwriting. returning']) - disp(['writing ', fname_out]) - return - - else - - disp(['creating ', fname_out]) - - end - - % compress data before writing in file. - - %idx_keep = find(any(abs(data_out -nodata) > nodata_tol,1)); - %lon_out_write = lon_out(idx_keep); - %lat_out_write = lat_out(idx_keep); - %data_out_write = data_out(:,idx_keep); - %tile_coord_tile_id_write = tile_coord_tile_id(idx_keep); - - - % write output for each DOY, sorted by all tiles - - if print_each_DOY + data_out(11,:,:) = o_data(1,:,:,w_days-floor(w_days/2.0))./N_data(1,:,:,w_days-floor(w_days/2.0)); + data_out(12,:,:) = m_data(1,:,:,w_days-floor(w_days/2.0))./N_data(1,:,:,w_days-floor(w_days/2.0)); + data_out(13,:,:) = o_data(2,:,:,w_days-floor(w_days/2.0))./N_data(2,:,:,w_days-floor(w_days/2.0)); + data_out(14,:,:) = m_data(2,:,:,w_days-floor(w_days/2.0))./N_data(2,:,:,w_days-floor(w_days/2.0)); + + % Get rid of NaN before writing a file + + data_out(isnan(data_out)) = nodata; + %lon_out(isnan(lon_out)) = nodata; + %lat_out(isnan(lat_out)) = nodata; + + % write output file + + date_time = end_time; + date_time = augment_date_time( -floor(w_days*(24*60*60)/2.0), date_time ); + + % always 365 files + + DOY = date_time.dofyr; + + if(is_leap_year(date_time.year) && DOY>=59) - write_seqbin_file(fname_out, lon_out, lat_out, ... - inc_angle, data_out(:,:,:), int_Asc, 0, ... %instead of writing the version#, write Ndata_min=0 - start_time, end_time, overwrite, ... - N_out_fields, write_ind_latlon, 'scaling',... - tile_coord_tile_id) - else + DOY = DOY-1; + + error('This code should never hit a leap year'); + + end + + + fname_out = [fname_out_base, '_DOY', num2str(DOY,'%3.3d'), '.bin']; - % if DOY is at middle of pentad, then copy the DOY to a pentad file - % DOY = pentad*5 - 2; ==> pentad = (DOY + 2)/5; - - pentad = (DOY + 2)/5; + % check whether output file exists + + if (exist(fname_out)==2 && overwrite) + + disp(['output file exists. overwriting', fname_out]) + + elseif (exist(fname_out)==2 && ~overwrite) + + disp(['output file exists. not overwriting. returning']) + disp(['writing ', fname_out]) + return + + else + + disp(['creating ', fname_out]) + + end - if mod((DOY + 2),5) == 0 + % write output for each DOY, sorted by all tiles - write_seqbin_file(fname_out, lon_out, lat_out, ... - inc_angle, data_out(:,:,:), int_Asc, 0, ... - start_time, end_time, overwrite, ... - N_out_fields, write_ind_latlon, 'scaling',... - tile_coord_tile_id) + if print_each_DOY + + write_seqbin_file(fname_out, lon_out, lat_out, ... + inc_angle, data_out(:,:,:), int_Asc, 0, ... % instead of writing the version#, write Ndata_min=0 + start_time, end_time, overwrite, ... + N_out_fields, write_ind_latlon, 'scaling', ... + tile_coord_tile_id) + else + + % if DOY is at middle of pentad, then copy the DOY to a pentad file + % DOY = pentad*5 - 2; ==> pentad = (DOY + 2)/5; + + pentad = (DOY + 2)/5; + + if mod((DOY + 2),5) == 0 + + write_seqbin_file(fname_out, lon_out, lat_out, ... + inc_angle, data_out(:,:,:), int_Asc, 0, ... + start_time, end_time, overwrite, ... + N_out_fields, write_ind_latlon, 'scaling', ... + tile_coord_tile_id) + + fname_out_p = [fname_out_base_p, '_p', num2str(pentad,'%2.2d'), '.bin']; + + copyfile(fname_out,fname_out_p); + + end - fname_out_p = [fname_out_base_p, '_p', num2str(pentad,'%2.2d'), '.bin']; - - copyfile(fname_out,fname_out_p); - end - end - - %clear idx_keep lon_out_write lat_out_write data_out_write tile_coord_tile_id_write - - % shift the window by one day and make room for the next day at the end - - o_data(:,:,:,1:w_days-1) = o_data(:,:,:,2:w_days); - m_data(:,:,:,1:w_days-1) = m_data(:,:,:,2:w_days); - o_data2(:,:,:,1:w_days-1) = o_data2(:,:,:,2:w_days); - m_data2(:,:,:,1:w_days-1) = m_data2(:,:,:,2:w_days); - N_data(:,:,:,1:w_days-1) = N_data(:,:,:,2:w_days); - - o_data(:,:,:,w_days) = NaN; - m_data(:,:,:,w_days) = NaN; - o_data2(:,:,:,w_days) = NaN; - m_data2(:,:,:,w_days) = NaN; - N_data(:,:,:,w_days) = NaN; - - data_out = NaN+0.0.*data_out; - - end - -end % day + %clear idx_keep lon_out_write lat_out_write data_out_write tile_coord_tile_id_write + + % shift the window by one day and make room for the next day at the end + + o_data( :,:,:,1:w_days-1) = o_data( :,:,:,2:w_days); + m_data( :,:,:,1:w_days-1) = m_data( :,:,:,2:w_days); + o_data2(:,:,:,1:w_days-1) = o_data2(:,:,:,2:w_days); + m_data2(:,:,:,1:w_days-1) = m_data2(:,:,:,2:w_days); + N_data( :,:,:,1:w_days-1) = N_data( :,:,:,2:w_days); + + o_data( :,:,:,w_days) = NaN; + m_data( :,:,:,w_days) = NaN; + o_data2(:,:,:,w_days) = NaN; + m_data2(:,:,:,w_days) = NaN; + N_data( :,:,:,w_days) = NaN; + + data_out = NaN+0.0.*data_out; + + end + + end % day end % month diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats_latlon_grid.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats_latlon_grid.m new file mode 100644 index 00000000..1d3a0c74 --- /dev/null +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats_latlon_grid.m @@ -0,0 +1,352 @@ + +function [] = get_model_and_obs_clim_stats_latlon_grid( species_names, ... + run_months, exp_path, exp_run, domain, start_year, end_year, ... + dt_assim, t0_assim, species, combine_species_stats, ... + resol, w_days, Ndata_min, prefix, print_each_DOY, ... + print_each_pentad, print_all_pentads,out_dir ) +% +% Adapted from get_model_and_obs_clim_stats.m +% +% Compute mean, stdv of model and observations from tile-based +% "innov" files for a selection of species on an Earth-fixed global +% lat/lon grid with resolution "resol". +% +% The main purpose of this function is to aggregate the information +% from the "innov" files so that the climatology statistics can +% be used in scaling of the observations before assimilation. +% +% One file with statistics is generated for every DOY (1,...,365). +% The temporal smoothing/averaging window (w_days) is given in days. +% +% We calculate the bias correction factors (scaling parameters) and +% write on an Earth-fixed lat/lon grid as there is no Earth-fixed +% regular grid for ASCAT observations. +% +% A. M. Fox - 27 Oct 2023 +% +% ------------------------------------------------------------------- +% begin user-defined inputs +% ------------------------------------------------------------------- + +nodata = -9999; +nodata_tol = 1e-4; +overwrite = 1; +Nf = 7; +N_pentads = 73; + +disp('ASSUMING obs are not on Earth-fixed regular grid (e.g., ASCAT)'); +disp(['Calculating scaling parameters on grid with resolution = ', num2str(resol) , ' degrees']); + +if combine_species_stats + N_species = 1; +else + N_species = length(species); +end + +inpath = [ exp_path, '/', exp_run, '/output/', domain ]; + +outpath = [ inpath, '/stats/', out_dir ]; + +% create outpath if it doesn't exist +if ~exist(outpath, 'dir') + mkdir(outpath); +end + +% assemble output file name +ind = start_year == min(start_year); +mi_m = min(run_months(ind)); +ind = end_year == max(end_year); +ma_m = max(run_months(ind)); + +D(1) = 1; +P(1) = 1; +if mi_m > 1 + D(1) = sum(days_in_month(2014, 1:mi_m-1)) + 1; + P(1) = ceil(D(1) / 5); +end +D(2) = sum(days_in_month(2014, 1:ma_m)); +P(2) = floor(D(2) / 5); + +fname_out_base_d = [outpath, '/', prefix, ... + num2str(min(start_year)), '_doy', num2str(D(1)), '_', ... + num2str(max(end_year)), '_doy', num2str(D(2)), ... + '_W_', num2str(w_days), 'd_Nmin_', num2str(Ndata_min)]; + +fname_out_base_p = [outpath, '/', prefix, ... + num2str(min(start_year)), '_p', num2str(P(1)), '_', ... + num2str(max(end_year)), '_p', num2str(P(2)), ... + '_W_', num2str(round(w_days/5)), 'p_Nmin_', num2str(Ndata_min)]; + +%====================================================== + +% Define lat/lon grid (dateline-on-edge, pole-on-edge) +% Define lower-left corner coordinates and grid cell size +ll_lon = -180; +ll_lat = -90; + +d_lon = resol; +d_lat = resol; + +% Calculate number of longitude and latitude grid cells +n_lon = round(360 / d_lon); +n_lat = round(180 / d_lat); + +% Calculate longitude and latitude values for the grid +ll_lons = linspace(ll_lon, ll_lon + (n_lon-1)*d_lon, n_lon); +ll_lats = linspace(ll_lat, ll_lat + (n_lat-1)*d_lat, n_lat); + +% Create grid index +obsnum = (1:n_lon*n_lat)'; +[i_out, j_out] = ind2sub([n_lon, n_lat], obsnum); +lon_out = ll_lons(i_out)'; +lat_out = ll_lats(j_out)'; +N_gridcells = length(obsnum); + +% initialize output statistics +o_data_sum = NaN(N_species, N_gridcells, w_days); +m_data_sum = NaN(N_species, N_gridcells, w_days); +o_data_sum2 = NaN(N_species, N_gridcells, w_days); +m_data_sum2 = NaN(N_species, N_gridcells, w_days); +m_data_min = NaN(N_species, N_gridcells, w_days); +m_data_max = NaN(N_species, N_gridcells, w_days); +N_data = NaN(N_species, N_gridcells, w_days); + +data_out = NaN(N_species, Nf, N_gridcells, N_pentads); +data2D = NaN(Nf, N_gridcells); + +% ------------------------------------------------------------- + +% make sure t0_assim is *first* analysis time in a day + +t0_assim = mod( t0_assim, dt_assim ); + +count = 0; + +for imonth = 1:length(run_months) + + month = run_months(imonth); + + for day = 1:days_in_month( 2014, month) %2014 = random non-leap year + + if count < w_days + count = count + 1; + else + count = w_days; + end + + for seconds_in_day = t0_assim:dt_assim:(86400-1) + + hour = floor( seconds_in_day/3600); + minute = floor((seconds_in_day-hour*3600)/60); + seconds = seconds_in_day-hour*3600-minute*60; + + if (seconds ~= 0) + input('something is wrong! Ctrl-c now') + end + + for year = start_year(imonth):end_year(imonth) + + YYYYMMDD = [num2str(year, '%4.4d'), num2str(month, '%2.2d'), num2str(day, '%2.2d')]; + HHMM = [num2str(hour, '%2.2d'), num2str(minute, '%2.2d')]; + + % read innov files + fname = [inpath, '/ana/ens_avg/', 'Y', YYYYMMDD(1:4), '/', 'M', YYYYMMDD(5:6), '/', exp_run, '.ens_avg.ldas_ObsFcstAna.', YYYYMMDD, '_', HHMM, 'z.bin']; + ifp = fopen(fname, 'r', 'l'); + + if (ifp > 0) % Proceed only if file exists + fclose(ifp); + [date_time, obs_assim, obs_species, obs_tilenum, obs_lon, obs_lat, obs_obs, obs_obsvar, obs_fcst, obs_fcstvar, obs_ana, obs_anavar] = read_ObsFcstAna(fname); + + % remove tiles where obs_fcst is no-data (note: read_ObsFcstAna() returns NaN) + + idx = isnan(obs_fcst); + + obs_assim( idx) = []; + obs_species(idx) = []; + obs_tilenum(idx) = []; + obs_lon( idx) = []; + obs_lat( idx) = []; + obs_obs( idx) = []; + obs_obsvar( idx) = []; + obs_fcst( idx) = []; + obs_fcstvar(idx) = []; + obs_ana( idx) = []; + obs_anavar( idx) = []; + + % extract species of interest + ind = []; + for scnt = 1:N_species + + if combine_species_stats + ind = find(ismember(obs_species, species)); + else + this_species = species(scnt); + ind = find(obs_species == this_species); + end + + if ~isempty(ind) + obs_tilenum_i = obs_tilenum(ind); + obs_obs_i = obs_obs( ind); + obs_fcst_i = obs_fcst( ind); + obs_lon_i = obs_lon( ind); + obs_lat_i = obs_lat( ind); + + % Check if any location receives more than 1 obs (or 1 species) + tmp = sort(obs_tilenum_i); + same_tile = find(diff(tmp) == 0, 1); + if ~isempty(same_tile) && ~combine_species_stats + error('multiple obs of the same species at one location? - only last one in line is used'); + end + + % Put obs lat/lon on our grid and figure out obsnum/grid index + i_idx = floor((obs_lon_i - ll_lon) / d_lon) + 1; + j_idx = floor((obs_lat_i - ll_lat) / d_lat) + 1; + [~, obs_idx] = ismember([i_idx, j_idx], [i_out, j_out], 'rows'); + obs_i = obsnum(obs_idx); + + o_data_sum( scnt, obs_i, count) = sum([o_data_sum( scnt, obs_i, count); obs_obs_i' ], "omitnan"); + m_data_sum( scnt, obs_i, count) = sum([m_data_sum( scnt, obs_i, count); obs_fcst_i' ], "omitnan"); + o_data_sum2(scnt, obs_i, count) = sum([o_data_sum2(scnt, obs_i, count); obs_obs_i'.^2 ], "omitnan"); + m_data_sum2(scnt, obs_i, count) = sum([m_data_sum2(scnt, obs_i, count); obs_fcst_i'.^2 ], "omitnan"); + m_data_min( scnt, obs_i, count) = min([m_data_min( scnt, obs_i, count); obs_fcst_i' ] ); + m_data_max( scnt, obs_i, count) = max([m_data_max( scnt, obs_i, count); obs_fcst_i' ] ); + N_data( scnt, obs_i, count) = sum([N_data( scnt, obs_i, count); ~isnan(obs_obs_i)' ], "omitnan"); + end + end + end + end + end + + if count >= w_days %wait initially until enough data is built up + end_time.year = 2014; + end_time.month = month; + end_time.day = day; + end_time.hour = hour; + end_time.min = minute; + end_time.sec = seconds; + + start_time = augment_date_time( -floor(w_days*(24*60*60)), end_time ); + + % At the end of each day, collect the obs and fcst of the last + % w_day period, and write out a statistics-file at [w_day - floor(w_day/2)] + o_data_sum(abs(o_data_sum - nodata) <= nodata_tol) = NaN; + m_data_sum(abs(m_data_sum - nodata) <= nodata_tol) = NaN; + + for i = 1:N_species + + N_window = sum(N_data( i,:,1:w_days), 3,"omitnan"); + + data2D(1,:) = sum(o_data_sum( i,:,1:w_days), 3,"omitnan")./N_window; + data2D(2,:) = sqrt(sum(o_data_sum2(i,:,1:w_days), 3,"omitnan")./N_window - data2D(1,:).^2); + data2D(3,:) = sum(m_data_sum( i,:,1:w_days), 3,"omitnan")./N_window; + data2D(4,:) = sqrt(sum(m_data_sum2(i,:,1:w_days), 3,"omitnan")./N_window - data2D(3,:).^2); + data2D(5,:) = N_window; + data2D(6,:) = min(m_data_min( i,:,1:w_days),[],3); % Want to use minimum mean daily value + data2D(7,:) = max(m_data_max( i,:,1:w_days),[],3); % Want to use maximum mean daily value + + % Set NaNs where there is not enough data + data2D([1:Nf],N_window=59) + error('This code should never hit a leap year'); + end + + if print_each_DOY + pentad = floor((DOY + 2)/5); + if combine_species_stats + fname_out = [fname_out_base_d, '_sp_ALL_DOY', num2str(DOY,'%3.3d'), '.nc4']; + else + fname_out = [fname_out_base_d,'_sp_', char(species_names(i)),'_DOY', num2str(DOY,'%3.3d'), '.nc4']; + end + if (exist(fname_out)==2 && overwrite) + disp(['Output file exists. overwriting', fname_out]) + elseif (exist(fname_out)==2 && ~overwrite) + disp(['Output file exists. not overwriting. returning']) + disp(['Writing ', fname_out]) + return + else + disp(['Creating ', fname_out]) + end + + % Write out the data + write_netcdf_latlon_grid( fname_out, i_out, j_out, ll_lons, ll_lats, data2D, pentad, ... + start_time, end_time, overwrite, Nf, ll_lon, ll_lat, d_lon, d_lat) + end + + if mod((DOY + 2),5) == 0 + pentad = (DOY + 2)/5; + data_out(i,:,:,pentad) = data2D; + start_time_p(pentad) = start_time; + end_time_p(pentad) = end_time; + if print_each_pentad + if combine_species_stats + fname_out = [fname_out_base_p, '_sp_ALL_p', num2str(pentad,'%2.2d'), '.nc4']; + else + fname_out = [fname_out_base_p, '_sp_', char(species_names(i)),'_p', num2str(pentad,'%2.2d'), '.nc4']; + end + if (exist(fname_out)==2 && overwrite) + disp(['Output file exists. overwriting', fname_out]) + elseif (exist(fname_out)==2 && ~overwrite) + disp(['Output file exists. not overwriting. returning']) + disp(['Writing ', fname_out]) + return + else + disp(['Creating ', fname_out]) + end + + % Write out the data + write_netcdf_latlon_grid( fname_out, i_out, j_out, ll_lons, ll_lats, data2D, pentad, ... + start_time, end_time, overwrite, Nf, ll_lon, ll_lat, d_lon, d_lat ) + end + end + + % Shift the data in the window to make room for next day + o_data_sum( i,:,1:w_days-1) = o_data_sum( i,:,2:w_days); + m_data_sum( i,:,1:w_days-1) = m_data_sum( i,:,2:w_days); + o_data_sum2(i,:,1:w_days-1) = o_data_sum2(i,:,2:w_days); + m_data_sum2(i,:,1:w_days-1) = m_data_sum2(i,:,2:w_days); + m_data_min( i,:,1:w_days-1) = m_data_min( i,:,2:w_days); + m_data_max( i,:,1:w_days-1) = m_data_max( i,:,2:w_days); + N_data( i,:,1:w_days-1) = N_data( i,:,2:w_days); + o_data_sum( i,:,w_days ) = NaN; + m_data_sum( i,:,w_days ) = NaN; + o_data_sum2(i,:,w_days ) = NaN; + m_data_sum2(i,:,w_days ) = NaN; + m_data_min( i,:,w_days ) = NaN; + m_data_max( i,:,w_days ) = NaN; + N_data( i,:,w_days ) = NaN; + + data2D = NaN+0.0.*data2D; + end + end % count >= w_days + end % day +end % month + +if print_all_pentads + for i = 1:N_species + data_o = squeeze(data_out(i,:,:,:)); + + if combine_species_stats + fname_out = [fname_out_base_d, '_sp_ALL_all_pentads.nc4']; + else + fname_out = [fname_out_base_d,'_sp_', char(species_names(i)),'_all_pentads.nc4']; + end + + if (exist(fname_out)==2 && overwrite) + disp(['Output file exists. overwriting', fname_out]) + elseif (exist(fname_out)==2 && ~overwrite) + disp(['Output file exists. not overwriting. returning']) + disp(['Writing ', fname_out]) + return + else + disp(['Creating ', fname_out]) + end + + write_netcdf_latlon_grid( fname_out, i_out, j_out, ll_lons, ll_lats, data_o, [1:73], ... + start_time_p, end_time_p, overwrite, Nf, ll_lon, ll_lat, d_lon, d_lat ) + end +end + + +% ==================== EOF ============================================== diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_tile_num_for_obs.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_tile_num_for_obs.m index ed1e9b8a..559853cf 100644 --- a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_tile_num_for_obs.m +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_tile_num_for_obs.m @@ -66,8 +66,10 @@ % map from i_ind, j_ind to tile_num - if ( ~isempty(strfind(tile_grid.gridtype, 'EASE_M')) || ... - ~isempty(strfind(tile_grid.gridtype, 'EASEv2_M')) ) + if ( ~isempty(strfind(tile_grid.gridtype, 'EASE_M')) || ... + ~isempty(strfind(tile_grid.gridtype, 'EASE-M')) || ... + ~isempty(strfind(tile_grid.gridtype, 'EASEv2-M')) || ... + ~isempty(strfind(tile_grid.gridtype, 'EASEv2_M')) ) % ASSUMPTION: tiles match EASE or EASEv2 grid cells exactly % (unless "outside" the domain, eg. water surface) diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_netcdf_latlon_grid.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_netcdf_latlon_grid.m new file mode 100644 index 00000000..49969ad5 --- /dev/null +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_netcdf_latlon_grid.m @@ -0,0 +1,232 @@ +function [] = write_netcdf_latlon_grid( fname, colind, rowind, ll_lons, ll_lats, ... + data, pentad, start_time, end_time, overwrite, N_out_fields, ll_lon, ll_lat, d_lon, d_lat ) + + int_precision = 'NC_INT'; % precision of fortran tag + float_precision = 'NC_DOUBLE'; % precision of data in input file + + % Define the compression level (0-9, where 0 is no compression and 9 is maximum compression) + compression_level = 5; + + version = 0; + + % check dimensions + if size(data,1)~=N_out_fields + error('ERROR: size of data incompatible with N_out_fields') + end + + % check for presence of optional input "overwrite" + if ~exist('overwrite','var') + overwrite = 0; % default: do NOT overwrite existing files + end + + % check if file exists + if exist(fname,'file') + if overwrite==0 + disp(['RETURNING!!! -- NOT OVERWRITING EXISTING FILE ', fname]) + return + else + disp(['OVERWRITING ', fname]) + end + else + disp(['writing ', fname]) + end + + % Convert the cell arrays to matrices using cell2mat (to deal with all_pentad case) + year_mat = cell2mat({start_time.year}'); + month_mat = cell2mat({start_time.month}'); + day_mat = cell2mat({start_time.day}'); + hour_mat = cell2mat({start_time.hour}'); + min_mat = cell2mat({start_time.min}'); + sec_mat = cell2mat({start_time.sec}'); + % Use the matrices as input to the datetime function + d = datetime(year_mat, month_mat, day_mat, hour_mat, min_mat, sec_mat); + % Convert to serial date number + serialNum = datenum(d); + % Subtract serial date number of January 1, 1950 + daysSince1950 = serialNum - datenum('January 1, 1950'); + tmp_start_time = daysSince1950; + + % Convert the cell arrays to matrices using cell2mat (to deal with all_pentad case) + year_mat = cell2mat({end_time.year}'); + month_mat = cell2mat({end_time.month}'); + day_mat = cell2mat({end_time.day}'); + hour_mat = cell2mat({end_time.hour}'); + min_mat = cell2mat({end_time.min}'); + sec_mat = cell2mat({end_time.sec}'); + % Use the matrices as input to the datetime function + d = datetime(year_mat, month_mat, day_mat, hour_mat, min_mat, sec_mat); + % Convert to serial date number + serialNum = datenum(d); + % Subtract serial date number of January 1, 1950 + daysSince1950 = serialNum - datenum('January 1, 1950'); + tmp_end_time = daysSince1950; + + N_lon = length(ll_lons); + N_lat = length(ll_lats); + + % Have we got multiple pentads + if ismatrix(data) + N_pentad = 1; + else + N_pentad = size(data,3); + end + + % create netCDF file + netcdf.setDefaultFormat('FORMAT_NETCDF4'); + ncid = netcdf.create(fname, 'NETCDF4'); + + % define dimensions + dimid_pentad = netcdf.defDim(ncid, 'pentad', N_pentad); + dimid_lon = netcdf.defDim(ncid, 'lon', N_lon); + dimid_lat = netcdf.defDim(ncid, 'lat', N_lat); + + % define variables + + varid_version = netcdf.defVar(ncid, 'version', int_precision, []); + + varid_ll_lon = netcdf.defVar(ncid, 'll_lon', float_precision, []); + netcdf.putAtt(ncid, varid_ll_lon, 'standard_name', 'longitude of lower left corner'); + netcdf.putAtt(ncid, varid_ll_lon, 'long_name', 'longitude of lower left corner'); + netcdf.putAtt(ncid, varid_ll_lon, 'units', 'degrees_east'); + netcdf.putAtt(ncid, varid_ll_lon, 'axis', 'X'); + + varid_ll_lat = netcdf.defVar(ncid, 'll_lat', float_precision, []); + netcdf.putAtt(ncid, varid_ll_lat, 'standard_name', 'latitude of lower left corner'); + netcdf.putAtt(ncid, varid_ll_lat, 'long_name', 'latitude of lower left corner'); + netcdf.putAtt(ncid, varid_ll_lat, 'units', 'degrees_north'); + netcdf.putAtt(ncid, varid_ll_lat, 'axis', 'Y'); + + varid_d_lon = netcdf.defVar(ncid, 'd_lon', float_precision, []); + netcdf.putAtt(ncid, varid_d_lon, 'standard_name', 'longitude grid spacing'); + netcdf.putAtt(ncid, varid_d_lon, 'long_name', 'longitude grid spacing'); + netcdf.putAtt(ncid, varid_d_lon, 'units', 'degrees'); + netcdf.putAtt(ncid, varid_d_lon, 'axis', 'X'); + + varid_d_lat = netcdf.defVar(ncid, 'd_lat', float_precision, []); + netcdf.putAtt(ncid, varid_d_lat, 'standard_name', 'latitude grid spacing'); + netcdf.putAtt(ncid, varid_d_lat, 'long_name', 'latitude grid spacing'); + netcdf.putAtt(ncid, varid_d_lat, 'units', 'degrees'); + netcdf.putAtt(ncid, varid_d_lat, 'axis', 'Y'); + + varid_pentad = netcdf.defVar(ncid, 'pentad', int_precision, [dimid_pentad]); + netcdf.putAtt(ncid, varid_pentad, 'standard_name', 'pentad'); + netcdf.putAtt(ncid, varid_pentad, 'long_name', 'pentad'); + netcdf.putAtt(ncid, varid_pentad, 'units', '1'); + netcdf.putAtt(ncid, varid_pentad, 'axis', 'T'); + + varid_start_time = netcdf.defVar(ncid, 'start_time', float_precision, [dimid_pentad]); + netcdf.putAtt(ncid, varid_start_time, 'standard_name', 'start time'); + netcdf.putAtt(ncid, varid_start_time, 'long_name', 'start time'); + netcdf.putAtt(ncid, varid_start_time, 'axis', 'T'); + netcdf.putAtt(ncid, varid_start_time, 'units', 'days since 1950-01-01 00:00:00.0 +0000'); + + varid_end_time = netcdf.defVar(ncid, 'end_time', float_precision, [dimid_pentad]); + netcdf.putAtt(ncid, varid_end_time, 'standard_name', 'end time'); + netcdf.putAtt(ncid, varid_end_time, 'long_name', 'end time'); + netcdf.putAtt(ncid, varid_end_time, 'axis', 'T'); + netcdf.putAtt(ncid, varid_end_time, 'units', 'days since 1950-01-01 00:00:00.0 +0000'); + + varid_om = netcdf.defVar(ncid, 'o_mean', float_precision, [dimid_lat dimid_lon dimid_pentad]); + netcdf.defVarDeflate(ncid,varid_om,true,true,compression_level); + netcdf.putAtt(ncid, varid_om, 'standard_name', 'observation mean'); + netcdf.putAtt(ncid, varid_om, 'long_name', 'Observation mean for pentad calculated over all years for window length'); + netcdf.putAtt(ncid, varid_om, 'units', 'Degree of saturation (0-1)'); + + varid_ov = netcdf.defVar(ncid, 'o_std', float_precision, [dimid_lat dimid_lon dimid_pentad]); + netcdf.defVarDeflate(ncid,varid_ov,true,true,compression_level); + netcdf.putAtt(ncid, varid_ov, 'standard_name', 'observation standard deviation'); + netcdf.putAtt(ncid, varid_ov, 'long_name', 'Observation standard deviation for pentad calculated over all years for window length'); + netcdf.putAtt(ncid, varid_ov, 'units', 'Degree of saturation (0-1)'); + + varid_mm = netcdf.defVar(ncid, 'm_mean', float_precision, [dimid_lat dimid_lon dimid_pentad]); + netcdf.defVarDeflate(ncid,varid_mm,true,true,compression_level); + netcdf.putAtt(ncid, varid_mm, 'standard_name', 'model mean'); + netcdf.putAtt(ncid, varid_mm, 'long_name', 'Model mean for pentad calculated over all years for window length'); + netcdf.putAtt(ncid, varid_mm, 'units', 'Surface soil moisture (m^3 m^-3)'); + + varid_mv = netcdf.defVar(ncid, 'm_std', float_precision, [dimid_lat dimid_lon dimid_pentad]); + netcdf.defVarDeflate(ncid,varid_mv,true,true,compression_level); + netcdf.putAtt(ncid, varid_mv, 'standard_name', 'model standard deviation'); + netcdf.putAtt(ncid, varid_mv, 'long_name', 'Model standard deviation for pentad calculated over all years for window length'); + netcdf.putAtt(ncid, varid_mv, 'units', 'Surface soil moisture (m^3 m^-3)'); + + varid_mi = netcdf.defVar(ncid, 'm_min', float_precision, [dimid_lat dimid_lon]); + netcdf.defVarDeflate(ncid,varid_mi,true,true,compression_level); + netcdf.putAtt(ncid, varid_mi, 'standard_name', 'model minimum'); + netcdf.putAtt(ncid, varid_mi, 'long_name', 'Model minimum calculated over all years'); + netcdf.putAtt(ncid, varid_mi, 'units', 'Surface soil moisture (m^3 m^-3)'); + + varid_ma = netcdf.defVar(ncid, 'm_max', float_precision, [dimid_lat dimid_lon]); + netcdf.defVarDeflate(ncid,varid_ma,true,true,compression_level); + netcdf.putAtt(ncid, varid_ma, 'standard_name', 'model maximum'); + netcdf.putAtt(ncid, varid_ma, 'long_name', 'Model maximum calculated over all years'); + netcdf.putAtt(ncid, varid_ma, 'units', 'Surface soil moisture (m^3 m^-3)'); + + varid_ndata = netcdf.defVar(ncid, 'n_data', float_precision, [dimid_lat dimid_lon dimid_pentad]); + netcdf.defVarDeflate(ncid,varid_ndata,true,true,compression_level); + netcdf.putAtt(ncid, varid_ndata, 'standard_name', 'number of data points'); + netcdf.putAtt(ncid, varid_ndata, 'long_name', 'Number of data points for pentad calculated over all years for window length'); + netcdf.putAtt(ncid, varid_ndata, 'units', '1'); + + % end define mode + netcdf.endDef(ncid); + + % write data + netcdf.putVar(ncid, varid_pentad, pentad); + netcdf.putVar(ncid, varid_start_time, tmp_start_time); + netcdf.putVar(ncid, varid_end_time, tmp_end_time); + + netcdf.putVar(ncid, varid_ll_lon, ll_lon); + netcdf.putVar(ncid, varid_ll_lat, ll_lat); + netcdf.putVar(ncid, varid_d_lon, d_lon); + netcdf.putVar(ncid, varid_d_lat, d_lat); + + if N_pentad ==1 + + data_out = ones(N_out_fields,N_lat,N_lon ) * -999.0; + + for n = 1:N_out_fields + for i = 1:length(colind) + data_out(n,rowind(i),colind(i)) = data(n,i); + end + end + + netcdf.putVar(ncid,varid_om, data_out(1,:,:) ); + netcdf.putVar(ncid,varid_ov, data_out(2,:,:) ); + netcdf.putVar(ncid,varid_mm, data_out(3,:,:) ); + netcdf.putVar(ncid,varid_mv, data_out(4,:,:) ); + netcdf.putVar(ncid,varid_mi, data_out(6,:,:) ); + netcdf.putVar(ncid,varid_ma, data_out(7,:,:) ); + netcdf.putVar(ncid,varid_ndata, data_out(5,:,:) ); + + else + + data_out = ones(N_out_fields,N_lat,N_lon,N_pentad) * -999.0; + + for n = 1:N_out_fields + for i = 1:length(colind) + data_out(n,rowind(i),colind(i),:) = data(n,i,:); + end + end + + netcdf.putVar(ncid,varid_om, data_out(1,:,:,:) ); + netcdf.putVar(ncid,varid_ov, data_out(2,:,:,:) ); + netcdf.putVar(ncid,varid_mm, data_out(3,:,:,:) ); + netcdf.putVar(ncid,varid_mv, data_out(4,:,:,:) ); + netcdf.putVar(ncid,varid_ndata, data_out(5,:,:,:) ); + netcdf.putVar(ncid,varid_ma, max(data_out(7,:,:,:),[],4)); % Max over all pentads, always only 2D + + min_data = squeeze(data_out(6, :, :,:)); + min_data(min_data < -9998) = NaN; % Switch current missing value to NaN before calculating min + min_data_out = min(min_data,[],3); + min_data_out(isnan(min_data_out)) = -9999.; + + netcdf.putVar(ncid,varid_mi, min_data_out); % Min over all pentads, always only 2D + end + + % close netCDF file + netcdf.close(ncid); + +end + +% ================ EOF ======================================================== diff --git a/src/Applications/LDAS_App/util/postproc/climatology/get_model_clim_stats.m b/src/Applications/LDAS_App/util/postproc/climatology/get_model_clim_stats.m index fef20cc8..7082a6c3 100644 --- a/src/Applications/LDAS_App/util/postproc/climatology/get_model_clim_stats.m +++ b/src/Applications/LDAS_App/util/postproc/climatology/get_model_clim_stats.m @@ -358,11 +358,11 @@ tmp = reshape(squeeze(hist_data(tile, s, :)),1,[]); - data_out(s,tile,1) = nanmean(tmp); % mean - data_out(s,tile,2) = nanstd(tmp); % stdv - data_out(s,tile,3) = min(tmp); % min - data_out(s,tile,4) = max(tmp); % max - data_out(s,tile,5) = sum(~isnan(tmp)); % N_data + data_out(s,tile,1) = mean( tmp,"omitnan"); % mean + data_out(s,tile,2) = std( tmp,"omitnan"); % stdv + data_out(s,tile,3) = min( tmp ); % min + data_out(s,tile,4) = max( tmp ); % max + data_out(s,tile,5) = sum(~isnan(tmp) ); % N_data % determine the CDF-parameters, or the edges for each % percentile diff --git a/src/Applications/LDAS_App/util/postproc/write_smapL4SMqa.m b/src/Applications/LDAS_App/util/postproc/write_smapL4SMqa.m index 7b14e671..7f510450 100644 --- a/src/Applications/LDAS_App/util/postproc/write_smapL4SMqa.m +++ b/src/Applications/LDAS_App/util/postproc/write_smapL4SMqa.m @@ -1258,7 +1258,6 @@ % % GDL, 16 Jan 2014 % GDL, 30 Jan 2014: remove NaN prior to the calculation of stats -% and avoid using nanmean, nanstdv, etc.. % GDL, 1 Feb 2014: - weighted statistics for mean and stdv % - add 6th statistic (frac): % the actual used fraction of N_data (based on weights) diff --git a/src/Applications/LDAS_App/util/shared/matlab/MAPL_ReadForcing_fullfile.m b/src/Applications/LDAS_App/util/shared/matlab/MAPL_ReadForcing_fullfile.m index 0e5b6227..14f8cc6c 100644 --- a/src/Applications/LDAS_App/util/shared/matlab/MAPL_ReadForcing_fullfile.m +++ b/src/Applications/LDAS_App/util/shared/matlab/MAPL_ReadForcing_fullfile.m @@ -12,10 +12,10 @@ % % check whether no-data variables are available on input -if ~exist('nodata'), nodata = 1.e15; end % default: MAPL_UNDEF -if ~exist('nodata_tolfrac'), nodata_tolfrac = 1.e-4; end +if ~exist('nodata', 'var'), nodata = 1.e15; end % default: MAPL_UNDEF +if ~exist('nodata_tolfrac', 'var'), nodata_tolfrac = 1.e-4; end -nodata_tol = abs( nodata*nodata_tol_frac ); +nodata_tol = abs( nodata*nodata_tolfrac ); % ------------------------------------------------------------------------- diff --git a/src/Applications/LDAS_App/util/shared/matlab/pentad_of_year.m b/src/Applications/LDAS_App/util/shared/matlab/pentad_of_year.m new file mode 100644 index 00000000..cc827841 --- /dev/null +++ b/src/Applications/LDAS_App/util/shared/matlab/pentad_of_year.m @@ -0,0 +1,14 @@ + +function pentad = pentad_of_year(day_of_year, year) + +if (is_leap_year(year) & day_of_year>=59) + + pentad = floor((day_of_year-2)/5)+1; + +else + + pentad = floor((day_of_year-1)/5)+1; + +end + +% ======================= EOF ================================== diff --git a/src/Applications/LDAS_App/util/shared/matlab/read_obsparam.m b/src/Applications/LDAS_App/util/shared/matlab/read_obsparam.m index 3c0447e1..19e66056 100644 --- a/src/Applications/LDAS_App/util/shared/matlab/read_obsparam.m +++ b/src/Applications/LDAS_App/util/shared/matlab/read_obsparam.m @@ -42,6 +42,8 @@ obs_param(i).units = fscanf(fid, '%s ', 1); obs_param(i).path = fscanf(fid, '%s ', 1); obs_param(i).name = fscanf(fid, '%s ', 1); + obs_param(i).maskpath = fscanf(fid, '%s ', 1); + obs_param(i).maskname = fscanf(fid, '%s ', 1); obs_param(i).scalepath = fscanf(fid, '%s ', 1); obs_param(i).scalename = fscanf(fid, '%s ', 1); obs_param(i).flistpath = fscanf(fid, '%s ', 1); @@ -59,9 +61,11 @@ obs_param(i).descr = obs_param(i).descr( 2:end-1); obs_param(i).FOV_units = obs_param(i).FOV_units(2:end-1); obs_param(i).varname = obs_param(i).varname( 2:end-1); + obs_param(i).units = obs_param(i).units( 2:end-1); obs_param(i).path = obs_param(i).path( 2:end-1); obs_param(i).name = obs_param(i).name( 2:end-1); - obs_param(i).units = obs_param(i).units( 2:end-1); + obs_param(i).maskpath = obs_param(i).maskpath( 2:end-1); + obs_param(i).maskname = obs_param(i).maskname( 2:end-1); obs_param(i).scalepath = obs_param(i).scalepath(2:end-1); obs_param(i).scalename = obs_param(i).scalename(2:end-1); obs_param(i).flistpath = obs_param(i).flistpath(2:end-1); diff --git a/src/Components/GEOSldas_GridComp/CMakeLists.txt b/src/Components/GEOSldas_GridComp/CMakeLists.txt index 05ddb49b..d6a7018a 100644 --- a/src/Components/GEOSldas_GridComp/CMakeLists.txt +++ b/src/Components/GEOSldas_GridComp/CMakeLists.txt @@ -12,6 +12,6 @@ set (alldirs esma_add_library(${this} SRCS GEOS_LdasGridComp.F90 SUBCOMPONENTS ${alldirs} - SUBDIRS Shared + SUBDIRS LDAS_Shared DEPENDENCIES GEOSland_GridComp makebcs MAPL INCLUDES ${INC_ESMF}) diff --git a/src/Components/GEOSldas_GridComp/GEOS_LdasGridComp.F90 b/src/Components/GEOSldas_GridComp/GEOS_LdasGridComp.F90 index a8ff3631..4c1b13ed 100644 --- a/src/Components/GEOSldas_GridComp/GEOS_LdasGridComp.F90 +++ b/src/Components/GEOSldas_GridComp/GEOS_LdasGridComp.F90 @@ -80,8 +80,6 @@ subroutine SetServices(gc, rc) integer :: i, k integer :: ens_id type(MAPL_MetaComp), pointer :: MAPL=>null() - type(ESMF_GridComp), pointer :: gcs(:)=>null() ! Children gridcomps - character(len=ESMF_MAXSTR), pointer :: gcnames(:)=>null() ! Children's names ! ErrLog variables integer :: status character(len=ESMF_MAXSTR) :: Iam @@ -400,7 +398,6 @@ subroutine Initialize(gc, import, export, clock, rc) logical :: IamRoot type(tile_coord_type), dimension(:), pointer :: tile_coord_f => null() - type(tile_coord_type), dimension(:), pointer :: tile_coord_l => null() integer,dimension(:),pointer :: f2g integer :: N_catf @@ -408,7 +405,7 @@ subroutine Initialize(gc, import, export, clock, rc) type(grid_def_type) :: tile_grid_g, pert_grid_g type(grid_def_type) :: tile_grid_f, pert_grid_f - type(grid_def_type) :: tile_grid_l, pert_grid_l + type(grid_def_type) :: pert_grid_l type(date_time_type):: start_time type(ESMF_Time) :: CurrentTime @@ -827,7 +824,6 @@ subroutine Run(gc, import, export, clock, rc) ! Misc variables integer :: igc,i, ens_id, FIRST_ENS_ID, ens_id_width logical :: IAmRoot - integer :: mpierr integer :: LSM_CHOICE type (ESMF_Field) :: field diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/CMakeLists.txt b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/CMakeLists.txt index dc2312bc..13ca535e 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/CMakeLists.txt +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/CMakeLists.txt @@ -16,7 +16,7 @@ find_package(HDF5 REQUIRED COMPONENTS Fortran) esma_add_library (${this} SRCS ${SRCS} SUBCOMPONENTS ${alldirs} - DEPENDENCIES GEOS_LdasShared GEOSens_GridComp GEOSlandpert_GridComp GEOSland_GridComp makebcs MAPL GMAO_gfio_r4 hdf5hl_fortran hdf5_fortran ${NETCDF_LIBRARIES} + DEPENDENCIES GEOS_LdasShared GEOSens_GridComp GEOSlandpert_GridComp GEOSland_GridComp makebcs MAPL NCEP_bufr_r4i4 GMAO_gfio_r4 hdf5hl_fortran hdf5_fortran ${NETCDF_LIBRARIES} INCLUDES ${INC_ESMF} ${INC_HDF5}) target_compile_definitions (${this} PRIVATE LDAS_MPI) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 index f13c1bfc..f24124fd 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 @@ -1,6 +1,7 @@ #include "MAPL_Generic.h" !============================================================================= + module GEOS_LandAssimGridCompMod !BOP @@ -51,6 +52,7 @@ module GEOS_LandAssimGridCompMod use catch_types, only: cat_progn_type use catch_types, only: cat_param_type use catch_types, only: cat_diagS_type + use catch_types, only: cat_diagS_max use catch_types, only: cat_diagS_sqrt use catch_types, only: assignment(=), operator (+), operator (-), operator (*), operator (/) use clsm_bias_routines, only: initialize_obs_bias @@ -61,7 +63,7 @@ module GEOS_LandAssimGridCompMod use clsm_ensupd_glob_param, only: echo_clsm_ensupd_glob_param use clsm_ensupd_enkf_update, only: get_enkf_increments use clsm_ensupd_enkf_update, only: apply_enkf_increments - use clsm_ensupd_enkf_update, only: output_incr_etc + use clsm_ensupd_enkf_update, only: output_ObsFcstAna_wrapper use clsm_ensupd_enkf_update, only: write_smapL4SMaup use clsm_ensdrv_out_routines, only: init_log, GEOS_output_smapL4SMlmc use clsm_ensdrv_drv_routines, only: recompute_diagS @@ -146,9 +148,8 @@ subroutine SetServices ( GC, RC ) ! Local Variables type(MAPL_MetaComp), pointer :: MAPL=>null() - type(ESMF_Config) :: CF character(len=ESMF_MAXSTR) :: LAND_ASSIM_STR, mwRTM_file - character(len=ESMF_MAXSTR) :: ensid_string,childname, fmt_str + character(len=ESMF_MAXSTR) :: ensid_string, childname integer :: i, ens_id_width, FIRST_ENS_ID, NUM_ENSEMBLE integer :: ens_id, export_id @@ -1111,7 +1112,7 @@ subroutine Initialize(gc, import, export, clock, rc) type(MAPL_MetaComp), pointer :: CHILD_MAPL=>null() ! Child's MAPL obj type(ESMF_GridComp), pointer :: gcs(:) - character(len=300) :: out_path,fname + character(len=300) :: out_path character(len=ESMF_MAXSTR) :: exp_id, GridName integer :: model_dtstep type(date_time_type) :: start_time @@ -1120,7 +1121,6 @@ subroutine Initialize(gc, import, export, clock, rc) type(T_TILECOORD_STATE), pointer :: tcinternal type(TILECOORD_WRAP) :: tcwrap - type(tile_coord_type), dimension(:), pointer :: tile_coord_f => null() type(tile_coord_type), dimension(:), pointer :: tile_coord_l => null() integer :: land_nt_local,i,mpierr, ens, ens_id_width @@ -1129,7 +1129,6 @@ subroutine Initialize(gc, import, export, clock, rc) integer, allocatable :: f2rf(:) ! mapping re-orderd rf to f for the LDASsa output character(len=300) :: seed_fname character(len=300) :: fname_tpl - character(len=14) :: datestamp character(len=ESMF_MAXSTR) :: ensid_string integer :: nymd, nhms, yy, mm, dd, h, m, s @@ -1464,7 +1463,7 @@ subroutine RUN ( GC, IMPORT, EXPORT, CLOCK, RC ) ! ! time ! - type(ESMF_Time) :: ModelTimeCur, ModelTimeNxt + type(ESMF_Time) :: ModelTimeCur type(ESMF_Alarm) :: LandAssimAlarm type(ESMF_TimeInterval) :: ModelTimeStep @@ -1484,8 +1483,6 @@ subroutine RUN ( GC, IMPORT, EXPORT, CLOCK, RC ) character(len=300) :: out_path character(len=ESMF_MAXSTR) :: exp_id - character(40) :: exp_domain - integer :: model_dtstep type(met_force_type), dimension(:), allocatable :: met_force @@ -1889,28 +1886,37 @@ subroutine RUN ( GC, IMPORT, EXPORT, CLOCK, RC ) ) _VERIFY(status) - ! mwRTM_param already contains static parameters, only need vegopacity. - - call get_vegopacity(MAPL, clock, N_catl, rc=status) - _VERIFY(STATUS) + if ( mwRTM ) then - ! Check no-data consistency of vegetation attenuation parameter values. - ! Good values are allowed for either the relevant static parameters - ! (bh, bv, lewt) or for the vegopacity values from the file, but not both. + ! mwRTM_param already contains static parameters, only need vegopacity. - do ii=1,N_catl - call mwRTM_param_nodata_check( mwRTM_param(ii) ) - end do + call get_vegopacity(MAPL, clock, N_catl, rc=status) + _VERIFY(STATUS) + ! Check no-data consistency of vegetation attenuation parameter values. + ! Good values are allowed for either the relevant static parameters + ! (bh, bv, lewt) or for the vegopacity values from the file, but not both. + + do ii=1,N_catl + call mwRTM_param_nodata_check( mwRTM_param(ii) ) + end do + + endif + + if(.not. allocated(mwRTM_param)) then + + allocate(mwRTM_param(0)) + + endif + call get_enkf_increments( & date_time_new, & NUM_ENSEMBLE, N_catl, N_catf, N_obsl_max, & - trim(out_path), trim(exp_id), exp_domain, & + trim(out_path), trim(exp_id), & met_force, lai, cat_param, mwRTM_param, & tile_coord_l, tile_coord_rf, & tcinternal%tgrid_g, tcinternal%pgrid_f, tcinternal%pgrid_g, & N_catl_vec, low_ind, l2rf, rf2l, & - N_force_pert, N_progn_pert, force_pert_param, progn_pert_param, & update_type, & LandAssimDTstep, & xcompact, ycompact, fcsterr_inflation_fac, & @@ -1941,15 +1947,15 @@ subroutine RUN ( GC, IMPORT, EXPORT, CLOCK, RC ) if (.true.) then ! replace obsolete check for analysis time with "if true" to keep indents - call output_incr_etc( out_ObsFcstAna, & - date_time_new, trim(out_path), trim(exp_id), & + call output_ObsFcstAna_wrapper( out_ObsFcstAna, & + date_time_new, trim(exp_id), & N_obsl, N_obs_param, NUM_ENSEMBLE, & N_catl, tile_coord_l, & - N_catf, tile_coord_rf, tcinternal%pgrid_f, tcinternal%pgrid_g, & - N_catl_vec, low_ind, rf2l, N_catg, rf2g, & + N_catf, tile_coord_rf, tcinternal%pgrid_g, & + N_catl_vec, low_ind, rf2l, & obs_param, & met_force, lai, & - cat_param, cat_progn, cat_progn_incr, mwRTM_param, & + cat_param, cat_progn, mwRTM_param, & Observations_l, rf2f=rf2f ) do ii = 1, N_catl @@ -2015,8 +2021,11 @@ subroutine RUN ( GC, IMPORT, EXPORT, CLOCK, RC ) cat_diagS_ensavg(ii) = cat_diagS_ensavg(ii)/real(NUM_ENSEMBLE) ! normalize --> ens avg - cat_diagS_ensstd(ii) = cat_diagS_sqrt( cat_diagS_ensstd(ii)/Nm1 - NdivNm1*(cat_diagS_ensavg(ii)*cat_diagS_ensavg(ii)) ) - + cat_diagS_ensstd(ii) = & + cat_diagS_sqrt( & + cat_diagS_max( 0., cat_diagS_ensstd(ii)/Nm1 - NdivNm1*(cat_diagS_ensavg(ii)*cat_diagS_ensavg(ii))) & + ) + end do else ! NUM_ENSEMBLE = 1 @@ -2058,9 +2067,9 @@ subroutine RUN ( GC, IMPORT, EXPORT, CLOCK, RC ) ! increments were computed) if (out_smapL4SMaup) & - call write_smapL4SMaup( 'analysis', date_time_new, trim(out_path), & + call write_smapL4SMaup( 'analysis', date_time_new, & trim(exp_id), NUM_ENSEMBLE, N_catl, N_catf, N_obsl, tile_coord_rf, & - tcinternal%tgrid_g, N_catl_vec, low_ind, & + tcinternal%tgrid_g, N_catl_vec, low_ind, & N_obs_param, obs_param, Observations_l, cat_param, cat_progn ) end if ! end if (.true.) @@ -2103,7 +2112,6 @@ subroutine UPDATE_ASSIM(gc, import, export, clock, rc) ! ESMF variables type(ESMF_Alarm) :: LandAssimAlarm - type(ESMF_VM) :: vm ! MAPL variables type(MAPL_MetaComp), pointer :: MAPL=>null() ! MAPL obj @@ -2268,25 +2276,6 @@ subroutine CALC_LAND_TB(gc, import, export, clock, rc) real, dimension(:), pointer :: WCSF real, dimension(:), pointer :: SWE - real, dimension(:), pointer :: VEGCLS - real, dimension(:), pointer :: SOILCLS - real, dimension(:), pointer :: SAND - real, dimension(:), pointer :: CLAY - real, dimension(:), pointer :: mw_POROS - real, dimension(:), pointer :: WANGWT - real, dimension(:), pointer :: WANGWP - real, dimension(:), pointer :: RGHHMIN - real, dimension(:), pointer :: RGHHMAX - real, dimension(:), pointer :: RGHWMAX - real, dimension(:), pointer :: RGHWMIN - real, dimension(:), pointer :: RGHNRH - real, dimension(:), pointer :: RGHNRV - real, dimension(:), pointer :: RGHPOLMIX - real, dimension(:), pointer :: OMEGA - real, dimension(:), pointer :: BH - real, dimension(:), pointer :: BV - real, dimension(:), pointer :: LEWT - ! export real, dimension(:), pointer :: TB_H_enavg real, dimension(:), pointer :: TB_V_enavg @@ -2298,7 +2287,7 @@ subroutine CALC_LAND_TB(gc, import, export, clock, rc) real, allocatable, dimension(:) :: Tb_h_tmp, TB_v_tmp - integer :: N_catl, n, mpierr + integer :: N_catl type(MAPL_LocStream) :: locstream call ESMF_GridCompGet ( GC, name=COMP_NAME, RC=STATUS ) @@ -2647,7 +2636,7 @@ subroutine read_pert_rseed(ensid_string,seed_fname,pert_rseed_r8) character(len=*),intent(in) :: seed_fname real(kind=ESMF_KIND_R8),intent(inout) :: pert_rseed_r8(:) - integer :: ncid, s_varid, en_dim, n_ens, id_varid, i, pos + integer :: ncid, s_varid logical :: file_exist character(len=ESMF_MAXSTR) :: tmpstr diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensdrv_drv_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensdrv_drv_routines.F90 index 3c1436a6..a5d417a6 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensdrv_drv_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensdrv_drv_routines.F90 @@ -68,13 +68,15 @@ module clsm_ensdrv_drv_routines ! ******************************************************************** - subroutine check_cat_progn( N_cat, cat_param, cat_progn ) + subroutine check_cat_progn( check_snow, N_cat, cat_param, cat_progn ) ! wrapper for subroutine check_catch_progn() which has been ! moved to "catch_iau.F90" in GEOScatch_GridComp - reichle, 3 Apr 2012 implicit none + logical, intent(in) :: check_snow + integer, intent(in) :: N_cat type(cat_param_type), dimension(N_cat), intent(in) :: cat_param @@ -124,7 +126,8 @@ subroutine check_cat_progn( N_cat, cat_param, cat_progn ) cat_progn%qa1, cat_progn%qa2, cat_progn%qa4, & cat_progn%capac, cat_progn%catdef, & cat_progn%rzexc, cat_progn%srfexc, & - ghtcnt, wesn, htsn, sndz ) + ghtcnt, wesn, htsn, sndz, & + check_snow=check_snow) ! copy 2-d arrays back into cat_progn fields diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 index 86d6449d..ea0be949 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_enkf_update.F90 @@ -16,7 +16,8 @@ module clsm_ensupd_enkf_update MAPL_TICE USE CATCH_CONSTANTS, ONLY : & - N_gt => CATCH_N_GT + N_gt => CATCH_N_GT, & + N_snow => CATCH_N_SNOW use catchment_model, ONLY: & catch_calc_tsurf @@ -110,6 +111,7 @@ module clsm_ensupd_enkf_update apply_adapt_R use LDAS_ensdrv_mpi, ONLY: & + MPI_met_force_type, & MPI_cat_param_type, & MPI_cat_progn_type, & root_proc, & @@ -132,7 +134,7 @@ module clsm_ensupd_enkf_update public :: get_enkf_increments public :: apply_enkf_increments - public :: output_incr_etc + public :: output_ObsFcstAna_wrapper public :: write_smapL4SMaup contains @@ -140,12 +142,11 @@ module clsm_ensupd_enkf_update subroutine get_enkf_increments( & date_time, & N_ens, N_catl, N_catf, N_obsl_max, & - work_path, exp_id, exp_domain, & + work_path, exp_id, & met_force, lai, cat_param, mwRTM_param, & tile_coord_l, tile_coord_f, & tile_grid_g, pert_grid_f, pert_grid_g, & N_catl_vec, low_ind, l2f, f2l, & - N_force_pert, N_progn_pert, force_pert_param, progn_pert_param, & update_type, & dtstep_assim, & xcompact, ycompact, fcsterr_inflation_fac, & @@ -177,7 +178,7 @@ subroutine get_enkf_increments( & integer, intent(in) :: N_obsl_max ! max number of observations allowed character(*), intent(in) :: work_path - character(*), intent(in) :: exp_id, exp_domain + character(*), intent(in) :: exp_id ! Meteorological forcings, Catchment model and microwave RTM parameters @@ -200,11 +201,6 @@ subroutine get_enkf_increments( & integer, intent(in), dimension(N_catf) :: f2l - integer, intent(in) :: N_force_pert, N_progn_pert - - type(pert_param_type), dimension(:), pointer :: force_pert_param ! input - type(pert_param_type), dimension(:), pointer :: progn_pert_param ! input - integer, intent(in) :: update_type, dtstep_assim real, intent(in) :: xcompact, ycompact, fcsterr_inflation_fac @@ -252,8 +248,6 @@ subroutine get_enkf_increments( & ! local variables - integer :: N_obslH - logical :: found_obs_f, assimflag type(obs_type), dimension(:), pointer :: Observations_lH => null() ! obs w/in halo @@ -300,14 +294,18 @@ subroutine get_enkf_increments( & integer :: nTiles_ana, nTilesAna_vec(numprocs) integer, dimension(:), allocatable :: indTiles_l, indTiles_f, indTiles_ana type(varLenIntArr) :: indTilesAna_vec(numprocs) + type(tile_coord_type), dimension(:), pointer :: tile_coord_ana ! input to cat_enkf_increment() is a pointer + + type(met_force_type), dimension(:), allocatable :: met_force_f, met_force_ana type(cat_param_type), dimension(:), allocatable :: cat_param_f, cat_param_ana + type(cat_progn_type), allocatable :: cat_progn_f(:), cat_progn_ana(:,:) type(cat_progn_type), allocatable :: tmp_cat_progn_ana(:) type(cat_progn_type), allocatable :: cat_progn_incr_f(:), cat_progn_incr_ana(:,:) type(cat_progn_type), allocatable :: recvBuf(:) - - ! Obs related + + ! obs related integer :: nObs_ana integer :: nObsAna_vec(numprocs) integer :: N_obsf_assim, N_obsl_assim @@ -328,8 +326,8 @@ subroutine get_enkf_increments( & character(12) :: tmpstr12 - character(len=*), parameter :: Iam = 'get_enkf_increments' - character(len=400) :: err_msg + character(len=*), parameter :: Iam = 'get_enkf_increments' + character(len=400) :: err_msg ! ********************************************************************** ! @@ -402,7 +400,7 @@ subroutine get_enkf_increments( & tile_coord_f%pert_i_indg, tile_coord_f%pert_j_indg, & pert_grid_f, maxval(N_tile_in_cell_ij_f), tile_num_in_cell_ij_f ) else - allocate(N_tile_in_cell_ij_f(0,0)) !for debugging + allocate(N_tile_in_cell_ij_f(0,0)) ! for debugging end if ! ********************************************************************* @@ -417,8 +415,8 @@ subroutine get_enkf_increments( & if (out_smapL4SMaup) & call output_smapL4SMaup( date_time, work_path, exp_id, dtstep_assim, & - N_ens, N_catl, N_catf, N_obsl, N_obsl_max, & - tile_coord_f, tile_coord_l, tile_grid_g, pert_grid_f, & + N_ens, N_catl, N_catf, N_obsl_max, & + tile_coord_f, tile_grid_g, pert_grid_f, & N_catl_vec, low_ind, l2f, N_tile_in_cell_ij_f, tile_num_in_cell_ij_f, & N_obs_param, obs_param, Observations_l, cat_param, cat_progn ) @@ -426,7 +424,7 @@ subroutine get_enkf_increments( & call collect_obs( & work_path, exp_id, date_time, dtstep_assim, & - N_catl, tile_coord_l, & + N_catl, & N_catf, tile_coord_f, pert_grid_f, & N_tile_in_cell_ij_f, tile_num_in_cell_ij_f, & N_catl_vec, low_ind, l2f, & @@ -435,7 +433,7 @@ subroutine get_enkf_increments( & ! -------------------------------------------------------------------- - + if (found_obs_f) then ! ++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -518,7 +516,6 @@ subroutine get_enkf_increments( & if (allocated(obsbias_ok)) deallocate(obsbias_ok) - ! IF NEEDED, INCLUDE WITHHOLDING SUBROUTINE HERE. ! SUCH A SUBROUTINE SHOULD CHANGE Observations(i)%assim TO FALSE ! IF THE OBSERVATION IS TO BE WITHHELD @@ -528,7 +525,7 @@ subroutine get_enkf_increments( & ! count observations across all processors that are left after ! model-based QC (done within get_obs_pred()) - + #ifdef LDAS_MPI call MPI_AllReduce( & @@ -613,7 +610,7 @@ subroutine get_enkf_increments( & ! them evenly among all procs, indTiles_ana. The corresponding ! numbers are nTiles_l, nTiles_f, nTiles_ana. Root needs ! nTilesAna_vec, indTilesAna_vec (list of nTiles_ana, - ! indTiles_ana on each proc) to distribute cat_param, cat_progn. + ! indTiles_ana on each proc) to distribute cat_param, cat_progn, etc. ! ! IMPORTANT: Regardless of update_type, obs from *all* species are ! considered (ie, N_select_species=0). This could result in @@ -646,7 +643,7 @@ subroutine get_enkf_increments( & !-AnaLoadBal-Prereq-starts-here- ! Step 1a: identify obs w/ obs%assim==.true. - allocate(ind_obsl_assim(N_obsl), source=-99) + allocate(ind_obsl_assim(N_obsl), source=-99) call get_ind_obs_assim(N_obsl, Observations_l%assim, N_obsl_assim, ind_obsl_assim) ! its easier to write ptr2indx than ind_obsl_assim(1:N_obsl_assim) ptr2indx => ind_obsl_assim(1:N_obsl_assim) @@ -704,7 +701,7 @@ subroutine get_enkf_increments( & if (root_proc) then allocate(indTiles_f(nTiles_f), source=-99) else - allocate(indTiles_f(0)) ! for debugging mode + allocate(indTiles_f(0)) ! for debugging mode endif if (root_proc) then @@ -742,7 +739,7 @@ subroutine get_enkf_increments( & if (allocated(indTiles_f)) deallocate(indTiles_f) ! Step 2d: indTiles_ana -> indTilesAna_vec (on root) - ! root needs indTiles_ana from each proc to distribute cat_param, cat_progn etc. + ! root needs indTiles_ana from each proc to distribute cat_param, cat_progn, etc. if (root_proc) then do iproc=1,numprocs allocate(indTilesAna_vec(iproc)%ind(nTilesAna_vec(iproc))) @@ -839,15 +836,44 @@ subroutine get_enkf_increments( & Obs_ana = Obs_f_assim(indObs_ana(1:nObs_ana)) if (allocated(Obs_f_assim)) deallocate(Obs_f_assim) - ! step 4b: tile_coord_ana + ! Step 4b: tile_coord_ana allocate(tile_coord_ana(nTiles_ana)) tile_coord_ana = tile_coord_f(indTiles_ana) - ! Step 4c: cat_param(N_catl) -> cat_param_f (on root) -> cat_param_ana + ! Step 4c: met_force(N_catl) -> met_force_f (on root) -> met_force_ana + if (root_proc) then + allocate(met_force_f(N_catf)) + else + allocate(met_force_f(0)) ! for debugging mode + endif + call MPI_Gatherv( & + met_force, N_catl, MPI_met_force_type, & + met_force_f, N_catl_vec, low_ind-1, MPI_met_force_type, & + 0, mpicomm, mpierr ) + allocate(met_force_ana(nTiles_ana)) + if (root_proc) then + met_force_ana = met_force_f(indTilesAna_vec(1)%ind) + do dest=1,numprocs-1 + sendtag = dest + sendct = nTilesAna_vec(dest+1) + call MPI_Send(met_force_f(indTilesAna_vec(dest+1)%ind), & + sendct,MPI_met_force_type, & + dest,sendtag,mpicomm,mpierr) + end do + else + ! source = 0 + recvtag = myid + recvct = nTiles_ana + call MPI_Recv(met_force_ana,recvct,MPI_met_force_type, & + 0,recvtag,mpicomm,mpistatus,mpierr) + end if + if (allocated(met_force_f)) deallocate(met_force_f) + + ! Step 4d: cat_param(N_catl) -> cat_param_f (on root) -> cat_param_ana if (root_proc) then allocate(cat_param_f(N_catf)) else - allocate(cat_param_f(0)) !for debugging mode + allocate(cat_param_f(0)) ! for debugging mode endif call MPI_Gatherv( & cat_param, N_catl, MPI_cat_param_type, & @@ -872,12 +898,12 @@ subroutine get_enkf_increments( & end if if (allocated(cat_param_f)) deallocate(cat_param_f) - ! Step 4d: cat_progn -> cat_progn_f (on root) -> cat_progn_ana + ! Step 4e: cat_progn -> cat_progn_f (on root) -> cat_progn_ana ! one ensemble at a time if (root_proc) then allocate(cat_progn_f(N_catf)) else - allocate(cat_progn_f(0)) ! for debugging mode + allocate(cat_progn_f(0)) ! for debugging mode endif allocate(cat_progn_ana(nTiles_ana,N_ens)) @@ -924,12 +950,12 @@ subroutine get_enkf_increments( & if (allocated( tmp_cat_progn_ana)) deallocate(tmp_cat_progn_ana) if (allocated(cat_progn_f)) deallocate(cat_progn_f) - ! Step 4e: Obs_pred_l (obs%assim=.true.) -> Obs_pred_f_assim (on root) -> Obs_pred_ana + ! Step 4f: Obs_pred_l (obs%assim=.true.) -> Obs_pred_f_assim (on root) -> Obs_pred_ana ! one ensemble at a time if (root_proc) then allocate(Obs_pred_f_assim(N_obsf_assim)) else - allocate(Obs_pred_f_assim(0)) ! for debugging mode + allocate(Obs_pred_f_assim(0)) ! for debugging mode endif allocate(Obs_pred_ana(nObs_ana,N_ens), source=0.) if (root_proc) then @@ -986,7 +1012,8 @@ subroutine get_enkf_increments( & ! of Observations_l and Obs_pred_l that are "good" ! [allocation of these arrays in get_obs_pred() is larger ! than eventual size] - call get_halo_obs( N_ens, N_catl, N_obsl, & + + call get_halo_obs( N_ens, N_obsl, & Observations_l(1:N_obsl), Obs_pred_l(1:N_obsl,1:N_ens), & tile_coord_l, xcompact, ycompact, & N_obslH, Observations_lH, Obs_pred_lH ) @@ -1050,6 +1077,7 @@ subroutine get_enkf_increments( & Obs_ana, & ! size: nObs_ana Obs_pred_ana, & ! size: (nObs_ana,N_ens) Obs_pert_tmp, & + met_force_ana, & cat_param_ana, & xcompact, ycompact, fcsterr_inflation_fac, & cat_progn_ana, cat_progn_incr_ana) @@ -1078,9 +1106,10 @@ subroutine get_enkf_increments( & Observations_lH(1:N_obslH), & Obs_pred_lH(1:N_obslH,1:N_ens), & Obs_pert_tmp, & + met_force, & cat_param, & xcompact, ycompact, fcsterr_inflation_fac, & - cat_progn, cat_progn_incr ) + cat_progn, cat_progn_incr, met_force ) #endif #ifdef LDAS_MPI @@ -1093,7 +1122,7 @@ subroutine get_enkf_increments( & allocate(cat_progn_incr_f(N_catf)) allocate(recvBuf(maxval(nTilesAna_vec))) ! temp storage of incoming data else - allocate(cat_progn_incr_f(0)) ! for debugging + allocate(cat_progn_incr_f(0)) ! for debugging end if do iEns=1,N_ens ! cat_progn_incr_ana -> cat_progn_incr_f @@ -1157,6 +1186,7 @@ subroutine get_enkf_increments( & if (allocated( indObs_ana)) deallocate(indObs_ana) if (allocated( cat_progn_ana)) deallocate(cat_progn_ana) if (allocated( cat_param_ana)) deallocate(cat_param_ana) + if (allocated( met_force_ana)) deallocate(met_force_ana) do iproc=1,numprocs if (allocated(indTilesAna_vec(iproc)%ind)) & deallocate(indTilesAna_vec(iproc)%ind) @@ -1195,7 +1225,7 @@ subroutine get_enkf_increments( & ! into SMAP L4_SM aup file if (out_smapL4SMaup) & - call write_smapL4SMaup( 'obs_fcst', date_time, work_path, exp_id, N_ens, & + call write_smapL4SMaup( 'obs_fcst', date_time, exp_id, N_ens, & N_catl, N_catf, N_obsl, tile_coord_f, tile_grid_g, N_catl_vec, low_ind, & N_obs_param, obs_param, Observations_l, cat_param, cat_progn ) @@ -1266,29 +1296,30 @@ subroutine apply_enkf_increments( N_catd, N_ens, update_type, & ! ----------------- - integer :: n, n_e + integer :: n, n_e, ii - logical :: cat_progn_has_changed + logical :: cat_progn_has_changed, check_snow character(len=*), parameter :: Iam = 'apply_enkf_increments' - character(len=400) :: err_msg ! ---------------------------------------------------------------- ! ! apply increments cat_progn_has_changed = .true. ! conservative initialization - + + check_snow = .true. ! conservative initialization + select_update_type: select case (update_type) - + case (1,2) select_update_type ! soil moisture update - + if (logit) write (logunit,*) & 'apply_enkf_increments(): applying soil moisture increments' - + do n=1,N_catd do n_e=1,N_ens - + cat_progn(n,n_e)%srfexc = & cat_progn(n,n_e)%srfexc + cat_progn_incr(n,n_e)%srfexc cat_progn(n,n_e)%rzexc = & @@ -1337,10 +1368,12 @@ subroutine apply_enkf_increments( N_catd, N_ens, update_type, & cat_progn_has_changed = .false. - case (6,8,9,10) select_update_type ! soil moisture and temperature update + case (6,8,9,10,13) select_update_type ! soil moisture and temperature update + + ! some of the increments fields below may be zero by design + ! (e.g., tc[X]=ght(1)=0 in update_type=13 when only sfmc or sfds obs are assimilated; + ! or catdef=0 in update_type 10 or 13 when tile has mineral soil) - ! for update_type 10, catdef increments may be zero by design - if (logit) write (logunit,*) & 'apply_enkf_increments(): applying soil moisture and Tskin/ght1 increments' @@ -1360,19 +1393,44 @@ subroutine apply_enkf_increments( N_catd, N_ens, update_type, & cat_progn(n,n_e)%tc2 + cat_progn_incr(n,n_e)%tc2 cat_progn(n,n_e)%tc4 = & cat_progn(n,n_e)%tc4 + cat_progn_incr(n,n_e)%tc4 - + cat_progn(n,n_e)%ght(1) = & cat_progn(n,n_e)%ght(1) + cat_progn_incr(n,n_e)%ght(1) - + end do end do cat_progn_has_changed = .true. + check_snow = .false. ! turn off for now to maintain 0-diff w/ SMAP Tb DA test case + + case(11) select_update_type ! empirical MODIS SCF update + + do n=1,N_catd ! for each tile + + do n_e=1,N_ens ! for each ensemble member + + do ii=1,N_snow ! for each snow layer + + cat_progn(n,n_e)%wesn(ii) = & + cat_progn(n,n_e)%wesn(ii) + cat_progn_incr(n,n_e)%wesn(ii) + + cat_progn(n,n_e)%sndz(ii) = & + cat_progn(n,n_e)%sndz(ii) + cat_progn_incr(n,n_e)%sndz(ii) + + cat_progn(n,n_e)%htsn(ii) = & + cat_progn(n,n_e)%htsn(ii) + cat_progn_incr(n,n_e)%htsn(ii) + + end do + end do + end do + + cat_progn_has_changed = .true. + case default call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'unknown update_type') - + end select select_update_type ! ------------------------------------------------------------------ @@ -1383,7 +1441,7 @@ subroutine apply_enkf_increments( N_catd, N_ens, update_type, & do n_e=1,N_ens - call check_cat_progn( N_catd, cat_param, cat_progn(:,n_e) ) + call check_cat_progn( check_snow, N_catd, cat_param, cat_progn(:,n_e) ) end do @@ -1393,8 +1451,8 @@ end subroutine apply_enkf_increments ! ******************************************************************** - subroutine output_ObsFcstAna(date_time, work_path, exp_id, & - N_obsl, Observations_l, N_obs_param, obs_param, rf2f) + subroutine output_ObsFcstAna(date_time, exp_id, & + N_obsl, Observations_l, N_obs_param, rf2f) ! obs space output: observations, obs space forecast, obs space analysis, and ! associated error variances @@ -1402,35 +1460,34 @@ subroutine output_ObsFcstAna(date_time, work_path, exp_id, & ! - reichle, 16 Jun 2011 implicit none + + type(date_time_type), intent(in) :: date_time + + character(*), intent(in) :: exp_id - character(*), intent(in) :: work_path - character(*), intent(in) :: exp_id - - integer, intent(in) :: N_obsl, N_obs_param + integer, intent(in) :: N_obsl, N_obs_param - type(date_time_type), intent(in) :: date_time type(obs_type), dimension(N_obsl), intent(in) :: Observations_l - type(obs_param_type), dimension(N_obs_param), intent(in) :: obs_param - integer, dimension(:), optional, intent(in) :: rf2f + integer, dimension(:), optional, intent(in) :: rf2f ! --------------------- ! locals - character(40), parameter :: file_tag = 'ldas_ObsFcstAna' - character(40), parameter :: dir_name = 'ana' + character(40), parameter :: file_tag = 'ldas_ObsFcstAna' + character(40), parameter :: dir_name = 'ana' type(obs_type), dimension(:), allocatable :: Observations_f, Observations_tmp integer :: n, N_obsf - integer, dimension(:), allocatable :: rf_tilenums, tilenums + integer, dimension(:), allocatable :: rf_tilenums, tilenums integer, dimension(numprocs) :: N_obsl_vec, tmp_low_ind character(300) :: fname - integer :: i + #ifdef LDAS_MPI integer :: this_species, ind_tmp, j @@ -1441,8 +1498,6 @@ subroutine output_ObsFcstAna(date_time, work_path, exp_id, & #endif - - ! -------------------------------------------------------------------- if (logit) write (logunit,*) 'writing ' // trim(file_tag) //' file' @@ -1622,14 +1677,14 @@ end subroutine output_ObsFcstAna ! ********************************************************************** - subroutine output_incr_etc( out_ObsFcstAna, & - date_time, work_path, exp_id, & + subroutine output_ObsFcstAna_wrapper( out_ObsFcstAna, & + date_time, exp_id, & N_obsl, N_obs_param, N_ens, & N_catl, tile_coord_l, & - N_catf, tile_coord_f, pert_grid_f, pert_grid_g, & - N_catl_vec, low_ind, f2l, N_catg, f2g, & + N_catf, tile_coord_f, pert_grid_g, & + N_catl_vec, low_ind, f2l, & obs_param, & - met_force, lai, cat_param, cat_progn, cat_progn_incr, mwRTM_param, & + met_force, lai, cat_param, cat_progn, mwRTM_param, & Observations_l, rf2f ) implicit none @@ -1646,23 +1701,19 @@ subroutine output_incr_etc( out_ObsFcstAna, & type(date_time_type), intent(in) :: date_time - character(len=*), intent(in) :: work_path character(len=*), intent(in) :: exp_id - integer, intent(in) :: N_obsl, N_obs_param, N_ens, N_catl, N_catf, N_catg + integer, intent(in) :: N_obsl, N_obs_param, N_ens, N_catl, N_catf type(tile_coord_type), dimension(:), pointer :: tile_coord_l ! input type(tile_coord_type), dimension(:), pointer :: tile_coord_f ! input - type(grid_def_type), intent(in) :: pert_grid_f type(grid_def_type), intent(in) :: pert_grid_g integer, dimension(numprocs), intent(in) :: N_catl_vec, low_ind integer, dimension(N_catf), intent(in) :: f2l - integer, dimension(N_catf), intent(in) :: f2g - type(obs_param_type), dimension(N_obs_param), intent(in) :: & obs_param @@ -1672,7 +1723,6 @@ subroutine output_incr_etc( out_ObsFcstAna, & type(cat_param_type), dimension(N_catl), intent(in) :: cat_param type(cat_progn_type), dimension(N_catl,N_ens), intent(in) :: cat_progn - type(cat_progn_type), dimension(N_catl,N_ens), intent(in) :: cat_progn_incr type(mwRTM_param_type), dimension(N_catl), intent(in) :: mwRTM_param @@ -1685,19 +1735,10 @@ subroutine output_incr_etc( out_ObsFcstAna, & real, dimension(:,:), pointer :: Obs_pred_l => null() - integer :: i, n_e, N_obsl_tmp - - type(cat_progn_type), dimension(N_catl) :: cat_progn_incr_ensavg - - type(cat_progn_type), dimension(:), allocatable :: cat_progn_incr_f - type(cat_progn_type), dimension(:), allocatable :: cat_progn_incr_tmp + integer :: N_obsl_tmp - type(cat_progn_type), dimension(:), allocatable :: cat_progn_incr_g - character(40) :: file_tag, dir_name - - character(len=*), parameter :: Iam = 'output_incr_etc' - character(len=400) :: err_msg + character(len=*), parameter :: Iam = 'output_ObsFcstAna_wrapper' ! -------------------------------------------------------------- @@ -1727,111 +1768,18 @@ subroutine output_incr_etc( out_ObsFcstAna, & ! write out model, observations, and "OminusA" information - call output_ObsFcstAna( date_time, work_path, exp_id, N_obsl, & - Observations_l(1:N_obsl), N_obs_param, obs_param, rf2f=rf2f ) + call output_ObsFcstAna( date_time, exp_id, N_obsl, & + Observations_l(1:N_obsl), N_obs_param, rf2f=rf2f ) end if - ! ---------------------------------------------------------------- - - ! output ens avg increments - -!! if (out_incr) then -!! -!! ! compute increments for local domain -!! -!! do i=1,N_catl -!! cat_progn_incr_ensavg(i) = 0. -!! do n_e=1,N_ens -!! cat_progn_incr_ensavg(i) = cat_progn_incr_ensavg(i) & -!! + cat_progn_incr(i,n_e) -!! end do -!! cat_progn_incr_ensavg(i) = cat_progn_incr_ensavg(i)/real(N_ens) -!! end do -!! -!! -!! ! gather and write to file -!! -!! file_tag = 'ldas_incr' -!! dir_name = 'ana' -!! -!! if (root_proc) allocate(cat_progn_incr_f(N_catf)) -!! -!!#ifdef LDAS_MPI -!! -!! call MPI_GATHERV( & -!! cat_progn_incr_ensavg, N_catl, MPI_cat_progn_type, & -!! cat_progn_incr_f, N_catl_vec, low_ind-1, MPI_cat_progn_type, & -!! 0, mpicomm, mpierr ) -!! -!!#else -!! cat_progn_incr_f = cat_progn_incr_ensavg -!!#endif -!! if (root_proc) then -!! -!! -!! select case (out_incr_format) -!! -!! case (0) -!! -!! ! output increments in LDASsa domain and in LDASsa tile order (standard LDASsa) -!! if(present(rf2f)) then -!! allocate(cat_progn_incr_tmp(N_catf)) -!! cat_progn_incr_tmp(:) = cat_progn_incr_f(rf2f(:)) -!! cat_progn_incr_f = cat_progn_incr_tmp -!! deallocate(cat_progn_incr_tmp) -!! endif -!! -!! call io_rstrt( 'w', work_path, exp_id, -1, date_time, & -!! N_catf, cat_progn_incr_f, file_tag, dir_name=dir_name) -!! -!! case (1) -!! -!! ! output increments on global domain in GEOS-5 global tile order -!! ! suitable for reading into GEOS-5 GCM as land incremental analysis -!! ! update (LIAU) -!! -!! allocate(cat_progn_incr_g(N_catg)) -!! -!! ! initialize -!! -!! do i=1,N_catg -!! cat_progn_incr_g(i) = 0.0 -!! end do -!! -!! ! reorder increments to GEOS-5 gcm global tile order -!! -!! do i=1,N_catf -!! cat_progn_incr_g(f2g(i)) = cat_progn_incr_f(i) -!! end do -!! -!! file_tag = trim(file_tag) // 'LIAU' -!! -!! call io_rstrt( 'w', work_path, exp_id, -1, date_time, & -!! N_catg, cat_progn_incr_g, file_tag, dir_name=dir_name, & -!! is_little_endian=.true. ) -!! -!! deallocate(cat_progn_incr_g) -!! -!! case default -!! -!! call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'unknown out_incr_format') -!! -!! end select -!! -!! deallocate(cat_progn_incr_f) -!! -!! end if ! root_proc -!! -!! end if ! out_incr - - end subroutine output_incr_etc + end subroutine output_ObsFcstAna_wrapper ! ********************************************************************** subroutine output_smapL4SMaup( date_time, work_path, exp_id, dtstep_assim, & - N_ens, N_catl, N_catf, N_obsl, N_obsl_max, & - tile_coord_f, tile_coord_l, tile_grid_g, pert_grid_f, & + N_ens, N_catl, N_catf, N_obsl_max, & + tile_coord_f, tile_grid_g, pert_grid_f, & N_catl_vec, low_ind, l2f, N_tile_in_cell_ij_f, tile_num_in_cell_ij_f, & N_obs_param, obs_param, Observations_l, cat_param, cat_progn ) @@ -1855,10 +1803,9 @@ subroutine output_smapL4SMaup( date_time, work_path, exp_id, dtstep_assim, & integer, intent(in) :: dtstep_assim integer, intent(in) :: N_ens, N_catl, N_catf - integer, intent(in) :: N_obsl, N_obsl_max, N_obs_param + integer, intent(in) :: N_obsl_max, N_obs_param type(tile_coord_type), dimension(:), pointer :: tile_coord_f ! input - type(tile_coord_type), dimension(:), pointer :: tile_coord_l ! input type(grid_def_type), intent(in) :: tile_grid_g type(grid_def_type), intent(in) :: pert_grid_f @@ -1935,7 +1882,7 @@ subroutine output_smapL4SMaup( date_time, work_path, exp_id, dtstep_assim, & call collect_obs( & work_path, exp_id, date_time, dtstep_assim, & - N_catl, tile_coord_l, & + N_catl, & N_catf, tile_coord_f, pert_grid_f, & N_tile_in_cell_ij_f, tile_num_in_cell_ij_f, & N_catl_vec, low_ind, l2f, & @@ -1944,7 +1891,7 @@ subroutine output_smapL4SMaup( date_time, work_path, exp_id, dtstep_assim, & ! write appropriate fields (according to 'option') into file - call write_smapL4SMaup( 'orig_obs', date_time, work_path, exp_id, N_ens, & + call write_smapL4SMaup( 'orig_obs', date_time, exp_id, N_ens, & N_catl, N_catf, N_obsl_tmp, tile_coord_f, tile_grid_g, & N_catl_vec, low_ind, & N_obs_param_tmp, obs_param_tmp(1:N_obs_param_tmp), Observations_l, & @@ -1954,7 +1901,7 @@ end subroutine output_smapL4SMaup ! ********************************************************************** - subroutine write_smapL4SMaup( option, date_time, work_path, exp_id, N_ens, & + subroutine write_smapL4SMaup( option, date_time, exp_id, N_ens, & N_catl, N_catf, N_obsl, tile_coord_f, tile_grid_g, N_catl_vec, low_ind, & N_obs_param, obs_param, Observations_l, cat_param, cat_progn ) @@ -2026,7 +1973,6 @@ subroutine write_smapL4SMaup( option, date_time, work_path, exp_id, N_ens, & type(date_time_type), intent(in) :: date_time - character(*), intent(in) :: work_path character(*), intent(in) :: exp_id integer, intent(in) :: N_ens, N_catl, N_catf diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 index d3cdcf16..678a0978 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_glob_param.F90 @@ -36,15 +36,19 @@ module clsm_ensupd_glob_param public :: FT_ANA_LOWERBOUND_ASNOW public :: FT_ANA_LOWERBOUND_TEFF public :: FT_ANA_UPPERBOUND_TEFF + public :: SCF_ANA_ALPHA + public :: SCF_ANA_BETA + public :: SCF_ANA_MAXINCRSWE + public :: SCF_ANA_MINFCSTSWE public :: echo_clsm_ensupd_glob_param ! ----------------------------------------------------------------------- ! - ! total number of all obs species defined in namelist file + ! total number of all obs species defined in "ensupd" namelist file ! (regardless of whether "assim" flag is true or false) - integer, parameter :: N_obs_species_nml = 48 + integer, parameter :: N_obs_species_nml = 53 ! ---------------------------------------------------------------------- ! @@ -93,7 +97,7 @@ module clsm_ensupd_glob_param ! ---------------------------------------------------------------- ! - ! parameter for freeze/thaw (FT) analysis + ! parameters for freeze/thaw (FT) analysis real, parameter :: FT_ANA_FT_THRESHOLD = 0.5 @@ -103,6 +107,15 @@ module clsm_ensupd_glob_param real, parameter :: FT_ANA_UPPERBOUND_TEFF = +1.0 + MAPL_TICE ! [Kelvin] ! ---------------------------------------------------------------- + ! + ! parameters for snow cover area fraction (SCF) analysis (modified from Toure et al. 2018) + + real, parameter :: SCF_ANA_ALPHA = 0.60 ! [-] add snow if asnow_fcst < asnow_obs*SCF_ANA_alpha (w/ "bias" adjustment for obs) + real, parameter :: SCF_ANA_BETA = 0.55 ! [-] remove snow if asnow_fcst >= asnow_obs*SCF_ANA_alpha .AND. asnow_obs < SCF_ANA_beta + real, parameter :: SCF_ANA_MAXINCRSWE = 5.0 ! [kg/m2] max total SWE increment + real, parameter :: SCF_ANA_MINFCSTSWE = 0.01 ! [kg/m2] threshold below which the ratio of swe_ana/swe_fcst becomes unreasonable + + ! ---------------------------------------------------------------- contains diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 index 5937a6e0..e87b3df4 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_read_obs.F90 @@ -2,10 +2,11 @@ ! this file contains subroutines for reading and processing observations ! for the GEOS5 land EnKF update algorithm ! -! reichle, 27 Jan 2005 -! reichle, 10 Jan 2011 - replaced "UVA" with "LPRM" -! reichle, 1 Jul 2015 - clarified definition of obs time stamp +! reichle, 27 Jan 2005 +! reichle, 10 Jan 2011 - replaced "UVA" with "LPRM" +! reichle, 1 Jul 2015 - clarified definition of obs time stamp ! (J2000 seconds w/ 'TT12' epoch) +! lcandre2, 10 Jul 2021 - confirmed and cleaned up MODIS obs ! added work_path to inputs of many subroutines so that "tmpfname" ! (needed several times for reading AMSR-E hdf files) is distinct for each job @@ -15,6 +16,9 @@ module clsm_ensupd_read_obs + use MAPL_BaseMod, ONLY: & + MAPL_UNDEF + use MAPL_ConstantsMod, ONLY: & MAPL_TICE @@ -83,12 +87,12 @@ module clsm_ensupd_read_obs public :: collect_obs contains - - ! ***************************************************************** - + + ! ***************************************************************** + subroutine read_ae_l2_sm_hdf( & N_files, fnames, N_data, lon, lat, ae_l2_sm, ease_col, ease_row ) - + ! read soil moisture data from one or more AMSR-E Land hdf files ! ! return ONLY valid data points (ie. excluding no-data-values) @@ -194,7 +198,7 @@ subroutine read_ae_l2_sm_hdf( & do j=1,N_files ! open and "start" hdf file - + file_id(j) = hopen( fnames(j), DFACC_READ, num_dds_block ) status = vfstart(file_id(j)) @@ -496,7 +500,6 @@ subroutine read_obs_ae_l2_sm( & integer, dimension(N_catd) :: N_obs_in_tile character(len=*), parameter :: Iam = 'read_obs_ae_l2_sm' - character(len=400) :: err_msg ! ------------------------------------------------------------------- @@ -1009,7 +1012,6 @@ subroutine read_obs_ae_sm_LPRM( & integer, dimension(N_catd) :: N_obs_in_tile character(len=*), parameter :: Iam = 'read_obs_ae_sm_LPRM' - character(len=400) :: err_msg ! ------------------------------------------------------------------- @@ -1320,7 +1322,6 @@ subroutine read_obs_sm_ASCAT( & real, parameter :: tol = 1e-2 character(len=*), parameter :: Iam = 'read_obs_sm_ASCAT' - character(len=400) :: err_msg ! ------------------------------------------------------------------- @@ -1431,7 +1432,7 @@ subroutine read_obs_sm_ASCAT( & if (N_files>0) then call read_sm_ASCAT_bin( & - this_obs_param, N_files, fnames, & + N_files, fnames, & N_tmp, tmp_lon, tmp_lat, tmp_obs ) if (logit) then @@ -1548,395 +1549,445 @@ subroutine read_obs_sm_ASCAT( & if (associated(tmp_lat)) deallocate(tmp_lat) end subroutine read_obs_sm_ASCAT + + ! **************************************************************************** - ! *************************************************************************** - - subroutine read_sm_ASCAT_bin( & - this_obs_param, N_files, fnames, N_data, lon, lat, sm_ASCAT, ease_col, ease_row ) + subroutine read_obs_sm_ASCAT_EUMET( & + date_time, dtstep_assim, N_catd, tile_coord, & + tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & + this_obs_param, & + found_obs, ASCAT_sm, ASCAT_sm_std, ASCAT_lon, ASCAT_lat, ASCAT_time ) - ! read soil moisture data from one or more ASCAT bin files - ! - ! return ONLY valid data points (ie. excluding no-data-values) + !--------------------------------------------------------------------- ! - ! no QC in addition to what was done in matlab-preprocessing + ! Routine to read in ASCAT surface degree of saturation (sfds) obs from + ! BUFR files for both ascending and descending passes. ! - ! DRAPER, May 2011 - ! based on read_ae_sm_LPRM_bin + ! ASCAT_sm and ASCAT_sm_std outputs from this subroutine are in wetness fraction (i.e., 0-1) units! ! - ! DRAPER, July 2012 - ! updated, for inclusion of SDS error in ASCAT file - ! (error info currently not saved) - + ! Read in EUMETSAT level 2 soil moisture product 25 km (SMO), PPF software version 5.0. + ! Soil moisture derived from re-sampled (spatially averaged) backscatter (sigma0) values + ! on a 25-km orbit swath grid. Input data files are in BUFR file format. + ! + ! EUMETSAT BUFR files contain data for both ascending and descending half-orbits. + ! The BUFR field DOMO ("Direction of motion of moving observing platform") could be used to + ! separate Asc and Desc. (The BUFR files do not contain any explicit orbit indicator variable.) + ! According to Pamela Schoebel-Pattiselanno, EUMETSAT User Services Helpdesk: + ! "When the value (of DOMO) is between 180 and 270 degrees, it is the descending part + ! of the orbit. When it is between 270 and 360 degrees, it is the ascending part." + ! + ! Q. Liu, Nov 2019 - based on read_obs_sm_ASCAT + ! A. Fox, reichle, Sep 2023 - updated + ! A. Fox, reichle, Feb 2024 - added ASCAT obs mask + ! + ! -------------------------------------------------------------------- + + use netcdf implicit none - type(obs_param_type), intent(in) :: this_obs_param + ! inputs: - integer, intent(in) :: N_files + type(date_time_type), intent(in) :: date_time - character(*), dimension(N_files), intent(in) :: fnames + integer, intent(in) :: dtstep_assim, N_catd - integer, intent(out) :: N_data + type(tile_coord_type), dimension(:), pointer :: tile_coord ! input - real, dimension(:), pointer :: lon, lat, sm_ASCAT ! output + type(grid_def_type), intent(in) :: tile_grid_d - integer, dimension(:), pointer, optional :: ease_col, ease_row ! output + integer, dimension(tile_grid_d%N_lon,tile_grid_d%N_lat), intent(in) :: & + N_tile_in_cell_ij - ! local variables + integer, dimension(:,:,:), pointer :: tile_num_in_cell_ij ! input - logical :: must_stop + type(obs_param_type), intent(in) :: this_obs_param - integer, dimension(N_files) :: N_data_tmp + ! outputs: + + logical, intent(out) :: found_obs + + real, intent(out), dimension(N_catd) :: ASCAT_sm ! sfds obs [fraction] (i.e., 0-1) + real, intent(out), dimension(N_catd) :: ASCAT_sm_std ! sfds obs err std [fraction] (i.e., 0-1) + real, intent(out), dimension(N_catd) :: ASCAT_lon, ASCAT_lat + real*8, intent(out), dimension(N_catd) :: ASCAT_time ! J2000 seconds - integer :: i, j, k_off + ! --------------- - integer, dimension(:), allocatable :: tmpintvec - real, dimension(:), allocatable :: tmprealvec + ! Each obs file contains ~100-110 minutes (1 full orbit?) of observations (dt_ASCAT_obsfile). + ! File name indicates start time of swath. - character(len=*), parameter :: Iam = 'read_sm_ASCAT_bin' - character(len=400) :: err_msg + integer, parameter :: dt_ASCAT_obsfile = 110*60 ! seconds + + integer, parameter :: N_fnames_max = 15 ! max number of files per day - ! ------------------------------------------------------------- + character(4), parameter :: J2000_epoch_id = 'TT12' ! see date_time_util.F90 - ! make sure pointers are not allocated or associated + character( 15) :: str_date_time + character( 80) :: fname_of_fname_list + character(300) :: tmpfname + + type(date_time_type) :: date_time_tmp + type(date_time_type) :: date_time_low, date_time_low_fname + type(date_time_type) :: date_time_up - must_stop = .false. + integer :: ii, ind, N_tmp, N_files, kk, N_obs, N_fnames, N_fnames_tmp, obs_dir_hier - if ( associated(lon) .or. associated(lat) .or. associated(sm_ASCAT) ) then - must_stop = .true. - end if + character(300), dimension(:), allocatable :: fnames, tmpfnames - if ( present(ease_col) ) then - if (associated(ease_col)) must_stop = .true. - end if + ! -------------------- + ! + ! variables for BUFR read + + real*8, dimension(14) :: tmp_vdata + + integer, parameter :: lnbufr = 50 ! BUFR file unit number + integer, parameter :: max_rec = 50000 ! max number of obs after QC (expecting < 6 hr assim window) + integer, parameter :: max_obs = 250000 ! max number of obs read by subroutine (expecting < 6 hr assim window) + + integer :: idate, iret, ireadmg, ireadsb + + character(8) :: subset + + ! -------------------- + ! + ! variables for obs mask read + + integer(kind=1), dimension(:,:), allocatable :: mask_data - if ( present(ease_row) ) then - if (associated(ease_row)) must_stop = .true. - end if + real :: mask_ll_lon, mask_ll_lat, mask_dlon, mask_dlat - if (must_stop) then - err_msg = 'output pointers must not be ' // & - 'associated or allocated on input.' - call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) - end if + integer :: ncid, ierr + integer :: mask_N_lon, mask_N_lat, mask_lon_ind, mask_lat_ind + integer :: lon_dimid, lat_dimid + integer :: mask_varid, ll_lon_varid, ll_lat_varid, dlon_varid, dlat_varid + character(300) :: mask_filename + + logical :: file_exists + + ! -------------------- + + character(100), dimension(2*N_fnames_max) :: fname_list ! max 2 days of files + + real, dimension(:), allocatable :: tmp1_obs, tmp1_lat, tmp1_lon + real*8, dimension(:), allocatable :: tmp1_jtime + real*8, dimension(:,:), allocatable :: tmp_data + + real, dimension(:), pointer :: tmp_obs, tmp_lat, tmp_lon + real*8, dimension(:), pointer :: tmp_jtime + + integer, dimension(:), pointer :: tmp_tile_num + + integer, dimension(N_catd) :: N_obs_in_tile + + character(len=*), parameter :: Iam = 'read_obs_sm_ASCAT_EUMET' + character(len=400) :: err_msg + + ! ------------------------------------------------------------------- - !write (logunit,*) 'read_ae_sm_LPRM_bin(): output pointers must not be ' // & - ! 'associated or allocated on input. STOPPING.' - !stop - ! - !end if + nullify( tmp_obs, tmp_lat, tmp_lon, tmp_tile_num, tmp_jtime ) - ! determine number of data to be read from each file + ! --------------- - N_data = 0 + ! initialize - do j=1,N_files - - ! open file - - open( 10, file=trim(fnames(j)), form='unformatted',convert='big_endian', action='read' ) - - read( 10) N_data_tmp(j) - - close(10, status='keep') - - end do + found_obs = .false. - ! allocate pointers (must be deallocated outside this subroutine!) + ! find files that are within half-open interval + ! (date_time-dtstep_assim/2,date_time+dtstep_assim/2] + + date_time_low = date_time + call augment_date_time( -(dtstep_assim/2), date_time_low) + date_time_up = date_time + call augment_date_time( (dtstep_assim/2), date_time_up) - N_data = sum(N_data_tmp) + ! calculate "extra" date_time_low to catch files w/ swath start time stamps before window + ! but containing relevant obs - allocate(lon( N_data)) - allocate(lat( N_data)) - allocate(sm_ASCAT(N_data)) + date_time_low_fname = date_time_low + call augment_date_time( -dt_ASCAT_obsfile, date_time_low_fname) - if (present(ease_col)) allocate(ease_col(N_data)) - if (present(ease_row)) allocate(ease_row(N_data)) + ! ---------------------------------------------------------------- + ! + ! read file with list of ASCAT file names for first day - ! read data into arrays, concatenate data from N_files files + fname_of_fname_list = 'dummy' ! make sure it is properly defined in obs_param nml + + obs_dir_hier = 1 - ! format of AMSR_sm_LPRM_EASE_bin files: - ! - ! record 1 -- N_data int*4 - ! record 2 -- lon( 1:N_data) real*4 - ! record 3 -- lat( 1:N_data) real*4 - ! record 4 -- sds( 1:N_data) real*4 - ! record 5 -- sds_noise (1:N_data) real*4 - ! record 6 -- ind_i(1:N_data) int*4 zero-based (!) EASE row index - ! record 7 -- ind_j(1:N_data) int*4 zero-based (!) EASE col index - - k_off = 0 + call read_obs_fnames( date_time_low_fname, this_obs_param, & + fname_of_fname_list, N_fnames_max, & + N_fnames, fname_list(1:N_fnames_max), obs_dir_hier ) - do j=1,N_files - - allocate(tmprealvec(N_data_tmp(j))) - - if (present(ease_col)) allocate(tmpintvec(N_data_tmp(j))) - - open (10, file=trim(fnames(j)), form='unformatted', convert='big_endian', action='read' ) - - ! re-read N_data - - read (10) N_data_tmp(j) - - ! read data as needed - - read (10) tmprealvec; lon(k_off+1:k_off+N_data_tmp(j)) = tmprealvec - read (10) tmprealvec; lat(k_off+1:k_off+N_data_tmp(j)) = tmprealvec + ! if needed, read file with list of ASCAT file names for second day and add + ! file names into "fname_list" + + if (date_time_low_fname%day /= date_time_up%day) then - read (10) tmprealvec; sm_ASCAT(k_off+1:k_off+N_data_tmp(j)) = tmprealvec + call read_obs_fnames( date_time_up, this_obs_param, & + fname_of_fname_list, N_fnames_max, & + N_fnames_tmp, fname_list((N_fnames+1):(N_fnames+N_fnames_max)), obs_dir_hier ) - ! skip record with error + N_fnames = N_fnames + N_fnames_tmp - read (10) ! tmprealvec; er_ASCAT(k_off+1:k_off+N_data_tmp(j)) = tmprealvec + end if + + tmpfnames = fname_list(1:N_fnames) + + ! ---------------------------------------------------------------- + ! + ! find files that have obs within assimilation window + + N_tmp = 0 + + do kk = 1,N_fnames + + tmpfname = fname_list(kk) + + ! Are we in the required assimilation window? + ! + ! e.g. Y2019/M07/M01-ASCA-ASCSMO02-NA-5.0-20190702075700.000000000Z-20190702084627-1350204.bfr + ! + ! 12345678901234567890123456789012345678901234567890123456789012345678901234567890 + ! 1 2 3 4 5 6 7 + + str_date_time = tmpfname(36:49) + + read(str_date_time( 1: 4), *) date_time_tmp%year + read(str_date_time( 5: 6), *) date_time_tmp%month + read(str_date_time( 7: 8), *) date_time_tmp%day + read(str_date_time( 9:10), *) date_time_tmp%hour + read(str_date_time(11:12), *) date_time_tmp%min + read(str_date_time(13:14), *) date_time_tmp%sec - if (present(ease_col) .and. present(ease_row)) then - - read (10) tmpintvec; ease_col(k_off+1:k_off+N_data_tmp(j)) = tmpintvec - read (10) tmpintvec; ease_row(k_off+1:k_off+N_data_tmp(j)) = tmpintvec + if ( datetime_lt_refdatetime( date_time_low_fname, date_time_tmp ) .and. & + datetime_le_refdatetime( date_time_tmp, date_time_up ) ) then + + N_tmp = N_tmp + 1 + + tmpfnames(N_tmp) = trim(this_obs_param%path) // '/' // trim(tmpfname) end if - ! clean up - - close(10, status='keep') - - deallocate(tmprealvec) - if (allocated(tmpintvec)) deallocate(tmpintvec) - - ! prepare next j - - k_off = k_off + N_data_tmp(j) - end do - ! ------------------------------------- - ! - ! eliminate no-data-values + fnames = tmpfnames(1:N_tmp) + N_files = N_tmp - j = 0 + ! ---------------------------------------------------------------- + ! + ! loop through files and read obs + metadata into tmp_data - do i=1,N_data + if (N_files>0) then + + ! read and process data if files are found + + allocate(tmp1_lon( max_rec )) + allocate(tmp1_lat( max_rec )) + allocate(tmp1_obs( max_rec )) + allocate(tmp1_jtime(max_rec )) - if (sm_ASCAT(i)>0.) then ! any neg is nodata + allocate(tmp_data( max_obs,14)) + + N_obs = 0 + + do kk = 1,N_files - j=j+1 + ! open bufr file - sm_ASCAT(j) = sm_ASCAT(i) - lon(j) = lon(i) - lat(j) = lat(i) - if (present(ease_col)) ease_col(j) = ease_col(i) - if (present(ease_row)) ease_row(j) = ease_row(i) + call closbf(lnbufr) ! if a file with unit number lnbufr is open in (or "linked" with) BUFR, close it + open(lnbufr, file=trim(fnames(kk)), action='read', form='unformatted') + call openbf(lnbufr, 'SEC3', lnbufr) + call mtinfo( trim(this_obs_param%path) // '/BUFR_mastertable/', lnbufr+1, lnbufr+2) + call datelen(10) ! select date/time format with 4-digit year (YYYYMMDDHH) - end if - - end do - - N_data = j - - end subroutine read_sm_ASCAT_bin + msg_report: do while( ireadmg(lnbufr,subset,idate) == 0 ) + + loop_report: do while( ireadsb(lnbufr) == 0 ) + + ! columns of tmp_data: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 + call ufbint(lnbufr,tmp_vdata,14,1,iret,'YEAR MNTH DAYS HOUR MINU SECO SSOM SMPF SMCF ALFR TPCX IWFR CLATH CLONH') - ! ***************************************************************** - - subroutine read_obs_LaRC_Tskin( & - work_path, exp_id, & - date_time, dtstep_assim, N_catd, tile_coord, & - tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & - this_obs_param, & - found_obs, ts_LARC, std_ts_LARC ) + N_obs = N_obs + 1 - !--------------------------------------------------------------------- - ! - ! Subroutine to read in Tskin from LaRC. - ! Draper, June 2012. - ! - ! -------------------------------------------------------------------- - - implicit none - - ! inputs: - - character(*), intent(in) :: work_path - character(*), intent(in) :: exp_id + if (N_obs > max_obs) then + err_msg = 'Attempting to read too many obs - how long is your assimilation window?' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + end if - type(date_time_type), intent(in) :: date_time - - integer, intent(in) :: dtstep_assim, N_catd - - type(tile_coord_type), dimension(:), pointer :: tile_coord ! input - - type(grid_def_type), intent(in) :: tile_grid_d - - integer, dimension(tile_grid_d%N_lon,tile_grid_d%N_lat), intent(in) :: & - N_tile_in_cell_ij + tmp_data(N_obs,:) = tmp_vdata + + end do loop_report + end do msg_report + + call closbf(lnbufr) + close(lnbufr) + + end do ! end file loop - integer, dimension(:,:,:), pointer :: tile_num_in_cell_ij ! input - - type(obs_param_type), intent(in) :: this_obs_param - - ! outputs: - - real, intent(out), dimension(N_catd) :: ts_LARC - real, intent(out), dimension(N_catd) :: std_ts_LARC - logical, intent(out) :: found_obs - - ! --------------- - - real, parameter :: min_Tskin = 200. - real, parameter :: max_Tskin = 370. - - real, parameter :: tol = 1.e-2 - - ! Offsets taken - - integer :: ts_time_offset ! in seconds - - character(6) :: DDHHMM - character(6) :: YYYYMM - - type(date_time_type) :: date_time_tmp - - integer :: i, ind, N_tmp, N_files - - ! 24 = max number of files in one cycle - ! (assumes daily assim cycle, and hourly files) - - character(300), dimension(24) :: fnames - - real, dimension(:), pointer :: tmp_obs, tmp_lat, tmp_lon - - integer, dimension(N_catd) :: N_obs_in_tile - - integer, dimension(:), pointer :: tmp_tile_num - - character(300) :: tmp_fname - - logical :: ex - - integer :: MM - - character(len=*), parameter :: Iam = 'read_obs_LaRC_Tskin' - character(len=400) :: err_msg + ! ---------------------------------------------------------------- + ! + ! read mask file for ASCAT obs (netcdf format, regular lat/lon grid) - ! ------------------------------------------------------------------- + mask_filename = trim(this_obs_param%maskpath) // '/' // trim(this_obs_param%maskname) - nullify( tmp_obs, tmp_lat, tmp_lon , tmp_tile_num) - - ! --------------- - - ! initialize + if (logit) write (logunit,'(400A)') ' reading mask for ASCAT obs from ', trim(mask_filename) + + ! check if file exists + + inquire(file=mask_filename, exist=file_exists) - ! time stampes are at start of scan. MET-09 scans much faster than others - - select case (trim(this_obs_param%descr)) - - case ('LaRC_tskin-GOESE','LaRC_tskin-GOESW', 'LaRC_tskin-FY2E-') - - ts_time_offset=26*60/2 + if (.not. file_exists) then + err_msg = 'Mask file for ASCAT obs not found!' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + end if - case ('LaRC_tskin-MTST2') - - ts_time_offset=28*60/2 - - case ('LaRC_tskin-MET09') - - ts_time_offset=12*60/2 - - case default - - call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'unknown obs_param%descr') + ! open netCDF mask file + ierr = nf90_open(mask_filename, nf90_nowrite, ncid) + + ! get variable IDs + ierr = nf90_inq_varid(ncid, 'mask', mask_varid) + ierr = nf90_inq_varid(ncid, 'll_lon', ll_lon_varid) + ierr = nf90_inq_varid(ncid, 'll_lat', ll_lat_varid) + ierr = nf90_inq_varid(ncid, 'd_lon', dlon_varid) + ierr = nf90_inq_varid(ncid, 'd_lat', dlat_varid) + + ! get variable dimension IDs + ierr = nf90_inq_dimid(ncid, 'lon', lon_dimid) + ierr = nf90_inq_dimid(ncid, 'lat', lat_dimid) + + ! get dimension size + ierr = nf90_inquire_dimension(ncid, lon_dimid, len=mask_N_lon) + ierr = nf90_inquire_dimension(ncid, lat_dimid, len=mask_N_lat) + + ! read grid parameters + ierr = nf90_get_var(ncid, ll_lon_varid, mask_ll_lon) + ierr = nf90_get_var(ncid, ll_lat_varid, mask_ll_lat) + ierr = nf90_get_var(ncid, dlon_varid, mask_dlon) + ierr = nf90_get_var(ncid, dlat_varid, mask_dlat) + + ! allocate memory for mask + allocate(mask_data(mask_N_lon, mask_N_lat)) ! note: lon-by-lat + + ! read mask + ierr = nf90_get_var(ncid, mask_varid, mask_data) - end select - - found_obs = .false. - - ! find files that are within half-open interval - ! [date_time-dtstep_assim/2,date_time+dtstep_assim/2) - - select case (trim(this_obs_param%descr)) + ! close netCDF mask file + ierr = nf90_close(ncid) - case ('LaRC_tskin-GOESW') - MM=00 - case ('LaRC_tskin-GOESE') - MM=45 - case ('LaRC_tskin-MET09') - MM=00 - case ('LaRC_tskin-FY2E-') - MM=00 - case ('LaRC_tskin-MTST2') - MM=30 - case default - call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'unknown obs_param%descr') - end select - - date_time_tmp = date_time - - call augment_date_time( -(dtstep_assim/2 + ts_time_offset), date_time_tmp ) - - ! identify all files within current assimilation interval - ! inquire for the file once per hour - will always be at same minutes past hour - - N_files=0 - - do i=1,(dtstep_assim/3600) - - write (YYYYMM, '(i6.6)') date_time_tmp%year*100 + date_time_tmp%month - write (DDHHMM, '(i6.6)') date_time_tmp%day*10000 + date_time_tmp%hour*100 + MM - - tmp_fname=trim(this_obs_param%path) // '/' // YYYYMM(1:4) // & - '/' // YYYYMM(5:6) // '/' // DDHHMM(1:2) // '/' // & - trim(this_obs_param%name) & - // YYYYMM // DDHHMM(1:2) // '_' // DDHHMM(3:6) // 'z.nc4' + ! ---------------------------------------------------------------- + ! + ! select obs within assimilation window and from desired orbit direction; apply basic QC based on obs info - inquire(file=trim(tmp_fname),exist=ex) + N_tmp = 0 - if (ex) then + do kk = 1,N_obs - N_files = N_files + 1 + date_time_tmp%year = int(tmp_data(kk, 1)) + date_time_tmp%month = int(tmp_data(kk, 2)) + date_time_tmp%day = int(tmp_data(kk, 3)) + date_time_tmp%hour = int(tmp_data(kk, 4)) + date_time_tmp%min = int(tmp_data(kk, 5)) + date_time_tmp%sec = int(tmp_data(kk, 6)) - fnames(N_files) = tmp_fname + ! skip if record outside of current assim window + if ( datetime_lt_refdatetime( date_time_tmp, date_time_low ) .and. & + datetime_le_refdatetime( date_time_up, date_time_tmp ) ) cycle - end if - - call augment_date_time( 3600, date_time_tmp ) - - end do - - ! read observations: - ! - ! 1.) read N_tmp observations and their lat/lon info from file - ! 2.) get tile number for each obs from lat/lon - ! 3.) compute super-obs for each tile from all obs w/in that tile - ! (also eliminate observations that are not in domain) - ! ---------------------------------------------------------------- - ! - ! 1.) read N_tmp observations and their lat/lon info from file - - if (N_files>0) then - - call read_LaRC_Tskin_nc4( & - this_obs_param, N_files, fnames(1:N_files), & - N_tmp, tmp_lon, tmp_lat, tmp_obs ) - + ! skip if record contains invalid soil moisture value + if ( tmp_data(kk, 7) > 100. .or. tmp_data(kk, 7) < 0. ) cycle + + ! to distinguish orbit directions, must read "DOMO" from BUFR file + ! + ! 180 <= DOMO < 270 : descending + ! 270 < DOMO <= 360 : ascending + ! + ! if (index(this_obs_param%descr,'_A') /=0 .and. (tmp_data(kk, 8) < 270 .or. tmp_data(kk, 8) > 360)) cycle + ! if (index(this_obs_param%descr,'_D') /=0 .and. (tmp_data(kk, 8) < 180 .or. tmp_data(kk, 8) >= 270)) cycle + + ! skip if processing flag is set + if(int(tmp_data(kk, 8)) /= 0) cycle + + ! skip if correction flag is set ("good" values are 0 and 4) + if (.not. ( (int(tmp_data(kk, 9)) == 0) .or. (int(tmp_data(kk, 9)) == 4)) ) cycle + + ! skip if land fraction is missing or < 0.9 + if(tmp_data(kk, 10) > 1. .or. tmp_data(kk, 10) < 0.9 ) cycle + + ! skip if topographic complexity > 10% + if(tmp_data(kk, 11) > 10.) cycle + + ! skip if inundation and wetland fraction > 10% + if(tmp_data(kk, 12) > 10.) cycle + + ! find lat/lon indices of ASCAT mask for this observation lat/lon + mask_lat_ind = max( min( ceiling((tmp_data(kk, 13) - mask_ll_lat)/mask_dlat), mask_N_lat ), 1) + mask_lon_ind = max( min( ceiling((tmp_data(kk, 14) - mask_ll_lon)/mask_dlon), mask_N_lon ), 1) + + ! skip if masked + if (mask_data( mask_lon_ind, mask_lat_ind ) /= 0) cycle ! note: lon-by-lat + + N_tmp = N_tmp + 1 ! passed all QC + + if (N_tmp > max_rec) then + err_msg = 'Too many obs have passed QC - how long is your assimilation window?' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + end if + + tmp1_jtime(N_tmp) = datetime_to_J2000seconds( date_time_tmp, J2000_epoch_id ) + + tmp1_lat( N_tmp) = tmp_data(kk, 13) + tmp1_lon( N_tmp) = tmp_data(kk, 14) + + tmp1_obs( N_tmp) = tmp_data(kk, 7)/100. ! change units from percent (0-100) to fraction (0-1) + + end do + if (logit) then - write (logunit,*) 'read_obs_LaRC_Tskin: read ', N_tmp, & - ' at date_time = ', date_time - do i=1,N_files - write (logunit,*) trim(fnames(i)) + write (logunit,*) 'read_obs_sm_ASCAT_EUMET: read ', N_tmp, ' at date_time = ', date_time, ' from:' + do ii=1,N_files + write (logunit,*) trim(fnames(ii)) end do write (logunit,*) '----------' + write (logunit,*) 'max(obs)=',maxval(tmp1_obs(1:N_tmp)), ', min(obs)=',minval(tmp1_obs(1:N_tmp)), & + ', avg(obs)=',sum(tmp1_obs(1:N_tmp))/N_tmp end if + + deallocate(fnames) + ! copy "good" obs with lat/lon/time into tmp_* (pointers) + + allocate(tmp_jtime(N_tmp)) + allocate(tmp_lon( N_tmp)) + allocate(tmp_lat( N_tmp)) + allocate(tmp_obs( N_tmp)) + + tmp_jtime = tmp1_jtime(1:N_tmp) + tmp_lon = tmp1_lon( 1:N_tmp) + tmp_lat = tmp1_lat( 1:N_tmp) + tmp_obs = tmp1_obs( 1:N_tmp) + + deallocate(tmp1_jtime) + deallocate(tmp1_lon) + deallocate(tmp1_lat) + deallocate(tmp1_obs) + deallocate(tmp_data) + deallocate(mask_data) + else N_tmp = 0 end if - - ! 2.) get tile number for each obs from lat/lon + + ! ---------------------------------------------------------------- + ! + ! 2.) for each observation + ! a) determine grid cell that contains lat/lon + ! b) determine tile within grid cell that contains lat/lon if (N_tmp>0) then @@ -1947,79 +1998,76 @@ subroutine read_obs_LaRC_Tskin( & N_tmp, tmp_lat, tmp_lon, & this_obs_param, & tmp_tile_num ) - - + + ! ---------------------------------------------------------------- ! ! 3.) compute super-obs for each tile from all obs w/in that tile ! (also eliminate observations that are not in domain) - ts_LARC = 0. - - N_obs_in_tile = 0 + ASCAT_sm = 0. + ASCAT_lon = 0. + ASCAT_lat = 0. + ASCAT_time = 0.0D0 - do i=1,N_tmp + N_obs_in_tile = 0 + + do ii=1,N_tmp - ind = tmp_tile_num(i) ! 1<=tmp_tile_num<=N_catd (unless nodata) + ind = tmp_tile_num(ii) ! 1<=tmp_tile_num<=N_catd (unless nodata) if (ind>0) then ! this step eliminates obs outside domain - ! make sure obs is within allowed range + ASCAT_sm( ind) = ASCAT_sm( ind) + tmp_obs( ii) + ASCAT_lon( ind) = ASCAT_lon( ind) + tmp_lon( ii) + ASCAT_lat( ind) = ASCAT_lat( ind) + tmp_lat( ii) + ASCAT_time(ind) = ASCAT_time(ind) + tmp_jtime(ii) + + N_obs_in_tile(ind) = N_obs_in_tile(ind) + 1 - if ( (min_Tskin1) then + ! set observation error standard deviation + + ASCAT_sm_std(ii) = this_obs_param%errstd/100. ! change units from percent (0-100) to fraction (0-1) + + ! normalize + + if (N_obs_in_tile(ii)>1) then - ts_LARC(i) = ts_LARC(i)/real(N_obs_in_tile(i)) + ASCAT_sm( ii) = ASCAT_sm( ii)/real(N_obs_in_tile(ii)) + ASCAT_lon( ii) = ASCAT_lon( ii)/real(N_obs_in_tile(ii)) + ASCAT_lat( ii) = ASCAT_lat( ii)/real(N_obs_in_tile(ii)) + ASCAT_time( ii) = ASCAT_time(ii)/real(N_obs_in_tile(ii),kind(0.0D0)) - elseif (N_obs_in_tile(i)==0) then + elseif (N_obs_in_tile(ii)==0) then - ts_LARC(i) = this_obs_param%nodata + ASCAT_sm( ii) = this_obs_param%nodata + ASCAT_lon( ii) = this_obs_param%nodata + ASCAT_lat( ii) = this_obs_param%nodata + ASCAT_time( ii) = real(this_obs_param%nodata,kind(0.0D0)) + ASCAT_sm_std(ii) = this_obs_param%nodata + + else + + ! nothing to do if N_obs_in_tile(ii)==1 (and assuming N_obs_in_tile is never negative) end if end do - if (associated(tmp_tile_num)) deallocate(tmp_tile_num) + ! clean up - do i=1,N_catd - - std_ts_LARC(i) = this_obs_param%errstd - - ! CSD - temporary - only works over Americas - ! if keep, base on SZA - - if ( (date_time_tmp%hour .GT. 2 ) .AND. (date_time_tmp%hour .LT. 14.5 )) then - - std_ts_LARC(i) = 1.3 ! 1.5 - - else - - std_ts_LARC(i) = 2.1 ! 2.2 - - end if - - ! CSD - end temporary. - ! -------------------------------- - - end do + if (associated(tmp_tile_num)) deallocate(tmp_tile_num) if (any(N_obs_in_tile>0)) then - + found_obs = .true. else @@ -2035,856 +2083,929 @@ subroutine read_obs_LaRC_Tskin( & if (associated(tmp_obs)) deallocate(tmp_obs) if (associated(tmp_lon)) deallocate(tmp_lon) if (associated(tmp_lat)) deallocate(tmp_lat) + if (associated(tmp_jtime)) deallocate(tmp_jtime) - end subroutine read_obs_LaRC_Tskin - + end subroutine read_obs_sm_ASCAT_EUMET + ! *************************************************************************** - subroutine read_LaRC_Tskin_nc4( & - this_obs_param, N_files, fnames, N_data, lon, lat, ts_LaRC ) + subroutine read_sm_ASCAT_bin( & + N_files, fnames, N_data, lon, lat, sm_ASCAT, ease_col, ease_row ) - ! read Tskin from LaRC nc4 files + ! read soil moisture data from one or more ASCAT bin files ! - ! Apply QC: - ! Screen longitude to retain obs only from closest GEOsat - ! Viewing zenith angle (VZA) - ! Cloud fraction - ! Sun zenith angle (SZA) - ! - ! returns number of data, and pointers to the lon, lat, and data ! return ONLY valid data points (ie. excluding no-data-values) - ! - ! Currently tailored to read in LaRC files that have been reprocessed to replace - ! integer data with float data (to enable GFIO to be used) ! - ! If LaRC fixes the files, will need to change: - ! if ( nvars .LT 5 ) - this is included as some LaRC files are missing HIRESTSKIN field - ! Replace lower case variable names with appropriate case - ! Replace nodata value (hardwired, as cannot read missing_value from file) - ! Replace time setting with actual minutes (currently rounded down to nearest hour, - ! due to bug/assumption in GFIO read var routines). + ! no QC in addition to what was done in matlab-preprocessing + ! + ! DRAPER, May 2011 + ! based on read_ae_sm_LPRM_bin + ! + ! DRAPER, July 2012 + ! updated, for inclusion of SDS error in ASCAT file + ! (error info currently not saved) - ! DRAPER, June 2011 - implicit none - type(obs_param_type), intent(in) :: this_obs_param - integer, intent(in) :: N_files character(*), dimension(N_files), intent(in) :: fnames integer, intent(out) :: N_data - real, dimension(:), pointer :: lon, lat, ts_LaRC ! output - - ! local variables - - integer :: i, j, fid, rc - integer :: x, x_min, x_max, y, y_min, y_max - integer :: YYYYMMDD, HHMMSS - integer :: g_nlon, g_nlat, km, lm, nvars, ngatts + real, dimension(:), pointer :: lon, lat, sm_ASCAT ! output - real :: nodata_LARC + integer, dimension(:), pointer, optional :: ease_col, ease_row ! output - real, parameter :: tol=0.01 - - ! QC + ! local variables - real, parameter :: max_fcld = 20. ! max total cloud fraction (%) - real, parameter :: max_vza = 60. ! max viewing zenith angle - real, parameter :: min_excl_sza = 82. ! min of sza exclusion interval - real, parameter :: max_excl_sza = 90. ! max of sza exclusion interval - - logical :: tskin_ok, fcld_ok, sza_ok, vza_ok + logical :: must_stop - real, dimension(2) :: lon_range, lat_range - - real :: dlat, dlon - - logical :: first + integer, dimension(N_files) :: N_data_tmp - real, dimension(:,:), allocatable :: tmp_data, ave_data, sum_data + integer :: i, j, k_off - integer, dimension(:,:), allocatable :: cnt_data + integer, dimension(:), allocatable :: tmpintvec + real, dimension(:), allocatable :: tmprealvec - real, dimension(:,:), allocatable :: tmp_vza, tmp_sza, tmp_fcld + character(len=*), parameter :: Iam = 'read_sm_ASCAT_bin' + character(len=400) :: err_msg - ! ---------------------- - ! - ! variables to fix viewing zenith angle bug in some of the 2012 GOES-East files - ! reprocessed by Ben Scarino - ! - ! the "tmp_goesEast_vza_*" parameters point to a dummy "vza.nc4" file that contains - ! the correct vza values (located within the path of the reprocessed GOES-East files) + ! ------------------------------------------------------------- - character( 40), parameter :: tmp_goesEast_vza_dirname = 'goesEast201205_201304_RM2' - character( 40), parameter :: tmp_goesEast_vza_fname = 'int2float/vza.nc4' - - integer, parameter :: tmp_goesEast_vza_YYYYMMDD = 20120629 - integer, parameter :: tmp_goesEast_vza_HHMMSS = 230000 + ! make sure pointers are not allocated or associated - character(300) :: tmp_fname + must_stop = .false. - integer :: ind, tmp_fid - - character(len=*), parameter :: Iam = 'read_LaRC_Tskin_nc4' - character(len=400) :: err_msg + if ( associated(lon) .or. associated(lat) .or. associated(sm_ASCAT) ) then + must_stop = .true. + end if - ! ------------------------------------------------------------- + if ( present(ease_col) ) then + if (associated(ease_col)) must_stop = .true. + end if - ! make sure pointers are not allocated or associated + if ( present(ease_row) ) then + if (associated(ease_row)) must_stop = .true. + end if - if ( associated(lon) .or. associated(lat) .or. associated(ts_LaRC) ) then - err_msg = 'output pointers must not be ' // & + if (must_stop) then + err_msg = 'output pointers must not be ' // & 'associated or allocated on input.' call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) end if + + + !write (logunit,*) 'read_ae_sm_LPRM_bin(): output pointers must not be ' // & + ! 'associated or allocated on input. STOPPING.' + !stop + ! + !end if + + ! determine number of data to be read from each file + + N_data = 0 + + do j=1,N_files - !----------------------------------------- - ! read data into global arrays, perform QC - !----------------------------------------- - - first = .true. + ! open file + + open( 10, file=trim(fnames(j)), form='unformatted',convert='big_endian', action='read' ) + + read( 10) N_data_tmp(j) + + close(10, status='keep') + + end do + + ! allocate pointers (must be deallocated outside this subroutine!) + + N_data = sum(N_data_tmp) + + allocate(lon( N_data)) + allocate(lat( N_data)) + allocate(sm_ASCAT(N_data)) + + if (present(ease_col)) allocate(ease_col(N_data)) + if (present(ease_row)) allocate(ease_row(N_data)) + + ! read data into arrays, concatenate data from N_files files + + ! format of AMSR_sm_LPRM_EASE_bin files: + ! + ! record 1 -- N_data int*4 + ! record 2 -- lon( 1:N_data) real*4 + ! record 3 -- lat( 1:N_data) real*4 + ! record 4 -- sds( 1:N_data) real*4 + ! record 5 -- sds_noise (1:N_data) real*4 + ! record 6 -- ind_i(1:N_data) int*4 zero-based (!) EASE row index + ! record 7 -- ind_j(1:N_data) int*4 zero-based (!) EASE col index + + k_off = 0 do j=1,N_files - if (logit) write(logunit,'(400A)') 'reading LaRC Tskin obs from ', trim(fnames(j)) - - call Gfio_Open ( fnames(j), 1, fid, rc ) + allocate(tmprealvec(N_data_tmp(j))) - if (rc<0) then - call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'Error opening gfio file') - end if + if (present(ease_col)) allocate(tmpintvec(N_data_tmp(j))) - ! temporary catch for files missing HIRESTSKIN (LaRC will fix this) + open (10, file=trim(fnames(j)), form='unformatted', convert='big_endian', action='read' ) - call GFIO_DimInquire (fid,g_nlon,g_nlat,km,lm,nvars,ngatts,rc) + ! re-read N_data - dlon=360./real(g_nlon ) - dlat=180./real(g_nlat-1) + read (10) N_data_tmp(j) - if (rc<0) then - err_msg = 'DimInquire error, reading gfio file' - call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + ! read data as needed + + read (10) tmprealvec; lon(k_off+1:k_off+N_data_tmp(j)) = tmprealvec + read (10) tmprealvec; lat(k_off+1:k_off+N_data_tmp(j)) = tmprealvec + + read (10) tmprealvec; sm_ASCAT(k_off+1:k_off+N_data_tmp(j)) = tmprealvec + + ! skip record with error + + read (10) ! tmprealvec; er_ASCAT(k_off+1:k_off+N_data_tmp(j)) = tmprealvec + + if (present(ease_col) .and. present(ease_row)) then + + read (10) tmpintvec; ease_col(k_off+1:k_off+N_data_tmp(j)) = tmpintvec + read (10) tmpintvec; ease_row(k_off+1:k_off+N_data_tmp(j)) = tmpintvec + end if - !if (nvars .LT. 24) then (for original LaRC files) + ! clean up - if (nvars .LT. 5) then ! reprocessed files have only 5 variables + close(10, status='keep') + + deallocate(tmprealvec) + if (allocated(tmpintvec)) deallocate(tmpintvec) + + ! prepare next j + + k_off = k_off + N_data_tmp(j) + + end do + + ! ------------------------------------- + ! + ! eliminate no-data-values + + j = 0 + + do i=1,N_data + + if (sm_ASCAT(i)>0.) then ! any neg is nodata - write (logunit,*) 'CSD_LaRC file missing a variable ', fnames(j) + j=j+1 - else + sm_ASCAT(j) = sm_ASCAT(i) + lon(j) = lon(i) + lat(j) = lat(i) + if (present(ease_col)) ease_col(j) = ease_col(i) + if (present(ease_row)) ease_row(j) = ease_row(i) - if (first) then - - ! Attribute cannot be read from LaRC (or reprocessed) files - ! no idea why this is not working. ncdump shows attribute is in file - ! call GFIO_GetRealAtt ( fid, 'missing_value', 1, nodata_LARC, rc ) - !if (rc<0) call stop_it('Get attribute error, reading nodata from gfio file') - - nodata_LARC=-9.99e33 ! For reprocessed files only!!! LaRC use different value - - write(logunit,*) & - 'No-data-value manually set for reprocessed files: ', nodata_LARC - - ! get dimensions of grid and allocate temporary arrays - - allocate(tmp_data(g_nlon, g_nlat)) - allocate(ave_data(g_nlon, g_nlat)) - allocate(sum_data(g_nlon, g_nlat)) - allocate(cnt_data(g_nlon, g_nlat)) - allocate(tmp_vza( g_nlon, g_nlat)) - allocate(tmp_sza( g_nlon, g_nlat)) - allocate(tmp_fcld(g_nlon, g_nlat)) - - sum_data=0 - cnt_data=0 - - ! get dimensions of subgrid containing data for this disk + end if + + end do + + N_data = j + + end subroutine read_sm_ASCAT_bin - lat_range=(/-52.0,52.0/) ! maximum range is +/-52.0 for VZA<60 - - ! specify boundary for min and max lon (select disk with lowest VZA) - - select case (trim(this_obs_param%descr)) - - case ('LaRC_tskin-GOESW') - lon_range=(/-175. ,-105. /) - case ('LaRC_tskin-GOESE') - lon_range=(/-105. , -36.875/) - case ('LaRC_tskin-MET09') - lon_range=(/ -36.875, 54. /) - case ('LaRC_tskin-FY2E-') - ! bounds will not change if not using FY2, as FY2 eastern hemisphere is missing - lon_range=(/ 54. , 90. /) - case ('LaRC_tskin-MTST2') - lon_range=(/ 90. , 180. /) ! avoid crossing the dateline - case default - err_msg = 'unknown obs_param%descr' - call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) - end select - - ! find index of smallest lon > min_lon and of largest lon <= max_lon - - x_min=floor( (minval(lon_range)-(-180.))/dlon ) + 2 - x_max=floor( (maxval(lon_range)-(-180.))/dlon ) + 1 - - ! find index of smallest lat >= min_lat and of largest lat <= max_lat - - y_min=floor( (lat_range(1)-(-90.))/dlat ) + 1 - y_max=floor( (lat_range(2)-(-90.))/dlat ) + 1 - - first = .false. - - endif ! first - - ! cannot use actual time, as obs files are rounded to nearest hour - - ! ORIGINAL LaRC FILES - ! -define time as "minutes since YYYYMMDD, HHMM", and have time=0 - ! read(fnames(j)(len_trim(fnames(j))-8:len_trim(fnames(j))-5),'(i4)') HHMMSS - ! HHMMSS=HHMMSS*100 ! add seconds + ! ***************************************************************** + + subroutine read_obs_LaRC_Tskin( & + date_time, dtstep_assim, N_catd, tile_coord, & + tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & + this_obs_param, & + found_obs, ts_LARC, std_ts_LARC ) + + !--------------------------------------------------------------------- + ! + ! Subroutine to read in Tskin from LaRC. + ! Draper, June 2012. + ! + ! -------------------------------------------------------------------- + + implicit none + + ! inputs: + + type(date_time_type), intent(in) :: date_time + + integer, intent(in) :: dtstep_assim, N_catd + + type(tile_coord_type), dimension(:), pointer :: tile_coord ! input + + type(grid_def_type), intent(in) :: tile_grid_d + + integer, dimension(tile_grid_d%N_lon,tile_grid_d%N_lat), intent(in) :: & + N_tile_in_cell_ij + + integer, dimension(:,:,:), pointer :: tile_num_in_cell_ij ! input + + type(obs_param_type), intent(in) :: this_obs_param + + ! outputs: + + real, intent(out), dimension(N_catd) :: ts_LARC + real, intent(out), dimension(N_catd) :: std_ts_LARC + logical, intent(out) :: found_obs + + ! --------------- + + real, parameter :: min_Tskin = 200. + real, parameter :: max_Tskin = 370. + + real, parameter :: tol = 1.e-2 + + ! Offsets taken + + integer :: ts_time_offset ! in seconds + + character(6) :: DDHHMM + character(6) :: YYYYMM + + type(date_time_type) :: date_time_tmp + + integer :: i, ind, N_tmp, N_files + + ! 24 = max number of files in one cycle + ! (assumes daily assim cycle, and hourly files) + + character(300), dimension(24) :: fnames + + real, dimension(:), pointer :: tmp_obs, tmp_lat, tmp_lon + + integer, dimension(N_catd) :: N_obs_in_tile + + integer, dimension(:), pointer :: tmp_tile_num + + character(300) :: tmp_fname + + logical :: ex + + integer :: MM + + character(len=*), parameter :: Iam = 'read_obs_LaRC_Tskin' + + ! ------------------------------------------------------------------- + + nullify( tmp_obs, tmp_lat, tmp_lon , tmp_tile_num) + + ! --------------- + + ! initialize + + ! time stampes are at start of scan. MET-09 scans much faster than others + + select case (trim(this_obs_param%descr)) + + case ('LaRC_tskin-GOESE','LaRC_tskin-GOESW', 'LaRC_tskin-FY2E-') + + ts_time_offset=26*60/2 + + case ('LaRC_tskin-MTST2') + + ts_time_offset=28*60/2 + + case ('LaRC_tskin-MET09') + + ts_time_offset=12*60/2 + + case default + + call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'unknown obs_param%descr') + + end select + + found_obs = .false. + + ! find files that are within half-open interval + ! [date_time-dtstep_assim/2,date_time+dtstep_assim/2) + + select case (trim(this_obs_param%descr)) + + case ('LaRC_tskin-GOESW') + MM=00 + case ('LaRC_tskin-GOESE') + MM=45 + case ('LaRC_tskin-MET09') + MM=00 + case ('LaRC_tskin-FY2E-') + MM=00 + case ('LaRC_tskin-MTST2') + MM=30 + case default + call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'unknown obs_param%descr') + end select + + date_time_tmp = date_time + + call augment_date_time( -(dtstep_assim/2 + ts_time_offset), date_time_tmp ) + + ! identify all files within current assimilation interval + ! inquire for the file once per hour - will always be at same minutes past hour + + N_files=0 + + do i=1,(dtstep_assim/3600) + + write (YYYYMM, '(i6.6)') date_time_tmp%year*100 + date_time_tmp%month + write (DDHHMM, '(i6.6)') date_time_tmp%day*10000 + date_time_tmp%hour*100 + MM + + tmp_fname=trim(this_obs_param%path) // '/' // YYYYMM(1:4) // & + '/' // YYYYMM(5:6) // '/' // DDHHMM(1:2) // '/' // & + trim(this_obs_param%name) & + // YYYYMM // DDHHMM(1:2) // '_' // DDHHMM(3:6) // 'z.nc4' + + inquire(file=trim(tmp_fname),exist=ex) + + if (ex) then - ! lat4d.sh REPROCESSED FILES - ! -define time as "hours since YYYYMMDD, HH", and have time=MM/60 - ! The GFIO routine getbegdatetime calculates the time increment in a file by - ! reading in first two values - ! If there is only one time value in the file, the second read (line 240) fails, - ! and incSecs=1 - ! This results in TimeIndex in GFIO_GetVar= (MM in seconds) (rather than 1) - ! (in summary, getbegdatetime assumes that if there are not multiple times in - ! a file, time must equal 0 - ! which it does not for reprocessed LaRC files) - ! Get around this by specifying MM=0 regardless of actual time + N_files = N_files + 1 - read(fnames(j)(len_trim(fnames(j)) -8:len_trim(fnames(j))-7),'(i2)') HHMMSS + fnames(N_files) = tmp_fname - HHMMSS=HHMMSS*10000 ! add seconds, assume minutes are zero + end if + + call augment_date_time( 3600, date_time_tmp ) + + end do + + ! read observations: + ! + ! 1.) read N_tmp observations and their lat/lon info from file + ! 2.) get tile number for each obs from lat/lon + ! 3.) compute super-obs for each tile from all obs w/in that tile + ! (also eliminate observations that are not in domain) + ! ---------------------------------------------------------------- + ! + ! 1.) read N_tmp observations and their lat/lon info from file + + if (N_files>0) then + + call read_LaRC_Tskin_nc4( & + this_obs_param, N_files, fnames(1:N_files), & + N_tmp, tmp_lon, tmp_lat, tmp_obs ) + + if (logit) then - read(fnames(j)(len_trim(fnames(j))-17:len_trim(fnames(j))-9),'(i8)') YYYYMMDD + write (logunit,*) 'read_obs_LaRC_Tskin: read ', N_tmp, & + ' at date_time = ', date_time + do i=1,N_files + write (logunit,*) trim(fnames(i)) + end do + write (logunit,*) '----------' + end if - ! read HIRESTSKIN + else + + N_tmp = 0 + + end if - call GFIO_GetVar( fid,'hirestskin', & - YYYYMMDD, HHMMSS, g_nlon, g_nlat, & - 0, 1, tmp_data(:,:), rc ) - if (rc<0) then - err_msg = 'GetVar error, reading hirestskin from gfio file' - call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) - end if - - ! Viewing zenith angle (VZA) + ! 2.) get tile number for each obs from lat/lon - call GFIO_GetVar( fid,'vza', & - YYYYMMDD, HHMMSS, g_nlon, g_nlat, & - 0, 1, tmp_vza, rc ) - if (rc<0) then - err_msg = 'GetVar error, reading vza from gfio file' - call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) - end if - - ! GOES-East VZA for end Sep, start Oct 2012 are incorrect in the files - ! reprocessed by Ben Scarino, replace VZA with that from a hard-coded file + if (N_tmp>0) then + + allocate(tmp_tile_num(N_tmp)) + + call get_tile_num_for_obs(N_catd, tile_coord, & + tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & + N_tmp, tmp_lat, tmp_lon, & + this_obs_param, & + tmp_tile_num ) + + + ! ---------------------------------------------------------------- + ! + ! 3.) compute super-obs for each tile from all obs w/in that tile + ! (also eliminate observations that are not in domain) + + ts_LARC = 0. + + N_obs_in_tile = 0 + + do i=1,N_tmp - ind = index(fnames(j), trim(tmp_goesEast_vza_dirname)) + ind = tmp_tile_num(i) ! 1<=tmp_tile_num<=N_catd (unless nodata) - if (ind/=0) then - - ! extract path to replacement vza file from "fnames(j)" - ! (=fnames(j) up to and including "tmp_goesEast_vza_dirname") - - tmp_fname = fnames(j)(1:ind+len_trim(tmp_goesEast_vza_dirname)-1) - - ! append "tmp_goesEast_vza_fname" - - tmp_fname = trim(tmp_fname) // '/' // trim(tmp_goesEast_vza_fname) + if (ind>0) then ! this step eliminates obs outside domain - call Gfio_Open (tmp_fname, 1, tmp_fid, rc ) + ! make sure obs is within allowed range - if (rc<0) then - err_msg = 'Error opening gfio file' - call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + if ( (min_Tskin1) then - call GFIO_Close ( tmp_fid, rc ) + ts_LARC(i) = ts_LARC(i)/real(N_obs_in_tile(i)) + + elseif (N_obs_in_tile(i)==0) then + + ts_LARC(i) = this_obs_param%nodata end if - - ! Sun zenith angle (SZA) - - call GFIO_GetVar( fid,'sza', & - YYYYMMDD, HHMMSS, g_nlon, g_nlat, & - 0, 1, tmp_sza, rc ) - if (rc<0) then - err_msg = 'GetVar error, reading sza from gfio file' - call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) - end if + end do + + if (associated(tmp_tile_num)) deallocate(tmp_tile_num) + + do i=1,N_catd + std_ts_LARC(i) = this_obs_param%errstd + + ! CSD - temporary - only works over Americas + ! if keep, base on SZA + + if ( (date_time_tmp%hour .GT. 2 ) .AND. (date_time_tmp%hour .LT. 14.5 )) then - ! Cloud fraction (FCLD), level 1 is total cloud - - call GFIO_GetVar( fid,'fcld', & - YYYYMMDD, HHMMSS, g_nlon, g_nlat, & - 1, 1, tmp_fcld, rc ) - if (rc<0) then - err_msg = 'GetVar error, reading fcld from gfio file' - call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + std_ts_LARC(i) = 1.3 ! 1.5 + + else + + std_ts_LARC(i) = 2.1 ! 2.2 + end if - - ! calculate mean of all data that passes QC - do x=x_min, x_max - - do y=y_min, y_max - - ! Tskin must not be no-data-value - - tskin_ok = (abs(tmp_data(x,y) - nodata_LARC) .GE. tol) - - ! fcld must not be no-data-value; fcld<=max_cld - - fcld_ok = & - (tmp_fcld(x,y) .LE. max_fcld) .AND. & - (abs(tmp_fcld(x,y)-nodata_LARC) .GT. tol) - - ! sza must not be no-data-value; sza<=min_excl_sza; sza>=max_excl_sza - - sza_ok = & - ( & - (tmp_sza(x,y) .LE. min_excl_sza) .OR. & - (tmp_sza(x,y) .GE. max_excl_sza) & - ) .AND. & - (abs(tmp_sza(x,y)-nodata_LARC) .GT. tol) - - ! vza must not be no-data-value; vza<=vza_max - - vza_ok = & - (tmp_vza( x,y) .LE. max_vza) .AND. & - (abs(tmp_vza( x,y)-nodata_LARC) .GT. tol) - - - if (tskin_ok .and. fcld_ok .and. sza_ok .and. vza_ok ) then - - sum_data(x,y) =sum_data(x,y) + tmp_data(x,y) - - cnt_data(x,y) = cnt_data(x,y)+1 - - end if - - end do - end do + ! CSD - end temporary. + ! -------------------------------- - end if ! nvars + end do - call GFIO_Close ( fid, rc ) + if (any(N_obs_in_tile>0)) then + + found_obs = .true. + + else + + found_obs = .false. + + end if - end do ! N_files + end if + ! clean up - if ( .not. first) then - - ! only calc averages if found file with HIRESTSKIN - temporary for incomplete files - - ! calculate average over appropriate lat/lon range, and count locations with data - - N_data=0 - - do x=x_min, x_max - do y=y_min, y_max - if(cnt_data(x,y)>0) then - ave_data(x,y)=sum_data(x,y)/cnt_data(x,y) - N_data=N_data+1 - else - ave_data(x,y)=nodata_LARC - endif - enddo - enddo - - ! allocate pointers for return vectors (must be deallocated outside this subroutine!) - - allocate(lon( N_data)) - allocate(lat( N_data)) - allocate(ts_LaRC(N_data)) - - ! pass return data into vectors - - i=1 - do x=x_min, x_max - do y=y_min, y_max - if ( abs(ave_data(x,y)-nodata_LARC) .GT. tol ) then - ts_LaRC(i)=ave_data(x,y) - lon(i)=(x-1)*dlon -180. - lat(i)=(y-1)*dlat - 90. - i=i+1 - endif - enddo - enddo - - ! clean up - - deallocate(tmp_data) - deallocate(sum_data) - deallocate(cnt_data) - deallocate(ave_data) - deallocate(tmp_vza) - deallocate(tmp_sza) - deallocate(tmp_fcld) - - else - - N_data=0 - - ! OK not to allocate pointers for data? - - endif + if (associated(tmp_obs)) deallocate(tmp_obs) + if (associated(tmp_lon)) deallocate(tmp_lon) + if (associated(tmp_lat)) deallocate(tmp_lat) - end subroutine read_LaRC_Tskin_nc4 + end subroutine read_obs_LaRC_Tskin - ! ***************************************************************** - - subroutine read_obs_RedArkOSSE_sm( & - date_time, N_catd, tile_coord, this_obs_param, & - found_obs, RedArkOSSE_sm, std_RedArkOSSE_sm ) + ! *************************************************************************** + + subroutine read_LaRC_Tskin_nc4( & + this_obs_param, N_files, fnames, N_data, lon, lat, ts_LaRC ) - ! Read observations of surface soil moisture from Wade Crow's - ! synthetic RedArk OSSE 36km soil moisture files. - ! Set flag "found_obs" to true if observations are available - ! for assimilation. + ! read Tskin from LaRC nc4 files ! - ! If there are N > 1 observations in a given tile, - ! a "super-observation" is computed by averaging the N observations. + ! Apply QC: + ! Screen longitude to retain obs only from closest GEOsat + ! Viewing zenith angle (VZA) + ! Cloud fraction + ! Sun zenith angle (SZA) + ! + ! returns number of data, and pointers to the lon, lat, and data + ! return ONLY valid data points (ie. excluding no-data-values) ! - ! inputs to this subroutine: - ! date_time = current model date and time - ! N_catd = number of catchments in domain - ! - ! reichle, 25 May 2006 - ! reichle, 26 Sep 2006 - added iostat to open statement - ! - ! -------------------------------------------------------------------- + ! Currently tailored to read in LaRC files that have been reprocessed to replace + ! integer data with float data (to enable GFIO to be used) + ! + ! If LaRC fixes the files, will need to change: + ! if ( nvars .LT 5 ) - this is included as some LaRC files are missing HIRESTSKIN field + ! Replace lower case variable names with appropriate case + ! Replace nodata value (hardwired, as cannot read missing_value from file) + ! Replace time setting with actual minutes (currently rounded down to nearest hour, + ! due to bug/assumption in GFIO read var routines). + + ! DRAPER, June 2011 implicit none - ! inputs: - - type(date_time_type), intent(in) :: date_time + type(obs_param_type), intent(in) :: this_obs_param + + integer, intent(in) :: N_files - integer, intent(in) :: N_catd + character(*), dimension(N_files), intent(in) :: fnames - type(tile_coord_type), dimension(:), pointer :: tile_coord ! input + integer, intent(out) :: N_data - type(obs_param_type), intent(in) :: this_obs_param + real, dimension(:), pointer :: lon, lat, ts_LaRC ! output - ! outputs: + ! local variables - real, intent(out), dimension(N_catd) :: RedArkOSSE_sm - real, intent(out), dimension(N_catd) :: std_RedArkOSSE_sm - logical, intent(out) :: found_obs + integer :: i, j, fid, rc + integer :: x, x_min, x_max, y, y_min, y_max + integer :: YYYYMMDD, HHMMSS + integer :: g_nlon, g_nlat, km, lm, nvars, ngatts - ! --------------- + real :: nodata_LARC - ! locals + real, parameter :: tol=0.01 - ! RedArkOSSE synthetic soil moisture obs at 36km are available once a day. - ! - ! Mapping of the 36km retrievals to catchment/tile space is precomputed - ! and stored in p2t_nearest.dat and t2p_nearest.dat - - integer, parameter :: N_p2t = 1120 ! # of 36 km pixels - integer, parameter :: N_t2p = 69 ! # of tiles that need "duplicated" obs - - integer, parameter :: HH_obs = 21 ! obs hour of day (UTC) = 3pm CST + ! QC - ! initial QC parameters + real, parameter :: max_fcld = 20. ! max total cloud fraction (%) + real, parameter :: max_vza = 60. ! max viewing zenith angle + real, parameter :: min_excl_sza = 82. ! min of sza exclusion interval + real, parameter :: max_excl_sza = 90. ! max of sza exclusion interval - real, parameter :: obs_min = 0.0 ! min allowed obs - real, parameter :: obs_max = 0.45 ! max allowed obs - real, parameter :: opac_max = 0.3 ! max allowed vegetation opacity + logical :: tskin_ok, fcld_ok, sza_ok, vza_ok - integer, parameter :: qc_failed_obs = -888. + real, dimension(2) :: lon_range, lat_range + + real :: dlat, dlon + + logical :: first - integer, dimension(N_p2t) :: p2t - integer, dimension(N_t2p,2) :: t2p + real, dimension(:,:), allocatable :: tmp_data, ave_data, sum_data - character(3) :: DDD - character(4) :: YYYY - character(300) :: tmpfname + integer, dimension(:,:), allocatable :: cnt_data - integer :: i, j, ind, N_tmp, tmp_tile_id, istat + real, dimension(:,:), allocatable :: tmp_vza, tmp_sza, tmp_fcld + + ! ---------------------- + ! + ! variables to fix viewing zenith angle bug in some of the 2012 GOES-East files + ! reprocessed by Ben Scarino + ! + ! the "tmp_goesEast_vza_*" parameters point to a dummy "vza.nc4" file that contains + ! the correct vza values (located within the path of the reprocessed GOES-East files) - real :: tmp_real, tmp_opac + character( 40), parameter :: tmp_goesEast_vza_dirname = 'goesEast201205_201304_RM2' + character( 40), parameter :: tmp_goesEast_vza_fname = 'int2float/vza.nc4' + + integer, parameter :: tmp_goesEast_vza_YYYYMMDD = 20120629 + integer, parameter :: tmp_goesEast_vza_HHMMSS = 230000 - real, dimension(:), allocatable :: tmp_obs - integer, dimension(:), allocatable :: tmp_tile_num + character(300) :: tmp_fname - integer, dimension(N_catd) :: N_obs_in_tile + integer :: ind, tmp_fid - character(len=*), parameter :: Iam = 'read_obs_RedArkOSSE_sm' + character(len=*), parameter :: Iam = 'read_LaRC_Tskin_nc4' character(len=400) :: err_msg - - ! ------------------------------------------------------------------- - ! initialize + ! ------------------------------------------------------------- - found_obs = .false. + ! make sure pointers are not allocated or associated - ! obs are available only once per day - ! (hard-coded b/c time-of-day is not clear from filename) + if ( associated(lon) .or. associated(lat) .or. associated(ts_LaRC) ) then + err_msg = 'output pointers must not be ' // & + 'associated or allocated on input.' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + end if + + !----------------------------------------- + ! read data into global arrays, perform QC + !----------------------------------------- + + first = .true. - if (date_time%hour == HH_obs) then + do j=1,N_files - ! read observations: - ! - ! 1.) read observations, p2t, and t2p from files - ! 2.) for each observation determine tile_num ("p2t") - ! 3.) duplicate observations for tiles that are not covered yet ("t2p") - ! 4.) compute super-obs for each tile from all obs w/in that tile - ! - ! ---------------------------------------------------------------- + if (logit) write(logunit,'(400A)') 'reading LaRC Tskin obs from ', trim(fnames(j)) + + call Gfio_Open ( fnames(j), 1, fid, rc ) - ! 1.) a) read obs + if (rc<0) then + call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'Error opening gfio file') + end if - write (YYYY,'(i4.4)') date_time%year - write (DDD, '(i3.3)') date_time%dofyr + ! temporary catch for files missing HIRESTSKIN (LaRC will fix this) - tmpfname = trim(this_obs_param%path) // '/' // YYYY // & - '/' // trim(this_obs_param%name) // YYYY // '.' // DDD + call GFIO_DimInquire (fid,g_nlon,g_nlat,km,lm,nvars,ngatts,rc) - open(10, file=tmpfname, form='formatted', action='read', iostat=istat) + dlon=360./real(g_nlon ) + dlat=180./real(g_nlat-1) - if (istat==0) then + if (rc<0) then + err_msg = 'DimInquire error, reading gfio file' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + end if + + !if (nvars .LT. 24) then (for original LaRC files) + + if (nvars .LT. 5) then ! reprocessed files have only 5 variables - N_tmp = N_p2t + N_t2p + write (logunit,*) 'CSD_LaRC file missing a variable ', fnames(j) - allocate(tmp_obs(N_tmp)) - allocate(tmp_tile_num(N_tmp)) + else - do i=1,N_p2t + if (first) then - read(10,*) tmp_real, tmp_opac + ! Attribute cannot be read from LaRC (or reprocessed) files + ! no idea why this is not working. ncdump shows attribute is in file + ! call GFIO_GetRealAtt ( fid, 'missing_value', 1, nodata_LARC, rc ) + !if (rc<0) call stop_it('Get attribute error, reading nodata from gfio file') - tmp_obs(i) = tmp_real/100. ! unit conversion + nodata_LARC=-9.99e33 ! For reprocessed files only!!! LaRC use different value - ! initial QC + write(logunit,*) & + 'No-data-value manually set for reprocessed files: ', nodata_LARC - if ( (tmp_opac > opac_max) .or. & - (tmp_obs(i) > obs_max) .or. & - (tmp_obs(i) < obs_min) ) then - - tmp_obs(i) = qc_failed_obs - - end if + ! get dimensions of grid and allocate temporary arrays - end do - - close(10,status='keep') - - ! 1.) b) read p2t - - tmpfname = trim(this_obs_param%path) // '/p2t_nearest.dat' - - open(10, file=tmpfname, form='formatted', action='read') - - do i=1,N_p2t + allocate(tmp_data(g_nlon, g_nlat)) + allocate(ave_data(g_nlon, g_nlat)) + allocate(sum_data(g_nlon, g_nlat)) + allocate(cnt_data(g_nlon, g_nlat)) + allocate(tmp_vza( g_nlon, g_nlat)) + allocate(tmp_sza( g_nlon, g_nlat)) + allocate(tmp_fcld(g_nlon, g_nlat)) - read(10,*) p2t(i), tmp_tile_id ! col 1: tile_num, col 2: tile_id + sum_data=0 + cnt_data=0 - ! check tile_id for consistency + ! get dimensions of subgrid containing data for this disk + + lat_range=(/-52.0,52.0/) ! maximum range is +/-52.0 for VZA<60 - if (p2t(i)>0) then ! if statement added 1 May 2007, reichle - if (tmp_tile_id/=tile_coord(p2t(i))%tile_id) then - - !write (logunit,*) 'read_obs_RedArkOSSE(): something is wrong (p2t)' - !!!write (logunit,*) i, p2t(i), tmp_tile_id, tile_coord(p2t(i))%tile_id - !stop + ! specify boundary for min and max lon (select disk with lowest VZA) + + select case (trim(this_obs_param%descr)) + + case ('LaRC_tskin-GOESW') + lon_range=(/-175. ,-105. /) + case ('LaRC_tskin-GOESE') + lon_range=(/-105. , -36.875/) + case ('LaRC_tskin-MET09') + lon_range=(/ -36.875, 54. /) + case ('LaRC_tskin-FY2E-') + ! bounds will not change if not using FY2, as FY2 eastern hemisphere is missing + lon_range=(/ 54. , 90. /) + case ('LaRC_tskin-MTST2') + lon_range=(/ 90. , 180. /) ! avoid crossing the dateline + case default + err_msg = 'unknown obs_param%descr' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + end select - err_msg = 'something is wrong (p2t)' - call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) - - end if - end if - end do - - close(10,status='keep') + ! find index of smallest lon > min_lon and of largest lon <= max_lon + + x_min=floor( (minval(lon_range)-(-180.))/dlon ) + 2 + x_max=floor( (maxval(lon_range)-(-180.))/dlon ) + 1 + + ! find index of smallest lat >= min_lat and of largest lat <= max_lat + + y_min=floor( (lat_range(1)-(-90.))/dlat ) + 1 + y_max=floor( (lat_range(2)-(-90.))/dlat ) + 1 + + first = .false. + + endif ! first - ! 1.) c) read t2p + ! cannot use actual time, as obs files are rounded to nearest hour - tmpfname = trim(this_obs_param%path) // '/t2p_nearest.dat' + ! ORIGINAL LaRC FILES + ! -define time as "minutes since YYYYMMDD, HHMM", and have time=0 + ! read(fnames(j)(len_trim(fnames(j))-8:len_trim(fnames(j))-5),'(i4)') HHMMSS + ! HHMMSS=HHMMSS*100 ! add seconds - open(10, file=tmpfname, form='formatted', action='read') + ! lat4d.sh REPROCESSED FILES + ! -define time as "hours since YYYYMMDD, HH", and have time=MM/60 + ! The GFIO routine getbegdatetime calculates the time increment in a file by + ! reading in first two values + ! If there is only one time value in the file, the second read (line 240) fails, + ! and incSecs=1 + ! This results in TimeIndex in GFIO_GetVar= (MM in seconds) (rather than 1) + ! (in summary, getbegdatetime assumes that if there are not multiple times in + ! a file, time must equal 0 + ! which it does not for reprocessed LaRC files) + ! Get around this by specifying MM=0 regardless of actual time - do i=1,N_t2p - - read(10,*) t2p(i,1:2), tmp_tile_id ! pixel_num, tile_num, tile_id - - if (tmp_tile_id/=tile_coord(t2p(i,2))%tile_id) then - err_msg = 'something is wrong (t2p)' - call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) - end if - - !write (logunit,*) 'read_obs_RedArkOSSE(): something is wrong (t2p)' - !stop - ! - !end if - - end do + read(fnames(j)(len_trim(fnames(j)) -8:len_trim(fnames(j))-7),'(i2)') HHMMSS - close(10,status='keep') + HHMMSS=HHMMSS*10000 ! add seconds, assume minutes are zero - ! ----------------------- - ! - ! 2.) for each observation determine tile_num ("p2t") + read(fnames(j)(len_trim(fnames(j))-17:len_trim(fnames(j))-9),'(i8)') YYYYMMDD - do i=1,N_p2t - - tmp_tile_num(i) = p2t(i) - - end do + + ! read HIRESTSKIN + + call GFIO_GetVar( fid,'hirestskin', & + YYYYMMDD, HHMMSS, g_nlon, g_nlat, & + 0, 1, tmp_data(:,:), rc ) + if (rc<0) then + err_msg = 'GetVar error, reading hirestskin from gfio file' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + end if - ! ----------------------- - ! - ! 3.) duplicate observations for tiles not covered yet ("t2p") + ! Viewing zenith angle (VZA) + + call GFIO_GetVar( fid,'vza', & + YYYYMMDD, HHMMSS, g_nlon, g_nlat, & + 0, 1, tmp_vza, rc ) + if (rc<0) then + err_msg = 'GetVar error, reading vza from gfio file' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + end if - do i=1,N_t2p + ! GOES-East VZA for end Sep, start Oct 2012 are incorrect in the files + ! reprocessed by Ben Scarino, replace VZA with that from a hard-coded file + + ind = index(fnames(j), trim(tmp_goesEast_vza_dirname)) + + if (ind/=0) then + + ! extract path to replacement vza file from "fnames(j)" + ! (=fnames(j) up to and including "tmp_goesEast_vza_dirname") - j = i + N_p2t + tmp_fname = fnames(j)(1:ind+len_trim(tmp_goesEast_vza_dirname)-1) - tmp_obs( j) = tmp_obs(t2p(i,1)) + ! append "tmp_goesEast_vza_fname" - tmp_tile_num(j) = t2p(i,2) + tmp_fname = trim(tmp_fname) // '/' // trim(tmp_goesEast_vza_fname) - end do - - - ! ------------------------ - ! - ! 4.) compute super-obs for each tile from all obs w/in that tile - ! (also eliminate observations that are not in domain) - - RedArkOSSE_sm = 0. - N_obs_in_tile = 0 - - do i=1,N_tmp + call Gfio_Open (tmp_fname, 1, tmp_fid, rc ) - ind = tmp_tile_num(i) ! 1<=tmp_tile_num<=N_catd (unless nodata) + if (rc<0) then + err_msg = 'Error opening gfio file' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + end if - if (ind>0) then ! this step eliminates obs outside domain - - if (tmp_obs(i)>0.) then ! this step eliminates no-data - - RedArkOSSE_sm(ind) = RedArkOSSE_sm(ind) + tmp_obs(i) - - N_obs_in_tile(ind) = N_obs_in_tile(ind) + 1 - - end if - + ! read replacement vza + + call GFIO_GetVar( tmp_fid,'vza', & + tmp_goesEast_vza_YYYYMMDD, tmp_goesEast_vza_HHMMSS, g_nlon, g_nlat, & + 0, 1, tmp_vza, rc ) + if (rc<0) then + err_msg = 'GetVar error, reading vza from gfio file (2)' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) end if - end do + call GFIO_Close ( tmp_fid, rc ) + + end if + - ! normalize + ! Sun zenith angle (SZA) + + call GFIO_GetVar( fid,'sza', & + YYYYMMDD, HHMMSS, g_nlon, g_nlat, & + 0, 1, tmp_sza, rc ) + if (rc<0) then + err_msg = 'GetVar error, reading sza from gfio file' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + end if - do i=1,N_catd + + ! Cloud fraction (FCLD), level 1 is total cloud + + call GFIO_GetVar( fid,'fcld', & + YYYYMMDD, HHMMSS, g_nlon, g_nlat, & + 1, 1, tmp_fcld, rc ) + if (rc<0) then + err_msg = 'GetVar error, reading fcld from gfio file' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + end if + + ! calculate mean of all data that passes QC + + do x=x_min, x_max - if (N_obs_in_tile(i)>1) then + do y=y_min, y_max + + ! Tskin must not be no-data-value - RedArkOSSE_sm(i) = RedArkOSSE_sm(i)/real(N_obs_in_tile(i)) + tskin_ok = (abs(tmp_data(x,y) - nodata_LARC) .GE. tol) - elseif (N_obs_in_tile(i)==0) then + ! fcld must not be no-data-value; fcld<=max_cld + + fcld_ok = & + (tmp_fcld(x,y) .LE. max_fcld) .AND. & + (abs(tmp_fcld(x,y)-nodata_LARC) .GT. tol) + + ! sza must not be no-data-value; sza<=min_excl_sza; sza>=max_excl_sza - RedArkOSSE_sm(i) = this_obs_param%nodata + sza_ok = & + ( & + (tmp_sza(x,y) .LE. min_excl_sza) .OR. & + (tmp_sza(x,y) .GE. max_excl_sza) & + ) .AND. & + (abs(tmp_sza(x,y)-nodata_LARC) .GT. tol) + + ! vza must not be no-data-value; vza<=vza_max - end if - - end do - - ! -------------------------------- - - ! set observation error standard deviation - - do i=1,N_catd - std_RedArkOSSE_sm(i) = this_obs_param%errstd + vza_ok = & + (tmp_vza( x,y) .LE. max_vza) .AND. & + (abs(tmp_vza( x,y)-nodata_LARC) .GT. tol) + + + if (tskin_ok .and. fcld_ok .and. sza_ok .and. vza_ok ) then + + sum_data(x,y) =sum_data(x,y) + tmp_data(x,y) + + cnt_data(x,y) = cnt_data(x,y)+1 + + end if + + end do end do - ! -------------------------------- - - if (any(N_obs_in_tile>0)) then - - found_obs = .true. - - else - - found_obs = .false. - - end if - - end if ! istat==0 - - ! clean up + end if ! nvars - if (allocated(tmp_tile_num)) deallocate(tmp_tile_num) - if (allocated(tmp_obs)) deallocate(tmp_obs) + call GFIO_Close ( fid, rc ) - end if - - end subroutine read_obs_RedArkOSSE_sm - - ! ******************************************************************* - - subroutine read_obs_RedArkOSSE_CLSMsynthSM( date_time, N_catd, & - this_obs_param, & - found_obs, RedArkOSSE_CLSMsynthSM, std_RedArkOSSE_CLSMsynthSM ) - - ! Read synthetic observations of surface soil moisture from CLSM - ! RedArkOSSE integration (generated in matlab from innov output with - ! get_RedArk_CLSM_synth_retrievals.m) - ! - ! synthetic RedArk OSSE 36km soil moisture files. - ! Set flag "found_obs" to true if observations are available - ! for assimilation. - ! - ! inputs to this subroutine: - ! date_time = current model date and time - ! N_catd = number of catchments in domain - ! - ! reichle, 16 Feb 2006 - ! reichle, 5 Apr 2007 - use obs std from default nml input - ! (instead of reading from file) - ! - ! -------------------------------------------------------------------- - - implicit none - - ! inputs: - - type(date_time_type), intent(in) :: date_time - - integer, intent(in) :: N_catd - - type(obs_param_type), intent(in) :: this_obs_param - - ! outputs: - - real, intent(out), dimension(N_catd) :: RedArkOSSE_CLSMsynthSM - real, intent(out), dimension(N_catd) :: std_RedArkOSSE_CLSMsynthSM - logical, intent(out) :: found_obs + end do ! N_files - ! --------------- - ! locals - - ! RedArkOSSE CLSM synthetic soil moisture obs are available once a day. - - integer, parameter :: HH_obs = 21 ! obs hour of day (UTC) = 3pm CST - - real, parameter :: nodata = -9999. - - ! initial QC parameters - - real, parameter :: obs_min = 0.0 ! min allowed obs - real, parameter :: obs_max = 0.5 ! max allowed obs - - character(2) :: MM, DD - character(4) :: YYYY, HHMM - character(300) :: tmpfname - - integer :: i, N_tmp, istat, tmp_tilenum - - real :: tmp_obs, tmp_obs_std - - ! ------------------------------------------------------------------- - - ! initialize - - found_obs = .false. - - ! obs are available only once per day - ! (hard-coded b/c time-of-day is not very clear in RedArkOSSE - - if (date_time%hour == HH_obs) then + if ( .not. first) then - write (YYYY,'(i4.4)') date_time%year - write (MM, '(i2.2)') date_time%month - write (DD, '(i2.2)') date_time%day - write (HHMM,'(i4.4)') 100*HH_obs + ! only calc averages if found file with HIRESTSKIN - temporary for incomplete files - tmpfname = trim(this_obs_param%path) // '/Y' // YYYY // '/M' // MM // & - '/' // trim(this_obs_param%name) // YYYY // MM // DD // '_' // HHMM + ! calculate average over appropriate lat/lon range, and count locations with data - open(10, file=tmpfname, form='formatted', action='read', iostat=istat) + N_data=0 - if (istat==0) then - - read(10,*) N_tmp - read(10,*) ! tmp_obs_std - - ! do NOT use obs std from file - ! (s.t. "wrong" obs std can be specified conveniently in nml file) - ! reichle, 5 Apr 2007 - - tmp_obs_std = this_obs_param%errstd - - RedArkOSSE_CLSMsynthSM( 1:N_catd) = nodata - std_RedArkOSSE_CLSMsynthSM(1:N_catd) = tmp_obs_std - - do i=1,N_tmp - - read(10,*) tmp_tilenum, tmp_obs - - ! initial QC - - tmp_obs = min( obs_max, tmp_obs ) - tmp_obs = max( obs_min, tmp_obs ) - - RedArkOSSE_CLSMsynthSM( tmp_tilenum ) = tmp_obs - - end do - - close(10,status='keep') - - found_obs = .true. - - end if ! istat==0 + do x=x_min, x_max + do y=y_min, y_max + if(cnt_data(x,y)>0) then + ave_data(x,y)=sum_data(x,y)/cnt_data(x,y) + N_data=N_data+1 + else + ave_data(x,y)=nodata_LARC + endif + enddo + enddo - end if + ! allocate pointers for return vectors (must be deallocated outside this subroutine!) + + allocate(lon( N_data)) + allocate(lat( N_data)) + allocate(ts_LaRC(N_data)) + + ! pass return data into vectors + + i=1 + do x=x_min, x_max + do y=y_min, y_max + if ( abs(ave_data(x,y)-nodata_LARC) .GT. tol ) then + ts_LaRC(i)=ave_data(x,y) + lon(i)=(x-1)*dlon -180. + lat(i)=(y-1)*dlat - 90. + i=i+1 + endif + enddo + enddo + + ! clean up + + deallocate(tmp_data) + deallocate(sum_data) + deallocate(cnt_data) + deallocate(ave_data) + deallocate(tmp_vza) + deallocate(tmp_sza) + deallocate(tmp_fcld) + + else + + N_data=0 + + ! OK not to allocate pointers for data? + + endif - end subroutine read_obs_RedArkOSSE_CLSMsynthSM + end subroutine read_LaRC_Tskin_nc4 ! ***************************************************************** - - subroutine read_obs_VivianaOK_CLSMsynthSM( date_time, N_catd, & - this_obs_param, & - found_obs, VivianaOK_CLSMsynthSM, std_VivianaOK_CLSMsynthSM ) - ! Read synthetic observations of surface soil moisture from CLSM - ! integration over Viviana's OK domain - ! + subroutine read_obs_RedArkOSSE_sm( & + date_time, N_catd, tile_coord, this_obs_param, & + found_obs, RedArkOSSE_sm, std_RedArkOSSE_sm ) + + ! Read observations of surface soil moisture from Wade Crow's + ! synthetic RedArk OSSE 36km soil moisture files. ! Set flag "found_obs" to true if observations are available ! for assimilation. ! + ! If there are N > 1 observations in a given tile, + ! a "super-observation" is computed by averaging the N observations. + ! ! inputs to this subroutine: ! date_time = current model date and time ! N_catd = number of catchments in domain ! - ! vmaggion + reichle, 4 Aug 2008: - ! adapted from read_obs_RedArkOSSE_CLSMsynthSM - ! use obs std from default nml input (instead of reading from file) + ! reichle, 25 May 2006 + ! reichle, 26 Sep 2006 - added iostat to open statement ! ! -------------------------------------------------------------------- @@ -2896,37 +3017,57 @@ subroutine read_obs_VivianaOK_CLSMsynthSM( date_time, N_catd, & integer, intent(in) :: N_catd + type(tile_coord_type), dimension(:), pointer :: tile_coord ! input + type(obs_param_type), intent(in) :: this_obs_param ! outputs: - real, intent(out), dimension(N_catd) :: VivianaOK_CLSMsynthSM - real, intent(out), dimension(N_catd) :: std_VivianaOK_CLSMsynthSM + real, intent(out), dimension(N_catd) :: RedArkOSSE_sm + real, intent(out), dimension(N_catd) :: std_RedArkOSSE_sm logical, intent(out) :: found_obs ! --------------- ! locals - ! VivianaOK CLSM synthetic soil moisture obs are available once a day. + ! RedArkOSSE synthetic soil moisture obs at 36km are available once a day. + ! + ! Mapping of the 36km retrievals to catchment/tile space is precomputed + ! and stored in p2t_nearest.dat and t2p_nearest.dat - integer, parameter :: HH_obs = 12 ! obs hour of day (UTC) = 6am CST + integer, parameter :: N_p2t = 1120 ! # of 36 km pixels + integer, parameter :: N_t2p = 69 ! # of tiles that need "duplicated" obs - real, parameter :: nodata = -9999. + integer, parameter :: HH_obs = 21 ! obs hour of day (UTC) = 3pm CST ! initial QC parameters - + real, parameter :: obs_min = 0.0 ! min allowed obs - real, parameter :: obs_max = 0.5 ! max allowed obs + real, parameter :: obs_max = 0.45 ! max allowed obs + real, parameter :: opac_max = 0.3 ! max allowed vegetation opacity - character(2) :: MM, DD, HH + integer, parameter :: qc_failed_obs = -888. + + integer, dimension(N_p2t) :: p2t + integer, dimension(N_t2p,2) :: t2p + + character(3) :: DDD character(4) :: YYYY character(300) :: tmpfname - integer :: i, istat + integer :: i, j, ind, N_tmp, tmp_tile_id, istat - real :: tmp_obs, tmp_obs_std + real :: tmp_real, tmp_opac + + real, dimension(:), allocatable :: tmp_obs + integer, dimension(:), allocatable :: tmp_tile_num + integer, dimension(N_catd) :: N_obs_in_tile + + character(len=*), parameter :: Iam = 'read_obs_RedArkOSSE_sm' + character(len=400) :: err_msg + ! ------------------------------------------------------------------- ! initialize @@ -2934,61 +3075,218 @@ subroutine read_obs_VivianaOK_CLSMsynthSM( date_time, N_catd, & found_obs = .false. ! obs are available only once per day - ! (hard-coded b/c time-of-day is not very clear in VivianaOK + ! (hard-coded b/c time-of-day is not clear from filename) if (date_time%hour == HH_obs) then + ! read observations: + ! + ! 1.) read observations, p2t, and t2p from files + ! 2.) for each observation determine tile_num ("p2t") + ! 3.) duplicate observations for tiles that are not covered yet ("t2p") + ! 4.) compute super-obs for each tile from all obs w/in that tile + ! + ! ---------------------------------------------------------------- + + ! 1.) a) read obs + write (YYYY,'(i4.4)') date_time%year - write (MM, '(i2.2)') date_time%month - write (DD, '(i2.2)') date_time%day - write (HH, '(i2.2)') HH_obs + write (DDD, '(i3.3)') date_time%dofyr - tmpfname = trim(this_obs_param%path) // '/' // & - trim(this_obs_param%name) // YYYY // MM // DD // '_' // HH // 'z.txt' + tmpfname = trim(this_obs_param%path) // '/' // YYYY // & + '/' // trim(this_obs_param%name) // YYYY // '.' // DDD open(10, file=tmpfname, form='formatted', action='read', iostat=istat) if (istat==0) then - ! do NOT use obs std from file - ! (s.t. "wrong" obs std can be specified conveniently in nml file) - - tmp_obs_std = this_obs_param%errstd + N_tmp = N_p2t + N_t2p - VivianaOK_CLSMsynthSM( 1:N_catd) = nodata - std_VivianaOK_CLSMsynthSM(1:N_catd) = tmp_obs_std + allocate(tmp_obs(N_tmp)) + allocate(tmp_tile_num(N_tmp)) - do i=1,N_catd + do i=1,N_p2t - read(10,*) tmp_obs + read(10,*) tmp_real, tmp_opac + + tmp_obs(i) = tmp_real/100. ! unit conversion ! initial QC - tmp_obs = min( obs_max, tmp_obs ) - tmp_obs = max( obs_min, tmp_obs ) + if ( (tmp_opac > opac_max) .or. & + (tmp_obs(i) > obs_max) .or. & + (tmp_obs(i) < obs_min) ) then + + tmp_obs(i) = qc_failed_obs + + end if - VivianaOK_CLSMsynthSM(i) = tmp_obs + end do + + close(10,status='keep') + + ! 1.) b) read p2t + + tmpfname = trim(this_obs_param%path) // '/p2t_nearest.dat' + + open(10, file=tmpfname, form='formatted', action='read') + + do i=1,N_p2t - if (abs(tmp_obs-nodata)>1e-4) found_obs = .true. + read(10,*) p2t(i), tmp_tile_id ! col 1: tile_num, col 2: tile_id + + ! check tile_id for consistency + + if (p2t(i)>0) then ! if statement added 1 May 2007, reichle + if (tmp_tile_id/=tile_coord(p2t(i))%tile_id) then + + !write (logunit,*) 'read_obs_RedArkOSSE(): something is wrong (p2t)' + !!!write (logunit,*) i, p2t(i), tmp_tile_id, tile_coord(p2t(i))%tile_id + !stop + + err_msg = 'something is wrong (p2t)' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + + end if + end if end do close(10,status='keep') + ! 1.) c) read t2p + + tmpfname = trim(this_obs_param%path) // '/t2p_nearest.dat' + + open(10, file=tmpfname, form='formatted', action='read') + + do i=1,N_t2p + + read(10,*) t2p(i,1:2), tmp_tile_id ! pixel_num, tile_num, tile_id + + if (tmp_tile_id/=tile_coord(t2p(i,2))%tile_id) then + err_msg = 'something is wrong (t2p)' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + end if + + !write (logunit,*) 'read_obs_RedArkOSSE(): something is wrong (t2p)' + !stop + ! + !end if + + end do + + close(10,status='keep') + + ! ----------------------- + ! + ! 2.) for each observation determine tile_num ("p2t") + + do i=1,N_p2t + + tmp_tile_num(i) = p2t(i) + + end do + + ! ----------------------- + ! + ! 3.) duplicate observations for tiles not covered yet ("t2p") + + do i=1,N_t2p + + j = i + N_p2t + + tmp_obs( j) = tmp_obs(t2p(i,1)) + + tmp_tile_num(j) = t2p(i,2) + + end do + + + ! ------------------------ + ! + ! 4.) compute super-obs for each tile from all obs w/in that tile + ! (also eliminate observations that are not in domain) + + RedArkOSSE_sm = 0. + N_obs_in_tile = 0 + + do i=1,N_tmp + + ind = tmp_tile_num(i) ! 1<=tmp_tile_num<=N_catd (unless nodata) + + if (ind>0) then ! this step eliminates obs outside domain + + if (tmp_obs(i)>0.) then ! this step eliminates no-data + + RedArkOSSE_sm(ind) = RedArkOSSE_sm(ind) + tmp_obs(i) + + N_obs_in_tile(ind) = N_obs_in_tile(ind) + 1 + + end if + + end if + + end do + + ! normalize + + do i=1,N_catd + + if (N_obs_in_tile(i)>1) then + + RedArkOSSE_sm(i) = RedArkOSSE_sm(i)/real(N_obs_in_tile(i)) + + elseif (N_obs_in_tile(i)==0) then + + RedArkOSSE_sm(i) = this_obs_param%nodata + + end if + + end do + + ! -------------------------------- + + ! set observation error standard deviation + + do i=1,N_catd + std_RedArkOSSE_sm(i) = this_obs_param%errstd + end do + + ! -------------------------------- + + if (any(N_obs_in_tile>0)) then + + found_obs = .true. + + else + + found_obs = .false. + + end if + end if ! istat==0 + ! clean up + + if (allocated(tmp_tile_num)) deallocate(tmp_tile_num) + if (allocated(tmp_obs)) deallocate(tmp_obs) + end if - end subroutine read_obs_VivianaOK_CLSMsynthSM - - ! ***************************************************************** + end subroutine read_obs_RedArkOSSE_sm - subroutine read_obs_RedArkOSSE_truth( & - date_time, N_catd, this_obs_param, & - found_obs, RedArkOSSE_truth, std_RedArkOSSE_truth ) + ! ******************************************************************* + + subroutine read_obs_RedArkOSSE_CLSMsynthSM( date_time, N_catd, & + this_obs_param, & + found_obs, RedArkOSSE_CLSMsynthSM, std_RedArkOSSE_CLSMsynthSM ) - ! Read "observations" of true surface soil moisture from Wade Crow's - ! truth soil moisture in CLSM catchment space. + ! Read synthetic observations of surface soil moisture from CLSM + ! RedArkOSSE integration (generated in matlab from innov output with + ! get_RedArk_CLSM_synth_retrievals.m) + ! + ! synthetic RedArk OSSE 36km soil moisture files. ! Set flag "found_obs" to true if observations are available ! for assimilation. ! @@ -2996,7 +3294,9 @@ subroutine read_obs_RedArkOSSE_truth( & ! date_time = current model date and time ! N_catd = number of catchments in domain ! - ! reichle, 18 Sep 2006 + ! reichle, 16 Feb 2006 + ! reichle, 5 Apr 2007 - use obs std from default nml input + ! (instead of reading from file) ! ! -------------------------------------------------------------------- @@ -3012,29 +3312,32 @@ subroutine read_obs_RedArkOSSE_truth( & ! outputs: - real, intent(out), dimension(N_catd) :: RedArkOSSE_truth - real, intent(out), dimension(N_catd) :: std_RedArkOSSE_truth + real, intent(out), dimension(N_catd) :: RedArkOSSE_CLSMsynthSM + real, intent(out), dimension(N_catd) :: std_RedArkOSSE_CLSMsynthSM logical, intent(out) :: found_obs ! --------------- ! locals - ! RedArkOSSE soil moisture truth available once a day. - ! - ! Truth is stored directly in Catchment space + ! RedArkOSSE CLSM synthetic soil moisture obs are available once a day. integer, parameter :: HH_obs = 21 ! obs hour of day (UTC) = 3pm CST - character(2), parameter :: HH = '15' ! might be CST??? + real, parameter :: nodata = -9999. - character(3) :: DDD - character(4) :: YYYY + ! initial QC parameters + + real, parameter :: obs_min = 0.0 ! min allowed obs + real, parameter :: obs_max = 0.5 ! max allowed obs + + character(2) :: MM, DD + character(4) :: YYYY, HHMM character(300) :: tmpfname - integer :: i, istat + integer :: i, N_tmp, istat, tmp_tilenum - real :: tmp_real + real :: tmp_obs, tmp_obs_std ! ------------------------------------------------------------------- @@ -3043,73 +3346,79 @@ subroutine read_obs_RedArkOSSE_truth( & found_obs = .false. ! obs are available only once per day - ! (hard-coded b/c time-of-day is not clear from filename) + ! (hard-coded b/c time-of-day is not very clear in RedArkOSSE if (date_time%hour == HH_obs) then - ! read observations from file - write (YYYY,'(i4.4)') date_time%year - write (DDD, '(i3.3)') date_time%dofyr - - ! file name - - tmpfname = trim(this_obs_param%path) // '/' // YYYY // & - '/' // trim(this_obs_param%name) // YYYY // '.' // DDD // '.' // HH + write (MM, '(i2.2)') date_time%month + write (DD, '(i2.2)') date_time%day + write (HHMM,'(i4.4)') 100*HH_obs - ! open file and read obs if available + tmpfname = trim(this_obs_param%path) // '/Y' // YYYY // '/M' // MM // & + '/' // trim(this_obs_param%name) // YYYY // MM // DD // '_' // HHMM open(10, file=tmpfname, form='formatted', action='read', iostat=istat) if (istat==0) then - do i=1,N_catd + read(10,*) N_tmp + read(10,*) ! tmp_obs_std + + ! do NOT use obs std from file + ! (s.t. "wrong" obs std can be specified conveniently in nml file) + ! reichle, 5 Apr 2007 + + tmp_obs_std = this_obs_param%errstd + + RedArkOSSE_CLSMsynthSM( 1:N_catd) = nodata + std_RedArkOSSE_CLSMsynthSM(1:N_catd) = tmp_obs_std + + do i=1,N_tmp - read(10,*) tmp_real + read(10,*) tmp_tilenum, tmp_obs - RedArkOSSE_truth(i) = tmp_real/100. ! unit conversion + ! initial QC + + tmp_obs = min( obs_max, tmp_obs ) + tmp_obs = max( obs_min, tmp_obs ) + + RedArkOSSE_CLSMsynthSM( tmp_tilenum ) = tmp_obs end do close(10,status='keep') - ! set observation error standard deviation - - do i=1,N_catd - std_RedArkOSSE_truth(i) = this_obs_param%errstd - end do - found_obs = .true. - end if + end if ! istat==0 + end if - - end subroutine read_obs_RedArkOSSE_truth + + end subroutine read_obs_RedArkOSSE_CLSMsynthSM ! ***************************************************************** - subroutine read_obs_isccp_tskin_gswp2_v1( & - date_time, N_catd, tile_coord, & - tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & - this_obs_param, & - found_obs, isccp_tskin_gswp2_v1, std_isccp_tskin_gswp2_v1 ) + subroutine read_obs_VivianaOK_CLSMsynthSM( date_time, N_catd, & + this_obs_param, & + found_obs, VivianaOK_CLSMsynthSM, std_VivianaOK_CLSMsynthSM ) - ! Read observations of land skin temperature from ISCCP data - ! produced by Sarith on GSWP-2 grid + ! Read synthetic observations of surface soil moisture from CLSM + ! integration over Viviana's OK domain + ! ! Set flag "found_obs" to true if observations are available ! for assimilation. ! - ! If there are N > 1 observations in a given tile, - ! a "super-observation" is computed by averaging the N observations - ! ! inputs to this subroutine: ! date_time = current model date and time ! N_catd = number of catchments in domain ! - ! reichle, 26 Sep 2005 + ! vmaggion + reichle, 4 Aug 2008: + ! adapted from read_obs_RedArkOSSE_CLSMsynthSM + ! use obs std from default nml input (instead of reading from file) ! ! -------------------------------------------------------------------- - + implicit none ! inputs: @@ -3118,32 +3427,254 @@ subroutine read_obs_isccp_tskin_gswp2_v1( & integer, intent(in) :: N_catd - type(tile_coord_type), dimension(:), pointer :: tile_coord ! input - - type(grid_def_type), intent(in) :: tile_grid_d - - integer, dimension(tile_grid_d%N_lon,tile_grid_d%N_lat), intent(in) :: & - N_tile_in_cell_ij - - integer, dimension(:,:,:), pointer :: tile_num_in_cell_ij ! input - type(obs_param_type), intent(in) :: this_obs_param ! outputs: - real, intent(out), dimension(N_catd) :: isccp_tskin_gswp2_v1 - real, intent(out), dimension(N_catd) :: std_isccp_tskin_gswp2_v1 + real, intent(out), dimension(N_catd) :: VivianaOK_CLSMsynthSM + real, intent(out), dimension(N_catd) :: std_VivianaOK_CLSMsynthSM logical, intent(out) :: found_obs ! --------------- ! locals + + ! VivianaOK CLSM synthetic soil moisture obs are available once a day. - integer, parameter :: N_gswp2_compressed = 15238 + integer, parameter :: HH_obs = 12 ! obs hour of day (UTC) = 6am CST - ! land_i_gswp2 and land_j_gswp2 as stored in - ! ISCCP_Tskin_GSWP2_grid_V1 files (by Sarith) follow the GSWP2 convention - ! for grid orientation, that is counting from north-to-south + real, parameter :: nodata = -9999. + + ! initial QC parameters + + real, parameter :: obs_min = 0.0 ! min allowed obs + real, parameter :: obs_max = 0.5 ! max allowed obs + + character(2) :: MM, DD, HH + character(4) :: YYYY + character(300) :: tmpfname + + integer :: i, istat + + real :: tmp_obs, tmp_obs_std + + ! ------------------------------------------------------------------- + + ! initialize + + found_obs = .false. + + ! obs are available only once per day + ! (hard-coded b/c time-of-day is not very clear in VivianaOK + + if (date_time%hour == HH_obs) then + + write (YYYY,'(i4.4)') date_time%year + write (MM, '(i2.2)') date_time%month + write (DD, '(i2.2)') date_time%day + write (HH, '(i2.2)') HH_obs + + tmpfname = trim(this_obs_param%path) // '/' // & + trim(this_obs_param%name) // YYYY // MM // DD // '_' // HH // 'z.txt' + + open(10, file=tmpfname, form='formatted', action='read', iostat=istat) + + if (istat==0) then + + ! do NOT use obs std from file + ! (s.t. "wrong" obs std can be specified conveniently in nml file) + + tmp_obs_std = this_obs_param%errstd + + VivianaOK_CLSMsynthSM( 1:N_catd) = nodata + std_VivianaOK_CLSMsynthSM(1:N_catd) = tmp_obs_std + + do i=1,N_catd + + read(10,*) tmp_obs + + ! initial QC + + tmp_obs = min( obs_max, tmp_obs ) + tmp_obs = max( obs_min, tmp_obs ) + + VivianaOK_CLSMsynthSM(i) = tmp_obs + + if (abs(tmp_obs-nodata)>1e-4) found_obs = .true. + + end do + + close(10,status='keep') + + end if ! istat==0 + + end if + + end subroutine read_obs_VivianaOK_CLSMsynthSM + + ! ***************************************************************** + + subroutine read_obs_RedArkOSSE_truth( & + date_time, N_catd, this_obs_param, & + found_obs, RedArkOSSE_truth, std_RedArkOSSE_truth ) + + ! Read "observations" of true surface soil moisture from Wade Crow's + ! truth soil moisture in CLSM catchment space. + ! Set flag "found_obs" to true if observations are available + ! for assimilation. + ! + ! inputs to this subroutine: + ! date_time = current model date and time + ! N_catd = number of catchments in domain + ! + ! reichle, 18 Sep 2006 + ! + ! -------------------------------------------------------------------- + + implicit none + + ! inputs: + + type(date_time_type), intent(in) :: date_time + + integer, intent(in) :: N_catd + + type(obs_param_type), intent(in) :: this_obs_param + + ! outputs: + + real, intent(out), dimension(N_catd) :: RedArkOSSE_truth + real, intent(out), dimension(N_catd) :: std_RedArkOSSE_truth + logical, intent(out) :: found_obs + + ! --------------- + + ! locals + + ! RedArkOSSE soil moisture truth available once a day. + ! + ! Truth is stored directly in Catchment space + + integer, parameter :: HH_obs = 21 ! obs hour of day (UTC) = 3pm CST + + character(2), parameter :: HH = '15' ! might be CST??? + + character(3) :: DDD + character(4) :: YYYY + character(300) :: tmpfname + + integer :: i, istat + + real :: tmp_real + + ! ------------------------------------------------------------------- + + ! initialize + + found_obs = .false. + + ! obs are available only once per day + ! (hard-coded b/c time-of-day is not clear from filename) + + if (date_time%hour == HH_obs) then + + ! read observations from file + + write (YYYY,'(i4.4)') date_time%year + write (DDD, '(i3.3)') date_time%dofyr + + ! file name + + tmpfname = trim(this_obs_param%path) // '/' // YYYY // & + '/' // trim(this_obs_param%name) // YYYY // '.' // DDD // '.' // HH + + ! open file and read obs if available + + open(10, file=tmpfname, form='formatted', action='read', iostat=istat) + + if (istat==0) then + + do i=1,N_catd + + read(10,*) tmp_real + + RedArkOSSE_truth(i) = tmp_real/100. ! unit conversion + + end do + + close(10,status='keep') + + ! set observation error standard deviation + + do i=1,N_catd + std_RedArkOSSE_truth(i) = this_obs_param%errstd + end do + + found_obs = .true. + + end if + end if + + end subroutine read_obs_RedArkOSSE_truth + + ! ***************************************************************** + + subroutine read_obs_isccp_tskin_gswp2_v1( & + date_time, N_catd, tile_coord, & + tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & + this_obs_param, & + found_obs, isccp_tskin_gswp2_v1, std_isccp_tskin_gswp2_v1 ) + + ! Read observations of land skin temperature from ISCCP data + ! produced by Sarith on GSWP-2 grid + ! Set flag "found_obs" to true if observations are available + ! for assimilation. + ! + ! If there are N > 1 observations in a given tile, + ! a "super-observation" is computed by averaging the N observations + ! + ! inputs to this subroutine: + ! date_time = current model date and time + ! N_catd = number of catchments in domain + ! + ! reichle, 26 Sep 2005 + ! + ! -------------------------------------------------------------------- + + implicit none + + ! inputs: + + type(date_time_type), intent(in) :: date_time + + integer, intent(in) :: N_catd + + type(tile_coord_type), dimension(:), pointer :: tile_coord ! input + + type(grid_def_type), intent(in) :: tile_grid_d + + integer, dimension(tile_grid_d%N_lon,tile_grid_d%N_lat), intent(in) :: & + N_tile_in_cell_ij + + integer, dimension(:,:,:), pointer :: tile_num_in_cell_ij ! input + + type(obs_param_type), intent(in) :: this_obs_param + + ! outputs: + + real, intent(out), dimension(N_catd) :: isccp_tskin_gswp2_v1 + real, intent(out), dimension(N_catd) :: std_isccp_tskin_gswp2_v1 + logical, intent(out) :: found_obs + + ! --------------- + + ! locals + + integer, parameter :: N_gswp2_compressed = 15238 + + ! land_i_gswp2 and land_j_gswp2 as stored in + ! ISCCP_Tskin_GSWP2_grid_V1 files (by Sarith) follow the GSWP2 convention + ! for grid orientation, that is counting from north-to-south ! and from west-to-east real, parameter :: minlon_gswp2 = -180.5 @@ -4531,61 +5062,971 @@ subroutine read_obs_SMOS( date_time, N_catd, this_obs_param, & deallocate(tmp_ang) - deallocate(tmp_lon) - deallocate(tmp_lat) - - deallocate(tmp_obs) + deallocate(tmp_lon) + deallocate(tmp_lat) + + deallocate(tmp_obs) + + end if + + do k=1,N_files + + close(unitnum(k),status='keep') + + end do + + deallocate(unitnum) + + deallocate(start_time) + deallocate(end_time) + deallocate(Asc_flag) + deallocate(N_ang_tmp) + + end if ! if N_files>0 + + ! ------------------------------------------------- + ! + ! write "obslog" file + + if (write_obslog) then + + YYYYMMDD_HHMMSSz = date_time2string(date_time) + + tmpstr80 = 'read_obs_SMOS()' ! name of this subroutine + + do k=1,N_files + + write (tmpstr12,'(i12)') N_obs_tmp(k) ! convert integer to string + + call add_to_obslog( YYYYMMDD_HHMMSSz, this_obs_param%descr, tmpstr80, & + tmpstr12, fnames(k) ) + + end do + + end if + + ! clean up + + if (N_files>0) deallocate(N_obs_tmp) + + deallocate(fnames) + + if (logit) write (logunit,*) 'read_obs_SMOS(): done.' + + end subroutine read_obs_SMOS + + + ! ***************************************************************** + + subroutine read_obs_MODIS_SCF( & + date_time, dtstep_assim, N_catd, tile_coord, & + tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & + this_obs_param, & + found_obs, MODIS_obs, std_MODIS_obs, MODIS_lon, MODIS_lat ) + + ! read MODIS snow cover fraction observations on MODIS 0.05-degree climate + ! modeling grid (CMG) + ! + ! Terra: MOD10C1 + ! Aqua: MYD10C1 + ! + ! For now, assume that MODIS resolution is finer than Catchment tile space + ! and super-ob data to tile space, with lat/lon coords of obs matching + ! lat/lon coords of tiles + ! + ! reichle, 18 Oct 2023 + ! + ! ------------------------------------------------------------------------------ + + implicit none + + ! inputs + + type(date_time_type), intent(in) :: date_time + + integer, intent(in) :: dtstep_assim ! [seconds] + integer, intent(in) :: N_catd + + type(tile_coord_type), dimension(:), pointer :: tile_coord ! input + + type(grid_def_type), intent(in) :: tile_grid_d + + integer, dimension(tile_grid_d%N_lon,tile_grid_d%N_lat), intent(in) :: N_tile_in_cell_ij + + integer, dimension(:,:,:), pointer :: tile_num_in_cell_ij ! input + + type(obs_param_type), intent(in) :: this_obs_param + + ! output + + logical, intent(out) :: found_obs + + real, dimension(N_catd), intent(out) :: MODIS_obs, std_MODIS_obs, MODIS_lon, MODIS_lat + + ! ------------------------------------------------------------------------ + + ! locals + + integer, parameter :: dtstep_assim_max = 21600 ! [seconds] avoid assim window spanning >=180 deg lon + + real, parameter :: CMG_dlon = 0.05 ! [degrees] longitude spacing of MODIS CMG grid + real, parameter :: CMG_dlat = 0.05 ! [degrees] latitude spacing of MODIS CMG grid + + real, parameter :: CMG_ll_lon = -180. ! [degrees] lower-left longitude of MODIS CMG grid + real, parameter :: CMG_ur_lat = 90. ! [degrees] upper-right latitude of MODIS CMG grid + + character(7) :: MODIS_product_ID + + character(4) :: YYYY + character(3) :: DDD ! day of year + + character(400) :: fname + + real :: overpass_hour, tmp_delta, tmp_real, max_delta_lon + + integer :: N_files, N_lon, N_lat, N_tmp, nn, kk, ind + integer :: N_CMG_obs, N_good_data, tmp_ind_start, tmp_ind_last + + type(date_time_type) :: date_time_beg, date_time_end + type(date_time_type) :: date_time_beg_MODIS, date_time_end_MODIS + + real :: lon_beg, lon_end + real :: lon_beg_MODIS, lon_end_MODIS + + integer :: delta_day_beg, delta_day_end + integer :: delta_day_beg_MODIS, delta_day_end_MODIS + + real :: lat_min, lat_max + + real, dimension(2) :: lon_min_vec, lon_max_vec + + integer, dimension(2) :: N_lon_vec, year_vec, dofyr_vec, start_ind, last_ind + + real, dimension(:), allocatable :: CMG_obs, CMG_lon, CMG_lat + + integer, dimension(:), allocatable :: tmp_tile_num + + integer, dimension(N_catd) :: N_obs_in_tile + + character(len=*), parameter :: Iam = 'read_obs_MODIS_SCF' + character(len=400) :: err_msg + + ! ---------------------------------------------------------------------------------- + ! + ! restrict assimilation time step to max allowed + + if (dtstep_assim > dtstep_assim_max) then + + err_msg = 'dtstep_assim exceeds max allowed' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + + end if + + + ! initialize + + found_obs = .false. + + + ! identify MODIS product and overpass hour + + MODIS_product_ID = this_obs_param%name(1:7) + + select case (MODIS_product_ID) + + case('MOD10C1'); overpass_hour = 10.5 ! [hours] Terra: 10:30am local time + + case('MYD10C1'); overpass_hour = 13.5 ! [hours] Aqua: 1:30pm local time + + end select + + + ! determine beginning and end of assimilation window + + date_time_beg = date_time + date_time_end = date_time + + call augment_date_time( -dtstep_assim/2, date_time_beg ) + call augment_date_time( dtstep_assim/2, date_time_end ) + + + ! determine longitude band associated with assimilation window and local overpass hour + ! + ! observations will be returned only for tiles with lon_end < tile_coord%com_lon <= lon_beg + + call localtime2longitude( date_time_beg, overpass_hour, lon_beg, delta_day_beg ) + call localtime2longitude( date_time_end, overpass_hour, lon_end, delta_day_end ) + + + ! determine (rough) longitude band for which MODIS obs need to be read + ! + ! --> because tiles have a non-zero extent, need to read MODIS obs in CMG grid cells located + ! in a wider band (lon_min-delta:lon_max+delta), + ! where delta should be somewhat larger than max( tile_coord%max_lon - tile_coord%min_lon ) + + tmp_delta = 3.*maxval( tile_coord(1:N_catd)%max_lon - tile_coord(1:N_catd)%min_lon ) ! [degrees] + + tmp_delta = tmp_delta/360.*86400. ! [seconds] + + date_time_beg_MODIS = date_time_beg + date_time_end_MODIS = date_time_end + + call augment_date_time( -nint(tmp_delta), date_time_beg_MODIS ) + call augment_date_time( nint(tmp_delta), date_time_end_MODIS ) + + call localtime2longitude( date_time_beg_MODIS, overpass_hour, lon_beg_MODIS, delta_day_beg_MODIS ) + call localtime2longitude( date_time_end_MODIS, overpass_hour, lon_end_MODIS, delta_day_end_MODIS ) + + ! adjust date_time_*_MODIS to reflect calendar date at lon_*_MODIS + + call augment_date_time( delta_day_beg_MODIS*86400, date_time_beg_MODIS ) + call augment_date_time( delta_day_end_MODIS*86400, date_time_end_MODIS ) + + ! put together arguments for call(s) to read_MODIS_SCF_hdf() + + lon_min_vec = MAPL_UNDEF + lon_max_vec = MAPL_UNDEF + + year_vec = -9999 + dofyr_vec = -9999 + + N_lon_vec = 0 + + if (lon_end_MODIS < lon_beg_MODIS) then + + if ( date_time_end_MODIS%dofyr == date_time_beg_MODIS%dofyr ) then + + ! need only one daily MODIS file and longitude band + + N_files = 1 + + lon_min_vec(1) = lon_end_MODIS + lon_max_vec(1) = lon_beg_MODIS + + year_vec( 1) = date_time_beg_MODIS%year + dofyr_vec( 1) = date_time_beg_MODIS%dofyr + + else + + ! this should never happen for dtstep_assim_max=21600 and overpass_hour=10:30am or 1:30pm + + write (logunit,*) 'overpass_hour = ', overpass_hour + write (logunit,*) 'date_time = ', date_time + write (logunit,*) 'date_time_beg = ', date_time_beg + write (logunit,*) 'date_time_end = ', date_time_end + write (logunit,*) 'date_time_beg_MODIS = ', date_time_beg_MODIS + write (logunit,*) 'date_time_end_MODIS = ', date_time_end_MODIS + write (logunit,*) 'lon_beg = ', lon_beg + write (logunit,*) 'lon_end = ', lon_end + write (logunit,*) 'lon_beg_MODIS = ', lon_beg_MODIS + write (logunit,*) 'lon_end_MODIS = ', lon_end_MODIS + + err_msg = 'encountered unexpected condition for longitude band!!!' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + + end if + + else + + ! longitude band wraps around dateline, two daily MODIS files are needed + ! (this could also occur if lon_*_MODIS=180., which would result in an + ! empty first longitude band, but because of tmp_delta>0, this should + ! never happen) + + N_files = 2 + + lon_min_vec(1) = lon_end_MODIS + lon_max_vec(1) = 179.999 ! use 179.999 such that zero-based last_ind<=N_lon-1 (see below) + + year_vec( 1) = date_time_end_MODIS%year + dofyr_vec( 1) = date_time_end_MODIS%dofyr + + lon_min_vec(2) = -180. + lon_max_vec(2) = lon_beg_MODIS + + year_vec( 2) = date_time_beg_MODIS%year + dofyr_vec( 2) = date_time_beg_MODIS%dofyr + + end if + + ! verify that longitude bands do not exceed max expected expected width + ! (add 0.1 degree of wiggle room) + + max_delta_lon = real(dtstep_assim_max + 2*nint(tmp_delta))/86400.*360. + 0.1 ! [degree] + + do nn=1,N_files + + if ( lon_max_vec(nn) - lon_min_vec(nn) > max_delta_lon ) then + + err_msg = 'longitude band too wide' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + + end if + + end do + + + ! determine latitude band covered by domain (no need to read obs outside domain) + + lat_min = minval( tile_coord(1:N_catd)%min_lat ) + lat_max = maxval( tile_coord(1:N_catd)%max_lat ) + + + ! determine N_lat and N_lon[_vec] (# CMG grid cells in lat/lon bands ) + + start_ind(1) = (CMG_ur_lat - lat_max )/CMG_dlat + last_ind(1) = (CMG_ur_lat - lat_min )/CMG_dlat + + N_lat = last_ind(1) - start_ind(1) + 1 + + start_ind = (lon_min_vec - CMG_ll_lon)/CMG_dlon + last_ind = (lon_max_vec - CMG_ll_lon)/CMG_dlon + + N_lon_vec = last_ind - start_ind + 1 + + N_lon = sum( N_lon_vec(1:N_files) ) + + + + ! ! dbg ! ! write (*,*) '###############################################################################' + ! ! dbg ! ! write (*,*) Iam // '():' + ! ! dbg ! ! write (*,*) 'lon_min_vec = ', lon_min_vec + ! ! dbg ! ! write (*,*) 'lon_max_vec = ', lon_max_vec + ! ! dbg ! ! write (*,*) 'start_ind = ', start_ind + ! ! dbg ! ! write (*,*) 'last_ind = ', last_ind + ! ! dbg ! ! write (*,*) 'lat_min = ', lat_min + ! ! dbg ! ! write (*,*) 'lat_max = ', lat_max + ! ! dbg ! ! write (*,*) 'year_vec = ', year_vec + ! ! dbg ! ! write (*,*) 'dofyr_vec = ', dofyr_vec + ! ! dbg ! ! write (*,*) 'N_lon_vec = ', N_lon_vec + ! ! dbg ! ! write (*,*) 'N_lat = ', N_lat + ! ! dbg ! ! write (*,*) '###############################################################################' + + + + ! allocate arrays for MODIS CMG data (max size that could possibly be needed for obs from both files) + + N_tmp = N_lon*N_lat + + allocate( CMG_obs(N_tmp) ) + allocate( CMG_lon(N_tmp) ) + allocate( CMG_lat(N_tmp) ) + + + ! read MODIS SCF obs + ! + ! - (renamed) files currently located at /discover/nobackup/projects/S2SHMA/MODIS/MOD10C1_V61/ (2010-2022) + ! + ! - in ensupd nml file, specify the file "name" according to the following template: + ! + ! %name = 'MOD10C1.Ayyyyddd.061.hdf' + ! + ! 1 2 + ! 123456789012345678901234 + ! + ! MOD10C1 = MODIS product name + ! .A = "acquisition time" indicator + ! yyyyddd = placeholder for year/day-of-year + ! .061 = version (Collection) indicator + ! .hdf = file name extension + ! + ! Assuming the MODIS file naming convention remains unchanged, the version can then + ! be specified in the nml file. + + N_CMG_obs = 0 ! initialize counter for "good" obs returned by calls to read_MODIS_SCF_hdf() + + do nn=1,N_files ! loop through longitude bands + + ! determine MODIS file name(s) + + write (YYYY,'(i4.4)') year_vec( nn) + write (DDD, '(i3.3)') dofyr_vec(nn) + + fname = & + trim(this_obs_param%path) // '/' // YYYY // '/' // & + this_obs_param%name(1:9) // YYYY // DDD // this_obs_param%name(17:24) + + ! determine sub-array of CMG_* + + tmp_ind_start = N_CMG_obs + 1 + tmp_ind_last = N_CMG_obs + N_lon_vec(nn)*N_lat + + call read_MODIS_SCF_hdf( fname, & + lon_min_vec(nn), lon_max_vec(nn), lat_min, lat_max, & + N_good_data, & + CMG_lon(tmp_ind_start:tmp_ind_last), & + CMG_lat(tmp_ind_start:tmp_ind_last), & + CMG_obs(tmp_ind_start:tmp_ind_last) ) + + N_CMG_obs = N_CMG_obs + N_good_data + + end do + + + ! return if no MODIS obs were found (found_obs=.false. per initialization above) + + if (N_CMG_obs==0) return + + + ! map to tile space + + allocate(tmp_tile_num(N_CMG_obs)) + + call get_tile_num_for_obs( N_catd, tile_coord, & + tile_grid_d, N_tile_in_cell_ij, & + tile_num_in_cell_ij, & + N_CMG_obs, CMG_lat(1:N_CMG_obs), CMG_lon(1:N_CMG_obs), & + this_obs_param, & + tmp_tile_num ) + + + std_MODIS_obs = this_obs_param%errstd + + MODIS_obs = 0. + MODIS_lon = 0. + MODIS_lat = 0. + + N_obs_in_tile = 0 + + do kk=1,N_CMG_obs + + ind = tmp_tile_num(kk) ! 1<=tmp_tile_num<=N_catd (unless nodata) + + if (ind>0) then ! this condition eliminates obs outside domain + + MODIS_obs( ind) = MODIS_obs( ind) + CMG_obs(kk) + MODIS_lon( ind) = MODIS_lon( ind) + CMG_lon(kk) + MODIS_lat( ind) = MODIS_lat( ind) + CMG_lat(kk) + + N_obs_in_tile(ind) = N_obs_in_tile(ind) + 1 + + end if + + end do + + ! normalize + + do kk=1,N_catd + if (N_obs_in_tile(kk)>0) then + + tmp_real = real(N_obs_in_tile(kk)) + + MODIS_obs(kk) = MODIS_obs(kk)/tmp_real + MODIS_lon(kk) = MODIS_lon(kk)/tmp_real + MODIS_lat(kk) = MODIS_lat(kk)/tmp_real + + else if (N_obs_in_tile(kk)==0) then + + MODIS_obs(kk) = this_obs_param%nodata + MODIS_lon(kk) = this_obs_param%nodata + MODIS_lat(kk) = this_obs_param%nodata + + end if + end do + + if (any(N_obs_in_tile>0)) then + + found_obs = .true. + + else + + found_obs = .false. + + end if + + deallocate(tmp_tile_num) + + deallocate(CMG_obs) + deallocate(CMG_lon) + deallocate(CMG_lat) + + ! to avoid double-counting of MODIS CMG obs, remove obs for tiles with center-of-mass longitude + ! falling outside the longitude band associated with assimilation window + + if (lon_end < lon_beg) then + + ! need only one longitude band (keep obs when lon_end<=com_lon<=lon_beg) + + do kk=1,N_catd + + if ( (tile_coord(kk)%com_lonlon_beg) ) & + MODIS_obs(kk) = this_obs_param%nodata + + end do + + else + + ! longitude band wraps around dateline (keep obs when -180<=com_lon<=lon_beg or lon_end<=com_lon<=180) + + do kk=1,N_catd + + if ( (tile_coord(kk)%com_lon>lon_beg) .and. (tile_coord(kk)%com_lon= 24.) ) then + + err_msg = 'input local_hour falls outside allowed range of 0:24' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + + end if + + ! initialize + + delta_day = 0 + + ! determine fractional UTC hour and time difference with local_hour + + UTC_hour = ( date_time%hour*3600 + date_time%min*60 + date_time%sec )/3600. ! 0 <= UTC_hour < 24 + + time_diff = local_hour - UTC_hour + + ! enforce -12. < time_diff <= 12. and determine associated date difference, if any + + if (time_diff <= -12.) then + + delta_day = 1 + + time_diff = time_diff + 24. + + elseif (time_diff > 12.) then + + delta_day = -1 + + time_diff = time_diff - 24. + + end if + + ! determine longitude + + longitude = time_diff/24.*360. + + end subroutine localtime2longitude + + ! ***************************************************************** + + subroutine read_MODIS_SCF_hdf( fname, lon_min, lon_max, lat_min, lat_max, & + N_good_data, CMG_lon, CMG_lat, CMG_SCF ) + + ! read snow cover area fraction (SCF) obs from daily MODIS Terra or Aqua M?D10C1, version 6.1 + ! - Terra: https://nsidc.org/data/mod10c1/versions/61 + ! - Aqua: https://nsidc.org/data/myd10c1/versions/61 + ! - daily data with spatial resolution of 0.05 deg on MODIS climate modeling grid (CMG) + ! - Terra: missing days 2016 d. 50-58 + ! - data are read for the requested lat/lon range + ! - apply QC + ! + ! reichle, 20 Oct 2023 + ! + ! ------------------------------------------------------------------------------------------------- + + implicit none + + character(*), intent(in) :: fname ! MODIS file name with full path + + real, intent(in) :: lon_min, lon_max ! -180 <= lon_* <= 180 + real, intent(in) :: lat_min, lat_max ! -90 <= lat_* <= 90 + + integer, intent(out) :: N_good_data + + real, dimension(:), intent(out) :: CMG_lon, CMG_lat, CMG_SCF ! NOTE: 1-dim array on CMG grid + + ! ------------------------------------------------- + + ! local parameters + + ! ll/ur_lon/lat simply indicate the extent of the MODIS CMG grid + ! + ! index increases from (-180,90) to (180,-90) (southward and eastward) + + integer, parameter :: CMG_N_lon = 7200 + integer, parameter :: CMG_N_lat = 3600 + + real, parameter :: CMG_ll_lon = -180. + real, parameter :: CMG_ll_lat = -90. + + real, parameter :: CMG_ur_lon = 180. + real, parameter :: CMG_ur_lat = 90. + + real, parameter :: CMG_dlon = 0.05 + real, parameter :: CMG_dlat = 0.05 + + integer, parameter :: N_fields = 3 + + character(22), dimension(N_fields), parameter :: field_names = (/ & + 'Day_CMG_Snow_Cover ', & ! 1 + 'Day_CMG_Clear_Index ', & ! 2 + 'Snow_Spatial_QA '/) ! 3 + + ! 1234567890123456789012 + ! 1 2 + + integer, parameter :: SCF_nodata = -9999. + + integer(KIND=2), parameter :: qc_snow_cover_max = 100 ! exclude lake ice, night, inland water, ocean, etc + integer(KIND=2), parameter :: qc_clear_index_min = 20 ! ensure sufficiently clear conditions + integer(KIND=2), parameter :: qc_snow_spatial_max = 2 ! data quality (0=best, 1=good, 2=OK, 3=poor, 4=other) + + integer, parameter :: DFACC_READ = 1 ! from hdf.inc + + integer, parameter :: uint8_min = 0 + integer, parameter :: uint8_max = 255 + + + ! local variables + + integer :: N_lon, N_lat, N_tmp, ii, jj, kk, nn + + real, dimension(:), allocatable :: lon_c + real, dimension(:), allocatable :: lat_c + + real, dimension(:), allocatable :: lon_ind + real, dimension(:), allocatable :: lat_ind + + integer, dimension(2) :: start, edge, stride, last, dimsizes + + logical :: file_exists, keep_data + + integer :: status, sd_id, sds_id, sds_index + + integer :: sfstart, sfn2index, sfselect, sfginfo + integer :: sfrdata, sfendacc, sfend + + character(64) :: sds_name + + integer :: rank, data_type, num_attrs + + integer(KIND=2), dimension(:,:), allocatable :: Snow_Cover + integer(KIND=2), dimension(:,:), allocatable :: Clear_Index + integer(KIND=2), dimension(:,:), allocatable :: Snow_Spatial_QA + + character(1), dimension(:,:), allocatable :: tmp_char1 + + character(len=*), parameter :: Iam = 'read_MODIS_SCF_hdf' + character(len=400) :: err_msg + + ! ------------------------------------------------------------------------- + ! + ! make sure file exists + + inquire( file=trim(fname), exist=file_exists ) + + if (.not. file_exists ) then + + if (logit) then + write (logunit,'(400A)') trim(Iam), ': cannot find file ', trim(fname) + write (logunit,* ) 'not reading MODIS SCF obs' + end if + + N_good_data = 0 + + return + + end if + + ! ensure lon_* and lat_* inputs are within range + + if ( (lon_min < CMG_ll_lon) .or. & + (lon_max > CMG_ur_lon) .or. & + (lat_min < CMG_ll_lat) .or. & + (lat_max > CMG_ur_lat) ) then + + err_msg = 'lat/lon min/max inputs out of range' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + + end if + + ! determine MODIS CMG array indices for requested lat/lon_min/max range + + ! MODIS CMG hdf files: + ! - lon-by-lat (NOTE: The metadata "s.Vgroup(1).Vgroup(1).SDS(1).Dims.Size" returned + ! by Matlab's hdfinfo() confusingly suggests that CMG files are + ! lat-by-lon, which is not the case!) + ! - index values increase eastward and southward + + start(1) = (lon_min - CMG_ll_lon)/CMG_dlon ! 0-based [as required for hdf read] + start(2) = (CMG_ur_lat - lat_max )/CMG_dlat ! 0-based [as required for hdf read] + + last(1) = (lon_max - CMG_ll_lon)/CMG_dlon ! 0-based [as required for hdf read] + last(2) = (CMG_ur_lat - lat_min )/CMG_dlat ! 0-based [as required for hdf read] + + N_lon = last(1) - start(1) + 1 + N_lat = last(2) - start(2) + 1 + + edge(1) = N_lon + edge(2) = N_lat + + stride(1) = 1 + stride(2) = 1 + + + + ! ! dbg ! ! write (*,*) '###############################################################################' + ! ! dbg ! ! write (*,*) Iam // '():' + ! ! dbg ! ! write (*,*) 'size(CMG_SCF), N_lon, N_lat = ', size(CMG_SCF), N_lon, N_lat + ! ! dbg ! ! write (*,*) 'lon_min, lon_max = ', lon_min, lon_max + ! ! dbg ! ! write (*,*) 'lat_min, lat_max = ', lat_min, lat_max + ! ! dbg ! ! write (*,*) 'start [lon, lat] = ', start + ! ! dbg ! ! write (*,*) 'last [lon, lat] = ', last + ! ! dbg ! ! write (*,*) 'edge [lon, lat] = ', edge + ! ! dbg ! ! write (*,*) '###############################################################################' + + + + ! checks array dimensions + + N_tmp = N_lon*N_lat + + if ( (N_tmp /= size(CMG_lon)) .or. & + (N_tmp /= size(CMG_lat)) .or. & + (N_tmp /= size(CMG_SCF)) ) then + + err_msg = 'inconsistent array dimensions' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + + end if + + ! check array bounds + + if ( ( start(1) < 0 ) .or. ( start(1) > CMG_N_lon - 1 ) .or. & + ( start(2) < 0 ) .or. ( start(2) > CMG_N_lat - 1 ) .or. & + ( last( 1) < 0 ) .or. ( last( 1) > CMG_N_lon - 1 ) .or. & + ( last( 2) < 0 ) .or. ( last( 2) > CMG_N_lat - 1 ) .or. & + ( start(1) > last(1) ) .or. ( start(2) > last(2) ) & + ) then + + err_msg = 'start/edge indices out of bounds' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + + end if + + if (logit) then + write (logunit,'(400A)') trim(Iam), '(): reading MODIS SCF obs from ', trim(fname) + write (logunit,* ) ' N_lon, N_lat, lon_min, lon_max, lat_min, lat_max = ' + write (logunit,* ) N_lon, N_lat, lon_min, lon_max, lat_min, lat_max + end if + + + ! allocate arrays + + allocate(lon_c( N_lon)) + allocate(lat_c( N_lat)) + + allocate(lon_ind(N_lon)) + allocate(lat_ind(N_lat)) + + allocate(Snow_Cover (N_lon,N_lat)) + allocate(Clear_Index (N_lon,N_lat)) + allocate(Snow_Spatial_QA(N_lon,N_lat)) + + allocate(tmp_char1( N_lon,N_lat)) + + ! -------------------------- + + ! determine center lat/lon of CMG cells + + lon_ind = (/(ii, ii=0, N_lon-1, 1)/) ! =0:(N_lon-1) + lat_ind = (/(jj, jj=0, N_lat-1, 1)/) ! =0:(N_lat-1) + + ! lat_c, lon_c are lat/lon at center of CMG grid cell + + lon_c = CMG_ll_lon + 0.5*CMG_dlon + (start(1)+lon_ind)*CMG_dlon + lat_c = CMG_ur_lat - 0.5*CMG_dlat - (start(2)+lat_ind)*CMG_dlat + + ! -------------------------- + + ! open hdf file (read-only) and initialize SD interface + + sd_id = sfstart(trim(fname), DFACC_READ) + + if (sd_id<0) then + + err_msg = 'cannot sfstart (open) file: ' // trim(fname) + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + + end if + + ! read data + + do nn=1,N_fields + + sds_index = sfn2index( sd_id, trim(field_names(nn)) ) + sds_id = sfselect( sd_id, sds_index ) + + + status = sfginfo( sds_id, sds_name, rank, dimsizes, data_type, num_attrs ) + + if ( (dimsizes(1)/=CMG_N_lon) .or. (dimsizes(2)/=CMG_N_lat) ) then + + err_msg = 'dimensions in hdf file doe not match CMG_N_lon and/or CMG_N_lat' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) end if - do k=1,N_files + + ! ######################################################### + ! ! dbg ! ! write (*,*) 'sds_name = ', trim(sds_name) + ! ! dbg ! ! write (*,*) 'rank, data_type, num_attrs = ', rank, data_type, num_attrs + ! ! dbg ! ! write (*,*) 'dimsizes = ', dimsizes + ! ######################################################### + - close(unitnum(k),status='keep') + select case (nn) - end do + case (1); status = sfrdata( sds_id, start, stride, edge, tmp_char1 ); Snow_Cover = ichar(tmp_char1,2) + case (2); status = sfrdata( sds_id, start, stride, edge, tmp_char1 ); Clear_Index = ichar(tmp_char1,2) + case (3); status = sfrdata( sds_id, start, stride, edge, tmp_char1 ); Snow_Spatial_QA = ichar(tmp_char1,2) + + case default; call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'unknown field') + + end select - deallocate(unitnum) + if (status/=0) then + + err_msg = 'error reading data from hdf file: ' // trim(fname) + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + + end if - deallocate(start_time) - deallocate(end_time) - deallocate(Asc_flag) - deallocate(N_ang_tmp) - - end if ! if N_files>0 + status = sfendacc(sds_id) ! terminate access to SDS (field) + + end do + + status = sfend(sd_id) ! close hdf file and SD interface - ! ------------------------------------------------- - ! - ! write "obslog" file + + ! ################################################################################# + ! ! dbg ! ! write (*,*) 'Snow_Cover(1:10,1:5)=' + ! ! dbg ! ! write (*,*) Snow_Cover(1:10,1:5) + ! ! dbg ! ! write (*,*) 'Clear_Index(1:10,1:5)=' + ! ! dbg ! ! write (*,*) Clear_Index(1:10,1:5) + ! ! dbg ! ! write (*,*) 'Snow_Spatial_QA(1:10,1:5)=' + ! ! dbg ! ! write (*,*) Snow_Spatial_QA(1:10,1:5) - if (write_obslog) then - - YYYYMMDD_HHMMSSz = date_time2string(date_time) + ! ! dbg ! ! !if ( (lon_min>-138) .and. (lon_min<-134) ) then + ! ! dbg ! ! if (.false.) then + ! ! dbg ! ! do jj=1,N_lat + ! ! dbg ! ! write(997) Snow_Cover( jj,:) + ! ! dbg ! ! write(998) Clear_Index( jj,:) + ! ! dbg ! ! write(999) Snow_Spatial_QA(jj,:) + ! ! dbg ! ! end do + ! ! dbg ! ! write (*,*) 'stopping after file dump ' + ! ! dbg ! ! stop + ! ! dbg ! ! end if + ! ################################################################################# + + + + ! check range (make sure uint8 from hdf file is correctly translated into Fortran integer) + + if ( any(Snow_Cover < uint8_min) .or. & + any(Snow_Cover > uint8_max) .or. & + any(Clear_Index < uint8_min) .or. & + any(Clear_Index > uint8_max) .or. & + any(Snow_Spatial_QA < uint8_min) .or. & + any(Snow_Spatial_QA > uint8_max) ) then - tmpstr80 = 'read_obs_SMOS()' ! name of this subroutine + err_msg = 'unexpected range in data from hdf file' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) - do k=1,N_files + end if + + ! ------------------------------------- + ! + ! apply QC and put SCF obs into output array + + CMG_lon = SCF_nodata ! initialize + CMG_lat = SCF_nodata ! initialize + CMG_SCF = SCF_nodata ! initialize + + kk = 0 ! initialize counter for "good" data + + do ii=1,N_lon + do jj=1,N_lat - write (tmpstr12,'(i12)') N_obs_tmp(k) ! convert integer to string + ! note: Snow_Cover >= 0 per range check above, no need to check for minimum - call add_to_obslog( YYYYMMDD_HHMMSSz, this_obs_param%descr, tmpstr80, & - tmpstr12, fnames(k) ) + keep_data = & + (Snow_Cover( ii,jj) <= qc_snow_cover_max ) .and. & ! 0<=SCF<=100 (1) + (Clear_Index( ii,jj) > qc_clear_index_min ) .and. & ! sufficiently clear sky (2) + (Snow_Spatial_QA(ii,jj) <= qc_snow_spatial_max) ! keep "best", "good", or "OK" quality (3) - end do - - end if - - ! clean up + ! (1) excludes "lake ice", "night", "inland water", "ocean", "cloud obscured water", "data not mapped", "fill" + ! (2) clear_index>100 already removed via qc_snow_cover_max + ! (3) excludes Antarctica + + if (keep_data) then - if (N_files>0) deallocate(N_obs_tmp) + kk = kk + 1 + + ! raw SCF value is for clear portion of grid cell only, need to normalize with Clear_Index + + CMG_SCF(kk) = real(Snow_Cover(ii,jj))/real(Clear_Index(ii,jj)) + + CMG_lon(kk) = lon_c(ii) + CMG_lat(kk) = lat_c(jj) + + end if + + end do + end do - deallocate(fnames) + N_good_data = kk - if (logit) write (logunit,*) 'read_obs_SMOS(): done.' + if (logit) write (logunit,*) 'N_good_data = ', N_good_data + + deallocate(lat_c) + deallocate(lon_c) - end subroutine read_obs_SMOS + deallocate(lat_ind) + deallocate(lon_ind) + + deallocate(Snow_Cover ) + deallocate(Clear_Index ) + deallocate(Snow_Spatial_QA) + + end subroutine read_MODIS_SCF_hdf ! ***************************************************************** - + subroutine read_obs_SMAP_FT( date_time, N_catd, this_obs_param, & dtstep_assim, tile_coord, tile_grid_d, & N_tile_in_cell_ij, tile_num_in_cell_ij, write_obslog, & @@ -4821,7 +6262,7 @@ subroutine read_obs_SMAP_FT( date_time, N_catd, this_obs_param, & ! read file with list of SMAP file names for first day - call read_obs_SMAP_fnames( date_time_low_fname, this_obs_param, & + call read_obs_fnames( date_time_low_fname, this_obs_param, & fname_of_fname_list, N_halforbits_max, & N_fnames, fname_list(1:N_halforbits_max) ) @@ -4830,7 +6271,7 @@ subroutine read_obs_SMAP_FT( date_time, N_catd, this_obs_param, & if (date_time_low_fname%day /= date_time_upp%day) then - call read_obs_SMAP_fnames( date_time_upp, this_obs_param, & + call read_obs_fnames( date_time_upp, this_obs_param, & fname_of_fname_list, N_halforbits_max, & N_fnames_tmp, fname_list((N_fnames+1):(N_fnames+N_halforbits_max)) ) @@ -5657,7 +7098,7 @@ subroutine read_obs_SMAP_halforbit_Tb( date_time, N_catd, this_obs_param, & ! read file with list of SMAP file names for first day - call read_obs_SMAP_fnames( date_time_low_fname, this_obs_param, & + call read_obs_fnames( date_time_low_fname, this_obs_param, & fname_of_fname_list, N_halforbits_max, & N_fnames, fname_list(1:N_halforbits_max) ) @@ -5666,7 +7107,7 @@ subroutine read_obs_SMAP_halforbit_Tb( date_time, N_catd, this_obs_param, & if (date_time_low_fname%day /= date_time_upp%day) then - call read_obs_SMAP_fnames( date_time_upp, this_obs_param, & + call read_obs_fnames( date_time_upp, this_obs_param, & fname_of_fname_list, N_halforbits_max, & N_fnames_tmp, fname_list((N_fnames+1):(N_fnames+N_halforbits_max)) ) @@ -6370,7 +7811,6 @@ subroutine turn_off_assim_SMAP_L1CTb(N_obs_param, obs_param, N_obsl, Observation logical, dimension(:,:), allocatable :: mask_h_D, mask_v_D character(len=*), parameter :: Iam = 'turn_off_assim_SMAP_L1CTb' - character(len=400) :: err_msg ! ------------------------------------------------------------------------------ @@ -6694,14 +8134,24 @@ end subroutine turn_off_assim_SMAP_L1CTb ! ***************************************************************** - subroutine read_obs_SMAP_fnames( date_time, this_obs_param, & - fname_of_fname_list, N_max, N_fnames, fname_list ) + subroutine read_obs_fnames( date_time, this_obs_param, & + fname_of_fname_list, N_max, N_fnames, fname_list, & + obs_dir_hier ) - ! read the file within a SMAP Yyyyy/Mmm/Ddd directory that lists - ! the SMAP h5 file names; preface file names with "Yyyyy/Mmm/Ddd" + ! read the file within an obs Yyyyy/Mmm/Ddd directory that lists + ! the obs file names, preface file names with "Yyyyy/Mmm/Ddd", + ! and return in "fname_list" + ! + ! optional input argument: + ! obs_dir_hier==1 : preface file names with "Yyyyy/Mmm" instead + ! + ! this subroutine is needed when obs file names cannot be predicted + ! and must be provided in a short text file that lists the file names + ! (e.g., SMAP Tb or soil moisture h5 files, ASCAT soil moisture BUFR files) ! ! reichle, 3 Jan 2014 ! reichle, 8 Jun 2017: Use "%flistpath" and "%flistname" from "obs_param_type". + ! A M Fox, reichle, 22 Sep 2023: added optional argument obs_dir_hier ! ! --------------------------------------------------------------------------------- @@ -6711,7 +8161,7 @@ subroutine read_obs_SMAP_fnames( date_time, this_obs_param, & type(obs_param_type), intent(in) :: this_obs_param - character( *), intent(in) :: fname_of_fname_list + character( *), intent(in) :: fname_of_fname_list integer, intent(in) :: N_max @@ -6719,6 +8169,8 @@ subroutine read_obs_SMAP_fnames( date_time, this_obs_param, & character(100), dimension(N_max), intent(out) :: fname_list + integer, optional, intent(in) :: obs_dir_hier + ! local variables character(300) :: fname @@ -6727,12 +8179,13 @@ subroutine read_obs_SMAP_fnames( date_time, this_obs_param, & character( 80) :: tmpstr80 character( 14) :: YYYYMMDDdir + character( 10) :: YYYYMMdir character( 4) :: YYYY character( 2) :: MM, DD integer :: ii, istat - character(len=*), parameter :: Iam = 'read_obs_SMAP_fnames' + character(len=*), parameter :: Iam = 'read_obs_fnames' character(len=400) :: err_msg ! --------------------------------------------------------------------- @@ -6742,6 +8195,7 @@ subroutine read_obs_SMAP_fnames( date_time, this_obs_param, & write (DD ,'(i2.2)') date_time%day YYYYMMDDdir = 'Y' // YYYY // '/M' // MM // '/D' // DD // '/' + YYYYMMdir = 'Y' // YYYY // '/M' // MM // '/' ! initialize default values @@ -6756,7 +8210,7 @@ subroutine read_obs_SMAP_fnames( date_time, this_obs_param, & fname = trim(fpath_tmp) // '/' // YYYYMMDDdir // trim(fname_tmp) open( 10, file=fname, form='formatted', action='read', iostat=istat) - + if (istat/=0) then err_msg = 'cannot open file ' // trim(fname) call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) @@ -6782,14 +8236,30 @@ subroutine read_obs_SMAP_fnames( date_time, this_obs_param, & call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) end if - ! preface file names with "Yyyyy/Mmm/Ddd" - + ! preface file names with "Yyyyy/Mmm/Ddd" (default) + fname_list(ii) = YYYYMMDDdir // trim(tmpstr80) + if (present(obs_dir_hier)) then + + if (obs_dir_hier == 1) then + + ! preface file names with "Yyyyy/Mmm" + + fname_list(ii) = YYYYMMdir // trim(tmpstr80) + + else + + err_msg = 'Unrecognized value of optional argument obs_dir_hier' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + + end if + end if + else exit - + end if end do @@ -6798,7 +8268,7 @@ subroutine read_obs_SMAP_fnames( date_time, this_obs_param, & N_fnames = ii - end subroutine read_obs_SMAP_fnames + end subroutine read_obs_fnames ! ***************************************************************** @@ -6941,7 +8411,7 @@ subroutine read_obs( & logical, intent(in) :: write_obslog ! outputs: - + real, intent(out), dimension(N_catd) :: tmp_obs real, intent(out), dimension(N_catd) :: tmp_std_obs real, intent(out), dimension(N_catd) :: tmp_lon @@ -6981,7 +8451,7 @@ subroutine read_obs( & ! choose appropriate reader select case (trim(this_obs_param%descr)) - + case ('ae_l2_sm_a', 'ae_l2_sm_d') call read_obs_ae_l2_sm( & @@ -7043,6 +8513,27 @@ subroutine read_obs( & tmp_obs, tmp_std_obs ) end if + + case ('ASCAT_META_SM','ASCAT_METB_SM','ASCAT_METC_SM' ) + + call read_obs_sm_ASCAT_EUMET( & + date_time, dtstep_assim, N_catd, tile_coord, & + tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & + this_obs_param, & + found_obs, tmp_obs, tmp_std_obs, tmp_lon, tmp_lat, & + tmp_time) + + ! scale observations to model climatology + + if (this_obs_param%scale .and. found_obs) then + + scaled_obs = .true. + + call scale_obs_sfmc_zscore( N_catd, tile_coord, & + date_time, this_obs_param, tmp_lon, tmp_lat, tmp_time, & + tmp_obs, tmp_std_obs ) + + end if case ('isccp_tskin_gswp2_v1') @@ -7197,7 +8688,7 @@ subroutine read_obs( & N_tile_in_cell_ij, tile_num_in_cell_ij, write_obslog, & found_obs, tmp_obs, tmp_std_obs, tmp_lon, tmp_lat ) - ! scale observations to model climatology XXXXXXX + ! scale observations to model climatology if (this_obs_param%scale .and. found_obs) then @@ -7207,7 +8698,15 @@ subroutine read_obs( & this_obs_param, tmp_obs, tmp_std_obs, tmp_assim ) end if - + + case ('MOD10C1','MYD10C1') + + call read_obs_MODIS_SCF( & + date_time, dtstep_assim, N_catd, tile_coord, & + tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & + this_obs_param, & + found_obs, tmp_obs, tmp_std_obs, tmp_lon, tmp_lat ) + case('SMAP_L1C_Tbh_A', 'SMAP_L1C_Tbv_A', & 'SMAP_L1C_Tbh_D', 'SMAP_L1C_Tbv_D', & 'SMAP_L1C_Tbh_E09_A', 'SMAP_L1C_Tbv_E09_A', & @@ -7216,14 +8715,14 @@ subroutine read_obs( & 'SMAP_L1C_Tbh_E27_D', 'SMAP_L1C_Tbv_E27_D', & 'SMAP_L2AP_Tbh_A', 'SMAP_L2AP_Tbv_A', & 'SMAP_L2AP_Tbh_D', 'SMAP_L2AP_Tbv_D' ) - + call read_obs_SMAP_halforbit_Tb( & date_time, N_catd, this_obs_param, & dtstep_assim, tile_coord, tile_grid_d, & N_tile_in_cell_ij, tile_num_in_cell_ij, write_obslog, & found_obs, tmp_obs, tmp_std_obs, tmp_lon, tmp_lat, tmp_time ) - ! scale observations to model climatology XXXXXXX + ! scale observations to model climatology if (this_obs_param%scale .and. found_obs) then @@ -7233,12 +8732,11 @@ subroutine read_obs( & this_obs_param, tmp_obs, tmp_std_obs, tmp_assim ) end if - + case('LaRC_tskin-GOESW', 'LaRC_tskin-GOESE', 'LaRC_tskin-MET09', & 'LaRC_tskin-FY2E-', 'LaRC_tskin-MTST2') call read_obs_LaRC_Tskin( & - work_path, exp_id, & date_time, dtstep_assim, N_catd, tile_coord, & tile_grid_d, N_tile_in_cell_ij, tile_num_in_cell_ij, & this_obs_param, & @@ -7657,6 +9155,251 @@ subroutine scale_obs_tskin_zscore( N_catd, tile_coord, & end subroutine scale_obs_tskin_zscore + + ! ***************************************************************** + + subroutine scale_obs_sfmc_zscore( N_catd, tile_coord, & + date_time, this_obs_param, tmp_lon, tmp_lat, tmp_time, & + tmp_obs, tmp_std_obs ) + + ! scale sfmc or sfds obs to model climatology via standard-normal-deviate (zscore) + ! scaling using seasonally varying (pentad) stats + ! Grid information is read from a NetCDF file + ! + ! Scaling parameters are read from a NetCDF file that contains the following: + ! variables: + ! int version ; + ! double ll_lon ; + ! ll_lon:standard_name = "longitude of lower left corner" ; + ! double ll_lat ; + ! ll_lat:standard_name = "latitude of lower left corner" ; + ! double d_lon ; + ! d_lon:standard_name = "longitude grid spacing" ; + ! double d_lat ; + ! d_lat:standard_name = "latitude grid spacing" ; + ! int pentad(pentad) ; + ! pentad:standard_name = "pentad" ; + ! double start_time(pentad) ; + ! start_time:standard_name = "start time" ; + ! double end_time(pentad) ; + ! end_time:standard_name = "end time" ; + ! double o_mean(pentad, lon, lat) ; + ! o_mean:standard_name = "observation mean" ; + ! double o_std(pentad, lon, lat) ; + ! o_std:standard_name = "observation standard deviation" ; + ! double m_mean(pentad, lon, lat) ; + ! m_mean:standard_name = "model mean" ; + ! double m_std(pentad, lon, lat) ; + ! m_std:standard_name = "model standard deviation" ; + ! double m_min(lon, lat) ; + ! m_min:standard_name = "model minimum" ; + ! double m_max(lon, lat) ; + ! m_max:standard_name = "model maximum" ; + ! double n_data(pentad, lon, lat) ; + ! n_data:standard_name = "number of data points" ; + ! + ! A M Fox, reichle, April 2023 + + use netcdf + implicit none + + integer, intent(in) :: N_catd + + type(tile_coord_type), dimension(:), pointer :: tile_coord ! input + + type(date_time_type), intent(in) :: date_time + + type(obs_param_type), intent(in) :: this_obs_param + + real, intent(in), dimension(N_catd) :: tmp_lon, tmp_lat + real*8, intent(in), dimension(N_catd) :: tmp_time ! J2000 seconds + + ! inout + + real, intent(inout), dimension(N_catd) :: tmp_obs + real, intent(inout), dimension(N_catd) :: tmp_std_obs + + ! ------------------- + + character(300) :: fname + + integer :: i, ind, pp, j_ind, i_ind + integer :: ncid, varid, ierr, ierr2 + integer :: pentad_dimid, lon_dimid, lat_dimid + integer :: N_pentad, N_lon, N_lat + integer :: pentad_varid + integer :: o_mean_varid, o_std_varid, m_mean_varid, m_std_varid, m_min_varid, m_max_varid + integer :: ll_lon_varid, ll_lat_varid, dlon_varid, dlat_varid + integer, dimension(3) :: start, icount + + logical :: file_exists + + real :: tmpreal, this_lon, this_lat, ll_lon, ll_lat, dlon, dlat + + integer, dimension(:), allocatable :: sclprm_tile_id + integer, dimension(:), allocatable :: pentads + + real, dimension(:,:), allocatable :: sclprm_mean_obs, sclprm_std_obs + real, dimension(:,:), allocatable :: sclprm_mean_mod, sclprm_std_mod + real, dimension(:,:), allocatable :: sclprm_min_mod, sclprm_max_mod + + character(len=*), parameter :: Iam = ' scale_obs_sfmc_zscore' + character(len=400) :: err_msg + + ! ------------------------------------------------------------------ + + ! Read scaling parameters from file + + fname = trim(this_obs_param%scalepath) // '/' // & + trim(this_obs_param%scalename) // '.nc4' + + if (logit) write (logunit,*) 'scaling obs species ', this_obs_param%species, ':' + if (logit) write (logunit,'(400A)') ' reading ', trim(fname) + + ! Check if file exists + + inquire(file=fname, exist=file_exists) + + if (.not. file_exists) then + + err_msg = 'Scaling parameter file not found' + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + + end if + + ! Determine pentad to use + + pp = date_time%pentad + + ! Open the NetCDF file + + ierr = nf90_open(fname, nf90_nowrite, ncid) + + ! Get the dimension and variable IDs + + ierr = nf90_inq_varid(ncid, 'll_lon', ll_lon_varid) + ierr = nf90_inq_varid(ncid, 'll_lat', ll_lat_varid) + ierr = nf90_inq_varid(ncid, 'd_lon', dlon_varid) + ierr = nf90_inq_varid(ncid, 'd_lat', dlat_varid) + + ! Get the dimension sizes + + ierr = nf90_inq_dimid(ncid, 'pentad', pentad_dimid) + ierr = nf90_inq_dimid(ncid, 'lon', lon_dimid) + ierr = nf90_inq_dimid(ncid, 'lat', lat_dimid) + + ierr = nf90_inquire_dimension(ncid, pentad_dimid, len = N_pentad) + ierr = nf90_inquire_dimension(ncid, lon_dimid, len = N_lon) + ierr = nf90_inquire_dimension(ncid, lat_dimid, len = N_lat) + + ! Get the variable IDs + + ierr = nf90_inq_varid(ncid, 'o_mean', o_mean_varid) + ierr = nf90_inq_varid(ncid, 'o_std', o_std_varid) + ierr = nf90_inq_varid(ncid, 'm_mean', m_mean_varid) + ierr = nf90_inq_varid(ncid, 'm_std', m_std_varid) + ierr = nf90_inq_varid(ncid, 'm_min', m_min_varid) + ierr = nf90_inq_varid(ncid, 'm_max', m_max_varid) + + ! Read grid variables + + ierr = nf90_get_var(ncid, ll_lon_varid, ll_lon) + ierr = nf90_get_var(ncid, ll_lat_varid, ll_lat) + ierr = nf90_get_var(ncid, dlon_varid, dlon) + ierr = nf90_get_var(ncid, dlat_varid, dlat) + + start = [1, 1, pp] + icount = [N_lat, N_lon, 1 ] + + ! Read mean and std variables + + allocate(sclprm_mean_obs(N_lat, N_lon), sclprm_std_obs(N_lat, N_lon)) + allocate(sclprm_mean_mod(N_lat, N_lon), sclprm_std_mod(N_lat, N_lon)) + allocate(sclprm_min_mod( N_lat, N_lon), sclprm_max_mod(N_lat, N_lon)) + + ierr = nf90_get_var(ncid, o_mean_varid, sclprm_mean_obs, start, icount) + ierr = nf90_get_var(ncid, o_std_varid, sclprm_std_obs, start, icount) + ierr = nf90_get_var(ncid, m_mean_varid, sclprm_mean_mod, start, icount) + ierr = nf90_get_var(ncid, m_std_varid, sclprm_std_mod, start, icount) + ierr = nf90_get_var(ncid, m_min_varid, sclprm_min_mod) + ierr = nf90_get_var(ncid, m_max_varid, sclprm_max_mod) + + ! Close the netcdf file + + ierr = nf90_close(ncid) + + ! -------------------------------------------------------------- + + ! Scale observations (at this point all obs are of same type because + ! of the way the subroutine is called from subroutine read_obs() + + do i=1,N_catd + + ! Check for no-data-values in observation (any neg value is no_data) + + if (tmp_obs(i)>=0.) then + + ! ll_lon and ll_lat refer to lower left corner of grid cell + ! (as opposed to the grid point in the center of the grid cell) + + this_lon = tmp_lon(i) + this_lat = tmp_lat(i) + + ! Find indices for current tile lat and lon on scaling parameter grid + + i_ind = ceiling((this_lon - ll_lon)/dlon) + j_ind = ceiling((this_lat - ll_lat)/dlat) + + ! Check for no-data-values in observation and fit parameters + ! (any negative number could be no-data-value for observations) + + if ( sclprm_mean_obs(j_ind, i_ind)>0. .and. & + sclprm_mean_mod(j_ind, i_ind)>0. .and. & + sclprm_std_obs(j_ind, i_ind)>=0. .and. & + sclprm_std_mod(j_ind, i_ind)>=0. ) then + + ! Scale via standard normal deviates + + tmpreal = sclprm_std_mod(j_ind, i_ind)/sclprm_std_obs(j_ind, i_ind) + + tmp_obs(i) = sclprm_mean_mod(j_ind, i_ind) & + + tmpreal*(tmp_obs(i)-sclprm_mean_obs(j_ind, i_ind)) + + ! Check of tmp_obs is within range of model climatology + + if (tmp_obs(i)sclprm_max_mod(j_ind, i_ind)) then + + tmp_obs(i) = sclprm_max_mod(j_ind, i_ind) + + end if + + ! Scale observation error std + + tmp_std_obs(i) = tmpreal*tmp_std_obs(i) + + else + + tmp_obs(i) = this_obs_param%nodata + + end if + + end if + + end do + + deallocate(sclprm_mean_obs) + deallocate(sclprm_std_obs) + deallocate(sclprm_mean_mod) + deallocate(sclprm_std_mod) + deallocate(sclprm_min_mod) + deallocate(sclprm_max_mod) + + end subroutine scale_obs_sfmc_zscore + ! ******************************************************************************** subroutine scale_obs_Tb_zscore( N_catd, tile_coord, date_time, this_obs_param, & @@ -8074,7 +9817,7 @@ end subroutine scale_obs_Tb_zscore subroutine collect_obs( & work_path, exp_id, date_time, dtstep_assim, & - N_catl, tile_coord_l, & + N_catl, & N_catf, tile_coord_f, tile_grid_f, N_tile_in_cell_ij_f, tile_num_in_cell_ij_f, & N_catl_vec, low_ind, l2f, & N_obs_param, obs_param, N_obsl_max, write_obslog, & @@ -8095,7 +9838,7 @@ subroutine collect_obs( implicit none - character(*), intent(in) :: work_path + character(*), intent(in) :: work_path character(*), intent(in) :: exp_id type(date_time_type), intent(in) :: date_time @@ -8109,7 +9852,7 @@ subroutine collect_obs( ! tile_coord_f of catchments in domain (length N_catf) - type(tile_coord_type), dimension(:), pointer :: tile_coord_l, tile_coord_f ! input + type(tile_coord_type), dimension(:), pointer :: tile_coord_f ! input type(grid_def_type), intent(in) :: tile_grid_f @@ -8192,7 +9935,7 @@ subroutine collect_obs( ! (typically global) and returns a vector in (full domain) ! tile space with the values of the observations (at most one ! observation per tile and per species) - + call read_obs( & work_path, exp_id, & date_time, dtstep_assim, N_catf, tile_coord_f, & @@ -8249,7 +9992,7 @@ subroutine collect_obs( call MPI_BCAST(any_scaled_obs, 1, MPI_LOGICAL, 0,mpicomm, mpierr) #endif - + N_obsl = obs_count ! ----------------------------------------------------------------- @@ -8281,11 +10024,11 @@ subroutine collect_obs( ind_start = 1 this_tilenum = Observations_l(ind_start)%tilenum - + do ii=2,N_obsl this_tilenum_new = Observations_l(ii)%tilenum - + if ( (this_tilenum_new/=this_tilenum) .or. (ii==N_obsl) ) then if ( (this_tilenum_new/=this_tilenum) .and. (ii<=N_obsl) ) then @@ -8302,11 +10045,11 @@ subroutine collect_obs( ! of (local) obs with the same tilenum N_tmp = ind_end - ind_start + 1 - + if (N_tmp>1) then tmp_species(1:N_tmp) = Observations_l(ind_start:ind_end)%species - + ! get index vector for sorting by species (see NOTES above!) call nr_indexx( N_tmp, real(tmp_species(1:N_tmp)), indx(1:N_tmp) ) @@ -8472,15 +10215,15 @@ subroutine put_into_Observations( this_obs_param, N_obs_max, N_catd, l2f, & real :: nodatavalue, tol ! ------------------------------------------------------ - + nodatavalue = this_obs_param%nodata tol = abs(nodatavalue*nodata_tolfrac_generic) - + do i=1,N_catd - + if (abs(tmp_obs(i)-nodatavalue) > tol) then ! check for no-data-value - + obs_count = obs_count+1 ! augment observation counter Observations(obs_count)%obs = tmp_obs(i) @@ -8497,14 +10240,14 @@ subroutine put_into_Observations( this_obs_param, N_obs_max, N_catd, l2f, & Observations(obs_count)%obsvar = this_obs_param%errstd**2 end if - + Observations(obs_count)%tilenum = l2f(i) Observations(obs_count)%time = tmp_time(i) Observations(obs_count)%lat = tmp_lat(i) Observations(obs_count)%lon = tmp_lon(i) - + Observations(obs_count)%species = this_obs_param%species Observations(obs_count)%assim = this_obs_param%assim .and. tmp_assim(i) @@ -8703,4 +10446,3 @@ end program test ! ******* EOF ************************************************************* - diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 index 6b8726ad..c8398b61 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/clsm_ensupd_upd_routines.F90 @@ -8,12 +8,17 @@ module clsm_ensupd_upd_routines use nr_ran2_gasdev, ONLY: & NRANDSEED + + use MAPL_BaseMod, ONLY: & + MAPL_UNDEF, & + MAPL_LAND use MAPL_ConstantsMod, ONLY: & MAPL_TICE, & MAPL_RADIUS, & - MAPL_PI - + MAPL_PI, & + MAPL_ALHF + use LDAS_ensdrv_Globals, ONLY: & logit, & logunit, & @@ -31,7 +36,10 @@ module clsm_ensupd_upd_routines FT_ANA_FT_THRESHOLD, & FT_ANA_LOWERBOUND_ASNOW, & FT_ANA_LOWERBOUND_TEFF, & - FT_ANA_UPPERBOUND_TEFF + FT_ANA_UPPERBOUND_TEFF, & + SCF_ANA_ALPHA, & + SCF_ANA_BETA, & + SCF_ANA_MAXINCRSWE use my_matrix_functions, ONLY: & row_variance, & @@ -102,11 +110,21 @@ module clsm_ensupd_upd_routines use catch_constants, ONLY: & N_snow => CATCH_N_SNOW, & N_gt => CATCH_N_GT, & + RHOFS => CATCH_SNOW_RHOFS, & + CATCH_SNOW_DZPARAM, & PEATCLSM_POROS_THRESHOLD + + use SurfParams, ONLY: & + WEMIN - use StieglitzSnow, ONLY: & - StieglitzSnow_calc_asnow - + use STIEGLITZSNOW, ONLY: & + StieglitzSnow_calc_asnow, & + StieglitzSnow_calc_tpsnow, & + StieglitzSnow_relayer, & + StieglitzSnow_CPW, & + StieglitzSnow_MINSWE, & + N_constit + use LDAS_ensdrv_mpi, ONLY: & numprocs, & myid, & @@ -395,7 +413,7 @@ subroutine read_ens_upd_inputs( & ! extract species into obs_param N_tmp = max( obs_param_nml(i)%N_ang, 1 ) - + do k=1,N_tmp j = j + 1 @@ -755,7 +773,7 @@ subroutine get_cat_progn_ens_avg(N_catd, N_ens, cat_progn, cat_progn_ensavg) type(cat_progn_type), dimension(N_catd,N_ens), intent(in) :: cat_progn type(cat_progn_type), dimension(N_catd), intent(out) :: cat_progn_ensavg - + ! locals integer :: i, n_e @@ -952,8 +970,8 @@ subroutine get_obs_pred( & real, dimension(:,:), pointer :: Obs_pred_l ! output - logical, intent(in), dimension(N_obsl), optional :: obsbias_ok - + logical, intent(in), dimension(N_obsl), optional :: obsbias_ok + real, intent(in), optional :: fcsterr_inflation_fac ! -------------------------------------------------------------------------------- @@ -991,7 +1009,7 @@ subroutine get_obs_pred( & logical :: get_tp_l logical :: get_Tb_l, get_Tb_lH logical :: get_FT_l, get_FT_lH - + logical :: get_asnow_l, get_asnow_lH type(grid_def_type) :: tile_grid_lH integer, dimension(N_obs_param) :: ind_obsparam2Tbspecies @@ -1019,7 +1037,7 @@ subroutine get_obs_pred( & real, dimension(N_catl,N_ens) :: sfmc_l, rzmc_l real, dimension(N_catl,N_ens) :: tsurf_l, stemp_l - real, dimension(N_catl,N_ens) :: FT_l + real, dimension(N_catl,N_ens) :: FT_l, asnow_l real, dimension(:,:,:), allocatable :: Tb_h_l, Tb_v_l @@ -1038,7 +1056,7 @@ subroutine get_obs_pred( & real, dimension(:,:), allocatable :: sfmc_lH, rzmc_lH real, dimension(:,:), allocatable :: tsurf_lH, stemp_lH - real, dimension(:,:), allocatable :: FT_lH + real, dimension(:,:), allocatable :: FT_lH, asnow_lH real, dimension(:,:,:), allocatable :: Tb_h_lH, Tb_v_lH @@ -1057,7 +1075,6 @@ subroutine get_obs_pred( & character(len=*), parameter :: Iam = 'get_obs_pred' character(len=400) :: err_msg - character(len= 10) :: tmpstring10 ! -------------------------------------------------------------- ! @@ -1106,7 +1123,8 @@ subroutine get_obs_pred( & get_tp_l = .false. get_FT_l = .false. get_Tb_l = .false. - + get_asnow_l = .false. + ! get_*_lH : directly match observed fields get_sfmc_lH = .false. @@ -1114,6 +1132,7 @@ subroutine get_obs_pred( & get_tsurf_lH = .false. get_FT_lH = .false. get_Tb_lH = .false. + get_asnow_lH = .false. ! loop through obs_param b/c obs on local proc may not reflect all obs @@ -1125,12 +1144,12 @@ subroutine get_obs_pred( & select case (trim(obs_param(i)%varname)) - case ('sfmc') + case ('sfmc', 'sfds') get_sfmc_l = .true. get_sfmc_lH = .true. get_tsurf_l = .true. ! needed for model-based QC - + case ('rzmc') get_rzmc_l = .true. @@ -1168,6 +1187,11 @@ subroutine get_obs_pred( & get_Tb_lH = .true. + case('asnow') + + get_asnow_l = .true. + get_asnow_lH = .true. + case default call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'unknown obs_param%varname') @@ -1337,7 +1361,15 @@ subroutine get_obs_pred( & call catch_calc_FT( N_catl, asnow, tp_l(1,:), tsurf_excl_snow, FT_l(:,n_e)) end if - + + if (get_asnow_l) then + + call StieglitzSnow_calc_asnow( N_snow, N_catl, & + catprogn2wesn(N_catl,cat_progn(:,n_e)), & + asnow_l(:,n_e) ) + + end if + if (get_Tb_l) then ! convert Catchment model variables into inputs suitable for the mwRTM @@ -1423,13 +1455,14 @@ subroutine get_obs_pred( & ! allocate and assemble tile_data_l allocate(tile_data_l(0,0,0)) ! for debugging to pass call get_tiles_in_halo( N_catl, N_fields, N_ens, tile_data_l, tile_coord_l, & - N_catf, tile_coord_f, N_catl_vec, low_ind, xhalo, yhalo, & + tile_coord_f, N_catl_vec, low_ind, xhalo, yhalo, & N_catlH, tile_coord_lH=tile_coord_lH ) if (get_sfmc_lH) allocate(sfmc_lH( N_catlH, N_ens)) if (get_rzmc_lH) allocate(rzmc_lH( N_catlH, N_ens)) if (get_tsurf_lH) allocate(tsurf_lH(N_catlH, N_ens)) if (get_FT_lH) allocate(FT_lH( N_catlH, N_ens)) + if (get_asnow_lH) allocate(asnow_lH(N_catlH, N_ens)) if (get_Tb_lH) allocate(stemp_lH(N_catlH, N_ens)) if (get_Tb_lH) allocate(Tb_h_lH( N_catlH,N_TbuniqFreqAngRTMid,N_ens)) if (get_Tb_lH) allocate(Tb_v_lH( N_catlH,N_TbuniqFreqAngRTMid,N_ens)) @@ -1437,32 +1470,32 @@ subroutine get_obs_pred( & #ifdef LDAS_MPI ! count number of fields that need to be communicated (N_fields), allocate as needed - + call get_obs_pred_comm_helper( N_catl, N_ens, N_TbuniqFreqAngRTMid, & - get_sfmc_lH, get_rzmc_lH, get_tsurf_lH, get_FT_lH, get_Tb_lH, N_fields) + get_sfmc_lH, get_rzmc_lH, get_tsurf_lH, get_FT_lH, get_asnow_lH, get_Tb_lH, N_fields) ! allocate and assemble tile_data_l - + if (allocated(tile_data_l)) deallocate(tile_data_l) allocate(tile_data_l(N_catl,N_fields,N_ens)) call get_obs_pred_comm_helper( N_catl, N_ens, N_TbuniqFreqAngRTMid, & - get_sfmc_lH, get_rzmc_lH, get_tsurf_lH, get_FT_lH, get_Tb_lH, N_fields, & + get_sfmc_lH, get_rzmc_lH, get_tsurf_lH, get_FT_lH, get_asnow_lH, get_Tb_lH, N_fields, & option=1, tile_data=tile_data_l, & sfmc=sfmc_l, rzmc=rzmc_l, tsurf=tsurf_l, FT=FT_l, stemp=stemp_l, & - Tb_h=Tb_h_l, Tb_v=Tb_v_l ) + Tb_h=Tb_h_l, Tb_v=Tb_v_l, asnow=asnow_l ) ! communicate tile_data_l as needed and get tile_data_lH - + call get_tiles_in_halo( N_catl, N_fields, N_ens, tile_data_l, tile_coord_l, & - N_catf, tile_coord_f, N_catl_vec, low_ind, xhalo, yhalo, & + tile_coord_f, N_catl_vec, low_ind, xhalo, yhalo, & N_catlH, tile_data_lH=tile_data_lH ) ! read out sfmc, rzmc, etc. from tile_data_lH - + call get_obs_pred_comm_helper( N_catlH, N_ens, N_TbuniqFreqAngRTMid, & - get_sfmc_lH, get_rzmc_lH, get_tsurf_lH, get_FT_lH, get_Tb_lH, N_fields, & + get_sfmc_lH, get_rzmc_lH, get_tsurf_lH, get_FT_lH, get_asnow_lH, get_Tb_lH, N_fields, & option=2, tile_data=tile_data_lH, & - sfmc=sfmc_lH, rzmc=rzmc_lH, tsurf=tsurf_lH, FT=FT_l, stemp=stemp_lH, & + sfmc=sfmc_lH, rzmc=rzmc_lH, tsurf=tsurf_lH, asnow=asnow_lH, FT=FT_l, stemp=stemp_lH, & Tb_h=Tb_h_lH, Tb_v=Tb_v_lH ) ! clean up @@ -1475,6 +1508,7 @@ subroutine get_obs_pred( & if (get_rzmc_lH) rzmc_lH = rzmc_l if (get_tsurf_lH) tsurf_lH = tsurf_l if (get_FT_lH) FT_lH = FT_l + if (get_asnow_lH) asnow_lH = asnow_l if (get_Tb_lH) stemp_lH = stemp_l if (get_Tb_lH) Tb_h_lH = Tb_h_l if (get_Tb_lH) Tb_v_lH = Tb_v_l @@ -1511,7 +1545,7 @@ subroutine get_obs_pred( & tile_grid_lH, maxval(N_tile_in_cell_ij_lH), tile_num_in_cell_ij_lH ) end if - + ! ----------------------- allocate(ind_tmp( N_catlH)) @@ -1642,7 +1676,7 @@ subroutine get_obs_pred( & select case (trim(obs_param(this_species)%varname)) - case ('sfmc') + case ('sfmc', 'sfds') tmp_data(1:N_tmp) = sfmc_lH( ind_tmp(1:N_tmp), n_e ) @@ -1657,7 +1691,11 @@ subroutine get_obs_pred( & case ('FT') tmp_data(1:N_tmp) = FT_lH( ind_tmp(1:N_tmp), n_e ) + + case ('asnow') + tmp_data(1:N_tmp) = asnow_lH( ind_tmp(1:N_tmp), n_e ) + case('Tb') ! start with QC based on model *soil* temperature, motivated by RFI @@ -1837,6 +1875,7 @@ subroutine get_obs_pred( & if (get_rzmc_lH) deallocate(rzmc_lH) if (get_tsurf_lH) deallocate(tsurf_lH) if (get_FT_lH) deallocate(FT_lH) + if (get_asnow_lH) deallocate(asnow_lH) if (get_Tb_lH) deallocate(stemp_lH) if (get_Tb_lH) deallocate(Tb_h_lH) if (get_Tb_lH) deallocate(Tb_v_lH) @@ -1938,9 +1977,9 @@ end subroutine get_obs_pred ! ***************************************************************** - subroutine get_obs_pred_comm_helper( & - N_cat, N_ens, N_Tb, get_sfmc, get_rzmc, get_tsurf, get_FT, get_Tb, & - N_fields, option, tile_data, sfmc, rzmc, tsurf, FT, stemp, Tb_h, Tb_v ) + subroutine get_obs_pred_comm_helper( & + N_cat, N_ens, N_Tb, get_sfmc, get_rzmc, get_tsurf, get_FT, get_asnow, get_Tb, & + N_fields, option, tile_data, sfmc, rzmc, tsurf, FT, asnow, stemp, Tb_h, Tb_v ) ! bundle/unbundle individual fields into/from single array for more ! efficient communication across processors @@ -1958,8 +1997,8 @@ subroutine get_obs_pred_comm_helper( & integer, intent(in) :: N_cat, N_ens, N_Tb - logical, intent(in) :: get_sfmc, get_rzmc, get_tsurf, get_FT, get_Tb - + logical, intent(in) :: get_sfmc, get_rzmc, get_tsurf, get_FT, get_Tb, get_asnow + integer, intent(inout) :: N_fields integer, intent(in), optional :: option @@ -1967,7 +2006,7 @@ subroutine get_obs_pred_comm_helper( & real, dimension(N_cat,N_fields,N_ens), intent(inout), optional :: tile_data real, dimension(N_cat, N_ens), intent(inout), optional :: sfmc, rzmc - real, dimension(N_cat, N_ens), intent(inout), optional :: tsurf, FT, stemp + real, dimension(N_cat, N_ens), intent(inout), optional :: tsurf, FT, asnow, stemp real, dimension(N_cat,N_Tb, N_ens), intent(inout), optional :: Tb_h, Tb_v ! ----------------------------------- @@ -1977,7 +2016,6 @@ subroutine get_obs_pred_comm_helper( & integer :: k, ks, opt character(len=*), parameter :: Iam = 'get_obs_pred_comm_helper' - character(len=400) :: err_msg ! ------------------------------------------------------------------------- @@ -1998,6 +2036,7 @@ subroutine get_obs_pred_comm_helper( & if ( ((get_sfmc ) .and. (.not. present(sfmc ))) .or. & ((get_rzmc ) .and. (.not. present(rzmc ))) .or. & ((get_tsurf) .and. (.not. present(tsurf))) .or. & + ((get_asnow) .and. (.not. present(asnow))) .or. & ((get_FT) .and. (.not. present(FT ))) .or. & ((get_Tb) .and. (.not. present(stemp))) .or. & ((get_Tb) .and. (.not. present(Tb_h ))) .or. & @@ -2005,7 +2044,7 @@ subroutine get_obs_pred_comm_helper( & call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'error 1') end if - if ( (get_sfmc .or. get_rzmc .or. get_tsurf .or. get_FT .or. get_Tb) .and. & + if ( (get_sfmc .or. get_rzmc .or. get_tsurf .or. get_FT .or. get_Tb .or. get_asnow) .and. & (.not. present(tile_data)) & ) then call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'error 2') @@ -2056,6 +2095,16 @@ subroutine get_obs_pred_comm_helper( & if (opt==2) FT = tile_data(1:N_cat,k,1:N_ens) end if + + if (get_asnow) then + + k = k+1 + + if (opt==1) tile_data(1:N_cat,k,1:N_ens) = asnow + + if (opt==2) asnow = tile_data(1:N_cat,k,1:N_ens) + + end if if (get_Tb) then @@ -2342,8 +2391,8 @@ end subroutine qc_model_based_for_Tb ! ********************************************************************* - subroutine get_halo_obs( N_ens, N_catl, N_obsl, Observations_l, Obs_pred_l, & - tile_coord_l, xcompact, ycompact, & + subroutine get_halo_obs( N_ens, N_obsl, Observations_l, Obs_pred_l, & + tile_coord_l, xcompact, ycompact, & N_obslH, Observations_lH, Obs_pred_lH ) ! collect observations from other local domains (processors) that are @@ -2375,7 +2424,7 @@ subroutine get_halo_obs( N_ens, N_catl, N_obsl, Observations_l, Obs_pred_l, & implicit none - integer, intent(in) :: N_ens, N_catl, N_obsl + integer, intent(in) :: N_ens, N_obsl type(obs_type), dimension(N_obsl), intent(in) :: Observations_l @@ -2766,7 +2815,7 @@ end subroutine get_halo_obs ! ********************************************************************* subroutine get_tiles_in_halo( N_catl, N_fields, N_ens, tile_data_l, tile_coord_l, & - N_catf, tile_coord_f, N_catl_vec, low_ind, xhalo, yhalo, & + tile_coord_f, N_catl_vec, low_ind, xhalo, yhalo, & N_catlH, tile_coord_lH, tile_data_lH ) ! collect (bundled) tile_data from other local domains (processors) that are @@ -2787,7 +2836,7 @@ subroutine get_tiles_in_halo( N_catl, N_fields, N_ens, tile_data_l, tile_coord_l implicit none integer, intent(in) :: N_catl, N_fields - integer, intent(in) :: N_ens, N_catf + integer, intent(in) :: N_ens real, dimension(N_catl,N_fields,N_ens), intent(in) :: tile_data_l @@ -3103,7 +3152,7 @@ subroutine get_obs_pert( N_ens, N_obs, N_obs_param, & ! ----------------------------------------------------------------- nullify(obs_pert_param) - + ! determine pert_grid_lH ! - pert_grid_lH is the local grid for which perturbations are needed ! - pert_grid_lH is larger than pert_grid_l by the "halo" @@ -3344,7 +3393,7 @@ subroutine get_obs_pert( N_ens, N_obs, N_obs_param, & !call check_obs_pert( N_ens, N_catd, N_obs, cat_param, Observations, & ! Obs_pert ) - + end subroutine get_obs_pert ! ********************************************************************* @@ -3354,7 +3403,7 @@ subroutine cat_enkf_increments( & update_type, obs_param, & tile_coord, l2f, & Observations, Obs_pred, Obs_pert, & - cat_param, & + met_force, cat_param, & xcompact, ycompact, fcsterr_inflation_fac, & cat_progn, cat_progn_incr ) @@ -3364,10 +3413,12 @@ subroutine cat_enkf_increments( & ! reichle, 27 Jul 2005 ! reichle, 18 Oct 2005 - return increments (instead of updated cat_progn) ! reichle, 17 Oct 2011 - added "l2f" for revised (MPI) analysis + ! jpark50, 28 Jul 2020 - added met_force to argument list for MODIS SCF assimilation ! reichle, 20 Feb 2022 - modified update_type 10 for PEATCLSM + ! amfox, 6 Feb 2024 - added update type 13 for combination of ASCAT SM and SMAP Tb ! ! -------------------------------------------------------------- - + ! IMPORTANT: ! on input, cat_progn must contain cat_progn_minus(1:N_catd,1:N_ens) ! on output, cat_progn_incr contains INCREMENTS @@ -3385,7 +3436,7 @@ subroutine cat_enkf_increments( & ! ------------------------------------------------------------------- implicit none - + ! inputs integer, intent(in) :: N_ens, N_obs, N_catd, N_obs_param, update_type @@ -3401,6 +3452,7 @@ subroutine cat_enkf_increments( & real, intent(in), dimension(N_obs,N_ens) :: Obs_pred real, intent(in), dimension(N_obs,N_ens) :: Obs_pert + type(met_force_type), dimension(N_catd), intent(in) :: met_force type(cat_param_type), dimension(N_catd), intent(in) :: cat_param real, intent(in) :: xcompact, ycompact, fcsterr_inflation_fac @@ -3424,9 +3476,9 @@ subroutine cat_enkf_increments( & real, parameter :: tp1_threshold = -HUGE(1.) ! = 0.2 ! [CELSIUS] - integer :: n, n_e, kk, ii + integer :: n, n_e, kk, ii, jj - integer :: N_state_max, N_state, N_selected_obs, N_select_varnames, N_select_species + integer :: N_state_max, N_state, N_selected_obs, N_select_varnames, N_select_species, N_select_species_Tb real :: halo_minlon, halo_maxlon, halo_minlat, halo_maxlat real :: tmp_minlon, tmp_maxlon, tmp_minlat, tmp_maxlat @@ -3437,13 +3489,13 @@ subroutine cat_enkf_increments( & real :: fice_plus, tp1_plus, ght1_plus integer, dimension(N_obs) :: ind_obs - + real, allocatable, dimension(:,:) :: State_incr real, allocatable, dimension(:,:) :: Obs_cov ! measurement error covariance real, allocatable, dimension(:) :: State_lon, State_lat - integer, dimension(N_obs_param) :: select_species ! alloc max possible length + integer, dimension(N_obs_param) :: select_species, select_species_Tb ! alloc max possible length character(40), dimension(N_obs_param) :: select_varnames ! alloc max possible length @@ -3453,7 +3505,6 @@ subroutine cat_enkf_increments( & integer, dimension(:,:,:), pointer :: tile_num_in_cell_ij => null() character(len=*), parameter :: Iam = 'cat_enkf_increments' - character(len=400) :: err_msg real, dimension( N_catd) :: r_x, tmp_dlon real :: r_y, tmp_dlat @@ -3472,10 +3523,23 @@ subroutine cat_enkf_increments( & real, dimension( N_catd) :: tsurf_ensavg real, dimension( N_catd) :: SWE_ensavg real, dimension( N_catd) :: tp1_ensavg + real, dimension( N_catd) :: asnow_ensavg type(obs_param_type) :: this_obs_param - - ! ----------------------------------------------------------------------- + + integer :: isnow + real :: asnow_fcst, swe_fcst, swe_ratio, snow_dens, snow_temp, fice_snow + real :: asnow_ana, swe_ana + logical :: log_dum, log_dum2 + real, dimension(N_catd,N_ens) :: swe_incr + real, dimension(N_catd,N_ens,N_snow) :: tmp_wesn, tmp_htsn, tmp_sndz + + real, dimension(N_snow) :: tpsn, fice_snow_vec ! for snow model relayer + real, dimension(N_snow,N_constit) :: rconstit + + logical :: found_Tb_obs + +! ----------------------------------------------------------------------- if (logit) write (logunit,*) & 'cat_enkf_increments(): getting assimilation increments...' @@ -3487,7 +3551,7 @@ subroutine cat_enkf_increments( & cat_progn_incr(kk,n_e) = 0. end do end do - + ! avoid unnecessary work or subroutine calls if (N_obs<=0) return ! nothing left to do @@ -3581,32 +3645,40 @@ subroutine cat_enkf_increments( & SWE_ensavg = 0. tsurf_ensavg = 0. tp1_ensavg = 0. - + asnow_ensavg = 0. + do n_e=1,N_ens - + SWE_ensavg = SWE_ensavg + SWE( :,n_e) tsurf_ensavg = tsurf_ensavg + tsurf( :,n_e) tp1_ensavg = tp1_ensavg + tp( 1,:,n_e) - + asnow_ensavg = asnow_ensavg + asnow( :,n_e) + end do SWE_ensavg = SWE_ensavg /real(N_ens) tsurf_ensavg = tsurf_ensavg /real(N_ens) tp1_ensavg = tp1_ensavg /real(N_ens) - + asnow_ensavg = asnow_ensavg /real(N_ens) + ! --------------------------------------------------------------------- select_update_type: select case (update_type) - case (1) select_update_type ! 1d soil moisture analysis; sfmc obs + case (1) select_update_type ! 1d soil moisture analysis; sfmc and/or sfds obs ! this 1d update requires that obs are on same tile space as model if (logit) write (logunit,*) 'get 1d soil moisture increments; sfmc obs' - N_select_varnames = 1 + ! disable update_type=1 (b/c it includes catdef in state vector for mineral soil) + + call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'update_type=1 no longer supported; use update_type=13 instead') + + N_select_varnames = 2 select_varnames(1) = 'sfmc' + select_varnames(2) = 'sfds' call get_select_species( & N_select_varnames, select_varnames(1:N_select_varnames), & @@ -3665,16 +3737,21 @@ subroutine cat_enkf_increments( & end do - case (2) select_update_type ! 3d soil moisture analysis; sfmc obs + case (2) select_update_type ! 3d soil moisture analysis; sfmc+sfds obs ! update each tile separately using all observations within ! the customized halo around each tile if (logit) write (logunit,*) 'get 3d soil moisture increments; sfmc obs' - N_select_varnames = 1 + ! disable update_type=2 (b/c it includes catdef in state vector for mineral soil) + + call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'update_type=2 no longer supported; use update_type=13 instead') + + N_select_varnames = 2 select_varnames(1) = 'sfmc' + select_varnames(2) = 'sfds' call get_select_species( & N_select_varnames, select_varnames(1:N_select_varnames), & @@ -3974,7 +4051,7 @@ subroutine cat_enkf_increments( & end do ! ---------------------------------- - + case (7) select_update_type ! 3d Tskin/ght(1) analysis; tskin obs ! update each tile separately using all observations within @@ -4403,6 +4480,413 @@ subroutine cat_enkf_increments( & end do + ! ---------------------------------- + + case (11) select_update_type ! 1d snow analysis (Toure et al. 2018 empirical gain); snow cover fraction obs + + if (logit) write (logunit, *) 'get 1d snow increments (Toure et al. 2018 empirical gain); snow cover fraction obs' + + ! ensure that max SWE increment parameter is less than WEMIN; larger increments make no sense because + ! at SWE=WEMIN, the tile is fully snow covered (asnow=1) + + if (SCF_ANA_MAXINCRSWE>WEMIN) call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'must use SCF_ANA_MAXINCRSWE<=WEMIN') + + ! identify the obs species of interest + + N_select_varnames = 1 + + select_varnames(1) = 'asnow' + + call get_select_species( & + N_select_varnames, select_varnames(1:N_select_varnames), & + N_obs_param, obs_param, N_select_species, select_species ) + + allocate(select_tilenum(1)) + + swe_incr = 0. ! total SWE increment; initialize to NO CHANGE + + ! loop through tiles and compute increments + + do kk=1,N_catd + + ! find observations for tile kk + + select_tilenum(1) = l2f(kk) + + call get_ind_obs( & + N_obs, Observations, & + 1, select_tilenum, & + N_select_species, select_species(1:N_select_species), & + N_selected_obs, ind_obs ) + + if (N_selected_obs > 0) then + + ! average in case there are multiple "asnow" obs (e.g., from MODIS and VIIRS) + + tmp_obs = sum(Observations(ind_obs(1:N_selected_obs))%obs) + + if (N_selected_obs > 1) tmp_obs = tmp_obs/real(N_selected_obs) + + do n_e=1,N_ens ! compute analysis separately for each ensemble member + + ! 1. Diagnose model forecast snow cover area fraction and total SWE + + asnow_fcst = asnow(kk,n_e) + swe_fcst = sum(cat_progn(kk,n_e)%wesn(1:N_snow)) + + ! 2. Calculate SWE increment based on modified eq 1 of Toure et al (2018) + + if (asnow_fcst .lt. tmp_obs * SCF_ANA_ALPHA) then + + ! ADD SNOW: Forecast SCF is less than observed SCF (after "bias" adjustment with alpha) + + swe_incr(kk,n_e) = SCF_ANA_MAXINCRSWE * (tmp_obs - asnow_fcst/SCF_ANA_ALPHA) + + elseif (tmp_obs .lt. SCF_ANA_BETA) then + + ! REMOVE SNOW: Simulated SCF is greater than observed SCF (after "bias" adjustment) + ! and observed SCF is less than beta threshold + + swe_incr(kk,n_e) = (-1.) * SCF_ANA_MAXINCRSWE * asnow_fcst * (1. - tmp_obs/SCF_ANA_BETA) + + else + + cycle ! NO CHANGE, skip rest of increment calcs and go straight to next ens member + + endif ! (Toure et al. 2018 Equation 1) + + ! 3. Derive SWE, snow heat content, and snow depth increments for each layer from total SWE increment + + swe_ana = max(swe_fcst + swe_incr(kk,n_e), 0.0) ! total SWE after analysis + + call StieglitzSnow_calc_asnow( swe_ana, asnow_ana ) ! asnow after analysis + + if (swe_fcst>=StieglitzSnow_MINSWE) then + swe_ratio = swe_ana / swe_fcst + else + swe_ratio = MAPL_UNDEF ! swe_ratio unreliable; set to MAPL_UNDEF to expose inadvertent use + end if + + ! loop through snow layers and compute SWE, snow heat content, and snow depth analysis for each layer + + do isnow=1,N_snow + + if (asnow_ana == 0.0) then + + ! no snow in analysis, remove all snow + + tmp_wesn(kk,n_e,isnow) = 0.0 + tmp_htsn(kk,n_e,isnow) = 0.0 + tmp_sndz(kk,n_e,isnow) = 0.0 + + elseif (swe_fcst < StieglitzSnow_MINSWE) then + + ! too little snow in forecast, use generic properties for added snow + + tmp_wesn(kk,n_e,isnow) = swe_ana / N_snow ! distribute SWE evenly across layers + + ! assign heat content for snow at 0 deg C and without liquid water content (100% frozen) + ! (based on StieglitzSnow: htsn = (CPW*tsnow - fice*MAPL_ALHF)*swe ) + + tmp_htsn(kk,n_e,isnow) = (0.0 - MAPL_ALHF)*tmp_wesn(kk,n_e,isnow) + + ! assign snow depth consistent with density of freshly fallen snow (must have SCF_ANA_MAXINCRSWE<=WEMIN) + + tmp_sndz(kk,n_e,isnow) = (WEMIN / RHOFS) / N_snow + + else + + ! snow in forecast and analysis, derive properties of analysis snow from properties of forecast snow + + ! update SWE: + + tmp_wesn(kk,n_e,isnow) = cat_progn(kk,n_e)%wesn(isnow) * swe_ratio + + ! update snow heat content (keep snow temperature constant): + + call StieglitzSnow_calc_tpsnow( cat_progn(kk,n_e)%htsn(isnow), cat_progn(kk,n_e)%wesn(isnow), & + snow_temp, fice_snow, log_dum, log_dum2, .false. ) + + tmp_htsn(kk,n_e,isnow) = (StieglitzSnow_CPW*snow_temp - fice_snow*MAPL_ALHF)*tmp_wesn(kk,n_e,isnow) + + ! update snow depth: + + if (asnow_ana < 1. .and. asnow_fcst < 1.) then + + ! keep snow depth constant when less than full snow cover in fcst and ana + + tmp_sndz(kk,n_e,isnow) = cat_progn(kk,n_e)%sndz(isnow) + + else + + ! compute analysis snow depth by keeping snow density constant + ! + ! in this case, it is possible that either asnow_fcst<1 or asnow_ana<1; + ! when computing density or depth, make sure that SWE value (which is per unit area) is + ! adjusted to reflect SWE value (per unit area) in the snow-covered fraction of the tile + + ! i) diagnose (layer-specific) forecast snow density + + snow_dens = ( cat_progn(kk,n_e)%wesn(isnow)/asnow_fcst ) / cat_progn(kk,n_e)%sndz(isnow) + + ! ii) diagnose analysis snow depth using forecast density + + tmp_sndz(kk,n_e,isnow) = ( tmp_wesn(kk,n_e,isnow)/asnow_ana ) / snow_dens + + end if + + end if + + end do ! isnow=1,N_snow (compute SWE, snow heat content, and snow depth analysis for each layer) + + ! 4. Relayer to balance the snow column (call with optional args for adjustment of htsnn) + + call StieglitzSnow_relayer( N_snow, N_constit, & + MAPL_LAND, CATCH_SNOW_DZPARAM, & + tmp_htsn(kk,n_e,1:N_snow), & + tmp_wesn(kk,n_e,1:N_snow), & + tmp_sndz(kk,n_e,1:N_snow), & + rconstit, tpsn, fice_snow_vec ) + + ! print the old and new swe, heat content and snow density + + !if (logit) write (logunit, *) & + ! 'fcst_wesn = ', cat_progn(kk, n_e)%wesn(1:N_snow), & + ! 'tmp_wesn = ', tmp_wesn( kk,n_e, 1:N_snow), & + ! 'fcst_htsn = ', cat_progn(kk, n_e)%htsn(1:N_snow), & + ! 'tmp_htsn = ', tmp_htsn( kk, n_e, 1:N_snow), & + ! 'fcst_sndz = ', cat_progn(kk, n_e)%sndz(1:N_snow), & + ! 'tmp_sndz = ', tmp_sndz( kk ,n_e, 1:N_snow), & + ! '--------------------------------------' + + ! 5. Diagnose increments + + cat_progn_incr(kk,n_e)%wesn(1:N_snow) = tmp_wesn(kk,n_e,1:N_snow) - cat_progn(kk,n_e)%wesn(1:N_snow) + cat_progn_incr(kk,n_e)%htsn(1:N_snow) = tmp_htsn(kk,n_e,1:N_snow) - cat_progn(kk,n_e)%htsn(1:N_snow) + cat_progn_incr(kk,n_e)%sndz(1:N_snow) = tmp_sndz(kk,n_e,1:N_snow) - cat_progn(kk,n_e)%sndz(1:N_snow) + + end do ! n_e=1,N_ens + + end if ! if (N_selected_obs > 0) + + end do ! kk=1,N_catd + + ! ---------------------------------- + + case (13) select_update_type ! 3d soil moisture/Tskin/ght(1) analysis; Tb+sfmc+sfds obs + + ! update each tile separately using all observations within customized halo around each tile + ! + ! state vector differs for each tile depending on assimilated obs and soil type + ! + ! obs | soil | N_state | state vector + ! ---------------------------------------------------------------------- + ! sfcm/sfds only | mineral | 2 | srfexc, rzexc + ! sfcm/sfds only | peat | 3 | srfexc, rzexc, catdef, + ! sfcm/sfds & Tb | mineral | 6 | srfexc, rzexc, tc[x], ght(1) + ! sfcm/sfds & Tb | peat | 7 | srfexc, rzexc, catdef, tc[x], ght(1) + ! + ! amfox+rreichle, 26 Feb 2024 + + if (logit) write (logunit,*) 'get 3d soil moisture/Tskin/ght(1) increments; Tb+sfmc obs' + + N_select_varnames = 0 + + do ii = 1,N_obs_param + if (trim(obs_param(ii)%varname) == 'Tb') then + N_select_varnames = N_select_varnames + 1 + select_varnames(N_select_varnames) = 'Tb' + exit + end if + end do + + do ii = 1,N_obs_param + if (trim(obs_param(ii)%varname) == 'sfmc') then + N_select_varnames = N_select_varnames + 1 + select_varnames(N_select_varnames) = 'sfmc' + exit + end if + end do + + do ii = 1,N_obs_param + if (trim(obs_param(ii)%varname) == 'sfds') then + N_select_varnames = N_select_varnames + 1 + select_varnames(N_select_varnames) = 'sfds' + exit + end if + end do + + ! Will get all species associated with Tb or sfds observations + + call get_select_species( & + N_select_varnames, select_varnames(1:N_select_varnames), & + N_obs_param, obs_param, N_select_species, select_species ) + + ! Determine which species are Tb + + call get_select_species(1, 'Tb', N_obs_param, obs_param, N_select_species_Tb, select_species_Tb ) + + N_state_max = 7 + + allocate( State_incr(N_state_max,N_ens)) + allocate( State_lon( N_state_max )) + allocate( State_lat( N_state_max )) + + do kk=1,N_catd + + N_state = 2 ! initialize (always have srfexc and rzexc in state vector) + + ! compute increments only for snow-free and non-frozen tiles + + if ( (SWE_ensavg(kk) < SWE_threshold) .and. & + (tp1_ensavg(kk) > tp1_threshold) ) then + + ! find observations within halo around tile kk + + halo_minlon = tile_coord(kk)%com_lon - xcompact + halo_maxlon = tile_coord(kk)%com_lon + xcompact + halo_minlat = tile_coord(kk)%com_lat - ycompact + halo_maxlat = tile_coord(kk)%com_lat + ycompact + + ! simple approach to dateline issue (cut halo back to at most -180:180, -90:90) + ! - reichle, 28 May 2013 + + halo_minlon = max(halo_minlon,-180.) + halo_maxlon = min(halo_maxlon, 180.) + halo_minlat = max(halo_minlat, -90.) + halo_maxlat = min(halo_maxlat, 90.) + + call get_ind_obs_lat_lon_box( & + N_obs, Observations, & + halo_minlon, halo_maxlon, halo_minlat, halo_maxlat, & + N_select_species, select_species(1:N_select_species), & + N_selected_obs, ind_obs ) + + if (N_selected_obs>0) then + + ! Determine if Tb observations are present + + found_Tb_obs = .false. + + do ii = 1,N_select_species_Tb + do jj = 1,N_selected_obs + if (select_species_Tb(ii) == Observations(ind_obs(jj))%species) then + found_Tb_obs = .true. + exit + end if + end do + if (found_Tb_obs) exit + end do + + ! if Tb_obs are present, add tc[X] and ght(1) to state vector + + if (found_Tb_obs) N_state = N_state + 4 + + ! for peatland tile, add catdef to state vector + + if (cat_param(kk)%poros>=PEATCLSM_POROS_THRESHOLD) N_state = N_state + 1 + + ! assemble State_minus + ! (on input, cat_progn contains cat_progn_minus) + + if ( N_state==2 ) then + + State_incr(1,:) = cat_progn( kk,:)%srfexc/scale_srfexc + State_incr(2,:) = cat_progn( kk,:)%rzexc /scale_rzexc + + elseif ( N_state==3 ) then + + State_incr(1,:) = cat_progn( kk,:)%srfexc/scale_srfexc + State_incr(2,:) = cat_progn( kk,:)%rzexc /scale_rzexc + State_incr(3,:) = cat_progn( kk,:)%catdef/scale_catdef ! catdef in State + + elseif ( N_state==6 ) then + + State_incr(1,:) = cat_progn( kk,:)%srfexc/scale_srfexc + State_incr(2,:) = cat_progn( kk,:)%rzexc /scale_rzexc + + State_incr(4,:) = cat_progn( kk,:)%tc1 /scale_temp + State_incr(5,:) = cat_progn( kk,:)%tc2 /scale_temp + State_incr(6,:) = cat_progn( kk,:)%tc4 /scale_temp + State_incr(7,:) = cat_progn( kk,:)%ght(1)/scale_ght1 + + else + + State_incr(1,:) = cat_progn( kk,:)%srfexc/scale_srfexc + State_incr(2,:) = cat_progn( kk,:)%rzexc /scale_rzexc + State_incr(3,:) = cat_progn( kk,:)%catdef/scale_catdef ! catdef in State + + State_incr(3,:) = cat_progn( kk,:)%tc1 /scale_temp + State_incr(4,:) = cat_progn( kk,:)%tc2 /scale_temp + State_incr(5,:) = cat_progn( kk,:)%tc4 /scale_temp + State_incr(6,:) = cat_progn( kk,:)%ght(1)/scale_ght1 + + end if + + State_lon( :) = tile_coord(kk )%com_lon + State_lat( :) = tile_coord(kk )%com_lat + + allocate(Obs_cov(N_selected_obs,N_selected_obs)) + + call assemble_obs_cov( N_selected_obs, N_obs_param, obs_param, & + Observations(ind_obs(1:N_selected_obs)), Obs_cov ) + + call enkf_increments( & + N_state, N_selected_obs, N_ens, & + Observations(ind_obs(1:N_selected_obs)), & + Obs_pred(ind_obs(1:N_selected_obs),:), & + Obs_pert(ind_obs(1:N_selected_obs),:), & + Obs_cov, & + State_incr(1:N_state,:), & + State_lon( 1:N_state ), & + State_lat( 1:N_state ), & + xcompact, ycompact, & + fcsterr_inflation_fac ) + + deallocate(Obs_cov) + + ! assemble cat_progn increments + + if ( N_state==2 ) then + + cat_progn_incr(kk,:)%srfexc = State_incr(1,:)*scale_srfexc + cat_progn_incr(kk,:)%rzexc = State_incr(2,:)*scale_rzexc + + elseif ( N_state==3 ) then + + cat_progn_incr(kk,:)%srfexc = State_incr(1,:)*scale_srfexc + cat_progn_incr(kk,:)%rzexc = State_incr(2,:)*scale_rzexc + cat_progn_incr(kk,:)%catdef = State_incr(3,:)*scale_catdef ! catdef in State + + elseif ( N_state==6 ) then + + cat_progn_incr(kk,:)%srfexc = State_incr(1,:)*scale_srfexc + cat_progn_incr(kk,:)%rzexc = State_incr(2,:)*scale_rzexc + + cat_progn_incr(kk,:)%tc1 = State_incr(4,:)*scale_temp + cat_progn_incr(kk,:)%tc2 = State_incr(5,:)*scale_temp + cat_progn_incr(kk,:)%tc4 = State_incr(6,:)*scale_temp + cat_progn_incr(kk,:)%ght(1) = State_incr(7,:)*scale_ght1 + + else + + cat_progn_incr(kk,:)%srfexc = State_incr(1,:)*scale_srfexc + cat_progn_incr(kk,:)%rzexc = State_incr(2,:)*scale_rzexc + cat_progn_incr(kk,:)%catdef = State_incr(3,:)*scale_catdef ! catdef in State + + cat_progn_incr(kk,:)%tc1 = State_incr(3,:)*scale_temp + cat_progn_incr(kk,:)%tc2 = State_incr(4,:)*scale_temp + cat_progn_incr(kk,:)%tc4 = State_incr(5,:)*scale_temp + cat_progn_incr(kk,:)%ght(1) = State_incr(6,:)*scale_ght1 + + end if + + end if + + end if ! thresholds + + end do + ! ---------------------------------- case default @@ -4417,7 +4901,7 @@ subroutine cat_enkf_increments( & if (allocated( State_lon )) deallocate( State_lon ) if (allocated( State_lat )) deallocate( State_lat ) if (allocated( select_tilenum )) deallocate( select_tilenum ) - + if (allocated( Obs_cov )) deallocate( Obs_cov ) if (associated(N_tile_in_cell_ij )) deallocate( N_tile_in_cell_ij ) @@ -4464,7 +4948,7 @@ subroutine get_select_species( & kk = 0 if (N_select_varnames > 0) then - + do ii=1,N_obs_param if (any(trim(obs_param(ii)%varname)==select_varnames)) then @@ -4518,7 +5002,7 @@ subroutine get_ind_obs( & integer, intent(in), dimension(N_select_tilenum) :: select_tilenum integer, intent(in), dimension(N_select_species) :: select_species - + integer, intent(out) :: N_selected_obs integer, intent(out), dimension(N_obs) :: ind_obs @@ -4527,10 +5011,10 @@ subroutine get_ind_obs( & ! locals - integer :: i, j, k, m - - logical :: selected_obs + integer :: i, k + + ! -------------------------------------------------------------- if (N_select_species==0 .and. N_select_tilenum==0) then @@ -4548,7 +5032,7 @@ subroutine get_ind_obs( & k = 0 ! counter for selected obs do i=1,N_obs - + if (any(Observations(i)%tilenum == select_tilenum)) then k = k+1 @@ -4802,7 +5286,7 @@ subroutine get_ind_obs_lat_lon_box( & ! locals - integer :: i, j, k + integer :: i, k real :: lon_obs, lat_obs @@ -4909,7 +5393,7 @@ subroutine check_compact_support( & select case (update_type) - case (1,3,4,5,6,9) ! "1d" updates + case (1,3,4,5,6,9,11) ! "1d" updates ! Make xcompact and ycompact just large enough so that ! the EnKF analysis correctly identifies the tiles @@ -4975,7 +5459,7 @@ subroutine check_compact_support( & Iam // '(): reset for 1d update_type: ycompact = ', ycompact if (logit) write (logunit,*) - case (2,7,8,10) ! "3d" updates, check consistency of xcompact, ycompact + case (2,7,8,10,13) ! "3d" updates, check consistency of xcompact, ycompact ! check xcompact/ycompact against corr scales of model error @@ -5140,7 +5624,7 @@ end subroutine dist_km2deg ! ! implicit none ! -! integer, intent(in) :: N_ens, N_obs, N_catd +! integer, intent(in) :: N_ens, N_obs, N_catd ! ! type(cat_param_type), dimension(N_catd), intent(in) :: cat_param ! @@ -5195,13 +5679,12 @@ end subroutine dist_km2deg ! end do ! ! end subroutine check_obs_pert - + ! ********************************************************************** ! ********************************************************************** ! ********************************************************************** - + end module clsm_ensupd_upd_routines ! **** EOF ****************************************************** - diff --git a/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/GEOS_LandPertGridComp.F90 b/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/GEOS_LandPertGridComp.F90 index 08f60083..205ec695 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/GEOS_LandPertGridComp.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/GEOS_LandPertGridComp.F90 @@ -24,7 +24,7 @@ module GEOS_LandPertGridCompMod use LDAS_TileCoordType, only: tile_coord_type use LDAS_TileCoordType, only: T_TILECOORD_STATE use LDAS_TileCoordType, only: TILECOORD_WRAP - use land_pert_routines, only: get_pert, propagate_pert + use land_pert_routines, only: get_pert, propagate_pert, clear_rf use land_pert_routines, only: get_init_pert_rseed use LDAS_PertRoutinesMod, only: apply_pert use LDAS_PertRoutinesMod, only: get_force_pert_param @@ -859,13 +859,11 @@ subroutine Initialize(gc, import, export, clock, rc) real(kind=ESMF_KIND_R8), pointer :: pert_rseed_r8(:)=>null() ! Misc variables - integer :: imjm(7), imjm_global(7) ! we need just the first 2 integer :: model_dtstep - integer :: land_nt_local,m,n, i1, in, j1, jn + integer :: land_nt_local, m, n, i1, in, j1, jn logical :: IAmRoot, f_exist - integer :: ipert,n_lon,n_lat, n_lon_g, n_lat_g + integer :: n_lon, n_lat, n_lon_g, n_lat_g integer, allocatable :: pert_rseed(:) - real :: dlon, dlat,locallat,locallon type(ESMF_Grid) :: Grid character(len=ESMF_MAXSTR) :: id_string integer :: ens_id_width @@ -903,6 +901,8 @@ subroutine Initialize(gc, import, export, clock, rc) VERIFY_(status) if (internal%PERTURBATIONS == 0) then ! no perturbations + allocate(progn_pert_param(0)) + allocate(force_pert_param(0)) call MAPL_TimerOff(MAPL, "Initialize") call MAPL_TimerOff(MAPL, "TOTAL") RETURN_(ESMF_SUCCESS) @@ -1320,9 +1320,8 @@ subroutine Phase2_Initialize(gc, import, export, clock, rc) real, allocatable :: fpert_grid(:,:,:), ppert_grid(:,:,:) integer,allocatable :: pert_rseed(:) - integer :: land_nt_local,n,ipert,i,j,n_lon,n_lat + integer :: land_nt_local,ipert,n_lon,n_lat logical :: IAmRoot - real :: locallat,locallon ! Begin... ! phase2_initialized is a global variables shared by all ensemble member @@ -1837,12 +1836,11 @@ subroutine ApplyForcePert(gc, import, export, clock, rc) type(tile_coord_type), pointer :: tile_coord(:)=>null() integer :: n_lon,n_lat - integer :: ipert, itile + integer :: ipert integer, allocatable :: pert_rseed(:) logical :: IAmRoot integer :: land_nt_local type(pert_param_type), pointer :: PertParam=>null() ! pert param - real :: tmpRealArrDim1(1) real, allocatable :: tmpreal(:) ! Begin... @@ -2275,14 +2273,13 @@ subroutine ApplyPrognPert(gc, import, export, clock, rc) type(tile_coord_type), pointer :: tile_coord(:)=>null() integer :: n_lon,n_lat - integer :: ipert,ntiles + integer :: ipert integer, allocatable :: pert_rseed(:) logical :: IAmRoot integer :: land_nt_local type(pert_param_type), pointer :: PertParam=>null() ! pert param integer :: model_dtstep real :: dtmh - integer :: m ! Begin... ! Get my name and setup traceback handle @@ -2667,7 +2664,7 @@ subroutine Finalize(gc, import, export, clock, rc) type(MAPL_LocStream) :: locstream type(TILECOORD_WRAP) :: tcwrap type(T_TILECOORD_STATE), pointer :: tcinternal - integer :: m,n_lon,n_lat, land_nt_local, ens_id_width + integer :: m, land_nt_local, ens_id_width integer :: nfpert, nppert, n_tile type(tile_coord_type), pointer :: tile_coord_f(:)=>null() @@ -2812,6 +2809,7 @@ subroutine Finalize(gc, import, export, clock, rc) VERIFY_(status) end if + call clear_rf() ! Call Finalize for every child call MAPL_GenericFinalize(gc, import, export, clock, rc=status) VERIFY_(status) diff --git a/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/LDAS_PertRoutines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/LDAS_PertRoutines.F90 index 00eece74..a351dde8 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/LDAS_PertRoutines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/LDAS_PertRoutines.F90 @@ -287,7 +287,6 @@ subroutine read_ens_prop_inputs( & type(force_pert_ccor_type) :: ccorr_force_pert ! Errlong variables - integer :: rc, status character(len=*), parameter :: Iam = 'read_ens_prop_inputs' ! MPI variables @@ -995,7 +994,6 @@ subroutine get_force_pert_inputs( pert_grid_l, & integer :: xstart, xcount, ystart, ycount ! for computing local indices ! Errlong variables - integer :: rc, status character(len=*), parameter :: Iam = 'get_force_pert_inputs' ! MPI variables @@ -1385,7 +1383,6 @@ subroutine get_progn_pert_inputs( pert_grid_l, & integer :: xstart, xcount, ystart, ycount ! for computing local indices ! Errlong variables - integer :: rc, status character(len=*), parameter :: Iam = 'get_progn_pert_inputs' ! MPI variables @@ -1902,7 +1899,7 @@ subroutine get_pert_select( N_pert_max, pert_grid_l, std_pert, & ! ! local variables - integer :: i,j,k, ierr + integer :: k, ierr ! --------------------------------------------------------------- ! @@ -2020,7 +2017,7 @@ end subroutine echo_pert_param ! WY noted :: -l is changed to _g. Only read part was kept subroutine io_pert_rstrt( action, work_path, exp_id, ens_id, & - date_time, tile_coord_g, pert_grid_g, pert_grid_f, & + date_time, pert_grid_g, pert_grid_f, & N_force_pert, N_progn_pert, Pert_rseed, & Force_pert_ntrmdt_g, Progn_pert_ntrmdt_g, rc ) @@ -2040,8 +2037,6 @@ subroutine io_pert_rstrt( action, work_path, exp_id, ens_id, & integer, intent(in) :: ens_id, N_force_pert, N_progn_pert - type(tile_coord_type), dimension(:), pointer :: tile_coord_g ! input - type(grid_def_type), intent(in) :: pert_grid_g, pert_grid_f integer, dimension(NRANDSEED), intent(inout) :: Pert_rseed diff --git a/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/land_pert.F90 b/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/land_pert.F90 index 1a6fe537..ee948e0e 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/land_pert.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/land_pert.F90 @@ -37,7 +37,8 @@ module land_pert_routines NRANDSEED, & init_randseed - use random_fields_class + use Random_FieldsMod + use StringRandom_fieldsMapMod use nr_jacobi, ONLY: & jacobi @@ -50,7 +51,8 @@ module land_pert_routines LDAS_GENERIC_ERROR use LDAS_ensdrv_Globals, only: root_logit, logunit - + + use MAPL implicit none ! everything is private by default unless made public @@ -62,9 +64,12 @@ module land_pert_routines public :: assemble_forcepert_param public :: get_sqrt_corr_matrix public :: get_init_Pert_rseed + public :: clear_rf ! ********************************************************************** + type(StringRandom_fieldsMap) :: random_fieldsMap + contains ! ********************************************************************** @@ -361,8 +366,6 @@ subroutine get_init_Pert_rseed( ens_id, init_Pert_rseed ) ! ! local variables - integer :: m, n, i, j - character(len=*), parameter :: Iam = 'get_init_Pert_rseed' character(len=400) :: err_msg @@ -452,7 +455,7 @@ subroutine propagate_pert( & ! ! ---------------------- - integer :: i, j, m, n, rNlon, rNlat, xStride, yStride, imax, jmax + integer :: i, j, m, n, Nx, Ny, Nx_fft, Ny_fft, xStride, yStride, imax, jmax real :: cc, dd, xCorr, yCorr, tCorr, tmpReal, rdlon, rdlat @@ -464,7 +467,8 @@ subroutine propagate_pert( & integer :: tmpInt, xstart, xend, ystart, yend - type(random_fields) :: rf + type(random_fields), pointer :: rf + type(ESMF_VM) :: vm integer :: mpicomm, status @@ -503,36 +507,11 @@ subroutine propagate_pert( & ! get grid parameters for generation of new random fields on ! possibly coarsened grid - if (pert_param(m)%coarsen) then - - xStride = max( 1, floor(coarsen_param * xCorr / pert_grid_f%dlon) ) - yStride = max( 1, floor(coarsen_param * yCorr / pert_grid_f%dlat) ) - - ! NOTE: Latitude spacing is undefined for *local* EASE grids! - - else - - xStride = 1 - yStride = 1 - - end if - - rdlon = real(xStride)*pert_grid_f%dlon - rdlat = real(yStride)*pert_grid_f%dlat - - ! NOTE: number of grid cells of coarsened grid might not evenly divide - ! that of pert_grid_f - - rNlon = pert_grid_f%N_lon / xStride - rNlat = pert_grid_f%N_lat / yStride - - if (mod(pert_grid_f%N_lon,xStride)>0) rNlon = rNlon + 1 - if (mod(pert_grid_f%N_lat,yStride)>0) rNlat = rNlat + 1 + call calc_fft_grid(pert_param(m), pert_grid_f, Nx, Ny, Nx_fft, Ny_fft, xStride, yStride, rdlon, rdlat) ptr2rfield => rfield( 1:pert_grid_f%N_lon:xStride,1:pert_grid_f%N_lat:yStride) ptr2rfield2 => rfield2(1:pert_grid_f%N_lon:xStride,1:pert_grid_f%N_lat:yStride) - ! generate new random fields and propagate AR(1) ! ! Note that rfg2d always produces a pair of random fields! @@ -548,9 +527,9 @@ subroutine propagate_pert( & ! this needs to be done for each pert field #ifdef MKL_AVAILABLE ! W.J Note: hardcoded comm = mpicomm to activate parallel fft - call rf%initialize(rNlon, rNlat, 1., xCorr, yCorr, rdlon, rdlat, comm=mpicomm ) + rf => find_rf(Nx, Ny, Nx_fft, Ny_fft, comm=mpicomm ) #else - call rf%initialize(rNlon, rNlat, 1., xCorr, yCorr, rdlon, rdlat ) + rf => find_rf(Nx, Ny, Nx_fft, Ny_fft) #endif do n=1,N_ens @@ -561,14 +540,13 @@ subroutine propagate_pert( & call rf%generate_white_field(Pert_rseed(:,n), ptr2rfield) - else ! spatially correlated random fields ! NOTE: rfg2d_fft() relies on CXML math library (22 Feb 05) ! rfg2d_fft() now relies on Intel MKL (19 Jun 13) if (.not. stored_field) then - call rf%rfg2d_fft(Pert_rseed(:,n), ptr2rfield, ptr2rfield2) + call rf%rfg2d_fft(Pert_rseed(:,n), ptr2rfield, ptr2rfield2, xCorr, yCorr, rdlon, rdlat) stored_field = .true. else rfield = rfield2 @@ -634,12 +612,62 @@ subroutine propagate_pert( & end do ! n=1,N_ens ! finalize rf - call rf%finalize + ! The rf map will be destroyed in the finalize of GEOSLandperp_Gridcomp + !call rf%finalize end do ! m=1,N_pert end subroutine propagate_pert + ! ****************************************************************************************** + + subroutine calc_fft_grid(pert_param, pert_grid_f, Nx, Ny, N_x_fft, N_y_fft, xStride, yStride, rdlon, rdlat) + + type(pert_param_type), intent(in) :: pert_param + type(grid_def_type), intent(in) :: pert_grid_f + + integer, intent(out) :: Nx, Ny, N_x_fft, N_y_fft, xStride, yStride + real, intent(out) :: rdlon, rdlat + + ! local variables + + integer :: Nx_fft, Ny_fft + real, parameter :: mult_of_xcorr = 2. + real, parameter :: mult_of_ycorr = 2. + real, parameter :: coarsen_param = 0.8 + real :: xCorr, yCorr + + xCorr = pert_param%xcorr + yCorr = pert_param%ycorr + + xStride = 1 + yStride = 1 + if (pert_param%coarsen) then + xStride = max( 1, floor(coarsen_param * xCorr / pert_grid_f%dlon) ) + yStride = max( 1, floor(coarsen_param * yCorr / pert_grid_f%dlat) ) + endif + rdlon = real(xStride)*pert_grid_f%dlon + rdlat = real(yStride)*pert_grid_f%dlat + + ! NOTE: number of grid cells of coarsened grid might not evenly divide + ! that of pert_grid_f + + Nx = pert_grid_f%N_lon / xStride + Ny = pert_grid_f%N_lat / yStride + + if (mod(pert_grid_f%N_lon,xStride)>0) Nx = Nx + 1 + if (mod(pert_grid_f%N_lat,yStride)>0) Ny = Ny + 1 + + ! add minimum required correlation lengths + Nx_fft = Nx + ceiling(mult_of_xcorr*xCorr/rdlon) + Ny_fft = Ny + ceiling(mult_of_ycorr*yCorr/rdlat) + + ! ensure N_x_fft, N_y_fft are powers of two + N_x_fft = 2**ceiling(log(real(Nx_fft))/log(2.)) + N_y_fft = 2**ceiling(log(real(Ny_fft))/log(2.)) + + end subroutine + ! ****************************************************************** subroutine truncate_std_normal( N_x, N_y, std_normal_max, grid_data ) @@ -1240,6 +1268,47 @@ subroutine get_sqrt_corr_matrix( N, A, S ) end subroutine get_sqrt_corr_matrix ! ************************************************************************ + + function find_rf(Nx, Ny, Nx_fft, Ny_fft, comm) result (rf) + + type(random_fields), pointer :: rf + integer, intent(in) :: Nx, Ny, Nx_fft, Ny_fft + integer, optional, intent(in) :: comm + + ! local variables + + type(StringRandom_fieldsMapIterator) :: iter + Character(len=:), allocatable :: id_string + type(random_fields) :: rf_tmp + + id_string = i_to_string(Nx)//":"//i_to_string(Ny)//":"//i_to_string(Nx_fft)//":"//i_to_string(Ny_fft) + iter = random_fieldsMap%find(id_string) + if (iter == random_fieldsMap%end() ) then + rf_tmp = random_fields(Nx, Ny, Nx_fft, Ny_fft, comm=comm) + call random_fieldsMap%insert(id_string, rf_tmp) + iter = random_fieldsMap%find(id_string) + endif + rf => iter%value() + + end function find_rf + + ! ************************************************************************ + + subroutine clear_rf() + + type(StringRandom_fieldsMapIterator) :: iter + type(random_fields), pointer :: rf_ptr + + iter = random_fieldsMap%begin() + do while (iter /= random_fieldsMap%end()) + rf_ptr => iter%value() + call rf_ptr%finalize() + ! remove the files + call random_fieldsMap%erase(iter) + iter = random_fieldsMap%begin() + enddo + end subroutine clear_rf + end module land_pert_routines diff --git a/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/random_fields.F90 b/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/random_fields.F90 index 61252d50..3ed12e69 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/random_fields.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/random_fields.F90 @@ -30,8 +30,11 @@ #define NR_FALLBACK #endif -module random_fields_class +#include "MAPL_ErrLog.h" +#include "unused_dummy.H" +module random_fieldsMod + #ifdef MKL_AVAILABLE use, intrinsic :: iso_c_binding, only: c_loc, c_f_pointer, c_ptr, c_sizeof, C_NULL_PTR use mpi @@ -43,9 +46,11 @@ module random_fields_class use nr_ran2_gasdev, ONLY: & NRANDSEED, & - nr_ran2_2d, & + nr_ran2_2d, & nr_gasdev - + + use MAPL_ExceptionHandling + implicit none private @@ -56,7 +61,6 @@ module random_fields_class type, public :: random_fields private integer :: N_x, N_y - real :: var, lx, ly, dx, dy integer :: N_x_fft, N_y_fft ! computed by calc_fft_grid real, allocatable :: field1_fft(:,:), field2_fft(:,:) integer :: fft_lens(2) ! length of each dim for 2D transform @@ -65,198 +69,172 @@ module random_fields_class integer :: node_comm integer :: win type (c_ptr) :: base_address - + type(DFTI_DESCRIPTOR), pointer :: Desc_Handle type(DFTI_DESCRIPTOR), pointer :: Desc_Handle_dim1 type(DFTI_DESCRIPTOR), pointer :: Desc_Handle_dim2 integer, allocatable :: dim1_counts(:) integer, allocatable :: dim2_counts(:) #endif + contains - procedure, public :: initialize + + ! procedure, public :: initialize procedure, public :: finalize procedure, public :: rfg2d_fft procedure, public :: generate_white_field procedure, private :: sqrt_gauss_spectrum_2d - procedure, private :: calc_fft_grid #ifdef MKL_AVAILABLE procedure, private :: win_allocate procedure, private :: win_deallocate #endif end type random_fields + + interface random_fields + module procedure new_random_fields + end interface random_fields contains - + ! constructor (set parameter values), allocate memory - subroutine initialize(this, Nx, Ny, var, lx, ly, dx, dy, comm) - + function new_random_fields(Nx, Ny, Nx_fft, Ny_fft, comm, rc) result (rf) + ! input/output variables [NEED class(random_fields) - ! instead of type(random_fields)] - F2003 quirk?!? - class(random_fields), intent(inout) :: this - integer, intent(in) :: Nx, Ny - real, intent(in) :: var, lx, ly, dx, dy - integer, optional, intent(in) :: comm + ! instead of type(random_fields)] - F2003 quirk?!? + type(random_fields) :: rf + integer, intent(in) :: Nx, Ny, Nx_fft, Ny_fft + integer, optional, intent(in) :: comm + integer, optional, intent(out) :: rc + + ! local variables + integer :: status, ierror + integer :: rank, npes, local_dim1, local_dim2, remainder + integer :: Stride(2) - ! local variable - integer :: mklstat, ierror, i, j - integer :: rank, npes, local_dim1, local_dim2, remainer - integer :: N1, N2, gcount(2), lstart(2), Stride(2) - ! set obj param vals - this%N_x = Nx - this%N_y = Ny - this%var = var - this%dx = dx - this%dy = dy - this%lx = lx - this%ly = ly + rf%N_x = Nx + rf%N_y = Ny - ! calculate fft grid (N_x_fft, N_y_fft) - call this%calc_fft_grid + ! ensure N_x_fft, N_y_fft are powers of two + rf%N_x_fft = Nx_fft + rf%N_y_fft = Ny_fft - ! lengths of transform in each dimension - this%fft_lens(1) = this%N_x_fft - this%fft_lens(2) = this%N_y_fft ! allocate memory - allocate(this%field1_fft(this%N_x_fft, this%N_y_fft)) - allocate(this%field2_fft(this%N_x_fft, this%N_y_fft)) + allocate(rf%field1_fft(rf%N_x_fft, rf%N_y_fft)) + allocate(rf%field2_fft(rf%N_x_fft, rf%N_y_fft)) #ifdef MKL_AVAILABLE if (present(comm)) then - this%comm = comm - - call MPI_Comm_split_type(this%comm, MPI_COMM_TYPE_SHARED, 0, MPI_INFO_NULL, this%Node_Comm,ierror) - call MPI_Comm_size(this%Node_Comm, npes,ierror) - call MPI_Comm_rank(this%Node_Comm, rank, ierror) - - - N1 = this%fft_lens(1) - N2 = this%fft_lens(2) + rf%comm = comm + + call MPI_Comm_split_type(rf%comm, MPI_COMM_TYPE_SHARED, 0, MPI_INFO_NULL, rf%Node_Comm,ierror) + call MPI_Comm_size(rf%Node_Comm, npes, ierror) + call MPI_Comm_rank(rf%Node_Comm, rank, ierror) + + if (npes > minval([Nx_fft, Ny_fft]) ) then + print*, " Two many processors are acquired in a node for parallel FFT" + print*, " The number of processors acquired in a node should be smaller than or equal to FFT grid size: ", minval([Nx_fft, Ny_fft]) + _FAIL('Parallel FFT failed') + endif - call this%win_allocate(N1, N2) + call rf%win_allocate(Nx_fft, Ny_fft, _RC) ! distribution of the grid for fft - allocate(this%dim1_counts(npes),this%dim2_counts(npes)) - local_dim1 = N1/npes - this%dim1_counts = local_dim1 - remainer = mod(N1, npes) - this%dim1_counts(1:remainer) = local_dim1 + 1 - local_dim1 = this%dim1_counts(rank+1) - - local_dim2 = N2/npes - this%dim2_counts = local_dim2 - remainer = mod(N2, npes) - this%dim2_counts(1:remainer) = local_dim2 + 1 - local_dim2 = this%dim2_counts(rank+1) - - - mklstat = DftiCreateDescriptor(this%Desc_Handle_Dim1, DFTI_SINGLE,& - DFTI_COMPLEX, 1, N1 ) - mklstat = DftiCreateDescriptor(this%Desc_Handle_Dim2, DFTI_SINGLE,& - DFTI_COMPLEX, 1, N2 ) + allocate(rf%dim1_counts(npes),rf%dim2_counts(npes)) + local_dim1 = Nx_fft/npes + rf%dim1_counts = local_dim1 + remainder = mod(Nx_fft, npes) + rf%dim1_counts(1:remainder) = local_dim1 + 1 + local_dim1 = rf%dim1_counts(rank+1) + + local_dim2 = Ny_fft/npes + rf%dim2_counts = local_dim2 + remainder = mod(Ny_fft, npes) + rf%dim2_counts(1:remainder) = local_dim2 + 1 + local_dim2 = rf%dim2_counts(rank+1) + + + status = DftiCreateDescriptor(rf%Desc_Handle_Dim1, DFTI_SINGLE,& + DFTI_COMPLEX, 1, Nx_fft ) + _VERIFY(status) + status = DftiCreateDescriptor(rf%Desc_Handle_Dim2, DFTI_SINGLE,& + DFTI_COMPLEX, 1, Ny_fft ) + _VERIFY(status) ! perform local_dim2 one-dimensional transforms along 1st dimension - mklstat = DftiSetValue( this%Desc_Handle_Dim1, DFTI_NUMBER_OF_TRANSFORMS, local_dim2 ) - mklstat = DftiSetValue( this%Desc_Handle_Dim1, DFTI_INPUT_DISTANCE, N1 ) - mklstat = DftiSetValue( this%Desc_Handle_Dim1, DFTI_OUTPUT_DISTANCE, N1 ) - mklstat = DftiCommitDescriptor( this%Desc_Handle_Dim1 ) - ! mklstat = DftiComputeForward( this%Desc_Handle_Dim1, X ) + status = DftiSetValue( rf%Desc_Handle_Dim1, DFTI_NUMBER_OF_TRANSFORMS, local_dim2 ) + _VERIFY(status) + status = DftiSetValue( rf%Desc_Handle_Dim1, DFTI_INPUT_DISTANCE, Nx_fft ) + _VERIFY(status) + status = DftiSetValue( rf%Desc_Handle_Dim1, DFTI_OUTPUT_DISTANCE, Nx_fft ) + _VERIFY(status) + status = DftiCommitDescriptor( rf%Desc_Handle_Dim1 ) + _VERIFY(status) + ! status = DftiComputeForward( rf%Desc_Handle_Dim1, X ) ! local_dim1 one-dimensional transforms along 2nd dimension Stride(1) = 0; Stride(2) = local_dim1 - mklstat = DftiSetValue( this%Desc_Handle_Dim2, DFTI_NUMBER_OF_TRANSFORMS, local_dim1) - mklstat = DftiSetValue( this%Desc_Handle_Dim2, DFTI_INPUT_DISTANCE, 1 ) - mklstat = DftiSetValue( this%Desc_Handle_Dim2, DFTI_OUTPUT_DISTANCE, 1 ) - mklstat = DftiSetValue( this%Desc_Handle_Dim2, DFTI_INPUT_STRIDES, Stride ) - mklstat = DftiSetValue( this%Desc_Handle_Dim2, DFTI_OUTPUT_STRIDES, Stride ) - mklstat = DftiCommitDescriptor( this%Desc_Handle_Dim2 ) - !mklstat = DftiComputeForward( this%Desc_Handle_Dim2, X ) + status = DftiSetValue( rf%Desc_Handle_Dim2, DFTI_NUMBER_OF_TRANSFORMS, local_dim1) + _VERIFY(status) + status = DftiSetValue( rf%Desc_Handle_Dim2, DFTI_INPUT_DISTANCE, 1 ) + _VERIFY(status) + status = DftiSetValue( rf%Desc_Handle_Dim2, DFTI_OUTPUT_DISTANCE, 1 ) + _VERIFY(status) + status = DftiSetValue( rf%Desc_Handle_Dim2, DFTI_INPUT_STRIDES, Stride ) + _VERIFY(status) + status = DftiSetValue( rf%Desc_Handle_Dim2, DFTI_OUTPUT_STRIDES, Stride ) + _VERIFY(status) + status = DftiCommitDescriptor( rf%Desc_Handle_Dim2 ) + _VERIFY(status) + !status = DftiComputeForward( rf%Desc_Handle_Dim2, X ) else - this%comm = MPI_COMM_NULL + rf%comm = MPI_COMM_NULL ! allocate mem and init mkl dft - mklstat = DftiCreateDescriptor(this%Desc_Handle, DFTI_SINGLE, DFTI_COMPLEX, 2, this%fft_lens) - if (mklstat/=DFTI_NO_ERROR) call quit('DftiCreateDescriptor failed!') + status = DftiCreateDescriptor(rf%Desc_Handle, DFTI_SINGLE, DFTI_COMPLEX, 2, [Nx_fft, Ny_fft]) + _VERIFY(status) ! initialize for actual dft computation - mklstat = DftiCommitDescriptor(this%Desc_Handle) - if (mklstat/=DFTI_NO_ERROR) call quit('DftiCommitDescriptor failed!') + status = DftiCommitDescriptor(rf%Desc_Handle) + _VERIFY(status) endif #endif - - end subroutine initialize - - - + _RETURN(_SUCCESS) + end function new_random_fields + + ! ************************************************************************** + ! destructor - deallocate memory - subroutine finalize(this) + subroutine finalize(this, rc) ! input/output variables class(random_fields), intent(inout) :: this - + integer, optional, intent(out) :: rc ! local variable - integer :: mklstat, i , npes, ierror + integer :: status ! deallocate memory if(allocated(this%field1_fft)) deallocate(this%field1_fft) if(allocated(this%field2_fft)) deallocate(this%field2_fft) - + #ifdef MKL_AVAILABLE if (this%comm == MPI_COMM_NULL) then - mklstat = DftiFreeDescriptor(this%Desc_Handle) - if (mklstat/=DFTI_NO_ERROR) call quit('DftiFreeDescriptor failed!') + status = DftiFreeDescriptor(this%Desc_Handle) + _VERIFY(status) else - - mklstat = DftiFreeDescriptor(this%Desc_Handle_dim1) - if (mklstat/=DFTI_NO_ERROR) call quit('DftiFreeDescriptor dim1 failed!') - mklstat = DftiFreeDescriptor(this%Desc_Handle_dim2) - if (mklstat/=DFTI_NO_ERROR) call quit('DftiFreeDescriptor dim2 failed!') - - call this%win_deallocate() - + + status = DftiFreeDescriptor(this%Desc_Handle_dim1) + _VERIFY(status) + status = DftiFreeDescriptor(this%Desc_Handle_dim2) + _VERIFY(status) + + call this%win_deallocate( _RC) + deallocate(this%dim1_counts, this%dim2_counts) endif #endif end subroutine finalize - - - - ! calculate fft grid (N_x_fft, N_y_fft) that extends - ! beyond the desired random field by about two correlation - ! lengths. its dimensions should be powers of 2 - subroutine calc_fft_grid(this) - - ! input/output variables - class(random_fields), intent(inout) :: this - - ! local variables - real, parameter :: mult_of_xcorr = 2. - real, parameter :: mult_of_ycorr = 2. - integer :: Nx_fft, Ny_fft - - ! add minimum required correlation lengths - Nx_fft = this%N_x + ceiling(mult_of_xcorr*this%lx/this%dx) - Ny_fft = this%N_y + ceiling(mult_of_ycorr*this%ly/this%dy) - - ! ensure N_x_fft, N_y_fft are powers of two - this%N_x_fft = 2**ceiling(log(real(Nx_fft))/log(2.)) - this%N_y_fft = 2**ceiling(log(real(Ny_fft))/log(2.)) - -#if TEST_RFG2D - write (*,*) - write (*,*) 'desired random field:' - write (*,*) 'N_x = ', this%N_x, ' N_y = ', this%N_y - write (*,*) 'dx = ', this%dx, ' dy = ', this%dy - write (*,*) 'xcorr = ', this%lx, ' ycorr = ', this%ly - write (*,*) - write (*,*) 'grid used for fft: ' - write (*,*) 'N_x_fft = ', this%N_x_fft, ' N_y_fft = ', this%N_y_fft - write (*,*) -#endif - - end subroutine calc_fft_grid - - + ! subroutine sqrt_gauss_spectrum_2d() ! @@ -289,24 +267,28 @@ end subroutine calc_fft_grid ! lambda_y : decorrelation length in y direction ! ! modifies this%field1_fft - subroutine sqrt_gauss_spectrum_2d(this) + + subroutine sqrt_gauss_spectrum_2d(this, lx, ly, dx, dy) ! input/output variables class(random_fields), intent(inout) :: this + real, intent(in) :: lx, ly, dx, dy ! local variables - real :: dkx, dky, fac, lamx2dkx2, lamy2dky2 - real :: lx2kx2(this%N_x_fft), ly2ky2(this%N_y_fft) + real :: dkx, dky, fac, lamx2dkx2, lamy2dky2 + real :: lx2kx2(this%N_x_fft), ly2ky2(this%N_y_fft) integer :: i, j, i1, i2, rank, ierror + real :: var + var = 1.0 ! start - dkx = (TWO_PI)/(float(this%N_x_fft)*this%dx) - dky = (TWO_PI)/(float(this%N_y_fft)*this%dy) + dkx = (TWO_PI)/(float(this%N_x_fft)*dx) + dky = (TWO_PI)/(float(this%N_y_fft)*dy) ! factor includes sqrt of volume element of ifft integral - fac = sqrt(this%var*this%lx*this%ly/(TWO_PI)*dkx*dky ) - lamx2dkx2 = this%lx*this%lx*dkx*dkx - lamy2dky2 = this%ly*this%ly*dky*dky + fac = sqrt(var*lx*ly/(TWO_PI)*dkx*dky ) + lamx2dkx2 = lx*lx*dkx*dkx + lamy2dky2 = ly*ly*dky*dky ! precompute (lambda_x*k_x)^2 in "wrap-around" ! order suitable for CXML fft @@ -342,7 +324,7 @@ subroutine sqrt_gauss_spectrum_2d(this) return end subroutine sqrt_gauss_spectrum_2d - + ! ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ! ---------------------------------------------------------------------- @@ -397,13 +379,14 @@ end subroutine sqrt_gauss_spectrum_2d ! (before re-scaling with sqrt(2)). ! The individual sample variances within each pair vary from ! realization to realization. - ! - subroutine rfg2d_fft(this, rseed, rfield, rfield2) - + + subroutine rfg2d_fft(this, rseed, rfield, rfield2, lx, ly, dx, dy) + ! input/output variables - class(random_fields), intent(inout) :: this ! ffield*_fft is modified - integer, intent(inout) :: rseed(NRANDSEED) ! nr_ran2 modifies rseed - real, dimension(this%N_x,this%N_y), intent(out) :: rfield, rfield2 + class(random_fields), intent(inout) :: this ! ffield*_fft is modified + integer, intent(inout) :: rseed(NRANDSEED) ! nr_ran2 modifies rseed + real, dimension(this%N_x,this%N_y), intent(out) :: rfield, rfield2 + real, intent(in) :: lx, ly, dx, dy ! local variables !real :: theta, ran_num ! rng @@ -413,7 +396,7 @@ subroutine rfg2d_fft(this, rseed, rfield, rfield2) integer :: N_x_fft, N_y_fft real :: N_xy_fft_real #ifdef MKL_AVAILABLE - integer :: mklstat + integer :: status complex, allocatable :: z_inout(:) complex, pointer :: tmp_field(:,:) complex, pointer :: tmp_field_dim1(:,:) @@ -433,7 +416,7 @@ subroutine rfg2d_fft(this, rseed, rfield, rfield2) ! compute dZ = H * exp(i*theta) * sqrt(d2k) ! start with square root of spectrum (factor H*sqrt(d2k)), put into field1 ! modify this%field1_fft - call this%sqrt_gauss_spectrum_2d + call this%sqrt_gauss_spectrum_2d(lx, ly, dx, dy) ! multiply by random phase angle !! do j=1,N_y_fft @@ -490,8 +473,8 @@ subroutine rfg2d_fft(this, rseed, rfield, rfield2) ! compute in-place backward transform (scale=1) ! NOTE: MKL backward transform is the same as NR forward transform - mklstat = DftiComputeBackward(this%Desc_Handle, z_inout) - if (mklstat/= DFTI_NO_ERROR) call quit('DftiComputeBackward failed!') + status = DftiComputeBackward(this%Desc_Handle, z_inout) + if (status/= DFTI_NO_ERROR) call quit('DftiComputeBackward failed!') ! extract random fields from z_inout z_inout = z_inout/N_xy_fft_real @@ -514,7 +497,8 @@ subroutine rfg2d_fft(this, rseed, rfield, rfield2) tmp_field_dim1 = cmplx(this%field1_fft(n1:n2,:),this%field2_fft(n1:n2,:)) cptr = c_loc(tmp_field_dim1(1,1)) call c_f_pointer (cptr, X, [ldim1*N_y_fft]) - mklstat = DftiComputeBackward( this%Desc_Handle_Dim2, X ) + status = DftiComputeBackward( this%Desc_Handle_Dim2, X ) + if (status/= DFTI_NO_ERROR) call quit('DftiComputeBackward dim2 failed!') call MPI_Barrier(this%node_comm, ierror) tmp_field(n1:n2,:) = tmp_field_dim1 @@ -527,7 +511,8 @@ subroutine rfg2d_fft(this, rseed, rfield, rfield2) tmp_field_dim2 = tmp_field(:,n1:n2) cptr = c_loc(tmp_field_dim2(1,1)) call c_f_pointer (cptr, X, [N_x_fft*ldim2]) - mklstat = DftiComputeBackward( this%Desc_Handle_Dim1, X ) + status = DftiComputeBackward( this%Desc_Handle_Dim1, X ) + if (status/= DFTI_NO_ERROR) call quit('DftiComputeBackward dim1 failed!') tmp_field(:,n1:n2) = tmp_field_dim2/N_xy_fft_real call MPI_Win_fence(0, this%win, ierror) @@ -626,8 +611,6 @@ subroutine generate_white_field(this, rseed, rfield) end if end subroutine generate_white_field - - ! a local, small stop routine subroutine quit(message) @@ -641,14 +624,14 @@ subroutine quit(message) end subroutine quit - subroutine win_allocate(this, nx, ny) + subroutine win_allocate(this, nx, ny, rc) class(random_fields), intent(inout) :: this integer, intent(in) :: nx, ny + integer, optional, intent(out) :: rc complex :: dummy integer(kind=MPI_ADDRESS_KIND) :: windowsize integer :: disp_unit,status, Rank integer(kind=MPI_ADDRESS_KIND) :: n_bytes - integer :: int_size call MPI_Comm_rank( this%node_comm, rank, status) @@ -658,117 +641,142 @@ subroutine win_allocate(this, nx, ny) disp_unit = 4 call MPI_Win_allocate_shared(windowsize, disp_unit, MPI_INFO_NULL, this%node_comm, & this%base_address, this%win, status) - + _VERIFY(status) if (rank /=0) CALL MPI_Win_shared_query(this%win, 0, windowsize, disp_unit, this%base_address, status) call MPI_Win_fence(0, this%win, status) + _VERIFY(status) call MPI_Barrier(this%node_comm, status) + _VERIFY(status) + _RETURN(_SUCCESS) end subroutine win_allocate - subroutine win_deallocate(this) + subroutine win_deallocate(this, rc) class(random_fields), intent(inout) :: this + integer, optional, intent(out) :: rc integer :: status call MPI_Win_fence(0, this%win, status) - call MPI_Win_free(this%win,status) + _VERIFY(status) + call MPI_Win_free(this%win, status) + _VERIFY(status) call MPI_comm_free(this%node_comm, status) + _VERIFY(status) end subroutine win_deallocate -end module random_fields_class - +end module Random_fieldsMod +module StringRandom_fieldsMapMod + use Random_fieldsMod -#ifdef TEST_RFG2D +#include "types/key_deferredLengthString.inc" +#define _value type (random_fields) +#define _value_equal_defined -program test_rfg2d - - use random_fields_class - use nr_ran2_gasdev - - implicit none - - integer :: N_x, N_y, i, j, n_e, N_e_tot - real :: dx, dy, lx, ly, var - real, allocatable, dimension(:,:) :: field1, field2 - - character(300) :: file_name - character(10) :: n_e_string - character(100) :: output_format - character(10) :: tmp_string +#define _map StringRandom_fieldsMap +#define _iterator StringRandom_fieldsMapIterator - integer :: RSEEDCONST - integer, dimension(NRANDSEED) :: rseed - - character(5) :: fft_tag - - ! instance of random_fields - type(random_fields) :: rf - - ! start - RSEEDCONST = -777 - rseed(1) = RSEEDCONST - write (*,*) RSEEDCONST - call init_randseed(rseed) - - N_x = 144 - N_y = 91 - dx = 5000. - dy = 5000. - lx = 45000. - ly = 45000. - var = 1. - - - allocate(field1(N_x,N_y)) - allocate(field2(N_x,N_y)) - -#ifdef MKL_AVAILABLE - fft_tag = 'mklx.' -#else - fft_tag = 'nrxx.' -#endif +#define _alt - ! get N_e fields - N_e_tot = 10 - do n_e=1,N_e_tot,2 - - call rf%initialize(N_x, N_y, var, lx, ly, dx, dy) - call rf%rfg2d_fft(rseed, field1, field2) - !call rf%generate_white_field(rseed, field1) - call rf%finalize - - ! write to file - ! field1 - write(n_e_string, '(i3.3)') n_e - file_name = 'rf.'//fft_tag// n_e_string(1:len_trim(n_e_string)) // '.dat' - write(tmp_string, '(i3.3)') N_y - output_format = '(' // tmp_string(1:len_trim(tmp_string)) // '(1x,e13.5))' - open (10,file=file_name,status='unknown') - do i=1,N_x - write (10,output_format(1:len_trim(output_format))) (field1(i,j), j=1,N_y) - end do - close (10,status='keep') - - ! field2 - write(n_e_string, '(i3.3)') n_e+1 - file_name = 'rf.' //fft_tag// n_e_string(1:len_trim(n_e_string)) // '.dat' - write(tmp_string, '(i3.3)') N_y - output_format = '(' // tmp_string(1:len_trim(tmp_string)) // '(1x,e13.5))' - open (10,file=file_name,status='unknown') - do i=1,N_x - write (10,output_format(1:len_trim(output_format))) (field2(i,j), j=1,N_y) - end do - close (10,status='keep') - - end do +#include "templates/map.inc" -end program test_rfg2d +#undef _alt +#undef _iterator +#undef _map +#undef _value +#undef _key +#undef _value_equal_defined +end module StringRandom_fieldsMapMod -#endif +#ifdef TEST_RFG2D +!program test_rfg2d +! +! use Random_fieldsMod +! use nr_ran2_gasdev +! +! implicit none +! +! integer :: N_x, N_y, i, j, n_e, N_e_tot +! real :: dx, dy, lx, ly, var +! real, allocatable, dimension(:,:) :: field1, field2 +! +! character(300) :: file_name +! character(10) :: n_e_string +! character(100) :: output_format +! character(10) :: tmp_string +! +! integer :: RSEEDCONST +! integer, dimension(NRANDSEED) :: rseed +! +! character(5) :: fft_tag +! +! ! instance of random_fields +! type(random_fields) :: rf +! +! ! start +! RSEEDCONST = -777 +! rseed(1) = RSEEDCONST +! write (*,*) RSEEDCONST +! call init_randseed(rseed) +! +! N_x = 144 +! N_y = 91 +! dx = 5000. +! dy = 5000. +! lx = 45000. +! ly = 45000. +! var = 1. +! +! +! allocate(field1(N_x,N_y)) +! allocate(field2(N_x,N_y)) +! +!#ifdef MKL_AVAILABLE +! fft_tag = 'mklx.' +!#else +! fft_tag = 'nrxx.' +!#endif +! +! ! get N_e fields +! N_e_tot = 10 +! do n_e=1,N_e_tot,2 +! +! rf = random_fields(N_x, N_y, Nx_fft, Ny_fft) +! call rf%rfg2d_fft(rseed, field1, field2, lx, ly, dx, dy) +! !call rf%generate_white_field(rseed, field1) +! call rf%finalize +! +! ! write to file +! ! field1 +! write(n_e_string, '(i3.3)') n_e +! file_name = 'rf.'//fft_tag// n_e_string(1:len_trim(n_e_string)) // '.dat' +! write(tmp_string, '(i3.3)') N_y +! output_format = '(' // tmp_string(1:len_trim(tmp_string)) // '(1x,e13.5))' +! open (10,file=file_name,status='unknown') +! do i=1,N_x +! write (10,output_format(1:len_trim(output_format))) (field1(i,j), j=1,N_y) +! end do +! close (10,status='keep') +! +! ! field2 +! write(n_e_string, '(i3.3)') n_e+1 +! file_name = 'rf.' //fft_tag// n_e_string(1:len_trim(n_e_string)) // '.dat' +! write(tmp_string, '(i3.3)') N_y +! output_format = '(' // tmp_string(1:len_trim(tmp_string)) // '(1x,e13.5))' +! open (10,file=file_name,status='unknown') +! do i=1,N_x +! write (10,output_format(1:len_trim(output_format))) (field2(i,j), j=1,N_y) +! end do +! close (10,status='keep') +! +! end do +! +!end program test_rfg2d -! ======= EOF ================================================== +#endif +! ======= EOF ================================================== diff --git a/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/GEOS_MetforceGridComp.F90 b/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/GEOS_MetforceGridComp.F90 index 78d3cf81..b306e9fd 100644 --- a/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/GEOS_MetforceGridComp.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/GEOS_MetforceGridComp.F90 @@ -215,8 +215,8 @@ subroutine SetServices(gc, rc) call MAPL_AddExportSpec( & gc, & - SHORT_NAME = "RainfSnowf", & - LONG_NAME = "rainf+snowf", & + SHORT_NAME = "RainfSnowf", & + LONG_NAME = "rainf+snowf", & UNITS = "kg m-2 s-1", & DIMS = MAPL_DimsTileOnly, & VLOCATION = MAPL_VlocationNone, & @@ -227,7 +227,7 @@ subroutine SetServices(gc, rc) call MAPL_AddExportSpec( & gc, & SHORT_NAME = "LWdown", & - LONG_NAME = "downward_longwave_radiation", & + LONG_NAME = "surface_absorbed_longwave_flux", & UNITS = "W m-2", & DIMS = MAPL_DimsTileOnly, & VLOCATION = MAPL_VlocationNone, & diff --git a/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 b/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 index dd6d4a23..b87e6734 100755 --- a/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/LDAS_Forcing.F90 @@ -3090,6 +3090,7 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & ! (for MERRA-2, always point to publicly available files) ! - updated comments ! + ! qliu+reichle, 5 Dec 2023 - added GEOS-IT ! ! ----------------------------------- ! @@ -3170,6 +3171,7 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & real, parameter :: nodata_GEOSgcm = 1.e15 character(40), dimension(N_G5DAS_vars, N_defs_cols) :: G5DAS_defs + character(40), dimension(N_G5DAS_vars, N_defs_cols) :: GEOSIT_defs character(40), dimension(N_MERRA_vars, N_defs_cols) :: MERRA_defs character(40), dimension(N_MERRA2plusAerosol_vars, N_defs_cols) :: M2INT_defs character(40), dimension(N_MERRA2plusAerosol_vars, N_defs_cols) :: M2COR_defs @@ -3205,7 +3207,7 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & logical :: minimize_shift, use_prec_corr, use_Predictor, tmp_init - logical :: daily_met_files + logical :: daily_met_files, daily_precipcorr_files integer :: nv_id, ierr, icount(3), istart(3), lonid, latid @@ -3243,6 +3245,32 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & G5DAS_defs(11,:)=[character(len=40):: 'QLML ','inst','inst1_2d_lfo_Nx','diag','S'] G5DAS_defs(12,:)=[character(len=40):: 'SPEEDLML','inst','inst1_2d_lfo_Nx','diag','S'] + ! ----------------------------------------------------------------------- + ! + ! define GEOS-IT file specs + ! + ! same as G5DAS except for file tag (column 3) + + GEOSIT_defs = G5DAS_defs + + ! GEOSIT character(40): + ! + ! 1 2 3 4 + ! 1234567890123456789012345678901234567890 + + GEOSIT_defs( 1,3) = 'lfo_tavg_1hr_glo_L576x361_slv ' + GEOSIT_defs( 2,3) = 'lfo_tavg_1hr_glo_L576x361_slv ' + GEOSIT_defs( 3,3) = 'lfo_tavg_1hr_glo_L576x361_slv ' + GEOSIT_defs( 4,3) = 'lfo_tavg_1hr_glo_L576x361_slv ' + GEOSIT_defs( 5,3) = 'lfo_tavg_1hr_glo_L576x361_slv ' + GEOSIT_defs( 6,3) = 'lfo_tavg_1hr_glo_L576x361_slv ' + GEOSIT_defs( 7,3) = 'lfo_tavg_1hr_glo_L576x361_slv ' + GEOSIT_defs( 8,3) = 'lfo_inst_1hr_glo_L576x361_slv ' + GEOSIT_defs( 9,3) = 'lfo_inst_1hr_glo_L576x361_slv ' + GEOSIT_defs(10,3) = 'lfo_inst_1hr_glo_L576x361_slv ' + GEOSIT_defs(11,3) = 'lfo_inst_1hr_glo_L576x361_slv ' + GEOSIT_defs(12,3) = 'lfo_inst_1hr_glo_L576x361_slv ' + ! MERRA-2 file specs with uncorrected (AGCM) precip from the "int" Collection ! (ie, the precip generated by the AGCM within the MERRA-2 system) @@ -3576,8 +3604,12 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & allocate(GEOSgcm_defs(N_GEOSgcm_vars,N_defs_cols)) - GEOSgcm_defs(1:N_G5DAS_vars, :) = G5DAS_defs - + if ( (index(met_tag, 'GEOSIT') > 0) .or. (index(met_tag, 'geosit') > 0) ) then + GEOSgcm_defs(1:N_G5DAS_vars,:) = GEOSIT_defs + else + GEOSgcm_defs(1:N_G5DAS_vars,:) = G5DAS_defs + end if + call parse_G5DAS_met_tag( met_path, met_tag, date_time_inst, & met_path_inst, prec_path_inst, met_tag_inst, use_prec_corr, & use_Predictor ) @@ -3664,9 +3696,9 @@ subroutine get_GEOS( date_time, force_dtstep, met_path, met_tag, & if ( (use_prec_corr) .and. (GEOSgcm_defs(GEOSgcm_var,1)(1:4)=='PREC') ) then call get_GEOS_corr_prec_filename(fname_full,file_exists,date_time_tmp, & - prec_path_tmp, met_tag_tmp, GEOSgcm_defs(GEOSgcm_var,:), precip_corr_file_ext ) + prec_path_tmp, met_tag_tmp, GEOSgcm_defs(GEOSgcm_var,:), precip_corr_file_ext, daily_precipcorr_files) - single_time_in_file = .true. ! corr precip files are always hourly (incl. MERRA-2) + single_time_in_file = .not. daily_precipcorr_files ! corr precip files are always hourly (incl. MERRA-2) else @@ -4607,8 +4639,8 @@ subroutine parse_G5DAS_met_tag( met_path_in, met_tag_in, date_time, & ! where {__prec[PREC]} and {__Nx+-} are optional and where ! ! G5DAS-NAME : name of standard G5DAS forcing (must not contain "__"!) - ! e.g., "e5110_fp", "d591_rpit1", "d591_fpit", ... - ! for cross-stream forcing, use "cross_d5124_RPFPIT" or "cross_FP" + ! e.g., "e5110_fp", "d591_rpit1", "d591_fpit", "d5294_geosit", ... + ! for cross-stream forcing, use "cross_d5294_GEOSIT", "cross_d5124_RPFPIT", "cross_FP" ! PREC : identifier for precip corrections to G5DAS forcing (eg., 'GPCPv1.1') ! ! If {__Nx+-} is present, set flag for use forcing files from the DAS/GCM Predictor @@ -4626,6 +4658,7 @@ subroutine parse_G5DAS_met_tag( met_path_in, met_tag_in, date_time, & ! reichle, 10 Oct 2019: added FP transition from f521 to f522 ! reichle, 17 Jan 2020: added FP transition from f522 to f525 ! reichle, 3 Apr 2020: added FP transition from f525 to f525_p5 + ! qliu+reichle, 5 Dec 2023: added GEOS-IT ! ! --------------------------------------------------------------------------- @@ -4658,6 +4691,10 @@ subroutine parse_G5DAS_met_tag( met_path_in, met_tag_in, date_time, & type(date_time_type) :: dt_end_d5124_rpit2 type(date_time_type) :: dt_end_d5124_rpit3 + type(date_time_type) :: dt_end_d5294_geosit1 + type(date_time_type) :: dt_end_d5294_geosit2 + type(date_time_type) :: dt_end_d5294_geosit3 + type(date_time_type) :: dt_end_e5110_fp type(date_time_type) :: dt_end_e5130_fp type(date_time_type) :: dt_end_e5131_fp @@ -4673,7 +4710,7 @@ subroutine parse_G5DAS_met_tag( met_path_in, met_tag_in, date_time, & ! ---------------------------------------------------------- ! - ! define transition times between RP-IT, FP-IT or FP streams + ! define transition times between RP-IT, FP-IT, GEOS-IT, or FP streams ! if "cross-stream" forcing is requested ! ! | stream start | stream end (as of 5 Dec 2014) @@ -4738,6 +4775,35 @@ subroutine parse_G5DAS_met_tag( met_path_in, met_tag_in, date_time, & dt_end_d5124_rpit3%min = 0 dt_end_d5124_rpit3%sec = 0 + ! | stream start | stream end + ! | (excl 1-yr | + ! | spinup) | + ! ---------------------------------------- + ! d5294_geosit1 | 1 Jan 1998 | 1 Jan 2008 + ! d5294_geosit2 | 1 Jan 2008 | 1 Jan 2018 + ! d5294_geosit3 | 1 Jan 2018 | (present) + + dt_end_d5294_geosit1%year = 2008 + dt_end_d5294_geosit1%month = 1 + dt_end_d5294_geosit1%day = 1 + dt_end_d5294_geosit1%hour = 0 + dt_end_d5294_geosit1%min = 0 + dt_end_d5294_geosit1%sec = 0 + + dt_end_d5294_geosit2%year = 2018 + dt_end_d5294_geosit2%month = 1 + dt_end_d5294_geosit2%day = 1 + dt_end_d5294_geosit2%hour = 0 + dt_end_d5294_geosit2%min = 0 + dt_end_d5294_geosit2%sec = 0 + + dt_end_d5294_geosit3%year = 9999 + dt_end_d5294_geosit3%month = 1 + dt_end_d5294_geosit3%day = 1 + dt_end_d5294_geosit3%hour = 0 + dt_end_d5294_geosit3%min = 0 + dt_end_d5294_geosit3%sec = 0 + ! --------------------------------- ! ! FP streams @@ -4957,6 +5023,23 @@ subroutine parse_G5DAS_met_tag( met_path_in, met_tag_in, date_time, & end if + elseif (met_tag_out(1:18)=='cross_d5294_GEOSIT') then + + if (datetime_lt_refdatetime( date_time, dt_end_d5294_geosit1 )) then + + stream = 'd5294_geosit_jan98' ! use d5294 GEOS-IT stream 1 + + elseif (datetime_lt_refdatetime( date_time, dt_end_d5294_geosit2 )) then + + stream = 'd5294_geosit_jan08' ! use d5294 GEOS-IT stream 2 + + else + + stream = 'd5294_geosit_jan18' ! use d5294 GEOS-IT stream 3 + + end if + + elseif (met_tag_out(1:8)=='cross_FP') then if (datetime_lt_refdatetime( date_time, dt_end_e5110_fp )) then @@ -5103,7 +5186,7 @@ subroutine get_GEOS_forcing_filename(fname_full,file_exists, date_time, daily_fi ! local variables character(300) :: fname, fname_full_tmp1, fname_full_tmp2 - character( 14) :: time_stamp + character( 16) :: time_stamp character( 4) :: YYYY, HHMM, day_dir character( 2) :: MM, DD @@ -5129,11 +5212,15 @@ subroutine get_GEOS_forcing_filename(fname_full,file_exists, date_time, daily_fi if (daily_file) then - time_stamp(1:8) = YYYY // MM // DD + time_stamp(1:8) = YYYY // MM // DD - else + elseif (index(met_tag,'GEOSIT') > 0 .or. index(met_tag,'geosit') > 0) then - time_stamp = YYYY // MM // DD // '_' // trim(HHMM) // 'z' + time_stamp(1:16) = YYYY //'-'// MM //'-'// DD // 'T' // trim(HHMM) // 'Z' + + else + + time_stamp(1:14) = YYYY // MM // DD // '_' // trim(HHMM) // 'z' end if @@ -5535,22 +5622,23 @@ subroutine GEOS_closefile(fid) ! **************************************************************** subroutine get_GEOS_corr_prec_filename(fname_full,file_exists, date_time, met_path, met_tag, & - GEOSgcm_defs, file_ext ) + GEOSgcm_defs, file_ext, daily_files) implicit none character(*), intent(inout) :: fname_full logical,intent(out) :: file_exists + logical,intent(out) :: daily_files type(date_time_type), intent(in) :: date_time character(*), intent(in) :: met_path character(*), intent(in) :: met_tag character( 40), dimension(5), intent(in) :: GEOSgcm_defs character(*), intent(in) :: file_ext - + ! local variables - character(100) :: fname + character(100) :: fname, fname_tmp character(200) :: fdir - character(300) :: fname_full_tmp1, fname_full_tmp2 + character(300) :: fname_full_tmp1, fname_full_tmp2, fname_full_tmp3 character( 4) :: YYYY, HHMM character( 2) :: MM, DD @@ -5573,14 +5661,20 @@ subroutine get_GEOS_corr_prec_filename(fname_full,file_exists, date_time, met_pa ! (as of 7 May 2020, no V02 or higher was issued for GEOS FP "lfo" products ! going back to Jun 2013) - fname = trim(met_tag) // '.' // trim(GEOSgcm_defs(3)) // '_corr.' // & + fname = trim(met_tag) // '.' // trim(GEOSgcm_defs(3)) // '_corr.' // & YYYY // MM // DD // '_' // trim(HHMM) // '.V01.' // trim(file_ext) - + + fname_tmp = trim(met_tag) // '.' // trim(GEOSgcm_defs(3)) // '_corr.' // & + YYYY // MM // DD // '.V01.' // trim(file_ext) + else - fname = trim(met_tag) // '.' // trim(GEOSgcm_defs(3)) // '_corr.' // & + fname = trim(met_tag) // '.' // trim(GEOSgcm_defs(3)) // '_corr.' // & YYYY // MM // DD // '_' // trim(HHMM) // 'z.' // trim(file_ext) - + + fname_tmp = trim(met_tag) // '.' // trim(GEOSgcm_defs(3)) // '_corr.' // & + YYYY // MM // DD // '.' // trim(file_ext) + end if ! assemble dir name with "/Yyy" (year) dir but without "/Mmm" (month) dir @@ -5591,7 +5685,7 @@ subroutine get_GEOS_corr_prec_filename(fname_full,file_exists, date_time, met_pa ! ----------------------------------------------------------------------- file_exists = .false. ! initialize - + daily_files = .false. ! first try: look for file in year/month dir ! (LDAS standard for corrected G5DAS precip) @@ -5604,8 +5698,19 @@ subroutine get_GEOS_corr_prec_filename(fname_full,file_exists, date_time, met_pa fname_full_tmp1 = trim(fname_full) ! remember for error log below + ! second try: look for daily file in year/month dir + fname_full = trim(fdir) // 'M' // MM // '/' // trim(fname_tmp) - ! second try: *without* "/Mmm" (month) dir + inquire(file=fname_full, exist=file_exists) + + if (file_exists) then + daily_files = .true. + return ! done + endif + + fname_full_tmp2 = trim(fname_full) ! remember for error log below + + ! third try: *without* "/Mmm" (month) dir ! THIS TRY IS PROBABLY OBSOLETE BUT COULD EASILY BE TWEAKED TO LOOK ! IN year/month/day DIRECTORY (WHICH POSSIBLY APPLIES TO CORRECTED @@ -5618,7 +5723,7 @@ subroutine get_GEOS_corr_prec_filename(fname_full,file_exists, date_time, met_pa if (file_exists) return ! done - fname_full_tmp2 = trim(fname_full) ! remember for error log below + fname_full_tmp3 = trim(fname_full) ! remember for error log below ! last try: for GEOS FP with generic file names, try product counter '.V02.' in year/month dir @@ -5649,6 +5754,7 @@ subroutine get_GEOS_corr_prec_filename(fname_full,file_exists, date_time, met_pa print '(400A)', trim(Iam) // ': Could not find any of the following files:' print '(400A)', trim(fname_full_tmp1) print '(400A)', trim(fname_full_tmp2) + print '(400A)', trim(fname_full_tmp3) print '(400A)', trim(fname_full) endif endif diff --git a/src/Components/GEOSldas_GridComp/Shared/CMakeLists.txt b/src/Components/GEOSldas_GridComp/LDAS_Shared/CMakeLists.txt similarity index 100% rename from src/Components/GEOSldas_GridComp/Shared/CMakeLists.txt rename to src/Components/GEOSldas_GridComp/LDAS_Shared/CMakeLists.txt diff --git a/src/Components/GEOSldas_GridComp/Shared/LDAS_Convert.F90 b/src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_Convert.F90 similarity index 100% rename from src/Components/GEOSldas_GridComp/Shared/LDAS_Convert.F90 rename to src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_Convert.F90 diff --git a/src/Components/GEOSldas_GridComp/Shared/LDAS_DriverTypes.F90 b/src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_DriverTypes.F90 similarity index 100% rename from src/Components/GEOSldas_GridComp/Shared/LDAS_DriverTypes.F90 rename to src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_DriverTypes.F90 diff --git a/src/Components/GEOSldas_GridComp/Shared/LDAS_Exceptions.F90 b/src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_Exceptions.F90 similarity index 100% rename from src/Components/GEOSldas_GridComp/Shared/LDAS_Exceptions.F90 rename to src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_Exceptions.F90 diff --git a/src/Components/GEOSldas_GridComp/Shared/LDAS_PertTypes.F90 b/src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_PertTypes.F90 similarity index 100% rename from src/Components/GEOSldas_GridComp/Shared/LDAS_PertTypes.F90 rename to src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_PertTypes.F90 diff --git a/src/Components/GEOSldas_GridComp/Shared/LDAS_RepairForcing.F90 b/src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_RepairForcing.F90 similarity index 100% rename from src/Components/GEOSldas_GridComp/Shared/LDAS_RepairForcing.F90 rename to src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_RepairForcing.F90 diff --git a/src/Components/GEOSldas_GridComp/Shared/LDAS_TileCoordRoutines.F90 b/src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_TileCoordRoutines.F90 similarity index 100% rename from src/Components/GEOSldas_GridComp/Shared/LDAS_TileCoordRoutines.F90 rename to src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_TileCoordRoutines.F90 diff --git a/src/Components/GEOSldas_GridComp/Shared/LDAS_TileCoordType.F90 b/src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_TileCoordType.F90 similarity index 100% rename from src/Components/GEOSldas_GridComp/Shared/LDAS_TileCoordType.F90 rename to src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_TileCoordType.F90 diff --git a/src/Components/GEOSldas_GridComp/Shared/LDAS_ensdrv_Globals.F90 b/src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_ensdrv_Globals.F90 similarity index 100% rename from src/Components/GEOSldas_GridComp/Shared/LDAS_ensdrv_Globals.F90 rename to src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_ensdrv_Globals.F90 diff --git a/src/Components/GEOSldas_GridComp/Shared/LDAS_ensdrv_functions.F90 b/src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_ensdrv_functions.F90 similarity index 100% rename from src/Components/GEOSldas_GridComp/Shared/LDAS_ensdrv_functions.F90 rename to src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_ensdrv_functions.F90 diff --git a/src/Components/GEOSldas_GridComp/Shared/LDAS_ensdrv_mpi.F90 b/src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_ensdrv_mpi.F90 similarity index 99% rename from src/Components/GEOSldas_GridComp/Shared/LDAS_ensdrv_mpi.F90 rename to src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_ensdrv_mpi.F90 index 8dd53c20..07cf17bd 100644 --- a/src/Components/GEOSldas_GridComp/Shared/LDAS_ensdrv_mpi.F90 +++ b/src/Components/GEOSldas_GridComp/LDAS_Shared/LDAS_ensdrv_mpi.F90 @@ -741,6 +741,8 @@ subroutine init_MPI_types() ! character(40) :: units ! character(200) :: path ! character(80) :: name + ! character(200) :: maskpath + ! character(80) :: maskname ! character(200) :: scalepath ! character(80) :: scalename ! character(200) :: flistpath @@ -779,7 +781,7 @@ subroutine init_MPI_types() iblock( 5) = 3 iblock( 6) = 4 iblock( 7) = 1 - iblock( 8) = 40+40+200+80+200+80+200+80 + iblock( 8) = 40+40+200+80+200+80+200+80+200+80 iblock( 9) = 2 iblock(10) = 2 iblock(11) = 2 diff --git a/src/Components/GEOSldas_GridComp/Shared/catch_types.F90 b/src/Components/GEOSldas_GridComp/LDAS_Shared/catch_types.F90 similarity index 98% rename from src/Components/GEOSldas_GridComp/Shared/catch_types.F90 rename to src/Components/GEOSldas_GridComp/LDAS_Shared/catch_types.F90 index df22a2b3..d26e5521 100644 --- a/src/Components/GEOSldas_GridComp/Shared/catch_types.F90 +++ b/src/Components/GEOSldas_GridComp/LDAS_Shared/catch_types.F90 @@ -38,7 +38,7 @@ module catch_types public :: assignment (=), operator (*), operator (/), operator (+), operator (-) - public :: cat_diagS_sqrt + public :: cat_diagS_sqrt, cat_diagS_max public :: catprogn2wesn, catprogn2htsn, catprogn2sndz, catprogn2ghtcnt @@ -1368,6 +1368,38 @@ function catprogn2ghtcnt(N_cat, cat_progn) end function catprogn2ghtcnt ! *********************************************************************** + + function cat_diagS_max( scalar, cat_diagS ) + + implicit none + + type(cat_diagS_type) :: cat_diagS_max + type(cat_diagS_type), intent(in) :: cat_diagS + + real, intent(in) :: scalar + + integer :: i ! local + + cat_diagS_max%ar1 = max(scalar, cat_diagS%ar1) + cat_diagS_max%ar2 = max(scalar, cat_diagS%ar2) + + cat_diagS_max%asnow = max(scalar, cat_diagS%asnow) + + cat_diagS_max%sfmc = max(scalar, cat_diagS%sfmc) + cat_diagS_max%rzmc = max(scalar, cat_diagS%rzmc) + cat_diagS_max%prmc = max(scalar, cat_diagS%prmc) + + cat_diagS_max%tsurf = max(scalar, cat_diagS%tsurf) + + do i=1,N_gt + cat_diagS_max%tp(i) = max(scalar, cat_diagS%tp(i)) + end do + + do i=1,N_snow + cat_diagS_max%tpsn(i) = max(scalar, cat_diagS%tpsn(i)) + end do + + end function cat_diagS_max end module catch_types diff --git a/src/Components/GEOSldas_GridComp/Shared/enkf_types.F90 b/src/Components/GEOSldas_GridComp/LDAS_Shared/enkf_types.F90 similarity index 89% rename from src/Components/GEOSldas_GridComp/Shared/enkf_types.F90 rename to src/Components/GEOSldas_GridComp/LDAS_Shared/enkf_types.F90 index 46e5ef5b..566c75ef 100644 --- a/src/Components/GEOSldas_GridComp/Shared/enkf_types.F90 +++ b/src/Components/GEOSldas_GridComp/LDAS_Shared/enkf_types.F90 @@ -21,6 +21,8 @@ module enkf_types ! ! reichle, 8 Jun 2017: added "%flistpath" and "%flistname" to "obs_param_type" ! + ! reichle,28 Feb 2024: added "%maskpath" and "%maskname" to "obs_param_type" + ! ! ------------------------------------------------------------------- implicit none @@ -53,7 +55,7 @@ module enkf_types ! added OminusA information for adaptive filtering - reichle, 1 Feb 2007 ! added "varname" field to "obs_param_type" - reichle 14 Jun 2011 ! major revisions to "obs_type" fields - reichle 16 Jun 2011 - ! added "units" field to "obs_param_tpye" - reichle 22 Nov 2011 + ! added "units" field to "obs_param_type" - reichle 22 Nov 2011 type :: obs_type @@ -96,6 +98,11 @@ module enkf_types integer :: species ! identifier for type of measurement integer :: orbit ! type of (half-)orbit + ! 0 = n/a [eg., in situ obs] + ! 1 = ascending + ! 2 = descending + ! 3 = ascending or descending + ! 4 = geostationary integer :: pol ! polarization ! 0 = n/a [eg., multi-pol. retrieval] @@ -104,10 +111,10 @@ module enkf_types ! 3 = ... ! [add 3rd/4th Stokes, HH, HV, VH, VV] - integer :: N_ang ! # angles in species + integer :: N_ang ! # satellite viewing angles in species (radiance obs only) real, & - dimension(N_obs_ang_max) :: ang ! vector of angles + dimension(N_obs_ang_max) :: ang ! vector of satellite viewing angles real :: freq ! frequency [Hz] @@ -133,6 +140,8 @@ module enkf_types character(200) :: path ! path to measurements file character(80) :: name ! name identifier for measurements + character(200) :: maskpath ! path to obs mask file + character(80) :: maskname ! filename for obs mask character(200) :: scalepath ! path to file with scaling parameters character(80) :: scalename ! filename for scaling parameters character(200) :: flistpath ! path to file with list of obs file names @@ -196,6 +205,8 @@ subroutine write_obs_param(unitnumber, N_obs_param, obs_param) write (unitnumber, '(42A)') "'" // trim(obs_param(i)%units) // "'" write (unitnumber,'(202A)') "'" // trim(obs_param(i)%path) // "'" write (unitnumber, '(82A)') "'" // trim(obs_param(i)%name) // "'" + write (unitnumber,'(202A)') "'" // trim(obs_param(i)%maskpath) // "'" + write (unitnumber, '(82A)') "'" // trim(obs_param(i)%maskname) // "'" write (unitnumber,'(202A)') "'" // trim(obs_param(i)%scalepath) // "'" write (unitnumber, '(82A)') "'" // trim(obs_param(i)%scalename) // "'" write (unitnumber,'(202A)') "'" // trim(obs_param(i)%flistpath) // "'" diff --git a/src/Components/GEOSldas_GridComp/Shared/my_lu_decomp.f b/src/Components/GEOSldas_GridComp/LDAS_Shared/my_lu_decomp.f similarity index 100% rename from src/Components/GEOSldas_GridComp/Shared/my_lu_decomp.f rename to src/Components/GEOSldas_GridComp/LDAS_Shared/my_lu_decomp.f diff --git a/src/Components/GEOSldas_GridComp/Shared/my_matrix_functions.F90 b/src/Components/GEOSldas_GridComp/LDAS_Shared/my_matrix_functions.F90 similarity index 100% rename from src/Components/GEOSldas_GridComp/Shared/my_matrix_functions.F90 rename to src/Components/GEOSldas_GridComp/LDAS_Shared/my_matrix_functions.F90 diff --git a/src/Components/GEOSldas_GridComp/Shared/nr_indexx.f b/src/Components/GEOSldas_GridComp/LDAS_Shared/nr_indexx.f similarity index 100% rename from src/Components/GEOSldas_GridComp/Shared/nr_indexx.f rename to src/Components/GEOSldas_GridComp/LDAS_Shared/nr_indexx.f diff --git a/src/Shared/.gitignore b/src/Shared/.gitignore index d5e49170..dba5156e 100644 --- a/src/Shared/.gitignore +++ b/src/Shared/.gitignore @@ -4,3 +4,6 @@ /@MAPL /MAPL /MAPL@ +/@NCEP_Shared +/NCEP_Shared +/NCEP_Shared@ diff --git a/src/Shared/CMakeLists.txt b/src/Shared/CMakeLists.txt index e7ace2f3..822331ee 100644 --- a/src/Shared/CMakeLists.txt +++ b/src/Shared/CMakeLists.txt @@ -1,3 +1,4 @@ esma_add_subdirectory (MAPL) esma_add_subdirectory (GMAO_Shared) esma_add_subdirectory (GEOS_Util) +esma_add_subdirectory (NCEP_Shared)