diff --git a/CMakeLists.txt b/CMakeLists.txt index b5d2dbf2d..7f432d428 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,7 +94,7 @@ if(BUILD_GDASBUNDLE) endif() ecbuild_bundle( PROJECT gsw GIT "https://github.com/jcsda-internal/GSW-Fortran.git" BRANCH develop ) ecbuild_bundle( PROJECT mom6 GIT "https://github.com/jcsda-internal/MOM6.git" BRANCH main-ecbuild RECURSIVE ) - ecbuild_bundle( PROJECT soca GIT "https://github.com/jcsda-internal/soca.git" BRANCH develop ) + ecbuild_bundle( PROJECT soca GIT "https://github.com/jcsda-internal/soca.git" BRANCH feature/change_mask_value ) # Build JEDI/DA or other peripherals ecbuild_bundle( PROJECT gdas-utils SOURCE "./utils" ) diff --git a/parm/soca/berror/saber_block_ens.yaml b/parm/soca/berror/saber_block_ens.yaml deleted file mode 100644 index 9420102b0..000000000 --- a/parm/soca/berror/saber_block_ens.yaml +++ /dev/null @@ -1,12 +0,0 @@ -covariance model: ensemble -members from template: - template: - read_from_file: 1 - date: '{{ATM_WINDOW_BEGIN}}' - basename: ./ens/ - ocn_filename: MOM.res_%mem%.nc - ice_filename: cice.res_%mem%.nc - remap_filename: ./bkg/MOM.res.nc - state variables: [tocn, sonc, ssh, hocn, cicen, hicen] - pattern: '%mem%' - nmembers: 3 \ No newline at end of file diff --git a/parm/soca/berror/saber_blocks.yaml b/parm/soca/berror/saber_blocks.yaml index 3fb4cf412..d039355da 100644 --- a/parm/soca/berror/saber_blocks.yaml +++ b/parm/soca/berror/saber_blocks.yaml @@ -27,21 +27,22 @@ components: - linear variable change name: BkgErrSOCA read_from_file: 3 - basename: ./ - ocn_filename: 'ocn.bkgerr_stddev.incr.{{ATM_WINDOW_BEGIN}}.nc' - ice_filename: 'ice.bkgerr_stddev.incr.{{ATM_WINDOW_BEGIN}}.nc' - remap_filename: ./INPUT/MOM.res.nc - date: '{{ATM_WINDOW_BEGIN}}' + basename: ./static_ens/ + ocn_filename: 'ocn.orig_ens_stddev.incr.{{ATM_WINDOW_BEGIN}}.nc' + ice_filename: 'ice.orig_ens_stddev.incr.{{ATM_WINDOW_BEGIN}}.nc' + #remap_filename: ./INPUT/MOM.res.nc + date: '{{ATM_WINDOW_MIDDLE}}' t_min: 0.1 - t_max: 5.0 - s_min: 0.0 - s_max: 0.0 + t_max: 10.0 + s_min: 0.1 + s_max: 10.0 ssh_min: 0.0 # std ssh=0 => ssh balance applied as ssh_max: 0.0 # strong constraint cicen_min: 0.1 cicen_max: 0.5 hicen_min: 0.0 hicen_max: 0.0 + standard deviation: true - linear variable change name: BalanceSOCA ksshts: @@ -53,34 +54,29 @@ components: members from template: template: read_from_file: 1 - date: '{{ATM_WINDOW_BEGIN}}' + date: '{{ATM_WINDOW_MIDDLE}}' basename: ./static_ens/ - ocn_filename: ocn.%mem%.nc - ice_filename: ice.%mem%.nc - remap_filename: ./INPUT/MOM.res.nc - state variables: [tocn, socn, ssh, uocn, vocn, hocn, cicen, hicen, hsnon, mld, layer_depth] + ocn_filename: 'ocn.filtered.%mem%.incr.{{ATM_WINDOW_BEGIN}}.nc' + ice_filename: 'ice.filtered.%mem%.incr.{{ATM_WINDOW_BEGIN}}.nc' + state variables: [tocn, socn, ssh, uocn, vocn, cicen, hicen, hsnon] pattern: '%mem%' nmembers: ${CLIM_ENS_SIZE} localization: localization method: SABER saber central block: saber block name: BUMP_NICAS - active variables: [tocn, socn, ssh, uocn, vocn, cicen, hicen, hsnon] read: io: data directory: bump - #files prefix: soca_bump drivers: - multivariate strategy: crossed + multivariate strategy: duplicated read local nicas: true - grids: - - model: - variables: [tocn, socn, uocn, vocn] -# io: -# files prefix: bump - - model: - variables: [ssh, cicen, hicen, hsnon] -# io: -# files prefix: bump + model: + do not cross mask boundaries: false + weight: - value: 1.0 + 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' + date: '{{ATM_WINDOW_MIDDLE}}' diff --git a/parm/soca/berror/soca_apply_steric.yaml b/parm/soca/berror/soca_apply_steric.yaml new file mode 100644 index 000000000..62e9ded2b --- /dev/null +++ b/parm/soca/berror/soca_apply_steric.yaml @@ -0,0 +1,43 @@ +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, uocn, vocn, hocn, cicen, hicen, hsnon] + output variables: [tocn, socn, ssh, uocn, vocn, hocn, cicen, hicen, hsnon] + do inverse: false + linear variable changes: + - linear variable change name: BkgErrFILT + ocean_depth_min: 500 # zero where ocean is shallower than 500m + rescale_bkgerr: 0.3 # rescale perturbation + efold_z: 1500.0 # Apply exponential decay + - linear variable change name: BalanceSOCA # linear steric height from (T,S) perturbation + +increments: +- date: '{{ATM_WINDOW_BEGIN}}' + input variables: [tocn, socn, ssh, uocn, vocn, hocn, cicen, hicen, hsnon] + input: + read_from_file: 1 + basename: ./static_ens/ + ocn_filename: 'ocn.bal.ens.MEMNUM.{{ATM_WINDOW_BEGIN}}.PT0S.nc' + ice_filename: 'ice.bal.ens.MEMNUM.{{ATM_WINDOW_BEGIN}}.PT0S.nc' + date: '{{ATM_WINDOW_BEGIN}}' + state variables: [ssh, tocn, socn, uocn, vocn, cicen, hicen, hsnon] + 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, hsnon, socn, tocn, uocn, vocn, ssh, hocn, mld, layer_depth] + output: + datadir: ./static_ens + exp: filtered.MEMNUM + type: incr + date: '{{ATM_WINDOW_BEGIN}}' diff --git a/parm/soca/berror/soca_bump_loc.yaml b/parm/soca/berror/soca_bump_loc.yaml index 1d6f35853..0312c5813 100644 --- a/parm/soca/berror/soca_bump_loc.yaml +++ b/parm/soca/berror/soca_bump_loc.yaml @@ -9,7 +9,7 @@ background: basename: ./INPUT/ ocn_filename: MOM.res.nc ice_filename: cice.res.nc - state variables: [cicen, hicen, hsnon, socn, tocn, uocn, vocn, ssh] + state variables: [tocn] background error: covariance model: SABER @@ -19,7 +19,7 @@ background error: io: data directory: bump drivers: - multivariate strategy: crossed + multivariate strategy: duplicated compute nicas: true write local nicas: true write nicas grids: true @@ -28,11 +28,6 @@ background error: nicas: resolution: !ENV ${NICAS_RESOL} max horizontal grid size: ${NICAS_GRID_SIZE} - grids: - - model: - variables: [socn, tocn, uocn, vocn] - - model: - variables: [ssh, cicen, hicen, hsnon] input model files: - parameter: rh @@ -40,14 +35,14 @@ background error: 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, socn, tocn, uocn, vocn, ssh] + ocn_filename: ocn.loc_rh.incr.0001-01-01T00:00:00Z.nc + ice_filename: ice.loc_rh.incr.0001-01-01T00:00:00Z.nc + state variables: [tocn] - 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, socn, tocn, uocn, vocn, ssh] + ocn_filename: ocn.loc_rv.incr.0001-01-01T00:00:00Z.nc + ice_filename: ice.loc_rv.incr.0001-01-01T00:00:00Z.nc + state variables: [tocn] diff --git a/parm/soca/berror/soca_bump_split.yaml b/parm/soca/berror/soca_bump_split.yaml index cb0822ca1..51bade388 100644 --- a/parm/soca/berror/soca_bump_split.yaml +++ b/parm/soca/berror/soca_bump_split.yaml @@ -9,7 +9,7 @@ background: basename: ./INPUT/ ocn_filename: MOM.res.nc ice_filename: cice.res.nc - state variables: [cicen, hicen, hsnon, socn, tocn, ssh] + state variables: [cicen, hicen, hsnon, socn, tocn, uocn, vocn, ssh] background error: covariance model: SABER diff --git a/parm/soca/berror/soca_clim_ens_moments.yaml b/parm/soca/berror/soca_clim_ens_moments.yaml new file mode 100644 index 000000000..6304ba0db --- /dev/null +++ b/parm/soca/berror/soca_clim_ens_moments.yaml @@ -0,0 +1,29 @@ +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 + remap_filename: ./INPUT/MOM.res.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/soca_clim_ens_perts.yaml b/parm/soca/berror/soca_clim_ens_perts.yaml new file mode 100644 index 000000000..90d0abb36 --- /dev/null +++ b/parm/soca/berror/soca_clim_ens_perts.yaml @@ -0,0 +1,35 @@ +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 + remap_filename: ./INPUT/MOM.res.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: bal + type: ens + date: '{{ATM_WINDOW_BEGIN}}' diff --git a/parm/soca/berror/soca_ensweights.yaml b/parm/soca/berror/soca_ensweights.yaml new file mode 100644 index 000000000..ee25ab73f --- /dev/null +++ b/parm/soca/berror/soca_ensweights.yaml @@ -0,0 +1,27 @@ +geometry: + mom6_input_nml: mom_input.nml + fields metadata: ./fields_metadata.yaml + +date: '{{ATM_WINDOW_MIDDLE}}' + +variables: + ice: [cicen, hicen, hsnon] + ocean: [tocn, socn, uocn, vocn, ssh] + +background: + date: '{{ATM_WINDOW_BEGIN}}' + 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.01 # 10% " " + +output: + datadir: ./ + date: '{{ATM_WINDOW_MIDDLE}}' + exp: ens_weights + type: incr diff --git a/parm/soca/berror/soca_setlocscales.yaml b/parm/soca/berror/soca_setlocscales.yaml new file mode 100644 index 000000000..981cb4fc5 --- /dev/null +++ b/parm/soca/berror/soca_setlocscales.yaml @@ -0,0 +1,26 @@ +resolution: + mom6_input_nml: mom_input.nml + fields metadata: ./fields_metadata.yaml + +date: 0001-01-01T00:00:00Z + +corr variables: [tocn, cicen] + +scales: + vert layers: 70 # in units of layer + tocn: + rossby mult: 1.00 + min grid mult: 2.0 + cicen: + rossby mult: 1.00 + min grid mult: 2.0 + +rh output: + datadir: ./ + exp: loc_rh + type: incr + +rv output: + datadir: ./ + exp: loc_rv + type: incr diff --git a/parm/soca/obs/config/salt_profile_fnmoc.yaml b/parm/soca/obs/config/salt_profile_fnmoc.yaml index 66689face..bba544fa8 100644 --- a/parm/soca/obs/config/salt_profile_fnmoc.yaml +++ b/parm/soca/obs/config/salt_profile_fnmoc.yaml @@ -9,8 +9,13 @@ obs space: type: H5File obsfile: !ENV ${DATA}/diags/salt_profile_fnmoc.${PDY}${cyc}.nc4 simulated variables: [salinity] + io pool: + max pool size: 1 obs operator: - name: MarineVertInterp + name: VertInterp observation alias file: ./obsop_name_map.yaml + vertical coordinate: sea_water_depth + observation vertical coordinate: depth + interpolation method: linear obs error: covariance model: diagonal diff --git a/parm/soca/obs/config/temp_profile_fnmoc.yaml b/parm/soca/obs/config/temp_profile_fnmoc.yaml index a96cf453b..d7de83182 100644 --- a/parm/soca/obs/config/temp_profile_fnmoc.yaml +++ b/parm/soca/obs/config/temp_profile_fnmoc.yaml @@ -8,8 +8,10 @@ obs space: engine: type: H5File obsfile: !ENV ${DATA}/diags/temp_profile_fnmoc.${PDY}${cyc}.nc4 - simulated variables: [sea_water_temperature] + simulated variables: [waterTemperature] + io pool: + max pool size: 1 obs operator: - name: Identity + name: InsituTemperature obs error: covariance model: diagonal diff --git a/parm/soca/variational/3dvarfgat.yaml b/parm/soca/variational/3dvarfgat.yaml index b429d7dc4..de59a03d8 100644 --- a/parm/soca/variational/3dvarfgat.yaml +++ b/parm/soca/variational/3dvarfgat.yaml @@ -1,16 +1,8 @@ cost function: - cost type: 4D-Var + cost type: 3D-FGAT window begin: '{{ATM_WINDOW_BEGIN}}' window length: $(ATM_WINDOW_LENGTH) analysis variables: &soca_ana_vars [cicen, hicen, hsnon, socn, tocn, uocn, vocn, ssh] -# variable change: -# variable change name: Ana2Model -# rotate: -# u: [] -# v: [] -# log: -# var: [] -# output variables: *soca_ana_vars geometry: mom6_input_nml: mom_input.nml @@ -19,7 +11,6 @@ cost function: model: name: PseudoModel tstep: PT3H - state variables: &soca_model_vars [cicen, hicen, hsnon, socn, tocn, uocn, vocn, ssh, hocn, mld, layer_depth] states: !INC ${BKG_LIST} background: @@ -28,7 +19,8 @@ cost function: ocn_filename: MOM.res.nc ice_filename: cice.res.nc date: '{{ATM_WINDOW_BEGIN}}' - state variables: *soca_model_vars + state variables: &soca_model_vars [cicen, hicen, hsnon, socn, tocn, uocn, vocn, ssh, hocn, mld, layer_depth] + background error: !INC ${SABER_BLOCKS_YAML} observations: !INC ${OBS_LIST} @@ -40,23 +32,11 @@ variational: - geometry: mom6_input_nml: mom_input.nml fields metadata: ./fields_metadata.yaml - linear model: - name: Identity - increment variables: *soca_ana_vars - variable change: Identity - tstep: PT3H ninner: !ENV ${SOCA_NINNER} gradient norm reduction: 1e-10 test: on diagnostics: departures: ombg - online diagnostics: - write increment: true - increment: - datadir: Data - date: '{{ATM_WINDOW_BEGIN}}' - exp: iter1 - type: incr minimizer: algorithm: RPCG @@ -65,6 +45,8 @@ output: datadir: Data exp: 3dvarfgat_pseudo type: an + frequency: PT3H # can only writes out the analysis at the middle of the window + # when using 3D-FGAT as cost function final: diagnostics: diff --git a/parm/soca/variational/socaincr2mom6.yaml b/parm/soca/variational/socaincr2mom6.yaml index c6c2a50c3..75101244e 100644 --- a/parm/soca/variational/socaincr2mom6.yaml +++ b/parm/soca/variational/socaincr2mom6.yaml @@ -17,7 +17,7 @@ vertical geometry: soca increment: date: '{{ATM_WINDOW_BEGIN}}' basename: ./Data/ - ocn_filename: 'ocn.3dvarfgat_pseudo.incr.{{ATM_WINDOW_BEGIN}}.nc' + ocn_filename: 'ocn.3dvarfgat_pseudo.incr.{{ATM_WINDOW_MIDDLE}}.nc' read_from_file: 1 mom6 iau increment: diff --git a/scripts/exgdas_global_marine_analysis_bmat.sh b/scripts/exgdas_global_marine_analysis_bmat.sh index caf9af092..28dab42cc 100755 --- a/scripts/exgdas_global_marine_analysis_bmat.sh +++ b/scripts/exgdas_global_marine_analysis_bmat.sh @@ -87,7 +87,7 @@ else fi ################################################################################ -# Prepare the diagonal of B +# Prepare the diagonal of the parametric B shopt -s nullglob files=(ocn.bkgerr_stddev.incr.*.nc) echo $files @@ -103,6 +103,51 @@ else fi shopt -u nullglob +################################################################################ +# 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 + +################################################################################ +# Compute the ens std. dev, ignore ssh variance +# TODO (G): Implement what's below into one single oops application +# 0 - Compute moments of original ensemble, used at the diag of the first +# component of the hybrid B +# 1 - Ensemble perturbations: +# o Vertically Interpolate to the deterministic layers +# o Recenter around 0 to create an ensemble of perturbations +# 2 - Filter members and apply the linear steric height balance to each members +# 3 - Copy h from deterministic to unbalanced perturbations +# 4 - Compute moments of converted ensemble perturbations + +# Compute ensemble moments +clean_yaml soca_clim_ens_moments.yaml +$APRUN_OCNANAL $JEDI_BIN/soca_ensmeanandvariance.x soca_clim_ens_moments.yaml +export err=$?; err_chk +if [ $err -gt 0 ]; then + exit $err +fi + +# Compute ensemble perturbations, vertically remap to cycle's vertical geometry +clean_yaml soca_clim_ens_perts.yaml +$APRUN_OCNANAL $JEDI_BIN/soca_ensrecenter.x soca_clim_ens_perts.yaml +export err=$?; err_chk +if [ $err -gt 0 ]; then + exit $err +fi + +# Vertical filtering of the 3D perturbations and recompute the steric height perturbation +clean_yaml soca_apply_steric.yaml +$APRUN_OCNANAL $JEDI_BIN/soca_convertincrement.x soca_apply_steric.yaml +export err=$?; err_chk +if [ $err -gt 0 ]; then + exit $err +fi + + ################################################################################ # Correlation and Localization operators shopt -s nullglob @@ -120,7 +165,15 @@ fi ################################################################################ # Set decorrelation scales for bump C -$APRUN_OCNANAL $JEDI_BIN/soca_setcorscales.x soca_setcorscales.yaml > soca_setcorscales.out 2>&1 +$APRUN_OCNANAL $JEDI_BIN/soca_setcorscales.x soca_setcorscales.yaml +export err=$?; err_chk +if [ $err -gt 0 ]; then + exit $err +fi + +################################################################################ +# Set localization scales for the hybrid en. var. +$APRUN_OCNANAL $JEDI_BIN/soca_setcorscales.x soca_setlocscales.yaml export err=$?; err_chk if [ $err -gt 0 ]; then exit $err diff --git a/scripts/exgdas_global_marine_analysis_post.py b/scripts/exgdas_global_marine_analysis_post.py index c1a0b4e11..04aaa10a3 100755 --- a/scripts/exgdas_global_marine_analysis_post.py +++ b/scripts/exgdas_global_marine_analysis_post.py @@ -51,6 +51,7 @@ def list_all_files(dir_in, dir_out, wc='*', fh_list=[]): gcyc = str((int(cyc) - 6) % 24).zfill(2) # previous cycle bdatedt = datetime.strptime(cdate, '%Y%m%d%H') - timedelta(hours=3) bdate = datetime.strftime(bdatedt, '%Y-%m-%dT%H:00:00Z') +mdate = datetime.strftime(datetime.strptime(cdate, '%Y%m%d%H'), '%Y-%m-%dT%H:00:00Z') post_file_list = [] @@ -59,15 +60,15 @@ def list_all_files(dir_in, dir_out, wc='*', fh_list=[]): os.path.join(com_ocean_analysis, f'{RUN}.t{cyc}z.ocninc.nc')]) # Copy of the diagonal of the background error for the cycle -post_file_list.append([os.path.join(anl_dir, f'ocn.bkgerr_stddev.incr.{bdate}.nc'), +post_file_list.append([os.path.join(anl_dir, 'static_ens', f'ocn.orig_ens_stddev.incr.{bdate}.nc'), os.path.join(com_ocean_analysis, f'{RUN}.t{cyc}z.ocn.bkgerr_stddev.nc')]) -post_file_list.append([os.path.join(anl_dir, f'ice.bkgerr_stddev.incr.{bdate}.nc'), +post_file_list.append([os.path.join(anl_dir, 'static_ens', f'ice.orig_ens_stddev.incr.{bdate}.nc'), os.path.join(com_ocean_analysis, f'{RUN}.t{cyc}z.ice.bkgerr_stddev.nc')]) # Copy the ice and ocean increments -post_file_list.append([os.path.join(anl_dir, 'Data', f'ocn.3dvarfgat_pseudo.incr.{bdate}.nc'), +post_file_list.append([os.path.join(anl_dir, 'Data', f'ocn.3dvarfgat_pseudo.incr.{mdate}.nc'), os.path.join(com_ocean_analysis, f'{RUN}.t{cyc}z.ocn.incr.nc')]) -post_file_list.append([os.path.join(anl_dir, 'Data', f'ice.3dvarfgat_pseudo.incr.{bdate}.nc'), +post_file_list.append([os.path.join(anl_dir, 'Data', f'ice.3dvarfgat_pseudo.incr.{mdate}.nc'), os.path.join(com_ocean_analysis, f'{RUN}.t{cyc}z.ice.incr.nc')]) # Copy DA grid (computed for the start of the window) @@ -75,9 +76,9 @@ def list_all_files(dir_in, dir_out, wc='*', fh_list=[]): os.path.join(com_ocean_analysis, f'{RUN}.t{bcyc}z.ocngrid.nc')]) # Copy the analysis at the start of the window -post_file_list.append([os.path.join(anl_dir, 'Data', f'ocn.3dvarfgat_pseudo.an.{bdate}.nc'), +post_file_list.append([os.path.join(anl_dir, 'Data', f'ocn.3dvarfgat_pseudo.an.{mdate}.nc'), os.path.join(com_ocean_analysis, f'{RUN}.t{cyc}z.ocnana.nc')]) -post_file_list.append([os.path.join(anl_dir, 'Data', f'ice.3dvarfgat_pseudo.an.{bdate}.nc'), +post_file_list.append([os.path.join(anl_dir, 'Data', f'ice.3dvarfgat_pseudo.an.{mdate}.nc'), os.path.join(com_ocean_analysis, f'{RUN}.t{cyc}z.iceana.nc')]) # Copy the CICE analysis restart diff --git a/scripts/exgdas_global_marine_analysis_prep.py b/scripts/exgdas_global_marine_analysis_prep.py index 21af4bcc7..a6bef66bc 100755 --- a/scripts/exgdas_global_marine_analysis_prep.py +++ b/scripts/exgdas_global_marine_analysis_prep.py @@ -22,6 +22,7 @@ import sys import yaml import glob +import copy import dateutil.parser as dparser import f90nml import shutil @@ -168,7 +169,8 @@ def gen_bkg_list(bkg_path, out_path, window_begin=' ', yaml_name='bkg.yaml', ice 'ocn_filename': ocn_filename, 'ice_filename': agg_ice_filename, 'read_from_file': 1, - 'remap_filename': './bkg/'+ocn_filename_ic} + '#remap_filename': './bkg/'+ocn_filename_ic} # TODO: Remapping bug in soca. Switch to z* + bkg_date = bkg_date + timedelta(hours=dt_pseudo) # TODO: make the bkg interval a configurable bkg_list.append(bkg_dict) @@ -233,8 +235,10 @@ def find_clim_ens(input_date): # Variables of convenience half_assim_freq = timedelta(hours=int(os.getenv('assim_freq'))/2) +window_middle = datetime.strptime(os.getenv('PDY')+os.getenv('cyc'), '%Y%m%d%H') window_begin = datetime.strptime(os.getenv('PDY')+os.getenv('cyc'), '%Y%m%d%H') - half_assim_freq window_begin_iso = window_begin.strftime('%Y-%m-%dT%H:%M:%SZ') +window_middle_iso = window_middle.strftime('%Y-%m-%dT%H:%M:%SZ') fcst_begin = datetime.strptime(os.getenv('PDY')+os.getenv('cyc'), '%Y%m%d%H') RUN = os.getenv('RUN') cyc = os.getenv('cyc') @@ -254,6 +258,7 @@ def find_clim_ens(input_date): 'r2d2_obs_dump': os.getenv('R2D2_OBS_DUMP'), 'r2d2_obs_db': os.getenv('R2D2_OBS_DB'), 'ATM_WINDOW_BEGIN': window_begin_iso, + 'ATM_WINDOW_MIDDLE': window_middle_iso, 'ATM_WINDOW_LENGTH': f"PT{os.getenv('assim_freq')}H"} stage_cfg = YAMLFile(path=os.path.join(gdas_home, 'parm', 'templates', 'stage.yaml')) stage_cfg = Template.substitute_structure(stage_cfg, TemplateConstants.DOUBLE_CURLY_BRACES, envconfig.get) @@ -274,7 +279,12 @@ def find_clim_ens(input_date): logging.info(f"******* {obs_file}") obs_src = os.path.join(os.getenv('COM_OBS'), obs_file) obs_dst = os.path.join(os.path.abspath(obs_in), obs_file) - obs_list.append([obs_src, obs_dst]) + if os.path.exists(obs_src): + logging.info(f"******* fetching {obs_file}") + obs_list.append([obs_src, obs_dst]) + else: + logging.info(f"******* {obs_file} is not in the database") + FileHandler({'copy': obs_list}).sync() ################################################################################ @@ -301,6 +311,8 @@ def find_clim_ens(input_date): clim_ens_member_list = [] clim_ens_dir = find_clim_ens(pytz.utc.localize(window_begin, is_dst=None)) clim_ens_size = len(glob.glob(os.path.abspath(os.path.join(clim_ens_dir, 'ocn.*.nc')))) +os.environ['CLIM_ENS_SIZE'] = str(clim_ens_size) + for domain in ['ocn', 'ice']: for mem in range(1, clim_ens_size+1): fname = domain+"."+str(mem)+".nc" @@ -338,6 +350,51 @@ def find_clim_ens(input_date): config = Template.substitute_structure(config, TemplateConstants.DOLLAR_PARENTHESES, envconfig.get) config.save(berr_yaml) +################################################################################ +# generate YAMLS file for diag of clim. ens. B +berror_yaml_dir = os.path.join(gdas_home, 'parm', 'soca', 'berror') + +logging.info(f"---------------- generate soca_clim_moments.yaml") +berr_yaml = os.path.join(anl_dir, 'soca_clim_ens_moments.yaml') +berr_yaml_template = os.path.join(berror_yaml_dir, 'soca_clim_ens_moments.yaml') +config = YAMLFile(path=berr_yaml_template) +config = Template.substitute_structure(config, TemplateConstants.DOUBLE_CURLY_BRACES, envconfig.get) +config = Template.substitute_structure(config, TemplateConstants.DOLLAR_PARENTHESES, envconfig.get) +config.save(berr_yaml) + +logging.info(f"---------------- generate soca_clim_ens_perts.yaml") +berr_yaml = os.path.join(anl_dir, 'soca_clim_ens_perts.yaml') +berr_yaml_template = os.path.join(berror_yaml_dir, 'soca_clim_ens_perts.yaml') +config = YAMLFile(path=berr_yaml_template) +config = Template.substitute_structure(config, TemplateConstants.DOUBLE_CURLY_BRACES, envconfig.get) +config = Template.substitute_structure(config, TemplateConstants.DOLLAR_PARENTHESES, envconfig.get) +config.save(berr_yaml) + +logging.info(f"---------------- generate soca_apply_steric.yaml") +berr_yaml = os.path.join(anl_dir, 'soca_apply_steric.yaml') +berr_yaml_template = os.path.join(berror_yaml_dir, 'soca_apply_steric.yaml') +config = YAMLFile(path=berr_yaml_template) +config = Template.substitute_structure(config, TemplateConstants.DOUBLE_CURLY_BRACES, envconfig.get) +config = Template.substitute_structure(config, TemplateConstants.DOLLAR_PARENTHESES, envconfig.get) +member_template = config['increments'][0] +ocn_fname_tmpl = member_template['input']['ocn_filename'] +ice_fname_tmpl = member_template['input']['ice_filename'] +config['increments'] = [] +for n in range(1, clim_ens_size+1): + member = copy.deepcopy(member_template) + member['input']['ocn_filename'] = member['input']['ocn_filename'].replace("MEMNUM", str(n)) + member['input']['ice_filename'] = member['input']['ice_filename'].replace("MEMNUM", str(n)) + member['output']['exp'] = member['output']['exp'].replace("MEMNUM", str(n)) + config['increments'].append(member) +config.save(berr_yaml) + +logging.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) + ################################################################################ # copy yaml for decorrelation length scales @@ -346,6 +403,14 @@ def find_clim_ens(input_date): corscales_yaml_dst = os.path.join(stage_cfg['stage_dir'], 'soca_setcorscales.yaml') FileHandler({'copy': [[corscales_yaml_src, corscales_yaml_dst]]}).sync() +################################################################################ +# copy yaml for localization length scales + +logging.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() + ################################################################################ # generate yaml for bump/nicas (used for correlation and/or localization) @@ -443,6 +508,7 @@ def find_clim_ens(input_date): ufsda.yamltools.save_check(varconfig.as_dict(), target=var_yaml, app='var') ################################################################################ +# Prepare the yamls for the "checkpoint" jjob # prepare yaml and CICE restart for soca to cice change of variable logging.info(f"---------------- generate soca to cice yamls") @@ -458,8 +524,8 @@ def find_clim_ens(input_date): "template": "", "output": "", "config": { - "OCN_ANA": "./Data/ocn.3dvarfgat_pseudo.an."+window_begin_iso+".nc", - "ICE_ANA": "./Data/ice.3dvarfgat_pseudo.an."+window_begin_iso+".nc", + "OCN_ANA": "./Data/ocn.3dvarfgat_pseudo.an."+window_middle_iso+".nc", + "ICE_ANA": "./Data/ice.3dvarfgat_pseudo.an."+window_middle_iso+".nc", "ICE_RST": ice_rst_ana, "FCST_BEGIN": fcst_begin.strftime('%Y-%m-%dT%H:%M:%SZ') } diff --git a/test/soca/testinput/socaincr2mom6.yaml b/test/soca/testinput/socaincr2mom6.yaml index 0b11b893d..a5b5cf600 100644 --- a/test/soca/testinput/socaincr2mom6.yaml +++ b/test/soca/testinput/socaincr2mom6.yaml @@ -17,7 +17,7 @@ vertical geometry: soca increment: date: 2018-04-15T09:00:00Z basename: ./Data/ - ocn_filename: 'ocn.3dvarfgat_pseudo.incr.2018-04-15T09:00:00Z.nc' + ocn_filename: 'ocn.3dvarfgat_pseudo.incr.2018-04-15T12:00:00Z.nc' read_from_file: 1 mom6 iau increment: