Skip to content

Commit fa09326

Browse files
Add code changes for the implementation of the low-resolution B (#1441)
As the title says. ## Dependencies - NOAA-EMC/jcb-gdas#66 - NOAA-EMC/global-workflow#3238 - Update of the static files in glopara: NOAA-EMC/global-workflow#3239 ## Work done in this PR Interp to low-resolution: - [ ] variance partitioning - [ ] preparation of the perturbations for the envar - [ ] hybrid weights - [ ] ... ## Testing Visual check showing the variance explained by the steric height (30 members) ![steic-explained-variance](https://github.com/user-attachments/assets/274c3fdb-94c3-42fc-ad6e-90867b39a778) left is native resolution, right is on the 1/2 deg grid. **"Science" note:** The explained variance above is almost the opposite to what I would have expected, and what we saw in the previous offline ensemble, or even what we see in tendencies. Check if there's a bug in the explained variance calculation. # Automated CI tests to run in Global Workflow <!-- Which Global Workflow CI tests are required to adequately test this PR? --> - [ ] atm_jjob <!-- JEDI atm single cycle DA !--> - [ ] C96C48_ufs_hybatmDA <!-- JEDI atm cycled DA !--> - [ ] C96C48_hybatmaerosnowDA <!-- JEDI aero/snow cycled DA !--> - [x] C48mx500_3DVarAOWCDA <!-- JEDI low-res marine 3DVar cycled DA !--> - [x] C48mx500_hybAOWCDA <!-- JEDI marine hybrid envar cycled DA !--> - [ ] C96C48_hybatmDA <!-- GSI atm cycled DA !-->
1 parent 74297a3 commit fa09326

10 files changed

+162
-82
lines changed

parm/soca/fms/input.nml.j2

+5-11
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,16 @@
11
&MOM_input_nml
22
output_directory = './',
3-
input_filename = 'r'
3+
input_filename = 'r',
4+
{% if not simple_geom %}
45
restart_input_dir = 'INPUT/',
56
restart_output_dir = 'RESTART/',
6-
parameter_filename = 'MOM_input' /
7+
{% endif %}
8+
parameter_filename = '{{ mom_input }}'
9+
/
710

811
&diag_manager_nml
912
/
1013

11-
&ocean_solo_nml
12-
months = 0
13-
days = 1
14-
date_init = {{ date_init }},
15-
hours = 0
16-
minutes = 0
17-
seconds = 0
18-
calendar = 'NOLEAP' /
19-
2014
&fms_io_nml
2115
max_files_w=100
2216
checksum_required=.false.

parm/soca/soca_fix_stage_025.yaml.j2

+5
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
mkdir:
22
- "{{ DATA }}/INPUT"
3+
- "{{ DATA }}/anl_geom"
34
######################################
45
# fix files to copy
56
######################################
67
copy:
8+
# Deterministic resource files
79
- ["{{ SOCA_INPUT_FIX_DIR }}/rossrad.nc", "{{ DATA }}/rossrad.nc"]
810
- ["{{ SOCA_INPUT_FIX_DIR }}/field_table", "{{ DATA }}/field_table"]
911
- ["{{ SOCA_INPUT_FIX_DIR }}/diag_table", "{{ DATA }}/diag_table"]
@@ -23,3 +25,6 @@ copy:
2325
- ["{{ SOCA_INPUT_FIX_DIR }}/INPUT/geothermal_davies2013_v1.nc", "{{ DATA }}/INPUT/geothermal_davies2013_v1.nc"]
2426
- ["{{ SOCA_INPUT_FIX_DIR }}/INPUT/interpolate_zgrid_46L.nc", "{{ DATA }}/INPUT/interpolate_zgrid_46L.nc"]
2527
- ["{{ SOCA_INPUT_FIX_DIR }}/INPUT/C384_mosaic.nc", "{{ DATA }}/INPUT/C384_mosaic.nc"]
28+
# Analysis resource files
29+
- ["{{ SOCA_ANL_GEOM }}/soca_gridspec.nc", "{{ DATA }}/anl_geom/soca_gridspec.nc"]
30+
- ["{{ SOCA_ANL_GEOM }}/MOM_input", "{{ DATA }}/anl_geom/MOM_input"]

parm/soca/soca_fix_stage_100.yaml.j2

+5
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
mkdir:
22
- "{{ DATA }}/INPUT"
3+
- "{{ DATA }}/anl_geom"
34
######################################
45
# fix files to copy
56
######################################
67
copy:
8+
# Deterministic resource files
79
- ["{{ SOCA_INPUT_FIX_DIR }}/rossrad.nc", "{{ DATA }}/rossrad.nc"]
810
- ["{{ SOCA_INPUT_FIX_DIR }}/field_table", "{{ DATA }}/field_table"]
911
- ["{{ SOCA_INPUT_FIX_DIR }}/diag_table", "{{ DATA }}/diag_table"]
@@ -23,3 +25,6 @@ copy:
2325
- ["{{ SOCA_INPUT_FIX_DIR }}/INPUT/topo_edits_011818.nc", "{{ DATA }}/INPUT/topo_edits_011818.nc"]
2426
- ["{{ SOCA_INPUT_FIX_DIR }}/INPUT/MOM_channels_SPEAR", "{{ DATA }}/INPUT/MOM_channels_SPEAR"]
2527
- ["{{ SOCA_INPUT_FIX_DIR }}/INPUT/seawifs_1998-2006_smoothed_2X.nc", "{{ DATA }}/INPUT/seawifs_1998-2006_smoothed_2X.nc"]
28+
# Analysis resource files
29+
- ["{{ SOCA_ANL_GEOM }}/soca_gridspec.nc", "{{ DATA }}/anl_geom/soca_gridspec.nc"]
30+
- ["{{ SOCA_ANL_GEOM }}/MOM_input", "{{ DATA }}/anl_geom/MOM_input"]

parm/soca/soca_fix_stage_500.yaml.j2

+5
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
mkdir:
22
- "{{ DATA }}/INPUT"
3+
- "{{ DATA }}/anl_geom"
34
######################################
45
# fix files to copy
56
######################################
67
copy:
8+
# Deterministic resource files
79
- ["{{ SOCA_INPUT_FIX_DIR }}/rossrad.nc", "{{ DATA }}/rossrad.nc"]
810
- ["{{ SOCA_INPUT_FIX_DIR }}/field_table", "{{ DATA }}/field_table"]
911
- ["{{ SOCA_INPUT_FIX_DIR }}/diag_table", "{{ DATA }}/diag_table"]
@@ -15,3 +17,6 @@ copy:
1517
- ["{{ SOCA_INPUT_FIX_DIR }}/INPUT/ocean_hgrid.nc", "{{ DATA }}/INPUT/ocean_hgrid.nc"]
1618
- ["{{ SOCA_INPUT_FIX_DIR }}/INPUT/ocean_mosaic.nc", "{{ DATA }}/INPUT/ocean_mosaic.nc"]
1719
- ["{{ SOCA_INPUT_FIX_DIR }}/INPUT/ocean_topog.nc", "{{ DATA }}/INPUT/ocean_topog.nc"]
20+
# Analysis resource files
21+
- ["{{ SOCA_ANL_GEOM }}/soca_gridspec.nc", "{{ DATA }}/anl_geom/soca_gridspec.nc"]
22+
- ["{{ SOCA_ANL_GEOM }}/MOM_input", "{{ DATA }}/anl_geom/MOM_input"]

utils/soca/gdas_ens_handler.h

+28-17
Original file line numberDiff line numberDiff line change
@@ -75,14 +75,22 @@ namespace gdasapp {
7575
// -----------------------------------------------------------------------------
7676

7777
int execute(const eckit::Configuration & fullConfig) const {
78-
// Setup the soca geometry
78+
// Setup the native geometry of the ens. members,
79+
// currently assumed to be the same as the deterministic
7980
const eckit::LocalConfiguration geomConfig(fullConfig, "geometry");
8081
oops::Log::info() << "geometry: " << std::endl << geomConfig << std::endl;
8182
const soca::Geometry geom(geomConfig, this->getComm());
8283

84+
// Setup the ensemble B (and output) soca geometry
85+
oops::Log::info() << "====================== ens B geometry" << std::endl;
86+
const std::string outputGeometryKey = fullConfig.has("output geometry")
87+
? "output geometry" // keep things backward compatible for now
88+
: "geometry"; // and default to the input geometry
89+
const eckit::LocalConfiguration geomOutConfig(fullConfig, outputGeometryKey);
90+
const soca::Geometry geomOut(geomOutConfig, this->getComm());
8391

8492
// Initialize the post processing
85-
PostProcIncr postProcIncr(fullConfig, geom, this->getComm());
93+
PostProcIncr postProcIncr(fullConfig, geom, this->getComm(), geomOut);
8694

8795
oops::Log::info() << "soca increments: " << std::endl
8896
<< postProcIncr.inputIncrConfig_ << std::endl;
@@ -93,7 +101,9 @@ namespace gdasapp {
93101
oops::Log::info() << postProcIncr.inputIncrConfig_ << std::endl;
94102

95103
// Assume z* output is the same for the trajectory and the state
96-
ensMembers.push_back(postProcIncr.read(i));
104+
soca::Increment fullResIncr = postProcIncr.read(i);
105+
soca::Increment lowResIncr(geomOut, fullResIncr); // interp to low resolution geometry
106+
ensMembers.push_back(lowResIncr);
97107
}
98108

99109
// Check if we need to recenter the increment around the deterministic
@@ -103,9 +113,9 @@ namespace gdasapp {
103113
}
104114

105115
// Compute ensemble moments
106-
soca::Increment ensMean(geom, postProcIncr.socaIncrVar_, postProcIncr.dt_);
107-
soca::Increment ensStd(geom, postProcIncr.socaIncrVar_, postProcIncr.dt_);
108-
soca::Increment ensVariance(geom, postProcIncr.socaIncrVar_, postProcIncr.dt_);
116+
soca::Increment ensMean(geomOut, postProcIncr.socaIncrVar_, postProcIncr.dt_);
117+
soca::Increment ensStd(geomOut, postProcIncr.socaIncrVar_, postProcIncr.dt_);
118+
soca::Increment ensVariance(geomOut, postProcIncr.socaIncrVar_, postProcIncr.dt_);
109119
gdasapp_ens_utils::ensMoments(ensMembers, ensMean, ensStd, ensVariance);
110120
oops::Log::info() << "mean: " << ensMean << std::endl;
111121
oops::Log::info() << "std: " << ensStd << std::endl;
@@ -123,14 +133,15 @@ namespace gdasapp {
123133

124134
// Initialize the trajectories used in the linear variable changes
125135
const eckit::LocalConfiguration trajConfig(fullConfig, "trajectory");
126-
soca::State determTraj(geom, trajConfig); // deterministic trajectory
136+
soca::State determTrajNative(geom, trajConfig); // deterministic trajectory at full res
137+
soca::State determTraj(geomOut, determTrajNative); // interpolated deterministic trajectory
127138
soca::State ensMeanTraj(determTraj); // trajectory defined as the ens. mean
128139
ensMeanTraj.zero();
129140
ensMeanTraj += ensMean;
130141

131142
// Compute the recentering increment as the difference between
132143
// the ensemble mean and the deterministic
133-
soca::Increment recenteringIncr(geom, postProcIncr.socaIncrVar_, postProcIncr.dt_);
144+
soca::Increment recenteringIncr(geomOut, postProcIncr.socaIncrVar_, postProcIncr.dt_);
134145
recenteringIncr.diff(determTraj, ensMeanTraj);
135146
postProcIncr.setToZero(recenteringIncr);
136147

@@ -192,7 +203,7 @@ namespace gdasapp {
192203

193204
// Save total ssh
194205
oops::Log::info() << "ssh ensemble member " << i << std::endl;
195-
soca::Increment ssh_tmp(geom, socaSshVar, postProcIncr.dt_);
206+
soca::Increment ssh_tmp(geomOut, socaSshVar, postProcIncr.dt_);
196207
ssh_tmp = ensMembers[i];
197208
sshTotal.push_back(ssh_tmp);
198209

@@ -257,9 +268,9 @@ namespace gdasapp {
257268
}
258269

259270
// Compute ensemble moments for total ssh
260-
soca::Increment sshMean(geom, socaSshVar, postProcIncr.dt_);
261-
soca::Increment sshStd(geom, socaSshVar, postProcIncr.dt_);
262-
soca::Increment sshTotalVariance(geom, socaSshVar, postProcIncr.dt_);
271+
soca::Increment sshMean(geomOut, socaSshVar, postProcIncr.dt_);
272+
soca::Increment sshStd(geomOut, socaSshVar, postProcIncr.dt_);
273+
soca::Increment sshTotalVariance(geomOut, socaSshVar, postProcIncr.dt_);
263274
gdasapp_ens_utils::ensMoments(sshTotal, sshMean, sshStd, sshTotalVariance);
264275
oops::Log::info() << "mean ssh total: " << sshMean << std::endl;
265276
oops::Log::info() << "std ssh total: " << sshStd << std::endl;
@@ -269,7 +280,7 @@ namespace gdasapp {
269280
// Compute ensemble moments for steric ssh
270281
sshMean.zero();
271282
sshStd.zero();
272-
soca::Increment sshStericVariance(geom, socaSshVar, postProcIncr.dt_);
283+
soca::Increment sshStericVariance(geomOut, socaSshVar, postProcIncr.dt_);
273284
gdasapp_ens_utils::ensMoments(sshSteric, sshMean, sshStd, sshStericVariance);
274285
oops::Log::info() << "mean steric ssh: " << sshMean << std::endl;
275286
oops::Log::info() << "std steric ssh: " << sshStd << std::endl;
@@ -278,8 +289,8 @@ namespace gdasapp {
278289

279290
// Compute ensemble moments for non-steric ssh
280291
sshMean.zero();
281-
soca::Increment sshNonStericVariance(geom, socaSshVar, postProcIncr.dt_);
282-
soca::Increment sshNonStericStd(geom, socaSshVar, postProcIncr.dt_);
292+
soca::Increment sshNonStericVariance(geomOut, socaSshVar, postProcIncr.dt_);
293+
soca::Increment sshNonStericStd(geomOut, socaSshVar, postProcIncr.dt_);
283294
sshNonStericStd.zero();
284295
gdasapp_ens_utils::ensMoments(sshNonSteric, sshMean, sshNonStericStd, sshNonStericVariance);
285296
oops::Log::info() << "mean non-steric ssh: " << sshMean << std::endl;
@@ -308,7 +319,7 @@ namespace gdasapp {
308319
ensStd.write(bkgErrOutputConfig);
309320

310321
// Explained variance by steric height R=1-SS(non-steric ssh)/SS(total ssh)
311-
soca::Increment varianceRatio(geom, socaSshVar, postProcIncr.dt_);
322+
soca::Increment varianceRatio(geomOut, socaSshVar, postProcIncr.dt_);
312323
varianceRatio = sshNonStericVariance;
313324
atlas::FieldSet varianceRatioFs;
314325
varianceRatio.toFieldSet(varianceRatioFs);
@@ -319,7 +330,7 @@ namespace gdasapp {
319330
util::divideFieldSets(varianceRatioFs, sshTotalVarianceFs, sshTotalVarianceFs);
320331
varianceRatio.fromFieldSet(varianceRatioFs);
321332

322-
soca::Increment stericExplainedVariance(geom, socaSshVar, postProcIncr.dt_);
333+
soca::Increment stericExplainedVariance(geomOut, socaSshVar, postProcIncr.dt_);
323334
stericExplainedVariance.ones();
324335
stericExplainedVariance -= varianceRatio;
325336

utils/soca/gdas_incr_handler.h

+8-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include <iostream>
44
#include <string>
5+
#include <vector>
56

67
#include "eckit/config/LocalConfiguration.h"
78

@@ -35,6 +36,12 @@ namespace gdasapp {
3536
oops::Log::info() << "geometry: " << std::endl << geomConfig << std::endl;
3637
const soca::Geometry geom(geomConfig, this->getComm());
3738

39+
// Domains to save
40+
std::vector<std::string> domains = {"ocn", "ice"};
41+
if (fullConfig.has("domains")) {
42+
fullConfig.get("domains", domains);
43+
}
44+
3845
// Check that we are using at least 2 mpi tasks
3946
if (this->getComm().size() < 2) {
4047
throw eckit::BadValue("This application requires at least 2 MPI tasks", Here());
@@ -65,7 +72,7 @@ namespace gdasapp {
6572
oops::Log::debug() << incr_mom6 << std::endl;
6673

6774
// Save final increment
68-
result = postProcIncr.save(incr_mom6, i);
75+
result = postProcIncr.save(incr_mom6, i, domains);
6976
oops::Log::debug() << "========= after appending layer and after saving:" << std::endl;
7077
oops::Log::debug() << incr_mom6 << std::endl;
7178
}

0 commit comments

Comments
 (0)