diff --git a/modulefiles/GDAS/hercules.intel.lua b/modulefiles/GDAS/hercules.intel.lua index c59b26482..fb97a90b7 100644 --- a/modulefiles/GDAS/hercules.intel.lua +++ b/modulefiles/GDAS/hercules.intel.lua @@ -61,7 +61,7 @@ load("py-pybind11/2.11.0") --load("crtm/v2.4_jedi") load("contrib/0.1") load("noaatools/3.1") -load("rocoto/1.3.5") +load("rocoto/1.3.7") load("hpc/1.2.0") unload("python/3.10.13") diff --git a/modulefiles/GDAS/orion.intel.lua b/modulefiles/GDAS/orion.intel.lua index e6692ceb1..1c4c60ac3 100644 --- a/modulefiles/GDAS/orion.intel.lua +++ b/modulefiles/GDAS/orion.intel.lua @@ -61,7 +61,7 @@ load("py-pybind11/2.11.0") --load("crtm/v2.4_jedi") load("contrib/0.1") load("noaatools/3.1") -load("rocoto/1.3.5") +load("rocoto/1.3.7") load("hpc/1.2.0") unload("python/3.10.13") diff --git a/parm/soca/berror/soca_bump_loc.yaml b/parm/soca/berror/obsolete/soca_bump_loc.yaml similarity index 100% rename from parm/soca/berror/soca_bump_loc.yaml rename to parm/soca/berror/obsolete/soca_bump_loc.yaml diff --git a/parm/soca/berror/soca_ensweights.yaml b/parm/soca/berror/obsolete/soca_ensweights.yaml similarity index 100% rename from parm/soca/berror/soca_ensweights.yaml rename to parm/soca/berror/obsolete/soca_ensweights.yaml diff --git a/parm/soca/berror/soca_parameters_diffusion_hz.yaml b/parm/soca/berror/obsolete/soca_parameters_diffusion_hz.yaml similarity index 100% rename from parm/soca/berror/soca_parameters_diffusion_hz.yaml rename to parm/soca/berror/obsolete/soca_parameters_diffusion_hz.yaml diff --git a/parm/soca/berror/soca_parameters_diffusion_vt.yaml b/parm/soca/berror/obsolete/soca_parameters_diffusion_vt.yaml similarity index 100% rename from parm/soca/berror/soca_parameters_diffusion_vt.yaml rename to parm/soca/berror/obsolete/soca_parameters_diffusion_vt.yaml diff --git a/parm/soca/berror/soca_setlocscales.yaml b/parm/soca/berror/obsolete/soca_setlocscales.yaml similarity index 100% rename from parm/soca/berror/soca_setlocscales.yaml rename to parm/soca/berror/obsolete/soca_setlocscales.yaml diff --git a/parm/soca/berror/old/parametric_stddev_b.yaml b/parm/soca/berror/old/parametric_stddev_b.yaml deleted file mode 100644 index a2052e8b1..000000000 --- a/parm/soca/berror/old/parametric_stddev_b.yaml +++ /dev/null @@ -1,58 +0,0 @@ -input geometry: - geom_grid_file: soca_gridspec.nc - mom6_input_nml: mom_input.nml - fields metadata: fields_metadata.yaml - -output geometry: - geom_grid_file: soca_gridspec.nc - mom6_input_nml: mom_input.nml - fields metadata: fields_metadata.yaml - -linear variable change: - input variables: [tocn, socn, ssh, cicen, hicen] - output variables: [tocn, socn, ssh, cicen, hicen] - linear variable changes: - - - linear variable change name: BkgErrGODAS - t_min: 0.1 - t_max: 2.0 - t_dz: 20.0 - t_efold: 500.0 - s_min: 0.0 - s_max: 0.25 - ssh_min: 0.0 # value at EQ - ssh_max: 0.1 # value in Extratropics - ssh_phi_ex: 20 # lat of transition from extratropics - cicen_min: 0.1 - cicen_max: 0.5 - hicen_min: 10.0 - hicen_max: 100.0 - - - linear variable change name: BkgErrFILT - ocean_depth_min: 1000 # [m] - rescale_bkgerr: 1.0 - efold_z: 2500.0 # [m] - - - linear variable change name: HorizFiltSOCA - niter: 3 - filter variables: [tocn, socn, ssh] - -increments: -- date: '{{ATM_WINDOW_BEGIN}}' - input variables: [tocn, socn, ssh, cicen, hicen] - input: - Identity: 1 - date: '{{ATM_WINDOW_BEGIN}}' - state variables: [ssh, tocn, socn, cicen, hicen] - trajectory: - read_from_file: 1 - basename: ./INPUT/ - ocn_filename: MOM.res.nc - ice_filename: cice.res.nc - date: '{{ATM_WINDOW_BEGIN}}' - state variables: [cicen, hicen, ssh, tocn, socn, hocn, layer_depth, mld] - output: - datadir: ./ - exp: bkgerr_stddev - type: incr - date: '{{ATM_WINDOW_BEGIN}}' diff --git a/parm/soca/berror/old/soca_apply_steric.yaml b/parm/soca/berror/old/soca_apply_steric.yaml deleted file mode 100644 index 5459a48ae..000000000 --- a/parm/soca/berror/old/soca_apply_steric.yaml +++ /dev/null @@ -1,50 +0,0 @@ -geometry: - geom_grid_file: soca_gridspec.nc - mom6_input_nml: mom_input.nml - fields metadata: fields_metadata.yaml - -date: '{{ATM_WINDOW_BEGIN}}' - -layers variable: [hocn] - -increment variables: [tocn, socn, uocn, vocn, ssh, hocn] - -set increment variables to zero: [ssh] - -vertical geometry: - read_from_file: 1 - basename: ./INPUT/ - ocn_filename: MOM.res.nc - date: '{{ATM_WINDOW_BEGIN}}' - -soca increments: - number of increments: ${CLIM_ENS_SIZE} - pattern: '%mem%' - template: - date: '{{ATM_WINDOW_BEGIN}}' - basename: ./static_ens/ - ocn_filename: 'ocn.pert.ens.%mem%.{{ATM_WINDOW_BEGIN}}.PT0S.nc' - read_from_file: 1 - -linear variable change: - linear variable changes: - - linear variable change name: BkgErrFILT - ocean_depth_min: 500 # zero where ocean is shallower than 500m - rescale_bkgerr: 1.0 # rescale perturbation - efold_z: 2500.0 # Apply exponential decay - - linear variable change name: BalanceSOCA - -trajectory: - state variables: [tocn, socn, uocn, vocn, ssh, hocn, layer_depth, mld] - date: '{{ATM_WINDOW_BEGIN}}' - basename: ./INPUT/ - ocn_filename: MOM.res.nc - read_from_file: 1 - -output increment: - datadir: ./static_ens/ - date: '{{ATM_WINDOW_BEGIN}}' - exp: tmp - type: incr - output file: 'ocn.pert.steric.%mem%.{{ATM_WINDOW_BEGIN}}.nc' - pattern: '%mem%' diff --git a/parm/soca/berror/old/soca_bump2d.yaml b/parm/soca/berror/old/soca_bump2d.yaml deleted file mode 100644 index 93e1fb7f0..000000000 --- a/parm/soca/berror/old/soca_bump2d.yaml +++ /dev/null @@ -1,53 +0,0 @@ -geometry: - geom_grid_file: soca_gridspec.nc - mom6_input_nml: mom_input.nml - fields metadata: fields_metadata.yaml - -background: - read_from_file: 1 - date: &date '{{ATM_WINDOW_BEGIN}}' - basename: ./INPUT/ - ocn_filename: MOM.res.nc - ice_filename: cice.res.nc - state variables: [cicen, hicen, hsnon, ssh] - -background error: - covariance model: SABER - saber central block: - saber block name: BUMP_NICAS - calibration: - io: - data directory: bump - drivers: - multivariate strategy: univariate - compute nicas: true - write local nicas: true - write nicas grids: true - model: - do not cross mask boundaries: false - nicas: - resolution: !ENV ${NICAS_RESOL} - max horizontal grid size: ${NICAS_GRID_SIZE} - grids: - - model: - variables: [cicen, hicen, hsnon, ssh] - io: - files prefix: bump2d - input model files: - - parameter: rh - file: - read_from_file: 1 - date: *date - basename: ./ - ocn_filename: ocn.cor_rh.incr.0001-01-01T00:00:00Z.nc - ice_filename: ice.cor_rh.incr.0001-01-01T00:00:00Z.nc - state variables: [cicen, hicen, hsnon, ssh] - - parameter: rv - file: - read_from_file: 1 - date: *date - basename: ./ - ocn_filename: ocn.cor_rv.incr.0001-01-01T00:00:00Z.nc - ice_filename: ice.cor_rv.incr.0001-01-01T00:00:00Z.nc - state variables: [cicen, hicen, hsnon, ssh] - diff --git a/parm/soca/berror/old/soca_bump_split.yaml b/parm/soca/berror/old/soca_bump_split.yaml deleted file mode 100644 index 51bade388..000000000 --- a/parm/soca/berror/old/soca_bump_split.yaml +++ /dev/null @@ -1,57 +0,0 @@ -geometry: - geom_grid_file: soca_gridspec.nc - mom6_input_nml: mom_input.nml - fields metadata: fields_metadata.yaml - -background: - read_from_file: 1 - date: &date '{{ATM_WINDOW_BEGIN}}' - basename: ./INPUT/ - ocn_filename: MOM.res.nc - ice_filename: cice.res.nc - state variables: [cicen, hicen, hsnon, socn, tocn, uocn, vocn, ssh] - -background error: - covariance model: SABER - saber central block: - saber block name: BUMP_NICAS - calibration: - io: - data directory: !ENV ${BUMPDIR} - drivers: - multivariate strategy: univariate - compute nicas: true - write local nicas: true - write nicas grids: true - model: - do not cross mask boundaries: false - nicas: - resolution: !ENV ${NICAS_RESOL} - max horizontal grid size: ${NICAS_GRID_SIZE} - grids: - - model: - variables: - - !ENV ${CVAR} - io: - files prefix: !ENV ${CVAR} - - input model files: - - parameter: rh - file: - read_from_file: 1 - date: *date - basename: ./ - ocn_filename: ocn.cor_rh.incr.0001-01-01T00:00:00Z.nc - ice_filename: ice.cor_rh.incr.0001-01-01T00:00:00Z.nc - state variables: - - !ENV ${CVAR} - - parameter: rv - file: - read_from_file: 1 - date: *date - basename: ./ - ocn_filename: ocn.cor_rv.incr.0001-01-01T00:00:00Z.nc - ice_filename: ice.cor_rv.incr.0001-01-01T00:00:00Z.nc - state variables: - - !ENV ${CVAR} - diff --git a/parm/soca/berror/old/soca_clim_ens_moments.yaml b/parm/soca/berror/old/soca_clim_ens_moments.yaml deleted file mode 100644 index df43fc516..000000000 --- a/parm/soca/berror/old/soca_clim_ens_moments.yaml +++ /dev/null @@ -1,28 +0,0 @@ -geometry: - geom_grid_file: soca_gridspec.nc - mom6_input_nml: mom_input.nml - fields metadata: fields_metadata.yaml - -ensemble: - members from template: - template: - read_from_file: 1 - date: '{{ATM_WINDOW_BEGIN}}' - basename: ./static_ens/ - ocn_filename: ocn.%mem%.nc - ice_filename: ice.%mem%.nc - state variables: [tocn, socn, ssh, uocn, vocn, hocn, cicen, hicen, hsnon] - pattern: '%mem%' - nmembers: ${CLIM_ENS_SIZE} - -mean output: - datadir: ./static_ens/ - exp: orig_ens_mean - type: incr - date: '{{ATM_WINDOW_BEGIN}}' - -standard deviation output: - datadir: ./static_ens/ - exp: orig_ens_stddev - type: incr - date: '{{ATM_WINDOW_BEGIN}}' diff --git a/parm/soca/berror/old/soca_clim_ens_perts.yaml b/parm/soca/berror/old/soca_clim_ens_perts.yaml deleted file mode 100644 index 83ef4996d..000000000 --- a/parm/soca/berror/old/soca_clim_ens_perts.yaml +++ /dev/null @@ -1,34 +0,0 @@ -geometry: - geom_grid_file: soca_gridspec.nc - mom6_input_nml: mom_input.nml - fields metadata: fields_metadata.yaml - -recenter variables: [cicen, hicen, hsnon, socn, tocn, uocn, vocn, ssh, hocn, mld, layer_depth] - -zero center: True - -center: - read_from_file: 1 - basename: ./INPUT/ - ocn_filename: MOM.res.nc - ice_filename: cice.res.nc - date: '{{ATM_WINDOW_BEGIN}}' - state variables: [cicen, hicen, hsnon, socn, tocn, uocn, vocn, ssh, hocn, mld, layer_depth] - -ensemble: - members from template: - template: - read_from_file: 1 - date: '{{ATM_WINDOW_BEGIN}}' - basename: ./static_ens/ - ocn_filename: ocn.%mem%.nc - ice_filename: ice.%mem%.nc - state variables: [cicen, hicen, hsnon, socn, tocn, uocn, vocn, ssh, hocn, mld, layer_depth] - pattern: '%mem%' - nmembers: ${CLIM_ENS_SIZE} - -recentered output: - datadir: ./static_ens - exp: pert - type: ens - date: '{{ATM_WINDOW_BEGIN}}' diff --git a/parm/soca/berror/old/soca_postproc_stddev.yaml b/parm/soca/berror/old/soca_postproc_stddev.yaml deleted file mode 100644 index 6720e1b5a..000000000 --- a/parm/soca/berror/old/soca_postproc_stddev.yaml +++ /dev/null @@ -1,31 +0,0 @@ -geometry: - geom_grid_file: soca_gridspec.nc - mom6_input_nml: mom_input.nml - fields metadata: fields_metadata.yaml - -date: '{{ATM_WINDOW_BEGIN}}' - -layers variable: [hocn] - -increment variables: [tocn, socn, uocn, vocn, ssh, hocn] - -set increment variables to zero: [ssh] - -vertical geometry: - read_from_file: 1 - basename: ./INPUT/ - ocn_filename: MOM.res.nc - date: '{{ATM_WINDOW_BEGIN}}' - -soca increment: - date: '{{ATM_WINDOW_BEGIN}}' - basename: ./static_ens/ - ocn_filename: 'ocn.orig_ens_stddev.incr.{{ATM_WINDOW_BEGIN}}.nc' - read_from_file: 1 - -output increment: - datadir: ./ - date: '{{ATM_WINDOW_BEGIN}}' - exp: filtered - type: incr - output file: 'ocn.orig_ens_stddev.incr.{{ATM_WINDOW_BEGIN}}.nc' diff --git a/parm/soca/berror/soca_diagb.yaml.j2 b/parm/soca/berror/soca_diagb.yaml.j2 index 767b41f92..8c394d67c 100644 --- a/parm/soca/berror/soca_diagb.yaml.j2 +++ b/parm/soca/berror/soca_diagb.yaml.j2 @@ -2,18 +2,18 @@ geometry: mom6_input_nml: mom_input.nml fields metadata: ./fields_metadata.yaml -date: '{{ ATM_WINDOW_MIDDLE }}' +date: '{{ MARINE_WINDOW_END | to_isotime }}' background: - date: '{{ ATM_WINDOW_MIDDLE }}' + date: '{{ MARINE_WINDOW_END | to_isotime }}' basename: ./bkg/ - ocn_filename: 'gdas.ocean.t{{ gcyc }}z.inst.f009.nc' - ice_filename: 'gdas.agg_ice.t{{ gcyc }}z.inst.f009.nc' + ocn_filename: 'ocean.bkg.f009.nc' + ice_filename: 'ice.bkg.f009.nc' read_from_file: 1 background error: - datadir: ./ - date: '{{ ATM_WINDOW_MIDDLE }}' + datadir: ./diagb/ + date: '{{ MARINE_WINDOW_MIDDLE | to_isotime }}' exp: bkgerr_stddev type: incr diff --git a/parm/soca/berror/soca_ensb.yaml b/parm/soca/berror/soca_ensb.yaml.j2 similarity index 59% rename from parm/soca/berror/soca_ensb.yaml rename to parm/soca/berror/soca_ensb.yaml.j2 index 7def815c4..48bc494f4 100644 --- a/parm/soca/berror/soca_ensb.yaml +++ b/parm/soca/berror/soca_ensb.yaml.j2 @@ -1,8 +1,9 @@ +# Configuration for the recentering and re-balancing of the ensemble members geometry: mom6_input_nml: mom_input.nml fields metadata: ./fields_metadata.yaml -date: '{{ATM_WINDOW_BEGIN}}' +date: '{{ MARINE_WINDOW_BEGIN | to_isotime }}' layers variable: [hocn] @@ -11,7 +12,7 @@ increment variables: [tocn, socn, uocn, vocn, ssh, hocn, cicen, hicen, hsnon] set increment variables to zero: [ssh] vertical geometry: - date: '{{ATM_WINDOW_BEGIN}}' + date: '{{ MARINE_WINDOW_BEGIN | to_isotime }}' basename: ./INPUT/ ocn_filename: MOM.res.nc read_from_file: 3 @@ -19,11 +20,11 @@ vertical geometry: add recentering increment: false soca increments: # Could also be states, but they are read as increments - number of increments: ${ENS_SIZE} + number of increments: {{ NMEM_ENS }} pattern: '%mem%' template: - date: '{{ATM_WINDOW_BEGIN}}' - basename: ./static_ens/ + date: '{{ MARINE_WINDOW_BEGIN | to_isotime }}' + basename: '{{ ENSPERT_RELPATH }}/ens/' ocn_filename: 'ocean.%mem%.nc' ice_filename: 'ice.%mem%.nc' read_from_file: 3 @@ -33,67 +34,64 @@ steric height: - linear variable change name: BalanceSOCA # Only the steric balance is applied ensemble mean output: - datadir: ./static_ens - date: '{{ATM_WINDOW_BEGIN}}' + datadir: ./diagb/ + date: '{{ MARINE_WINDOW_BEGIN | to_isotime }}' exp: ens_mean type: incr ssh output: unbalanced: - datadir: ./static_ens - date: '{{ATM_WINDOW_BEGIN}}' + datadir: ./diagb/ + date: '{{ MARINE_WINDOW_BEGIN | to_isotime }}' exp: ssh_unbal_stddev type: incr steric: - datadir: ./static_ens - date: '{{ATM_WINDOW_BEGIN}}' + datadir: ./diagb/ + date: '{{ MARINE_WINDOW_BEGIN | to_isotime }}' exp: ssh_steric_stddev type: incr total: - datadir: ./static_ens - date: '{{ATM_WINDOW_BEGIN}}' + datadir: ./diagb/ + date: '{{ MARINE_WINDOW_BEGIN | to_isotime }}' exp: ssh_total_stddev type: incr explained variance: - datadir: ./static_ens - date: '{{ATM_WINDOW_BEGIN}}' + datadir: ./diagb/ + date: '{{ MARINE_WINDOW_BEGIN | to_isotime }}' exp: steric_explained_variance type: incr recentering error: - datadir: ./static_ens - date: '{{ATM_WINDOW_BEGIN}}' + datadir: ./diagb/ + date: '{{ MARINE_WINDOW_BEGIN | to_isotime }}' exp: ssh_recentering_error type: incr background error output: - datadir: ./static_ens - date: '{{ATM_WINDOW_BEGIN}}' + datadir: ./diagb/ + date: '{{ MARINE_WINDOW_BEGIN | to_isotime }}' exp: bkgerr_stddev type: incr linear variable change: linear variable changes: -# - linear variable change name: BkgErrFILT -# ocean_depth_min: 500 # zero where ocean is shallower than 500m -# rescale_bkgerr: 1.0 # rescale perturbation -# efold_z: 1500.0 # Apply exponential decay - linear variable change name: BalanceSOCA trajectory: state variables: [tocn, socn, uocn, vocn, ssh, hocn, layer_depth, mld, cicen, hicen, hsnon] - date: '{{ATM_WINDOW_BEGIN}}' + date: '{{ MARINE_WINDOW_BEGIN | to_isotime }}' basename: ./INPUT/ ocn_filename: MOM.res.nc ice_filename: cice.res.nc read_from_file: 1 output increment: - datadir: ./static_ens - date: '{{ATM_WINDOW_BEGIN}}' + # TODO: Revert this when fms can take more than 128 charactres file names + datadir: '{{ ENSPERT_RELPATH }}/ens/' + date: '{{ MARINE_WINDOW_BEGIN | to_isotime }}' exp: trash type: incr output file: 'ocn.pert.steric.%mem%.nc' diff --git a/parm/soca/berror/soca_ensweights.yaml.j2 b/parm/soca/berror/soca_ensweights.yaml.j2 new file mode 100644 index 000000000..f677d2a8d --- /dev/null +++ b/parm/soca/berror/soca_ensweights.yaml.j2 @@ -0,0 +1,37 @@ +geometry: + mom6_input_nml: mom_input.nml + fields metadata: ./fields_metadata.yaml + +date: '{{ MARINE_WINDOW_MIDDLE | to_isotime }}' + +variables: + ice: [cicen, hicen, hsnon] + ocean: [tocn, socn, uocn, vocn, ssh] + +background: + date: '{{ MARINE_WINDOW_BEGIN | to_isotime }}' + basename: ./INPUT/ + ocn_filename: MOM.res.nc + ice_filename: cice.res.nc + read_from_file: 1 + +weights: + # Need to provide weights^2 when reading from file + ice: 0.0025 # 5% of original variance + ocean: 0.0625 # 25% " " + # Apply localized weights to the ocean ens. B + ocean local weights: + - lon: -172.0 + lat: 11.0 + amplitude: -1.0 + length scale: 700.0 + - lon: -160.0 + lat: 12.0 + amplitude: -1.0 + length scale: 700.0 + +output: + datadir: ./ + date: '{{ MARINE_WINDOW_MIDDLE | to_isotime }}' + exp: ens_weights + type: incr diff --git a/parm/soca/berror/soca_hybrid_bmat.yaml b/parm/soca/berror/soca_hybrid_bmat.yaml index 6e3d35351..302cb6441 100644 --- a/parm/soca/berror/soca_hybrid_bmat.yaml +++ b/parm/soca/berror/soca_hybrid_bmat.yaml @@ -34,8 +34,8 @@ components: model file: date: '{{ATM_WINDOW_MIDDLE}}' basename: ./ - ocn_filename: 'ocn.bkgerr_stddev.incr.{{ATM_WINDOW_MIDDLE}}.nc' - ice_filename: 'ice.bkgerr_stddev.incr.{{ATM_WINDOW_MIDDLE}}.nc' + ocn_filename: 'ocean.bkgerr_stddev.nc' + ice_filename: 'ice.bkgerr_stddev.nc' read_from_file: 3 linear variable change: @@ -53,7 +53,7 @@ components: template: read_from_file: 1 date: '{{ATM_WINDOW_MIDDLE}}' - basename: ./static_ens/ + basename: ./ens/ ocn_filename: 'ocn.pert.steric.%mem%.nc' ice_filename: 'ice.%mem%.nc' state variables: [tocn, socn, ssh, uocn, vocn, cicen, hicen, hsnon] @@ -87,6 +87,6 @@ components: weight: read_from_file: 3 basename: ./ - ocn_filename: 'ocn.ens_weights.incr.{{ATM_WINDOW_MIDDLE}}.nc' - ice_filename: 'ice.ens_weights.incr.{{ATM_WINDOW_MIDDLE}}.nc' + ocn_filename: 'ocean.ens_weights.nc' + ice_filename: 'ice.ens_weights.nc' date: '{{ATM_WINDOW_MIDDLE}}' diff --git a/parm/soca/berror/soca_parameters_diffusion_hz.yaml.j2 b/parm/soca/berror/soca_parameters_diffusion_hz.yaml.j2 new file mode 100644 index 000000000..759a0ed03 --- /dev/null +++ b/parm/soca/berror/soca_parameters_diffusion_hz.yaml.j2 @@ -0,0 +1,37 @@ +geometry: &geom + mom6_input_nml: mom_input.nml + fields metadata: ./fields_metadata.yaml + +background: + read_from_file: 1 + basename: ./INPUT/ + ocn_filename: MOM.res.nc + ice_filename: cice.res.nc + date: '{{ MARINE_WINDOW_END | to_isotime }}' + state variables: [cicen, hicen, hsnon, socn, tocn, uocn, vocn, ssh] + +background error: + covariance model: SABER + saber central block: + saber block name: EXPLICIT_DIFFUSION + geometry: *geom + calibration: + normalization: + method: randomization + iterations: 10000 + + groups: + - name: ocean + horizontal: + from file: + filename: ocn.cor_rh.incr.0001-01-01T00:00:00Z.nc + variable name: ave_ssh + write: + filename: hz_ocean.nc + + - name: ice + horizontal: + as gaussian: true + fixed value: 50000.0 + write: + filename: hz_ice.nc diff --git a/parm/soca/berror/soca_parameters_diffusion_vt.yaml.j2 b/parm/soca/berror/soca_parameters_diffusion_vt.yaml.j2 new file mode 100644 index 000000000..c740b37a7 --- /dev/null +++ b/parm/soca/berror/soca_parameters_diffusion_vt.yaml.j2 @@ -0,0 +1,32 @@ +geometry: &geom + mom6_input_nml: mom_input.nml + fields metadata: ./fields_metadata.yaml + +background: + read_from_file: 1 + basename: ./INPUT/ + ocn_filename: MOM.res.nc + ice_filename: cice.res.nc + date: '{{ MARINE_WINDOW_MIDDLE | to_isotime }}' + state variables: [cicen, hicen, hsnon, socn, tocn, uocn, vocn, ssh] + +background error: + covariance model: SABER + saber central block: + saber block name: EXPLICIT_DIFFUSION + geometry: *geom + calibration: + normalization: + # NOTE, not actually used here, since the normalization spec is only used for hz + method: randomization #< other option is "brute force" + iterations: 1000 #< in the real world you'll want to use 1e4 or so + + groups: + - name: vt_ocean + vertical: + as gaussian: true + from file: + filename: vt_scales.nc + variable name: vt + write: + filename: vt_ocean.nc diff --git a/parm/soca/berror/soca_static_bmat.yaml b/parm/soca/berror/soca_static_bmat.yaml index 36e9274a7..640af506c 100644 --- a/parm/soca/berror/soca_static_bmat.yaml +++ b/parm/soca/berror/soca_static_bmat.yaml @@ -31,8 +31,8 @@ saber outer blocks: model file: date: '{{ATM_WINDOW_MIDDLE}}' basename: ./ - ocn_filename: 'ocn.bkgerr_stddev.incr.{{ATM_WINDOW_MIDDLE}}.nc' - ice_filename: 'ice.bkgerr_stddev.incr.{{ATM_WINDOW_MIDDLE}}.nc' + ocn_filename: 'ocean.bkgerr_stddev.nc' + ice_filename: 'ice.bkgerr_stddev.nc' read_from_file: 3 linear variable change: diff --git a/parm/soca/berror/soca_vtscales.yaml.j2 b/parm/soca/berror/soca_vtscales.yaml.j2 index bad7d623f..0b5d7a104 100644 --- a/parm/soca/berror/soca_vtscales.yaml.j2 +++ b/parm/soca/berror/soca_vtscales.yaml.j2 @@ -1,6 +1,6 @@ gridspec_filename: soca_gridspec.nc restart_filename: ./INPUT/MOM.res.nc -mld_filename: 'ocn.bkgerr_stddev.incr.{{ ATM_WINDOW_MIDDLE }}.nc' +mld_filename: './diagb/ocn.bkgerr_stddev.incr.{{ MARINE_WINDOW_END | to_isotime }}.nc' output_filename: ./vt_scales.nc output_variable_vt: vt output_variable_hz: hz diff --git a/parm/soca/ensda/stage_ens_mem.yaml.j2 b/parm/soca/ensda/stage_ens_mem.yaml.j2 new file mode 100644 index 000000000..e30a337e7 --- /dev/null +++ b/parm/soca/ensda/stage_ens_mem.yaml.j2 @@ -0,0 +1,27 @@ +###################################### +# set some variables +###################################### +{% set gPDY = previous_cycle | to_YMD %} +{% set gcyc = previous_cycle | strftime("%H") %} +{% set PDY = current_cycle | to_YMD %} +{% set cyc = current_cycle | strftime("%H") %} +###################################### +# create working directories +###################################### +mkdir: +- "{{ DATAenspert }}/ens" + +###################################### +# copy ensemble background files +###################################### +copy: +{% for mem in range(1, NMEM_ENS + 1) %} + # define variables used in the history template + {% set tmpl_dict = {'${ROTDIR}':ROTDIR, + '${RUN}': GDUMP_ENS, + '${YMD}':gPDY, + '${HH}':gcyc, + '${MEMDIR}':"mem" + '%03d' % mem} %} + - ["{{ COM_OCEAN_HISTORY_TMPL | replace_tmpl(tmpl_dict) }}/{{ GDUMP_ENS }}.ocean.t{{ gcyc }}z.inst.f006.nc", "{{ DATAenspert }}/ens/ocean.{{ mem }}.nc"] + - ["{{ COM_ICE_HISTORY_TMPL | replace_tmpl(tmpl_dict) }}/{{ GDUMP_ENS }}.ice.t{{ gcyc }}z.inst.f006.nc", "{{ DATAenspert }}/ens/ice.{{ mem }}.nc"] +{% endfor %} diff --git a/parm/soca/soca_det_bkg_stage.yaml.j2 b/parm/soca/soca_det_bkg_stage.yaml.j2 new file mode 100644 index 000000000..a0474ee59 --- /dev/null +++ b/parm/soca/soca_det_bkg_stage.yaml.j2 @@ -0,0 +1,23 @@ +###################################### +# set some variables +###################################### +{% set gPDY = previous_cycle | to_YMD %} +{% set gcyc = previous_cycle | strftime("%H") %} +###################################### +# create ens bkg directories +###################################### +mkdir: +- "{{ DATA }}/bkg" + +###################################### +# copy ensemble background files +###################################### +copy: +# stage initial conditions +- ["{{ COMIN_OCEAN_HISTORY_PREV }}/gdas.ocean.t{{ gcyc }}z.inst.f003.nc", "{{ DATA }}/INPUT/MOM.res.nc"] +- ["{{ COMIN_ICE_HISTORY_PREV }}/gdas.ice.t{{ gcyc }}z.inst.f003.nc", "{{ DATA }}/INPUT/cice.res.nc"] +# stage f006 and f009 backgrounds +{% for fcsth in ['f006', 'f009'] %} +- ["{{ COMIN_OCEAN_HISTORY_PREV }}/gdas.ocean.t{{ gcyc }}z.inst.{{ fcsth }}.nc", "{{ DATA }}/bkg/ocean.bkg.{{ fcsth }}.nc"] +- ["{{ COMIN_ICE_HISTORY_PREV }}/gdas.ice.t{{ gcyc }}z.inst.{{ fcsth }}.nc", "{{ DATA }}/bkg/ice.bkg.{{ fcsth }}.nc"] +{% endfor %} diff --git a/parm/soca/soca_fix_stage_025.yaml.j2 b/parm/soca/soca_fix_stage_025.yaml.j2 new file mode 100644 index 000000000..fdd502276 --- /dev/null +++ b/parm/soca/soca_fix_stage_025.yaml.j2 @@ -0,0 +1,27 @@ +# TODO(AFE): make resolution dependent +mkdir: +- "{{ DATA }}/INPUT" +###################################### +# fix files to copy +###################################### +copy: +- ["{{ SOCA_INPUT_FIX_DIR }}/rossrad.nc", "{{ DATA }}/rossrad.nc"] # +- ["{{ SOCA_INPUT_FIX_DIR }}/field_table", "{{ DATA }}/field_table"] # +- ["{{ SOCA_INPUT_FIX_DIR }}/diag_table", "{{ DATA }}/diag_table"] # +- ["{{ SOCA_INPUT_FIX_DIR }}/MOM_input", "{{ DATA }}/MOM_input"] # +- ["{{ SOCA_INPUT_FIX_DIR }}/fields_metadata.yaml", "{{ DATA }}/fields_metadata.yaml"] # +- ["{{ SOCA_INPUT_FIX_DIR }}/obsop_name_map.yaml", "{{ DATA }}/obsop_name_map.yaml"] # +- ["{{ SOCA_INPUT_FIX_DIR }}/INPUT/grid_spec.nc", "{{ DATA }}/INPUT/grid_spec.nc"] # +- ["{{ SOCA_INPUT_FIX_DIR }}/INPUT/hycom1_75_800m.nc", "{{ DATA }}/INPUT/hycom1_75_800m.nc"] +- ["{{ SOCA_INPUT_FIX_DIR }}/INPUT/layer_coord.nc", "{{ DATA }}/INPUT/layer_coord.nc"] +- ["{{ SOCA_INPUT_FIX_DIR }}/INPUT/ocean_hgrid.nc", "{{ DATA }}/INPUT/ocean_hgrid.nc"] +- ["{{ SOCA_INPUT_FIX_DIR }}/INPUT/ocean_mosaic.nc", "{{ DATA }}/INPUT/ocean_mosaic.nc"] +- ["{{ SOCA_INPUT_FIX_DIR }}/INPUT/ocean_topog.nc", "{{ DATA }}/INPUT/ocean_topog.nc"] +- ["{{ SOCA_INPUT_FIX_DIR }}/INPUT/tidal_amplitude.v20140616.nc", "{{ DATA }}/INPUT/tidal_amplitude.v20140616.nc"] +- ["{{ SOCA_INPUT_FIX_DIR }}/INPUT/interpolate_zgrid_40L.nc", "{{ DATA }}/INPUT/interpolate_zgrid_40L.nc"] +- ["{{ SOCA_INPUT_FIX_DIR }}/INPUT/All_edits.nc", "{{ DATA }}/INPUT/All_edits.nc"] +- ["{{ SOCA_INPUT_FIX_DIR }}/INPUT/MOM_channels_global_025", "{{ DATA }}/INPUT/MOM_channels_global_025"] +- ["{{ SOCA_INPUT_FIX_DIR }}/INPUT/seawifs-clim-1997-2010.1440x1080.v20180328.nc", "{{ DATA }}/INPUT/seawifs-clim-1997-2010.1440x1080.v20180328.nc"] +- ["{{ SOCA_INPUT_FIX_DIR }}/INPUT/geothermal_davies2013_v1.nc", "{{ DATA }}/INPUT/geothermal_davies2013_v1.nc"] +- ["{{ SOCA_INPUT_FIX_DIR }}/INPUT/interpolate_zgrid_46L.nc", "{{ DATA }}/INPUT/interpolate_zgrid_46L.nc"] +- ["{{ SOCA_INPUT_FIX_DIR }}/INPUT/C384_mosaic.nc", "{{ DATA }}/INPUT/C384_mosaic.nc"] diff --git a/parm/soca/soca_fix_stage.yaml.j2 b/parm/soca/soca_fix_stage_500.yaml.j2 similarity index 100% rename from parm/soca/soca_fix_stage.yaml.j2 rename to parm/soca/soca_fix_stage_500.yaml.j2 diff --git a/scripts/exgdas_global_marine_analysis_bmat.sh b/scripts/exgdas_global_marine_analysis_bmat.sh deleted file mode 100755 index 315e9fdc7..000000000 --- a/scripts/exgdas_global_marine_analysis_bmat.sh +++ /dev/null @@ -1,141 +0,0 @@ -#!/bin/bash -################################################################################ -#### UNIX Script Documentation Block -# . . -# Script name: exgdas_global_marine_analysis_bmat.sh -# Script description: Performs calculations in preparation for the global -# marine analysis with SOCA -# -# Author: Andrew Eichamnn Org: NCEP/EMC Date: 2023-01-12 -# -# Abstract: This script does the follwing in preparation for creating the -# global model ocean sea-ice analysis using SOCA: -# - generates the DA grid -# - computes diagonal of B based on the background if a std. dev. file -# was not staged. TODO: Remove this option in the future -# - initialize the loacalization and correlation operator -# -# $Id$ -# -# Attributes: -# Language: POSIX shell -# Machine: Orion -# -################################################################################ - -# Set environment. -export VERBOSE=${VERBOSE:-"YES"} -if [ $VERBOSE = "YES" ]; then - echo $(date) EXECUTING $0 $* >&2 - set -x -fi - -# Directories -pwd=$(pwd) - -# Utilities -export NLN=${NLN:-"/bin/ln -sf"} - -function clean_yaml() -{ - mv $1 tmp_yaml; - sed -e "s/'//g" tmp_yaml > $1 -} - -################################################################################ -# Generate soca geometry if needed -if [[ -e 'soca_gridspec.nc' ]]; then - echo "soca_gridspc.nc already exists, skip the grid generation step" -else - # Run gdas_soca_gridgen.x if the grid was not staged - # TODO (Guillaume): Should not use all pe's for the grid generation - $APRUN_OCNANAL $JEDI_BIN/gdas_soca_gridgen.x gridgen.yaml - export err=$?; err_chk - if [ $err -gt 0 ]; then - exit $err - fi -fi - - -################################################################################ -# Ensemble processing -if [ "${NMEM_ENS}" -ge 3 ]; then - ################################################################################ - # Write ensemble weights for the hybrid envar - $APRUN_OCNANAL $JEDI_BIN/gdas_socahybridweights.x soca_ensweights.yaml - export err=$?; err_chk - if [ $err -gt 0 ]; then - exit $err - fi - - ################################################################################ - # Ensemble perturbations for the EnVAR - # Ensemble diagnostics: - # - Compute moments of original ensemble with the balanced ssh removed - # from the statistics - # - # Ensemble of perturbations: - # - apply the linear steric height balance to each members, using the - # deterministic for trajectory. - # - add the unblanced ssh to the steric ssh field - # Diagnostics: - # - variance explained by the steric heigh - # - moments - clean_yaml soca_clim_ens_moments.yaml - $APRUN_OCNANAL $JEDI_BIN/gdas_ens_handler.x soca_ensb.yaml - export err=$?; err_chk - if [ $err -gt 0 ]; then - exit $err - fi -fi - -################################################################################ -# Compute the parametric diag of B -$APRUN_OCNANAL $JEDI_BIN/gdas_soca_diagb.x soca_diagb.yaml -export err=$?; err_chk -if [ $err -gt 0 ]; then - exit $err -fi - -################################################################################ -# Horizontal diffusion -if [ ! -f "ocn.cor_rh.incr.0001-01-01T00:00:00Z.nc" ]; then - # Set decorrelation scales for the static B - $APRUN_OCNANAL $JEDI_BIN/gdas_soca_setcorscales.x soca_setcorscales.yaml - export err=$?; err_chk - if [ $err -gt 0 ]; then - exit $err - fi - # Initialize the horizontal diffusion block and normalize - clean_yaml soca_parameters_diffusion_hz.yaml - $APRUN_OCNANAL $JEDI_BIN/gdas_soca_error_covariance_toolbox.x soca_parameters_diffusion_hz.yaml - export err=$?; err_chk - if [ $err -gt 0 ]; then - exit $err - fi -else - echo "Diffusion weights already calculated, skipping the init of the horizontal diffusion" -fi - -################################################################################ -# Initialize the vertical diffusion block -# Compute the MLD dependent vertical scales -# TODO(G): Probably not the right way to execute this script -python ${HOMEgfs}/sorc/gdas.cd/sorc/soca/tools/calc_scales.py soca_vtscales.yaml -clean_yaml soca_parameters_diffusion_vt.yaml - -# Initialize the vertical diffusion block and normalize -$APRUN_OCNANAL $JEDI_BIN/gdas_soca_error_covariance_toolbox.x soca_parameters_diffusion_vt.yaml -export err=$?; err_chk -if [ $err -gt 0 ]; then - exit $err -fi - -################################################################################ -set +x -if [ $VERBOSE = "YES" ]; then - echo $(date) EXITING $0 with return code $err >&2 -fi -exit $err - -################################################################################ diff --git a/scripts/exgdas_global_marine_analysis_post.py b/scripts/exgdas_global_marine_analysis_post.py index 119fed228..4d2d8e889 100755 --- a/scripts/exgdas_global_marine_analysis_post.py +++ b/scripts/exgdas_global_marine_analysis_post.py @@ -67,6 +67,7 @@ def list_all_files(dir_in, dir_out, wc='*', fh_list=[]): domains = ['ocn', 'ice'] for domain in domains: + ''' # Copy of the diagonal of the background error for the cycle post_file_list.append([os.path.join(anl_dir, f'{domain}.bkgerr_stddev.incr.{mdate}.nc'), os.path.join(com_ocean_analysis, f'{RUN}.t{cyc}z.{domain}.bkgerr_stddev.nc')]) @@ -75,6 +76,7 @@ def list_all_files(dir_in, dir_out, wc='*', fh_list=[]): if nmem_ens > 2: post_file_list.append([os.path.join(anl_dir, 'static_ens', f'{domain}.ssh_recentering_error.incr.{bdate}.nc'), os.path.join(com_ocean_analysis, f'{RUN}.t{cyc}z.{domain}.recentering_error.nc')]) + ''' # Copy the ice and ocean increments post_file_list.append([os.path.join(anl_dir, 'Data', f'{domain}.3dvarfgat_pseudo.incr.{mdate}.nc'), @@ -85,6 +87,7 @@ def list_all_files(dir_in, dir_out, wc='*', fh_list=[]): os.path.join(com_ocean_analysis, f'{RUN}.t{cyc}z.{domain}ana.nc')]) # Copy of the ssh diagnostics +''' if nmem_ens > 2: for string in ['ssh_steric_stddev', 'ssh_unbal_stddev', 'ssh_total_stddev', 'steric_explained_variance']: post_file_list.append([os.path.join(anl_dir, 'static_ens', f'ocn.{string}.incr.{bdate}.nc'), @@ -93,6 +96,7 @@ def list_all_files(dir_in, dir_out, wc='*', fh_list=[]): # Copy DA grid (computed for the start of the window) post_file_list.append([os.path.join(anl_dir, 'soca_gridspec.nc'), os.path.join(com_ocean_analysis, f'{RUN}.t{bcyc}z.ocngrid.nc')]) +''' # Copy the CICE analysis restart if os.getenv('DOIAU') == "YES": diff --git a/scripts/exgdas_global_marine_analysis_prep.py b/scripts/exgdas_global_marine_analysis_prep.py index dba491868..3b601c680 100755 --- a/scripts/exgdas_global_marine_analysis_prep.py +++ b/scripts/exgdas_global_marine_analysis_prep.py @@ -16,7 +16,7 @@ from jcb import render from wxflow import (Logger, Template, TemplateConstants, - YAMLFile, FileHandler, AttrDict, parse_j2yaml) + YAMLFile, FileHandler) logger = Logger() @@ -168,120 +168,49 @@ def parse_obs_list_file(): ################################################################################ # stage ensemble members -if dohybvar: - logger.info("---------------- Stage ensemble members") - ens_member_list = [] - for mem in range(1, nmem_ens+1): - for domain in ['ocean', 'ice']: - # TODO(Guillaume): make use and define ensemble COM in the j-job - ensroot = os.getenv('COM_OCEAN_HISTORY_PREV') - ensdir = os.path.join(os.getenv('COM_OCEAN_HISTORY_PREV'), '..', '..', '..', '..', '..', - f'enkf{RUN}.{PDY}', f'{gcyc}', f'mem{str(mem).zfill(3)}', - 'model', domain, 'history') - ensdir_real = os.path.realpath(ensdir) - f009 = f'enkfgdas.{domain}.t{gcyc}z.inst.f009.nc' - - fname_in = os.path.abspath(os.path.join(ensdir_real, f009)) - fname_out = os.path.realpath(os.path.join(static_ens, domain+"."+str(mem)+".nc")) - ens_member_list.append([fname_in, fname_out]) - FileHandler({'copy': ens_member_list}).sync() - - # reformat the cice history output - for mem in range(1, nmem_ens+1): - cice_fname = os.path.realpath(os.path.join(static_ens, "ice."+str(mem)+".nc")) - bkg_utils.cice_hist2fms(cice_fname, cice_fname) -else: - if nmem_ens >= 3: - logger.info("---------------- Stage offline ensemble members") - ens_member_list = [] - clim_ens_dir = find_clim_ens(pytz.utc.localize(window_begin, is_dst=None)) - list_of_members = glob.glob(os.path.join(clim_ens_dir, 'ocean.*.nc')) - nmem_ens = min(nmem_ens, len(list_of_members)) - for domain in ['ocean', 'ice']: - for mem in range(1, nmem_ens+1): - fname = domain+"."+str(mem)+".nc" - fname_in = os.path.join(clim_ens_dir, fname) - fname_out = os.path.join(static_ens, fname) - ens_member_list.append([fname_in, fname_out]) - FileHandler({'copy': ens_member_list}).sync() - -os.environ['ENS_SIZE'] = str(nmem_ens) +if dohybvar or nmem_ens >= 3: + # TODO: No symlink allowed but this script will be refactored soon + # Relative path to ensemble perturbations + ens_perturbations = os.path.join('..', f'gdasmarinebmat.{PDY}{cyc}', 'enspert', 'ens') + os.symlink(ens_perturbations, 'ens') ################################################################################ # prepare JEDI yamls - +os.environ['ENS_SIZE'] = str(nmem_ens) logger.info(f"---------------- Generate JEDI yaml files") ################################################################################ -# copy yaml for grid generation - -logger.info(f"---------------- generate gridgen.yaml") -gridgen_yaml_src = os.path.realpath(os.path.join(gdas_home, 'parm', 'soca', 'gridgen', 'gridgen.yaml')) -gridgen_yaml_dst = os.path.realpath(os.path.join(stage_cfg['stage_dir'], 'gridgen.yaml')) -FileHandler({'copy': [[gridgen_yaml_src, gridgen_yaml_dst]]}).sync() - -################################################################################ -# generate the YAML file for the post processing of the clim. ens. B -berror_yaml_dir = os.path.join(gdas_home, 'parm', 'soca', 'berror') - -logger.info(f"---------------- generate soca_diagb.yaml") -conf = parse_j2yaml(path=os.path.join(berror_yaml_dir, 'soca_diagb.yaml.j2'), - data=envconfig) -conf.save(os.path.join(anl_dir, 'soca_diagb.yaml')) - -logger.info(f"---------------- generate soca_ensb.yaml") -berr_yaml = os.path.join(anl_dir, 'soca_ensb.yaml') -berr_yaml_template = os.path.join(berror_yaml_dir, 'soca_ensb.yaml') -config = YAMLFile(path=berr_yaml_template) -config = Template.substitute_structure(config, TemplateConstants.DOUBLE_CURLY_BRACES, envconfig.get) -config.save(berr_yaml) - -logger.info(f"---------------- generate soca_ensweights.yaml") -berr_yaml = os.path.join(anl_dir, 'soca_ensweights.yaml') -berr_yaml_template = os.path.join(berror_yaml_dir, 'soca_ensweights.yaml') -config = YAMLFile(path=berr_yaml_template) -config = Template.substitute_structure(config, TemplateConstants.DOUBLE_CURLY_BRACES, envconfig.get) -config.save(berr_yaml) +# Stage the soca grid +src = os.path.join(os.getenv('COMIN_OCEAN_BMATRIX'), 'soca_gridspec.nc') +dst = os.path.join(anl_dir, 'soca_gridspec.nc') +FileHandler({'copy': [[src, dst]]}).sync() ################################################################################ -# copy yaml for localization length scales - -logger.info(f"---------------- generate soca_setlocscales.yaml") -locscales_yaml_src = os.path.join(gdas_home, 'parm', 'soca', 'berror', 'soca_setlocscales.yaml') -locscales_yaml_dst = os.path.join(stage_cfg['stage_dir'], 'soca_setlocscales.yaml') -FileHandler({'copy': [[locscales_yaml_src, locscales_yaml_dst]]}).sync() - -################################################################################ -# copy yaml for correlation length scales - -logger.info(f"---------------- generate soca_setcorscales.yaml") -corscales_yaml_src = os.path.join(gdas_home, 'parm', 'soca', 'berror', 'soca_setcorscales.yaml') -corscales_yaml_dst = os.path.join(stage_cfg['stage_dir'], 'soca_setcorscales.yaml') -FileHandler({'copy': [[corscales_yaml_src, corscales_yaml_dst]]}).sync() +# stage the static B-matrix +bmat_list = [] +# Diagonal of the B matrix +bmat_list.append([os.path.join(os.getenv('COMIN_OCEAN_BMATRIX'), f"{RUN}.t{cyc}z.ocean.bkgerr_stddev.nc"), + os.path.join(anl_dir, "ocean.bkgerr_stddev.nc")]) +bmat_list.append([os.path.join(os.getenv('COMIN_ICE_BMATRIX'), f"{RUN}.t{cyc}z.ice.bkgerr_stddev.nc"), + os.path.join(anl_dir, "ice.bkgerr_stddev.nc")]) +# Correlation operator +bmat_list.append([os.path.join(os.getenv('COMIN_ICE_BMATRIX'), f"{RUN}.t{cyc}z.hz_ice.nc"), + os.path.join(anl_dir, "hz_ice.nc")]) +bmat_list.append([os.path.join(os.getenv('COMIN_OCEAN_BMATRIX'), f"{RUN}.t{cyc}z.hz_ocean.nc"), + os.path.join(anl_dir, "hz_ocean.nc")]) +bmat_list.append([os.path.join(os.getenv('COMIN_OCEAN_BMATRIX'), f"{RUN}.t{cyc}z.vt_ocean.nc"), + os.path.join(anl_dir, "vt_ocean.nc")]) +FileHandler({'copy': bmat_list}).sync() ################################################################################ -# copy yaml for diffusion initialization - -logger.info(f"---------------- generate soca_parameters_diffusion_hz.yaml") -diffu_hz_yaml = os.path.join(anl_dir, 'soca_parameters_diffusion_hz.yaml') -diffu_hz_yaml_dir = os.path.join(gdas_home, 'parm', 'soca', 'berror') -diffu_hz_yaml_template = os.path.join(berror_yaml_dir, 'soca_parameters_diffusion_hz.yaml') -config = YAMLFile(path=diffu_hz_yaml_template) -config = Template.substitute_structure(config, TemplateConstants.DOUBLE_CURLY_BRACES, envconfig.get) -config.save(diffu_hz_yaml) - -logger.info(f"---------------- generate soca_vtscales.yaml") -conf = parse_j2yaml(path=os.path.join(gdas_home, 'parm', 'soca', 'berror', 'soca_vtscales.yaml.j2'), - data=envconfig) -conf.save(os.path.join(anl_dir, 'soca_vtscales.yaml')) - -logger.info(f"---------------- generate soca_parameters_diffusion_vt.yaml") -diffu_vt_yaml = os.path.join(anl_dir, 'soca_parameters_diffusion_vt.yaml') -diffu_vt_yaml_dir = os.path.join(gdas_home, 'parm', 'soca', 'berror') -diffu_vt_yaml_template = os.path.join(berror_yaml_dir, 'soca_parameters_diffusion_vt.yaml') -config = YAMLFile(path=diffu_vt_yaml_template) -config = Template.substitute_structure(config, TemplateConstants.DOUBLE_CURLY_BRACES, envconfig.get) -config.save(diffu_vt_yaml) +# stage the ens B-matrix weights +if dohybvar or nmem_ens >= 3: + ensbmat_list = [] + ensbmat_list.append([os.path.join(os.getenv('COMIN_OCEAN_BMATRIX'), f"{RUN}.t{cyc}z.ocean.ens_weights.nc"), + os.path.join(anl_dir, "ocean.ens_weights.nc")]) + ensbmat_list.append([os.path.join(os.getenv('COMIN_ICE_BMATRIX'), f"{RUN}.t{cyc}z.ice.ens_weights.nc"), + os.path.join(anl_dir, "ice.ens_weights.nc")]) + FileHandler({'copy': ensbmat_list}).sync() ################################################################################ # generate yaml for soca_var @@ -308,10 +237,10 @@ def parse_obs_list_file(): os.environ['SABER_BLOCKS_YAML'] = os.path.join(gdas_home, 'parm', 'soca', 'berror', 'soca_static_bmat.yaml') # substitute templated variables in the var config -logger.info(f"{config}") +logger.info(f"{envconfig}") varconfig = YAMLFile(path=var_yaml_template) -varconfig = Template.substitute_structure(varconfig, TemplateConstants.DOUBLE_CURLY_BRACES, config.get) -varconfig = Template.substitute_structure(varconfig, TemplateConstants.DOLLAR_PARENTHESES, config.get) +varconfig = Template.substitute_structure(varconfig, TemplateConstants.DOUBLE_CURLY_BRACES, envconfig.get) +varconfig = Template.substitute_structure(varconfig, TemplateConstants.DOLLAR_PARENTHESES, envconfig.get) varconfig = Template.substitute_structure(varconfig, TemplateConstants.DOUBLE_CURLY_BRACES, envconfig.get) varconfig = Template.substitute_structure(varconfig, TemplateConstants.DOLLAR_PARENTHESES, envconfig.get) @@ -320,7 +249,7 @@ def parse_obs_list_file(): # Produce JEDI YAML file using JCB (for demonstration purposes) # ------------------------------------------------------------- - +""" # Make a copy of the env config before modifying to avoid breaking something else envconfig_jcb = copy.deepcopy(envconfig) @@ -362,7 +291,7 @@ def parse_obs_list_file(): # Save the JEDI configuration file var_yaml_jcb = os.path.join(anl_dir, 'var-jcb.yaml') ufsda.yamltools.save_check(jedi_config, target=var_yaml_jcb, app='var') - +""" ################################################################################ # Prepare the yamls for the "checkpoint" jjob diff --git a/test/gw-ci/CMakeLists.txt b/test/gw-ci/CMakeLists.txt index dfd2a112f..357beaafe 100644 --- a/test/gw-ci/CMakeLists.txt +++ b/test/gw-ci/CMakeLists.txt @@ -46,8 +46,8 @@ set(pslot "WCDA-3DVAR-C48mx500") set(YAML_PATH ${HOMEgfs}/ci/cases/pr/C48mx500_3DVarAOWCDA.yaml) set(TASK_LIST "gdasprepoceanobs" + "gdasmarinebmat" "gdasocnanalprep" - "gdasocnanalbmat" "gdasocnanalrun" "gdasocnanalchkpt" "gdasocnanalpost" diff --git a/test/soca/gw/CMakeLists.txt b/test/soca/gw/CMakeLists.txt index 0b6acd866..1936ae994 100644 --- a/test/soca/gw/CMakeLists.txt +++ b/test/soca/gw/CMakeLists.txt @@ -10,11 +10,19 @@ add_test(NAME test_gdasapp_soca_prep ENVIRONMENT "PYTHONPATH=${PROJECT_BINARY_DIR}/ush:${PROJECT_SOURCE_DIR}/../../ush/python/wxflow:$ENV{PYTHONPATH}") # Identify machine -if (MACHINE STREQUAL "hercules") - set(PARTITION "hercules") -ELSEIF (MACHINE STREQUAL "orion") - set(PARTITION "orion") -ELSEIF (MACHINE STREQUAL "hera") +set(MACHINE "container") +IF (IS_DIRECTORY /work2) + string(SUBSTRING $ENV{HOSTNAME} 0 8 HOST) + IF ("${HOST}" STREQUAL "hercules") + set(MACHINE "hercules") + set(PARTITION "hercules") + ELSE() + set(MACHINE "orion") + set(PARTITION "orion") + ENDIF() +ENDIF() +IF (IS_DIRECTORY /scratch2/NCEPDEV/) + set(MACHINE "hera") set(PARTITION "hera") ENDIF() @@ -35,10 +43,11 @@ add_test(NAME test_gdasapp_soca_setup_obsprep # Test JGDAS_GLOBAL_OCEAN_ANALYSIS_* set(jjob_list "JGLOBAL_PREP_OCEAN_OBS" + "JGLOBAL_MARINE_BMAT" "JGDAS_GLOBAL_OCEAN_ANALYSIS_PREP" - "JGDAS_GLOBAL_OCEAN_ANALYSIS_BMAT" +# "JGDAS_GLOBAL_OCEAN_ANALYSIS_BMAT" "JGDAS_GLOBAL_OCEAN_ANALYSIS_RUN" - "JGDAS_GLOBAL_OCEAN_ANALYSIS_ECEN" +# "JGDAS_GLOBAL_OCEAN_ANALYSIS_ECEN" # "JGDAS_GLOBAL_OCEAN_ANALYSIS_LETKF" "JGDAS_GLOBAL_OCEAN_ANALYSIS_CHKPT" "JGDAS_GLOBAL_OCEAN_ANALYSIS_POST") @@ -70,7 +79,7 @@ foreach(jjob ${jjob_list}) WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/test/soca/gw/testrun) set_tests_properties(${test_name} PROPERTIES - ENVIRONMENT "PYTHONPATH=${PROJECT_SOURCE_DIR}/ush/ioda/bufr2ioda::${PROJECT_SOURCE_DIR}/ush:${PROJECT_BINARY_DIR}/../lib/python${Python3_VERSION_MAJOR}.${Python3_VERSION_MINOR}:$ENV{PYTHONPATH}:${PROJECT_SOURCE_DIR}/../../../../ush/python") + ENVIRONMENT "PYTHONPATH=${PROJECT_SOURCE_DIR}/ush/ioda/bufr2ioda::${PROJECT_SOURCE_DIR}/ush:${PROJECT_BINARY_DIR}/../lib/python${Python3_VERSION_MAJOR}.${Python3_VERSION_MINOR}:${PROJECT_SOURCE_DIR}/ush/soca:${PROJECT_SOURCE_DIR}/../../../../ush/python:$ENV{PYTHONPATH}") set(setup "--skip") # Only run the setup of the first test, if not, it will hang @@ -78,7 +87,7 @@ foreach(jjob ${jjob_list}) endforeach() # Test gdas/oops applications -set(ctest_list "socahybridweights" "incr_handler" "ens_handler") +# add ens_handler back to the list when testing ensemble DA again foreach(ctest ${ctest_list}) set(TEST ${ctest}) set(EXEC ${PROJECT_BINARY_DIR}/../bin/gdas_${ctest}.x) diff --git a/test/soca/gw/run_jjobs.yaml.test b/test/soca/gw/run_jjobs.yaml.test index f2331b07a..d8e4e6338 100644 --- a/test/soca/gw/run_jjobs.yaml.test +++ b/test/soca/gw/run_jjobs.yaml.test @@ -48,7 +48,7 @@ setup_expt config: DO_JEDIOCNVAR: "YES" DO_JEDISNOWDA: "NO" DO_MERGENSST: "NO" - NMEM_ENS: "4" + NMEM_ENS: "0" DOHYBVAR: "NO" ocnanal: SOCA_INPUT_FIX_DIR: @HOMEgfs@/sorc/gdas.cd/build/gdas/soca_static diff --git a/ush/soca/calc_scales.py b/ush/soca/calc_scales.py new file mode 100755 index 000000000..2ca6ce205 --- /dev/null +++ b/ush/soca/calc_scales.py @@ -0,0 +1,136 @@ +#!/usr/bin/env python +# TODO: Copied/pasted from SOCA, point to the original one after we update the JEDI # + +import netCDF4 as nc +import numpy as np +import warnings +from scipy.ndimage import gaussian_filter, distance_transform_edt +import yaml +import argparse + + +def load_config(config_file): + with open(config_file, 'r') as stream: + config = yaml.safe_load(stream) + return config + + +def run(yaml_file): + config = load_config(yaml_file) + gridspec_filename = config.get('gridspec_filename', "./soca_gridspec.nc") + restart_filename = config.get('restart_filename', "./MOM.res.nc") + mld_filename = config.get('mld_filename', "./average_MLD.nc") + output_filename = config.get('output_filename', "./scales.nc") + output_variable_vt = config.get('output_variable_vt', 'vt') + output_variable_hz = config.get('output_variable_hz', 'hz') + + VT_MIN = float(config.get('VT_MIN', 1.5)) + VT_MAX = float(config.get('VT_MAX', 10)) + + HZ_ROSSBY_MULT = float(config.get('HZ_ROSSBY_MULT', 1.0)) + HZ_MAX = float(config.get('HZ_MAX', 200e3)) + HZ_MIN_GRID_MULT = float(config.get('HZ_MIN_GRID_MULT', 1.0)) + + # read input + with nc.Dataset(gridspec_filename, 'r') as src: + rossbyRadius = src.variables['rossby_radius'][0] + dx = src.variables['dx'][0] + dy = src.variables['dy'][0] + area = src.variables['area'][0] + mask = src.variables['mask2d'][0] + with nc.Dataset(restart_filename, 'r') as src: + h = src.variables['h'][0] + varType = src.variables['h'].datatype + with nc.Dataset(mld_filename, 'r') as src: + mld = src.variables['MLD'][0] + nz = h.shape[0] + + # calculate horizontal scales + hz_scales = rossbyRadius * HZ_ROSSBY_MULT + hz_scales = np.clip(hz_scales, a_min=dx*HZ_MIN_GRID_MULT, a_max=HZ_MAX) + hz_scales = np.clip(hz_scales, a_min=dy*HZ_MIN_GRID_MULT, a_max=HZ_MAX) + + # calculate hz smoothing scales for use inside this script. + # The scales (in units of # of grid cells) is zonally averaged, we assume hz scales + # do not vary as much with longitude as they do with latitude + with warnings.catch_warnings(): + warnings.simplefilter("ignore", category=RuntimeWarning) + smoothingScale = np.nanmean(np.where(mask, hz_scales/np.sqrt(area), np.NaN), axis=1) + smoothingScale[0] = smoothingScale[1] + smoothingScale[-1] = smoothingScale[-2] + + # smooth the horizontal scales WITH the horizontal scales. + hz_scales_orig = hz_scales.copy() + for j in range(hz_scales.shape[0]): # zonally for efficiency (otherwise it would be am i/j set of for loops) + hz_scales[j, :] = gaussian_filter(hz_scales_orig, sigma=smoothingScale[j], mode='nearest')[j, :] + hz_scales = np.where(mask, hz_scales, 0) + del hz_scales_orig + + # calculate vertical scales. + # --------------------------------------------------------- + + # initialize with zeros + vtScales = np.zeros_like(h) + + # smooth the MLD with the horizontal scales. + mld_orig = mld.copy() + # fill missing + mld_orig = mld[tuple(distance_transform_edt(mask == 0, return_distances=False, return_indices=True))] + for j in range(mld.shape[0]): # zonally for efficiency (otherwise it would be am i/j set of for loops) + mld[j, :] = gaussian_filter(mld_orig, sigma=smoothingScale[j], mode='nearest')[j, :] + mld = np.where(mask, mld, 0) + del mld_orig + + # calculate layer depths for use later + layerDepth = np.cumsum(h, axis=0) - h/2.0 + maxLevels = np.sum(np.where(h > 0.01, 1, 0), axis=0) # number of lvls before we hit bottom + + # find index of last level in the mixed layer + mlLastLevel = np.where(layerDepth < np.stack([mld]*nz, axis=0), 1, 0) + mlLastLevel[h <= 0.01] = 0 # don't count small bottom layers + mlLastLevel = np.clip(np.sum(mlLastLevel, axis=0)-1, a_min=0, a_max=nz-2) + + # add to that a fraction of layer at the bottom of the mixed layer + # for a total fractional number of levels in the ML + y_idx, x_idx = np.indices(mlLastLevel.shape) + depth1 = layerDepth[mlLastLevel, y_idx, x_idx] + depth2 = layerDepth[mlLastLevel+1, y_idx, x_idx] + mlLayers = mlLastLevel + (mld - depth1) / (depth2-depth1) + mlLayers = np.clip(mlLayers, a_min=1, a_max=maxLevels) + + # set the top to the number of levels in the ML, interpolate down to bottom of ML + # AND enforce a min/max value. The max value is important in order + # to keep the number of diffusion iterations in check. The resulting diracs + # are not quite the same... but close enough. + layer, _, _ = np.indices(h.shape) + mlLayers3D = np.stack([mlLayers]*nz, axis=0) + vtScales[:] = np.clip(mlLayers3D - layer, a_min=VT_MIN, a_max=VT_MAX) + + # ignore thin layers at the bottom + vtScales[h <= 0.01] = 0 + + # write output file + with nc.Dataset(output_filename, 'w') as dst: + dst.createDimension('Time', None) + dst.createDimension('z', vtScales.shape[0]) + dst.createDimension('y', vtScales.shape[1]) + dst.createDimension('x', vtScales.shape[2]) + + time = dst.createVariable('Time', varType, ('Time',)) + var_vt = dst.createVariable(output_variable_vt, varType, ('z', 'y', 'x')) + var_hz = dst.createVariable(output_variable_hz, varType, ('y', 'x')) + + var_vt[:] = vtScales + var_hz[:] = hz_scales + + +def main(): + parser = argparse.ArgumentParser(description='Process some netCDF files.') + parser.add_argument('config_file', help='Path to the YAML configuration file') + args = parser.parse_args() + + run(args.config_file) + + +if __name__ == "__main__": + main()