IODA Bundle
ObsSpaceParameters.h
Go to the documentation of this file.
1 /*
2  * (C) Copyright 2020 UCAR
3  *
4  * This software is licensed under the terms of the Apache Licence Version 2.0
5  * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
6  */
7 
8 #ifndef OBSSPACEPARAMETERS_H_
9 #define OBSSPACEPARAMETERS_H_
10 
11 #include <string>
12 #include <vector>
13 
14 #include "ioda/core/FileFormat.h"
15 #include "ioda/core/ParameterTraitsFileFormat.h"
17 #include "ioda/Misc/Dimensions.h"
18 #include "ioda/io/ObsIoFactory.h"
19 #include "ioda/io/ObsIoParametersBase.h"
20 
21 #include "eckit/exception/Exceptions.h"
22 #include "eckit/mpi/Comm.h"
23 
24 #include "oops/base/ObsSpaceBase.h" // for ObsSpaceParametersBase
26 #include "oops/util/DateTime.h"
27 #include "oops/util/Logger.h"
28 #include "oops/util/parameters/OptionalParameter.h"
29 #include "oops/util/parameters/Parameter.h"
30 #include "oops/util/parameters/Parameters.h"
31 #include "oops/util/parameters/RequiredParameter.h"
32 #include "oops/util/parameters/RequiredPolymorphicParameter.h"
33 
34 
35 namespace eckit {
36  class Configuration;
37 }
38 
39 namespace ioda {
40 
42  OOPS_CONCRETE_PARAMETERS(ObsFileInParameters, ObsIoParametersBase)
43 
44  public:
45  /// input obs file name
46  oops::RequiredParameter<std::string> fileName{"obsfile", this};
47 
48  /// input obs file format
49  ///
50  /// Possible values:
51  /// * `hdf5`: HDF5 file format
52  /// * `odb`: ODB file format
53  /// * `auto` (default): file format determined automatically from the file name extension
54  /// (`.odb` -- ODB, everything else -- HDF5).
55  oops::Parameter<FileFormat> format{"format", FileFormat::AUTO, this};
56 
57  /// reading from multiple files (1 per MPI task)
58  /// This option is not typically used. It is used to tell the system
59  /// to read observations from the ioda output files (one per MPI task)
60  /// from a prior run instead of reading and distributing from the original
61  /// file. This is currently being used in LETKF applictions.
62  oops::Parameter<bool> readFromSeparateFiles{"read obs from separate file", false, this};
63 
64  /// file with variable name mapping rules
65  ///
66  /// Required for obs files in the ODB format, unused otherwise.
67  oops::Parameter<std::string> mappingFile{"mapping file", "", this};
68  /// file with query parameters
69  ///
70  /// Required for obs files in the ODB format, unused otherwise.
71  oops::Parameter<std::string> queryFile{"query file", "", this};
72 };
73 
75  OOPS_CONCRETE_PARAMETERS(ObsFileOutParameters, ObsIoParametersBase)
76 
77  public:
78  /// output obs file name
79  oops::RequiredParameter<std::string> fileName{"obsfile", this};
80 };
81 
82 class ObsExtendParameters : public oops::Parameters {
83  OOPS_CONCRETE_PARAMETERS(ObsExtendParameters, oops::Parameters)
84 
85  public:
86  /// number of model levels in target of the averaging function
87  oops::RequiredParameter<int> numModelLevels{"average profiles onto model levels", this};
88 
89  /// number of model levels in target of the averaging function
90  oops::Parameter<std::vector<std::string>> nonMissingExtendedVars
91  {"variables filled with non-missing values",
92  { "latitude", "longitude", "datetime", "air_pressure", "air_pressure_levels" },
93  this};
94 };
95 
97  OOPS_ABSTRACT_PARAMETERS(ObsGenerateParametersBase, ObsIoParametersBase)
98 
99  public:
100  /// obs error estimates
101  oops::Parameter<std::vector<float>> obsErrors{"obs errors", { }, this};
102 };
103 
104 class EmbeddedObsGenerateRandomParameters : public oops::Parameters {
105  OOPS_CONCRETE_PARAMETERS(EmbeddedObsGenerateRandomParameters, Parameters)
106 
107  public:
108  /// number of observations
109  oops::RequiredParameter<int> numObs{"nobs", this};
110 
111  /// latitude range start
112  oops::RequiredParameter<float> latStart{"lat1", this};
113 
114  /// latitude range end
115  oops::RequiredParameter<float> latEnd{"lat2", this};
116 
117  /// longitude range start
118  oops::RequiredParameter<float> lonStart{"lon1", this};
119 
120  /// longitude range end
121  oops::RequiredParameter<float> lonEnd{"lon2", this};
122 
123  /// random seed
124  oops::OptionalParameter<int> ranSeed{"random seed", this};
125 };
126 
127 /// Options controlling the ObsIoGenerateRandom class
129  OOPS_CONCRETE_PARAMETERS(ObsGenerateRandomParameters, ObsGenerateParametersBase)
130 
131  public:
132  /// options shared by this class and the legacy implementation (LegacyObsGenerateParameters)
134 };
135 
136 class EmbeddedObsGenerateListParameters : public oops::Parameters {
137  OOPS_CONCRETE_PARAMETERS(EmbeddedObsGenerateListParameters, Parameters)
138 
139  public:
140  /// latitude values
141  oops::RequiredParameter<std::vector<float>> lats{"lats", this};
142 
143  /// longitude values
144  oops::RequiredParameter<std::vector<float>> lons{"lons", this};
145 
146  /// datetime values
147  oops::RequiredParameter<std::vector<std::string>> datetimes{"datetimes", this};
148 };
149 
150 /// Options controlling the ObsIoGenerateList class
152  OOPS_CONCRETE_PARAMETERS(ObsGenerateListParameters, ObsGenerateParametersBase)
153 
154  public:
155  /// options shared by this class and the legacy implementation (LegacyObsGenerateParameters)
157 };
158 
159 /// \brief Options in the 'generate' YAML section.
160 ///
161 /// \note If you add or remove any Parameter member variables from this class, be sure to update
162 /// ObsTopLevelParameters::deserialize() to match.
163 class LegacyObsGenerateParameters : public oops::Parameters {
164  OOPS_CONCRETE_PARAMETERS(LegacyObsGenerateParameters, Parameters)
165 
166  public:
167  /// specification for generating using the random method
168  oops::OptionalParameter<EmbeddedObsGenerateRandomParameters> random{"random", this};
169 
170  /// specification for generating using the list method
171  oops::OptionalParameter<EmbeddedObsGenerateListParameters> list{"list", this};
172 
173  /// options controlling obs record grouping
174  oops::Parameter<ObsGroupingParameters> obsGrouping{"obsgrouping", { }, this};
175 
176  /// obs error estimates
177  oops::Parameter<std::vector<float>> obsErrors{"obs errors", { }, this};
178 
179  /// maximum frame size
180  oops::Parameter<int> maxFrameSize{"max frame size", DEFAULT_FRAME_SIZE, this};
181 };
182 
183 class ObsIoParametersWrapper : public oops::Parameters {
184  OOPS_CONCRETE_PARAMETERS(ObsIoParametersWrapper, Parameters)
185  public:
186  oops::RequiredPolymorphicParameter<ObsIoParametersBase, ObsIoFactory>
187  obsIoInParameters{"type", this};
188 };
189 
190 class ObsTopLevelParameters : public oops::ObsSpaceParametersBase {
191  OOPS_CONCRETE_PARAMETERS(ObsTopLevelParameters, ObsSpaceParametersBase)
192 
193  public:
194  /// Reimplemented to store contents of the `obsdatain` or `generate` section (if present)
195  /// in the source member variable. This makes it possible for the options related to the source
196  /// of input data to be accessed in a uniform way (regardless of in which section they were
197  /// specified) by calling obsIoInParameters().
198  void deserialize(util::CompositePath &path, const eckit::Configuration &config) override;
199 
200  /// name of obs space
201  oops::RequiredParameter<std::string> obsSpaceName{"name", this};
202 
203  /// name of MPI distribution
204  oops::Parameter<std::string> distName{"distribution", "RoundRobin", this};
205 
206  /// If saveObsDistribution/"save obs distribution" set to true,
207  /// global location indices and record numbers will be stored
208  /// in the MetaData/saved_index and MetaData/saved_record_number variables, respectively.
209  /// These variables will be saved along with all other variables
210  /// to the output files generated if the obsdataout.obsfile option is set.
211  ///
212  /// When the "obsdatain.read obs from separate file" option is set
213  /// and hence each process reads a separate input file,
214  /// the presence of these variables makes it possible
215  /// to identify observations stored in more than one input file.
216 
217  oops::Parameter<bool> saveObsDistribution{"save obs distribution", false, this};
218 
219  /// simulated variables
220  oops::RequiredParameter<oops::Variables> simVars{"simulated variables", this};
221 
222  /// Simulated variables whose observed values may be absent from the input file, but must be
223  /// created (computed) by the start of the data assimilation stage.
224  oops::Parameter<oops::Variables> derivedSimVars{"derived simulated variables", {}, this};
225 
226  /// Halo distribution center
227  oops::OptionalParameter<std::vector<float>> haloCenter{"center", this};
228 
229  /// Halo distribution radius
230  oops::OptionalParameter<float> haloRadius{"radius", this};
231 
232  /// output specification by writing to a file
233  oops::OptionalParameter<ObsFileOutParameters> obsOutFile{"obsdataout", this};
234 
235  /// extend the ObsSpace with extra fixed-size records
236  oops::OptionalParameter<ObsExtendParameters> obsExtend{"extension", this};
237 
238  /// parameters indicating where to load data from
240  if (source.value() != boost::none)
241  return source.value()->obsIoInParameters.value();
242  throw eckit::BadValue("obsIoInParameters() must not be called before deserialize()", Here());
243  }
244 
245  private:
246  /// \brief Fill this section to read observations from a file.
247  oops::OptionalParameter<ObsFileInParameters> obsInFile{"obsdatain", this};
248 
249  /// \brief Fill this section to generate observations on the fly.
250  oops::OptionalParameter<LegacyObsGenerateParameters> obsGenerate{"generate", this};
251 
252  /// \brief Fill this section instead of `obsdatain` and `generate` to load observations from
253  /// any other source.
254  oops::OptionalParameter<ObsIoParametersWrapper> source{"source", this};
255 };
256 
258  public:
259  /// sub groups of parameters
261 
262  /// Constructor
264  const util::DateTime & winStart, const util::DateTime & winEnd,
265  const eckit::mpi::Comm & comm, const eckit::mpi::Comm & timeComm) :
266  top_level_(topLevelParams),
267  win_start_(winStart), win_end_(winEnd), comm_(comm),
269  new_dims_(), max_var_size_(0) {
270  // Record the MPI rank number. The rank number is being saved during the
271  // construction of the Parameters for the ObsSpace saveToFile routine.
272  // (saveToFile will uniquify the output file name by tagging on the MPI rank
273  // number) For some reason, querying the saved MPI communicator (comm_) during
274  // the deconstruction process (when saveToFile is being run) will not reliably
275  // return the correct rank number. It was attempted to put in an MPI barrier call
276  // in case the issue was one rank finishing up before the other got to the query, but
277  // the barrier command itself caused a crash. It appears that the saved MPI
278  // communicator is getting corrupted during the deconstruction, but this has not
279  // been fully debugged, and should therefore be looked at later.
280  mpi_rank_ = comm.rank();
281  if (timeComm.size() > 1) {
282  mpi_time_rank_ = timeComm.rank();
283  } else {
284  mpi_time_rank_ = -1;
285  }
286  }
287 
288  /// \brief return the start of the DA timing window
289  const util::DateTime & windowStart() const {return win_start_;}
290 
291  /// \brief return the end of the DA timing window
292  const util::DateTime & windowEnd() const {return win_end_;}
293 
294  /// \brief return the associated MPI group communicator
295  const eckit::mpi::Comm & comm() const {return comm_;}
296 
297  /// \brief return the associated perturbations seed
298  int obsPertSeed() const {return top_level_.obsPerturbationsSeed;}
299 
300  /// \brief return the associated MPI time communicator
301  const eckit::mpi::Comm & timeComm() const {return time_comm_;}
302 
303  /// \brief set a new dimension scale
304  void setDimScale(const std::string & dimName, const Dimensions_t curSize,
305  const Dimensions_t maxSize, const Dimensions_t chunkSize) {
306  new_dims_.push_back(
307  NewDimensionScale<int>(dimName, curSize, maxSize, chunkSize));
308  }
309 
310  /// \brief get a new dimension scale
312 
313  /// \brief set the maximum variable size
314  void setMaxVarSize(const Dimensions_t maxVarSize) { max_var_size_ = maxVarSize; }
315 
316  /// \brief get the maximum variable size
317  Dimensions_t getMaxVarSize() const { return max_var_size_; }
318 
319  /// \brief get the MPI rank number
320  std::size_t getMpiRank() const { return mpi_rank_; }
321 
322  /// \brief get the MPI rank number
323  int getMpiTimeRank() const { return mpi_time_rank_; }
324 
325  private:
326  /// \brief Beginning of DA timing window
327  const util::DateTime win_start_;
328 
329  /// \brief End of DA timing window
330  const util::DateTime win_end_;
331 
332  /// \brief MPI group communicator
333  const eckit::mpi::Comm & comm_;
334 
335  /// \brief MPI time communicator
336  const eckit::mpi::Comm & time_comm_;
337 
338  /// \brief new dimension scales for output file construction
340 
341  /// \brief maximum variable size for output file contruction
342  Dimensions_t max_var_size_;
343 
344  /// \brief group MPI rank number for output file construction
345  std::size_t mpi_rank_;
346 
347  /// \brief time MPI rank number of output file construction
349 };
350 
351 } // namespace ioda
352 
353 #endif // OBSSPACEPARAMETERS_H_
Convenience classes for constructing ObsSpaces and setting up new Dimension Scales.
Describe the dimensions of a ioda::Attribute or ioda::Variable.
oops::RequiredParameter< std::vector< float > > lats
latitude values
oops::RequiredParameter< std::vector< std::string > > datetimes
datetime values
oops::RequiredParameter< std::vector< float > > lons
longitude values
oops::RequiredParameter< float > latEnd
latitude range end
oops::RequiredParameter< float > lonStart
longitude range start
oops::RequiredParameter< float > latStart
latitude range start
oops::OptionalParameter< int > ranSeed
random seed
oops::RequiredParameter< float > lonEnd
longitude range end
oops::RequiredParameter< int > numObs
number of observations
Options in the 'generate' YAML section.
oops::Parameter< std::vector< float > > obsErrors
obs error estimates
oops::Parameter< ObsGroupingParameters > obsGrouping
options controlling obs record grouping
oops::OptionalParameter< EmbeddedObsGenerateRandomParameters > random
specification for generating using the random method
oops::OptionalParameter< EmbeddedObsGenerateListParameters > list
specification for generating using the list method
oops::Parameter< int > maxFrameSize
maximum frame size
oops::Parameter< std::vector< std::string > > nonMissingExtendedVars
number of model levels in target of the averaging function
oops::RequiredParameter< int > numModelLevels
number of model levels in target of the averaging function
oops::Parameter< FileFormat > format
oops::Parameter< std::string > queryFile
oops::Parameter< std::string > mappingFile
oops::Parameter< bool > readFromSeparateFiles
oops::RequiredParameter< std::string > fileName
input obs file name
oops::RequiredParameter< std::string > fileName
output obs file name
Options controlling the ObsIoGenerateList class.
EmbeddedObsGenerateListParameters list
options shared by this class and the legacy implementation (LegacyObsGenerateParameters)
oops::Parameter< std::vector< float > > obsErrors
obs error estimates
Options controlling the ObsIoGenerateRandom class.
EmbeddedObsGenerateRandomParameters random
options shared by this class and the legacy implementation (LegacyObsGenerateParameters)
Base of classes storing the configuration parameters of ObsIo subclasses.
oops::RequiredPolymorphicParameter< ObsIoParametersBase, ObsIoFactory > obsIoInParameters
const eckit::mpi::Comm & time_comm_
MPI time communicator.
int obsPertSeed() const
return the associated perturbations seed
NewDimensionScales_t new_dims_
new dimension scales for output file construction
int getMpiTimeRank() const
get the MPI rank number
const util::DateTime & windowEnd() const
return the end of the DA timing window
void setMaxVarSize(const Dimensions_t maxVarSize)
set the maximum variable size
ObsTopLevelParameters top_level_
sub groups of parameters
std::size_t mpi_rank_
group MPI rank number for output file construction
std::size_t getMpiRank() const
get the MPI rank number
NewDimensionScales_t getDimScales() const
get a new dimension scale
const util::DateTime win_start_
Beginning of DA timing window.
const eckit::mpi::Comm & comm_
MPI group communicator.
void setDimScale(const std::string &dimName, const Dimensions_t curSize, const Dimensions_t maxSize, const Dimensions_t chunkSize)
set a new dimension scale
Dimensions_t getMaxVarSize() const
get the maximum variable size
int mpi_time_rank_
time MPI rank number of output file construction
const eckit::mpi::Comm & timeComm() const
return the associated MPI time communicator
const util::DateTime & windowStart() const
return the start of the DA timing window
const eckit::mpi::Comm & comm() const
return the associated MPI group communicator
const util::DateTime win_end_
End of DA timing window.
ObsSpaceParameters(const ObsTopLevelParameters &topLevelParams, const util::DateTime &winStart, const util::DateTime &winEnd, const eckit::mpi::Comm &comm, const eckit::mpi::Comm &timeComm)
Constructor.
Dimensions_t max_var_size_
maximum variable size for output file contruction
oops::OptionalParameter< ObsFileInParameters > obsInFile
Fill this section to read observations from a file.
oops::OptionalParameter< float > haloRadius
Halo distribution radius.
oops::OptionalParameter< LegacyObsGenerateParameters > obsGenerate
Fill this section to generate observations on the fly.
oops::RequiredParameter< oops::Variables > simVars
simulated variables
void deserialize(util::CompositePath &path, const eckit::Configuration &config) override
oops::OptionalParameter< ObsIoParametersWrapper > source
Fill this section instead of obsdatain and generate to load observations from any other source.
oops::OptionalParameter< std::vector< float > > haloCenter
Halo distribution center.
oops::OptionalParameter< ObsExtendParameters > obsExtend
extend the ObsSpace with extra fixed-size records
oops::RequiredParameter< std::string > obsSpaceName
name of obs space
oops::Parameter< bool > saveObsDistribution
oops::OptionalParameter< ObsFileOutParameters > obsOutFile
output specification by writing to a file
oops::Parameter< oops::Variables > derivedSimVars
oops::Parameter< std::string > distName
name of MPI distribution
const ObsIoParametersBase & obsIoInParameters() const
parameters indicating where to load data from
std::vector< std::shared_ptr< NewDimensionScale_Base > > NewDimensionScales_t
constexpr int DEFAULT_FRAME_SIZE