IODA Bundle
LocalizationBase.h
Go to the documentation of this file.
1 /*
2  * (C) Copyright 2009-2016 ECMWF.
3  * (C) Copyright 2020-2020 UCAR
4  *
5  * This software is licensed under the terms of the Apache Licence Version 2.0
6  * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
7  * In applying this licence, ECMWF does not waive the privileges and immunities
8  * granted to it by virtue of its status as an intergovernmental organisation nor
9  * does it submit to any jurisdiction.
10  */
11 
12 #ifndef OOPS_BASE_LOCALIZATIONBASE_H_
13 #define OOPS_BASE_LOCALIZATIONBASE_H_
14 
15 #include <map>
16 #include <memory>
17 #include <string>
18 
19 #include <boost/noncopyable.hpp>
20 
21 #include "oops/base/Geometry.h"
22 #include "oops/base/Increment.h"
23 #include "oops/mpi/mpi.h"
24 #include "oops/util/Logger.h"
25 #include "oops/util/Printable.h"
26 
27 namespace eckit {
28  class Configuration;
29 }
30 
31 namespace oops {
32 
33 // -----------------------------------------------------------------------------
34 /// Model-space localization base class
35 template <typename MODEL>
36 class LocalizationBase : public util::Printable,
37  private boost::noncopyable {
39 
40  public:
41  LocalizationBase() = default;
42  virtual ~LocalizationBase() = default;
43 
44  /// 4D localization with the same localization for time blocks
45  virtual void randomize(Increment_ &) const;
46  virtual void multiply(Increment_ &) const;
47 
48  protected:
49  virtual void doRandomize(Increment_ &) const = 0;
50  virtual void doMultiply(Increment_ &) const = 0;
51 
52  private:
53  virtual void print(std::ostream &) const = 0;
54 };
55 
56 // -----------------------------------------------------------------------------
57 /// Randomize
58 template <typename MODEL>
60  Log::trace() << "LocalizationBase<MODEL>::randomize starting" << std::endl;
61  const eckit::mpi::Comm & comm = dx.timeComm();
62  static int tag = 23456;
63  size_t nslots = comm.size();
64  int mytime = comm.rank();
65 
66  if (mytime > 0) {
67  util::DateTime dt = dx.validTime(); // Save original time value
68  dx.zero();
69  oops::mpi::receive(comm, dx, 0, tag);
70  dx.updateTime(dt - dx.validTime()); // Set time back to original value
71  } else {
72  // Apply 3D localization
73  this->doRandomize(dx);
74 
75  // Copy result to all timeslots
76  for (size_t jj = 1; jj < nslots; ++jj) {
77  oops::mpi::send(comm, dx, jj, tag);
78  }
79  }
80  ++tag;
81 
82  Log::trace() << "LocalizationBase<MODEL>::randomize done" << std::endl;
83 }
84 
85 // -----------------------------------------------------------------------------
86 /// Multiply
87 template <typename MODEL>
89  Log::trace() << "LocalizationBase<MODEL>::multiply starting" << std::endl;
90  const eckit::mpi::Comm & comm = dx.timeComm();
91  static int tag = 23456;
92  size_t nslots = comm.size();
93  int mytime = comm.rank();
94 
95  if (mytime > 0) {
96  util::DateTime dt = dx.validTime(); // Save original time value
97  oops::mpi::send(comm, dx, 0, tag);
98  dx.zero();
99  oops::mpi::receive(comm, dx, 0, tag);
100  dx.updateTime(dt - dx.validTime()); // Set time back to original value
101  } else {
102  // Sum over timeslots
103  for (size_t jj = 1; jj < nslots; ++jj) {
104  Increment_ dxtmp(dx);
105  oops::mpi::receive(comm, dxtmp, jj, tag);
106  dx.axpy(1.0, dxtmp, false);
107  }
108 
109  // Apply 3D localization
110  this->doMultiply(dx);
111 
112  // Copy result to all timeslots
113  for (size_t jj = 1; jj < nslots; ++jj) {
114  oops::mpi::send(comm, dx, jj, tag);
115  }
116  }
117  ++tag;
118 
119  Log::trace() << "LocalizationBase<MODEL>::multiply done" << std::endl;
120 }
121 
122 // =============================================================================
123 
124 /// Localization Factory
125 template <typename MODEL>
128  public:
129  static std::unique_ptr<LocalizationBase<MODEL>> create(const Geometry_ &,
130  const util::DateTime &,
131  const eckit::Configuration &);
132  virtual ~LocalizationFactory() = default;
133  protected:
134  explicit LocalizationFactory(const std::string &);
135  private:
137  const util::DateTime &,
138  const eckit::Configuration &) = 0;
139  static std::map < std::string, LocalizationFactory<MODEL> * > & getMakers() {
140  static std::map < std::string, LocalizationFactory<MODEL> * > makers_;
141  return makers_;
142  }
143 };
144 
145 // -----------------------------------------------------------------------------
146 
147 template<class MODEL, class T>
148 class LocalizationMaker : public LocalizationFactory<MODEL> {
150  virtual LocalizationBase<MODEL> * make(const Geometry_ & geometry,
151  const util::DateTime & time,
152  const eckit::Configuration & conf)
153  { return new T(geometry, time, conf); }
154  public:
155  explicit LocalizationMaker(const std::string & name) : LocalizationFactory<MODEL>(name) {}
156 };
157 
158 // =============================================================================
159 
160 template <typename MODEL>
162  if (getMakers().find(name) != getMakers().end()) {
163  throw std::runtime_error(name + " already registered in localization factory.");
164  }
165  getMakers()[name] = this;
166 }
167 
168 // -----------------------------------------------------------------------------
169 
170 template <typename MODEL>
171 std::unique_ptr<LocalizationBase<MODEL>>
173  const util::DateTime & time,
174  const eckit::Configuration & conf) {
175  Log::trace() << "LocalizationBase<MODEL>::create starting" << std::endl;
176  const std::string id = conf.getString("localization method");
177  typename std::map<std::string, LocalizationFactory<MODEL>*>::iterator
178  jloc = getMakers().find(id);
179  if (jloc == getMakers().end()) {
180  Log::error() << id << " does not exist in localization factory." << std::endl;
181  Log::error() << "Obs Localization Factory has " << getMakers().size()
182  << " elements:" << std::endl;
183  for (typename std::map<std::string, LocalizationFactory<MODEL>*>::const_iterator
184  jj = getMakers().begin(); jj != getMakers().end(); ++jj) {
185  Log::error() << "A " << jj->first << " Localization" << std::endl;
186  }
187  throw std::runtime_error(id + " does not exist in localization factory.");
188  }
189  std::unique_ptr<LocalizationBase<MODEL>> ptr(jloc->second->make(geometry, time, conf));
190  Log::trace() << "LocalizationBase<MODEL>::create done" << std::endl;
191  return ptr;
192 }
193 
194 // -----------------------------------------------------------------------------
195 
196 } // namespace oops
197 
198 #endif // OOPS_BASE_LOCALIZATIONBASE_H_
Geometry class used in oops; subclass of interface class interface::Geometry.
Increment class used in oops.
const eckit::mpi::Comm & timeComm() const
Accessor to the time communicator.
Model-space localization base class.
Increment< MODEL > Increment_
virtual void randomize(Increment_ &) const
4D localization with the same localization for time blocks
virtual void multiply(Increment_ &) const
Multiply.
virtual void doRandomize(Increment_ &) const =0
virtual void doMultiply(Increment_ &) const =0
virtual void print(std::ostream &) const =0
virtual ~LocalizationBase()=default
Localization Factory.
virtual ~LocalizationFactory()=default
LocalizationFactory(const std::string &)
virtual LocalizationBase< MODEL > * make(const Geometry_ &, const util::DateTime &, const eckit::Configuration &)=0
Geometry< MODEL > Geometry_
static std::unique_ptr< LocalizationBase< MODEL > > create(const Geometry_ &, const util::DateTime &, const eckit::Configuration &)
static std::map< std::string, LocalizationFactory< MODEL > * > & getMakers()
Geometry< MODEL > Geometry_
LocalizationMaker(const std::string &name)
virtual LocalizationBase< MODEL > * make(const Geometry_ &geometry, const util::DateTime &time, const eckit::Configuration &conf)
void axpy(const double &w, const Increment &dx, const bool check=true)
void updateTime(const util::Duration &dt)
Updates this Increment's valid time by dt (used in PseudoModel)
void zero()
Zero out this Increment.
const util::DateTime validTime() const
Accessor to the time of this Increment.
void send(const eckit::mpi::Comm &comm, const SERIALIZABLE &sendobj, const int dest, const int tag)
Extend eckit Comm for Serializable oops objects.
Definition: oops/mpi/mpi.h:44
void receive(const eckit::mpi::Comm &comm, SERIALIZABLE &recvobj, const int source, const int tag)
Definition: oops/mpi/mpi.h:55
The namespace for the main oops code.