diff --git a/.circleci/config.yml b/.circleci/config.yml index 9bc8e492..096c8ed0 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,42 +1,22 @@ version: 2.1 +# Anchor to prevent forgetting to update a version +baselibs_version: &baselibs_version v7.7.0 + orbs: - circleci-tools: geos-esm/circleci-tools@0.13.0 + ci: geos-esm/circleci-tools@1 workflows: build-test: jobs: - - build-GEOSldas: + - ci/build: name: build-GEOSldas-on-<< matrix.compiler >> - matrix: - parameters: - compiler: [gfortran, ifort] context: - docker-hub-creds - -jobs: - build-GEOSldas: - parameters: - compiler: - type: string - executor: - name: circleci-tools/<< parameters.compiler >> - resource_class: large - working_directory: /root/project - steps: - - checkout: - path: GEOSldas - - circleci-tools/versions: - compiler: << parameters.compiler >> - - circleci-tools/mepoclone: - repo: GEOSldas - - circleci-tools/checkout_if_exists: - repo: GEOSldas - - circleci-tools/cmake: - repo: GEOSldas - compiler: << parameters.compiler >> - - circleci-tools/buildinstall: + matrix: + parameters: + compiler: [ifort, gfortran] + baselibs_version: *baselibs_version repo: GEOSldas - - circleci-tools/compress_artifacts - - store_artifacts: - path: /logfiles + mepodevelop: false + persist_workspace: false # Needs to be true to run fv3/gcm experiment, costs extra diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..986cead4 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,27 @@ +# Global Editor Config for MAPL +# +# This is an ini style configuration. See http://editorconfig.org/ for more information on this file. +# +# Top level editor config. +root = true + +# Always use Unix style new lines with new line ending on every file and trim whitespace +[*] +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +# Python: PEP8 defines 4 spaces for indentation +[*.py] +indent_style = space +indent_size = 4 + +# YAML format, 2 spaces +[{*.yaml,*.yml}] +indent_style = space +indent_size = 2 + +# CMake (from KitWare: https://github.com/Kitware/CMake/blob/master/.editorconfig) +[{CMakeLists.txt,*.cmake,*.rst}] +indent_style = space +indent_size = 2 diff --git a/.github/workflows/enforce-labels.yml b/.github/workflows/enforce-labels.yml new file mode 100644 index 00000000..6e1720ef --- /dev/null +++ b/.github/workflows/enforce-labels.yml @@ -0,0 +1,29 @@ +name: Enforce PR Labels + +on: + pull_request: + types: [opened, labeled, unlabeled, edited, synchronize] + +jobs: + require-label: + runs-on: ubuntu-latest + steps: + - uses: mheap/github-action-required-labels@v2 + 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" + add_comment: true + blocking-label: + runs-on: ubuntu-latest + steps: + - uses: mheap/github-action-required-labels@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + mode: exactly + count: 0 + labels: "Contingent - DNA,Needs Lead Approval,Contingent -- Do Not Approve" + add_comment: true diff --git a/.gitignore b/.gitignore index bd061d50..9fb68704 100644 --- a/.gitignore +++ b/.gitignore @@ -5,10 +5,14 @@ /@env/ /env/ /env@/ -/BUILD/ -/build*/ -/install*/ /.mepo/ parallel_build.o* log.* CMakeUserPresets.json + +*.swp +*.swo +.DS_Store +*# +.#* +**/CVS/ diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 00000000..77d1727c --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,143 @@ +{ + "version": 3, + "cmakeMinimumRequired": { + "major": 3, + "minor": 21, + "patch": 0 + }, + "configurePresets": [ + { + "name": "base-configure", + "hidden": true, + "displayName": "Base Configure Settings", + "description": "Sets build and install directories", + "binaryDir": "${sourceDir}/build-${presetName}", + "cacheVariables": { + "BASEDIR": "$env{BASEDIR}", + "CMAKE_INSTALL_PREFIX": "${sourceDir}/install-${presetName}" + } + }, + { + "name": "base-gnu", + "hidden": true, + "inherits": "base-configure", + "displayName": "Base GNU Make Config", + "description": "Sets GNU Make generator", + "generator": "Unix Makefiles" + }, + { + "name": "base-ninja", + "hidden": true, + "inherits": "base-configure", + "displayName": "Base Ninja Config", + "description": "Sets Ninja generator", + "generator": "Ninja" + }, + { + "name": "Release", + "inherits": "base-gnu", + "displayName": "Release Configure", + "description": "Release build using GNU Make generator", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release" + } + }, + { + "name": "Debug", + "inherits": "base-gnu", + "displayName": "Debug Configure", + "description": "Debug build using GNU Make generator", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + } + }, + { + "name": "Aggressive", + "inherits": "base-gnu", + "displayName": "Aggressive Configure", + "description": "Aggressive build using GNU Make generator", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Aggressive" + } + }, + { + "name": "Release-Ninja", + "inherits": "base-ninja", + "displayName": "Release Ninja Configure", + "description": "Release build using Ninja generator", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release" + } + }, + { + "name": "Debug-Ninja", + "inherits": "base-ninja", + "displayName": "Debug Ninja Configure", + "description": "Debug build using Ninja generator", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + } + }, + { + "name": "Aggressive-Ninja", + "inherits": "base-ninja", + "displayName": "Aggressive Ninja Configure", + "description": "Aggressive build using Ninja generator", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Aggressive" + } + } + ], + "buildPresets": [ + { + "name": "base-build", + "hidden": true, + "displayName": "Base Build Config", + "description": "Sets default build options", + "jobs": 6, + "targets": ["install"] + }, + { + "name": "Release", + "configurePreset": "Release", + "inherits": "base-build", + "displayName": "Release Build", + "description": "Release build using GNU Make generator" + }, + { + "name": "Debug", + "configurePreset": "Debug", + "inherits": "base-build", + "displayName": "Debug Build", + "description": "Debug build using GNU Make generator" + }, + { + "name": "Aggressive", + "configurePreset": "Aggressive", + "inherits": "base-build", + "displayName": "Aggressive Build", + "description": "Aggressive build using GNU Make generator" + }, + { + "name": "Release-Ninja", + "configurePreset": "Release-Ninja", + "inherits": "base-build", + "displayName": "Release Ninja Build", + "description": "Release build using Ninja generator" + }, + { + "name": "Debug-Ninja", + "configurePreset": "Debug-Ninja", + "inherits": "base-build", + "displayName": "Debug Ninja Build", + "description": "Debug build using Ninja generator" + }, + { + "name": "Aggressive-Ninja", + "configurePreset": "Aggressive-Ninja", + "inherits": "base-build", + "displayName": "Aggressive Ninja Build", + "description": "Aggressive build using Ninja generator" + } + ] +} diff --git a/components.yaml b/components.yaml index a1033517..b77a2af4 100644 --- a/components.yaml +++ b/components.yaml @@ -4,31 +4,31 @@ GEOSldas: env: local: ./@env remote: ../ESMA_env.git - tag: v3.13.0 + tag: v4.8.0 cmake: local: ./@cmake remote: ../ESMA_cmake.git - tag: v3.12.0 + tag: v3.21.0 ecbuild: local: ./@cmake/@ecbuild remote: ../ecbuild.git - tag: geos/v1.2.0 + tag: geos/v1.3.0 GMAO_Shared: local: ./src/Shared/@GMAO_Shared remote: ../GMAO_Shared.git sparse: ./config/GMAO_Shared.sparse - tag: v1.5.5 + tag: v1.6.3 MAPL: local: ./src/Shared/@MAPL remote: ../MAPL.git - tag: v2.19.0 + tag: v2.33.0 GEOSgcm_GridComp: local: ./src/Components/GEOSldas_GridComp/@GEOSgcm_GridComp remote: ../GEOSgcm_GridComp.git sparse: ./config/GEOSgcm_GridComp_ldas.sparse - tag: v1.15.5 + tag: v1.17.2 diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index 6babd21a..6320b4f5 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -33,6 +33,52 @@ This README file contains the history of stable GEOSldas versions ("tags") in Gi Overview of Git Releases: ============================ +[v17.12.0](https://github.com/GEOS-ESM/GEOSldas/releases/tag/v17.12.0) - 2022-12-16 +------------------------------ + +- Not zero-diff vs. v17.11.1 for simulations with data assimilation in EASE-grid tile space. Simulations in EASE-grid tile space without data assimilation are zero-diff except for roundoff differences in “tilegrids” and “tilecoord” parameters (`ll_lat`, `ll_lon`, `ur_lat`, `ur_lon`, `dlon`, `dlat`, `area`). Zero-diff for simulations in cube-sphere tile space with and without data assimilation. + +- Science changes: + - Support for MODIS-based snow albedo (GEOSgcm_GridComp [PR#618](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/618)). + - Support for CatchCN ensemble simulations ([PR #584](https://github.com/GEOS-ESM/GEOSldas/pull/584), GEOSgcm_GridComp [PR#645](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/645)). + +- Utilities: + - Re-mapping of restart files ([PR #551](https://github.com/GEOS-ESM/GEOSldas/pull/551), GMAO_Shared [PR#238](https://github.com/GEOS-ESM/GMAO_Shared/pull/238), GEOSgcm_GridComp [PR#571](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/571) and [PR#658](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/658)): + - New GMAO_Shared utility `remap_restarts.py`, including fixes to re-mapping of CatchCN restart variables (not fixed for `regrid.pl`). + - Deprecated perl script `regrid.pl`. + - New GEOSldas utility `process_rst.py` (replaces `process_rst.csh`). + - Re-mapping of LDASsa-formatted binary restarts is no longer supported. + - Trivial non-zero diff changes (presence/absence) in optional restart fields (`TSURF`, `WW`, `FR`, `CQ`, `CH`). + - Major cleanup of Catch[CN]-related routines for processing restarts in GEOSldas and GEOSgcm_GridComp. + - Updated `ldas_setup` to python3. + - Further cleanup and reorganization of EASE grid utilities and make_bcs ([PR #586](https://github.com/GEOS-ESM/GEOSldas/pull/586), GEOSgcm_GridComp [PR#601](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/601) and [PR#634]( https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/634)): + - Unified source code for EASEv1 and EASEv2 utilities, which causes roundoff differences. + - Reorganized and added utilities in LDAS_App ([PR #569](https://github.com/GEOS-ESM/GEOSldas/pull/569)): + - Added matlab routines for generation of Tb scaling parameters, mwRTM parameters, and climatology files. + - Added LADAS-related utilities and sample config files, incl. option for ensemble forcing of LDAS coupled to deterministic simulation in Hybrid4DEnVar. + - Added script for rewinding existing GEOSldas run ([PR #606](https://github.com/GEOS-ESM/GEOSldas/pull/606)). + +- Interface: + - Increased character length of string variables to avoid truncation of input file paths/names ([PR #574](https://github.com/GEOS-ESM/GEOSldas/pull/574)). + - Changed ensemble member identifier string in HISTORY.rc to “_e[XXXX]” ([PR #584](https://github.com/GEOS-ESM/GEOSldas/pull/584)). + - Restored GEOSldas “debug” mode ([PR #587](https://github.com/GEOS-ESM/GEOSldas/pull/587), [PR #589](https://github.com/GEOS-ESM/GEOSldas/pull/589), and [PR #591](https://github.com/GEOS-ESM/GEOSldas/pull/591)). + +- Infrastructure: + - Updated environment, CMake, ecbuild, and MAPL ([PR #604](https://github.com/GEOS-ESM/GEOSldas/pull/604)): + - ESMA_env v4.8.0 + - ESMA_cmake v3.21.0 + - ecbuild v1.3.0 + - MAPL 2.33.0 + - GMAO_Shared v1.6.3 + - GEOSgcm_GridComp v1.17.2 + +- Documentation: + - Added README_LDAS_App ([PR #569](https://github.com/GEOS-ESM/GEOSldas/pull/569)) + +- Bug fixes and other minor changes: + - Fixed units labels of several CatchCNCLM45 restart variables (GEOSgcm_GridComp [PR#660](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/660)) + +------------------------------ [v17.11.1](https://github.com/GEOS-ESM/GEOSldas/releases/tag/v17.11.1) - 2022-06-15 ------------------------------ @@ -50,6 +96,7 @@ Overview of Git Releases: - Bug fixes and other minor changes: - Corrected exports for water table depth and free-standing water change over peat ([PR #556](https://github.com/GEOS-ESM/GEOSldas/pull/556), [GEOSgcm_GridComp PR #593](https://github.com/GEOS-ESM/GEOSgcm_GridComp/pull/593)). +------------------------------ [v17.11.0](https://github.com/GEOS-ESM/GEOSldas/releases/tag/v17.11.0) - 2022-03-04 ------------------------------ diff --git a/src/Applications/LDAS_App/CMakeLists.txt b/src/Applications/LDAS_App/CMakeLists.txt index c78cf867..f2f5ed36 100644 --- a/src/Applications/LDAS_App/CMakeLists.txt +++ b/src/Applications/LDAS_App/CMakeLists.txt @@ -16,16 +16,28 @@ ecbuild_add_executable ( ecbuild_add_executable ( TARGET mwrtm_bin2nc4.x - SOURCES mwrtm_bin2nc4.F90 + SOURCES util/inputs/mwRTM_params/mwrtm_bin2nc4.F90 LIBS GEOSlandassim_GridComp) -install( - PROGRAMS ldas_setup process_hist.csh process_rst.csh util/average_ensemble_forcing.py +set (scripts + ldas_setup + process_hist.csh + process_rst.py + ens_forcing/average_ensemble_forcing.py + ens_forcing/ensemble_forc.py + ens_forcing/regrid_forc.csh + ens_forcing/enpert_forc.csh + util/config/rewind_GEOSldas.csh + ) + +install ( + PROGRAMS ${scripts} DESTINATION bin ) -file(GLOB rc_files GEOSldas_*rc) +file(GLOB rc_files GEOSldas_*rc) file(GLOB nml_files LDASsa_DEFAULT*nml) + install( FILES ${rc_files} ${nml_files} lenkf.j.template DESTINATION etc diff --git a/src/Applications/LDAS_App/GEOSldas_HIST.rc b/src/Applications/LDAS_App/GEOSldas_HIST.rc index 7b1cbe7e..40299e69 100644 --- a/src/Applications/LDAS_App/GEOSldas_HIST.rc +++ b/src/Applications/LDAS_App/GEOSldas_HIST.rc @@ -179,7 +179,7 @@ COLLECTIONS: >>>HIST_CATCHCN<<< 'CNTOTC' , 'GridComp' , >>>HIST_CATCHCN<<< 'CNVEGC' , 'GridComp' , >>>HIST_CATCHCN<<< 'CNROOT' , 'GridComp' , ->>>HIST_CATCHCNCLM45<<< 'CNFROOTC' , 'CATCHCNCLM45' , +>>>HIST_CATCHCNCLM45<<< 'CNFROOTC' , 'GridComp' , >>>HIST_CATCHCN<<< 'CNNPP' , 'GridComp' , >>>HIST_CATCHCN<<< 'CNGPP' , 'GridComp' , >>>HIST_CATCHCN<<< 'CNSR' , 'GridComp' , @@ -281,7 +281,7 @@ COLLECTIONS: >>>HIST_CATCHCN<<< 'CNTOTC' , 'GridComp' , >>>HIST_CATCHCN<<< 'CNVEGC' , 'GridComp' , >>>HIST_CATCHCN<<< 'CNROOT' , 'GridComp' , ->>>HIST_CATCHCNCLM45<<< 'CNFROOTC' , 'CATCHCNCLM45' , +>>>HIST_CATCHCNCLM45<<< 'CNFROOTC' , 'GridComp' , >>>HIST_CATCHCN<<< 'CNNPP' , 'GridComp' , >>>HIST_CATCHCN<<< 'CNGPP' , 'GridComp' , >>>HIST_CATCHCN<<< 'CNSR' , 'GridComp' , diff --git a/src/Applications/LDAS_App/GEOSldas_LDAS.rc b/src/Applications/LDAS_App/GEOSldas_LDAS.rc index 2f95e9c5..8e35303b 100644 --- a/src/Applications/LDAS_App/GEOSldas_LDAS.rc +++ b/src/Applications/LDAS_App/GEOSldas_LDAS.rc @@ -120,7 +120,8 @@ FIRST_ENS_ID: 0 # # NO : Deterministic met forcing (default) # YES : Ensemble met forcing -# - Typically used in land-atmosphere data assimilation (LADAS) configuration. +# - Typically used in land-atmosphere data assimilation (LADAS) configuration +# when coupled to 4dHybridEnVar ADAS. # - Must have forcing with matching ensemble ID for each land ensemble member. # - Forcing files must be stored in member-specific directories MET_PATH[NNN]/, # where NNN is the 3-digit ensemble ID. diff --git a/src/Applications/LDAS_App/README_LDAS_App b/src/Applications/LDAS_App/README_LDAS_App new file mode 100644 index 00000000..d36a506d --- /dev/null +++ b/src/Applications/LDAS_App/README_LDAS_App @@ -0,0 +1,36 @@ +README_LDAS_App: README file for GEOSldas/src/Applications/LDAS_App + +rreichle, 8 July 2022: Initial version + +This directory contains a collection of programs, scripts, and config files, specifically: + +[..]/LDAS_App/ + +- Config files and programs/scripts needed by ldas_setup or lenkf.j (GEOSldas job script). + +[..]/LDAS_App/ens_forcing/ + +- Scripts needed by lenkf.j to process ensemble-based forcing (primarily for LADAS). + +[..]/LDAS_App/sample_config_files/ + +- Sample config files for ldas_setup and HISTORY. + +[..]/LDAS_App/util/config/ + +- Miscellaneous scripts to (manually) create/modify config files. + +[..]/LDAS_App/util/inputs/ + +- Miscellaneous scripts to (manually) create/modify input files. + +[..]/LDAS_App/util/postproc/ + +- Miscellaneous scripts for post-processing GEOSldas output. + +[..]/LDAS_App/util/shared/ + +- Miscellaneous shared reader and helper scripts (primarily matlab). + + +=============== EOF =============================================================== \ No newline at end of file diff --git a/src/Applications/LDAS_App/util/average_ensemble_forcing.py b/src/Applications/LDAS_App/ens_forcing/average_ensemble_forcing.py similarity index 100% rename from src/Applications/LDAS_App/util/average_ensemble_forcing.py rename to src/Applications/LDAS_App/ens_forcing/average_ensemble_forcing.py diff --git a/src/Applications/LDAS_App/ens_forcing/enpert_forc.csh b/src/Applications/LDAS_App/ens_forcing/enpert_forc.csh new file mode 100755 index 00000000..6372a1d5 --- /dev/null +++ b/src/Applications/LDAS_App/ens_forcing/enpert_forc.csh @@ -0,0 +1,55 @@ +#!/usr/bin/csh -f + +# Script to create re-centered ensemble land forcing files (*inst1_2d_lfo*, *tavg1_2d_lfo*), +# typically used in LADAS: +# +# 1. Regrid coarse-resolution lfo files from the ADAS atmospheric ensemble to the higher +# resolution of the single-member central (or deterministic) simulation. +# +# 2. Compute perturbations from regridded lfo files. +# +# 3. Apply perturbations to lfo files from central simulation. +# +# Requires environment variables: +# ADAS_EXPDIR - path the ADAS experiment directory (ensemble of lfo files) +# GRID - target grid of forcing files (typically that of deterministic ADAS simulation) +# NENS - number of (LDAS) ensemble members (<= number of ADAS ensemble members) +# GEOSBIN - GEOSldas "ROOT" directory (typically GEOSldas/install/bin) +# +# Input data sets: +# 1. lfo files from coarse-resolution ADAS ensemble +# 2. lfo files from higher-resolution deterministic ADAS simulation +# +# Output data set: +# 1. ensemble of lfo files at resolution of deterministic ADAS simulation +# +# ------------------------------------------------------------------------------------ + +set force_cntr = "${ADAS_EXPDIR}/recycle/holdforc" +set force_orig = "${ADAS_EXPDIR}/atmens" +set force_rgd = "${ADAS_EXPDIR}/atmens/rgdlfo" +set outgrid = "${GRID}" + +mkdir $force_rgd + +$GEOSBIN/regrid_forc.csh $force_orig $force_rgd $outgrid + +rm -rf $force_orig/tmp* + +python $GEOSBIN/ensemble_forc.py $force_rgd $force_cntr $NENS + +cd $force_rgd +@ inens = 0 +while ($inens < $NENS) + @ inens ++ + if ($inens <10) then + set ENSDIR = `echo mem00${inens}` + else if($inens<100) then + set ENSDIR=`echo mem0${inens}` + endif + cd ${ENSDIR} + /bin/rm -rf *lfo*nc4 + $GEOSBIN/stripname nc4.Cpert nc4 + cd $force_rgd +end + diff --git a/src/Applications/LDAS_App/ens_forcing/ensemble_forc.py b/src/Applications/LDAS_App/ens_forcing/ensemble_forc.py new file mode 100755 index 00000000..413c5700 --- /dev/null +++ b/src/Applications/LDAS_App/ens_forcing/ensemble_forc.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python +# +# module load python/GEOSpyD/Ana2019.03_py3.7 +# module load nco/4.8.1 +# +# Script for creating ensemble-perturbed land forcing (lfo) files. +# Usage: ensemble_forc.py [in_path] [cntr_path] [nens] +# +# where +# +# in_path : path to ensemble lfo files +# cntr_path : path to deterministic lfo files +# nens : number of ensemble members +#=========================================== + +import sys +import os +import glob +import subprocess as sp +import numpy as np +from netCDF4 import Dataset + + +def averaging_forcing(in_path, avg_path, nens): + """ The ensemble number will be appended to in_path starting from 001. + The out_path will be created if it does not exist. """ + print ( " average ensemble " ) + if not os.path.exists(avg_path): + os.makedirs(avg_path) + files_list=[] + for i in range(1,nens+1): + sfx = '%03d'%(i) + folder = in_path+'/mem'+sfx + fs = sorted(glob.glob(folder+'/*lfo*.nc4')) + files_list.append(fs) + for fs in zip(*files_list): + k = 1 + # verify filenames are the same. + for f in fs: + n = f.rindex('/') + if (k==1): + f0 = f[n+1:] + k = k+1 + f1 = f[n+1:] + assert f0 == f1, "averaging different files. Each folder should have same files" + fnames = " ".join(fs) + cmd = 'ncea ' + fnames + ' ' + avg_path +'/' + f0 + sp.call(cmd, shell=True) + +def mean_diff(ensm_path, cntr_path): + print ( " prepare central - ensmean for recentering ") + files_list=[] + folder = ensm_path + fs = sorted(glob.glob(folder+'/*lfo*.nc4')) + files_list.append(fs) + for fs in zip(*files_list): + k = 1 + for f in fs: + n = f.rindex('/') + if (k==1): + f0 = f[n+1:] + k = k+1 + f1 = f[n+1:] + assert f0 == f1, "central and ensmean should have same filenames" + cmd = 'ncbo --op_typ=sbt ' + cntr_path + '/' + f1 + ' ' + f + ' ' + f +'.dif' + #print ( cmd ) + sp.call(cmd, shell=True) + +def recenter_forc(in_path, avg_path, cntr_path, nens): + print ( "recenter ens forcing to central forcing " ) + Varlist = ["PRECCU", "PRECLS", "PRECSNO", "SWGDN" ] + print ( "Varlist for multipl-recentering: ", Varlist) + + mean_diff(avg_path, cntr_path) + + files_list1=[] + for i in range(1,nens+1): + sfx = '%03d'%(i) + folder = in_path+'/mem'+sfx + fs1 = sorted(glob.glob(folder+'/*lfo*.nc4')) + files_list1.append(fs1) + for fs in zip(*files_list1): + k = 1 + for f in fs: + n = f.rindex('/') + if (k==1): + f0 = f[n+1:] + k = k+1 + f1 = f[n+1:] + assert f0 == f1, "memeber and ensmean should have same filenames" + cmd = 'ncbo --op_typ=add ' + f + ' ' + avg_path +'/' + f1 + '.dif' + ' ' + f +'.Cpert' + sp.call(cmd, shell=True) + + files_list=[] + for i in range(1,nens+1): + sfx = '%03d'%(i) + folder = in_path+'/mem'+sfx + fs = sorted(glob.glob(folder+'/*tavg*lfo*.nc4')) + files_list.append(fs) + for fs in zip(*files_list): + k = 1 + for f in fs: + n = f.rindex('/') + if (k==1): + f0 = f[n+1:] + m_file = avg_path+'/'+f0 + Var_m = readlfo(m_file, Varlist) + c_file = cntr_path+'/'+f0 + Var_c = readlfo(c_file, Varlist) + k = k+1 + f1 = f[n+1:] + fout = f + '.Cpert' + Var_e = readlfo(f, Varlist) + Var_ux = fact_multpl(Var_m,Var_e,Var_c) + upd_vars(fout, Var_ux, Varlist) + +def readlfo(ncfile, Varlist): + wkfile = Dataset(ncfile, "r") + nydim = len(wkfile.dimensions["Ydim"]) + nxdim = len(wkfile.dimensions["Xdim"]) + nfdim = len(wkfile.dimensions["nf"]) + dim3 = [nfdim, nydim, nxdim] + nvar = len(Varlist) + vardata = np.zeros((nvar, dim3[0], dim3[1], dim3[2]), dtype=float) + for rdvar in iter(range(nvar)): + vardata[rdvar] = wkfile.variables[Varlist[rdvar]][0] + + wkfile.close() + return vardata + +def upd_vars(ncfile, Dataupd, Varupd): + + wkfile = Dataset(ncfile,'r+') + nvar = len(Varupd) + for rdvar in iter(range(nvar)) : + wkfile.variables[Varupd[rdvar]][0] = Dataupd[rdvar] + + wkfile.close() + +def fact_multpl(Var_dn,Var_up,Var_cn): + + dim = np.shape(Var_dn) + ndim = len(dim) + dim3 = [ dim[1], dim[2],dim[3] ] + ndim3 = len(dim3) + + #sum precip [0, 1, 2 from Varlist(4) ) + Var_3pup = np.zeros(dim3, dtype=float) + Var_3pdn = np.zeros(dim3, dtype=float) + Var_3pup[:,:,:] = Var_up[0,:,:,:] + Var_up[1,:,:,:] + Var_up[2,:,:,:] + Var_3pdn[:,:,:] = Var_dn[0,:,:,:] + Var_dn[1,:,:,:] + Var_dn[2,:,:,:] + nvec = 1 + for id in iter(range(ndim3)): + nvec = dim3[id]*nvec + + vecdn = np.reshape(Var_3pdn,nvec) + vecup = np.reshape(Var_3pup,nvec) + vecnew = np.zeros(nvec,dtype=float) + + ind = np.argwhere(vecdn>1.0e-10) + vecnew [ind] = vecup[ind] / vecdn[ind] + + Var_uu = np.zeros((dim3), dtype=float) + Var_uu = np.reshape(vecnew,(dim3)) + # apply the same factor to 3 precip + Var_upx = np.zeros((dim), dtype=float) + Var_upx[0,:,:,:] = Var_uu[:,:,:] * Var_cn[0,:,:,:] + Var_upx[1,:,:,:] = Var_uu[:,:,:] * Var_cn[1,:,:,:] + Var_upx[2,:,:,:] = Var_uu[:,:,:] * Var_cn[2,:,:,:] + # deal with swgdn + Var_3pup[:,:,:] = Var_up[3,:,:,:] + Var_3pdn[:,:,:] = Var_dn[3,:,:,:] + vecdn = np.reshape(Var_3pdn,nvec) + vecup = np.reshape(Var_3pup,nvec) + vecnew = np.zeros(nvec,dtype=float) + ind = np.argwhere(vecdn!=0) + vecnew [ind] = vecup[ind] / vecdn[ind] + Var_uu = np.zeros((dim3), dtype=float) + Var_uu = np.reshape(vecnew,(dim3)) + Var_upx[3,:,:,:] = Var_uu[:,:,:] * Var_cn[3,:,:,:] + + return Var_upx + + +if __name__ == '__main__' : + + in_path = sys.argv[1] + cntr_path = sys.argv[2] + nens = int(sys.argv[3]) + mean_path = in_path + '/lfomean' + averaging_forcing(in_path,mean_path, nens) + recenter_forc(in_path, mean_path, cntr_path, nens) diff --git a/src/Applications/LDAS_App/ens_forcing/regrid_forc.csh b/src/Applications/LDAS_App/ens_forcing/regrid_forc.csh new file mode 100755 index 00000000..d6b80f34 --- /dev/null +++ b/src/Applications/LDAS_App/ens_forcing/regrid_forc.csh @@ -0,0 +1,63 @@ +#!/usr/bin/csh -f + +set echo +setenv MYNAME regrid_forc.csh + +if ( $#argv < 3 ) then + echo " " + echo " SYNOPSIS " + echo " " + echo " $MYNAME force_in force_rgd outgrid" + echo " " + echo " where" + echo " force_in - path to orginal forcing, e.g., $ADAS_EXPDIR/atmens/" + echo " force_rgd - path to regrid forcing, e.g., $ADAS_EXPDIR/atmens/rgdlfo" + echo " outgrid - output grid , e.g., PE180x1080-CF ") + echo " NENS ensemble number , e.g., 24 should be env var ") + exit(0) +endif + +set ogdir = $1 +set rgdir = $2 +set outgrid = $3 + +set NENSin = $NENS +echo "check NENS, $NENSin " + +mkdir $ogdir/tmpd + +@ inens = 0 +while ($inens < $NENSin) + @ inens ++ + if ($inens <10) then + set ENSDIR = `echo mem00${inens}` + else if($inens<100) then + set ENSDIR=`echo mem0${inens}` + endif + /bin/ln -s $ogdir/ensdiag/${ENSDIR} $ogdir/tmpd/${ENSDIR} + mkdir $rgdir/${ENSDIR} +end + +cd $ogdir +/bin/ls -1 tmpd/mem*/*inst*lfo*nc4| awk 'NR == 1 {printf $0} NR > 1 {printf ", %s",$0} END {printf "\n"}' > tmpf +cat tmpf | sed 's/, /,/g' > tmpff +set ininst1 = (`cat tmpff `) +set outinst1 = (`cat tmpff | sed 's/tmpd/rgdlfo/g' `) + +/bin/ls -1 tmpd/mem*/*tavg*lfo*nc4| awk 'NR == 1 {printf $0} NR > 1 {printf ", %s",$0} END {printf "\n"}' > tmpf +cat tmpf | sed 's/, /,/g' > tmpff +set intavg1 = (`cat tmpff `) +set outtavg1 = (`cat tmpff | sed 's/tmpd/rgdlfo/g' `) + +set mympi = "mpirun" + + $mympi -np 24 $GEOSBIN/Regrid_Util.x -i $ininst1 \ + -o $outinst1 \ + -nx 4 -ny 6 \ + -ogrid $outgrid + + $mympi -np 24 $GEOSBIN/Regrid_Util.x -i $intavg1 \ + -o $outtavg1 \ + -nx 4 -ny 6 \ + -ogrid $outgrid + diff --git a/src/Applications/LDAS_App/ens_forcing/test_enpert_forc.j b/src/Applications/LDAS_App/ens_forcing/test_enpert_forc.j new file mode 100755 index 00000000..820027fb --- /dev/null +++ b/src/Applications/LDAS_App/ens_forcing/test_enpert_forc.j @@ -0,0 +1,40 @@ +#!/usr/bin/csh + +# sample script for testing "enpert_forc.csh" +# +# must edit paths before submitting this script +# +# ----------------------------------------------------------- + +#SBATCH --ntasks=1 +#SBATCH --time=1:00:00 +#SBATCH --job-name=test_enpert_forc +#SBATCH --output=/discover/nobackup/[USER]/test_enpert_forc.o%j.txt +#SBATCH --export=NONE +#SBATCH --qos=debug + +# set environment variables needed by enpert_forc.csh + +setenv GEOSBIN /discover/nobackup/[USER]/GEOSldas/install/bin +setenv ADAS_EXPDIR /discover/nobackup/[USER]/[ADAS_EXPID]/ +setenv NENS 24 +setenv GRID PE180x1080-CF + +# load modules + +source $GEOSBIN/g5_modules + +# python should come with ESMA_env g5_modules +# module load python/GEOSpyD/Ana2019.03_py3.7 + +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 + +# execute test + +$GEOSBIN/enpert_forc.csh + +# ====================== EOF =================================== diff --git a/src/Applications/LDAS_App/ldas_setup b/src/Applications/LDAS_App/ldas_setup index 68a3480d..8b469d1a 100755 --- a/src/Applications/LDAS_App/ldas_setup +++ b/src/Applications/LDAS_App/ldas_setup @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 import os import sys @@ -16,7 +16,9 @@ from datetime import datetime from datetime import timedelta from collections import OrderedDict from dateutil.relativedelta import relativedelta - +from remap_utils import * +from remap_catchANDcn import * +from process_rst import * """ This script is intended to be run from any installed directory with GEOSldas.x and ldas_setup @@ -105,11 +107,13 @@ class LDASsetup: self.assim = False self.has_landassim_seed = False self.has_geos_pert = False - self.has_ldassa_pert = False self.nSegments = 1 self.perturb = 0 self.first_ens_id = 0 self.ladas_coupling = 0 + self.in_rstfile = None + self.in_tilefile = 'None' # default string + self.ens_id_width = 6 # _eXXXX # ------ # Read exe input file which is required to set up the dir # ------ @@ -138,7 +142,7 @@ class LDASsetup: # print rqd exe inputs if self.verbose: - print '\nInputs from execfile:\n' + print ('\nInputs from execfile:\n') _printdict(self.rqdExeInp) # nens is an integer and =1 for model run @@ -156,7 +160,10 @@ class LDASsetup: if self.nens > 1: self.perturb = 1 self.ensdirs = ['ens%04d'%iens for iens in range(self.first_ens_id, self.nens + self.first_ens_id)] - self.ensids = ['%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 = [ _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 self.ensids=[''] @@ -183,7 +190,7 @@ class LDASsetup: ) if self.rqdExeInp['RESTART'].isdigit() : if int(self.rqdExeInp['RESTART']) == 0 : - print "No restart file (cold restart): Forcing start date to January 1, 0z" + print ("No restart file (cold restart): Forcing start date to January 1, 0z") year = self.begDates[0].year self.begDates[0]=datetime(year =year,month=1,day =1,hour =0, minute= 0,second= 0) @@ -223,14 +230,14 @@ class LDASsetup: _difftime =timedelta(days = _years*365+_months*30+_days,hours = _hours,minutes=_mins,seconds=_seconds) _difftime = int(self.rqdExeInp['NUM_SGMT'])*_difftime - print int(self.rqdExeInp['NUM_SGMT']) + print (int(self.rqdExeInp['NUM_SGMT'])) _d = self.begDates[0] _endDate = self.endDates[0] _d = _d + _difftime while _d < _endDate : - print _difftime.days + print (_difftime.days) self.nSegments +=1 - print _d.year, _d.month, _d.day + print (_d.year, _d.month, _d.day) self.begDates.append(_d) self.endDates.insert(-1,_d) _d = _d+ _difftime @@ -292,6 +299,15 @@ class LDASsetup: ldas_domain = self.rqdExeInp['RESTART_PATH']+ \ self.rqdExeInp['RESTART_ID'] + \ '/output/'+self.rqdExeInp['RESTART_DOMAIN']+'/rc_out/'+self.rqdExeInp['RESTART_ID']+'.ldas_domain.txt' + inpdir=self.rqdExeInp['RESTART_PATH']+self.rqdExeInp['RESTART_ID']+'/input/' + in_tilefiles_ = glob.glob(inpdir+'*tile.data') + if len(in_tilefiles_) == 0 : + inpdir=self.rqdExeInp['RESTART_PATH']+self.rqdExeInp['RESTART_ID']+'/output/'+self.rqdExeInp['RESTART_DOMAIN']+'/rc_out/' + in_tilefiles_ = glob.glob(inpdir+'MAPL_*.til') + 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] @@ -338,12 +354,12 @@ class LDASsetup: _domain_dic['EXCLUDE_FILE']= "''" _domain_dic['INCLUDE_FILE']= "''" - for key,val in _domain_dic.iteritems() : + 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') - for key,val in _domain_dic.iteritems() : + for key,val in _domain_dic.items() : keyn=(key+" = ").ljust(16) valn = str(val) if '_FILE' in key: @@ -362,13 +378,9 @@ 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 - ldassa_tmp=self.rqdExeInp['RESTART_ID']+'.ens0000.'+self.catch+'_ldas_rst.'+y4m2d2_h2m2+'z.bin' - ldassaCN_tmp=self.rqdExeInp['RESTART_ID']+'.ens0000.'+self.catch+'_ldas_rst.'+y4m2d2_h2m2+'z' - LDASsa_catchRstFile=tmpRstDir+'/'+ldassa_tmp - LDASsa_CNRstFile=tmpRstDir+'/'+ldassaCN_tmp - assert os.path.isfile(catchRstFile) or os.path.isfile(LDASsa_catchRstFile) or os.path.isfile(LDASsa_CNRstFile), \ - self.catch+'_internal_rst file [%s] or [%s] does not exist!' %(catchRstFile, LDASsa_catchRstFile) + 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' @@ -384,12 +396,26 @@ class LDASsetup: landpertRstFile=tmpRstDir+'/'+tmpFile if ( os.path.isfile(landpertRstFile)) : self.has_geos_pert = True - else : - ldassa_tmp=self.rqdExeInp['RESTART_ID']+'.ens0000.pert_ldas_rst.'+y4m2d2_h2m2+'z.bin' - LDASsa_pertRstFile=tmpRstDir+'/'+ldassa_tmp - if (os.path.isfile(LDASsa_pertRstFile)) : - self.has_ldassa_pert = True - + + 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' + 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' + self.in_tilefile = '/discover/nobackup/ltakacs/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' \ + '/CatchCN/M36/19800101_0000/catchcnclm45_internal_dummy' + self.in_tilefile = '/discover/nobackup/ltakacs/bcs/Icarus-NLv3/Icarus-NLv3_EASE/SMAP_EASEv2_M36/SMAP_EASEv2_M36_964x406.til' + else: + 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 @@ -437,7 +463,7 @@ class LDASsetup: # print rqd rm inputs if self.verbose: - print '\n\nRequired inputs for resource manager:' + print ('\n\nRequired inputs for resource manager:') _printdict(self.rqdRmInp) # OPTIONAL inputs @@ -448,7 +474,7 @@ class LDASsetup: # print opt rm inputs if self.verbose: - print '\n\nOptional inputs for resource manager:' + print ('\n\nOptional inputs for resource manager:') _printdict(self.optRmInp) # ------ @@ -483,7 +509,7 @@ class LDASsetup: my_ntasks_per_node = int(self.rqdRmInp['ntasks-per-node']) # default number of nodes - my_nodes = self.rqdRmInp['ntasks_model'] / my_ntasks_per_node + my_nodes = self.rqdRmInp['ntasks_model'] // my_ntasks_per_node if self.rqdRmInp['ntasks_model'] % my_ntasks_per_node > 0 : my_nodes = my_nodes + 1 @@ -539,7 +565,7 @@ class LDASsetup: key = key.strip() val = val.strip() if not key or not val: - print "WARNING: " + errstr % (linenum, inpfile) + print ("WARNING: " + errstr % (linenum, inpfile)) continue #raise Exception(errstr % (linenum, inpfile)) if key in inpdict: @@ -578,12 +604,12 @@ class LDASsetup: self._mkdir_p(self.scratchdir) #-start-shorthand-function- - def _getDirName(outtyp, ensid, yyyymm): + def _getDirName(outtyp, ensdir, yyyymm): return '/'.join([ self.outdir, self.rqdExeInp['EXP_DOMAIN'], outtyp, # ana/cat/rs/rc_out - ensid, + ensdir, yyyymm ]) #-end-shorthand-function- @@ -606,15 +632,15 @@ class LDASsetup: y4m2_list.append('Y%4d/M%02d' % (newDate.year, newDate.month)) # ExpDomain/ana/, /cat/ directories - for ensid in self.ensdirs_avg: + for ensdir in self.ensdirs_avg: for y4m2 in y4m2_list: - self._mkdir_p(_getDirName('ana', ensid, y4m2)) - self._mkdir_p(_getDirName('cat', ensid, y4m2)) + self._mkdir_p(_getDirName('ana', ensdir, y4m2)) + self._mkdir_p(_getDirName('cat', ensdir, y4m2)) # ExpDomain/rs/ directories - for ensid in self.ensdirs: + for ensdir in self.ensdirs: for y4m2 in y4m2_list: - self._mkdir_p(_getDirName('rs', ensid, y4m2)) + self._mkdir_p(_getDirName('rs', ensdir, y4m2)) # ExpDomain/rc_out/ - only for _start self._mkdir_p(_getDirName('rc_out', '', y4m2_list[0])) @@ -663,10 +689,10 @@ class LDASsetup: tile=newtile # if three extra lines exist, remove them and save it to inputdir - print '\nCorrect the tile file if it is an old EASE tile format... \n' + 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 + print ("cmd: " + cmd) sp.call(shlex.split(cmd)) if os.path.isfile(EASEtile) : @@ -699,8 +725,8 @@ class LDASsetup: cmd = './preprocess_ldas.x c_f2g ' + tile + ' ' + domain_def + ' '+ self.out_path + ' ' + catchment_def + ' ' + exp_id + ' ' + _y4m2d2h2m2 + ' '+ dzsf - print 'Creating f2g.txt....\n' - print "cmd: " + cmd + print ('Creating f2g.txt....\n') + print ("cmd: " + cmd) sp.call(shlex.split(cmd)) # check if it is local or global with open('f2g.txt') as f2gfile : @@ -711,10 +737,10 @@ class LDASsetup: # 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" + 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 - print "cmd: " + cmd + print ("cmd: " + cmd) sp.call(shlex.split(cmd)) short_tile=short_tile +'.domain' tile = newlocalTile @@ -739,18 +765,18 @@ class LDASsetup: bcs=bcstmp if self.islocal: - print "Creating the boundary files for the simulation domain...\n" + 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' - print "cmd: " + cmd + print ("cmd: " + cmd) sp.call(shlex.split(cmd)) bcs_tmp=bcs_tmp+[bcf+'.domain'] bcs=bcs_tmp # link BC - print "linking bcs..." + print ("linking bcs...") bcnames=['green','lai','ndvi','nirdf','visdf'] if (self.rqdExeInp['LNFM_FILE'] != ''): bcnames += ['lnfm'] @@ -761,7 +787,7 @@ class LDASsetup: os.symlink(bc,myBC) # create and link restart - print "Creating and lining restart..." + print ("Creating and linking restart...") _start = self.begDates[0] y4m2='Y%4d/M%02d'%(_start.year, _start.month) @@ -780,9 +806,9 @@ class LDASsetup: sponsorid = self.rqdRmInp['account'] exp_id = self.rqdExeInp['EXP_ID'] exp_dir = self.exphome - bcdir = self.rqdExeInp['BCS_PATH'] - tilefile = os.path.basename(self.rqdExeInp['TILING_FILE']) - have_rst = str(self.rqdExeInp['RESTART']) + out_bcdir = self.rqdExeInp['BCS_PATH'] + out_tilefile = self.rqdExeInp['TILING_FILE'] + RESTART_str = str(self.rqdExeInp['RESTART']) YYYYMMDD = '%4d%02d%02d' % (_start.year, _start.month,_start.day) YYYYMMDDHH= '%4d%02d%02d%02d' % (_start.year, _start.month,_start.day, _start.hour) rstid = self.rqdExeInp['RESTART_ID'] @@ -799,31 +825,59 @@ class LDASsetup: shutil.copy(landassim_seeds, _seeds) os.symlink(_seeds, myRstDir+ '/landassim_obspertrseed'+ _ensid +'_rst') self.has_landassim_seed = True - - cmd= ' '.join(['./process_rst.csh', sponsorid, exp_id, exp_dir, - bcdir, tilefile, self.catch, have_rst, YYYYMMDDHH, - rstid, rstdomain, rstpath0, str(self.nens), str(self.rqdExeInp['RUN_IRRIG']), - dzsf, wemin_in, wemin_out]) - 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.) + 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]) + + if (RESTART_str != '1'): + 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['input']['surface']['catch_tilefile'] = self.in_tilefile + config['input']['shared']['expid'] = self.rqdExeInp['RESTART_ID'] + config['input']['shared']['yyyymmddhh'] = YYYYMMDDHH + config['input']['shared']['rst_dir'] = os.path.dirname(self.in_rstfile)+'/' + config['input']['surface']['wemin'] = wemin_in + config['input']['surface']['catch_model'] = self.catch + + 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']['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']) + + 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 = '' for iens in range(self.nens) : - ens = self.ensdirs[iens] - ensid = self.ensids[iens] + ensdir = self.ensdirs[iens] + ensid = self.ensids[iens] myCatchRst = myRstDir+'/'+self.catch +ensid +'_internal_rst' myVegRst = myRstDir+'/'+'vegdyn'+ensid +'_internal_rst' myPertRst = myRstDir+'/'+ 'landpert' +ensid +'_internal_rst' @@ -831,85 +885,70 @@ class LDASsetup: catchRstFile = '' vegdynRstFile = '' pertRstFile = '' - print "restart: " + self.rqdExeInp['RESTART'] + print ("restart: " + self.rqdExeInp['RESTART']) + 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] - catchRstFile = self.exphome+'/'+exp_id+'/mk_restarts/'+self.catch+'_internal_rst.'+YYYYMMDD - else : - catchRstFile = rstpath+ens +'/'+ y4m2+'/'+self.rqdExeInp['RESTART_ID']+'.'+self.catch+'_internal_rst.'+y4m2d2_h2m2 - _catchRstFile = self.exphome+'/'+exp_id+'/mk_restarts/'+self.catch+ensid+'_internal_rst.'+YYYYMMDD - vegdynRstFile= rstpath+ens +'/'+self.rqdExeInp['RESTART_ID']+ '.vegdyn_internal_rst' + 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] - if (self.nens == 1) : - _catchRstFile = self.exphome+'/'+exp_id+'/mk_restarts/'+self.catch+'0000_internal_rst.'+YYYYMMDD - if os.path.isfile(_catchRstFile): # from LDASsa restart - catchRstFile = _catchRstFile - assert int(self.rqdExeInp['RST_FROM_GLOBAL']) == 1, 'restart from LDASsa should be global' + if not os.path.isfile(vegdynRstFile0): + vegdynRstFile = glob.glob(self.rqdExeInp['BCS_PATH']+'vegdyn_*.dat')[0] else : vegdynRstFile = glob.glob(self.rqdExeInp['BCS_PATH']+'vegdyn_*.dat')[0] - catchRstFile = self.exphome+'/'+exp_id+'/mk_restarts/'+self.catch+'_internal_rst.'+YYYYMMDD + catchRstFile = glob.glob(self.exphome+'/'+exp_id+'/mk_restarts/*'+self.catch+'_internal_rst.'+YYYYMMDD+'*')[0] # catchment restart file - print 'catchRstFile: ' + catchRstFile if os.path.isfile(catchRstFile) : - - catchLocal = self.rstdir+ens +'/'+ y4m2+'/'+self.rqdExeInp['EXP_ID']+'.'+self.catch+'_internal_rst.'+y4m2d2_h2m2 + 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" + print( "Creating local catchment restart file... \n") cmd='./preprocess_ldas.x c_localcatchrst '+ catchRstFile +' ' + catchLocal - print "cmd: "+cmd + print ("cmd: "+cmd) sp.call(shlex.split(cmd)) else : shutil.copy(catchRstFile,catchLocal) catchRstFile = catchLocal - if '0000' in ens : + if '0000' in ensdir : catchRstFile0 = catchRstFile - else : + else : # re-use 0000 catch file catchRstFile = catchRstFile0 # vegdyn restart file if os.path.isfile(vegdynRstFile) : - - vegdynLocal = self.rstdir+ens +'/'+self.rqdExeInp['EXP_ID']+'.vegdyn_internal_rst' + vegdynLocal = self.rstdir+ensdir +'/'+self.rqdExeInp['EXP_ID']+'.vegdyn_internal_rst' if self.islocal : - print "Creating the local veg restart file... \n" + print ("Creating the local veg restart file... \n") cmd='./preprocess_ldas.x c_localvegrst '+ vegdynRstFile +' ' + vegdynLocal - print "cmd: " + cmd + print ("cmd: " + cmd) sp.call(shlex.split(cmd)) else : shutil.copy(vegdynRstFile,vegdynLocal) vegdynRstFile = vegdynLocal - if '0000' in ens : + if '0000' in ensdir : vegdynRstFile0 = vegdynRstFile else : vegdynRstFile = vegdynRstFile0 if (self.has_geos_pert and self.perturb == 1) : - pertRstFile = rstpath+ens +'/'+ y4m2+'/'+self.rqdExeInp['RESTART_ID']+'.landpert_internal_rst.'+y4m2d2_h2m2 - pertLocal = self.rstdir+ens +'/'+ y4m2+'/'+self.rqdExeInp['EXP_ID']+'.landpert_internal_rst.'+y4m2d2_h2m2 + pertRstFile = rstpath+ensdir +'/'+ y4m2+'/'+self.rqdExeInp['RESTART_ID']+'.landpert_internal_rst.'+y4m2d2_h2m2 + pertLocal = self.rstdir+ensdir +'/'+ y4m2+'/'+self.rqdExeInp['EXP_ID']+'.landpert_internal_rst.'+y4m2d2_h2m2 shutil.copy(pertRstFile,pertLocal) pertRstFile = pertLocal - if (self.has_ldassa_pert and self.perturb == 1 ) : - pertRstFile = rstpath+ens +'/'+ y4m2+'/'+self.rqdExeInp['RESTART_ID']+'.'+ens+'.pert_ldas_rst.'+y4m2d2_h2m2+'z.bin' - pertLocal = self.rstdir+ens +'/'+ y4m2+'/'+self.rqdExeInp['EXP_ID']+'.landpert_internal_rst.'+y4m2d2_h2m2 - print "Convert LDASsa pert " + ensid + " rst to GEOSldas rst" - cmd = './preprocess_ldas.x c_convert_pert '+ pertRstFile + ' ' + pertLocal + ' ' + self.out_path + ' ' + self.rqdExeInp['EXP_ID'] - sp.call(shlex.split(cmd)) - pertRstFile = pertLocal - - print 'catchRstFile: ' + catchRstFile - + print ('catchRstFile: ' + catchRstFile) + print ('vegdynRstFile: ' + vegdynRstFile) os.symlink(catchRstFile, myCatchRst) os.symlink(vegdynRstFile, myVegRst) - if ( (self.has_geos_pert or self.has_ldassa_pert) and self.perturb == 1 ): + if ( self.has_geos_pert and self.perturb == 1 ): os.symlink(pertRstFile, myPertRst) # catch_param restar file @@ -920,9 +959,9 @@ class LDASsetup: mwRTMRstFile = self.mwrtm_file 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" + print ("Creating the local mwRTM restart file... \n") cmd='./preprocess_ldas.x c_localmwrtmrst '+ mwRTMRstFile +' ' + mwRTMLocal - print "cmd: " + cmd + print ("cmd: " + cmd) sp.call(shlex.split(cmd)) else : shutil.copy(mwRTMRstFile,mwRTMLocal) @@ -932,7 +971,7 @@ class LDASsetup: os.symlink(mwRTMRstFile, mymwRTMRst) # update 'restart_path' to use relative path from outdir - print "Updating restart path..." + print ("Updating restart path...") self.rqdExeInp['RESTART_PATH'] = myRstDir if os.path.isfile('f2g.txt'): os.remove('f2g.txt') @@ -993,15 +1032,15 @@ class LDASsetup: if os.path.isfile('optimized_distribution'): os.remove('optimized_distribution') - print "Optimizing... decomposition of processes.... \n" + print ("Optimizing... decomposition of processes.... \n") cmd = './preprocess_ldas.x optimize '+ self.inpdir+'/tile.data '+ str(self.rqdRmInp['ntasks_model']) - print "cmd: " + cmd + print ("cmd: " + cmd) sp.call(shlex.split(cmd)) optinxny=self._parseInputFile('optimized_distribution') 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']) + 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+'/') @@ -1013,10 +1052,10 @@ class LDASsetup: # DEFAULT rc files default_rc = glob.glob(etcdir+'/GEOSldas_*.rc') assert len(default_rc)==4 - print default_rc + print (default_rc) for rcfile in default_rc: shortfile=rcfile.rsplit('GEOSldas_',1)[1] - print shortfile + ' ' + etcdir + ' ' + self.rundir + print (shortfile + ' ' + etcdir + ' ' + self.rundir) if shortfile =='HIST.rc': tmprcfile=self.rundir+'/HISTORY.rc' histrc_file=rcfile @@ -1044,7 +1083,7 @@ class LDASsetup: #os.system(cmd) sp.call(shlex.split(cmd)) for line in fileinput.input(tmprcfile,inplace=True): - print line.rstrip().replace('GEOSldas_expid',self.rqdExeInp['EXP_ID']) + 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) @@ -1056,33 +1095,33 @@ class LDASsetup: _num_sgmt = int(self.rqdExeInp['NUM_SGMT']) for line in fileinput.input(tmprcfile,inplace=True): - print line.rstrip().replace('JOB_SGMT:',self.job_sgmt[0]) + print (line.rstrip().replace('JOB_SGMT:',self.job_sgmt[0])) for line in fileinput.input(tmprcfile,inplace=True): - print line.rstrip().replace('NUM_SGMT:','NUM_SGMT: %d'% _num_sgmt) + print (line.rstrip().replace('NUM_SGMT:','NUM_SGMT: %d'% _num_sgmt)) for line in fileinput.input(tmprcfile,inplace=True): - print line.rstrip().replace('BEG_DATE:',self.begDates[0].strftime('BEG_DATE: %Y%m%d %H%M%S')) + 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')) + 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 default_surfrcInp = self._parseInputFile(etcdir+'/GEOS_SurfaceGridComp.rc') - for key,val in default_surfrcInp.iteritems() : + for key,val in default_surfrcInp.items() : ldasrcInp[key] = val # ldas default, may overwrite land default default_ldasrcInp = self._parseInputFile(rcfile) - for key,val in default_ldasrcInp.iteritems() : + for key,val in default_ldasrcInp.items() : ldasrcInp[key] = val # exeinp, may overwrite ldas default - for key,val in self.rqdExeInp.iteritems(): + for key,val in self.rqdExeInp.items(): if key not in self.NoneLDASrcKeys: ldasrcInp[key]= val # overide by optimized distribution - #for key,val in optinxny.iteritems(): + #for key,val in optinxny.items(): # ldasrcInp[key]= val # create BC in rc file @@ -1125,7 +1164,7 @@ class LDASsetup: if self.nens > 1 : keyn='ENS_ID_WIDTH' - valn='4' + valn=str(self.ens_id_width) ldasrcInp[keyn]= valn if self.has_landassim_seed and self.assim : @@ -1163,10 +1202,10 @@ class LDASsetup: # write LDAS.rc fout =open(self.rundir+'/'+shortfile,'w') # ldasrcInp['NUM_LDAS_ENSEMBLE']=ldasrcInp.pop('NUM_ENSEMBLE') - for key,val in optinxny.iteritems(): + for key,val in optinxny.items(): keyn=(key+":").ljust(36) fout.write(keyn+str(val)+'\n') - for key,val in ldasrcInp.iteritems() : + for key,val in ldasrcInp.items() : keyn=(key+":").ljust(36) fout.write(keyn+str(val)+'\n') fout.write("OUT_PATH:".ljust(36)+self.out_path+'\n') @@ -1230,7 +1269,7 @@ class LDASsetup: fout.write("\nsed -i 's/#if($capdate<$enddate) sbatch/if($capdate<$enddate) sbatch /g' lenkf.j") fout.close() - os.chmod(self.rundir+'/ldas_batchrun.j', 0755) + sp.call(['chmod', '755', self.rundir+'/ldas_batchrun.j']) status = True return status @@ -1326,11 +1365,11 @@ class LDASsetup: else : fout.write(line.replace('MY_EXPDIR',self.exphome+'/$EXPID')) - os.chmod('lenkf.j', 0755) + sp.call(['chmod', '755', 'lenkf.j']) expdir = '/'.join(self.rundir.rstrip('/').split('/')[:-1]) - print '\nExperiment directory: %s' % expdir - print + print ('\nExperiment directory: %s' % expdir) + print () status = True return status @@ -1339,186 +1378,184 @@ def _printdict(d): Private method: print a 'flat' dictionary """ - for key, val in d.iteritems(): - print key.ljust(23), ':', val + for key, val in d.items(): + print (key.ljust(23), ':', val) def _printExeInputKeys(rqdExeInpKeys): """ Private method: print sample exe input """ - print '####################################################################################' - print '# #' - print '# REQUIRED INPUTS #' - print '# #' - print '# These inputs are needed to set up output dir structure. #' - print '# #' - print '####################################################################################' - print - print '############################################################' - print '# #' - print '# EXPERIMENT INFO #' - print '# #' - print '# Format for start/end times is yyyymmdd hhmmss. #' - print '# #' - print '############################################################' - print - print 'EXP_ID:' - print 'EXP_DOMAIN:' - print 'NUM_LDAS_ENSEMBLE:' - print 'BEG_DATE:' - print 'END_DATE:' - print - print '############################################################' - print '# #' - print '# RESTART INFO #' - print '# #' - print '# (i) Select "RESTART" option: #' - print '# #' - print '# Use one of the following options if you *have* a #' - print '# GEOSldas- or LDASsa-produced restart file: #' - print '# #' - print '# RESTART: 1 #' - print '# YES, have restart file from GEOSldas *or* LDASsa #' - print '# in SAME tile space (grid) with SAME boundary #' - print '# conditions and SAME snow model parameter (WEMIN). #' - print '# GEOSldas-produced restart can be for the same or #' - print '# a larger domain. #' - print '# LDASsa-produced restart *must* be for the GLOBAL #' - print '# domain. #' - print '# #' - print '# RESTART: 2 #' - print '# YES, have restart file from GEOSldas *or* LDASsa but #' - print '# in a DIFFERENT tile space (grid) or with #' - print '# DIFFERENT boundary conditions or DIFFERENT snow #' - print '# model parameter (WEMIN). #' - print '# Restart *must* be for the GLOBAL domain. #' - print '# #' - print '# Use one of the following options if you DO NOT have a #' - print '# GEOSldas- or LDASsa-produced 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 '# #' - print '# RESTART: F #' - print '# Re-tile from FP (Forward Processing) restart file. #' - print '# #' - print '# RESTART: G #' - print '# Re-tile from any AGCM catch[cnclmxx]_internal_rst file.#' - print '# #' - print '# -------------------------------------------------------- #' - print '# IMPORTANT: #' - print '# Except for RESTART=1, SPIN-UP is REQUIRED in almost #' - print '# all cases. #' - 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 '# 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 '# For RESTART=G: #' - print '# RESTART_ID : full_path_to_AGCM_experiment_directory #' - print '# RESTART_PATH : full_path_of_the_AGCM_restart_file #' - print '# RESTART_DOMAIN is NOT required. #' - print '# #' - print '############################################################' - print - print 'RESTART:' - print '#RESTART_ID:' - print '#RESTART_PATH:' - print '#RESTART_DOMAIN:' - print - print '############################################################' - print '# #' - print '# SURFACE METEOROLOGICAL FORCING #' - print '# #' - print '# Surface meteorological forcing time step is in seconds. #' - print '# #' - print '# For more information, see: #' - print '# GEOSldas/doc/README.MetForcing_and_BCS.md #' - print '# #' - print '############################################################' - print - print 'MET_TAG:' - print 'MET_PATH:' - print 'FORCE_DTSTEP:' - print - print '############################################################' - print '# #' - print '# LAND BOUNDARY CONDITIONS (BCS) #' - print '# #' - print '# Path to and (atmospheric) resolution of BCS. #' - print '# #' - print '# For more information, see: #' - print '# GEOSldas/doc/README.MetForcing_and_BCS.md #' - print '# [..]/GEOSsurface_GridComp/Utils/Raster/make_bcs #' - print '# #' - print '############################################################' - print - print 'BCS_PATH:' - print 'BCS_RESOLUTION:' - print - print '############################################################' - print '# #' - print '# LADAS COUPLING #' - print '# #' - print '# Coupling of LDAS to ADAS ("LADAS"): #' - 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 '# Requirements for LADAS_COUPLING > 0: #' - 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 '# (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 '# [ADAS_EXPDIR]/atmens/ensdiag/forc #' - 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 #' - print '# #' - print '# (5) JOB_SGMT must match ADAS analysis window #' - print '# (typically 6h) #' - print '# #' - print '# (6) NUM_SGMT must be set to 1 #' - print '# #' - print '# (7) HISTORY: #' - 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 '# "catch_progn_incr[ENS_INDEX]" #' - print '# #' - print '############################################################' - print - print 'LADAS_COUPLING: 0' - print - print + print ('####################################################################################') + print ('# #') + print ('# REQUIRED INPUTS #') + print ('# #') + print ('# These inputs are needed to set up output dir structure. #') + print ('# #') + print ('####################################################################################') + print () + print ('############################################################') + print ('# #') + print ('# EXPERIMENT INFO #') + print ('# #') + print ('# Format for start/end times is yyyymmdd hhmmss. #') + print ('# #') + print ('############################################################') + print () + print ('EXP_ID:') + print ('EXP_DOMAIN:') + print ('NUM_LDAS_ENSEMBLE:') + print ('BEG_DATE:') + print ('END_DATE:') + print () + print ('############################################################') + print ('# #') + print ('# RESTART INFO #') + print ('# #') + print ('# (i) Select "RESTART" option: #') + print ('# #') + print ('# Use one of the following options if you *have* a #') + 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 ('# #') + print ('# RESTART: 2 #') + print ('# YES, have restart file from GEOSldas but #') + print ('# in a DIFFERENT tile space (grid) or with #') + print ('# DIFFERENT boundary conditions or DIFFERENT snow #') + print ('# model parameter (WEMIN). #') + 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 ('# (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 ('# #') + print ('# RESTART: F #') + print ('# Re-tile from FP (Forward Processing) restart file. #') + print ('# #') + print ('# RESTART: G #') + print ('# Re-tile from any AGCM catch[cnclmxx]_internal_rst file.#') + print ('# #') + print ('# -------------------------------------------------------- #') + print ('# IMPORTANT: #') + print ('# Except for RESTART=1, SPIN-UP is REQUIRED in almost #') + print ('# all cases. #') + 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 ('# 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 ('# For RESTART=G: #') + print ('# RESTART_ID : full_path_to_AGCM_experiment_directory #') + print ('# RESTART_PATH : full_path_of_the_AGCM_restart_file #') + print ('# RESTART_DOMAIN is NOT required. #') + print ('# #') + print ('############################################################') + print () + print ('RESTART:') + print ('#RESTART_ID:') + print ('#RESTART_PATH:') + print ('#RESTART_DOMAIN:') + print () + print ('############################################################') + print ('# #') + print ('# SURFACE METEOROLOGICAL FORCING #') + print ('# #') + print ('# Surface meteorological forcing time step is in seconds. #') + print ('# #') + print ('# For more information, see: #') + print ('# GEOSldas/doc/README.MetForcing_and_BCS.md #') + print ('# #') + print ('############################################################') + print () + print ('MET_TAG:') + print ('MET_PATH:') + print ('FORCE_DTSTEP:') + print () + print ('############################################################') + print ('# #') + print ('# LAND BOUNDARY CONDITIONS (BCS) #') + print ('# #') + print ('# Path to and (atmospheric) resolution of BCS. #') + print ('# #') + print ('# For more information, see: #') + print ('# GEOSldas/doc/README.MetForcing_and_BCS.md #') + print ('# [..]/GEOSsurface_GridComp/Utils/Raster/make_bcs #') + print ('# #') + print ('############################################################') + print () + print ('BCS_PATH:') + print ('BCS_RESOLUTION:') + print () + print ('############################################################') + print ('# #') + print ('# LADAS COUPLING #') + print ('# #') + print ('# Coupling of LDAS to ADAS ("LADAS"): #') + 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 ('# Requirements for LADAS_COUPLING > 0: #') + 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 ('# (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 ('# [ADAS_EXPDIR]/atmens/ensdiag/forc #') + 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 #') + print ('# #') + print ('# (5) JOB_SGMT must match ADAS analysis window #') + print ('# (typically 6h) #') + print ('# #') + print ('# (6) NUM_SGMT must be set to 1 #') + print ('# #') + print ('# (7) HISTORY: #') + 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 ('# "catch_progn_incr[ENS_INDEX]" #') + print ('# #') + print ('############################################################') + print () + print ('LADAS_COUPLING: 0') + print () + print () _fn = '../etc/GEOSldas_LDAS.rc' # run ldas_setup from /bin directory @@ -1529,8 +1566,8 @@ def _printExeInputKeys(rqdExeInpKeys): sys.stdout.write(line) sys.stdout.flush() i_ += 1 - print - print + print () + print () _fn = '../etc/GEOS_SurfaceGridComp.rc' # run ldas_setup from /bin directory @@ -1549,42 +1586,42 @@ def _printExeInputKeys(rqdExeInpKeys): sys.stdout.write(line) sys.stdout.flush() i_ += 1 - print - print + print () + print () def _printRmInputKeys(rqdRmInpKeys, optRmInpKeys): """ Private method: print sample resource manager input """ - print '#' - print '# REQUIRED inputs' - print '#' - print '# NOTE:' - print '# - account = computational project number' - 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 '#' + print ('#') + print ('# REQUIRED inputs') + print ('#') + print ('# NOTE:') + print ('# - account = computational project number') + 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 ('#') for key in rqdRmInpKeys: - print key + ':' - print - print '#' - print '# OPTIONAL inputs' - print '#' - print '# NOTE:' - print '# - job_name = name of experiment; default is "exp_id"' - print '# - qos = quality-of-service; do not specify by default; specify "debug" for faster but limited service.' - print '# - oserver_nodes = number of nodes for oserver ( default is 0 )' - print '# - writers-per-node = tasks per oserver_node for writing ( default is 5 ),' - print '# IMPORTANT REQUIREMENT: total #writers = writers-per-node * oserver_nodes >= 2' - print '# Jobs will hang when oserver_nodes = writers-per-node = 1.' - print '#' + print (key + ':') + print () + print ('#') + print ('# OPTIONAL inputs') + print ('#') + print ('# NOTE:') + print ('# - job_name = name of experiment; default is "exp_id"') + print ('# - qos = quality-of-service; do not specify by default; specify "debug" for faster but limited service.') + print ('# - oserver_nodes = number of nodes for oserver ( default is 0 )') + print ('# - writers-per-node = tasks per oserver_node for writing ( default is 5 ),') + print ('# IMPORTANT REQUIREMENT: total #writers = writers-per-node * oserver_nodes >= 2') + print ('# Jobs will hang when oserver_nodes = writers-per-node = 1.') + print ('#') for key in optRmInpKeys: - print '#'+key + ':' + print ('#'+key + ':') def parseCmdLine(): """ @@ -1675,21 +1712,21 @@ if __name__=='__main__': args = vars(parseCmdLine()) # vars converts to dict ld = LDASsetup(args) - print "creating dir structure" + print ("creating dir structure") status = ld.createDirStructure() assert(status) - print "creating restart and bc" + print ("creating restart and bc") status = ld.createLnRstBc() assert(status) - print "creating RC Files" + print ("creating RC Files") status =ld.createRCFiles() assert status - print "creating gcm style batch Run scripts lenkf.j" + print ("creating gcm style batch Run scripts lenkf.j") status = ld.createRunScripts() - print "creating batch Run scripts" + print ("creating batch Run scripts") status = ld.createBatchRun() assert (status) diff --git a/src/Applications/LDAS_App/lenkf.j.template b/src/Applications/LDAS_App/lenkf.j.template index 2d97fb42..ac20eb37 100644 --- a/src/Applications/LDAS_App/lenkf.j.template +++ b/src/Applications/LDAS_App/lenkf.j.template @@ -30,6 +30,14 @@ setenv ESMADIR $EXPDIR/build/ setenv GEOSBIN $ESMADIR/bin/ # need to unsetenv LD_LIBRARY_PATH for execution of LDAS within the coupled land-atm DAS unsetenv LD_LIBRARY_PATH + +set debug_flag = 0 +if ( "$1" == "-debug" ) then + set debug_flag = 1 +endif +unset argv +setenv argv + source $GEOSBIN/g5_modules setenv I_MPI_DAPL_UD enable @@ -66,9 +74,9 @@ setenv POSTPROC_HIST MY_POSTPROC_HIST # : 1 -- LDAS coupled to central (deterministic) component of ADAS # : 2 -- LDAS coupled to atmospheric ensemble component of ADAS -setenv LADAS_COUPLING MY_LADAS_COUPLING +setenv LADAS_COUPLING MY_LADAS_COUPLING setenv ENSEMBLE_FORCING MY_ENSEMBLE_FORCING -setenv ADAS_EXPDIR MY_ADAS_EXPDIR +setenv ADAS_EXPDIR MY_ADAS_EXPDIR set NENS = `grep NUM_LDAS_ENSEMBLE: $HOMDIR/LDAS.rc | cut -d':' -f2` set END_DATE = `grep END_DATE: $HOMDIR/CAP.rc | cut -d':' -f2` @@ -109,13 +117,30 @@ if( ${LSMCHOICE} > 1 ) then # CatchCN Only ln -s /discover/nobackup/projects/gmao/ssd/land/l_data/LandBCs_files_for_mkCatchParam/V001/FPAR_CDF_Params-M09.nc4 endif -######################################################################## -# if $LADAS_COUPLING == 1 use $FVWORK and copy forcing to Scratch -######################################################################## +####################################################################### +# if $LADAS_COUPLING == 1: LDAS coupled to central ADAS simulation +####################################################################### if ( $LADAS_COUPLING == 1 ) then - echo "copying lfo_Nx+- met forcing from $FVWORK to $SCRDIR" - /bin/cp -f $FVWORK/*lfo_Nx+-*nc4 $SCRDIR/. + + if ( $ENSEMBLE_FORCING == "YES" ) then + + # create perturbed forcing from central simulation and atm ensemble + + # python should come with ESMA_env g5_modules + #module load python/GEOSpyD/Ana2019.03_py3.7 + set forcgrid = `grep GEOSldas.GRIDNAME LDAS.rc | cut -d':' -f2 | awk '{print $1}'` + setenv GRID $forcgrid + $GEOSBIN/enpert_forc.csh + 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/. + + endif endif ####################################################################### @@ -354,15 +379,18 @@ while ( $counter <= ${NUM_SGMT} ) # Debugging # --------- - if ( "$1" == "-debug" ) then + if ( $debug_flag == 1 ) then echo "" echo "------------------------------------------------------------------" echo "" echo "lenkf.j -debug:" echo "" - echo "To start debugging, you must now manually launch your debugging tool" - echo "with GEOSldas.x from here, e.g.," + echo "To start debugging, you must now go to the experiment's scratch directory." + echo "From there, source g5_modules and launch your debugging tool with GEOSldas.x, e.g.," echo "" + echo " cd $SCRDIR + echo " source $GEOSBIN/g5_modules [for bash or zsh: source g5_modules.[z]sh]" + echo " module load tview [at NCCS] echo " totalview $GEOSBIN/GEOSldas.x" echo "" echo "Availability of tools depends on the computing system and may require" @@ -649,6 +677,7 @@ EOF set ENSDIR = `echo ens${inens}` endif set ENSID = `echo $ENSDIR | cut -c4-7` + set ENSID = _e${ENSID} if ( $NENS == 1) set ENSID ='' set THISDIR = $EXPDIR/output/$EXPDOMAIN/rs/$ENSDIR/Y${eYEAR}/M${eMON}/ if (! -e $THISDIR ) mkdir -p $THISDIR diff --git a/src/Applications/LDAS_App/preprocess_ldas.F90 b/src/Applications/LDAS_App/preprocess_ldas.F90 index 387e2fac..30a68f97 100644 --- a/src/Applications/LDAS_App/preprocess_ldas.F90 +++ b/src/Applications/LDAS_App/preprocess_ldas.F90 @@ -18,30 +18,30 @@ program main implicit none character(len=20 ) :: option - character(len=200) :: arg1 - character(len=200) :: arg2 - character(len=200) :: arg3 - character(len=200) :: arg4 - character(len=200) :: arg5 - character(len=200) :: arg6 - character(len=200) :: arg7 + character(len=512) :: arg1 + character(len=512) :: arg2 + character(len=512) :: arg3 + character(len=512) :: arg4 + character(len=512) :: arg5 + character(len=512) :: arg6 + character(len=512) :: arg7 - character(len=200) :: orig_tile - character(len=200) :: new_tile - character(len=200) :: domain_def_file - character(len=200) :: catch_def_file - character(len=200) :: out_path - character(len=200) :: exp_id - character(len=200) :: orig_catch - character(len=200) :: new_rtm - character(len=200) :: orig_rtm - character(len=200) :: new_catch - character(len=200) :: orig_BC - character(len=200) :: new_BC - character(len=200) :: orig_Veg - character(len=200) :: new_veg - character(len=200) :: orig_ease - character(len=200) :: new_ease + character(len=512) :: orig_tile + character(len=512) :: new_tile + character(len=512) :: domain_def_file + character(len=512) :: catch_def_file + character(len=512) :: out_path + character(len=512) :: exp_id + character(len=512) :: orig_catch + character(len=512) :: new_rtm + character(len=512) :: orig_rtm + character(len=512) :: new_catch + character(len=512) :: orig_BC + character(len=512) :: new_BC + character(len=512) :: orig_Veg + character(len=512) :: new_veg + character(len=512) :: orig_ease + character(len=512) :: new_ease character(len=12 ) :: ymdhm character(len=12 ) :: SURFLAY diff --git a/src/Applications/LDAS_App/preprocess_ldas_routines.F90 b/src/Applications/LDAS_App/preprocess_ldas_routines.F90 index f425fcb9..78c1dcdb 100644 --- a/src/Applications/LDAS_App/preprocess_ldas_routines.F90 +++ b/src/Applications/LDAS_App/preprocess_ldas_routines.F90 @@ -118,8 +118,8 @@ subroutine createf2g(orig_tile,domain_def,out_path,catch_def_file,exp_id,ymdhm, character(*) :: SURFLAY real :: minlon,maxlon,minlat,maxlat - character(len=200):: exclude_file,include_file - character(len=300):: bcs_path + character(len=512):: exclude_file,include_file + character(len=512):: bcs_path logical :: file_exist logical :: d_exist,c_exist @@ -420,7 +420,7 @@ subroutine domain_setup( & type(grid_def_type) :: tmp_grid_def logical :: c3_grid - character(300) :: fname + character(512) :: fname character(len=*), parameter :: Iam = 'domain_setup' character(len=400) :: err_msg @@ -739,7 +739,7 @@ integer function open_land_param_file( unitnumber, formatted_file, is_big_endian ! local variables - character(len=400) :: filename + character(len=512) :: filename integer :: i, istat @@ -1405,7 +1405,7 @@ end subroutine read_cat_param subroutine write_cat_param(cat_param, N_catd) type(cat_param_type), intent(in) :: cat_param(:) integer,intent(in) :: N_catd - character(len=300):: fname + character(len=512):: fname type(date_time_type) :: start_time integer :: k,n @@ -1557,7 +1557,7 @@ subroutine createLocalTilefile(orig_tile,new_tile) character(*), intent(in) :: orig_tile character(*), intent(in) :: new_tile - character(len=200) :: line + character(len=256) :: line character(len=3) :: MAPL_Land_STRING character(len=4) :: MAPL_Land_ExcludeFromDomain_STRING character(len=400) :: err_msg @@ -1972,7 +1972,7 @@ subroutine correctEase(orig_ease,new_ease) character(*),intent(in) :: new_ease logical :: file_exist,is_oldEASE integer :: i, N_tile, N_grid - character(len=200) :: tmpline + character(len=256) :: tmpline inquire(file=trim(orig_ease),exist=file_exist) if( .not. file_exist) stop (" no ease_tile_file") @@ -2053,8 +2053,8 @@ subroutine optimize_latlon(fname_tilefile, N_proc_string) integer :: avg_land,n0,local integer :: i,s,e,j,k,n1,n2 logical :: file_exist - character(len=100):: tmpLine - character(len=100):: gridname + character(len=256):: tmpLine + character(len=128):: gridname real :: rate,rates(60),maxf(60) integer :: IMGLOB, JMGLOB integer :: face(6),face_land(6) @@ -2855,8 +2855,9 @@ subroutine LDAS_read_til_file( tile_file, catch_file, tile_grid_g, tile_coord_la logical :: ease_grid integer :: typ,k,fid - character(200) :: tmpline,gridname - character(300) :: fname + character(256) :: tmpline + character(128) :: gridname + character(512) :: fname character(len=*), parameter :: Iam = 'LDAS_read_til_file' @@ -2897,7 +2898,7 @@ subroutine LDAS_read_til_file( tile_file, catch_file, tile_grid_g, tile_coord_la call LDAS_create_grid_g( gridname, n_lon, n_lat, & tile_grid_g, i_indg_offset, j_indg_offset, ease_cell_area ) - if (index(tile_grid_g%gridtype,'EASE')/=0) ease_grid = .true. ! 'EASE' and 'EASEv2' + if (index(tile_grid_g%gridtype,'EASE')/=0) ease_grid = .true. ! 'EASEv1' or 'EASEv2' if (index(tile_grid_g%gridtype,'SiB2')/=0) col_order=1 ! old bcs allocate(tile_coord(N_tile)) @@ -2948,7 +2949,10 @@ subroutine LDAS_read_til_file( tile_file, catch_file, tile_grid_g, tile_coord_la tile_coord(i)%frac_cell ! 7 tile_coord(i)%frac_pfaf = nodata_generic - tile_coord(i)%area = ease_cell_area*tile_coord(i)%frac_cell + + ! compute area of tile in [km^2] (units convention in tile_coord structure) + + tile_coord(i)%area = ease_cell_area*tile_coord(i)%frac_cell/1000./1000. ! [km^2] else ! not ease grid diff --git a/src/Applications/LDAS_App/process_hist.csh b/src/Applications/LDAS_App/process_hist.csh index e7923053..73d3b421 100755 --- a/src/Applications/LDAS_App/process_hist.csh +++ b/src/Applications/LDAS_App/process_hist.csh @@ -53,7 +53,13 @@ endif if($NENS > 1) then set GridComp = ENSAVG - sed -i 's|VEGDYN|'VEGDYN0000'|g' $HISTRC + sed -i 's|VEGDYN|'VEGDYN_e0000'|g' $HISTRC + sed -i 's|TP1|'TSOIL1TILE'|g' $HISTRC + sed -i 's|TP2|'TSOIL2TILE'|g' $HISTRC + sed -i 's|TP3|'TSOIL3TILE'|g' $HISTRC + sed -i 's|TP4|'TSOIL4TILE'|g' $HISTRC + sed -i 's|TP5|'TSOIL5TILE'|g' $HISTRC + sed -i 's|TP6|'TSOIL6TILE'|g' $HISTRC # sed -i 's|DATAATM|'DATAATM0000'|g' $HISTRC endif diff --git a/src/Applications/LDAS_App/process_rst.csh b/src/Applications/LDAS_App/process_rst.csh deleted file mode 100755 index 677803a2..00000000 --- a/src/Applications/LDAS_App/process_rst.csh +++ /dev/null @@ -1,385 +0,0 @@ -#!/bin/csh -f - -setenv SPONSORID $1 -setenv EXPID $2 -setenv EXPDIR $3 -setenv BCSDIR $4 -setenv TILFILE $5 -setenv MODEL $6 -setenv HAVE_RESTART $7 -setenv YYYYMMDDHH $8 -setenv RESTART_ID $9 -setenv RESTART_DOMAIN $10 -setenv RESTART_PATH $11 -setenv NUMENS $12 -setenv RUN_IRRIG $13 -setenv SURFLAY $14 -setenv WEMIN_IN $15 -setenv WEMIN_OUT $16 -setenv RESTART_short ${RESTART_PATH}/${RESTART_ID}/output/${RESTART_DOMAIN}/ -setenv PARAM_FILE `ls $RESTART_short/rc_out/*/*/*ldas_catparam* | head -1` - -set PWD=`pwd` -setenv INSTDIR `echo $PWD | rev | cut -d'/' -f2- | rev` - -if ($MODEL == 'catch') then - setenv SCALE bin/Scale_Catch -else - setenv SCALE bin/Scale_CatchCN -endif - -set YYYYMMDD = `echo $YYYYMMDDHH | cut -c1-8` - -switch ($HAVE_RESTART) - -case [0] : - - echo - echo "########################################################" - echo - echo " NOTE: IMPORTANT IMPORTANT IMPROTANT " - echo " " - echo " In the absence of a restart file, " - echo " a global catch(cn)_internal_rst file is being " - echo " produced by regridding SMAP_Nature_v05 restarts " - echo " from SMAP 9km grid to the BCS grid. The start date " - echo " will be forced January 1st. " - echo " " - echo " PLEASE SPIN UP BEFORE USE " - echo - echo "########################################################" - echo - -## No restarts : regrid from archived SMAP M09 restarts - - mkdir -p $EXPDIR/$EXPID/mk_restarts/InData/ - mkdir -p $EXPDIR/$EXPID/mk_restarts/OutData/ - ln -s $BCSDIR/$TILFILE $EXPDIR/$EXPID/mk_restarts/InData/OutTileFile - ln -s $BCSDIR/$TILFILE $EXPDIR/$EXPID/mk_restarts/OutData/OutTileFile - ln -s $BCSDIR/clsm $EXPDIR/$EXPID/mk_restarts/OutData/clsm - ln -s $INSTDIR/bin $EXPDIR/$EXPID/mk_restarts/ - - cd $EXPDIR/$EXPID/mk_restarts/ - - cat << _EOI_ > mkLDASsa.j -#!/bin/csh -fx - -#SBATCH --account=${SPONSORID} -#SBATCH --time=1:00:00 -#SBATCH --ntasks=56 -#SBATCH --job-name=mkLDAS -###SBATCH --constraint=hasw -#SBATCH --qos=debug -#SBATCH --output=mkLDAS.o -#SBATCH --error=mkLDAS.e - -source $INSTDIR/bin/g5_modules -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 - -setenv LAIFILE `find ${BCSDIR}/lai_clim*` -setenv LD_LIBRARY_PATH ${LD_LIBRARY_PATH}:${BASEDIR}/Linux/lib - -limit stacksize unlimited - -$INSTDIR/bin/esma_mpirun -np 56 bin/mk_GEOSldasRestarts -a ${SPONSORID} -b ${BCSDIR} -t ${TILFILE} -m ${MODEL} -s ${SURFLAY} -j Y - -sleep 3 - -/bin/cp InData/${MODEL}_internal_rst OutData/${MODEL}_internal_rst - -$INSTDIR/bin/esma_mpirun -np 56 bin/mk_GEOSldasRestarts -a ${SPONSORID} -b ${BCSDIR} -t ${TILFILE} -m ${MODEL} -s ${SURFLAY} -j Y - -${SCALE} InData/${MODEL}_internal_rst OutData/${MODEL}_internal_rst ${MODEL}_internal_rst $SURFLAY $WEMIN_IN $WEMIN_OUT - -# Done creating catch*_internal_rst file - -sleep 2 - -ln -s ${MODEL}_internal_rst ${MODEL}_internal_rst.$YYYYMMDD -echo DONE > done_rst_file - -_EOI_ - - sbatch mkLDASsa.j - cd $PWD - breaksw - -case [1]: - - set coordfile=${RESTART_short}/rc_out/${RESTART_ID}.ldas_tilecoord.bin - if (-e $coordfile ) then - set ENDI=`file -b $coordfile | rev | cut -d' ' -f2 | rev` - else - echo "WARNING : no file $coordfile. DEFAULT GEOSldas restart" - set ENDI = LSB - endif - - - ## restart is from old LDAS which produce big endian binary - if($ENDI == MSB) then - echo ' ' - mkdir -p $EXPDIR/$EXPID/mk_restarts/OutData/ - ln -s $BCSDIR/$TILFILE $EXPDIR/$EXPID/mk_restarts/OutData/OutTileFile - ln -s $BCSDIR/clsm $EXPDIR/$EXPID/mk_restarts/OutData/clsm - ln -s $INSTDIR/bin $EXPDIR/$EXPID/mk_restarts/ - - cd $EXPDIR/$EXPID/mk_restarts/ - echo '#\!/bin/csh -f ' > this.file - - echo "#SBATCH --account=${SPONSORID}">> this.file - echo "#SBATCH --time=1:00:00" >> this.file - echo "#SBATCH --ntasks=$NUMENS" >> this.file - echo "#SBATCH --job-name=mkRst" >> this.file - echo "#SBATCH --qos=debug" >> this.file - echo "#SBATCH --output=mkRst.o" >> this.file - echo "#SBATCH --error=mkRst.e" >> this.file - echo 'source $INSTDIR/bin/g5_modules' >> this.file - echo 'if ( -e /etc/os-release ) then' >> this.file - echo ' module load nco/4.8.1' >> this.file - echo 'else' >> this.file - echo ' module load other/nco-4.6.8-gcc-5.3-sp3 ' >> this.file - echo 'endif' >> this.file - echo 'setenv LD_LIBRARY_PATH ${LD_LIBRARY_PATH}:${BASEDIR}/Linux/lib' >> this.file - - set mpi_mpmd = "${INSTDIR}/bin/esma_mpirun -np 1 bin/mk_GEOSldasRestarts -b ${BCSDIR} -d ${YYYYMMDDHH} -e ${RESTART_ID} -k 0000 -l ${RESTART_short} -m ${MODEL} -s ${SURFLAY} -r Y -t ${TILFILE}" - set j = 1 - while ($j < $NUMENS) - set ENS = `printf '%04d' $j` - set mpi_mpmd = "${mpi_mpmd} : -np 1 bin/mk_GEOSldasRestarts -b ${BCSDIR} -d ${YYYYMMDDHH} -e ${RESTART_ID} -k ${ENS} -l ${RESTART_short} -m ${MODEL} -s ${SURFLAY} -r Y -t ${TILFILE}" - @ j++ - end - echo $mpi_mpmd >> this.file - - set j = 0 - while ($j < $NUMENS) - set ENS = `printf '%04d' $j` - @ j++ - end - echo 'wait' >> this.file - echo 'echo DONE > done_rst_file' >> this.file - sbatch this.file - cd $PWD - sleep 1 - else - ## restart is from GEOSldas little endian binary - if( ! -e $EXPDIR/$EXPID/mk_restarts ) mkdir -p $EXPDIR/$EXPID/mk_restarts/ - echo DONE > $EXPDIR/$EXPID/mk_restarts/done_rst_file - sleep 1 - endif - - breaksw - -case [2]: - - echo ' ' - mkdir -p $EXPDIR/$EXPID/mk_restarts/InData/ - mkdir -p $EXPDIR/$EXPID/mk_restarts/OutData/ - ln -s $BCSDIR/$TILFILE $EXPDIR/$EXPID/mk_restarts/InData/OutTileFile - ln -s $BCSDIR/$TILFILE $EXPDIR/$EXPID/mk_restarts/OutData/OutTileFile - ln -s $BCSDIR/clsm $EXPDIR/$EXPID/mk_restarts/OutData/clsm - ln -s $INSTDIR/bin $EXPDIR/$EXPID/mk_restarts/ - - cd $EXPDIR/$EXPID/mk_restarts/ - - cat << _EOI3_ > mkLDASsa.j -#!/bin/csh -fx - -#SBATCH --account=${SPONSORID} -#SBATCH --time=1:00:00 -#SBATCH --ntasks=56 -#SBATCH --job-name=mkLDAS -#SBATCH --constraint=hasw -#SBATCH --qos=debug -#SBATCH --output=mkLDAS.o -#SBATCH --error=mkLDAS.e - -source $INSTDIR/bin/g5_modules -setenv OMPI_MCA_shmem_mmap_enable_nfs_warning 0 -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 -setenv LAIFILE `find ${BCSDIR}/lai_clim*` -limit stacksize unlimited - -$INSTDIR/bin/esma_mpirun -np 56 bin/mk_GEOSldasRestarts -b ${BCSDIR} -d ${YYYYMMDDHH} -e ${RESTART_ID} -l ${RESTART_short} -t ${TILFILE} -m ${MODEL} -s $SURFLAY -j Y -r R -p ${PARAM_FILE} -sleep 3 - - -${SCALE} InData/${MODEL}_internal_rst OutData/${MODEL}_internal_rst ${MODEL}_internal_rst $SURFLAY $WEMIN_IN $WEMIN_OUT - -# Done creating catch*_internal_rst file - -sleep 2 - -ln -s ${MODEL}_internal_rst ${MODEL}_internal_rst.$YYYYMMDD -echo DONE > done_rst_file - -_EOI3_ - - sbatch mkLDASsa.j - cd $PWD - breaksw - -case [FGM]: - - set YYYY = `echo $YYYYMMDD | cut -c1-4` - set MM = `echo $YYYYMMDD | cut -c5-6` - set DD = `echo $YYYYMMDD | cut -c7-8` - - mkdir -p $EXPDIR/$EXPID/mk_restarts/InData/ - mkdir -p $EXPDIR/$EXPID/mk_restarts/OutData.1/ - mkdir -p $EXPDIR/$EXPID/mk_restarts/OutData.2/ - - if ($HAVE_RESTART == M) then - set ARCDIR = /archive/users/gmao_ops/MERRA2/gmao_ops/GEOSadas-5_12_4/d5124_m2_jan79/rs/Y ; set mlable = jan79 - if ($YYYY > 1991) set ARCDIR = /archive/users/gmao_ops/MERRA2/gmao_ops/GEOSadas-5_12_4/d5124_m2_jan91/rs/Y ; set mlable = jan91 - if ($YYYY > 2000) set ARCDIR = /archive/users/gmao_ops/MERRA2/gmao_ops/GEOSadas-5_12_4/d5124_m2_jan00/rs/Y ; set mlable = jan00 - if ($YYYY > 2010) set ARCDIR = /archive/users/gmao_ops/MERRA2/gmao_ops/GEOSadas-5_12_4/d5124_m2_jan10/rs/Y ; set mlable = jan10 - set rstfile = ${ARCDIR}${YYYY}/M${MM}/d5124_m2_${mlable}.${MODEL}_internal_rst.${YYYYMMDD}_21z.bin - dmget $rstfile - set INTILFILE = /gpfsm/dnb02/ltakacs/bcs/Ganymed-4_0/Ganymed-4_0_MERRA-2/CF0180x6C_DE1440xPE0720/CF0180x6C_DE1440xPE0720-Pfafstetter.til - set WEMIN_IN = 26 - /bin/cp -p $rstfile $EXPDIR/$EXPID/mk_restarts/InData/M2Restart - endif - - if ($HAVE_RESTART == G) then - set rstfile = `echo $RESTART_PATH | rev | cut -c 2- | rev` - set INTILFILE = `readlink $RESTART_ID/scratch/tile.data` - if ( `echo $INTILFILE | grep -n 'NLv3'` == '' ) set WEMIN_IN = 26 - /bin/cp -p $rstfile $EXPDIR/$EXPID/mk_restarts/InData/M2Restart - endif - - if ($HAVE_RESTART == F) then - - set date_16 = `date -d"2017-1-24" +%Y%m%d` - set date_17 = `date -d"2017-11-1" +%Y%m%d` - set date_21 = `date -d"2018-7-11" +%Y%m%d` - set date_22 = `date -d"2019-3-13" +%Y%m%d` - set date_25 = `date -d"2020-1-30" +%Y%m%d` - set expdate = `date -d"$YYYY-$MM-$DD" +%Y%m%d` - - if ($expdate < $date_16) then - echo "WARNING : FP restarts before $date_16 are not availale." - echo " Please select RESTART: M and use MERRA-2, instead." - exit - endif - - if (($expdate >= $date_16) && ($expdate < $date_17)) then - set fpver = GEOS-5.16/GEOSadas-5_16/ - set fplab = f516_fp - set INTILFILE = /discover/nobackup/ltakacs/bcs/Ganymed-4_0/Ganymed-4_0_Ostia/CF0720x6C_DE2880xPE1440/CF0720x6C_DE2880xPE1440-Pfafstetter.til - set WEMIN_IN = 26 - set rstfile = /archive/u/dao_ops/$fpver/${fplab}/rs/Y${YYYY}/M${MM}/${fplab}.${MODEL}_internal_rst.${YYYYMMDD}_21z.bin - dmget $rstfile - /bin/cp -p $rstfile $EXPDIR/$EXPID/mk_restarts/InData/M2Restart - endif - if (($expdate >= $date_17) && ($expdate < $date_21)) then - set fpver = GEOS-5.17/GEOSadas-5_17/ - set fplab = f517_fp - set INTILFILE = /discover/nobackup/ltakacs/bcs/Icarus/Icarus_Ostia/CF0720x6C_CF0720x6C/CF0720x6C_CF0720x6C-Pfafstetter.til - set WEMIN_IN = 26 - set TARFILE = /archive/u/dao_ops/$fpver/${fplab}/rs/Y${YYYY}/M${MM}/${fplab}.rst.${YYYYMMDD}_21z.tar - dmget $TARFILE - set rstfile = ${fplab}.${MODEL}_internal_rst.${YYYYMMDD}_21z.nc4 - tar -xvf $TARFILE $rstfile && /bin/mv $rstfile $EXPDIR/$EXPID/mk_restarts/InData/M2Restart - endif - if (($expdate >= $date_21) && ($expdate < $date_22)) then - set fpver = GEOS-5.21/GEOSadas-5_21/ - set fplab = f521_fp - set INTILFILE = /discover/nobackup/ltakacs/bcs/Icarus/Icarus_Ostia/CF0720x6C_CF0720x6C/CF0720x6C_CF0720x6C-Pfafstetter.til - set WEMIN_IN = 26 - set TARFILE = /archive/u/dao_ops/$fpver/${fplab}/rs/Y${YYYY}/M${MM}/${fplab}.rst.${YYYYMMDD}_21z.tar - dmget $TARFILE - set rstfile = ${fplab}.${MODEL}_internal_rst.${YYYYMMDD}_21z.nc4 - tar -xvf $TARFILE $rstfile && /bin/mv $rstfile $EXPDIR/$EXPID/mk_restarts/InData/M2Restart - endif - if (($expdate >= $date_22) && ($expdate < $date_25)) then - set fpver = GEOS-5.22/GEOSadas-5_22/ - set fplab = f522_fpp - set INTILFILE = /discover/nobackup/ltakacs/bcs/Icarus/Icarus_Ostia/CF0720x6C_CF0720x6C/CF0720x6C_CF0720x6C-Pfafstetter.til - set WEMIN_IN = 26 - set TARFILE = /archive/u/dao_ops/$fpver/${fplab}/rs/Y${YYYY}/M${MM}/${fplab}.rst.${YYYYMMDD}_21z.tar - dmget $TARFILE - set rstfile = ${fplab}.${MODEL}_internal_rst.${YYYYMMDD}_21z.nc4 - tar -xvf $TARFILE $rstfile && /bin/mv $rstfile $EXPDIR/$EXPID/mk_restarts/InData/M2Restart - endif - if ($expdate >= $date_25) then - set fpver = GEOS-5.25/GEOSadas-5_25/ - set fplab = f525land_fpp - set INTILFILE = /discover/nobackup/ltakacs/bcs/Icarus-NLv3/Icarus-NLv3_Ostia/CF0720x6C_CF0720x6C/CF0720x6C_CF0720x6C-Pfafstetter.til - set WEMIN_IN = 13 - set TARFILE = /archive/u/dao_ops/$fpver/${fplab}/rs/Y${YYYY}/M${MM}/${fplab}.rst.${YYYYMMDD}_21z.tar - dmget $TARFILE - set rstfile = ${fplab}.${MODEL}_internal_rst.${YYYYMMDD}_21z.nc4 - tar -xvf $TARFILE $rstfile && /bin/mv $rstfile $EXPDIR/$EXPID/mk_restarts/InData/M2Restart - endif - - endif - - /bin/ln -s $INTILFILE $EXPDIR/$EXPID/mk_restarts/InData/InTilFile - /bin/ln -s $BCSDIR/$TILFILE $EXPDIR/$EXPID/mk_restarts/OutData.1/OutTilFile - /bin/ln -s $BCSDIR/$TILFILE $EXPDIR/$EXPID/mk_restarts/OutData.2/OutTilFile - /bin/ln -s $BCSDIR/clsm $EXPDIR/$EXPID/mk_restarts/OutData.2/clsm - /bin/ln -s $INSTDIR/bin $EXPDIR/$EXPID/mk_restarts/ - cd $EXPDIR/$EXPID/mk_restarts/ - - cat << _EOI5_ > mkLDASsa.j -#!/bin/csh -fx - -#SBATCH --account=${SPONSORID} -#SBATCH --time=1:00:00 -#SBATCH --ntasks=56 -#SBATCH --job-name=mkLDAS -#SBATCH --constraint=hasw -#SBATCH --qos=debug -#SBATCH --output=mkLDAS.o -#SBATCH --error=mkLDAS.e - -source $INSTDIR/bin/g5_modules -setenv OMPI_MCA_shmem_mmap_enable_nfs_warning 0 -#setenv MKL_CBWR SSE4_2 # ensure zero-diff across archs -#setenv MV2_ON_DEMAND_THRESHOLD 8192 # MVAPICH2 -setenv LAIFILE `find ${BCSDIR}/lai_clim*` -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 -limit stacksize unlimited - -/bin/ln -s OutData.1 OutData -if(${MODEL} == 'catch') then -$INSTDIR/bin/esma_mpirun -np 56 bin/mk_CatchRestarts OutData/OutTilFile InData/InTilFile InData/M2Restart $SURFLAY 4 -else -$INSTDIR/bin/esma_mpirun -np 56 bin/mk_CatchCNRestarts OutData/OutTilFile InData/InTilFile InData/M2Restart $SURFLAY $YYYYMMDD 4 -endif -/bin/rm OutData - -/bin/ln -s OutData.2 OutData -if(${MODEL} == 'catch') then -$INSTDIR/bin/esma_mpirun -np 1 bin/mk_CatchRestarts OutData/OutTilFile OutData.1/OutTilFile OutData.1/M2Restart $SURFLAY 4 -else -$INSTDIR/bin/esma_mpirun -np 1 bin/mk_CatchCNRestarts OutData/OutTilFile OutData.1/OutTilFile OutData.1/M2Restart $SURFLAY $YYYYMMDD 4 -endif -/bin/rm OutData - -${SCALE} OutData.1/M2Restart OutData.2/M2Restart ${MODEL}_internal_rst $SURFLAY 26 $WEMIN_OUT - -/bin/ln -s ${MODEL}_internal_rst ${MODEL}_internal_rst.$YYYYMMDD - -echo DONE > done_rst_file -_EOI5_ - - sbatch mkLDASsa.j - cd $PWD - breaksw - -default : - echo $HAVE_RESTART is not implemented -endsw diff --git a/src/Applications/LDAS_App/process_rst.py b/src/Applications/LDAS_App/process_rst.py new file mode 100644 index 00000000..af67bfdf --- /dev/null +++ b/src/Applications/LDAS_App/process_rst.py @@ -0,0 +1,91 @@ +import os +import sys +import subprocess +import shutil +import glob +import ruamel.yaml +import shlex +from remap_utils import * + +def remap_config_ldas(config, RESTART_str, RESTART_PATH, RESTART_ID): + yyyymmddhh = config['input']['shared']['yyyymmddhh'] + MODEL = config['input']['surface']['catch_model'] + out_dir = config['output']['shared']['out_dir'] + # MERRA2 + if RESTART_str == "M" : + 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'] = '/gpfsm/dnb02/ltakacs/bcs/Ganymed-4_0/Ganymed-4_0_MERRA-2/CF0180x6C_DE1440xPE0720/' + + 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') + config['input']['shared']['rst_dir'] = os.path.dirname(RESTART_PATH) + '/' + config['input']['surface']['wemin'] = 13 + if 'NLv' in config['input']['surface']['catch_tilefile'] : config['input']['surface']['wemin'] = 26 + + if RESTART_str == "F" : + date_16 = 20170124 + date_17 = 20171101 + date_21 = 20180711 + date_22 = 20190313 + date_25 = 20200130 + date_27 = 20210225 + date_29 = 20220228 + expdata = int(yyyymmddhh[0:8]) + if (expdate < date_16): + print( "WARNING : FP restarts before $date_16 are not availale.") + print( " Please select RESTART: M and use MERRA-2, instead.") + sys.exit(1) + + config['input']['shared']['bcs_dir'] = '/discover/nobackup/ltakacs/bcs/Icarus/Icarus_Ostia/CF0720x6C_CF0720x6C/' + config['input']['surface']['wemin'] = 26 + config['input']['shared']['rst_dir'] = out_dir+'/InData'+ '/' + suffix = '_21z.tar' + + 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/ltakacs/bcs/Ganymed-4_0/Ganymed-4_0_Ostia/CF0720x6C_DE2880xPE1440/' + suffix = '_21z.bin' + + if ((date_17 <= expdate) and (expdate < date_21)): + fpver = 'GEOS-5.17/GEOSadas-5_17/' + fplab = 'f517_fp' + + if ((date_21 <= expdate) and (expdate < date_22)): + fpver = 'GEOS-5.21/GEOSadas-5_21/' + fplab = 'f521_fp' + + if ((date_22 <= expdate) and (expdate < date_25)): + fpver = 'GEOS-5.22/GEOSadas-5_22/' + fplab = 'f522_fp' + + if (date_25 <= expdate and expdate < date_27) : + fpver = 'GEOS-5.25/GEOSadas-5_25/' + fplab = 'f525land_fpp' + config['input']['surface']['wemin'] = 13 + + if (date_27 <= expdate and expdate < date_29) : + fpver = 'GEOS-5.27/GEOSadas-5_27/' + fplab = 'f5271_fpp' + config['input']['surface']['wemin'] = 13 + + if (date_29 <= expdate ) : + fpver = 'GEOS-5.29/GEOSadas-5_29/' + fplab = 'f5293_fpp' + config['input']['surface']['wemin'] = 13 + + + rstfile = '/archive/u/dao_ops/'+fpver+'/'+fplab+'/rs/Y'+YYYY+'/M'+MM+'/'+fplab+'.'+MODEL+'_internal_rst.'+YYYYMMDD + suffix + fname = os.path.basename(rstfile) + dest = out_dir+'/InData'+ '/'+fname + print("Copy file "+ rstfile +" to " + out_dir+'/InData'+ '/') + shutil.copy(rstfile, dest) + + if suffix == "_21z.tar" : + new_rst = out_dir+'/InData'+ '/'+ fplab+'.'+MODEL+'_internal_rst.'+YYYYMMDD+'_21z.nc4' + subprocess.call(['tar', '-xvf', dest, new_rst]) + + return config 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 new file mode 100644 index 00000000..8a21db30 --- /dev/null +++ b/src/Applications/LDAS_App/sample_config_files/LADAS/HISTORY.rc.atmens @@ -0,0 +1,1132 @@ +# +# 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: +# +# (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 + +COLLECTIONS: +'inst3_2d_lndfcstana_Nx' +'catch_progn_incr0001' +'catch_progn_incr0002' +'catch_progn_incr0003' +'catch_progn_incr0004' +'catch_progn_incr0005' +'catch_progn_incr0006' +'catch_progn_incr0007' +'catch_progn_incr0008' +'catch_progn_incr0009' +'catch_progn_incr0010' +'catch_progn_incr0011' +'catch_progn_incr0012' +'catch_progn_incr0013' +'catch_progn_incr0014' +'catch_progn_incr0015' +'catch_progn_incr0016' +'catch_progn_incr0017' +'catch_progn_incr0018' +'catch_progn_incr0019' +'catch_progn_incr0020' +'catch_progn_incr0021' +'catch_progn_incr0022' +'catch_progn_incr0023' +'catch_progn_incr0024' +'catch_progn_incr0025' +'catch_progn_incr0026' +'catch_progn_incr0027' +'catch_progn_incr0028' +'catch_progn_incr0029' +'catch_progn_incr0030' +'catch_progn_incr0031' +'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_incr0002.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', +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_incr0003.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', +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_incr0004.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', +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_incr0005.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', +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_incr0006.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', +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_incr0007.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', +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_incr0008.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', +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_incr0009.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', +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_incr0010.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', +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_incr0011.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', +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_incr0012.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', +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_incr0013.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', +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_incr0014.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', +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_incr0015.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', +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_incr0016.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', +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_incr0017.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', +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_incr0018.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', +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_incr0019.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', +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_incr0020.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', +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_incr0021.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', +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_incr0022.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', +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_incr0023.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', +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_incr0024.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', +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_incr0025.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', +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_incr0026.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', +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_incr0027.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', +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_incr0028.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', +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_incr0029.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', +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_incr0030.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', +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_incr0031.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', +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_incr0032.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation, Land Prognostics Increments', +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' , + +:: + diff --git a/src/Applications/LDAS_App/sample_config_files/LADAS/HISTORY.rc.central b/src/Applications/LDAS_App/sample_config_files/LADAS/HISTORY.rc.central new file mode 100644 index 00000000..363af785 --- /dev/null +++ b/src/Applications/LDAS_App/sample_config_files/LADAS/HISTORY.rc.central @@ -0,0 +1,98 @@ +# +# Sample GEOSldas HISTORY.rc file for LADAS (central simulation) +# +# This sample is for the GEOSldas instance that is coupled with the central +# simulation component of the Hy4dEnVar ADAS: +# +# (1) The "catch_progn_incr" is output is the ensemble average. +# (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: MyGEOSldasCentral + +COLLECTIONS: + 'catch_progn_incr' + 'inst3_2d_lndfcstana_Nx' + :: + +GRID_LABELS: PC720x361-DC + PC576x361-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 + + +catch_progn_incr.descr: 'Tile-space,3-Hourly,Instantaneous,Single-Level,Assimilation,Ensemble-Average Land Prognostics Increments', +catch_progn_incr.template: '%y4%m2%d2_%h2%n2z.bin', +catch_progn_incr.mode: 'instantaneous', +catch_progn_incr.frequency: 030000, +catch_progn_incr.ref_time: 013000, +catch_progn_incr.fields: 'TCFSAT_INCR' , 'LANDASSIM' , + 'TCFTRN_INCR' , 'LANDASSIM' , + 'TCFWLT_INCR' , 'LANDASSIM' , + 'QCFSAT_INCR' , 'LANDASSIM' , + 'QCFTRN_INCR' , 'LANDASSIM' , + 'QCFWLT_INCR' , 'LANDASSIM' , + 'CAPAC_INCR' , 'LANDASSIM' , + 'CATDEF_INCR' , 'LANDASSIM' , + 'RZEXC_INCR' , 'LANDASSIM' , + 'SRFEXC_INCR' , 'LANDASSIM' , + 'GHTCNT1_INCR' , 'LANDASSIM' , + 'GHTCNT2_INCR' , 'LANDASSIM' , + 'GHTCNT3_INCR' , 'LANDASSIM' , + 'GHTCNT4_INCR' , 'LANDASSIM' , + 'GHTCNT5_INCR' , 'LANDASSIM' , + 'GHTCNT6_INCR' , 'LANDASSIM' , + 'WESNN1_INCR' , 'LANDASSIM' , + 'WESNN2_INCR' , 'LANDASSIM' , + 'WESNN3_INCR' , 'LANDASSIM' , + 'HTSNNN1_INCR' , 'LANDASSIM' , + 'HTSNNN2_INCR' , 'LANDASSIM' , + 'HTSNNN3_INCR' , 'LANDASSIM' , + 'SNDZN1_INCR' , 'LANDASSIM' , + 'SNDZN2_INCR' , 'LANDASSIM' , + 'SNDZN3_INCR' , 'LANDASSIM' , + :: + + +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.archive: '%c/Y%y4', +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: 'PE180x1080-CF', +inst3_2d_lndfcstana_Nx.grid_label: PC576x361-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' , + :: + +# ========================== EOF ============================================================== diff --git a/src/Applications/LDAS_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.atmens b/src/Applications/LDAS_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.atmens new file mode 100644 index 00000000..bf4e17a9 --- /dev/null +++ b/src/Applications/LDAS_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.atmens @@ -0,0 +1,37 @@ +# +# Sample GEOSldas "exeinp" file for LADAS (atm ensemble) +# +# This sample is for the GEOSldas instance that is coupled with the atmospheric +# ensemble component of the Hy4dEnVar ADAS: +# +# (1) Create exeinp template using: +# ldas_setup sample --exeinp > MY_exeinp.txt +# +# (2) Use the resource parameter settings below when editing MY_exeinp.txt +# +############################################################################## + +NUM_LDAS_ENSEMBLE: [NUM_ATM_ENSEMBLE] + +LADAS_COUPLING: 2 + +ADAS_EXPDIR: [full_path]/[ADAS_EXPDIR] + +MET_TAG: [ADAS_EXPID]__Nx+- +MET_PATH: [ADAS_EXPDIR]/atmens/ensdiag/mem + +MET_HINTERP: 0 + +LAND_ASSIM: YES + +LANDASSIM_DT: 10800 +LANDASSIM_T0: 013000 + +FIRST_ENS_ID: 1 + +ENSEMBLE_FORCING: YES + +JOB_SGMT: 00000000 060000 +NUM_SGMT: 1 + +################################# EOF ######################################## 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 new file mode 100644 index 00000000..34d69d97 --- /dev/null +++ b/src/Applications/LDAS_App/sample_config_files/LADAS/exeinp.txt.Hy4dEnVar.central @@ -0,0 +1,39 @@ +# +# Sample GEOSldas "exeinp" file for LADAS (central simulation) +# +# This sample is for the GEOSldas instance that is coupled with the central +# simulation component of the Hy4dEnVar ADAS: +# +# (1) Create exeinp template using: +# ldas_setup sample --exeinp > MY_exeinp.txt +# +# (2) Use the resource parameter settings below when editing MY_exeinp.txt +# +############################################################################## + +LADAS_COUPLING: 1 + +ADAS_EXPDIR: [full_path]/[ADAS_EXPDIR] + +MET_TAG: [ADAS_EXPID]__Nx+- +MET_PATH: [ADAS_EXPDIR]/lana/forc +# option to use perturbed forcing created from central simulation and atm ensemble +# MET_PATH: [ADAS_EXPDIR]/atmens/rgdlfo + +MET_HINTERP: 0 + +LAND_ASSIM: YES + +LANDASSIM_DT: 10800 +LANDASSIM_T0: 013000 + +FIRST_ENS_ID: 1 + +ENSEMBLE_FORCING: NO +# option to use perturbed forcing created from central simulation and atm ensemble +# ENSEMBLE_FORCING: YES + +JOB_SGMT: 00000000 060000 +NUM_SGMT: 1 + +################################# EOF ######################################## diff --git a/src/Applications/LDAS_App/tile_bin2nc4.F90 b/src/Applications/LDAS_App/tile_bin2nc4.F90 index 8ff57fb2..a9d6c6a1 100644 --- a/src/Applications/LDAS_App/tile_bin2nc4.F90 +++ b/src/Applications/LDAS_App/tile_bin2nc4.F90 @@ -5,12 +5,11 @@ PROGRAM tile_bin2nc4 integer :: i,k, n, NTILES integer :: NCFOutID, Vid, STATUS, CellID, TimID, nVars - character*256 :: Usage="tile_bin2nc4.x BINFILE DESCRIPTOR TILECOORD" - character*256 :: BINFILE, TILECOORD, DESCRIPTOR, arg(3) - character*100 :: MYNAME, BUF + character(256) :: Usage="tile_bin2nc4.x BINFILE DESCRIPTOR TILECOORD" + character(512) :: BINFILE, TILECOORD, DESCRIPTOR, arg(3) + character(128) :: MYNAME, BUF integer, dimension(8) :: date_time_values character (22) :: time_stamp - character*100 :: Str_Atr real, allocatable, dimension (:) :: lons, lats, var integer, allocatable, dimension (:) :: tileid, i_index, j_index integer :: myunit1, myunit2 @@ -189,7 +188,7 @@ FUNCTION getAttribute (SHORT_NAME, LNAME, UNT) result (str_atr) character(*), intent(in) :: SHORT_NAME integer, intent (in), optional :: LNAME, UNT - character(100) :: str_atr, LONG_NAME, UNITS + character(128) :: str_atr, LONG_NAME, UNITS SELECT case (trim(SHORT_NAME)) diff --git a/src/Applications/LDAS_App/util/create_ccorr_cat_progn_default.m b/src/Applications/LDAS_App/util/config/Create_ccorr_cat_progn_default.m similarity index 100% rename from src/Applications/LDAS_App/util/create_ccorr_cat_progn_default.m rename to src/Applications/LDAS_App/util/config/Create_ccorr_cat_progn_default.m diff --git a/src/Applications/LDAS_App/util/generate_catchincr_hist.py b/src/Applications/LDAS_App/util/config/generate_catchincr_hist.py similarity index 100% rename from src/Applications/LDAS_App/util/generate_catchincr_hist.py rename to src/Applications/LDAS_App/util/config/generate_catchincr_hist.py diff --git a/src/Applications/LDAS_App/util/config/rewind_GEOSldas.csh b/src/Applications/LDAS_App/util/config/rewind_GEOSldas.csh new file mode 100755 index 00000000..a52a1951 --- /dev/null +++ b/src/Applications/LDAS_App/util/config/rewind_GEOSldas.csh @@ -0,0 +1,117 @@ +#!/bin/csh + +# rewind existing GEOSldas run to specified date/time + +setenv MYNAME rewind_GEOSldas.csh + +if ( $#argv < 4 ) then + echo " " + echo " NAME " + echo " " + echo " $MYNAME - rewind existing GEOSldas run to restart time of nymd nhms" + echo " " + echo " SYNOPSIS " + echo " " + echo " $MYNAME nymd nhms expid exppath " + echo " " + echo " where " + echo " nymd - restart date, as YYYYMMDD " + echo " time - restart time, as HHMMSS " + echo " expid - experiment name, e.g., ldas4coup " + echo " exppath - run directory path, e.g., /discover/nobackup/[user]/ " + echo " " + echo " DESCRIPTION " + echo " " + echo " This procedure rewinds and resets the GEOSldas experiment " + echo " specified by expid and exppath to the restart date/time " + echo " specified by nymd and nhms. " + echo " " + echo " Example of valid command line: " + echo " $MYNAME 20170829 210000 ldas4coup /discover/nobackup/qzhang " + exit(0) +endif + +set nymd = $1 +set nhms = $2 + +echo " ymd = $nymd " +echo " hms = $nhms " + +set yin = `echo $nymd | cut -c1-4` +set min = `echo $nymd | cut -c5-6` +set hin = `echo $nhms | cut -c1-4` + +set date = ${nymd}_${hin} + +set expid = $3 +set rundir = $4 +echo " expid = $expid " + +cd ${rundir}/${expid}/run +set nmem = `grep NUM_LDAS_ENSEMBLE: LDAS.rc | cut -d':' -f2` +cd ${rundir}/${expid} +set grid = `ls output` + +## rewind links to restart files + +@ NENS = $nmem + +set rsout = ${rundir}/${expid}/output/${grid}/rs +set rstin = ${rundir}/${expid}/input/restart +cd $rstin + +/bin/rm -rf catch*_internal_rst +/bin/rm -rf landpert*_internal_rst +/bin/rm -rf landassim_obspertrseed*_rst + +@ inens = 1 + +while ($inens <= $NENS) + + if ($inens < 10) then + set ENSDIR = `echo ens000${inens}` + set catin = `echo catch000${inens}` + set pertin = `echo landpert000${inens}` + set seedin = `echo obspertrseed000${inens}` + else if($inens < 100) then + set ENSDIR = `echo ens00${inens}` + set catin = `echo catch00${inens}` + set pertin = `echo landpert00${inens}` + set seedin = `echo obspertrseed00${inens}` + else if($inens < 1000) then + set ENSDIR = `echo ens0${inens}` + set catin = `echo catch0${inens}` + set pertin = `echo landpert0${inens}` + set seedin = `echo obspertrseed0${inens}` + else + set ENSDIR = `echo ens${inens}` + set catin = `echo catch${inens}` + set pertin = `echo landpert${inens}` + set seedin = `echo obspertrseed${inens}` + endif + + /bin/ln -s ${rsout}/${ENSDIR}/Y${yin}/M${min}/${expid}.catch_internal_rst.${date} ${catin}_internal_rst + + if (-e ${rsout}/${ENSDIR}/Y${yin}/M${min}/${expid}.landpert_internal_rst.${date}.gz ) then + gunzip ${rsout}/${ENSDIR}/Y${yin}/M${min}/${expid}.landpert_internal_rst.${date}.gz + endif + + /bin/ln -s ${rsout}/${ENSDIR}/Y${yin}/M${min}/${expid}.landpert_internal_rst.${date} ${pertin}_internal_rst + + /bin/ln -s ${rsout}/${ENSDIR}/Y${yin}/M${min}/${expid}.landassim_obspertrseed_rst.${date} landassim_${seedin}_rst + + @ inens ++ +end + +## -- remove records in rc_out +cd ${rundir}/${expid}/output/${grid}/rc_out/Y${yin}/M${min} +/bin/rm -rf *smapL4*${date}z.bin +/bin/rm -rf *.${date}z.txt +/bin/rm -rf *.${date}z.nml + +## -- reset cap_restart +cd ${rundir}/${expid}/run +/bin/rm -rf cap_restart +echo $nymd ${nhms} > cap_restart + +## EOF #################################################################### diff --git a/src/Applications/LDAS_App/util/inputs/mwRTM_params/Create_mwRTM_param_file.m b/src/Applications/LDAS_App/util/inputs/mwRTM_params/Create_mwRTM_param_file.m new file mode 100644 index 00000000..6a9859ce --- /dev/null +++ b/src/Applications/LDAS_App/util/inputs/mwRTM_params/Create_mwRTM_param_file.m @@ -0,0 +1,240 @@ +% --------------------------------------------------------------------------- +% This script is to generate the mwRTM_param.nc4 file for the GEOSldas mwRTM. +% All constant mwRTM parameters are in this file. They come from 3 different +% sources: cat_param, vegcls lookup table and preprocessed L2DCA daily mat files. +% Therefore, need to run Preprocess_L2DCA_mwRTM_into_dailymat.m before running +% this script. + +% qliu + rreichle, 29 Jul 2022 + +% ---------------------------------------------------------------------------- + +clear + +% add path to matlab functions in src/Applications/LDAS_App/util/shared/matlab/ +addpath('../../shared/matlab/'); + +% option to fill small gaps based on neighboring grids, 1 is recommended. +fill_small_gaps = 1; + +% fill value in output file +fillValue = single(1.e15); + +% resolution of output parameters: only works with "M09" or "M36". +EASEv2_grid = 'M09'; + +% older version mwRTM_param.nc4 file for parameter names and attributes +fname_in = ['/home/qliu/smap/SMAP_Nature/bcs/RTM_params/RTMParam_SMAP_L4SM_v004/SMAP_EASEv2_',EASEv2_grid,'/mwRTM_param.nc4']; + +% target mwRTM_param file name +fname_out = ['/home/qliu/smap/SMAP_Nature/bcs/RTM_params/RTMParam_L2_omega_H_tmp/SMAP_EASEv2_',EASEv2_grid,'/mwRTM_param_L2_omega_H_fillValue_bhbvlewt.nc4']; + +% get inputs for fill_gaps_in_tiledata() below +if fill_small_gaps + + if strcmp(EASEv2_grid,'M09') + N_cells = 5; + iscube = 0; + elseif strcmp(EASEv2_grid,'M36') + N_cells = 3; + iscube = 0; + else + error('invalid resolution, use ''M09'' or ''M36'' only') + end + + tmpstr = num2str(N_cells); + + fname_out = strrep(fname_out,'.nc4','_',tmpstr,'gx',tmpstr,'gfilled.nc4'); +end + +% Do not overwrite if file exists +if exist(fname_out,'file') + + disp(['file exist ',fname_out]) + return + +end + +% GEOSldas experiment for tilecoord and cat_params +exp_path = '/home/qliu/smap/SMAP_Nature/SMAP_Nature_v10/'; + +if strcmp(EASEv2_grid,'M09') + exp_run = 'SMAP_Nature_v10.0'; + domain = 'SMAP_EASEv2_M09_GLOBAL'; +else + exp_run = 'SMAP_Nature_v10.0_M36'; + domain = 'SMAP_EASEv2_M36_GLOBAL'; +end + +fname_tc = [exp_path,exp_run,'/output/',domain,'/rc_out/',exp_run,'.ldas_tilecoord.bin']; +fname_tg = [exp_path,exp_run,'/output/',domain,'/rc_out/',exp_run,'.ldas_tilegrids.bin']; +fname_catparam = [exp_path,exp_run,'/output/',domain,'/rc_out/Y2015/M04/',exp_run,'.ldas_catparam.20150401_0000z.bin']; + +% If use L4 products in /css/smapl4/ +if ~exist(fname_tc, 'file') + fname_tc = [exp_path,exp_run,'/rc_out/',exp_run,'.ldas_tilecoord.bin']; + fname_tg = [exp_path,exp_run,'/rc_out/',exp_run,'.ldas_tilegrids.bin']; + fname_catparam = [exp_path,exp_run,'/rc_out/Y2015/M04/',exp_run,'.ldas_catparam.20150401_0000z.bin']; +end + +tc = read_tilecoord(fname_tc); + +% double check for tile order, may not work if exp_run uses older bcs +% version +if max(abs(transpose([1:tc.N_tile])-tc.tile_id)) > 0 + error('tile order is not strictly tile_id ascending, need to modify script to reorder') + return +end + +tg = read_tilegrids(fname_tg); +cat_param = read_catparam(fname_catparam, tc.N_tile); + +% L2RTM parameter source information +L2_version = 'R18290'; +L2_start_time.year = 2015; L2_start_time.month = 4; L2_start_time.day = 1; +L2_end_time.year = 2022; L2_end_time.month = 4; L2_end_time.day = 1; + +if strcmp(EASEv2_grid,'M36') + L2_file_tag = 'L2_SM_P'; +else + L2_file_tag = 'L2_SM_P_E'; +end + +% L2DCA based parameters +L2_param = get_L2_RTM_constants_tile_data(tc,L2_file_tag,... + L2_version,L2_start_time, L2_end_time); +omega = L2_param.Albedo; +hparam = L2_param.Roughness; +clear L2_param + +% cat_param based parameters +mwRTMparam.soilcls = int32(cat_param.soilcls30); +mwRTMparam.sand = cat_param.sand30/100.; +mwRTMparam.clay = cat_param.clay30/100.; + +% there are 0 values in poros30 for unknown reasons, set 0 to next minimum +% value (0.3741) +mwRTMparam.poros = max(0.3741, cat_param.poros30); +mwRTMparam.wang_wp = cat_param.wpwet30 .* cat_param.poros30; +mwRTMparam.wang_wt = 0.49*mwRTMparam.wang_wp + 0.165; +mwRTMparam.rgh_wmin = mwRTMparam.wang_wt; +mwRTMparam.rgh_wmax = mwRTMparam.poros; + +% Initialize the input and output file interface + +netcdf.setDefaultFormat('FORMAT_NETCDF4'); + +fin_id = netcdf.open(fname_in, 'NOWRITE'); +fout_id = netcdf.create(fname_out, 'NETCDF4'); + +if fout_id < 0, error(['Creating ' fname_out 'failed']); end + +finfo = ncinfo(fname_in); netcdf.close(fin_id) + +% Define Dimension (tile) +Dim_id = netcdf.defDim(fout_id,'tile',tc.N_tile); + +nvar_in_file = length(finfo.Variables); + +for i=1: nvar_in_file + + data_name = finfo.Variables(i).Name; + data_type = finfo.Variables(i).Datatype; + + data_type = 'float'; + + data_size = finfo.Variables(i).Size; + + varid(i) = netcdf.defVar(fout_id, data_name, data_type, Dim_id ); + + netcdf.defVarFill(fout_id, varid(i), false, fillValue); + + n_attr = length(finfo.Variables(i).Attributes); + + for iv = 1:n_attr + att_name = finfo.Variables(i).Attributes(iv).Name; + att_value = finfo.Variables(i).Attributes(iv).Value; + + netcdf.putAtt(fout_id, varid(i), att_name, att_value); + end + + netcdf.endDef(fout_id); + + startVAR = repmat([0], 1, length(data_size)); + countVAR = data_size; + + % get parameter values from their respective sources + % Total of 18 mwRTM parameters: + % 8 from cat_param: SOILCLS, SOIL, CLAY, POROS, WANGWT, WANTWP, RGHWMIN, RGHWMAX + % 4 from vegcls lookup table : VEGCLS, RGHNRH, RGHNRV,POLMIX + % 3 from L2RTM: RGHHMIN, RGHHMAX, OMEGA + % 3 are set to fillValue: BH,BV, OMEGA + + if strcmp(data_name,'MWRTM_OMEGA') + if fill_small_gaps + omega_filled = fill_gaps_in_tiledata(tc, tg, transpose(omega), N_cells, iscube ); + data = omega_filled; + else + data = omega; + end + elseif contains(data_name, 'MWRTM_RGHHM') + if fill_small_gaps + hparam_filled = = fill_gaps_in_tiledata(tc, tg, transpose(hparam), N_cells, iscube ); + data = hparam_filled; + else + data = hparam; + end + elseif strcmp(data_name,'MWRTM_SOILCLS') + data = mwRTMparam.soilcls; + elseif strcmp(data_name,'MWRTM_SAND') + data = mwRTMparam.sand; + elseif strcmp(data_name,'MWRTM_CLAY') + data = mwRTMparam.clay; + elseif strcmp(data_name,'MWRTM_POROS') + data = mwRTMparam.poros; + elseif strcmp(data_name,'MWRTM_WANGWT') + data = mwRTMparam.wang_wt; + elseif strcmp(data_name,'MWRTM_WANGWP') + data = mwRTMparam.wang_wp; + elseif strcmp(data_name,'MWRTM_RGHWMIN') + data = mwRTMparam.rgh_wmin; + elseif strcmp(data_name,'MWRTM_RGHWMAX') + data = mwRTMparam.rgh_wmax; + elseif strcmp(data_name,'MWRTM_LEWT') || contains(data_name, 'MWRTM_B') + data = fillValue .* ones(data_size,1); + else + if strcmp(EASEv2_grid,'M09') + dominant_M36vegcls = 1; + else + dominant_M36vegcls = 0; + end + tmp_rtm = get_mwRTM_vegcls_based( tc, dominant_M36vegcls,['EASEv2_',EASEv2_grid]); + if strcmp(data_name,'MWRTM_RGHNRH') + data = tmp_rtm.rgh_Nrh; + elseif strcmp(data_name,'MWRTM_RGHNRV') + data = tmp_rtm.rgh_Nrv; + elseif strcmp(data_name,'MWRTM_VEGCLS') + data = tmp_rtm.vegcls; + elseif strcmp(data_name,'MWRTM_RGHPOLMIX') + data = tmp_rtm.rgh_polmix; + end + end + + % earlier fillValue was -9999. replace with new fillValue (1.e15) + data(abs(data-(-9999.)) < abs(-9999.*1e-4)) = NaN; + + data(isnan(data)) = fillValue; + + netcdf.putVar(fout_id, varid(i), startVAR, countVAR, data); clear data + + netcdf.reDef(fout_id); + +end + +netcdf.endDef(fout_id); + +netcdf.close(fout_id); + +disp(['done writing ',fname_out]) + +% --------------------------EOF-------------------------------------------- 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 new file mode 100644 index 00000000..6c70e07d --- /dev/null +++ b/src/Applications/LDAS_App/util/inputs/mwRTM_params/Create_vegopacity_8day_clim.m @@ -0,0 +1,341 @@ +% script to create 8-day climatology of vegetation opacity for L-band microwave +% radiative transfer model (mwRTM) +% +% requires pre-processing of SMAP L2 data into daily *.mat files using +% Preprocess_L2DCA_mwRTM_params_to_dailymat.m +% +% output files written in MAPL_ReadForcing format +% +% qliu + rreichle, 29 Jul 2022 +% +% ------------------------------------------------------------------------------------- + +clear + +% add path to matlab functions in src/Applications/LDAS_App/util/shared/matlab/ +addpath('../../shared/matlab/'); + +L2_Ascdes_all = {'_A_','_D_'}; + +out_Para = 'VOD'; + +L2_file_tag = 'L2_SM_P'; +L2_version = 'R18290'; + +if strcmp(L2_file_tag(end-1:end),'_E') + resolution = 'M09'; +else + resolution = 'M36'; +end + +out_path = '/discover/nobackup/qliu/matlab/SMAP/L2L4/VOD/QC_frozen_RFI/'; + +fill_small_gaps = 1; + +% provide a GEOSldas simulation with matching tile information +if strcmp(resolution,'M36') + L4_path = '/gpfsm/dnb05/projects/p51/SMAP_Nature/SMAP_Nature_v9.x/'; + L4_version = 'SMAP_Nature_v9.1_M36'; + based_on_h5 = 0; + out_Nlon = 3856/4; + out_Nlat = 1624/4; +else + L4_path = '/css/smapl4/public/L4_Products/L4_SM/'; + L4_version = 'Vv6030'; + based_on_h5 = 1; + out_Nlon = 3856; + out_Nlat = 1624; +end + +ftilecoord = [L4_path,L4_version,'/output/SMAP_EASEv2_',resolution,'_GLOBAL/rc_out/', ... + L4_version,'.ldas_tilecoord.bin']; +ftilegrids = [L4_path,L4_version,'/output/SMAP_EASEv2_',resolution,'_GLOBAL/rc_out/', ... + L4_version,'.ldas_tilegrids.bin']; + +if ~exist(ftilecoord,'file') + ftilecoord = [L4_path,L4_version,'/rc_out/SPL4SM_', L4_version,'.ldas_tilecoord.bin']; + ftilegrids = [L4_path,L4_version,'/rc_out/SPL4SM_', L4_version,'.ldas_tilegrids.bin']; +end +% read tile info for binary output +tc = read_tilecoord( ftilecoord); +tg = read_tilegrids( ftilegrids); + +int_precision = 'int32'; +float_precision = 'float32'; + +for iAD = 1:2 + + L2_Ascdes = L2_Ascdes_all{iAD}; + L2_qc_yes = 1; + + dtstep = 10800; + + % time period for computing climatology + start_time.year = 2015; + start_time.month = 4; + start_time.day = 1; + + start_time.hour = 1; + start_time.min = 30; + start_time.sec = 0; + + end_time.year = 2022; + end_time.month = 4; + end_time.day = 1; + end_time.hour = start_time.hour; + end_time.min = start_time.min; + end_time.sec = start_time.sec; + + start_time = get_dofyr_pentad(start_time); + end_time = get_dofyr_pentad(end_time); + + % lookup table of month and day of first day in 8-day average (non-leap year) + + clim_8d_m1 = [ 1 1 1 1 2 2 2 2 ... + 3 3 3 3 4 4 4 ... + 5 5 5 5 6 6 6 6 ... + 7 7 7 7 8 8 8 8 ... + 9 9 9 9 10 10 10 ... + 11 11 11 11 12 12 12 12]; + + clim_8d_d1 = [ 1 9 17 25 2 10 18 26 ... + 6 14 22 30 7 15 23 ... + 1 9 17 25 2 10 18 26 ... + 4 12 20 28 5 13 21 29 ... + 6 14 22 30 8 16 24 ... + 1 9 17 25 3 11 19 27 ]; + + clim_8d_m2 = [clim_8d_m1(2:46) 1]; + clim_8d_d2 = [clim_8d_d1(2:46) 1]; + + % ----------------------------------------------------------------------- + % read from preprocessed daily mat file + if end_time.month ==1 + time_tag = [num2str(start_time.year,'%4.4d'),num2str(start_time.month,'%2.2d'), ... + '_',num2str(end_time.year-1,'%4.4d'),'12']; + else + time_tag = [num2str(start_time.year,'%4.4d'),num2str(start_time.month,'%2.2d'), ... + '_',num2str(end_time.year,'%4.4d'),num2str(end_time.month-1,'%2.2d')]; + end + + fname_clim = [out_path,'/',out_Para,'_clim_L2_',L2_version,L2_Ascdes,'8d_',resolution,'tile_',time_tag,'_w24d.bin']; + + L2_tau_clim_sum = zeros(46,out_Nlon,out_Nlat); + N_L2_clim_sum = zeros(46,out_Nlon,out_Nlat); + + if exist(fname_clim,'file') + + disp(['found preprocessed climatology file ',fname_clim]) + + else + + date_time = start_time; + + while 1 + + if (date_time.year ==end_time.year && ... + date_time.month==end_time.month && ... + date_time.day ==end_time.day ) + break + end + + outfile_tag = [num2str(date_time.year,'%4.4d'), ... + num2str(date_time.month,'%2.2d'), ... + num2str(date_time.day,'%2.2d')]; + + mat_fname = [out_path,'L2DCA_RTM_',L2_file_tag,'_',L2_version,L2_Ascdes, outfile_tag,'.mat']; + + if exist(mat_fname,'file') + + disp(['loading ', mat_fname]) + if contains(fname_clim,'VOD_') + load(mat_fname,'L2_tau') + elseif contains(fname_clim,'Albedo_') + load(mat_fname,'L2_omg') + L2_tau = L2_omg; clear L2_omg + elseif contains(fname_clim,'Roughness_') + load(mat_fname,'L2_h') + L2_tau = L2_h; clear L2_h + else + error(['unknown clim fname ',fname_clim]) + end + + d_idx = find(date_time.month == clim_8d_m1 & date_time.day >= clim_8d_d1); + if ~isempty(d_idx) + d_idx = d_idx(end); + else + d_idx = find(date_time.month == clim_8d_m2 & date_time.day < clim_8d_d2); + d_idx = d_idx(1); + end + + % compute climatology + tmp = max(L2_tau,0); % make sure no negative values in tau + tmp(isnan(tmp)) = 0; + + L2_tau_clim_sum(d_idx,:,:) = squeeze(L2_tau_clim_sum(d_idx,:,:)) + tmp; clear tmp + tmp = ~isnan(L2_tau); + N_L2_clim_sum(d_idx,:,:) = squeeze(N_L2_clim_sum(d_idx,:,:)) + tmp; clear tmp + + clear L2_tau + + else + + error('daily mat file not found') + + end + + date_time = augment_date_time(86400, date_time); + + end + + L2_tau_clim = L2_tau_clim_sum ./N_L2_clim_sum; + + + % regrid to til grid + + L2_tau_tile = NaN + ones(46, tc.N_tile); + for k = 1:tc.N_tile + L2_tau_tile(:,k) = L2_tau_clim(:,tc.i_indg(k)+1, tc.j_indg(k)+1); + end + + ifp = fopen(fname_clim,'w','l'); + + for n = 1: 48 + if n == 1 + y1 = 0; + y2 = 1; + + nidx = 46; + nidx_pre = 45; + nidx_nxt = 1; + elseif n == 2 + y1 = 1; + y2 = 1; + nidx = n-1; + nidx_pre = 46; + nidx_nxt = n; + elseif n == 47 + y1 = 1; + y2 = 2; + + nidx = n-1; + nidx_pre = n-2; + nidx_nxt = 1; + elseif n == 48 + y1 = 2; + y2 = 2; + nidx = 1; + nidx_pre = 46; + nidx_nxt = 2; + else + y1 = 1; + y2 = 1; + nidx = n-1; + nidx_pre = n-2; + nidx_nxt = n; + end + m1 = clim_8d_m1(nidx); + m2 = clim_8d_m2(nidx); + d1 = clim_8d_d1(nidx); + d2 = clim_8d_d2(nidx); + + 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(isnan(tile_data)) = 1.e15; + + fwrite( ifp, 14*4, int_precision ); % fortran_tag + fwrite( ifp, header, float_precision ); + fwrite( ifp, 14*4, int_precision ); % fortran_tag + + fwrite( ifp, tc.N_tile*4, int_precision );% fortran_tag + fwrite( ifp, tile_data(:), float_precision ); + fwrite( ifp, tc.N_tile*4, int_precision );% fortran_tag + + clear header tile_data + end + fclose(ifp) + end + +end + +% ======================== +% The final vegopacity.bin file contains data averaged (nanmean) 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); +for iAD = 1:2 + + L2_Ascdes = L2_Ascdes_all{iAD}; + + fname = [out_path,'/',out_Para,'_clim_L2_',L2_version,L2_Ascdes,'8d_',resolution,'tile_',time_tag,'_w24d.bin']; + + disp(['read ',fname]) + ifp = fopen(fname,'r','l'); + + for n = 1:48 + + fortran_tag = fread( ifp, 1, int_precision ); + tmp = fread( ifp, 14, float_precision ); + header(n,:) = tmp; + fortran_tag = fread( ifp, 1, int_precision ); + + fortran_tag = fread( ifp, 1, int_precision ); + tmp = fread( ifp, tc.N_tile, float_precision ); + fortran_tag = fread( ifp, 1, int_precision ); + + data_clim_tile(n,:,iAD) = tmp; + + end + + fclose(ifp); +end + +data_clim_tile(data_clim_tile > 10.) = NaN; +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); +fname_out = strrep(fname, L2_Ascdes,'_AD_'); +if fill_small_gaps + + if strcmp(resolution,'M09') + N_cells = 5; + iscube = 0; + elseif strcmp(resolution,'M36') + N_cells = 3; + iscube = 0; + else + error('invalid resolution, use ''M09'' or ''M36'' only') + end + + tmpstr = num2str(N_cells); + + fname_out = [fname_out(1:end-4),'_',tmpstr,'gx',tmpstr,'gfilled_test.bin']; + + tile_data = fill_gaps_in_tiledata(tc, tg, tile_data, N_cells, iscube ); + +end + +tile_data(isnan(tile_data)) = 1.e15; % fillValue = 1.e15 + +disp(['write ',fname_out]) + +ifp = fopen(fname_out,'w','l'); +for n = 1:48 + + % write header + + fwrite( ifp, 14*4, int_precision ); + fwrite( ifp, header(n,:), float_precision ); + fwrite( ifp, 14*4, int_precision ); + + % write science data + + fwrite( ifp, tc.N_tile*4, int_precision ); + fwrite( ifp, tile_data(n,:), float_precision ); + fwrite( ifp, tc.N_tile*4, int_precision ); +end +fclose(ifp); + +% ============================ EOF ====================================== diff --git a/src/Applications/LDAS_App/util/inputs/mwRTM_params/Preprocess_L2DCA_mwRTM_params_to_dailymat.m b/src/Applications/LDAS_App/util/inputs/mwRTM_params/Preprocess_L2DCA_mwRTM_params_to_dailymat.m new file mode 100644 index 00000000..6e2d9fdf --- /dev/null +++ b/src/Applications/LDAS_App/util/inputs/mwRTM_params/Preprocess_L2DCA_mwRTM_params_to_dailymat.m @@ -0,0 +1,241 @@ +% Script to read SMAP L2 files and extract RTM variables (albedo, vegopacity, roughness) +% to store in global EASEv2 grid daily composite (Asc and Desc separately) mat files for future use. + +% Q. Liu 18 Jul 2022 + +clear + +% add path to matlab functions in src/Applications/LDAS_App/util/shared/matlab/ +addpath('../../shared/matlab/'); + +L2_Ascdes = {'_A_','_D_'}; +L2_qc_yes = 1; + +% L2 file information. Use 'L2_SM_P' for M36 resolution and 'L2_SM_P_E' for M09 +SMAP_product = 'L2_SM_P'; %'L2_SM_P'; +L2_path = ['/discover/nobackup/projects/gmao/smap/SMAP_L4/SMAP/OPS/',SMAP_product,'/'] ; + +L2_version = 'R18290'; %'R17000'; + +out_path = '/discover/nobackup/qliu/matlab/SMAP/L2L4/VOD/QC_frozen_RFI/'; + +L2_dtstep = 10800; + +start_time.year = 2021; +start_time.month = 4; +start_time.day = 1; + +end_time.year = 2022; +end_time.month = 4; +end_time.day = 1; + +M09_Nlon = 3856; +M09_Nlat = 1624; + +M36_Nlon = M09_Nlon/4; +M36_Nlat = M09_Nlat/4; + +if strcmp(SMAP_product(end-1:end),'_E') + out_Nlon = M09_Nlon; + out_Nlat = M09_Nlat; +else + out_Nlon = M36_Nlon; + out_Nlat = M36_Nlat; +end + +% ----------------------------------------------------------------------- +% Read L2 data +for iorb = 1:length(L2_Ascdes) + + date_time = start_time; + date_time.hour = 0; + date_time.min = 0; + date_time.sec = 0; + + fname_L2_pre = []; + + while 1 + + if (date_time.year ==end_time.year && ... + date_time.month==end_time.month && ... + date_time.day ==end_time.day ) + break + end + + outfile_tag = [num2str(date_time.year,'%4.4d'), ... + num2str(date_time.month,'%2.2d'), ... + num2str(date_time.day,'%2.2d')]; + + mat_fname = [out_path,'L2DCA_RTM_',SMAP_product,'_',L2_version,L2_Ascdes{iorb}, outfile_tag,'.mat']; + + if exist(mat_fname,'file') + + disp(['mat file exist ',mat_fname]) + + else + + L2_tau = NaN + ones(out_Nlon,out_Nlat); + L2_omg = NaN + ones(out_Nlon,out_Nlat); + L2_h = NaN + ones(out_Nlon,out_Nlat); + + L2_data_path = [L2_path, '/Y', num2str(date_time.year,'%4.4d'), ... + '/M', num2str(date_time.month, '%2.2d'), ... + '/D', num2str(date_time.day, '%2.2d')]; + + % get list of all files in subdirectory of given date + L2_files_all = dir([L2_data_path, '/SMAP_',SMAP_product,'*',L2_Ascdes{iorb},'*_',L2_version,'_*.h5']); + + % check if multiple versions of the same half orbit file + % only keep the data with the highest version id + + L2_files = {}; + kk = 0; % counter of the final file list + % Remove duplicate files from the list when multiple versions exist + for ff = 1:length(L2_files_all) + % check if v002 or higher exist + if str2num(L2_files_all(ff).name(end-4:end-3)) > 1 + L2_files{kk} = L2_files_all(ff).name; + % if v002 or higher matches previous file in final flist, replace + % previous file in list. Only increase the final file counter when there is no duplicates + if ~strcmp(L2_files{kk}(1:end-5), L2_files_all(ff).name(1:end-5)) + kk = kk + 1; + end + else + kk = kk + 1; + L2_files{kk} = L2_files_all(ff).name; + end + end + + clear L2_fiels_all L2_fname + if ~isempty(L2_files) + + for ifile = 1:length(L2_files) + L2_fname{ifile} = [L2_data_path,'/', L2_files{ifile}]; + end + + if ~isempty(fname_L2_pre) + L2_fname((ifile+1):(ifile+length(fname_L2_pre))) = fname_L2_pre; + end + + fname_L2_pre = []; + + ii = 0; + for ifile = 1: length(L2_fname) + + fname = L2_fname{ifile}; + + disp(fname) + + L2_row = h5read(fname,'/Soil_Moisture_Retrieval_Data/EASE_row_index'); %zero-based + L2_row = L2_row + 1; + L2_col = h5read(fname,'/Soil_Moisture_Retrieval_Data/EASE_column_index'); + L2_col = L2_col + 1; + + L2_utc_seconds = h5read(fname,'/Soil_Moisture_Retrieval_Data/tb_time_seconds'); + + L2_vod = h5read(fname,'/Soil_Moisture_Retrieval_Data/vegetation_opacity_option3'); + fill_value = h5readatt(fname,'/Soil_Moisture_Retrieval_Data/vegetation_opacity_option3','_FillValue'); + L2_vod(L2_vod == fill_value) = NaN; + + L2_alb = h5read(fname,'/Soil_Moisture_Retrieval_Data/albedo_option3'); + fill_value = h5readatt(fname,'/Soil_Moisture_Retrieval_Data/albedo_option3','_FillValue'); + L2_alb(L2_alb == fill_value) = NaN; + + L2_rough = h5read(fname,'/Soil_Moisture_Retrieval_Data/roughness_coefficient_option3'); + fill_value = h5readatt(fname,'/Soil_Moisture_Retrieval_Data/roughness_coefficient_option3','_FillValue'); + L2_rough(L2_rough == fill_value) = NaN; + + % quality flag + L2_qf = h5read(fname,'/Soil_Moisture_Retrieval_Data/retrieval_qual_flag_option3'); + + % surface status land = 0, nonland = 1 + L2_ss = h5read(fname,'/Soil_Moisture_Retrieval_Data/grid_surface_status'); + + % surface flag + L2_sf = h5read(fname,'/Soil_Moisture_Retrieval_Data/surface_flag'); + + L2_rfi_h = h5read(fname,'/Soil_Moisture_Retrieval_Data/tb_qual_flag_h'); + L2_rfi_v = h5read(fname,'/Soil_Moisture_Retrieval_Data/tb_qual_flag_v'); + + % exclude points according to quality flag + if L2_qc_yes + + % QC based on retrieval quality flag + %L2_rt = bitget(L2_qf, 1); % only use retrieval_recommended + L2_rt = bitget(L2_qf, 3); % use retrieval_succeeded + + % QC b ased on surface flag + L2_frozen_model = bitget(L2_sf, 9); % model frozen ground + L2_snow = bitget(L2_sf,6); % snow and ice + L2_pice = bitget(L2_sf,7); % permanent snow and ice + L2_rfi_h_qf = bitget(L2_rfi_h,1); % quality flag RFI H + L2_rfi_v_qf = bitget(L2_rfi_v,1); % quality flag RFI V + idx = find(L2_rt == 0 & L2_frozen_model ==0 & ... + L2_snow == 0 & L2_pice ==0 & L2_ss == 0 & ... + L2_rfi_h_qf == 0 & L2_rfi_v_qf == 0); + + % only keep data/coord that pass QC + L2_vod = L2_vod(idx); + L2_alb = L2_alb(idx); + L2_rough = L2_rough(idx); + L2_row = L2_row(idx); + L2_col = L2_col(idx); + L2_utc_seconds = L2_utc_seconds(idx); + clear idx + end + + if ~isempty(L2_vod) + + % round date_time to nearest 3 hourly UTC + utc_t2k = round(double(L2_utc_seconds)/L2_dtstep)*L2_dtstep; + + [yr, doy, mm, dd, hr, mn] = J2000_to_DateTime( utc_t2k ); + + % use points for current UTC day only + idx = find(yr == date_time.year & mm == date_time.month & ... + dd == date_time.day); + + % points across UTC days will be saved in next daily file + if length(idx) < length(L2_utc_seconds) && ifile <= length(L2_files) + disp('L2 across UTC days') + ii = ii + 1; + fname_L2_pre{ii} = fname; + end + + L2_vod = L2_vod(idx); + L2_alb = L2_alb(idx); + L2_rough = L2_rough(idx); + L2_row = L2_row(idx); + L2_col = L2_col(idx); + L2_utc_seconds = L2_utc_seconds(idx); + hr = hr(idx); + clear idx + + % Map L2 to 2d grid + for k = 1:length(L2_vod) + this_col = L2_col(k); + this_row = L2_row(k); + + L2_tau(this_col, this_row) = L2_vod(k); + L2_omg(this_col, this_row) = L2_alb(k); + L2_h(this_col, this_row) = L2_rough(k); + end + end + end + + else + + disp(['no L2 data found in', L2_data_path]) + pause + end + + save(mat_fname,'L2_tau','L2_omg','L2_h') + clear L2_tau L2_omg L2_h + + end + + date_time = augment_date_time(86400, date_time); + end +end + +% ------------------------EOF----------------------------------------- diff --git a/src/Applications/LDAS_App/util/inputs/mwRTM_params/fill_gaps_in_tiledata.m b/src/Applications/LDAS_App/util/inputs/mwRTM_params/fill_gaps_in_tiledata.m new file mode 100644 index 00000000..03d5ea3a --- /dev/null +++ b/src/Applications/LDAS_App/util/inputs/mwRTM_params/fill_gaps_in_tiledata.m @@ -0,0 +1,94 @@ +function [tile_data_filled] = fill_gaps_in_tiledata(tile_coord, tile_grid_g, tile_data, N_cells, iscube ) + +% Fill missing values in tile-space data with the mean value (excl. NaNs) of surrounding grid cells. +% +% N_cells is number of grid cells averaged in each linear dimension; e.g., N_cells=5 averages across +% a 5-by-5 neighborhood (-2, -1, 0, 1, 2 in each direction). +% +% Uses tile2grid() --> Should work for EASE[_v2] and lat/lon tile spaces. +% Probably needs work for cube-sphere tile space!!! +% +% iscube: required input to alert user that fn is not ready for data in cube-sphere tile space +% +% tile_data[_filled] = N_fields-by-N_tile +% +% Q. Liu, 19 Jul 2022 +% reichle, 29 Jul 2022 - minor clean-up and generalization +% +% ----------------------------------------------------------------------------------------------- + +if ~exist('iscube'), error('Must specify if data is in cube-sphere tile space.'), end + +if iscube, error('Function not ready for data in cube-sphere tile space.'), end + +tc = tile_coord; +tg = tile_grid_g; + +%if strcmp(EASEv2_grid,'M09') +% N_cells = 5; +%elseif strcmp(EASEv2_grid,'M36') +% N_cells = 3; +%else +% error('input grid invalid, use only M09 or M36') +%end + +if size(tile_data,2) ~= tc.N_tile + error('N_tile incorrect, input data size should be [N_fields,N_tile].') +end + +grid_data = tile2grid(tile_data, tc, tg); + +N_f = size(tile_data,1); +N_lon = size(grid_data,1); +N_lat = size(grid_data,2); + +tile_data_filled = tile_data; + +Nshift = floor(N_cells/2); + +for ff = 1:N_f + + grid = grid_data(:,:,ff); + d_sum = zeros(size(grid)); + N_sum = zeros(size(grid)); + + for xshift = -Nshift:Nshift + for yshift = -Nshift:Nshift + + shift = circshift(grid,[xshift, yshift]); + + if xshift < 0 + shift(end+xshift+1:end,:) = NaN; + elseif xshift > 0 + shift(1:xshift, :) = NaN; + end + if yshift < 0 + shift(:,end+yshift+1:end) = NaN; + elseif yshift > 0 + shift(:,1:yshift ) = NaN; + end + + d_sum(~isnan(shift)) = d_sum(~isnan(shift)) + shift(~isnan(shift)); + N_sum(~isnan(shift)) = N_sum(~isnan(shift)) + 1; + + clear shift + end + end + + coarse = d_sum ./ N_sum; + coarse(isinf(coarse)) = NaN; + + idx_nan = find(isnan(tile_data(ff,:))); + + for i = 1:length(idx_nan) + + tile_data_filled(ff,idx_nan(i)) ... + = ... + coarse(tc.i_indg(idx_nan(i))+1, tc.j_indg(idx_nan(i))+1); + end + + clear grid d_sum smooth N_sum + +end + +% ===================== EOF ===================================== 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 new file mode 100644 index 00000000..09689d02 --- /dev/null +++ b/src/Applications/LDAS_App/util/inputs/mwRTM_params/get_L2_RTM_constants_tile_data.m @@ -0,0 +1,218 @@ + +function out_mwRTM = ... + get_L2_RTM_constants_tile_data(tile_coord,L2_file_tag,... + 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 +% with maximum coverage across Asc/Desc passes. + +% Q. Liu 18 Jul 2022 + +L2_Ascdes_all = {'_A_','_D_'}; + +out_Para = {'Albedo','Roughness'}; + +%L2_file_tag = 'L2_SM_P_E'; +%L2_version = 'R18290'; + +if strcmp(L2_file_tag(end-1:end),'_E') + resolution = 'M09'; + out_Nlon = 3856; + out_Nlat = 1624; +else + resolution = 'M36'; + out_Nlon = 964; + out_Nlat = 406; +end + +% provide a GEOSldas with proper tile information +%if strcmp(resolution,'M36') +% L4_path = '/gpfsm/dnb05/projects/p51/SMAP_Nature/SMAP_Nature_v9.x/'; +% L4_version = 'SMAP_Nature_v9.1_M36'; +% based_on_h5 = 0; +% out_Nlon = 3856/4; +% out_Nlat = 1624/4; +% ftilecoord = [L4_path,L4_version,'/output/SMAP_EASEv2_M36_GLOBAL/rc_out/', ... +% L4_version,'.ldas_tilecoord.bin']; +%else +% L4_path = '/css/smapl4/public/L4_Products/L4_SM/'; +% L4_version = 'Vv6030'; +% based_on_h5 = 1; +% out_Nlon = 3856; +% out_Nlat = 1624; +% ftilecoord = [L4_path,L4_version,'/rc_out/SPL4SM_', L4_version,'.ldas_tilecoord.bin']; + +%end + +% daily mat file path +mat_path = '/discover/nobackup/qliu/matlab/SMAP/L2L4/VOD/QC_frozen_RFI/'; + +int_precision = 'int32'; +float_precision = 'float32'; + +% read tile info for binary output +tc = tile_coord; +%tc = read_tilecoord( ftilecoord); + +% 2 parameters +for iPara = 1:length(out_Para) + + % 2 overpasses + for iAD = 1:2 + + L2_Ascdes = L2_Ascdes_all{iAD}; + L2_qc_yes = 1; + + dtstep = 10800; + + % time period for computing climatology + %start_time.year = 2015; + %start_time.month = 4; + %start_time.day = 1; + +% start_time.hour = 1; +% start_time.min = 30; +% start_time.sec = 0; +% +% end_time.year = 2022; +% end_time.month = 4; +% end_time.day = 1; +% end_time.hour = start_time.hour; +% end_time.min = start_time.min; +% end_time.sec = start_time.sec; +% +% start_time = get_dofyr_pentad(start_time); +% end_time = get_dofyr_pentad(end_time); + + % ----------------------------------------------------------------------- + % read time series of SMAP L2 fields + if end_time.month ==1 + time_tag = [num2str(start_time.year,'%4.4d'),num2str(start_time.month,'%2.2d'), ... + '_',num2str(end_time.year-1,'%4.4d'),'12']; + else + time_tag = [num2str(start_time.year,'%4.4d'),num2str(start_time.month,'%2.2d'), ... + '_',num2str(end_time.year,'%4.4d'),num2str(end_time.month-1,'%2.2d')]; + end + + % file to save long term mean tile data + fname_clim = [mat_path,'/',out_Para{iPara},'_clim_L2_',L2_version,L2_Ascdes,resolution,'tile_',time_tag,'.bin']; + + L2_para_clim_sum = zeros(out_Nlon,out_Nlat); + N_L2_clim_sum = zeros(out_Nlon,out_Nlat); + + % only do time loop if no previously saved climatology file is found + if ~exist(fname_clim,'file') + + start_time.day = 1; + start_time.hour = 0; + start_time.min = 0; + start_time.sec = 0; + + end_time.day = 1; + date_time = start_time; + + while 1 + + if (date_time.year ==end_time.year && ... + date_time.month==end_time.month && ... + date_time.day ==end_time.day ) + break + end + + dt_tag = [num2str(date_time.year,'%4.4d'), ... + num2str(date_time.month,'%2.2d'), ... + num2str(date_time.day,'%2.2d')]; + + mat_fname = [mat_path,'L2DCA_RTM_',L2_file_tag,'_',L2_version,L2_Ascdes, dt_tag,'.mat']; + + if exist(mat_fname,'file') + + disp(['loading ', mat_fname]) + if contains(fname_clim,'Albedo_') + load(mat_fname,'L2_omg') + L2_para = L2_omg; clear L2_omg + elseif contains(fname_clim,'Roughness_') + load(mat_fname,'L2_h') + L2_para = L2_h; clear L2_h + else + error(['unknown clim fname ',fname_clim]) + end + + % compute climatology + tmp = L2_para; + tmp(isnan(tmp)) = 0; + L2_para_clim_sum(:,:) = squeeze(L2_para_clim_sum(:,:)) + tmp; clear tmp + + tmp = ~isnan(L2_para); + N_L2_clim_sum(:,:) = squeeze(N_L2_clim_sum(:,:)) + tmp; clear tmp + + clear L2_para + + else + + error('daily mat file not found') + + end + + date_time = augment_date_time(86400, date_time); + + end + + L2_para_clim = L2_para_clim_sum ./N_L2_clim_sum; + L2_para_clim(N_L2_clim_sum < 1) = NaN; + + % regrid to til grid + + L2_para_tile = NaN + ones(tc.N_tile,1); + for k = 1:tc.N_tile + L2_para_tile(k,1) = L2_para_clim(tc.i_indg(k)+1, tc.j_indg(k)+1); + end + + ifp = fopen(fname_clim,'w','l'); + + + tile_data = L2_para_tile; % should be non-negative? + + tile_data(isnan(tile_data)) = 1.e15; + + fwrite( ifp, tc.N_tile*4, int_precision );% fortran_tag + fwrite( ifp, tile_data(:), float_precision ); + fwrite( ifp, tc.N_tile*4, int_precision );% fortran_tag + + clear tile_data + + fclose(ifp) + end + + end + + % combine Asc and Desc data for maximum spatial coverage + data_clim_tile = NaN + ones(tc.N_tile,2); + for iAD = 1:2 + + L2_Ascdes = L2_Ascdes_all{iAD}; + + fname = [mat_path,'/',out_Para{iPara},'_clim_L2_',L2_version,L2_Ascdes,resolution,'tile_',time_tag,'.bin']; + + disp(['read ',fname]) + ifp = fopen(fname,'r','l'); + + fortran_tag = fread( ifp, 1, int_precision ); + tmp = fread( ifp, tc.N_tile, float_precision ); + fortran_tag = fread( ifp, 1, int_precision ); + + data_clim_tile(:,iAD) = tmp; + + fclose(ifp); + end + + % fllValue = 1.e15 + data_clim_tile(data_clim_tile > 10.) = NaN; + 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); + + eval(['out_mwRTM.',out_Para{iPara},'=tile_data;']) +end diff --git a/src/Applications/LDAS_App/util/inputs/mwRTM_params/get_mwRTM_lookup.m b/src/Applications/LDAS_App/util/inputs/mwRTM_params/get_mwRTM_lookup.m new file mode 100644 index 00000000..341d05cc --- /dev/null +++ b/src/Applications/LDAS_App/util/inputs/mwRTM_params/get_mwRTM_lookup.m @@ -0,0 +1,167 @@ +function [ veg_lookup, soil_lookup ] = get_mwRTM_lookup(option); + +% Gabrielle De Lannoy, GSFC, 22Jul11 +% +% Same lookup table as in LDASsa +% +% Updated: +% GDL, 6 Sept 2011: 16 IGBP vegetation classes +% GDL, 27 Sept 2011: h=1.2 for conif forest (paper J. Grant), +% rather than h=1.6 (CMEM) +%================================================================== +% VEGETATION +%================================================================== +% +% N_vegcls = 8; +% +% ! 1 Broadleaf evergreen trees 0.1 0.1 0.12 0.14 0.10 0.30 1.0 0.0 +% ! 2 Broadleaf deciduous trees 0.1 0.1 0.12 0.14 0.10 0.2 1.0 2.0 +% ! 3 Needleleaf trees 0.1 0.1 0.12 0.12 0.08 0.1 1.75 0.0 +% ! 4 Grassland 0.1 0.1 0.05 0.11 0.09 0.15 1.0 0.0 +% ! 5 Broadleaf shrubs 0.1 0.1 0.12 0.12 0.10 0.2 1.0 1.0 +% ! 6 Dwarf trees 0.1 0.1 0.05 0.11 0.09 0.15 1.0 1.0 +% ! 7 Bare soil 0.1 0.1 0.00 0.00 0.00 0. 0.0 -1.0 +% ! 8 Desert soil 0.1 0.1 0.00 0.00 0.00 0. 0.0 -1.0 +% +% veg_lookup.rgh_hmin = [ 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 ]*0.5; +% veg_lookup.rgh_hmax = [ 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 ]*0.5; +% veg_lookup.omega = [ 0.12, 0.12, 0.12, 0.05, 0.12, 0.05, 0.00, 0.00 ]; +% veg_lookup.lewt = [ 0.30, 0.20, 0.10, 0.15, 0.20, 0.15, 0.00, 0.00 ]; +% veg_lookup.bh = [ 0.10, 0.10, 0.08, 0.09, 0.10, 0.09, 0.00, 0.00 ]; +% veg_lookup.bv = [ 0.14, 0.14, 0.12, 0.11, 0.12, 0.11, 0.00, 0.00 ]; +% veg_lookup.rgh_Nrh = [ 1.00, 1.00, 1.75, 1.00, 1.00, 1.00, 0.00, 0.00 ]; +% veg_lookup.rgh_Nrv = [ 0.00, 2.00, 0.00, 0.00, 1.00, 1.00, -1.00, -1.00 ]; +% veg_lookup.tag = {'rgh_hmin [-]', 'h_ [-]', '\omega [-]', 'lewt [-]',... +% 'b_h [-]', 'b_v [-]', 'Nr_h [-]', 'Nr_h [-]'}; + +%1 Evergreen Needleleaf Forest +%2 Evergreen Broadleaf Forest +%3 Deciduous Needleleaf Forest +%4 Deciduous Broadleaf Forest +%5 Mixed Forest +%6 Closed Shrublands +%7 Open Shrublands +%8 Woody Savannas +%9 Savannas +%10 Grasslands +%11 Permanent Wetlands +%12 Croplands +%13 Urban and Built-Up +%14 Cropland & Natural Vegetation +%15 Snow and Ice +%16 Barren or Sparsely Vegetated + + +N_vegcls = 16; +veg_lookup.tag = {'rgh_hmin [-]', 'rgh_hmax [-]', '\omega [-]', 'lewt [-]',... + 'b_h [-]', 'b_v [-]', 'Nr_h [-]', 'Nr_h [-]'}; + +if (strcmp(option,'CMEM') || strcmp(option,'Lit2')) + + %ECMWF CMEM-code + %veg_lookup.rgh_hmin = [ 1.6, 1.3, 1.6, 1, 1.3, 0.7, 0.7, 0.7, 0.5, 0.1, 0.1, 0.5, 0, 0.7, 0, 0.1 ]; + %veg_lookup.rgh_hmax = [ 1.6, 1.3, 1.6, 1, 1.3, 0.7, 0.7, 0.7, 0.5, 0.1, 0.1, 0.5, 0, 0.7, 0, 0.1 ]; + veg_lookup.rgh_hmin = [ 1.2, 1.3, 1.2, 1, 1.3, 0.7, 0.7, 0.7, 0.5, 0.1, 0.1, 0.5, 0, 0.7, 0, 0.1 ]; + veg_lookup.rgh_hmax = [ 1.2, 1.3, 1.2, 1, 1.3, 0.7, 0.7, 0.7, 0.5, 0.1, 0.1, 0.5, 0, 0.7, 0, 0.1 ]; + + veg_lookup.omega = [ 0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05 ]; + veg_lookup.lewt = [ 1, 1, 1, 1, 1, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0, 0.5, 0, 0 ]; + veg_lookup.bh = [ 0.33,0.33,0.33,0.33,0.33, 0.3, 0.3, 0.3, 0.2, 0.2, 0.2, 0.15, 0, 0.15, 0, 0 ]; + veg_lookup.bv = [ 0.33,0.33,0.33,0.33,0.33, 0.3, 0.3, 0.3, 0.2, 0.2, 0.2, 0.15, 0, 0.15, 0, 0 ]; + veg_lookup.rgh_Nrh = [ 1, 1.75,1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0 ]; + veg_lookup.rgh_Nrv = [ 0, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, -1, 1, -1, 1,-1 ]; + veg_lookup.st_scale = [ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ]; + +elseif (strcmp(option,'CMEM_SMOS') || strcmp(option,'Lit3')) + + %ECMWF SMOS monitoring-setup + veg_lookup.rgh_hmin = [ 1.66, 1.66, 1.66, 1.66, 1.66, 1.66, 1.66, 1.66, 1.66, 1.66, 1.66, 1.66, 1.66, 1.66, 1.66, 1.66 ]; + veg_lookup.rgh_hmax = [ 1.66, 1.66, 1.66, 1.66, 1.66, 1.66, 1.66, 1.66, 1.66, 1.66, 1.66, 1.66, 1.66, 1.66, 1.66, 1.66 ]; + + veg_lookup.omega = [ 0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05 ]; + veg_lookup.lewt = [ 1, 1, 1, 1, 1, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0, 0.5, 0, 0 ]; + veg_lookup.bh = [ 0.33,0.33,0.33,0.33,0.33, 0.3, 0.3, 0.3, 0.2, 0.2, 0.2, 0.15,0, 0.15,0, 0 ]; + veg_lookup.bv = [ 0.33,0.33,0.33,0.33,0.33, 0.3, 0.3, 0.3, 0.2, 0.2, 0.2, 0.15,0, 0.15,0, 0 ]; + veg_lookup.rgh_Nrh = [ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ]; + veg_lookup.rgh_Nrv = [ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ]; + veg_lookup.st_scale = [ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ]; + +elseif (strcmp(option,'SMAP') || strcmp(option,'Lit1')) + + %Peggy O'Neill's SMAP ATBD, Table 2 + veg_lookup.rgh_hmin = [ 0.16, 0.16, 0.16, 0.16, 0.16, 0.11, 0.11, 0.125, 0.156, 0.156, 0.156, 0.108, 0, 0.13, 0, 0.15 ]; + veg_lookup.rgh_hmax = [ 0.16, 0.16, 0.16, 0.16, 0.16, 0.11, 0.11, 0.125, 0.156, 0.156, 0.156, 0.108, 0, 0.13, 0, 0.15 ]; + veg_lookup.omega = [ 0.12, 0.12, 0.12, 0.12, 0.08, 0.05, 0.05, 0.12, 0.08, 0.05, 0.05, 0.05, 0, 0.065,0, 0 ]; + veg_lookup.lewt = [ 0.3, 0.3, 0.2, 0.2, 0.2, 0.2, 0.2, 0.15, 0.15, 0.15, 0.15, 0.15, 0, 0.15, 0, 0 ]; + veg_lookup.bh = [ 0.1, 0.1, 0.12, 0.12, 0.12, 0.11, 0.11, 0.11, 0.11, 0.1, 0.1, 0.11, 0, 0.11, 0, 0 ]; + veg_lookup.bv = [ 0.1, 0.1, 0.12, 0.12, 0.12, 0.11, 0.11, 0.11, 0.11, 0.1, 0.1, 0.11, 0, 0.11, 0, 0 ]; + veg_lookup.rgh_Nrh = [ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ]; + veg_lookup.rgh_Nrv = [ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ]; + veg_lookup.st_scale = [ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ]; + +elseif (strcmp(option,'Lit4')) + + %ECMWF CMEM-code; same as Lit2, but with new lewt values to go with new LAI values + %veg_lookup.rgh_hmin = [ 1.6, 1.3, 1.6, 1, 1.3, 0.7, 0.7, 0.7, 0.5, 0.1, 0.1, 0.5, 0, 0.7, 0, 0.1 ]; + %veg_lookup.rgh_hmax = [ 1.6, 1.3, 1.6, 1, 1.3, 0.7, 0.7, 0.7, 0.5, 0.1, 0.1, 0.5, 0, 0.7, 0, 0.1 ]; + veg_lookup.rgh_hmin = [ 1.2, 1.3, 1.2, 1, 1.3, 0.7, 0.7, 0.7, 0.5, 0.1, 0.1, 0.5, 0, 0.7, 0, 0.1 ]; + veg_lookup.rgh_hmax = [ 1.2, 1.3, 1.2, 1, 1.3, 0.7, 0.7, 0.7, 0.5, 0.1, 0.1, 0.5, 0, 0.7, 0, 0.1 ]; + + veg_lookup.omega = [ 0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05 ]; + veg_lookup.lewt = [ 1.9, 1.5, 1.5, 1.5, 1.7, 0.9, 0.8, 0.9, 0.8, 0.9, 0.8, 0.8, 0, 0.9, 0, 0 ]; + %veg_lookup.lewt = [ 1, 1, 1, 1, 1, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0, 0.5, 0, 0 ]; + veg_lookup.bh = [ 0.33,0.33,0.33,0.33,0.33, 0.3, 0.3, 0.3, 0.2, 0.2, 0.2, 0.15, 0, 0.15, 0, 0 ]; + veg_lookup.bv = [ 0.33,0.33,0.33,0.33,0.33, 0.3, 0.3, 0.3, 0.2, 0.2, 0.2, 0.15, 0, 0.15, 0, 0 ]; + veg_lookup.rgh_Nrh = [ 1, 1.75,1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0 ]; + veg_lookup.rgh_Nrv = [ 0, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, -1, 1, -1, 1,-1 ]; + veg_lookup.st_scale = [ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ]; + + +elseif (strcmp(option,'Cal3c')) + + load('/hydro/gdelanno/proc_analysis/initial_lookup_3c_rgh_hmin_rgh_hmax_rgh_Nrh_rgh_Nrv_lewt_omega_bh_bv_st_scale.mat'); + +%was Cal2c before +elseif (strcmp(option,'CalD2')) + + load('/hydro/gdelanno/proc_analysis/initial_lookup_D2_rgh_hmin_rgh_hmax_rgh_Nrh_rgh_Nrv_lewt_omega_bh_bv_st_scale.mat'); + +else + + error(['ERROR: Option ',option,' does not exist']) + +end + +%================================================================== +% SOIL +%================================================================== +%1 Sand +%2 Loamy Sand +%3 Sandy Loam +%4 Loam (F) ==> Silt Loam +%5 Silt Loam (F) ==> Silt +%6 Silt (F) ==> Loam +%7 Sandy Clay Loam +%8 Clay Loam (F) ==> Silty Clay Loam +%9 Silty Clay Loam (F) ==> Clay Loam +%10 Sandy Clay Loam +%11 Silty Clay Loam +%12 Clay + + +N_soilcls = 12; + +soil_lookup.sf = [.92, .82, .58, .17, .10, .43, .58, .10, .32, .52, .06, .22]; +soil_lookup.cf = [.03, .06, .10, .13, .05, .18, .27, .34, .34, .42, .47, .58]; +soil_lookup.fc = [0.132, 0.156, 0.196, 0.27 , 0.361, 0.25 , 0.253, 0.334, 0.301, 0.288, 0.363, 0.353]; +soil_lookup.wp = [0.033, 0.051, 0.086, 0.169, 0.045, 0.148, 0.156, 0.249, 0.211, 0.199, 0.286, 0.276]; +soil_lookup.poros = [0.373, 0.386, 0.419, 0.476, 0.471, 0.437, 0.412, 0.478, 0.447, 0.415, 0.478, 0.45]; +soil_lookup.b = [3.3, 3.8, 4.34, 5.25, 3.63, 5.96, 7.32, 8.41, 8.34, 9.7, 10.78, 12.93]; +soil_lookup.PsiS = [-0.05, -0.07, -0.16, -0.65, -0.84, -0.24, -0.12, -0.63, -0.28, -0.12, -0.58, -0.27]; +soil_lookup.Ksat = [2.45E-05, 1.75E-05, 8.35E-06, 2.36E-06, 1.10E-06, 4.66E-06, 6.31E-06, 1.44E-06, 2.72E-06, 4.25E-06, 1.02E-06, 1.33E-06]; +soil_lookup.tag = {'Sand [-]', 'Clay [-]', 'Field Capacity [m3/m3]', ... + 'Wilting Point [m3/m3]', 'Porosity [m3/m3]', 'b [ ]', 'Psisat [m]', 'Ksat [m/s]'}; + +end + +%==========================EOF===================================== diff --git a/src/Applications/LDAS_App/util/inputs/mwRTM_params/get_mwRTM_vegcls_based.m b/src/Applications/LDAS_App/util/inputs/mwRTM_params/get_mwRTM_vegcls_based.m new file mode 100644 index 00000000..a36ab3f3 --- /dev/null +++ b/src/Applications/LDAS_App/util/inputs/mwRTM_params/get_mwRTM_vegcls_based.m @@ -0,0 +1,129 @@ +function [mwRTMparam] = get_mwRTM_vegcls_based( tile_coord, dominant_M36vegcls,resolution) + +% Helper function to get RTM parameter values based on the vegcls lookup table +% before writing in the mwRTM_params.nc4 file. The function is called in +% Write_mwRTM_nc4_file.m + +% Q. Liu 20 Jul 2022 + + +% Vegetation-based RTM-parameters +lookup_option = 'Lit4'; + +%---------------------------------------------------------------------------- + +% Vegetation classes +% read in M36 & M09 vegcls for both M36 and M09 mwRTM +vegcls_fname = '/discover/nobackup/qliu/gdelanno_RTM/SMAP_aux/EASEV2/dominantIGBP36km.406x964.uint8'; + +ifp = fopen( vegcls_fname, 'r', 'b' ); +veg_clsM36 = fread( ifp, [406 964] ,'uint8'); +fclose(ifp); + +vegcls_fname = '/discover/nobackup/qliu/gdelanno_RTM/SMAP_aux/EASEV2/dominantIGBP09km.1624x3856.uint8'; + +ifp = fopen( vegcls_fname, 'r', 'b' ); +veg_clsM09 = fread( ifp, [1624 3856] ,'uint8'); +fclose(ifp); + +% list of parameters can be based on vegcls lookup table +fn_mwRTMparam = { ... + 'vegcls', ... + 'rgh_Nrh', 'rgh_Nrv', ... + 'rgh_polmix','omega', 'bh', 'bv', 'lewt'}; + +for i=1:length(fn_mwRTMparam) + + mwRTMparam.(fn_mwRTMparam{i}) = [NaN+zeros(length(tile_coord.N_tile),1)]; + +end + +[ veg_lookup, tmp ] = get_mwRTM_lookup(lookup_option); +clear tmp + +%==================================================================== + +%order of tiles depend on LDASsa-output; tile_coord.txt +%output from this code should *always* be sorted as [1:N_tile], that is - +%even if re-ordered output from an LDASsa-run is used as input, the +%resulting mwRTMparam.xxxx(:) is always monotonically increasingly sorted + +[row_M09,col_M09] = smapeasev2_latlon2ind(tile_coord.com_lat,tile_coord.com_lon,'M09'); +row_M09 = row_M09 +1; +col_M09 = col_M09 +1; + +[row_M36,col_M36] = smapeasev2_latlon2ind(tile_coord.com_lat,tile_coord.com_lon,'M36'); +row_M36 = row_M36 + 1; +col_M36 = col_M36 + 1; + +for tile = 1 : tile_coord.N_tile + + %since m10_p3, the tile-order has changed, so tile<>tile_id ! + tileid = tile_coord.tile_id(tile); + + if contains(resolution,'_M09') && ~dominant_M36vegcls + + jj = row_M09(tile); + ii = col_M09(tile); + i_vegcls = int32(veg_clsM09(jj,ii)); + + else + + % First, rely on M36 database + jj = row_M36(tile); + ii = col_M36(tile); + i_vegcls = int32(veg_clsM36(jj,ii)); + + % Next, fill missing vegcls with the dominant vegcls of the + % M09 grids + + if (i_vegcls<=0 || i_vegcls>200 || isnan(i_vegcls)) + + if contains(resolution,'M09') + tmp_ind = find(row_M36 == jj & col_M36 == ii); + for t = 1:length(tmp_ind) + i_vegcls(t) = int32(veg_clsM09(row_M09(tmp_ind(t)),col_M09(tmp_ind(t)))); + end + else + t=0; + for j1 = ((jj-1)*4+1):(jj*4) + for i1 = ((ii-1)*4+1):(ii*4) + t = t+1; + i_vegcls(t) = int32(veg_clsM09(j1,i1)); + end + end + end + + ind_veg = find(~(i_vegcls<=0 | i_vegcls>200 | isnan(i_vegcls))); + if ~isempty(ind_veg) + i_vegcls = i_vegcls(ind_veg); + end + i_vegcls = mode(i_vegcls); + + end + end + %====for valid vegetation classes in IGBP:==== + if (i_vegcls > 0 ) + + mwRTMparam.vegcls(tileid,1) = i_vegcls; %IGBP + + mwRTMparam.rgh_Nrh(tileid,1) = veg_lookup.rgh_Nrh(i_vegcls); + mwRTMparam.rgh_Nrv(tileid,1) = veg_lookup.rgh_Nrv(i_vegcls); + + mwRTMparam.rgh_polmix(tileid,1) = 0; + mwRTMparam.omega(tileid,1) = veg_lookup.omega(i_vegcls); + mwRTMparam.bh(tileid,1) = veg_lookup.bh(i_vegcls); + mwRTMparam.bv(tileid,1) = veg_lookup.bv(i_vegcls); + mwRTMparam.lewt(tileid,1) = veg_lookup.lewt(i_vegcls); + + else + + for i = 1:length(fn_mwRTMparam) + mwRTMparam.(fn_mwRTMparam{i})(tileid,1) = NaN; + end + + end + +end + +%===============================EOF====================================== diff --git a/src/Applications/LDAS_App/mwrtm_bin2nc4.F90 b/src/Applications/LDAS_App/util/inputs/mwRTM_params/mwrtm_bin2nc4.F90 similarity index 96% rename from src/Applications/LDAS_App/mwrtm_bin2nc4.F90 rename to src/Applications/LDAS_App/util/inputs/mwRTM_params/mwrtm_bin2nc4.F90 index f2696258..114f24b7 100644 --- a/src/Applications/LDAS_App/mwrtm_bin2nc4.F90 +++ b/src/Applications/LDAS_App/util/inputs/mwRTM_params/mwrtm_bin2nc4.F90 @@ -12,12 +12,10 @@ PROGRAM mwrtm_bin2nc4 implicit none INCLUDE 'netcdf.inc' - integer :: i,k, n, iargc, NTILES + integer :: i,k, n, command_argument_count, NTILES integer :: NCFOutID, Vid, STATUS, CellID, TimID, nVars - character*256 :: Usage="mwrtm_bin2nc4.x mwrtm_BINFILE mwRTM_param.nc4" - character*256 :: BINFILE, MWRTMNC4, arg(3) - character*100 :: MYNAME - character*100 :: Str_Atr + character(512):: Usage="mwrtm_bin2nc4.x mwrtm_BINFILE mwRTM_param.nc4" + character(512):: BINFILE, MWRTMNC4, arg(3) real, allocatable, dimension (:) :: var integer, allocatable,dimension (:) :: NT character(len=:),allocatable :: shnms(:) @@ -48,7 +46,7 @@ PROGRAM mwrtm_bin2nc4 'MWRTM_LEWT '] ! processing command line agruments - I = iargc() + I = command_argument_count() if( I /=2 ) then print *, "Wrong Number of arguments: ", i @@ -57,14 +55,12 @@ PROGRAM mwrtm_bin2nc4 end if do n=1,I - call getarg(n,arg(n)) + call get_command_argument(n,arg(n)) enddo - call getenv ("MYNAME" ,MYNAME ) read(arg(1),'(a)') BINFILE read(arg(2),'(a)') MWRTMNC4 - print *,MYNAME print *,trim(BINFILE) print *,trim(MWRTMNC4) @@ -212,7 +208,7 @@ FUNCTION getAttribute (SHORT_NAME, LNAME, UNT) result (str_atr) character(*), intent(in) :: SHORT_NAME integer, intent (in), optional :: LNAME, UNT - character(100) :: str_atr, LONG_NAME, UNITS + character(128) :: str_atr, LONG_NAME, UNITS SELECT case (trim(SHORT_NAME)) case('MWRTM_VEGCLS'); LONG_NAME = 'L-band RTM model: Vegetation class. Type is Unsigned32'; UNITS = '1' diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_L4_Tb_scale_SMAP.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_L4_Tb_scale_SMAP.m new file mode 100644 index 00000000..62f54caa --- /dev/null +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/Run_get_L4_Tb_scale_SMAP.m @@ -0,0 +1,178 @@ +% Calculate scaling files for Tb-DA based on SMAP Tb +% +% GDL, 11 Sep 2012 +% QLiu, Dec 2016 +%===================================================================== + +clear + +% add path to matlab functions in src/Applications/LDAS_App/util/shared/matlab/ +addpath('../../shared/matlab/'); + +%====== + +run_months = [1:12 1:4]; %loop through 1:4 again to get complete pentads + +%exp_path = '/smap1/qliu/output/SMAP_Nature_v8.3/NRv8.3_innov_RTMv4/'; +%exp_run = {'SMAP_NRv8.3inv_RTMv4'}; +%exp_path = '/hydro/qliu/WORK/output/L4_SM_SMAP/'; +%exp_run = {'SPL4SM_OL4001'}; +%exp_path = '/smap1/qliu/output/SMAP_Nature_v8.3/NRv8.3_innov/S1/'; +%exp_run = {'SMAP_NRv8.3_innov'}; +exp_path = '/home/qliu/smap/SMAP_Nature/'; +exp_run = {'SPL4SM_OL7000'}; +domain = 'SMAP_EASEv2_M09_GLOBAL'; + +%Start and end year for each month +start_year = [repmat(2016,1,3) repmat(2015,1,9) repmat(2016,1,3) repmat(2015,1,1)]; %corresp to [1:12 1 2] +end_year = [repmat(2022,1,3) repmat(2021,1,9) repmat(2022,1,3) repmat(2021,1,1)]; %runs till end of run_months for end_year + +orbit = [ 2]; %1=A, 2=D !DO *NOT* USE ASC AND DESC TOGETHER! +pol = [ 1 2 ]; %1=H, 2=V +inc_ang = [ 40.0 ]; + +prefix_out = 'L4SM_OL7000_SMAPL1CR17000_zscore_stats_'; + +dt_assim = 3*60*60; % [seconds] land analysis time step, + % same as LANDASSIM_DT in GEOSldas) +t0_assim = 0; % [seconds] land analysis "reference" time (offset from 0z), + % same as LANDASSIM_T0 in GEOSldas (except for units), + % typically 0 in offline runs and 1.5*60*60 in LADAS + +%====== + +obs_param_fname = [exp_path, '/', exp_run{1}, '/output/', domain, '/rc_out/', ... + '/Y2015/M04/',exp_run{1}, '.ldas_obsparam.20150401_0000z.txt']; + +var_name = {'Tb'}; + +% added to identify SMOS or SMAP from runs that include both +descr = 'SMAP_L1C' ; % 'SMOS_fit' + +%====== +if (length(orbit) > 1) + error('ONLY pick one orbit!') +end + +if (orbit(1) == 1) int_Asc = 1; end %Asc +if (orbit(1) == 2) int_Asc = 0; end %Desc + +%====== +%TO GO FROM SMOS TO SMAP ONLY!!! +%int_Asc = abs(int_Asc - 1); +%====== + +%Spatial sampling +hscale = 0.0; % degrees lat/lon + +% Temporal sampling window(days), current hard coded and need to be divisive by 5 and be an odd number +w_days = 75; + +Ndata_min = 20; + +%To limit M09 tiles to administering M36 tiles only (smaller files), +%provide convert_grid +if isempty(strfind(prefix_out,'M09')) + convert_grid='EASEv2_M36'; +end + +if (mod(w_days,10) == 0) + disp('w_days should be 5, 15, 25, 35, ...') + error('Need an odd number of pentads |xxxxx|xxXxx|xxxxx|') +end +if (mod(w_days, 5) > 0) + error('Aiming at pentad files') +end + +% ------------------------------------------------------------------------ + +[N_obs_param, obs_param ] = read_obsparam(obs_param_fname); + +species =[]; + +for oo=1:length(orbit) + for pp=1:length(pol) + for aa=1:length(inc_ang) + + add_species = obs_param(strcmp(var_name,{obs_param.varname}) & ... + orbit(oo) == [obs_param.orbit] & ... + inc_ang(aa) == [obs_param.ang] & ... + pol(pp) == [obs_param.pol] & ... + ~cellfun(@isempty, strfind({obs_param.descr},descr))).species; + + species = union(species,add_species); + + end + end +end + +species +% ------------------ + +for n=1:length(exp_run) + + if (exist('convert_grid','var')) + + if exist('time_of_day_in_hours','var') + + + for j=1:length(time_of_day_in_hours) + + for k=1:length(run_months) + + get_model_and_obs_clim_stats( var_name, ... + run_months{k}, exp_path, exp_run{n}, domain, ... + start_year, end_year, ... + dt_assim, t0_assim, species, obs_param, ... + hscale, inc_ang, int_Asc, w_days, Ndata_min, prefix_out,... + convert_grid, time_of_day_in_hours(j) ); + + end + + end + + else + + get_model_and_obs_clim_stats( var_name, ... + run_months, exp_path, exp_run{n}, domain, start_year, end_year, ... + dt_assim, t0_assim, species, obs_param, ... + hscale, inc_ang, int_Asc, w_days, Ndata_min, prefix_out,... + convert_grid ); + + end + else + + if exist('time_of_day_in_hours','var') + + + for j=1:length(time_of_day_in_hours) + + for k=1:length(run_months) + + get_model_and_obs_clim_stats( var_name, ... + run_months{k}, exp_path, exp_run{n}, domain, ... + start_year, end_year, ... + dt_assim, t0_assim, species, obs_param, ... + hscale, inc_ang, int_Asc, w_days, Ndata_min, prefix_out,... + time_of_day_in_hours(j) ); + + end + + end + + else + + get_model_and_obs_clim_stats( var_name, ... + run_months, exp_path, exp_run{n}, domain, start_year, end_year, ... + dt_assim, t0_assim, species, obs_param, ... + hscale, inc_ang, int_Asc, w_days, Ndata_min, prefix_out); + + end + + end +end + + +% ============= EOF ==================================================== + + diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/dist_km2deg.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/dist_km2deg.m new file mode 100644 index 00000000..939c2e31 --- /dev/null +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/dist_km2deg.m @@ -0,0 +1,26 @@ +%========================================================================= + +function [dist_x_deg, dist_y_deg] = dist_km2deg( dist_km, lat ) + + MAPL_PI = 3.14159265358979323846; + MAPL_RADIUS = 6371.0E3; + + % distance between latitudes is equal (always full meridional radius circle) + % assumuming the Earth is a perfect ball. + % NOTE: MAPL_radius (Earth radius) is in [m] and dist_km is in [km] + + dist_y_deg = dist_km .* (180./MAPL_PI) ./ (MAPL_RADIUS./1000.); + + % distance between longitudes decreases towards the poles + % (radius of parallel circles decreases) + % NOTE: cos() needs argument in [rad], lat is in [deg] (-90:90) + + dist_x_deg = dist_y_deg ./ cos( MAPL_PI./180. .* lat ); + + if (any(dist_x_deg<0. | dist_y_deg<0.)) + disp( 'encountered negative distance' ); + end + +end + +%========================================================================= diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_ij_ind_from_latlon.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_ij_ind_from_latlon.m new file mode 100644 index 00000000..dc9becfa --- /dev/null +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_ij_ind_from_latlon.m @@ -0,0 +1,24 @@ +%========================================================================= + +function [i_ind,j_ind] = get_ij_ind_from_latlon( tile_grid, lat, lon) + + if (strcmp(tile_grid.gridtype,'EASEv2_M36')) + %row, col + [j_indg,i_indg] = ... + smapeasev2_latlon2ind(lat,lon,'M36'); + elseif (strcmp(tile_grid.gridtype,'EASEv2_M09')) + %row, col + [j_indg,i_indg] = ... + smapeasev2_latlon2ind(lat,lon,'M09'); + else + error('not ready for this grid'); + end + + % convert to index into array defined by tile_grid_d + + i_ind = i_indg - tile_grid.i_offg - (tile_grid.ind_base - 1); + j_ind = j_indg - tile_grid.j_offg - (tile_grid.ind_base - 1); + +end + +%========================================================================= \ No newline at end of file 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 new file mode 100644 index 00000000..52e55f76 --- /dev/null +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_model_and_obs_clim_stats.m @@ -0,0 +1,787 @@ + +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, ... + convert_grid , time_of_day_in_hours ) + +% +% get_model_and_obs_clim_stats.m +% +% Compute mean, stdv of model and observations from tile-based +% "innov" files for a selection of species. +% +% 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. +% +% Stats output file in a similar format as the SMOS-data files +% +% ==HEADER== +% N_tiles N_angles +% angles +% +% ==DATA== +% +% %%%% tile ID --> for all tiles (1:N_tiles, not sorted by tile_id!) +% lat +% lon +% +% [for angles] +% mean_obs_H +% std_obs_H +% mean_mod_H +% std_mod_H +% N_data_H +% +% mean_obs_V +% std_obs_V +% mean_mod_V +% std_mod_V +% N_data_V +% +% H_obs +% H_mod +% V_obs +% V_mod +% [end angles] +% +% GDL, 10 sept 2012 +% +% GDL, aug 2013: added 'convert_grid' (= EASEv2_M36, EASE_M36, ...) +% to project the Obs (always M36 for SMOS) and Fcst to M36 +% M09 obs are administered by tiles (0) that could be anywhere +% around the center of the observed pixel (M36) +% ----------- +% | X X X X | +% | X O O X | +% | X O O X | +% | X X X X | +% ----------- +% GDL, jan 2014: the above issue that "any" M09 tile in the center (0) +% could potentially administer the M36 obs is not true +% anymore with later LDASsa-tags. +% => no need to pass on 'convert_grid' for tags later than +% the summer of 2013 +% reichle, qliu, 13 July 2022: +% "convert_grid" is still needed to limit the number of tiles +% in the scaling parameter file. With "convert_grid" turned on, +% only the M09 tile to the northeast of the M36 center point +% is kept in the scaling parameter file, consistent with the +% "tmp_shift_lat" and "tmp_shift_lon" operations in the SMOS +% and SMAP Fortran readers. (It is not clear if this matlab +% function works properly if there is no M09 [land] tile +% immediately to the northeast of the M36 center point. In +% such a case, the Fortran reader assigns the nearest M09 +% land tile as the tile that administers the obs.) +% Presumably, scaling parameters for all M09 tiles could be kept +% if they are stored in (compressed) nc4 format. In this case, +% the NaN values for the scaling parameters of 15 out of each 16 +% M09 tiles can be compressed to almost nothing. +% +% ------------------------------------------------------------------- +% begin user-defined inputs +% ------------------------------------------------------------------- + +% obs species to be processed (see ens_upd_inputs.nml for a list) +% +% (only observation species that represent observations of the same +% model prognostic or diagnostic can be processed together!) + +nodata = -9999; +nodata_tol = 1e-4; + +% minimum number of data points to include in window statistics + +% N_data_min = w_days/10.; % initial screening on minimum # points in a +% % window to calculate a mean or stdv +% include a final decision about "good" stats later, when merging years + +% no-data-value for points that don't have good statistics + +no_data_stats = -9999.; + +disp('ASSUMING EASEv2 M36 observations'); + +if ~isempty(strfind(domain,'M36')) && isempty(strfind(obs_param(species(1)).descr, '_E')) + tol = 1E-3; +else + tol = 2; +end + +% output specs + +overwrite = 1; + +Nf = 5; %5 fields per polarization +N_out_fields = 2*Nf+4; %14; + +write_ind_latlon = 'latlon_id'; %'latlon'; + +N_angle = length(inc_angle); +N_pol = 2; + +tmp_shift_lon = 0.01; +tmp_shift_lat = 0.005; + +store_all_M09inM36 = 0; +print_each_DOY = 0; + +% ------------------------------------------------------------------- +% end user-defined inputs +% ------------------------------------------------------------------- + +% assemble input and output paths + +%inpath = [ exp_path, '/output/', exp_run, '/', domain ]; +inpath = [ exp_path, '/', exp_run, '/output/', domain ]; + +outpath = [ inpath, '/stats/z_score_clim/' ]; + +% create outpath if it doesn't exist + +if exist(outpath)~=2 + eval(['!mkdir -p ', outpath]); +end + +% ------------------------------------------------------------- + +% assemble output file name + +ind = find(start_year == min(start_year)); +mi_m = min(run_months(ind)); +ind = find(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 +if ma_m > 1 + D(2) = sum(days_in_month( 2014, [1:ma_m])); +else + 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'); +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_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'; +else + Orbit_tag = '_D'; %'_Desc'; +end + +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_p = [fname_out_base_p, '_', num2str(time_of_day_in_hours,'%2.2d'), 'z']; + +end + +% ------------------------------------------------------------- + +% load catchment coordinates + +fname = [inpath, '/rc_out/', exp_run, '.ldas_tilecoord.bin']; +fnameg= [inpath, '/rc_out/', exp_run, '.ldas_tilegrids.bin']; + +[ tile_coord ] = read_tilecoord( fname ); +[ tile_grid ] = read_tilegrids( fnameg ); + +N_tile = length(tile_coord.tile_id); + +% ------------------------------------------------------------- + +% determine tiles to whose statistics the current obs will contribute to + +disp('pre-computing index for regional averaging') + +central_lat = tile_coord.com_lat; +central_lon = tile_coord.com_lon; +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] = smapeasev2_latlon2ind(central_lat,central_lon,gridid); + [central_lat,central_lon] = smapeasev2_ind2latlon(central_row,central_col,gridid); + elseif (~isempty(strfind(convert_grid, 'M36')) && ~isempty(strfind(convert_grid, 'EASEv1'))) + 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 + + %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; + +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); + + +if hscale>0 + + 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 + +else + + hscale_ind = num2cell(ia); + +end + + +% initialize output statistics +% Note: Rolf suggests to have all species as one dimension, rather than +% 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); + +data_out = NaN+zeros(N_out_fields,N_tile_obs,N_angle); + +% ------------------------------------------------------------- + +% 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); + + % 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 + + 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') ]; + + 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 (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 + + 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'); + 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 + 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. + 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') + end + + %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])']); + + 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 + + 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 + + % 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_windowM09_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'); + + 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 + + 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 + + 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 +end % month + + +% ==================== 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 new file mode 100644 index 00000000..ed1e9b8a --- /dev/null +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_tile_num_for_obs.m @@ -0,0 +1,123 @@ +%========================================================================= + +function [tile_num] = get_tile_num_for_obs(tile_coord, tile_grid,... + N_tile_in_cell_ij, tile_num_in_cell_ij, ... + option, this_FOV, lat, lon) + + N_dat = length(lat); + +% find one tile for each obs that "administers" the obs + +% get "max_dist" in deg lat/lon from field-of-view (FOV) +% +% "max_dist" = Maximum distance allowed between obs lat/lon and tile com_lat/com_lon +% when searching for a tile to which the obs will be assigned. +% +% NOTE: Subroutine get_tile_num_from_latlon() computes distances in Minkowski norm. + + if ~isempty(strfind(option,'FOV_in_deg')) + + max_dist_y = this_FOV; + max_dist_x(1:N_dat) = this_FOV; + + elseif ~isempty(strfind(option,'FOV_in_km')) + + % convert from [km] (FOV) to [deg] (max_dist_*) + + [max_dist_x, max_dist_y] = dist_km2deg( this_FOV, lat); + + else + + error('unknown FOV_option') + + end + + if (max_dist_y<0. || any(max_dist_x<0.)) + error('encountered negative max_dist'); + end + + tile_num = zeros(N_dat,1); + + for n=1:N_dat + + % make sure lat/lon is *inside* tile_grid (to within "max_dist"), + % otherwise do nothing + + if ( tile_grid.ll_lat <= (lat(n)+max_dist_y ) &&... + tile_grid.ll_lon <= (lon(n)+max_dist_x(n)) &&... + (lat(n)-max_dist_y ) <= tile_grid.ur_lat &&... + (lon(n)-max_dist_x(n)) <= tile_grid.ur_lon ) + + % min_dist = distance betw lat/lon in question and center-of-mass of + % matching tile + + min_dist_x = 1.e10; % initialize + min_dist_y = 1.e10; % initialize + + % determine grid cell that contains lat/lon + + [i_ind,j_ind] = get_ij_ind_from_latlon( tile_grid, lat(n), lon(n)); + + % make sure that i/j_ind is still within bounds + % (works in conjunction with if statement above re. ll/ur_lat/lon) + + i_ind = min( max(i_ind, 1), tile_grid.N_lon ); + j_ind = min( max(j_ind, 1), tile_grid.N_lat ); + + % map from i_ind, j_ind to tile_num + + if ( ~isempty(strfind(tile_grid.gridtype, 'EASE_M')) || ... + ~isempty(strfind(tile_grid.gridtype, 'EASEv2_M')) ) + + % ASSUMPTION: tiles match EASE or EASEv2 grid cells exactly + % (unless "outside" the domain, eg. water surface) + + if (N_tile_in_cell_ij(i_ind,j_ind)==1) + + tile_num(n)=tile_num_in_cell_ij(i_ind,j_ind,1); + + min_dist_x = abs(lon(n) - tile_coord.com_lon(tile_num(n))); + min_dist_y = abs(lat(n) - tile_coord.com_lat(tile_num(n))); + + elseif (N_tile_in_cell_ij(i_ind,j_ind)==0) + + % Do nothing. If given EASE or EASEv2 grid cell is not land, + % tile_num will not change from its initialized value. + + else + + error( 'something wrong for EASE grid'); + + end + + else + error('not ready'); + end + + if (tile_num(n)>0) + + outside_bbox = ( ... + lon(n) < tile_coord.min_lon(tile_num(n)) || ... + lon(n) > tile_coord.max_lon(tile_num(n)) || ... + lat(n) < tile_coord.min_lat(tile_num(n)) || ... + lat(n) > tile_coord.max_lat(tile_num(n)) ); + + too_far_away = ( ... + min_dist_x > max_dist_x(n) || ... + min_dist_y > max_dist_y ); + + % keep tile_num unless obs is outside the bounding box *and* too far away + + if (outside_bbox && too_far_away) + tile_num(n) = NaN; + end + + end + + end + + end + +end + +%========================================================================= diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_tile_num_in_cell_ij.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_tile_num_in_cell_ij.m new file mode 100644 index 00000000..51090891 --- /dev/null +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/get_tile_num_in_cell_ij.m @@ -0,0 +1,42 @@ +%========================================================================= + +function [N_tile_in_cell_ij, tile_num_in_cell_ij] = ... + get_tile_num_in_cell_ij(tile_coord, tile_grid) + + % Initialize + + max_tile_in_cell = 10; %for EASE grids, this is really just 1 + + tile_num_in_cell_ij = NaN+zeros(tile_grid.N_lon,tile_grid.N_lat,max_tile_in_cell); + + % adjust for 0-based indexing (eg., EASE grids) + + off_i = tile_grid.i_offg + (tile_grid.ind_base - 1); + off_j = tile_grid.j_offg + (tile_grid.ind_base - 1); + + % (re-)initialize + + N_tile_in_cell_ij = zeros(tile_grid.N_lon,tile_grid.N_lat); + + for n=1:tile_coord.N_tile + + i = tile_coord.i_indg(n) - off_i; + j = tile_coord.j_indg(n) - off_j; + + N_tile_in_cell_ij(i,j) = N_tile_in_cell_ij(i,j) + 1; + + k = N_tile_in_cell_ij(i,j); + + tile_num_in_cell_ij(i,j,k) = n; + + end + + max_N = max(max(N_tile_in_cell_ij)); + + disp(['Maximum number of tiles in tile def grid cell = ', num2str(max_N)]); + + tile_num_in_cell_ij = tile_num_in_cell_ij(:,:,1:max_N); + +end + +%========================================================================= \ No newline at end of file diff --git a/src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_seqbin_file.m b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_seqbin_file.m new file mode 100644 index 00000000..14153721 --- /dev/null +++ b/src/Applications/LDAS_App/util/inputs/obs_scaling_params/write_seqbin_file.m @@ -0,0 +1,305 @@ +function [] = write_seqbin_file(fname, colind, rowind,... + av_angle_bin, data, asc_flag, ... + version, ... + start_time, end_time, overwrite, N_out_fields, ... + write_ind_latlon, data_product,... + tile_id) %last argument is optional + +% write "fortran sequential" tile tavg files (identical to LDASsa output) +% +% optional input: +% +% overwrite = 0 -- do NOT overwrite existing files, print warning +% message, return +% overwrite = 1 -- overwrite existing files, print warning message +% +% De Lannoy, 4 Oct 2010 +% De Lannoy, 26 Sep 2012: added optional argument of tile_id +% used to write scaling files, with ''latlon_id''. +% De Lannoy, 25 Oct 2012: added the processor version number, +% inserted after the Asc_flag. +% ------------------------------------------------------------------ + +%N_out_fields % 1 - Col-index, 0-based; + % 2 - Row-index, 0-based; + %OR (for nearest neighbout) + % 1 - Lon; + % 2 - Lat; + +%N_out_fields % 1 - Tbh; + % 2 - Tbv; + + % 3 - heterogeneity index Tbh + % 4 - heterogeneity index Tbv + + % 5 - # SMOS pixels in EASE grid pixel Tbh + % 6 - # SMOS pixels in EASE grid pixel Tbv + + % 7 - RA Tbh + % 8 - RA Tbv + + %=> repeated for T3 and T4 (9-16) + + %OR FOR SMUDP2: + + % 1 - SM + % 2 - ST + % 3 - opacity + % 4 - Tbh; + % 5 - Tbv; + + % 6 - SM RSTD + % 7 - ST RSTD + % 8 - opac RSTD + + % 9 - stdv in SM (grid cell averaging) + % 10 - # small SMOS pixels inside 1 EASE grid cell; + + % 11 - omega; scattering albedo + % 12 - diff_albedos (om_H-om_V) + % 13 - max_roughness + % 14 - RSTD omega + % 15 - RSTD diff_omega + % 16 - RSTD max_roughness + +int_precision = 'int32'; % precision of fortran tag +float_precision = 'float32'; % precision of data in input file + +% 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 + +% open file + +ifp = fopen( fname, 'w', 'b' ); + +% determine number of grid cells ; further check dimensions + +N_grid = size(data,2); +N_angle= 1; + +if (length(size(data)) == 3) + N_angle = size(data,3); + data_org = data; + if (N_angle ~= length(av_angle_bin)) + disp(['ERROR in N_angle']) + return + end +end + +if (strcmp(write_ind_latlon,'latlon_id') && nargin == 14) + + if( size(tile_id,1) ~= N_grid ) + error('tile_id dimensions ??') + end + if ( size(tile_id,2) > 1) + disp(['# subgridcells per gridcell: ',num2str(size(tile_id,2))]); + end + +end + + +% write all records + +fortran_tag = 2*4; % length of each record in bytes + +count = fwrite( ifp, fortran_tag, int_precision ); +count = fwrite( ifp, [asc_flag version], int_precision ); +count = fwrite( ifp, fortran_tag, int_precision ); + +fortran_tag = 5*4; % length of each record in bytes + +count = fwrite( ifp, fortran_tag, int_precision ); +count = fwrite( ifp, [start_time.year, start_time.month, ... + start_time.day, start_time.hour, start_time.min], int_precision ); +count = fwrite( ifp, fortran_tag, int_precision ); + +count = fwrite( ifp, fortran_tag, int_precision ); +count = fwrite( ifp, [end_time.year, end_time.month, ... + end_time.day, end_time.hour, end_time.min], int_precision ); +count = fwrite( ifp, fortran_tag, int_precision ); + + +if (~(strcmp(data_product,'scaling') && strcmp(write_ind_latlon,'latlon_id') && nargin == 14)) + fortran_tag = 2*4; % length of each record in bytes + count = fwrite( ifp, fortran_tag, int_precision ); + count = fwrite( ifp, [N_grid N_angle], int_precision ); + count = fwrite( ifp, fortran_tag, int_precision ); +else + fortran_tag = 3*4; % length of each record in bytes + count = fwrite( ifp, fortran_tag, int_precision ); + count = fwrite( ifp, [N_grid N_angle size(tile_id,2)], int_precision ); + count = fwrite( ifp, fortran_tag, int_precision ); +end + +if (N_grid >= 1) + + fortran_tag = N_angle*4; %angles for which the output fields will be repeated below + + count = fwrite( ifp, fortran_tag, int_precision ); + count = fwrite( ifp, squeeze(av_angle_bin(:)), float_precision ); + count = fwrite( ifp, fortran_tag, int_precision ); + + fortran_tag = N_grid*4; % length of each record in bytes + + if (strcmp(write_ind_latlon,'ind') ) + + count = fwrite( ifp, fortran_tag, int_precision ); + count = fwrite( ifp, round(colind(:)), int_precision ); + count = fwrite( ifp, fortran_tag, int_precision ); + + count = fwrite( ifp, fortran_tag, int_precision ); + count = fwrite( ifp, round(rowind(:)), int_precision ); + count = fwrite( ifp, fortran_tag, int_precision ); + + elseif (strcmp(write_ind_latlon,'latlon') ) + + count = fwrite( ifp, fortran_tag, int_precision ); + count = fwrite( ifp, colind(:), float_precision ); + count = fwrite( ifp, fortran_tag, int_precision ); + + count = fwrite( ifp, fortran_tag, int_precision ); + count = fwrite( ifp, rowind(:), float_precision ); + count = fwrite( ifp, fortran_tag, int_precision ); + + elseif (strcmp(write_ind_latlon,'latlon_id') && nargin == 14) + + count = fwrite( ifp, fortran_tag, int_precision ); + count = fwrite( ifp, colind(:), float_precision ); + count = fwrite( ifp, fortran_tag, int_precision ); + + count = fwrite( ifp, fortran_tag, int_precision ); + count = fwrite( ifp, rowind(:), float_precision ); + count = fwrite( ifp, fortran_tag, int_precision ); + + for i=1:size(tile_id,2) + count = fwrite( ifp, fortran_tag, int_precision ); + count = fwrite( ifp, round(tile_id(:,i)), int_precision ); + count = fwrite( ifp, fortran_tag, int_precision ); + end + + else + + error('output-arguments do not line up') + + end + + fortran_tag = N_grid*4; + + for i=1:N_out_fields + + for j=1:N_angle + + if (N_angle > 1) + data = squeeze(data_org(:,:,j)); + end + + count = fwrite( ifp, fortran_tag, int_precision ); + count = fwrite( ifp, data(i,:), float_precision ); + count = fwrite( ifp, fortran_tag, int_precision ); + + + end + + end + +else + + fortran_tag = N_angle*4; + + count = fwrite( ifp, fortran_tag, int_precision ); + count = fwrite( ifp, squeeze(av_angle_bin(:)), float_precision ); + count = fwrite( ifp, fortran_tag, int_precision ); + + fortran_tag = 4; % length of each record in bytes + + if (strcmp(write_ind_latlon,'ind') ) + + count = fwrite( ifp, fortran_tag, int_precision ); + count = fwrite( ifp, 0, int_precision ); + count = fwrite( ifp, fortran_tag, int_precision ); + + count = fwrite( ifp, fortran_tag, int_precision ); + count = fwrite( ifp, 0, int_precision ); + count = fwrite( ifp, fortran_tag, int_precision ); + + elseif (strcmp(write_ind_latlon,'latlon') ) + + count = fwrite( ifp, fortran_tag, int_precision ); + count = fwrite( ifp, 0.0, float_precision ); + count = fwrite( ifp, fortran_tag, int_precision ); + + count = fwrite( ifp, fortran_tag, int_precision ); + count = fwrite( ifp, 0.0, float_precision ); + count = fwrite( ifp, fortran_tag, int_precision ); + + elseif (strcmp(write_ind_latlon,'latlon_id') && nargin == 14) + + count = fwrite( ifp, fortran_tag, int_precision ); + count = fwrite( ifp, 0.0, float_precision ); + count = fwrite( ifp, fortran_tag, int_precision ); + + count = fwrite( ifp, fortran_tag, int_precision ); + count = fwrite( ifp, 0.0, float_precision ); + count = fwrite( ifp, fortran_tag, int_precision ); + + count = fwrite( ifp, fortran_tag, int_precision ); + count = fwrite( ifp, 0, int_precision ); + count = fwrite( ifp, fortran_tag, int_precision ); + + else + + error('output-arguments do not line up') + + end + + for i=1:N_out_fields + + for j=1:N_angle + + count = fwrite( ifp, fortran_tag, int_precision ); + count = fwrite( ifp, -999.0, float_precision ); + count = fwrite( ifp, fortran_tag, int_precision ); + + end + + end + +end + +fclose(ifp); + + diff --git a/src/Applications/LDAS_App/util/postproc/climatology/README b/src/Applications/LDAS_App/util/postproc/climatology/README new file mode 100644 index 00000000..0f2e3bde --- /dev/null +++ b/src/Applications/LDAS_App/util/postproc/climatology/README @@ -0,0 +1,24 @@ + +The scripts in this directory are used to generate climatology data from GEOSldas output. + +L4_SM Application: +------------------ +Post-process GEOSldas output into the soil moisture climatology nc4 file needed by the +SMAP L4SM ops system's "prcntl.py" script, which generates the soil moisture percentile +output ("sm_rootzone_pctl", "sm_profile_pctl") in the L4SM "Geophysical" (gph) file +collection. +The soil moisture climatology file needed by "prcntl.py" is created in two steps: + +1) Execute "Run_L4_sm_clim_stats.m" to create pentad binary climatology files + (73 for "sm_rootzone" + 73 for "sm_profile"). + +2) Execute "Write_L4_sm_clim_stat_bin2nc4.m" to create the single L4 input netcdf file + (*after* all binary pentad files are done). + +These jobs are memory intensive and typically take hours to run. On Discover, it is +necessary to use designated compute nodes. Step 1 may need to be run separately for +root-zone and profile soil moisture. + +Q. Liu, 29 Aug 2022 + +=========================== EOF ======================================================== \ No newline at end of file diff --git a/src/Applications/LDAS_App/util/postproc/climatology/Run_L4_sm_clim_stats.m b/src/Applications/LDAS_App/util/postproc/climatology/Run_L4_sm_clim_stats.m new file mode 100644 index 00000000..2534672d --- /dev/null +++ b/src/Applications/LDAS_App/util/postproc/climatology/Run_L4_sm_clim_stats.m @@ -0,0 +1,82 @@ +% Compute statistics of root-zone and profile soil moisture, which are needed to compute +% L4SM soil moisture percentile output. + +clear +addpath ../../shared/matlab +%------------------------------------------------------------------------- + +% experiment information +exp_path = {'/home/qliu/smap/SMAP_Nature/SMAP_Nature_v10/'}; +exp_run = {'SMAP_Nature_v10.0'}; + +domain = 'SMAP_EASEv2_M09_GLOBAL'; + +file_tag = {'tavg3_1d_lnr_Nt'}; + +% climatological period start and end year +start_year(1:12) = [repmat(2001,12,1)]; %start year for each month,the short start year was due to CPCU data inconsistance +end_year(1:12) = [repmat(2021,12,1)]; %end year for each month + +% only use 1 variable if running into memory issues +field_names = {'sm_rootzone','sm_profile'}; + +% convert soil moisture variables in "field_names" (if any) into +% wetness units +% (needed for L4SM because L4 ops script "prcntl.py" expects clim in +% wetness units, but clim is computed from Nature Run, which only +% outputs volumetric soil moisture) +out_wetness = 1; + +% linked to the output resolution +start_HHSS.hour = 1; +start_HHSS.min = 30; +start_HHSS.sec = 0; + +out_freq = 'pentad'; % pentad or monthly for now + +% now define the smoothing window based on the number of years of the clim period +if end_year(1) - start_year(1) > 9 + w_out_freq = 5; % smoothing window (number of pentads or months) +else + w_out_freq = 11; +end + +% minimum number of data requirement is based on number of years and window size +N_data_min = 2 * w_out_freq *(end_year(1)-start_year(1)+1); %per out_freq + +% ------------------ + +for n=1:length(exp_run) + + for ff = 1:length(field_names) + + if exist('time_of_day_in_hours','var') + + for j=1:length(time_of_day_in_hours) + + get_model_clim_stats( field_names{ff}, ... + exp_path{n}, exp_run{n}, domain, start_year, end_year, ... + out_freq, w_out_freq, file_tag{n}, ... + out_wetness, ... + N_data_min, time_of_day_in_hours(j) ) + + end + + else + + get_model_clim_stats( field_names{ff}, ... + exp_path{n}, exp_run{n}, domain, ... + start_year, end_year, start_HHSS, ... + out_freq, w_out_freq, file_tag{n}, ... + out_wetness, ... + N_data_min ) + + end + + end +end + + +% ============= EOF ==================================================== + + diff --git a/src/Applications/LDAS_App/util/postproc/climatology/Write_L4_sm_clim_stat_bin2nc4.m b/src/Applications/LDAS_App/util/postproc/climatology/Write_L4_sm_clim_stat_bin2nc4.m new file mode 100644 index 00000000..f476a5a4 --- /dev/null +++ b/src/Applications/LDAS_App/util/postproc/climatology/Write_L4_sm_clim_stat_bin2nc4.m @@ -0,0 +1,208 @@ +%========================================================================= +% script to convert SMAPL4 SM climatology statistic binary output to nc4 +% file. +% +% The tile_ids are in the same order as in ldas_tilecoord.txt +% +% Q. Liu - Jun 20, 2016 +% G. De Lannoy - Apr 21, 2015 +%========================================================================= + +clear all + +write_GEOSldas_tileorder = 0; + +time_stamp = '2001_p1_2021_p73'; +specs_tag = '_W_5p_Nmin_210'; + +bin_fpath = '/home/qliu/smap/SMAP_Nature/SMAP_Nature_v10/SMAP_Nature_v10.0/output/SMAP_EASEv2_M09_GLOBAL/stats/cli/'; + +file_out = ['L4SM_NRv10.0_cli_',time_stamp,specs_tag,'_sm_wetness_EASEv2_M09.nc4']; + +if write_GEOSldas_tileorder + file_out = ['GEOSldas_',file_out]; +end + +fname_out = [bin_fpath, file_out]; + +% read an arbitrary file to get header info +fname = [bin_fpath, 'cli_',time_stamp,specs_tag,'_sm_rootzone_wet_p06.bin']; + +N_stat = 99 + 5; % 99 percentile values + 5 stats (mean, stdv,min, max, N_data) + +[data_tmp, tile_id, lon, lat] = ... + read_seqbin_clim_pctl_file(fname, 1, N_stat, 'latlon_id','cli'); + +N_tile = length(tile_id); + +if write_GEOSldas_tileorder + + [tile_id_out, tile_idx] = sort(tile_id,'ascend'); + lon_out = lon(tile_idx); + lat_out = lat(tile_idx); +else + tile_id_out = tile_id; + lon_out = lon; + lat_out = lat; +end + +clear data_tmp + +netcdf.setDefaultFormat('FORMAT_NETCDF4'); +fout_id = netcdf.create(fname_out, 'NETCDF4'); + +if fout_id < 0, error(['Creating ' fname_out 'failed']); end + +% Setup global attributes + +NC_GLOBAL = netcdf.getConstant('GLOBAL'); + +netcdf.putAtt(fout_id, NC_GLOBAL, 'Title', ['SMAP L4 SM pentad clim. ',time_stamp,' statistics on EASEv2 M09']); + +netcdf.putAtt(fout_id, NC_GLOBAL, 'Filename', file_out); +netcdf.putAtt(fout_id, NC_GLOBAL, 'Institution', 'NASA GMAO'); +netcdf.putAtt(fout_id, NC_GLOBAL, 'History', ['File written by matlab-r2021a on ',datestr(now)]); +netcdf.putAtt(fout_id, NC_GLOBAL, 'Contact', 'NASA/GMAO Rolf Reichle'); +netcdf.putAtt(fout_id, NC_GLOBAL, 'Comments', 'NETCDF-4'); + +% Define dimensions: + +dimid1 = netcdf.defDim(fout_id,'tile',length(tile_id_out)); +dimid2 = netcdf.defDim(fout_id,'percentile_wetness' , 99); +dimid3 = netcdf.defDim(fout_id,'pentad', netcdf.getConstant('UNLIMITED')); + +% Define global variables: + +varid = netcdf.defVar(fout_id,'tile_id','int',dimid1); +netcdf.putAtt(fout_id,varid,'standard_name','tile_id'); +netcdf.putAtt(fout_id,varid,'long_name','tile_id'); +netcdf.putAtt(fout_id,varid,'units','-'); +netcdf.putVar(fout_id,varid,tile_id_out); + +varid = netcdf.defVar(fout_id,'lon','double',dimid1); +netcdf.putAtt(fout_id,varid,'standard_name','longitude'); +netcdf.putAtt(fout_id,varid,'long_name','longitude'); +netcdf.putAtt(fout_id,varid,'units','degrees_east'); +netcdf.putVar(fout_id,varid,lon_out); + +varid = netcdf.defVar(fout_id,'lat','double',dimid1); +netcdf.putAtt(fout_id,varid,'standard_name','latitude'); +netcdf.putAtt(fout_id,varid,'long_name','latitude'); +netcdf.putAtt(fout_id,varid,'units','degrees_north'); +netcdf.putVar(fout_id,varid,lat_out); + +% Synchronize global +netcdf.sync(fout_id) + +% Define groups and variables in each group + +vars = {'mean', 'stdv', 'min', 'max', 'N_data', 'percentile_UL'}; + +da_group_id(1) = netcdf.defGrp(fout_id, 'rootzone_wetness_cli_stat'); + +da_group_id(2) = netcdf.defGrp(fout_id, 'profile_wetness_cli_stat'); + +fillValue = single(1.e15); + +DeflateLevel = 5; + +% Put data into the data group: + +% Insert data: + +for i=1:length(da_group_id) %loop through groups + + start_time = 0; + + for k = 1:73 % loop through pentad + + clear data + + if i==1 + + fname = [bin_fpath, 'cli_',time_stamp,specs_tag,'_sm_rootzone_wet_p', ... + num2str(k, '%2.2d'), '.bin']; + + else + + fname = [bin_fpath, 'cli_',time_stamp,specs_tag,'_sm_profile_wet_p', ... + num2str(k, '%2.2d'), '.bin']; + + end + + [data_tmp, tile_id_old, lon_old, lat_old] = ... + read_seqbin_clim_pctl_file(fname, 1, 104, 'latlon_id','cli'); + + clear tile_id_old lon_old lat_old + + if write_GEOSldas_tileorder + data = data_tmp(tile_idx,:); + else + data = data_tmp; + end + + clear data_tmp + + for iv = [1 3 4 6:size(data,2)] + data(data(:,iv)>1, iv) = 1.; + end + + + data(data<-9998) = fillValue; + data(isnan(data)) = fillValue; + + + for iv = 1:4 % loop through variables + + if k == 1 + + varid(iv) = netcdf.defVar(da_group_id(i),vars{iv},'float',[dimid1,dimid3]); + netcdf.putAtt(da_group_id(i),varid(iv),'name', vars{iv}); + netcdf.putAtt(da_group_id(i),varid(iv),'units','wetness'); + netcdf.defVarFill(da_group_id(i),varid(iv),false,fillValue); + netcdf.defVarDeflate(da_group_id(i),varid(iv),true,true, DeflateLevel); + + end + + netcdf.putVar(da_group_id(i),varid(iv),[0,start_time], [N_tile,1], squeeze(data(:,iv))); + + end + + if k == 1 + + varid(5) = netcdf.defVar(da_group_id(i),vars{5},'int',[dimid1,dimid3]); + netcdf.putAtt(da_group_id(i),varid(5),'name', vars{5}); + netcdf.putAtt(da_group_id(i),varid(5),'units','-'); + netcdf.defVarDeflate(da_group_id(i),varid(5),true,true, DeflateLevel); + + end + + netcdf.putVar(da_group_id(i),varid(5),[0,start_time], [N_tile,1],squeeze(data(:,5))); + + if k==1 + + varid(6) = netcdf.defVar(da_group_id(i),vars{6},'float',[dimid2,dimid1,dimid3]); + netcdf.putAtt(da_group_id(i),varid(6),'name', vars{6}); + netcdf.putAtt(da_group_id(i),varid(6),'units','wetness'); + netcdf.defVarFill(da_group_id(i),varid(6),false,fillValue); + netcdf.defVarDeflate(da_group_id(i),varid(6),true,true, DeflateLevel); + + end + + netcdf.putVar(da_group_id(i),varid(6),[0,0,start_time], [99,N_tile, 1],squeeze(data(:,6:104)')); + + start_time = start_time +1; + end + + netcdf.sync(da_group_id(i)) + + +end + +% Synchronize: +netcdf.close(fout_id) + +%====================================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 new file mode 100644 index 00000000..fef20cc8 --- /dev/null +++ b/src/Applications/LDAS_App/util/postproc/climatology/get_model_clim_stats.m @@ -0,0 +1,433 @@ +function [] = get_model_clim_stats( fieldname, ... + exp_path, exp_run, domain, ... + start_year, end_year, start_HHSS, ... + out_freq, w_out_freq, file_tag, ... + out_wetness, ... + N_data_min, time_of_day_in_hours ) + +%======================================================================= +% +% Compute mean, stdv and CDF-stats of simulated fields from +% - tile-based "nc4" files +% - or gridded "h5" files +% for a selection of fieldname. +% +% The main purpose of this function is to aggregate the information +% from the "cat" files so that the climatology statistics can +% be used for the computation of percentiles. +% +% +% Need to fix those file_tag-s... at some point, we had to calculate cli-files +% based on all different file types... ugly +% +% +% One file with statistics is generated for every pentad or month. +% +% fieldname: (single) model field to be processed +% start_year: start year for each month (12 entries!) +% end_year: end year for each month (12 entries!) +% start_HHSS: hour, min, sec of first file (depends on output resolution) +% out_freq: 'monthly' or 'pentad' climatology files +% w_out_freq: number of months or pentads used in the temporal smoothing +% N_data_min: minimum number of data points to calculate a good stat +% +% 'cli'-file has a similar format as the SMOS-data files and +% observation scaling files for assimilation. +% +% ==HEADER== +% N_tiles N_fields N_stat +% fields +% +% ==DATA== +% +% %%%% tile ID --> for all tiles (1:N_tiles, not sorted by tile_id!) +% lat +% lon +% +% [for fields] +% mean +% std +% min +% max +% N_data +% CDF_parameter_1 OR UL_1st_percentile +% CDF_parameter_2 UL_2st_percentile +% CDF_parameter_... UL_... +% CDF_parameter_N UL_99st_percentile +% [end fields] +% +% GDL, feb 2014 +% +% ------------------------------------------------------------------- +% begin user-defined inputs +% ------------------------------------------------------------------- + +nodata = -9999; +nodata_tol = 1e-4; + +ens_tag = 'ens0000'; + +dtstep = 3*60*60; % hardwired 3-hourly if x-hourly output is given + +% when reading h5-data + +datagroup_name = '/Geophysical_Data/'; + +% output specs + +overwrite = 1; + +percentiles = [1:99]; + +N_stat = 5; %mean, stdv, min, max, N_data +N_CDF = length(percentiles); + +N_stat_CDF = N_stat+N_CDF; + +write_ind_latlon = 'latlon_id'; %'latlon'; + +% ------------------------------------------------------------------- +% end user-defined inputs +% ------------------------------------------------------------------- + +N_fields = 1; + +fieldno = 1; + +field_tag = ['_',fieldname]; + +% ------------------------------------------------------------------- + +% determine number of entries in smoothing time window + +if (std(end_year-start_year) ~= 0) + error('same number of years should contribute to each month') +end + +if strcmp(out_freq,'pentad') + n_days = 5; +elseif strcmp(out_freq,'monthly') + n_days = 365/12.0; % could adjust this and work w/ min_days=28, max_days=31 +end + +disp(['smoothing window is ',num2str(n_days*w_out_freq),' days']); + +n_time_count = round(w_out_freq * n_days * (max(end_year-start_year)+1) *... + ((24*60*60)./dtstep)); + +% auxiliary start-end_time to get 1 year climatology: +% - loop over all days in any non-leap year (365 days) +% - make sure to loop into the next year to cover all climatology pentads +% or months w/ the complete smoothing window + +start_time = start_HHSS; +start_time.year = 2014; +start_time.month = 1; +start_time.day = 1; + +start_time = get_dofyr_pentad(start_time); %ini correct pentad + +end_time = augment_date_time((365 + w_out_freq * n_days)*24*60*60, ... + start_time); + +% effective period used in climatology calculation + +start_time_true = start_time; +start_time_true.year = min(start_year); +tmp = find(start_year==min(start_year)); +start_time_true.month = tmp(1); +start_time_true = get_dofyr_pentad( start_time_true ); + +end_time_true = end_time; +end_time_true.year = max(end_year); +tmp = find(start_year==max(start_year)); +end_time_true.month = tmp(end); +end_time_true.day = days_in_month( end_time_true.year, end_time_true.month); +end_time_true = get_dofyr_pentad( end_time_true ); + +% assemble input and output paths + +inpath = [ exp_path, '/', exp_run, '/output/', domain ]; +outpath = [ inpath, '/stats/cli/' ]; + +% create outpath if it doesn't exist + +if ~exist(outpath,'dir') + eval(['!mkdir -p ', outpath]); +end + +% ------------------------------------------------------------- + +% load catchment coordinates + +fname = [inpath, '/rc_out/', exp_run, '.ldas_tilecoord.bin']; + +[ tile_coord ] = read_tilecoord( fname ); + +N_tile = tile_coord.N_tile; + +lat_out = tile_coord.com_lat; +lon_out = tile_coord.com_lon; +tile_coord_tile_id = tile_coord.tile_id; + +% determine if conversion of soil moisture variables to wetness is +% needed; if yes, get porosity from cat_param file + +convert_to_wetness = 0; + +if contains(field_tag,'sm_') & ~contains(field_tag,'wet') & out_wetness + + field_tag = [field_tag,'_wet']; + convert_to_wetness = 1; + + catfname = [exp_path,'/',exp_run,'/output/',domain,'/rc_out/','/Y2015/M01/',... + exp_run,'.ldas_catparam.','20150101_0000','z.bin']; + + cat_param = read_catparam( catfname, N_tile ); + + poros = cat_param.poros; clear cat_param + +end + +% ------------------------------------------------------------- + +% assemble output file name + +if strcmp(out_freq,'pentad') + + fname_out_base = [ outpath, '/', 'cli_', ... + num2str(start_time_true.year), '_p', ... + num2str(start_time_true.pentad),'_', ... + num2str(end_time_true.year), '_p', ... + num2str(end_time_true.pentad), '_', ... + 'W_', num2str(w_out_freq),'p_', ... + 'Nmin_', num2str(round(N_data_min),'%d'), ... + field_tag]; + +else strcmp(out_freq,'monthly') + + fname_out_base = [ outpath, '/', 'cli_', ... + num2str(start_time_true.year), '_M', ... + num2str(start_time_true.month),'_', ... + num2str(end_time_true.year), '_M', ... + num2str(end_time_true.month), '_', ... + 'W_', num2str(w_out_freq),'M_', ... + 'Nmin_', num2str(round(N_data_min),'%d'), ... + field_tag]; + +end + +if exist( 'time_of_day_in_hours', 'var') + + fname_out_base = [fname_out_base, '_', num2str(time_of_day_in_hours,'%2.2d'), 'z']; + +end + +% ------------------------------------------------------------- + +% initialize output statistics + +hist_data = zeros(N_tile,N_fields,n_time_count); + +time_count = 0; + +data_out = NaN+zeros(N_fields,N_tile,N_stat_CDF); + +% ------------------------------------------------------------- + +disp('climatology calculation') + +time_new = start_time; + +while 1 + + if (time_new.year == end_time.year &... + time_new.month == end_time.month &... + time_new.day == end_time.day &... + time_new.hour == end_time.hour &... + time_new.min == end_time.min &... + time_new.sec == end_time.sec ) + break + end + + % augment date_time + + time_old = time_new; + pentad_old = time_new.pentad; + month_old = time_new.month; + + time_new = augment_date_time(dtstep, time_old); + pentad_new = time_new.pentad; + month_new = time_new.month; + + % check if diurnal stats are needed + + if exist('time_of_day_in_hours','var') + tmp_hour = time_of_day_in_hours; + else + tmp_hour = time_old.hour; % all hours of day will be included + end + + if time_old.hour==tmp_hour + + minute = time_old.min; % floor( (seconds_in_day-hour*3600)/60 ); + seconds = time_old.sec; % seconds_in_day-hour*3600-minute*60; + + if (seconds~=0) + error('something is wrong! (seconds~=0)') + end + + for year = start_year(time_old.month):end_year(time_old.month) + + time_count = time_count+1; + + YYYYMMDD = [ num2str(year, '%4.4d'), ... + num2str(time_old.month, '%2.2d'), ... + num2str(time_old.day, '%2.2d') ]; + + HHMM = [ num2str(time_old.hour, '%2.2d'), ... + num2str(time_old.min, '%2.2d') ]; + + fname = [ inpath, ... + '/cat/', ens_tag, ... + '/Y', num2str(year, '%4.4d'), ... + '/M', num2str(time_old.month,'%2.2d'), ... + '/', exp_run, ... + '.', file_tag, '.', YYYYMMDD, '.nc4' ]; + + if ~exist(fname,'file') + + % try again with "_[HHMM]z" inserted into file name + + fname = [ inpath, ... + '/cat/', ens_tag, ... + '/Y', num2str(year, '%4.4d'), ... + '/M', num2str(time_old.month,'%2.2d'), ... + '/', exp_run, ... + '.', file_tag, '.', YYYYMMDD, '_', HHMM, 'z.nc4' ]; + + end + + disp(['reading ',fieldname,' from ',fname]) + data_tmp = ncread(fname, fieldname); + + if size(data_tmp,2) == 8 % hard-wired 3-hourly time step?? + tile_data_tmp = data_tmp(:,ceil(time_old.hour/3.)); clear data_tmp + elseif size(data_tmp,2) == 1 + tile_data_tmp = data_tmp; clear data_tmp + else + error(['data size is incorrect from ', fname]) + end + + for s=1:N_fields + + if ~convert_to_wetness + tile_data_tmp_1D = tile_data_tmp(:); + else + tile_data_tmp_1D = tile_data_tmp(:)./poros(:); + end + + good_data = find(~(abs(tile_data_tmp_1D - nodata) < nodata_tol)); + + tile_data_tmp_1D = tile_data_tmp_1D(good_data); + + %Keep a record of time series + + total_bin_good_ind = (time_count-1).*(N_fields*N_tile) + ... + (s-1)*N_tile+good_data'; + + hist_data(total_bin_good_ind) = tile_data_tmp_1D; + + end + + end % loop through years + + end % time_of_day_in_hours + + % check if output needs to be written + + if (time_count == n_time_count ) + + % write output + + for s=1:N_fields + + %edges = edge_min(s):edge_dx(s):edge_max(s); + + for tile=1:N_tile + + 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 + + % determine the CDF-parameters, or the edges for each + % percentile + + perc = round(percentiles./100*data_out(s,tile,5)); + + tmp = sort(tmp); + + data_out(s,tile,N_stat+1:N_stat+N_CDF) = tmp(perc); + + end + + end + + bad_ind = find(data_out(:,:,5) 1) + + if (strcmp(file_type,'cli')) + + if (strcmp(read_ind_latlon,'ind')) + + fortran_tag = fread( ifp, 1, int_precision ); + col_ind = fread( ifp, [1 N_grid], int_precision ); + fortran_tag = fread( ifp, 1, int_precision ); + + fortran_tag = fread( ifp, 1, int_precision ); + row_ind = fread( ifp, [1 N_grid], int_precision ); + fortran_tag = fread( ifp, 1, int_precision ); + + elseif (strcmp(read_ind_latlon,'latlon')) + + fortran_tag = fread( ifp, 1, int_precision ); + col_ind = fread( ifp, [1 N_grid], float_precision ); + fortran_tag = fread( ifp, 1, int_precision ); + + fortran_tag = fread( ifp, 1, int_precision ); + row_ind = fread( ifp, [1 N_grid], float_precision ); + fortran_tag = fread( ifp, 1, int_precision ); + + elseif (strcmp(read_ind_latlon,'latlon_id') ) + + fortran_tag = fread( ifp, 1, int_precision ); + col_ind = fread( ifp, [1 N_grid], float_precision ); + fortran_tag = fread( ifp, 1, int_precision ); + + fortran_tag = fread( ifp, 1, int_precision ); + row_ind = fread( ifp, [1 N_grid], float_precision ); + fortran_tag = fread( ifp, 1, int_precision ); + + fortran_tag = fread( ifp, 1, int_precision ); + tile_id = fread( ifp, [1 N_grid], int_precision ); + fortran_tag = fread( ifp, 1, int_precision ); + + else + + error('not sure how the file looks like, based on the combination of input-specs') + + end + + end + + data = NaN*ones(N_field,N_grid,N_stat); + + for j=1:N_stat + + for i=1:N_field + + if (j == 5 && strcmp(file_type,'cli')) + + fortran_tag = fread( ifp, 1, int_precision ); + tmp_data = fread( ifp, [1 N_grid], int_precision ); + fortran_tag = fread( ifp, 1, int_precision ); + + else + + fortran_tag = fread( ifp, 1, int_precision ); + tmp_data = fread( ifp, [1 N_grid], float_precision ); + fortran_tag = fread( ifp, 1, int_precision ); + + end + + data(i,1:N_grid,j) = tmp_data(1:N_grid); + + end + + end + + data = squeeze(data); + +else + + data = NaN*ones(N_field,1); + col_ind = NaN; + row_ind = NaN; + fieldno = NaN; + +end + +fclose(ifp); + +% ======= EOF ========================================================== diff --git a/src/Applications/LDAS_App/util/postproc/climatology/write_seqbin_clim_pctl_file.m b/src/Applications/LDAS_App/util/postproc/climatology/write_seqbin_clim_pctl_file.m new file mode 100644 index 00000000..22f35698 --- /dev/null +++ b/src/Applications/LDAS_App/util/postproc/climatology/write_seqbin_clim_pctl_file.m @@ -0,0 +1,255 @@ +function [] = write_seqbin_clim_pctl_file(fname, colind, rowind,... + data, fieldno, N_stat,... + overwrite, ... + write_ind_latlon, file_type, tile_id) %last argument is optional + +% write "fortran binary sequential" tile files with climatology info +% or percentile output +% +% optional input: +% +% overwrite = 0 -- do NOT overwrite existing files, print warning +% message, return +% overwrite = 1 -- overwrite existing files, print warning message +% +% De Lannoy, 27 Feb 2014: adopted from write_seqbin_file.m +% ------------------------------------------------------------------ + +nodata_val = -9999.0; + +int_precision = 'int32'; % precision of fortran tag +float_precision = 'float32'; % precision of data in input file + +% check dimensions + +if size(data,1)~=length(fieldno) + + error('ERROR: size of data incompatible with N_fields') + +end + +N_grid = size(data,2); + +N_field = length(fieldno); + +if (length(size(data)) == 3) + + N_stat_tmp = size(data,3); + + data_org = data; + + if (N_stat_tmp ~= N_stat) + disp(['ERROR in N_stat ',num2str(N_stat_tmp),' vs ',num2str(N_stat)]) + return + end + +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 + +% open file + +ifp = fopen( fname, 'w', 'b' ); + +% determine number of grid cells ; further check dimensions + + +if (strcmp(write_ind_latlon,'latlon_id') && exist('tile_id','var')) + + if ( size(tile_id,1) ~= N_grid ) + error('tile_id dimensions ??') + end + if ( size(tile_id,2) > 1) + disp(['# subgridcells per gridcell: ',num2str(size(tile_id,2))]); + end + +end + + +% write all records + +if (strcmp(file_type,'cli')) + + % dimensions + + fortran_tag = 2*4; % length of each record in bytes + + count = fwrite( ifp, fortran_tag, int_precision ); + count = fwrite( ifp, [N_grid N_field], int_precision ); + count = fwrite( ifp, fortran_tag, int_precision ); + +end + +if (N_grid >= 1) + + if (strcmp(file_type,'cli') ) + + fortran_tag = N_grid*4; % length of each record in bytes + + if (strcmp(write_ind_latlon,'ind') ) + + count = fwrite( ifp, fortran_tag, int_precision ); + count = fwrite( ifp, round(colind(:)), int_precision ); + count = fwrite( ifp, fortran_tag, int_precision ); + + count = fwrite( ifp, fortran_tag, int_precision ); + count = fwrite( ifp, round(rowind(:)), int_precision ); + count = fwrite( ifp, fortran_tag, int_precision ); + + elseif (strcmp(write_ind_latlon,'latlon') ) + + count = fwrite( ifp, fortran_tag, int_precision ); + count = fwrite( ifp, colind(:), float_precision ); + count = fwrite( ifp, fortran_tag, int_precision ); + + count = fwrite( ifp, fortran_tag, int_precision ); + count = fwrite( ifp, rowind(:), float_precision ); + count = fwrite( ifp, fortran_tag, int_precision ); + + elseif (strcmp(write_ind_latlon,'latlon_id') ) + + count = fwrite( ifp, fortran_tag, int_precision ); + count = fwrite( ifp, colind(:), float_precision ); + count = fwrite( ifp, fortran_tag, int_precision ); + + count = fwrite( ifp, fortran_tag, int_precision ); + count = fwrite( ifp, rowind(:), float_precision ); + count = fwrite( ifp, fortran_tag, int_precision ); + + for i=1:size(tile_id,2) + count = fwrite( ifp, fortran_tag, int_precision ); + count = fwrite( ifp, round(tile_id(:,i)), int_precision ); + count = fwrite( ifp, fortran_tag, int_precision ); + end + + else + + error('output-arguments do not line up') + + end + + end + + fortran_tag = N_grid*4; + + for j=1:N_stat + + for i=1:N_field + + if (N_stat > 1) + data = squeeze(data_org(:,:,j)); + end + + if ( j == 5 && strcmp(file_type,'cli')) + count = fwrite( ifp, fortran_tag, int_precision ); + count = fwrite( ifp, round(data(i,:)), int_precision ); + count = fwrite( ifp, fortran_tag, int_precision ); + else + count = fwrite( ifp, fortran_tag, int_precision ); + count = fwrite( ifp, data(i,:), float_precision ); + count = fwrite( ifp, fortran_tag, int_precision ); + end + + end + + end + +else + + if (strcmp(file_type,'cli')) + + fortran_tag = 4; % length of each record in bytes + + if (strcmp(write_ind_latlon,'ind') ) + + count = fwrite( ifp, fortran_tag, int_precision ); + count = fwrite( ifp, 0, int_precision ); + count = fwrite( ifp, fortran_tag, int_precision ); + + count = fwrite( ifp, fortran_tag, int_precision ); + count = fwrite( ifp, 0, int_precision ); + count = fwrite( ifp, fortran_tag, int_precision ); + + elseif (strcmp(write_ind_latlon,'latlon') ) + + count = fwrite( ifp, fortran_tag, int_precision ); + count = fwrite( ifp, 0.0, float_precision ); + count = fwrite( ifp, fortran_tag, int_precision ); + + count = fwrite( ifp, fortran_tag, int_precision ); + count = fwrite( ifp, 0.0, float_precision ); + count = fwrite( ifp, fortran_tag, int_precision ); + + elseif (strcmp(write_ind_latlon,'latlon_id')) + + count = fwrite( ifp, fortran_tag, int_precision ); + count = fwrite( ifp, 0.0, float_precision ); + count = fwrite( ifp, fortran_tag, int_precision ); + + count = fwrite( ifp, fortran_tag, int_precision ); + count = fwrite( ifp, 0.0, float_precision ); + count = fwrite( ifp, fortran_tag, int_precision ); + + count = fwrite( ifp, fortran_tag, int_precision ); + count = fwrite( ifp, 0, int_precision ); + count = fwrite( ifp, fortran_tag, int_precision ); + + else + + error('output-arguments do not line up') + + end + + end + + for j=1:N_stat + + for i=1:N_field + + if ( j == 5 && strcmp(file_type,'cli')) + count = fwrite( ifp, fortran_tag, int_precision ); + count = fwrite( ifp, 0, int_precision ); + count = fwrite( ifp, fortran_tag, int_precision ); + else + count = fwrite( ifp, fortran_tag, int_precision ); + count = fwrite( ifp, nodata_val, float_precision ); + count = fwrite( ifp, fortran_tag, int_precision ); + end + + end + + end + +end + +fclose(ifp); + +%=========================EOF==================================== diff --git a/src/Applications/LDAS_App/util/compress_bit-shaved_nc4.sh b/src/Applications/LDAS_App/util/postproc/compress_bit-shaved_nc4.sh similarity index 100% rename from src/Applications/LDAS_App/util/compress_bit-shaved_nc4.sh rename to src/Applications/LDAS_App/util/postproc/compress_bit-shaved_nc4.sh diff --git a/src/Applications/LDAS_App/util/write_smapL4SMqa.m b/src/Applications/LDAS_App/util/postproc/write_smapL4SMqa.m similarity index 100% rename from src/Applications/LDAS_App/util/write_smapL4SMqa.m rename to src/Applications/LDAS_App/util/postproc/write_smapL4SMqa.m diff --git a/src/Applications/LDAS_App/util/shared/matlab/J2000_to_DateTime.m b/src/Applications/LDAS_App/util/shared/matlab/J2000_to_DateTime.m new file mode 100644 index 00000000..d2e52d2f --- /dev/null +++ b/src/Applications/LDAS_App/util/shared/matlab/J2000_to_DateTime.m @@ -0,0 +1,111 @@ +function [yr, mm, dd, hr, mn, ss, doy, pen] = J2000_to_DateTime( J2000_seconds, epoch_id) +% +% Convert J2000 time [seconds] into calendar date time. +% +% J2000 time is used in SMAP products (epoch_id = "TT12"). See subfunction J2000_epoch() below. +% +% See also GEOSldas module LDAS_DateTimeMod.F90 +% +% reichle, 28 Jul 2028 +% +% --------------------------------------------------------------------------- + +if ~exist( 'epoch_id', 'var' ) epoch_id = 'TT12'; end % default is what SMAP uses + +date_time_epoch = J2000_epoch( epoch_id ); + +N = length(J2000_seconds); + +yr = zeros(N,1); +mm = zeros(N,1); +dd = zeros(N,1); +hr = zeros(N,1); +mn = zeros(N,1); +ss = zeros(N,1); +doy = zeros(N,1); +pen = zeros(N,1); + +% Loop through elements of J2000_seconds for now. In future, should vectorize +% augment_date_time.m, is_leap_year.m, days_in_month.m, get_dofyr_pentad.m + +for ii = 1:N + + % add (rounded) J2000_seconds to date_time_epoch + + date_time = augment_date_time( round(J2000_seconds), date_time_epoch ); + + yr( ii) = date_time.year ; + mm( ii) = date_time.month ; + dd( ii) = date_time.day ; + hr( ii) = date_time.hour ; + mn( ii) = date_time.min ; + ss( ii) = date_time.sec ; + pen(ii) = date_time.pentad; + doy(ii) = date_time.dofyr ; + +end + +% ---------------------------------------------------------------------------------- + +function [J2000_epoch_datetime] = J2000_epoch( epoch_id ) + +% definition of J2000 epochs +% +% "J2000 seconds" are elapsed seconds since J2000 Epoch, which is either +% +% - "UT12": 11:58:55.816 on 1 Jan 2000 in Coordinated Universal Time (UTC), or +% - "TT12": 12:00:00.000 on 1 Jan 2000 in Terrestrial Time (TT), or +% - "UT00": 00:00:00.000 on 1 Jan 2000 in Coordinated Universal Time (UTC) +% +% NOTE: Per SMAP L1C_TB data products specs document, SMAP time stamps use "UT12" +% but sample granules appear to be using "TT12". +% NOTE: Per Clara Draper (30 Jun 2015), the nc4 ASCAT soil moisture retrieval +% product uses "UT00". + +J2000_UT12.year = 2000; +J2000_UT12.month = 1; +J2000_UT12.day = 1; +J2000_UT12.hour = 11; +J2000_UT12.min = 58; +J2000_UT12.sec = 55; % rounded down +J2000_UT12.pentad = 1; +J2000_UT12.dofyr = 1; + +J2000_TT12.year = 2000; +J2000_TT12.month = 1; +J2000_TT12.day = 1; +J2000_TT12.hour = 12; +J2000_TT12.min = 0; +J2000_TT12.sec = 0; +J2000_TT12.pentad = 1; +J2000_TT12.dofyr = 1; + +J2000_UT00.year = 2000; +J2000_UT00.month = 1; +J2000_UT00.day = 1; +J2000_UT00.hour = 0; +J2000_UT00.min = 0; +J2000_UT00.sec = 0; +J2000_UT00.pentad = 1; +J2000_UT00.dofyr = 1; + +% ---------------------------------- + +switch epoch_id + +case 'UT12' + J2000_epoch_datetime = J2000_UT12; + +case 'TT12' + J2000_epoch_datetime = J2000_TT12; + +case 'UT00' + J2000_epoch_datetime = J2000_UT00; + +otherwise + + error('J2000_to_DateTime: unknown J2000 epoch_id') + +end + +% ======================= EOF ================================================= 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 new file mode 100644 index 00000000..0e5b6227 --- /dev/null +++ b/src/Applications/LDAS_App/util/shared/matlab/MAPL_ReadForcing_fullfile.m @@ -0,0 +1,80 @@ +function [tile_data,N_tile,start_time,end_time] = ... + MAPL_ReadForcing_fullfile(fname,nodata,nodata_tolfrac) + +% Matlab version of MAPL_ReadForcing(). So far only reads complete file! +% +% Reads binary climatology or time series files (e.g., lai.dat, vegopacity.dat). + +% Q. Liu, 18 Jul 2022 +% rreichle, 29 Jul 2022 + +% ------------------------------------------------------------------------- +% +% 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 + +nodata_tol = abs( nodata*nodata_tol_frac ); + +% ------------------------------------------------------------------------- + +int_precision = 'int32'; % precision of fortran tag +float_precision = 'float32'; % precision of data in input file + +disp(['reading from ', fname]) + +ifp = fopen( fname, 'r', 'l' ); + +% time loop (continue until reach end-of-file) + +nn=0; + +while 1 + + nn = nn +1; + + % read header + + fortran_tag = fread( ifp, 1, int_precision ); + header = fread( ifp, 14, float_precision ); + fortran_tag = fread( ifp, 1, int_precision ); + + % safe way to detect end-of-file + if isempty(header) + break + end + + start_time(nn).year = header( 1); + start_time(nn).month = header( 2); + start_time(nn).day = header( 3); + start_time(nn).hour = header( 4); + start_time(nn).min = header( 5); + start_time(nn).sec = header( 6); + + end_time( nn).year = header( 7); + end_time( nn).month = header( 8); + end_time( nn).day = header( 9); + end_time( nn).hour = header(10); + end_time( nn).min = header(11); + end_time( nn).sec = header(12); + + N_tile = header(13); + + % read science data + + fortran_tag = fread( ifp, 1, int_precision ); + tmp_data = fread( ifp, [1 N_tile], float_precision ); + fortran_tag = fread( ifp, 1, int_precision ); + + tile_data(nn,:) = tmp_data; + +end + +% replace nodata values with NaN + +tile_data( abs( single(tile_data) - single(nodata) ) < nodata_tol ) = NaN; + +fclose(ifp); + +% ========================= EOF ============================================= diff --git a/src/Applications/LDAS_App/util/shared/matlab/augment_date_time.m b/src/Applications/LDAS_App/util/shared/matlab/augment_date_time.m new file mode 100644 index 00000000..f3257074 --- /dev/null +++ b/src/Applications/LDAS_App/util/shared/matlab/augment_date_time.m @@ -0,0 +1,149 @@ + +function [date_time] = augment_date_time( dtstep, date_time_old ) + +% reichle, 22 Jun 2005 + +% dtstep in seconds + +date_time = date_time_old; + +dtstep_left = dtstep; + +if isnan(dtstep) + + error('ERROR: dtstep=NaN in augment_date_time.m'); + +elseif dtstep==0 % trivial case + + date_time = get_dofyr_pentad(date_time); + + return + +elseif dtstep>0 + + while (dtstep_left>0) + + % increase by one day at a time + + dtstep_tmp = min( dtstep_left, 86400 ); + + dtstep_left = round( dtstep_left - dtstep_tmp ); + + % compute secs_in_day from hh:mm:ss + + secs_in_day = date_time.hour*3600 + date_time.min*60 + date_time.sec; + + % augment + + secs_in_day = secs_in_day + dtstep_tmp; + + % compute new hh:mm:ss from secs_in_day + + date_time.hour = (floor(mod(secs_in_day,86400)/3600)); + date_time.min = (floor(mod(secs_in_day,86400)/60) - date_time.hour*60); + date_time.sec = (floor(mod(secs_in_day,86400)) ... + - date_time.hour*3600 ... + - date_time.min*60); + + % augment year/month/day and dofyr as necessary + + if ( secs_in_day >= 86400 ) + + % get number of days in month + + last_day = days_in_month( date_time.year, date_time.month); + + if (date_time.day==last_day) + + if (date_time.month==12) + + date_time.year = date_time.year + 1; + date_time.month = 1; + date_time.day = 1; + + else + + date_time.month = date_time.month + 1; + date_time.day = 1; + + end + + else + + date_time.day = date_time.day + 1; + + end + + end + + end + +else + + while (dtstep_left<0) + + % decrease by one day at a time + + dtstep_tmp = max( dtstep_left, -86400 ); + + dtstep_left = round( dtstep_left - dtstep_tmp ); + + % compute secs_in_day from hh:mm:ss + + secs_in_day = date_time.hour*3600 + date_time.min*60 + date_time.sec; + + % augment + + secs_in_day = secs_in_day + dtstep_tmp; + + % compute new hh:mm:ss from secs_in_day + + secs_in_day_tmp = secs_in_day + 86400; + + date_time.hour = (floor(mod(secs_in_day_tmp,86400)/3600)); + date_time.min = (floor(mod(secs_in_day_tmp,86400)/60)-date_time.hour*60); + date_time.sec = (floor(mod(secs_in_day_tmp,86400)) ... + - date_time.hour*3600 ... + - date_time.min*60); + + % augment year/month/day and dofyr as necessary + + if ( secs_in_day < 0 ) + + if (date_time.day==1) + + if (date_time.month==1) + + date_time.year = date_time.year - 1; + date_time.month = 12; + date_time.day = 31; + + else + + date_time.month = date_time.month - 1; + + % get number of days in previous month + + date_time.day = days_in_month( date_time.year, date_time.month); + + end + + else + + date_time.day = date_time.day - 1; + + end + + end + + end + +end + +% get dofyr and pentad + +date_time = get_dofyr_pentad(date_time); + + +% ****** EOF ******************************************************* + diff --git a/src/Applications/LDAS_App/util/shared/matlab/days_in_month.m b/src/Applications/LDAS_App/util/shared/matlab/days_in_month.m new file mode 100644 index 00000000..5e89e648 --- /dev/null +++ b/src/Applications/LDAS_App/util/shared/matlab/days_in_month.m @@ -0,0 +1,16 @@ + +function [n_days] = days_in_month( year, month ) + +% reichle, 22 Jun 2005 + +days_in_month_leap = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; + +days_in_month_nonleap = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; + +if (is_leap_year(year)) + n_days = days_in_month_leap(month); +else + n_days = days_in_month_nonleap(month); +end + +% **************************** EOF ******************************** \ No newline at end of file diff --git a/src/Applications/LDAS_App/util/shared/matlab/get_dofyr_pentad.m b/src/Applications/LDAS_App/util/shared/matlab/get_dofyr_pentad.m new file mode 100644 index 00000000..63432a9d --- /dev/null +++ b/src/Applications/LDAS_App/util/shared/matlab/get_dofyr_pentad.m @@ -0,0 +1,19 @@ + +function [ date_time ] = get_dofyr_pentad( date_time ) + +% compute dofyr and pentad for date_time + +date_time.dofyr = date_time.day; + +% add up days in months prior to current month + +for i=1:(date_time.month-1) + + date_time.dofyr = date_time.dofyr + days_in_month(date_time.year,i); + +end + +date_time.pentad = pentad_of_year(date_time.dofyr, date_time.year); + + +% ======================= EOF ================================== \ No newline at end of file diff --git a/src/Applications/LDAS_App/util/shared/matlab/is_leap_year.m b/src/Applications/LDAS_App/util/shared/matlab/is_leap_year.m new file mode 100644 index 00000000..1da1af71 --- /dev/null +++ b/src/Applications/LDAS_App/util/shared/matlab/is_leap_year.m @@ -0,0 +1,30 @@ +function [ leap ] = is_leap_year(year) + +% determine whether a given year is a leap yearb +% +% input: year, must be SCALAR ! +% +% output: leap = 0 if year is not leap year +% leap = 1 if year is leap year +% +% reichle, 1 Mar 2001 +% +% --------------------------------------------------------------------- + +if (length(year) ~= 1) + disp('error, input to is_leap_year() must be scalar, exiting...') + return +end + +if (mod(year,4) ~= 0) + leap = 0; +elseif (mod(year,400) == 0) + leap = 1; +elseif (mod(year,100) == 0) + leap = 0; +else + leap = 1; +end + +% ========= EOF ========================================================= + \ No newline at end of file diff --git a/src/Applications/LDAS_App/util/read_ObsFcstAna.m b/src/Applications/LDAS_App/util/shared/matlab/read_ObsFcstAna.m similarity index 100% rename from src/Applications/LDAS_App/util/read_ObsFcstAna.m rename to src/Applications/LDAS_App/util/shared/matlab/read_ObsFcstAna.m diff --git a/src/Applications/LDAS_App/util/read_catparam.m b/src/Applications/LDAS_App/util/shared/matlab/read_catparam.m similarity index 96% rename from src/Applications/LDAS_App/util/read_catparam.m rename to src/Applications/LDAS_App/util/shared/matlab/read_catparam.m index 3a8f6a99..394e4052 100644 --- a/src/Applications/LDAS_App/util/read_catparam.m +++ b/src/Applications/LDAS_App/util/shared/matlab/read_catparam.m @@ -8,6 +8,7 @@ % structures" to "structure of vectors" % reichle, 1 Apr 2015 - added new soil parameter fields (file_format==3) % - added cat_param_units +% reichle, 28 Jul 2022 - cleaned up LDASsa/GEOSldas switch for commit into GEOSldas repo % NOTE: For large files this reader is inefficient (slow execution, % excessive memory demand) due to the use of a matlab structure @@ -87,6 +88,8 @@ % % ------------------------------------------------------------------ +if ~exist('isLDASsa','var') isLDASsa = 0; end % default is GEOSldas output + % for backward compatibility, back out number of parameters in file % from file size: @@ -94,7 +97,7 @@ tmps = dir(fname); -if exist('isLDASsa','var') && isLDASsa == 1 +if isLDASsa ~= 0 machfmt = 'b'; % big-endian, LDASsa else machfmt = 'l'; % little-endian, GEOSldas @@ -106,14 +109,22 @@ file_format = 1; - int_columns = 18; - + if isLDASsa ~= 0 + int_columns = 18; % vegcls + else + int_columns = []; % GEOSldas files contain only real*4 numbers + end + elseif N_param==42 | N_param==51 | N_param==52 file_format = 2; + + if isLDASsa ~= 0 + int_columns = [ 18 19 20 ]; % vegcls, soilcls30, soilcls100 + else + int_columns = []; % GEOSldas files contain only real*4 numbers + end - int_columns = [ 18 19 20 ]; - else error('read_catparam.m: something wrong with file size or format') diff --git a/src/Applications/LDAS_App/util/read_obslog.m b/src/Applications/LDAS_App/util/shared/matlab/read_obslog.m similarity index 100% rename from src/Applications/LDAS_App/util/read_obslog.m rename to src/Applications/LDAS_App/util/shared/matlab/read_obslog.m diff --git a/src/Applications/LDAS_App/util/read_obsparam.m b/src/Applications/LDAS_App/util/shared/matlab/read_obsparam.m similarity index 100% rename from src/Applications/LDAS_App/util/read_obsparam.m rename to src/Applications/LDAS_App/util/shared/matlab/read_obsparam.m diff --git a/src/Applications/LDAS_App/util/read_smapL4SMaup.m b/src/Applications/LDAS_App/util/shared/matlab/read_smapL4SMaup.m similarity index 96% rename from src/Applications/LDAS_App/util/read_smapL4SMaup.m rename to src/Applications/LDAS_App/util/shared/matlab/read_smapL4SMaup.m index 9293ed2a..9418d2b5 100644 --- a/src/Applications/LDAS_App/util/read_smapL4SMaup.m +++ b/src/Applications/LDAS_App/util/shared/matlab/read_smapL4SMaup.m @@ -5,12 +5,15 @@ % reichle, 5 Feb 2014 - added tb_[h/v]_obs_time_sec % reichle, 21 Mar 2015 - changed units of soil moisture output from wetness % [dimensionless] to volumetric soil moisture [m3/m3] +% reichle, 28 Jul 2022 - cleaned up LDASsa/GEOSldas switch for commit into GEOSldas repo % NOTE: For large files this reader is inefficient (slow execution, % excessive memory demand) due to the use of a matlab structure % array. If better performance is needed, convert to reading % data into a regular matrix (as opposed to a structure array). +if ~exist('isLDASsa','var') is_LDASsa = 0; end % default is GEOSldas output + N_param = 31; % number of records dbl_records = [1 2]; % double precision records @@ -26,8 +29,7 @@ disp(['read_smapL4SMaup.m: reading from ', fname]) - -if exist('isLDASsa','var') && isLDASsa == 1 +if isLDASsa ~= 0 machfmt = 'b'; % big-endian, LDASsa else machfmt = 'l'; % little-endian, GEOSldas diff --git a/src/Applications/LDAS_App/util/read_smapL4SMlmc.m b/src/Applications/LDAS_App/util/shared/matlab/read_smapL4SMlmc.m similarity index 96% rename from src/Applications/LDAS_App/util/read_smapL4SMlmc.m rename to src/Applications/LDAS_App/util/shared/matlab/read_smapL4SMlmc.m index f9e00b44..f0cf783e 100644 --- a/src/Applications/LDAS_App/util/read_smapL4SMlmc.m +++ b/src/Applications/LDAS_App/util/shared/matlab/read_smapL4SMlmc.m @@ -12,9 +12,12 @@ % - revised fieldnames for consistency with L4_SM Product Specs Doc % reichle, 27 May 2014: - changed wilting point output from "clsm_wpwet" to "clsm_wp" % reichle, 17 Nov 2015: - added "veghght" output +% reichle, 28 Jul 2022 - cleaned up LDASsa/GEOSldas switch for commit into GEOSldas repo % ---------------------------------------------------------------- +if ~exist('isLDASsa','var') isLDASsa = 0; end % default is GEOSldas output + % for backward compatibility, back out number of parameters in file % from file size: @@ -43,7 +46,7 @@ disp(['read_smapL4SMlmc.m: reading from ', fname]) -if exist('isLDASsa','var') && isLDASsa == 1 +if isLDASsa ~= 0 machfmt = 'b'; % big-endian, LDASsa else machfmt = 'l'; % little-endian, GEOSldas diff --git a/src/Applications/LDAS_App/util/read_tilecoord.m b/src/Applications/LDAS_App/util/shared/matlab/read_tilecoord.m similarity index 95% rename from src/Applications/LDAS_App/util/read_tilecoord.m rename to src/Applications/LDAS_App/util/shared/matlab/read_tilecoord.m index 35c1df9a..422f6fb8 100644 --- a/src/Applications/LDAS_App/util/read_tilecoord.m +++ b/src/Applications/LDAS_App/util/shared/matlab/read_tilecoord.m @@ -6,15 +6,19 @@ % reichle, 29 Jun 2005 % GDL, 22 Jun 2010 - changed i_atm/j_atm/frac_atm to i_indg/j_indg/frac_cell % reichle, 31 May 2011 - accomodate new field "elev" (elevation) -% reichle, 7 Jan 2014 - added capability to read binary "tilegrids" files +% reichle, 7 Jan 2014 - added capability to read binary "tilecoord" files % and to convert a binary file into a txt file % file extension: ".txt" --> ASCII file % ".bin" --> binary file % ASCII option maintains backward compatibility % % jperket, 1 Dec 2017 - added flag for LDASsa, big-endian format +% reichle, 28 Jul 2022 - cleaned up LDASsa/GEOSldas switch for commit into GEOSldas repo +% % ------------------------------------------------------------- +if ~exist('isLDASsa','var') isLDASsa = 0; end % default is GEOSldas output + int_precision = 'int32'; % precision of fortran tag float_precision = 'float32'; % precision of data in input file @@ -26,7 +30,7 @@ end -if exist('isLDASsa','var') && isLDASsa == 1 +if isLDASsa ~= 0 machfmt = 'b'; % big-endian, LDASsa else machfmt = 'l'; % little-endian, GEOSldas @@ -55,7 +59,7 @@ else - error('read_tilegrids.m: ERROR - unknown file extension') + error('read_tilecoord.m: ERROR - unknown file extension') end diff --git a/src/Applications/LDAS_App/util/read_tilegrids.m b/src/Applications/LDAS_App/util/shared/matlab/read_tilegrids.m similarity index 95% rename from src/Applications/LDAS_App/util/read_tilegrids.m rename to src/Applications/LDAS_App/util/shared/matlab/read_tilegrids.m index acc08f16..42997686 100644 --- a/src/Applications/LDAS_App/util/read_tilegrids.m +++ b/src/Applications/LDAS_App/util/shared/matlab/read_tilegrids.m @@ -9,13 +9,16 @@ % file extension: ".txt" --> ASCII file % ".bin" --> binary file % jperket, 4 Dec 2017 - added flag for LDASsa, big-endian format +% reichle, 28 Jul 2022 - cleaned up LDASsa/GEOSldas switch for commit into GEOSldas repo % % ------------------------------------------------------------- +if ~exist('isLDASsa','var') isLDASsa = 0; end % default is GEOSldas output + int_precision = 'int32'; % precision of fortran tag float_precision = 'float32'; % precision of data in input file -if exist('isLDASsa','var') && isLDASsa == 1 +if isLDASsa ~= 0 machfmt = 'b'; % big-endian, LDASsa else machfmt = 'l'; % little-endian, GEOSldas diff --git a/src/Applications/LDAS_App/util/tile2grid.m b/src/Applications/LDAS_App/util/shared/matlab/tile2grid.m similarity index 100% rename from src/Applications/LDAS_App/util/tile2grid.m rename to src/Applications/LDAS_App/util/shared/matlab/tile2grid.m diff --git a/src/Components/GEOSldas_GridComp/CMakeLists.txt b/src/Components/GEOSldas_GridComp/CMakeLists.txt index 65d57024..2f96b712 100644 --- a/src/Components/GEOSldas_GridComp/CMakeLists.txt +++ b/src/Components/GEOSldas_GridComp/CMakeLists.txt @@ -13,5 +13,5 @@ esma_add_library(${this} SRCS GEOS_LdasGridComp.F90 SUBCOMPONENTS ${alldirs} SUBDIRS Shared - DEPENDENCIES GEOSland_GridComp MAPL + DEPENDENCIES GEOSland_GridComp raster MAPL INCLUDES ${INC_ESMF}) diff --git a/src/Components/GEOSldas_GridComp/GEOS_LdasGridComp.F90 b/src/Components/GEOSldas_GridComp/GEOS_LdasGridComp.F90 index 77f4331b..2401e935 100644 --- a/src/Components/GEOSldas_GridComp/GEOS_LdasGridComp.F90 +++ b/src/Components/GEOSldas_GridComp/GEOS_LdasGridComp.F90 @@ -15,7 +15,7 @@ module GEOS_LdasGridCompMod use GEOS_EnsGridCompMod, only: EnsSetServices => SetServices use GEOS_LandAssimGridCompMod, only: LandAssimSetServices => SetServices - use LDAS_EASE_conv, only: ease_inverse + use EASE_conv, only: ease_inverse use LDAS_TileCoordType, only: tile_coord_type , T_TILECOORD_STATE, TILECOORD_WRAP use LDAS_TileCoordType, only: grid_def_type, io_grid_def_type use LDAS_TileCoordRoutines, only: get_tile_grid, get_ij_ind_from_latlon, io_domain_files @@ -26,7 +26,7 @@ module GEOS_LdasGridCompMod use LDAS_ensdrv_mpi, only: MPI_tile_coord_type, MPI_grid_def_type use LDAS_ensdrv_mpi, only: init_MPI_types,mpicomm,numprocs,myid use LDAS_ensdrv_mpi, only: root_proc - use LDAS_ensdrv_Globals, only: logunit,logit,root_logit,echo_clsm_ensdrv_glob_param + use LDAS_ensdrv_Globals, only: logunit,logit,root_logit,echo_clsm_ensdrv_glob_param, get_ensid_string use catch_constants, only: echo_catch_constants use StieglitzSnow, only: StieglitzSnow_echo_constants use SurfParams, only: SurfParams_init @@ -78,7 +78,7 @@ subroutine SetServices(gc, rc) ! ensemble set up: integer :: i, k - integer,allocatable :: ens_id(:) + 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 @@ -86,7 +86,7 @@ subroutine SetServices(gc, rc) integer :: status character(len=ESMF_MAXSTR) :: Iam character(len=ESMF_MAXSTR) :: comp_name - character(len=ESMF_MAXSTR) :: id_string,childname, fmt_str + character(len=ESMF_MAXSTR) :: ensid_string,childname character(len=ESMF_MAXSTR) :: LAND_ASSIM_STR, mwRTM_file, ENS_FORCING_STR integer :: ens_id_width ! Local variables @@ -173,21 +173,29 @@ subroutine SetServices(gc, rc) allocate(METFORCE(1)) endif - allocate(ens_id(NUM_ENSEMBLE),LAND(NUM_ENSEMBLE),LANDPERT(NUM_ENSEMBLE)) - _ASSERT( ens_id_width < 10, "need 1 billion ensemble members? increase ens_id_width first") - write (fmt_str, "(A2,I1,A1,I1,A1)") "(I", ens_id_width,".",ens_id_width,")" + allocate(LAND(NUM_ENSEMBLE),LANDPERT(NUM_ENSEMBLE)) + + ! ens_id_with = 2 + number of digits = total number of chars in ensid_string ("_eXXXX") + ! + ! Assert ens_id_width<=2+9 so number of digits remains single-digit and "I1" can be + ! hardwired when assembling a format string. + ! Assert ens_id_width>=2+3 to avoid user configuration errors when LDAS is coupled into ADAS. + ! (Met forcing from the atm ensemble uses hardwired, 3-character ensemble IDs.) + + if (NUM_ENSEMBLE > 1) then + _ASSERT( ens_id_width < 12, "Must use ens_id_width <= 11 (2 for '_e' + 9 digits max)") + _ASSERT( ens_id_width >= 5, "Must use ens_id_width >= 5 (2 for '_e' + 3 digits min)") + endif do i=1,NUM_ENSEMBLE - ens_id(i) = i-1 + FIRST_ENS_ID ! id start form FIRST_ENS_ID - if(NUM_ENSEMBLE == 1 .or. .not. ensemble_forcing) then - id_string='' - else - write(id_string, fmt_str) ens_id(i) - endif + ens_id = i-1 + FIRST_ENS_ID ! id start form FIRST_ENS_ID + + call get_ensid_string(ensid_string, ens_id, ens_id_width, NUM_ENSEMBLE) ! "_eXXXX" - id_string=trim(id_string) + ! allow for Catchment ensemble simulation to be forced with single-member met inputs + if (.not. ensemble_forcing ) ensid_string = '' - childname='METFORCE'//trim(id_string) + childname='METFORCE'//trim(ensid_string) METFORCE(i) = MAPL_AddChild(gc, name=trim(childname), ss=MetforceSetServices, rc=status) VERIFY_(status) ! exit after i=1 if using deterministic forcing @@ -195,20 +203,15 @@ subroutine SetServices(gc, rc) enddo do i=1,NUM_ENSEMBLE - ens_id(i) = i-1 + FIRST_ENS_ID ! id start form FIRST_ENS_ID - if(NUM_ENSEMBLE == 1 ) then - id_string='' - else - write(id_string, fmt_str) ens_id(i) - endif + ens_id = i-1 + FIRST_ENS_ID ! id start form FIRST_ENS_ID - id_string=trim(id_string) + call get_ensid_string(ensid_string, ens_id, ens_id_width, NUM_ENSEMBLE) - childname='LANDPERT'//trim(id_string) + childname='LANDPERT'//trim(ensid_string) LANDPERT(i) = MAPL_AddChild(gc, name=childname, ss=LandPertSetServices, rc=status) VERIFY_(status) - childname='LAND'//trim(id_string) + childname='LAND'//trim(ensid_string) LAND(i) = MAPL_AddChild(gc, name=childname, ss=LandSetServices, rc=status) VERIFY_(status) enddo @@ -800,19 +803,25 @@ subroutine Run(gc, import, export, clock, rc) type(ESMF_GridComp), pointer :: gcs(:) type(ESMF_State), pointer :: gim(:) type(ESMF_State), pointer :: gex(:) + type(ESMF_State) :: member_export + character(len=ESMF_MAXSTR), pointer :: gcnames(:) type(ESMF_Time) :: ModelTimeCur + character(len=ESMF_MAXSTR) :: member_name + character(len=ESMF_MAXSTR) :: ensid_string ! MAPL variables type(MAPL_MetaComp), pointer :: MAPL ! Misc variables - integer :: igc,i + integer :: igc,i, ens_id, FIRST_ENS_ID, ens_id_width logical :: IAmRoot integer :: mpierr integer :: LSM_CHOICE + type (ESMF_Field) :: field - ! Begin... + + ! Begin... ! Get component's name and setup traceback handle call ESMF_GridCompget(gc, name=comp_name, rc=status) @@ -831,6 +840,11 @@ subroutine Run(gc, import, export, clock, rc) call MAPL_Get(MAPL, GCS=gcs, GIM=gim, GEX=gex, GCNAMES=gcnames, rc=status) VERIFY_(STATUS) + call MAPL_GetResource ( MAPL, ens_id_width, Label="ENS_ID_WIDTH:", DEFAULT=0, RC=STATUS) + VERIFY_(STATUS) + call MAPL_GetResource ( MAPL, FIRST_ENS_ID, Label="FIRST_ENS_ID:", DEFAULT=0, RC=STATUS) + VERIFY_(STATUS) + ! MPI call ESMF_VmGetCurrent(vm, rc=status) VERIFY_(status) @@ -916,15 +930,26 @@ subroutine Run(gc, import, export, clock, rc) ! Use LAND's output as the input to calculate the ensemble average igc = LAND(i) if (LSM_CHOICE == 1) then - ! collect cat_param - call ESMF_GridCompRun(gcs(ENSAVG), importState=gex(igc), exportState=gex(ENSAVG), clock=clock,phase=3, userRC=status) + ! collect cat_param + ens_id = i-1 + FIRST_ENS_ID ! id start form FIRST_ENS_ID + call get_ensid_string(ensid_string, ens_id, ens_id_width, NUM_ENSEMBLE) + + member_name = 'CATCH'//trim(ensid_string)//"_Exports" + + call ESMF_StateGet(gex(igc), trim(member_name), member_export, _RC) + call ESMF_StateGet(gex(igc), "Z2CH", field, _RC) + call ESMF_StateAddReplace(member_export, [field],_RC) + call ESMF_StateGet(gex(igc), "LAI", field, _RC) + call ESMF_StateAddReplace(member_export, [field],_RC) + + call ESMF_GridCompRun(gcs(ENSAVG), importState=member_export, exportState=gex(ENSAVG), clock=clock,phase=3, userRC=status) VERIFY_(status) - call ESMF_GridCompRun(gcs(ENSAVG), importState=gex(igc), exportState=gex(ENSAVG), clock=clock,phase=2, userRC=status) + call ESMF_GridCompRun(gcs(ENSAVG), importState=member_export, exportState=gex(ENSAVG), clock=clock,phase=2, userRC=status) VERIFY_(status) if( mwRTM ) then ! Calculate ensemble-average L-band Tb using LAND's output (add up and normalize after last member has been added) - call ESMF_GridCompRun(gcs(LANDASSIM), importState=gex(igc), exportState=gex(LANDASSIM), clock=clock,phase=3, userRC=status) + call ESMF_GridCompRun(gcs(LANDASSIM), importState=member_export, exportState=gex(LANDASSIM), clock=clock,phase=3, userRC=status) VERIFY_(status) endif endif diff --git a/src/Components/GEOSldas_GridComp/GEOSens_GridComp/GEOS_EnsGridComp.F90 b/src/Components/GEOSldas_GridComp/GEOSens_GridComp/GEOS_EnsGridComp.F90 index 611b2e6d..b32e8044 100644 --- a/src/Components/GEOSldas_GridComp/GEOSens_GridComp/GEOS_EnsGridComp.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSens_GridComp/GEOS_EnsGridComp.F90 @@ -1478,7 +1478,203 @@ subroutine SetServices(gc, rc) VERIFY_(STATUS) - + call MAPL_AddExportSpec(GC ,& + LONG_NAME = 'CN_exposed_leaf-area_index',& + UNITS = '1' ,& + SHORT_NAME = 'CNLAI' ,& + DIMS = MAPL_DimsTileOnly ,& + VLOCATION = MAPL_VLocationNone ,& + RC=STATUS ) + VERIFY_(STATUS) + + call MAPL_AddExportSpec(GC ,& + LONG_NAME = 'CN_total_leaf-area_index' ,& + UNITS = '1' ,& + SHORT_NAME = 'CNTLAI' ,& + DIMS = MAPL_DimsTileOnly ,& + VLOCATION = MAPL_VLocationNone ,& + RC=STATUS ) + VERIFY_(STATUS) + + call MAPL_AddExportSpec(GC ,& + LONG_NAME = 'CN_exposed_stem-area_index',& + UNITS = '1' ,& + SHORT_NAME = 'CNSAI' ,& + DIMS = MAPL_DimsTileOnly ,& + VLOCATION = MAPL_VLocationNone ,& + RC=STATUS ) + VERIFY_(STATUS) + + call MAPL_AddExportSpec(GC ,& + LONG_NAME = 'CN_total_carbon' ,& + UNITS = 'kg m-2' ,& + SHORT_NAME = 'CNTOTC' ,& + DIMS = MAPL_DimsTileOnly ,& + VLOCATION = MAPL_VLocationNone ,& + RC=STATUS ) + VERIFY_(STATUS) + + call MAPL_AddExportSpec(GC ,& + LONG_NAME = 'CN_total_vegetation_carbon',& + UNITS = 'kg m-2' ,& + SHORT_NAME = 'CNVEGC' ,& + DIMS = MAPL_DimsTileOnly ,& + VLOCATION = MAPL_VLocationNone ,& + RC=STATUS ) + VERIFY_(STATUS) + call MAPL_AddExportSpec(GC ,& + LONG_NAME = 'CN_net_primary_production' ,& + UNITS = 'kg m-2 s-1' ,& + SHORT_NAME = 'CNNPP' ,& + DIMS = MAPL_DimsTileOnly ,& + VLOCATION = MAPL_VLocationNone ,& + RC=STATUS ) + VERIFY_(STATUS) + + call MAPL_AddExportSpec(GC ,& + LONG_NAME = 'CN_gross_primary_production',& + UNITS = 'kg m-2 s-1' ,& + SHORT_NAME = 'CNGPP' ,& + DIMS = MAPL_DimsTileOnly ,& + VLOCATION = MAPL_VLocationNone ,& + RC=STATUS ) + VERIFY_(STATUS) + + call MAPL_AddExportSpec(GC ,& + LONG_NAME = 'CN_total_soil_respiration' ,& + UNITS = 'kg m-2 s-1' ,& + SHORT_NAME = 'CNSR' ,& + DIMS = MAPL_DimsTileOnly ,& + VLOCATION = MAPL_VLocationNone ,& + RC=STATUS ) + VERIFY_(STATUS) + + call MAPL_AddExportSpec(GC ,& + LONG_NAME = 'CN_net_ecosystem_exchange' ,& + UNITS = 'kg m-2 s-1' ,& + SHORT_NAME = 'CNNEE' ,& + DIMS = MAPL_DimsTileOnly ,& + VLOCATION = MAPL_VLocationNone ,& + RC=STATUS ) + VERIFY_(STATUS) + + call MAPL_AddExportSpec(GC ,& + LONG_NAME = 'abstract_C_pool_to_meet_excess_MR_demand' ,& + UNITS = 'kg m-2' ,& + SHORT_NAME = 'CNXSMR' ,& + DIMS = MAPL_DimsTileOnly ,& + VLOCATION = MAPL_VLocationNone ,& + RC=STATUS ) + VERIFY_(STATUS) + + call MAPL_AddExportSpec(GC ,& + LONG_NAME = 'CN_added_to_maintain_positive_C' ,& + UNITS = 'kg m-2 s-1' ,& + SHORT_NAME = 'CNADD' ,& + DIMS = MAPL_DimsTileOnly ,& + VLOCATION = MAPL_VLocationNone ,& + RC=STATUS ) + VERIFY_(STATUS) + + call MAPL_AddExportSpec(GC ,& + LONG_NAME = 'CN_carbon_loss_to_fire' ,& + UNITS = 'kg m-2 s-1' ,& + SHORT_NAME = 'CNLOSS' ,& + DIMS = MAPL_DimsTileOnly ,& + VLOCATION = MAPL_VLocationNone ,& + RC=STATUS ) + VERIFY_(STATUS) + + call MAPL_AddExportSpec(GC ,& + LONG_NAME = 'CN_fractional_area_burn_rate' ,& + UNITS = 's-1' ,& + SHORT_NAME = 'CNBURN' ,& + DIMS = MAPL_DimsTileOnly ,& + VLOCATION = MAPL_VLocationNone ,& + RC=STATUS ) + VERIFY_(STATUS) + + call MAPL_AddExportSpec(GC ,& + LONG_NAME = 'CN_total_root_C' ,& + UNITS = 'kg m-2' ,& + SHORT_NAME = 'CNROOT' ,& + DIMS = MAPL_DimsTileOnly ,& + VLOCATION = MAPL_VLocationNone ,& + RC=STATUS ) + + call MAPL_AddExportSpec(GC ,& + LONG_NAME = 'CN_fine_root_carbon' ,& + UNITS = 'kg m-2' ,& + SHORT_NAME = 'CNFROOTC' ,& + DIMS = MAPL_DimsTileOnly ,& + VLOCATION = MAPL_VLocationNone ,& + RC=STATUS ) + VERIFY_(STATUS) + + call MAPL_AddExportSpec(GC ,& + LONG_NAME = 'fire season length' ,& + UNITS = 'days' ,& + SHORT_NAME = 'CNFSEL' ,& + DIMS = MAPL_DimsTileOnly ,& + VLOCATION = MAPL_VLocationNone ,& + RC=STATUS ) + + call MAPL_AddExportSpec(GC ,& + LONG_NAME = 'absorbed_PAR' ,& + UNITS = 'W m-2' ,& + SHORT_NAME = 'PARABS' ,& + DIMS = MAPL_DimsTileOnly ,& + VLOCATION = MAPL_VLocationNone ,& + RC=STATUS ) + VERIFY_(STATUS) + + call MAPL_AddExportSpec(GC ,& + LONG_NAME = 'incident_PAR' ,& + UNITS = 'W m-2' ,& + SHORT_NAME = 'PARINC' ,& + DIMS = MAPL_DimsTileOnly ,& + VLOCATION = MAPL_VLocationNone ,& + RC=STATUS ) + VERIFY_(STATUS) + + call MAPL_AddExportSpec(GC ,& + LONG_NAME = 'saturated_stomatal_conductance' ,& + UNITS = 'm s-1' ,& + SHORT_NAME = 'SCSAT' ,& + DIMS = MAPL_DimsTileOnly ,& + VLOCATION = MAPL_VLocationNone ,& + RC=STATUS ) + VERIFY_(STATUS) + + call MAPL_AddExportSpec(GC ,& + LONG_NAME = 'unstressed_stomatal_conductance' ,& + UNITS = 'm s-1' ,& + SHORT_NAME = 'SCUNS' ,& + DIMS = MAPL_DimsTileOnly ,& + VLOCATION = MAPL_VLocationNone ,& + RC=STATUS ) + VERIFY_(STATUS) + + call MAPL_AddExportSpec(GC ,& + LONG_NAME = 'transpiration coefficient' ,& + UNITS = '1' ,& + SHORT_NAME = 'BTRANT' ,& + DIMS = MAPL_DimsTileOnly ,& + VLOCATION = MAPL_VLocationNone ,& + RC=STATUS ) + VERIFY_(STATUS) + + + call MAPL_AddExportSpec(GC ,& + LONG_NAME = 'solar induced fluorescence',& + UNITS = 'umol m-2 sm s-1' ,& + SHORT_NAME = 'SIF' ,& + DIMS = MAPL_DimsTileOnly ,& + VLOCATION = MAPL_VLocationNone ,& + RC=STATUS ) + VERIFY_(STATUS) + + ! !EXPORT FORCING STATE: call MAPL_AddExportSpec( & @@ -1828,6 +2024,7 @@ subroutine Collect_force_ens(gc, import, export, clock, rc) real, pointer :: DZ_enavg(:)=>null() real, pointer :: RainfSnowf(:)=>null() + ! Get my name and setup traceback handle call ESMF_GridCompget(gc, name=comp_name, rc=status) VERIFY_(status) @@ -2181,6 +2378,29 @@ subroutine Collect_land_ens(gc, import, export, clock, rc) real, dimension(:),pointer :: PEATCLSM_WATERLEVEL,PEATCLSM_WATERLEVEL_enavg real, dimension(:),pointer :: PEATCLSM_FSWCHANGE, PEATCLSM_FSWCHANGE_enavg + real, dimension(:), pointer :: CNLAI, CNLAI_enavg + real, dimension(:), pointer :: CNTLAI, CNTLAI_enavg + real, dimension(:), pointer :: CNSAI, CNSAI_enavg + real, dimension(:), pointer :: CNTOTC, CNTOTC_enavg + real, dimension(:), pointer :: CNVEGC, CNVEGC_enavg + real, dimension(:), pointer :: CNROOT, CNROOT_enavg + real, dimension(:), pointer :: CNFROOTC, CNFROOTC_enavg + real, dimension(:), pointer :: CNNPP, CNNPP_enavg + real, dimension(:), pointer :: CNGPP, CNGPP_enavg + real, dimension(:), pointer :: CNSR, CNSR_enavg + real, dimension(:), pointer :: CNNEE, CNNEE_enavg + real, dimension(:), pointer :: CNXSMR, CNXSMR_enavg + real, dimension(:), pointer :: CNADD, CNADD_enavg + real, dimension(:), pointer :: PARABS, PARABS_enavg + real, dimension(:), pointer :: PARINC, PARINC_enavg + real, dimension(:), pointer :: SCSAT, SCSAT_enavg + real, dimension(:), pointer :: SCUNS, SCUNS_enavg + real, dimension(:), pointer :: BTRANT, BTRANT_enavg + real, dimension(:), pointer :: SIF, SIF_enavg + real, dimension(:), pointer :: CNLOSS, CNLOSS_enavg + real, dimension(:), pointer :: CNBURN, CNBURN_enavg + real, dimension(:), pointer :: CNFSEL, CNFSEL_enavg + ! Get my name and setup traceback handle call ESMF_GridCompget(gc, name=comp_name, rc=status) VERIFY_(status) @@ -2526,6 +2746,32 @@ subroutine Collect_land_ens(gc, import, export, clock, rc) call MAPL_GetPointer(import, ITY, 'ITY' ,rc=status) VERIFY_(status) + ! CatchCN-specific variables (not available in standard Catch) + + call MAPL_GetPointer(import, CNLAI , 'CNLAI' , notFoundOK=.true., _RC) + call MAPL_GetPointer(import, CNTLAI , 'CNTLAI', notFoundOK=.true., _RC) + call MAPL_GetPointer(import, CNSAI , 'CNSAI' , notFoundOK=.true., _RC) + call MAPL_GetPointer(import, CNTOTC , 'CNTOTC', notFoundOK=.true., _RC) + call MAPL_GetPointer(import, CNVEGC , 'CNVEGC', notFoundOK=.true., _RC) + call MAPL_GetPointer(import, CNROOT , 'CNROOT', notFoundOK=.true., _RC) ! CatchCNCLM45 only + call MAPL_GetPointer(import, CNFROOTC , 'CNFROOTC', notFoundOK=.true., _RC) + call MAPL_GetPointer(import, CNNPP , 'CNNPP' , notFoundOK=.true., _RC) + call MAPL_GetPointer(import, CNGPP , 'CNGPP' , notFoundOK=.true., _RC) + call MAPL_GetPointer(import, CNSR , 'CNSR' , notFoundOK=.true., _RC) + call MAPL_GetPointer(import, CNNEE , 'CNNEE' , notFoundOK=.true., _RC) + call MAPL_GetPointer(import, CNXSMR , 'CNXSMR', notFoundOK=.true., _RC) + call MAPL_GetPointer(import, CNADD , 'CNADD' , notFoundOK=.true., _RC) + call MAPL_GetPointer(import, PARABS , 'PARABS', notFoundOK=.true., _RC) + call MAPL_GetPointer(import, PARINC , 'PARINC', notFoundOK=.true., _RC) + call MAPL_GetPointer(import, SCSAT , 'SCSAT' , notFoundOK=.true., _RC) + call MAPL_GetPointer(import, SCUNS , 'SCUNS' , notFoundOK=.true., _RC) + call MAPL_GetPointer(import, BTRANT , 'BTRANT', notFoundOK=.true., _RC) + call MAPL_GetPointer(import, SIF , 'SIF' , notFoundOK=.true., _RC) + call MAPL_GetPointer(import, CNLOSS , 'CNLOSS', notFoundOK=.true., _RC) + call MAPL_GetPointer(import, CNBURN , 'CNBURN', notFoundOK=.true., _RC) + call MAPL_GetPointer(import, CNFSEL , 'CNFSEL', notFoundOK=.true., _RC) + + call MAPL_GetPointer(export, TC_enavg, 'TC' ,rc=status) VERIFY_(status) @@ -2792,6 +3038,29 @@ subroutine Collect_land_ens(gc, import, export, clock, rc) call MAPL_GetPointer(export, out_lai, 'LAI' , alloc=.true., rc=status) VERIFY_(status) + call MAPL_GetPointer(export, CNLAI_enavg , 'CNLAI' , _RC) + call MAPL_GetPointer(export, CNTLAI_enavg , 'CNTLAI', _RC) + call MAPL_GetPointer(export, CNSAI_enavg , 'CNSAI' , _RC) + call MAPL_GetPointer(export, CNTOTC_enavg , 'CNTOTC', _RC) + call MAPL_GetPointer(export, CNVEGC_enavg , 'CNVEGC', _RC) + call MAPL_GetPointer(export, CNROOT_enavg , 'CNROOT', _RC) + call MAPL_GetPointer(export, CNFROOTC_enavg, 'CNFROOTC', _RC) + call MAPL_GetPointer(export, CNNPP_enavg , 'CNNPP' , _RC) + call MAPL_GetPointer(export, CNGPP_enavg , 'CNGPP' , _RC) + call MAPL_GetPointer(export, CNSR_enavg , 'CNSR' , _RC) + call MAPL_GetPointer(export, CNNEE_enavg , 'CNNEE' , _RC) + call MAPL_GetPointer(export, CNXSMR_enavg , 'CNXSMR', _RC) + call MAPL_GetPointer(export, CNADD_enavg , 'CNADD' , _RC) + call MAPL_GetPointer(export, PARABS_enavg , 'PARABS', _RC) + call MAPL_GetPointer(export, PARINC_enavg , 'PARINC', _RC) + call MAPL_GetPointer(export, SCSAT_enavg , 'SCSAT' , _RC) + call MAPL_GetPointer(export, SCUNS_enavg , 'SCUNS' , _RC) + call MAPL_GetPointer(export, BTRANT_enavg , 'BTRANT', _RC) + call MAPL_GetPointer(export, SIF_enavg , 'SIF' , _RC) + call MAPL_GetPointer(export, CNLOSS_enavg , 'CNLOSS', _RC) + call MAPL_GetPointer(export, CNBURN_enavg , 'CNBURN', _RC) + call MAPL_GetPointer(export, CNFSEL_enavg , 'CNFSEL', _RC) + out_lai = in_lai if (collect_land_counter == 0) then @@ -2926,6 +3195,29 @@ subroutine Collect_land_ens(gc, import, export, clock, rc) if(associated(SPSNOW_enavg)) SPSNOW_enavg = 0.0 if(associated(PEATCLSM_WATERLEVEL_enavg)) PEATCLSM_WATERLEVEL_enavg = 0.0 if(associated(PEATCLSM_FSWCHANGE_enavg)) PEATCLSM_FSWCHANGE_enavg = 0.0 + + if(associated( CNLAI_enavg)) CNLAI_enavg = 0.0 + if(associated( CNTLAI_enavg)) CNTLAI_enavg = 0.0 + if(associated( CNSAI_enavg)) CNSAI_enavg = 0.0 + if(associated( CNTOTC_enavg)) CNTOTC_enavg = 0.0 + if(associated( CNVEGC_enavg)) CNVEGC_enavg = 0.0 + if(associated( CNROOT_enavg)) CNROOT_enavg = 0.0 + if(associated( CNFROOTC_enavg)) CNFROOTC_enavg = 0.0 + if(associated( CNNPP_enavg)) CNNPP_enavg = 0.0 + if(associated( CNGPP_enavg)) CNGPP_enavg = 0.0 + if(associated( CNSR_enavg)) CNSR_enavg = 0.0 + if(associated( CNNEE_enavg)) CNNEE_enavg = 0.0 + if(associated( CNXSMR_enavg)) CNXSMR_enavg = 0.0 + if(associated( CNADD_enavg)) CNADD_enavg = 0.0 + if(associated( PARABS_enavg)) PARABS_enavg = 0.0 + if(associated( PARINC_enavg)) PARINC_enavg = 0.0 + if(associated( SCSAT_enavg)) SCSAT_enavg = 0.0 + if(associated( SCUNS_enavg)) SCUNS_enavg = 0.0 + if(associated( BTRANT_enavg)) BTRANT_enavg = 0.0 + if(associated( SIF_enavg)) SIF_enavg = 0.0 + if(associated( CNLOSS_enavg)) CNLOSS_enavg = 0.0 + if(associated( CNBURN_enavg)) CNBURN_enavg = 0.0 + if(associated( CNFSEL_enavg)) CNFSEL_enavg = 0.0 endif if(associated(TC_enavg) .and. associated(TC)) & @@ -3191,6 +3483,29 @@ subroutine Collect_land_ens(gc, import, export, clock, rc) if(associated(PEATCLSM_FSWCHANGE_enavg) .and. associated(PEATCLSM_FSWCHANGE)) & PEATCLSM_FSWCHANGE_enavg = PEATCLSM_FSWCHANGE_enavg + PEATCLSM_FSWCHANGE + if(associated( CNLAI_enavg) .and. associated( CNLAI)) CNLAI_enavg = CNLAI_enavg + CNLAI + if(associated( CNTLAI_enavg) .and. associated(CNTLAI)) CNTLAI_enavg = CNTLAI_enavg + CNTLAI + if(associated( CNSAI_enavg) .and. associated( CNSAI)) CNSAI_enavg = CNSAI_enavg + CNSAI + if(associated( CNTOTC_enavg) .and. associated(CNTOTC)) CNTOTC_enavg = CNTOTC_enavg + CNTOTC + if(associated( CNVEGC_enavg) .and. associated(CNVEGC)) CNVEGC_enavg = CNVEGC_enavg + CNVEGC + if(associated( CNROOT_enavg) .and. associated(CNROOT)) CNROOT_enavg = CNROOT_enavg + CNROOT + if(associated( CNFROOTC_enavg) .and. associated(CNFROOTC)) CNFROOTC_enavg = CNFROOTC_enavg + CNFROOTC + if(associated( CNNPP_enavg) .and. associated( CNNPP)) CNNPP_enavg = CNNPP_enavg + CNNPP + if(associated( CNGPP_enavg) .and. associated( CNGPP)) CNGPP_enavg = CNGPP_enavg + CNGPP + if(associated( CNSR_enavg) .and. associated( CNSR)) CNSR_enavg = CNSR_enavg + CNSR + if(associated( CNNEE_enavg) .and. associated( CNNEE)) CNNEE_enavg = CNNEE_enavg + CNNEE + if(associated( CNXSMR_enavg).and. associated( CNXSMR))CNXSMR_enavg = CNXSMR_enavg+ CNXSMR + if(associated( CNADD_enavg) .and. associated( CNADD)) CNADD_enavg = CNADD_enavg + CNADD + if(associated( PARABS_enavg) .and. associated(PARABS)) PARABS_enavg = PARABS_enavg + PARABS + if(associated( PARINC_enavg) .and. associated(PARINC)) PARINC_enavg = PARINC_enavg + PARINC + if(associated( SCSAT_enavg) .and. associated( SCSAT)) SCSAT_enavg = SCSAT_enavg + SCSAT + if(associated( SCUNS_enavg) .and. associated( SCUNS)) SCUNS_enavg = SCUNS_enavg + SCUNS + if(associated( BTRANT_enavg) .and. associated(BTRANT)) BTRANT_enavg = BTRANT_enavg + BTRANT + if(associated( SIF_enavg) .and. associated( SIF)) SIF_enavg = SIF_enavg + SIF + if(associated( CNLOSS_enavg) .and. associated(CNLOSS)) CNLOSS_enavg = CNLOSS_enavg + CNLOSS + if(associated( CNBURN_enavg) .and. associated(CNBURN)) CNBURN_enavg = CNBURN_enavg + CNBURN + if(associated( CNFSEL_enavg) .and. associated(CNFSEL)) CNFSEL_enavg = CNFSEL_enavg + CNFSEL + ! This counter is relative to ens_id collect_land_counter = collect_land_counter + 1 !collect catch_progn @@ -3367,6 +3682,29 @@ subroutine Collect_land_ens(gc, import, export, clock, rc) if(associated(PEATCLSM_WATERLEVEL_enavg)) PEATCLSM_WATERLEVEL_enavg = PEATCLSM_WATERLEVEL_enavg/NUM_ENSEMBLE if(associated(PEATCLSM_FSWCHANGE_enavg)) PEATCLSM_FSWCHANGE_enavg = PEATCLSM_FSWCHANGE_enavg /NUM_ENSEMBLE + if(associated( CNLAI_enavg)) CNLAI_enavg = CNLAI_enavg/NUM_ENSEMBLE + if(associated( CNTLAI_enavg)) CNTLAI_enavg = CNTLAI_enavg/NUM_ENSEMBLE + if(associated( CNSAI_enavg)) CNSAI_enavg = CNSAI_enavg/NUM_ENSEMBLE + if(associated( CNTOTC_enavg)) CNTOTC_enavg = CNTOTC_enavg/NUM_ENSEMBLE + if(associated( CNVEGC_enavg)) CNVEGC_enavg = CNVEGC_enavg/NUM_ENSEMBLE + if(associated( CNROOT_enavg)) CNROOT_enavg = CNROOT_enavg/NUM_ENSEMBLE + if(associated( CNFROOTC_enavg)) CNFROOTC_enavg = CNFROOTC_enavg/NUM_ENSEMBLE + if(associated( CNNPP_enavg)) CNNPP_enavg = CNNPP_enavg/NUM_ENSEMBLE + if(associated( CNGPP_enavg)) CNGPP_enavg = CNGPP_enavg/NUM_ENSEMBLE + if(associated( CNSR_enavg)) CNSR_enavg = CNSR_enavg/NUM_ENSEMBLE + if(associated( CNNEE_enavg)) CNNEE_enavg = CNNEE_enavg/NUM_ENSEMBLE + if(associated( CNXSMR_enavg)) CNXSMR_enavg = CNXSMR_enavg/NUM_ENSEMBLE + if(associated( CNADD_enavg)) CNADD_enavg = CNADD_enavg/NUM_ENSEMBLE + if(associated( PARABS_enavg)) PARABS_enavg = PARABS_enavg/NUM_ENSEMBLE + if(associated( PARINC_enavg)) PARINC_enavg = PARINC_enavg/NUM_ENSEMBLE + if(associated( SCSAT_enavg)) SCSAT_enavg = SCSAT_enavg/NUM_ENSEMBLE + if(associated( SCUNS_enavg)) SCUNS_enavg = SCUNS_enavg/NUM_ENSEMBLE + if(associated( BTRANT_enavg)) BTRANT_enavg = BTRANT_enavg/NUM_ENSEMBLE + if(associated( SIF_enavg)) SIF_enavg = SIF_enavg/NUM_ENSEMBLE + if(associated( CNLOSS_enavg)) CNLOSS_enavg = CNLOSS_enavg/NUM_ENSEMBLE + if(associated( CNBURN_enavg)) CNBURN_enavg = CNBURN_enavg/NUM_ENSEMBLE + if(associated( CNFSEL_enavg)) CNFSEL_enavg = CNFSEL_enavg/NUM_ENSEMBLE + ! Deal with no-data-values ! ! Surface temperature components may be nodata in some but not all ensemble members. @@ -3384,10 +3722,10 @@ subroutine Collect_land_ens(gc, import, export, clock, rc) ! ! - reichle, 29 May 2020 - if(associated(TPSNOW_enavg)) where (TPSNOW_enavg > enavg_nodata_threshold) TPSNOW_enavg = MAPL_UNDEF - if(associated(TPSAT_enavg )) where (TPSAT_enavg > enavg_nodata_threshold) TPSAT_enavg = MAPL_UNDEF - if(associated(TPWLT_enavg )) where (TPWLT_enavg > enavg_nodata_threshold) TPWLT_enavg = MAPL_UNDEF - if(associated(TPUNST_enavg)) where (TPUNST_enavg > enavg_nodata_threshold) TPUNST_enavg = MAPL_UNDEF + if(associated(TPSNOW_enavg)) where (TPSNOW_enavg > enavg_nodata_threshold) TPSNOW_enavg = MAPL_UNDEF + if(associated(TPSAT_enavg )) where (TPSAT_enavg > enavg_nodata_threshold) TPSAT_enavg = MAPL_UNDEF + if(associated(TPWLT_enavg )) where (TPWLT_enavg > enavg_nodata_threshold) TPWLT_enavg = MAPL_UNDEF + if(associated(TPUNST_enavg)) where (TPUNST_enavg > enavg_nodata_threshold) TPUNST_enavg = MAPL_UNDEF ! restore exact no-data-values for PEATCLSM diagnostics in mineral tiles diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/CMakeLists.txt b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/CMakeLists.txt index cfccafa6..89684a1e 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 MAPL GMAO_gfio_r4 hdf5hl_fortran hdf5_fortran ${NETCDF_LIBRARIES} + DEPENDENCIES GEOS_LdasShared GEOSens_GridComp GEOSlandpert_GridComp GEOSland_GridComp raster MAPL 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 9e7c9046..d72d3521 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/GEOS_LandAssimGridComp.F90 @@ -31,7 +31,7 @@ module GEOS_LandAssimGridCompMod use LDAS_ensdrv_mpi, only: MPI_obs_param_type use LDAS_DateTimeMod, only: date_time_type - use LDAS_ensdrv_Globals, only: logunit, LDAS_is_nodata, nodata_generic + use LDAS_ensdrv_Globals, only: logunit, LDAS_is_nodata, nodata_generic, get_ensid_string use LDAS_ConvertMod, only: esmf2ldas use LDAS_DriverTypes, only: met_force_type @@ -144,9 +144,9 @@ subroutine SetServices ( GC, RC ) type(MAPL_MetaComp), pointer :: MAPL=>null() type(ESMF_Config) :: CF character(len=ESMF_MAXSTR) :: LAND_ASSIM_STR, mwRTM_file - character(len=ESMF_MAXSTR) :: id_string,childname, fmt_str + character(len=ESMF_MAXSTR) :: ensid_string,childname, fmt_str integer :: i, ens_id_width, FIRST_ENS_ID, NUM_ENSEMBLE - integer, allocatable, dimension(:) :: ens_id, export_id + integer :: ens_id, export_id ! Begin... ! -------- @@ -1002,20 +1002,14 @@ subroutine SetServices ( GC, RC ) call MAPL_GetResource ( MAPL, ens_id_width, Label="ENS_ID_WIDTH:", DEFAULT=0, RC=STATUS) VERIFY_(STATUS) - write (fmt_str, "(A2,I1,A1,I1,A1)") "(I", ens_id_width,".",ens_id_width,")" - allocate(ens_id(NUM_ENSEMBLE), export_id(NUM_ENSEMBLE)) do i=1,NUM_ENSEMBLE - ens_id(i) = i-1 + FIRST_ENS_ID ! id start form FIRST_ENS_ID - if (NUM_ENSEMBLE == 1 ) then - id_string='' - else - write(id_string, fmt_str) ens_id(i) - endif - id_string=trim(id_string) + ens_id = i-1 + FIRST_ENS_ID ! id start form FIRST_ENS_ID - childname='CATCHINCR'//trim(id_string) - export_id(i) = MAPL_AddChild(gc, name=childname, ss=ExportCatchIncrSetServices, rc=status) + call get_ensid_string(ensid_string, ens_id, ens_id_width, NUM_ENSEMBLE) + + childname='CATCHINCR'//trim(ensid_string) + export_id = MAPL_AddChild(gc, name=childname, ss=ExportCatchIncrSetServices, rc=status) VERIFY_(status) enddo endif @@ -1089,7 +1083,7 @@ subroutine Initialize(gc, import, export, clock, rc) character(len=300) :: seed_fname character(len=300) :: fname_tpl character(len=14) :: datestamp - character(len=ESMF_MAXSTR) :: id_string + character(len=ESMF_MAXSTR) :: ensid_string integer :: nymd, nhms, yy, mm, dd, h, m, s !! from LDASsa @@ -1249,10 +1243,10 @@ subroutine Initialize(gc, import, export, clock, rc) allocate(Pert_rseed_r8(NRANDSEED, NUM_ENSEMBLE), source = 0.0d0) if (root_proc) then - call MAPL_GetResource( MAPL, ens_id_width,"ENS_ID_WIDTH:", default=4, RC=STATUS) + call MAPL_GetResource( MAPL, ens_id_width,"ENS_ID_WIDTH:", default=6, RC=STATUS) _VERIFY(status) call MAPL_GetResource( MAPL, fname_tpl, Label="LANDASSIM_OBSPERTRSEED_RESTART_FILE:", & - DEFAULT="../input/restart/landassim_obspertrseed%s_rst", RC=STATUS) + DEFAULT="../input/restart/landassim_obspertrseed%s_rst", RC=STATUS) _VERIFY(STATUS) ! It is consistent with the default that psert seed time is one LandAssim_DT behind assim time @@ -1271,10 +1265,10 @@ subroutine Initialize(gc, import, export, clock, rc) nhms = h *10000 + m*100 + s do ens = 0, NUM_ENSEMBLE-1 - call get_id_string(id_string, ens + FIRST_ENS_ID, ens_id_width) + call get_ensid_string(ensid_string, ens + FIRST_ENS_ID, ens_id_width, NUM_ENSEMBLE ) ! "_eXXXX" seed_fname = "" - call ESMF_CFIOStrTemplate(seed_fname,fname_tpl,'GRADS', xid=trim(id_string), nymd=nymd,nhms=nhms,stat=status) - call read_pert_rseed(trim(id_string),seed_fname,Pert_rseed_r8(:,ens+1)) + call ESMF_CFIOStrTemplate(seed_fname,fname_tpl,'GRADS', xid=trim(ensid_string), nymd=nymd,nhms=nhms,stat=status) + call read_pert_rseed(trim(ensid_string),seed_fname,Pert_rseed_r8(:,ens+1)) Pert_rseed(:,ens+1) = nint(Pert_rseed_r8(:,ens+1)) if (all(Pert_rseed(:,ens+1) == 0)) then @@ -1354,7 +1348,7 @@ subroutine Initialize(gc, import, export, clock, rc) call MAPL_GetResource ( MAPL, GridName, Label="GEOSldas.GRIDNAME:", DEFAULT="EASE", RC=STATUS) _VERIFY(STATUS) _ASSERT( (NUM_ENSEMBLE>1), "out_smapL4SMaup=.true. only works for NUM_ENSEMBLE>1") - _ASSERT( (index(GridName,"EASEv2-M09") /=0), "out_smapL4SMaup=.true. only works with EASEv2-M09 tile space") + _ASSERT( (index(GridName,"EASEv2-M09") /=0 .or. index(GridName,"EASEv2_M09") /=0), "out_smapL4SMaup=.true. only works with EASEv2-M09 tile space") end if @@ -1504,7 +1498,7 @@ subroutine RUN ( GC, IMPORT, EXPORT, CLOCK, RC ) integer :: N_catbias character(len=300) :: seed_fname character(len=300) :: fname_tpl - character(len=ESMF_MAXSTR) :: id_string + character(len=ESMF_MAXSTR) :: ensid_string integer :: ens, nymd, nhms, ens_id_width integer :: LandassimDTstep #ifdef DBG_LANDASSIM_INPUTS @@ -1583,7 +1577,7 @@ subroutine RUN ( GC, IMPORT, EXPORT, CLOCK, RC ) if (MAPL_RecordAlarmIsRinging(MAPL)) then if (root_proc) then Pert_rseed_r8 = Pert_rseed - call MAPL_GetResource( MAPL, ens_id_width,"ENS_ID_WIDTH:", default=4, RC=STATUS) + call MAPL_GetResource( MAPL, ens_id_width,"ENS_ID_WIDTH:", default=6, RC=STATUS) _VERIFY(status) call MAPL_GetResource ( MAPL, fname_tpl, Label="LANDASSIM_OBSPERTRSEED_CHECKPOINT_FILE:", DEFAULT="landassim_obspertrseed%s_checkpoint", RC=STATUS) _VERIFY(STATUS) @@ -1594,9 +1588,9 @@ subroutine RUN ( GC, IMPORT, EXPORT, CLOCK, RC ) read(datestamp(10:13),*) nhms nhms = nhms*100 do ens = 0, NUM_ENSEMBLE-1 - call get_id_string(id_string, ens + FIRST_ENS_ID, ens_id_width) + call get_ensid_string(ensid_string, ens + FIRST_ENS_ID, ens_id_width, NUM_ENSEMBLE) ! " _eXXXX" seed_fname = "" - call ESMF_CFIOStrTemplate(seed_fname,fname_tpl,'GRADS', xid=trim(id_string),nymd=nymd,nhms=nhms,stat=status) + call ESMF_CFIOStrTemplate(seed_fname,fname_tpl,'GRADS', xid=trim(ensid_string),nymd=nymd,nhms=nhms,stat=status) _VERIFY(STATUS) call write_pert_rseed(trim(seed_fname), Pert_rseed_r8(:,ens+1)) enddo @@ -2532,9 +2526,9 @@ end subroutine EXPORT_INCR ! ****************************************************************************** - subroutine read_pert_rseed(id_string,seed_fname,pert_rseed_r8) + subroutine read_pert_rseed(ensid_string,seed_fname,pert_rseed_r8) use netcdf - character(len=*),intent(in) :: id_string + character(len=*),intent(in) :: ensid_string character(len=*),intent(in) :: seed_fname real(kind=ESMF_KIND_R8),intent(inout) :: pert_rseed_r8(:) @@ -2545,7 +2539,7 @@ subroutine read_pert_rseed(id_string,seed_fname,pert_rseed_r8) inquire (file = trim(seed_fname), exist=file_exist) if ( .not. file_exist) then - tmpstr = 'Cold-starting OBSPERTRSEED for ens member ' // trim(id_string) // '.' + tmpstr = 'Cold-starting OBSPERTRSEED for ens member ' // trim(ensid_string) // '.' if (len_trim(seed_fname)>0) then print *, trim(tmpstr), 'File not found: ', trim(seed_fname) else @@ -2554,7 +2548,7 @@ subroutine read_pert_rseed(id_string,seed_fname,pert_rseed_r8) pert_rseed_r8 = 0 return else - tmpstr = 'Reading OBSPERTRSEED for ens member ' // trim(id_string) // ' from ' + tmpstr = 'Reading OBSPERTRSEED for ens member ' // trim(ensid_string) // ' from ' print *, trim(tmpstr), trim(seed_fname) endif @@ -2802,20 +2796,6 @@ end subroutine get_vegopacity ! ****************************************************************************** - subroutine get_id_string(id_string, id, ens_id_width) - character(*), intent(inout) :: id_string - integer, intent(in) :: id - integer, intent(in) :: ens_id_width - - character(len=ESMF_MAXSTR) :: fmt_str - - write (fmt_str, "(A2,I1,A1,I1,A1)") "(I", ens_id_width,".",ens_id_width,")" - write (id_string, fmt_str) id - - end subroutine - - ! ****************************************************************************** - !BOP ! !IROTUINE: Finalize -- finalize method for LDAS GC ! !INTERFACE: @@ -2840,7 +2820,7 @@ subroutine Finalize(gc, import, export, clock, rc) character(len=300) :: fname_tpl character(len=300) :: out_path character(len=ESMF_MAXSTR) :: exp_id - character(len=ESMF_MAXSTR) :: id_string + character(len=ESMF_MAXSTR) :: ensid_string character(len=14) :: datestamp integer :: ens, nymd, nhms, ens_id_width @@ -2861,7 +2841,7 @@ subroutine Finalize(gc, import, export, clock, rc) if (root_proc) then if (out_obslog) call finalize_obslog() Pert_rseed_r8 = Pert_rseed - call MAPL_GetResource( MAPL, ens_id_width,"ENS_ID_WIDTH:", default=4, RC=STATUS) + call MAPL_GetResource( MAPL, ens_id_width,"ENS_ID_WIDTH:", default=6, RC=STATUS) _VERIFY(status) call MAPL_GetResource ( MAPL, fname_tpl, Label="LANDASSIM_OBSPERTRSEED_CHECKPOINT_FILE:", & DEFAULT="landassim_obspertrseed%s_checkpoint", RC=STATUS) @@ -2873,9 +2853,9 @@ subroutine Finalize(gc, import, export, clock, rc) read(datestamp(10:13),*) nhms nhms = nhms*100 do ens = 0, NUM_ENSEMBLE-1 - call get_id_string(id_string, ens + FIRST_ENS_ID, ens_id_width) + call get_ensid_string(ensid_string, ens + FIRST_ENS_ID, ens_id_width, NUM_ENSEMBLE ) seed_fname = "" - call ESMF_CFIOStrTemplate(seed_fname,fname_tpl,'GRADS', xid=trim(id_string),nymd=nymd,nhms=nhms,stat=status) + call ESMF_CFIOStrTemplate(seed_fname,fname_tpl,'GRADS', xid=trim(ensid_string),nymd=nymd,nhms=nhms,stat=status) _VERIFY(STATUS) call write_pert_rseed(trim(seed_fname), Pert_rseed_r8(:,ens+1)) enddo 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 6736c503..764cfada 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 @@ -73,9 +73,8 @@ module clsm_ensupd_enkf_update use nr_ran2_gasdev, ONLY: & NRANDSEED - use LDAS_ease_conv, ONLY: & - easeV1_convert, & - easeV2_convert + use ease_conv, ONLY: & + ease_convert use my_matrix_functions, ONLY: & row_std @@ -2100,14 +2099,14 @@ subroutine write_smapL4SMaup( option, date_time, work_path, exp_id, N_ens, & character(len=*), parameter :: Iam = 'write_smapL4SMaup' character(len=400) :: err_msg + character(len=10) :: gridname_tmp ! -------------------------------------------------------------- ! ! smapL4SMaup output only works for 9 km EASE grids - if ( (trim(tile_grid_g%gridtype)/='EASE_M09' ) .and. & - (trim(tile_grid_g%gridtype)/='EASEv2_M09') ) then - err_msg = 'out_smapL4SMaup requires tile-space for 9 km EASE[v2] grid' + if ( index(tile_grid_g%gridtype, 'M09') == 0 ) then + err_msg = 'out_smapL4SMaup requires tile-space for 9 km EASEv1 or EASEv2 grid' call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) end if @@ -2228,17 +2227,11 @@ subroutine write_smapL4SMaup( option, date_time, work_path, exp_id, N_ens, & 'SMAP_L1C_Tbh_E09_D', 'SMAP_L1C_Tbv_E09_D', & 'SMAP_L1C_Tbh_E09_A', 'SMAP_L1C_Tbv_E09_A' & ) - - if (trim(tile_grid_g%gridtype)=='EASE_M09') then - - call easeV1_convert('M09', this_lat, this_lon, col_ind, row_ind) - - elseif (trim(tile_grid_g%gridtype)=='EASEv2_M09') then - - call easeV2_convert('M09', this_lat, this_lon, col_ind, row_ind) - - end if - + + if (index(tile_grid_g%gridtype, 'M09') /=0) then + call ease_convert(trim(tile_grid_g%gridtype), this_lat, this_lon, col_ind, row_ind) + endif + ! col_ind and row_ind are zero-based, need one-based index here col_beg_9km(n) = nint(col_ind)+1 @@ -2253,16 +2246,10 @@ subroutine write_smapL4SMaup( option, date_time, work_path, exp_id, N_ens, & case('SMAP_L1C_Tbh_E27_D', 'SMAP_L1C_Tbv_E27_D', & 'SMAP_L1C_Tbh_E27_A', 'SMAP_L1C_Tbv_E27_A' & ) - - if (trim(tile_grid_g%gridtype)=='EASE_M09') then - - call easeV1_convert('M09', this_lat, this_lon, col_ind, row_ind) - - elseif (trim(tile_grid_g%gridtype)=='EASEv2_M09') then - - call easeV2_convert('M09', this_lat, this_lon, col_ind, row_ind) - - end if + + if (index(tile_grid_g%gridtype, 'M09') /=0) then + call ease_convert(trim(tile_grid_g%gridtype), this_lat, this_lon, col_ind, row_ind) + endif ! col_ind and row_ind are zero-based, need one-based index here ! L1C E27 spacing is one every three in each direction (~27-km spacing) @@ -2282,16 +2269,12 @@ subroutine write_smapL4SMaup( option, date_time, work_path, exp_id, N_ens, & 'SMOS_fit_Tbh_A', 'SMOS_fit_Tbv_A' & ) - if (trim(tile_grid_g%gridtype)=='EASE_M09') then - - call easeV1_convert('M36', this_lat, this_lon, col_ind, row_ind) - - elseif (trim(tile_grid_g%gridtype)=='EASEv2_M09') then - - call easeV2_convert('M36', this_lat, this_lon, col_ind, row_ind) - - end if - + if (index(tile_grid_g%gridtype, 'M09') /=0) then + ! subindex (1:7) to get the string EASEvx_ + gridname_tmp = tile_grid_g%gridtype(1:7)//'M36' + call ease_convert(gridname_tmp, this_lat, this_lon, col_ind, row_ind) + endif + ! col_ind and row_ind are zero-based, need one-based index here col_beg_9km(n) = nint(col_ind) *4 + 1 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 0f892960..5937a6e0 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 @@ -21,9 +21,9 @@ module clsm_ensupd_read_obs use io_hdf5, ONLY: & hdf5read - use LDAS_ease_conv, ONLY: & - easeV2_convert, & - easeV2_extent + use EASE_conv, ONLY: & + ease_convert, & + ease_extent use LDAS_ensdrv_globals, ONLY: & logit, & @@ -4436,12 +4436,12 @@ subroutine read_obs_SMOS( date_time, N_catd, this_obs_param, & if (tmp_tile_num(ii)>0) then - call easeV2_convert('M36', & + call ease_convert('EASEv2_M36', & tile_coord(tmp_tile_num(ii))%com_lat, & tile_coord(tmp_tile_num(ii))%com_lon, & M36_col_ind_tile, M36_row_ind_tile ) - call easeV2_convert('M36', & + call ease_convert('EASEv2_M36', & tmp_lat(ii), & tmp_lon(ii), & M36_col_ind_obs, M36_row_ind_obs ) @@ -5127,12 +5127,12 @@ subroutine read_obs_SMAP_FT( date_time, N_catd, this_obs_param, & if (tmp_tile_num(ii)>0) then - call easeV2_convert('M09', & + call ease_convert('EASEv2_M09', & tile_coord(tmp_tile_num(ii))%com_lat, & tile_coord(tmp_tile_num(ii))%com_lon, & M09_col_ind_tile, M09_row_ind_tile ) - call easeV2_convert('M09', & + call ease_convert('EASEv2_M09', & tmp_lat(ii), & tmp_lon(ii), & M09_col_ind_obs, M09_row_ind_obs ) @@ -6118,7 +6118,7 @@ subroutine read_obs_SMAP_halforbit_Tb( date_time, N_catd, this_obs_param, & ! shift M36 obs lat/lon for proper assignment of M09 tile? - if ( L1C_files .and. (index(tile_grid_d%gridtype, 'EASEv2_M09') /=0) ) then + if ( L1C_files .and. (index(tile_grid_d%gridtype, 'EASEv2_M09') /=0 .or. index(tile_grid_d%gridtype, 'EASEv2-M09') /=0 )) then ! temporarily shift lat/lon of obs for computation of nearest tile to ! avoid ambiguous assignment of M09 model tile within M36 obs grid cell @@ -6185,12 +6185,12 @@ subroutine read_obs_SMAP_halforbit_Tb( date_time, N_catd, this_obs_param, & if (tmp_tile_num(ii)>0) then - call easeV2_convert('M36', & + call ease_convert('EASEv2_M36', & tile_coord(tmp_tile_num(ii))%com_lat, & tile_coord(tmp_tile_num(ii))%com_lon, & M36_col_ind_tile, M36_row_ind_tile ) - call easeV2_convert('M36', & + call ease_convert('EASEv2_M36', & tmp_lat(ii), & tmp_lon(ii), & M36_col_ind_obs, M36_row_ind_obs ) @@ -6486,7 +6486,7 @@ subroutine turn_off_assim_SMAP_L1CTb(N_obs_param, obs_param, N_obsl, Observation ! ! assemble 36 km EASEv2 mask of L2AP_Tb obs - call easeV2_extent( 'M36', N_cols, N_rows ) + call ease_extent( 'EASEv2_M36', N_cols, N_rows ) allocate( mask_h_A(N_cols,N_rows) ) allocate( mask_h_D(N_cols,N_rows) ) @@ -6508,7 +6508,7 @@ subroutine turn_off_assim_SMAP_L1CTb(N_obs_param, obs_param, N_obsl, Observation if (Observations_f(ii)%species==species_L2AP_Tbh_A) then - call easeV2_convert('M36', Observations_f(ii)%lat, Observations_f(ii)%lon, & + call ease_convert('EASEv2_M36', Observations_f(ii)%lat, Observations_f(ii)%lon, & col, row) ! set mask=.true. for the M36 grid cell that contains the L2AP_Tb obs; @@ -6530,7 +6530,7 @@ subroutine turn_off_assim_SMAP_L1CTb(N_obs_param, obs_param, N_obsl, Observation if (Observations_f(ii)%species==species_L2AP_Tbh_D) then - call easeV2_convert('M36', Observations_f(ii)%lat, Observations_f(ii)%lon, & + call ease_convert('EASEv2_M36', Observations_f(ii)%lat, Observations_f(ii)%lon, & col, row) ! set mask=.true. for the M36 grid cell that contains the L2AP_Tb obs; @@ -6552,7 +6552,7 @@ subroutine turn_off_assim_SMAP_L1CTb(N_obs_param, obs_param, N_obsl, Observation if (Observations_f(ii)%species==species_L2AP_Tbv_A) then - call easeV2_convert('M36', Observations_f(ii)%lat, Observations_f(ii)%lon, & + call ease_convert('EASEv2_M36', Observations_f(ii)%lat, Observations_f(ii)%lon, & col, row) ! set mask=.true. for the M36 grid cell that contains the L2AP_Tb obs; @@ -6574,7 +6574,7 @@ subroutine turn_off_assim_SMAP_L1CTb(N_obs_param, obs_param, N_obsl, Observation if (Observations_f(ii)%species==species_L2AP_Tbv_D) then - call easeV2_convert('M36', Observations_f(ii)%lat, Observations_f(ii)%lon, & + call ease_convert('EASEv2_M36', Observations_f(ii)%lat, Observations_f(ii)%lon, & col, row) ! set mask=.true. for the M36 grid cell that contains the L2AP_Tb obs; @@ -6609,7 +6609,7 @@ subroutine turn_off_assim_SMAP_L1CTb(N_obs_param, obs_param, N_obsl, Observation if (Observations_l(ii)%species==species_L1C_Tbh_A) then - call easeV2_convert('M36', & + call ease_convert('EASEv2_M36', & Observations_l(ii)%lat, Observations_l(ii)%lon, col, row) ! note conversion to one-based indices @@ -6628,7 +6628,7 @@ subroutine turn_off_assim_SMAP_L1CTb(N_obs_param, obs_param, N_obsl, Observation if (Observations_l(ii)%species==species_L1C_Tbh_D) then - call easeV2_convert('M36', & + call ease_convert('EASEv2_M36', & Observations_l(ii)%lat, Observations_l(ii)%lon, col, row) ! note conversion to one-based indices @@ -6649,7 +6649,7 @@ subroutine turn_off_assim_SMAP_L1CTb(N_obs_param, obs_param, N_obsl, Observation if (Observations_l(ii)%species==species_L1C_Tbv_A) then - call easeV2_convert('M36', & + call ease_convert('EASEv2_M36', & Observations_l(ii)%lat, Observations_l(ii)%lon, col, row) ! note conversion to one-based indices @@ -6668,7 +6668,7 @@ subroutine turn_off_assim_SMAP_L1CTb(N_obs_param, obs_param, N_obsl, Observation if (Observations_l(ii)%species==species_L1C_Tbv_D) then - call easeV2_convert('M36', & + call ease_convert('EASEv2_M36', & Observations_l(ii)%lat, Observations_l(ii)%lon, col, row) ! note conversion to one-based indices 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 6f88b864..d102cdfc 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 @@ -1707,9 +1707,7 @@ subroutine get_obs_pred( & ! for EASE grids *ONLY*: screen for non-land surfaces (e.g., lakes) ! - reichle, 28 Mar 2015 - if ( & - (index(tile_grid_g%gridtype, 'EASE_M') /=0) .or. & - (index(tile_grid_g%gridtype, 'EASEv2_M')/=0) ) then + if (index(tile_grid_g%gridtype, 'EASEv') /=0) then ! ASSUMPTIONS: ! - at most one land tile per grid cell @@ -3204,8 +3202,7 @@ subroutine get_obs_pert( N_ens, N_obs, N_obs_param, & pert_grid_lH%ur_lon = pert_grid_lH%ll_lon + delta_lon pert_grid_lH%ur_lat = pert_grid_lH%ll_lat + delta_lat - elseif ( (index(pert_grid_lH%gridtype,'EASE_M') /=0) .or. & - (index(pert_grid_lH%gridtype,'EASEv2_M')/=0) ) then + elseif ( index(pert_grid_lH%gridtype,'EASEv') /=0 ) then pert_grid_lH%dlon = pert_grid_f%dlon diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/mwRTM_routines.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/mwRTM_routines.F90 index a0975464..9c299dab 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/mwRTM_routines.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/mwRTM_routines.F90 @@ -69,7 +69,7 @@ module mwRTM_routines ! Subroutine mwRTM_get_param() reads binary mwRTM files and is no longer used. ! ! The subroutine has been replaced by: - ! - Applications/LDAS_App/mwrtm_bin2nc4.F90 converts mwRTM files from binary to nc4 + ! - Applications/LDAS_App/[..]/mwrtm_bin2nc4.F90 converts mwRTM files from binary to nc4 ! - get_mwrtm_param() in GEOS_LandAssimGridComp.F90 converts the internal state ! variables of the Land Assim GridComp into the mwRTM structure. ! diff --git a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/mwRTM_types.F90 b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/mwRTM_types.F90 index 3d911be2..5c88a945 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/mwRTM_types.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandassim_GridComp/mwRTM_types.F90 @@ -92,7 +92,7 @@ module mwRTM_types ! Subroutine io_mwRTM_param_type() reads and writes binary mwRTM files and is no longer used. ! ! The subroutine has been replaced by: - ! - Applications/LDAS_App/mwrtm_bin2nc4.F90 converts mwRTM files from binary to nc4 + ! - Applications/LDAS_App/[..]/mwrtm_bin2nc4.F90 converts mwRTM files from binary to nc4 ! - get_mwrtm_param() in GEOS_LandAssimGridComp.F90 converts the internal state ! variables of the Land Assim GridComp into the mwRTM structure. ! diff --git a/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/GEOS_LandPertGridComp.F90 b/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/GEOS_LandPertGridComp.F90 index 66ff262b..dd159ffc 100644 --- a/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/GEOS_LandPertGridComp.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSlandpert_GridComp/GEOS_LandPertGridComp.F90 @@ -16,7 +16,7 @@ module GEOS_LandPertGridCompMod use nr_ran2_gasdev, only: NRANDSEED, init_randseed use LDAS_ConvertMod, only: esmf2ldas - use LDAS_ensdrv_Globals, only: nodata_generic, nodata_tol_generic + use LDAS_ensdrv_Globals, only: nodata_generic, nodata_tol_generic, get_ensid_string use LDAS_DriverTypes, only: met_force_type use LDAS_DateTimeMod, only: date_time_type, date_time_print use RepairForcingMod, only: repair_forcing @@ -185,8 +185,8 @@ subroutine SetServices(gc, rc) FIRST_ENS_ID = GEOSldas_FIRST_ENS_ID ens_id = FIRST_ENS_ID if ( internal%NUM_ENSEMBLE > 1) then - !landpertxxxx - read(comp_name(9:12),*) ens_id + !landpert_eXXXX + read(comp_name(11:),*) ens_id endif internal%ens_id= ens_id @@ -956,12 +956,8 @@ subroutine Initialize(gc, import, export, clock, rc) call MAPL_GetResource(MAPL, rst_fname_tmp, 'LANDPERT_INTERNAL_RESTART_FILE:',DEFAULT='NONE', rc=status) VERIFY_(status) - id_string="" - if (internal%NUM_ENSEMBLE > 1) then - n = len(trim(COMP_NAME)) - id_string = COMP_NAME(n-ens_id_width+1:n) - endif - + call get_ensid_string(id_string,internal%ens_id, ens_id_width, internal%NUM_ENSEMBLE) + call ESMF_CFIOStrTemplate(rst_fname, trim(adjustl(rst_fname_tmp)),'GRADS', xid = trim(id_string), stat=status) if (index(rst_fname, 'NONE') == 0 ) then @@ -1673,11 +1669,7 @@ subroutine GenerateRaw_ntrmdt(gc, import, export, clock, rc) call MAPL_DateStampGet(clock, datestamp, rc=status) VERIFY_(STATUS) - id_string='' - if (internal%NUM_ENSEMBLE > 1) then - m = len(trim(COMP_NAME)) - id_string = COMP_NAME(m-ens_id_width+1:m) - endif + call get_ensid_string(id_string,internal%ens_id, ens_id_width, internal%NUM_ENSEMBLE) chk_fname = 'landpert'//trim(id_string)//'_internal_checkpoint.'//datestamp//'.nc4' @@ -2754,11 +2746,8 @@ subroutine Finalize(gc, import, export, clock, rc) enddo ! 4) writing - id_string='' - if (internal%NUM_ENSEMBLE > 1) then - m = len(trim(COMP_NAME)) - id_string = COMP_NAME(m-ens_id_width+1:m) - endif + + call get_ensid_string(id_string,internal%ens_id, ens_id_width, internal%NUM_ENSEMBLE) chk_fname = 'landpert'//trim(id_string)//'_internal_checkpoint' call write_pert_checkpoint(trim(chk_fname),internal%fpert_ntrmdt, internal%ppert_ntrmdt, internal%pert_rseed_r8) diff --git a/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/GEOS_MetforceGridComp.F90 b/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/GEOS_MetforceGridComp.F90 index d8bf4953..78d3cf81 100644 --- a/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/GEOS_MetforceGridComp.F90 +++ b/src/Components/GEOSldas_GridComp/GEOSmetforce_GridComp/GEOS_MetforceGridComp.F90 @@ -559,7 +559,7 @@ subroutine Initialize(gc, import, export, clock, rc) type(tile_coord_type), pointer :: tile_coord(:)=>null() ! Misc variables - integer :: land_nt_local, k, NUM_ENSEMBLE, ens_id_width + integer :: land_nt_local, k, NUM_ENSEMBLE integer :: ForceDtStep type(met_force_type) :: mf_nodata logical :: MERRA_file_specs, ensemble_forcing @@ -567,8 +567,9 @@ subroutine Initialize(gc, import, export, clock, rc) integer :: AEROSOL_DEPOSITION type(MAPL_LocStream) :: locstream - character(len=ESMF_MAXSTR) :: grid_type, ENS_FORCING_STR, ens_forcing_path, id_string + character(len=ESMF_MAXSTR) :: grid_type, ENS_FORCING_STR, ens_forcing_path character(len=ESMF_MAXSTR) :: gridname + character(3) :: ensid_string3 type(ESMF_Grid) :: agrid integer :: dims(ESMF_MAXDIM) ! Begin... @@ -677,13 +678,10 @@ subroutine Initialize(gc, import, export, clock, rc) VERIFY_(STATUS) ensemble_forcing = (trim(ENS_FORCING_STR) == 'YES') if (ensemble_forcing .and. NUM_ENSEMBLE > 1) then - id_string = "" - call MAPL_GetResource ( MAPL, ens_id_width, Label="ENS_ID_WIDTH:", DEFAULT=0, RC=STATUS) + ! note: comp_name ends in "_eXXXX"; for GEOS ADAS forcing, extract hard-coded 3-digit ens id string k = len(trim(comp_name)) - id_string = comp_name(k-ens_id_width+1:k) - k = len(trim(id_string)) - ! hard coded 3 character for forcing - call ESMF_CFIOStrTemplate(ens_forcing_path, trim(adjustl(mf%Path)),'GRADS', xid = trim(id_string(k-2:k)), stat=status) + ensid_string3 = comp_name(k-2:k) + call ESMF_CFIOStrTemplate(ens_forcing_path, trim(adjustl(mf%Path)),'GRADS', xid = ensid_string3, stat=status) mf%Path = ens_forcing_path endif ! Put MetForcing in Ldas' pvt internal state diff --git a/src/Components/GEOSldas_GridComp/Shared/CMakeLists.txt b/src/Components/GEOSldas_GridComp/Shared/CMakeLists.txt index da7f7ec6..a18409aa 100644 --- a/src/Components/GEOSldas_GridComp/Shared/CMakeLists.txt +++ b/src/Components/GEOSldas_GridComp/Shared/CMakeLists.txt @@ -4,7 +4,7 @@ set (SRCS enkf_types.F90 catch_types.F90 LDAS_ensdrv_Globals.F90 LDAS_DateTimeMod.F90 LDAS_DriverTypes.F90 LDAS_Convert.F90 LDAS_Exceptions.F90 LDAS_TileCoordType.F90 LDAS_PertTypes.F90 LDAS_ensdrv_functions.F90 my_matrix_functions.F90 - LDAS_EASE_conv.F90 LDAS_TileCoordRoutines.F90 + LDAS_TileCoordRoutines.F90 LDAS_RepairForcing.F90 LDAS_ensdrv_mpi.F90 ) @@ -15,5 +15,5 @@ list (APPEND SRCS esma_add_library(${this} SRCS ${SRCS} - DEPENDENCIES MAPL GEOS_Shared GEOS_LandShared + DEPENDENCIES MAPL GEOS_Shared GEOS_LandShared raster INCLUDES ${INC_ESMF} ${INC_NETCDF}) diff --git a/src/Components/GEOSldas_GridComp/Shared/LDAS_EASE_conv.F90 b/src/Components/GEOSldas_GridComp/Shared/LDAS_EASE_conv.F90 deleted file mode 100644 index 9aaf636f..00000000 --- a/src/Components/GEOSldas_GridComp/Shared/LDAS_EASE_conv.F90 +++ /dev/null @@ -1,675 +0,0 @@ - -module LDAS_EASE_conv - - ! ========================================================================== - ! - ! easeV1_conv.F90 - FORTRAN routines for conversion of azimuthal - ! equal area and equal area cylindrical grid coordinates - ! - ! 30-Jan-1992 H.Maybee - ! 20-Mar-1992 Ken Knowles 303-492-0644 knowles@kryos.colorado.edu - ! 16-Dec-1993 MJ Brodzik 303-492-8263 brodzik@jokull.colorado.edu - ! Copied from nsmconv.f, changed resolutions from - ! 40-20-10 km to 25-12.5 km - ! 21-Dec-1993 MJ Brodzik 303-492-8263 brodzik@jokull.colorado.edu - ! Fixed sign of Southern latitudes in ease_inverse. - ! 12-Sep-1994 David Hoogstrate 303-492-4116 hoogstra@jokull.colorado.edu - ! Changed grid cell size. Changed "c","f" to "l","h" - ! 25-Oct-1994 David Hoogstrate 303-492-4116 hoogstra@jokull.colorado.edu - ! Changed row size from 587 to 586 for Mercator projection - ! 11-May-2011 reichle: Changed "smap" to "easeV1". - ! Added SSM/I and AMSR-E "M25" grid. - ! So far ONLY for cylindrical grids. - ! Converted from *.f to *.F90 module - ! - ! $Log$ - ! Revision 1.1.2.3 2018/09/13 20:42:50 wjiang - ! change M25 - ! - ! Revision 1.1.2.2 2017/09/18 15:10:25 wjiang - ! "fix" strange compiler erro on comment line. - ! - ! Revision 1.1.2.1 2017/01/19 19:35:58 wjiang - ! 1)add EASE grid support - ! 2)add ensemble average for HISTORY - ! - ! Revision 1.2 2014-08-26 17:33:55 rreichle - ! - clean-up of *.F90 in GEOSlana_GridComp: - ! - make sure all modules include "private" statement - ! - follow all "use" statements with "ONLY" - ! - removed unused files (esat_qsat.F90, nr_sort.f) - ! - removed unused variables - ! - ! Revision 1.1 2011-05-11 21:58:46 rreichle - ! - ! Adding utilities to map between EASE grids and lat/lon coordinates. - ! - ! Revision 1.3 1994/11/01 23:40:43 brodzik - ! Replaced all references to 'ease' with 'smap' - ! Replaced all references to 'smap' with 'easeV1' -- reichle - ! - ! ========================================================================== - - implicit none - - private - - public :: ease_convert - public :: ease_inverse - public :: easeV1_convert - public :: easeV1_inverse - public :: easeV2_convert - public :: easeV2_inverse - public :: easeV2_extent - - - ! ***NEVER*** change these constants to GEOS-5 MAPL constants!!!! - - ! radius of the earth (km), authalic sphere based on International datum - - real*8, parameter :: RE_km = 6371.228 - - ! scale factor for standard paralles at +/-30.00 degrees - - real*8, parameter :: COS_PHI1 = .866025403 - - real*8, parameter :: PI = 3.14159265358979323846 - - ! ========================================================================== - ! - ! easeV2_conv.F90 - FORTRAN routines for converting grid coordinates - ! (latitude/longitude <--> row/column indices) - ! of the Equal Area Scalable Earth, version 2 (EASEv2) grid - ! - ! ***** ONLY cylindrical ('M') projection implemented ***** - ! - ! Ported from Steven Chan's matlab code (smapease2inverse.m, - ! smapease2forward.m), which has been ported from NSIDC's IDL code - ! (wgs84_convert.pro, wgs84_inverse.pro) available from - ! ftp://sidads.colorado.edu/pub/tools/easegrid/geolocation_tools/ - ! - ! 04-Apr-2013 - reichle - ! - ! Official references: - ! doi:10.3390/ijgi1010032 - ! doi:10.3390/ijgi3031154 -- correction of M25 "map_scale_m" parameters! - ! - ! 04-Apr-2013 - reichle - ! 11-Sep-2018 - reichle, mgirotto -- added 'M25' grid parameters - ! - ! ========================================================================== - - - ! ***NEVER*** change these constants to GEOS-5 MAPL constants!!!! - - ! radius of the earth (m) and map eccentricity - - real*8, parameter :: map_equatorial_radius_m = 6378137.0 - - real*8, parameter :: map_eccentricity = 0.081819190843 - - - real*8, parameter :: e2 = map_eccentricity * map_eccentricity - real*8, parameter :: e4 = e2 * e2 - real*8, parameter :: e6 = e2 * e4 - - real*8, parameter :: epsilon = 1.e-6 - - real*8, parameter :: map_reference_longitude = 0.0 ! 'M', 'N', 'S' - - ! constants for 'N' and 'S' (azimuthal) projections - - real*8, parameter :: N_map_reference_latitude = 90.0 - real*8, parameter :: S_map_reference_latitude = -90.0 - - ! constants for 'M' (cylindrical) projection - - real*8, parameter :: M_map_reference_latitude = 0.0 - real*8, parameter :: M_map_second_reference_latitude = 30.0 - - real*8, parameter :: M_sin_phi1 = sin(M_map_second_reference_latitude*PI/180.) - real*8, parameter :: M_cos_phi1 = cos(M_map_second_reference_latitude*PI/180.) - - real*8, parameter :: M_kz = M_cos_phi1/sqrt(1.0-e2*M_sin_phi1*M_sin_phi1) - - -contains - - subroutine ease_convert (gridname, lat, lon, r, s) - character*(*), intent(in) :: gridname - real, intent(in) :: lat, lon - real, intent(out) :: r, s - character(3) :: grid - - if (index(gridname,'M36') /=0 ) then - grid='M36' - else if (index(gridname,'M25') /=0 ) then - grid='M25' - else if (index(gridname,'M09') /=0 ) then - grid='M09' - else if (index(gridname,'M03') /=0 ) then - grid='M03' - else if (index(gridname,'M01') /=0 ) then - grid='M01' - endif - - if(index(gridname,'EASEv2') /=0) then - call easeV2_convert(grid,lat,lon,r,s) - else if(index(gridname,'EASE') /=0) then - call easeV1_convert(grid,lat,lon,r,s) - else - print*,"wrong gridname: "//gridname - endif - end subroutine - - subroutine ease_inverse (gridname, r, s, lat, lon) - character*(*), intent(in) :: gridname - real, intent(in) :: r, s - real, intent(out) :: lat, lon - character(3) :: grid - - if (index(gridname,'M36') /=0 ) then - grid='M36' - else if (index(gridname,'M25') /=0 ) then - grid='M25' - else if (index(gridname,'M09') /=0 ) then - grid='M09' - else if (index(gridname,'M03') /=0 ) then - grid='M03' - else if (index(gridname,'M01') /=0 ) then - grid='M01' - endif - - if(index(gridname,'EASEv2') /=0) then - call easeV2_inverse(grid,r,s,lat,lon) - else if(index(gridname,'EASE') /=0) then - call easeV1_inverse(grid,r,s,lat,lon) - else - print*,"wrong gridname: "//gridname - endif - end subroutine ease_inverse - - ! ******************************************************************* - - subroutine easeV1_convert (grid, lat, lon, r, s) - - ! convert geographic coordinates (spherical earth) to - ! azimuthal equal area or equal area cylindrical grid coordinates - ! - ! status = easeV1_convert (grid, lat, lon, r, s) - ! - ! input : grid - projection name '[M][xx]' - ! where xx = approximate resolution [km] - ! ie xx = "01", "03", "09", "36" (SMAP) - ! or xx = "12", "25" (SSM/I, AMSR-E) - ! lat, lon = geo. coords. (decimal degrees) - ! - ! output: r, s - column, row coordinates - ! - ! result: status = 0 indicates normal successful completion - ! -1 indicates error status (point not on grid) - ! - ! -------------------------------------------------------------------------- - - character*(*), intent(in) :: grid - real, intent(in) :: lat, lon - real, intent(out) :: r, s - - ! local variables - - integer :: cols, rows - real*8 :: Rg, phi, lam, rho, CELL_km, r0, s0 - - ! --------------------------------------------------------------------- - - call easeV1_get_params( grid, CELL_km, cols, rows, r0, s0, Rg ) - - phi = lat*PI/180. ! convert from degree to radians - lam = lon*PI/180. ! convert from degree to radians - - if (grid(1:1).eq.'N') then - rho = 2 * Rg * sin(PI/4. - phi/2.) - r = r0 + rho * sin(lam) - s = s0 + rho * cos(lam) - - else if (grid(1:1).eq.'S') then - rho = 2 * Rg * cos(PI/4. - phi/2.) - r = r0 + rho * sin(lam) - s = s0 - rho * cos(lam) - - else if (grid(1:1).eq.'M') then - r = r0 + Rg * lam * COS_PHI1 - s = s0 - Rg * sin(phi) / COS_PHI1 - - endif - - end subroutine easeV1_convert - - ! ******************************************************************* - - subroutine easeV1_inverse (grid, r, s, lat, lon) - - ! convert azimuthal equal area or equal area cylindrical - ! grid coordinates to geographic coordinates (spherical earth) - ! - ! status = easeV1_inverse (grid, r, s, lat, lon) - ! - ! input : grid - projection name '[M][xx]' - ! where xx = approximate resolution [km] - ! ie xx = "01", "03", "09", "36" (SMAP) - ! or xx = "12", "25" (SSM/I, AMSR-E) - ! r, s - column, row coordinates - ! - ! output: lat, lon = geo. coords. (decimal degrees) - ! - ! result: status = 0 indicates normal successful completion - ! -1 indicates error status (point not on grid) - ! - ! -------------------------------------------------------------------------- - - character*(*), intent(in) :: grid - real, intent(in) :: r, s - real, intent(out) :: lat, lon - - ! local variables - - integer :: cols, rows - real*8 :: Rg, phi, lam, rho, CELL_km, r0, s0 - real*8 :: gamma, beta, epsilon, x, y, c - real*8 :: sinphi1, cosphi1 - - ! --------------------------------------------------------------------- - - call easeV1_get_params( grid, CELL_km, cols, rows, r0, s0, Rg ) - - x = r - r0 - y = -(s - s0) - - if ((grid(1:1).eq.'N').or.(grid(1:1).eq.'S')) then - rho = sqrt(x*x + y*y) - if (rho.eq.0.0) then - if (grid(1:1).eq.'N') lat = 90.0 - if (grid(1:1).eq.'S') lat = -90.0 - lon = 0.0 - else - if (grid(1:1).eq.'N') then - sinphi1 = sin(PI/2.) - cosphi1 = cos(PI/2.) - if (y.eq.0.) then - if (r.le.r0) lam = -PI/2. - if (r.gt.r0) lam = PI/2. - else - lam = atan2(x,-y) - endif - else if (grid(1:1).eq.'S') then - sinphi1 = sin(-PI/2.) - cosphi1 = cos(-PI/2.) - if (y.eq.0.) then - if (r.le.r0) lam = -PI/2. - if (r.gt.r0) lam = PI/2. - else - lam = atan2(x,y) - endif - endif - gamma = rho/(2 * Rg) - if (abs(gamma) .gt. 1.) return - c = 2 * asin(gamma) - beta = cos(c) * sinphi1 + y * sin(c) * (cosphi1/rho) - if (abs(beta).gt.1.) return - phi = asin(beta) - lat = phi*180./PI ! convert from radians to degree - lon = lam*180./PI ! convert from radians to degree - endif - - else if (grid(1:1).eq.'M') then - - ! allow .5 cell tolerance in arcsin function - ! so that grid coordinates which are less than .5 cells - ! above 90.00N or below 90.00S are given a lat of 90.00 - - epsilon = 1 + 0.5/Rg - beta = y*COS_PHI1/Rg - if (abs(beta).gt.epsilon) return - if (beta.le.-1.) then - phi = -PI/2. - else if (beta.ge.1.) then - phi = PI/2. - else - phi = asin(beta) - endif - lam = x/COS_PHI1/Rg - lat = phi*180./PI ! convert from radians to degree - lon = lam*180./PI ! convert from radians to degree - endif - - end subroutine easeV1_inverse - - ! ******************************************************************* - - subroutine easeV1_get_params( grid, CELL_km, cols, rows, r0, s0, Rg ) - - implicit none - - character*(*), intent(in) :: grid - real*8, intent(out) :: CELL_km, r0, s0, Rg - integer, intent(out) :: cols, rows - - ! -------------------------------------------------------- - ! - ! r0,s0 are defined such that cells at all scales have - ! coincident center points - ! - !c r0 = (cols-1)/2. * scale - !c s0 = (rows-1)/2. * scale - ! - ! -------------------------------------------------------- - - if ((grid(1:1).eq.'N').or.(grid(1:1).eq.'S')) then - - print *,'Polar projections not implemented yet' - stop - - else if (grid(1:1).eq.'M') then - - if (grid .eq. 'M36') then ! SMAP 36 km grid - CELL_km = 36.00040279063 ! nominal cell size in kilometers - cols = 963 - rows = 408 - r0 = 481.0 - s0 = 203.5 - - else if (grid .eq. 'M25') then ! SSM/I, AMSR-E 25 km grid - CELL_km = 25.067525 ! nominal cell size in kilometers - cols = 1383 - rows = 586 - r0 = 691.0 - s0 = 292.5 - - else if (grid .eq. 'M09') then ! SMAP 9 km grid - CELL_km = 9.00010069766 ! nominal cell size in kilometers - cols = 3852 - rows = 1632 - r0 = 1925.5 - s0 = 815.5 - - else if (grid .eq. 'M03') then ! SMAP 3 km grid - CELL_km = 3.00003356589 ! nominal cell size in kilometers - cols = 11556 - rows = 4896 - r0 = 5777.5 - s0 = 2447.5 - - else if (grid .eq. 'M01') then ! SMAP 1 km grid - CELL_km = 1.00001118863 ! nominal cell size in kilometers - cols = 34668 - rows = 14688 - r0 = 17333.5 - s0 = 7343.5 - - else - - print *,'easeV1_convert: unknown resolution: ',grid - stop - - endif - - else - - print *, 'easeV1_convert: unknown projection: ', grid - stop - - endif - - Rg = RE_km/CELL_km - - end subroutine easeV1_get_params - - - - subroutine easeV2_convert (grid, lat, lon, col_ind, row_ind) - - ! convert geographic coordinates (spherical earth) to - ! azimuthal equal area or equal area cylindrical grid coordinates - ! - ! *** NOTE order of calling arguments: "lat-lon-lon-lat" *** - ! - ! useage: call easeV2_convert (grid, lat, lon, r, s) - ! - ! input : grid - projection name '[M][xx]' - ! where xx = approximate resolution [km] - ! ie xx = "01", "03", "09", "36" (SMAP) - ! lat, lon = geo. coords. (decimal degrees) - ! - ! output: col_ind, row_ind - column, row coordinates - ! - ! -------------------------------------------------------------------------- - - character*(*), intent(in) :: grid - real, intent(in) :: lat, lon - real, intent(out) :: col_ind, row_ind - - ! local variables - - integer :: cols, rows - real*8 :: dlon, phi, lam, map_scale_m, r0, s0, ms, x, y, sin_phi, q - - ! --------------------------------------------------------------------- - - call easeV2_get_params( grid, map_scale_m, cols, rows, r0, s0 ) - - dlon = lon - - if (abs(map_reference_longitude)>epsilon) then - - dlon = lon - map_reference_longitude - - end if - - if (dlon .lt. -180.0) dlon = dlon + 360.0 - if (dlon .gt. 180.0) dlon = dlon - 360.0 - - phi = lat*PI/180. ! convert from degree to radians - lam = dlon*PI/180. ! convert from degree to radians - - sin_phi = sin(phi) - - ms = map_eccentricity*sin_phi - - q = (1. - e2)* & - ( & - (sin_phi /(1. - e2*sin_phi*sin_phi)) & - - & - .5/map_eccentricity*log((1.-ms)/(1.+ms)) & - ) - - ! note: "qp" only needed for 'N' and 'S' projections - - if (grid(1:1).eq.'M') then - - x = map_equatorial_radius_m*M_kz*lam - - y = (map_equatorial_radius_m*q)/(2.*M_kz) - - else - - print *,'Polar projections not implemented yet' - stop - - endif - - row_ind = s0 - (y/map_scale_m) - col_ind = r0 + (x/map_scale_m) - - end subroutine easeV2_convert - - ! ******************************************************************* - - subroutine easeV2_inverse (grid, r, s, lat, lon) - - ! convert azimuthal equal area or equal area cylindrical - ! grid coordinates to geographic coordinates (spherical earth) - ! - ! *** NOTE order of calling arguments: "lon-lat-lat-lon" *** - ! - ! useage: call easeV1_inverse (grid, r, s, lat, lon) - ! - ! input : grid - projection name '[M][xx]' - ! where xx = approximate resolution [km] - ! ie xx = "01", "03", "09", "36" (SMAP) - ! r, s - column, row coordinates - ! - ! output: lat, lon = geo. coords. (decimal degrees) - ! - ! -------------------------------------------------------------------------- - - character*(*), intent(in) :: grid - real, intent(in) :: r, s - real, intent(out) :: lat, lon - - ! local variables - - integer :: cols, rows - real*8 :: phi, lam, map_scale_m, r0, s0, beta, x, y, qp - - ! --------------------------------------------------------------------- - - call easeV2_get_params( grid, map_scale_m, cols, rows, r0, s0 ) - - x = (r - r0)*map_scale_m - y = -(s - s0)*map_scale_m - - qp = (1. - e2)* & - ( & - (1./(1.-e2)) & - - & - .5/map_eccentricity*log((1.-map_eccentricity)/(1.+map_eccentricity)) & - ) - - if (grid(1:1).eq.'M') then - - beta = asin(2.*y*M_kz/(map_equatorial_radius_m*qp)) - - lam = x/(map_equatorial_radius_m*M_kz) - - else - - print *,'Polar projections not implemented yet' - stop - - endif - - phi = beta & - + ( ( e2/3. + 31./180.*e4 + 517./ 5040.*e6 )*sin(2.*beta) ) & - + ( ( 23./360.*e4 + 251./ 3780.*e6 )*sin(4.*beta) ) & - + ( ( 761./45360.*e6 )*sin(6.*beta) ) - - lat = phi*180./PI ! convert from radians to degree - lon = lam*180./PI + map_reference_longitude ! convert from radians to degree - - if (lon .lt. -180.0) lon = lon + 360.0 - if (lon .gt. 180.0) lon = lon - 360.0 - - end subroutine easeV2_inverse - - ! ******************************************************************* - - subroutine easeV2_get_params( grid, map_scale_m, cols, rows, r0, s0 ) - - implicit none - - character*(*), intent(in) :: grid - real*8, intent(out) :: map_scale_m, r0, s0 - integer, intent(out) :: cols, rows - - - if (grid(1:1).eq.'M') then - - if (grid .eq. 'M36') then ! SMAP 36 km grid - - map_scale_m = 36032.220840584 ! nominal cell size in meters - cols = 964 - rows = 406 - r0 = (cols-1)/2.0 - s0 = (rows-1)/2.0 - - - else if (grid .eq. 'M25') then ! 25 km grid - - map_scale_m = 25025.2600000 ! nominal cell size in meters (see doi:10.3390/ijgi3031154) - cols = 1388 - rows = 584 - r0 = (cols-1)/2.0 - s0 = (rows-1)/2 - - else if (grid .eq. 'M09') then ! SMAP 9 km grid - - map_scale_m = 9008.055210146 ! nominal cell size in meters - cols = 3856 - rows = 1624 - r0 = (cols-1)/2.0 - s0 = (rows-1)/2.0 - - else if (grid .eq. 'M03') then ! SMAP 3 km grid - - map_scale_m = 3002.6850700487 ! nominal cell size in meters - cols = 11568 - rows = 4872 - r0 = (cols-1)/2.0 - s0 = (rows-1)/2.0 - - else if (grid .eq. 'M01') then ! SMAP 1 km grid - - map_scale_m = 1000.89502334956 ! nominal cell size in meters - cols = 34704 - rows = 14616 - r0 = (cols-1)/2.0 - s0 = (rows-1)/2.0 - - else - - print *,'easeV2_convert: unknown resolution: ',grid - stop - - endif - - else if ((grid(1:1).eq.'N').or.(grid(1:1).eq.'S')) then - - print *,'Polar projections not implemented yet' - stop - - else - - print *, 'easeV2_convert: unknown projection: ', grid - stop - - endif - - end subroutine easeV2_get_params - - ! ******************************************************************* - - subroutine easeV2_extent( grid, N_cols, N_rows ) - - ! simple wrapper to get N_cols (N_lon) and N_rows (N_lat) - - implicit none - - character*(*), intent(in) :: grid - integer, intent(out) :: N_cols, N_rows - - ! local variables - - real*8 :: map_scale_m, r0, s0 - - ! ------------------------------------------------ - - call easeV2_get_params( grid, map_scale_m, N_cols, N_rows, r0, s0 ) - - end subroutine easeV2_extent - - ! ******************************************************************* - -end module LDAS_EASE_conv - -! =============================== EOF ================================= - diff --git a/src/Components/GEOSldas_GridComp/Shared/LDAS_TileCoordRoutines.F90 b/src/Components/GEOSldas_GridComp/Shared/LDAS_TileCoordRoutines.F90 index 1b2332c0..a059ed1b 100644 --- a/src/Components/GEOSldas_GridComp/Shared/LDAS_TileCoordRoutines.F90 +++ b/src/Components/GEOSldas_GridComp/Shared/LDAS_TileCoordRoutines.F90 @@ -26,8 +26,10 @@ module LDAS_TileCoordRoutines use MAPL_ConstantsMod, ONLY: & MAPL_RADIUS ! Earth radius - use LDAS_EASE_conv, ONLY: & - easev1_convert,easev2_convert + use EASE_conv, ONLY: & + ease_convert, & + ease_inverse, & + ease_extent use LDAS_ExceptionsMod, ONLY: & ldas_abort, & @@ -279,7 +281,7 @@ subroutine LDAS_create_grid_g( gridname, n_lon, n_lat, & ! ! outputs: ! offsets - ! cell_area (optional, for EASE grids only) + ! cell_area [m^2] (optional, for EASE grids only) implicit none @@ -295,7 +297,7 @@ subroutine LDAS_create_grid_g( gridname, n_lon, n_lat, & logical :: date_line_on_center, pole_on_center logical :: ease_grid, c3_grid, latlon_grid logical :: file_exist - + integer :: k, rows, cols character(len=*), parameter :: Iam = 'create global ldas_grid ' character(len=400) :: err_msg @@ -330,7 +332,7 @@ subroutine LDAS_create_grid_g( gridname, n_lon, n_lat, & pole_on_center = .true. endif - if (index(gridname,"EASE") /=0) then + if (index(gridname,"EASEv") /=0) then ease_grid = .true. latlon_grid = .false. endif @@ -360,70 +362,33 @@ subroutine LDAS_create_grid_g( gridname, n_lon, n_lat, & if (ease_grid) then + ! gridname may be EASEv2-M36 or EASEv2_M36 (to be cleaned up later) + + k = index(gridname, 'EASEv') + + if (k == 0) then + err_msg = 'unknown EASE grid tile defs, gridname = ' // trim( gridname) + call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) + end if + + tile_grid%gridtype = trim(gridname(k:)) + tile_grid%ind_base = 0 ! global cylindrical EASE grid - tile_grid%ll_lon = -180. - tile_grid%ur_lon = 180. - tile_grid%i_dir = +1 tile_grid%j_dir = -1 - ! It is sloppy that the name may be EASEv2-M36 or EASEv2_M36 - - if (index(gridname, 'EASEv2_M36')/=0 .or. index(gridname, 'EASEv2-M36')/=0) then ! version *2* - - tile_grid%gridtype = 'EASEv2_M36' - - tile_grid%ll_lat = -85.04456 - tile_grid%ur_lat = 85.04456 - - ease_cell_area = 1298.320938704616 - - elseif (index(gridname, 'EASEv2_M09')/=0 .or. index(gridname, 'EASEv2-M09')/=0) then ! version *2* - - tile_grid%gridtype = 'EASEv2_M09' - - tile_grid%ll_lat = -85.04456 - tile_grid%ur_lat = 85.04456 - - ease_cell_area = 81.145058669038477 - - elseif (index(gridname, 'EASE_M36')/=0 .or. index(gridname, 'EASE-M36')/=0) then - - tile_grid%gridtype = 'EASE_M36' - - tile_grid%ll_lat = -86.62256 ! minimal change, reichle, 5 Apr 2013 - tile_grid%ur_lat = 86.62256 ! minimal change, reichle, 5 Apr 2013 - - ease_cell_area = 1296.029001087600 - - elseif (index(gridname, 'EASE_M09')/=0 .or. index(gridname, 'EASE-M09')/=0) then - - tile_grid%gridtype = 'EASE_M09' - - tile_grid%ll_lat = -86.62256 ! minimal change, reichle, 5 Apr 2013 - tile_grid%ur_lat = 86.62256 ! minimal change, reichle, 5 Apr 2013 - - ease_cell_area = 81.001812568020028 - - elseif (index(gridname, 'EASE_M25')/=0 .or. index(gridname, 'EASE-M25')/=0 ) then - - tile_grid%gridtype = 'EASE_M25' - - tile_grid%ll_lat = -86.7167 ! need to double-check (reichle, 11 May 2011) - tile_grid%ur_lat = 86.7167 ! need to double-check (reichle, 11 May 2011) - - ease_cell_area = 628.38080962 - - else - - err_msg = 'unknown EASE grid tile defs, grid name = ' // trim( gridname) - call ldas_abort(LDAS_GENERIC_ERROR, Iam, err_msg) - - end if - + call ease_extent ( & + gridname, cols, rows, & + cell_area = ease_cell_area, & ! [m^2] + ll_lon = tile_grid%ll_lon, & + ll_lat = tile_grid%ll_lat, & + ur_lon = tile_grid%ur_lon, & + ur_lat = tile_grid%ur_lat & + ) + tile_grid%dlon = 360./real(tile_grid%N_lon) tile_grid%dlat = (tile_grid%ur_lat-tile_grid%ll_lat)/real(tile_grid%N_lat) ! *avg* dlat! @@ -616,8 +581,7 @@ subroutine get_tile_grid( N_tile, tc_i_indg, tc_j_indg, tc_minlon, tc_minlat, tc tile_grid%ur_lon = tile_grid%ll_lon + real(tile_grid%N_lon)*tile_grid%dlon tile_grid%ur_lat = tile_grid%ll_lat + real(tile_grid%N_lat)*tile_grid%dlat - elseif ( (index(tile_grid_g%gridtype,'EASE_M') /=0) .or. & - (index(tile_grid_g%gridtype,'EASEv2_M')/=0) ) then + elseif ( index(tile_grid_g%gridtype,'EASEv') /=0 ) then ! *average* dlat over the domain @@ -895,11 +859,9 @@ subroutine get_tile_num_from_latlon(N_catd, tile_coord, & ! map from i_ind, j_ind to tile_num - if ( & - (index(tile_grid%gridtype, 'EASE_M') /=0) .or. & - (index(tile_grid%gridtype, 'EASEv2_M')/=0) ) then + if ( index(tile_grid%gridtype, 'EASEv') /=0 ) then - ! ASSUMPTION: tiles match EASE or EASEv2 grid cells exactly + ! ASSUMPTION: tiles match EASE grid cells exactly ! (unless "outside" the domain, eg. water surface) if (N_tile_in_cell_ij(i_ind,j_ind)==1) then @@ -911,7 +873,7 @@ subroutine get_tile_num_from_latlon(N_catd, tile_coord, & elseif (N_tile_in_cell_ij(i_ind,j_ind)==0) then - ! Do nothing. If given EASE or EASEv2 grid cell is not land, + ! Do nothing. If given EASE grid cell is not land, ! tile_num will not change from its initialized value. else @@ -921,7 +883,6 @@ subroutine get_tile_num_from_latlon(N_catd, tile_coord, & end if - elseif (index(tile_grid%gridtype, 'LatLon')/=0) then ! Loop through all tiles within grid cell that contain lat/lon and @@ -1037,23 +998,11 @@ subroutine get_ij_ind_from_latlon( tile_grid, lat, lon, i_ind, j_ind ) ! ! select grid type - if (index(tile_grid%gridtype, 'EASE')/=0) then + if (index(tile_grid%gridtype, 'EASEv')/=0) then ! EASE grid lat/lon to index provides *global*, *0-based* index! - - if (index(tile_grid%gridtype, 'EASE_M') /=0) then - - call easeV1_convert( tile_grid%gridtype(6:8), lat, lon, r, s) - - elseif (index(tile_grid%gridtype, 'EASEv2_M')/=0) then - - call easeV2_convert( tile_grid%gridtype(8:10), lat, lon, r, s) - - else - - call ldas_abort(LDAS_GENERIC_ERROR, Iam, 'unknown EASE grid type') - - end if + + call ease_convert(tile_grid%gridtype, lat, lon, r, s) i_indg = nint(r) ! i_ind or lon_ind j_indg = nint(s) ! j_ind or lat_ind diff --git a/src/Components/GEOSldas_GridComp/Shared/LDAS_TileCoordType.F90 b/src/Components/GEOSldas_GridComp/Shared/LDAS_TileCoordType.F90 index 66c68f19..414a9800 100644 --- a/src/Components/GEOSldas_GridComp/Shared/LDAS_TileCoordType.F90 +++ b/src/Components/GEOSldas_GridComp/Shared/LDAS_TileCoordType.F90 @@ -80,19 +80,19 @@ module LDAS_TileCoordType ! Possible grid types (structure field "gridtype"): ! ! - "LatLon" : regular lat/lon grid (constant dlon, dlat) - ! - "EASE_Mxx" : cylindrical EASE grid (constant dlon, variable dlat) + ! - "EASEv1_Mxx" : cylindrical EASEv1 grid (constant dlon, variable dlat) ! - "EASEv2_Mxx" : cylindrical EASEv2 grid (constant dlon, variable dlat) ! ! Grid orientation (convention): ! ! "LatLon" : 1-based indexing, SouthWest to NorthEast - ! "EASE_Mxx" : 0-based indexing, NorthWest to SouthEast + ! "EASEv1_Mxx" : 0-based indexing, NorthWest to SouthEast ! "EASEv2_Mxx" : 0-based indexing, NorthWest to SouthEast ! ! Grids are defined by the following fields: ! ! --------------------------------------------------------- - ! | || "LatLon" | "EASE_Mxx" | + ! | || "LatLon" | "EASEv1_Mxx" | ! | || | "EASEv2_Mxx" | ! --------------------------------------------------------- ! | indexing || ind_base | ind_base | @@ -123,7 +123,7 @@ module LDAS_TileCoordType ! any subroutines or operators defined herein ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - character(40) :: gridtype ! type of grid, eg. "LatLon", "EASE_M36", "EASEv2_M09", ... + character(40) :: gridtype ! type of grid, eg. "LatLon", "EASEv1_M36", "EASEv2_M09", ... integer :: ind_base ! 0=zero-based indices (EASE), 1=one-based indices (LatLon) integer :: i_dir ! direction of indices (+1=W-to-E, -1=E-to-W) integer :: j_dir ! direction of indices (+1=S-to-N, -1=N-to-S) @@ -133,7 +133,7 @@ module LDAS_TileCoordType integer :: j_offg ! minimum lat index (offset from *global* grid) ! ! "LatLon" : i_offg -> westernmost longitude ! ! j_offg -> southernmost latitude - ! ! "EASE_Mxx" : i_offg -> westernmost longitude + ! ! "EASEv1_Mxx": i_offg -> westernmost longitude ! ! j_offg -> northernmost latitude ! ! "EASEv2_Mxx": i_offg -> westernmost longitude ! ! j_offg -> northernmost latitude @@ -144,7 +144,7 @@ module LDAS_TileCoordType real :: dlon ! longitude grid spacing [deg] real :: dlat ! latitude grid spacing [deg] ! ! "LatLon" : constant - ! ! "EASE_Mxx" : *average* dlat over grid extent + ! ! "EASEv1_Mxx": *average* dlat over grid extent ! ! "EASEv2_Mxx": *average* dlat over grid extent !CLSM_ENSDRV_MPI is NOT updated. will not be saved and bcasted diff --git a/src/Components/GEOSldas_GridComp/Shared/LDAS_ensdrv_Globals.F90 b/src/Components/GEOSldas_GridComp/Shared/LDAS_ensdrv_Globals.F90 index 700abc92..c690c55c 100644 --- a/src/Components/GEOSldas_GridComp/Shared/LDAS_ensdrv_Globals.F90 +++ b/src/Components/GEOSldas_GridComp/Shared/LDAS_ensdrv_Globals.F90 @@ -13,6 +13,7 @@ module LDAS_ensdrv_Globals use, intrinsic :: iso_fortran_env, only : output_unit use MAPL_BaseMod, only : MAPL_UNDEF + use LDAS_ExceptionsMod, only: ldas_abort, LDAS_GENERIC_ERROR implicit none @@ -29,6 +30,7 @@ module LDAS_ensdrv_Globals public :: echo_clsm_ensdrv_glob_param public :: write_status + public :: get_ensid_string ! ---------------------------------------------------------------------- @@ -141,7 +143,33 @@ elemental function LDAS_is_nodata(data) result(no_data) end function LDAS_is_nodata ! ************************************************************* + ! + ! return ensemble id string "_eXXXX" + subroutine get_ensid_string(ensid_string, id, ens_id_width, num_ensemble) + + ! ens_id_with = 2 + number of digits = total number of chars in ensid_string ("_eXXXX") + + character(*), intent(inout) :: ensid_string + integer, intent(in) :: id + integer, intent(in) :: ens_id_width + integer, intent(in) :: num_ensemble + + character(len=100) :: fmt_str + + if (num_ensemble == 1) then + ensid_string = '' + return + endif + + ! the following format string works only if ens_id_width<=2+9 (see _ASSERT in GEOS_LdasGridcomp.F90) + + write (fmt_str, "(A2,I1,A1,I1,A1)") "(I", ens_id_width-2,".",ens_id_width-2,")" + write (ensid_string, fmt_str) id + ensid_string = '_e'//trim(ensid_string) + + end subroutine get_ensid_string + end module LDAS_ensdrv_Globals