diff --git a/parm/atm/utils/fv3jedi_fv3inc.yaml.j2 b/parm/atm/utils/fv3jedi_fv3inc.yaml.j2 deleted file mode 100644 index cb27bb7fa..000000000 --- a/parm/atm/utils/fv3jedi_fv3inc.yaml.j2 +++ /dev/null @@ -1,63 +0,0 @@ -variable change: - variable change name: Model2GeoVaLs - input variables: &inputvars [ua,va,t,ps,sphum,ice_wat,liq_wat,o3mr,phis] - output variables: [ua,va,t,sphum,ice_wat,liq_wat,o3mr,delp,hydrostatic_delz] -background: - geometry: - fms initialization: - namelist filename: ./fv3jedi/fmsmpp.nml - field table filename: ./fv3jedi/field_table - akbk: ./fv3jedi/akbk.nc4 - layout: - - {{ layout_x }} - - {{ layout_y }} - npx: {{ npx_ges }} - npy: {{ npy_ges }} - npz: {{ npz_ges }} - field metadata override: ./fv3jedi/fv3jedi_fieldmetadata_restart.yaml - input: - datapath: ./bkg - filetype: fms restart - datetime: '{{ current_cycle | to_isotime }}' - filename_core: '{{ current_cycle | to_fv3time }}.fv_core.res.nc' - filename_trcr: '{{ current_cycle | to_fv3time }}.fv_tracer.res.nc' - filename_sfcd: '{{ current_cycle | to_fv3time }}.sfc_data.nc' - filename_sfcw: '{{ current_cycle | to_fv3time }}.fv_srf_wnd.res.nc' - filename_cplr: '{{ current_cycle | to_fv3time }}.coupler.res' - state variables: *inputvars -jedi increment: - input variables: [ua,va,t,ps,sphum,ice_wat,liq_wat,o3mr] - geometry: - fms initialization: - namelist filename: ./fv3jedi/fmsmpp.nml - field table filename: ./fv3jedi/field_table - akbk: ./fv3jedi/akbk.nc4 - layout: - - {{ layout_x }} - - {{ layout_y }} - npx: {{ npx_anl }} - npy: {{ npy_anl }} - npz: {{ npz_anl }} - field metadata override: ./fv3jedi/fv3jedi_fieldmetadata_history.yaml - input: - filetype: cube sphere history - filename: ./anl/atminc.{{ current_cycle | to_fv3time }}.nc4 - provider: ufs -fv3 increment: - geometry: - fms initialization: - namelist filename: ./fv3jedi/fmsmpp.nml - field table filename: ./fv3jedi/field_table - akbk: ./fv3jedi/akbk.nc4 - layout: - - {{ layout_x }} - - {{ layout_y }} - npx: {{ npx_anl }} - npy: {{ npy_anl }} - npz: {{ npz_anl }} - field metadata override: ./fv3jedi/fv3jedi_fieldmetadata_fv3inc.yaml - output: - filetype: auxgrid - gridtype: gaussian - filename: ./anl/atminc. - diff --git a/parm/atm/utils/fv3jedi_fv3inc_lgetkf.yaml.j2 b/parm/atm/utils/fv3jedi_fv3inc_lgetkf.yaml.j2 new file mode 100644 index 000000000..786dfd171 --- /dev/null +++ b/parm/atm/utils/fv3jedi_fv3inc_lgetkf.yaml.j2 @@ -0,0 +1,62 @@ +variable change: + variable change name: Model2GeoVaLs + input variables: &bkgvars [ua,va,t,ps,sphum,ice_wat,liq_wat,o3mr,surface_geopotential_height] + output variables: &fv3incrvars [ua,va,t,sphum,ice_wat,liq_wat,o3mr,delp,hydrostatic_delz] +jedi increment variables: [ua,va,t,ps,sphum,ice_wat,liq_wat,o3mr] +fv3 increment variables: *fv3incrvars +background geometry: + fms initialization: + namelist filename: ./fv3jedi/fmsmpp.nml + field table filename: ./fv3jedi/field_table + akbk: ./fv3jedi/akbk.nc4 + layout: + - {{ layout_x }} + - {{ layout_y }} + npx: {{ npx_ges }} + npy: {{ npy_ges }} + npz: {{ npz_ges }} + field metadata override: ./fv3jedi/fv3jedi_fieldmetadata_history.yaml +jedi increment geometry: + fms initialization: + namelist filename: ./fv3jedi/fmsmpp.nml + field table filename: ./fv3jedi/field_table + akbk: ./fv3jedi/akbk.nc4 + layout: + - {{ layout_x }} + - {{ layout_y }} + npx: {{ npx_ges }} + npy: {{ npy_ges }} + npz: {{ npz_ges }} + field metadata override: ./fv3jedi/fv3jedi_fieldmetadata_history.yaml +fv3 increment geometry: + fms initialization: + namelist filename: ./fv3jedi/fmsmpp.nml + field table filename: ./fv3jedi/field_table + akbk: ./fv3jedi/akbk.nc4 + layout: + - {{ layout_x }} + - {{ layout_y }} + npx: {{ npx_ges }} + npy: {{ npy_ges }} + npz: {{ npz_ges }} + field metadata override: ./fv3jedi/fv3jedi_fieldmetadata_fv3inc.yaml +members from template: + template: + background input: + datetime: '{{ current_cycle | to_isotime }}' + filetype: cube sphere history + provider: ufs + datapath: ./bkg/mem%mem% + filename: {{ EPREFIX }}atmf006.nc + state variables: *bkgvars + jedi increment input: + filetype: cube sphere history + filename: ./anl/mem%mem%/atminc.{{ current_cycle | to_fv3time }}.nc4 + provider: ufs + fv3 increment output: + filetype: auxgrid + gridtype: gaussian + filename: ./anl/mem%mem%/atminc. + pattern: '%mem%' + nmembers: {{ NMEM_ENS }} + zero padding: 3 diff --git a/parm/atm/utils/fv3jedi_fv3inc_variational.yaml.j2 b/parm/atm/utils/fv3jedi_fv3inc_variational.yaml.j2 new file mode 100644 index 000000000..9467b1526 --- /dev/null +++ b/parm/atm/utils/fv3jedi_fv3inc_variational.yaml.j2 @@ -0,0 +1,62 @@ +variable change: + variable change name: Model2GeoVaLs + input variables: &bkgvars [ua,va,t,ps,sphum,ice_wat,liq_wat,o3mr,phis] + output variables: &fv3incrvars [ua,va,t,sphum,ice_wat,liq_wat,o3mr,delp,hydrostatic_delz] +jedi increment variables: [ua,va,t,ps,sphum,ice_wat,liq_wat,o3mr] +fv3 increment variables: *fv3incrvars +background geometry: + fms initialization: + namelist filename: ./fv3jedi/fmsmpp.nml + field table filename: ./fv3jedi/field_table + akbk: ./fv3jedi/akbk.nc4 + layout: + - {{ layout_x }} + - {{ layout_y }} + npx: {{ npx_ges }} + npy: {{ npy_ges }} + npz: {{ npz_ges }} + field metadata override: ./fv3jedi/fv3jedi_fieldmetadata_restart.yaml +jedi increment geometry: + fms initialization: + namelist filename: ./fv3jedi/fmsmpp.nml + field table filename: ./fv3jedi/field_table + akbk: ./fv3jedi/akbk.nc4 + layout: + - {{ layout_x }} + - {{ layout_y }} + npx: {{ npx_anl }} + npy: {{ npy_anl }} + npz: {{ npz_anl }} + field metadata override: ./fv3jedi/fv3jedi_fieldmetadata_history.yaml +fv3 increment geometry: + fms initialization: + namelist filename: ./fv3jedi/fmsmpp.nml + field table filename: ./fv3jedi/field_table + akbk: ./fv3jedi/akbk.nc4 + layout: + - {{ layout_x }} + - {{ layout_y }} + npx: {{ npx_anl }} + npy: {{ npy_anl }} + npz: {{ npz_anl }} + field metadata override: ./fv3jedi/fv3jedi_fieldmetadata_fv3inc.yaml +members: +- background input: + datapath: ./bkg + filetype: fms restart + datetime: '{{ current_cycle | to_isotime }}' + filename_core: '{{ current_cycle | to_fv3time }}.fv_core.res.nc' + filename_trcr: '{{ current_cycle | to_fv3time }}.fv_tracer.res.nc' + filename_sfcd: '{{ current_cycle | to_fv3time }}.sfc_data.nc' + filename_sfcw: '{{ current_cycle | to_fv3time }}.fv_srf_wnd.res.nc' + filename_cplr: '{{ current_cycle | to_fv3time }}.coupler.res' + state variables: *bkgvars + jedi increment input: + filetype: cube sphere history + filename: ./anl/atminc.{{ current_cycle | to_fv3time }}.nc4 + provider: ufs + fv3 increment output: + filetype: auxgrid + gridtype: gaussian + filename: ./anl/atminc. + diff --git a/test/fv3jedi/testinput/gdasapp_fv3jedi_fv3inc.yaml b/test/fv3jedi/testinput/gdasapp_fv3jedi_fv3inc.yaml index b0c08350c..185f8789c 100644 --- a/test/fv3jedi/testinput/gdasapp_fv3jedi_fv3inc.yaml +++ b/test/fv3jedi/testinput/gdasapp_fv3jedi_fv3inc.yaml @@ -1,60 +1,59 @@ variable change: variable change name: Model2GeoVaLs - input variables: &inputvars [ua,va,t,ps,sphum,ice_wat,liq_wat,o3mr,phis] - output variables: [ua,va,t,sphum,ice_wat,liq_wat,o3mr,delp,hydrostatic_delz] -background: - geometry: - fms initialization: - namelist filename: ./fv3jedi/fmsmpp.nml - field table filename: ./fv3jedi/field_table_gfdl - akbk: ./fv3jedi/akbk127.nc4 - layout: - - '1' - - '1' - npx: '13' - npy: '13' - npz: '127' - field metadata override: ./fv3jedi/fv3jedi_fieldmetadata_history.yaml - input: + input variables: &bkgvars [ua,va,t,ps,sphum,ice_wat,liq_wat,o3mr,phis] + output variables: &fv3incrvars [ua,va,t,sphum,ice_wat,liq_wat,o3mr,delp,hydrostatic_delz] +jedi increment variables: [ua,va,t,ps,sphum,ice_wat,liq_wat,o3mr] +fv3 increment variables: *fv3incrvars +background geometry: + fms initialization: + namelist filename: ./fv3jedi/fmsmpp.nml + field table filename: ./fv3jedi/field_table_gfdl + akbk: ./fv3jedi/akbk127.nc4 + layout: + - '1' + - '1' + npx: '13' + npy: '13' + npz: '127' + field metadata override: ./fv3jedi/fv3jedi_fieldmetadata_history.yaml +jedi increment geometry: + fms initialization: + namelist filename: ./fv3jedi/fmsmpp.nml + field table filename: ./fv3jedi/field_table_gfdl + akbk: ./fv3jedi/akbk127.nc4 + layout: + - '1' + - '1' + npx: '13' + npy: '13' + npz: '127' + field metadata override: ./fv3jedi/fv3jedi_fieldmetadata_history.yaml +fv3 increment geometry: + fms initialization: + namelist filename: ./fv3jedi/fmsmpp.nml + field table filename: ./fv3jedi/field_table_gfdl + akbk: ./fv3jedi/akbk127.nc4 + layout: + - '1' + - '1' + npx: '13' + npy: '13' + npz: '127' + field metadata override: ./fv3jedi/fv3jedi_fieldmetadata_fv3inc.yaml +members: +- background input: filetype: cube sphere history datapath: ../testdata/ provider: ufs datetime: '2021-07-31T12:00:00Z' filename: gdas.t06z.atmf006.nc - state variables: [ua,va,t,ps,sphum,ice_wat,liq_wat,o3mr,phis] -jedi increment: - input variables: [ua,va,t,ps,sphum,ice_wat,liq_wat,o3mr] - geometry: - fms initialization: - namelist filename: ./fv3jedi/fmsmpp.nml - field table filename: ./fv3jedi/field_table_gfdl - akbk: ./fv3jedi/akbk127.nc4 - layout: - - '1' - - '1' - npx: '13' - npy: '13' - npz: '127' - field metadata override: ./fv3jedi/fv3jedi_fieldmetadata_history.yaml - input: + state variables: *bkgvars + jedi increment input: filetype: cube sphere history datapath: ../testdata/ filename: atminc.20210731.120000.nc4 provider: ufs -fv3 increment: - geometry: - fms initialization: - namelist filename: ./fv3jedi/fmsmpp.nml - field table filename: ./fv3jedi/field_table_gfdl - akbk: ./fv3jedi/akbk127.nc4 - layout: - - '1' - - '1' - npx: '13' - npy: '13' - npz: '127' - field metadata override: ./fv3jedi/fv3jedi_fieldmetadata_fv3inc.yaml - output: + fv3 increment output: filetype: cube sphere history filename: atminc.20210731_120000.nc4 provider: ufs diff --git a/utils/fv3jedi/fv3jedi_fv3inc.h b/utils/fv3jedi/fv3jedi_fv3inc.h index 9e732c337..d0052fe87 100644 --- a/utils/fv3jedi/fv3jedi_fv3inc.h +++ b/utils/fv3jedi/fv3jedi_fv3inc.h @@ -3,6 +3,9 @@ #include #include #include +#include + +#include "atlas/field/FieldSet.h" #include "eckit/config/LocalConfiguration.h" @@ -13,6 +16,7 @@ #include "oops/mpi/mpi.h" #include "oops/runs/Application.h" +#include "oops/util/ConfigFunctions.h" #include "oops/util/DateTime.h" #include "oops/util/Logger.h" @@ -26,56 +30,139 @@ namespace gdasapp { static const std::string classname() {return "gdasapp::fv3inc";} int execute(const eckit::Configuration & fullConfig, bool validate) const { - // Setup variable change - const eckit::LocalConfiguration varChangeConfig(fullConfig, "variable change"); - oops::Variables stateVarin(varChangeConfig, "input variables"); - oops::Variables stateVarout(varChangeConfig, "output variables"); + // Configurations + // --------------------------------------------------------------------------------- - // Setup background - const eckit::LocalConfiguration bkgConfig(fullConfig, "background"); - const eckit::LocalConfiguration stateGeomConfig(bkgConfig, "geometry"); - const eckit::LocalConfiguration stateInputConfig(bkgConfig, "input"); + // Get variable change + const eckit::LocalConfiguration varChangeConfig(fullConfig, "variable change"); + oops::Variables bkgVars(varChangeConfig, "input variables"); + oops::Variables varChangeIncrVars(varChangeConfig, "output variables"); + + // Get increment variables + oops::Variables jediIncrVars(fullConfig, "jedi increment variables"); + oops::Variables fv3IncrVars(fullConfig, "fv3 increment variables"); + + // Get geometries + const eckit::LocalConfiguration stateGeomConfig(fullConfig, "background geometry"); + const eckit::LocalConfiguration jediIncrGeomConfig(fullConfig, "jedi increment geometry"); + const eckit::LocalConfiguration fv3IncrGeomConfig(fullConfig, "fv3 increment geometry"); + + // Ensemble Members + int nmem; + std::vector membersConfig; + if ( fullConfig.has("members") ) { + fullConfig.get("members", membersConfig); + nmem = membersConfig.size(); + } else { + eckit::LocalConfiguration membersFromTemplateConfig(fullConfig, "members from template"); + eckit::LocalConfiguration templateConfig(membersFromTemplateConfig, "template"); + std::string pattern; + membersFromTemplateConfig.get("pattern", pattern); + membersFromTemplateConfig.get("nmembers", nmem); + int start = 1; + if (membersFromTemplateConfig.has("start")) { + membersFromTemplateConfig.get("start", start); + } + std::vector except; + if (membersFromTemplateConfig.has("except")) { + membersFromTemplateConfig.get("except", except); + } + int zpad = 0; + if ( membersFromTemplateConfig.has("zero padding") ) { + membersFromTemplateConfig.get("zero padding", zpad); + } + + int count = start; + for ( int imem = 0; imem < nmem; imem++ ) { + while (std::count(except.begin(), except.end(), count)) { + count += 1; + } + eckit::LocalConfiguration memberConfig(templateConfig); + util::seekAndReplace(memberConfig, pattern, count, zpad); + membersConfig.push_back(memberConfig); + count += 1; + } + } + + // Setup + // --------------------------------------------------------------------------------- + + // Setup geometries const fv3jedi::Geometry stateGeom(stateGeomConfig, this->getComm()); - fv3jedi::State xxBkg(stateGeom, stateInputConfig); - oops::Log::test() << "Background State: " << std::endl << xxBkg << std::endl; - - // Setup JEDI increment - const eckit::LocalConfiguration jediIncrConfig(fullConfig, "jedi increment"); - const eckit::LocalConfiguration jediIncrGeomConfig(jediIncrConfig, "geometry"); - const eckit::LocalConfiguration jediIncrInputConfig(jediIncrConfig, "input"); - oops::Variables jediIncrVarin(jediIncrConfig, "input variables"); const fv3jedi::Geometry jediIncrGeom(jediIncrGeomConfig, this->getComm()); - fv3jedi::Increment dx(jediIncrGeom, jediIncrVarin, xxBkg.validTime()); - dx.read(jediIncrInputConfig); - oops::Log::test() << "JEDI Increment: " << std::endl << dx << std::endl; - - // Setup FV3 increment - const eckit::LocalConfiguration fv3IncrConfig(fullConfig, "fv3 increment"); - const eckit::LocalConfiguration fv3IncrGeomConfig(fv3IncrConfig, "geometry"); - const eckit::LocalConfiguration fv3IncrOuputConfig(fv3IncrConfig, "output"); const fv3jedi::Geometry fv3IncrGeom(fv3IncrGeomConfig, this->getComm()); - // + // Setup variable change std::unique_ptr vc; vc.reset(new fv3jedi::VariableChange(varChangeConfig, stateGeom)); - // ---------------------------------------------------------------------------- - - // Add increment to background to get analysis - fv3jedi::State xxAnl(stateGeom, xxBkg); - xxAnl += dx; - - // Perform variables change on background and analysis - vc->changeVar(xxBkg, stateVarout); - vc->changeVar(xxAnl, stateVarout); - - // Get final FV3 increment - fv3jedi::Increment dxFV3(fv3IncrGeom, stateVarout, xxBkg.validTime()); - dxFV3.diff(xxAnl, xxBkg); - oops::Log::test() << "FV3 Increment: " << std::endl << dxFV3 << std::endl; - - // Write FV3 increment - dxFV3.write(fv3IncrOuputConfig); + // Loop through ensemble member + // --------------------------------------------------------------------------------- + + for ( int imem = 0; imem < nmem; imem++ ) { + // Inputs setup + // --------------------------------------------------------------------------------- + + // Get input configurations + eckit::LocalConfiguration stateInputConfig(membersConfig[imem], "background input"); + eckit::LocalConfiguration jediIncrInputConfig(membersConfig[imem], "jedi increment input"); + eckit::LocalConfiguration fv3IncrOuputConfig(membersConfig[imem], "fv3 increment output"); + + // Read background state + fv3jedi::State xxBkg(stateGeom, stateInputConfig); + + // Read JEDI increment + fv3jedi::Increment dxJEDI(jediIncrGeom, jediIncrVars, xxBkg.validTime()); + dxJEDI.read(jediIncrInputConfig); + + // Increment conversion + // --------------------------------------------------------------------------------- + + // Add JEDI increment to background to get analysis + fv3jedi::State xxAnl(stateGeom, xxBkg); + xxAnl += dxJEDI; + + // Perform variables change on background and analysis + vc->changeVar(xxBkg, varChangeIncrVars); + vc->changeVar(xxAnl, varChangeIncrVars); + + // Get FV3 increment by subtracting background and analysis after variable change + fv3jedi::Increment dxFV3(fv3IncrGeom, fv3IncrVars, xxBkg.validTime()); + dxFV3.diff(xxAnl, xxBkg); + + // Put JEDI increment fields not created by variable change into FV3 increment + // because of interpolation between full and half resolution. Also, + // mixing-ratio variables may be set to zero in the analysis if the increment + // addition makes them negative. In both cases, subtracting the background and + // analysis won't yield back the same increment as we started with. + atlas::FieldSet dxFsJEDI; + atlas::FieldSet dxFsFV3; + dxJEDI.toFieldSet(dxFsJEDI); + dxFV3.toFieldSet(dxFsFV3); + for (size_t iField = 0; iField < dxFsFV3.size(); ++iField) { + if ( dxFsJEDI.has(dxFsFV3[iField].name()) ) { + auto viewJEDI = atlas::array::make_view(dxFsJEDI[dxFsFV3[iField].name()]); + auto viewFV3 = atlas::array::make_view(dxFsFV3[iField]); + + size_t gridSize = viewFV3.shape(0); + int nLevels = viewFV3.shape(1); + for (int iLevel = 0; iLevel < nLevels + 1; ++iLevel) { + for ( size_t jNode = 0; jNode < gridSize ; ++jNode ) { + viewFV3(jNode, iLevel) = viewJEDI(jNode, iLevel); + } + } + } + } + dxFV3.fromFieldSet(dxFsFV3); + + // Write FV3 increment + dxFV3.write(fv3IncrOuputConfig); + + // Output for testing + oops::Log::test() << "Background State: " << std::endl << xxBkg << std::endl; + oops::Log::test() << "JEDI Increment: " << std::endl << dxJEDI << std::endl; + oops::Log::test() << "FV3 Increment: " << std::endl << dxFV3 << std::endl; + } return 0; }